Home | History | Annotate | Download | only in common
      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