cifsacl.c 27.6 KB
Newer Older
1 2 3
/*
 *   fs/cifs/cifsacl.c
 *
4
 *   Copyright (C) International Business Machines  Corp., 2007,2008
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   Contains the routines for mapping CIFS/NTFS ACLs
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

24
#include <linux/fs.h>
25
#include <linux/slab.h>
26 27 28 29
#include <linux/string.h>
#include <linux/keyctl.h>
#include <linux/key-type.h>
#include <keys/user-type.h>
30 31
#include "cifspdu.h"
#include "cifsglob.h"
32
#include "cifsacl.h"
33 34 35
#include "cifsproto.h"
#include "cifs_debug.h"

36
/* security id for everyone/world system group */
37 38
static const struct cifs_sid sid_everyone = {
	1, 1, {0, 0, 0, 0, 0, 1}, {0} };
39 40
/* security id for Authenticated Users system group */
static const struct cifs_sid sid_authusers = {
41
	1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
42
/* group users */
S
Steve French 已提交
43
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
44

45
static const struct cred *root_cred;
46

47
static int
48
cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
49 50 51
{
	char *payload;

52 53 54 55 56 57 58 59 60 61 62 63 64 65
	/*
	 * If the payload is less than or equal to the size of a pointer, then
	 * an allocation here is wasteful. Just copy the data directly to the
	 * payload.value union member instead.
	 *
	 * With this however, you must check the datalen before trying to
	 * dereference payload.data!
	 */
	if (prep->datalen <= sizeof(void *)) {
		key->payload.value = 0;
		memcpy(&key->payload.value, prep->data, prep->datalen);
		key->datalen = prep->datalen;
		return 0;
	}
66
	payload = kmalloc(prep->datalen, GFP_KERNEL);
67 68 69
	if (!payload)
		return -ENOMEM;

70
	memcpy(payload, prep->data, prep->datalen);
71
	key->payload.data = payload;
72
	key->datalen = prep->datalen;
73 74 75 76 77 78
	return 0;
}

static inline void
cifs_idmap_key_destroy(struct key *key)
{
79 80
	if (key->datalen > sizeof(void *))
		kfree(key->payload.data);
81 82
}

83
static struct key_type cifs_idmap_key_type = {
84
	.name        = "cifs.idmap",
85 86 87 88 89 90
	.instantiate = cifs_idmap_key_instantiate,
	.destroy     = cifs_idmap_key_destroy,
	.describe    = user_describe,
	.match       = user_match,
};

91 92
static char *
sid_to_key_str(struct cifs_sid *sidptr, unsigned int type)
93
{
94
	int i, len;
95
	unsigned int saval;
96
	char *sidstr, *strptr;
97

98 99 100 101 102 103
	/* 3 bytes for prefix */
	sidstr = kmalloc(3 + SID_STRING_BASE_SIZE +
			 (SID_STRING_SUBAUTH_SIZE * sidptr->num_subauth),
			 GFP_KERNEL);
	if (!sidstr)
		return sidstr;
104

105 106 107 108
	strptr = sidstr;
	len = sprintf(strptr, "%cs:S-%hhu", type == SIDOWNER ? 'o' : 'g',
			sidptr->revision);
	strptr += len;
109

110
	for (i = 0; i < NUM_AUTHS; ++i) {
111
		if (sidptr->authority[i]) {
112 113
			len = sprintf(strptr, "-%hhu", sidptr->authority[i]);
			strptr += len;
114 115 116 117 118
		}
	}

	for (i = 0; i < sidptr->num_subauth; ++i) {
		saval = le32_to_cpu(sidptr->sub_auth[i]);
119 120
		len = sprintf(strptr, "-%u", saval);
		strptr += len;
121
	}
122 123

	return sidstr;
124 125
}

J
Jeff Layton 已提交
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
/*
 * if the two SIDs (roughly equivalent to a UUID for a user or group) are
 * the same returns zero, if they do not match returns non-zero.
 */
static int
compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
{
	int i;
	int num_subauth, num_sat, num_saw;

	if ((!ctsid) || (!cwsid))
		return 1;

	/* compare the revision */
	if (ctsid->revision != cwsid->revision) {
		if (ctsid->revision > cwsid->revision)
			return 1;
		else
			return -1;
	}

	/* compare all of the six auth values */
	for (i = 0; i < NUM_AUTHS; ++i) {
		if (ctsid->authority[i] != cwsid->authority[i]) {
			if (ctsid->authority[i] > cwsid->authority[i])
				return 1;
			else
				return -1;
		}
	}

	/* compare all of the subauth values if any */
	num_sat = ctsid->num_subauth;
	num_saw = cwsid->num_subauth;
	num_subauth = num_sat < num_saw ? num_sat : num_saw;
	if (num_subauth) {
		for (i = 0; i < num_subauth; ++i) {
			if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) {
				if (le32_to_cpu(ctsid->sub_auth[i]) >
					le32_to_cpu(cwsid->sub_auth[i]))
					return 1;
				else
					return -1;
			}
		}
	}

	return 0; /* sids compare/match */
}

