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