1 #ifndef lint 2 static char sccsid[] = "@(#)rcp.c 4.2 82/05/05"; 3 #endif 4 5 #include <stdio.h> 6 #include <signal.h> 7 #include <sys/types.h> 8 #include <sys/stat.h> 9 #include <sys/ioctl.h> 10 #include <net/in.h> 11 #include <pwd.h> 12 #include <ctype.h> 13 #include <errno.h> 14 /* 15 * rcp 16 */ 17 int rem; 18 char *colon(), *index(), *rindex(), *malloc(), *strcpy(), *sprintf(); 19 int errs; 20 int lostconn(); 21 int iamremote; 22 23 int errno; 24 char *sys_errlist[]; 25 int iamremote, targetshouldbedirectory; 26 int iamrecursive; 27 struct passwd *pwd; 28 struct passwd *getpwuid(); 29 30 /*VARARGS*/ 31 int error(); 32 33 #define ga() (void) write(rem, "", 1) 34 35 main(argc, argv) 36 int argc; 37 char **argv; 38 { 39 char *targ, *host, *src; 40 char *suser, *tuser; 41 int i; 42 char buf[BUFSIZ], cmd[16]; 43 44 setpwent(); 45 pwd = getpwuid(getuid()); 46 endpwent(); 47 if (pwd == 0) { 48 fprintf(stderr, "who are you?\n"); 49 exit(1); 50 } 51 argc--, argv++; 52 if (argc > 0 && !strcmp(*argv, "-r")) { 53 iamrecursive++; 54 argc--, argv++; 55 } 56 if (argc > 0 && !strcmp(*argv, "-d")) { 57 targetshouldbedirectory = 1; 58 argc--, argv++; 59 } 60 if (argc > 0 && !strcmp(*argv, "-f")) { 61 argc--, argv++; iamremote = 1; 62 (void) response(); 63 (void) setuid(getuid()); 64 source(argc, argv); 65 exit(errs); 66 } 67 if (argc > 0 && !strcmp(*argv, "-t")) { 68 argc--, argv++; iamremote = 1; 69 (void) setuid(getuid()); 70 sink(argc, argv); 71 exit(errs); 72 } 73 rem = -1; 74 if (argc > 2) 75 targetshouldbedirectory = 1; 76 (void) sprintf(cmd, "rcp%s%s", 77 iamrecursive ? " -r" : "", targetshouldbedirectory ? " -d" : ""); 78 sigsys(SIGPIPE, lostconn); 79 targ = colon(argv[argc - 1]); 80 if (targ) { 81 *targ++ = 0; 82 tuser = rindex(argv[argc - 1], '.'); 83 if (tuser) { 84 *tuser++ = 0; 85 if (!okname(tuser)) 86 exit(1); 87 } else 88 tuser = pwd->pw_name; 89 for (i = 0; i < argc - 1; i++) { 90 src = colon(argv[i]); 91 if (src) { 92 *src++ = 0; 93 suser = rindex(argv[i], '.'); 94 if (suser) { 95 *suser++ = 0; 96 if (!okname(suser)) 97 continue; 98 (void) sprintf(buf, "rsh %s -L %s %s %s '%s:%s' </dev/null", 99 argv[i], suser, cmd, 100 src, argv[argc - 1], targ); 101 } else 102 (void) sprintf(buf, "rsh %s %s %s '%s:%s' </dev/null", 103 argv[i], cmd, 104 src, argv[argc - 1], targ); 105 (void) susystem(buf); 106 } else { 107 if (rem == -1) { 108 (void) sprintf(buf, "%s -t %s", 109 cmd, targ); 110 host = argv[argc - 1]; 111 rem = rcmd(&host, IPPORT_CMDSERVER, 112 pwd->pw_name, tuser, 113 buf, 0); 114 if (rem < 0) 115 exit(1); 116 if (response() < 0) 117 exit(1); 118 } 119 source(1, argv+i); 120 } 121 } 122 } else { 123 if (targetshouldbedirectory) 124 verifydir(argv[argc - 1]); 125 for (i = 0; i < argc - 1; i++) { 126 src = colon(argv[i]); 127 if (src == 0) { 128 (void) sprintf(buf, "/bin/cp%s %s %s", 129 iamrecursive ? " -r" : "", 130 argv[i], argv[argc - 1]); 131 (void) susystem(buf); 132 } else { 133 *src++ = 0; 134 suser = rindex(argv[i], '.'); 135 if (suser) { 136 *suser++ = 0; 137 if (!okname(suser)) 138 continue; 139 } else 140 suser = pwd->pw_name; 141 (void) sprintf(buf, "%s -f %s", cmd, src); 142 host = argv[i]; 143 rem = rcmd(&host, IPPORT_CMDSERVER, 144 pwd->pw_name, suser, 145 buf, 0); 146 if (rem < 0) 147 exit(1); 148 sink(1, argv+argc-1); 149 (void) close(rem); 150 rem = -1; 151 } 152 } 153 } 154 exit(errs); 155 } 156 157 verifydir(cp) 158 char *cp; 159 { 160 struct stat stb; 161 162 if (stat(cp, &stb) < 0) 163 goto bad; 164 if ((stb.st_mode & S_IFMT) == S_IFDIR) 165 return; 166 errno = ENOTDIR; 167 bad: 168 error("rcp: %s: %s.\n", cp, sys_errlist[errno]); 169 exit(1); 170 } 171 172 char * 173 colon(cp) 174 char *cp; 175 { 176 177 while (*cp) { 178 if (*cp == ':') 179 return (cp); 180 if (*cp == '/') 181 return (0); 182 cp++; 183 } 184 return (0); 185 } 186 187 okname(cp0) 188 char *cp0; 189 { 190 register char *cp = cp0; 191 register int c; 192 193 do { 194 c = *cp; 195 if (c & 0200) 196 goto bad; 197 if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 198 goto bad; 199 cp++; 200 } while (*cp); 201 return (1); 202 bad: 203 fprintf(stderr, "rcp: invalid user name %s\n", cp0); 204 return (0); 205 } 206 207 susystem(buf) 208 char *buf; 209 { 210 211 if (fork() == 0) { 212 (void) setuid(getuid()); 213 (void) system(buf); 214 _exit(0); 215 } else 216 (void) wait((int *)0); 217 } 218 219 source(argc, argv) 220 int argc; 221 char **argv; 222 { 223 char *last, *name; 224 struct stat stb; 225 char buf[BUFSIZ]; 226 int x, sizerr, f; 227 off_t i; 228 229 for (x = 0; x < argc; x++) { 230 name = argv[x]; 231 if (access(name, 4) < 0 || (f = open(name, 0)) < 0) { 232 error("rcp: %s: %s\n", name, sys_errlist[errno]); 233 continue; 234 } 235 if (fstat(f, &stb) < 0) 236 goto notreg; 237 switch (stb.st_mode&S_IFMT) { 238 239 case S_IFREG: 240 break; 241 242 case S_IFDIR: 243 if (iamrecursive) { 244 (void) close(f); 245 rsource(name, (int)stb.st_mode); 246 continue; 247 } 248 /* fall into ... */ 249 default: 250 notreg: 251 (void) close(f); 252 error("rcp: %s: not a plain file\n", name); 253 continue; 254 } 255 last = rindex(name, '/'); 256 if (last == 0) 257 last = name; 258 else 259 last++; 260 (void) sprintf(buf, "C%04o %D %s\n", 261 stb.st_mode&07777, stb.st_size, last); 262 (void) write(rem, buf, strlen(buf)); 263 if (response() < 0) { 264 (void) close(f); 265 continue; 266 } 267 sizerr = 0; 268 for (i = 0; i < stb.st_size; i += BUFSIZ) { 269 int amt = BUFSIZ; 270 if (i + amt > stb.st_size) 271 amt = stb.st_size - i; 272 if (sizerr == 0 && read(f, buf, amt) != amt) 273 sizerr = 1; 274 (void) write(rem, buf, amt); 275 } 276 (void) close(f); 277 if (sizerr == 0) 278 ga(); 279 else 280 error("rcp: %s: file changed size\n", name); 281 (void) response(); 282 } 283 } 284 285 #include <ndir.h> 286 287 rsource(name, mode) 288 char *name; 289 int mode; 290 { 291 DIR *d = opendir(name); 292 char *last; 293 struct direct *dp; 294 char buf[BUFSIZ]; 295 char *bufv[1]; 296 297 if (d == 0) { 298 error("%s: %s\n", name, sys_errlist[errno]); 299 return; 300 } 301 last = rindex(name, '/'); 302 if (last == 0) 303 last = name; 304 else 305 last++; 306 (void) sprintf(buf, "D%04o %d %s\n", mode&07777, 0, last); 307 (void) write(rem, buf, strlen(buf)); 308 if (response() < 0) { 309 closedir(d); 310 return; 311 } 312 while (dp = readdir(d)) { 313 if (dp->d_ino == 0) 314 continue; 315 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 316 continue; 317 if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 318 error("%s/%s: Name too long.\n", name, dp->d_name); 319 continue; 320 } 321 (void) sprintf(buf, "%s/%s", name, dp->d_name); 322 bufv[0] = buf; 323 source(1, bufv); 324 } 325 closedir(d); 326 (void) write(rem, "E\n", 2); 327 (void) response(); 328 } 329 330 response() 331 { 332 char resp, c, rbuf[BUFSIZ], *cp = rbuf; 333 334 if (read(rem, &resp, 1) != 1) 335 lostconn(); 336 switch (resp) { 337 338 case 0: 339 return (0); 340 341 default: 342 *cp++ = resp; 343 /* fall into... */ 344 case 1: 345 case 2: 346 do { 347 if (read(rem, &c, 1) != 1) 348 lostconn(); 349 *cp++ = c; 350 } while (cp < &rbuf[BUFSIZ] && c != '\n'); 351 if (iamremote == 0) 352 (void) write(2, rbuf, cp - rbuf); 353 errs++; 354 if (resp == 1) 355 return (-1); 356 exit(1); 357 } 358 /*NOTREACHED*/ 359 } 360 361 lostconn() 362 { 363 364 if (iamremote == 0) 365 fprintf(stderr, "rcp: lost connection\n"); 366 exit(1); 367 } 368 369 sink(argc, argv) 370 int argc; 371 char **argv; 372 { 373 char *targ; 374 char cmdbuf[BUFSIZ], nambuf[BUFSIZ], buf[BUFSIZ], *cp; 375 int of, mode, wrerr, exists; 376 off_t i, size; 377 char *whopp; 378 struct stat stb; int targisdir = 0; 379 #define SCREWUP(str) { whopp = str; goto screwup; } 380 int mask = umask(0); 381 char *myargv[1]; 382 383 umask(mask); 384 if (argc > 1) { 385 error("rcp: ambiguous target\n"); 386 exit(1); 387 } 388 targ = *argv; 389 if (targetshouldbedirectory) 390 verifydir(targ); 391 ga(); 392 if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 393 targisdir = 1; 394 for (;;) { 395 cp = cmdbuf; 396 if (read(rem, cp, 1) <= 0) 397 return; 398 if (*cp++ == '\n') 399 SCREWUP("unexpected '\\n'"); 400 do { 401 if (read(rem, cp, 1) != 1) 402 SCREWUP("lost connection"); 403 } while (*cp++ != '\n'); 404 *cp = 0; 405 if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') { 406 if (iamremote == 0) 407 (void) write(2, cmdbuf, strlen(cmdbuf)); 408 if (cmdbuf[0] == '\02') 409 exit(1); 410 errs++; 411 continue; 412 } 413 *--cp = 0; 414 cp = cmdbuf; 415 if (*cp == 'E') { 416 ga(); 417 return; 418 } 419 if (*cp != 'C' && *cp != 'D') 420 SCREWUP("expected control record"); 421 cp++; 422 mode = 0; 423 for (; cp < cmdbuf+5; cp++) { 424 if (*cp < '0' || *cp > '7') 425 SCREWUP("bad mode"); 426 mode = (mode << 3) | (*cp - '0'); 427 } 428 if (*cp++ != ' ') 429 SCREWUP("mode not delimited"); 430 size = 0; 431 while (*cp >= '0' && *cp <= '9') 432 size = size * 10 + (*cp++ - '0'); 433 if (*cp++ != ' ') 434 SCREWUP("size not delimited"); 435 if (targisdir) 436 (void) sprintf(nambuf, "%s%s%s", targ, 437 *targ ? "/" : "", cp); 438 else 439 (void) strcpy(nambuf, targ); 440 exists = stat(nambuf, &stb) == 0; 441 if (exists && access(nambuf, 2) < 0) 442 goto bad2; 443 { char *slash = rindex(nambuf, '/'), *dir; 444 if (slash == 0) { 445 slash = "/"; 446 dir = "."; 447 } else { 448 *slash = 0; 449 dir = nambuf; 450 } 451 if (exists == 0 && access(dir, 2) < 0) 452 goto bad; 453 *slash = '/'; 454 if (cmdbuf[0] == 'D') { 455 if (stat(nambuf, &stb) == 0) { 456 if ((stb.st_mode&S_IFMT) != S_IFDIR) { 457 errno = ENOTDIR; 458 goto bad; 459 } 460 } else if (mkdir(nambuf, mode) < 0) 461 goto bad; 462 myargv[0] = nambuf; 463 sink(1, myargv); 464 continue; 465 } 466 if ((of = creat(nambuf, mode)) < 0) { 467 bad: 468 *slash = '/'; 469 bad2: 470 error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 471 continue; 472 } 473 } 474 if (exists == 0) { 475 (void) stat(nambuf, &stb); 476 (void) chown(nambuf, pwd->pw_uid, stb.st_gid); 477 (void) chmod(nambuf, mode &~ mask); 478 } 479 ga(); 480 wrerr = 0; 481 for (i = 0; i < size; i += BUFSIZ) { 482 int amt = BUFSIZ; 483 char *cp = buf; 484 485 if (i + amt > size) 486 amt = size - i; 487 do { 488 int j = read(rem, cp, amt); 489 490 if (j <= 0) 491 exit(1); 492 amt -= j; 493 cp += j; 494 } while (amt > 0); 495 amt = BUFSIZ; 496 if (i + amt > size) 497 amt = size - i; 498 if (wrerr == 0 && write(of, buf, amt) != amt) 499 wrerr++; 500 } 501 (void) close(of); 502 (void) response(); 503 if (wrerr) 504 error("rcp: %s: %s\n", cp, sys_errlist[errno]); 505 else 506 ga(); 507 } 508 screwup: 509 error("rcp: protocol screwup: %s\n", whopp); 510 exit(1); 511 } 512 513 /*VARARGS*/ 514 error(fmt, a1, a2, a3, a4, a5) 515 char *fmt; 516 int a1, a2, a3, a4, a5; 517 { 518 char buf[BUFSIZ], *cp = buf; 519 520 errs++; 521 *cp++ = 1; 522 (void) sprintf(cp, fmt, a1, a2, a3, a4, a5); 523 (void) write(rem, buf, strlen(buf)); 524 if (iamremote == 0) 525 (void) write(2, buf+1, strlen(buf+1)); 526 } 527 528 mkdir(name, mode) 529 char *name; 530 int mode; 531 { 532 char *argv[4]; 533 int pid, rc; 534 535 argv[0] = "mkdir"; 536 argv[1] = name; 537 argv[2] = 0; 538 pid = fork(); 539 if (pid < 0) { 540 perror("cp"); 541 return (1); 542 } 543 if (pid) { 544 while (wait(&rc) != pid) 545 continue; 546 if (rc == 0) 547 if (chmod(name, mode) < 0) { 548 perror(name); 549 rc = 1; 550 } 551 return (rc); 552 } 553 (void) setuid(getuid()); 554 execv("/bin/mkdir", argv); 555 execv("/usr/bin/mkdir", argv); 556 perror("mkdir"); 557 _exit(1); 558 /*NOTREACHED*/ 559 } 560 561