home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / rcp / rcp.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  22KB  |  988 lines

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