cifsacl.c 21.9 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
#include "cifspdu.h"
#include "cifsglob.h"
28
#include "cifsacl.h"
29 30 31
#include "cifsproto.h"
#include "cifs_debug.h"

S
Steve French 已提交
32

33
static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
S
Steve French 已提交
34 35
	{{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
	{{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
36 37 38 39 40
	{{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
	{{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
	{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
	{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
	{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
S
Steve French 已提交
41
;
S
Steve French 已提交
42 43


44
/* security id for everyone/world system group */
45 46
static const struct cifs_sid sid_everyone = {
	1, 1, {0, 0, 0, 0, 0, 1}, {0} };
47 48 49
/* security id for Authenticated Users system group */
static const struct cifs_sid sid_authusers = {
	1, 1, {0, 0, 0, 0, 0, 5}, {11} };
50
/* group users */
S
Steve French 已提交
51
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
52

S
Steve French 已提交
53 54 55 56 57 58 59 60

int match_sid(struct cifs_sid *ctsid)
{
	int i, j;
	int num_subauth, num_sat, num_saw;
	struct cifs_sid *cwsid;

	if (!ctsid)
61
		return -1;
S
Steve French 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78

	for (i = 0; i < NUM_WK_SIDS; ++i) {
		cwsid = &(wksidarr[i].cifssid);

		/* compare the revision */
		if (ctsid->revision != cwsid->revision)
			continue;

		/* compare all of the six auth values */
		for (j = 0; j < 6; ++j) {
			if (ctsid->authority[j] != cwsid->authority[j])
				break;
		}
		if (j < 6)
			continue; /* all of the auth values did not match */

		/* compare all of the subauth values if any */
79 80
		num_sat = ctsid->num_subauth;
		num_saw = cwsid->num_subauth;
S
Steve French 已提交
81 82 83 84 85 86 87 88 89 90
		num_subauth = num_sat < num_saw ? num_sat : num_saw;
		if (num_subauth) {
			for (j = 0; j < num_subauth; ++j) {
				if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
					break;
			}
			if (j < num_subauth)
				continue; /* all sub_auth values do not match */
		}

91
		cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
92
		return 0; /* sids compare/match */
S
Steve French 已提交
93 94
	}

95
	cFYI(1, "No matching sid");
96
	return -1;
S
Steve French 已提交
97 98
}

S
Steve French 已提交
99 100
/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
   the same returns 1, if they do not match returns 0 */
S
Steve French 已提交
101
int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
S
Steve French 已提交
102 103 104 105 106
{
	int i;
	int num_subauth, num_sat, num_saw;

	if ((!ctsid) || (!cwsid))
107
		return 0;
S
Steve French 已提交
108 109 110

	/* compare the revision */
	if (ctsid->revision != cwsid->revision)
111
		return 0;
S
Steve French 已提交
112 113 114 115

	/* compare all of the six auth values */
	for (i = 0; i < 6; ++i) {
		if (ctsid->authority[i] != cwsid->authority[i])
116
			return 0;
S
Steve French 已提交
117 118 119
	}

	/* compare all of the subauth values if any */
S
Steve French 已提交
120
	num_sat = ctsid->num_subauth;
S
Steve French 已提交
121
	num_saw = cwsid->num_subauth;
S
Steve French 已提交
122 123 124 125
	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])
126
				return 0;
S
Steve French 已提交
127 128 129
		}
	}

130
	return 1; /* sids compare/match */
S
Steve French 已提交
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

/* 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)
{
	int i;

	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);

	nowner_sid_ptr->revision = owner_sid_ptr->revision;
	nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
	for (i = 0; i < 6; i++)
		nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
	for (i = 0; i < 5; i++)
		nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];

	/* 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));

	ngroup_sid_ptr->revision = group_sid_ptr->revision;
	ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
	for (i = 0; i < 6; i++)
		ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
	for (i = 0; i < 5; i++)
174
		ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
175 176 177 178 179

	return;
}


S
Steve French 已提交
180 181 182 183 184
/*
   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 已提交
185
static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
186
				 umode_t *pbits_to_set)
S
Steve French 已提交
187
{
A
Al Viro 已提交
188
	__u32 flags = le32_to_cpu(ace_flags);
189
	/* the order of ACEs is important.  The canonical order is to begin with
190
	   DENY entries followed by ALLOW, otherwise an allow entry could be
191
	   encountered first, making the subsequent deny entry like "dead code"
192
	   which would be superflous since Windows stops when a match is made
193 194 195 196 197
	   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 已提交
198
		if (flags & GENERIC_ALL)
199
			*pbits_to_set &= ~S_IRWXUGO;
S
Steve French 已提交
200

A
Al Viro 已提交
201 202
		if ((flags & GENERIC_WRITE) ||
			((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
203
			*pbits_to_set &= ~S_IWUGO;
A
Al Viro 已提交
204 205
		if ((flags & GENERIC_READ) ||
			((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
206
			*pbits_to_set &= ~S_IRUGO;
A
Al Viro 已提交
207 208
		if ((flags & GENERIC_EXECUTE) ||
			((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
209 210 211
			*pbits_to_set &= ~S_IXUGO;
		return;
	} else if (type != ACCESS_ALLOWED) {
212
		cERROR(1, "unknown access control type %d", type);
213 214 215
		return;
	}
	/* else ACCESS_ALLOWED type */
S
Steve French 已提交
216

A
Al Viro 已提交
217
	if (flags & GENERIC_ALL) {
218
		*pmode |= (S_IRWXUGO & (*pbits_to_set));
219
		cFYI(DBG2, "all perms");
S
Steve French 已提交
220 221
		return;
	}
A
Al Viro 已提交
222 223
	if ((flags & GENERIC_WRITE) ||
			((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
224
		*pmode |= (S_IWUGO & (*pbits_to_set));
A
Al Viro 已提交
225 226
	if ((flags & GENERIC_READ) ||
			((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
227
		*pmode |= (S_IRUGO & (*pbits_to_set));
A
Al Viro 已提交
228 229
	if ((flags & GENERIC_EXECUTE) ||
			((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
230
		*pmode |= (S_IXUGO & (*pbits_to_set));
S
Steve French 已提交
231

232
	cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
S
Steve French 已提交
233 234 235
	return;
}

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
/*
   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;

261
	cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
262 263 264
	return;
}

A
Al Viro 已提交
265
static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
			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;
	for (i = 0; i < 6; i++)
		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);

289
	return size;
290 291
}

S
Steve French 已提交
292

293 294
#ifdef CONFIG_CIFS_DEBUG2
static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
295 296 297 298
{
	int num_subauth;

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

S
Steve French 已提交
300
	if (le16_to_cpu(pace->size) < 16) {
301
		cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
S
Steve French 已提交
302 303 304 305
		return;
	}

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

S
Steve French 已提交
310
	num_subauth = pace->sid.num_subauth;
311
	if (num_subauth) {
312
		int i;
313
		cFYI(1, "ACE revision %d num_auth %d type %d flags %d size %d",
S
Steve French 已提交
314
			pace->sid.revision, pace->sid.num_subauth, pace->type,
315
			pace->flags, le16_to_cpu(pace->size));
S
Steve French 已提交
316
		for (i = 0; i < num_subauth; ++i) {
317 318
			cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
				le32_to_cpu(pace->sid.sub_auth[i]));
S
Steve French 已提交
319 320 321 322 323 324 325 326
		}

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

	return;
}
327
#endif
S
Steve French 已提交
328

329

S
Steve French 已提交
330
static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
S
Steve French 已提交
331
		       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
332
		       struct cifs_fattr *fattr)
333 334 335 336 337 338 339 340 341
{
	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 */

342 343 344
	if (!pdacl) {
		/* no DACL in the security descriptor, set
		   all the permissions for user/group/other */
345
		fattr->cf_mode |= S_IRWXUGO;
346 347 348
		return;
	}

349
	/* validate that we do not go past end of acl */
350
	if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) {
351
		cERROR(1, "ACL too small to parse DACL");
352 353 354
		return;
	}

355
	cFYI(DBG2, "DACL revision %d size %d num aces %d",
356
		le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size),
357
		le32_to_cpu(pdacl->num_aces));
358

359 360 361
	/* 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 */
362
	fattr->cf_mode &= ~(S_IRWXUGO);
363

364 365 366
	acl_base = (char *)pdacl;
	acl_size = sizeof(struct cifs_acl);

S
Steve French 已提交
367
	num_aces = le32_to_cpu(pdacl->num_aces);
368
	if (num_aces  > 0) {
369 370
		umode_t user_mask = S_IRWXU;
		umode_t group_mask = S_IRWXG;
371
		umode_t other_mask = S_IRWXU | S_IRWXG | S_IRWXO;
372

373 374
		ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
				GFP_KERNEL);
375 376 377 378
		if (!ppace) {
			cERROR(1, "DACL memory allocation error");
			return;
		}
379 380

		for (i = 0; i < num_aces; ++i) {
S
Steve French 已提交
381
			ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
382 383 384
#ifdef CONFIG_CIFS_DEBUG2
			dump_ace(ppace[i], end_of_acl);
#endif
385 386
			if (compare_sids(&(ppace[i]->sid), pownersid))
				access_flags_to_mode(ppace[i]->access_req,
387
						     ppace[i]->type,
388
						     &fattr->cf_mode,
389
						     &user_mask);
390 391
			if (compare_sids(&(ppace[i]->sid), pgrpsid))
				access_flags_to_mode(ppace[i]->access_req,
392
						     ppace[i]->type,
393
						     &fattr->cf_mode,
394
						     &group_mask);
395 396
			if (compare_sids(&(ppace[i]->sid), &sid_everyone))
				access_flags_to_mode(ppace[i]->access_req,
397
						     ppace[i]->type,
398
						     &fattr->cf_mode,
399
						     &other_mask);
400 401 402 403 404 405
			if (compare_sids(&(ppace[i]->sid), &sid_authusers))
				access_flags_to_mode(ppace[i]->access_req,
						     ppace[i]->type,
						     &fattr->cf_mode,
						     &other_mask);

406

S
Steve French 已提交
407
/*			memcpy((void *)(&(cifscred->aces[i])),
S
Steve French 已提交
408 409
				(void *)ppace[i],
				sizeof(struct cifs_ace)); */
410

S
Steve French 已提交
411 412
			acl_base = (char *)ppace[i];
			acl_size = le16_to_cpu(ppace[i]->size);
413 414 415 416 417 418 419 420
		}

		kfree(ppace);
	}

	return;
}

421

422 423 424
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
			struct cifs_sid *pgrpsid, __u64 nmode)
{
A
Al Viro 已提交
425
	u16 size = 0;
426 427 428 429 430 431 432 433 434 435 436 437
	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));
438
	pndacl->num_aces = cpu_to_le32(3);
439

440
	return 0;
441 442 443
}


444 445 446 447
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 已提交
448 449 450
	/* 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) {
451
		cERROR(1, "ACL too small to parse SID %p", psid);
452 453
		return -EINVAL;
	}
454

455
	if (psid->num_subauth) {
456
#ifdef CONFIG_CIFS_DEBUG2
457
		int i;
458 459
		cFYI(1, "SID revision %d num_auth %d",
			psid->revision, psid->num_subauth);
460

461
		for (i = 0; i < psid->num_subauth; i++) {
462 463
			cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
				le32_to_cpu(psid->sub_auth[i]));
464 465
		}

S
Steve French 已提交
466
		/* BB add length check to make sure that we do not have huge
467
			num auths and therefore go off the end */
468 469
		cFYI(1, "RID 0x%x",
			le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
470
#endif
471 472
	}

473 474 475
	return 0;
}

476

477
/* Convert CIFS ACL to POSIX form */
S
Steve French 已提交
478
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
479
			  struct cifs_fattr *fattr)
480
{
481
	int rc;
482 483 484
	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;
485
	__u32 dacloffset;
486

487
	if (pntsd == NULL)
S
Steve French 已提交
488 489
		return -EIO;

490
	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
491
				le32_to_cpu(pntsd->osidoffset));
492
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
493
				le32_to_cpu(pntsd->gsidoffset));
494
	dacloffset = le32_to_cpu(pntsd->dacloffset);
495
	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
496
	cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
497
		 "sacloffset 0x%x dacloffset 0x%x",
498 499
		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
		 le32_to_cpu(pntsd->gsidoffset),
500
		 le32_to_cpu(pntsd->sacloffset), dacloffset);
S
Steve French 已提交
501
/*	cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
502 503 504 505 506 507 508 509
	rc = parse_sid(owner_sid_ptr, end_of_acl);
	if (rc)
		return rc;

	rc = parse_sid(group_sid_ptr, end_of_acl);
	if (rc)
		return rc;

510 511
	if (dacloffset)
		parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
512
			   group_sid_ptr, fattr);
513
	else
514
		cFYI(1, "no ACL"); /* BB grant all or default perms? */
515

516 517 518
/*	cifscred->uid = owner_sid_ptr->rid;
	cifscred->gid = group_sid_ptr->rid;
	memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
S
Steve French 已提交
519
			sizeof(struct cifs_sid));
520
	memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
S
Steve French 已提交
521
			sizeof(struct cifs_sid)); */
522

523
	return 0;
524
}
S
Steve French 已提交
525 526


527 528
/* Convert permission bits from mode to equivalent CIFS ACL */
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
529
				struct inode *inode, __u64 nmode)
530 531 532 533 534 535 536 537 538 539
{
	int rc = 0;
	__u32 dacloffset;
	__u32 ndacloffset;
	__u32 sidsoffset;
	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */

	if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
540
		return -EIO;
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562

	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->osidoffset));
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
				le32_to_cpu(pntsd->gsidoffset));

	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 security descriptor control portion and owner and group sid */
	copy_sec_desc(pntsd, pnntsd, sidsoffset);

563
	return rc;
564 565
}

