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