xref: /freebsd/sys/fs/nfs/nfs_commonacl.c (revision 830940567b49bb0c08dfaed40418999e76616909)
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$");
30 
31 #ifndef APPLEKEXT
32 #include <fs/nfs/nfsport.h>
33 
34 extern int nfsrv_useacl;
35 #endif
36 
37 static 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  */
44 APPLESTATIC int
45 nfsrv_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);
176 nfsmout:
177 	return (error);
178 }
179 
180 /*
181  * Turn an NFSv4 ace mask into R/W/X flag bits.
182  */
183 static int
184 nfsrv_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_EXECUTE;
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  */
270 APPLESTATIC int
271 nfsrv_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);
360 nfsmout:
361 	return (error);
362 }
363 
364 /*
365  * Turn an NFSv4 ace mask into R/W/X flag bits.
366  */
367 static int
368 nfsrv_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 */
450 static 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  */
456 static int
457 nfsrv_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_EXECUTE)
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  */
563 APPLESTATIC int
564 nfsrv_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  */
628 APPLESTATIC int
629 nfsrv_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  */
689 APPLESTATIC int
690 nfsrv_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 	if (!error)
707 		error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p);
708 	return (error);
709 }
710 
711 /*
712  * Compare two NFSv4 acls.
713  * Return 0 if they are the same, 1 if not the same.
714  */
715 APPLESTATIC int
716 nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2)
717 {
718 	int i;
719 	struct acl_entry *acep1, *acep2;
720 
721 	if (aclp1->acl_cnt != aclp2->acl_cnt)
722 		return (1);
723 	acep1 = aclp1->acl_entry;
724 	acep2 = aclp2->acl_entry;
725 	for (i = 0; i < aclp1->acl_cnt; i++) {
726 		if (acep1->ae_tag != acep2->ae_tag)
727 			return (1);
728 		switch (acep1->ae_tag) {
729 		case ACL_GROUP:
730 		case ACL_USER:
731 			if (acep1->ae_id != acep2->ae_id)
732 				return (1);
733 			/* fall through */
734 		case ACL_USER_OBJ:
735 		case ACL_GROUP_OBJ:
736 		case ACL_OTHER:
737 			if (acep1->ae_perm != acep2->ae_perm)
738 				return (1);
739 		};
740 		acep1++;
741 		acep2++;
742 	}
743 	return (0);
744 }
745 
746 #endif	/* NFS4_ACL_EXTATTR_NAME */
747