176 177 178
static void
cifs_copy_sid(struct cifs_sid *dst, const struct cifs_sid *src)
{
179 180 181
	int i;

	dst->revision = src->revision;
182
	dst->num_subauth = min_t(u8, src->num_subauth, SID_MAX_SUB_AUTHORITIES);
183 184 185 186
	for (i = 0; i < NUM_AUTHS; ++i)
		dst->authority[i] = src->authority[i];
	for (i = 0; i < dst->num_subauth; ++i)
		dst->sub_auth[i] = src->sub_auth[i];
187 188
}

189
static int
190
id_to_sid(unsigned int cid, uint sidtype, struct cifs_sid *ssid)
191
{
192
	int rc;
193
	struct key *sidkey;
194
	char desc[3 + 10 + 1]; /* 3 byte prefix + 10 bytes for value + NULL */
195 196
	const struct cred *saved_cred;

197 198 199 200
	rc = snprintf(desc, sizeof(desc), "%ci:%u",
			sidtype == SIDOWNER ? 'o' : 'g', cid);
	if (rc >= sizeof(desc))
		return -EINVAL;
201

202 203 204 205
	rc = 0;
	saved_cred = override_creds(root_cred);
	sidkey = request_key(&cifs_idmap_key_type, desc, "");
	if (IS_ERR(sidkey)) {
206
		rc = -EINVAL;
207 208 209 210 211 212 213 214
		cFYI(1, "%s: Can't map %cid %u to a SID", __func__,
			sidtype == SIDOWNER ? 'u' : 'g', cid);
		goto out_revert_creds;
	} else if (sidkey->datalen < CIFS_SID_BASE_SIZE) {
		rc = -EIO;
		cFYI(1, "%s: Downcall contained malformed key "
			"(datalen=%hu)", __func__, sidkey->datalen);
		goto out_key_put;
215
	}
216 217 218 219 220
	cifs_copy_sid(ssid, (struct cifs_sid *)sidkey->payload.data);
out_key_put:
	key_put(sidkey);
out_revert_creds:
	revert_creds(saved_cred);
221 222 223
	return rc;
}

224 225 226 227 228
static int
sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid,
		struct cifs_fattr *fattr, uint sidtype)
{
	int rc;
229 230
	struct key *sidkey;
	char *sidstr;
231
	const struct cred *saved_cred;
232 233
	uid_t fuid = cifs_sb->mnt_uid;
	gid_t fgid = cifs_sb->mnt_gid;
234 235

	/*
236 237
	 * If we have too many subauthorities, then something is really wrong.
	 * Just return an error.
238
	 */
239 240 241 242
	if (unlikely(psid->num_subauth > SID_MAX_SUB_AUTHORITIES)) {
		cFYI(1, "%s: %u subauthorities is too many!", __func__,
			psid->num_subauth);
		return -EIO;
243 244
	}

245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
	sidstr = sid_to_key_str(psid, sidtype);
	if (!sidstr)
		return -ENOMEM;

	saved_cred = override_creds(root_cred);
	sidkey = request_key(&cifs_idmap_key_type, sidstr, "");
	if (IS_ERR(sidkey)) {
		rc = -EINVAL;
		cFYI(1, "%s: Can't map SID %s to a %cid", __func__, sidstr,
			sidtype == SIDOWNER ? 'u' : 'g');
		goto out_revert_creds;
	}

