nfs_commonacl.c revision 192818
1/*-
2 * Copyright (c) 2009 Rick Macklem, University of Guelph
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/fs/nfs/nfs_commonacl.c 192818 2009-05-26 17:01:00Z trasz $");
30
31#ifndef APPLEKEXT
32#include <fs/nfs/nfsport.h>
33
34extern int nfsrv_useacl;
35#endif
36
37static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
38    enum vtype type, acl_perm_t *permp);
39
40#if defined(NFS4_ACL_EXTATTR_NAME)
41/*
42 * Handle xdr for an ace.
43 */
44APPLESTATIC int
45nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
46    int *aceerrp, int *acesizep, NFSPROC_T *p)
47{
48	u_int32_t *tl;
49	int len, gotid = 0, owner = 0, error = 0, aceerr = 0;
50	u_char *name, namestr[NFSV4_SMALLSTR + 1];
51	u_int32_t flag, mask, acetype;
52	gid_t gid;
53	uid_t uid;
54
55	*aceerrp = 0;
56	acep->ae_flags = 0;
57	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
58	acetype = fxdr_unsigned(u_int32_t, *tl++);
59	flag = fxdr_unsigned(u_int32_t, *tl++);
60	mask = fxdr_unsigned(u_int32_t, *tl++);
61	len = fxdr_unsigned(int, *tl);
62	if (len < 0) {
63		return (NFSERR_BADXDR);
64	} else if (len == 0) {
65		/* Netapp filers return a 0 length who for nil users */
66		acep->ae_tag = ACL_UNDEFINED_TAG;
67		acep->ae_id = ACL_UNDEFINED_ID;
68		acep->ae_perm = (acl_perm_t)0;
69		acep->ae_entry_type = ACL_ENTRY_TYPE_DENY;
70		if (acesizep)
71			*acesizep = 4 * NFSX_UNSIGNED;
72		return (0);
73	}
74	if (len > NFSV4_SMALLSTR)
75		name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
76	else
77		name = namestr;
78	error = nfsrv_mtostr(nd, name, len);
79	if (error) {
80		if (len > NFSV4_SMALLSTR)
81			free(name, M_NFSSTRING);
82		return (error);
83	}
84	if (len == 6) {
85		if (!NFSBCMP(name, "OWNER@", 6)) {
86			acep->ae_tag = ACL_USER_OBJ;
87			acep->ae_id = ACL_UNDEFINED_ID;
88			owner = 1;
89			gotid = 1;
90		} else if (!NFSBCMP(name, "GROUP@", 6)) {
91			acep->ae_tag = ACL_GROUP_OBJ;
92			acep->ae_id = ACL_UNDEFINED_ID;
93			gotid = 1;
94		}
95	} else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) {
96		acep->ae_tag = ACL_EVERYONE;
97		acep->ae_id = ACL_UNDEFINED_ID;
98		gotid = 1;
99	}
100	if (gotid == 0) {
101		if (flag & NFSV4ACE_IDENTIFIERGROUP) {
102			acep->ae_tag = ACL_GROUP;
103			aceerr = nfsv4_strtogid(name, len, &gid, p);
104			if (aceerr == 0)
105				acep->ae_id = (uid_t)gid;
106		} else {
107			acep->ae_tag = ACL_USER;
108			aceerr = nfsv4_strtouid(name, len, &uid, p);
109			if (aceerr == 0)
110				acep->ae_id = uid;
111		}
112	}
113	if (len > NFSV4_SMALLSTR)
114		free(name, M_NFSSTRING);
115
116	if (aceerr == 0) {
117		/*
118		 * Handle the flags.
119		 */
120		flag &= ~NFSV4ACE_IDENTIFIERGROUP;
121		if (flag & NFSV4ACE_FILEINHERIT) {
122			flag &= ~NFSV4ACE_FILEINHERIT;
123			acep->ae_flags |= ACL_ENTRY_FILE_INHERIT;
124		}
125		if (flag & NFSV4ACE_DIRECTORYINHERIT) {
126			flag &= ~NFSV4ACE_DIRECTORYINHERIT;
127			acep->ae_flags |= ACL_ENTRY_DIRECTORY_INHERIT;
128		}
129		if (flag & NFSV4ACE_NOPROPAGATEINHERIT) {
130			flag &= ~NFSV4ACE_NOPROPAGATEINHERIT;
131			acep->ae_flags |= ACL_ENTRY_NO_PROPAGATE_INHERIT;
132		}
133		if (flag & NFSV4ACE_INHERITONLY) {
134			flag &= ~NFSV4ACE_INHERITONLY;
135			acep->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
136		}
137		if (flag & NFSV4ACE_SUCCESSFULACCESS) {
138			flag &= ~NFSV4ACE_SUCCESSFULACCESS;
139			acep->ae_flags |= ACL_ENTRY_SUCCESSFUL_ACCESS;
140		}
141		if (flag & NFSV4ACE_FAILEDACCESS) {
142			flag &= ~NFSV4ACE_FAILEDACCESS;
143			acep->ae_flags |= ACL_ENTRY_FAILED_ACCESS;
144		}
145		/*
146		 * Set ae_entry_type.
147		 */
148		if (acetype == NFSV4ACE_ALLOWEDTYPE)
149			acep->ae_entry_type = ACL_ENTRY_TYPE_ALLOW;
150		else if (acetype == NFSV4ACE_DENIEDTYPE)
151			acep->ae_entry_type = ACL_ENTRY_TYPE_DENY;
152		else if (acetype == NFSV4ACE_AUDITTYPE)
153			acep->ae_entry_type = ACL_ENTRY_TYPE_AUDIT;
154		else if (acetype == NFSV4ACE_ALARMTYPE)
155			acep->ae_entry_type = ACL_ENTRY_TYPE_ALARM;
156		else
157			aceerr = NFSERR_ATTRNOTSUPP;
158	}
159
160	/*
161	 * Now, check for unsupported flag bits.
162	 */
163	if (aceerr == 0 && flag != 0)
164		aceerr = NFSERR_ATTRNOTSUPP;
165
166	/*
167	 * And turn the mask into perm bits.
168	 */
169	if (aceerr == 0)
170		aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG,
171		    &acep->ae_perm);
172	*aceerrp = aceerr;
173	if (acesizep)
174		*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
175	return (0);
176nfsmout:
177	return (error);
178}
179
180/*
181 * Turn an NFSv4 ace mask into R/W/X flag bits.
182 */
183static int
184nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
185    enum vtype type, acl_perm_t *permp)
186{
187	acl_perm_t perm = 0x0;
188
189	if (mask & NFSV4ACE_READDATA) {
190		mask &= ~NFSV4ACE_READDATA;
191		perm |= ACL_READ_DATA;
192	}
193	if (mask & NFSV4ACE_LISTDIRECTORY) {
194		mask &= ~NFSV4ACE_LISTDIRECTORY;
195		perm |= ACL_LIST_DIRECTORY;
196	}
197	if (mask & NFSV4ACE_WRITEDATA) {
198		mask &= ~NFSV4ACE_WRITEDATA;
199		perm |= ACL_WRITE_DATA;
200	}
201	if (mask & NFSV4ACE_ADDFILE) {
202		mask &= ~NFSV4ACE_ADDFILE;
203		perm |= ACL_ADD_FILE;
204	}
205	if (mask & NFSV4ACE_APPENDDATA) {
206		mask &= ~NFSV4ACE_APPENDDATA;
207		perm |= ACL_APPEND_DATA;
208	}
209	if (mask & NFSV4ACE_ADDSUBDIRECTORY) {
210		mask &= ~NFSV4ACE_ADDSUBDIRECTORY;
211		perm |= ACL_ADD_SUBDIRECTORY;
212	}
213	if (mask & NFSV4ACE_READNAMEDATTR) {
214		mask &= ~NFSV4ACE_READNAMEDATTR;
215		perm |= ACL_READ_NAMED_ATTRS;
216	}
217	if (mask & NFSV4ACE_WRITENAMEDATTR) {
218		mask &= ~NFSV4ACE_WRITENAMEDATTR;
219		perm |= ACL_WRITE_NAMED_ATTRS;
220	}
221	if (mask & NFSV4ACE_EXECUTE) {
222		mask &= ~NFSV4ACE_EXECUTE;
223		perm |= ACL_EXECUTE;
224	}
225	if (mask & NFSV4ACE_SEARCH) {
226		mask &= ~NFSV4ACE_SEARCH;
227		perm |= ACL_SEARCH;
228	}
229	if (mask & NFSV4ACE_DELETECHILD) {
230		mask &= ~NFSV4ACE_DELETECHILD;
231		perm |= ACL_DELETE_CHILD;
232	}
233	if (mask & NFSV4ACE_READATTRIBUTES) {
234		mask &= ~NFSV4ACE_READATTRIBUTES;
235		perm |= ACL_READ_ATTRIBUTES;
236	}
237	if (mask & NFSV4ACE_WRITEATTRIBUTES) {
238		mask &= ~NFSV4ACE_WRITEATTRIBUTES;
239		perm |= ACL_WRITE_ATTRIBUTES;
240	}
241	if (mask & NFSV4ACE_DELETE) {
242		mask &= ~NFSV4ACE_DELETE;
243		perm |= ACL_DELETE;
244	}
245	if (mask & NFSV4ACE_READACL) {
246		mask &= ~NFSV4ACE_READACL;
247		perm |= ACL_READ_ACL;
248	}
249	if (mask & NFSV4ACE_WRITEACL) {
250		mask &= ~NFSV4ACE_WRITEACL;
251		perm |= ACL_WRITE_ACL;
252	}
253	if (mask & NFSV4ACE_WRITEOWNER) {
254		mask &= ~NFSV4ACE_WRITEOWNER;
255		perm |= ACL_WRITE_OWNER;
256	}
257	if (mask & NFSV4ACE_SYNCHRONIZE) {
258		mask &= ~NFSV4ACE_SYNCHRONIZE;
259		perm |= ACL_SYNCHRONIZE;
260	}
261	if (mask != 0)
262		return (NFSERR_ATTRNOTSUPP);
263	*permp = perm;
264	return (0);
265}
266#else
267/*
268 * Handle xdr for an ace.
269 */
270APPLESTATIC int
271nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
272    int *aceerrp, int *acesizep, NFSPROC_T *p)
273{
274	u_int32_t *tl;
275	int len, gotid = 0, owner = 0, error = 0, aceerr = 0;
276	u_char *name, namestr[NFSV4_SMALLSTR + 1];
277	u_int32_t flag, mask, acetype;
278	gid_t gid;
279	uid_t uid;
280
281	*aceerrp = 0;
282	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
283	acetype = fxdr_unsigned(u_int32_t, *tl++);
284	flag = fxdr_unsigned(u_int32_t, *tl++);
285	mask = fxdr_unsigned(u_int32_t, *tl++);
286	len = fxdr_unsigned(int, *tl);
287	if (len < 0) {
288		return (NFSERR_BADXDR);
289	} else if (len == 0) {
290		/* Netapp filers return a 0 length who for nil users */
291		acep->ae_tag = ACL_UNDEFINED_TAG;
292		acep->ae_id = ACL_UNDEFINED_ID;
293		acep->ae_perm = (acl_perm_t)0;
294		if (acesizep)
295			*acesizep = 4 * NFSX_UNSIGNED;
296		return (0);
297	}
298	if (len > NFSV4_SMALLSTR)
299		name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
300	else
301		name = namestr;
302	error = nfsrv_mtostr(nd, name, len);
303	if (error) {
304		if (len > NFSV4_SMALLSTR)
305			free(name, M_NFSSTRING);
306		return (error);
307	}
308	if (len == 6) {
309		if (!NFSBCMP(name, "OWNER@", 6)) {
310			acep->ae_tag = ACL_USER_OBJ;
311			acep->ae_id = ACL_UNDEFINED_ID;
312			owner = 1;
313			gotid = 1;
314		} else if (!NFSBCMP(name, "GROUP@", 6)) {
315			acep->ae_tag = ACL_GROUP_OBJ;
316			acep->ae_id = ACL_UNDEFINED_ID;
317			gotid = 1;
318			flag &= ~NFSV4ACE_IDENTIFIERGROUP;
319		}
320	} else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) {
321		acep->ae_tag = ACL_OTHER;
322		acep->ae_id = ACL_UNDEFINED_ID;
323		gotid = 1;
324	}
325	if (!gotid) {
326		if (flag & NFSV4ACE_IDENTIFIERGROUP) {
327			flag &= ~NFSV4ACE_IDENTIFIERGROUP;
328			acep->ae_tag = ACL_GROUP;
329			aceerr = nfsv4_strtogid(name, len, &gid, p);
330			if (!aceerr)
331				acep->ae_id = (uid_t)gid;
332		} else {
333			acep->ae_tag = ACL_USER;
334			aceerr = nfsv4_strtouid(name, len, &uid, p);
335			if (!aceerr)
336				acep->ae_id = uid;
337		}
338	}
339	if (len > NFSV4_SMALLSTR)
340		free(name, M_NFSSTRING);
341
342	/*
343	 * Now, check for unsupported types or flag bits.
344	 */
345	if (!aceerr && ((acetype != NFSV4ACE_ALLOWEDTYPE &&
346	     acetype != NFSV4ACE_AUDITTYPE && acetype != NFSV4ACE_ALARMTYPE
347	     && acetype != NFSV4ACE_DENIEDTYPE) || flag))
348		aceerr = NFSERR_ATTRNOTSUPP;
349
350	/*
351	 * And turn the mask into perm bits.
352	 */
353	if (!aceerr)
354		aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG,
355			&acep->ae_perm);
356	*aceerrp = aceerr;
357	if (acesizep)
358		*acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
359	return (0);
360nfsmout:
361	return (error);
362}
363
364/*
365 * Turn an NFSv4 ace mask into R/W/X flag bits.
366 */
367static int
368nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
369    enum vtype type, acl_perm_t *permp)
370{
371	acl_perm_t perm = 0x0;
372
373	if (acetype != NFSV4ACE_ALLOWEDTYPE && acetype != NFSV4ACE_DENIEDTYPE){
374		if (mask & ~NFSV4ACE_AUDITMASK)
375			return (NFSERR_ATTRNOTSUPP);
376	}
377	if (mask & NFSV4ACE_DELETE) {
378		return (NFSERR_ATTRNOTSUPP);
379	}
380	if (acetype == NFSV4ACE_DENIEDTYPE) {
381		if (mask & NFSV4ACE_ALLFILESMASK) {
382			return (NFSERR_ATTRNOTSUPP);
383		}
384		if (owner) {
385			if (mask & NFSV4ACE_OWNERMASK) {
386				return (NFSERR_ATTRNOTSUPP);
387			}
388		} else {
389			if ((mask & NFSV4ACE_OWNERMASK) != NFSV4ACE_OWNERMASK) {
390				return (NFSERR_ATTRNOTSUPP);
391			}
392			mask &= ~NFSV4ACE_OWNERMASK;
393		}
394	} else if (acetype == NFSV4ACE_ALLOWEDTYPE) {
395		if ((mask & NFSV4ACE_ALLFILESMASK) != NFSV4ACE_ALLFILESMASK) {
396			return (NFSERR_ATTRNOTSUPP);
397		}
398		mask &= ~NFSV4ACE_ALLFILESMASK;
399		if (owner) {
400			if ((mask & NFSV4ACE_OWNERMASK) != NFSV4ACE_OWNERMASK) {
401				return (NFSERR_ATTRNOTSUPP);
402			}
403			mask &= ~NFSV4ACE_OWNERMASK;
404		} else if (mask & NFSV4ACE_OWNERMASK) {
405			return (NFSERR_ATTRNOTSUPP);
406		}
407	}
408	if (type == VDIR) {
409		if ((mask & NFSV4ACE_DIRREADMASK) == NFSV4ACE_DIRREADMASK) {
410			perm |= ACL_READ;
411			mask &= ~NFSV4ACE_DIRREADMASK;
412		}
413		if ((mask & NFSV4ACE_DIRWRITEMASK) == NFSV4ACE_DIRWRITEMASK) {
414			perm |= ACL_WRITE;
415			mask &= ~NFSV4ACE_DIRWRITEMASK;
416		}
417		if ((mask & NFSV4ACE_DIREXECUTEMASK)==NFSV4ACE_DIREXECUTEMASK){
418			perm |= ACL_EXECUTE;
419			mask &= ~NFSV4ACE_DIREXECUTEMASK;
420		}
421	} else {
422		if (acetype == NFSV4ACE_DENIEDTYPE &&
423		    (mask & NFSV4ACE_SYNCHRONIZE)) {
424			return (NFSERR_ATTRNOTSUPP);
425		}
426		mask &= ~(NFSV4ACE_SYNCHRONIZE | NFSV4ACE_DELETECHILD);
427		if ((mask & NFSV4ACE_READMASK) == NFSV4ACE_READMASK) {
428			perm |= ACL_READ;
429			mask &= ~NFSV4ACE_READMASK;
430		}
431		if ((mask & NFSV4ACE_WRITEMASK) == NFSV4ACE_WRITEMASK) {
432			perm |= ACL_WRITE;
433			mask &= ~NFSV4ACE_WRITEMASK;
434		}
435		if ((mask & NFSV4ACE_EXECUTEMASK) == NFSV4ACE_EXECUTEMASK) {
436			perm |= ACL_EXECUTE;
437			mask &= ~NFSV4ACE_EXECUTEMASK;
438		}
439	}
440	if (mask) {
441		return (NFSERR_ATTRNOTSUPP);
442	}
443	*permp = perm;
444	return (0);
445}
446#endif	/* !NFS4_ACL_EXTATTR_NAME */
447
448#ifdef NFS4_ACL_EXTATTR_NAME
449/* local functions */
450static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int,
451    enum vtype, int, int, struct acl_entry *);
452
453/*
454 * This function builds an NFS ace.
455 */
456static int
457nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen,
458    enum vtype type, int group, int owner, struct acl_entry *ace)
459{
460	u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype;
461	int full_len;
462
463	full_len = NFSM_RNDUP(namelen);
464	NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len);
465
466	/*
467	 * Fill in the ace type.
468	 */
469	if (ace->ae_entry_type & ACL_ENTRY_TYPE_ALLOW)
470		acetype = NFSV4ACE_ALLOWEDTYPE;
471	else if (ace->ae_entry_type & ACL_ENTRY_TYPE_DENY)
472		acetype = NFSV4ACE_DENIEDTYPE;
473	else if (ace->ae_entry_type & ACL_ENTRY_TYPE_AUDIT)
474		acetype = NFSV4ACE_AUDITTYPE;
475	else
476		acetype = NFSV4ACE_ALARMTYPE;
477	*tl++ = txdr_unsigned(acetype);
478
479	/*
480	 * Set the flag bits from the ACL.
481	 */
482	if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT)
483		aceflag |= NFSV4ACE_FILEINHERIT;
484	if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT)
485		aceflag |= NFSV4ACE_DIRECTORYINHERIT;
486	if (ace->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)
487		aceflag |= NFSV4ACE_NOPROPAGATEINHERIT;
488	if (ace->ae_flags & ACL_ENTRY_INHERIT_ONLY)
489		aceflag |= NFSV4ACE_INHERITONLY;
490	if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS)
491		aceflag |= NFSV4ACE_SUCCESSFULACCESS;
492	if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS)
493		aceflag |= NFSV4ACE_FAILEDACCESS;
494	if (group)
495		aceflag |= NFSV4ACE_IDENTIFIERGROUP;
496	*tl++ = txdr_unsigned(aceflag);
497	if (type == VDIR) {
498		if (ace->ae_perm & ACL_LIST_DIRECTORY)
499			acemask |= NFSV4ACE_LISTDIRECTORY;
500		if (ace->ae_perm & ACL_ADD_FILE)
501			acemask |= NFSV4ACE_ADDFILE;
502		if (ace->ae_perm & ACL_ADD_SUBDIRECTORY)
503			acemask |= NFSV4ACE_ADDSUBDIRECTORY;
504		if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
505			acemask |= NFSV4ACE_READNAMEDATTR;
506		if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
507			acemask |= NFSV4ACE_WRITENAMEDATTR;
508		if (ace->ae_perm & ACL_SEARCH)
509			acemask |= NFSV4ACE_SEARCH;
510		if (ace->ae_perm & ACL_DELETE_CHILD)
511			acemask |= NFSV4ACE_DELETECHILD;
512		if (ace->ae_perm & ACL_READ_ATTRIBUTES)
513			acemask |= NFSV4ACE_READATTRIBUTES;
514		if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
515			acemask |= NFSV4ACE_WRITEATTRIBUTES;
516		if (ace->ae_perm & ACL_DELETE)
517			acemask |= NFSV4ACE_DELETE;
518		if (ace->ae_perm & ACL_READ_ACL)
519			acemask |= NFSV4ACE_READACL;
520		if (ace->ae_perm & ACL_WRITE_ACL)
521			acemask |= NFSV4ACE_WRITEACL;
522		if (ace->ae_perm & ACL_WRITE_OWNER)
523			acemask |= NFSV4ACE_WRITEOWNER;
524	} else {
525		if (ace->ae_perm & ACL_READ_DATA)
526			acemask |= NFSV4ACE_READDATA;
527		if (ace->ae_perm & ACL_WRITE_DATA)
528			acemask |= NFSV4ACE_WRITEDATA;
529		if (ace->ae_perm & ACL_APPEND_DATA)
530			acemask |= NFSV4ACE_APPENDDATA;
531		if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
532			acemask |= NFSV4ACE_READNAMEDATTR;
533		if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
534			acemask |= NFSV4ACE_WRITENAMEDATTR;
535		if (ace->ae_perm & ACL_EXECUTE)
536			acemask |= NFSV4ACE_EXECUTE;
537		if (ace->ae_perm & ACL_READ_ATTRIBUTES)
538			acemask |= NFSV4ACE_READATTRIBUTES;
539		if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
540			acemask |= NFSV4ACE_WRITEATTRIBUTES;
541		if (ace->ae_perm & ACL_DELETE)
542			acemask |= NFSV4ACE_DELETE;
543		if (ace->ae_perm & ACL_READ_ACL)
544			acemask |= NFSV4ACE_READACL;
545		if (ace->ae_perm & ACL_WRITE_ACL)
546			acemask |= NFSV4ACE_WRITEACL;
547		if (ace->ae_perm & ACL_WRITE_OWNER)
548			acemask |= NFSV4ACE_WRITEOWNER;
549		if (ace->ae_perm & ACL_SYNCHRONIZE)
550			acemask |= NFSV4ACE_SYNCHRONIZE;
551	}
552	*tl++ = txdr_unsigned(acemask);
553	*tl++ = txdr_unsigned(namelen);
554	if (full_len - namelen)
555		*(tl + (namelen / NFSX_UNSIGNED)) = 0x0;
556	NFSBCOPY(name, (caddr_t)tl, namelen);
557	return (full_len + 4 * NFSX_UNSIGNED);
558}
559
560/*
561 * Build an NFSv4 ACL.
562 */
563APPLESTATIC int
564nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, enum vtype type,
565    NFSPROC_T *p)
566{
567	int i, entrycnt = 0, retlen;
568	u_int32_t *entrycntp;
569	int isowner, isgroup, namelen, malloced;
570	u_char *name, namestr[NFSV4_SMALLSTR];
571
572	NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED);
573	retlen = NFSX_UNSIGNED;
574	/*
575	 * Loop through the acl entries, building each one.
576	 */
577	for (i = 0; i < aclp->acl_cnt; i++) {
578		isowner = isgroup = malloced = 0;
579		switch (aclp->acl_entry[i].ae_tag) {
580		case ACL_USER_OBJ:
581			isowner = 1;
582			name = "OWNER@";
583			namelen = 6;
584			break;
585		case ACL_GROUP_OBJ:
586			isgroup = 1;
587			name = "GROUP@";
588			namelen = 6;
589			break;
590		case ACL_EVERYONE:
591			name = "EVERYONE@";
592			namelen = 9;
593			break;
594		case ACL_USER:
595			name = namestr;
596			nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name,
597			    &namelen, p);
598			if (name != namestr)
599				malloced = 1;
600			break;
601		case ACL_GROUP:
602			isgroup = 1;
603			name = namestr;
604			nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name,
605			    &namelen, p);
606			if (name != namestr)
607				malloced = 1;
608			break;
609		default:
610			continue;
611		};
612		retlen += nfsrv_buildace(nd, name, namelen, type, isgroup,
613		    isowner, &aclp->acl_entry[i]);
614		entrycnt++;
615		if (malloced)
616			free(name, M_NFSSTRING);
617	}
618	*entrycntp = txdr_unsigned(entrycnt);
619	return (retlen);
620}
621
622/*
623 * Check access for an NFSv4 acl.
624 * The vflags are the basic VREAD, VWRITE, VEXEC. The mask is the NFSV4ACE
625 * mask bits for the more detailed check.
626 * If the more detailed check fails, due to no acl, do a basic one.
627 */
628APPLESTATIC int
629nfsrv_aclaccess(vnode_t vp, accmode_t vflags, u_int32_t mask,
630    struct ucred *cred, NFSPROC_T *p)
631{
632	int error = 0;
633	accmode_t access;
634
635	if (nfsrv_useacl == 0) {
636		error = VOP_ACCESS(vp, vflags, cred, p);
637		return (error);
638	}
639
640	/* Convert NFSV4ACE mask to vaccess_t */
641	access = 0;
642	if (mask & NFSV4ACE_READDATA)
643		access |= VREAD;
644	if (mask & NFSV4ACE_LISTDIRECTORY)
645		access |= VREAD;
646	if (mask & NFSV4ACE_WRITEDATA)
647		access |= VWRITE;
648	if (mask & NFSV4ACE_ADDFILE)
649		access |= VWRITE;
650	if (mask & NFSV4ACE_APPENDDATA)
651		access |= VAPPEND;
652	if (mask & NFSV4ACE_ADDSUBDIRECTORY)
653		access |= VAPPEND;
654	if (mask & NFSV4ACE_READNAMEDATTR)
655		access |= VREAD_NAMED_ATTRS;
656	if (mask & NFSV4ACE_WRITENAMEDATTR)
657		access |= VWRITE_NAMED_ATTRS;
658	if (mask & NFSV4ACE_EXECUTE)
659		access |= VEXEC;
660	if (mask & NFSV4ACE_SEARCH)
661		access |= VEXEC;
662	if (mask & NFSV4ACE_DELETECHILD)
663		access |= VDELETE_CHILD;
664	if (mask & NFSV4ACE_READATTRIBUTES)
665		access |= VREAD_ATTRIBUTES;
666	if (mask & NFSV4ACE_WRITEATTRIBUTES)
667		access |= VWRITE_ATTRIBUTES;
668	if (mask & NFSV4ACE_DELETE)
669		access |= VDELETE;
670	if (mask & NFSV4ACE_READACL)
671		access |= VREAD_ACL;
672	if (mask & NFSV4ACE_WRITEACL)
673		access |= VWRITE_ACL;
674	if (mask & NFSV4ACE_WRITEOWNER)
675		access |= VWRITE_OWNER;
676	if (mask & NFSV4ACE_SYNCHRONIZE)
677		access |= VSYNCHRONIZE;
678
679	if (access != 0)
680		error = VOP_ACCESS(vp, access, cred, p);
681	else
682		error = VOP_ACCESS(vp, vflags, cred, p);
683	return (error);
684}
685
686/*
687 * Set an NFSv4 acl.
688 */
689APPLESTATIC int
690nfsrv_setacl(vnode_t vp, NFSACL_T *aclp, struct ucred *cred,
691    NFSPROC_T *p)
692{
693	int error;
694
695	if (nfsrv_useacl == 0 || !NFSHASNFS4ACL(vnode_mount(vp)))
696		return (NFSERR_ATTRNOTSUPP);
697	/*
698	 * With NFS4 ACLs, chmod(2) may need to add additional entries.
699	 * Make sure it has enough room for that - splitting every entry
700	 * into two and appending "canonical six" entries at the end.
701	 * Cribbed out of kern/vfs_acl.c - Rick M.
702	 */
703	if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2)
704		return (NFSERR_ATTRNOTSUPP);
705	error = VOP_ACLCHECK(vp, ACL_TYPE_NFS4, aclp, cred, p);
706#ifdef MAC
707	if (!error)
708		error = mac_check_vnode_setacl(cred, vp, ACL_TYPE_NFS4, aclp);
709#endif
710	if (!error)
711		error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p);
712	return (error);
713}
714
715/*
716 * Compare two NFSv4 acls.
717 * Return 0 if they are the same, 1 if not the same.
718 */
719APPLESTATIC int
720nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2)
721{
722	int i;
723	struct acl_entry *acep1, *acep2;
724
725	if (aclp1->acl_cnt != aclp2->acl_cnt)
726		return (1);
727	acep1 = aclp1->acl_entry;
728	acep2 = aclp2->acl_entry;
729	for (i = 0; i < aclp1->acl_cnt; i++) {
730		if (acep1->ae_tag != acep2->ae_tag)
731			return (1);
732		switch (acep1->ae_tag) {
733		case ACL_GROUP:
734		case ACL_USER:
735			if (acep1->ae_id != acep2->ae_id)
736				return (1);
737			/* fall through */
738		case ACL_USER_OBJ:
739		case ACL_GROUP_OBJ:
740		case ACL_OTHER:
741			if (acep1->ae_perm != acep2->ae_perm)
742				return (1);
743		};
744		acep1++;
745		acep2++;
746	}
747	return (0);
748}
749
750#endif	/* NFS4_ACL_EXTATTR_NAME */
751