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 375 376
		ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
				GFP_KERNEL);

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

402

S
Steve French 已提交
403
/*			memcpy((void *)(&(cifscred->aces[i])),
S
Steve French 已提交
404 405
				(void *)ppace[i],
				sizeof(struct cifs_ace)); */
406

S
Steve French 已提交
407 408
			acl_base = (char *)ppace[i];
			acl_size = le16_to_cpu(ppace[i]->size);
409 410 411 412 413 414 415 416
		}

		kfree(ppace);
	}

	return;
}

417

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

436
	return 0;
437 438 439
}


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

451
	if (psid->num_subauth) {
452
#ifdef CONFIG_CIFS_DEBUG2
453
		int i;
454 455
		cFYI(1, "SID revision %d num_auth %d",
			psid->revision, psid->num_subauth);
456

457
		for (i = 0; i < psid->num_subauth; i++) {
458 459
			cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
				le32_to_cpu(psid->sub_auth[i]));
460 461
		}

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

469 470 471
	return 0;
}

472

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

483
	if (pntsd == NULL)
S
Steve French 已提交
484 485
		return -EIO;

486
	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
487
				le32_to_cpu(pntsd->osidoffset));
488
	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
489
				le32_to_cpu(pntsd->gsidoffset));
490
	dacloffset = le32_to_cpu(pntsd->dacloffset);
491
	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
492
	cFYI(DBG2, "revision %d type 0x%x ooffset 0x%x goffset 0x%x "
493
		 "sacloffset 0x%x dacloffset 0x%x",
494 495
		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
		 le32_to_cpu(pntsd->gsidoffset),
496
		 le32_to_cpu(pntsd->sacloffset), dacloffset);
S
Steve French 已提交
497
/*	cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
498 499 500 501 502 503 504 505
	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;

506 507
	if (dacloffset)
		parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
508
			   group_sid_ptr, fattr);
509
	else
510
		cFYI(1, "no ACL"); /* BB grant all or default perms? */
511

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

519
	return 0;
520
}
S
Steve French 已提交
521 522


523 524
/* Convert permission bits from mode to equivalent CIFS ACL */
static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
525
				struct inode *inode, __u64 nmode)
526 527 528 529 530 531 532 533 534 535
{
	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))
536
		return -EIO;
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

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

559
	return rc;
560 561
}

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

	if (IS_ERR(tlink))
570
		return ERR_CAST(tlink);
S
Steve French 已提交
571

572
	xid = GetXid();
573
	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
574
	FreeXid(xid);
S
Steve French 已提交
575

576
	cifs_put_tlink(tlink);
S
Steve French 已提交
577

578 579 580
	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
581 582
	return pntsd;
}
583

584 585 586 587 588 589 590
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;
591 592 593 594
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
595
		return ERR_CAST(tlink);
S
Steve French 已提交
596

597
	tcon = tlink_tcon(tlink);
598 599
	xid = GetXid();

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

608
	cifs_put_tlink(tlink);
609
	FreeXid(xid);
610 611 612 613

	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
614 615 616
	return pntsd;
}

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

	if (inode)
626
		open_file = find_readable_file(CIFS_I(inode), true);
627 628 629 630
	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);
631
	cifsFileInfo_put(open_file);
632 633 634
	return pntsd;
}

635 636
static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
		struct cifs_ntsd *pnntsd, u32 acllen)
637
{
638
	int xid, rc;
639 640 641 642
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

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

644
	xid = GetXid();
645
	rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
646
	FreeXid(xid);
647
	cifs_put_tlink(tlink);
648

649
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
650 651
	return rc;
}
652

653 654 655 656 657 658
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;
659 660
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
661

662 663 664 665
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);

	tcon = tlink_tcon(tlink);
666 667
	xid = GetXid();

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

676
	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
677
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
678

679 680
	CIFSSMBClose(xid, tcon, fid);
out:
681
	FreeXid(xid);
682
	cifs_put_tlink(tlink);
683 684
	return rc;
}
685

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

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

696
	open_file = find_readable_file(CIFS_I(inode), true);
697 698 699 700
	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);
701
	cifsFileInfo_put(open_file);
702
	return rc;
703 704
}

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

714
	cFYI(DBG2, "converting ACL to mode for %s", path);
715 716 717 718 719

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

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

732
	return rc;
S
Steve French 已提交
733
}
734

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

743
	cFYI(DBG2, "set ACL from mode for %s", path);
744 745

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

748 749
	/* Add three ACEs for owner, group, everyone getting rid of
	   other ACEs as chmod disables ACEs and set the security descriptor */
750

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

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

768
		rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
769

770
		cFYI(DBG2, "build_sec_desc rc: %d", rc);
771 772 773

		if (!rc) {
			/* Set the security descriptor */
774
			rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
775
			cFYI(DBG2, "set_cifs_acl rc: %d", rc);
776 777 778 779 780 781
		}

		kfree(pnntsd);
		kfree(pntsd);
	}

782
	return rc;
783
}