	/*
	 * FIXME: Here we assume that uid_t and gid_t are same size. It's
	 * probably a safe assumption but might be better to check based on
	 * sidtype.
	 */
263
	if (sidkey->datalen != sizeof(uid_t)) {
264 265 266 267
		rc = -EIO;
		cFYI(1, "%s: Downcall contained malformed key "
			"(datalen=%hu)", __func__, sidkey->datalen);
		goto out_key_put;
268 269 270
	}

	if (sidtype == SIDOWNER)
271
		memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t));
272
	else
273
		memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t));
274 275 276 277 278 279

out_key_put:
	key_put(sidkey);
out_revert_creds:
	revert_creds(saved_cred);
	kfree(sidstr);
280

281 282 283 284 285 286 287 288
	/*
	 * Note that we return 0 here unconditionally. If the mapping
	 * fails then we just fall back to using the mnt_uid/mnt_gid.
	 */
	if (sidtype == SIDOWNER)
		fattr->cf_uid = fuid;
	else
		fattr->cf_gid = fgid;
289 290 291
	return 0;
}

292 293 294 295 296 297 298
int
init_cifs_idmap(void)
{
	struct cred *cred;
	struct key *keyring;
	int ret;

299
	cFYI(1, "Registering the %s key type", cifs_idmap_key_type.name);
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

	/* create an override credential set with a special thread keyring in
	 * which requests are cached
	 *
	 * this is used to prevent malicious redirections from being installed
	 * with add_key().
	 */
	cred = prepare_kernel_cred(NULL);
	if (!cred)
		return -ENOMEM;

	keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
			    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
			    KEY_USR_VIEW | KEY_USR_READ,
			    KEY_ALLOC_NOT_IN_QUOTA);
	if (IS_ERR(keyring)) {
		ret = PTR_ERR(keyring);
		goto failed_put_cred;
	}

	ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
	if (ret < 0)
		goto failed_put_key;

	ret = register_key_type(&cifs_idmap_key_type);
	if (ret < 0)
		goto failed_put_key;

	/* instruct request_key() to use this special keyring as a cache for
	 * the results it looks up */
330
	set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
331 332 333 334
	cred->thread_keyring = keyring;
	cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
	root_cred = cred;

335
	cFYI(1, "cifs idmap keyring: %d", key_serial(keyring));
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
	return 0;

failed_put_key:
	key_put(keyring);
failed_put_cred:
	put_cred(cred);
	return ret;
}

void
exit_cifs_idmap(void)
{
	key_revoke(root_cred->thread_keyring);
	unregister_key_type(&cifs_idmap_key_type);
	put_cred(root_cred);
351
	cFYI(1, "Unregistered %s key type", cifs_idmap_key_type.name);
352 353
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
/* copy ntsd, owner sid, and group sid from a security descriptor to another */
static void copy_sec_desc(const struct cifs_ntsd *pntsd,
				struct cifs_ntsd *pnntsd, __u32 sidsoffset)
{
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;

	/* copy security descriptor control portion */
	pnntsd->revision = pntsd->revision;
	pnntsd->type = pntsd->type;
	pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
	pnntsd->sacloffset = 0;
	pnntsd->osidoffset = cpu_to_le32(sidsoffset);
	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));

	/* copy owner sid */
	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->osidoffset));
	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
373
	cifs_copy_sid(nowner_sid_ptr, owner_sid_ptr);
374 375 376 377 378 379

	/* copy group sid */
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->gsidoffset));
	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
					sizeof(struct cifs_sid));
380
	cifs_copy_sid(ngroup_sid_ptr, group_sid_ptr);
381 382 383 384 385

	return;
}


S
Steve French 已提交
386 387 388 389 390
/*
   change posix mode to reflect permissions
   pmode is the existing mode (we only want to overwrite part of this
   bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
*/
A
Al Viro 已提交
391
static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
392
				 umode_t *pbits_to_set)
