cifsacl.c 21.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
#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 34

#ifdef CONFIG_CIFS_EXPERIMENTAL

35
static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
S
Steve French 已提交
36 37
	{{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"},
38 39 40 41 42
	{{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 已提交
43
;
S
Steve French 已提交
44 45


46
/* security id for everyone */
47 48
static const struct cifs_sid sid_everyone = {
	1, 1, {0, 0, 0, 0, 0, 1}, {0} };
49
/* group users */
S
Steve French 已提交
50
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
51

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

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

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

	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 */
78 79
		num_sat = ctsid->num_subauth;
		num_saw = cwsid->num_subauth;
S
Steve French 已提交
80 81 82 83 84 85 86 87 88 89
		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 */
		}

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

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

S
Steve French 已提交
98 99
/* 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 已提交
100
int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
S
Steve French 已提交
101 102 103 104 105
{
	int i;
	int num_subauth, num_sat, num_saw;

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

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

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

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

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

/* 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++)
173
		ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
174 175 176 177 178

	return;
}


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

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

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

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

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

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

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

288
	return size;
289 290
}

S
Steve French 已提交
291

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

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

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

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

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

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

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

328

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

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

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

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

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

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

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

372 373 374 375
		ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
				GFP_KERNEL);

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

S
Steve French 已提交
396
/*			memcpy((void *)(&(cifscred->aces[i])),
S
Steve French 已提交
397 398
				(void *)ppace[i],
				sizeof(struct cifs_ace)); */
399

S
Steve French 已提交
400 401
			acl_base = (char *)ppace[i];
			acl_size = le16_to_cpu(ppace[i]->size);
402 403 404 405 406 407 408 409
		}

		kfree(ppace);
	}

	return;
}

410

411 412 413
static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
			struct cifs_sid *pgrpsid, __u64 nmode)
{
A
Al Viro 已提交
414
	u16 size = 0;
415 416 417 418 419 420 421 422 423 424 425 426
	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));
427
	pndacl->num_aces = cpu_to_le32(3);
428

429
	return 0;
430 431 432
}


433 434 435 436
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 已提交
437 438 439
	/* 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) {
440
		cERROR(1, "ACL too small to parse SID %p", psid);
441 442
		return -EINVAL;
	}
443

444
	if (psid->num_subauth) {
445
#ifdef CONFIG_CIFS_DEBUG2
446
		int i;
447 448
		cFYI(1, "SID revision %d num_auth %d",
			psid->revision, psid->num_subauth);
449

450
		for (i = 0; i < psid->num_subauth; i++) {
451 452
			cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
				le32_to_cpu(psid->sub_auth[i]));
453 454
		}

S
Steve French 已提交
455
		/* BB add length check to make sure that we do not have huge
456
			num auths and therefore go off the end */
457 458
		cFYI(1, "RID 0x%x",
			le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
459
#endif
460 461
	}

462 463 464
	return 0;
}

465

466
/* Convert CIFS ACL to POSIX form */
S
Steve French 已提交
467
static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
468
			  struct cifs_fattr *fattr)
469
{
470
	int rc;
471 472 473
	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;
474
	__u32 dacloffset;
475

476
	if (pntsd == NULL)
S
Steve French 已提交
477 478
		return -EIO;

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

499 500
	if (dacloffset)
		parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr,
501
			   group_sid_ptr, fattr);
502
	else
503
		cFYI(1, "no ACL"); /* BB grant all or default perms? */
504

505 506 507
/*	cifscred->uid = owner_sid_ptr->rid;
	cifscred->gid = group_sid_ptr->rid;
	memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
S
Steve French 已提交
508
			sizeof(struct cifs_sid));
509
	memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
S
Steve French 已提交
510
			sizeof(struct cifs_sid)); */
511

512
	return 0;
513
}
S
Steve French 已提交
514 515


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

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

552
	return rc;
553 554
}

555 556
static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
		__u16 fid, u32 *pacllen)
S
Steve French 已提交
557 558
{
	struct cifs_ntsd *pntsd = NULL;
559
	int xid, rc;
560 561 562
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
563
		return ERR_CAST(tlink);
S
Steve French 已提交
564

565
	xid = GetXid();
566
	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
567
	FreeXid(xid);
S
Steve French 已提交
568

569
	cifs_put_tlink(tlink);
S
Steve French 已提交
570

571 572 573
	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
574 575
	return pntsd;
}
576

577 578 579 580 581 582 583
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;
584 585 586 587
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

	if (IS_ERR(tlink))
588
		return ERR_CAST(tlink);
S
Steve French 已提交
589

590
	tcon = tlink_tcon(tlink);
591 592
	xid = GetXid();

593
	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, READ_CONTROL, 0,
594 595
			 &fid, &oplock, NULL, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
