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