xref: /illumos-gate/usr/src/lib/libsec/common/acl.y (revision a194faf8907a6722dcf10ad16c6ca72c9b7bd0ba)
1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma	ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <acl_common.h>
29 #include <aclutils.h>
30 
31 extern int yyinteractive;
32 extern acl_t *yyacl;
33 %}
34 
35 %union {
36 	char *str;
37 	int val;
38 	struct acl_perm_type acl_perm;
39 	ace_t ace;
40 	aclent_t aclent;
41 	acl_t *acl;
42 }
43 
44 
45 %token USER_TOK GROUP_TOK MASK_TOK OTHER_TOK OWNERAT_TOK
46 %token GROUPAT_TOK EVERYONEAT_TOK DEFAULT_USER_TOK DEFAULT_GROUP_TOK
47 %token DEFAULT_MASK_TOK DEFAULT_OTHER_TOK COLON COMMA NL SLASH
48 %token <str> IDNAME PERM_TOK INHERIT_TOK
49 %token <val> ID ERROR ACE_PERM ACE_INHERIT ENTRY_TYPE ACCESS_TYPE
50 
51 %type <str> idname
52 %type <acl_perm> perms perm aclent_perm ace_perms
53 %type <acl> acl_entry
54 %type <ace> ace
55 %type <aclent> aclent
56 %type <val> iflags verbose_iflag compact_iflag access_type id entry_type
57 
58 %left ERROR COLON
59 
60 %%
61 
62 acl:	acl_entry NL
63 	{
64 		yyacl = $1;
65 		return (0);
66 	}
67 
68 	/* This seems illegal, but the old aclfromtext() allows it */
69 	| acl_entry COMMA NL
70 	{
71 		yyacl = $1;
72 		return (0);
73 	}
74 	| acl_entry COMMA acl
75 	{
76 		yyacl = $1;
77 		return (0);
78 	}
79 
80 acl_entry: ace
81 	{
82 		ace_t *acep;
83 
84 		if (yyacl == NULL) {
85 			yyacl = acl_alloc(ACE_T);
86 			if (yyacl == NULL) {
87 				yycleanup();
88 				return (EACL_MEM_ERROR);
89 			}
90 		}
91 
92 		$$ = yyacl;
93 		if ($$->acl_type == ACLENT_T) {
94 			acl_error(dgettext(TEXT_DOMAIN,
95 			    "Cannot have POSIX draft ACL entries"
96 			    " with NFSv4/ZFS ACL entries.\n"));
97 			acl_free(yyacl);
98 			yyacl = NULL;
99 			yycleanup();
100 			return (EACL_DIFF_TYPE);
101 		}
102 
103 		$$->acl_aclp = realloc($$->acl_aclp,
104 		    ($$->acl_entry_size * ($$->acl_cnt + 1)));
105 		if ($$->acl_aclp == NULL) {
106 			free (yyacl);
107 			yycleanup();
108 			return (EACL_MEM_ERROR);
109 		}
110 		acep = $$->acl_aclp;
111 		acep[$$->acl_cnt] = $1;
112 		$$->acl_cnt++;
113 		yycleanup();
114 	}
115 	| aclent
116 	{
117 		aclent_t *aclent;
118 
119 		if (yyacl == NULL) {
120 			yyacl = acl_alloc(ACLENT_T);
121 			if (yyacl == NULL) {
122 				yycleanup();
123 				return (EACL_MEM_ERROR);
124 			}
125 		}
126 
127 		$$ = yyacl;
128 		if ($$->acl_type == ACE_T) {
129 			acl_error(dgettext(TEXT_DOMAIN,
130 			    "Cannot have NFSv4/ZFS ACL entries"
131 			    " with POSIX draft ACL entries.\n"));
132 			acl_free(yyacl);
133 			yyacl = NULL;
134 			yycleanup();
135 			return (EACL_DIFF_TYPE);
136 		}
137 
138 		$$->acl_aclp = realloc($$->acl_aclp,
139 		    ($$->acl_entry_size  * ($$->acl_cnt +1)));
140 		if ($$->acl_aclp == NULL) {
141 			free (yyacl);
142 			yycleanup();
143 			return (EACL_MEM_ERROR);
144 		}
145 		aclent = $$->acl_aclp;
146 		aclent[$$->acl_cnt] = $1;
147 		$$->acl_cnt++;
148 		yycleanup();
149 	}
150 
151 ace:	entry_type idname ace_perms access_type
152 	{
153 		int error;
154 		int id;
155 		int mask;
156 
157 		error = get_id($1, $2, &id);
158 		if (error) {
159 			acl_error(dgettext(TEXT_DOMAIN,
160 			    "Invalid user %s specified.\n"), $2);
161 			yycleanup();
162 			return (EACL_INVALID_USER_GROUP);
163 		}
164 
165 		$$.a_who = id;
166 		$$.a_flags = ace_entry_type($1);
167 		error = ace_perm_mask(&$3, &$$.a_access_mask);
168 		if (error) {
169 			yycleanup();
170 			return (error);
171 		}
172 		$$.a_type = $4;
173 
174 	}
175 	| entry_type idname ace_perms access_type COLON id
176 	{
177 		int error;
178 		int id;
179 
180 		if (yyinteractive) {
181 			acl_error(dgettext(TEXT_DOMAIN,
182 			    "Extra fields on the end of "
183 			    "ACL specification.\n"));
184 			yycleanup();
185 			return (EACL_UNKNOWN_DATA);
186 		}
187 		error = get_id($1, $2, &id);
188 		if (error) {
189 			$$.a_who = $6;
190 		} else {
191 			$$.a_who = id;
192 		}
193 		$$.a_flags = ace_entry_type($1);
194 		error = ace_perm_mask(&$3, &$$.a_access_mask);
195 		if (error) {
196 			yycleanup();
197 			return (error);
198 		}
199 		$$.a_type = $4;
200 	}
201 	| entry_type idname ace_perms iflags access_type
202 	{
203 		int error;
204 		int id;
205 
206 		error = get_id($1, $2, &id);
207 		if (error) {
208 			acl_error(dgettext(TEXT_DOMAIN,
209 			    "Invalid user %s specified.\n"), $2);
210 			yycleanup();
211 			return (EACL_INVALID_USER_GROUP);
212 		}
213 
214 		$$.a_who = id;
215 		$$.a_flags = ace_entry_type($1);
216 		error = ace_perm_mask(&$3, &$$.a_access_mask);
217 		if (error) {
218 			yycleanup();
219 			return (error);
220 		}
221 		$$.a_type = $5;
222 		$$.a_flags |= $4;
223 	}
224 	| entry_type idname ace_perms iflags access_type COLON id
225 	{
226 		int error;
227 		int  id;
228 
229 		if (yyinteractive) {
230 			acl_error(dgettext(TEXT_DOMAIN,
231 			    "Extra fields on the end of "
232 			    "ACL specification.\n"));
233 			yycleanup();
234 			return (EACL_UNKNOWN_DATA);
235 		}
236 		error = get_id($1, $2, &id);
237 		if (error) {
238 			$$.a_who = $7;
239 		} else {
240 			$$.a_who = id;
241 		}
242 
243 		$$.a_flags = ace_entry_type($1);
244 		error = ace_perm_mask(&$3, &$$.a_access_mask);
245 		if (error) {
246 			yycleanup();
247 			return (error);
248 		}
249 
250 		$$.a_type = $5;
251 		$$.a_flags |= $4;
252 	}
253 	| entry_type ace_perms access_type
254 	{
255 		int error;
256 
257 		$$.a_who = -1;
258 		$$.a_flags = ace_entry_type($1);
259 		error = ace_perm_mask(&$2, &$$.a_access_mask);
260 		if (error) {
261 			yycleanup();
262 			return (error);
263 		}
264 		$$.a_type = $3;
265 	}
266 	| entry_type ace_perms access_type COLON id
267 	{
268 		yycleanup();
269 		if (yyinteractive) {
270 			acl_error(dgettext(TEXT_DOMAIN,
271 			    "Extra fields on the end of "
272 			    "ACL specification.\n"));
273 			return (EACL_UNKNOWN_DATA);
274 		}
275 
276 		return (EACL_ENTRY_ERROR);
277 	}
278 	| entry_type ace_perms iflags access_type
279 	{
280 		int error;
281 
282 		$$.a_who = -1;
283 		$$.a_flags = ace_entry_type($1);
284 		error = ace_perm_mask(&$2, &$$.a_access_mask);
285 		if (error) {
286 			yycleanup();
287 			return (error);
288 		}
289 		$$.a_type = $4;
290 		$$.a_flags |= $3;
291 
292 	}
293 	| entry_type ace_perms iflags access_type COLON id
294 	{
295 		yycleanup();
296 		if (yyinteractive) {
297 			acl_error(dgettext(TEXT_DOMAIN,
298 			    "Extra fields on the end of "
299 			    "ACL specification.\n"));
300 			return (EACL_UNKNOWN_DATA);
301 		}
302 		return (EACL_ENTRY_ERROR);
303 	}
304 
305 aclent: entry_type idname aclent_perm	/* user or group */
306 	{
307 		int error;
308 		int id;
309 
310 		error = get_id($1, $2, &id);
311 		if (error) {
312 			acl_error(dgettext(TEXT_DOMAIN,
313 			    "Invalid user '%s' specified.\n"), $2);
314 			yycleanup();
315 			return (EACL_INVALID_USER_GROUP);
316 		}
317 
318 		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
319 		if (error) {
320 			acl_error(dgettext(TEXT_DOMAIN,
321 			    "Invalid permission(s) '%s' specified.\n"),
322 			    $3.perm_str);
323 			yycleanup();
324 			return (error);
325 		}
326 		$$.a_id = id;
327 		error = aclent_entry_type($1, 0, &$$.a_type);
328 		if (error) {
329 			acl_error(
330 			    dgettext(TEXT_DOMAIN,
331 			    "Invalid ACL entry type '%s' specified.\n"), $1);
332 			yycleanup();
333 			return (error);
334 		}
335 	}
336 	| entry_type COLON aclent_perm		/* owner group other */
337 	{
338 		int error;
339 
340 		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
341 		if (error) {
342 			acl_error(dgettext(TEXT_DOMAIN,
343 			    "Invalid permission(s) '%s' specified.\n"),
344 			    $3.perm_str);
345 			yycleanup();
346 			return (error);
347 		}
348 		$$.a_id = -1;
349 		error = aclent_entry_type($1, 1, &$$.a_type);
350 		if (error) {
351 			acl_error(
352 			    dgettext(TEXT_DOMAIN,
353 			    "Invalid ACL entry type '%s' specified.\n"), $1);
354 			yycleanup();
355 			return (error);
356 		}
357 	}
358 	| entry_type COLON aclent_perm COLON id
359 	{
360 		yycleanup();
361 		if (yyinteractive) {
362 			acl_error(dgettext(TEXT_DOMAIN,
363 			    "Extra fields on the end of ACL specification.\n"));
364 			return (EACL_UNKNOWN_DATA);
365 		}
366 		return (EACL_ENTRY_ERROR);
367 	}
368 	| entry_type idname aclent_perm COLON id 	/* user or group */
369 	{
370 		int error;
371 		int id;
372 
373 		if (yyinteractive) {
374 			acl_error(dgettext(TEXT_DOMAIN,
375 			    "Extra fields on the end of ACL specification.\n"));
376 			yycleanup();
377 			return (EACL_UNKNOWN_DATA);
378 		}
379 		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
380 		if (error) {
381 			acl_error(dgettext(TEXT_DOMAIN,
382 			    "Invalid permission(s) '%s' specified.\n"),
383 			    $3.perm_str);
384 			yycleanup();
385 			return (error);
386 		}
387 		error = get_id($1, $2, &id);
388 		if (error)
389 			$$.a_id = $5;
390 		else
391 			$$.a_id = id;
392 
393 		error = aclent_entry_type($1, 0, &$$.a_type);
394 		if (error) {
395 			acl_error(
396 			    dgettext(TEXT_DOMAIN,
397 			    "Invalid ACL entry type '%s' specified.\n"), $1);
398 			yycleanup();
399 			return (error);
400 		}
401 	}
402 	| entry_type aclent_perm  /* mask entry */
403 	{
404 		int error;
405 
406 		error = compute_aclent_perms($2.perm_str, &$$.a_perm);
407 		if (error) {
408 			acl_error(dgettext(TEXT_DOMAIN,
409 			    "Invalid permission(s) '%s' specified.\n"),
410 			    $2.perm_str);
411 			yycleanup();
412 			return (error);
413 		}
414 		$$.a_id = -1;
415 		error = aclent_entry_type($1, 0, &$$.a_type);
416 		if (error) {
417 			acl_error(
418 			    dgettext(TEXT_DOMAIN,
419 			    "Invalid ACL entry type specified %d.\n"),
420 			    error);
421 			yycleanup();
422 			return (error);
423 		}
424 	}
425 	| entry_type aclent_perm COLON id
426 	{
427 		yycleanup();
428 		if (yyinteractive) {
429 			acl_error(dgettext(TEXT_DOMAIN,
430 			    "Extra fields on the end of ACL specification.\n"));
431 			return (EACL_UNKNOWN_DATA);
432 		}
433 		return (EACL_ENTRY_ERROR);
434 	}
435 
436 iflags: compact_iflag COLON {$$ = $1;}
437 	| verbose_iflag COLON {$$ = $1;}
438 	| COLON {$$ = 0;}
439 
440 compact_iflag : INHERIT_TOK
441 	{
442 		int error;
443 		uint32_t iflags;
444 
445 		error = compute_ace_inherit($1, &iflags);
446 		if (error) {
447 			acl_error(dgettext(TEXT_DOMAIN,
448 			    "Invalid inheritance flags '%s' specified.\n"), $1);
449 			yycleanup();
450 			return (error);
451 		}
452 		$$ = iflags;
453 	}
454 	| INHERIT_TOK SLASH verbose_iflag
455 	{
456 		acl_error(dgettext(TEXT_DOMAIN,
457 		    "Can't mix compact inherit flags with"
458 		    " verbose inheritance flags.\n"));
459 		yycleanup();
460 		return (EACL_INHERIT_ERROR);
461 	}
462 
463 verbose_iflag: ACE_INHERIT	{$$ |= $1;}
464 	| ACE_INHERIT SLASH verbose_iflag {$$ = $1 | $3;}
465 	| ACE_INHERIT SLASH compact_iflag
466 	{
467 		acl_error(dgettext(TEXT_DOMAIN,
468 		    "Can't mix verbose inherit flags with"
469 		    " compact inheritance flags.\n"));
470 		yycleanup();
471 		return (EACL_INHERIT_ERROR);
472 	}
473 	| ACE_INHERIT SLASH ACCESS_TYPE
474 	{
475 		acl_error(dgettext(TEXT_DOMAIN,
476 		    "Inheritance flags can't be mixed with access type.\n"));
477 		yycleanup();
478 		return (EACL_INHERIT_ERROR);
479 	}
480 	| ACE_INHERIT SLASH ERROR
481 	{
482 		yycleanup();
483 		return ($3);
484 	}
485 
486 aclent_perm: PERM_TOK
487 	{
488 		$$.perm_style = PERM_TYPE_UNKNOWN;
489 		$$.perm_str = $1;
490 		$$.perm_val = 0;
491 	}
492 	| PERM_TOK ERROR
493 	{
494 		acl_error(dgettext(TEXT_DOMAIN,
495 		    "ACL entry permissions are incorrectly specified.\n"));
496 		yycleanup();
497 		return ($2);
498 	}
499 
500 access_type: ACCESS_TYPE {$$ = $1;}
501 	| ERROR
502 	{
503 		yycleanup();
504 		return ($1);
505 	}
506 
507 id: ID {$$ = $1;}
508   	| COLON
509 	{
510 		acl_error(dgettext(TEXT_DOMAIN,
511 		    "Invalid uid/gid specified.\nThe field"
512 		    " should be a numeric value.\n"));
513 		yycleanup();
514 		return (EACL_UNKNOWN_DATA);
515 	}
516 	| ERROR
517 	{
518 		yycleanup();
519 		return ($1);
520 	}
521 
522 ace_perms: perm {$$ = $1;}
523 	| aclent_perm COLON {$$ = $1;}
524 	| ERROR
525 	{
526 		yycleanup();
527 		return ($1);
528 	}
529 
530 perm: perms COLON {$$ = $1;}
531     	| COLON {$$.perm_style = PERM_TYPE_EMPTY;}
532 
533 perms: ACE_PERM
534      	{
535 		$$.perm_style = PERM_TYPE_ACE;
536 		$$.perm_val |= $1;
537 	}
538 	| ACE_PERM SLASH perms
539 	{
540 		$$.perm_style = PERM_TYPE_ACE;
541 		$$.perm_val = $1 | $3.perm_val;
542 	}
543 	| ACE_PERM SLASH aclent_perm
544 	{
545 
546 		acl_error(dgettext(TEXT_DOMAIN,
547 		   "Can't mix verbose permissions with"
548 		    " compact permission.\n"));
549 		yycleanup();
550 		return (EACL_PERM_MASK_ERROR);
551 
552 	}
553 	| ACE_PERM SLASH ERROR
554 	{
555 		yycleanup();
556 		return ($3);
557 	}
558 
559 
560 idname: IDNAME {$$ = $1;}
561 
562 entry_type: ENTRY_TYPE {$$ = $1;}
563 	| ERROR
564 	{
565 		yycleanup();
566 		return ($1);
567 	}
568