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