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