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