sftp.c revision 92555
179455Sobrien/* 279455Sobrien * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 379455Sobrien * 479455Sobrien * Redistribution and use in source and binary forms, with or without 579455Sobrien * modification, are permitted provided that the following conditions 679455Sobrien * are met: 779455Sobrien * 1. Redistributions of source code must retain the above copyright 879455Sobrien * notice, this list of conditions and the following disclaimer. 979455Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1079455Sobrien * notice, this list of conditions and the following disclaimer in the 1179455Sobrien * documentation and/or other materials provided with the distribution. 1279455Sobrien * 1379455Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1479455Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1579455Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1679455Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1779455Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1879455Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1979455Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2079455Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2179455Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2279455Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2379455Sobrien */ 2479455Sobrien 2579455Sobrien#include "includes.h" 2679455Sobrien 2779455SobrienRCSID("$OpenBSD: sftp.c,v 1.26 2002/02/12 12:32:27 djm Exp $"); 2879455Sobrien 29128463Stjr/* XXX: short-form remote directory listings (like 'ls -C') */ 3079455Sobrien 3179455Sobrien#include "buffer.h" 3279455Sobrien#include "xmalloc.h" 3379455Sobrien#include "log.h" 3479455Sobrien#include "pathnames.h" 3579455Sobrien#include "misc.h" 3679455Sobrien 3779455Sobrien#include "sftp.h" 3879455Sobrien#include "sftp-common.h" 3979455Sobrien#include "sftp-client.h" 4079455Sobrien#include "sftp-int.h" 4179455Sobrien 4279455SobrienFILE* infile; 43203872Skibsize_t copy_buffer_len = 32768; 4479455Sobriensize_t num_requests = 16; 4579455Sobrien 4679455Sobrienstatic void 4779455Sobrienconnect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 4879455Sobrien{ 49203872Skib int c_in, c_out; 5079455Sobrien#ifdef USE_PIPES 51203872Skib int pin[2], pout[2]; 5279455Sobrien if ((pipe(pin) == -1) || (pipe(pout) == -1)) 5379455Sobrien fatal("pipe: %s", strerror(errno)); 5479455Sobrien *in = pin[0]; 5579455Sobrien *out = pout[1]; 5679455Sobrien c_in = pout[0]; 5779455Sobrien c_out = pin[1]; 5879455Sobrien#else /* USE_PIPES */ 5979455Sobrien int inout[2]; 6079455Sobrien if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 6179455Sobrien fatal("socketpair: %s", strerror(errno)); 6279455Sobrien *in = *out = inout[0]; 6379455Sobrien c_in = c_out = inout[1]; 6479455Sobrien#endif /* USE_PIPES */ 6579455Sobrien 6679455Sobrien if ((*sshpid = fork()) == -1) 6779455Sobrien fatal("fork: %s", strerror(errno)); 6879455Sobrien else if (*sshpid == 0) { 6979455Sobrien if ((dup2(c_in, STDIN_FILENO) == -1) || 7079455Sobrien (dup2(c_out, STDOUT_FILENO) == -1)) { 7179455Sobrien fprintf(stderr, "dup2: %s\n", strerror(errno)); 7279455Sobrien exit(1); 7379455Sobrien } 7479455Sobrien close(*in); 7579455Sobrien close(*out); 7679455Sobrien close(c_in); 7779455Sobrien close(c_out); 7879455Sobrien execv(path, args); 7979455Sobrien fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 8079455Sobrien exit(1); 8179455Sobrien } 8279455Sobrien 8379455Sobrien close(c_in); 8479455Sobrien close(c_out); 8579455Sobrien} 8679455Sobrien 8779455Sobrienstatic void 8879455Sobrienusage(void) 8979455Sobrien{ 9079455Sobrien extern char *__progname; 91102231Strhodes 9279455Sobrien fprintf(stderr, 9379455Sobrien "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 9479455Sobrien " [-F config] [-P direct server path] [-S program]\n" 9579455Sobrien " [user@]host[:file [file]]\n", __progname); 9679455Sobrien exit(1); 9779455Sobrien} 9879455Sobrien 9979455Sobrienint 10079455Sobrienmain(int argc, char **argv) 10179455Sobrien{ 10279455Sobrien int in, out, ch; 10379455Sobrien pid_t sshpid; 10479455Sobrien char *host, *userhost, *cp, *file2; 10579455Sobrien int debug_level = 0, sshver = 2; 10679455Sobrien char *file1 = NULL, *sftp_server = NULL; 10779455Sobrien char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 10879455Sobrien LogLevel ll = SYSLOG_LEVEL_INFO; 10979455Sobrien arglist args; 11079455Sobrien extern int optind; 11179455Sobrien extern char *optarg; 11279455Sobrien 11379455Sobrien args.list = NULL; 11479455Sobrien addargs(&args, "ssh"); /* overwritten with ssh_program */ 11579455Sobrien addargs(&args, "-oFallBackToRsh no"); 11679455Sobrien addargs(&args, "-oForwardX11 no"); 117175853Syar addargs(&args, "-oForwardAgent no"); 118175853Syar addargs(&args, "-oClearAllForwardings yes"); 11979455Sobrien ll = SYSLOG_LEVEL_INFO; 12079455Sobrien infile = stdin; /* Read from STDIN unless changed by -b */ 12179455Sobrien 12279455Sobrien while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 12379455Sobrien switch (ch) { 12479455Sobrien case 'C': 12579455Sobrien addargs(&args, "-C"); 12679455Sobrien break; 12779455Sobrien case 'v': 12879455Sobrien if (debug_level < 3) { 12979455Sobrien addargs(&args, "-v"); 13079455Sobrien ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 13179455Sobrien } 13279455Sobrien debug_level++; 13379455Sobrien break; 13479455Sobrien case 'F': 13579455Sobrien case 'o': 13679455Sobrien addargs(&args, "-%c%s", ch, optarg); 13779455Sobrien break; 13879455Sobrien case '1': 13979455Sobrien sshver = 1; 14079455Sobrien if (sftp_server == NULL) 14179455Sobrien sftp_server = _PATH_SFTP_SERVER; 14279455Sobrien break; 14379455Sobrien case 's': 14479455Sobrien sftp_server = optarg; 14579455Sobrien break; 14679455Sobrien case 'S': 14779455Sobrien ssh_program = optarg; 14879455Sobrien break; 14979455Sobrien case 'b': 15079455Sobrien if (infile == stdin) { 15179455Sobrien infile = fopen(optarg, "r"); 15279455Sobrien if (infile == NULL) 153128463Stjr fatal("%s (%s).", strerror(errno), optarg); 154128463Stjr } else 155203872Skib fatal("Filename already specified."); 156203872Skib break; 157203872Skib case 'P': 158203872Skib sftp_direct = optarg; 159203872Skib break; 160203872Skib case 'B': 161203872Skib copy_buffer_len = strtol(optarg, &cp, 10); 162203872Skib if (copy_buffer_len == 0 || *cp != '\0') 163203872Skib fatal("Invalid buffer size \"%s\"", optarg); 164203872Skib break; 165203872Skib case 'R': 166203872Skib num_requests = strtol(optarg, &cp, 10); 167203872Skib if (num_requests == 0 || *cp != '\0') 168203872Skib fatal("Invalid number of requests \"%s\"", 169203872Skib optarg); 170203872Skib break; 17179455Sobrien case 'h': 17279455Sobrien default: 17379455Sobrien usage(); 17479455Sobrien } 17579455Sobrien } 17679455Sobrien 17779455Sobrien if (sftp_direct == NULL) { 17879455Sobrien if (optind == argc || argc > (optind + 2)) 17979455Sobrien usage(); 18079455Sobrien 18179455Sobrien userhost = xstrdup(argv[optind]); 18279455Sobrien file2 = argv[optind+1]; 18379455Sobrien 18479455Sobrien if ((cp = colon(userhost)) != NULL) { 18579455Sobrien *cp++ = '\0'; 18679455Sobrien file1 = cp; 18779455Sobrien } 18879455Sobrien 18979455Sobrien if ((host = strchr(userhost, '@')) == NULL) 19079455Sobrien host = userhost; 19179455Sobrien else { 19279455Sobrien *host++ = '\0'; 19379455Sobrien if (!userhost[0]) { 19479455Sobrien fprintf(stderr, "Missing username\n"); 19579455Sobrien usage(); 19679455Sobrien } 19779455Sobrien addargs(&args, "-l%s",userhost); 19879455Sobrien } 19979455Sobrien 20079455Sobrien host = cleanhostname(host); 20179455Sobrien if (!*host) { 20279455Sobrien fprintf(stderr, "Missing hostname\n"); 20379455Sobrien usage(); 20479455Sobrien } 20579455Sobrien 20679455Sobrien log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 20779455Sobrien addargs(&args, "-oProtocol %d", sshver); 20879455Sobrien 20979455Sobrien /* no subsystem if the server-spec contains a '/' */ 21079455Sobrien if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 21179455Sobrien addargs(&args, "-s"); 21279455Sobrien 21379455Sobrien addargs(&args, "%s", host); 21479455Sobrien addargs(&args, "%s", (sftp_server != NULL ? 21579455Sobrien sftp_server : "sftp")); 21679455Sobrien args.list[0] = ssh_program; 21779455Sobrien 21879455Sobrien fprintf(stderr, "Connecting to %s...\n", host); 21979455Sobrien connect_to_server(ssh_program, args.list, &in, &out, 22079455Sobrien &sshpid); 22179455Sobrien } else { 22279455Sobrien args.list = NULL; 22379455Sobrien addargs(&args, "sftp-server"); 22479455Sobrien 22579455Sobrien fprintf(stderr, "Attaching to %s...\n", sftp_direct); 22679455Sobrien connect_to_server(sftp_direct, args.list, &in, &out, 22779455Sobrien &sshpid); 22879455Sobrien } 22979455Sobrien 23079455Sobrien interactive_loop(in, out, file1, file2); 23179455Sobrien 23279455Sobrien close(in); 23379455Sobrien close(out); 234203872Skib if (infile != stdin) 23579455Sobrien fclose(infile); 23679455Sobrien 23779455Sobrien if (waitpid(sshpid, NULL, 0) == -1) 23879455Sobrien fatal("Couldn't wait for ssh process: %s", strerror(errno)); 23979455Sobrien 24079455Sobrien exit(0); 24179455Sobrien} 24279455Sobrien