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