[BACK]Return to scp.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/scp.c, Revision 1.1

1.1     ! deraadt     1: /*
        !             2:
        !             3: scp - secure remote copy.  This is basically patched BSD rcp which uses ssh
        !             4: to do the data transfer (instead of using rcmd).
        !             5:
        !             6: NOTE: This version should NOT be suid root.  (This uses ssh to do the transfer
        !             7: and ssh has the necessary privileges.)
        !             8:
        !             9: 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
        !            10:
        !            11: */
        !            12:
        !            13: /*
        !            14:  * Copyright (c) 1983, 1990, 1992, 1993, 1995
        !            15:  *     The Regents of the University of California.  All rights reserved.
        !            16:  *
        !            17:  * Redistribution and use in source and binary forms, with or without
        !            18:  * modification, are permitted provided that the following conditions
        !            19:  * are met:
        !            20:  * 1. Redistributions of source code must retain the above copyright
        !            21:  *    notice, this list of conditions and the following disclaimer.
        !            22:  * 2. Redistributions in binary form must reproduce the above copyright
        !            23:  *    notice, this list of conditions and the following disclaimer in the
        !            24:  *    documentation and/or other materials provided with the distribution.
        !            25:  * 3. All advertising materials mentioning features or use of this software
        !            26:  *    must display the following acknowledgement:
        !            27:  *     This product includes software developed by the University of
        !            28:  *     California, Berkeley and its contributors.
        !            29:  * 4. Neither the name of the University nor the names of its contributors
        !            30:  *    may be used to endorse or promote products derived from this software
        !            31:  *    without specific prior written permission.
        !            32:  *
        !            33:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            34:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            35:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            36:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            37:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            38:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            39:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            40:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            41:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            42:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            43:  * SUCH DAMAGE.
        !            44:  *
        !            45:  *     $Id: scp.c,v 1.6 1999/05/04 11:59:09 bg Exp $
        !            46:  */
        !            47:
        !            48: #include "includes.h"
        !            49: RCSID("$Id: scp.c,v 1.6 1999/05/04 11:59:09 bg Exp $");
        !            50:
        !            51: #include "ssh.h"
        !            52: #include "xmalloc.h"
        !            53: #ifdef HAVE_UTIME_H
        !            54: #include <utime.h>
        !            55: #ifdef _NEXT_SOURCE
        !            56: struct utimbuf {
        !            57:   time_t actime;
        !            58:   time_t modtime;
        !            59: };
        !            60: #endif /* _NEXT_SOURCE */
        !            61: #else
        !            62: struct utimbuf
        !            63: {
        !            64:   long actime;
        !            65:   long modtime;
        !            66: };
        !            67: #endif
        !            68:
        !            69: #define _PATH_CP "cp"
        !            70:
        !            71: #ifndef STDIN_FILENO
        !            72: #define STDIN_FILENO 0
        !            73: #endif
        !            74: #ifndef STDOUT_FILENO
        !            75: #define STDOUT_FILENO 1
        !            76: #endif
        !            77: #ifndef STDERR_FILENO
        !            78: #define STDERR_FILENO 2
        !            79: #endif
        !            80:
        !            81: #if defined(KERBEROS_TGT_PASSING) || defined(AFS)
        !            82: /* This is set to non-zero to disable authentication forwarding. */
        !            83: int nofwd = 0;
        !            84: #endif
        !            85:
        !            86: /* This is set to non-zero to enable verbose mode. */
        !            87: int verbose = 0;
        !            88:
        !            89: /* This is set to non-zero if compression is desired. */
        !            90: int compress = 0;
        !            91:
        !            92: /* This is set to non-zero if running in batch mode (that is, password
        !            93:    and passphrase queries are not allowed). */
        !            94: int batchmode = 0;
        !            95:
        !            96: /* This is set to the cipher type string if given on the command line. */
        !            97: char *cipher = NULL;
        !            98:
        !            99: /* This is set to the RSA authentication identity file name if given on
        !           100:    the command line. */
        !           101: char *identity = NULL;
        !           102:
        !           103: /* This is the port to use in contacting the remote site (is non-NULL). */
        !           104: char *port = NULL;
        !           105:
        !           106: /* This function executes the given command as the specified user on the given
        !           107:    host.  This returns < 0 if execution fails, and >= 0 otherwise.
        !           108:    This assigns the input and output file descriptors on success. */
        !           109:
        !           110: int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
        !           111: {
        !           112:   int pin[2], pout[2], reserved[2];
        !           113:
        !           114:   if (verbose)
        !           115:     fprintf(stderr, "Executing: host %s, user %s, command %s\n",
        !           116:            host, remuser ? remuser : "(unspecified)", cmd);
        !           117:
        !           118:   /* Reserve two descriptors so that the real pipes won't get descriptors
        !           119:      0 and 1 because that will screw up dup2 below. */
        !           120:   pipe(reserved);
        !           121:
        !           122:   /* Create a socket pair for communicating with ssh. */
        !           123:   if (pipe(pin) < 0)
        !           124:     fatal("pipe: %s", strerror(errno));
        !           125:   if (pipe(pout) < 0)
        !           126:     fatal("pipe: %s", strerror(errno));
        !           127:
        !           128:   /* Free the reserved descriptors. */
        !           129:   close(reserved[0]);
        !           130:   close(reserved[1]);
        !           131:
        !           132:   /* For a child to execute the command on the remote host using ssh. */
        !           133:   if (fork() == 0)
        !           134:     {
        !           135:       char *args[100];
        !           136:       unsigned int i;
        !           137:
        !           138:       /* Child. */
        !           139:       close(pin[1]);
        !           140:       close(pout[0]);
        !           141:       dup2(pin[0], 0);
        !           142:       dup2(pout[1], 1);
        !           143:       close(pin[0]);
        !           144:       close(pout[1]);
        !           145:
        !           146:       i = 0;
        !           147:       args[i++] = SSH_PROGRAM;
        !           148:       args[i++] = "-x";
        !           149:       args[i++] = "-oFallBackToRsh no";
        !           150:       if (verbose)
        !           151:        args[i++] = "-v";
        !           152:       if (compress)
        !           153:        args[i++] = "-C";
        !           154:       if (batchmode)
        !           155:        args[i++] = "-oBatchMode yes";
        !           156: #if defined(KERBEROS_TGT_PASSING) || defined(AFS)
        !           157:       if (nofwd)
        !           158:        args[i++] = "-k";
        !           159: #endif
        !           160:       if (cipher != NULL)
        !           161:        {
        !           162:          args[i++] = "-c";
        !           163:          args[i++] = cipher;
        !           164:        }
        !           165:       if (identity != NULL)
        !           166:        {
        !           167:          args[i++] = "-i";
        !           168:          args[i++] = identity;
        !           169:        }
        !           170:       if (port != NULL)
        !           171:        {
        !           172:          args[i++] = "-p";
        !           173:          args[i++] = port;
        !           174:        }
        !           175:       if (remuser != NULL)
        !           176:        {
        !           177:          args[i++] = "-l";
        !           178:          args[i++] = remuser;
        !           179:        }
        !           180:       args[i++] = host;
        !           181:       args[i++] = cmd;
        !           182:       args[i++] = NULL;
        !           183:
        !           184:       execvp(SSH_PROGRAM, args);
        !           185:       perror(SSH_PROGRAM);
        !           186:       exit(1);
        !           187:     }
        !           188:   /* Parent.  Close the other side, and return the local side. */
        !           189:   close(pin[0]);
        !           190:   *fdout = pin[1];
        !           191:   close(pout[1]);
        !           192:   *fdin = pout[0];
        !           193:   return 0;
        !           194: }
        !           195:
        !           196: void fatal(const char *fmt, ...)
        !           197: {
        !           198:   va_list ap;
        !           199:   char buf[1024];
        !           200:
        !           201:   va_start(ap, fmt);
        !           202:   vsnprintf(buf, sizeof(buf), fmt, ap);
        !           203:   va_end(ap);
        !           204:   fprintf(stderr, "%s\n", buf);
        !           205:   exit(255);
        !           206: }
        !           207:
        !           208: /* This stuff used to be in BSD rcp extern.h. */
        !           209:
        !           210: typedef struct {
        !           211:        int cnt;
        !           212:        char *buf;
        !           213: } BUF;
        !           214:
        !           215: extern int iamremote;
        !           216:
        !           217: BUF    *allocbuf(BUF *, int, int);
        !           218: char   *colon(char *);
        !           219: void    lostconn(int);
        !           220: void    nospace(void);
        !           221: int     okname(char *);
        !           222: void    run_err(const char *, ...);
        !           223: void    verifydir(char *);
        !           224:
        !           225: /* Stuff from BSD rcp.c continues. */
        !           226:
        !           227: struct passwd *pwd;
        !           228: uid_t  userid;
        !           229: int errs, remin, remout;
        !           230: int pflag, iamremote, iamrecursive, targetshouldbedirectory;
        !           231:
        !           232: #define        CMDNEEDS        64
        !           233: char cmd[CMDNEEDS];            /* must hold "rcp -r -p -d\0" */
        !           234:
        !           235: int     response(void);
        !           236: void    rsource(char *, struct stat *);
        !           237: void    sink(int, char *[]);
        !           238: void    source(int, char *[]);
        !           239: void    tolocal(int, char *[]);
        !           240: void    toremote(char *, int, char *[]);
        !           241: void    usage(void);
        !           242:
        !           243: int
        !           244: main(argc, argv)
        !           245:        int argc;
        !           246:        char *argv[];
        !           247: {
        !           248:        int ch, fflag, tflag;
        !           249:        char *targ;
        !           250:        extern char *optarg;
        !           251:        extern int optind;
        !           252:
        !           253:        fflag = tflag = 0;
        !           254: #if defined(KERBEROS_TGT_PASSING) || defined(AFS)
        !           255:        while ((ch = getopt(argc, argv, "kdfprtvBCc:i:P:")) != EOF)
        !           256: #else
        !           257:        while ((ch = getopt(argc, argv,  "dfprtvBCc:i:P:")) != EOF)
        !           258: #endif
        !           259:                switch(ch) {                    /* User-visible flags. */
        !           260:                case 'p':
        !           261:                        pflag = 1;
        !           262:                        break;
        !           263:                case 'P':
        !           264:                        port = optarg;
        !           265:                        break;
        !           266:                case 'r':
        !           267:                        iamrecursive = 1;
        !           268:                        break;
        !           269:                                                /* Server options. */
        !           270: #if defined(KERBEROS_TGT_PASSING) || defined(AFS)
        !           271:                case 'k':
        !           272:                        nofwd = 1;
        !           273:                        break;
        !           274: #endif
        !           275:                case 'd':
        !           276:                        targetshouldbedirectory = 1;
        !           277:                        break;
        !           278:                case 'f':                       /* "from" */
        !           279:                        iamremote = 1;
        !           280:                        fflag = 1;
        !           281:                        break;
        !           282:                case 't':                       /* "to" */
        !           283:                        iamremote = 1;
        !           284:                        tflag = 1;
        !           285:                        break;
        !           286:                case 'c':
        !           287:                        cipher = optarg;
        !           288:                        break;
        !           289:                case 'i':
        !           290:                        identity = optarg;
        !           291:                        break;
        !           292:                case 'v':
        !           293:                        verbose = 1;
        !           294:                        break;
        !           295:                case 'B':
        !           296:                        batchmode = 1;
        !           297:                        break;
        !           298:                case 'C':
        !           299:                        compress = 1;
        !           300:                        break;
        !           301:                case '?':
        !           302:                default:
        !           303:                        usage();
        !           304:                }
        !           305:        argc -= optind;
        !           306:        argv += optind;
        !           307:
        !           308:        if ((pwd = getpwuid(userid = getuid())) == NULL)
        !           309:                fatal("unknown user %d", (int)userid);
        !           310:
        !           311:        remin = STDIN_FILENO;
        !           312:        remout = STDOUT_FILENO;
        !           313:
        !           314:        if (fflag) {                    /* Follow "protocol", send data. */
        !           315:                (void)response();
        !           316:                source(argc, argv);
        !           317:                exit(errs != 0);
        !           318:        }
        !           319:
        !           320:        if (tflag) {                    /* Receive data. */
        !           321:                sink(argc, argv);
        !           322:                exit(errs != 0);
        !           323:        }
        !           324:
        !           325:        if (argc < 2)
        !           326:                usage();
        !           327:        if (argc > 2)
        !           328:                targetshouldbedirectory = 1;
        !           329:
        !           330:        remin = remout = -1;
        !           331:        /* Command to be executed on remote system using "ssh". */
        !           332:        (void)sprintf(cmd, "scp%s%s%s%s", verbose ? " -v" : "",
        !           333:            iamrecursive ? " -r" : "", pflag ? " -p" : "",
        !           334:            targetshouldbedirectory ? " -d" : "");
        !           335:
        !           336:        (void)signal(SIGPIPE, lostconn);
        !           337:
        !           338:        if ((targ = colon(argv[argc - 1])))     /* Dest is remote host. */
        !           339:                toremote(targ, argc, argv);
        !           340:        else {
        !           341:                tolocal(argc, argv);            /* Dest is local host. */
        !           342:                if (targetshouldbedirectory)
        !           343:                        verifydir(argv[argc - 1]);
        !           344:        }
        !           345:        exit(errs != 0);
        !           346: }
        !           347:
        !           348: void
        !           349: toremote(targ, argc, argv)
        !           350:        char *targ, *argv[];
        !           351:        int argc;
        !           352: {
        !           353:        int i, len;
        !           354:        char *bp, *host, *src, *suser, *thost, *tuser;
        !           355:
        !           356:        *targ++ = 0;
        !           357:        if (*targ == 0)
        !           358:                targ = ".";
        !           359:
        !           360:        if ((thost = strchr(argv[argc - 1], '@'))) {
        !           361:                /* user@host */
        !           362:                *thost++ = 0;
        !           363:                tuser = argv[argc - 1];
        !           364:                if (*tuser == '\0')
        !           365:                        tuser = NULL;
        !           366:                else if (!okname(tuser))
        !           367:                        exit(1);
        !           368:        } else {
        !           369:                thost = argv[argc - 1];
        !           370:                tuser = NULL;
        !           371:        }
        !           372:
        !           373:        for (i = 0; i < argc - 1; i++) {
        !           374:                src = colon(argv[i]);
        !           375:                if (src) {                      /* remote to remote */
        !           376:                        *src++ = 0;
        !           377:                        if (*src == 0)
        !           378:                                src = ".";
        !           379:                        host = strchr(argv[i], '@');
        !           380:                        len = strlen(SSH_PROGRAM) + strlen(argv[i]) +
        !           381:                            strlen(src) + (tuser ? strlen(tuser) : 0) +
        !           382:                            strlen(thost) + strlen(targ) + CMDNEEDS + 32;
        !           383:                        bp = xmalloc(len);
        !           384:                        if (host) {
        !           385:                                *host++ = 0;
        !           386:                                suser = argv[i];
        !           387:                                if (*suser == '\0')
        !           388:                                        suser = pwd->pw_name;
        !           389:                                else if (!okname(suser))
        !           390:                                        continue;
        !           391:                                (void)sprintf(bp,
        !           392:                                    "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'",
        !           393:                                    SSH_PROGRAM, verbose ? " -v" : "",
        !           394:                                    suser, host, cmd, src,
        !           395:                                    tuser ? tuser : "", tuser ? "@" : "",
        !           396:                                    thost, targ);
        !           397:                        } else
        !           398:                                (void)sprintf(bp,
        !           399:                                    "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'",
        !           400:                                    SSH_PROGRAM, verbose ? " -v" : "",
        !           401:                                    argv[i], cmd, src,
        !           402:                                    tuser ? tuser : "", tuser ? "@" : "",
        !           403:                                    thost, targ);
        !           404:                        if (verbose)
        !           405:                          fprintf(stderr, "Executing: %s\n", bp);
        !           406:                        (void)system(bp);
        !           407:                        (void)xfree(bp);
        !           408:                } else {                        /* local to remote */
        !           409:                        if (remin == -1) {
        !           410:                                len = strlen(targ) + CMDNEEDS + 20;
        !           411:                                bp = xmalloc(len);
        !           412:                                (void)sprintf(bp, "%s -t %s", cmd, targ);
        !           413:                                host = thost;
        !           414:                                if (do_cmd(host,  tuser,
        !           415:                                           bp, &remin, &remout) < 0)
        !           416:                                  exit(1);
        !           417:                                if (response() < 0)
        !           418:                                        exit(1);
        !           419:                                (void)xfree(bp);
        !           420:                        }
        !           421:                        source(1, argv+i);
        !           422:                }
        !           423:        }
        !           424: }
        !           425:
        !           426: void
        !           427: tolocal(argc, argv)
        !           428:        int argc;
        !           429:        char *argv[];
        !           430: {
        !           431:        int i, len;
        !           432:        char *bp, *host, *src, *suser;
        !           433:
        !           434:        for (i = 0; i < argc - 1; i++) {
        !           435:                if (!(src = colon(argv[i]))) {          /* Local to local. */
        !           436:                        len = strlen(_PATH_CP) + strlen(argv[i]) +
        !           437:                            strlen(argv[argc - 1]) + 20;
        !           438:                        bp = xmalloc(len);
        !           439:                        (void)sprintf(bp, "exec %s%s%s %s %s", _PATH_CP,
        !           440:                            iamrecursive ? " -r" : "", pflag ? " -p" : "",
        !           441:                            argv[i], argv[argc - 1]);
        !           442:                        if (verbose)
        !           443:                          fprintf(stderr, "Executing: %s\n", bp);
        !           444:                        if (system(bp))
        !           445:                                ++errs;
        !           446:                        (void)xfree(bp);
        !           447:                        continue;
        !           448:                }
        !           449:                *src++ = 0;
        !           450:                if (*src == 0)
        !           451:                        src = ".";
        !           452:                if ((host = strchr(argv[i], '@')) == NULL) {
        !           453:                        host = argv[i];
        !           454:                        suser = NULL;
        !           455:                } else {
        !           456:                        *host++ = 0;
        !           457:                        suser = argv[i];
        !           458:                        if (*suser == '\0')
        !           459:                                suser = pwd->pw_name;
        !           460:                        else if (!okname(suser))
        !           461:                                continue;
        !           462:                }
        !           463:                len = strlen(src) + CMDNEEDS + 20;
        !           464:                bp = xmalloc(len);
        !           465:                (void)sprintf(bp, "%s -f %s", cmd, src);
        !           466:                if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
        !           467:                  (void)xfree(bp);
        !           468:                  ++errs;
        !           469:                  continue;
        !           470:                }
        !           471:                xfree(bp);
        !           472:                sink(1, argv + argc - 1);
        !           473:                (void)close(remin);
        !           474:                remin = remout = -1;
        !           475:        }
        !           476: }
        !           477:
        !           478: void
        !           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 amt, fd, haderr, indx, result;
        !           488:        char *last, *name, buf[2048];
        !           489:
        !           490:        for (indx = 0; indx < argc; ++indx) {
        !           491:                 name = argv[indx];
        !           492:                if ((fd = open(name, O_RDONLY, 0)) < 0)
        !           493:                        goto syserr;
        !           494:                if (fstat(fd, &stb) < 0) {
        !           495: syserr:                        run_err("%s: %s", name, strerror(errno));
        !           496:                        goto next;
        !           497:                }
        !           498:                switch (stb.st_mode & S_IFMT) {
        !           499:                case S_IFREG:
        !           500:                        break;
        !           501:                case S_IFDIR:
        !           502:                        if (iamrecursive) {
        !           503:                                rsource(name, &stb);
        !           504:                                goto next;
        !           505:                        }
        !           506:                        /* FALLTHROUGH */
        !           507:                default:
        !           508:                        run_err("%s: not a regular file", name);
        !           509:                        goto next;
        !           510:                }
        !           511:                if ((last = strrchr(name, '/')) == NULL)
        !           512:                        last = name;
        !           513:                else
        !           514:                        ++last;
        !           515:                if (pflag) {
        !           516:                        /*
        !           517:                         * Make it compatible with possible future
        !           518:                         * versions expecting microseconds.
        !           519:                         */
        !           520:                        (void)sprintf(buf, "T%lu 0 %lu 0\n",
        !           521:                                      (unsigned long)stb.st_mtime,
        !           522:                                      (unsigned long)stb.st_atime);
        !           523:                        (void)write(remout, buf, strlen(buf));
        !           524:                        if (response() < 0)
        !           525:                                goto next;
        !           526:                }
        !           527: #define        FILEMODEMASK    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
        !           528:                (void)sprintf(buf, "C%04o %lu %s\n",
        !           529:                              (unsigned int)(stb.st_mode & FILEMODEMASK),
        !           530:                              (unsigned long)stb.st_size,
        !           531:                              last);
        !           532:                if (verbose)
        !           533:                  {
        !           534:                    fprintf(stderr, "Sending file modes: %s", buf);
        !           535:                    fflush(stderr);
        !           536:                  }
        !           537:                (void)write(remout, buf, strlen(buf));
        !           538:                if (response() < 0)
        !           539:                        goto next;
        !           540:                if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
        !           541: next:                  (void)close(fd);
        !           542:                        continue;
        !           543:                }
        !           544:
        !           545:                /* Keep writing after an error so that we stay sync'd up. */
        !           546:                for (haderr = 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 (!haderr) {
        !           551:                                result = read(fd, bp->buf, amt);
        !           552:                                if (result != amt)
        !           553:                                        haderr = result >= 0 ? EIO : errno;
        !           554:                        }
        !           555:                        if (haderr)
        !           556:                                (void)write(remout, bp->buf, amt);
        !           557:                        else {
        !           558:                                result = write(remout, bp->buf, amt);
        !           559:                                if (result != amt)
        !           560:                                        haderr = result >= 0 ? EIO : errno;
        !           561:                        }
        !           562:                }
        !           563:                if (close(fd) < 0 && !haderr)
        !           564:                        haderr = errno;
        !           565:                if (!haderr)
        !           566:                        (void)write(remout, "", 1);
        !           567:                else
        !           568:                        run_err("%s: %s", name, strerror(haderr));
        !           569:                (void)response();
        !           570:        }
        !           571: }
        !           572:
        !           573: void
        !           574: rsource(name, statp)
        !           575:        char *name;
        !           576:        struct stat *statp;
        !           577: {
        !           578:        DIR *dirp;
        !           579:        struct dirent *dp;
        !           580:        char *last, *vect[1], path[1100];
        !           581:
        !           582:        if (!(dirp = opendir(name))) {
        !           583:                run_err("%s: %s", name, strerror(errno));
        !           584:                return;
        !           585:        }
        !           586:        last = strrchr(name, '/');
        !           587:        if (last == 0)
        !           588:                last = name;
        !           589:        else
        !           590:                last++;
        !           591:        if (pflag) {
        !           592:                (void)sprintf(path, "T%lu 0 %lu 0\n",
        !           593:                              (unsigned long)statp->st_mtime,
        !           594:                              (unsigned long)statp->st_atime);
        !           595:                (void)write(remout, path, strlen(path));
        !           596:                if (response() < 0) {
        !           597:                        closedir(dirp);
        !           598:                        return;
        !           599:                }
        !           600:        }
        !           601:        (void)sprintf(path,
        !           602:            "D%04o %d %.1024s\n", (unsigned int)(statp->st_mode & FILEMODEMASK),
        !           603:                      0, last);
        !           604:        if (verbose)
        !           605:          fprintf(stderr, "Entering directory: %s", path);
        !           606:        (void)write(remout, path, strlen(path));
        !           607:        if (response() < 0) {
        !           608:                closedir(dirp);
        !           609:                return;
        !           610:        }
        !           611:        while ((dp = readdir(dirp))) {
        !           612:                if (dp->d_ino == 0)
        !           613:                        continue;
        !           614:                if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
        !           615:                        continue;
        !           616:                if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
        !           617:                        run_err("%s/%s: name too long", name, dp->d_name);
        !           618:                        continue;
        !           619:                }
        !           620:                (void)sprintf(path, "%s/%s", name, dp->d_name);
        !           621:                vect[0] = path;
        !           622:                source(1, vect);
        !           623:        }
        !           624:        (void)closedir(dirp);
        !           625:        (void)write(remout, "E\n", 2);
        !           626:        (void)response();
        !           627: }
        !           628:
        !           629: void
        !           630: sink(argc, argv)
        !           631:        int argc;
        !           632:        char *argv[];
        !           633: {
        !           634:        static BUF buffer;
        !           635:        struct stat stb;
        !           636:        enum { YES, NO, DISPLAYED } wrerr;
        !           637:        BUF *bp;
        !           638:        off_t i, j;
        !           639:        int amt, count, exists, first, mask, mode, ofd, omode;
        !           640:        int setimes, size, targisdir, wrerrno = 0;
        !           641:        char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
        !           642:        struct utimbuf ut;
        !           643:        int dummy_usec;
        !           644:
        !           645: #define        SCREWUP(str)    { why = str; goto screwup; }
        !           646:
        !           647:        setimes = targisdir = 0;
        !           648:        mask = umask(0);
        !           649:        if (!pflag)
        !           650:                (void)umask(mask);
        !           651:        if (argc != 1) {
        !           652:                run_err("ambiguous target");
        !           653:                exit(1);
        !           654:        }
        !           655:        targ = *argv;
        !           656:        if (targetshouldbedirectory)
        !           657:                verifydir(targ);
        !           658:
        !           659:        (void)write(remout, "", 1);
        !           660:        if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
        !           661:                targisdir = 1;
        !           662:        for (first = 1;; first = 0) {
        !           663:                cp = buf;
        !           664:                if (read(remin, cp, 1) <= 0)
        !           665:                        return;
        !           666:                if (*cp++ == '\n')
        !           667:                        SCREWUP("unexpected <newline>");
        !           668:                do {
        !           669:                        if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
        !           670:                                SCREWUP("lost connection");
        !           671:                        *cp++ = ch;
        !           672:                } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
        !           673:                *cp = 0;
        !           674:
        !           675:                if (buf[0] == '\01' || buf[0] == '\02') {
        !           676:                        if (iamremote == 0)
        !           677:                                (void)write(STDERR_FILENO,
        !           678:                                    buf + 1, strlen(buf + 1));
        !           679:                        if (buf[0] == '\02')
        !           680:                                exit(1);
        !           681:                        ++errs;
        !           682:                        continue;
        !           683:                }
        !           684:                if (buf[0] == 'E') {
        !           685:                        (void)write(remout, "", 1);
        !           686:                        return;
        !           687:                }
        !           688:
        !           689:                if (ch == '\n')
        !           690:                        *--cp = 0;
        !           691:
        !           692: #define getnum(t) (t) = 0; \
        !           693:   while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0');
        !           694:                cp = buf;
        !           695:                if (*cp == 'T') {
        !           696:                        setimes++;
        !           697:                        cp++;
        !           698:                        getnum(ut.modtime);
        !           699:                        if (*cp++ != ' ')
        !           700:                                SCREWUP("mtime.sec not delimited");
        !           701:                        getnum(dummy_usec);
        !           702:                        if (*cp++ != ' ')
        !           703:                                SCREWUP("mtime.usec not delimited");
        !           704:                        getnum(ut.actime);
        !           705:                        if (*cp++ != ' ')
        !           706:                                SCREWUP("atime.sec not delimited");
        !           707:                        getnum(dummy_usec);
        !           708:                        if (*cp++ != '\0')
        !           709:                                SCREWUP("atime.usec not delimited");
        !           710:                        (void)write(remout, "", 1);
        !           711:                        continue;
        !           712:                }
        !           713:                if (*cp != 'C' && *cp != 'D') {
        !           714:                        /*
        !           715:                         * Check for the case "rcp remote:foo\* local:bar".
        !           716:                         * In this case, the line "No match." can be returned
        !           717:                         * by the shell before the rcp command on the remote is
        !           718:                         * executed so the ^Aerror_message convention isn't
        !           719:                         * followed.
        !           720:                         */
        !           721:                        if (first) {
        !           722:                                run_err("%s", cp);
        !           723:                                exit(1);
        !           724:                        }
        !           725:                        SCREWUP("expected control record");
        !           726:                }
        !           727:                mode = 0;
        !           728:                for (++cp; cp < buf + 5; cp++) {
        !           729:                        if (*cp < '0' || *cp > '7')
        !           730:                                SCREWUP("bad mode");
        !           731:                        mode = (mode << 3) | (*cp - '0');
        !           732:                }
        !           733:                if (*cp++ != ' ')
        !           734:                        SCREWUP("mode not delimited");
        !           735:
        !           736:                for (size = 0; *cp >= '0' && *cp <= '9';)
        !           737:                        size = size * 10 + (*cp++ - '0');
        !           738:                if (*cp++ != ' ')
        !           739:                        SCREWUP("size not delimited");
        !           740:                if (targisdir) {
        !           741:                        static char *namebuf;
        !           742:                        static int cursize;
        !           743:                        size_t need;
        !           744:
        !           745:                        need = strlen(targ) + strlen(cp) + 250;
        !           746:                        if (need > cursize)
        !           747:                          namebuf = xmalloc(need);
        !           748:                        (void)sprintf(namebuf, "%s%s%s", targ,
        !           749:                            *targ ? "/" : "", cp);
        !           750:                        np = namebuf;
        !           751:                } else
        !           752:                        np = targ;
        !           753:                exists = stat(np, &stb) == 0;
        !           754:                if (buf[0] == 'D') {
        !           755:                        int mod_flag = pflag;
        !           756:                        if (exists) {
        !           757:                                if (!S_ISDIR(stb.st_mode)) {
        !           758:                                        errno = ENOTDIR;
        !           759:                                        goto bad;
        !           760:                                }
        !           761:                                if (pflag)
        !           762:                                        (void)chmod(np, mode);
        !           763:                        } else {
        !           764:                                /* Handle copying from a read-only directory */
        !           765:                                mod_flag = 1;
        !           766:                                if (mkdir(np, mode | S_IRWXU) < 0)
        !           767:                                        goto bad;
        !           768:                        }
        !           769:                        vect[0] = np;
        !           770:                        sink(1, vect);
        !           771:                        if (setimes) {
        !           772:                                setimes = 0;
        !           773:                                if (utime(np, &ut) < 0)
        !           774:                                    run_err("%s: set times: %s",
        !           775:                                        np, strerror(errno));
        !           776:                        }
        !           777:                        if (mod_flag)
        !           778:                                (void)chmod(np, mode);
        !           779:                        continue;
        !           780:                }
        !           781:                omode = mode;
        !           782:                mode |= S_IWRITE;
        !           783:                if ((ofd = open(np, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) {
        !           784: bad:                   run_err("%s: %s", np, strerror(errno));
        !           785:                        continue;
        !           786:                }
        !           787:                (void)write(remout, "", 1);
        !           788:                if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
        !           789:                        (void)close(ofd);
        !           790:                        continue;
        !           791:                }
        !           792:                cp = bp->buf;
        !           793:                wrerr = NO;
        !           794:                for (count = i = 0; i < size; i += 4096) {
        !           795:                        amt = 4096;
        !           796:                        if (i + amt > size)
        !           797:                                amt = size - i;
        !           798:                        count += amt;
        !           799:                        do {
        !           800:                                j = read(remin, cp, amt);
        !           801:                                if (j <= 0) {
        !           802:                                        run_err("%s", j ? strerror(errno) :
        !           803:                                            "dropped connection");
        !           804:                                        exit(1);
        !           805:                                }
        !           806:                                amt -= j;
        !           807:                                cp += j;
        !           808:                        } while (amt > 0);
        !           809:                        if (count == bp->cnt) {
        !           810:                                /* Keep reading so we stay sync'd up. */
        !           811:                                if (wrerr == NO) {
        !           812:                                        j = write(ofd, bp->buf, count);
        !           813:                                        if (j != count) {
        !           814:                                                wrerr = YES;
        !           815:                                                wrerrno = j >= 0 ? EIO : errno;
        !           816:                                        }
        !           817:                                }
        !           818:                                count = 0;
        !           819:                                cp = bp->buf;
        !           820:                        }
        !           821:                }
        !           822:                if (count != 0 && wrerr == NO &&
        !           823:                    (j = write(ofd, bp->buf, count)) != count) {
        !           824:                        wrerr = YES;
        !           825:                        wrerrno = j >= 0 ? EIO : errno;
        !           826:                }
        !           827: #if 0
        !           828:                if (ftruncate(ofd, size)) {
        !           829:                        run_err("%s: truncate: %s", np, strerror(errno));
        !           830:                        wrerr = DISPLAYED;
        !           831:                }
        !           832: #endif
        !           833:                if (pflag) {
        !           834:                        if (exists || omode != mode)
        !           835: #ifdef HAVE_FCHMOD
        !           836:                                if (fchmod(ofd, omode))
        !           837: #else /* HAVE_FCHMOD */
        !           838:                                if (chmod(np, omode))
        !           839: #endif /* HAVE_FCHMOD */
        !           840:                                        run_err("%s: set mode: %s",
        !           841:                                            np, strerror(errno));
        !           842:                } else {
        !           843:                        if (!exists && omode != mode)
        !           844: #ifdef HAVE_FCHMOD
        !           845:                                if (fchmod(ofd, omode & ~mask))
        !           846: #else /* HAVE_FCHMOD */
        !           847:                                if (chmod(np, omode & ~mask))
        !           848: #endif /* HAVE_FCHMOD */
        !           849:                                        run_err("%s: set mode: %s",
        !           850:                                            np, strerror(errno));
        !           851:                }
        !           852:                (void)close(ofd);
        !           853:                (void)response();
        !           854:                if (setimes && wrerr == NO) {
        !           855:                        setimes = 0;
        !           856:                        if (utime(np, &ut) < 0) {
        !           857:                                run_err("%s: set times: %s",
        !           858:                                    np, strerror(errno));
        !           859:                                wrerr = DISPLAYED;
        !           860:                        }
        !           861:                }
        !           862:                switch(wrerr) {
        !           863:                case YES:
        !           864:                        run_err("%s: %s", np, strerror(wrerrno));
        !           865:                        break;
        !           866:                case NO:
        !           867:                        (void)write(remout, "", 1);
        !           868:                        break;
        !           869:                case DISPLAYED:
        !           870:                        break;
        !           871:                }
        !           872:        }
        !           873: screwup:
        !           874:        run_err("protocol error: %s", why);
        !           875:        exit(1);
        !           876: }
        !           877:
        !           878: int
        !           879: response()
        !           880: {
        !           881:        char ch, *cp, resp, rbuf[2048];
        !           882:
        !           883:        if (read(remin, &resp, sizeof(resp)) != sizeof(resp))
        !           884:                lostconn(0);
        !           885:
        !           886:        cp = rbuf;
        !           887:        switch(resp) {
        !           888:        case 0:                         /* ok */
        !           889:                return (0);
        !           890:        default:
        !           891:                *cp++ = resp;
        !           892:                /* FALLTHROUGH */
        !           893:        case 1:                         /* error, followed by error msg */
        !           894:        case 2:                         /* fatal error, "" */
        !           895:                do {
        !           896:                        if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
        !           897:                                lostconn(0);
        !           898:                        *cp++ = ch;
        !           899:                } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
        !           900:
        !           901:                if (!iamremote)
        !           902:                        (void)write(STDERR_FILENO, rbuf, cp - rbuf);
        !           903:                ++errs;
        !           904:                if (resp == 1)
        !           905:                        return (-1);
        !           906:                exit(1);
        !           907:        }
        !           908:        /* NOTREACHED */
        !           909: }
        !           910:
        !           911: void
        !           912: usage()
        !           913: {
        !           914:        (void)fprintf(stderr,
        !           915:            "usage: scp [-p] f1 f2; or: scp [-pr] f1 ... fn directory\n");
        !           916:        exit(1);
        !           917: }
        !           918:
        !           919: void
        !           920: run_err(const char *fmt, ...)
        !           921: {
        !           922:        static FILE *fp;
        !           923:        va_list ap;
        !           924:        va_start(ap, fmt);
        !           925:
        !           926:        ++errs;
        !           927:        if (fp == NULL && !(fp = fdopen(remout, "w")))
        !           928:                return;
        !           929:        (void)fprintf(fp, "%c", 0x01);
        !           930:        (void)fprintf(fp, "scp: ");
        !           931:        (void)vfprintf(fp, fmt, ap);
        !           932:        (void)fprintf(fp, "\n");
        !           933:        (void)fflush(fp);
        !           934:
        !           935:        if (!iamremote)
        !           936:          {
        !           937:            vfprintf(stderr, fmt, ap);
        !           938:            fprintf(stderr, "\n");
        !           939:          }
        !           940:
        !           941:        va_end(ap);
        !           942: }
        !           943:
        !           944: /* Stuff below is from BSD rcp util.c. */
        !           945:
        !           946: /*-
        !           947:  * Copyright (c) 1992, 1993
        !           948:  *     The Regents of the University of California.  All rights reserved.
        !           949:  *
        !           950:  * Redistribution and use in source and binary forms, with or without
        !           951:  * modification, are permitted provided that the following conditions
        !           952:  * are met:
        !           953:  * 1. Redistributions of source code must retain the above copyright
        !           954:  *    notice, this list of conditions and the following disclaimer.
        !           955:  * 2. Redistributions in binary form must reproduce the above copyright
        !           956:  *    notice, this list of conditions and the following disclaimer in the
        !           957:  *    documentation and/or other materials provided with the distribution.
        !           958:  * 3. All advertising materials mentioning features or use of this software
        !           959:  *    must display the following acknowledgement:
        !           960:  *     This product includes software developed by the University of
        !           961:  *     California, Berkeley and its contributors.
        !           962:  * 4. Neither the name of the University nor the names of its contributors
        !           963:  *    may be used to endorse or promote products derived from this software
        !           964:  *    without specific prior written permission.
        !           965:  *
        !           966:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !           967:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !           968:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !           969:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !           970:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !           971:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !           972:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !           973:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !           974:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !           975:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !           976:  * SUCH DAMAGE.
        !           977:  *
        !           978:  *     $Id: scp.c,v 1.6 1999/05/04 11:59:09 bg Exp $
        !           979:  */
        !           980:
        !           981: char *
        !           982: colon(cp)
        !           983:        char *cp;
        !           984: {
        !           985:        if (*cp == ':')         /* Leading colon is part of file name. */
        !           986:                return (0);
        !           987:
        !           988:        for (; *cp; ++cp) {
        !           989:                if (*cp == ':')
        !           990:                        return (cp);
        !           991:                if (*cp == '/')
        !           992:                        return (0);
        !           993:        }
        !           994:        return (0);
        !           995: }
        !           996:
        !           997: void
        !           998: verifydir(cp)
        !           999:        char *cp;
        !          1000: {
        !          1001:        struct stat stb;
        !          1002:
        !          1003:        if (!stat(cp, &stb)) {
        !          1004:                if (S_ISDIR(stb.st_mode))
        !          1005:                        return;
        !          1006:                errno = ENOTDIR;
        !          1007:        }
        !          1008:        run_err("%s: %s", cp, strerror(errno));
        !          1009:        exit(1);
        !          1010: }
        !          1011:
        !          1012: int
        !          1013: okname(cp0)
        !          1014:        char *cp0;
        !          1015: {
        !          1016:        int c;
        !          1017:        char *cp;
        !          1018:
        !          1019:        cp = cp0;
        !          1020:        do {
        !          1021:                c = *cp;
        !          1022:                if (c & 0200)
        !          1023:                        goto bad;
        !          1024:                if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
        !          1025:                        goto bad;
        !          1026:        } while (*++cp);
        !          1027:        return (1);
        !          1028:
        !          1029: bad:   fprintf(stderr, "%s: invalid user name", cp0);
        !          1030:        return (0);
        !          1031: }
        !          1032:
        !          1033: BUF *
        !          1034: allocbuf(bp, fd, blksize)
        !          1035:        BUF *bp;
        !          1036:        int fd, blksize;
        !          1037: {
        !          1038:        size_t size;
        !          1039: #ifdef HAVE_ST_BLKSIZE
        !          1040:        struct stat stb;
        !          1041:
        !          1042:        if (fstat(fd, &stb) < 0) {
        !          1043:                run_err("fstat: %s", strerror(errno));
        !          1044:                return (0);
        !          1045:        }
        !          1046:         if (stb.st_blksize == 0)
        !          1047:          size = blksize;
        !          1048:         else
        !          1049:          size = blksize + (stb.st_blksize - blksize % stb.st_blksize) %
        !          1050:          stb.st_blksize;
        !          1051: #else /* HAVE_ST_BLKSIZE */
        !          1052:        size = blksize;
        !          1053: #endif /* HAVE_ST_BLKSIZE */
        !          1054:        if (bp->cnt >= size)
        !          1055:                return (bp);
        !          1056:        if (bp->buf == NULL)
        !          1057:          bp->buf = xmalloc(size);
        !          1058:        else
        !          1059:          bp->buf = xrealloc(bp->buf, size);
        !          1060:        bp->cnt = size;
        !          1061:        return (bp);
        !          1062: }
        !          1063:
        !          1064: void
        !          1065: lostconn(signo)
        !          1066:        int signo;
        !          1067: {
        !          1068:        if (!iamremote)
        !          1069:                fprintf(stderr, "lost connection\n");
        !          1070:        exit(1);
        !          1071: }