S
Steve French 已提交
393
{
A
Al Viro 已提交
394
	__u32 flags = le32_to_cpu(ace_flags);
395
	/* the order of ACEs is important.  The canonical order is to begin with
396
	   DENY entries followed by ALLOW, otherwise an allow entry could be
397
	   encountered first, making the subsequent deny entry like "dead code"
398
	   which would be superflous since Windows stops when a match is made
399 400 401 402 403
	   for the operation you are trying to perform for your user */

	/* For deny ACEs we change the mask so that subsequent allow access
	   control entries do not turn on the bits we are denying */
	if (type == ACCESS_DENIED) {
S
Steve French 已提交
404
		if (flags & GENERIC_ALL)
405
			*pbits_to_set &= ~S_IRWXUGO;
S
Steve French 已提交
406

A
Al Viro 已提交
407 408
		if ((flags & GENERIC_WRITE) ||
			((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
409
			*pbits_to_set &= ~S_IWUGO;
A
Al Viro 已提交
410 411
		if ((flags & GENERIC_READ) ||
			((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
412
			*pbits_to_set &= ~S_IRUGO;
A
Al Viro 已提交
413 414
		if ((flags & GENERIC_EXECUTE) ||
			((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
415 416 417
			*pbits_to_set &= ~S_IXUGO;
		return;
	} else if (type != ACCESS_ALLOWED) {
418
		cERROR(1, "unknown access control type %d", type);
419 420 421
		return;
	}
	/* else ACCESS_ALLOWED type */
S
Steve French 已提交
422

A
Al Viro 已提交
423
	if (flags & GENERIC_ALL) {
424
		*pmode |= (S_IRWXUGO & (*pbits_to_set));
425
		cFYI(DBG2, "all perms");
S
Steve French 已提交
426 427
		return;
	}
A
Al Viro 已提交
428 429
	if ((flags & GENERIC_WRITE) ||
			((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
430
		*pmode |= (S_IWUGO & (*pbits_to_set));
A
Al Viro 已提交
431 432
	if ((flags & GENERIC_READ) ||
			((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
433
		*pmode |= (S_IRUGO & (*pbits_to_set));
A
Al Viro 已提交
434 435
	if ((flags & GENERIC_EXECUTE) ||
			((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
436
		*pmode |= (S_IXUGO & (*pbits_to_set));
S
Steve French 已提交
437

438
	cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
S
Steve French 已提交
439 440 441
	return;
}

442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
/*
   Generate access flags to reflect permissions mode is the existing mode.
   This function is called for every ACE in the DACL whose SID matches
   with either owner or group or everyone.
*/

static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
				__u32 *pace_flags)
{
	/* reset access mask */
	*pace_flags = 0x0;

	/* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
	mode &= bits_to_use;

	/* check for R/W/X UGO since we do not know whose flags
	   is this but we have cleared all the bits sans RWX for
	   either user or group or other as per bits_to_use */
	if (mode & S_IRUGO)
		*pace_flags |= SET_FILE_READ_RIGHTS;
	if (mode & S_IWUGO)
		*pace_flags |= SET_FILE_WRITE_RIGHTS;
	if (mode & S_IXUGO)
		*pace_flags |= SET_FILE_EXEC_RIGHTS;

467
	cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
468 469 470
	return;
}

A
Al Viro 已提交
471
static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
			const struct cifs_sid *psid, __u64 nmode, umode_t bits)
{
	int i;
	__u16 size = 0;
	__u32 access_req = 0;

	pntace->type = ACCESS_ALLOWED;
	pntace->flags = 0x0;
	mode_to_access_flags(nmode, bits, &access_req);
	if (!access_req)
		access_req = SET_MINIMUM_RIGHTS;
	pntace->access_req = cpu_to_le32(access_req);

	pntace->sid.revision = psid->revision;
	pntace->sid.num_subauth = psid->num_subauth;
487
	for (i = 0; i < NUM_AUTHS; i++)
488 489 490 491 492 493 494
		pntace->sid.authority[i] = psid->authority[i];
	for (i = 0; i < psid->num_subauth; i++)
		pntace->sid.sub_auth[i] = psid->sub_auth[i];

	size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
	pntace->size = cpu_to_le16(size);

495
	return size;
496 497
}

S
Steve French 已提交
498

499 500
#ifdef CONFIG_CIFS_DEBUG2
static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
501 502 503 504
{
	int num_subauth;

	/* validate that we do not go past end of acl */
S
Steve French 已提交
505

S
Steve French 已提交
506
	if (le16_to_cpu(pace->size) < 16) {
507
		cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
S
Steve French 已提交
508 509 510 511
		return;
	}

	if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
512
		cERROR(1, "ACL too small to parse ACE");
513
		return;
S
Steve French 已提交
514
	}
515

S
Steve French 已提交
516
	num_subauth = pace->sid.num_subauth;
517
	if (num_subauth) {
518
		int i;
519
		cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
S
Steve French 已提交
520
			pace->sid.revision, pace->sid.num_subauth, pace->type,
521
			pace->flags, le16_to_cpu(pace->size));
S
Steve French 已提交
522
		for (i = 0; i < num_subauth; ++i) {
523 524
			cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
				le32_to_cpu(pace->sid.sub_auth[i]));
S
Steve French 已提交
525 526 527 528 529 530 531 532
		}

		/* BB add length check to make sure that we do not have huge
			num auths and therefore go off the end */
	}

	return;
}
533
#endif
S
Steve French 已提交
534

535

S
Steve French 已提交
536
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
S
Steve French 已提交
537
		       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
538
		       struct cifs_fattr *fattr)
539 540 541 542 543 544 545 546 547
{
	int i;
	int num_aces = 0;
	int acl_size;
	char *acl_base;
	struct cifs_ace **ppace;

	/* BB need to add parm so we can store the SID BB */

548 549 550
	if (!pdacl) {
		/* no DACL in the security descriptor, set
		   all the permissions for user/group/other */
551
		fattr->cf_mode |= S_IRWXUGO;
552 553 554
		return;
	}

555
	/* validate that we do not go past end of acl */
556
	if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
557
		cERROR(1, "ACL too small to parse DACL");
558 559 560
		return;
	}

561
	cFYI(DBG2, "DACL revision %d size %d num aces %d",
562
		le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
563
		le32_to_cpu(pdacl->num_aces));
564

565 566 567
	/* reset rwx permissions for user/group/other.
	   Also, if num_aces is 0 i.e. DACL has no ACEs,
	   user/group/other have no permissions */
568
	fattr->cf_mode &= ~(S_IRWXUGO);
569

570 571 572
	acl_base = (char *)pdacl;
	acl_size = sizeof(struct cifs_acl);

S
Steve French 已提交
573
	num_aces = le32_to_cpu(pdacl->num_aces);
574
	if (num_aces > 0) {
575 576
		umode_t user_mask = S_IRWXU;
		umode_t group_mask = S_IRWXG;
577
		umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
578

579 580
		if (num_aces > ULONG_MAX / sizeof(struct cifs_ace *))
			return;
581 582
		ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
				GFP_KERNEL);
583 584 585 586
		if (!ppace) {
			cERROR(1, "DACL memory allocation error");
			return;
		}
587 588

		for (i = 0; i < num_aces; ++i) {
S
Steve French 已提交
589
			ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
590 591 592
#ifdef CONFIG_CIFS_DEBUG2
			dump_ace(ppace[i], end_of_acl);
#endif
593
			if (compare_sids(&(ppace[i]->sid), pownersid) == 0)
594
				access_flags_to_mode(ppace[i]->access_req,
595
						     ppace[i]->type,
596
						     &fattr->cf_mode,
597
						     &user_mask);
598
			if (compare_sids(&(ppace[i]->sid), pgrpsid) == 0)
599
				access_flags_to_mode(ppace[i]->access_req,
600
						     ppace[i]->type,
601
						     &fattr->cf_mode,
602
						     &group_mask);
603
			if (compare_sids(&(ppace[i]->sid), &sid_everyone) == 0)
604
				access_flags_to_mode(ppace[i]->access_req,
605
						     ppace[i]->type,
606
						     &fattr->cf_mode,
607
						     &other_mask);
608
			if (compare_sids(&(ppace[i]->sid), &sid_authusers) == 0)
609 610 611 612 613
				access_flags_to_mode(ppace[i]->access_req,
						     ppace[i]->type,
						     &fattr->cf_mode,
						     &other_mask);

614

S
Steve French 已提交
615
/*			memcpy((void *)(&(cifscred->aces[i])),
S
Steve French 已提交
616 617
				(void *)ppace[i],
				sizeof(struct cifs_ace)); */
618

S
Steve French 已提交
619 620
			acl_base = (char *)ppace[i];
			acl_size = le16_to_cpu(ppace[i]->size);
621 622 623 624 625 626 627 628
		}

		kfree(ppace);
	}

	return;
}

629

630 631 632
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
			struct cifs_sid *pgrpsid, __u64 nmode)
{
A
Al Viro 已提交
633
	u16 size = 0;
634 635 636 637 638 639 640 641 642 643 644 645
	struct cifs_acl *pnndacl;

	pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));

	size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
					pownersid, nmode, S_IRWXU);
	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
					pgrpsid, nmode, S_IRWXG);
	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
					 &sid_everyone, nmode, S_IRWXO);

	pndacl->size = cpu_to_le16(size + sizeof(struct cifs_acl));
646
	pndacl->num_aces = cpu_to_le32(3);
647

648
	return 0;
649 650 651
}


652 653 654 655
static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
{
	/* BB need to add parm so we can store the SID BB */

S
Steve French 已提交
656 657 658
	/* validate that we do not go past end of ACL - sid must be at least 8
	   bytes long (assuming no sub-auths - e.g. the null SID */
	if (end_of_acl < (char *)psid + 8) {
659
		cERROR(1, "ACL too small to parse SID %p", psid);
660 661
		return -EINVAL;
	}
662

663
#ifdef CONFIG_CIFS_DEBUG2
664
	if (psid->num_subauth) {
665
		int i;
666 667
		cFYI(1, "SID revision %d num_auth %d",
			psid->revision, psid->num_subauth);
668

669
		for (i = 0; i < psid->num_subauth; i++) {
670 671
			cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
				le32_to_cpu(psid->sub_auth[i]));
672 673
		}

S
Steve French 已提交
674
		/* BB add length check to make sure that we do not have huge
675
			num auths and therefore go off the end */
676 677
		cFYI(1, "RID 0x%x",
			le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
678
	}
679
#endif
680

681 682 683
	return 0;
}

684

685
/* Convert CIFS ACL to POSIX form */
686 687
static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
		struct cifs_ntsd *pntsd, int acl_len, struct cifs_fattr *fattr)
688
{
689
	int rc = 0;
690 691 692
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
	char *end_of_acl = ((char *)pntsd) + acl_len;
693
	__u32 dacloffset;
694

695
	if (pntsd == NULL)
S
Steve French 已提交
696 697
		return -EIO;

698
	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
699
				le32_to_cpu(pntsd->osidoffset));
700
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
701
				le32_to_cpu(pntsd->gsidoffset));
702
	dacloffset = le32_to_cpu(pntsd->dacloffset);
703
	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
704
	cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
705
		 "sacloffset 0x%x dacloffset 0x%x",
706 707
		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
		 le32_to_cpu(pntsd->gsidoffset),
708
		 le32_to_cpu(pntsd->sacloffset), dacloffset);
S
Steve French 已提交
709
/*	cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
710
	rc = parse_sid(owner_sid_ptr, end_of_acl);
711 712 713 714 715 716 717
	if (rc) {
		cFYI(1, "%s: Error %d parsing Owner SID", __func__, rc);
		return rc;
	}
	rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
	if (rc) {
		cFYI(1, "%s: Error %d mapping Owner SID to uid", __func__, rc);
718
		return rc;
719
	}
720 721

	rc = parse_sid(group_sid_ptr, end_of_acl);
722 723
	if (rc) {
		cFYI(1, "%s: Error %d mapping Owner SID to gid", __func__, rc);
724
		return rc;
725 726 727 728 729 730
	}
	rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
	if (rc) {
		cFYI(1, "%s: Error %d mapping Group SID to gid", __func__, rc);
		return rc;
	}
731

732 733
	if (dacloffset)
		parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
734
			   group_sid_ptr, fattr);
735
	else
736
		cFYI(1, "no ACL"); /* BB grant all or default perms? */
737

738
	return rc;
739
}
S
Steve French 已提交
740

