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 2006 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 <errno.h> 31 #include "acl.tab.h" 32 33 #ifdef input 34 #undef input 35 #endif 36 37 #ifdef unput 38 #undef unput 39 #endif 40 41 int grab_string(char *terminators); 42 static int input(); 43 static void unput(int); 44 45 int 46 yyerror(const char *s) 47 { 48 return (0); 49 } 50 51 int 52 yywrap(void) 53 { 54 return (1); 55 } 56 57 extern char *yybuf; 58 int yybufpos; 59 60 %} 61 62 %s TS NS PS AIS AS US ES 63 /* 64 * TS = type state 65 * NS = name state 66 * PS = Permission state 67 * AIS = Allow/deny/inheritance state 68 * AS = Allow state (only used when inheritance detected) 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 <AS>allow/[:,\n] { 364 365 int c; 366 367 c = input(); 368 unput(c); 369 if (c == ',' || c == '\n') 370 BEGIN ES; 371 else 372 BEGIN US; 373 yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE; 374 return (ACCESS_TYPE); 375 } 376 <AS>deny/[:,\n] { 377 378 int c; 379 380 c = input(); 381 unput(c); 382 if (c == ',' || c == '\n') 383 BEGIN ES; 384 else 385 BEGIN US; 386 387 yylval.val = ACE_ACCESS_DENIED_ACE_TYPE; 388 return (ACCESS_TYPE); 389 } 390 <AS>: { 391 392 acl_error(gettext("Invalid Access type " 393 "specified.\nThe field is blank, when" 394 " it should be either allow or deny.\n")); 395 yylval.val = EACL_INVALID_ACCESS_TYPE; 396 return (ERROR); 397 } 398 <AS>"\n" { 399 acl_error(gettext("ACL access type must " 400 "be specified.\n")); 401 yylval.val = EACL_INVALID_ACCESS_TYPE; 402 return (ERROR); 403 } 404 <AS>. { 405 if (yytext[0] != '\n' && yytext[0] != '\0') { 406 if (grab_string(":\n") != 0) { 407 acl_error(gettext("Failed to " 408 "retrieve error " 409 "string.\n")); 410 yylval.val = EACL_MEM_ERROR; 411 return (ERROR); 412 } 413 acl_error( 414 gettext("Invalid access " 415 "type '%s' specified.\n"), 416 yylval.str); 417 } else { 418 acl_error( 419 gettext("No access " 420 "type specified.\n"), yylval.str); 421 } 422 423 free(yylval.str); 424 yylval.val = EACL_INVALID_ACCESS_TYPE; 425 return (ERROR); 426 } 427 <AIS>allow/[:,\n] { 428 429 int c; 430 431 c = input(); 432 unput(c); 433 if (c == ',' || c == '\n') 434 BEGIN ES; 435 else 436 BEGIN US; 437 yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE; 438 return (ACCESS_TYPE); 439 } 440 <AIS>deny/[:,\n] { 441 442 int c; 443 444 c = input(); 445 unput(c); 446 if (c == ',' || c == '\n') 447 BEGIN ES; 448 else 449 BEGIN US; 450 451 yylval.val = ACE_ACCESS_DENIED_ACE_TYPE; 452 return (ACCESS_TYPE); 453 } 454 <AIS>file_inherit/[:/] { 455 yylval.val = ACE_FILE_INHERIT_ACE; 456 return (ACE_INHERIT); 457 } 458 <AIS>dir_inherit/[:/] { 459 yylval.val = ACE_DIRECTORY_INHERIT_ACE; 460 return (ACE_INHERIT); 461 } 462 <AIS>no_propagate/[/:] { 463 yylval.val = ACE_NO_PROPAGATE_INHERIT_ACE; 464 return (ACE_INHERIT); 465 } 466 <AIS>inherit_only/[/:] { 467 yylval.val = ACE_INHERIT_ONLY_ACE; 468 return (ACE_INHERIT); 469 } 470 <AIS>{INHERIT_STR}/[:] { 471 yylval.str = strdup(yytext); 472 if (yylval.str == NULL) { 473 yylval.val = EACL_MEM_ERROR; 474 return (ERROR); 475 } 476 return (INHERIT_TOK); 477 } 478 <AIS>: { 479 /* 480 * Only inheritance fields should hit this. 481 * allow/deny fields match on ":" as part 482 * of the regexp. 483 */ 484 BEGIN AS; 485 return (COLON); 486 } 487 <AIS>"/" { 488 return (SLASH); 489 } 490 <AIS>"\n" { 491 acl_error( 492 gettext("Invalid ACL specification." 493 "\nWas expecting to find" 494 " access type or inheritance flags.\n"), 495 yylval.str); 496 yylval.val = EACL_UNKNOWN_DATA; 497 return (ERROR); 498 } 499 <AIS>. { 500 if (yytext[0] != '\n' && yytext[0] != '\0') { 501 if (grab_string(":\n") != 0) { 502 acl_error(gettext("Failed to " 503 "retrieve error " 504 "string.\n")); 505 yylval.val = EACL_MEM_ERROR; 506 return (ERROR); 507 } 508 acl_error( 509 gettext("Invalid inheritance or" 510 " access type '%s' specified.\n"), 511 yylval.str); 512 } else { 513 acl_error( 514 gettext("No inheritance or " 515 "access type specified.\n"), 516 yylval.str); 517 } 518 519 free(yylval.str); 520 yylval.val = EACL_INVALID_ACCESS_TYPE; 521 return (ERROR); 522 } 523 <US>{ID} { 524 BEGIN ES; 525 yylval.val = atoi(yytext); 526 return (ID); 527 } 528 <US>: { 529 return (COLON); 530 } 531 <US>{INHERIT_STR} { /* 532 * Catch specific error to produce 533 * nice message for users who are trying 534 * to use old syntax format which had 535 * inheritance flags as the last field. 536 */ 537 acl_error(gettext("Access type should be final" 538 " field in ACL specification.\n")); 539 yylval.val = EACL_ENTRY_ERROR; 540 return (ERROR); 541 } 542 <US>. { 543 if (grab_string(",\n") != 0) { 544 acl_error(gettext("Failed to retrieve" 545 " error string.\n")); 546 yylval.val = EACL_MEM_ERROR; 547 return (ERROR); 548 } 549 acl_error( 550 gettext("Invalid data ':%s' specified" 551 " on end of ACL.\n"), yylval.str); 552 free(yylval.str); 553 yylval.val = EACL_ENTRY_ERROR; 554 return (ERROR); 555 } 556 <US>"\n" { 557 acl_error(gettext("Missing fields in ACL " 558 "specification.\nWas expecting to find " 559 "uid/gid.\n")); 560 yylval.val = EACL_ENTRY_ERROR; 561 return (ERROR); 562 } 563 <ES>"," { 564 BEGIN TS; 565 return (COMMA); 566 } 567 <ES>. { 568 if (grab_string("/:\n") != 0) { 569 acl_error( 570 gettext("Failed to retrieve error" 571 " string.\n")); 572 yylval.val = EACL_MEM_ERROR; 573 return (ERROR); 574 } 575 acl_error( 576 gettext("Unrecognized data '%s' found" 577 " in ACL specification.\n"), yylval.str); 578 free(yylval.str); 579 yylval.val = EACL_UNKNOWN_DATA; 580 return (ERROR); 581 } 582 <ES>"\n" { 583 return (NL); 584 } 585 %% 586 587 588 /* 589 * pull string up to terminator of off input string. 590 * used for retrieving illegal data in ACL specification. 591 */ 592 int 593 grab_string(char *terminators) 594 { 595 int c; 596 int done = 0; 597 int cnt; 598 int alloced; 599 int error = 0; 600 char *ptr; 601 602 cnt = strlen(yytext); 603 yylval.str = calloc(cnt + 1, sizeof (char)); 604 if (yylval.str == NULL) { 605 return (1); 606 } 607 alloced = cnt + 1; 608 strcpy(yylval.str, yytext); 609 610 do { 611 c = input(); 612 if (c == EOF) 613 break; 614 615 for (ptr = terminators; *ptr; ptr++) { 616 if (c == *ptr) { 617 done = 1; 618 break; 619 } 620 } 621 622 if (done) 623 break; 624 625 if (cnt >= alloced) { 626 yylval.str = realloc(yylval.str, 627 alloced + 80); 628 alloced += 80; 629 if (yylval.str == NULL) 630 return (1); 631 632 memset(yylval.str + cnt, 0, 633 alloced - strlen(yylval.str)); 634 } 635 yylval.str[strlen(yylval.str)] = c; 636 cnt++; 637 } while (!done); 638 639 return (error); 640 } 641 642 static int 643 input(void) 644 { 645 int c; 646 647 c = yybuf[yybufpos++]; 648 if (c == '\0') { 649 return (EOF); 650 } 651 652 return (c); 653 } 654 655 static void 656 unput(int c) 657 { 658 if (c == '\0') { 659 return; 660 } 661 662 if (yybufpos > 0) { 663 --yybufpos; 664 } 665 } 666 667 /* 668 * return ACE entry type 669 */ 670 int 671 ace_entry_type(int type) 672 { 673 int ret = -1; 674 switch (type) { 675 case USER_TOK: 676 ret = 0; 677 break; 678 case GROUP_TOK: 679 ret = ACE_IDENTIFIER_GROUP; 680 break; 681 case OWNERAT_TOK: 682 ret = ACE_OWNER; 683 break; 684 case GROUPAT_TOK: 685 ret = ACE_IDENTIFIER_GROUP | ACE_GROUP; 686 break; 687 case EVERYONEAT_TOK: 688 ret = ACE_EVERYONE; 689 break; 690 } 691 return (ret); 692 } 693 694 695 /* 696 * return aclent entry type 697 */ 698 int 699 aclent_entry_type(int type, int owning, int *ret) 700 { 701 702 *ret = 0; 703 704 switch (type) { 705 case USER_TOK: 706 *ret = (owning == 0) ? USER : USER_OBJ; 707 break; 708 case GROUP_TOK: 709 *ret = (owning == 0) ? GROUP : GROUP_OBJ; 710 break; 711 712 case OTHER_TOK: 713 *ret = OTHER_OBJ; 714 break; 715 716 case MASK_TOK: 717 *ret = CLASS_OBJ; 718 break; 719 case DEFAULT_USER_TOK: 720 *ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ; 721 break; 722 case DEFAULT_GROUP_TOK: 723 *ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ; 724 break; 725 case DEFAULT_MASK_TOK: 726 *ret = DEF_CLASS_OBJ; 727 break; 728 case DEFAULT_OTHER_TOK: 729 *ret = DEF_OTHER_OBJ; 730 break; 731 default: 732 return (EACL_ENTRY_ERROR); 733 } 734 735 return (0); 736 } 737 738 /* 739 * convert string into numeric id. 740 */ 741 static int 742 acl_str_to_id(char *str, int *id) 743 { 744 char *end; 745 uid_t value; 746 747 errno = 0; 748 value = strtol(str, &end, 10); 749 750 if (errno != 0 || *end != '\0') 751 return (EACL_INVALID_USER_GROUP); 752 753 *id = value; 754 755 return (0); 756 } 757 758 /* 759 * determine either uid/gid for given entry type 760 */ 761 int 762 get_id(int entry_type, char *name, int *id) 763 { 764 struct passwd *pw; 765 struct group *gr; 766 int error; 767 768 if (entry_type == USER_TOK || entry_type == DEFAULT_USER_TOK) { 769 pw = getpwnam(name); 770 if (pw) { 771 *id = pw->pw_uid; 772 return (0); 773 } 774 } else { 775 gr = getgrnam(name); 776 if (gr) { 777 *id = gr->gr_gid; 778 return (0); 779 } 780 } 781 782 /* 783 * getpwnam or getgrnam failed, try and see if 784 * they are numeric strings. 785 */ 786 error = acl_str_to_id(name, id); 787 788 if (error) 789 return (error); 790 return (0); 791 } 792 /* 793 * reset beginning state to TS and set character position 794 * back to zero. 795 */ 796 void 797 yyreset() 798 { 799 yybufpos = 0; 800 BEGIN TS; 801 } 802 803