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