741 742
/* Convert permission bits from mode to equivalent CIFS ACL */
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
743
	__u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag)
744 745 746 747 748 749
{
	int rc = 0;
	__u32 dacloffset;
	__u32 ndacloffset;
	__u32 sidsoffset;
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
750
	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
751 752 753
	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */

754 755
	if (nmode != NO_CHANGE_64) { /* chmod */
		owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
756
				le32_to_cpu(pntsd->osidoffset));
757
		group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
758
				le32_to_cpu(pntsd->gsidoffset));
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
		dacloffset = le32_to_cpu(pntsd->dacloffset);
		dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
		ndacloffset = sizeof(struct cifs_ntsd);
		ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
		ndacl_ptr->revision = dacl_ptr->revision;
		ndacl_ptr->size = 0;
		ndacl_ptr->num_aces = 0;

		rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr,
					nmode);
		sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
		/* copy sec desc control portion & owner and group sids */
		copy_sec_desc(pntsd, pnntsd, sidsoffset);
		*aclflag = CIFS_ACL_DACL;
	} else {
		memcpy(pnntsd, pntsd, secdesclen);
		if (uid != NO_CHANGE_32) { /* chown */
			owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
					le32_to_cpu(pnntsd->osidoffset));
			nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid),
								GFP_KERNEL);
			if (!nowner_sid_ptr)
				return -ENOMEM;
			rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr);
			if (rc) {
				cFYI(1, "%s: Mapping error %d for owner id %d",
						__func__, rc, uid);
				kfree(nowner_sid_ptr);
				return rc;
			}
