1*48618Sbostic /*- 2*48618Sbostic * Copyright (c) 1980, 1991 The Regents of the University of California. 3*48618Sbostic * All rights reserved. 4*48618Sbostic * 5*48618Sbostic * %sccs.include.redist.c% 6*48618Sbostic */ 7*48618Sbostic 813691Ssam #ifndef lint 9*48618Sbostic char copyright[] = 10*48618Sbostic "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\ 11*48618Sbostic All rights reserved.\n"; 12*48618Sbostic #endif /* not lint */ 1313691Ssam 14*48618Sbostic #ifndef lint 15*48618Sbostic static char sccsid[] = "@(#)uusend.c 5.4 (Berkeley) 04/24/91"; 16*48618Sbostic #endif /* not lint */ 17*48618Sbostic 1813691Ssam /* 1913691Ssam * uusend: primitive operation to allow uucp like copy of binary files 2013691Ssam * but handle indirection over systems. 2113691Ssam * 2213691Ssam * usage: uusend [-r] [-m ooo] localfile sysname1!sysname2!...!destfile 2313691Ssam * uusend [-r] [-m ooo] - sysname1!sysname2!...!destfile 2413691Ssam * 2513691Ssam * Author: Mark Horton, May 1980. 2613691Ssam * 2713691Ssam * "-r" switch added. Has same effect as "-r" in uux. 11/82 CCW 2813691Ssam * 2913691Ssam * Error recovery (a la uucp) added & ifdefs for ruusend (as in rmail). 3013691Ssam * Checks for illegal access to /usr/lib/uucp. 3113691Ssam * February 1983 Christopher Woodbury 3213691Ssam * Fixed mode set[ug]id loophole. 4/8/83 CCW 3313691Ssam * 3413691Ssam * Add '-f' to make uusend syntax more similar to UUCP. "destname" 3513691Ssam * can now be a directory. June 1983 CCW 3613691Ssam */ 3713691Ssam 3837931Sbostic #include <sys/types.h> 3937931Sbostic #include <sys/stat.h> 4013691Ssam #include <stdio.h> 4113691Ssam #include <pwd.h> 4213691Ssam 4317844Sralph /* 4417844Sralph * define RECOVER to permit requests like 'uusend file sys1!sys2!~uucp' 4517844Sralph * (abbreviation for 'uusend file sys1!sys2!~uucp/file'). 4617844Sralph * define DEBUG to keep log of uusend uusage. 4717844Sralph * define RUUSEND if neighboring sites permit 'ruusend', 4817844Sralph * which they certainly should to avoid security holes 4917844Sralph */ 5013691Ssam #define RECOVER 5117844Sralph /*#define DEBUG "/usr/spool/uucp/uusend.log"/**/ 5213691Ssam 5313691Ssam FILE *in, *out; 5413691Ssam FILE *dout; 5513691Ssam 5617844Sralph extern FILE *popen(); 5717844Sralph extern char *index(), *strcpy(), *strcat(), *ctime(); 5813691Ssam 5913691Ssam #ifdef RUUSEND 6013691Ssam int rsend; 6117844Sralph #endif RUUSEND 6213691Ssam int mode = -1; /* mode to chmod new file to */ 6313691Ssam char *nextsys; /* next system in the chain */ 6413691Ssam char dnbuf[200]; /* buffer for result of ~user/file */ 6513691Ssam char cmdbuf[256]; /* buffer to build uux command in */ 6613691Ssam char *rflg = ""; /* default value of rflg ccw -- 1 Nov '82 */ 6713691Ssam 6813691Ssam struct passwd *user; /* entry in /etc/passwd for ~user */ 6913691Ssam struct passwd *getpwnam(); 7013691Ssam struct stat stbuf; 7113691Ssam 7213691Ssam char *excl; /* location of first ! in destname */ 7313691Ssam char *sl; /* location of first / in destname */ 7413691Ssam char *sourcename; /* argv[1] */ 7513691Ssam char *destname; /* argv[2] */ 7613691Ssam char *UULIB = "/usr/lib/uucp"; /* UUCP lib directory */ 7713691Ssam 7813691Ssam #ifdef RECOVER 7913691Ssam char *UUPUB = "/usr/spool/uucppublic/"; /* public UUCP directory */ 8013691Ssam char *filename; /* file name from end of destname */ 8113691Ssam char *getfname(); /* routine to get filename from destname */ 8213691Ssam int fflg; 8313691Ssam char f[100]; /* name of default output file */ 8417844Sralph #else !RECOVER 8513691Ssam char *f = ""; /* so we waste a little space */ 8617844Sralph #endif !RECOVER 8713691Ssam 8813691Ssam main(argc, argv) 8913691Ssam int argc; 9013691Ssam char **argv; 9113691Ssam { 9213691Ssam register int c; 9317844Sralph long count; 9417844Sralph extern char **environ; 9513691Ssam 9613691Ssam #ifdef DEBUG 9713691Ssam long t; 9817844Sralph umask(022); 9913691Ssam dout = fopen(DEBUG, "a"); 10013691Ssam if (dout == NULL) { 10113691Ssam printf("Cannot append to %s\n", DEBUG); 10213691Ssam exit(1); 10313691Ssam } 10413691Ssam freopen(DEBUG, "a", stdout); 10513691Ssam fprintf(dout, "\nuusend run: "); 10613691Ssam for (c=0; c<argc; c++) 10713691Ssam fprintf(dout, "%s ", argv[c]); 10813691Ssam time(&t); 10913691Ssam fprintf(dout, "%s", ctime(&t)); 11017844Sralph #endif DEBUG 11113691Ssam 11213691Ssam #ifdef RUUSEND 11313691Ssam if(argv[0][0] == 'r') 11413691Ssam rsend++; 11517844Sralph #endif RUUSEND 11613691Ssam while (argc > 1 && argv[1][0] == '-' && argv[1][1]) { 11713691Ssam switch(argv[1][1]) { 11813691Ssam case 'm': 11913691Ssam sscanf(argv[2], "%o", &mode); 12013691Ssam mode &= 0777; /* fix set[ug]id loophole */ 12113691Ssam argc--; argv++; 12213691Ssam break; 12313691Ssam case 'r': /* -r flag for uux */ 12413691Ssam rflg = "-r "; 12513691Ssam break; 12613691Ssam #ifdef RECOVER 12713691Ssam case 'f': 12813691Ssam fflg++; 12913691Ssam strcpy(f, argv[1]); 13013691Ssam break; 13117844Sralph #endif RECOVER 13213691Ssam default: 13313691Ssam fprintf(stderr, "Bad flag: %s\n", argv[1]); 13413691Ssam break; 13513691Ssam } 13613691Ssam argc--; argv++; 13713691Ssam } 13813691Ssam 13913691Ssam if (argc != 3) { 14013691Ssam fprintf(stderr, "Usage: uusend [-m ooo] [-r] -/file sys!sys!..!rfile\n"); 14113691Ssam exit(1); 14213691Ssam } 14313691Ssam 14413691Ssam sourcename = argv[1]; 14513691Ssam destname = argv[2]; 14613691Ssam 14713691Ssam if (sourcename[0] == '-') 14813691Ssam in = stdin; 14913691Ssam else { 15013691Ssam #ifdef RUUSEND 15113691Ssam if (rsend) { 15213691Ssam fprintf(stderr, "illegal input\n"); 15313691Ssam exit(2); 15413691Ssam } 15517844Sralph #endif RUUSEND 15613691Ssam in = fopen(sourcename, "r"); 15713691Ssam if (in == NULL) { 15813691Ssam perror(argv[1]); 15913691Ssam exit(2); 16013691Ssam } 16113691Ssam if (!fflg || f[2] == '\0') { 16213691Ssam strcpy(f, "-f"); 16313691Ssam strcat(f, getfname(sourcename)); 16413691Ssam fflg++; 16513691Ssam } 16613691Ssam } 16713691Ssam 16813691Ssam excl = index(destname, '!'); 16913691Ssam if (excl) { 17013691Ssam /* 17113691Ssam * destname is on a remote system. 17213691Ssam */ 17313691Ssam nextsys = destname; 17413691Ssam *excl++ = 0; 17513691Ssam destname = excl; 17613691Ssam if (mode < 0) { 17713691Ssam fstat(fileno(in), &stbuf); 17813691Ssam mode = stbuf.st_mode & 0777; 17913691Ssam } 18013691Ssam #ifdef RUUSEND 18117844Sralph sprintf(cmdbuf,"uux -gn -z %s- \"%s!ruusend %s -m %o - (%s)\"", 18217844Sralph #else !RUUSEND 18317844Sralph sprintf(cmdbuf, "uux -gn -z %s- \"%s!uusend %s -m %o - (%s)\"", 18417844Sralph #endif !RUUSEND 18513691Ssam rflg, nextsys, f, mode, destname); 18613691Ssam #ifdef DEBUG 18713691Ssam fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf); 18817844Sralph #endif DEBUG 18913691Ssam out = popen(cmdbuf, "w"); 19013691Ssam } else { 19113691Ssam /* 19213691Ssam * destname is local. 19313691Ssam */ 19413691Ssam if (destname[0] == '~') { 19513691Ssam #ifdef DEBUG 19613691Ssam fprintf(dout, "before ~: '%s'\n", destname); 19713691Ssam fflush(dout); 19817844Sralph #endif DEBUG 19913691Ssam sl = index(destname, '/'); 20013691Ssam #ifdef RECOVER 20113691Ssam if (sl == NULL && !fflg) { 20213691Ssam fprintf(stderr, "Illegal ~user\n"); 20313691Ssam exit(3); 20413691Ssam } 20513691Ssam for (sl = destname; *sl != '\0'; sl++) 20613691Ssam ; /* boy, is this a hack! */ 20717844Sralph #else !RECOVER 20813691Ssam if (sl == NULL) { 20913691Ssam fprintf(stderr, "Illegal ~user\n"); 21013691Ssam exit(3); 21113691Ssam } 21213691Ssam *sl++ = 0; 21317844Sralph #endif !RECOVER 21413691Ssam user = getpwnam(destname+1); 21513691Ssam if (user == NULL) { 21613691Ssam fprintf(stderr, "No such user as %s\n", 21713691Ssam destname); 21813691Ssam #ifdef RECOVER 21913691Ssam if ((filename =getfname(sl)) == NULL && 22013691Ssam !fflg) 22113691Ssam exit(4); 22213691Ssam strcpy(dnbuf, UUPUB); 22313691Ssam if (fflg) 22413691Ssam strcat(dnbuf, &f[2]); 22513691Ssam else 22613691Ssam strcat(dnbuf, filename); 22713691Ssam } 22813691Ssam else { 22913691Ssam strcpy(dnbuf, user->pw_dir); 23013691Ssam strcat(dnbuf, "/"); 23113691Ssam strcat(dnbuf, sl); 23213691Ssam } 23317844Sralph #else !RECOVER 23413691Ssam exit(4); 23513691Ssam } 23613691Ssam strcpy(dnbuf, user->pw_dir); 23713691Ssam strcat(dnbuf, "/"); 23813691Ssam strcat(dnbuf, sl); 23917844Sralph #endif !RECOVER 24013691Ssam destname = dnbuf; 24113691Ssam } 24213691Ssam #ifdef RECOVER 24313691Ssam else 24413691Ssam destname = strcpy(dnbuf, destname); 24517844Sralph #endif !RECOVER 24613691Ssam if(strncmp(UULIB, destname, strlen(UULIB)) == 0) { 24713691Ssam fprintf(stderr, "illegal file: %s", destname); 24813691Ssam exit(4); 24913691Ssam } 25013691Ssam #ifdef RECOVER 25113691Ssam if (stat(destname, &stbuf) == 0 && 25213691Ssam (stbuf.st_mode & S_IFMT) == S_IFDIR && 25313691Ssam fflg) { 25417844Sralph strcat(destname, "/"); 25517844Sralph strcat(destname, &f[2]); 25613691Ssam } 25717844Sralph #endif RECOVER 25813691Ssam out = fopen(destname, "w"); 25913691Ssam #ifdef DEBUG 26013691Ssam fprintf(dout, "local, file='%s'\n", destname); 26117844Sralph #endif DEBUG 26213691Ssam if (out == NULL) { 26313691Ssam perror(destname); 26413691Ssam #ifdef RECOVER 26513691Ssam if (strncmp(destname,UUPUB,strlen(UUPUB)) == 0) 26613691Ssam exit(5); /* forget it! */ 26713691Ssam filename = getfname(destname); 26813691Ssam if (destname == dnbuf) /* cmdbuf is scratch */ 26913691Ssam filename = strcpy(cmdbuf, filename); 27013691Ssam destname = strcpy(dnbuf, UUPUB); 27113691Ssam if (user != NULL) { 27213691Ssam strcat(destname, user->pw_name); 27313691Ssam if (stat(destname, &stbuf) == -1) { 27417844Sralph mkdir(destname, 0777); 27513691Ssam } 27613691Ssam strcat(destname, "/"); 27713691Ssam } 27813691Ssam if (fflg) 27913691Ssam strcat(destname, &f[2]); 28013691Ssam else 28113691Ssam strcat(destname, filename); 28213691Ssam if ((out = fopen(destname, "w")) == NULL) 28313691Ssam exit(5); /* all for naught! */ 28417844Sralph #else !RECOVER 28513691Ssam exit(5); 28617844Sralph #endif !RECOVER 28713691Ssam } 28813691Ssam if (mode > 0) 28913691Ssam chmod(destname, mode); /* don't bother to check it */ 29013691Ssam } 29113691Ssam 29213691Ssam /* 29313691Ssam * Now, in any case, copy from in to out. 29413691Ssam */ 29513691Ssam 29617844Sralph count = 0; 29713691Ssam while ((c=getc(in)) != EOF) { 29813691Ssam putc(c, out); 29913691Ssam count++; 30013691Ssam } 30113691Ssam #ifdef DEBUG 30213691Ssam fprintf(dout, "count %ld bytes\n", count); 30313691Ssam fclose(dout); 30417844Sralph #endif DEBUG 30517844Sralph 30613691Ssam fclose(in); 30713691Ssam fclose(out); /* really should pclose in that case */ 30813691Ssam exit(0); 30913691Ssam } 31013691Ssam 31113691Ssam /* 31213691Ssam * Return the ptr in sp at which the character c appears; 31313691Ssam * NULL if not found. Included so I don't have to fight the 31413691Ssam * index/strchr battle. 31513691Ssam */ 31613691Ssam 31713691Ssam #define NULL 0 31813691Ssam 31913691Ssam char * 32013691Ssam index(sp, c) 32113691Ssam register char *sp, c; 32213691Ssam { 32313691Ssam do { 32413691Ssam if (*sp == c) 32513691Ssam return(sp); 32613691Ssam } while (*sp++); 32713691Ssam return(NULL); 32813691Ssam } 32913691Ssam 33013691Ssam #ifdef RECOVER 33113691Ssam char * 33213691Ssam getfname(p) 33313691Ssam register char *p; 33413691Ssam { 33513691Ssam register char *s; 33613691Ssam s = p; 33713691Ssam while (*p != '\0') 33813691Ssam p++; 33913691Ssam if (p == s) 34013691Ssam return (NULL); 34113691Ssam for (;p != s; p--) 34213691Ssam if (*p == '/') { 34313691Ssam p++; 34413691Ssam break; 34513691Ssam } 34613691Ssam return (p); 34713691Ssam } 34813691Ssam 34917844Sralph #ifndef BSD4_2 35017844Sralph makedir(dirname, mode) 35113691Ssam char *dirname; 35217844Sralph int mode; 35313691Ssam { 35413691Ssam register int pid; 35513691Ssam int retcode, status; 35613691Ssam switch ((pid = fork())) { 35713691Ssam case -1: /* error */ 35813691Ssam return (-1); 35913691Ssam case 0: /* child */ 36013691Ssam umask(0); 36117844Sralph execl("/bin/mkdir", "mkdir", dirname, (char *)0); 36213691Ssam exit(1); 36317844Sralph /* NOTREACHED */ 36413691Ssam default: /* parent */ 36513691Ssam while ((retcode=wait(&status)) != pid && retcode != -1) 36613691Ssam ; 36713691Ssam if (retcode == -1) 36817844Sralph return -1; 36917844Sralph else { 37017844Sralph chmod(dirname, mode); 37117844Sralph return status; 37217844Sralph } 37313691Ssam } 37417844Sralph /* NOTREACHED */ 37513691Ssam } 37617844Sralph #endif !BSD4_2 37717844Sralph #endif RECOVER 378