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 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 /* 30 * Copyright (c) 2016 by Delphix. All rights reserved. 31 */ 32 33 #ifndef UUCHECK 34 #include "uucp.h" 35 #endif 36 37 38 /* field array indexes for PERMISSIONS parameters */ 39 #define U_LOGNAME 0 40 #define U_MACHINE 1 41 #define U_CALLBACK 2 42 #define U_REQUEST 3 43 #define U_SENDFILES 4 44 #define U_READPATH 5 45 #define U_WRITEPATH 6 46 #define U_NOREADPATH 7 47 #define U_NOWRITEPATH 8 48 #define U_MYNAME 9 49 #define U_COMMANDS 10 50 #define U_VALIDATE 11 51 #define U_PUBDIR 12 52 #define U_DIRECT 13 53 #define U_ALIAS 14 54 #define U_PATH 15 55 /* NUMFLDS should be one more than the highest U_ value */ 56 #define NUMFLDS 16 57 58 /* fields found in PERMISSIONS for requested system/login */ 59 static char *_Flds[NUMFLDS]; 60 61 /* keyword/value structure */ 62 struct keywords { 63 char* kword; 64 int kvalue; 65 }; 66 static struct keywords _Kwords[] = { 67 {"LOGNAME", U_LOGNAME}, 68 {"MACHINE", U_MACHINE}, 69 {"CALLBACK", U_CALLBACK}, 70 {"REQUEST", U_REQUEST}, 71 {"SENDFILES", U_SENDFILES}, 72 {"READ", U_READPATH}, 73 {"WRITE", U_WRITEPATH}, 74 {"NOREAD", U_NOREADPATH}, 75 {"NOWRITE", U_NOWRITEPATH}, 76 {"MYNAME", U_MYNAME}, 77 {"COMMANDS", U_COMMANDS}, 78 {"VALIDATE", U_VALIDATE}, 79 {"PUBDIR", U_PUBDIR}, 80 {"DIRECT", U_DIRECT}, 81 {"ALIAS", U_ALIAS}, 82 {"PATH", U_PATH}, 83 }; 84 85 #define MAXCMDS 30 86 #define MAXPATHS 20 87 88 /* for all options on paths - read, write, noread, nowrite */ 89 /* NB: all pointers assumed to point to static data */ 90 static char *_RPaths[MAXPATHS+1]; 91 static char *_WPaths[MAXPATHS+1]; 92 static char *_NoRPaths[MAXPATHS+1]; 93 static char *_NoWPaths[MAXPATHS+1]; 94 static char *_Commands[MAXCMDS+1]; 95 static char _Cmd_defaults[BUFSIZ]; 96 97 /* option variables */ 98 static int _Request; /* TRUE can request, FALSE can not request files */ 99 static int _Switch; /* FALSE requires a call back to send any files */ 100 static int _CallBack; /* TRUE for call back for any transaction */ 101 static int _NoSpool; /* TRUE if delivering directly to destination file */ 102 static char _MyName[MAXBASENAME+1]; /* Myname from PERMISSIONS file */ 103 /* NB: _Pubdir and _Path assumed to point to dynamic data */ 104 static char *_Pubdir = NULL; /* PUBDIR from PERMISSIONS file */ 105 static char *_Path = NULL; /* PATH from PERMISSIONS file */ 106 107 struct name_value 108 { 109 char *name; 110 char *value; 111 }; 112 113 /* file pointer for PERMISSIONS */ 114 static FILE *Fp = NULL; 115 116 /* functions */ 117 extern char *next_token(), *nextarg(); 118 extern int parse_tokens(), canPath(), mkdirs(); 119 static void fillFlds(); 120 static void fillList(); 121 static int cmdMatch(), listMatch(), nameMatch(), 122 userFind(), validateFind(); 123 124 int 125 noSpool() 126 { 127 return(_NoSpool); 128 } 129 130 /* 131 * fill in fields for login name 132 * name - the login id 133 * rmtname - remote system name 134 * 135 * return: 136 * 0 -> found login name 137 * FAIL -> did not find login 138 */ 139 140 int 141 logFind(name, rmtname) 142 char *name, *rmtname; 143 { 144 int ret; 145 DEBUG(5, "logFind called (name: %s, ", name); 146 DEBUG(5, "rmtname: %s)\n", rmtname); 147 148 ret = validateFind (rmtname); 149 if (ret == SUCCESS) { /* found VALIDATE entry */ 150 ret = userFind (name, rmtname, U_VALIDATE); 151 if (ret) { 152 DEBUG(5, "machine/login match failed%s", ""); 153 return(FAIL); 154 } 155 } 156 else 157 ret = userFind (name, "", U_LOGNAME); 158 159 DEBUG(7, "_Request (%s), ", 160 requestOK() ? "TRUE" : "FALSE"); 161 DEBUG(7, "_Switch (%s), ", 162 switchRole() ? "TRUE" : "FALSE"); 163 DEBUG(7, "_CallBack (%s), ", 164 callBack() ? "TRUE" : "FALSE"); 165 DEBUG(7, "_MyName (%s), ", _MyName); 166 DEBUG(7, "_NoSpool (%s), ", 167 noSpool() ? "TRUE" : "FALSE"); 168 return(ret); 169 } 170 171 /* 172 * fill in fields for machine name 173 * return: 174 * 0 -> found machine name 175 * FAIL -> did not find machine 176 */ 177 178 int 179 mchFind(name) 180 char *name; 181 { 182 int i, ret; 183 DEBUG(5, "mchFind called (%s)\n", name); 184 if ( (ret = userFind (name, "", U_MACHINE)) == FAIL) 185 /* see if there is a default line */ 186 (void) userFind ("OTHER", "", U_MACHINE); 187 188 /* mchFind is from MASTER mode - switch role is always ok */ 189 _Switch = TRUE; 190 191 DEBUG(7, "_Request (%s), ", 192 requestOK() ? "TRUE" : "FALSE"); 193 DEBUG(7, "_Switch (%s), ", 194 switchRole() ? "TRUE" : "FALSE"); 195 DEBUG(7, "_CallBack (%s), ", 196 callBack() ? "TRUE" : "FALSE"); 197 DEBUG(7, "_MyName (%s), ", _MyName); 198 DEBUG(7, "_NoSpool (%s), ", 199 noSpool() ? "TRUE" : "FALSE"); 200 for (i=0; _Commands[i] != NULL; i++) 201 DEBUG(7, "_Commands %s\n", _Commands[i]); 202 return(ret); 203 } 204 205 /* 206 * this function will find a login name in the LOGNAME 207 * field. 208 * input: 209 * name -> who the remote says they are 210 * return: 211 * SUCCESS -> found 212 * FAIL -> not found 213 */ 214 static int 215 nameMatch(name, fld) 216 char *name, *fld; 217 { 218 char *arg; 219 220 if (fld == NULL) 221 return(FAIL); 222 223 while (*fld) { 224 fld = nextarg(fld, &arg); 225 if (EQUALS(arg, name)) 226 return(SUCCESS); 227 } 228 return (FAIL); 229 } 230 231 232 /* 233 * interpret the _Flds options and set the option variables 234 */ 235 static void 236 fillFlds() 237 { 238 239 if (_Flds[U_REQUEST] != NULL) { 240 if (EQUALS(_Flds[U_REQUEST], "yes")) 241 _Request = TRUE; 242 else 243 _Request = FALSE; 244 } 245 246 if (_Flds[U_SENDFILES] != NULL) { 247 if (EQUALS(_Flds[U_SENDFILES], "yes")) 248 _Switch = TRUE; 249 else 250 _Switch = FALSE; 251 } 252 253 if (_Flds[U_CALLBACK] != NULL) { 254 if (EQUALS(_Flds[U_CALLBACK], "yes")) 255 _CallBack = TRUE; 256 else 257 _CallBack = FALSE; 258 } 259 260 if (_Flds[U_DIRECT] != NULL) { 261 if (EQUALS(_Flds[U_DIRECT], "yes")) 262 _NoSpool = TRUE; 263 else 264 _NoSpool = FALSE; 265 } 266 267 if (_Flds[U_MYNAME] != NULL) { 268 strncpy(_MyName, _Flds[U_MYNAME], MAXBASENAME); 269 _MyName[MAXBASENAME] = NULLCHAR; 270 } 271 272 if (_Flds[U_PUBDIR] != NULL) { 273 if (_Pubdir != NULL) 274 free(_Pubdir); /* get rid of previous one */ 275 _Pubdir = strdup(_Flds[U_PUBDIR]); 276 #ifndef UUCHECK 277 ASSERT(_Pubdir != NULL, Ct_ALLOCATE, _Flds[U_PUBDIR], 0); 278 #else /* UUCHECK */ 279 if (_Pubdir == NULL) { 280 perror(gettext("malloc() error")); 281 exit(1); 282 } 283 #endif /* UUCHECK */ 284 Pubdir = _RPaths[0] = _WPaths[0] = _Pubdir; /* reset default */ 285 } 286 287 if (_Flds[U_PATH] != NULL) { 288 if (_Path != NULL) 289 free(_Path); /* get rid of previous one */ 290 _Path = strdup(_Flds[U_PATH]); 291 #ifndef UUCHECK 292 ASSERT(_Path != NULL, Ct_ALLOCATE, _Flds[U_PATH], 0); 293 #else /* UUCHECK */ 294 if (_Path == NULL) { 295 perror(gettext("malloc() error")); 296 exit(1); 297 } 298 #endif /* UUCHECK */ 299 } 300 301 return; 302 } 303 304 /* 305 * fill in the list vector for the system/login 306 * input: 307 * type - list type (read, write, noread, nowrite, command) 308 * output: 309 * list - filled in with items. 310 * return: 311 * number of items in list 312 */ 313 static void 314 fillList(type, list) 315 int type; 316 char *list[]; 317 { 318 char *p; 319 int num; 320 int maxlist = 0; 321 322 p = _Flds[type]; 323 324 /* find list limit */ 325 if (type == U_READPATH || type == U_WRITEPATH 326 || type == U_NOREADPATH || type == U_NOWRITEPATH) 327 maxlist = MAXPATHS; 328 else if (type == U_COMMANDS) 329 maxlist = MAXCMDS; 330 331 if (p == NULL || !*p) { 332 /* no names specified, default already setup */ 333 return; 334 } 335 336 num = 0; 337 while (*p && num < maxlist) { 338 list[num] = p; 339 if (*p == ':') { /* null path */ 340 *p++ = NULLCHAR; 341 continue; 342 } 343 while (*p && *p != ':') 344 p++; 345 if (*p == ':') 346 *p++ = NULLCHAR; 347 DEBUG(7, "list (%s) ", list[num]); 348 num++; 349 } 350 DEBUG(7, "num = %d\n", num); 351 list[num] = NULL; 352 return; 353 } 354 355 /* 356 * Find the line of PERMISSIONS for login. 357 * The search is determined by the type field 358 * (type=U_LOGNAME, U_MACHINE or U_VALIDATE) 359 * For U_LOGNAME: 360 * search for "name" in a LOGNAME= option 361 * For U_MACHINE: 362 * search for "name" in a MACHINE= option 363 * For U_VALIDATE: 364 * search for "rmtname" in a VALIDATE= option and 365 * for the same entry see if "name" is in the LOGNAME= option 366 * input: 367 * name -> search name 368 * logname -> for validate entry 369 * type -> U_MACHINE or U_LOGNAME 370 * output: 371 * The global values of all options will be set 372 * (e.g. _RPaths, _WPaths, _Request, ...) 373 * return: 374 * 0 -> ok 375 * FAIL -> no match found 376 */ 377 static int 378 userFind(name, rmtname, type) 379 char *name, *rmtname; 380 int type; 381 { 382 char *p, *arg, *buf = NULL; 383 static char default_buf[BUFSIZ]; 384 385 if (name != NULL && strcmp(name, "DEFAULT") != 0) { 386 /* call ourself recursively to set defaults */ 387 (void) userFind("DEFAULT", "", U_MACHINE); 388 } else { 389 /* 390 * Handle case where looking for DEFAULT entry. 391 * First initialize all defaults to their "base" 392 * values. Then the DEFAULT entry, if found, 393 * will override these settings. 394 */ 395 _Request = FALSE; 396 _CallBack = FALSE; 397 _Switch = FALSE; 398 _NoSpool = FALSE; 399 _MyName[0] = NULLCHAR; 400 _RPaths[0] = _WPaths[0] = PUBDIR; /* default is public */ 401 _RPaths[1] = _WPaths[1] = NULLCHAR; 402 _NoRPaths[0] = NULLCHAR; 403 _NoWPaths[0] = NULLCHAR; 404 if (_Pubdir != NULL) 405 free(_Pubdir); 406 Pubdir = _Pubdir = strdup(PUBDIR); 407 if (_Path != NULL) 408 free(_Path); 409 _Path = strdup(PATH); 410 /* set up Commands defaults */ 411 _Flds[U_COMMANDS] = strcpy(_Cmd_defaults, DEFAULTCMDS); 412 fillList(U_COMMANDS, _Commands); 413 /* 414 * put defaults we read in in here so they're not overwritten 415 * by non-DEFAULT entries. 416 */ 417 buf = default_buf; 418 } 419 420 if (name == NULL) /* use defaults */ 421 return(0); /* I don't think this will ever happen */ 422 423 if ( (Fp = fopen(PERMISSIONS, "r")) == NULL) { 424 DEBUG(5, "can't open %s\n", PERMISSIONS); 425 return(FAIL); 426 } 427 428 for (;;) { 429 if (parse_tokens (_Flds, buf) != 0) { 430 (void) fclose(Fp); 431 DEBUG(5, "name (%s) not found; return FAIL\n", name); 432 return(FAIL); 433 } 434 435 p = _Flds[type]; 436 while (p && *p) { 437 p = nextarg(p, &arg); 438 switch (type) { 439 case U_VALIDATE: 440 if (EQUALS(arg, rmtname) 441 && nameMatch(name, _Flds[U_LOGNAME])==SUCCESS) 442 break; 443 continue; 444 445 case U_LOGNAME: 446 if (EQUALS(arg, name)) 447 break; 448 continue; 449 450 case U_MACHINE: 451 if (EQUALSN(arg, name, MAXBASENAME)) 452 break; 453 continue; 454 } 455 456 (void) fclose(Fp); 457 fillFlds(); 458 459 /* fill in path lists */ 460 fillList(U_READPATH, _RPaths); 461 fillList(U_WRITEPATH, _WPaths); 462 if (!requestOK()) 463 _Flds[U_NOREADPATH] = "/"; 464 fillList(U_NOREADPATH, _NoRPaths); 465 fillList(U_NOWRITEPATH, _NoWPaths); 466 467 /* fill in command list */ 468 fillList(U_COMMANDS, _Commands); 469 470 return(0); 471 } 472 } 473 } 474 475 /* 476 * see if name is in a VALIDATE option 477 * return: 478 * FAIL -> not found 479 * SUCCESS -> found 480 */ 481 static int 482 validateFind(name) 483 char *name; 484 { 485 486 if ( (Fp = fopen(PERMISSIONS, "r")) == NULL) { 487 DEBUG(5, "can't open %s\n", PERMISSIONS); 488 return(FAIL); 489 } 490 491 for (;;) { 492 if (parse_tokens (_Flds, NULL) != 0) { 493 DEBUG(5, "validateFind (%s) FAIL\n", name); 494 (void) fclose(Fp); 495 return(FAIL); 496 } 497 498 if (_Flds[U_VALIDATE] == NULL) 499 continue; 500 if (nameMatch(name, _Flds[U_VALIDATE])==SUCCESS) { 501 (void) fclose(Fp); 502 return (SUCCESS); 503 } 504 } 505 506 } 507 508 /* 509 * see if name is in an ALIAS option 510 * return: 511 * NULL -> not found 512 * otherwise -> machine name 513 */ 514 char * 515 aliasFind(name) 516 char *name; 517 { 518 519 if ( (Fp = fopen(PERMISSIONS, "r")) == NULL) { 520 DEBUG(5, "can't open %s\n", PERMISSIONS); 521 return(NULL); 522 } 523 524 for (;;) { 525 if (parse_tokens (_Flds, NULL) != 0) { 526 DEBUG(5, "aliasFind (%s) FAIL\n", name); 527 (void) fclose(Fp); 528 return(NULL); 529 } 530 531 if (_Flds[U_ALIAS] == NULL) 532 continue; 533 if (nameMatch(name, _Flds[U_ALIAS])==SUCCESS) { 534 (void) fclose(Fp); 535 #ifndef UUCHECK 536 ASSERT(strchr(_Flds[U_MACHINE], ':') == NULL, 537 "PERMISSIONS file: ALIAS is one-to-many:", 538 _Flds[U_MACHINE], 0); 539 #else /* UUCHECK */ 540 if (strchr(_Flds[U_MACHINE], ':') != NULL) { 541 printf(gettext("ALIAS is one-to-many: %s -> %s\n"), 542 name, _Flds[U_MACHINE]); 543 return(NULL); 544 } 545 #endif /* UUCHECK */ 546 return(_Flds[U_MACHINE]); 547 } 548 } 549 550 } 551 552 /* 553 * parse a line in PERMISSIONS and return a vector 554 * of fields (flds) 555 * 556 * return: 557 * 0 - OK 558 * EOF - at end of file 559 */ 560 int 561 parse_tokens(flds, buf) 562 char *flds[]; 563 char *buf; 564 { 565 int i; 566 char *p; 567 struct name_value pair; 568 static char _line[BUFSIZ]; 569 char *line = buf; 570 571 if (buf == NULL) 572 line = _line; /* if no buffer specified, use default */ 573 /* initialize defaults in case parameter is not specified */ 574 for (i=0;i<NUMFLDS;i++) 575 flds[i] = NULL; 576 577 if (getuline(Fp, line) == 0) 578 return(EOF); 579 580 for (p=line;p && *p;) { 581 p = next_token (p, &pair); 582 583 for (i=0; i<NUMFLDS; i++) { 584 if (EQUALS(pair.name, _Kwords[i].kword)) { 585 flds[i] = pair.value; 586 break; 587 } 588 } 589 #ifndef UUCHECK 590 ASSERT(i<NUMFLDS, "PERMISSIONS file: BAD OPTION--", 591 pair.name, NUMFLDS); 592 #else /* UUCHECK */ 593 if (i >= NUMFLDS) { 594 DEBUG(3, "bad option (%s) in PERMISSIONS\n",pair.name); 595 (void) printf("\n*****************************\n"); 596 (void) printf(gettext("**BAD OPTION in PERMISSIONS file: %s\n"), 597 pair.name); 598 (void) printf("*****************************\n"); 599 Uerrors++; 600 return(0); 601 } 602 #endif /* UUCHECK */ 603 604 } 605 return(0); 606 } 607 608 /* 609 * return a name value pair 610 * string -> input pointer 611 * pair -> name value pair 612 * return: 613 * pointer to next character 614 */ 615 char * 616 next_token (string, pair) 617 char *string; 618 struct name_value *pair; 619 { 620 char *prev = _uu_setlocale(LC_ALL, "C"); 621 622 while ( (*string) && ((*string == '\t') || (*string == ' ')) ) 623 string++; 624 625 pair->name = string; 626 while ((*string) && (*string != '=')) 627 string++; 628 if (*string) 629 *string++ = NULLCHAR; 630 631 pair->value = string; 632 while ((*string) && (*string != '\t') && (*string != ' ') 633 && (*string != '\n')) 634 string++; 635 636 if (*string) 637 *string++ = NULLCHAR; 638 639 (void) _uu_resetlocale(LC_ALL, prev); 640 return (string); 641 } 642 643 /* 644 * get a line from the PERMISSIONS 645 * take care of comments (#) in col 1 646 * and continuations (\) in last col 647 * return: 648 * len of line 649 * 0 -> end of file 650 */ 651 int 652 getuline(fp, line) 653 FILE *fp; 654 char *line; 655 { 656 char *p, *c; 657 char buf[BUFSIZ]; 658 659 p = line; 660 for (;fgets(buf, BUFSIZ, fp) != NULL;) { 661 /* remove trailing white space */ 662 c = &buf[strlen(buf)-1]; 663 while (c>=buf && (*c == '\n' || *c == '\t' || *c == ' ') ) 664 *c-- = NULLCHAR; 665 666 if (buf[0] == '#' || buf[0] == '\n' || buf[0] == NULLCHAR) 667 continue; 668 (void) strcpy(p, buf); 669 p += strlen(buf); 670 if ( *(p-1) == '\\') 671 p--; 672 else 673 break; 674 } 675 676 return(p-line); 677 } 678 679 680 #define SMAX 15 681 682 /* 683 * get the next colon separated argument from the list 684 * return: 685 * p -> pointer to next arg in string 686 * input: 687 * str -> pointer to input string 688 * output: 689 * name -> pointer to arg string 690 */ 691 char * 692 nextarg(str, name) 693 char *str, **name; 694 { 695 char *p, *b; 696 static char buf[SMAX+1]; 697 698 for(b=buf,p=str; *p != ':' && *p && b < buf+SMAX;) 699 *b++ = *p++; 700 *b++ = NULLCHAR; 701 if (*p == ':') 702 p++; 703 *name = buf; 704 return(p); 705 } 706 707 /* 708 * check if requesting files is permitted 709 * return 710 * TRUE -> request permitted 711 * FALSE -> request denied 712 */ 713 int 714 requestOK() 715 { 716 return(_Request); 717 } 718 719 /* 720 * myName - return my name from PERMISSIONS file 721 * or if not there, from uucpname() 722 * return: none 723 */ 724 725 void 726 myName(name) 727 char *name; 728 { 729 if (*_MyName) 730 strcpy(name, _MyName); 731 else 732 uucpname(name); 733 return; 734 } 735 736 /* 737 * check for callback required for any transaction 738 * return: 739 * TRUE -> callback required 740 * FALSE-> callback NOT required 741 */ 742 int 743 callBack() 744 { 745 return(_CallBack); 746 } 747 748 /* 749 * check for callback to send any files from here 750 * This means that the called (SLAVE) system will not switch roles. 751 * return: 752 * TRUE -> callback requried to send files 753 * FALSE-> callback NOT required to send files 754 */ 755 int 756 switchRole() 757 { 758 return(_Switch); 759 } 760 761 /* 762 * Check to see if command is valid for a specific machine. 763 * The PERMISSIONS file has an option COMMANDS=name1:name2:... for 764 * any machine that does not have the default list which is 765 * rmail 766 * Note that the PERMISSIONS file is read once for each system 767 * at the time the Rmtname is set in xprocess(). 768 * Return codes: 769 * ok: TRUE 770 * fail: FALSE 771 */ 772 int 773 cmdOK(cmd, fullcmd) 774 char *cmd, *fullcmd; 775 { 776 DEBUG(7, "cmdOK(%s, )\n", cmd); 777 return(cmdMatch(cmd, fullcmd)); 778 } 779 780 781 /* 782 * check a name against a list 783 * input: 784 * name -> name 785 * list -> list of names 786 * return: 787 * TRUE -> found path 788 * FALSE -> not found 789 */ 790 static int 791 listMatch(name, list) 792 char *name, *list[]; 793 { 794 int i; 795 char *temp, *tend; 796 struct stat statbuf; 797 dev_t _dev[MAXPATHS+1]; 798 ino_t _ino[MAXPATHS+1]; 799 800 /* ino set to 0 so stat is only done first time */ 801 for (i=0; list[i] != NULL; i++) 802 _ino[i] = 0; 803 804 /* try to match inodes */ 805 if ( (temp = strdup(name)) != NULL ) { 806 for ( tend = temp + strlen(temp) ; *temp; ) { 807 if ( stat(temp, &statbuf) == 0 ) { 808 for (i=0; list[i] != NULL; i++) { 809 if ( _ino[i] == 0 ) { 810 struct stat tempbuf; 811 if ( stat(list[i], &tempbuf) == 0 ) { 812 _dev[i] = tempbuf.st_dev; 813 _ino[i] = tempbuf.st_ino; 814 } 815 } 816 if ( _dev[i] == statbuf.st_dev 817 && _ino[i] == statbuf.st_ino ) { 818 free(temp); 819 return(TRUE); 820 } 821 } 822 } 823 *tend = '\0'; 824 if ( (tend = strrchr(temp, '/')) == NULL ) { 825 free(temp); 826 break; 827 } else 828 *(tend+1) = '\0'; 829 } 830 } 831 832 return(FALSE); 833 } 834 835 836 /* 837 * Check "name" against a BASENAME or full name of _Commands list. 838 * If "name" specifies full path, check full, else check BASENAME. 839 * e.g. "name" rmail matches list item /usr/bin/rmail 840 * input: 841 * name -> name 842 * output: 843 * fullname -> copy full command name into fullname if 844 * a full path was specified in _Commands; 845 * if not, put name into fullname. 846 * return: 847 * TRUE -> found path 848 * FALSE -> not found 849 */ 850 static int 851 cmdMatch(name, fullname) 852 char *name; 853 char *fullname; 854 { 855 int i; 856 char *bname; 857 int allok = FALSE; 858 859 for (i=0; _Commands[i] != NULL; i++) { 860 if (EQUALS(_Commands[i], "ALL")) { 861 /* if ALL specified in the list 862 * set allok and continue in case 863 * a full path name is specified for the command 864 */ 865 allok = TRUE; 866 continue; 867 } 868 if (name[0] != '/') 869 bname = BASENAME(_Commands[i], '/'); 870 else 871 bname = _Commands[i]; 872 DEBUG(7, "bname=%s\n", bname); 873 if (EQUALS(bname, name)) { 874 (void) strcpy(fullname, _Commands[i]); 875 return(TRUE); 876 } 877 } 878 if (allok == TRUE) { 879 /* ALL was specified and the command was not found in list */ 880 (void) strcpy(fullname, name); 881 return(TRUE); 882 } 883 (void) strcpy(fullname, "NuLL"); /* this is a dummy command */ 884 return(FALSE); 885 } 886 887 888 /* 889 * check the paths for this login/machine 890 * input: 891 * path pathname 892 * flag CK_READ or CK_WRITE 893 * output: 894 * path may be modified to canonical form 895 * (../, ./, // will be interpreted/removed) 896 * returns: 897 * 0 -> success 898 * FAIL -> failure - not a valid path for access 899 */ 900 int 901 chkpth(char *path, int flag) 902 { 903 char *s; 904 905 /* 906 * this is probably redundant, 907 * because expfile did it, but that's ok 908 * Note - the /../ check is not required because of canPath 909 */ 910 if (canPath(path) == FAIL) 911 return(FAIL); 912 913 if (flag == CK_READ) 914 if (listMatch(path, _RPaths) 915 && !listMatch(path, _NoRPaths)) 916 return(0); 917 if (flag == CK_WRITE) 918 if (listMatch(path, _WPaths) 919 && !listMatch(path, _NoWPaths)) 920 return(0); 921 922 923 /* ok if uucp generated D. or X. name for the spool directory */ 924 if (PREFIX(RemSpool, path) ) { 925 s = &path[strlen(RemSpool)]; 926 if ( (*s++ == '/') 927 && (*s == DATAPRE || *s == XQTPRE) 928 && (*(++s) == '.') 929 && (strchr(s, '/') == NULL) ) 930 return(0); 931 } 932 933 /* path name not valid */ 934 return(FAIL); 935 } 936 937 /* 938 * check write permission of file. 939 * if mopt != NULL and permissions are ok, 940 * a side effect of this routine is to make 941 * directories up to the last part of the 942 * "to" ( if they do not exit). 943 * Input: 944 * to - a path name of the destination file or directory 945 * from - full path name of source file 946 * opt - create directory option (NULL - don't create) 947 * Output: 948 * to - will be the full path name of the destination file 949 * returns: 950 * 0 ->success 951 * FAIL -> failure 952 */ 953 int 954 chkperm(from, to, opt) 955 char *from, *to, *opt; 956 { 957 char *lxp, *p; 958 struct stat s; 959 char dir[MAXFULLNAME]; 960 961 if (*(p = LASTCHAR(to)) == '/') { 962 if (strlcpy(p+1, BASENAME(from, '/'), MAXFULLNAME - strlen(to)) >= 963 MAXFULLNAME - strlen(to)) { 964 return(FAIL); 965 } 966 } else if (DIRECTORY(to)) { 967 *++p = '/'; 968 if (strlcpy(p+1, BASENAME(from, '/'), MAXFULLNAME - strlen(to)) >= 969 MAXFULLNAME - strlen(to)) { 970 return(FAIL); 971 } 972 } 973 974 /* to is now the full path name of the destination file */ 975 976 if (WRITEANY(to)) 977 return(0); 978 if (stat(to, &s) == 0) 979 return(FAIL); /* file exists, but not writeable */ 980 981 /* file does not exist--check directory and make when necessary */ 982 983 (void) strcpy(dir, to); 984 if ( (lxp=strrchr(dir, '/')) == NULL) 985 return(FAIL); /* no directory part of name */ 986 if (lxp == dir) /* at root */ 987 lxp++; 988 *lxp = NULLCHAR; 989 990 /* should check WRITEANY on parent before mkdirs() */ 991 if (!DIRECTORY(dir)) { 992 if (opt == NULL) 993 return(FAIL); /* no directory and no opt to make them */ 994 else if (mkdirs(dir, PUBMASK) == FAIL) 995 return(FAIL); 996 } 997 998 /* the directory now exists--check for writability */ 999 if (EQUALS(RemSpool, dir) || WRITEANY(dir)) 1000 return(0); 1001 1002 return(FAIL); 1003 } 1004