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 27545d5ecaSDag-Erling Smørgrav RCSID("$OpenBSD: sftp.c,v 1.29 2002/04/02 17:37:48 markus 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 421e8db6e2SBrian Feldman FILE* infile; 43ae1f160dSDag-Erling Smørgrav size_t copy_buffer_len = 32768; 44ae1f160dSDag-Erling Smørgrav size_t num_requests = 16; 451e8db6e2SBrian Feldman 46ae1f160dSDag-Erling Smørgrav static void 47ae1f160dSDag-Erling Smørgrav connect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 481e8db6e2SBrian Feldman { 491e8db6e2SBrian Feldman int c_in, c_out; 501e8db6e2SBrian Feldman #ifdef USE_PIPES 511e8db6e2SBrian Feldman int pin[2], pout[2]; 521e8db6e2SBrian Feldman if ((pipe(pin) == -1) || (pipe(pout) == -1)) 531e8db6e2SBrian Feldman fatal("pipe: %s", strerror(errno)); 541e8db6e2SBrian Feldman *in = pin[0]; 551e8db6e2SBrian Feldman *out = pout[1]; 561e8db6e2SBrian Feldman c_in = pout[0]; 571e8db6e2SBrian Feldman c_out = pin[1]; 581e8db6e2SBrian Feldman #else /* USE_PIPES */ 591e8db6e2SBrian Feldman int inout[2]; 601e8db6e2SBrian Feldman if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 611e8db6e2SBrian Feldman fatal("socketpair: %s", strerror(errno)); 621e8db6e2SBrian Feldman *in = *out = inout[0]; 631e8db6e2SBrian Feldman c_in = c_out = inout[1]; 641e8db6e2SBrian Feldman #endif /* USE_PIPES */ 651e8db6e2SBrian Feldman 661e8db6e2SBrian Feldman if ((*sshpid = fork()) == -1) 671e8db6e2SBrian Feldman fatal("fork: %s", strerror(errno)); 681e8db6e2SBrian Feldman else if (*sshpid == 0) { 691e8db6e2SBrian Feldman if ((dup2(c_in, STDIN_FILENO) == -1) || 701e8db6e2SBrian Feldman (dup2(c_out, STDOUT_FILENO) == -1)) { 711e8db6e2SBrian Feldman fprintf(stderr, "dup2: %s\n", strerror(errno)); 721e8db6e2SBrian Feldman exit(1); 731e8db6e2SBrian Feldman } 741e8db6e2SBrian Feldman close(*in); 751e8db6e2SBrian Feldman close(*out); 761e8db6e2SBrian Feldman close(c_in); 771e8db6e2SBrian Feldman close(c_out); 78ae1f160dSDag-Erling Smørgrav execv(path, args); 79ae1f160dSDag-Erling Smørgrav fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 801e8db6e2SBrian Feldman exit(1); 811e8db6e2SBrian Feldman } 821e8db6e2SBrian Feldman 831e8db6e2SBrian Feldman close(c_in); 841e8db6e2SBrian Feldman close(c_out); 851e8db6e2SBrian Feldman } 861e8db6e2SBrian Feldman 87ae1f160dSDag-Erling Smørgrav static void 881e8db6e2SBrian Feldman usage(void) 891e8db6e2SBrian Feldman { 90ae1f160dSDag-Erling Smørgrav extern char *__progname; 91ae1f160dSDag-Erling Smørgrav 92ae1f160dSDag-Erling Smørgrav fprintf(stderr, 93ae1f160dSDag-Erling Smørgrav "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 94ae1f160dSDag-Erling Smørgrav " [-F config] [-P direct server path] [-S program]\n" 95ae1f160dSDag-Erling Smørgrav " [user@]host[:file [file]]\n", __progname); 961e8db6e2SBrian Feldman exit(1); 971e8db6e2SBrian Feldman } 981e8db6e2SBrian Feldman 991e8db6e2SBrian Feldman int 1001e8db6e2SBrian Feldman main(int argc, char **argv) 1011e8db6e2SBrian Feldman { 102ae1f160dSDag-Erling Smørgrav int in, out, ch; 1031e8db6e2SBrian Feldman pid_t sshpid; 1041e8db6e2SBrian Feldman char *host, *userhost, *cp, *file2; 105ae1f160dSDag-Erling Smørgrav int debug_level = 0, sshver = 2; 106ae1f160dSDag-Erling Smørgrav char *file1 = NULL, *sftp_server = NULL; 107ae1f160dSDag-Erling Smørgrav char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 108ae1f160dSDag-Erling Smørgrav LogLevel ll = SYSLOG_LEVEL_INFO; 109ae1f160dSDag-Erling Smørgrav arglist args; 1101e8db6e2SBrian Feldman extern int optind; 1111e8db6e2SBrian Feldman extern char *optarg; 1121e8db6e2SBrian Feldman 113ae1f160dSDag-Erling Smørgrav args.list = NULL; 114ae1f160dSDag-Erling Smørgrav addargs(&args, "ssh"); /* overwritten with ssh_program */ 115ae1f160dSDag-Erling Smørgrav addargs(&args, "-oFallBackToRsh no"); 116ae1f160dSDag-Erling Smørgrav addargs(&args, "-oForwardX11 no"); 117ae1f160dSDag-Erling Smørgrav addargs(&args, "-oForwardAgent no"); 118ae1f160dSDag-Erling Smørgrav addargs(&args, "-oClearAllForwardings yes"); 119ae1f160dSDag-Erling Smørgrav ll = SYSLOG_LEVEL_INFO; 1201e8db6e2SBrian Feldman infile = stdin; /* Read from STDIN unless changed by -b */ 1211e8db6e2SBrian Feldman 122ae1f160dSDag-Erling Smørgrav while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 1231e8db6e2SBrian Feldman switch (ch) { 1241e8db6e2SBrian Feldman case 'C': 125ae1f160dSDag-Erling Smørgrav addargs(&args, "-C"); 1261e8db6e2SBrian Feldman break; 1271e8db6e2SBrian Feldman case 'v': 128ae1f160dSDag-Erling Smørgrav if (debug_level < 3) { 129ae1f160dSDag-Erling Smørgrav addargs(&args, "-v"); 130ae1f160dSDag-Erling Smørgrav ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 131ae1f160dSDag-Erling Smørgrav } 132ae1f160dSDag-Erling Smørgrav debug_level++; 1331e8db6e2SBrian Feldman break; 134ae1f160dSDag-Erling Smørgrav case 'F': 1351e8db6e2SBrian Feldman case 'o': 136ae1f160dSDag-Erling Smørgrav addargs(&args, "-%c%s", ch, optarg); 1371e8db6e2SBrian Feldman break; 1381e8db6e2SBrian Feldman case '1': 139ae1f160dSDag-Erling Smørgrav sshver = 1; 1401e8db6e2SBrian Feldman if (sftp_server == NULL) 1411e8db6e2SBrian Feldman sftp_server = _PATH_SFTP_SERVER; 1421e8db6e2SBrian Feldman break; 1431e8db6e2SBrian Feldman case 's': 1441e8db6e2SBrian Feldman sftp_server = optarg; 1451e8db6e2SBrian Feldman break; 1461e8db6e2SBrian Feldman case 'S': 1471e8db6e2SBrian Feldman ssh_program = optarg; 1481e8db6e2SBrian Feldman break; 1491e8db6e2SBrian Feldman case 'b': 1501e8db6e2SBrian Feldman if (infile == stdin) { 1511e8db6e2SBrian Feldman infile = fopen(optarg, "r"); 1521e8db6e2SBrian Feldman if (infile == NULL) 1531e8db6e2SBrian Feldman fatal("%s (%s).", strerror(errno), optarg); 1541e8db6e2SBrian Feldman } else 1551e8db6e2SBrian Feldman fatal("Filename already specified."); 1561e8db6e2SBrian Feldman break; 157ae1f160dSDag-Erling Smørgrav case 'P': 158ae1f160dSDag-Erling Smørgrav sftp_direct = optarg; 159ae1f160dSDag-Erling Smørgrav break; 160ae1f160dSDag-Erling Smørgrav case 'B': 161ae1f160dSDag-Erling Smørgrav copy_buffer_len = strtol(optarg, &cp, 10); 162ae1f160dSDag-Erling Smørgrav if (copy_buffer_len == 0 || *cp != '\0') 163ae1f160dSDag-Erling Smørgrav fatal("Invalid buffer size \"%s\"", optarg); 164ae1f160dSDag-Erling Smørgrav break; 165ae1f160dSDag-Erling Smørgrav case 'R': 166ae1f160dSDag-Erling Smørgrav num_requests = strtol(optarg, &cp, 10); 167ae1f160dSDag-Erling Smørgrav if (num_requests == 0 || *cp != '\0') 168ae1f160dSDag-Erling Smørgrav fatal("Invalid number of requests \"%s\"", 169ae1f160dSDag-Erling Smørgrav optarg); 170ae1f160dSDag-Erling Smørgrav break; 1711e8db6e2SBrian Feldman case 'h': 1721e8db6e2SBrian Feldman default: 1731e8db6e2SBrian Feldman usage(); 1741e8db6e2SBrian Feldman } 1751e8db6e2SBrian Feldman } 1761e8db6e2SBrian Feldman 177545d5ecaSDag-Erling Smørgrav log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 178545d5ecaSDag-Erling Smørgrav 179ae1f160dSDag-Erling Smørgrav if (sftp_direct == NULL) { 1801e8db6e2SBrian Feldman if (optind == argc || argc > (optind + 2)) 1811e8db6e2SBrian Feldman usage(); 1821e8db6e2SBrian Feldman 1831e8db6e2SBrian Feldman userhost = xstrdup(argv[optind]); 1841e8db6e2SBrian Feldman file2 = argv[optind+1]; 1851e8db6e2SBrian Feldman 1861e8db6e2SBrian Feldman if ((cp = colon(userhost)) != NULL) { 1871e8db6e2SBrian Feldman *cp++ = '\0'; 1881e8db6e2SBrian Feldman file1 = cp; 1891e8db6e2SBrian Feldman } 1901e8db6e2SBrian Feldman 1911e8db6e2SBrian Feldman if ((host = strchr(userhost, '@')) == NULL) 1921e8db6e2SBrian Feldman host = userhost; 1931e8db6e2SBrian Feldman else { 1941e8db6e2SBrian Feldman *host++ = '\0'; 1951e8db6e2SBrian Feldman if (!userhost[0]) { 1961e8db6e2SBrian Feldman fprintf(stderr, "Missing username\n"); 1971e8db6e2SBrian Feldman usage(); 1981e8db6e2SBrian Feldman } 199ae1f160dSDag-Erling Smørgrav addargs(&args, "-l%s",userhost); 2001e8db6e2SBrian Feldman } 2011e8db6e2SBrian Feldman 2021e8db6e2SBrian Feldman host = cleanhostname(host); 2031e8db6e2SBrian Feldman if (!*host) { 2041e8db6e2SBrian Feldman fprintf(stderr, "Missing hostname\n"); 2051e8db6e2SBrian Feldman usage(); 2061e8db6e2SBrian Feldman } 2071e8db6e2SBrian Feldman 208ae1f160dSDag-Erling Smørgrav addargs(&args, "-oProtocol %d", sshver); 2091e8db6e2SBrian Feldman 210ae1f160dSDag-Erling Smørgrav /* no subsystem if the server-spec contains a '/' */ 211ae1f160dSDag-Erling Smørgrav if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 212ae1f160dSDag-Erling Smørgrav addargs(&args, "-s"); 213ae1f160dSDag-Erling Smørgrav 214ae1f160dSDag-Erling Smørgrav addargs(&args, "%s", host); 215ae1f160dSDag-Erling Smørgrav addargs(&args, "%s", (sftp_server != NULL ? 216ae1f160dSDag-Erling Smørgrav sftp_server : "sftp")); 217ae1f160dSDag-Erling Smørgrav args.list[0] = ssh_program; 2181e8db6e2SBrian Feldman 2191e8db6e2SBrian Feldman fprintf(stderr, "Connecting to %s...\n", host); 220ae1f160dSDag-Erling Smørgrav connect_to_server(ssh_program, args.list, &in, &out, 221ae1f160dSDag-Erling Smørgrav &sshpid); 222ae1f160dSDag-Erling Smørgrav } else { 223ae1f160dSDag-Erling Smørgrav args.list = NULL; 224ae1f160dSDag-Erling Smørgrav addargs(&args, "sftp-server"); 2251e8db6e2SBrian Feldman 226ae1f160dSDag-Erling Smørgrav fprintf(stderr, "Attaching to %s...\n", sftp_direct); 227ae1f160dSDag-Erling Smørgrav connect_to_server(sftp_direct, args.list, &in, &out, 228ae1f160dSDag-Erling Smørgrav &sshpid); 229ae1f160dSDag-Erling Smørgrav } 2301e8db6e2SBrian Feldman 2311e8db6e2SBrian Feldman interactive_loop(in, out, file1, file2); 2321e8db6e2SBrian Feldman 2331e8db6e2SBrian Feldman close(in); 2341e8db6e2SBrian Feldman close(out); 2351e8db6e2SBrian Feldman if (infile != stdin) 2361e8db6e2SBrian Feldman fclose(infile); 2371e8db6e2SBrian Feldman 238545d5ecaSDag-Erling Smørgrav while (waitpid(sshpid, NULL, 0) == -1) 239545d5ecaSDag-Erling Smørgrav if (errno != EINTR) 240545d5ecaSDag-Erling Smørgrav fatal("Couldn't wait for ssh process: %s", 241545d5ecaSDag-Erling Smørgrav strerror(errno)); 2421e8db6e2SBrian Feldman 2431e8db6e2SBrian Feldman exit(0); 2441e8db6e2SBrian Feldman } 245