]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/fs/nfs/nfs_commonacl.c
Mark more nodes as CTLFLAG_MPSAFE or CTLFLAG_NEEDGIANT (17 of many)
[FreeBSD/FreeBSD.git] / sys / fs / nfs / nfs_commonacl.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009 Rick Macklem, University of Guelph
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #ifndef APPLEKEXT
34 #include <fs/nfs/nfsport.h>
35
36 extern int nfsrv_useacl;
37 #endif
38
39 static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
40     enum vtype type, acl_perm_t *permp);
41
42 /*
43  * Handle xdr for an ace.
44  */
45 APPLESTATIC int
46 nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
47     int *aceerrp, int *acesizep, NFSPROC_T *p)
48 {
49         u_int32_t *tl;
50         int len, gotid = 0, owner = 0, error = 0, aceerr = 0;
51         u_char *name, namestr[NFSV4_SMALLSTR + 1];
52         u_int32_t flag, mask, acetype;
53         gid_t gid;
54         uid_t uid;
55
56         *aceerrp = 0;
57         acep->ae_flags = 0;
58         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
59         acetype = fxdr_unsigned(u_int32_t, *tl++);
60         flag = fxdr_unsigned(u_int32_t, *tl++);
61         mask = fxdr_unsigned(u_int32_t, *tl++);
62         len = fxdr_unsigned(int, *tl);
63         if (len < 0) {
64                 error = NFSERR_BADXDR;
65                 goto nfsmout;
66         } else if (len == 0) {
67                 /* Netapp filers return a 0 length who for nil users */
68                 acep->ae_tag = ACL_UNDEFINED_TAG;
69                 acep->ae_id = ACL_UNDEFINED_ID;
70                 acep->ae_perm = (acl_perm_t)0;
71                 acep->ae_entry_type = ACL_ENTRY_TYPE_DENY;
72                 if (acesizep)
73                         *acesizep = 4 * NFSX_UNSIGNED;
74                 error = 0;
75                 goto nfsmout;
76         }
77         if (len > NFSV4_SMALLSTR)
78                 name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
79         else
80                 name = namestr;
81         error = nfsrv_mtostr(nd, name, len);
82         if (error) {
83                 if (len > NFSV4_SMALLSTR)
84                         free(name, M_NFSSTRING);
85                 goto nfsmout;
86         }
87         if (len == 6) {
88                 if (!NFSBCMP(name, "OWNER@", 6)) {
89                         acep->ae_tag = ACL_USER_OBJ;
90                         acep->ae_id = ACL_UNDEFINED_ID;
91                         owner = 1;
92                         gotid = 1;
93                 } else if (!NFSBCMP(name, "GROUP@", 6)) {
94                         acep->ae_tag = ACL_GROUP_OBJ;
95                         acep->ae_id = ACL_UNDEFINED_ID;
96                         gotid = 1;
97                 }
98         } else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) {
99                 acep->ae_tag = ACL_EVERYONE;
100                 acep->ae_id = ACL_UNDEFINED_ID;
101                 gotid = 1;
102         }
103         if (gotid == 0) {
104                 if (flag & NFSV4ACE_IDENTIFIERGROUP) {
105                         acep->ae_tag = ACL_GROUP;
106                         aceerr = nfsv4_strtogid(nd, name, len, &gid);
107                         if (aceerr == 0)
108                                 acep->ae_id = (uid_t)gid;
109                 } else {
110                         acep->ae_tag = ACL_USER;
111                         aceerr = nfsv4_strtouid(nd, name, len, &uid);
112                         if (aceerr == 0)
113                                 acep->ae_id = uid;
114                 }
115         }
116         if (len > NFSV4_SMALLSTR)
117                 free(name, M_NFSSTRING);
118
119         if (aceerr == 0) {
120                 /*
121                  * Handle the flags.
122                  */
123                 flag &= ~NFSV4ACE_IDENTIFIERGROUP;
124                 if (flag & NFSV4ACE_FILEINHERIT) {
125                         flag &= ~NFSV4ACE_FILEINHERIT;
126                         acep->ae_flags |= ACL_ENTRY_FILE_INHERIT;
127                 }
128                 if (flag & NFSV4ACE_DIRECTORYINHERIT) {
129                         flag &= ~NFSV4ACE_DIRECTORYINHERIT;
130                         acep->ae_flags |= ACL_ENTRY_DIRECTORY_INHERIT;
131                 }
132                 if (flag & NFSV4ACE_NOPROPAGATEINHERIT) {
133                         flag &= ~NFSV4ACE_NOPROPAGATEINHERIT;
134                         acep->ae_flags |= ACL_ENTRY_NO_PROPAGATE_INHERIT;
135                 }
136                 if (flag & NFSV4ACE_INHERITONLY) {
137                         flag &= ~NFSV4ACE_INHERITONLY;
138                         acep->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
139                 }
140                 if (flag & NFSV4ACE_SUCCESSFULACCESS) {
141                         flag &= ~NFSV4ACE_SUCCESSFULACCESS;
142                         acep->ae_flags |= ACL_ENTRY_SUCCESSFUL_ACCESS;
143                 }
144                 if (flag & NFSV4ACE_FAILEDACCESS) {
145                         flag &= ~NFSV4ACE_FAILEDACCESS;
146                         acep->ae_flags |= ACL_ENTRY_FAILED_ACCESS;
147                 }
148                 /*
149                  * Set ae_entry_type.
150                  */
151                 if (acetype == NFSV4ACE_ALLOWEDTYPE)
152                         acep->ae_entry_type = ACL_ENTRY_TYPE_ALLOW;
153                 else if (acetype == NFSV4ACE_DENIEDTYPE)
154                         acep->ae_entry_type = ACL_ENTRY_TYPE_DENY;
155                 else if (acetype == NFSV4ACE_AUDITTYPE)
156                         acep->ae_entry_type = ACL_ENTRY_TYPE_AUDIT;
157                 else if (acetype == NFSV4ACE_ALARMTYPE)
158                         acep->ae_entry_type = ACL_ENTRY_TYPE_ALARM;
159                 else
160                         aceerr = NFSERR_ATTRNOTSUPP;
161         }
162
163         /*
164          * Now, check for unsupported flag bits.
165          */
166         if (aceerr == 0 && flag != 0)
167                 aceerr = NFSERR_ATTRNOTSUPP;
168
169         /*
170          * And turn the mask into perm bits.
171          */
172         if (aceerr == 0)
173                 aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG,
174                     &acep->ae_perm);
175         *aceerrp = aceerr;
176         if (acesizep)
177                 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
178         error = 0;
179 nfsmout:
180         NFSEXITCODE(error);
181         return (error);
182 }
183
184 /*
185  * Turn an NFSv4 ace mask into R/W/X flag bits.
186  */
187 static int
188 nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
189     enum vtype type, acl_perm_t *permp)
190 {
191         acl_perm_t perm = 0x0;
192         int error = 0;
193
194         if (mask & NFSV4ACE_READDATA) {
195                 mask &= ~NFSV4ACE_READDATA;
196                 perm |= ACL_READ_DATA;
197         }
198         if (mask & NFSV4ACE_LISTDIRECTORY) {
199                 mask &= ~NFSV4ACE_LISTDIRECTORY;
200                 perm |= ACL_LIST_DIRECTORY;
201         }
202         if (mask & NFSV4ACE_WRITEDATA) {
203                 mask &= ~NFSV4ACE_WRITEDATA;
204                 perm |= ACL_WRITE_DATA;
205         }
206         if (mask & NFSV4ACE_ADDFILE) {
207                 mask &= ~NFSV4ACE_ADDFILE;
208                 perm |= ACL_ADD_FILE;
209         }
210         if (mask & NFSV4ACE_APPENDDATA) {
211                 mask &= ~NFSV4ACE_APPENDDATA;
212                 perm |= ACL_APPEND_DATA;
213         }
214         if (mask & NFSV4ACE_ADDSUBDIRECTORY) {
215                 mask &= ~NFSV4ACE_ADDSUBDIRECTORY;
216                 perm |= ACL_ADD_SUBDIRECTORY;
217         }
218         if (mask & NFSV4ACE_READNAMEDATTR) {
219                 mask &= ~NFSV4ACE_READNAMEDATTR;
220                 perm |= ACL_READ_NAMED_ATTRS;
221         }
222         if (mask & NFSV4ACE_WRITENAMEDATTR) {
223                 mask &= ~NFSV4ACE_WRITENAMEDATTR;
224                 perm |= ACL_WRITE_NAMED_ATTRS;
225         }
226         if (mask & NFSV4ACE_EXECUTE) {
227                 mask &= ~NFSV4ACE_EXECUTE;
228                 perm |= ACL_EXECUTE;
229         }
230         if (mask & NFSV4ACE_SEARCH) {
231                 mask &= ~NFSV4ACE_SEARCH;
232                 perm |= ACL_EXECUTE;
233         }
234         if (mask & NFSV4ACE_DELETECHILD) {
235                 mask &= ~NFSV4ACE_DELETECHILD;
236                 perm |= ACL_DELETE_CHILD;
237         }
238         if (mask & NFSV4ACE_READATTRIBUTES) {
239                 mask &= ~NFSV4ACE_READATTRIBUTES;
240                 perm |= ACL_READ_ATTRIBUTES;
241         }
242         if (mask & NFSV4ACE_WRITEATTRIBUTES) {
243                 mask &= ~NFSV4ACE_WRITEATTRIBUTES;
244                 perm |= ACL_WRITE_ATTRIBUTES;
245         }
246         if (mask & NFSV4ACE_DELETE) {
247                 mask &= ~NFSV4ACE_DELETE;
248                 perm |= ACL_DELETE;
249         }
250         if (mask & NFSV4ACE_READACL) {
251                 mask &= ~NFSV4ACE_READACL;
252                 perm |= ACL_READ_ACL;
253         }
254         if (mask & NFSV4ACE_WRITEACL) {
255                 mask &= ~NFSV4ACE_WRITEACL;
256                 perm |= ACL_WRITE_ACL;
257         }
258         if (mask & NFSV4ACE_WRITEOWNER) {
259                 mask &= ~NFSV4ACE_WRITEOWNER;
260                 perm |= ACL_WRITE_OWNER;
261         }
262         if (mask & NFSV4ACE_SYNCHRONIZE) {
263                 mask &= ~NFSV4ACE_SYNCHRONIZE;
264                 perm |= ACL_SYNCHRONIZE;
265         }
266         if (mask != 0) {
267                 error = NFSERR_ATTRNOTSUPP;
268                 goto out;
269         }
270         *permp = perm;
271
272 out:
273         NFSEXITCODE(error);
274         return (error);
275 }
276
277 /* local functions */
278 static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int,
279     enum vtype, int, int, struct acl_entry *);
280
281 /*
282  * This function builds an NFS ace.
283  */
284 static int
285 nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen,
286     enum vtype type, int group, int owner, struct acl_entry *ace)
287 {
288         u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype;
289         int full_len;
290
291         full_len = NFSM_RNDUP(namelen);
292         NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len);
293
294         /*
295          * Fill in the ace type.
296          */
297         if (ace->ae_entry_type & ACL_ENTRY_TYPE_ALLOW)
298                 acetype = NFSV4ACE_ALLOWEDTYPE;
299         else if (ace->ae_entry_type & ACL_ENTRY_TYPE_DENY)
300                 acetype = NFSV4ACE_DENIEDTYPE;
301         else if (ace->ae_entry_type & ACL_ENTRY_TYPE_AUDIT)
302                 acetype = NFSV4ACE_AUDITTYPE;
303         else
304                 acetype = NFSV4ACE_ALARMTYPE;
305         *tl++ = txdr_unsigned(acetype);
306
307         /*
308          * Set the flag bits from the ACL.
309          */
310         if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT)
311                 aceflag |= NFSV4ACE_FILEINHERIT;
312         if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT)
313                 aceflag |= NFSV4ACE_DIRECTORYINHERIT;
314         if (ace->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)
315                 aceflag |= NFSV4ACE_NOPROPAGATEINHERIT;
316         if (ace->ae_flags & ACL_ENTRY_INHERIT_ONLY)
317                 aceflag |= NFSV4ACE_INHERITONLY;
318         if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS)
319                 aceflag |= NFSV4ACE_SUCCESSFULACCESS;
320         if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS)
321                 aceflag |= NFSV4ACE_FAILEDACCESS;
322         if (group)
323                 aceflag |= NFSV4ACE_IDENTIFIERGROUP;
324         *tl++ = txdr_unsigned(aceflag);
325         if (type == VDIR) {
326                 if (ace->ae_perm & ACL_LIST_DIRECTORY)
327                         acemask |= NFSV4ACE_LISTDIRECTORY;
328                 if (ace->ae_perm & ACL_ADD_FILE)
329                         acemask |= NFSV4ACE_ADDFILE;
330                 if (ace->ae_perm & ACL_ADD_SUBDIRECTORY)
331                         acemask |= NFSV4ACE_ADDSUBDIRECTORY;
332                 if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
333                         acemask |= NFSV4ACE_READNAMEDATTR;
334                 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
335                         acemask |= NFSV4ACE_WRITENAMEDATTR;
336                 if (ace->ae_perm & ACL_EXECUTE)
337                         acemask |= NFSV4ACE_SEARCH;
338                 if (ace->ae_perm & ACL_DELETE_CHILD)
339                         acemask |= NFSV4ACE_DELETECHILD;
340                 if (ace->ae_perm & ACL_READ_ATTRIBUTES)
341                         acemask |= NFSV4ACE_READATTRIBUTES;
342                 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
343                         acemask |= NFSV4ACE_WRITEATTRIBUTES;
344                 if (ace->ae_perm & ACL_DELETE)
345                         acemask |= NFSV4ACE_DELETE;
346                 if (ace->ae_perm & ACL_READ_ACL)
347                         acemask |= NFSV4ACE_READACL;
348                 if (ace->ae_perm & ACL_WRITE_ACL)
349                         acemask |= NFSV4ACE_WRITEACL;
350                 if (ace->ae_perm & ACL_WRITE_OWNER)
351                         acemask |= NFSV4ACE_WRITEOWNER;
352                 if (ace->ae_perm & ACL_SYNCHRONIZE)
353                         acemask |= NFSV4ACE_SYNCHRONIZE;
354         } else {
355                 if (ace->ae_perm & ACL_READ_DATA)
356                         acemask |= NFSV4ACE_READDATA;
357                 if (ace->ae_perm & ACL_WRITE_DATA)
358                         acemask |= NFSV4ACE_WRITEDATA;
359                 if (ace->ae_perm & ACL_APPEND_DATA)
360                         acemask |= NFSV4ACE_APPENDDATA;
361                 if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
362                         acemask |= NFSV4ACE_READNAMEDATTR;
363                 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
364                         acemask |= NFSV4ACE_WRITENAMEDATTR;
365                 if (ace->ae_perm & ACL_EXECUTE)
366                         acemask |= NFSV4ACE_EXECUTE;
367                 if (ace->ae_perm & ACL_READ_ATTRIBUTES)
368                         acemask |= NFSV4ACE_READATTRIBUTES;
369                 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
370                         acemask |= NFSV4ACE_WRITEATTRIBUTES;
371                 if (ace->ae_perm & ACL_DELETE)
372                         acemask |= NFSV4ACE_DELETE;
373                 if (ace->ae_perm & ACL_READ_ACL)
374                         acemask |= NFSV4ACE_READACL;
375                 if (ace->ae_perm & ACL_WRITE_ACL)
376                         acemask |= NFSV4ACE_WRITEACL;
377                 if (ace->ae_perm & ACL_WRITE_OWNER)
378                         acemask |= NFSV4ACE_WRITEOWNER;
379                 if (ace->ae_perm & ACL_SYNCHRONIZE)
380                         acemask |= NFSV4ACE_SYNCHRONIZE;
381         }
382         *tl++ = txdr_unsigned(acemask);
383         *tl++ = txdr_unsigned(namelen);
384         if (full_len - namelen)
385                 *(tl + (namelen / NFSX_UNSIGNED)) = 0x0;
386         NFSBCOPY(name, (caddr_t)tl, namelen);
387         return (full_len + 4 * NFSX_UNSIGNED);
388 }
389
390 /*
391  * Build an NFSv4 ACL.
392  */
393 APPLESTATIC int
394 nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, enum vtype type,
395     NFSPROC_T *p)
396 {
397         int i, entrycnt = 0, retlen;
398         u_int32_t *entrycntp;
399         int isowner, isgroup, namelen, malloced;
400         u_char *name, namestr[NFSV4_SMALLSTR];
401
402         NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED);
403         retlen = NFSX_UNSIGNED;
404         /*
405          * Loop through the acl entries, building each one.
406          */
407         for (i = 0; i < aclp->acl_cnt; i++) {
408                 isowner = isgroup = malloced = 0;
409                 switch (aclp->acl_entry[i].ae_tag) {
410                 case ACL_USER_OBJ:
411                         isowner = 1;
412                         name = "OWNER@";
413                         namelen = 6;
414                         break;
415                 case ACL_GROUP_OBJ:
416                         isgroup = 1;
417                         name = "GROUP@";
418                         namelen = 6;
419                         break;
420                 case ACL_EVERYONE:
421                         name = "EVERYONE@";
422                         namelen = 9;
423                         break;
424                 case ACL_USER:
425                         name = namestr;
426                         nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name,
427                             &namelen);
428                         if (name != namestr)
429                                 malloced = 1;
430                         break;
431                 case ACL_GROUP:
432                         isgroup = 1;
433                         name = namestr;
434                         nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name,
435                             &namelen);
436                         if (name != namestr)
437                                 malloced = 1;
438                         break;
439                 default:
440                         continue;
441                 }
442                 retlen += nfsrv_buildace(nd, name, namelen, type, isgroup,
443                     isowner, &aclp->acl_entry[i]);
444                 entrycnt++;
445                 if (malloced)
446                         free(name, M_NFSSTRING);
447         }
448         *entrycntp = txdr_unsigned(entrycnt);
449         return (retlen);
450 }
451
452 /*
453  * Compare two NFSv4 acls.
454  * Return 0 if they are the same, 1 if not the same.
455  */
456 APPLESTATIC int
457 nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2)
458 {
459         int i;
460         struct acl_entry *acep1, *acep2;
461
462         if (aclp1->acl_cnt != aclp2->acl_cnt)
463                 return (1);
464         acep1 = aclp1->acl_entry;
465         acep2 = aclp2->acl_entry;
466         for (i = 0; i < aclp1->acl_cnt; i++) {
467                 if (acep1->ae_tag != acep2->ae_tag)
468                         return (1);
469                 switch (acep1->ae_tag) {
470                 case ACL_GROUP:
471                 case ACL_USER:
472                         if (acep1->ae_id != acep2->ae_id)
473                                 return (1);
474                         /* fall through */
475                 case ACL_USER_OBJ:
476                 case ACL_GROUP_OBJ:
477                 case ACL_OTHER:
478                         if (acep1->ae_perm != acep2->ae_perm)
479                                 return (1);
480                 }
481                 acep1++;
482                 acep2++;
483         }
484         return (0);
485 }