596 597 598
	if (!rc) {
		rc = CIFSSMBGetCIFSACL(xid, tcon, fid, &pntsd, pacllen);
		CIFSSMBClose(xid, tcon, fid);
S
Steve French 已提交
599 600
	}

601
	cifs_put_tlink(tlink);
602
	FreeXid(xid);
603 604 605 606

	cFYI(1, "%s: rc = %d ACL len %d", __func__, rc, *pacllen);
	if (rc)
		return ERR_PTR(rc);
607 608 609
	return pntsd;
}

610 611 612 613 614 615 616 617 618
/* Retrieve an ACL from the server */
static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
				      struct inode *inode, const char *path,
				      u32 *pacllen)
{
	struct cifs_ntsd *pntsd = NULL;
	struct cifsFileInfo *open_file = NULL;

	if (inode)
619
		open_file = find_readable_file(CIFS_I(inode), true);
620 621 622 623
	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);
624
	cifsFileInfo_put(open_file);
625 626 627
	return pntsd;
}

628 629
static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
		struct cifs_ntsd *pnntsd, u32 acllen)
630
{
631
	int xid, rc;
632 633 634 635
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);

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

637
	xid = GetXid();
638
	rc = CIFSSMBSetCIFSACL(xid, tlink_tcon(tlink), fid, pnntsd, acllen);
639
	FreeXid(xid);
640
	cifs_put_tlink(tlink);
641

642
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
643 644
	return rc;
}
645

646 647 648 649 650 651
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;
652 653
	struct cifsTconInfo *tcon;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
654

655 656 657 658
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);

	tcon = tlink_tcon(tlink);
659 660
	xid = GetXid();

661
	rc = CIFSSMBOpen(xid, tcon, path, FILE_OPEN, WRITE_DAC, 0,
662 663 664
			 &fid, &oplock, NULL, cifs_sb->local_nls,
			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
	if (rc) {
665
		cERROR(1, "Unable to open file to set ACL");
666
		goto out;
667 668
	}

669
	rc = CIFSSMBSetCIFSACL(xid, tcon, fid, pnntsd, acllen);
670
	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
671

672 673
	CIFSSMBClose(xid, tcon, fid);
out:
674
	FreeXid(xid);
675
	cifs_put_tlink(tlink);
676 677
	return rc;
}
678

679 680 681 682 683 684 685 686
/* 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;

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

689
	open_file = find_readable_file(CIFS_I(inode), true);
690 691 692 693
	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);
694
	cifsFileInfo_put(open_file);
695
	return rc;
696 697
}

698
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
699
int
700 701
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
		  struct inode *inode, const char *path, const __u16 *pfid)
702 703 704 705 706
{
	struct cifs_ntsd *pntsd = NULL;
	u32 acllen = 0;
	int rc = 0;

707
	cFYI(DBG2, "converting ACL to mode for %s", path);
708 709 710 711 712

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

	/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
715 716 717 718
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
		cERROR(1, "%s: error %d getting sec desc", __func__, rc);
	} else {
719
		rc = parse_sec_desc(pntsd, acllen, fattr);
720 721 722 723
		kfree(pntsd);
		if (rc)
			cERROR(1, "parse sec desc failed rc = %d", rc);
	}
724

725
	return rc;
S
Steve French 已提交
726
}
727

728
/* Convert mode bits to an ACL so we can update the ACL on the server */
729
int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
730 731
{
	int rc = 0;
732
	__u32 secdesclen = 0;
733 734
	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
735

736
	cFYI(DBG2, "set ACL from mode for %s", path);
737 738

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

741 742
	/* Add three ACEs for owner, group, everyone getting rid of
	   other ACEs as chmod disables ACEs and set the security descriptor */
743

744 745 746 747
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
		cERROR(1, "%s: error %d getting sec desc", __func__, rc);
	} else {
748 749 750
		/* allocate memory for the smb header,
		   set security descriptor request security descriptor
		   parameters, and secuirty descriptor itself */
751

752 753 754
		secdesclen = secdesclen < DEFSECDESCLEN ?
					DEFSECDESCLEN : secdesclen;
		pnntsd = kmalloc(secdesclen, GFP_KERNEL);
755
		if (!pnntsd) {
756
			cERROR(1, "Unable to allocate security descriptor");
757
			kfree(pntsd);
758
			return -ENOMEM;
759
		}
760

761
		rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
762

763
		cFYI(DBG2, "build_sec_desc rc: %d", rc);
764 765 766

		if (!rc) {
			/* Set the security descriptor */
767
			rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
768
			cFYI(DBG2, "set_cifs_acl rc: %d", rc);
769 770 771 772 773 774
		}

		kfree(pnntsd);
		kfree(pntsd);
	}

775
	return rc;
776
}
S
Steve French 已提交
777
#endif /* CONFIG_CIFS_EXPERIMENTAL */