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