xref: /titanic_52/usr/src/lib/libsec/common/acl_lex.l (revision fb3fb4f3d76d55b64440afd0af72775dfad3bd1d)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * 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 %{
29 #include <sys/acl.h>
30 #include <aclutils.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 
63 %s TS NS PS AIS US ES
64 /*
65  * TS = type state
66  * NS = name state
67  * PS = Permission state
68  * AIS = Allow/deny/inheritance state
69  * US = UID/GID state
70  * ES = End state
71  */
72 
73 ID	[1-9][0-9]*
74 LOGNAME [a-z0-9A-Z]+:
75 BADLOGNAME [a-z0-9A-Z]+
76 PERM_STR [rRwWxpdDaAcCos-]+
77 INHERIT_STR [fdinFS-]+
78 
79 %%
80 
81 <TS>user:		{
82 				BEGIN NS;
83 				yylval.val = USER_TOK;
84 				return (ENTRY_TYPE);
85 			}
86 <TS>owner@:		{
87 				BEGIN PS;
88 				yylval.val = OWNERAT_TOK;
89 				return (ENTRY_TYPE);
90 			}
91 <TS>group@:		{
92 				BEGIN PS;
93 				yylval.val = GROUPAT_TOK;
94 				return (ENTRY_TYPE);
95 			}
96 <TS>everyone@:		{
97 				BEGIN PS;
98 				yylval.val = EVERYONEAT_TOK;
99 				return (ENTRY_TYPE);
100 			}
101 <TS>group:		{
102 				BEGIN NS;
103 				yylval.val = GROUP_TOK;
104 				return (ENTRY_TYPE);
105 			}
106 <TS>mask:		{
107 				BEGIN PS;
108 				yylval.val = MASK_TOK;
109 				return (ENTRY_TYPE);
110 			}
111 <TS>mask::		{
112 				BEGIN PS;
113 				yylval.val = MASK_TOK;
114 				return (ENTRY_TYPE);
115 			}
116 <TS>other:		{
117 				BEGIN PS;
118 				yylval.val = OTHER_TOK;
119 				return (ENTRY_TYPE);
120 			}
121 <TS>other::		{
122 				BEGIN PS;
123 				yylval.val = OTHER_TOK;
124 				return (ENTRY_TYPE);
125 			}
126 <TS>defaultuser: 	{
127 				BEGIN NS;
128 				yylval.val = DEFAULT_USER_TOK;
129 				return (ENTRY_TYPE);
130 			}
131 <TS>default:user:	{
132 				BEGIN NS;
133 				yylval.val = DEFAULT_USER_TOK;
134 				return (ENTRY_TYPE);
135 			}
136 <TS>defaultgroup: 	{
137 				BEGIN NS;
138 				yylval.val = DEFAULT_GROUP_TOK;
139 				return (ENTRY_TYPE);
140 			}
141 <TS>default:group:	{
142 				BEGIN NS;
143 				yylval.val = DEFAULT_GROUP_TOK;
144 				return (ENTRY_TYPE);
145 			}
146 <TS>defaultother: 	{
147 				BEGIN PS;
148 				yylval.val = DEFAULT_OTHER_TOK;
149 				return (ENTRY_TYPE);
150 			}
151 <TS>defaultother:: 	{
152 				BEGIN PS;
153 				yylval.val = DEFAULT_OTHER_TOK;
154 				return (ENTRY_TYPE);
155 			}
156 <TS>default:other:	{
157 				BEGIN PS;
158 				yylval.val = DEFAULT_OTHER_TOK;
159 				return (ENTRY_TYPE);
160 			}
161 <TS>defaultmask: 	{
162 				BEGIN PS;
163 				yylval.val = DEFAULT_MASK_TOK;
164 				return (ENTRY_TYPE);
165 			}
166 <TS>defaultmask:: 	{
167 				BEGIN PS;
168 				yylval.val = DEFAULT_MASK_TOK;
169 				return (ENTRY_TYPE);
170 			}
171 <TS>default:mask:		{
172 				BEGIN PS;
173 				yylval.val = DEFAULT_MASK_TOK;
174 				return (ENTRY_TYPE);
175 			}
176 <TS>"\n"		{
177 				return (NL);
178 			}
179 <TS>.			{
180 				if (grab_string(":\n") != 0) {
181 					acl_error(gettext("Failed to retrieve"
182 					    " error string\n"));
183 					yylval.val = EACL_MEM_ERROR;
184 					return (ERROR);
185 				}
186 				acl_error(gettext("Invalid ACL entry "
187 				    "type '%s' specified\n"), yylval.str);
188 				free(yylval.str);
189 				yylval.val = EACL_ENTRY_ERROR;
190 				return (ERROR);
191 			}
192 <NS>:			{
193 				BEGIN PS;
194 				return (COLON);
195 			}
196 <NS>{LOGNAME}		{
197 				yylval.str = strdup(yytext);
198 				if (yylval.str == NULL) {
199 					yylval.val = EACL_MEM_ERROR;
200 					return (ERROR);
201 				}
202 				yylval.str[strlen(yylval.str) -1] = '\0';
203 				BEGIN PS;
204 				return (IDNAME);
205 			}
206 <NS>{BADLOGNAME}	{
207 				acl_error(gettext("Missing fields after "
208 				    "user/group '%s'\n"), yytext);
209 				yylval.val = EACL_MISSING_FIELDS;
210 				return (ERROR);
211 			}
212 <NS>"\n"		{
213 				acl_error(gettext("Missing user/group name"
214 				    " from ACL specification\n"));
215 				yylval.val = EACL_MISSING_FIELDS;
216 				return (ERROR);
217 			}
218 <NS>.			{
219 				int error;
220 
221 				error = grab_string(":\n");
222 				if (error != 0) {
223 					acl_error(gettext("Invalid user/group "
224 					    "name specification\n"));
225 					yylval.val = EACL_INVALID_USER_GROUP;
226 				} else {
227 					acl_error(gettext("User/Group name "
228 					    "'%s' not specified correctly\n"),
229 					    yylval.str);
230 					free(yylval.str);
231 					yylval.val = EACL_ENTRY_ERROR;
232 				}
233 				return (ERROR);
234 			}
235 <PS>read_data/[:/]	{
236 				yylval.val = ACE_READ_DATA;
237 				return (ACE_PERM);
238 			}
239 <PS>list_directory/[:/] {
240 				yylval.val = ACE_LIST_DIRECTORY;
241 			 	return (ACE_PERM);
242 			}
243 <PS>write_data/[:/]	{
244 				yylval.val = ACE_WRITE_DATA;
245 				return (ACE_PERM);
246 			}
247 <PS>add_file/[:/]	{
248 				yylval.val = ACE_ADD_FILE;
249 				return (ACE_PERM);
250 			}
251 <PS>append_data/[:/]	{
252 				yylval.val = ACE_APPEND_DATA;
253 				return (ACE_PERM);
254 			}
255 <PS>add_subdirectory/[:/] {
256 				yylval.val = ACE_ADD_SUBDIRECTORY;
257 				return (ACE_PERM);
258 			}
259 <PS>read_xattr/[:/]	{
260 				yylval.val = ACE_READ_NAMED_ATTRS;
261 				return (ACE_PERM);
262 			}
263 <PS>write_xattr/[:/]	{
264 				yylval.val = ACE_WRITE_NAMED_ATTRS;
265 				return (ACE_PERM);
266 			}
267 <PS>execute/[:/]	{
268 				yylval.val = ACE_EXECUTE;
269 				return (ACE_PERM);
270 			}
271 <PS>delete_child/[:/]	{
272 				yylval.val = ACE_DELETE_CHILD;
273 				return (ACE_PERM);
274 			}
275 <PS>read_attributes/[:/] {
276 				yylval.val = ACE_READ_ATTRIBUTES;
277 				return (ACE_PERM);
278 			}
279 <PS>write_attributes/[:/] {
280 				yylval.val = ACE_WRITE_ATTRIBUTES;
281 			 	return (ACE_PERM);
282 			}
283 <PS>delete/[:/]		{
284 				yylval.val = ACE_DELETE;
285 				return (ACE_PERM);
286 			}
287 <PS>read_acl/[:/]	{
288 				yylval.val = ACE_READ_ACL;
289 				return (ACE_PERM);
290 			}
291 <PS>write_acl/[:/]	{
292 				yylval.val = ACE_WRITE_ACL;
293 				return (ACE_PERM);
294 			}
295 <PS>write_owner/[:/]	{
296 				yylval.val = ACE_WRITE_OWNER;
297 				return (ACE_PERM);
298 			}
299 <PS>synchronize/[:/]	{
300 				yylval.val = ACE_SYNCHRONIZE;
301 				return (ACE_PERM);
302 			}
303 <PS>{PERM_STR}		{
304 				int c;
305 
306 				c = input();
307 				unput(c);
308 				yylval.str = strdup(yytext);
309 				if (yylval.str == NULL) {
310 					yylval.val = EACL_MEM_ERROR;
311 					return (ERROR);
312 				}
313 
314 				/*
315 				 * aclent are done after permissions.
316 				 */
317 				if (isdigit(c))
318 					BEGIN US;
319 				else if (c != ':')
320 					BEGIN ES;
321 
322 				return (PERM_TOK);
323 			}
324 <PS>"/:"		{
325 				acl_error(gettext("Invalid permission /: "
326 				    "specified\n"));
327 				yylval.val = EACL_ENTRY_ERROR;
328 				return (ERROR);
329 			}
330 <PS>:			{
331 				int c;
332 
333 				c = input();
334 				unput(c);
335 				if (isdigit(c))
336 					BEGIN (US);
337 				else
338 					BEGIN AIS;
339 				return (COLON);
340 			}
341 <PS>"/"			{
342 				return (SLASH);
343 			}
344 <PS>"\n"		{
345 				acl_error(gettext("ACL entry is missing "
346 				    "permission fields\n"));
347 				yylval.val = EACL_MISSING_FIELDS;
348 				return (ERROR);
349 			}
350 <PS>. 			{
351 				if (grab_string("/:\n") != 0) {
352 					acl_error(gettext("Failed to retrieve"
353 					    " error string\n"));
354 					yylval.val = EACL_MEM_ERROR;
355 					return (ERROR);
356 				}
357 				acl_error(gettext("Invalid permission '%s' "
358 				    "specified\n"), yylval.str);
359 				free(yylval.str);
360 				yylval.val = EACL_PERM_MASK_ERROR;
361 				return (ERROR);
362 			}
363 <AIS>allow/[:,\n]	{
364 
365 				int c;
366 
367 				c = input();
368 				if (c == ',' || c == '\n')
369 					BEGIN ES;
370 				unput(c);
371 				yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE;
372 				return (ACCESS_TYPE);
373 			}
374 <AIS>deny/[:,\n]	{
375 
376 				int c;
377 
378 				c = input();
379 				if (c == ',' || c == '\n')
380 					BEGIN ES;
381 				unput(c);
382 				yylval.val = ACE_ACCESS_DENIED_ACE_TYPE;
383 				return (ACCESS_TYPE);
384 			}
385 
386 <AIS>file_inherit/[:/] {
387 				yylval.val = ACE_FILE_INHERIT_ACE;
388 				return (ACE_INHERIT);
389 			}
390 <AIS>dir_inherit/[:/]	{
391 				yylval.val = ACE_DIRECTORY_INHERIT_ACE;
392 				return (ACE_INHERIT);
393 			}
394 <AIS>no_propagate/[/:]	{
395 				yylval.val = ACE_NO_PROPAGATE_INHERIT_ACE;
396 				return (ACE_INHERIT);
397 			}
398 <AIS>inherit_only/[/:]	{
399 				yylval.val = ACE_INHERIT_ONLY_ACE;
400 				return (ACE_INHERIT);
401 			}
402 <AIS>{INHERIT_STR}	{
403 				yylval.str = strdup(yytext);
404 				if (yylval.str == NULL) {
405 					yylval.val = EACL_MEM_ERROR;
406 					return (ERROR);
407 				}
408 				return (INHERIT_TOK);
409 			}
410 <AIS>:			{
411 				int c;
412 
413 				c = input();
414 				unput(c);
415 
416 				if (isdigit(c)) {
417 					BEGIN US;
418 				}
419 				return (COLON);
420 			}
421 <AIS>"/"		{
422 				return (SLASH);
423 			}
424 <AIS>"\n"		{
425 				acl_error(
426 				    gettext("Extra data on end of ACL "
427 				    "specification\n"), yylval.str);
428 				yylval.val = EACL_UNKNOWN_DATA;
429 				return (ERROR);
430 			}
431 <AIS>.			{
432 				if (yytext[0] != '\n' && yytext[0] != '\0') {
433 					if (grab_string(":\n") != 0) {
434 						acl_error(gettext("Failed to "
435 						    "retrieve error string\n"));
436 						yylval.val = EACL_MEM_ERROR;
437 						return (ERROR);
438 					}
439 					acl_error(
440 					    gettext("Invalid inheritance or"
441 				    	    " access type '%s' specified\n"),
442 				    	    yylval.str);
443 				} else {
444 					acl_error(
445 					    gettext("No inheritance or "
446 					    "access type specified\n"),
447 					    yylval.str);
448 				}
449 
450 				free(yylval.str);
451 				yylval.val = EACL_INVALID_ACCESS_TYPE;
452 				return (ERROR);
453 			}
454 <US>{ID}		{
455 				BEGIN ES;
456 				yylval.val = atoi(yytext);
457 				return (ID);
458 			}
459 <US>.			{
460 				if (grab_string(",\n") != 0) {
461 					acl_error(gettext("Failed to retrieve"
462 					    " error string\n"));
463 					yylval.val = EACL_MEM_ERROR;
464 					return (ERROR);
465 				}
466 				acl_error(
467 				    gettext("Invalid uid/gid '%s' specified\n"),
468 			    	    yylval.str);
469 				free(yylval.str);
470 				yylval.val = EACL_ENTRY_ERROR;
471 				return (ERROR);
472 			}
473 <US>"\n"		{
474 				acl_error(gettext("Missing fields in ACL "
475 				    "specification.\nShould either have "
476 				    "inheritance flags or uid/gid "
477 				    "specified.\n"));
478 				yylval.val = EACL_ENTRY_ERROR;
479 				return (ERROR);
480 			}
481 <ES>","			{
482 				BEGIN TS;
483 				return (COMMA);
484 			}
485 <ES>.			{
486 				if (grab_string("/:\n") != 0) {
487 					acl_error(
488 					    gettext("Failed to retrieve error"
489 				    	    " string\n"));
490 					yylval.val = EACL_MEM_ERROR;
491 					return (ERROR);
492 				}
493 				acl_error(
494 				    gettext("Unrecognized data '%s' found"
495 			    	    " in ACL specification\n"), yylval.str);
496 				free(yylval.str);
497 				yylval.val = EACL_UNKNOWN_DATA;
498 				return (ERROR);
499 			}
500 <ES>"\n"		{
501 				return (NL);
502 			}
503 %%
504 
505 
506 /*
507  * pull string up to terminator of off input string.
508  * used for retrieving illegal data in ACL specification.
509  */
510 int
511 grab_string(char *terminators)
512 {
513 		int c;
514 		int done = 0;
515 		int cnt;
516 		int alloced;
517 		int error = 0;
518 		char *ptr;
519 
520 		cnt = strlen(yytext);
521 		yylval.str = calloc(cnt + 1, sizeof (char));
522 		if (yylval.str == NULL) {
523 			return (1);
524 		}
525 		alloced = cnt + 1;
526 		strcpy(yylval.str, yytext);
527 
528 		do {
529 			c = input();
530 			if (c == EOF)
531 				break;
532 
533 			for (ptr = terminators; *ptr; ptr++) {
534 				if (c == *ptr) {
535 					done = 1;
536 					break;
537 				}
538 			}
539 
540 			if (done)
541 				break;
542 
543 			if (cnt >= alloced) {
544 				yylval.str = realloc(yylval.str,
545 				    alloced + 80);
546 					alloced += 80;
547 				if (yylval.str == NULL)
548 					return (1);
549 
550 				memset(yylval.str + cnt, 0,
551 				    alloced - strlen(yylval.str));
552 			}
553 			yylval.str[strlen(yylval.str)] = c;
554 			cnt++;
555 		} while (!done);
556 
557 		return (error);
558 }
559 
560 static int
561 input(void)
562 {
563 	int c;
564 
565 	c = yybuf[yybufpos++];
566 	if (c == '\0') {
567 		return (EOF);
568 	}
569 
570 	return (c);
571 }
572 
573 static void
574 unput(int c)
575 {
576 	if (c == '\0') {
577 		return;
578 	}
579 
580 	if (yybufpos > 0) {
581 		--yybufpos;
582 	}
583 }
584 
585 /*
586  * return ACE entry type
587  */
588 int
589 ace_entry_type(int type)
590 {
591 	int ret = -1;
592 	switch (type) {
593 		case USER_TOK:
594 			ret = 0;
595 			break;
596 		case GROUP_TOK:
597 			ret = ACE_IDENTIFIER_GROUP;
598 			break;
599 		case OWNERAT_TOK:
600 			ret = ACE_OWNER;
601 			break;
602 		case GROUPAT_TOK:
603 			ret = ACE_IDENTIFIER_GROUP | ACE_GROUP;
604 			break;
605 		case EVERYONEAT_TOK:
606 			ret = ACE_EVERYONE;
607 			break;
608 	}
609 	return (ret);
610 }
611 
612 
613 /*
614  * return aclent entry type
615  */
616 int
617 aclent_entry_type(int type, int owning, int *ret)
618 {
619 
620 	*ret = 0;
621 
622 	switch (type) {
623 	case USER_TOK:
624 		*ret = (owning == 0) ? USER : USER_OBJ;
625 		break;
626 	case GROUP_TOK:
627 		*ret = (owning == 0) ? GROUP : GROUP_OBJ;
628 		break;
629 
630 	case OTHER_TOK:
631 		*ret = OTHER_OBJ;
632 		break;
633 
634 	case MASK_TOK:
635 		*ret = CLASS_OBJ;
636 		break;
637 	case DEFAULT_USER_TOK:
638 		*ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ;
639 		break;
640 	case DEFAULT_GROUP_TOK:
641 		*ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ;
642 		break;
643 	case DEFAULT_MASK_TOK:
644 		*ret = DEF_CLASS_OBJ;
645 		break;
646 	case DEFAULT_OTHER_TOK:
647 		*ret = DEF_OTHER_OBJ;
648 		break;
649 	default:
650 		return (EACL_ENTRY_ERROR);
651 	}
652 
653 	return (0);
654 }
655 
656 /*
657  * convert string into numeric id.
658  */
659 static int
660 acl_str_to_id(char *str, int *id)
661 {
662 	char *end;
663 	uid_t value;
664 
665 	value = strtol(str, &end, 10);
666 
667 	if (errno != 0 || *end != '\0')
668 		return (EACL_INVALID_USER_GROUP);
669 
670 	*id = value;
671 
672 	return (0);
673 }
674 
675 /*
676  * determine either uid/gid for given entry type
677  */
678 int
679 get_id(int entry_type, char *name, int *id)
680 {
681 	struct passwd *pw;
682 	struct group *gr;
683 	int error;
684 
685 	if (entry_type == USER_TOK || entry_type == DEFAULT_USER_TOK) {
686 		pw = getpwnam(name);
687 		if (pw) {
688 			*id = pw->pw_uid;
689 			return (0);
690 		}
691 	} else {
692 		gr = getgrnam(name);
693 		if (gr) {
694 			*id = gr->gr_gid;
695 			return (0);
696 		}
697 	}
698 
699 	/*
700 	 * getpwnam or getgrnam failed, try and see if
701 	 * they are numeric strings.
702 	 */
703 	error = acl_str_to_id(name, id);
704 
705 	if (error)
706 		return (error);
707 	return (0);
708 }
709 /*
710  * reset beginning state to TS and set character position
711  * back to zero.
712  */
713 void
714 yyreset()
715 {
716 	yybufpos = 0;
717 	BEGIN TS;
718 }
719 
720