]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/fs/nfs/nfs_commonacl.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / fs / nfs / nfs_commonacl.c
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  * Set an NFSv4 acl.
624  */
625 APPLESTATIC int
626 nfsrv_setacl(vnode_t vp, NFSACL_T *aclp, struct ucred *cred,
627     NFSPROC_T *p)
628 {
629         int error;
630
631         if (nfsrv_useacl == 0 || !NFSHASNFS4ACL(vnode_mount(vp)))
632                 return (NFSERR_ATTRNOTSUPP);
633         /*
634          * With NFSv4 ACLs, chmod(2) may need to add additional entries.
635          * Make sure it has enough room for that - splitting every entry
636          * into two and appending "canonical six" entries at the end.
637          * Cribbed out of kern/vfs_acl.c - Rick M.
638          */
639         if (aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2)
640                 return (NFSERR_ATTRNOTSUPP);
641         error = VOP_ACLCHECK(vp, ACL_TYPE_NFS4, aclp, cred, p);
642         if (!error)
643                 error = VOP_SETACL(vp, ACL_TYPE_NFS4, aclp, cred, p);
644         return (error);
645 }
646
647 /*
648  * Compare two NFSv4 acls.
649  * Return 0 if they are the same, 1 if not the same.
650  */
651 APPLESTATIC int
652 nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2)
653 {
654         int i;
655         struct acl_entry *acep1, *acep2;
656
657         if (aclp1->acl_cnt != aclp2->acl_cnt)
658                 return (1);
659         acep1 = aclp1->acl_entry;
660         acep2 = aclp2->acl_entry;
661         for (i = 0; i < aclp1->acl_cnt; i++) {
662                 if (acep1->ae_tag != acep2->ae_tag)
663                         return (1);
664                 switch (acep1->ae_tag) {
665                 case ACL_GROUP:
666                 case ACL_USER:
667                         if (acep1->ae_id != acep2->ae_id)
668                                 return (1);
669                         /* fall through */
670                 case ACL_USER_OBJ:
671                 case ACL_GROUP_OBJ:
672                 case ACL_OTHER:
673                         if (acep1->ae_perm != acep2->ae_perm)
674                                 return (1);
675                 };
676                 acep1++;
677                 acep2++;
678         }
679         return (0);
680 }
681
682 #endif  /* NFS4_ACL_EXTATTR_NAME */