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