1*13691Ssam #ifndef lint 2*13691Ssam static char sccsid[] = "@(#)uusend.c 5.1 (Berkeley) 07/02/83"; 3*13691Ssam #endif 4*13691Ssam 5*13691Ssam /* 6*13691Ssam * uusend: primitive operation to allow uucp like copy of binary files 7*13691Ssam * but handle indirection over systems. 8*13691Ssam * 9*13691Ssam * usage: uusend [-r] [-m ooo] localfile sysname1!sysname2!...!destfile 10*13691Ssam * uusend [-r] [-m ooo] - sysname1!sysname2!...!destfile 11*13691Ssam * 12*13691Ssam * Author: Mark Horton, May 1980. 13*13691Ssam * 14*13691Ssam * "-r" switch added. Has same effect as "-r" in uux. 11/82 CCW 15*13691Ssam * 16*13691Ssam * Error recovery (a la uucp) added & ifdefs for ruusend (as in rmail). 17*13691Ssam * Checks for illegal access to /usr/lib/uucp. 18*13691Ssam * February 1983 Christopher Woodbury 19*13691Ssam * Fixed mode set[ug]id loophole. 4/8/83 CCW 20*13691Ssam * 21*13691Ssam * Add '-f' to make uusend syntax more similar to UUCP. "destname" 22*13691Ssam * can now be a directory. June 1983 CCW 23*13691Ssam */ 24*13691Ssam 25*13691Ssam #include <stdio.h> 26*13691Ssam #include <pwd.h> 27*13691Ssam #include <sys/types.h> 28*13691Ssam #include <sys/stat.h> 29*13691Ssam 30*13691Ssam #define RECOVER 31*13691Ssam 32*13691Ssam FILE *in, *out; 33*13691Ssam FILE *dout; 34*13691Ssam 35*13691Ssam FILE *popen(); 36*13691Ssam char *index(), *strcpy(); 37*13691Ssam 38*13691Ssam #ifdef RUUSEND 39*13691Ssam int rsend; 40*13691Ssam #endif 41*13691Ssam int mode = -1; /* mode to chmod new file to */ 42*13691Ssam char *nextsys; /* next system in the chain */ 43*13691Ssam char dnbuf[200]; /* buffer for result of ~user/file */ 44*13691Ssam char cmdbuf[256]; /* buffer to build uux command in */ 45*13691Ssam char *rflg = ""; /* default value of rflg ccw -- 1 Nov '82 */ 46*13691Ssam 47*13691Ssam struct passwd *user; /* entry in /etc/passwd for ~user */ 48*13691Ssam struct passwd *getpwnam(); 49*13691Ssam struct stat stbuf; 50*13691Ssam 51*13691Ssam char *excl; /* location of first ! in destname */ 52*13691Ssam char *sl; /* location of first / in destname */ 53*13691Ssam char *sourcename; /* argv[1] */ 54*13691Ssam char *destname; /* argv[2] */ 55*13691Ssam char *UULIB = "/usr/lib/uucp"; /* UUCP lib directory */ 56*13691Ssam 57*13691Ssam #ifdef RECOVER 58*13691Ssam char *UUPUB = "/usr/spool/uucppublic/"; /* public UUCP directory */ 59*13691Ssam char *filename; /* file name from end of destname */ 60*13691Ssam char *getfname(); /* routine to get filename from destname */ 61*13691Ssam int fflg; 62*13691Ssam char f[100]; /* name of default output file */ 63*13691Ssam #else 64*13691Ssam char *f = ""; /* so we waste a little space */ 65*13691Ssam #endif 66*13691Ssam 67*13691Ssam main(argc, argv) 68*13691Ssam int argc; 69*13691Ssam char **argv; 70*13691Ssam { 71*13691Ssam register int c; 72*13691Ssam long count = 0; 73*13691Ssam 74*13691Ssam #ifdef DEBUG 75*13691Ssam long t; 76*13691Ssam dout = fopen(DEBUG, "a"); 77*13691Ssam if (dout == NULL) { 78*13691Ssam printf("Cannot append to %s\n", DEBUG); 79*13691Ssam exit(1); 80*13691Ssam } 81*13691Ssam freopen(DEBUG, "a", stdout); 82*13691Ssam /*xxx 83*13691Ssam freopen(DEBUG, "a", stderr); 84*13691Ssam xxx*/ 85*13691Ssam chmod(DEBUG, 0666); 86*13691Ssam fprintf(dout, "\nuusend run: "); 87*13691Ssam for (c=0; c<argc; c++) 88*13691Ssam fprintf(dout, "%s ", argv[c]); 89*13691Ssam time(&t); 90*13691Ssam fprintf(dout, "%s", ctime(&t)); 91*13691Ssam #endif 92*13691Ssam 93*13691Ssam #ifdef RUUSEND 94*13691Ssam if(argv[0][0] == 'r') 95*13691Ssam rsend++; 96*13691Ssam #endif 97*13691Ssam while (argc > 1 && argv[1][0] == '-' && argv[1][1]) { 98*13691Ssam switch(argv[1][1]) { 99*13691Ssam case 'm': 100*13691Ssam sscanf(argv[2], "%o", &mode); 101*13691Ssam mode &= 0777; /* fix set[ug]id loophole */ 102*13691Ssam argc--; argv++; 103*13691Ssam break; 104*13691Ssam case 'r': /* -r flag for uux */ 105*13691Ssam rflg = "-r "; 106*13691Ssam break; 107*13691Ssam #ifdef RECOVER 108*13691Ssam case 'f': 109*13691Ssam fflg++; 110*13691Ssam strcpy(f, argv[1]); 111*13691Ssam break; 112*13691Ssam #endif 113*13691Ssam default: 114*13691Ssam fprintf(stderr, "Bad flag: %s\n", argv[1]); 115*13691Ssam break; 116*13691Ssam } 117*13691Ssam argc--; argv++; 118*13691Ssam } 119*13691Ssam 120*13691Ssam if (argc != 3) { 121*13691Ssam fprintf(stderr, "Usage: uusend [-m ooo] [-r] -/file sys!sys!..!rfile\n"); 122*13691Ssam exit(1); 123*13691Ssam } 124*13691Ssam 125*13691Ssam sourcename = argv[1]; 126*13691Ssam destname = argv[2]; 127*13691Ssam 128*13691Ssam if (sourcename[0] == '-') 129*13691Ssam in = stdin; 130*13691Ssam else { 131*13691Ssam #ifdef RUUSEND 132*13691Ssam if (rsend) { 133*13691Ssam fprintf(stderr, "illegal input\n"); 134*13691Ssam exit(2); 135*13691Ssam } 136*13691Ssam #endif 137*13691Ssam in = fopen(sourcename, "r"); 138*13691Ssam if (in == NULL) { 139*13691Ssam perror(argv[1]); 140*13691Ssam exit(2); 141*13691Ssam } 142*13691Ssam if (!fflg || f[2] == '\0') { 143*13691Ssam strcpy(f, "-f"); 144*13691Ssam strcat(f, getfname(sourcename)); 145*13691Ssam fflg++; 146*13691Ssam } 147*13691Ssam } 148*13691Ssam 149*13691Ssam excl = index(destname, '!'); 150*13691Ssam if (excl) { 151*13691Ssam /* 152*13691Ssam * destname is on a remote system. 153*13691Ssam */ 154*13691Ssam nextsys = destname; 155*13691Ssam *excl++ = 0; 156*13691Ssam destname = excl; 157*13691Ssam if (mode < 0) { 158*13691Ssam fstat(fileno(in), &stbuf); 159*13691Ssam mode = stbuf.st_mode & 0777; 160*13691Ssam } 161*13691Ssam #ifdef RUUSEND 162*13691Ssam sprintf(cmdbuf,"uux %s- \"%s!ruusend %s -m %o - (%s)\"", 163*13691Ssam #else 164*13691Ssam sprintf(cmdbuf, "uux %s- \"%s!uusend %s -m %o - (%s)\"", 165*13691Ssam #endif 166*13691Ssam rflg, nextsys, f, mode, destname); 167*13691Ssam #ifdef DEBUG 168*13691Ssam fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf); 169*13691Ssam #endif 170*13691Ssam out = popen(cmdbuf, "w"); 171*13691Ssam } else { 172*13691Ssam /* 173*13691Ssam * destname is local. 174*13691Ssam */ 175*13691Ssam if (destname[0] == '~') { 176*13691Ssam #ifdef DEBUG 177*13691Ssam fprintf(dout, "before ~: '%s'\n", destname); 178*13691Ssam fflush(dout); 179*13691Ssam #endif 180*13691Ssam sl = index(destname, '/'); 181*13691Ssam #ifdef RECOVER 182*13691Ssam if (sl == NULL && !fflg) { 183*13691Ssam fprintf(stderr, "Illegal ~user\n"); 184*13691Ssam exit(3); 185*13691Ssam } 186*13691Ssam for (sl = destname; *sl != '\0'; sl++) 187*13691Ssam ; /* boy, is this a hack! */ 188*13691Ssam #else 189*13691Ssam if (sl == NULL) { 190*13691Ssam fprintf(stderr, "Illegal ~user\n"); 191*13691Ssam exit(3); 192*13691Ssam } 193*13691Ssam *sl++ = 0; 194*13691Ssam #endif 195*13691Ssam user = getpwnam(destname+1); 196*13691Ssam if (user == NULL) { 197*13691Ssam fprintf(stderr, "No such user as %s\n", 198*13691Ssam destname); 199*13691Ssam #ifdef RECOVER 200*13691Ssam if ((filename =getfname(sl)) == NULL && 201*13691Ssam !fflg) 202*13691Ssam exit(4); 203*13691Ssam strcpy(dnbuf, UUPUB); 204*13691Ssam if (fflg) 205*13691Ssam strcat(dnbuf, &f[2]); 206*13691Ssam else 207*13691Ssam strcat(dnbuf, filename); 208*13691Ssam } 209*13691Ssam else { 210*13691Ssam strcpy(dnbuf, user->pw_dir); 211*13691Ssam strcat(dnbuf, "/"); 212*13691Ssam strcat(dnbuf, sl); 213*13691Ssam } 214*13691Ssam #else 215*13691Ssam exit(4); 216*13691Ssam } 217*13691Ssam strcpy(dnbuf, user->pw_dir); 218*13691Ssam strcat(dnbuf, "/"); 219*13691Ssam strcat(dnbuf, sl); 220*13691Ssam #endif 221*13691Ssam destname = dnbuf; 222*13691Ssam } 223*13691Ssam #ifdef RECOVER 224*13691Ssam else 225*13691Ssam destname = strcpy(dnbuf, destname); 226*13691Ssam #endif 227*13691Ssam if(strncmp(UULIB, destname, strlen(UULIB)) == 0) { 228*13691Ssam fprintf(stderr, "illegal file: %s", destname); 229*13691Ssam exit(4); 230*13691Ssam } 231*13691Ssam #ifdef RECOVER 232*13691Ssam if (stat(destname, &stbuf) == 0 && 233*13691Ssam (stbuf.st_mode & S_IFMT) == S_IFDIR && 234*13691Ssam fflg) { 235*13691Ssam strcat(dnbuf, "/"); 236*13691Ssam strcat(dnbuf, &f[2]); 237*13691Ssam } 238*13691Ssam #endif 239*13691Ssam out = fopen(destname, "w"); 240*13691Ssam #ifdef DEBUG 241*13691Ssam fprintf(dout, "local, file='%s'\n", destname); 242*13691Ssam #endif 243*13691Ssam if (out == NULL) { 244*13691Ssam perror(destname); 245*13691Ssam #ifdef RECOVER 246*13691Ssam if (strncmp(destname,UUPUB,strlen(UUPUB)) == 0) 247*13691Ssam exit(5); /* forget it! */ 248*13691Ssam filename = getfname(destname); 249*13691Ssam if (destname == dnbuf) /* cmdbuf is scratch */ 250*13691Ssam filename = strcpy(cmdbuf, filename); 251*13691Ssam destname = strcpy(dnbuf, UUPUB); 252*13691Ssam if (user != NULL) { 253*13691Ssam strcat(destname, user->pw_name); 254*13691Ssam if (stat(destname, &stbuf) == -1) { 255*13691Ssam mkdir(destname); 256*13691Ssam chmod(destname, 0777); 257*13691Ssam } 258*13691Ssam strcat(destname, "/"); 259*13691Ssam } 260*13691Ssam #ifdef RECOVER 261*13691Ssam if (fflg) 262*13691Ssam strcat(destname, &f[2]); 263*13691Ssam else 264*13691Ssam strcat(destname, filename); 265*13691Ssam #endif 266*13691Ssam if ((out = fopen(destname, "w")) == NULL) 267*13691Ssam exit(5); /* all for naught! */ 268*13691Ssam #else 269*13691Ssam exit(5); 270*13691Ssam #endif 271*13691Ssam } 272*13691Ssam if (mode > 0) 273*13691Ssam chmod(destname, mode); /* don't bother to check it */ 274*13691Ssam } 275*13691Ssam 276*13691Ssam /* 277*13691Ssam * Now, in any case, copy from in to out. 278*13691Ssam */ 279*13691Ssam 280*13691Ssam while ((c=getc(in)) != EOF) { 281*13691Ssam putc(c, out); 282*13691Ssam count++; 283*13691Ssam } 284*13691Ssam #ifdef DEBUG 285*13691Ssam fprintf(dout, "count %ld bytes\n", count); 286*13691Ssam fclose(dout); 287*13691Ssam #endif 288*13691Ssam 289*13691Ssam fclose(in); 290*13691Ssam fclose(out); /* really should pclose in that case */ 291*13691Ssam exit(0); 292*13691Ssam } 293*13691Ssam 294*13691Ssam /* 295*13691Ssam * Return the ptr in sp at which the character c appears; 296*13691Ssam * NULL if not found. Included so I don't have to fight the 297*13691Ssam * index/strchr battle. 298*13691Ssam */ 299*13691Ssam 300*13691Ssam #define NULL 0 301*13691Ssam 302*13691Ssam char * 303*13691Ssam index(sp, c) 304*13691Ssam register char *sp, c; 305*13691Ssam { 306*13691Ssam do { 307*13691Ssam if (*sp == c) 308*13691Ssam return(sp); 309*13691Ssam } while (*sp++); 310*13691Ssam return(NULL); 311*13691Ssam } 312*13691Ssam 313*13691Ssam #ifdef RECOVER 314*13691Ssam char * 315*13691Ssam getfname(p) 316*13691Ssam register char *p; 317*13691Ssam { 318*13691Ssam register char *s; 319*13691Ssam s = p; 320*13691Ssam while (*p != '\0') 321*13691Ssam p++; 322*13691Ssam if (p == s) 323*13691Ssam return (NULL); 324*13691Ssam for (;p != s; p--) 325*13691Ssam if (*p == '/') { 326*13691Ssam p++; 327*13691Ssam break; 328*13691Ssam } 329*13691Ssam return (p); 330*13691Ssam } 331*13691Ssam 332*13691Ssam mkdir(dirname) 333*13691Ssam char *dirname; 334*13691Ssam { 335*13691Ssam register int pid; 336*13691Ssam int retcode, status; 337*13691Ssam switch ((pid = fork())) { 338*13691Ssam case -1: /* error */ 339*13691Ssam return (-1); 340*13691Ssam break; 341*13691Ssam case 0: /* child */ 342*13691Ssam umask(0); 343*13691Ssam execl("/bin/mkdir", "mkdir", dirname, 0); 344*13691Ssam exit(1); 345*13691Ssam break; 346*13691Ssam default: /* parent */ 347*13691Ssam while ((retcode=wait(&status)) != pid && retcode != -1) 348*13691Ssam ; 349*13691Ssam if (retcode == -1) 350*13691Ssam return (-1); 351*13691Ssam else 352*13691Ssam return (status); 353*13691Ssam break; 354*13691Ssam } 355*13691Ssam } 356*13691Ssam #endif 357