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} { 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' " 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} { 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 of off input string. 613 * used for retrieving illegal data in ACL specification. 614 */ 615 int 616 grab_string(char *terminators) 617 { 618 int c; 619 int done = 0; 620 int cnt; 621 int alloced; 622 int error = 0; 623 char *ptr; 624 625 cnt = strlen(yytext); 626 yylval.str = calloc(cnt + 1, sizeof (char)); 627 if (yylval.str == NULL) { 628 return (1); 629 } 630 alloced = cnt + 1; 631 strcpy(yylval.str, yytext); 632 633 do { 634 c = input(); 635 if (c == EOF) 636 break; 637 638 for (ptr = terminators; *ptr; ptr++) { 639 if (c == *ptr) { 640 done = 1; 641 break; 642 } 643 } 644 645 if (done) 646 break; 647 648 if (cnt >= alloced) { 649 yylval.str = realloc(yylval.str, 650 alloced + 80); 651 alloced += 80; 652 if (yylval.str == NULL) 653 return (1); 654 655 memset(yylval.str + cnt, 0, 656 alloced - strlen(yylval.str)); 657 } 658 yylval.str[strlen(yylval.str)] = c; 659 cnt++; 660 } while (!done); 661 662 return (error); 663 } 664 665 static int 666 input(void) 667 { 668 int c; 669 670 c = yybuf[yybufpos++]; 671 if (c == '\0') { 672 return (EOF); 673 } 674 675 return (c); 676 } 677 678 static void 679 unput(int c) 680 { 681 if (c == '\0') { 682 return; 683 } 684 685 if (yybufpos > 0) { 686 --yybufpos; 687 } 688 } 689 690 /* 691 * return ACE entry type 692 */ 693 int 694 ace_entry_type(int type) 695 { 696 int ret = -1; 697 switch (type) { 698 case USER_TOK: 699 ret = 0; 700 break; 701 case GROUP_TOK: 702 ret = ACE_IDENTIFIER_GROUP; 703 break; 704 case OWNERAT_TOK: 705 ret = ACE_OWNER; 706 break; 707 case GROUPAT_TOK: 708 ret = ACE_IDENTIFIER_GROUP | ACE_GROUP; 709 break; 710 case EVERYONEAT_TOK: 711 ret = ACE_EVERYONE; 712 break; 713 } 714 return (ret); 715 } 716 717 718 /* 719 * return aclent entry type 720 */ 721 int 722 aclent_entry_type(int type, int owning, int *ret) 723 { 724 725 *ret = 0; 726 727 switch (type) { 728 case USER_TOK: 729 *ret = (owning == 0) ? USER : USER_OBJ; 730 break; 731 case GROUP_TOK: 732 *ret = (owning == 0) ? GROUP : GROUP_OBJ; 733 break; 734 735 case OTHER_TOK: 736 *ret = OTHER_OBJ; 737 break; 738 739 case MASK_TOK: 740 *ret = CLASS_OBJ; 741 break; 742 case DEFAULT_USER_TOK: 743 *ret = (owning == 0) ? DEF_USER : DEF_USER_OBJ; 744 break; 745 case DEFAULT_GROUP_TOK: 746 *ret = (owning == 0) ? DEF_GROUP : DEF_GROUP_OBJ; 747 break; 748 case DEFAULT_MASK_TOK: 749 *ret = DEF_CLASS_OBJ; 750 break; 751 case DEFAULT_OTHER_TOK: 752 *ret = DEF_OTHER_OBJ; 753 break; 754 default: 755 return (EACL_ENTRY_ERROR); 756 } 757 758 return (0); 759 } 760 761 /* 762 * convert string into numeric id. 763 */ 764 static int 765 acl_str_to_id(char *str, int *id) 766 { 767 char *end; 768 uid_t value; 769 770 errno = 0; 771 value = strtol(str, &end, 10); 772 773 if (errno != 0 || *end != '\0') 774 return (EACL_INVALID_USER_GROUP); 775 776 *id = value; 777 778 return (0); 779 } 780 781 /* 782 * determine either uid/gid for given entry type 783 */ 784 int 785 get_id(int entry_type, char *name, int *id) 786 { 787 struct passwd *pw; 788 struct group *gr; 789 int error; 790 791 if (entry_type == USER_TOK || entry_type == DEFAULT_USER_TOK) { 792 pw = getpwnam(name); 793 if (pw) { 794 *id = pw->pw_uid; 795 return (0); 796 } 797 } else { 798 gr = getgrnam(name); 799 if (gr) { 800 *id = gr->gr_gid; 801 return (0); 802 } 803 } 804 805 /* 806 * getpwnam or getgrnam failed, try and see if 807 * they are numeric strings. 808 */ 809 error = acl_str_to_id(name, id); 810 811 if (error) 812 return (error); 813 return (0); 814 } 815 /* 816 * reset beginning state to TS and set character position 817 * back to zero. 818 */ 819 void 820 yyreset() 821 { 822 yybufpos = 0; 823 BEGIN TS; 824 } 825 826