sftp.c revision 98937
176259Sgreen/* 292555Sdes * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 376259Sgreen * 476259Sgreen * Redistribution and use in source and binary forms, with or without 576259Sgreen * modification, are permitted provided that the following conditions 676259Sgreen * are met: 776259Sgreen * 1. Redistributions of source code must retain the above copyright 876259Sgreen * notice, this list of conditions and the following disclaimer. 976259Sgreen * 2. Redistributions in binary form must reproduce the above copyright 1076259Sgreen * notice, this list of conditions and the following disclaimer in the 1176259Sgreen * documentation and/or other materials provided with the distribution. 1276259Sgreen * 1376259Sgreen * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1476259Sgreen * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1576259Sgreen * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1676259Sgreen * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1776259Sgreen * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1876259Sgreen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1976259Sgreen * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2076259Sgreen * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2176259Sgreen * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2276259Sgreen * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2376259Sgreen */ 2476259Sgreen 2576259Sgreen#include "includes.h" 2676259Sgreen 2798675SdesRCSID("$OpenBSD: sftp.c,v 1.29 2002/04/02 17:37:48 markus Exp $"); 2876259Sgreen 2976259Sgreen/* XXX: short-form remote directory listings (like 'ls -C') */ 3076259Sgreen 3176259Sgreen#include "buffer.h" 3276259Sgreen#include "xmalloc.h" 3376259Sgreen#include "log.h" 3476259Sgreen#include "pathnames.h" 3592555Sdes#include "misc.h" 3676259Sgreen 3776259Sgreen#include "sftp.h" 3876259Sgreen#include "sftp-common.h" 3976259Sgreen#include "sftp-client.h" 4076259Sgreen#include "sftp-int.h" 4176259Sgreen 4298937Sdes#ifdef HAVE___PROGNAME 4398937Sdesextern char *__progname; 4498937Sdes#else 4598937Sdeschar *__progname; 4698937Sdes#endif 4798937Sdes 4876259SgreenFILE* infile; 4992555Sdessize_t copy_buffer_len = 32768; 5092555Sdessize_t num_requests = 16; 5176259Sgreen 5292555Sdesstatic void 5392555Sdesconnect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 5476259Sgreen{ 5576259Sgreen int c_in, c_out; 5676259Sgreen#ifdef USE_PIPES 5776259Sgreen int pin[2], pout[2]; 5876259Sgreen if ((pipe(pin) == -1) || (pipe(pout) == -1)) 5976259Sgreen fatal("pipe: %s", strerror(errno)); 6076259Sgreen *in = pin[0]; 6176259Sgreen *out = pout[1]; 6276259Sgreen c_in = pout[0]; 6376259Sgreen c_out = pin[1]; 6476259Sgreen#else /* USE_PIPES */ 6576259Sgreen int inout[2]; 6676259Sgreen if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 6776259Sgreen fatal("socketpair: %s", strerror(errno)); 6876259Sgreen *in = *out = inout[0]; 6976259Sgreen c_in = c_out = inout[1]; 7076259Sgreen#endif /* USE_PIPES */ 7176259Sgreen 7276259Sgreen if ((*sshpid = fork()) == -1) 7376259Sgreen fatal("fork: %s", strerror(errno)); 7476259Sgreen else if (*sshpid == 0) { 7576259Sgreen if ((dup2(c_in, STDIN_FILENO) == -1) || 7676259Sgreen (dup2(c_out, STDOUT_FILENO) == -1)) { 7776259Sgreen fprintf(stderr, "dup2: %s\n", strerror(errno)); 7876259Sgreen exit(1); 7976259Sgreen } 8076259Sgreen close(*in); 8176259Sgreen close(*out); 8276259Sgreen close(c_in); 8376259Sgreen close(c_out); 8492555Sdes execv(path, args); 8592555Sdes fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 8676259Sgreen exit(1); 8776259Sgreen } 8876259Sgreen 8976259Sgreen close(c_in); 9076259Sgreen close(c_out); 9176259Sgreen} 9276259Sgreen 9392555Sdesstatic void 9476259Sgreenusage(void) 9576259Sgreen{ 9692555Sdes extern char *__progname; 9798675Sdes 9892555Sdes fprintf(stderr, 9992555Sdes "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 10092555Sdes " [-F config] [-P direct server path] [-S program]\n" 10192555Sdes " [user@]host[:file [file]]\n", __progname); 10276259Sgreen exit(1); 10376259Sgreen} 10476259Sgreen 10576259Sgreenint 10676259Sgreenmain(int argc, char **argv) 10776259Sgreen{ 10892555Sdes int in, out, ch; 10976259Sgreen pid_t sshpid; 11076259Sgreen char *host, *userhost, *cp, *file2; 11192555Sdes int debug_level = 0, sshver = 2; 11292555Sdes char *file1 = NULL, *sftp_server = NULL; 11392555Sdes char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 11492555Sdes LogLevel ll = SYSLOG_LEVEL_INFO; 11592555Sdes arglist args; 11676259Sgreen extern int optind; 11776259Sgreen extern char *optarg; 11876259Sgreen 11998937Sdes __progname = get_progname(argv[0]); 12092555Sdes args.list = NULL; 12192555Sdes addargs(&args, "ssh"); /* overwritten with ssh_program */ 12292555Sdes addargs(&args, "-oFallBackToRsh no"); 12392555Sdes addargs(&args, "-oForwardX11 no"); 12492555Sdes addargs(&args, "-oForwardAgent no"); 12592555Sdes addargs(&args, "-oClearAllForwardings yes"); 12692555Sdes ll = SYSLOG_LEVEL_INFO; 12776259Sgreen infile = stdin; /* Read from STDIN unless changed by -b */ 12876259Sgreen 12992555Sdes while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 13076259Sgreen switch (ch) { 13176259Sgreen case 'C': 13292555Sdes addargs(&args, "-C"); 13376259Sgreen break; 13476259Sgreen case 'v': 13592555Sdes if (debug_level < 3) { 13692555Sdes addargs(&args, "-v"); 13792555Sdes ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 13892555Sdes } 13992555Sdes debug_level++; 14076259Sgreen break; 14192555Sdes case 'F': 14276259Sgreen case 'o': 14392555Sdes addargs(&args, "-%c%s", ch, optarg); 14476259Sgreen break; 14576259Sgreen case '1': 14692555Sdes sshver = 1; 14776259Sgreen if (sftp_server == NULL) 14876259Sgreen sftp_server = _PATH_SFTP_SERVER; 14976259Sgreen break; 15076259Sgreen case 's': 15176259Sgreen sftp_server = optarg; 15276259Sgreen break; 15376259Sgreen case 'S': 15476259Sgreen ssh_program = optarg; 15576259Sgreen break; 15676259Sgreen case 'b': 15776259Sgreen if (infile == stdin) { 15876259Sgreen infile = fopen(optarg, "r"); 15976259Sgreen if (infile == NULL) 16076259Sgreen fatal("%s (%s).", strerror(errno), optarg); 16176259Sgreen } else 16276259Sgreen fatal("Filename already specified."); 16376259Sgreen break; 16492555Sdes case 'P': 16592555Sdes sftp_direct = optarg; 16692555Sdes break; 16792555Sdes case 'B': 16892555Sdes copy_buffer_len = strtol(optarg, &cp, 10); 16992555Sdes if (copy_buffer_len == 0 || *cp != '\0') 17092555Sdes fatal("Invalid buffer size \"%s\"", optarg); 17192555Sdes break; 17292555Sdes case 'R': 17392555Sdes num_requests = strtol(optarg, &cp, 10); 17492555Sdes if (num_requests == 0 || *cp != '\0') 17598675Sdes fatal("Invalid number of requests \"%s\"", 17692555Sdes optarg); 17792555Sdes break; 17876259Sgreen case 'h': 17976259Sgreen default: 18076259Sgreen usage(); 18176259Sgreen } 18276259Sgreen } 18376259Sgreen 18498675Sdes log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 18598675Sdes 18692555Sdes if (sftp_direct == NULL) { 18792555Sdes if (optind == argc || argc > (optind + 2)) 18892555Sdes usage(); 18976259Sgreen 19092555Sdes userhost = xstrdup(argv[optind]); 19192555Sdes file2 = argv[optind+1]; 19276259Sgreen 19392555Sdes if ((cp = colon(userhost)) != NULL) { 19492555Sdes *cp++ = '\0'; 19592555Sdes file1 = cp; 19692555Sdes } 19776259Sgreen 19892555Sdes if ((host = strchr(userhost, '@')) == NULL) 19992555Sdes host = userhost; 20092555Sdes else { 20192555Sdes *host++ = '\0'; 20292555Sdes if (!userhost[0]) { 20392555Sdes fprintf(stderr, "Missing username\n"); 20492555Sdes usage(); 20592555Sdes } 20692555Sdes addargs(&args, "-l%s",userhost); 20792555Sdes } 20892555Sdes 20992555Sdes host = cleanhostname(host); 21092555Sdes if (!*host) { 21192555Sdes fprintf(stderr, "Missing hostname\n"); 21276259Sgreen usage(); 21376259Sgreen } 21476259Sgreen 21592555Sdes addargs(&args, "-oProtocol %d", sshver); 21676259Sgreen 21792555Sdes /* no subsystem if the server-spec contains a '/' */ 21892555Sdes if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 21992555Sdes addargs(&args, "-s"); 22076259Sgreen 22192555Sdes addargs(&args, "%s", host); 22298675Sdes addargs(&args, "%s", (sftp_server != NULL ? 22392555Sdes sftp_server : "sftp")); 22492555Sdes args.list[0] = ssh_program; 22576259Sgreen 22692555Sdes fprintf(stderr, "Connecting to %s...\n", host); 22798675Sdes connect_to_server(ssh_program, args.list, &in, &out, 22892555Sdes &sshpid); 22992555Sdes } else { 23092555Sdes args.list = NULL; 23192555Sdes addargs(&args, "sftp-server"); 23276259Sgreen 23392555Sdes fprintf(stderr, "Attaching to %s...\n", sftp_direct); 23498675Sdes connect_to_server(sftp_direct, args.list, &in, &out, 23592555Sdes &sshpid); 23692555Sdes } 23776259Sgreen 23876259Sgreen interactive_loop(in, out, file1, file2); 23976259Sgreen 24098937Sdes#if !defined(USE_PIPES) 24198937Sdes shutdown(in, SHUT_RDWR); 24298937Sdes shutdown(out, SHUT_RDWR); 24398937Sdes#endif 24498937Sdes 24576259Sgreen close(in); 24676259Sgreen close(out); 24776259Sgreen if (infile != stdin) 24876259Sgreen fclose(infile); 24976259Sgreen 25098675Sdes while (waitpid(sshpid, NULL, 0) == -1) 25198675Sdes if (errno != EINTR) 25298675Sdes fatal("Couldn't wait for ssh process: %s", 25398675Sdes strerror(errno)); 25476259Sgreen 25576259Sgreen exit(0); 25676259Sgreen} 257