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 27d0c8c0bcSDag-Erling Smørgrav RCSID("$OpenBSD: sftp.c,v 1.34 2003/01/10 08:19:07 fgsch Exp $"); 281e8db6e2SBrian Feldman 291e8db6e2SBrian Feldman /* XXX: short-form remote directory listings (like 'ls -C') */ 301e8db6e2SBrian Feldman 311e8db6e2SBrian Feldman #include "buffer.h" 321e8db6e2SBrian Feldman #include "xmalloc.h" 331e8db6e2SBrian Feldman #include "log.h" 341e8db6e2SBrian Feldman #include "pathnames.h" 35ae1f160dSDag-Erling Smørgrav #include "misc.h" 361e8db6e2SBrian Feldman 371e8db6e2SBrian Feldman #include "sftp.h" 381e8db6e2SBrian Feldman #include "sftp-common.h" 391e8db6e2SBrian Feldman #include "sftp-client.h" 401e8db6e2SBrian Feldman #include "sftp-int.h" 411e8db6e2SBrian Feldman 4283d2307dSDag-Erling Smørgrav #ifdef HAVE___PROGNAME 4383d2307dSDag-Erling Smørgrav extern char *__progname; 4483d2307dSDag-Erling Smørgrav #else 4583d2307dSDag-Erling Smørgrav char *__progname; 4683d2307dSDag-Erling Smørgrav #endif 4783d2307dSDag-Erling Smørgrav 481e8db6e2SBrian Feldman FILE* infile; 49ae1f160dSDag-Erling Smørgrav size_t copy_buffer_len = 32768; 50ae1f160dSDag-Erling Smørgrav size_t num_requests = 16; 511e8db6e2SBrian Feldman 52d0c8c0bcSDag-Erling Smørgrav extern int showprogress; 53d0c8c0bcSDag-Erling Smørgrav 54ae1f160dSDag-Erling Smørgrav static void 55ae1f160dSDag-Erling Smørgrav connect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 561e8db6e2SBrian Feldman { 571e8db6e2SBrian Feldman int c_in, c_out; 58ee21a45fSDag-Erling Smørgrav 591e8db6e2SBrian Feldman #ifdef USE_PIPES 601e8db6e2SBrian Feldman int pin[2], pout[2]; 61ee21a45fSDag-Erling Smørgrav 621e8db6e2SBrian Feldman if ((pipe(pin) == -1) || (pipe(pout) == -1)) 631e8db6e2SBrian Feldman fatal("pipe: %s", strerror(errno)); 641e8db6e2SBrian Feldman *in = pin[0]; 651e8db6e2SBrian Feldman *out = pout[1]; 661e8db6e2SBrian Feldman c_in = pout[0]; 671e8db6e2SBrian Feldman c_out = pin[1]; 681e8db6e2SBrian Feldman #else /* USE_PIPES */ 691e8db6e2SBrian Feldman int inout[2]; 70ee21a45fSDag-Erling Smørgrav 711e8db6e2SBrian Feldman if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 721e8db6e2SBrian Feldman fatal("socketpair: %s", strerror(errno)); 731e8db6e2SBrian Feldman *in = *out = inout[0]; 741e8db6e2SBrian Feldman c_in = c_out = inout[1]; 751e8db6e2SBrian Feldman #endif /* USE_PIPES */ 761e8db6e2SBrian Feldman 771e8db6e2SBrian Feldman if ((*sshpid = fork()) == -1) 781e8db6e2SBrian Feldman fatal("fork: %s", strerror(errno)); 791e8db6e2SBrian Feldman else if (*sshpid == 0) { 801e8db6e2SBrian Feldman if ((dup2(c_in, STDIN_FILENO) == -1) || 811e8db6e2SBrian Feldman (dup2(c_out, STDOUT_FILENO) == -1)) { 821e8db6e2SBrian Feldman fprintf(stderr, "dup2: %s\n", strerror(errno)); 831e8db6e2SBrian Feldman exit(1); 841e8db6e2SBrian Feldman } 851e8db6e2SBrian Feldman close(*in); 861e8db6e2SBrian Feldman close(*out); 871e8db6e2SBrian Feldman close(c_in); 881e8db6e2SBrian Feldman close(c_out); 89ae1f160dSDag-Erling Smørgrav execv(path, args); 90ae1f160dSDag-Erling Smørgrav fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 911e8db6e2SBrian Feldman exit(1); 921e8db6e2SBrian Feldman } 931e8db6e2SBrian Feldman 941e8db6e2SBrian Feldman close(c_in); 951e8db6e2SBrian Feldman close(c_out); 961e8db6e2SBrian Feldman } 971e8db6e2SBrian Feldman 98ae1f160dSDag-Erling Smørgrav static void 991e8db6e2SBrian Feldman usage(void) 1001e8db6e2SBrian Feldman { 101ae1f160dSDag-Erling Smørgrav extern char *__progname; 102ae1f160dSDag-Erling Smørgrav 103ae1f160dSDag-Erling Smørgrav fprintf(stderr, 104ae1f160dSDag-Erling Smørgrav "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 105ae1f160dSDag-Erling Smørgrav " [-F config] [-P direct server path] [-S program]\n" 106ae1f160dSDag-Erling Smørgrav " [user@]host[:file [file]]\n", __progname); 1071e8db6e2SBrian Feldman exit(1); 1081e8db6e2SBrian Feldman } 1091e8db6e2SBrian Feldman 1101e8db6e2SBrian Feldman int 1111e8db6e2SBrian Feldman main(int argc, char **argv) 1121e8db6e2SBrian Feldman { 113d0c8c0bcSDag-Erling Smørgrav int in, out, ch, err; 1141e8db6e2SBrian Feldman pid_t sshpid; 1151e8db6e2SBrian Feldman char *host, *userhost, *cp, *file2; 116ae1f160dSDag-Erling Smørgrav int debug_level = 0, sshver = 2; 117ae1f160dSDag-Erling Smørgrav char *file1 = NULL, *sftp_server = NULL; 118ae1f160dSDag-Erling Smørgrav char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 119ae1f160dSDag-Erling Smørgrav LogLevel ll = SYSLOG_LEVEL_INFO; 120ae1f160dSDag-Erling Smørgrav arglist args; 1211e8db6e2SBrian Feldman extern int optind; 1221e8db6e2SBrian Feldman extern char *optarg; 1231e8db6e2SBrian Feldman 12483d2307dSDag-Erling Smørgrav __progname = get_progname(argv[0]); 125ae1f160dSDag-Erling Smørgrav args.list = NULL; 126ae1f160dSDag-Erling Smørgrav addargs(&args, "ssh"); /* overwritten with ssh_program */ 127ae1f160dSDag-Erling Smørgrav addargs(&args, "-oForwardX11 no"); 128ae1f160dSDag-Erling Smørgrav addargs(&args, "-oForwardAgent no"); 129ae1f160dSDag-Erling Smørgrav addargs(&args, "-oClearAllForwardings yes"); 130ae1f160dSDag-Erling Smørgrav ll = SYSLOG_LEVEL_INFO; 1311e8db6e2SBrian Feldman infile = stdin; /* Read from STDIN unless changed by -b */ 1321e8db6e2SBrian Feldman 133ae1f160dSDag-Erling Smørgrav while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 1341e8db6e2SBrian Feldman switch (ch) { 1351e8db6e2SBrian Feldman case 'C': 136ae1f160dSDag-Erling Smørgrav addargs(&args, "-C"); 1371e8db6e2SBrian Feldman break; 1381e8db6e2SBrian Feldman case 'v': 139ae1f160dSDag-Erling Smørgrav if (debug_level < 3) { 140ae1f160dSDag-Erling Smørgrav addargs(&args, "-v"); 141ae1f160dSDag-Erling Smørgrav ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 142ae1f160dSDag-Erling Smørgrav } 143ae1f160dSDag-Erling Smørgrav debug_level++; 1441e8db6e2SBrian Feldman break; 145ae1f160dSDag-Erling Smørgrav case 'F': 1461e8db6e2SBrian Feldman case 'o': 147ae1f160dSDag-Erling Smørgrav addargs(&args, "-%c%s", ch, optarg); 1481e8db6e2SBrian Feldman break; 1491e8db6e2SBrian Feldman case '1': 150ae1f160dSDag-Erling Smørgrav sshver = 1; 1511e8db6e2SBrian Feldman if (sftp_server == NULL) 1521e8db6e2SBrian Feldman sftp_server = _PATH_SFTP_SERVER; 1531e8db6e2SBrian Feldman break; 1541e8db6e2SBrian Feldman case 's': 1551e8db6e2SBrian Feldman sftp_server = optarg; 1561e8db6e2SBrian Feldman break; 1571e8db6e2SBrian Feldman case 'S': 1581e8db6e2SBrian Feldman ssh_program = optarg; 1591e8db6e2SBrian Feldman break; 1601e8db6e2SBrian Feldman case 'b': 1611e8db6e2SBrian Feldman if (infile == stdin) { 1621e8db6e2SBrian Feldman infile = fopen(optarg, "r"); 1631e8db6e2SBrian Feldman if (infile == NULL) 1641e8db6e2SBrian Feldman fatal("%s (%s).", strerror(errno), optarg); 1651e8db6e2SBrian Feldman } else 1661e8db6e2SBrian Feldman fatal("Filename already specified."); 167d0c8c0bcSDag-Erling Smørgrav showprogress = 0; 1681e8db6e2SBrian Feldman break; 169ae1f160dSDag-Erling Smørgrav case 'P': 170ae1f160dSDag-Erling Smørgrav sftp_direct = optarg; 171ae1f160dSDag-Erling Smørgrav break; 172ae1f160dSDag-Erling Smørgrav case 'B': 173ae1f160dSDag-Erling Smørgrav copy_buffer_len = strtol(optarg, &cp, 10); 174ae1f160dSDag-Erling Smørgrav if (copy_buffer_len == 0 || *cp != '\0') 175ae1f160dSDag-Erling Smørgrav fatal("Invalid buffer size \"%s\"", optarg); 176ae1f160dSDag-Erling Smørgrav break; 177ae1f160dSDag-Erling Smørgrav case 'R': 178ae1f160dSDag-Erling Smørgrav num_requests = strtol(optarg, &cp, 10); 179ae1f160dSDag-Erling Smørgrav if (num_requests == 0 || *cp != '\0') 180ae1f160dSDag-Erling Smørgrav fatal("Invalid number of requests \"%s\"", 181ae1f160dSDag-Erling Smørgrav optarg); 182ae1f160dSDag-Erling Smørgrav break; 1831e8db6e2SBrian Feldman case 'h': 1841e8db6e2SBrian Feldman default: 1851e8db6e2SBrian Feldman usage(); 1861e8db6e2SBrian Feldman } 1871e8db6e2SBrian Feldman } 1881e8db6e2SBrian Feldman 189545d5ecaSDag-Erling Smørgrav log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 190545d5ecaSDag-Erling Smørgrav 191ae1f160dSDag-Erling Smørgrav if (sftp_direct == NULL) { 1921e8db6e2SBrian Feldman if (optind == argc || argc > (optind + 2)) 1931e8db6e2SBrian Feldman usage(); 1941e8db6e2SBrian Feldman 1951e8db6e2SBrian Feldman userhost = xstrdup(argv[optind]); 1961e8db6e2SBrian Feldman file2 = argv[optind+1]; 1971e8db6e2SBrian Feldman 1981e8db6e2SBrian Feldman if ((cp = colon(userhost)) != NULL) { 1991e8db6e2SBrian Feldman *cp++ = '\0'; 2001e8db6e2SBrian Feldman file1 = cp; 2011e8db6e2SBrian Feldman } 2021e8db6e2SBrian Feldman 203d0c8c0bcSDag-Erling Smørgrav if ((host = strrchr(userhost, '@')) == NULL) 2041e8db6e2SBrian Feldman host = userhost; 2051e8db6e2SBrian Feldman else { 2061e8db6e2SBrian Feldman *host++ = '\0'; 2071e8db6e2SBrian Feldman if (!userhost[0]) { 2081e8db6e2SBrian Feldman fprintf(stderr, "Missing username\n"); 2091e8db6e2SBrian Feldman usage(); 2101e8db6e2SBrian Feldman } 211ae1f160dSDag-Erling Smørgrav addargs(&args, "-l%s",userhost); 2121e8db6e2SBrian Feldman } 2131e8db6e2SBrian Feldman 2141e8db6e2SBrian Feldman host = cleanhostname(host); 2151e8db6e2SBrian Feldman if (!*host) { 2161e8db6e2SBrian Feldman fprintf(stderr, "Missing hostname\n"); 2171e8db6e2SBrian Feldman usage(); 2181e8db6e2SBrian Feldman } 2191e8db6e2SBrian Feldman 220ae1f160dSDag-Erling Smørgrav addargs(&args, "-oProtocol %d", sshver); 2211e8db6e2SBrian Feldman 222ae1f160dSDag-Erling Smørgrav /* no subsystem if the server-spec contains a '/' */ 223ae1f160dSDag-Erling Smørgrav if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 224ae1f160dSDag-Erling Smørgrav addargs(&args, "-s"); 225ae1f160dSDag-Erling Smørgrav 226ae1f160dSDag-Erling Smørgrav addargs(&args, "%s", host); 227ae1f160dSDag-Erling Smørgrav addargs(&args, "%s", (sftp_server != NULL ? 228ae1f160dSDag-Erling Smørgrav sftp_server : "sftp")); 229ae1f160dSDag-Erling Smørgrav args.list[0] = ssh_program; 2301e8db6e2SBrian Feldman 2311e8db6e2SBrian Feldman fprintf(stderr, "Connecting to %s...\n", host); 232ae1f160dSDag-Erling Smørgrav connect_to_server(ssh_program, args.list, &in, &out, 233ae1f160dSDag-Erling Smørgrav &sshpid); 234ae1f160dSDag-Erling Smørgrav } else { 235ae1f160dSDag-Erling Smørgrav args.list = NULL; 236ae1f160dSDag-Erling Smørgrav addargs(&args, "sftp-server"); 2371e8db6e2SBrian Feldman 238ae1f160dSDag-Erling Smørgrav fprintf(stderr, "Attaching to %s...\n", sftp_direct); 239ae1f160dSDag-Erling Smørgrav connect_to_server(sftp_direct, args.list, &in, &out, 240ae1f160dSDag-Erling Smørgrav &sshpid); 241ae1f160dSDag-Erling Smørgrav } 2421e8db6e2SBrian Feldman 243d0c8c0bcSDag-Erling Smørgrav err = interactive_loop(in, out, file1, file2); 2441e8db6e2SBrian Feldman 24583d2307dSDag-Erling Smørgrav #if !defined(USE_PIPES) 24683d2307dSDag-Erling Smørgrav shutdown(in, SHUT_RDWR); 24783d2307dSDag-Erling Smørgrav shutdown(out, SHUT_RDWR); 24883d2307dSDag-Erling Smørgrav #endif 24983d2307dSDag-Erling Smørgrav 2501e8db6e2SBrian Feldman close(in); 2511e8db6e2SBrian Feldman close(out); 2521e8db6e2SBrian Feldman if (infile != stdin) 2531e8db6e2SBrian Feldman fclose(infile); 2541e8db6e2SBrian Feldman 255545d5ecaSDag-Erling Smørgrav while (waitpid(sshpid, NULL, 0) == -1) 256545d5ecaSDag-Erling Smørgrav if (errno != EINTR) 257545d5ecaSDag-Erling Smørgrav fatal("Couldn't wait for ssh process: %s", 258545d5ecaSDag-Erling Smørgrav strerror(errno)); 2591e8db6e2SBrian Feldman 260d0c8c0bcSDag-Erling Smørgrav exit(err == 0 ? 0 : 1); 2611e8db6e2SBrian Feldman } 262