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(dgettext(TEXT_DOMAIN, 182 "Failed to retrieve" 183 " error string.\n")); 184 yylval.val = EACL_MEM_ERROR; 185 return (ERROR); 186 } 187 acl_error(dgettext(TEXT_DOMAIN, 188 "Invalid ACL entry " 189 "type '%s' specified.\n"), yylval.str); 190 free(yylval.str); 191 yylval.val = EACL_ENTRY_ERROR; 192 return (ERROR); 193 } 194 <NS>: { 195 BEGIN PS; 196 return (COLON); 197 } 198 <NS>{LOGNAME} { 199 yylval.str = strdup(yytext); 200 if (yylval.str == NULL) { 201 yylval.val = EACL_MEM_ERROR; 202 return (ERROR); 203 } 204 yylval.str[strlen(yylval.str) -1] = '\0'; 205 BEGIN PS; 206 return (IDNAME); 207 } 208 <NS>{BADLOGNAME} { 209 acl_error(dgettext(TEXT_DOMAIN, 210 "Missing fields after " 211 "user/group '%s'.\n"), yytext); 212 yylval.val = EACL_MISSING_FIELDS; 213 return (ERROR); 214 } 215 <NS>"\n" { 216 acl_error(dgettext(TEXT_DOMAIN, 217 "Missing user/group name" 218 " from ACL specification.\n")); 219 yylval.val = EACL_MISSING_FIELDS; 220 return (ERROR); 221 } 222 <NS>. { 223 int error; 224 225 error = grab_string(":,\n"); 226 if (error != 0) { 227 acl_error(dgettext(TEXT_DOMAIN, 228 "Invalid user/group " 229 "name specification.\n")); 230 yylval.val = EACL_INVALID_USER_GROUP; 231 } else { 232 acl_error(dgettext(TEXT_DOMAIN, 233 "User/Group name " 234 "'%s' not specified correctly.\n"), 235 yylval.str); 236 free(yylval.str); 237 yylval.val = EACL_ENTRY_ERROR; 238 } 239 return (ERROR); 240 } 241 <PS>read_data/[:/] { 242 yylval.val = ACE_READ_DATA; 243 return (ACE_PERM); 244 } 245 <PS>list_directory/[:/] { 246 yylval.val = ACE_LIST_DIRECTORY; 247 return (ACE_PERM); 248 } 249 <PS>write_data/[:/] { 250 yylval.val = ACE_WRITE_DATA; 251 return (ACE_PERM); 252 } 253 <PS>add_file/[:/] { 254 yylval.val = ACE_ADD_FILE; 255 return (ACE_PERM); 256 } 257 <PS>append_data/[:/] { 258 yylval.val = ACE_APPEND_DATA; 259 return (ACE_PERM); 260 } 261 <PS>add_subdirectory/[:/] { 262 yylval.val = ACE_ADD_SUBDIRECTORY; 263 return (ACE_PERM); 264 } 265 <PS>read_xattr/[:/] { 266 yylval.val = ACE_READ_NAMED_ATTRS; 267 return (ACE_PERM); 268 } 269 <PS>write_xattr/[:/] { 270 yylval.val = ACE_WRITE_NAMED_ATTRS; 271 return (ACE_PERM); 272 } 273 <PS>execute/[:/] { 274 yylval.val = ACE_EXECUTE; 275 return (ACE_PERM); 276 } 277 <PS>delete_child/[:/] { 278 yylval.val = ACE_DELETE_CHILD; 279 return (ACE_PERM); 280 } 281 <PS>read_attributes/[:/] { 282 yylval.val = ACE_READ_ATTRIBUTES; 283 return (ACE_PERM); 284 } 285 <PS>write_attributes/[:/] { 286 yylval.val = ACE_WRITE_ATTRIBUTES; 287 return (ACE_PERM); 288 } 289 <PS>delete/[:/] { 290 yylval.val = ACE_DELETE; 291 return (ACE_PERM); 292 } 293 <PS>read_acl/[:/] { 294 yylval.val = ACE_READ_ACL; 295 return (ACE_PERM); 296 } 297 <PS>write_acl/[:/] { 298 yylval.val = ACE_WRITE_ACL; 299 return (ACE_PERM); 300 } 301 <PS>write_owner/[:/] { 302 yylval.val = ACE_WRITE_OWNER; 303 return (ACE_PERM); 304 } 305 <PS>synchronize/[:/] { 306 yylval.val = ACE_SYNCHRONIZE; 307 return (ACE_PERM); 308 } 309 <PS>{PERM_STR}/[:,\n] { 310 int c; 311 312 c = input(); 313 unput(c); 314 yylval.str = strdup(yytext); 315 if (yylval.str == NULL) { 316 yylval.val = EACL_MEM_ERROR; 317 return (ERROR); 318 } 319 320 /* 321 * aclent are done after permissions. 322 */ 323 if (isdigit(c)) 324 BEGIN US; 325 else if (c != ':') 326 BEGIN ES; 327 328 return (PERM_TOK); 329 } 330 <PS>"/:" { 331 acl_error(dgettext(TEXT_DOMAIN, 332 "Invalid permission /: specified.\n")); 333 yylval.val = EACL_ENTRY_ERROR; 334 return (ERROR); 335 } 336 <PS>: { 337 int c; 338 339 c = input(); 340 unput(c); 341 if (isdigit(c)) 342 BEGIN (US); 343 else 344 BEGIN AIS; 345 return (COLON); 346 } 347 <PS>"/" { 348 return (SLASH); 349 } 350 <PS>"\n" { 351 acl_error(dgettext(TEXT_DOMAIN, 352 "ACL entry is missing " 353 "permission fields.\n")); 354 yylval.val = EACL_MISSING_FIELDS; 355 return (ERROR); 356 } 357 <PS>. { 358 if (grab_string("/:,\n") != 0) { 359 acl_error(dgettext(TEXT_DOMAIN, 360 "Failed to retrieve" 361 " error string.\n")); 362 yylval.val = EACL_MEM_ERROR; 363 return (ERROR); 364 } 365 acl_error(dgettext(TEXT_DOMAIN, 366 "Invalid permission(s) '%s' " 367 "specified.\n"), yylval.str); 368 free(yylval.str); 369 yylval.val = EACL_PERM_MASK_ERROR; 370 return (ERROR); 371 } 372 <AS>allow/[:,\n] { 373 374 int c; 375 376 c = input(); 377 unput(c); 378 if (c == ',' || c == '\n') 379 BEGIN ES; 380 else 381 BEGIN US; 382 yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE; 383 return (ACCESS_TYPE); 384 } 385 <AS>deny/[:,\n] { 386 387 int c; 388 389 c = input(); 390 unput(c); 391 if (c == ',' || c == '\n') 392 BEGIN ES; 393 else 394 BEGIN US; 395 396 yylval.val = ACE_ACCESS_DENIED_ACE_TYPE; 397 return (ACCESS_TYPE); 398 } 399 <AS>: { 400 401 acl_error(dgettext(TEXT_DOMAIN, 402 "Invalid Access type " 403 "specified.\nThe field is blank, when" 404 " it should be either allow or deny.\n")); 405 yylval.val = EACL_INVALID_ACCESS_TYPE; 406 return (ERROR); 407 } 408 <AS>"\n" { 409 acl_error(dgettext(TEXT_DOMAIN, 410 "ACL access type must be specified.\n")); 411 yylval.val = EACL_INVALID_ACCESS_TYPE; 412 return (ERROR); 413 } 414 <AS>. { 415 if (yytext[0] != '\n' && yytext[0] != '\0') { 416 if (grab_string(":,\n") != 0) { 417 acl_error(dgettext(TEXT_DOMAIN, 418 "Failed to " 419 "retrieve error " 420 "string.\n")); 421 yylval.val = EACL_MEM_ERROR; 422 return (ERROR); 423 } 424 acl_error( 425 dgettext(TEXT_DOMAIN, 426 "Invalid access " 427 "type '%s' specified.\n"), 428 yylval.str); 429 } else { 430 acl_error( 431 dgettext(TEXT_DOMAIN, 432 "No access " 433 "type specified.\n"), yylval.str); 434 } 435 436 free(yylval.str); 437 yylval.val = EACL_INVALID_ACCESS_TYPE; 438 return (ERROR); 439 } 440 <AIS>allow/[:,\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 yylval.val = ACE_ACCESS_ALLOWED_ACE_TYPE; 451 return (ACCESS_TYPE); 452 } 453 <AIS>deny/[:,\n] { 454 455 int c; 456 457 c = input(); 458 unput(c); 459 if (c == ',' || c == '\n') 460 BEGIN ES; 461 else 462 BEGIN US; 463 464 yylval.val = ACE_ACCESS_DENIED_ACE_TYPE; 465 return (ACCESS_TYPE); 466 } 467 <AIS>file_inherit/[:/] { 468 yylval.val = ACE_FILE_INHERIT_ACE; 469 return (ACE_INHERIT); 470 } 471 <AIS>dir_inherit/[:/] { 472 yylval.val = ACE_DIRECTORY_INHERIT_ACE; 473 return (ACE_INHERIT); 474 } 475 <AIS>no_propagate/[/:] { 476 yylval.val = ACE_NO_PROPAGATE_INHERIT_ACE; 477 return (ACE_INHERIT); 478 } 479 <AIS>inherit_only/[/:] { 480 yylval.val = ACE_INHERIT_ONLY_ACE; 481 return (ACE_INHERIT); 482 } 483 <AIS>{INHERIT_STR}/[:] { 484 yylval.str = strdup(yytext); 485 if (yylval.str == NULL) { 486 yylval.val = EACL_MEM_ERROR; 487 return (ERROR); 488 } 489 return (INHERIT_TOK); 490 } 491 <AIS>: { 492 /* 493 * Only inheritance fields should hit this. 494 * allow/deny fields match on ":" as part 495 * of the regexp. 496 */ 497 BEGIN AS; 498 return (COLON); 499 } 500 <AIS>"/" { 501 return (SLASH); 502 } 503 <AIS>"\n" { 504 acl_error( 505 dgettext(TEXT_DOMAIN, 506 "Invalid ACL specification." 507 "\nWas expecting to find" 508 " access type or inheritance flags.\n"), 509 yylval.str); 510 yylval.val = EACL_UNKNOWN_DATA; 511 return (ERROR); 512 } 513 <AIS>. { 514 if (yytext[0] != '\n' && yytext[0] != '\0') { 515 if (grab_string(":,\n") != 0) { 516 acl_error(dgettext(TEXT_DOMAIN, 517 "Failed to " 518 "retrieve error " 519 "string.\n")); 520 yylval.val = EACL_MEM_ERROR; 521 return (ERROR); 522 } 523 acl_error( 524 dgettext(TEXT_DOMAIN, 525 "Invalid inheritance or" 526 " access type '%s' specified.\n"), 527 yylval.str); 528 } else { 529 acl_error( 530 dgettext(TEXT_DOMAIN, 531 "No inheritance or " 532 "access type specified.\n"), 533 yylval.str); 534 } 535 536 free(yylval.str); 537 yylval.val = EACL_INVALID_ACCESS_TYPE; 538 return (ERROR); 539 } 540 <US>{ID}/[,\n] { 541 BEGIN ES; 542 yylval.val = atoi(yytext); 543 return (ID); 544 } 545 <US>: { 546 return (COLON); 547 } 548 <US>{INHERIT_STR} { /* 549 * Catch specific error to produce 550 * nice message for users who are trying 551 * to use old syntax format which had 552 * inheritance flags as the last field. 553 */ 554 acl_error(dgettext(TEXT_DOMAIN, 555 "Access type should be final" 556 " field in ACL specification.\n")); 557 yylval.val = EACL_ENTRY_ERROR; 558 return (ERROR); 559 } 560 <US>. { 561 if (grab_string(",\n") != 0) { 562 acl_error(dgettext(TEXT_DOMAIN, 563 "Failed to retrieve" 564 " error string.\n")); 565 yylval.val = EACL_MEM_ERROR; 566 return (ERROR); 567 } 568 acl_error( 569 dgettext(TEXT_DOMAIN, 570 "Invalid data ':%s' specified" 571 " on end of ACL.\n"), yylval.str); 572 free(yylval.str); 573 yylval.val = EACL_ENTRY_ERROR; 574 return (ERROR); 575 } 576 <US>"\n" { 577 acl_error(dgettext(TEXT_DOMAIN, 578 "Missing fields in ACL " 579 "specification.\nWas expecting to find " 580 "uid/gid.\n")); 581 yylval.val = EACL_ENTRY_ERROR; 582 return (ERROR); 583 } 584 <ES>"," { 585 BEGIN TS; 586 return (COMMA); 587 } 588 <ES>. { 589 if (grab_string("/:,\n") != 0) { 590 acl_error( 591 dgettext(TEXT_DOMAIN, 592 "Failed to retrieve error" 593 " string.\n")); 594 yylval.val = EACL_MEM_ERROR; 595 return (ERROR); 596 } 597 acl_error( 598 dgettext(TEXT_DOMAIN, 599 "Unrecognized data '%s' found" 600 " in ACL specification.\n"), yylval.str); 601 free(yylval.str); 602 yylval.val = EACL_UNKNOWN_DATA; 603 return (ERROR); 604 } 605 <ES>"\n" { 606 return (NL); 607 } 608 %% 609 610 611 /* 612 * Pull string up to terminator off of input string. 613 * used for retrieving illegal data in ACL specification. 614 * 615 * The first set of characters is retrieved from yytext. 616 * subseequent characters are pulled from the input stream, 617 * until either EOF or one of the requested terminators is scene. 618 * Result is returned in yylval.str which is malloced. 619 */ 620 int 621 grab_string(char *terminators) 622 { 623 int c; 624 int done = 0; 625 int cnt; 626 int alloced; 627 int error = 0; 628 char *ptr; 629 630 cnt = strlen(yytext); 631 yylval.str = calloc(cnt + 1, sizeof (char)); 632 if (yylval.str == NULL) { 633 return (1); 634 } 635 alloced = cnt + 1; 636 strcpy(yylval.str, yytext); 637 638 do { 639 c = input(); 640 if (c == EOF) 641 break; 642 643 for (ptr = terminators; *ptr; ptr++) { 644 if (c == *ptr) { 645 done = 1; 646 break; 647 } 648 } 649 650 if (done) 651 break; 652 653 if (cnt + 1 >= alloced) { 654 yylval.str = realloc(yylval.str, 655 alloced + 80); 656 alloced += 80; 657 if (yylval.str == NULL) 658 return (1); 659 660 memset(yylval.str + cnt, 0, 661 alloced - strlen(yylval.str)); 662 } 663 yylval.str[strlen(yylval.str)] = c; 664 cnt++; 665 } while (!done); 666 667 return (error); 668 } 669 670 static int 671 input(void) 672 { 673 int c; 674 675 c = yybuf[yybufpos++]; 676 if (c == '\0') { 677 return (EOF); 678 } 679 680 return (c); 681 } 682 683 static void 684 unput(int c) 685 { 686 if (c == '\0') { 687 return; 688 } 689 690 if (yybufpos > 0) { 691 --yybufpos; 692 } 693 } 694 695 /* 696 * return ACE entry type 697 */ 698 int 699 ace_entry_type(int type) 700 { 701 int ret = -1; 702 switch (type) { 703 case USER_TOK: 704 ret = 0; 705 break; 706 case GROUP_TOK: 707 ret = ACE_IDENTIFIER_GROUP; 708 break; 709 case OWNERAT_TOK: 710 ret = ACE_OWNER; 711 break; 712 case GROUPAT_TOK: 713 ret = ACE_IDENTIFIER_GROUP | ACE_GROUP; 714 break; 715 case EVERYONEAT_TOK: 716 ret = ACE_EVERYONE; 717 break; 718 } 719 return (ret); 720 } 721 722 723 /* 724 * return aclent entry type 725 */ 726 int 727 aclent_entry_type(int type, int owning, int *ret) 728 { 729 730 *ret = 0; 731 732 switch (type) { 733 case USER_TOK: 734 *ret = (owning == 0) ? USER : USER_OBJ; 735 break; 736 case GROUP_TOK: 737 *ret = (owning == 0) ? GROUP : GROUP_OBJ; 738 break; 739 case OTHER_TOK: 740 *ret = OTHER_OBJ; 741 break; 742 case MASK_TOK: 743 *ret = CLASS_OBJ; 744 break; 745 case DEFAULT_USER_TOK: 746 *ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ; 747 break; 748 case DEFAULT_GROUP_TOK: 749 *ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ; 750 break; 751 case DEFAULT_MASK_TOK: 752 *ret = DEF_CLASS_OBJ; 753 break; 754 case DEFAULT_OTHER_TOK: 755 *ret = DEF_OTHER_OBJ; 756 break; 757 default: 758 return (EACL_ENTRY_ERROR); 759 } 760 761 return (0); 762 } 763 764 /* 765 * convert string into numeric id. 766 */ 767 static int 768 acl_str_to_id(char *str, int *id) 769 { 770 char *end; 771 uid_t value; 772 773 errno = 0; 774 value = strtol(str, &end, 10); 775 776 if (errno != 0 || *end != '\0') 777 return (EACL_INVALID_USER_GROUP); 778 779 *id = value; 780 781 return (0); 782 } 783 784 /* 785 * determine either uid/gid for given entry type 786 */ 787 int 788 get_id(int entry_type, char *name, int *id) 789 { 790 struct passwd *pw; 791 struct group *gr; 792 int error; 793 794 /* 795 * First see if uid/gid is an all-numeric value 796 * otherwise, try getpwnam/getgrnam. 797 */ 798 error = acl_str_to_id(name, id); 799 800 if (error != 0) { 801 if (entry_type == USER_TOK || entry_type == DEFAULT_USER_TOK) { 802 pw = getpwnam(name); 803 if (pw) { 804 *id = pw->pw_uid; 805 error = 0; 806 } 807 } else { 808 gr = getgrnam(name); 809 if (gr) { 810 *id = gr->gr_gid; 811 error = 0; 812 } 813 } 814 } 815 816 return (error); 817 } 818 /* 819 * reset beginning state to TS and set character position 820 * back to zero. 821 */ 822 void 823 yyreset() 824 { 825 yybufpos = 0; 826 BEGIN TS; 827 } 828 829