1 #ifndef lint 2 static char sccsid[] = "@(#)rcp.c 4.1 82/04/02"; 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, i; 227 228 for (x = 0; x < argc; x++) { 229 name = argv[x]; 230 if (access(name, 4) < 0 || (f = open(name, 0)) < 0) { 231 error("rcp: %s: %s\n", name, sys_errlist[errno]); 232 continue; 233 } 234 if (fstat(f, &stb) < 0) 235 goto notreg; 236 switch (stb.st_mode&S_IFMT) { 237 238 case S_IFREG: 239 break; 240 241 case S_IFDIR: 242 if (iamrecursive) { 243 (void) close(f); 244 rsource(name, (int)stb.st_mode); 245 continue; 246 } 247 /* fall into ... */ 248 default: 249 notreg: 250 (void) close(f); 251 error("rcp: %s: not a plain file\n", name); 252 continue; 253 } 254 last = rindex(name, '/'); 255 if (last == 0) 256 last = name; 257 else 258 last++; 259 (void) sprintf(buf, "C%04o %d %s\n", 260 stb.st_mode&07777, stb.st_size, last); 261 (void) write(rem, buf, strlen(buf)); 262 if (response() < 0) { 263 (void) close(f); 264 continue; 265 } 266 sizerr = 0; 267 for (i = 0; i < stb.st_size; i += BUFSIZ) { 268 int amt = BUFSIZ; 269 if (i + amt > stb.st_size) 270 amt = stb.st_size - i; 271 if (sizerr == 0 && read(f, buf, amt) != amt) 272 sizerr = 1; 273 (void) write(rem, buf, amt); 274 } 275 (void) close(f); 276 if (sizerr == 0) 277 ga(); 278 else 279 error("rcp: %s: file changed size\n", name); 280 (void) response(); 281 } 282 } 283 284 #include <ndir.h> 285 286 rsource(name, mode) 287 char *name; 288 int mode; 289 { 290 DIR *d = opendir(name); 291 char *last; 292 struct direct *dp; 293 char buf[BUFSIZ]; 294 char *bufv[1]; 295 296 if (d == 0) { 297 error("%s: %s\n", name, sys_errlist[errno]); 298 return; 299 } 300 last = rindex(name, '/'); 301 if (last == 0) 302 last = name; 303 else 304 last++; 305 (void) sprintf(buf, "D%04o %d %s\n", mode&07777, 0, last); 306 (void) write(rem, buf, strlen(buf)); 307 if (response() < 0) { 308 closedir(d); 309 return; 310 } 311 while (dp = readdir(d)) { 312 if (dp->d_ino == 0) 313 continue; 314 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 315 continue; 316 if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 317 error("%s/%s: Name too long.\n", name, dp->d_name); 318 continue; 319 } 320 (void) sprintf(buf, "%s/%s", name, dp->d_name); 321 bufv[0] = buf; 322 source(1, bufv); 323 } 324 closedir(d); 325 (void) write(rem, "E\n", 2); 326 (void) response(); 327 } 328 329 response() 330 { 331 char resp, c, rbuf[BUFSIZ], *cp = rbuf; 332 333 if (read(rem, &resp, 1) != 1) 334 lostconn(); 335 switch (resp) { 336 337 case 0: 338 return (0); 339 340 default: 341 *cp++ = resp; 342 /* fall into... */ 343 case 1: 344 case 2: 345 do { 346 if (read(rem, &c, 1) != 1) 347 lostconn(); 348 *cp++ = c; 349 } while (cp < &rbuf[BUFSIZ] && c != '\n'); 350 if (iamremote == 0) 351 (void) write(2, rbuf, cp - rbuf); 352 errs++; 353 if (resp == 1) 354 return (-1); 355 exit(1); 356 } 357 /*NOTREACHED*/ 358 } 359 360 lostconn() 361 { 362 363 if (iamremote == 0) 364 fprintf(stderr, "rcp: lost connection\n"); 365 exit(1); 366 } 367 368 sink(argc, argv) 369 int argc; 370 char **argv; 371 { 372 char *targ; 373 char cmdbuf[BUFSIZ], nambuf[BUFSIZ], buf[BUFSIZ], *cp; 374 int of, mode, i, size, wrerr, exists; 375 char *whopp; 376 struct stat stb; int targisdir = 0; 377 #define SCREWUP(str) { whopp = str; goto screwup; } 378 int mask = umask(0); 379 char *myargv[1]; 380 381 umask(mask); 382 if (argc > 1) { 383 error("rcp: ambiguous target\n"); 384 exit(1); 385 } 386 targ = *argv; 387 if (targetshouldbedirectory) 388 verifydir(targ); 389 ga(); 390 if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 391 targisdir = 1; 392 for (;;) { 393 cp = cmdbuf; 394 if (read(rem, cp, 1) <= 0) 395 return; 396 if (*cp++ == '\n') 397 SCREWUP("unexpected '\\n'"); 398 do { 399 if (read(rem, cp, 1) != 1) 400 SCREWUP("lost connection"); 401 } while (*cp++ != '\n'); 402 *cp = 0; 403 if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') { 404 if (iamremote == 0) 405 (void) write(2, cmdbuf, strlen(cmdbuf)); 406 if (cmdbuf[0] == '\02') 407 exit(1); 408 errs++; 409 continue; 410 } 411 *--cp = 0; 412 cp = cmdbuf; 413 if (*cp == 'E') { 414 ga(); 415 return; 416 } 417 if (*cp != 'C' && *cp != 'D') 418 SCREWUP("expected control record"); 419 cp++; 420 mode = 0; 421 for (; cp < cmdbuf+5; cp++) { 422 if (*cp < '0' || *cp > '7') 423 SCREWUP("bad mode"); 424 mode = (mode << 3) | (*cp - '0'); 425 } 426 if (*cp++ != ' ') 427 SCREWUP("mode not delimited"); 428 size = 0; 429 while (*cp >= '0' && *cp <= '9') 430 size = size * 10 + (*cp++ - '0'); 431 if (*cp++ != ' ') 432 SCREWUP("size not delimited"); 433 if (targisdir) 434 (void) sprintf(nambuf, "%s%s%s", targ, 435 *targ ? "/" : "", cp); 436 else 437 (void) strcpy(nambuf, targ); 438 exists = stat(nambuf, &stb) == 0; 439 if (exists && access(nambuf, 2) < 0) 440 goto bad2; 441 { char *slash = rindex(nambuf, '/'), *dir; 442 if (slash == 0) { 443 slash = "/"; 444 dir = "."; 445 } else { 446 *slash = 0; 447 dir = nambuf; 448 } 449 if (exists == 0 && access(dir, 2) < 0) 450 goto bad; 451 *slash = '/'; 452 if (cmdbuf[0] == 'D') { 453 if (stat(nambuf, &stb) == 0) { 454 if ((stb.st_mode&S_IFMT) != S_IFDIR) { 455 errno = ENOTDIR; 456 goto bad; 457 } 458 } else if (mkdir(nambuf, mode) < 0) 459 goto bad; 460 myargv[0] = nambuf; 461 sink(1, myargv); 462 continue; 463 } 464 if ((of = creat(nambuf, mode)) < 0) { 465 bad: 466 *slash = '/'; 467 bad2: 468 error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 469 continue; 470 } 471 } 472 if (exists == 0) { 473 (void) stat(nambuf, &stb); 474 (void) chown(nambuf, pwd->pw_uid, stb.st_gid); 475 (void) chmod(nambuf, mode &~ mask); 476 } 477 ga(); 478 wrerr = 0; 479 for (i = 0; i < size; i += BUFSIZ) { 480 int amt = BUFSIZ; 481 char *cp = buf; 482 483 if (i + amt > size) 484 amt = size - i; 485 do { 486 int j = read(rem, cp, amt); 487 488 if (j <= 0) 489 exit(1); 490 amt -= j; 491 cp += j; 492 } while (amt > 0); 493 amt = BUFSIZ; 494 if (i + amt > size) 495 amt = size - i; 496 if (wrerr == 0 && write(of, buf, amt) != amt) 497 wrerr++; 498 } 499 (void) close(of); 500 (void) response(); 501 if (wrerr) 502 error("rcp: %s: %s\n", cp, sys_errlist[errno]); 503 else 504 ga(); 505 } 506 screwup: 507 error("rcp: protocol screwup: %s\n", whopp); 508 exit(1); 509 } 510 511 /*VARARGS*/ 512 error(fmt, a1, a2, a3, a4, a5) 513 char *fmt; 514 int a1, a2, a3, a4, a5; 515 { 516 char buf[BUFSIZ], *cp = buf; 517 518 errs++; 519 *cp++ = 1; 520 (void) sprintf(cp, fmt, a1, a2, a3, a4, a5); 521 (void) write(rem, buf, strlen(buf)); 522 if (iamremote == 0) 523 (void) write(2, buf+1, strlen(buf+1)); 524 } 525 526 mkdir(name, mode) 527 char *name; 528 int mode; 529 { 530 char *argv[4]; 531 int pid, rc; 532 533 argv[0] = "mkdir"; 534 argv[1] = name; 535 argv[2] = 0; 536 pid = fork(); 537 if (pid < 0) { 538 perror("cp"); 539 return (1); 540 } 541 if (pid) { 542 while (wait(&rc) != pid) 543 continue; 544 if (rc == 0) 545 if (chmod(name, mode) < 0) { 546 perror(name); 547 rc = 1; 548 } 549 return (rc); 550 } 551 (void) setuid(getuid()); 552 execv("/bin/mkdir", argv); 553 execv("/usr/bin/mkdir", argv); 554 perror("mkdir"); 555 _exit(1); 556 /*NOTREACHED*/ 557 } 558