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