789
			cifs_copy_sid(owner_sid_ptr, nowner_sid_ptr);
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
			kfree(nowner_sid_ptr);
			*aclflag = CIFS_ACL_OWNER;
		}
		if (gid != NO_CHANGE_32) { /* chgrp */
			group_sid_ptr = (struct cifs_sid *)((char *)pnntsd +
					le32_to_cpu(pnntsd->gsidoffset));
			ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid),
								GFP_KERNEL);
			if (!ngroup_sid_ptr)
				return -ENOMEM;
			rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr);
			if (rc) {
				cFYI(1, "%s: Mapping error %d for group id %d",
						__func__, rc, gid);
				kfree(ngroup_sid_ptr);
				return rc;
			}
807
			cifs_copy_sid(group_sid_ptr, ngroup_sid_ptr);
808 809 810 811
			kfree(ngroup_sid_ptr);
			*aclflag = CIFS_ACL_GROUP;
		}
	}
812

813
	return rc;
814 815
}

816 817
static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
		__u16 fid, u32 *pacllen)
S
Steve French 已提交
818 819
{
	struct cifs_ntsd *pntsd = NULL;
820 821
	unsigned int xid;
	int rc;
822 823 824
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
825
		return ERR_CAST(tlink);
S
Steve French 已提交
826

827
	xid = get_xid();
828
	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
829
	free_xid(xid);
S
Steve French 已提交
830

831
	cifs_put_tlink(tlink);
S
Steve French 已提交
832

833 834 835
	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
836 837
	return pntsd;
}
838

