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