xref: /illumos-gate/usr/src/lib/libsec/common/acl_lex.l (revision 508a0e8cf1600b06c1f7361ad76e736710d3fdf8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
22  * Use is subject to license terms.
23  */
24 
25 %{
26 #include <sys/acl.h>
27 #include <aclutils.h>
28 #include <idmap.h>
29 #include <errno.h>
30 #include "acl.tab.h"
31 
32 #ifdef input
33 #undef input
34 #endif
35 
36 #ifdef unput
37 #undef unput
38 #endif
39 
40 int grab_string(char *terminators);
41 static int input();
42 static void unput(int);
43 
44 int
45 yyerror(const char *s)
46 {
47 	return (0);
48 }
49 
50 int
51 yywrap(void)
52 {
53 	return (1);
54 }
55 
56 extern char *yybuf;
57 int yybufpos;
58 
59 /*
60  * Used for tracking allocated strings while walking through an ACL.
61  */
62 struct yystrings {
63 	char *y_logname;	/* user/group name from LOGNAME */
64 	char *y_perms;		/* permssions from PERM_TOK */
65 	char *y_iflags;		/* iflags from INHERIT_TOK */
66 	char *y_idstr;		/* string of appened id */
67 } yystrings;
68 
69 %}
70 
71 %e 1500
72 %s TS NS PS AIS AS US ES
73 %p 5000
74 
75 /*
76  * TS = type state
77  * NS = name state
78  * PS = Permission state
79  * AIS = Allow/deny/inheritance state
80  * AS = Allow state (only used when inheritance detected)
81  * US = UID/GID state
82  * ES = End state
83  */
84 
85 ID	[0-9]+
86 SID	S-[^:,\n]+
87 LOGNAME [^:]+:
88 PERM_STR [rRwWxpdDaAcCos-]+
89 INHERIT_STR [fdinFSI-]+
90 
91 %%
92 
93 <TS>user:		{
94 				BEGIN NS;
95 				yylval.val = USER_TOK;
96 				return (ENTRY_TYPE);
97 			}
98 <TS>usersid:		{
99 				BEGIN NS;
100 				yylval.val = USER_SID_TOK;
101 				return (ENTRY_TYPE);
102 			}
103 <TS>owner@:		{
104 				BEGIN PS;
105 				yylval.val = OWNERAT_TOK;
106 				return (ENTRY_TYPE);
107 			}
108 <TS>group@:		{
109 				BEGIN PS;
110 				yylval.val = GROUPAT_TOK;
111 				return (ENTRY_TYPE);
112 			}
113 <TS>everyone@:		{
114 				BEGIN PS;
115 				yylval.val = EVERYONEAT_TOK;
116 				return (ENTRY_TYPE);
117 			}
118 <TS>group:		{
119 				BEGIN NS;
120 				yylval.val = GROUP_TOK;
121 				return (ENTRY_TYPE);
122 			}
123 <TS>groupsid:		{
124 				BEGIN NS;
125 				yylval.val = GROUP_SID_TOK;
126 				return (ENTRY_TYPE);
127 			}
128 <TS>sid:		{
129 				BEGIN NS;
130 				yylval.val = GROUP_SID_TOK;
131 				return (ENTRY_TYPE);
132 			}
133 <TS>mask:		{
134 				BEGIN PS;
135 				yylval.val = MASK_TOK;
136 				return (ENTRY_TYPE);
137 			}
138 <TS>mask::		{
139 				BEGIN PS;
140 				yylval.val = MASK_TOK;
141 				return (ENTRY_TYPE);
142 			}
143 <TS>other:		{
144 				BEGIN PS;
145 				yylval.val = OTHER_TOK;
146 				return (ENTRY_TYPE);
147 			}
148 <TS>other::		{
149 				BEGIN PS;
150 				yylval.val = OTHER_TOK;
151 				return (ENTRY_TYPE);
152 			}
153 <TS>defaultuser: 	{
154 				BEGIN NS;
155 				yylval.val = DEFAULT_USER_TOK;
156 				return (ENTRY_TYPE);
157 			}
158 <TS>default:user:	{
159 				BEGIN NS;
160 				yylval.val = DEFAULT_USER_TOK;
161 				return (ENTRY_TYPE);
162 			}
163 <TS>defaultgroup: 	{
164 				BEGIN NS;
165 				yylval.val = DEFAULT_GROUP_TOK;
166 				return (ENTRY_TYPE);
167 			}
168 <TS>default:group:	{
169 				BEGIN NS;
170 				yylval.val = DEFAULT_GROUP_TOK;
171 				return (ENTRY_TYPE);
172 			}
173 <TS>defaultother: 	{
174 				BEGIN PS;
175 				yylval.val = DEFAULT_OTHER_TOK;
176 				return (ENTRY_TYPE);
177 			}
178 <TS>defaultother:: 	{
179 				BEGIN PS;
180 				yylval.val = DEFAULT_OTHER_TOK;
181 				return (ENTRY_TYPE);
182 			}
183 <TS>default:other:	{
184 				BEGIN PS;
185 				yylval.val = DEFAULT_OTHER_TOK;
186 				return (ENTRY_TYPE);
187 			}
188 <TS>defaultmask: 	{
189 				BEGIN PS;
190 				yylval.val = DEFAULT_MASK_TOK;
191 				return (ENTRY_TYPE);
192 			}
193 <TS>defaultmask:: 	{
194 				BEGIN PS;
195 				yylval.val = DEFAULT_MASK_TOK;
196 				return (ENTRY_TYPE);
197 			}
198 <TS>default:mask:		{
199 				BEGIN PS;
200 				yylval.val = DEFAULT_MASK_TOK;
201 				return (ENTRY_TYPE);
202 			}
203 <TS>"\n"		{
204 				return (NL);
205 			}
206 <TS>.			{
207 				if (grab_string(":,\n") != 0) {
208 					acl_error(dgettext(TEXT_DOMAIN,
209 					    "Failed to retrieve"
210 					    " error string.\n"));
211 					yylval.val = EACL_MEM_ERROR;
212 					return (ERROR);
213 				}
214 				acl_error(dgettext(TEXT_DOMAIN,
215 				    "Invalid ACL entry "
216 				    "type '%s' specified.\n"), yylval.str);
217 				free(yylval.str);
218 				yylval.val = EACL_ENTRY_ERROR;
219 				return (ERROR);
220 			}
221 <NS>:			{
222 				BEGIN PS;
223 				return (COLON);
224 			}
225 <NS>{LOGNAME}		{
226 				yylval.str = strdup(yytext);
227 				if (yylval.str == NULL) {
228 					yylval.val = EACL_MEM_ERROR;
229 					return (ERROR);
230 				}
231 				yylval.str[strlen(yylval.str) -1] = '\0';
232 				yystrings.y_logname = yylval.str;
233 				BEGIN PS;
234 				return (IDNAME);
235 			}
236 <NS>"\n"		{
237 				acl_error(dgettext(TEXT_DOMAIN,
238 				    "Missing user/group name"
239 				    " from ACL specification.\n"));
240 				yylval.val = EACL_MISSING_FIELDS;
241 				return (ERROR);
242 			}
243 <NS>.			{
244 				int error;
245 
246 				error = grab_string(":,\n");
247 				if (error != 0) {
248 					acl_error(dgettext(TEXT_DOMAIN,
249 					    "Invalid user/group "
250 					    "name specification.\n"));
251 					yylval.val = EACL_INVALID_USER_GROUP;
252 				} else {
253 					acl_error(dgettext(TEXT_DOMAIN,
254 					    "User/Group name "
255 					    "'%s' not specified correctly.\n"),
256 					    yylval.str);
257 					free(yylval.str);
258 					yylval.val = EACL_ENTRY_ERROR;
259 				}
260 				return (ERROR);
261 			}
262 <PS>read_data/[:/,]	{
263 				yylval.val = ACE_READ_DATA;
264 				return (ACE_PERM);
265 			}
266 <PS>list_directory/[:/,] {
267 				yylval.val = ACE_LIST_DIRECTORY;
268 			 	return (ACE_PERM);
269 			}
270 <PS>write_data/[:/,]	{
271 				yylval.val = ACE_WRITE_DATA;
272 				return (ACE_PERM);
273 			}
274 <PS>add_file/[:/,]	{
275 				yylval.val = ACE_ADD_FILE;
276 				return (ACE_PERM);
277 			}
278 <PS>append_data/[:/,]	{
279 				yylval.val = ACE_APPEND_DATA;
280 				return (ACE_PERM);
281 			}
282 <PS>add_subdirectory/[:/,] {
283 				yylval.val = ACE_ADD_SUBDIRECTORY;
284 				return (ACE_PERM);
285 			}
286 <PS>read_xattr/[:/,]	{
287 				yylval.val = ACE_READ_NAMED_ATTRS;
288 				return (ACE_PERM);
289 			}
290 <PS>write_xattr/[:/,]	{
291 				yylval.val = ACE_WRITE_NAMED_ATTRS;
292 				return (ACE_PERM);
293 			}
294 <PS>execute/[:/,]	{
295 				yylval.val = ACE_EXECUTE;
296 				return (ACE_PERM);
297 			}
298 <PS>delete_child/[:/,]	{
299 				yylval.val = ACE_DELETE_CHILD;
300 				return (ACE_PERM);
301 			}
302 <PS>read_attributes/[:/,] {
303 				yylval.val = ACE_READ_ATTRIBUTES;
304 				return (ACE_PERM);
305 			}
306 <PS>write_attributes/[:/,] {
307 				yylval.val = ACE_WRITE_ATTRIBUTES;
308 			 	return (ACE_PERM);
309 			}
310 <PS>delete/[:/,]		{
311 				yylval.val = ACE_DELETE;
312 				return (ACE_PERM);
313 			}
314 <PS>read_acl/[:/,]	{
315 				yylval.val = ACE_READ_ACL;
316 				return (ACE_PERM);
317 			}
318 <PS>write_acl/[:/,]	{
319 				yylval.val = ACE_WRITE_ACL;
320 				return (ACE_PERM);
321 			}
322 <PS>write_owner/[:/,]	{
323 				yylval.val = ACE_WRITE_OWNER;
324 				return (ACE_PERM);
325 			}
326 <PS>synchronize/[:/,]	{
327 				yylval.val = ACE_SYNCHRONIZE;
328 				return (ACE_PERM);
329 			}
330 <PS>read_set/[:/,]	{
331 				yylval.val = ACE_READ_PERMS;
332 				return (ACE_PERM);
333 			}
334 <PS>write_set/[:/,]	{
335 				yylval.val = ACE_WRITE_PERMS;
336 				return (ACE_PERM);
337 			}
338 <PS>modify_set/[:/,]	{
339 				yylval.val = ACE_MODIFY_PERMS;
340 				return (ACE_PERM);
341 			}
342 <PS>full_set/[:/,]	{
343 				yylval.val = ACE_ALL_PERMS;
344 				return (ACE_PERM);
345 			}
346 <PS>{PERM_STR}/[:,\n]	{
347 				int c;
348 
349 				c = input();
350 				unput(c);
351 				yylval.str = strdup(yytext);
352 				if (yylval.str == NULL) {
353 					yylval.val = EACL_MEM_ERROR;
354 					return (ERROR);
355 				}
356 				yystrings.y_perms = yylval.str;
357 
358 				/*
359 				 * aclent are done after permissions.
360 				 */
361 				if (isdigit(c))
362 					BEGIN US;
363 				else if (c != ':')
364 					BEGIN ES;
365 
366 				return (PERM_TOK);
367 			}
368 <PS>"/:"		{
369 				acl_error(dgettext(TEXT_DOMAIN,
370 				    "Invalid permission /: specified.\n"));
371 				yylval.val = EACL_ENTRY_ERROR;
372 				return (ERROR);
373 			}
374 <PS>:			{
375 				int c;
376 
377 				c = input();
378 				unput(c);
379 				if (isdigit(c))
380 					BEGIN (US);
381 				else
382 					BEGIN AIS;
383 				return (COLON);
384 			}
385 <PS>"/"			{
386 				return (SLASH);
387 			}
388 <PS>"\n"		{
389 				acl_error(dgettext(TEXT_DOMAIN,
390 				    "ACL entry is missing "
391 				    "permission fields.\n"));
392 				yylval.val = EACL_MISSING_FIELDS;
393 				return (ERROR);
394 			}
395 <PS>","			{
396 				acl_error(
397 				    dgettext(TEXT_DOMAIN,
398 				    "The ',' is not a valid permission field "
399 				    "separator.\nThe comma is used to separate "
400 				    "access control entries.\nSee acl(5) for "
401 				    "examples of specifying ACL entries.\n"));
402 				yylval.val = EACL_PERM_MASK_ERROR;
403 				return (ERROR);
404 			}
405 <PS>. 			{
406 				if (grab_string("/:,\n") != 0) {
407 					acl_error(dgettext(TEXT_DOMAIN,
408 					    "Failed to retrieve"
409 					    " error string.\n"));
410 					yylval.val = EACL_MEM_ERROR;
411 					return (ERROR);
412 				}
413 				acl_error(dgettext(TEXT_DOMAIN,
414 				    "Invalid permission(s) '%s' "
415 				    "specified.\n"), yylval.str);
416 				free(yylval.str);
417 				yylval.val = EACL_PERM_MASK_ERROR;
418 				return (ERROR);
419 			}
420 <AS>allow/[:,\n]	{
421 
422 				int c;
423 
424 				c = input();
425 				unput(c);
426 				if (c == ',' || c == '\n')
427 					BEGIN ES;
428 				else
429 					BEGIN US;
430 				yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE;
431 				return (ACCESS_TYPE);
432 			}
433 <AS>deny/[:,\n]		{
434 
435 				int c;
436 
437 				c = input();
438 				unput(c);
439 				if (c == ',' || c == '\n')
440 					BEGIN ES;
441 				else
442 					BEGIN US;
443 
444 				yylval.val = ACE_ACCESS_DENIED_ACE_TYPE;
445 				return (ACCESS_TYPE);
446 			}
447 <AS>audit/[:,\n]	{
448 				int c;
449 
450 				c = input();
451 				unput(c);
452 				if (c == ',' || c == '\n')
453 					BEGIN ES;
454 				else
455 					BEGIN US;
456 
457 				yylval.val = ACE_SYSTEM_AUDIT_ACE_TYPE;
458 				return (ACCESS_TYPE);
459 			}
460 <AS>alarm/[:,\n]	{
461 				int c;
462 
463 				c = input();
464 				unput(c);
465 				if (c == ',' || c == '\n')
466 					BEGIN ES;
467 				else
468 					BEGIN US;
469 
470 				yylval.val = ACE_SYSTEM_ALARM_ACE_TYPE;
471 				return (ACCESS_TYPE);
472 			}
473 <AS>:			{
474 
475 				acl_error(dgettext(TEXT_DOMAIN,
476 				    "Invalid Access type "
477 				    "specified.\nThe field is blank, when"
478 				    " it should be either allow or deny.\n"));
479 				yylval.val = EACL_INVALID_ACCESS_TYPE;
480 				return (ERROR);
481 			}
482 <AS>"\n"		{
483 				acl_error(dgettext(TEXT_DOMAIN,
484 				    "ACL access type must be specified.\n"));
485 				yylval.val = EACL_INVALID_ACCESS_TYPE;
486 				return (ERROR);
487 			}
488 <AS>.			{
489 				if (yytext[0] != '\n' && yytext[0] != '\0') {
490 					if (grab_string(":,\n") != 0) {
491 						acl_error(dgettext(TEXT_DOMAIN,
492 						    "Failed to "
493 						    "retrieve error "
494 						    "string.\n"));
495 						yylval.val = EACL_MEM_ERROR;
496 						return (ERROR);
497 					}
498 					acl_error(
499 					    dgettext(TEXT_DOMAIN,
500 					    "Invalid access "
501 					    "type '%s' specified.\n"),
502 					    yylval.str);
503 				} else {
504 					acl_error(
505 					    dgettext(TEXT_DOMAIN,
506 					    "No access "
507 					    "type specified.\n"), yylval.str);
508 				}
509 
510 				free(yylval.str);
511 				yylval.val = EACL_INVALID_ACCESS_TYPE;
512 				return (ERROR);
513 			}
514 <AIS>allow/[:,\n]	{
515 
516 				int c;
517 
518 				c = input();
519 				unput(c);
520 				if (c == ',' || c == '\n')
521 					BEGIN ES;
522 				else
523 					BEGIN US;
524 				yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE;
525 				return (ACCESS_TYPE);
526 			}
527 <AIS>deny/[:,\n]	{
528 
529 				int c;
530 
531 				c = input();
532 				unput(c);
533 				if (c == ',' || c == '\n')
534 					BEGIN ES;
535 				else
536 					BEGIN US;
537 
538 				yylval.val = ACE_ACCESS_DENIED_ACE_TYPE;
539 				return (ACCESS_TYPE);
540 			}
541 <AIS>audit/[:,\n]	{
542 				int c;
543 
544 				c = input();
545 				unput(c);
546 				if (c == ',' || c == '\n')
547 					BEGIN ES;
548 				else
549 					BEGIN US;
550 
551 				yylval.val = ACE_SYSTEM_AUDIT_ACE_TYPE;
552 				return (ACCESS_TYPE);
553 			}
554 <AIS>alarm/[:,\n]	{
555 
556 				int c;
557 
558 				c = input();
559 				unput(c);
560 				if (c == ',' || c == '\n')
561 					BEGIN ES;
562 				else
563 					BEGIN US;
564 
565 				yylval.val = ACE_SYSTEM_ALARM_ACE_TYPE;
566 				return (ACCESS_TYPE);
567 			}
568 <AIS>file_inherit/[:/,] {
569 				yylval.val = ACE_FILE_INHERIT_ACE;
570 				return (ACE_INHERIT);
571 			}
572 <AIS>dir_inherit/[:/,]	{
573 				yylval.val = ACE_DIRECTORY_INHERIT_ACE;
574 				return (ACE_INHERIT);
575 			}
576 <AIS>no_propagate/[/:,]	{
577 				yylval.val = ACE_NO_PROPAGATE_INHERIT_ACE;
578 				return (ACE_INHERIT);
579 			}
580 <AIS>inherit_only/[/:,]	{
581 				yylval.val = ACE_INHERIT_ONLY_ACE;
582 				return (ACE_INHERIT);
583 			}
584 
585 <AIS>successful_access/[/:,] {
586 				yylval.val = ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
587 				return (ACE_INHERIT);
588 			}
589 <AIS>failed_access/[/:,] {
590 				yylval.val = ACE_FAILED_ACCESS_ACE_FLAG;
591 				return (ACE_INHERIT);
592 			}
593 <AIS>inherited/[/:,] {
594 				yylval.val = ACE_INHERITED_ACE;
595 				return (ACE_INHERIT);
596 			}
597 <AIS>{INHERIT_STR}/[:]	{
598 				yylval.str = strdup(yytext);
599 				if (yylval.str == NULL) {
600 					yylval.val = EACL_MEM_ERROR;
601 					return (ERROR);
602 				}
603 				yystrings.y_iflags = yylval.str;
604 				return (INHERIT_TOK);
605 			}
606 <AIS>:			{
607 				/*
608 				 * Only inheritance fields should hit this.
609 				 * allow/deny fields match on ":" as part
610 				 * of the regexp.
611 				 */
612 				BEGIN AS;
613 				return (COLON);
614 			}
615 <AIS>"/"		{
616 				return (SLASH);
617 			}
618 <AIS>"\n"		{
619 				acl_error(
620 				    dgettext(TEXT_DOMAIN,
621 				    "Invalid ACL specification."
622 				    "\nWas expecting to find"
623 				    " access type or inheritance flags.\n"),
624 				    yylval.str);
625 				yylval.val = EACL_UNKNOWN_DATA;
626 				return (ERROR);
627 			}
628 <AIS>","		{
629 				acl_error(
630 				    dgettext(TEXT_DOMAIN,
631 				    "The ',' is not a valid inheritance field "
632 				    "separator.\nThe comma is used to separate "
633 				    "access control entries.\nSee acl(5) for "
634 				    "examples of specifying ACL entries.\n"));
635 				yylval.val = EACL_INVALID_ACCESS_TYPE;
636 				return (ERROR);
637 			}
638 <AIS>.			{
639 				if (yytext[0] != '\n' && yytext[0] != '\0') {
640 					if (grab_string(":,\n") != 0) {
641 						acl_error(dgettext(TEXT_DOMAIN,
642 						    "Failed to "
643 						    "retrieve error "
644 						    "string.\n"));
645 						yylval.val = EACL_MEM_ERROR;
646 						return (ERROR);
647 					}
648 					acl_error(
649 					    dgettext(TEXT_DOMAIN,
650 					    "Invalid inheritance or"
651 				    	    " access type '%s' specified.\n"),
652 				    	    yylval.str);
653 				} else {
654 					acl_error(
655 					    dgettext(TEXT_DOMAIN,
656 					    "No inheritance or "
657 					    "access type specified.\n"),
658 					    yylval.str);
659 				}
660 
661 				free(yylval.str);
662 				yylval.val = EACL_INVALID_ACCESS_TYPE;
663 				return (ERROR);
664 			}
665 <US>{ID}/[,\n]		{
666 				BEGIN ES;
667 				yylval.str = strdup(yytext);
668 				if (yylval.str == NULL) {
669 					yylval.val = EACL_MEM_ERROR;
670 					return (ERROR);
671 				}
672 				yystrings.y_idstr = yylval.str;
673 				return (ID);
674 			}
675 <US>{SID}/[,\n]		{
676 				BEGIN ES;
677 				yylval.str = strdup(yytext);
678 				if (yylval.str == NULL) {
679 					yylval.val = EACL_MEM_ERROR;
680 					return (ERROR);
681 				}
682 				yystrings.y_idstr = yylval.str;
683 				return (SID);
684 			}
685 <US>:			{
686 				return (COLON);
687 			}
688 <US>{INHERIT_STR}	{	/*
689 				 * Catch specific error to produce
690 				 * nice message for users who are trying
691 				 * to use old syntax format which had
692 				 * inheritance flags as the last field.
693 				 */
694 				acl_error(dgettext(TEXT_DOMAIN,
695 				    "Access type should be final"
696 				    " field in ACL specification.\n"));
697 				yylval.val = EACL_ENTRY_ERROR;
698 				return (ERROR);
699 			}
700 <US>.			{
701 				if (grab_string(",\n") != 0) {
702 					acl_error(dgettext(TEXT_DOMAIN,
703 					    "Failed to retrieve"
704 					    " error string.\n"));
705 					yylval.val = EACL_MEM_ERROR;
706 					return (ERROR);
707 				}
708 				acl_error(
709 				    dgettext(TEXT_DOMAIN,
710 				    "Invalid data ':%s' specified"
711 				    " on end of ACL.\n"), yylval.str);
712 				free(yylval.str);
713 				yylval.val = EACL_ENTRY_ERROR;
714 				return (ERROR);
715 			}
716 <US>"\n"		{
717 				acl_error(dgettext(TEXT_DOMAIN,
718 				    "Missing fields in ACL "
719 				    "specification.\nWas expecting to find "
720 				    "uid/gid.\n"));
721 				yylval.val = EACL_ENTRY_ERROR;
722 				return (ERROR);
723 			}
724 <ES>","			{
725 				BEGIN TS;
726 				return (COMMA);
727 			}
728 <ES>.			{
729 				if (grab_string("/:,\n") != 0) {
730 					acl_error(
731 					    dgettext(TEXT_DOMAIN,
732 					    "Failed to retrieve error"
733 				    	    " string.\n"));
734 					yylval.val = EACL_MEM_ERROR;
735 					return (ERROR);
736 				}
737 				acl_error(
738 				    dgettext(TEXT_DOMAIN,
739 				    "Unrecognized data '%s' found"
740 			    	    " in ACL specification.\n"), yylval.str);
741 				free(yylval.str);
742 				yylval.val = EACL_UNKNOWN_DATA;
743 				return (ERROR);
744 			}
745 <ES>"\n"		{
746 				return (NL);
747 			}
748 %%
749 
750 
751 /*
752  * Pull string up to terminator off of input string.
753  * used for retrieving illegal data in ACL specification.
754  *
755  * The first set of characters is retrieved from yytext.
756  * subsequent characters are pulled from the input stream,
757  * until either EOF or one of the requested terminators is scene.
758  * Result is returned in yylval.str which is malloced.
759  */
760 int
761 grab_string(char *terminators)
762 {
763 		int c;
764 		int done = 0;
765 		int cnt;
766 		int alloced;
767 		int error = 0;
768 		char *ptr;
769 
770 		cnt = strlen(yytext);
771 		yylval.str = calloc(cnt + 1, sizeof (char));
772 		if (yylval.str == NULL) {
773 			return (1);
774 		}
775 		alloced = cnt + 1;
776 		strcpy(yylval.str, yytext);
777 
778 		do {
779 			c = input();
780 			if (c == EOF)
781 				break;
782 
783 			for (ptr = terminators; *ptr; ptr++) {
784 				if (c == *ptr) {
785 					done = 1;
786 					break;
787 				}
788 			}
789 
790 			if (done)
791 				break;
792 
793 			if (cnt + 1 >= alloced) {
794 				yylval.str = realloc(yylval.str,
795 				    alloced + 80);
796 					alloced += 80;
797 				if (yylval.str == NULL)
798 					return (1);
799 
800 				memset(yylval.str + cnt, 0,
801 				    alloced - strlen(yylval.str));
802 			}
803 			yylval.str[strlen(yylval.str)] = c;
804 			cnt++;
805 		} while (!done);
806 
807 		return (error);
808 }
809 
810 static int
811 input(void)
812 {
813 	int c;
814 
815 	c = yybuf[yybufpos++];
816 	if (c == '\0') {
817 		return (EOF);
818 	}
819 
820 	return (c);
821 }
822 
823 static void
824 unput(int c)
825 {
826 	if (c == '\0') {
827 		return;
828 	}
829 
830 	if (yybufpos > 0) {
831 		--yybufpos;
832 	}
833 }
834 
835 /*
836  * return ACE entry type
837  */
838 int
839 ace_entry_type(int type)
840 {
841 	int ret = -1;
842 	switch (type) {
843 		case USER_TOK:
844 		case USER_SID_TOK:
845 			ret = 0;
846 			break;
847 		case GROUP_TOK:
848 		case GROUP_SID_TOK:
849 			ret = ACE_IDENTIFIER_GROUP;
850 			break;
851 		case OWNERAT_TOK:
852 			ret = ACE_OWNER;
853 			break;
854 		case GROUPAT_TOK:
855 			ret = ACE_IDENTIFIER_GROUP | ACE_GROUP;
856 			break;
857 		case EVERYONEAT_TOK:
858 			ret = ACE_EVERYONE;
859 			break;
860 	}
861 	return (ret);
862 }
863 
864 
865 /*
866  * return aclent entry type
867  */
868 int
869 aclent_entry_type(int type, int owning, int *ret)
870 {
871 
872 	*ret = 0;
873 
874 	switch (type) {
875 	case USER_TOK:
876 		*ret = (owning == 0) ? USER : USER_OBJ;
877 		break;
878 	case GROUP_TOK:
879 		*ret = (owning == 0) ? GROUP : GROUP_OBJ;
880 		break;
881 	case OTHER_TOK:
882 		*ret = OTHER_OBJ;
883 		break;
884 	case MASK_TOK:
885 		*ret = CLASS_OBJ;
886 		break;
887 	case DEFAULT_USER_TOK:
888 		*ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ;
889 		break;
890 	case DEFAULT_GROUP_TOK:
891 		*ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ;
892 		break;
893 	case DEFAULT_MASK_TOK:
894 		*ret = DEF_CLASS_OBJ;
895 		break;
896 	case DEFAULT_OTHER_TOK:
897 		*ret = DEF_OTHER_OBJ;
898 		break;
899 	default:
900 		return (EACL_ENTRY_ERROR);
901 	}
902 
903 	return (0);
904 }
905 
906 /*
907  * convert string into numeric id.
908  */
909 static int
910 acl_str_to_id(char *str, uid_t *id)
911 {
912 	char *end;
913 	uid_t value;
914 
915 	errno = 0;
916 	value = strtoul(str, &end, 10);
917 
918 	if (errno != 0 || *end != '\0')
919 		return (EACL_INVALID_USER_GROUP);
920 
921 	*id = value;
922 
923 	return (0);
924 }
925 
926 /*
927  * determine either uid/gid for given entry type
928  */
929 int
930 get_id(int entry_type, char *name, uid_t *id)
931 {
932 	struct passwd *pw;
933 	struct group *gr;
934 	int error = 0;
935 
936 	switch (entry_type) {
937 	case USER_TOK:
938 	case DEFAULT_USER_TOK:
939 		if ((error = acl_str_to_id(name, id)) == 0)
940 			break;
941 		pw = getpwnam(name);
942 		if (pw) {
943 			*id = pw->pw_uid;
944 			error = 0;
945 		}
946 		break;
947 
948 	case GROUP_TOK:
949 	case DEFAULT_GROUP_TOK:
950 		if ((error = acl_str_to_id(name, id)) == 0)
951 			break;
952 		gr = getgrnam(name);
953 		if (gr) {
954 			*id = gr->gr_gid;
955 			error = 0;
956 		}
957 		break;
958 	case USER_SID_TOK:
959 		if (sid_to_id(name, B_TRUE, id))
960 			error = EACL_INVALID_USER_GROUP;
961 		break;
962 
963 	case GROUP_SID_TOK:
964 		if (sid_to_id(name, B_FALSE, id))
965 			error = EACL_INVALID_USER_GROUP;
966 		break;
967 	}
968 
969 	return (error);
970 }
971 
972 int
973 get_id_nofail(int entry_type, char *name)
974 {
975 	uid_t id;
976 
977 	if (get_id(entry_type, name, &id))
978 		return (UID_NOBODY);
979 	else
980 		return (id);
981 }
982 
983 /*
984  * reset beginning state to TS and set character position
985  * back to zero.
986  */
987 void
988 yyreset()
989 {
990 	yybufpos = 0;
991 	memset(&yystrings, 0, sizeof (yystrings));
992 	BEGIN TS;
993 }
994 
995 void
996 yycleanup()
997 {
998 	if (yystrings.y_logname)
999 		free(yystrings.y_logname);
1000 	if (yystrings.y_perms)
1001 		free(yystrings.y_perms);
1002 	if (yystrings.y_iflags)
1003 		free(yystrings.y_iflags);
1004 	if (yystrings.y_idstr)
1005 		free(yystrings.y_idstr);
1006 	yystrings.y_logname = NULL;
1007 	yystrings.y_perms = NULL;
1008 	yystrings.y_iflags = NULL;
1009 	yystrings.y_idstr = NULL;
1010 }
1011