113691Ssam #ifndef lint 2*17844Sralph static char sccsid[] = "@(#)uusend.c 5.2 (Berkeley) 01/22/85"; 313691Ssam #endif 413691Ssam 513691Ssam /* 613691Ssam * uusend: primitive operation to allow uucp like copy of binary files 713691Ssam * but handle indirection over systems. 813691Ssam * 913691Ssam * usage: uusend [-r] [-m ooo] localfile sysname1!sysname2!...!destfile 1013691Ssam * uusend [-r] [-m ooo] - sysname1!sysname2!...!destfile 1113691Ssam * 1213691Ssam * Author: Mark Horton, May 1980. 1313691Ssam * 1413691Ssam * "-r" switch added. Has same effect as "-r" in uux. 11/82 CCW 1513691Ssam * 1613691Ssam * Error recovery (a la uucp) added & ifdefs for ruusend (as in rmail). 1713691Ssam * Checks for illegal access to /usr/lib/uucp. 1813691Ssam * February 1983 Christopher Woodbury 1913691Ssam * Fixed mode set[ug]id loophole. 4/8/83 CCW 2013691Ssam * 2113691Ssam * Add '-f' to make uusend syntax more similar to UUCP. "destname" 2213691Ssam * can now be a directory. June 1983 CCW 2313691Ssam */ 2413691Ssam 2513691Ssam #include <stdio.h> 2613691Ssam #include <pwd.h> 2713691Ssam #include <sys/types.h> 2813691Ssam #include <sys/stat.h> 2913691Ssam 30*17844Sralph /* 31*17844Sralph * define RECOVER to permit requests like 'uusend file sys1!sys2!~uucp' 32*17844Sralph * (abbreviation for 'uusend file sys1!sys2!~uucp/file'). 33*17844Sralph * define DEBUG to keep log of uusend uusage. 34*17844Sralph * define RUUSEND if neighboring sites permit 'ruusend', 35*17844Sralph * which they certainly should to avoid security holes 36*17844Sralph */ 3713691Ssam #define RECOVER 38*17844Sralph /*#define DEBUG "/usr/spool/uucp/uusend.log"/**/ 3913691Ssam 4013691Ssam FILE *in, *out; 4113691Ssam FILE *dout; 4213691Ssam 43*17844Sralph extern FILE *popen(); 44*17844Sralph extern char *index(), *strcpy(), *strcat(), *ctime(); 4513691Ssam 4613691Ssam #ifdef RUUSEND 4713691Ssam int rsend; 48*17844Sralph #endif RUUSEND 4913691Ssam int mode = -1; /* mode to chmod new file to */ 5013691Ssam char *nextsys; /* next system in the chain */ 5113691Ssam char dnbuf[200]; /* buffer for result of ~user/file */ 5213691Ssam char cmdbuf[256]; /* buffer to build uux command in */ 5313691Ssam char *rflg = ""; /* default value of rflg ccw -- 1 Nov '82 */ 5413691Ssam 5513691Ssam struct passwd *user; /* entry in /etc/passwd for ~user */ 5613691Ssam struct passwd *getpwnam(); 5713691Ssam struct stat stbuf; 5813691Ssam 5913691Ssam char *excl; /* location of first ! in destname */ 6013691Ssam char *sl; /* location of first / in destname */ 6113691Ssam char *sourcename; /* argv[1] */ 6213691Ssam char *destname; /* argv[2] */ 6313691Ssam char *UULIB = "/usr/lib/uucp"; /* UUCP lib directory */ 6413691Ssam 6513691Ssam #ifdef RECOVER 6613691Ssam char *UUPUB = "/usr/spool/uucppublic/"; /* public UUCP directory */ 6713691Ssam char *filename; /* file name from end of destname */ 6813691Ssam char *getfname(); /* routine to get filename from destname */ 6913691Ssam int fflg; 7013691Ssam char f[100]; /* name of default output file */ 71*17844Sralph #else !RECOVER 7213691Ssam char *f = ""; /* so we waste a little space */ 73*17844Sralph #endif !RECOVER 7413691Ssam 7513691Ssam main(argc, argv) 7613691Ssam int argc; 7713691Ssam char **argv; 7813691Ssam { 7913691Ssam register int c; 80*17844Sralph long count; 81*17844Sralph extern char **environ; 8213691Ssam 8313691Ssam #ifdef DEBUG 8413691Ssam long t; 85*17844Sralph umask(022); 8613691Ssam dout = fopen(DEBUG, "a"); 8713691Ssam if (dout == NULL) { 8813691Ssam printf("Cannot append to %s\n", DEBUG); 8913691Ssam exit(1); 9013691Ssam } 9113691Ssam freopen(DEBUG, "a", stdout); 9213691Ssam fprintf(dout, "\nuusend run: "); 9313691Ssam for (c=0; c<argc; c++) 9413691Ssam fprintf(dout, "%s ", argv[c]); 9513691Ssam time(&t); 9613691Ssam fprintf(dout, "%s", ctime(&t)); 97*17844Sralph #endif DEBUG 9813691Ssam 9913691Ssam #ifdef RUUSEND 10013691Ssam if(argv[0][0] == 'r') 10113691Ssam rsend++; 102*17844Sralph #endif RUUSEND 10313691Ssam while (argc > 1 && argv[1][0] == '-' && argv[1][1]) { 10413691Ssam switch(argv[1][1]) { 10513691Ssam case 'm': 10613691Ssam sscanf(argv[2], "%o", &mode); 10713691Ssam mode &= 0777; /* fix set[ug]id loophole */ 10813691Ssam argc--; argv++; 10913691Ssam break; 11013691Ssam case 'r': /* -r flag for uux */ 11113691Ssam rflg = "-r "; 11213691Ssam break; 11313691Ssam #ifdef RECOVER 11413691Ssam case 'f': 11513691Ssam fflg++; 11613691Ssam strcpy(f, argv[1]); 11713691Ssam break; 118*17844Sralph #endif RECOVER 11913691Ssam default: 12013691Ssam fprintf(stderr, "Bad flag: %s\n", argv[1]); 12113691Ssam break; 12213691Ssam } 12313691Ssam argc--; argv++; 12413691Ssam } 12513691Ssam 12613691Ssam if (argc != 3) { 12713691Ssam fprintf(stderr, "Usage: uusend [-m ooo] [-r] -/file sys!sys!..!rfile\n"); 12813691Ssam exit(1); 12913691Ssam } 13013691Ssam 13113691Ssam sourcename = argv[1]; 13213691Ssam destname = argv[2]; 13313691Ssam 13413691Ssam if (sourcename[0] == '-') 13513691Ssam in = stdin; 13613691Ssam else { 13713691Ssam #ifdef RUUSEND 13813691Ssam if (rsend) { 13913691Ssam fprintf(stderr, "illegal input\n"); 14013691Ssam exit(2); 14113691Ssam } 142*17844Sralph #endif RUUSEND 14313691Ssam in = fopen(sourcename, "r"); 14413691Ssam if (in == NULL) { 14513691Ssam perror(argv[1]); 14613691Ssam exit(2); 14713691Ssam } 14813691Ssam if (!fflg || f[2] == '\0') { 14913691Ssam strcpy(f, "-f"); 15013691Ssam strcat(f, getfname(sourcename)); 15113691Ssam fflg++; 15213691Ssam } 15313691Ssam } 15413691Ssam 15513691Ssam excl = index(destname, '!'); 15613691Ssam if (excl) { 15713691Ssam /* 15813691Ssam * destname is on a remote system. 15913691Ssam */ 16013691Ssam nextsys = destname; 16113691Ssam *excl++ = 0; 16213691Ssam destname = excl; 16313691Ssam if (mode < 0) { 16413691Ssam fstat(fileno(in), &stbuf); 16513691Ssam mode = stbuf.st_mode & 0777; 16613691Ssam } 16713691Ssam #ifdef RUUSEND 168*17844Sralph sprintf(cmdbuf,"uux -gn -z %s- \"%s!ruusend %s -m %o - (%s)\"", 169*17844Sralph #else !RUUSEND 170*17844Sralph sprintf(cmdbuf, "uux -gn -z %s- \"%s!uusend %s -m %o - (%s)\"", 171*17844Sralph #endif !RUUSEND 17213691Ssam rflg, nextsys, f, mode, destname); 17313691Ssam #ifdef DEBUG 17413691Ssam fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf); 175*17844Sralph #endif DEBUG 17613691Ssam out = popen(cmdbuf, "w"); 17713691Ssam } else { 17813691Ssam /* 17913691Ssam * destname is local. 18013691Ssam */ 18113691Ssam if (destname[0] == '~') { 18213691Ssam #ifdef DEBUG 18313691Ssam fprintf(dout, "before ~: '%s'\n", destname); 18413691Ssam fflush(dout); 185*17844Sralph #endif DEBUG 18613691Ssam sl = index(destname, '/'); 18713691Ssam #ifdef RECOVER 18813691Ssam if (sl == NULL && !fflg) { 18913691Ssam fprintf(stderr, "Illegal ~user\n"); 19013691Ssam exit(3); 19113691Ssam } 19213691Ssam for (sl = destname; *sl != '\0'; sl++) 19313691Ssam ; /* boy, is this a hack! */ 194*17844Sralph #else !RECOVER 19513691Ssam if (sl == NULL) { 19613691Ssam fprintf(stderr, "Illegal ~user\n"); 19713691Ssam exit(3); 19813691Ssam } 19913691Ssam *sl++ = 0; 200*17844Sralph #endif !RECOVER 20113691Ssam user = getpwnam(destname+1); 20213691Ssam if (user == NULL) { 20313691Ssam fprintf(stderr, "No such user as %s\n", 20413691Ssam destname); 20513691Ssam #ifdef RECOVER 20613691Ssam if ((filename =getfname(sl)) == NULL && 20713691Ssam !fflg) 20813691Ssam exit(4); 20913691Ssam strcpy(dnbuf, UUPUB); 21013691Ssam if (fflg) 21113691Ssam strcat(dnbuf, &f[2]); 21213691Ssam else 21313691Ssam strcat(dnbuf, filename); 21413691Ssam } 21513691Ssam else { 21613691Ssam strcpy(dnbuf, user->pw_dir); 21713691Ssam strcat(dnbuf, "/"); 21813691Ssam strcat(dnbuf, sl); 21913691Ssam } 220*17844Sralph #else !RECOVER 22113691Ssam exit(4); 22213691Ssam } 22313691Ssam strcpy(dnbuf, user->pw_dir); 22413691Ssam strcat(dnbuf, "/"); 22513691Ssam strcat(dnbuf, sl); 226*17844Sralph #endif !RECOVER 22713691Ssam destname = dnbuf; 22813691Ssam } 22913691Ssam #ifdef RECOVER 23013691Ssam else 23113691Ssam destname = strcpy(dnbuf, destname); 232*17844Sralph #endif !RECOVER 23313691Ssam if(strncmp(UULIB, destname, strlen(UULIB)) == 0) { 23413691Ssam fprintf(stderr, "illegal file: %s", destname); 23513691Ssam exit(4); 23613691Ssam } 23713691Ssam #ifdef RECOVER 23813691Ssam if (stat(destname, &stbuf) == 0 && 23913691Ssam (stbuf.st_mode & S_IFMT) == S_IFDIR && 24013691Ssam fflg) { 241*17844Sralph strcat(destname, "/"); 242*17844Sralph strcat(destname, &f[2]); 24313691Ssam } 244*17844Sralph #endif RECOVER 24513691Ssam out = fopen(destname, "w"); 24613691Ssam #ifdef DEBUG 24713691Ssam fprintf(dout, "local, file='%s'\n", destname); 248*17844Sralph #endif DEBUG 24913691Ssam if (out == NULL) { 25013691Ssam perror(destname); 25113691Ssam #ifdef RECOVER 25213691Ssam if (strncmp(destname,UUPUB,strlen(UUPUB)) == 0) 25313691Ssam exit(5); /* forget it! */ 25413691Ssam filename = getfname(destname); 25513691Ssam if (destname == dnbuf) /* cmdbuf is scratch */ 25613691Ssam filename = strcpy(cmdbuf, filename); 25713691Ssam destname = strcpy(dnbuf, UUPUB); 25813691Ssam if (user != NULL) { 25913691Ssam strcat(destname, user->pw_name); 26013691Ssam if (stat(destname, &stbuf) == -1) { 261*17844Sralph mkdir(destname, 0777); 26213691Ssam } 26313691Ssam strcat(destname, "/"); 26413691Ssam } 26513691Ssam if (fflg) 26613691Ssam strcat(destname, &f[2]); 26713691Ssam else 26813691Ssam strcat(destname, filename); 26913691Ssam if ((out = fopen(destname, "w")) == NULL) 27013691Ssam exit(5); /* all for naught! */ 271*17844Sralph #else !RECOVER 27213691Ssam exit(5); 273*17844Sralph #endif !RECOVER 27413691Ssam } 27513691Ssam if (mode > 0) 27613691Ssam chmod(destname, mode); /* don't bother to check it */ 27713691Ssam } 27813691Ssam 27913691Ssam /* 28013691Ssam * Now, in any case, copy from in to out. 28113691Ssam */ 28213691Ssam 283*17844Sralph count = 0; 28413691Ssam while ((c=getc(in)) != EOF) { 28513691Ssam putc(c, out); 28613691Ssam count++; 28713691Ssam } 28813691Ssam #ifdef DEBUG 28913691Ssam fprintf(dout, "count %ld bytes\n", count); 29013691Ssam fclose(dout); 291*17844Sralph #endif DEBUG 292*17844Sralph 29313691Ssam fclose(in); 29413691Ssam fclose(out); /* really should pclose in that case */ 29513691Ssam exit(0); 29613691Ssam } 29713691Ssam 29813691Ssam /* 29913691Ssam * Return the ptr in sp at which the character c appears; 30013691Ssam * NULL if not found. Included so I don't have to fight the 30113691Ssam * index/strchr battle. 30213691Ssam */ 30313691Ssam 30413691Ssam #define NULL 0 30513691Ssam 30613691Ssam char * 30713691Ssam index(sp, c) 30813691Ssam register char *sp, c; 30913691Ssam { 31013691Ssam do { 31113691Ssam if (*sp == c) 31213691Ssam return(sp); 31313691Ssam } while (*sp++); 31413691Ssam return(NULL); 31513691Ssam } 31613691Ssam 31713691Ssam #ifdef RECOVER 31813691Ssam char * 31913691Ssam getfname(p) 32013691Ssam register char *p; 32113691Ssam { 32213691Ssam register char *s; 32313691Ssam s = p; 32413691Ssam while (*p != '\0') 32513691Ssam p++; 32613691Ssam if (p == s) 32713691Ssam return (NULL); 32813691Ssam for (;p != s; p--) 32913691Ssam if (*p == '/') { 33013691Ssam p++; 33113691Ssam break; 33213691Ssam } 33313691Ssam return (p); 33413691Ssam } 33513691Ssam 336*17844Sralph #ifndef BSD4_2 337*17844Sralph makedir(dirname, mode) 33813691Ssam char *dirname; 339*17844Sralph int mode; 34013691Ssam { 34113691Ssam register int pid; 34213691Ssam int retcode, status; 34313691Ssam switch ((pid = fork())) { 34413691Ssam case -1: /* error */ 34513691Ssam return (-1); 34613691Ssam case 0: /* child */ 34713691Ssam umask(0); 348*17844Sralph execl("/bin/mkdir", "mkdir", dirname, (char *)0); 34913691Ssam exit(1); 350*17844Sralph /* NOTREACHED */ 35113691Ssam default: /* parent */ 35213691Ssam while ((retcode=wait(&status)) != pid && retcode != -1) 35313691Ssam ; 35413691Ssam if (retcode == -1) 355*17844Sralph return -1; 356*17844Sralph else { 357*17844Sralph chmod(dirname, mode); 358*17844Sralph return status; 359*17844Sralph } 36013691Ssam } 361*17844Sralph /* NOTREACHED */ 36213691Ssam } 363*17844Sralph #endif !BSD4_2 364*17844Sralph #endif RECOVER 365