sftp.c revision 99060
150397Sobrien/* 2117395Skan * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 3117395Skan * 450397Sobrien * Redistribution and use in source and binary forms, with or without 550397Sobrien * modification, are permitted provided that the following conditions 690075Sobrien * are met: 750397Sobrien * 1. Redistributions of source code must retain the above copyright 890075Sobrien * notice, this list of conditions and the following disclaimer. 990075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1090075Sobrien * notice, this list of conditions and the following disclaimer in the 1190075Sobrien * documentation and/or other materials provided with the distribution. 1250397Sobrien * 1390075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1490075Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1590075Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1690075Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1750397Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1850397Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1990075Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2090075Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2190075Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2250397Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2350397Sobrien */ 2450397Sobrien 2550397Sobrien#include "includes.h" 2690075Sobrien 2790075SobrienRCSID("$OpenBSD: sftp.c,v 1.30 2002/06/23 09:30:14 deraadt Exp $"); 2890075Sobrien 2950397Sobrien/* XXX: short-form remote directory listings (like 'ls -C') */ 3050397Sobrien 3150397Sobrien#include "buffer.h" 3290075Sobrien#include "xmalloc.h" 3350397Sobrien#include "log.h" 3452284Sobrien#include "pathnames.h" 3550397Sobrien#include "misc.h" 3690075Sobrien 3752284Sobrien#include "sftp.h" 3890075Sobrien#include "sftp-common.h" 3990075Sobrien#include "sftp-client.h" 40117395Skan#include "sftp-int.h" 4150397Sobrien 4252284Sobrien#ifdef HAVE___PROGNAME 4352284Sobrienextern char *__progname; 4490075Sobrien#else 4590075Sobrienchar *__progname; 4652284Sobrien#endif 4752284Sobrien 4852284SobrienFILE* infile; 4952284Sobriensize_t copy_buffer_len = 32768; 5052284Sobriensize_t num_requests = 16; 5152284Sobrien 5252284Sobrienstatic void 5352284Sobrienconnect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 5452284Sobrien{ 5552284Sobrien int c_in, c_out; 5652284Sobrien 5752284Sobrien#ifdef USE_PIPES 5852284Sobrien int pin[2], pout[2]; 5990075Sobrien 6090075Sobrien if ((pipe(pin) == -1) || (pipe(pout) == -1)) 6190075Sobrien fatal("pipe: %s", strerror(errno)); 6252284Sobrien *in = pin[0]; 6390075Sobrien *out = pout[1]; 6490075Sobrien c_in = pout[0]; 6590075Sobrien c_out = pin[1]; 6690075Sobrien#else /* USE_PIPES */ 6790075Sobrien int inout[2]; 6852284Sobrien 6952284Sobrien if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 7052284Sobrien fatal("socketpair: %s", strerror(errno)); 7152284Sobrien *in = *out = inout[0]; 7290075Sobrien c_in = c_out = inout[1]; 7390075Sobrien#endif /* USE_PIPES */ 7452284Sobrien 7590075Sobrien if ((*sshpid = fork()) == -1) 7652284Sobrien fatal("fork: %s", strerror(errno)); 7752284Sobrien else if (*sshpid == 0) { 7890075Sobrien if ((dup2(c_in, STDIN_FILENO) == -1) || 7952284Sobrien (dup2(c_out, STDOUT_FILENO) == -1)) { 80117395Skan fprintf(stderr, "dup2: %s\n", strerror(errno)); 8152284Sobrien exit(1); 8252284Sobrien } 8352284Sobrien close(*in); 8452284Sobrien close(*out); 8552284Sobrien close(c_in); 8690075Sobrien close(c_out); 8790075Sobrien execv(path, args); 8890075Sobrien fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 8990075Sobrien exit(1); 9050397Sobrien } 9190075Sobrien 9290075Sobrien close(c_in); 9390075Sobrien close(c_out); 9490075Sobrien} 9590075Sobrien 9690075Sobrienstatic void 9790075Sobrienusage(void) 9890075Sobrien{ 9990075Sobrien extern char *__progname; 10090075Sobrien 10190075Sobrien fprintf(stderr, 10290075Sobrien "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 10390075Sobrien " [-F config] [-P direct server path] [-S program]\n" 10490075Sobrien " [user@]host[:file [file]]\n", __progname); 10590075Sobrien exit(1); 10690075Sobrien} 10790075Sobrien 10890075Sobrienint 10990075Sobrienmain(int argc, char **argv) 11090075Sobrien{ 11190075Sobrien int in, out, ch; 11290075Sobrien pid_t sshpid; 113117395Skan char *host, *userhost, *cp, *file2; 114117395Skan int debug_level = 0, sshver = 2; 11590075Sobrien char *file1 = NULL, *sftp_server = NULL; 116117395Skan char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 117117395Skan LogLevel ll = SYSLOG_LEVEL_INFO; 118117395Skan arglist args; 119117395Skan extern int optind; 12090075Sobrien extern char *optarg; 12150397Sobrien 12250397Sobrien __progname = get_progname(argv[0]); 12390075Sobrien args.list = NULL; 12450397Sobrien addargs(&args, "ssh"); /* overwritten with ssh_program */ 12550397Sobrien addargs(&args, "-oFallBackToRsh no"); 12650397Sobrien addargs(&args, "-oForwardX11 no"); 12752284Sobrien addargs(&args, "-oForwardAgent no"); 12852284Sobrien addargs(&args, "-oClearAllForwardings yes"); 12952284Sobrien ll = SYSLOG_LEVEL_INFO; 13052284Sobrien infile = stdin; /* Read from STDIN unless changed by -b */ 13152284Sobrien 13250397Sobrien while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 13350397Sobrien switch (ch) { 13490075Sobrien case 'C': 13550397Sobrien addargs(&args, "-C"); 136117395Skan break; 13750397Sobrien case 'v': 13850397Sobrien if (debug_level < 3) { 13950397Sobrien addargs(&args, "-v"); 14050397Sobrien ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 14150397Sobrien } 14250397Sobrien debug_level++; 14350397Sobrien break; 14450397Sobrien case 'F': 145117395Skan case 'o': 14650397Sobrien addargs(&args, "-%c%s", ch, optarg); 14790075Sobrien break; 14890075Sobrien case '1': 14990075Sobrien sshver = 1; 15090075Sobrien if (sftp_server == NULL) 15190075Sobrien sftp_server = _PATH_SFTP_SERVER; 15290075Sobrien break; 15390075Sobrien case 's': 15490075Sobrien sftp_server = optarg; 15590075Sobrien break; 156117395Skan case 'S': 15790075Sobrien ssh_program = optarg; 15890075Sobrien break; 15990075Sobrien case 'b': 160117395Skan if (infile == stdin) { 161117395Skan infile = fopen(optarg, "r"); 162117395Skan if (infile == NULL) 163117395Skan fatal("%s (%s).", strerror(errno), optarg); 16450397Sobrien } else 16590075Sobrien fatal("Filename already specified."); 16690075Sobrien break; 16750397Sobrien case 'P': 16850397Sobrien sftp_direct = optarg; 16950397Sobrien break; 17050397Sobrien case 'B': 17150397Sobrien copy_buffer_len = strtol(optarg, &cp, 10); 17250397Sobrien if (copy_buffer_len == 0 || *cp != '\0') 17350397Sobrien fatal("Invalid buffer size \"%s\"", optarg); 17450397Sobrien break; 17550397Sobrien case 'R': 17650397Sobrien num_requests = strtol(optarg, &cp, 10); 17750397Sobrien if (num_requests == 0 || *cp != '\0') 17890075Sobrien fatal("Invalid number of requests \"%s\"", 17990075Sobrien optarg); 18090075Sobrien break; 18190075Sobrien case 'h': 18250397Sobrien default: 18350397Sobrien usage(); 18450397Sobrien } 18590075Sobrien } 18650397Sobrien 18750397Sobrien log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 18850397Sobrien 18950397Sobrien if (sftp_direct == NULL) { 19090075Sobrien if (optind == argc || argc > (optind + 2)) 19190075Sobrien usage(); 19290075Sobrien 19390075Sobrien userhost = xstrdup(argv[optind]); 19490075Sobrien file2 = argv[optind+1]; 19590075Sobrien 19690075Sobrien if ((cp = colon(userhost)) != NULL) { 19790075Sobrien *cp++ = '\0'; 19890075Sobrien file1 = cp; 19950397Sobrien } 20050397Sobrien 20150397Sobrien if ((host = strchr(userhost, '@')) == NULL) 20250397Sobrien host = userhost; 203117395Skan else { 20450397Sobrien *host++ = '\0'; 20552284Sobrien if (!userhost[0]) { 20652284Sobrien fprintf(stderr, "Missing username\n"); 20790075Sobrien usage(); 20852284Sobrien } 20952284Sobrien addargs(&args, "-l%s",userhost); 21052284Sobrien } 21152284Sobrien 21252284Sobrien host = cleanhostname(host); 21390075Sobrien if (!*host) { 21452284Sobrien fprintf(stderr, "Missing hostname\n"); 21590075Sobrien usage(); 21690075Sobrien } 21752284Sobrien 21890075Sobrien addargs(&args, "-oProtocol %d", sshver); 21952284Sobrien 22052284Sobrien /* no subsystem if the server-spec contains a '/' */ 22190075Sobrien if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 22290075Sobrien addargs(&args, "-s"); 22352284Sobrien 224117395Skan addargs(&args, "%s", host); 22552284Sobrien addargs(&args, "%s", (sftp_server != NULL ? 22652284Sobrien sftp_server : "sftp")); 22752284Sobrien args.list[0] = ssh_program; 22852284Sobrien 229117395Skan fprintf(stderr, "Connecting to %s...\n", host); 23052284Sobrien connect_to_server(ssh_program, args.list, &in, &out, 23152284Sobrien &sshpid); 23252284Sobrien } else { 23352284Sobrien args.list = NULL; 23452284Sobrien addargs(&args, "sftp-server"); 23552284Sobrien 23652284Sobrien fprintf(stderr, "Attaching to %s...\n", sftp_direct); 23790075Sobrien connect_to_server(sftp_direct, args.list, &in, &out, 23890075Sobrien &sshpid); 23952284Sobrien } 24052284Sobrien 24152284Sobrien interactive_loop(in, out, file1, file2); 24290075Sobrien 24390075Sobrien#if !defined(USE_PIPES) 24490075Sobrien shutdown(in, SHUT_RDWR); 24590075Sobrien shutdown(out, SHUT_RDWR); 24690075Sobrien#endif 24790075Sobrien 24890075Sobrien close(in); 24990075Sobrien close(out); 25090075Sobrien if (infile != stdin) 25190075Sobrien fclose(infile); 25290075Sobrien 25390075Sobrien while (waitpid(sshpid, NULL, 0) == -1) 25490075Sobrien if (errno != EINTR) 25590075Sobrien fatal("Couldn't wait for ssh process: %s", 25690075Sobrien strerror(errno)); 25790075Sobrien 25890075Sobrien exit(0); 25990075Sobrien} 26090075Sobrien