1 #ifndef lint 2 static char sccsid[] = "@(#)uusend.c 5.2 (Berkeley) 01/22/85"; 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 /usr/lib/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 = "/usr/lib/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 365