566 567
static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
		__u16 fid, u32 *pacllen)
S
Steve French 已提交
568 569
{
	struct cifs_ntsd *pntsd = NULL;
570
	int xid, rc;
571 572 573
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
574
		return ERR_CAST(tlink);
S
Steve French 已提交
575

576
	xid = GetXid();
577
	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
578
	FreeXid(xid);
S
Steve French 已提交
579

580
	cifs_put_tlink(tlink);
S
Steve French 已提交
581

582 583 584
	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
585 586
	return pntsd;
}
587

588 589 590 591 592 593 594
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;
	int xid, rc;
	__u16 fid;
595 596 597 598
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
599
		return ERR_CAST(tlink);
S
Steve French 已提交
600

601
	tcon = tlink_tcon(tlink);
602 603
	xid = GetXid();

604
	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
605 606
			 &fid, &oplock, NULL, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
607 608 609
	if (!rc) {
		rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
		CIFSSMBClose(xid, tcon, fid);
S
Steve French 已提交
610 611
	}

612
	cifs_put_tlink(tlink);
613
	FreeXid(xid);
614 615 616 617

	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
618 619 620
	return pntsd;
}

621
/* Retrieve an ACL from the server */
622
struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
623 624 625 626 627 628 629
				      struct inode *inode, const char *path,
				      u32 *pacllen)
{
	struct cifs_ntsd *pntsd = NULL;
	struct cifsFileInfo *open_file = NULL;

	if (inode)
630
		open_file = find_readable_file(CIFS_I(inode), true);
631 632 633 634
	if (!open_file)
		return get_cifs_acl_by_path(cifs_sb, path, pacllen);

	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
635
	cifsFileInfo_put(open_file);
636 637 638
	return pntsd;
}

