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 #include <fs/nfs/nfsport.h>
34
35 extern int nfsrv_useacl;
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 /*
41 * Handle xdr for an ace.
42 */
43 int
44 nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
45 int *aceerrp, int *acesizep, NFSPROC_T *p)
46 {
47 u_int32_t *tl;
48 int len, gotid = 0, owner = 0, error = 0, aceerr = 0;
49 u_char *name, namestr[NFSV4_SMALLSTR + 1];
50 u_int32_t flag, mask, acetype;
51 gid_t gid;
52 uid_t uid;
53
54 *aceerrp = 0;
55 acep->ae_flags = 0;
56 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
57 acetype = fxdr_unsigned(u_int32_t, *tl++);
58 flag = fxdr_unsigned(u_int32_t, *tl++);
59 mask = fxdr_unsigned(u_int32_t, *tl++);
60 len = fxdr_unsigned(int, *tl);
61 /*
62 * The RFCs do not specify a limit to the length of the "who", but
63 * NFSV4_OPAQUELIMIT (1024) should be sufficient.
64 */
65 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
66 error = NFSERR_BADXDR;
67 goto nfsmout;
68 } else if (len == 0) {
69 /* Netapp filers return a 0 length who for nil users */
70 acep->ae_tag = ACL_UNDEFINED_TAG;
71 acep->ae_id = ACL_UNDEFINED_ID;
72 acep->ae_perm = (acl_perm_t)0;
73 acep->ae_entry_type = ACL_ENTRY_TYPE_DENY;
74 if (acesizep)
75 *acesizep = 4 * NFSX_UNSIGNED;
76 error = 0;
77 goto nfsmout;
78 }
79 if (len > NFSV4_SMALLSTR)
80 name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
81 else
82 name = namestr;
83 error = nfsrv_mtostr(nd, name, len);
84 if (error) {
85 if (len > NFSV4_SMALLSTR)
86 free(name, M_NFSSTRING);
87 goto nfsmout;
88 }
89 if (len == 6) {
90 if (!NFSBCMP(name, "OWNER@", 6)) {
91 acep->ae_tag = ACL_USER_OBJ;
92 acep->ae_id = ACL_UNDEFINED_ID;
93 owner = 1;
94 gotid = 1;
95 } else if (!NFSBCMP(name, "GROUP@", 6)) {
96 acep->ae_tag = ACL_GROUP_OBJ;
97 acep->ae_id = ACL_UNDEFINED_ID;
98 gotid = 1;
99 }
100 } else if (len == 9 && !NFSBCMP(name, "EVERYONE@", 9)) {
101 acep->ae_tag = ACL_EVERYONE;
102 acep->ae_id = ACL_UNDEFINED_ID;
103 gotid = 1;
104 }
105 if (gotid == 0) {
106 if (flag & NFSV4ACE_IDENTIFIERGROUP) {
107 acep->ae_tag = ACL_GROUP;
108 aceerr = nfsv4_strtogid(nd, name, len, &gid, p);
109 if (aceerr == 0)
110 acep->ae_id = (uid_t)gid;
111 } else {
112 acep->ae_tag = ACL_USER;
113 aceerr = nfsv4_strtouid(nd, name, len, &uid, p);
114 if (aceerr == 0)
115 acep->ae_id = uid;
116 }
117 }
118 if (len > NFSV4_SMALLSTR)
119 free(name, M_NFSSTRING);
120
121 if (aceerr == 0) {
122 /*
123 * Handle the flags.
124 */
125 flag &= ~NFSV4ACE_IDENTIFIERGROUP;
126 if (flag & NFSV4ACE_FILEINHERIT) {
127 flag &= ~NFSV4ACE_FILEINHERIT;
128 acep->ae_flags |= ACL_ENTRY_FILE_INHERIT;
129 }
130 if (flag & NFSV4ACE_DIRECTORYINHERIT) {
131 flag &= ~NFSV4ACE_DIRECTORYINHERIT;
132 acep->ae_flags |= ACL_ENTRY_DIRECTORY_INHERIT;
133 }
134 if (flag & NFSV4ACE_NOPROPAGATEINHERIT) {
135 flag &= ~NFSV4ACE_NOPROPAGATEINHERIT;
136 acep->ae_flags |= ACL_ENTRY_NO_PROPAGATE_INHERIT;
137 }
138 if (flag & NFSV4ACE_INHERITONLY) {
139 flag &= ~NFSV4ACE_INHERITONLY;
140 acep->ae_flags |= ACL_ENTRY_INHERIT_ONLY;
141 }
142 if (flag & NFSV4ACE_SUCCESSFULACCESS) {
143 flag &= ~NFSV4ACE_SUCCESSFULACCESS;
144 acep->ae_flags |= ACL_ENTRY_SUCCESSFUL_ACCESS;
145 }
146 if (flag & NFSV4ACE_FAILEDACCESS) {
147 flag &= ~NFSV4ACE_FAILEDACCESS;
148 acep->ae_flags |= ACL_ENTRY_FAILED_ACCESS;
149 }
150 /*
151 * Set ae_entry_type.
152 */
153 if (acetype == NFSV4ACE_ALLOWEDTYPE)
154 acep->ae_entry_type = ACL_ENTRY_TYPE_ALLOW;
155 else if (acetype == NFSV4ACE_DENIEDTYPE)
156 acep->ae_entry_type = ACL_ENTRY_TYPE_DENY;
157 else if (acetype == NFSV4ACE_AUDITTYPE)
158 acep->ae_entry_type = ACL_ENTRY_TYPE_AUDIT;
159 else if (acetype == NFSV4ACE_ALARMTYPE)
160 acep->ae_entry_type = ACL_ENTRY_TYPE_ALARM;
161 else
162 aceerr = NFSERR_ATTRNOTSUPP;
163 }
164
165 /*
166 * Now, check for unsupported flag bits.
167 */
168 if (aceerr == 0 && flag != 0)
169 aceerr = NFSERR_ATTRNOTSUPP;
170
171 /*
172 * And turn the mask into perm bits.
173 */
174 if (aceerr == 0)
175 aceerr = nfsrv_acemasktoperm(acetype, mask, owner, VREG,
176 &acep->ae_perm);
177 *aceerrp = aceerr;
178 if (acesizep)
179 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
180 error = 0;
181 nfsmout:
182 NFSEXITCODE(error);
183 return (error);
184 }
185
186 /*
187 * Turn an NFSv4 ace mask into R/W/X flag bits.
188 */
189 static int
190 nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
191 enum vtype type, acl_perm_t *permp)
192 {
193 acl_perm_t perm = 0x0;
194 int error = 0;
195
196 if (mask & NFSV4ACE_READDATA) {
197 mask &= ~NFSV4ACE_READDATA;
198 perm |= ACL_READ_DATA;
199 }
200 if (mask & NFSV4ACE_LISTDIRECTORY) {
201 mask &= ~NFSV4ACE_LISTDIRECTORY;
202 perm |= ACL_LIST_DIRECTORY;
203 }
204 if (mask & NFSV4ACE_WRITEDATA) {
205 mask &= ~NFSV4ACE_WRITEDATA;
206 perm |= ACL_WRITE_DATA;
207 }
208 if (mask & NFSV4ACE_ADDFILE) {
209 mask &= ~NFSV4ACE_ADDFILE;
210 perm |= ACL_ADD_FILE;
211 }
212 if (mask & NFSV4ACE_APPENDDATA) {
213 mask &= ~NFSV4ACE_APPENDDATA;
214 perm |= ACL_APPEND_DATA;
215 }
216 if (mask & NFSV4ACE_ADDSUBDIRECTORY) {
217 mask &= ~NFSV4ACE_ADDSUBDIRECTORY;
218 perm |= ACL_ADD_SUBDIRECTORY;
219 }
220 if (mask & NFSV4ACE_READNAMEDATTR) {
221 mask &= ~NFSV4ACE_READNAMEDATTR;
222 perm |= ACL_READ_NAMED_ATTRS;
223 }
224 if (mask & NFSV4ACE_WRITENAMEDATTR) {
225 mask &= ~NFSV4ACE_WRITENAMEDATTR;
226 perm |= ACL_WRITE_NAMED_ATTRS;
227 }
228 if (mask & NFSV4ACE_EXECUTE) {
229 mask &= ~NFSV4ACE_EXECUTE;
230 perm |= ACL_EXECUTE;
231 }
232 if (mask & NFSV4ACE_SEARCH) {
233 mask &= ~NFSV4ACE_SEARCH;
234 perm |= ACL_EXECUTE;
235 }
236 if (mask & NFSV4ACE_DELETECHILD) {
237 mask &= ~NFSV4ACE_DELETECHILD;
238 perm |= ACL_DELETE_CHILD;
239 }
240 if (mask & NFSV4ACE_READATTRIBUTES) {
241 mask &= ~NFSV4ACE_READATTRIBUTES;
242 perm |= ACL_READ_ATTRIBUTES;
243 }
244 if (mask & NFSV4ACE_WRITEATTRIBUTES) {
245 mask &= ~NFSV4ACE_WRITEATTRIBUTES;
246 perm |= ACL_WRITE_ATTRIBUTES;
247 }
248 if (mask & NFSV4ACE_DELETE) {
249 mask &= ~NFSV4ACE_DELETE;
250 perm |= ACL_DELETE;
251 }
252 if (mask & NFSV4ACE_READACL) {
253 mask &= ~NFSV4ACE_READACL;
254 perm |= ACL_READ_ACL;
255 }
256 if (mask & NFSV4ACE_WRITEACL) {
257 mask &= ~NFSV4ACE_WRITEACL;
258 perm |= ACL_WRITE_ACL;
259 }
260 if (mask & NFSV4ACE_WRITEOWNER) {
261 mask &= ~NFSV4ACE_WRITEOWNER;
262 perm |= ACL_WRITE_OWNER;
263 }
264 if (mask & NFSV4ACE_SYNCHRONIZE) {
265 mask &= ~NFSV4ACE_SYNCHRONIZE;
266 perm |= ACL_SYNCHRONIZE;
267 }
268 if (mask != 0) {
269 error = NFSERR_ATTRNOTSUPP;
270 goto out;
271 }
272 *permp = perm;
273
274 out:
275 NFSEXITCODE(error);
276 return (error);
277 }
278
279 /* local functions */
280 static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int,
281 enum vtype, int, int, struct acl_entry *);
282
283 /*
284 * This function builds an NFS ace.
285 */
286 static int
287 nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen,
288 enum vtype type, int group, int owner, struct acl_entry *ace)
289 {
290 u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype;
291 int full_len;
292
293 full_len = NFSM_RNDUP(namelen);
294 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len);
295
296 /*
297 * Fill in the ace type.
298 */
299 if (ace->ae_entry_type & ACL_ENTRY_TYPE_ALLOW)
300 acetype = NFSV4ACE_ALLOWEDTYPE;
301 else if (ace->ae_entry_type & ACL_ENTRY_TYPE_DENY)
302 acetype = NFSV4ACE_DENIEDTYPE;
303 else if (ace->ae_entry_type & ACL_ENTRY_TYPE_AUDIT)
304 acetype = NFSV4ACE_AUDITTYPE;
305 else
306 acetype = NFSV4ACE_ALARMTYPE;
307 *tl++ = txdr_unsigned(acetype);
308
309 /*
310 * Set the flag bits from the ACL.
311 */
312 if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT)
313 aceflag |= NFSV4ACE_FILEINHERIT;
314 if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT)
315 aceflag |= NFSV4ACE_DIRECTORYINHERIT;
316 if (ace->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)
317 aceflag |= NFSV4ACE_NOPROPAGATEINHERIT;
318 if (ace->ae_flags & ACL_ENTRY_INHERIT_ONLY)
319 aceflag |= NFSV4ACE_INHERITONLY;
320 if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS)
321 aceflag |= NFSV4ACE_SUCCESSFULACCESS;
322 if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS)
323 aceflag |= NFSV4ACE_FAILEDACCESS;
324 if (group)
325 aceflag |= NFSV4ACE_IDENTIFIERGROUP;
326 *tl++ = txdr_unsigned(aceflag);
327 if (type == VDIR) {
328 if (ace->ae_perm & ACL_LIST_DIRECTORY)
329 acemask |= NFSV4ACE_LISTDIRECTORY;
330 if (ace->ae_perm & ACL_ADD_FILE)
331 acemask |= NFSV4ACE_ADDFILE;
332 if (ace->ae_perm & ACL_ADD_SUBDIRECTORY)
333 acemask |= NFSV4ACE_ADDSUBDIRECTORY;
334 if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
335 acemask |= NFSV4ACE_READNAMEDATTR;
336 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
337 acemask |= NFSV4ACE_WRITENAMEDATTR;
338 if (ace->ae_perm & ACL_EXECUTE)
339 acemask |= NFSV4ACE_SEARCH;
340 if (ace->ae_perm & ACL_DELETE_CHILD)
341 acemask |= NFSV4ACE_DELETECHILD;
342 if (ace->ae_perm & ACL_READ_ATTRIBUTES)
343 acemask |= NFSV4ACE_READATTRIBUTES;
344 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
345 acemask |= NFSV4ACE_WRITEATTRIBUTES;
346 if (ace->ae_perm & ACL_DELETE)
347 acemask |= NFSV4ACE_DELETE;
348 if (ace->ae_perm & ACL_READ_ACL)
349 acemask |= NFSV4ACE_READACL;
350 if (ace->ae_perm & ACL_WRITE_ACL)
351 acemask |= NFSV4ACE_WRITEACL;
352 if (ace->ae_perm & ACL_WRITE_OWNER)
353 acemask |= NFSV4ACE_WRITEOWNER;
354 if (ace->ae_perm & ACL_SYNCHRONIZE)
355 acemask |= NFSV4ACE_SYNCHRONIZE;
356 } else {
357 if (ace->ae_perm & ACL_READ_DATA)
358 acemask |= NFSV4ACE_READDATA;
359 if (ace->ae_perm & ACL_WRITE_DATA)
360 acemask |= NFSV4ACE_WRITEDATA;
361 if (ace->ae_perm & ACL_APPEND_DATA)
362 acemask |= NFSV4ACE_APPENDDATA;
363 if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
364 acemask |= NFSV4ACE_READNAMEDATTR;
365 if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
366 acemask |= NFSV4ACE_WRITENAMEDATTR;
367 if (ace->ae_perm & ACL_EXECUTE)
368 acemask |= NFSV4ACE_EXECUTE;
369 if (ace->ae_perm & ACL_READ_ATTRIBUTES)
370 acemask |= NFSV4ACE_READATTRIBUTES;
371 if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
372 acemask |= NFSV4ACE_WRITEATTRIBUTES;
373 if (ace->ae_perm & ACL_DELETE)
374 acemask |= NFSV4ACE_DELETE;
375 if (ace->ae_perm & ACL_READ_ACL)
376 acemask |= NFSV4ACE_READACL;
377 if (ace->ae_perm & ACL_WRITE_ACL)
378 acemask |= NFSV4ACE_WRITEACL;
379 if (ace->ae_perm & ACL_WRITE_OWNER)
380 acemask |= NFSV4ACE_WRITEOWNER;
381 if (ace->ae_perm & ACL_SYNCHRONIZE)
382 acemask |= NFSV4ACE_SYNCHRONIZE;
383 }
384 *tl++ = txdr_unsigned(acemask);
385 *tl++ = txdr_unsigned(namelen);
386 if (full_len - namelen)
387 *(tl + (namelen / NFSX_UNSIGNED)) = 0x0;
388 NFSBCOPY(name, (caddr_t)tl, namelen);
389 return (full_len + 4 * NFSX_UNSIGNED);
390 }
391
392 /*
393 * Build an NFSv4 ACL.
394 */
395 int
396 nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, enum vtype type,
397 NFSPROC_T *p)
398 {
399 int i, entrycnt = 0, retlen;
400 u_int32_t *entrycntp;
401 int isowner, isgroup, namelen, malloced;
402 u_char *name, namestr[NFSV4_SMALLSTR];
403
404 NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED);
405 retlen = NFSX_UNSIGNED;
406 /*
407 * Loop through the acl entries, building each one.
408 */
409 for (i = 0; i < aclp->acl_cnt; i++) {
410 isowner = isgroup = malloced = 0;
411 switch (aclp->acl_entry[i].ae_tag) {
412 case ACL_USER_OBJ:
413 isowner = 1;
414 name = "OWNER@";
415 namelen = 6;
416 break;
417 case ACL_GROUP_OBJ:
418 isgroup = 1;
419 name = "GROUP@";
420 namelen = 6;
421 break;
422 case ACL_EVERYONE:
423 name = "EVERYONE@";
424 namelen = 9;
425 break;
426 case ACL_USER:
427 name = namestr;
428 nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name,
429 &namelen, p);
430 if (name != namestr)
431 malloced = 1;
432 break;
433 case ACL_GROUP:
434 isgroup = 1;
435 name = namestr;
436 nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name,
437 &namelen, p);
438 if (name != namestr)
439 malloced = 1;
440 break;
441 default:
442 continue;
443 }
444 retlen += nfsrv_buildace(nd, name, namelen, type, isgroup,
445 isowner, &aclp->acl_entry[i]);
446 entrycnt++;
447 if (malloced)
448 free(name, M_NFSSTRING);
449 }
450 *entrycntp = txdr_unsigned(entrycnt);
451 return (retlen);
452 }
453
454 /*
455 * Compare two NFSv4 acls.
456 * Return 0 if they are the same, 1 if not the same.
457 */
458 int
459 nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2)
460 {
461 int i;
462 struct acl_entry *acep1, *acep2;
463
464 if (aclp1->acl_cnt != aclp2->acl_cnt)
465 return (1);
466 acep1 = aclp1->acl_entry;
467 acep2 = aclp2->acl_entry;
468 for (i = 0; i < aclp1->acl_cnt; i++) {
469 if (acep1->ae_tag != acep2->ae_tag)
470 return (1);
471 switch (acep1->ae_tag) {
472 case ACL_GROUP:
473 case ACL_USER:
474 if (acep1->ae_id != acep2->ae_id)
475 return (1);
476 /* fall through */
477 case ACL_USER_OBJ:
478 case ACL_GROUP_OBJ:
479 case ACL_OTHER:
480 if (acep1->ae_perm != acep2->ae_perm)
481 return (1);
482 }
483 acep1++;
484 acep2++;
485 }
486 return (0);
487 }
Cache object: 1bfdcfb76b448c14ae8a5b414bf1e2ac
|