home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / rcp / rcp.c,v < prev    next >
Encoding:
Text File  |  1994-05-23  |  21.1 KB  |  1,011 lines

  1. head    1.1;
  2. access;
  3. symbols;
  4. locks
  5.     rzsfl:1.1; strict;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.1
  10. date    94.05.23.09.07.47;    author rzsfl;    state Exp;
  11. branches;
  12. next    ;
  13.  
  14.  
  15. desc
  16. @Original
  17. @
  18.  
  19.  
  20. 1.1
  21. log
  22. @Initial revision
  23. @
  24. text
  25. @/*
  26.  * Copyright (c) 1983, 1990 The Regents of the University of California.
  27.  * All rights reserved.
  28.  *
  29.  * Redistribution and use in source and binary forms, with or without
  30.  * modification, are permitted provided that the following conditions
  31.  * are met:
  32.  * 1. Redistributions of source code must retain the above copyright
  33.  *    notice, this list of conditions and the following disclaimer.
  34.  * 2. Redistributions in binary form must reproduce the above copyright
  35.  *    notice, this list of conditions and the following disclaimer in the
  36.  *    documentation and/or other materials provided with the distribution.
  37.  * 3. All advertising materials mentioning features or use of this software
  38.  *    must display the following acknowledgement:
  39.  *    This product includes software developed by the University of
  40.  *    California, Berkeley and its contributors.
  41.  * 4. Neither the name of the University nor the names of its contributors
  42.  *    may be used to endorse or promote products derived from this software
  43.  *    without specific prior written permission.
  44.  *
  45.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  46.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  47.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  48.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  49.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  50.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  51.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  52.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  53.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  54.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  55.  * SUCH DAMAGE.
  56.  */
  57.  
  58. #ifndef lint
  59. char copyright[] =
  60. "@@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\
  61.  All rights reserved.\n";
  62. #endif /* not lint */
  63.  
  64. #ifndef lint
  65. /*static char sccsid[] = "from: @@(#)rcp.c    5.32 (Berkeley) 2/25/91";*/
  66. static char rcsid[] = "$Id: rcp.c,v 1.4 1993/08/01 18:58:57 mycroft Exp $";
  67. #endif /* not lint */
  68.  
  69. /*
  70.  * rcp
  71.  */
  72. #include <sys/param.h>
  73. #include <sys/stat.h>
  74. #include <sys/time.h>
  75. #include <sys/ioctl.h>
  76. #include <sys/socket.h>
  77. #include <sys/wait.h>
  78. #include <netinet/in.h>
  79. #include <netinet/in_systm.h>
  80. #include <netinet/ip.h>
  81. #include <dirent.h>
  82. #include <fcntl.h>
  83. #include <signal.h>
  84. #include <pwd.h>
  85. #include <netdb.h>
  86. #include <errno.h>
  87. #include <unistd.h>
  88. #include <stdio.h>
  89. #include <stdlib.h>
  90. #include <string.h>
  91. #include <ctype.h>
  92. #include "pathnames.h"
  93.  
  94. #ifdef KERBEROS
  95. #include <kerberosIV/des.h>
  96. #include <kerberosIV/krb.h>
  97. char    dst_realm_buf[REALM_SZ];
  98. char    *dest_realm = NULL;
  99. int    use_kerberos = 1;
  100. CREDENTIALS     cred;
  101. Key_schedule    schedule;
  102. extern    char    *krb_realmofhost();
  103. #ifdef CRYPT
  104. int    doencrypt = 0;
  105. #define    OPTIONS    "dfk:prtx"
  106. #else
  107. #define    OPTIONS    "dfk:prt"
  108. #endif
  109. #else
  110. #define    OPTIONS "dfprt"
  111. #endif
  112.  
  113. struct passwd *pwd;
  114. u_short    port;
  115. uid_t    userid;
  116. int errs, rem;
  117. int pflag, iamremote, iamrecursive, targetshouldbedirectory;
  118.  
  119. #define    CMDNEEDS    64
  120. char cmd[CMDNEEDS];        /* must hold "rcp -r -p -d\0" */
  121.  
  122. typedef struct _buf {
  123.     int    cnt;
  124.     char    *buf;
  125. } BUF;
  126.  
  127. void lostconn();
  128.  
  129. main(argc, argv)
  130.     int argc;
  131.     char **argv;
  132. {
  133.     extern int optind;
  134.     extern char *optarg;
  135.     struct servent *sp;
  136.     int ch, fflag, tflag;
  137.     char *targ, *shell, *colon();
  138.  
  139.     fflag = tflag = 0;
  140.     while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
  141.         switch(ch) {
  142.         /* user-visible flags */
  143.         case 'p':            /* preserve access/mod times */
  144.             ++pflag;
  145.             break;
  146.         case 'r':
  147.             ++iamrecursive;
  148.             break;
  149. #ifdef    KERBEROS
  150.         case 'k':
  151.             strncpy(dst_realm_buf, optarg, REALM_SZ);
  152.             dest_realm = dst_realm_buf;
  153.             break;
  154. #ifdef CRYPT
  155.         case 'x':
  156.             doencrypt = 1;
  157.             /* des_set_key(cred.session, schedule); */
  158.             break;
  159. #endif
  160. #endif
  161.         /* rshd-invoked options (server) */
  162.         case 'd':
  163.             targetshouldbedirectory = 1;
  164.             break;
  165.         case 'f':            /* "from" */
  166.             iamremote = 1;
  167.             fflag = 1;
  168.             break;
  169.         case 't':            /* "to" */
  170.             iamremote = 1;
  171.             tflag = 1;
  172.             break;
  173.  
  174.         case '?':
  175.         default:
  176.             usage();
  177.         }
  178.     argc -= optind;
  179.     argv += optind;
  180.  
  181. #ifdef KERBEROS
  182. #ifdef CRYPT
  183.     shell = doencrypt ? "ekshell" : "kshell";
  184. #else
  185.     shell = "kshell";
  186. #endif
  187.     sp = getservbyname(shell, "tcp");
  188.     if (sp == NULL) {
  189.         char    msgbuf[64];
  190.         use_kerberos = 0;
  191.         (void)snprintf(msgbuf, sizeof(msgbuf),
  192.             "can't get entry for %s/tcp service", shell);
  193.         old_warning(msgbuf);
  194.         sp = getservbyname(shell = "shell", "tcp");
  195.     }
  196. #else
  197.     sp = getservbyname(shell = "shell", "tcp");
  198. #endif
  199.     if (sp == NULL) {
  200.         (void)fprintf(stderr, "rcp: %s/tcp: unknown service\n", shell);
  201.         exit(1);
  202.     }
  203.     port = sp->s_port;
  204.  
  205.     if (!(pwd = getpwuid(userid = getuid()))) {
  206.         (void)fprintf(stderr, "rcp: unknown user %d.\n", (int)userid);
  207.         exit(1);
  208.     }
  209.  
  210.     if (fflag) {
  211.         /* follow "protocol", send data */
  212.         (void)response();
  213.         (void)setuid(userid);
  214.         source(argc, argv);
  215.         exit(errs);
  216.     }
  217.  
  218.     if (tflag) {
  219.         /* receive data */
  220.         (void)setuid(userid);
  221.         sink(argc, argv);
  222.         exit(errs);
  223.     }
  224.  
  225.     if (argc < 2)
  226.         usage();
  227.     if (argc > 2)
  228.         targetshouldbedirectory = 1;
  229.  
  230.     rem = -1;
  231.     /* command to be executed on remote system using "rsh" */
  232. #ifdef    KERBEROS
  233.     (void)snprintf(cmd, sizeof(cmd),
  234.         "rcp%s%s%s%s", iamrecursive ? " -r" : "",
  235. #ifdef CRYPT
  236.         ((doencrypt && use_kerberos) ? " -x" : ""),
  237. #else
  238.         "",
  239. #endif
  240.         pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
  241. #else
  242.     (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s",
  243.         iamrecursive ? " -r" : "", pflag ? " -p" : "",
  244.         targetshouldbedirectory ? " -d" : "");
  245. #endif
  246.  
  247.     (void)signal(SIGPIPE, lostconn);
  248.  
  249.     if (targ = colon(argv[argc - 1]))
  250.         toremote(targ, argc, argv);    /* destination is remote host */
  251.     else {
  252.         tolocal(argc, argv);        /* destination is local host */
  253.         if (targetshouldbedirectory)
  254.             verifydir(argv[argc - 1]);
  255.     }
  256.     exit(errs);
  257. }
  258.  
  259. toremote(targ, argc, argv)
  260.     char *targ;
  261.     int argc;
  262.     char **argv;
  263. {
  264.     int i, len, tos;
  265.     char *bp, *host, *src, *suser, *thost, *tuser;
  266.     char *colon();
  267.  
  268.     *targ++ = 0;
  269.     if (*targ == 0)
  270.         targ = ".";
  271.  
  272.     if (thost = index(argv[argc - 1], '@@')) {
  273.         /* user@@host */
  274.         *thost++ = 0;
  275.         tuser = argv[argc - 1];
  276.         if (*tuser == '\0')
  277.             tuser = NULL;
  278.         else if (!okname(tuser))
  279.             exit(1);
  280.     } else {
  281.         thost = argv[argc - 1];
  282.         tuser = NULL;
  283.     }
  284.  
  285.     for (i = 0; i < argc - 1; i++) {
  286.         src = colon(argv[i]);
  287.         if (src) {            /* remote to remote */
  288.             *src++ = 0;
  289.             if (*src == 0)
  290.                 src = ".";
  291.             host = index(argv[i], '@@');
  292.             len = strlen(_PATH_RSH) + strlen(argv[i]) +
  293.                 strlen(src) + (tuser ? strlen(tuser) : 0) +
  294.                 strlen(thost) + strlen(targ) + CMDNEEDS + 20;
  295.             if (!(bp = malloc(len)))
  296.                 nospace();
  297.             if (host) {
  298.                 *host++ = 0;
  299.                 suser = argv[i];
  300.                 if (*suser == '\0')
  301.                     suser = pwd->pw_name;
  302.                 else if (!okname(suser))
  303.                     continue;
  304.                 (void)snprintf(bp, len,
  305.                     "%s %s -l %s -n %s %s '%s%s%s:%s'",
  306.                     _PATH_RSH, host, suser, cmd, src,
  307.                     tuser ? tuser : "", tuser ? "@@" : "",
  308.                     thost, targ);
  309.             } else
  310.                 (void)snprintf(bp, len,
  311.                     "%s %s -n %s %s '%s%s%s:%s'",
  312.                     _PATH_RSH, argv[i], cmd, src,
  313.                     tuser ? tuser : "", tuser ? "@@" : "",
  314.                     thost, targ);
  315.             (void)susystem(bp);
  316.             (void)free(bp);
  317.         } else {            /* local to remote */
  318.             if (rem == -1) {
  319.                 len = strlen(targ) + CMDNEEDS + 20;
  320.                 if (!(bp = malloc(len)))
  321.                     nospace();
  322.                 (void)snprintf(bp, len, "%s -t %s", cmd, targ);
  323.                 host = thost;
  324. #ifdef KERBEROS
  325.                 if (use_kerberos)
  326.                     rem = kerberos(&host, bp,
  327.                         pwd->pw_name,
  328.                         tuser ? tuser : pwd->pw_name);
  329.                 else
  330. #endif
  331.                     rem = rcmd(&host, port, pwd->pw_name,
  332.                         tuser ? tuser : pwd->pw_name,
  333.                         bp, 0);
  334.                 if (rem < 0)
  335.                     exit(1);
  336.                 tos = IPTOS_THROUGHPUT;
  337.                 if (setsockopt(rem, IPPROTO_IP, IP_TOS,
  338.                     (char *)&tos, sizeof(int)) < 0)
  339.                     perror("rcp: setsockopt TOS (ignored)");
  340.                 if (response() < 0)
  341.                     exit(1);
  342.                 (void)free(bp);
  343.                 (void)setuid(userid);
  344.             }
  345.             source(1, argv+i);
  346.         }
  347.     }
  348. }
  349.  
  350. tolocal(argc, argv)
  351.     int argc;
  352.     char **argv;
  353. {
  354.     int i, len, tos;
  355.     char *bp, *host, *src, *suser;
  356.     char *colon();
  357.  
  358.     for (i = 0; i < argc - 1; i++) {
  359.         if (!(src = colon(argv[i]))) {    /* local to local */
  360.             len = strlen(_PATH_CP) + strlen(argv[i]) +
  361.                 strlen(argv[argc - 1]) + 20;
  362.             if (!(bp = malloc(len)))
  363.                 nospace();
  364.             (void)snprintf(bp, len, "%s%s%s %s %s", _PATH_CP,
  365.                 iamrecursive ? " -r" : "", pflag ? " -p" : "",
  366.                 argv[i], argv[argc - 1]);
  367.             (void)susystem(bp);
  368.             (void)free(bp);
  369.             continue;
  370.         }
  371.         *src++ = 0;
  372.         if (*src == 0)
  373.             src = ".";
  374.         host = index(argv[i], '@@');
  375.         if (host) {
  376.             *host++ = 0;
  377.             suser = argv[i];
  378.             if (*suser == '\0')
  379.                 suser = pwd->pw_name;
  380.             else if (!okname(suser))
  381.                 continue;
  382.         } else {
  383.             host = argv[i];
  384.             suser = pwd->pw_name;
  385.         }
  386.         len = strlen(src) + CMDNEEDS + 20;
  387.         if (!(bp = malloc(len)))
  388.             nospace();
  389.         (void)snprintf(bp, len, "%s -f %s", cmd, src);
  390. #ifdef KERBEROS
  391.         if (use_kerberos)
  392.             rem = kerberos(&host, bp, pwd->pw_name, suser);
  393.         else
  394. #endif
  395.             rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0);
  396.         (void)free(bp);
  397.         if (rem < 0)
  398.             continue;
  399.         (void)seteuid(userid);
  400.         tos = IPTOS_THROUGHPUT;
  401.         if (setsockopt(rem, IPPROTO_IP, IP_TOS,
  402.             (char *)&tos, sizeof(int)) < 0)
  403.             perror("rcp: setsockopt TOS (ignored)");
  404.         sink(1, argv + argc - 1);
  405.         (void)seteuid(0);
  406.         (void)close(rem);
  407.         rem = -1;
  408.     }
  409. }
  410.  
  411. verifydir(cp)
  412.     char *cp;
  413. {
  414.     struct stat stb;
  415.  
  416.     if (stat(cp, &stb) >= 0) {
  417.         if ((stb.st_mode & S_IFMT) == S_IFDIR)
  418.             return;
  419.         errno = ENOTDIR;
  420.     }
  421.     error("rcp: %s: %s.\n", cp, strerror(errno));
  422.     exit(1);
  423. }
  424.  
  425. char *
  426. colon(cp)
  427.     register char *cp;
  428. {
  429.     for (; *cp; ++cp) {
  430.         if (*cp == ':')
  431.             return(cp);
  432.         if (*cp == '/')
  433.             return(0);
  434.     }
  435.     return(0);
  436. }
  437.  
  438. okname(cp0)
  439.     char *cp0;
  440. {
  441.     register char *cp = cp0;
  442.     register int c;
  443.  
  444.     do {
  445.         c = *cp;
  446.         if (c & 0200)
  447.             goto bad;
  448.         if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
  449.             goto bad;
  450.     } while (*++cp);
  451.     return(1);
  452. bad:
  453.     (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0);
  454.     return(0);
  455. }
  456.  
  457. susystem(s)
  458.     char *s;
  459. {
  460.     int status, pid, w;
  461.     register sig_t istat, qstat;
  462.  
  463.     if ((pid = vfork()) == 0) {
  464.         (void)setuid(userid);
  465.         execl(_PATH_BSHELL, "sh", "-c", s, (char *)0);
  466.         _exit(127);
  467.     }
  468.     istat = signal(SIGINT, SIG_IGN);
  469.     qstat = signal(SIGQUIT, SIG_IGN);
  470.     while ((w = wait(&status)) != pid && w != -1)
  471.         ;
  472.     if (w == -1)
  473.         status = -1;
  474.     (void)signal(SIGINT, istat);
  475.     (void)signal(SIGQUIT, qstat);
  476.     return(status);
  477. }
  478.  
  479. source(argc, argv)
  480.     int argc;
  481.     char **argv;
  482. {
  483.     struct stat stb;
  484.     static BUF buffer;
  485.     BUF *bp;
  486.     off_t i;
  487.     int x, readerr, f, amt;
  488.     char *last, *name, buf[BUFSIZ];
  489.     BUF *allocbuf();
  490.  
  491.     for (x = 0; x < argc; x++) {
  492.         name = argv[x];
  493.         if ((f = open(name, O_RDONLY, 0)) < 0) {
  494.             error("rcp: %s: %s\n", name, strerror(errno));
  495.             continue;
  496.         }
  497.         if (fstat(f, &stb) < 0)
  498.             goto notreg;
  499.         switch (stb.st_mode&S_IFMT) {
  500.  
  501.         case S_IFREG:
  502.             break;
  503.  
  504.         case S_IFDIR:
  505.             if (iamrecursive) {
  506.                 (void)close(f);
  507.                 rsource(name, &stb);
  508.                 continue;
  509.             }
  510.             /* FALLTHROUGH */
  511.         default:
  512. notreg:            (void)close(f);
  513.             error("rcp: %s: not a plain file\n", name);
  514.             continue;
  515.         }
  516.         last = rindex(name, '/');
  517.         if (last == 0)
  518.             last = name;
  519.         else
  520.             last++;
  521.         if (pflag) {
  522.             /*
  523.              * Make it compatible with possible future
  524.              * versions expecting microseconds.
  525.              */
  526.             (void)snprintf(buf, sizeof(buf),
  527.                 "T%ld 0 %ld 0\n", stb.st_mtime, stb.st_atime);
  528.             (void)write(rem, buf, (int)strlen(buf));
  529.             if (response() < 0) {
  530.                 (void)close(f);
  531.                 continue;
  532.             }
  533.         }
  534.         (void)snprintf(buf, sizeof(buf),
  535.             "C%04o %ld %s\n", stb.st_mode&07777, stb.st_size, last);
  536.         (void)write(rem, buf, (int)strlen(buf));
  537.         if (response() < 0) {
  538.             (void)close(f);
  539.             continue;
  540.         }
  541.         if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) {
  542.             (void)close(f);
  543.             continue;
  544.         }
  545.         readerr = 0;
  546.         for (i = 0; i < stb.st_size; i += bp->cnt) {
  547.             amt = bp->cnt;
  548.             if (i + amt > stb.st_size)
  549.                 amt = stb.st_size - i;
  550.             if (readerr == 0 && read(f, bp->buf, amt) != amt)
  551.                 readerr = errno;
  552.             (void)write(rem, bp->buf, amt);
  553.         }
  554.         (void)close(f);
  555.         if (readerr == 0)
  556.             (void)write(rem, "", 1);
  557.         else
  558.             error("rcp: %s: %s\n", name, strerror(readerr));
  559.         (void)response();
  560.     }
  561. }
  562.  
  563. rsource(name, statp)
  564.     char *name;
  565.     struct stat *statp;
  566. {
  567.     DIR *dirp;
  568.     struct dirent *dp;
  569.     char *last, *vect[1], path[MAXPATHLEN];
  570.  
  571.     if (!(dirp = opendir(name))) {
  572.         error("rcp: %s: %s\n", name, strerror(errno));
  573.         return;
  574.     }
  575.     last = rindex(name, '/');
  576.     if (last == 0)
  577.         last = name;
  578.     else
  579.         last++;
  580.     if (pflag) {
  581.         (void)snprintf(path, sizeof(path),
  582.             "T%ld 0 %ld 0\n", statp->st_mtime, statp->st_atime);
  583.         (void)write(rem, path, (int)strlen(path));
  584.         if (response() < 0) {
  585.             closedir(dirp);
  586.             return;
  587.         }
  588.     }
  589.     (void)snprintf(path, sizeof(path),
  590.         "D%04o %d %s\n", statp->st_mode&07777, 0, last);
  591.     (void)write(rem, path, (int)strlen(path));
  592.     if (response() < 0) {
  593.         closedir(dirp);
  594.         return;
  595.     }
  596.     while (dp = readdir(dirp)) {
  597.         if (dp->d_ino == 0)
  598.             continue;
  599.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  600.             continue;
  601.         if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
  602.             error("%s/%s: name too long.\n", name, dp->d_name);
  603.             continue;
  604.         }
  605.         (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
  606.         vect[0] = path;
  607.         source(1, vect);
  608.     }
  609.     closedir(dirp);
  610.     (void)write(rem, "E\n", 2);
  611.     (void)response();
  612. }
  613.  
  614. response()
  615. {
  616.     register char *cp;
  617.     char ch, resp, rbuf[BUFSIZ];
  618.  
  619.     if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
  620.         lostconn();
  621.  
  622.     cp = rbuf;
  623.     switch(resp) {
  624.     case 0:                /* ok */
  625.         return(0);
  626.     default:
  627.         *cp++ = resp;
  628.         /* FALLTHROUGH */
  629.     case 1:                /* error, followed by err msg */
  630.     case 2:                /* fatal error, "" */
  631.         do {
  632.             if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  633.                 lostconn();
  634.             *cp++ = ch;
  635.         } while (cp < &rbuf[BUFSIZ] && ch != '\n');
  636.  
  637.         if (!iamremote)
  638.             (void)write(2, rbuf, cp - rbuf);
  639.         ++errs;
  640.         if (resp == 1)
  641.             return(-1);
  642.         exit(1);
  643.     }
  644.     /*NOTREACHED*/
  645. }
  646.  
  647. void
  648. lostconn()
  649. {
  650.     if (!iamremote)
  651.         (void)fprintf(stderr, "rcp: lost connection\n");
  652.     exit(1);
  653. }
  654.  
  655. sink(argc, argv)
  656.     int argc;
  657.     char **argv;
  658. {
  659.     register char *cp;
  660.     static BUF buffer;
  661.     struct stat stb;
  662.     struct timeval tv[2];
  663.     enum { YES, NO, DISPLAYED } wrerr;
  664.     BUF *bp, *allocbuf();
  665.     off_t i, j;
  666.     char ch, *targ, *why;
  667.     int amt, count, exists, first, mask, mode;
  668.     int ofd, setimes, size, targisdir;
  669.     char *np, *vect[1], buf[BUFSIZ];
  670.  
  671. #define    atime    tv[0]
  672. #define    mtime    tv[1]
  673. #define    SCREWUP(str)    { why = str; goto screwup; }
  674.  
  675.     setimes = targisdir = 0;
  676.     mask = umask(0);
  677.     if (!pflag)
  678.         (void)umask(mask);
  679.     if (argc != 1) {
  680.         error("rcp: ambiguous target\n");
  681.         exit(1);
  682.     }
  683.     targ = *argv;
  684.     if (targetshouldbedirectory)
  685.         verifydir(targ);
  686.     (void)write(rem, "", 1);
  687.     if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
  688.         targisdir = 1;
  689.     for (first = 1;; first = 0) {
  690.         cp = buf;
  691.         if (read(rem, cp, 1) <= 0)
  692.             return;
  693.         if (*cp++ == '\n')
  694.             SCREWUP("unexpected <newline>");
  695.         do {
  696.             if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
  697.                 SCREWUP("lost connection");
  698.             *cp++ = ch;
  699.         } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
  700.         *cp = 0;
  701.  
  702.         if (buf[0] == '\01' || buf[0] == '\02') {
  703.             if (iamremote == 0)
  704.                 (void)write(2, buf + 1, (int)strlen(buf + 1));
  705.             if (buf[0] == '\02')
  706.                 exit(1);
  707.             errs++;
  708.             continue;
  709.         }
  710.         if (buf[0] == 'E') {
  711.             (void)write(rem, "", 1);
  712.             return;
  713.         }
  714.  
  715.         if (ch == '\n')
  716.             *--cp = 0;
  717.  
  718. #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
  719.         cp = buf;
  720.         if (*cp == 'T') {
  721.             setimes++;
  722.             cp++;
  723.             getnum(mtime.tv_sec);
  724.             if (*cp++ != ' ')
  725.                 SCREWUP("mtime.sec not delimited");
  726.             getnum(mtime.tv_usec);
  727.             if (*cp++ != ' ')
  728.                 SCREWUP("mtime.usec not delimited");
  729.             getnum(atime.tv_sec);
  730.             if (*cp++ != ' ')
  731.                 SCREWUP("atime.sec not delimited");
  732.             getnum(atime.tv_usec);
  733.             if (*cp++ != '\0')
  734.                 SCREWUP("atime.usec not delimited");
  735.             (void)write(rem, "", 1);
  736.             continue;
  737.         }
  738.         if (*cp != 'C' && *cp != 'D') {
  739.             /*
  740.              * Check for the case "rcp remote:foo\* local:bar".
  741.              * In this case, the line "No match." can be returned
  742.              * by the shell before the rcp command on the remote is
  743.              * executed so the ^Aerror_message convention isn't
  744.              * followed.
  745.              */
  746.             if (first) {
  747.                 error("%s\n", cp);
  748.                 exit(1);
  749.             }
  750.             SCREWUP("expected control record");
  751.         }
  752.         mode = 0;
  753.         for (++cp; cp < buf + 5; cp++) {
  754.             if (*cp < '0' || *cp > '7')
  755.                 SCREWUP("bad mode");
  756.             mode = (mode << 3) | (*cp - '0');
  757.         }
  758.         if (*cp++ != ' ')
  759.             SCREWUP("mode not delimited");
  760.         size = 0;
  761.         while (isdigit(*cp))
  762.             size = size * 10 + (*cp++ - '0');
  763.         if (*cp++ != ' ')
  764.             SCREWUP("size not delimited");
  765.         if (targisdir) {
  766.             static char *namebuf;
  767.             static int cursize;
  768.             size_t need;
  769.  
  770.             need = strlen(targ) + strlen(cp) + 250;
  771.             if (need > cursize) {
  772.                 if (!(namebuf = malloc(need)))
  773.                     error("out of memory\n");
  774.             }
  775.             (void)snprintf(namebuf, need, "%s%s%s", targ,
  776.                 *targ ? "/" : "", cp);
  777.             np = namebuf;
  778.         }
  779.         else
  780.             np = targ;
  781.         exists = stat(np, &stb) == 0;
  782.         if (buf[0] == 'D') {
  783.             if (exists) {
  784.                 if ((stb.st_mode&S_IFMT) != S_IFDIR) {
  785.                     errno = ENOTDIR;
  786.                     goto bad;
  787.                 }
  788.                 if (pflag)
  789.                     (void)chmod(np, mode);
  790.             } else if (mkdir(np, mode) < 0)
  791.                 goto bad;
  792.             vect[0] = np;
  793.             sink(1, vect);
  794.             if (setimes) {
  795.                 setimes = 0;
  796.                 if (utimes(np, tv) < 0)
  797.                     error("rcp: can't set times on %s: %s\n",
  798.                     np, strerror(errno));
  799.             }
  800.             continue;
  801.         }
  802.         if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
  803. bad:            error("rcp: %s: %s\n", np, strerror(errno));
  804.             continue;
  805.         }
  806.         if (exists && pflag)
  807.             (void)fchmod(ofd, mode);
  808.         (void)write(rem, "", 1);
  809.         if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) {
  810.             (void)close(ofd);
  811.             continue;
  812.         }
  813.         cp = bp->buf;
  814.         count = 0;
  815.         wrerr = NO;
  816.         for (i = 0; i < size; i += BUFSIZ) {
  817.             amt = BUFSIZ;
  818.             if (i + amt > size)
  819.                 amt = size - i;
  820.             count += amt;
  821.             do {
  822.                 j = read(rem, cp, amt);
  823.                 if (j <= 0) {
  824.                     error("rcp: %s\n",
  825.                         j ? strerror(errno) :
  826.                         "dropped connection");
  827.                     exit(1);
  828.                 }
  829.                 amt -= j;
  830.                 cp += j;
  831.             } while (amt > 0);
  832.             if (count == bp->cnt) {
  833.                 if (wrerr == NO &&
  834.                     write(ofd, bp->buf, count) != count)
  835.                     wrerr = YES;
  836.                 count = 0;
  837.                 cp = bp->buf;
  838.             }
  839.         }
  840.         if (count != 0 && wrerr == NO &&
  841.             write(ofd, bp->buf, count) != count)
  842.             wrerr = YES;
  843.         if (ftruncate(ofd, size)) {
  844.             error("rcp: can't truncate %s: %s\n", np,
  845.                 strerror(errno));
  846.             wrerr = DISPLAYED;
  847.         }
  848.         (void)close(ofd);
  849.         (void)response();
  850.         if (setimes && wrerr == NO) {
  851.             setimes = 0;
  852.             if (utimes(np, tv) < 0) {
  853.                 error("rcp: can't set times on %s: %s\n",
  854.                     np, strerror(errno));
  855.                 wrerr = DISPLAYED;
  856.             }
  857.         }
  858.         switch(wrerr) {
  859.         case YES:
  860.             error("rcp: %s: %s\n", np, strerror(errno));
  861.             break;
  862.         case NO:
  863.             (void)write(rem, "", 1);
  864.             break;
  865.         case DISPLAYED:
  866.             break;
  867.         }
  868.     }
  869. screwup:
  870.     error("rcp: protocol screwup: %s\n", why);
  871.     exit(1);
  872. }
  873.  
  874. BUF *
  875. allocbuf(bp, fd, blksize)
  876.     BUF *bp;
  877.     int fd, blksize;
  878. {
  879.     struct stat stb;
  880.     size_t size;
  881.  
  882.     if (fstat(fd, &stb) < 0) {
  883.         error("rcp: fstat: %s\n", strerror(errno));
  884.         return(0);
  885.     }
  886.     size = roundup(stb.st_blksize, blksize);
  887.     if (size == 0)
  888.         size = blksize;
  889.     if (bp->cnt < size) {
  890.         if (bp->buf != 0)
  891.             free(bp->buf);
  892.         bp->buf = malloc(size);
  893.         if (!bp->buf) {
  894.             error("rcp: malloc: out of memory\n");
  895.             return(0);
  896.         }
  897.     }
  898.     bp->cnt = size;
  899.     return(bp);
  900. }
  901.  
  902. /* VARARGS1 */
  903. error(fmt, a1, a2, a3)
  904.     char *fmt;
  905.     int a1, a2, a3;
  906. {
  907.     static FILE *fp;
  908.  
  909.     ++errs;
  910.     if (!fp && !(fp = fdopen(rem, "w")))
  911.         return;
  912.     (void)fprintf(fp, "%c", 0x01);
  913.     (void)fprintf(fp, fmt, a1, a2, a3);
  914.     (void)fflush(fp);
  915.     if (!iamremote)
  916.         (void)fprintf(stderr, fmt, a1, a2, a3);
  917. }
  918.  
  919. nospace()
  920. {
  921.     (void)fprintf(stderr, "rcp: out of memory.\n");
  922.     exit(1);
  923. }
  924.  
  925.  
  926. usage()
  927. {
  928. #ifdef KERBEROS
  929. #ifdef CRYPT
  930.     (void)fprintf(stderr, "%s\n\t%s\n",
  931.         "usage: rcp [-k realm] [-px] f1 f2",
  932.         "or: rcp [-k realm] [-rpx] f1 ... fn directory");
  933. #else
  934.     (void)fprintf(stderr, "%s\n\t%s\n",
  935.         "usage: rcp [-k realm] [-p] f1 f2",
  936.         "or: rcp [-k realm] [-rp] f1 ... fn directory");
  937. #endif
  938. #else
  939.     (void)fprintf(stderr,
  940.         "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n");
  941. #endif
  942.     exit(1);
  943. }
  944.  
  945. #ifdef KERBEROS
  946. old_warning(str)
  947.     char *str;
  948. {
  949.     (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str);
  950. }
  951.  
  952. int
  953. kerberos(host, bp, locuser, user)
  954.  
  955.     char **host, *bp, *locuser, *user;
  956. {
  957.     struct servent *sp;
  958.  
  959. again:
  960.     if (use_kerberos) {
  961.         rem = KSUCCESS;
  962.         errno = 0;
  963.         if (dest_realm == NULL)
  964.             dest_realm = krb_realmofhost(*host);
  965.  
  966. #ifdef CRYPT
  967.         if (doencrypt)
  968.             rem = krcmd_mutual(
  969.                 host, port,
  970.                 user, bp, 0,
  971.                     dest_realm,
  972.                 &cred, schedule);
  973.         else
  974. #endif
  975.             rem = krcmd(
  976.                 host, port,
  977.                 user, bp, 0, dest_realm);
  978.  
  979.         if (rem < 0) {
  980.             use_kerberos = 0;
  981.             sp = getservbyname("shell", "tcp");
  982.             if (sp == NULL) {
  983.                 (void)fprintf(stderr,
  984.                         "rcp: unknown service shell/tcp\n");
  985.                 exit(1);
  986.             }
  987.             if (errno == ECONNREFUSED)
  988.                 old_warning(
  989.                     "remote host doesn't support Kerberos");
  990.  
  991.             if (errno == ENOENT)
  992.                 old_warning(
  993.                     "Can't provide Kerberos auth data");
  994.             port = sp->s_port;
  995.             goto again;
  996.         }
  997.     } else {
  998. #ifdef CRYPT
  999.         if (doencrypt) {
  1000.             fprintf(stderr,
  1001.                 "The -x option requires Kerberos authentication\n");
  1002.             exit(1);
  1003.         }
  1004. #endif
  1005.         rem = rcmd(host, sp->s_port, locuser, user, bp, 0);
  1006.     }
  1007.     return(rem);
  1008. }
  1009. #endif /* KERBEROS */
  1010. @
  1011.