639 640
static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
		struct cifs_ntsd *pnntsd, u32 acllen)
641
{
642
	int xid, rc;
643 644 645 646
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
647

648
	xid = GetXid();
649
	rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
650
	FreeXid(xid);
651
	cifs_put_tlink(tlink);
652

653
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
654 655
	return rc;
}
656

657 658 659 660 661 662
static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
		struct cifs_ntsd *pnntsd, u32 acllen)
{
	int oplock = 0;
	int xid, rc;
	__u16 fid;
663 664
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
665

666 667 668 669
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);

	tcon = tlink_tcon(tlink);
670 671
	xid = GetXid();

672
	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
673 674 675
			 &fid, &oplock, NULL, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc) {
676
		cERROR(1, "Unable to open file to set ACL");
677
		goto out;
678 679
	}

680
	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
681
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
682

683 684
	CIFSSMBClose(xid, tcon, fid);
out:
685
	FreeXid(xid);
686
	cifs_put_tlink(tlink);
687 688
	return rc;
}
689

690
/* Set an ACL on the server */
691
int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
692 693 694 695 696 697
				struct inode *inode, const char *path)
{
	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
	struct cifsFileInfo *open_file;
	int rc;

698
	cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
699

700
	open_file = find_readable_file(CIFS_I(inode), true);
701 702 703 704
	if (!open_file)
		return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);

	rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
