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