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 #include "uucp.h" 33 34 /* 35 * uucp 36 * user id 37 * make a copy in spool directory 38 */ 39 int Copy = 0; 40 static int _Transfer = 0; 41 char Nuser[32]; 42 char *Ropt = " "; 43 char Optns[10]; 44 char Uopts[BUFSIZ]; 45 char Xopts[BUFSIZ]; 46 char Sgrade[NAMESIZE]; 47 int Mail = 0; 48 int Notify = 0; 49 50 void cleanup(), ruux(), usage(); 51 int eaccess(), guinfo(), vergrd(), gwd(), ckexpf(), uidstat(), uidxcp(), 52 copy(), gtcfile(); 53 void commitall(), wfabort(), mailst(), gename(), svcfile(); 54 55 char Sfile[MAXFULLNAME]; 56 57 int 58 main(argc, argv, envp) 59 int argc; 60 char *argv[]; 61 char **envp; 62 { 63 char *jid(); 64 int ret; 65 int errors = 0; 66 char *fopt, *sys2p; 67 char sys1[MAXFULLNAME], sys2[MAXFULLNAME]; 68 char fwd1[MAXFULLNAME], fwd2[MAXFULLNAME]; 69 char file1[MAXFULLNAME], file2[MAXFULLNAME]; 70 short jflag = 0; /* -j flag Jobid printout */ 71 extern int split(); 72 73 74 /* Set locale environment variables local definitions */ 75 (void) setlocale(LC_ALL, ""); 76 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 77 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */ 78 #endif 79 (void) textdomain(TEXT_DOMAIN); 80 81 /* this fails in some versions, but it doesn't hurt */ 82 Uid = getuid(); 83 Euid = geteuid(); 84 if (Uid == 0) 85 (void) setuid(UUCPUID); 86 87 /* choose LOGFILE */ 88 (void) strcpy(Logfile, LOGUUCP); 89 90 Env = envp; 91 fopt = NULL; 92 (void) strcpy(Progname, "uucp"); 93 Pchar = 'U'; 94 *Uopts = NULLCHAR; 95 *Xopts = NULLCHAR; 96 *Sgrade = NULLCHAR; 97 98 if (eaccess(GRADES, 0) != -1) { 99 Grade = 'A'; 100 Sgrades = TRUE; 101 sprintf(Sgrade, "%s", "default"); 102 } 103 104 /* 105 * find name of local system 106 */ 107 uucpname(Myname); 108 Optns[0] = '-'; 109 Optns[1] = 'd'; 110 Optns[2] = 'c'; 111 Optns[3] = Nuser[0] = Sfile[0] = NULLCHAR; 112 113 /* 114 * find id of user who spawned command to 115 * determine 116 */ 117 (void) guinfo(Uid, User); 118 119 /* 120 * create/append command log 121 */ 122 commandlog(argc,argv); 123 124 while ((ret = getopt(argc, argv, "Ccdfg:jmn:rs:x:")) != EOF) { 125 switch (ret) { 126 127 /* 128 * make a copy of the file in the spool 129 * directory. 130 */ 131 case 'C': 132 Copy = 1; 133 Optns[2] = 'C'; 134 break; 135 136 /* 137 * not used (default) 138 */ 139 case 'c': 140 break; 141 142 /* 143 * not used (default) 144 */ 145 case 'd': 146 break; 147 case 'f': 148 Optns[1] = 'f'; 149 break; 150 151 /* 152 * set service grade 153 */ 154 case 'g': 155 snprintf(Xopts, sizeof (Xopts), "-g%s", optarg); 156 if (!Sgrades) { 157 if (strlen(optarg) < (size_t)2 && isalnum(*optarg)) 158 Grade = *optarg; 159 else { 160 (void) fprintf(stderr, gettext("No" 161 " administrator defined service" 162 " grades available on this" 163 " machine.\n")); 164 (void) fprintf(stderr, gettext("UUCP" 165 " service grades range from" 166 " [A-Z][a-z] only.\n")); 167 cleanup(-1); 168 } 169 } 170 else { 171 (void) strncpy(Sgrade, optarg, NAMESIZE-1); 172 Sgrade[NAMESIZE-1] = NULLCHAR; 173 if (vergrd(Sgrade) != SUCCESS) 174 cleanup(FAIL); 175 } 176 break; 177 178 case 'j': /* job id */ 179 jflag = 1; 180 break; 181 182 /* 183 * send notification to local user 184 */ 185 case 'm': 186 Mail = 1; 187 (void) strcat(Optns, "m"); 188 break; 189 190 /* 191 * send notification to user on remote 192 * if no user specified do not send notification 193 */ 194 case 'n': 195 /* 196 * We should add "n" option to Optns only once, 197 * even if multiple -n option are passed to uucp 198 */ 199 if (!Notify) { 200 (void) strlcat(Optns, "n", sizeof (Optns)); 201 Notify = 1; 202 } 203 (void) sprintf(Nuser, "%.8s", optarg); 204 205 /* 206 * We do the copy multiple times when multiple 207 * -n options are specified, but 208 * only the last -n value is used. 209 */ 210 (void) snprintf(Uopts, sizeof (Uopts), "-n%s ", Nuser); 211 212 break; 213 214 /* 215 * create JCL files but do not start uucico 216 */ 217 case 'r': 218 Ropt = "-r"; 219 break; 220 221 /* 222 * return status file 223 */ 224 case 's': 225 fopt = optarg; 226 /* "m" needed for compatability */ 227 (void) strcat(Optns, "mo"); 228 break; 229 230 /* 231 * turn on debugging 232 */ 233 case 'x': 234 Debug = atoi(optarg); 235 if (Debug <= 0) 236 Debug = 1; 237 #ifdef SMALL 238 fprintf(stderr, gettext("WARNING: uucp built with SMALL" 239 " flag defined -- no debug info available\n")); 240 #endif /* SMALL */ 241 break; 242 243 default: 244 usage(); 245 break; 246 } 247 } 248 DEBUG(4, "\n\n** %s **\n", "START"); 249 gwd(Wrkdir); 250 if (fopt) { 251 if (*fopt != '/') 252 (void) snprintf(Sfile, MAXFULLNAME, "%s/%s", 253 Wrkdir, fopt); 254 else 255 (void) snprintf(Sfile, MAXFULLNAME, "%s", fopt); 256 257 } 258 else 259 if (strlcpy(Sfile, "dummy", sizeof (Sfile)) >= sizeof (Sfile)) 260 return (2); 261 262 /* 263 * work in WORKSPACE directory 264 */ 265 ret = chdir(WORKSPACE); 266 if (ret != 0) { 267 (void) fprintf(stderr, gettext("No work directory - %s -" 268 " get help\n"), WORKSPACE); 269 cleanup(-12); 270 } 271 272 if (Nuser[0] == NULLCHAR) 273 (void) strcpy(Nuser, User); 274 (void) strcpy(Loginuser, User); 275 DEBUG(4, "UID %ld, ", (long) Uid); 276 DEBUG(4, "User %s\n", User); 277 if (argc - optind < 2) { 278 usage(); 279 } 280 281 /* 282 * set up "to" system and file names 283 */ 284 285 (void) split(argv[argc - 1], sys2, fwd2, file2); 286 if (*sys2 != NULLCHAR) { 287 (void) strncpy(Rmtname, sys2, MAXBASENAME); 288 Rmtname[MAXBASENAME] = NULLCHAR; 289 290 /* get real Myname - it depends on who I'm calling--Rmtname */ 291 (void) mchFind(Rmtname); 292 myName(Myname); 293 294 if (versys(sys2) != 0) { 295 (void) fprintf(stderr, 296 gettext("bad system: %s\n"), sys2); 297 cleanup(-EX_NOHOST); 298 } 299 } 300 301 DEBUG(9, "sys2: %s, ", sys2); 302 DEBUG(9, "fwd2: %s, ", fwd2); 303 DEBUG(9, "file2: %s\n", file2); 304 305 /* 306 * if there are more than 2 argsc, file2 is a directory 307 */ 308 if (argc - optind > 2) 309 (void) strcat(file2, "/"); 310 311 /* 312 * do each from argument 313 */ 314 315 for ( ; optind < argc - 1; optind++) { 316 (void) split(argv[optind], sys1, fwd1, file1); 317 if (*sys1 != NULLCHAR) { 318 if (versys(sys1) != 0) { 319 (void) fprintf(stderr, 320 gettext("bad system: %s\n"), sys1); 321 cleanup(-EX_NOHOST); 322 } 323 } 324 325 /* source files can have at most one ! */ 326 if (*fwd1 != NULLCHAR) { 327 /* syntax error */ 328 (void) fprintf(stderr, 329 gettext("illegal syntax %s\n"), argv[optind]); 330 exit(2); 331 } 332 333 /* 334 * check for required remote expansion of file names -- generate 335 * and execute a uux command 336 * e.g. 337 * uucp owl!~/dan/.. ~/dan/ 338 * 339 * NOTE: The source file part must be full path name. 340 * If ~ it will be expanded locally - it assumes the remote 341 * names are the same. 342 */ 343 344 if (*sys1 != NULLCHAR) 345 if ((strchr(file1, '*') != NULL 346 || strchr(file1, '?') != NULL 347 || strchr(file1, '[') != NULL)) { 348 /* do a uux command */ 349 if (ckexpf(file1) == FAIL) 350 exit(6); 351 (void) strncpy(Rmtname, sys1, MAXBASENAME); 352 Rmtname[MAXBASENAME] = NULLCHAR; 353 /* get real Myname - it depends on who I'm calling--Rmtname */ 354 (void) mchFind(Rmtname); 355 myName(Myname); 356 if (*sys2 == NULLCHAR) 357 sys2p = Myname; 358 ruux(sys1, sys1, file1, sys2p, fwd2, file2); 359 continue; 360 } 361 362 /* 363 * check for forwarding -- generate and execute a uux command 364 * e.g. 365 * uucp uucp.c raven!owl!~/dan/ 366 */ 367 368 if (*fwd2 != NULLCHAR) { 369 ruux(sys2, sys1, file1, "", fwd2, file2); 370 continue; 371 } 372 373 /* 374 * check for both source and destination on other systems -- 375 * generate and execute a uux command 376 */ 377 378 if (*sys1 != NULLCHAR ) 379 if ( (!EQUALS(Myname, sys1)) 380 && *sys2 != NULLCHAR 381 && (!EQUALS(sys2, Myname)) ) { 382 ruux(sys2, sys1, file1, "", fwd2, file2); 383 continue; 384 } 385 386 387 sys2p = sys2; 388 if (*sys1 == NULLCHAR) { 389 if (*sys2 == NULLCHAR) 390 sys2p = Myname; 391 (void) strcpy(sys1, Myname); 392 } else { 393 (void) strncpy(Rmtname, sys1, MAXBASENAME); 394 Rmtname[MAXBASENAME] = NULLCHAR; 395 /* get real Myname - it depends on who I'm calling--Rmtname */ 396 (void) mchFind(Rmtname); 397 myName(Myname); 398 if (*sys2 == NULLCHAR) 399 sys2p = Myname; 400 } 401 402 DEBUG(4, "sys1 - %s, ", sys1); 403 DEBUG(4, "file1 - %s, ", file1); 404 DEBUG(4, "Rmtname - %s\n", Rmtname); 405 if (copy(sys1, file1, sys2p, file2)) 406 errors++; 407 } 408 409 /* move the work files to their proper places */ 410 commitall(); 411 412 /* 413 * Wait for all background uux processes to finish so 414 * that our caller will know that we're done with all 415 * input files and it's safe to remove them. 416 */ 417 while (wait(NULL) != -1) 418 ; 419 420 /* 421 * do not spawn daemon if -r option specified 422 */ 423 if (*Ropt != '-') { 424 #ifndef V7 425 long limit; 426 char msg[100]; 427 limit = ulimit(1, (long) 0); 428 if (limit < MINULIMIT) { 429 (void) sprintf(msg, 430 "ULIMIT (%ld) < MINULIMIT (%ld)", limit, MINULIMIT); 431 logent(msg, "Low-ULIMIT"); 432 } 433 else 434 #endif 435 xuucico(Rmtname); 436 } 437 if (jflag) { 438 (void) strncpy(Jobid, jid(), NAMESIZE); 439 printf("%s\n", Jobid); 440 } 441 cleanup(errors); 442 /*NOTREACHED*/ 443 return (0); 444 } 445 446 /* 447 * cleanup lock files before exiting 448 */ 449 void 450 cleanup(code) 451 int code; 452 { 453 static int first = 1; 454 455 if (first) { 456 first = 0; 457 rmlock(CNULL); 458 if (code != 0) 459 wfabort(); /* this may be extreme -- abort all work */ 460 } 461 if (code < 0) { 462 (void) fprintf(stderr, 463 gettext("uucp failed completely (%d)\n"), (-code)); 464 exit(-code); 465 } 466 else if (code > 0) { 467 (void) fprintf(stderr, gettext( 468 "uucp failed partially: %d file(s) sent; %d error(s)\n"), 469 _Transfer, code); 470 exit(code); 471 } 472 exit(code); 473 } 474 475 /* 476 * generate copy files for s1!f1 -> s2!f2 477 * Note: only one remote machine, other situations 478 * have been taken care of in main. 479 * return: 480 * 0 -> success 481 * Non-zero -> failure 482 */ 483 int 484 copy(s1, f1, s2, f2) 485 char *s1, *f1, *s2, *f2; 486 { 487 FILE *cfp; 488 static FILE *syscfile(); 489 struct stat stbuf, stbuf1; 490 int type, statret; 491 char dfile[NAMESIZE]; 492 char cfile[NAMESIZE]; 493 char command[10+(2*MAXFULLNAME)]; 494 char file1[MAXFULLNAME], file2[MAXFULLNAME]; 495 char msg[BUFSIZ]; 496 497 type = 0; 498 (void) strcpy(file1, f1); 499 (void) strcpy(file2, f2); 500 if (!EQUALS(s1, Myname)) 501 type = 1; 502 if (!EQUALS(s2, Myname)) 503 type = 2; 504 505 DEBUG(4, "copy: file1=<%s> ", file1); 506 DEBUG(4, "file2=<%s>\n", file2); 507 switch (type) { 508 case 0: 509 510 /* 511 * all work here 512 */ 513 DEBUG(4, "all work here %d\n", type); 514 515 /* 516 * check access control permissions 517 */ 518 if (ckexpf(file1)) 519 return(-6); 520 if (ckexpf(file2)) 521 return(-7); 522 523 setuid(Uid); 524 if (chkperm(file1, file2, strchr(Optns, 'd')) && 525 (access(file2, W_OK) == -1)) { 526 (void) fprintf(stderr, gettext("permission denied\n")); 527 cleanup(1); 528 } 529 530 /* 531 * copy file locally 532 * 533 * Changed from uidxcp() to fic file made and owner 534 * being modified for existing files, and local file 535 * name expansion. 536 */ 537 DEBUG(2, "local copy: %s -> ", file1); 538 DEBUG(2, "%s\n", file2); 539 540 sprintf(command, "cp %s %s", file1, file2); 541 if ((cfp = popen(command, "r")) == NULL) { 542 perror("popen"); 543 DEBUG(5, "popen failed - errno %d\n", errno); 544 setuid(Euid); 545 return (FAIL); 546 } 547 if (pclose(cfp) != 0) { 548 DEBUG(5, "Copy failed - errno %d\n", errno); 549 return (FAIL); 550 } 551 setuid(Euid); 552 553 /* 554 * if user specified -m, notify "local" user 555 */ 556 if ( Mail ) { 557 sprintf(msg, 558 "REQUEST: %s!%s --> %s!%s (%s)\n(SYSTEM %s) copy succeeded\n", 559 s1, file1, s2, file2, User, s2 ); 560 mailst(User, "copy succeeded", msg, "", ""); 561 } 562 /* 563 * if user specified -n, notify "remote" user 564 */ 565 if ( Notify ) { 566 sprintf(msg, "%s from %s!%s arrived\n", 567 file2, s1, User ); 568 mailst(Nuser, msg, msg, "", ""); 569 } 570 return(0); 571 case 1: 572 573 /* 574 * receive file 575 */ 576 DEBUG(4, "receive file - %d\n", type); 577 578 /* 579 * expand source and destination file names 580 * and check access permissions 581 */ 582 if (file1[0] != '~') 583 if (ckexpf(file1)) 584 return(6); 585 if (ckexpf(file2)) 586 return(7); 587 588 589 gename(DATAPRE, s2, Grade, dfile); 590 591 /* 592 * insert JCL card in file 593 */ 594 cfp = syscfile(cfile, s1); 595 (void) fprintf(cfp, 596 "R %s %s %s %s %s %o %s %s\n", file1, file2, 597 User, Optns, 598 *Sfile ? Sfile : "dummy", 599 0777, Nuser, dfile); 600 (void) fclose(cfp); 601 (void) sprintf(msg, "%s!%s --> %s!%s", Rmtname, file1, 602 Myname, file2); 603 logent(msg, "QUEUED"); 604 break; 605 case 2: 606 607 /* 608 * send file 609 */ 610 if (ckexpf(file1)) 611 return(6); 612 /* XQTDIR hook enables 3rd party uux requests (cough) */ 613 DEBUG(4, "Workdir = <%s>\n", Wrkdir); 614 if (file2[0] != '~' && !EQUALS(Wrkdir, XQTDIR)) 615 if (ckexpf(file2)) 616 return(7); 617 DEBUG(4, "send file - %d\n", type); 618 619 if (uidstat(file1, &stbuf) != 0) { 620 (void) fprintf(stderr, 621 gettext("can't get status for file %s\n"), file1); 622 return(8); 623 } 624 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 625 (void) fprintf(stderr, 626 gettext("directory name illegal - %s\n"), file1); 627 return(9); 628 } 629 /* see if I can read this file as read uid, gid */ 630 if (access(file1, R_OK) != 0) { 631 (void) fprintf(stderr, 632 gettext("uucp can't read (%s) mode (%o)\n"), 633 file1, stbuf.st_mode&0777); 634 return(3); 635 } 636 637 /* 638 * make a copy of file in spool directory 639 */ 640 641 gename(DATAPRE, s2, Grade, dfile); 642 643 if (Copy || !READANY(file1) ) { 644 645 if (uidxcp(file1, dfile)) 646 return(5); 647 648 (void) chmod(dfile, DFILEMODE); 649 } 650 651 cfp = syscfile(cfile, s2); 652 (void) fprintf(cfp, "S %s %s %s %s %s %lo %s %s\n", 653 file1, file2, User, Optns, dfile, 654 (long) stbuf.st_mode & LEGALMODE, Nuser, Sfile); 655 (void) fclose(cfp); 656 (void) sprintf(msg, "%s!%s --> %s!%s", Myname, file1, 657 Rmtname, file2); 658 logent(msg, "QUEUED"); 659 break; 660 } 661 _Transfer++; 662 return(0); 663 } 664 665 666 /* 667 * syscfile(file, sys) 668 * char *file, *sys; 669 * 670 * get the cfile for system sys (creat if need be) 671 * return stream pointer 672 * 673 * returns 674 * stream pointer to open cfile 675 * 676 */ 677 678 static FILE * 679 syscfile(file, sys) 680 char *file, *sys; 681 { 682 FILE *cfp; 683 684 if (gtcfile(file, sys) == FAIL) { 685 gename(CMDPRE, sys, Grade, file); 686 ASSERT(access(file, 0) != 0, Fl_EXISTS, file, errno); 687 cfp = fdopen(creat(file, CFILEMODE), "w"); 688 svcfile(file, sys, Sgrade); 689 } else 690 cfp = fopen(file, "a"); 691 ASSERT(cfp != NULL, Ct_OPEN, file, errno); 692 return(cfp); 693 } 694 695 696 /* 697 * generate and execute a uux command 698 */ 699 700 void 701 ruux(rmt, sys1, file1, sys2, fwd2, file2) 702 char *rmt, *sys1, *file1, *sys2, *fwd2, *file2; 703 { 704 char cmd[BUFSIZ]; 705 char xcmd[BUFSIZ]; 706 char * xarg[6]; 707 int narg = 0; 708 int i; 709 710 /* get real Myname - it depends on who I'm calling--rmt */ 711 (void) mchFind(rmt); 712 myName(Myname); 713 714 xarg[narg++] = UUX; 715 xarg[narg++] = "-C"; 716 if (*Xopts != NULLCHAR) 717 xarg[narg++] = Xopts; 718 if (*Ropt != ' ') 719 xarg[narg++] = Ropt; 720 721 (void) sprintf(cmd, "%s!uucp -C", rmt); 722 723 if (*Uopts != NULLCHAR) 724 (void) sprintf(cmd+strlen(cmd), " (%s) ", Uopts); 725 726 if (*sys1 == NULLCHAR || EQUALS(sys1, Myname)) { 727 if (ckexpf(file1)) 728 exit(6); 729 (void) sprintf(cmd+strlen(cmd), " %s!%s ", sys1, file1); 730 } 731 else 732 if (!EQUALS(rmt, sys1)) 733 (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", sys1, file1); 734 else 735 (void) sprintf(cmd+strlen(cmd), " (%s) ", file1); 736 737 if (*fwd2 != NULLCHAR) { 738 if (*sys2 != NULLCHAR) 739 (void) sprintf(cmd+strlen(cmd), 740 " (%s!%s!%s) ", sys2, fwd2, file2); 741 else 742 (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", fwd2, file2); 743 } 744 else { 745 if (*sys2 == NULLCHAR || EQUALS(sys2, Myname)) 746 if (ckexpf(file2)) 747 exit(7); 748 (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", sys2, file2); 749 } 750 751 xarg[narg++] = cmd; 752 xarg[narg] = (char *) 0; 753 754 xcmd[0] = NULLCHAR; 755 for (i=0; i < narg; i++) { 756 strcat(xcmd, xarg[i]); 757 strcat(xcmd, " "); 758 } 759 DEBUG(2, "cmd: %s\n", xcmd); 760 logent(xcmd, "QUEUED"); 761 762 if (fork() == 0) { 763 ASSERT(setuid(getuid()) == 0, "setuid", "failed", 99); 764 execv(UUX, xarg); 765 exit(0); 766 } 767 return; 768 } 769 770 void 771 usage() 772 { 773 774 (void) fprintf(stderr, gettext( 775 "Usage: %s [-c|-C] [-d|-f] [-g GRADE] [-jm] [-n USER]\\\n" 776 "[-r] [-s FILE] [-x DEBUG_LEVEL] source-files destination-file\n"), 777 Progname); 778 cleanup(-2); 779 } 780