705
	cifsFileInfo_put(open_file);
706
	return rc;
707 708
}

709
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
710
int
711 712
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
		  struct inode *inode, const char *path, const __u16 *pfid)
713 714 715 716 717
{
	struct cifs_ntsd *pntsd = NULL;
	u32 acllen = 0;
	int rc = 0;

718
	cFYI(DBG2, "converting ACL to mode for %s", path);
719 720 721 722 723

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

	/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
726 727 728 729
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
		cERROR(1, "%s: error %d getting sec desc", __func__, rc);
	} else {
730
		rc = parse_sec_desc(pntsd, acllen, fattr);
731 732 733 734
		kfree(pntsd);
		if (rc)
			cERROR(1, "parse sec desc failed rc = %d", rc);
	}
735

736
	return rc;
S
Steve French 已提交
737
}
738

739
/* Convert mode bits to an ACL so we can update the ACL on the server */
740
int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode)
741 742
{
	int rc = 0;
743
	__u32 secdesclen = 0;
744 745
	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
746

747
	cFYI(DBG2, "set ACL from mode for %s", path);
748 749

	/* Get the security descriptor */
750
	pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
751

752 753
	/* Add three ACEs for owner, group, everyone getting rid of
	   other ACEs as chmod disables ACEs and set the security descriptor */
754

755 756 757 758
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
		cERROR(1, "%s: error %d getting sec desc", __func__, rc);
	} else {
759 760 761
		/* allocate memory for the smb header,
		   set security descriptor request security descriptor
		   parameters, and secuirty descriptor itself */
762

763 764 765
		secdesclen = secdesclen < DEFSECDESCLEN ?
					DEFSECDESCLEN : secdesclen;
		pnntsd = kmalloc(secdesclen, GFP_KERNEL);
766
		if (!pnntsd) {
767
			cERROR(1, "Unable to allocate security descriptor");
768
			kfree(pntsd);
769
			return -ENOMEM;
770
		}
771

772
		rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
773

774
		cFYI(DBG2, "build_sec_desc rc: %d", rc);
775 776 777

		if (!rc) {
			/* Set the security descriptor */
778
			rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
779
			cFYI(DBG2, "set_cifs_acl rc: %d", rc);
780 781 782 783 784 785
		}

		kfree(pnntsd);
		kfree(pntsd);
	}

786
	return rc;
787
}