1/*
2 *   fs/cifs/cifsacl.c
3 *
4 *   Copyright (C) International Business Machines  Corp., 2007,2008
5 *   Author(s): Steve French (sfrench@us.ibm.com)
6 *
7 *   Contains the routines for mapping CIFS/NTFS ACLs
8 *
9 *   This library is free software; you can redistribute it and/or modify
10 *   it under the terms of the GNU Lesser General Public License as published
11 *   by the Free Software Foundation; either version 2.1 of the License, or
12 *   (at your option) any later version.
13 *
14 *   This library is distributed in the hope that it will be useful,
15 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17 *   the GNU Lesser General Public License for more details.
18 *
19 *   You should have received a copy of the GNU Lesser General Public License
20 *   along with this library; if not, write to the Free Software
21 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include <linux/fs.h>
25#include <linux/slab.h>
26#include "cifspdu.h"
27#include "cifsglob.h"
28#include "cifsacl.h"
29#include "cifsproto.h"
30#include "cifs_debug.h"
31
32
33#ifdef CONFIG_CIFS_EXPERIMENTAL
34
35static struct cifs_wksid wksidarr[NUM_WK_SIDS] = {
36	{{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"},
37	{{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"},
38	{{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"},
39	{{1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(18), 0, 0, 0, 0} }, "sys"},
40	{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(544), 0, 0, 0} }, "root"},
41	{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(545), 0, 0, 0} }, "users"},
42	{{1, 2, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(32), __constant_cpu_to_le32(546), 0, 0, 0} }, "guest"} }
43;
44
45
46/* security id for everyone */
47static const struct cifs_sid sid_everyone = {
48	1, 1, {0, 0, 0, 0, 0, 1}, {0} };
49/* group users */
50static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
51
52
53int match_sid(struct cifs_sid *ctsid)
54{
55	int i, j;
56	int num_subauth, num_sat, num_saw;
57	struct cifs_sid *cwsid;
58
59	if (!ctsid)
60		return -1;
61
62	for (i = 0; i < NUM_WK_SIDS; ++i) {
63		cwsid = &(wksidarr[i].cifssid);
64
65		/* compare the revision */
66		if (ctsid->revision != cwsid->revision)
67			continue;
68
69		/* compare all of the six auth values */
70		for (j = 0; j < 6; ++j) {
71			if (ctsid->authority[j] != cwsid->authority[j])
72				break;
73		}
74		if (j < 6)
75			continue; /* all of the auth values did not match */
76
77		/* compare all of the subauth values if any */
78		num_sat = ctsid->num_subauth;
79		num_saw = cwsid->num_subauth;
80		num_subauth = num_sat < num_saw ? num_sat : num_saw;
81		if (num_subauth) {
82			for (j = 0; j < num_subauth; ++j) {
83				if (ctsid->sub_auth[j] != cwsid->sub_auth[j])
84					break;
85			}
86			if (j < num_subauth)
87				continue; /* all sub_auth values do not match */
88		}
89
90		cFYI(1, "matching sid: %s\n", wksidarr[i].sidname);
91		return 0; /* sids compare/match */
92	}
93
94	cFYI(1, "No matching sid");
95	return -1;
96}
97
98/* if the two SIDs (roughly equivalent to a UUID for a user or group) are
99   the same returns 1, if they do not match returns 0 */
100int compare_sids(const struct cifs_sid *ctsid, const struct cifs_sid *cwsid)
101{
102	int i;
103	int num_subauth, num_sat, num_saw;
104
105	if ((!ctsid) || (!cwsid))
106		return 0;
107
108	/* compare the revision */
109	if (ctsid->revision != cwsid->revision)
110		return 0;
111
112	/* compare all of the six auth values */
113	for (i = 0; i < 6; ++i) {
114		if (ctsid->authority[i] != cwsid->authority[i])
115			return 0;
116	}
117
118	/* compare all of the subauth values if any */
119	num_sat = ctsid->num_subauth;
120	num_saw = cwsid->num_subauth;
121	num_subauth = num_sat < num_saw ? num_sat : num_saw;
122	if (num_subauth) {
123		for (i = 0; i < num_subauth; ++i) {
124			if (ctsid->sub_auth[i] != cwsid->sub_auth[i])
125				return 0;
126		}
127	}
128
129	return 1; /* sids compare/match */
130}
131
132
133/* copy ntsd, owner sid, and group sid from a security descriptor to another */
134static void copy_sec_desc(const struct cifs_ntsd *pntsd,
135				struct cifs_ntsd *pnntsd, __u32 sidsoffset)
136{
137	int i;
138
139	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
140	struct cifs_sid *nowner_sid_ptr, *ngroup_sid_ptr;
141
142	/* copy security descriptor control portion */
143	pnntsd->revision = pntsd->revision;
144	pnntsd->type = pntsd->type;
145	pnntsd->dacloffset = cpu_to_le32(sizeof(struct cifs_ntsd));
146	pnntsd->sacloffset = 0;
147	pnntsd->osidoffset = cpu_to_le32(sidsoffset);
148	pnntsd->gsidoffset = cpu_to_le32(sidsoffset + sizeof(struct cifs_sid));
149
150	/* copy owner sid */
151	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
152				le32_to_cpu(pntsd->osidoffset));
153	nowner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset);
154
155	nowner_sid_ptr->revision = owner_sid_ptr->revision;
156	nowner_sid_ptr->num_subauth = owner_sid_ptr->num_subauth;
157	for (i = 0; i < 6; i++)
158		nowner_sid_ptr->authority[i] = owner_sid_ptr->authority[i];
159	for (i = 0; i < 5; i++)
160		nowner_sid_ptr->sub_auth[i] = owner_sid_ptr->sub_auth[i];
161
162	/* copy group sid */
163	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
164				le32_to_cpu(pntsd->gsidoffset));
165	ngroup_sid_ptr = (struct cifs_sid *)((char *)pnntsd + sidsoffset +
166					sizeof(struct cifs_sid));
167
168	ngroup_sid_ptr->revision = group_sid_ptr->revision;
169	ngroup_sid_ptr->num_subauth = group_sid_ptr->num_subauth;
170	for (i = 0; i < 6; i++)
171		ngroup_sid_ptr->authority[i] = group_sid_ptr->authority[i];
172	for (i = 0; i < 5; i++)
173		ngroup_sid_ptr->sub_auth[i] = group_sid_ptr->sub_auth[i];
174
175	return;
176}
177
178
179/*
180   change posix mode to reflect permissions
181   pmode is the existing mode (we only want to overwrite part of this
182   bits to set can be: S_IRWXU, S_IRWXG or S_IRWXO ie 00700 or 00070 or 00007
183*/
184static void access_flags_to_mode(__le32 ace_flags, int type, umode_t *pmode,
185				 umode_t *pbits_to_set)
186{
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	   for the operation you are trying to perform for your user */
193
194	/* For deny ACEs we change the mask so that subsequent allow access
195	   control entries do not turn on the bits we are denying */
196	if (type == ACCESS_DENIED) {
197		if (flags & GENERIC_ALL)
198			*pbits_to_set &= ~S_IRWXUGO;
199
200		if ((flags & GENERIC_WRITE) ||
201			((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
202			*pbits_to_set &= ~S_IWUGO;
203		if ((flags & GENERIC_READ) ||
204			((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
205			*pbits_to_set &= ~S_IRUGO;
206		if ((flags & GENERIC_EXECUTE) ||
207			((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
208			*pbits_to_set &= ~S_IXUGO;
209		return;
210	} else if (type != ACCESS_ALLOWED) {
211		cERROR(1, "unknown access control type %d", type);
212		return;
213	}
214	/* else ACCESS_ALLOWED type */
215
216	if (flags & GENERIC_ALL) {
217		*pmode |= (S_IRWXUGO & (*pbits_to_set));
218		cFYI(DBG2, "all perms");
219		return;
220	}
221	if ((flags & GENERIC_WRITE) ||
222			((flags & FILE_WRITE_RIGHTS) == FILE_WRITE_RIGHTS))
223		*pmode |= (S_IWUGO & (*pbits_to_set));
224	if ((flags & GENERIC_READ) ||
225			((flags & FILE_READ_RIGHTS) == FILE_READ_RIGHTS))
226		*pmode |= (S_IRUGO & (*pbits_to_set));
227	if ((flags & GENERIC_EXECUTE) ||
228			((flags & FILE_EXEC_RIGHTS) == FILE_EXEC_RIGHTS))
229		*pmode |= (S_IXUGO & (*pbits_to_set));
230
231	cFYI(DBG2, "access flags 0x%x mode now 0x%x", flags, *pmode);
232	return;
233}
234
235/*
236   Generate access flags to reflect permissions mode is the existing mode.
237   This function is called for every ACE in the DACL whose SID matches
238   with either owner or group or everyone.
239*/
240
241static void mode_to_access_flags(umode_t mode, umode_t bits_to_use,
242				__u32 *pace_flags)
243{
244	/* reset access mask */
245	*pace_flags = 0x0;
246
247	/* bits to use are either S_IRWXU or S_IRWXG or S_IRWXO */
248	mode &= bits_to_use;
249
250	/* check for R/W/X UGO since we do not know whose flags
251	   is this but we have cleared all the bits sans RWX for
252	   either user or group or other as per bits_to_use */
253	if (mode & S_IRUGO)
254		*pace_flags |= SET_FILE_READ_RIGHTS;
255	if (mode & S_IWUGO)
256		*pace_flags |= SET_FILE_WRITE_RIGHTS;
257	if (mode & S_IXUGO)
258		*pace_flags |= SET_FILE_EXEC_RIGHTS;
259
260	cFYI(DBG2, "mode: 0x%x, access flags now 0x%x", mode, *pace_flags);
261	return;
262}
263
264static __u16 fill_ace_for_sid(struct cifs_ace *pntace,
265			const struct cifs_sid *psid, __u64 nmode, umode_t bits)
266{
267	int i;
268	__u16 size = 0;
269	__u32 access_req = 0;
270
271	pntace->type = ACCESS_ALLOWED;
272	pntace->flags = 0x0;
273	mode_to_access_flags(nmode, bits, &access_req);
274	if (!access_req)
275		access_req = SET_MINIMUM_RIGHTS;
276	pntace->access_req = cpu_to_le32(access_req);
277
278	pntace->sid.revision = psid->revision;
279	pntace->sid.num_subauth = psid->num_subauth;
280	for (i = 0; i < 6; i++)
281		pntace->sid.authority[i] = psid->authority[i];
282	for (i = 0; i < psid->num_subauth; i++)
283		pntace->sid.sub_auth[i] = psid->sub_auth[i];
284
285	size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth * 4);
286	pntace->size = cpu_to_le16(size);
287
288	return size;
289}
290
291
292#ifdef CONFIG_CIFS_DEBUG2
293static void dump_ace(struct cifs_ace *pace, char *end_of_acl)
294{
295	int num_subauth;
296
297	/* validate that we do not go past end of acl */
298
299	if (le16_to_cpu(pace->size) < 16) {
300		cERROR(1, "ACE too small %d", le16_to_cpu(pace->size));
301		return;
302	}
303
304	if (end_of_acl < (char *)pace + le16_to_cpu(pace->size)) {
305		cERROR(1, "ACL too small to parse ACE");
306		return;
307	}
308
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",
313			pace->sid.revision, pace->sid.num_subauth, pace->type,
314			pace->flags, le16_to_cpu(pace->size));
315		for (i = 0; i < num_subauth; ++i) {
316			cFYI(1, "ACE sub_auth[%d]: 0x%x", i,
317				le32_to_cpu(pace->sid.sub_auth[i]));
318		}
319
320		/* BB add length check to make sure that we do not have huge
321			num auths and therefore go off the end */
322	}
323
324	return;
325}
326#endif
327
328
329static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
330		       struct cifs_sid *pownersid, struct cifs_sid *pgrpsid,
331		       struct cifs_fattr *fattr)
332{
333	int i;
334	int num_aces = 0;
335	int acl_size;
336	char *acl_base;
337	struct cifs_ace **ppace;
338
339	/* BB need to add parm so we can store the SID BB */
340
341	if (!pdacl) {
342		/* no DACL in the security descriptor, set
343		   all the permissions for user/group/other */
344		fattr->cf_mode |= S_IRWXUGO;
345		return;
346	}
347
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		return;
352	}
353
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	/* reset rwx permissions for user/group/other.
359	   Also, if num_aces is 0 i.e. DACL has no ACEs,
360	   user/group/other have no permissions */
361	fattr->cf_mode &= ~(S_IRWXUGO);
362
363	acl_base = (char *)pdacl;
364	acl_size = sizeof(struct cifs_acl);
365
366	num_aces = le32_to_cpu(pdacl->num_aces);
367	if (num_aces  > 0) {
368		umode_t user_mask = S_IRWXU;
369		umode_t group_mask = S_IRWXG;
370		umode_t other_mask = S_IRWXO;
371
372		ppace = kmalloc(num_aces * sizeof(struct cifs_ace *),
373				GFP_KERNEL);
374
375		for (i = 0; i < num_aces; ++i) {
376			ppace[i] = (struct cifs_ace *) (acl_base + acl_size);
377#ifdef CONFIG_CIFS_DEBUG2
378			dump_ace(ppace[i], end_of_acl);
379#endif
380			if (compare_sids(&(ppace[i]->sid), pownersid))
381				access_flags_to_mode(ppace[i]->access_req,
382						     ppace[i]->type,
383						     &fattr->cf_mode,
384						     &user_mask);
385			if (compare_sids(&(ppace[i]->sid), pgrpsid))
386				access_flags_to_mode(ppace[i]->access_req,
387						     ppace[i]->type,
388						     &fattr->cf_mode,
389						     &group_mask);
390			if (compare_sids(&(ppace[i]->sid), &sid_everyone))
391				access_flags_to_mode(ppace[i]->access_req,
392						     ppace[i]->type,
393						     &fattr->cf_mode,
394						     &other_mask);
395
396/*			memcpy((void *)(&(cifscred->aces[i])),
397				(void *)ppace[i],
398				sizeof(struct cifs_ace)); */
399
400			acl_base = (char *)ppace[i];
401			acl_size = le16_to_cpu(ppace[i]->size);
402		}
403
404		kfree(ppace);
405	}
406
407	return;
408}
409
410
411static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
412			struct cifs_sid *pgrpsid, __u64 nmode)
413{
414	u16 size = 0;
415	struct cifs_acl *pnndacl;
416
417	pnndacl = (struct cifs_acl *)((char *)pndacl + sizeof(struct cifs_acl));
418
419	size += fill_ace_for_sid((struct cifs_ace *) ((char *)pnndacl + size),
420					pownersid, nmode, S_IRWXU);
421	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
422					pgrpsid, nmode, S_IRWXG);
423	size += fill_ace_for_sid((struct cifs_ace *)((char *)pnndacl + size),
424					 &sid_everyone, nmode, S_IRWXO);
425
426	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
433static int parse_sid(struct cifs_sid *psid, char *end_of_acl)
434{
435	/* BB need to add parm so we can store the SID BB */
436
437	/* validate that we do not go past end of ACL - sid must be at least 8
438	   bytes long (assuming no sub-auths - e.g. the null SID */
439	if (end_of_acl < (char *)psid + 8) {
440		cERROR(1, "ACL too small to parse SID %p", psid);
441		return -EINVAL;
442	}
443
444	if (psid->num_subauth) {
445#ifdef CONFIG_CIFS_DEBUG2
446		int i;
447		cFYI(1, "SID revision %d num_auth %d",
448			psid->revision, psid->num_subauth);
449
450		for (i = 0; i < psid->num_subauth; i++) {
451			cFYI(1, "SID sub_auth[%d]: 0x%x ", i,
452				le32_to_cpu(psid->sub_auth[i]));
453		}
454
455		/* BB add length check to make sure that we do not have huge
456			num auths and therefore go off the end */
457		cFYI(1, "RID 0x%x",
458			le32_to_cpu(psid->sub_auth[psid->num_subauth-1]));
459#endif
460	}
461
462	return 0;
463}
464
465
466/* Convert CIFS ACL to POSIX form */
467static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len,
468			  struct cifs_fattr *fattr)
469{
470	int rc;
471	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
472	struct cifs_acl *dacl_ptr; /* no need for SACL ptr */
473	char *end_of_acl = ((char *)pntsd) + acl_len;
474	__u32 dacloffset;
475
476	if (pntsd == NULL)
477		return -EIO;
478
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		 pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset),
488		 le32_to_cpu(pntsd->gsidoffset),
489		 le32_to_cpu(pntsd->sacloffset), dacloffset);
490/*	cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
491	rc = parse_sid(owner_sid_ptr, end_of_acl);
492	if (rc)
493		return rc;
494
495	rc = parse_sid(group_sid_ptr, end_of_acl);
496	if (rc)
497		return rc;
498
499	if (dacloffset)
500		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/*	cifscred->uid = owner_sid_ptr->rid;
506	cifscred->gid = group_sid_ptr->rid;
507	memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr,
508			sizeof(struct cifs_sid));
509	memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr,
510			sizeof(struct cifs_sid)); */
511
512	return 0;
513}
514
515
516/* Convert permission bits from mode to equivalent CIFS ACL */
517static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
518				struct inode *inode, __u64 nmode)
519{
520	int rc = 0;
521	__u32 dacloffset;
522	__u32 ndacloffset;
523	__u32 sidsoffset;
524	struct cifs_sid *owner_sid_ptr, *group_sid_ptr;
525	struct cifs_acl *dacl_ptr = NULL;  /* no need for SACL ptr */
526	struct cifs_acl *ndacl_ptr = NULL; /* no need for SACL ptr */
527
528	if ((inode == NULL) || (pntsd == NULL) || (pnntsd == NULL))
529		return -EIO;
530
531	owner_sid_ptr = (struct cifs_sid *)((char *)pntsd +
532				le32_to_cpu(pntsd->osidoffset));
533	group_sid_ptr = (struct cifs_sid *)((char *)pntsd +
534				le32_to_cpu(pntsd->gsidoffset));
535
536	dacloffset = le32_to_cpu(pntsd->dacloffset);
537	dacl_ptr = (struct cifs_acl *)((char *)pntsd + dacloffset);
538
539	ndacloffset = sizeof(struct cifs_ntsd);
540	ndacl_ptr = (struct cifs_acl *)((char *)pnntsd + ndacloffset);
541	ndacl_ptr->revision = dacl_ptr->revision;
542	ndacl_ptr->size = 0;
543	ndacl_ptr->num_aces = 0;
544
545	rc = set_chmod_dacl(ndacl_ptr, owner_sid_ptr, group_sid_ptr, nmode);
546
547	sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
548
549	/* copy security descriptor control portion and owner and group sid */
550	copy_sec_desc(pntsd, pnntsd, sidsoffset);
551
552	return rc;
553}
554
555static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
556		__u16 fid, u32 *pacllen)
557{
558	struct cifs_ntsd *pntsd = NULL;
559	int xid, rc;
560
561	xid = GetXid();
562	rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
563	FreeXid(xid);
564
565
566	cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
567	return pntsd;
568}
569
570static struct cifs_ntsd *get_cifs_acl_by_path(struct cifs_sb_info *cifs_sb,
571		const char *path, u32 *pacllen)
572{
573	struct cifs_ntsd *pntsd = NULL;
574	int oplock = 0;
575	int xid, rc;
576	__u16 fid;
577
578	xid = GetXid();
579
580	rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, READ_CONTROL, 0,
581			 &fid, &oplock, NULL, cifs_sb->local_nls,
582			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
583	if (rc) {
584		cERROR(1, "Unable to open file to get ACL");
585		goto out;
586	}
587
588	rc = CIFSSMBGetCIFSACL(xid, cifs_sb->tcon, fid, &pntsd, pacllen);
589	cFYI(1, "GetCIFSACL rc = %d ACL len %d", rc, *pacllen);
590
591	CIFSSMBClose(xid, cifs_sb->tcon, fid);
592 out:
593	FreeXid(xid);
594	return pntsd;
595}
596
597/* Retrieve an ACL from the server */
598static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
599				      struct inode *inode, const char *path,
600				      u32 *pacllen)
601{
602	struct cifs_ntsd *pntsd = NULL;
603	struct cifsFileInfo *open_file = NULL;
604
605	if (inode)
606		open_file = find_readable_file(CIFS_I(inode));
607	if (!open_file)
608		return get_cifs_acl_by_path(cifs_sb, path, pacllen);
609
610	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
611	cifsFileInfo_put(open_file);
612	return pntsd;
613}
614
615static int set_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, __u16 fid,
616		struct cifs_ntsd *pnntsd, u32 acllen)
617{
618	int xid, rc;
619
620	xid = GetXid();
621	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
622	FreeXid(xid);
623
624	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
625	return rc;
626}
627
628static int set_cifs_acl_by_path(struct cifs_sb_info *cifs_sb, const char *path,
629		struct cifs_ntsd *pnntsd, u32 acllen)
630{
631	int oplock = 0;
632	int xid, rc;
633	__u16 fid;
634
635	xid = GetXid();
636
637	rc = CIFSSMBOpen(xid, cifs_sb->tcon, path, FILE_OPEN, WRITE_DAC, 0,
638			 &fid, &oplock, NULL, cifs_sb->local_nls,
639			 cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
640	if (rc) {
641		cERROR(1, "Unable to open file to set ACL");
642		goto out;
643	}
644
645	rc = CIFSSMBSetCIFSACL(xid, cifs_sb->tcon, fid, pnntsd, acllen);
646	cFYI(DBG2, "SetCIFSACL rc = %d", rc);
647
648	CIFSSMBClose(xid, cifs_sb->tcon, fid);
649 out:
650	FreeXid(xid);
651	return rc;
652}
653
654/* Set an ACL on the server */
655static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
656				struct inode *inode, const char *path)
657{
658	struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
659	struct cifsFileInfo *open_file;
660	int rc;
661
662	cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
663
664	open_file = find_readable_file(CIFS_I(inode));
665	if (!open_file)
666		return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
667
668	rc = set_cifs_acl_by_fid(cifs_sb, open_file->netfid, pnntsd, acllen);
669	cifsFileInfo_put(open_file);
670	return rc;
671}
672
673/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
674void
675cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
676		  struct inode *inode, const char *path, const __u16 *pfid)
677{
678	struct cifs_ntsd *pntsd = NULL;
679	u32 acllen = 0;
680	int rc = 0;
681
682	cFYI(DBG2, "converting ACL to mode for %s", path);
683
684	if (pfid)
685		pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
686	else
687		pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
688
689	/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
690	if (pntsd)
691		rc = parse_sec_desc(pntsd, acllen, fattr);
692	if (rc)
693		cFYI(1, "parse sec desc failed rc = %d", rc);
694
695	kfree(pntsd);
696	return;
697}
698
699/* Convert mode bits to an ACL so we can update the ACL on the server */
700int mode_to_acl(struct inode *inode, const char *path, __u64 nmode)
701{
702	int rc = 0;
703	__u32 secdesclen = 0;
704	struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
705	struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
706
707	cFYI(DBG2, "set ACL from mode for %s", path);
708
709	/* Get the security descriptor */
710	pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
711
712	/* Add three ACEs for owner, group, everyone getting rid of
713	   other ACEs as chmod disables ACEs and set the security descriptor */
714
715	if (pntsd) {
716		/* allocate memory for the smb header,
717		   set security descriptor request security descriptor
718		   parameters, and secuirty descriptor itself */
719
720		secdesclen = secdesclen < DEFSECDESCLEN ?
721					DEFSECDESCLEN : secdesclen;
722		pnntsd = kmalloc(secdesclen, GFP_KERNEL);
723		if (!pnntsd) {
724			cERROR(1, "Unable to allocate security descriptor");
725			kfree(pntsd);
726			return -ENOMEM;
727		}
728
729		rc = build_sec_desc(pntsd, pnntsd, inode, nmode);
730
731		cFYI(DBG2, "build_sec_desc rc: %d", rc);
732
733		if (!rc) {
734			/* Set the security descriptor */
735			rc = set_cifs_acl(pnntsd, secdesclen, inode, path);
736			cFYI(DBG2, "set_cifs_acl rc: %d", rc);
737		}
738
739		kfree(pnntsd);
740		kfree(pntsd);
741	}
742
743	return rc;
744}
745#endif /* CONFIG_CIFS_EXPERIMENTAL */
746