839 840 841 842 843
static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
		const char *path, u32 *pacllen)
{
	struct cifs_ntsd *pntsd = NULL;
	int oplock = 0;
844 845
	unsigned int xid;
	int rc, create_options = 0;
846
	__u16 fid;
847
	struct cifs_tcon *tcon;
848 849 850
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
851
		return ERR_CAST(tlink);
S
Steve French 已提交
852

853
	tcon = tlink_tcon(tlink);
854
	xid = get_xid();
855

856 857 858 859 860 861
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL,
			create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
862 863 864
	if (!rc) {
		rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
		CIFSSMBClose(xid, tcon, fid);
S
Steve French 已提交
865 866
	}

867
	cifs_put_tlink(tlink);
868
	free_xid(xid);
869 870 871 872

	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
873 874 875
	return pntsd;
}

876
/* Retrieve an ACL from the server */
877
struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
878 879 880 881 882 883 884
				      struct inode *inode, const char *path,
				      u32 *pacllen)
{
	struct cifs_ntsd *pntsd = NULL;
	struct cifsFileInfo *open_file = NULL;

	if (inode)
885
		open_file = find_readable_file(CIFS_I(inode), true);
886 887 888
	if (!open_file)
		return get_cifs_acl_by_path(cifs_sb, path, pacllen);

889
	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
890
	cifsFileInfo_put(open_file);
891 892 893
	return pntsd;
}

