11e8db6e2SBrian Feldman /* 2ae1f160dSDag-Erling Smørgrav * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 31e8db6e2SBrian Feldman * 41e8db6e2SBrian Feldman * Redistribution and use in source and binary forms, with or without 51e8db6e2SBrian Feldman * modification, are permitted provided that the following conditions 61e8db6e2SBrian Feldman * are met: 71e8db6e2SBrian Feldman * 1. Redistributions of source code must retain the above copyright 81e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer. 91e8db6e2SBrian Feldman * 2. Redistributions in binary form must reproduce the above copyright 101e8db6e2SBrian Feldman * notice, this list of conditions and the following disclaimer in the 111e8db6e2SBrian Feldman * documentation and/or other materials provided with the distribution. 121e8db6e2SBrian Feldman * 131e8db6e2SBrian Feldman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 141e8db6e2SBrian Feldman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 151e8db6e2SBrian Feldman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 161e8db6e2SBrian Feldman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 171e8db6e2SBrian Feldman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 181e8db6e2SBrian Feldman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 191e8db6e2SBrian Feldman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 201e8db6e2SBrian Feldman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 211e8db6e2SBrian Feldman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 221e8db6e2SBrian Feldman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 231e8db6e2SBrian Feldman */ 241e8db6e2SBrian Feldman 251e8db6e2SBrian Feldman #include "includes.h" 261e8db6e2SBrian Feldman 27d95e11bfSDag-Erling Smørgrav RCSID("$OpenBSD: sftp.c,v 1.37 2003/07/10 20:05:55 markus Exp $"); 281e8db6e2SBrian Feldman 291e8db6e2SBrian Feldman #include "buffer.h" 301e8db6e2SBrian Feldman #include "xmalloc.h" 311e8db6e2SBrian Feldman #include "log.h" 321e8db6e2SBrian Feldman #include "pathnames.h" 33ae1f160dSDag-Erling Smørgrav #include "misc.h" 341e8db6e2SBrian Feldman 351e8db6e2SBrian Feldman #include "sftp.h" 361e8db6e2SBrian Feldman #include "sftp-common.h" 371e8db6e2SBrian Feldman #include "sftp-client.h" 381e8db6e2SBrian Feldman #include "sftp-int.h" 391e8db6e2SBrian Feldman 4083d2307dSDag-Erling Smørgrav #ifdef HAVE___PROGNAME 4183d2307dSDag-Erling Smørgrav extern char *__progname; 4283d2307dSDag-Erling Smørgrav #else 4383d2307dSDag-Erling Smørgrav char *__progname; 4483d2307dSDag-Erling Smørgrav #endif 4583d2307dSDag-Erling Smørgrav 461e8db6e2SBrian Feldman FILE* infile; 47ae1f160dSDag-Erling Smørgrav size_t copy_buffer_len = 32768; 48ae1f160dSDag-Erling Smørgrav size_t num_requests = 16; 49d95e11bfSDag-Erling Smørgrav static pid_t sshpid = -1; 501e8db6e2SBrian Feldman 51d0c8c0bcSDag-Erling Smørgrav extern int showprogress; 52d0c8c0bcSDag-Erling Smørgrav 53ae1f160dSDag-Erling Smørgrav static void 54d95e11bfSDag-Erling Smørgrav killchild(int signo) 55d95e11bfSDag-Erling Smørgrav { 56d95e11bfSDag-Erling Smørgrav if (sshpid > 1) 57d95e11bfSDag-Erling Smørgrav kill(sshpid, signo); 58d95e11bfSDag-Erling Smørgrav 59d95e11bfSDag-Erling Smørgrav _exit(1); 60d95e11bfSDag-Erling Smørgrav } 61d95e11bfSDag-Erling Smørgrav 62d95e11bfSDag-Erling Smørgrav static void 63d95e11bfSDag-Erling Smørgrav connect_to_server(char *path, char **args, int *in, int *out) 641e8db6e2SBrian Feldman { 651e8db6e2SBrian Feldman int c_in, c_out; 66ee21a45fSDag-Erling Smørgrav 671e8db6e2SBrian Feldman #ifdef USE_PIPES 681e8db6e2SBrian Feldman int pin[2], pout[2]; 69ee21a45fSDag-Erling Smørgrav 701e8db6e2SBrian Feldman if ((pipe(pin) == -1) || (pipe(pout) == -1)) 711e8db6e2SBrian Feldman fatal("pipe: %s", strerror(errno)); 721e8db6e2SBrian Feldman *in = pin[0]; 731e8db6e2SBrian Feldman *out = pout[1]; 741e8db6e2SBrian Feldman c_in = pout[0]; 751e8db6e2SBrian Feldman c_out = pin[1]; 761e8db6e2SBrian Feldman #else /* USE_PIPES */ 771e8db6e2SBrian Feldman int inout[2]; 78ee21a45fSDag-Erling Smørgrav 791e8db6e2SBrian Feldman if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 801e8db6e2SBrian Feldman fatal("socketpair: %s", strerror(errno)); 811e8db6e2SBrian Feldman *in = *out = inout[0]; 821e8db6e2SBrian Feldman c_in = c_out = inout[1]; 831e8db6e2SBrian Feldman #endif /* USE_PIPES */ 841e8db6e2SBrian Feldman 85d95e11bfSDag-Erling Smørgrav if ((sshpid = fork()) == -1) 861e8db6e2SBrian Feldman fatal("fork: %s", strerror(errno)); 87d95e11bfSDag-Erling Smørgrav else if (sshpid == 0) { 881e8db6e2SBrian Feldman if ((dup2(c_in, STDIN_FILENO) == -1) || 891e8db6e2SBrian Feldman (dup2(c_out, STDOUT_FILENO) == -1)) { 901e8db6e2SBrian Feldman fprintf(stderr, "dup2: %s\n", strerror(errno)); 911e8db6e2SBrian Feldman exit(1); 921e8db6e2SBrian Feldman } 931e8db6e2SBrian Feldman close(*in); 941e8db6e2SBrian Feldman close(*out); 951e8db6e2SBrian Feldman close(c_in); 961e8db6e2SBrian Feldman close(c_out); 97ae1f160dSDag-Erling Smørgrav execv(path, args); 98ae1f160dSDag-Erling Smørgrav fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 991e8db6e2SBrian Feldman exit(1); 1001e8db6e2SBrian Feldman } 1011e8db6e2SBrian Feldman 102d95e11bfSDag-Erling Smørgrav signal(SIGTERM, killchild); 103d95e11bfSDag-Erling Smørgrav signal(SIGINT, killchild); 104d95e11bfSDag-Erling Smørgrav signal(SIGHUP, killchild); 1051e8db6e2SBrian Feldman close(c_in); 1061e8db6e2SBrian Feldman close(c_out); 1071e8db6e2SBrian Feldman } 1081e8db6e2SBrian Feldman 109ae1f160dSDag-Erling Smørgrav static void 1101e8db6e2SBrian Feldman usage(void) 1111e8db6e2SBrian Feldman { 112ae1f160dSDag-Erling Smørgrav extern char *__progname; 113ae1f160dSDag-Erling Smørgrav 114ae1f160dSDag-Erling Smørgrav fprintf(stderr, 115d95e11bfSDag-Erling Smørgrav "usage: %s [-vC1] [-b batchfile] [-o ssh_option] [-s subsystem | sftp_server]\n" 116d95e11bfSDag-Erling Smørgrav " [-B buffer_size] [-F ssh_config] [-P sftp_server path]\n" 117d95e11bfSDag-Erling Smørgrav " [-R num_requests] [-S program]\n" 118ae1f160dSDag-Erling Smørgrav " [user@]host[:file [file]]\n", __progname); 1191e8db6e2SBrian Feldman exit(1); 1201e8db6e2SBrian Feldman } 1211e8db6e2SBrian Feldman 1221e8db6e2SBrian Feldman int 1231e8db6e2SBrian Feldman main(int argc, char **argv) 1241e8db6e2SBrian Feldman { 125d0c8c0bcSDag-Erling Smørgrav int in, out, ch, err; 1261e8db6e2SBrian Feldman char *host, *userhost, *cp, *file2; 127ae1f160dSDag-Erling Smørgrav int debug_level = 0, sshver = 2; 128ae1f160dSDag-Erling Smørgrav char *file1 = NULL, *sftp_server = NULL; 129ae1f160dSDag-Erling Smørgrav char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 130ae1f160dSDag-Erling Smørgrav LogLevel ll = SYSLOG_LEVEL_INFO; 131ae1f160dSDag-Erling Smørgrav arglist args; 1321e8db6e2SBrian Feldman extern int optind; 1331e8db6e2SBrian Feldman extern char *optarg; 1341e8db6e2SBrian Feldman 135d95e11bfSDag-Erling Smørgrav __progname = ssh_get_progname(argv[0]); 136ae1f160dSDag-Erling Smørgrav args.list = NULL; 137ae1f160dSDag-Erling Smørgrav addargs(&args, "ssh"); /* overwritten with ssh_program */ 138ae1f160dSDag-Erling Smørgrav addargs(&args, "-oForwardX11 no"); 139ae1f160dSDag-Erling Smørgrav addargs(&args, "-oForwardAgent no"); 140ae1f160dSDag-Erling Smørgrav addargs(&args, "-oClearAllForwardings yes"); 141ae1f160dSDag-Erling Smørgrav ll = SYSLOG_LEVEL_INFO; 1421e8db6e2SBrian Feldman infile = stdin; /* Read from STDIN unless changed by -b */ 1431e8db6e2SBrian Feldman 144ae1f160dSDag-Erling Smørgrav while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 1451e8db6e2SBrian Feldman switch (ch) { 1461e8db6e2SBrian Feldman case 'C': 147ae1f160dSDag-Erling Smørgrav addargs(&args, "-C"); 1481e8db6e2SBrian Feldman break; 1491e8db6e2SBrian Feldman case 'v': 150ae1f160dSDag-Erling Smørgrav if (debug_level < 3) { 151ae1f160dSDag-Erling Smørgrav addargs(&args, "-v"); 152ae1f160dSDag-Erling Smørgrav ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 153ae1f160dSDag-Erling Smørgrav } 154ae1f160dSDag-Erling Smørgrav debug_level++; 1551e8db6e2SBrian Feldman break; 156ae1f160dSDag-Erling Smørgrav case 'F': 1571e8db6e2SBrian Feldman case 'o': 158ae1f160dSDag-Erling Smørgrav addargs(&args, "-%c%s", ch, optarg); 1591e8db6e2SBrian Feldman break; 1601e8db6e2SBrian Feldman case '1': 161ae1f160dSDag-Erling Smørgrav sshver = 1; 1621e8db6e2SBrian Feldman if (sftp_server == NULL) 1631e8db6e2SBrian Feldman sftp_server = _PATH_SFTP_SERVER; 1641e8db6e2SBrian Feldman break; 1651e8db6e2SBrian Feldman case 's': 1661e8db6e2SBrian Feldman sftp_server = optarg; 1671e8db6e2SBrian Feldman break; 1681e8db6e2SBrian Feldman case 'S': 1691e8db6e2SBrian Feldman ssh_program = optarg; 1701e8db6e2SBrian Feldman break; 1711e8db6e2SBrian Feldman case 'b': 1721e8db6e2SBrian Feldman if (infile == stdin) { 1731e8db6e2SBrian Feldman infile = fopen(optarg, "r"); 1741e8db6e2SBrian Feldman if (infile == NULL) 1751e8db6e2SBrian Feldman fatal("%s (%s).", strerror(errno), optarg); 1761e8db6e2SBrian Feldman } else 1771e8db6e2SBrian Feldman fatal("Filename already specified."); 178d0c8c0bcSDag-Erling Smørgrav showprogress = 0; 1791e8db6e2SBrian Feldman break; 180ae1f160dSDag-Erling Smørgrav case 'P': 181ae1f160dSDag-Erling Smørgrav sftp_direct = optarg; 182ae1f160dSDag-Erling Smørgrav break; 183ae1f160dSDag-Erling Smørgrav case 'B': 184ae1f160dSDag-Erling Smørgrav copy_buffer_len = strtol(optarg, &cp, 10); 185ae1f160dSDag-Erling Smørgrav if (copy_buffer_len == 0 || *cp != '\0') 186ae1f160dSDag-Erling Smørgrav fatal("Invalid buffer size \"%s\"", optarg); 187ae1f160dSDag-Erling Smørgrav break; 188ae1f160dSDag-Erling Smørgrav case 'R': 189ae1f160dSDag-Erling Smørgrav num_requests = strtol(optarg, &cp, 10); 190ae1f160dSDag-Erling Smørgrav if (num_requests == 0 || *cp != '\0') 191ae1f160dSDag-Erling Smørgrav fatal("Invalid number of requests \"%s\"", 192ae1f160dSDag-Erling Smørgrav optarg); 193ae1f160dSDag-Erling Smørgrav break; 1941e8db6e2SBrian Feldman case 'h': 1951e8db6e2SBrian Feldman default: 1961e8db6e2SBrian Feldman usage(); 1971e8db6e2SBrian Feldman } 1981e8db6e2SBrian Feldman } 1991e8db6e2SBrian Feldman 200545d5ecaSDag-Erling Smørgrav log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 201545d5ecaSDag-Erling Smørgrav 202ae1f160dSDag-Erling Smørgrav if (sftp_direct == NULL) { 2031e8db6e2SBrian Feldman if (optind == argc || argc > (optind + 2)) 2041e8db6e2SBrian Feldman usage(); 2051e8db6e2SBrian Feldman 2061e8db6e2SBrian Feldman userhost = xstrdup(argv[optind]); 2071e8db6e2SBrian Feldman file2 = argv[optind+1]; 2081e8db6e2SBrian Feldman 2091e8db6e2SBrian Feldman if ((cp = colon(userhost)) != NULL) { 2101e8db6e2SBrian Feldman *cp++ = '\0'; 2111e8db6e2SBrian Feldman file1 = cp; 2121e8db6e2SBrian Feldman } 2131e8db6e2SBrian Feldman 214d0c8c0bcSDag-Erling Smørgrav if ((host = strrchr(userhost, '@')) == NULL) 2151e8db6e2SBrian Feldman host = userhost; 2161e8db6e2SBrian Feldman else { 2171e8db6e2SBrian Feldman *host++ = '\0'; 2181e8db6e2SBrian Feldman if (!userhost[0]) { 2191e8db6e2SBrian Feldman fprintf(stderr, "Missing username\n"); 2201e8db6e2SBrian Feldman usage(); 2211e8db6e2SBrian Feldman } 222ae1f160dSDag-Erling Smørgrav addargs(&args, "-l%s",userhost); 2231e8db6e2SBrian Feldman } 2241e8db6e2SBrian Feldman 2251e8db6e2SBrian Feldman host = cleanhostname(host); 2261e8db6e2SBrian Feldman if (!*host) { 2271e8db6e2SBrian Feldman fprintf(stderr, "Missing hostname\n"); 2281e8db6e2SBrian Feldman usage(); 2291e8db6e2SBrian Feldman } 2301e8db6e2SBrian Feldman 231ae1f160dSDag-Erling Smørgrav addargs(&args, "-oProtocol %d", sshver); 2321e8db6e2SBrian Feldman 233ae1f160dSDag-Erling Smørgrav /* no subsystem if the server-spec contains a '/' */ 234ae1f160dSDag-Erling Smørgrav if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 235ae1f160dSDag-Erling Smørgrav addargs(&args, "-s"); 236ae1f160dSDag-Erling Smørgrav 237ae1f160dSDag-Erling Smørgrav addargs(&args, "%s", host); 238ae1f160dSDag-Erling Smørgrav addargs(&args, "%s", (sftp_server != NULL ? 239ae1f160dSDag-Erling Smørgrav sftp_server : "sftp")); 240ae1f160dSDag-Erling Smørgrav args.list[0] = ssh_program; 2411e8db6e2SBrian Feldman 2421e8db6e2SBrian Feldman fprintf(stderr, "Connecting to %s...\n", host); 243d95e11bfSDag-Erling Smørgrav connect_to_server(ssh_program, args.list, &in, &out); 244ae1f160dSDag-Erling Smørgrav } else { 245ae1f160dSDag-Erling Smørgrav args.list = NULL; 246ae1f160dSDag-Erling Smørgrav addargs(&args, "sftp-server"); 2471e8db6e2SBrian Feldman 248ae1f160dSDag-Erling Smørgrav fprintf(stderr, "Attaching to %s...\n", sftp_direct); 249d95e11bfSDag-Erling Smørgrav connect_to_server(sftp_direct, args.list, &in, &out); 250ae1f160dSDag-Erling Smørgrav } 2511e8db6e2SBrian Feldman 252d0c8c0bcSDag-Erling Smørgrav err = interactive_loop(in, out, file1, file2); 2531e8db6e2SBrian Feldman 25483d2307dSDag-Erling Smørgrav #if !defined(USE_PIPES) 25583d2307dSDag-Erling Smørgrav shutdown(in, SHUT_RDWR); 25683d2307dSDag-Erling Smørgrav shutdown(out, SHUT_RDWR); 25783d2307dSDag-Erling Smørgrav #endif 25883d2307dSDag-Erling Smørgrav 2591e8db6e2SBrian Feldman close(in); 2601e8db6e2SBrian Feldman close(out); 2611e8db6e2SBrian Feldman if (infile != stdin) 2621e8db6e2SBrian Feldman fclose(infile); 2631e8db6e2SBrian Feldman 264545d5ecaSDag-Erling Smørgrav while (waitpid(sshpid, NULL, 0) == -1) 265545d5ecaSDag-Erling Smørgrav if (errno != EINTR) 266545d5ecaSDag-Erling Smørgrav fatal("Couldn't wait for ssh process: %s", 267545d5ecaSDag-Erling Smørgrav strerror(errno)); 2681e8db6e2SBrian Feldman 269d0c8c0bcSDag-Erling Smørgrav exit(err == 0 ? 0 : 1); 2701e8db6e2SBrian Feldman } 271