xref: /illumos-gate/usr/src/lib/libsec/common/acl_lex.l (revision 051aabe6136ff13e81542a427e9693ffe1503525)
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 #pragma	ident	"%Z%%M%	%I%	%E% SMI"
26 
27 %{
28 #include <sys/acl.h>
29 #include <aclutils.h>
30 #include <idmap.h>
31 #include <errno.h>
32 #include "acl.tab.h"
33 
34 #ifdef input
35 #undef input
36 #endif
37 
38 #ifdef unput
39 #undef unput
40 #endif
41 
42 int grab_string(char *terminators);
43 static int input();
44 static void unput(int);
45 
46 int
47 yyerror(const char *s)
48 {
49 	return (0);
50 }
51 
52 int
53 yywrap(void)
54 {
55 	return (1);
56 }
57 
58 extern char *yybuf;
59 int yybufpos;
60 
61 /*
62  * Used for tracking allocated strings while walking through an ACL.
63  */
64 struct yystrings {
65 	char *y_logname;	/* user/group name from LOGNAME */
66 	char *y_perms;		/* permssions from PERM_TOK */
67 	char *y_iflags;		/* iflags from INHERIT_TOK */
68 } yystrings;
69 
70 %}
71 
72 %e 1500
73 %s TS NS PS AIS AS US ES
74 %p 5000
75 
76 /*
77  * TS = type state
78  * NS = name state
79  * PS = Permission state
80  * AIS = Allow/deny/inheritance state
81  * AS = Allow state (only used when inheritance detected)
82  * US = UID/GID state
83  * ES = End state
84  */
85 
86 ID	[0-9]+
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.val = atoi(yytext);
668 				return (ID);
669 			}
670 <US>:			{
671 				return (COLON);
672 			}
673 <US>{INHERIT_STR}	{	/*
674 				 * Catch specific error to produce
675 				 * nice message for users who are trying
676 				 * to use old syntax format which had
677 				 * inheritance flags as the last field.
678 				 */
679 				acl_error(dgettext(TEXT_DOMAIN,
680 				    "Access type should be final"
681 				    " field in ACL specification.\n"));
682 				yylval.val = EACL_ENTRY_ERROR;
683 				return (ERROR);
684 			}
685 <US>.			{
686 				if (grab_string(",\n") != 0) {
687 					acl_error(dgettext(TEXT_DOMAIN,
688 					    "Failed to retrieve"
689 					    " error string.\n"));
690 					yylval.val = EACL_MEM_ERROR;
691 					return (ERROR);
692 				}
693 				acl_error(
694 				    dgettext(TEXT_DOMAIN,
695 				    "Invalid data ':%s' specified"
696 				    " on end of ACL.\n"), yylval.str);
697 				free(yylval.str);
698 				yylval.val = EACL_ENTRY_ERROR;
699 				return (ERROR);
700 			}
701 <US>"\n"		{
702 				acl_error(dgettext(TEXT_DOMAIN,
703 				    "Missing fields in ACL "
704 				    "specification.\nWas expecting to find "
705 				    "uid/gid.\n"));
706 				yylval.val = EACL_ENTRY_ERROR;
707 				return (ERROR);
708 			}
709 <ES>","			{
710 				BEGIN TS;
711 				return (COMMA);
712 			}
713 <ES>.			{
714 				if (grab_string("/:,\n") != 0) {
715 					acl_error(
716 					    dgettext(TEXT_DOMAIN,
717 					    "Failed to retrieve error"
718 				    	    " string.\n"));
719 					yylval.val = EACL_MEM_ERROR;
720 					return (ERROR);
721 				}
722 				acl_error(
723 				    dgettext(TEXT_DOMAIN,
724 				    "Unrecognized data '%s' found"
725 			    	    " in ACL specification.\n"), yylval.str);
726 				free(yylval.str);
727 				yylval.val = EACL_UNKNOWN_DATA;
728 				return (ERROR);
729 			}
730 <ES>"\n"		{
731 				return (NL);
732 			}
733 %%
734 
735 
736 /*
737  * Pull string up to terminator off of input string.
738  * used for retrieving illegal data in ACL specification.
739  *
740  * The first set of characters is retrieved from yytext.
741  * subsequent characters are pulled from the input stream,
742  * until either EOF or one of the requested terminators is scene.
743  * Result is returned in yylval.str which is malloced.
744  */
745 int
746 grab_string(char *terminators)
747 {
748 		int c;
749 		int done = 0;
750 		int cnt;
751 		int alloced;
752 		int error = 0;
753 		char *ptr;
754 
755 		cnt = strlen(yytext);
756 		yylval.str = calloc(cnt + 1, sizeof (char));
757 		if (yylval.str == NULL) {
758 			return (1);
759 		}
760 		alloced = cnt + 1;
761 		strcpy(yylval.str, yytext);
762 
763 		do {
764 			c = input();
765 			if (c == EOF)
766 				break;
767 
768 			for (ptr = terminators; *ptr; ptr++) {
769 				if (c == *ptr) {
770 					done = 1;
771 					break;
772 				}
773 			}
774 
775 			if (done)
776 				break;
777 
778 			if (cnt + 1 >= alloced) {
779 				yylval.str = realloc(yylval.str,
780 				    alloced + 80);
781 					alloced += 80;
782 				if (yylval.str == NULL)
783 					return (1);
784 
785 				memset(yylval.str + cnt, 0,
786 				    alloced - strlen(yylval.str));
787 			}
788 			yylval.str[strlen(yylval.str)] = c;
789 			cnt++;
790 		} while (!done);
791 
792 		return (error);
793 }
794 
795 static int
796 input(void)
797 {
798 	int c;
799 
800 	c = yybuf[yybufpos++];
801 	if (c == '\0') {
802 		return (EOF);
803 	}
804 
805 	return (c);
806 }
807 
808 static void
809 unput(int c)
810 {
811 	if (c == '\0') {
812 		return;
813 	}
814 
815 	if (yybufpos > 0) {
816 		--yybufpos;
817 	}
818 }
819 
820 /*
821  * return ACE entry type
822  */
823 int
824 ace_entry_type(int type)
825 {
826 	int ret = -1;
827 	switch (type) {
828 		case USER_TOK:
829 		case USER_SID_TOK:
830 			ret = 0;
831 			break;
832 		case GROUP_TOK:
833 		case GROUP_SID_TOK:
834 			ret = ACE_IDENTIFIER_GROUP;
835 			break;
836 		case OWNERAT_TOK:
837 			ret = ACE_OWNER;
838 			break;
839 		case GROUPAT_TOK:
840 			ret = ACE_IDENTIFIER_GROUP | ACE_GROUP;
841 			break;
842 		case EVERYONEAT_TOK:
843 			ret = ACE_EVERYONE;
844 			break;
845 	}
846 	return (ret);
847 }
848 
849 
850 /*
851  * return aclent entry type
852  */
853 int
854 aclent_entry_type(int type, int owning, int *ret)
855 {
856 
857 	*ret = 0;
858 
859 	switch (type) {
860 	case USER_TOK:
861 		*ret = (owning == 0) ? USER : USER_OBJ;
862 		break;
863 	case GROUP_TOK:
864 		*ret = (owning == 0) ? GROUP : GROUP_OBJ;
865 		break;
866 	case OTHER_TOK:
867 		*ret = OTHER_OBJ;
868 		break;
869 	case MASK_TOK:
870 		*ret = CLASS_OBJ;
871 		break;
872 	case DEFAULT_USER_TOK:
873 		*ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ;
874 		break;
875 	case DEFAULT_GROUP_TOK:
876 		*ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ;
877 		break;
878 	case DEFAULT_MASK_TOK:
879 		*ret = DEF_CLASS_OBJ;
880 		break;
881 	case DEFAULT_OTHER_TOK:
882 		*ret = DEF_OTHER_OBJ;
883 		break;
884 	default:
885 		return (EACL_ENTRY_ERROR);
886 	}
887 
888 	return (0);
889 }
890 
891 /*
892  * convert string into numeric id.
893  */
894 static int
895 acl_str_to_id(char *str, uid_t *id)
896 {
897 	char *end;
898 	uid_t value;
899 
900 	errno = 0;
901 	value = strtoul(str, &end, 10);
902 
903 	if (errno != 0 || *end != '\0')
904 		return (EACL_INVALID_USER_GROUP);
905 
906 	*id = value;
907 
908 	return (0);
909 }
910 
911 /*
912  * determine either uid/gid for given entry type
913  */
914 int
915 get_id(int entry_type, char *name, uid_t *id)
916 {
917 	struct passwd *pw;
918 	struct group *gr;
919 	int error = 0;
920 
921 	switch (entry_type) {
922 	case USER_TOK:
923 	case DEFAULT_USER_TOK:
924 		if ((error = acl_str_to_id(name, id)) == 0)
925 			break;
926 		pw = getpwnam(name);
927 		if (pw) {
928 			*id = pw->pw_uid;
929 			error = 0;
930 		}
931 		break;
932 
933 	case GROUP_TOK:
934 	case DEFAULT_GROUP_TOK:
935 		if ((error = acl_str_to_id(name, id)) == 0)
936 			break;
937 		gr = getgrnam(name);
938 		if (gr) {
939 			*id = gr->gr_gid;
940 			error = 0;
941 		}
942 		break;
943 	case USER_SID_TOK:
944 		if (sid_to_id(name, B_TRUE, id))
945 			error = EACL_INVALID_USER_GROUP;
946 		break;
947 
948 	case GROUP_SID_TOK:
949 		if (sid_to_id(name, B_FALSE, id))
950 			error = EACL_INVALID_USER_GROUP;
951 		break;
952 	}
953 
954 	return (error);
955 }
956 
957 /*
958  * reset beginning state to TS and set character position
959  * back to zero.
960  */
961 void
962 yyreset()
963 {
964 	yybufpos = 0;
965 	memset(&yystrings, 0, sizeof (yystrings));
966 	BEGIN TS;
967 }
968 
969 void
970 yycleanup()
971 {
972 	if (yystrings.y_logname)
973 		free(yystrings.y_logname);
974 	if (yystrings.y_perms)
975 		free(yystrings.y_perms);
976 	if (yystrings.y_iflags)
977 		free(yystrings.y_iflags);
978 	yystrings.y_logname = NULL;
979 	yystrings.y_perms = NULL;
980 	yystrings.y_iflags = NULL;
981 }
982