xref: /illumos-gate/usr/src/lib/libsec/common/acl.y (revision ea8dc4b6d2251b437950c0056bc626b311c73c27)
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 2006 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 <sys/acl.h>
29 #include <aclutils.h>
30 
31 extern int yyinteractive;
32 extern acl_t *yyacl;
33 %}
34 
35 
36 %union {
37 	char *str;
38 	int val;
39 	struct acl_perm_type acl_perm;
40 	ace_t ace;
41 	aclent_t aclent;
42 	acl_t *acl;
43 }
44 
45 
46 %token USER_TOK GROUP_TOK MASK_TOK OTHER_TOK OWNERAT_TOK
47 %token GROUPAT_TOK EVERYONEAT_TOK DEFAULT_USER_TOK DEFAULT_GROUP_TOK
48 %token DEFAULT_MASK_TOK DEFAULT_OTHER_TOK COLON COMMA NL SLASH
49 %token <str> IDNAME PERM_TOK INHERIT_TOK
50 %token <val> ID ERROR ACE_PERM ACE_INHERIT ENTRY_TYPE ACCESS_TYPE
51 
52 %type <str> idname
53 %type <acl_perm> perms perm aclent_perm ace_perms
54 %type <acl> acl_entry
55 %type <ace> ace
56 %type <aclent> aclent
57 %type <val> iflags verbose_iflag compact_iflag access_type id entry_type
58 
59 %left ERROR COLON
60 
61 %%
62 
63 acl:	acl_entry NL
64 	{
65 		yyacl = $1;
66 		return (0);
67 	}
68 
69 	/* This seems illegal, but the old aclfromtext() allows it */
70 	| acl_entry COMMA NL
71 	{
72 		yyacl = $1;
73 		return (0);
74 	}
75 	| acl_entry COMMA acl
76 	{
77 		yyacl = $1;
78 		return (0);
79 	}
80 
81 acl_entry: ace
82 	{
83 		ace_t *acep;
84 
85 		if (yyacl == NULL) {
86 			yyacl = acl_alloc(ACE_T);
87 			if (yyacl == NULL)
88 				return (EACL_MEM_ERROR);
89 		}
90 
91 		$$ = yyacl;
92 		if ($$->acl_type == ACLENT_T) {
93 			acl_error(gettext("Cannot have POSIX draft ACL entries"
94 			     " with NFSv4/ZFS ACL entries.\n"));
95 			acl_free(yyacl);
96 			yyacl = NULL;
97 			return (EACL_DIFF_TYPE);
98 		}
99 
100 		$$->acl_aclp = realloc($$->acl_aclp,
101 		    ($$->acl_entry_size * ($$->acl_cnt + 1)));
102 		if ($$->acl_aclp == NULL) {
103 			free (yyacl);
104 			return (EACL_MEM_ERROR);
105 		}
106 		acep = $$->acl_aclp;
107 		acep[$$->acl_cnt] = $1;
108 		$$->acl_cnt++;
109 	}
110 	| aclent
111 	{
112 		aclent_t *aclent;
113 
114 		if (yyacl == NULL) {
115 			yyacl = acl_alloc(ACLENT_T);
116 			if (yyacl == NULL)
117 				return (EACL_MEM_ERROR);
118 		}
119 
120 		$$ = yyacl;
121 		if ($$->acl_type == ACE_T) {
122 			acl_error(gettext("Cannot have NFSv4/ZFS ACL entries"
123 			     " with POSIX draft ACL entries.\n"));
124 			acl_free(yyacl);
125 			yyacl = NULL;
126 			return (EACL_DIFF_TYPE);
127 		}
128 
129 		$$->acl_aclp = realloc($$->acl_aclp,
130 		    ($$->acl_entry_size  * ($$->acl_cnt +1)));
131 		if ($$->acl_aclp == NULL) {
132 			free (yyacl);
133 			return (EACL_MEM_ERROR);
134 		}
135 		aclent = $$->acl_aclp;
136 		aclent[$$->acl_cnt] = $1;
137 		$$->acl_cnt++;
138 	}
139 
140 ace:	entry_type idname ace_perms access_type
141 	{
142 		int error;
143 		int id;
144 		int mask;
145 
146 		error = get_id($1, $2, &id);
147 		if (error) {
148 			acl_error(gettext("Invalid user %s specified.\n"), $2);
149 			free($2);
150 			return (EACL_INVALID_USER_GROUP);
151 		}
152 
153 		$$.a_who = id;
154 		$$.a_flags = ace_entry_type($1);
155 		free($2);
156 		error = ace_perm_mask(&$3, &$$.a_access_mask);
157 		if (error)
158 			return (error);
159 		$$.a_type = $4;
160 
161 	}
162 	| entry_type idname ace_perms access_type COLON id
163 	{
164 		int error;
165 		int id;
166 
167 		if (yyinteractive) {
168 			acl_error(gettext("Extra fields on the end of "
169 			    "ACL specification.\n"));
170 			return (EACL_UNKNOWN_DATA);
171 		}
172 		error = get_id($1, $2, &id);
173 		if (error) {
174 			$$.a_who = $6;
175 		} else {
176 			$$.a_who = id;
177 		}
178 		$$.a_flags = ace_entry_type($1);
179 		free($2);
180 		error = ace_perm_mask(&$3, &$$.a_access_mask);
181 		if (error)
182 			return (error);
183 		$$.a_type = $4;
184 	}
185 	| entry_type idname ace_perms iflags access_type
186 	{
187 		int error;
188 		int id;
189 
190 		error = get_id($1, $2, &id);
191 		if (error) {
192 			acl_error(gettext("Invalid user %s specified.\n"), $2);
193 			free($2);
194 			return (EACL_INVALID_USER_GROUP);
195 		}
196 
197 		$$.a_who = id;
198 		$$.a_flags = ace_entry_type($1);
199 		free($2);
200 		error = ace_perm_mask(&$3, &$$.a_access_mask);
201 		if (error)
202 			return (error);
203 		$$.a_type = $5;
204 		$$.a_flags |= $4;
205 	}
206 	| entry_type idname ace_perms iflags access_type COLON id
207 	{
208 		int error;
209 		int  id;
210 
211 		if (yyinteractive) {
212 			acl_error(gettext("Extra fields on the end of "
213 			    "ACL specification.\n"));
214 			return (EACL_UNKNOWN_DATA);
215 		}
216 		error = get_id($1, $2, &id);
217 		if (error) {
218 			$$.a_who = $7;
219 		} else {
220 			$$.a_who = id;
221 		}
222 
223 		$$.a_flags = ace_entry_type($1);
224 		free($2);
225 		error = ace_perm_mask(&$3, &$$.a_access_mask);
226 		if (error)
227 			return (error);
228 
229 		$$.a_type = $5;
230 		$$.a_flags |= $4;
231 	}
232 	| entry_type ace_perms access_type
233 	{
234 		int error;
235 
236 		$$.a_who = -1;
237 		$$.a_flags = ace_entry_type($1);
238 		error = ace_perm_mask(&$2, &$$.a_access_mask);
239 		if (error) {
240 			return (error);
241 		}
242 		$$.a_type = $3;
243 	}
244 	| entry_type ace_perms access_type COLON id
245 	{
246 		if (yyinteractive) {
247 			acl_error(gettext("Extra fields on the end of "
248 			    "ACL specification.\n"));
249 			return (EACL_UNKNOWN_DATA);
250 		}
251 
252 		return (EACL_ENTRY_ERROR);
253 	}
254 	| entry_type ace_perms iflags access_type
255 	{
256 		int error;
257 
258 		$$.a_who = -1;
259 		$$.a_flags = ace_entry_type($1);
260 		error = ace_perm_mask(&$2, &$$.a_access_mask);
261 		if (error)
262 			return (error);
263 		$$.a_type = $4;
264 		$$.a_flags |= $3;
265 
266 	}
267 	| entry_type ace_perms iflags access_type COLON id
268 	{
269 		if (yyinteractive) {
270 			acl_error(gettext("Extra fields on the end of "
271 			    "ACL specification.\n"));
272 			return (EACL_UNKNOWN_DATA);
273 		}
274 		return (EACL_ENTRY_ERROR);
275 	}
276 
277 aclent: entry_type idname aclent_perm	/* user or group */
278 	{
279 		int error;
280 		int id;
281 
282 		error = get_id($1, $2, &id);
283 		if (error) {
284 			acl_error(gettext("Invalid user '%s' specified.\n"),
285 			    $2);
286 			free($2);
287 			return (EACL_INVALID_USER_GROUP);
288 		}
289 
290 		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
291 		if (error) {
292 			free($2);
293 			acl_error(gettext(
294 			    "Invalid permission(s) '%s' specified.\n"),
295 			    $3.perm_str);
296 			return (error);
297 		}
298 		$$.a_id = id;
299 		error = aclent_entry_type($1, 0, &$$.a_type);
300 		free($2);
301 		if (error) {
302 			acl_error(
303 			    gettext("Invalid ACL entry type '%s' "
304 			    "specified.\n"), $1);
305 			return (error);
306 		}
307 	}
308 	| entry_type COLON aclent_perm		/* owner group other */
309 	{
310 		int error;
311 
312 		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
313 		if (error) {
314 			acl_error(gettext(
315 			    "Invalid permission(s) '%s' specified.\n"),
316 			    $3.perm_str);
317 			return (error);
318 		}
319 		$$.a_id = -1;
320 		error = aclent_entry_type($1, 1, &$$.a_type);
321 		if (error) {
322 			acl_error(
323 			    gettext("Invalid ACL entry type '%s' specified.\n"),
324 			    $1);
325 			return (error);
326 		}
327 	}
328 	| entry_type COLON aclent_perm COLON id
329 	{
330 		if (yyinteractive) {
331 			acl_error(gettext("Extra fields on the end of "
332 			    "ACL specification.\n"));
333 			return (EACL_UNKNOWN_DATA);
334 		}
335 		return (EACL_ENTRY_ERROR);
336 	}
337 	| entry_type idname aclent_perm COLON id 	/* user or group */
338 	{
339 		int error;
340 		int id;
341 
342 		if (yyinteractive) {
343 			acl_error(gettext("Extra fields on the end of "
344 			    "ACL specification.\n"));
345 			return (EACL_UNKNOWN_DATA);
346 		}
347 		error = compute_aclent_perms($3.perm_str, &$$.a_perm);
348 		if (error) {
349 			free($2);
350 			acl_error(gettext(
351 			    "Invalid permission(s) '%s' specified.\n"),
352 			    $3.perm_str);
353 			return (error);
354 		}
355 		error = get_id($1, $2, &id);
356 		if (error)
357 			$$.a_id = $5;
358 		else
359 			$$.a_id = id;
360 
361 		error = aclent_entry_type($1, 0, &$$.a_type);
362 		free($2);
363 		if (error) {
364 			acl_error(
365 			    gettext("Invalid ACL entry type '%s' specified.\n"),
366 			    $1);
367 			return (error);
368 		}
369 	}
370 	| entry_type aclent_perm  /* mask entry */
371 	{
372 		int error;
373 
374 		error = compute_aclent_perms($2.perm_str, &$$.a_perm);
375 		if (error) {
376 			acl_error(gettext(
377 			    "Invalid permission(s) '%s' specified.\n"),
378 			    $2.perm_str);
379 			return (error);
380 		}
381 		$$.a_id = -1;
382 		error = aclent_entry_type($1, 0, &$$.a_type);
383 		if (error) {
384 			acl_error(
385 			    gettext("Invalid ACL entry type specified %d.\n"),
386 			    error);
387 			return (error);
388 		}
389 	}
390 	| entry_type aclent_perm COLON id
391 	{
392 		if (yyinteractive) {
393 			acl_error(gettext("Extra fields on the end of "
394 			    "ACL specification.\n"));
395 			return (EACL_UNKNOWN_DATA);
396 		}
397 		return (EACL_ENTRY_ERROR);
398 	}
399 
400 iflags: compact_iflag COLON {$$ = $1;}
401 	| verbose_iflag COLON {$$ = $1;}
402 	| COLON {$$ = 0;}
403 
404 compact_iflag : INHERIT_TOK
405 	{
406 		int error;
407 		uint32_t iflags;
408 
409 		error = compute_ace_inherit($1, &iflags);
410 		if (error) {
411 			acl_error(gettext("Invalid inheritance flags "
412 			    "'%s' specified.\n"), $1);
413 			free($1);
414 			return (error);
415 		}
416 		$$ = iflags;
417 	}
418 	| INHERIT_TOK SLASH verbose_iflag
419 	{
420 		acl_error(gettext("Can't mix compact inherit flags with"
421 		    " verbose inheritance flags.\n"));
422 		return (EACL_INHERIT_ERROR);
423 	}
424 
425 verbose_iflag: ACE_INHERIT	{$$ |= $1;}
426 	| ACE_INHERIT SLASH verbose_iflag {$$ = $1 | $3;}
427 	| ACE_INHERIT SLASH compact_iflag
428 	{
429 		acl_error(gettext("Can't mix verbose inherit flags with"
430 		    " compact inheritance flags.\n"));
431 		return (EACL_INHERIT_ERROR);
432 	}
433 	| ACE_INHERIT SLASH ACCESS_TYPE
434 	{
435 		acl_error(gettext("Inheritance flags can't be mixed with"
436 		    " access type.\n"));
437 		return (EACL_INHERIT_ERROR);
438 	}
439 	| ACE_INHERIT SLASH ERROR {return ($3);}
440 
441 aclent_perm: PERM_TOK
442 	{
443 		$$.perm_style = PERM_TYPE_UNKNOWN;
444 		$$.perm_str = $1;
445 		$$.perm_val = 0;
446 	}
447 	| PERM_TOK ERROR
448 	{
449 		acl_error(gettext("ACL entry permissions are incorrectly "
450 		    "specified.\n"));
451 		return ($2);
452 	}
453 
454 access_type: ACCESS_TYPE {$$ = $1;}
455 	| ERROR {return ($1);}
456 
457 id: ID {$$ = $1;}
458   	| COLON
459 	{
460 		acl_error(gettext("Invalid uid/gid specified.\nThe field"
461 		    " should be a numeric value.\n"));
462 		return (EACL_UNKNOWN_DATA);
463 	}
464 	| ERROR {return ($1);}
465 
466 ace_perms: perm {$$ = $1;}
467 	| aclent_perm COLON {$$ = $1;}
468 	| ERROR {return ($1);}
469 
470 perm: perms COLON {$$ = $1;}
471     	| COLON {$$.perm_style = PERM_TYPE_EMPTY;}
472 
473 perms: ACE_PERM
474      	{
475 		$$.perm_style = PERM_TYPE_ACE;
476 		$$.perm_val |= $1;
477 	}
478 	| ACE_PERM SLASH perms
479 	{
480 		$$.perm_style = PERM_TYPE_ACE;
481 		$$.perm_val = $1 | $3.perm_val;
482 	}
483 	| ACE_PERM SLASH aclent_perm
484 	{
485 
486 		acl_error(gettext("Can't mix verbose permissions with"
487 		    " compact permission.\n"));
488 		return (EACL_PERM_MASK_ERROR);
489 
490 	}
491 	| ACE_PERM SLASH ERROR {return ($3);}
492 
493 
494 idname: IDNAME {$$ = $1;}
495 
496 entry_type: ENTRY_TYPE {$$ = $1;}
497 	| ERROR {return ($1);}
498