894 895 896
 /* Set an ACL on the server */
int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
			struct inode *inode, const char *path, int aclflag)
897 898
{
	int oplock = 0;
899 900
	unsigned int xid;
	int rc, access_flags, create_options = 0;
901
	__u16 fid;
902
	struct cifs_tcon *tcon;
903
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
904
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
905

906 907 908 909
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);

	tcon = tlink_tcon(tlink);
910
	xid = get_xid();
911

912 913 914
	if (backup_cred(cifs_sb))
		create_options |= CREATE_OPEN_BACKUP_INTENT;

915 916 917 918 919 920 921 922
	if (aclflag == CIFS_ACL_OWNER || aclflag == CIFS_ACL_GROUP)
		access_flags = WRITE_OWNER;
	else
		access_flags = WRITE_DAC;

	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, access_flags,
			create_options, &fid, &oplock, NULL, cifs_sb->local_nls,
			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
923
	if (rc) {
924
		cERROR(1, "Unable to open file to set ACL");
925
		goto out;
926 927
	}

928
	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen, aclflag);
929
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
930

931 932
	CIFSSMBClose(xid, tcon, fid);
out:
933
	free_xid(xid);
934
	cifs_put_tlink(tlink);
935 936
	return rc;
}
937

938
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
939
int
940 941
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
		  struct inode *inode, const char *path, const __u16 *pfid)
942 943 944 945 946
{
	struct cifs_ntsd *pntsd = NULL;
	u32 acllen = 0;
	int rc = 0;

947
	cFYI(DBG2, "converting ACL to mode for %s", path);
948 949 950 951 952

	if (pfid)
		pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
	else
		pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
953 954

	/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
955 956 957 958
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
		cERROR(1, "%s: error %d getting sec desc", __func__, rc);
	} else {
959
		rc = parse_sec_desc(cifs_sb, pntsd, acllen, fattr);
960 961 962 963
		kfree(pntsd);
		if (rc)
			cERROR(1, "parse sec desc failed rc = %d", rc);
	}
964

965
	return rc;
S
Steve French 已提交
966
}
967

968
/* Convert mode bits to an ACL so we can update the ACL on the server */
969 970 971
int
id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode,
			uid_t uid, gid_t gid)
972 973
{
	int rc = 0;
974
	int aclflag = CIFS_ACL_DACL; /* default flag to set */
975
	__u32 secdesclen = 0;
976 977
	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
978

979
	cFYI(DBG2, "set ACL from mode for %s", path);
980 981

	/* Get the security descriptor */
982
	pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
983 984 985
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
		cERROR(1, "%s: error %d getting sec desc", __func__, rc);
J
Jeff Layton 已提交
986 987
		goto out;
	}
988

J
Jeff Layton 已提交
989 990 991 992 993 994 995 996 997 998 999 1000 1001
	/*
	 * Add three ACEs for owner, group, everyone getting rid of other ACEs
	 * as chmod disables ACEs and set the security descriptor. Allocate
	 * memory for the smb header, set security descriptor request security
	 * descriptor parameters, and secuirty descriptor itself
	 */
	secdesclen = max_t(u32, secdesclen, DEFSECDESCLEN);
	pnntsd = kmalloc(secdesclen, GFP_KERNEL);
	if (!pnntsd) {
		cERROR(1, "Unable to allocate security descriptor");
		kfree(pntsd);
		return -ENOMEM;
	}
1002

J
Jeff Layton 已提交
1003 1004
	rc = build_sec_desc(pntsd, pnntsd, secdesclen, nmode, uid, gid,
				&aclflag);
1005

J
Jeff Layton 已提交
1006
	cFYI(DBG2, "build_sec_desc rc: %d", rc);
1007

J
Jeff Layton 已提交
1008 1009 1010 1011
	if (!rc) {
		/* Set the security descriptor */
		rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
		cFYI(DBG2, "set_cifs_acl rc: %d", rc);
1012 1013
	}

J
Jeff Layton 已提交
1014 1015 1016
	kfree(pnntsd);
	kfree(pntsd);
out:
1017
	return rc;
1018
}