xref: /freebsd/sys/fs/nfs/nfs_commonacl.c (revision 535af610)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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_uint8(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     bool server, 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);
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);
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 (!server && acetype == NFSV4ACE_AUDITTYPE)
158 			acep->ae_entry_type = ACL_ENTRY_TYPE_AUDIT;
159 		else if (!server && 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_uint8(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_uint8(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_uint8(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_uint8(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);
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);
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 }
488