xref: /src/sys/fs/nfs/nfs_commonacl.c (revision 9f49f436a9ec9441dacae8117280a83ddea7b9c6)
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 #include <fs/nfs/nfsport.h>
32 
33 extern int nfsrv_useacl;
34 
35 static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
36     __enum_uint8(vtype) type, acl_perm_t *permp);
37 
38 /*
39  * Handle xdr for an NFSv4 ace.
40  */
41 int
nfsrv_dissectace(struct nfsrv_descript * nd,struct acl_entry * acep,bool server,int * aceerrp,int * acesizep)42 nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep,
43     bool server, int *aceerrp, int *acesizep)
44 {
45 	u_int32_t *tl;
46 	int len, gotid = 0, owner = 0, error = 0, aceerr = 0;
47 	u_char *name, namestr[NFSV4_SMALLSTR + 1];
48 	u_int32_t flag, mask, acetype;
49 	gid_t gid;
50 	uid_t uid;
51 
52 	*aceerrp = 0;
53 	acep->ae_flags = 0;
54 	NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
55 	acetype = fxdr_unsigned(u_int32_t, *tl++);
56 	flag = fxdr_unsigned(u_int32_t, *tl++);
57 	mask = fxdr_unsigned(u_int32_t, *tl++);
58 	len = fxdr_unsigned(int, *tl);
59 	/*
60 	 * The RFCs do not specify a limit to the length of the "who", but
61 	 * NFSV4_OPAQUELIMIT (1024) should be sufficient.
62 	 */
63 	if (len < 0 || len > NFSV4_OPAQUELIMIT) {
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_EVERYONE;	/* Avoid panics. */
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 (!server && acetype == NFSV4ACE_AUDITTYPE)
156 			acep->ae_entry_type = ACL_ENTRY_TYPE_AUDIT;
157 		else if (!server && 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 static acl_tag_t nfsv4_to_posixacltag[NFSV4_POSIXACL_TAG_OTHER + 1] =
185     { ACL_UNDEFINED_TAG, ACL_USER_OBJ, ACL_USER, ACL_GROUP_OBJ,
186     ACL_GROUP, ACL_MASK, ACL_OTHER };
187 
188 /*
189  * Handle xdr for a POSIX draft ace.
190  */
191 int
nfsrv_dissectposixace(struct nfsrv_descript * nd,struct acl_entry * acep,bool server,int * aceerrp,int * acesizep)192 nfsrv_dissectposixace(struct nfsrv_descript *nd, struct acl_entry *acep,
193     bool server, int *aceerrp, int *acesizep)
194 {
195 	uint32_t *tl, tag;
196 	int len, error = 0, aceerr = 0;
197 	u_char *name, namestr[NFSV4_SMALLSTR + 1];
198 	gid_t gid;
199 	uid_t uid;
200 
201 	*aceerrp = 0;
202 	NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
203 	tag = fxdr_unsigned(uint32_t, *tl++);
204 	acep->ae_perm = fxdr_unsigned(acl_perm_t, *tl++);
205 	len = fxdr_unsigned(int, *tl);
206 	/*
207 	 * The RFCs do not specify a limit to the length of the "who", but
208 	 * NFSV4_OPAQUELIMIT (1024) should be sufficient.
209 	 */
210 	if (len < 0 || len > NFSV4_OPAQUELIMIT) {
211 		error = NFSERR_BADXDR;
212 		goto nfsmout;
213 	}
214 	if (tag < NFSV4_POSIXACL_TAG_USER_OBJ ||
215 	    tag > NFSV4_POSIXACL_TAG_OTHER) {
216 		error = NFSERR_ATTRNOTSUPP;
217 		goto nfsmout;
218 	}
219 	acep->ae_tag = nfsv4_to_posixacltag[tag];
220 	if (len > NFSV4_SMALLSTR)
221 		name = malloc(len + 1, M_NFSSTRING, M_WAITOK);
222 	else
223 		name = namestr;
224 	if (len > 0)
225 		error = nfsrv_mtostr(nd, name, len);
226 	if (error != 0) {
227 		if (len > NFSV4_SMALLSTR)
228 			free(name, M_NFSSTRING);
229 		goto nfsmout;
230 	}
231 	switch (acep->ae_tag) {
232 	case ACL_USER:
233 		aceerr = nfsv4_strtouid(nd, name, len, &uid);
234 		if (aceerr == 0)
235 			acep->ae_id = uid;
236 		break;
237 	case ACL_GROUP:
238 		aceerr = nfsv4_strtogid(nd, name, len, &gid);
239 		if (aceerr == 0)
240 			acep->ae_id = (uid_t)gid;
241 		break;
242 	case ACL_USER_OBJ:
243 	case ACL_GROUP_OBJ:
244 	case ACL_MASK:
245 	case ACL_OTHER:
246 		break;
247 	default:
248 		aceerr = NFSERR_ATTRNOTSUPP;
249 	}
250 	if (len > NFSV4_SMALLSTR)
251 		free(name, M_NFSSTRING);
252 
253 	*aceerrp = aceerr;
254 	if (acesizep != NULL)
255 		*acesizep = NFSM_RNDUP(len) + (3 * NFSX_UNSIGNED);
256 	error = 0;
257 nfsmout:
258 	NFSEXITCODE(error);
259 	return (error);
260 }
261 
262 /*
263  * Turn an NFSv4 ace mask into R/W/X flag bits.
264  */
265 static int
nfsrv_acemasktoperm(u_int32_t acetype,u_int32_t mask,int owner,__enum_uint8 (vtype)type,acl_perm_t * permp)266 nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner,
267     __enum_uint8(vtype) type, acl_perm_t *permp)
268 {
269 	acl_perm_t perm = 0x0;
270 	int error = 0;
271 
272 	if (mask & NFSV4ACE_READDATA) {
273 		mask &= ~NFSV4ACE_READDATA;
274 		perm |= ACL_READ_DATA;
275 	}
276 	if (mask & NFSV4ACE_LISTDIRECTORY) {
277 		mask &= ~NFSV4ACE_LISTDIRECTORY;
278 		perm |= ACL_LIST_DIRECTORY;
279 	}
280 	if (mask & NFSV4ACE_WRITEDATA) {
281 		mask &= ~NFSV4ACE_WRITEDATA;
282 		perm |= ACL_WRITE_DATA;
283 	}
284 	if (mask & NFSV4ACE_ADDFILE) {
285 		mask &= ~NFSV4ACE_ADDFILE;
286 		perm |= ACL_ADD_FILE;
287 	}
288 	if (mask & NFSV4ACE_APPENDDATA) {
289 		mask &= ~NFSV4ACE_APPENDDATA;
290 		perm |= ACL_APPEND_DATA;
291 	}
292 	if (mask & NFSV4ACE_ADDSUBDIRECTORY) {
293 		mask &= ~NFSV4ACE_ADDSUBDIRECTORY;
294 		perm |= ACL_ADD_SUBDIRECTORY;
295 	}
296 	if (mask & NFSV4ACE_READNAMEDATTR) {
297 		mask &= ~NFSV4ACE_READNAMEDATTR;
298 		perm |= ACL_READ_NAMED_ATTRS;
299 	}
300 	if (mask & NFSV4ACE_WRITENAMEDATTR) {
301 		mask &= ~NFSV4ACE_WRITENAMEDATTR;
302 		perm |= ACL_WRITE_NAMED_ATTRS;
303 	}
304 	if (mask & NFSV4ACE_EXECUTE) {
305 		mask &= ~NFSV4ACE_EXECUTE;
306 		perm |= ACL_EXECUTE;
307 	}
308 	if (mask & NFSV4ACE_SEARCH) {
309 		mask &= ~NFSV4ACE_SEARCH;
310 		perm |= ACL_EXECUTE;
311 	}
312 	if (mask & NFSV4ACE_DELETECHILD) {
313 		mask &= ~NFSV4ACE_DELETECHILD;
314 		perm |= ACL_DELETE_CHILD;
315 	}
316 	if (mask & NFSV4ACE_READATTRIBUTES) {
317 		mask &= ~NFSV4ACE_READATTRIBUTES;
318 		perm |= ACL_READ_ATTRIBUTES;
319 	}
320 	if (mask & NFSV4ACE_WRITEATTRIBUTES) {
321 		mask &= ~NFSV4ACE_WRITEATTRIBUTES;
322 		perm |= ACL_WRITE_ATTRIBUTES;
323 	}
324 	if (mask & NFSV4ACE_DELETE) {
325 		mask &= ~NFSV4ACE_DELETE;
326 		perm |= ACL_DELETE;
327 	}
328 	if (mask & NFSV4ACE_READACL) {
329 		mask &= ~NFSV4ACE_READACL;
330 		perm |= ACL_READ_ACL;
331 	}
332 	if (mask & NFSV4ACE_WRITEACL) {
333 		mask &= ~NFSV4ACE_WRITEACL;
334 		perm |= ACL_WRITE_ACL;
335 	}
336 	if (mask & NFSV4ACE_WRITEOWNER) {
337 		mask &= ~NFSV4ACE_WRITEOWNER;
338 		perm |= ACL_WRITE_OWNER;
339 	}
340 	if (mask & NFSV4ACE_SYNCHRONIZE) {
341 		mask &= ~NFSV4ACE_SYNCHRONIZE;
342 		perm |= ACL_SYNCHRONIZE;
343 	}
344 	if (mask != 0) {
345 		error = NFSERR_ATTRNOTSUPP;
346 		goto out;
347 	}
348 	*permp = perm;
349 
350 out:
351 	NFSEXITCODE(error);
352 	return (error);
353 }
354 
355 /* local functions */
356 static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int,
357     __enum_uint8(vtype), int, int, struct acl_entry *);
358 static int nfsrv_buildposixace(struct nfsrv_descript *, u_char *, int,
359     struct acl_entry *);
360 
361 /*
362  * This function builds an NFSv4 ace.
363  */
364 static int
nfsrv_buildace(struct nfsrv_descript * nd,u_char * name,int namelen,__enum_uint8 (vtype)type,int group,int owner,struct acl_entry * ace)365 nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen,
366     __enum_uint8(vtype) type, int group, int owner, struct acl_entry *ace)
367 {
368 	u_int32_t *tl, aceflag = 0x0, acemask = 0x0, acetype;
369 	int full_len;
370 
371 	full_len = NFSM_RNDUP(namelen);
372 	NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED + full_len);
373 
374 	/*
375 	 * Fill in the ace type.
376 	 */
377 	if (ace->ae_entry_type & ACL_ENTRY_TYPE_ALLOW)
378 		acetype = NFSV4ACE_ALLOWEDTYPE;
379 	else if (ace->ae_entry_type & ACL_ENTRY_TYPE_DENY)
380 		acetype = NFSV4ACE_DENIEDTYPE;
381 	else if (ace->ae_entry_type & ACL_ENTRY_TYPE_AUDIT)
382 		acetype = NFSV4ACE_AUDITTYPE;
383 	else
384 		acetype = NFSV4ACE_ALARMTYPE;
385 	*tl++ = txdr_unsigned(acetype);
386 
387 	/*
388 	 * Set the flag bits from the ACL.
389 	 */
390 	if (ace->ae_flags & ACL_ENTRY_FILE_INHERIT)
391 		aceflag |= NFSV4ACE_FILEINHERIT;
392 	if (ace->ae_flags & ACL_ENTRY_DIRECTORY_INHERIT)
393 		aceflag |= NFSV4ACE_DIRECTORYINHERIT;
394 	if (ace->ae_flags & ACL_ENTRY_NO_PROPAGATE_INHERIT)
395 		aceflag |= NFSV4ACE_NOPROPAGATEINHERIT;
396 	if (ace->ae_flags & ACL_ENTRY_INHERIT_ONLY)
397 		aceflag |= NFSV4ACE_INHERITONLY;
398 	if (ace->ae_flags & ACL_ENTRY_SUCCESSFUL_ACCESS)
399 		aceflag |= NFSV4ACE_SUCCESSFULACCESS;
400 	if (ace->ae_flags & ACL_ENTRY_FAILED_ACCESS)
401 		aceflag |= NFSV4ACE_FAILEDACCESS;
402 	if (group)
403 		aceflag |= NFSV4ACE_IDENTIFIERGROUP;
404 	*tl++ = txdr_unsigned(aceflag);
405 	if (type == VDIR) {
406 		if (ace->ae_perm & ACL_LIST_DIRECTORY)
407 			acemask |= NFSV4ACE_LISTDIRECTORY;
408 		if (ace->ae_perm & ACL_ADD_FILE)
409 			acemask |= NFSV4ACE_ADDFILE;
410 		if (ace->ae_perm & ACL_ADD_SUBDIRECTORY)
411 			acemask |= NFSV4ACE_ADDSUBDIRECTORY;
412 		if (ace->ae_perm & ACL_READ_NAMED_ATTRS)
413 			acemask |= NFSV4ACE_READNAMEDATTR;
414 		if (ace->ae_perm & ACL_WRITE_NAMED_ATTRS)
415 			acemask |= NFSV4ACE_WRITENAMEDATTR;
416 		if (ace->ae_perm & ACL_EXECUTE)
417 			acemask |= NFSV4ACE_SEARCH;
418 		if (ace->ae_perm & ACL_DELETE_CHILD)
419 			acemask |= NFSV4ACE_DELETECHILD;
420 		if (ace->ae_perm & ACL_READ_ATTRIBUTES)
421 			acemask |= NFSV4ACE_READATTRIBUTES;
422 		if (ace->ae_perm & ACL_WRITE_ATTRIBUTES)
423 			acemask |= NFSV4ACE_WRITEATTRIBUTES;
424 		if (ace->ae_perm & ACL_DELETE)
425 			acemask |= NFSV4ACE_DELETE;
426 		if (ace->ae_perm & ACL_READ_ACL)
427 			acemask |= NFSV4ACE_READACL;
428 		if (ace->ae_perm & ACL_WRITE_ACL)
429 			acemask |= NFSV4ACE_WRITEACL;
430 		if (ace->ae_perm & ACL_WRITE_OWNER)
431 			acemask |= NFSV4ACE_WRITEOWNER;
432 		if (ace->ae_perm & ACL_SYNCHRONIZE)
433 			acemask |= NFSV4ACE_SYNCHRONIZE;
434 	} else {
435 		acemask = nfs_aceperm(ace->ae_perm);
436 	}
437 	*tl++ = txdr_unsigned(acemask);
438 	*tl++ = txdr_unsigned(namelen);
439 	if (full_len - namelen)
440 		*(tl + (namelen / NFSX_UNSIGNED)) = 0x0;
441 	NFSBCOPY(name, (caddr_t)tl, namelen);
442 	return (full_len + 4 * NFSX_UNSIGNED);
443 }
444 
445 /*
446  * Convert ae_perm to NFSv4 ACL acemask4 for regular files.
447  */
448 uint32_t
nfs_aceperm(acl_perm_t ae_perm)449 nfs_aceperm(acl_perm_t ae_perm)
450 {
451 	uint32_t acemask = 0x0;
452 
453 	if (ae_perm & ACL_READ_DATA)
454 		acemask |= NFSV4ACE_READDATA;
455 	if (ae_perm & ACL_WRITE_DATA)
456 		acemask |= NFSV4ACE_WRITEDATA;
457 	if (ae_perm & ACL_APPEND_DATA)
458 		acemask |= NFSV4ACE_APPENDDATA;
459 	if (ae_perm & ACL_READ_NAMED_ATTRS)
460 		acemask |= NFSV4ACE_READNAMEDATTR;
461 	if (ae_perm & ACL_WRITE_NAMED_ATTRS)
462 		acemask |= NFSV4ACE_WRITENAMEDATTR;
463 	if (ae_perm & ACL_EXECUTE)
464 		acemask |= NFSV4ACE_EXECUTE;
465 	if (ae_perm & ACL_READ_ATTRIBUTES)
466 		acemask |= NFSV4ACE_READATTRIBUTES;
467 	if (ae_perm & ACL_WRITE_ATTRIBUTES)
468 		acemask |= NFSV4ACE_WRITEATTRIBUTES;
469 	if (ae_perm & ACL_DELETE)
470 		acemask |= NFSV4ACE_DELETE;
471 	if (ae_perm & ACL_READ_ACL)
472 		acemask |= NFSV4ACE_READACL;
473 	if (ae_perm & ACL_WRITE_ACL)
474 		acemask |= NFSV4ACE_WRITEACL;
475 	if (ae_perm & ACL_WRITE_OWNER)
476 		acemask |= NFSV4ACE_WRITEOWNER;
477 	if (ae_perm & ACL_SYNCHRONIZE)
478 		acemask |= NFSV4ACE_SYNCHRONIZE;
479 	return (acemask);
480 }
481 
482 /*
483  * This function builds a POSIX draft ace.
484  */
485 static int
nfsrv_buildposixace(struct nfsrv_descript * nd,u_char * name,int namelen,struct acl_entry * ace)486 nfsrv_buildposixace(struct nfsrv_descript *nd, u_char *name, int namelen,
487     struct acl_entry *ace)
488 {
489 	uint32_t *tl;
490 	int full_len;
491 
492 	full_len = NFSM_RNDUP(namelen);
493 	NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED + full_len);
494 
495 	/*
496 	 * Fill in the ace tag.
497 	 */
498 	switch (ace->ae_tag) {
499 	case ACL_USER_OBJ:
500 		*tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_USER_OBJ);
501 		break;
502 	case ACL_USER:
503 		*tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_USER);
504 		break;
505 	case ACL_GROUP_OBJ:
506 		*tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_GROUP_OBJ);
507 		break;
508 	case ACL_GROUP:
509 		*tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_GROUP);
510 		break;
511 	case ACL_MASK:
512 		*tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_MASK);
513 		break;
514 	case ACL_OTHER:
515 		*tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_OTHER);
516 		break;
517 	default:
518 		printf("nfsrv_buildposixace: bad ae_tag 0x%x\n", ace->ae_tag);
519 		*tl++ = txdr_unsigned(0);
520 	}
521 
522 	/*
523 	 * Fill in the permission bits.
524 	 */
525 	*tl++ = txdr_unsigned(ace->ae_perm);
526 	*tl++ = txdr_unsigned(namelen);
527 	if (namelen > 0) {
528 		if (full_len - namelen)
529 			*(tl + (namelen / NFSX_UNSIGNED)) = 0x0;
530 		memcpy(tl, name, namelen);
531 	}
532 	return (full_len + 3 * NFSX_UNSIGNED);
533 }
534 
535 /*
536  * Build an NFSv4 ACL.
537  */
538 int
nfsrv_buildacl(struct nfsrv_descript * nd,NFSACL_T * aclp,__enum_uint8 (vtype)type,NFSPROC_T * p)539 nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, __enum_uint8(vtype) type,
540     NFSPROC_T *p)
541 {
542 	int i, entrycnt = 0, retlen;
543 	u_int32_t *entrycntp;
544 	int isowner, isgroup, namelen, malloced;
545 	u_char *name, namestr[NFSV4_SMALLSTR];
546 
547 	NFSM_BUILD(entrycntp, u_int32_t *, NFSX_UNSIGNED);
548 	retlen = NFSX_UNSIGNED;
549 	/*
550 	 * Loop through the acl entries, building each one.
551 	 */
552 	for (i = 0; i < aclp->acl_cnt; i++) {
553 		isowner = isgroup = malloced = 0;
554 		switch (aclp->acl_entry[i].ae_tag) {
555 		case ACL_USER_OBJ:
556 			isowner = 1;
557 			name = "OWNER@";
558 			namelen = 6;
559 			break;
560 		case ACL_GROUP_OBJ:
561 			isgroup = 1;
562 			name = "GROUP@";
563 			namelen = 6;
564 			break;
565 		case ACL_EVERYONE:
566 			name = "EVERYONE@";
567 			namelen = 9;
568 			break;
569 		case ACL_USER:
570 			name = namestr;
571 			nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name,
572 			    &namelen);
573 			if (name != namestr)
574 				malloced = 1;
575 			break;
576 		case ACL_GROUP:
577 			isgroup = 1;
578 			name = namestr;
579 			nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name,
580 			    &namelen);
581 			if (name != namestr)
582 				malloced = 1;
583 			break;
584 		default:
585 			continue;
586 		}
587 		retlen += nfsrv_buildace(nd, name, namelen, type, isgroup,
588 		    isowner, &aclp->acl_entry[i]);
589 		entrycnt++;
590 		if (malloced)
591 			free(name, M_NFSSTRING);
592 	}
593 	*entrycntp = txdr_unsigned(entrycnt);
594 	return (retlen);
595 }
596 
597 /*
598  * Build a POSIX draft ACL.
599  */
600 int
nfsrv_buildposixacl(struct nfsrv_descript * nd,NFSACL_T * aclp,acl_type_t acltype)601 nfsrv_buildposixacl(struct nfsrv_descript *nd, NFSACL_T *aclp,
602     acl_type_t acltype)
603 {
604 	int i, entrycnt = 0, retlen;
605 	uint32_t *entrycntp;
606 	unsigned int cnt;
607 	int namelen;
608 	u_char *name, namestr[NFSV4_SMALLSTR];
609 	bool malloced;
610 
611 	NFSM_BUILD(entrycntp, uint32_t *, NFSX_UNSIGNED);
612 	retlen = NFSX_UNSIGNED;
613 	cnt = 0;
614 	if (aclp != NULL)
615 		cnt = aclp->acl_cnt;
616 	/*
617 	 * Loop through the acl entries, building each one.
618 	 */
619 	for (i = 0; i < cnt; i++) {
620 		malloced = false;
621 		switch (aclp->acl_entry[i].ae_tag) {
622 		case ACL_USER_OBJ:
623 		case ACL_GROUP_OBJ:
624 		case ACL_OTHER:
625 		case ACL_MASK:
626 			namelen = 0;
627 			break;
628 		case ACL_USER:
629 			name = namestr;
630 			nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name,
631 			    &namelen);
632 			if (name != namestr)
633 				malloced = true;
634 			break;
635 		case ACL_GROUP:
636 			name = namestr;
637 			nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name,
638 			    &namelen);
639 			if (name != namestr)
640 				malloced = true;
641 			break;
642 		default:
643 			continue;
644 		}
645 		retlen += nfsrv_buildposixace(nd, name, namelen,
646 		    &aclp->acl_entry[i]);
647 		entrycnt++;
648 		if (malloced)
649 			free(name, M_NFSSTRING);
650 	}
651 	*entrycntp = txdr_unsigned(entrycnt);
652 	return (retlen);
653 }
654 
655 /*
656  * Compare two NFSv4 acls.
657  * Return 0 if they are the same, 1 if not the same.
658  */
659 int
nfsrv_compareacl(NFSACL_T * aclp1,NFSACL_T * aclp2)660 nfsrv_compareacl(NFSACL_T *aclp1, NFSACL_T *aclp2)
661 {
662 	int i;
663 	struct acl_entry *acep1, *acep2;
664 
665 	if (aclp1->acl_cnt != aclp2->acl_cnt)
666 		return (1);
667 	acep1 = aclp1->acl_entry;
668 	acep2 = aclp2->acl_entry;
669 	for (i = 0; i < aclp1->acl_cnt; i++) {
670 		if (acep1->ae_tag != acep2->ae_tag)
671 			return (1);
672 		switch (acep1->ae_tag) {
673 		case ACL_GROUP:
674 		case ACL_USER:
675 			if (acep1->ae_id != acep2->ae_id)
676 				return (1);
677 			/* fall through */
678 		case ACL_USER_OBJ:
679 		case ACL_GROUP_OBJ:
680 		case ACL_OTHER:
681 			if (acep1->ae_perm != acep2->ae_perm)
682 				return (1);
683 		}
684 		acep1++;
685 		acep2++;
686 	}
687 	return (0);
688 }
689