sftp.c revision 113908
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 27113908SdesRCSID("$OpenBSD: sftp.c,v 1.34 2003/01/10 08:19:07 fgsch 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 52113908Sdesextern int showprogress; 53113908Sdes 5492555Sdesstatic void 5592555Sdesconnect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 5676259Sgreen{ 5776259Sgreen int c_in, c_out; 5899060Sdes 5976259Sgreen#ifdef USE_PIPES 6076259Sgreen int pin[2], pout[2]; 6199060Sdes 6276259Sgreen if ((pipe(pin) == -1) || (pipe(pout) == -1)) 6376259Sgreen fatal("pipe: %s", strerror(errno)); 6476259Sgreen *in = pin[0]; 6576259Sgreen *out = pout[1]; 6676259Sgreen c_in = pout[0]; 6776259Sgreen c_out = pin[1]; 6876259Sgreen#else /* USE_PIPES */ 6976259Sgreen int inout[2]; 7099060Sdes 7176259Sgreen if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 7276259Sgreen fatal("socketpair: %s", strerror(errno)); 7376259Sgreen *in = *out = inout[0]; 7476259Sgreen c_in = c_out = inout[1]; 7576259Sgreen#endif /* USE_PIPES */ 7676259Sgreen 7776259Sgreen if ((*sshpid = fork()) == -1) 7876259Sgreen fatal("fork: %s", strerror(errno)); 7976259Sgreen else if (*sshpid == 0) { 8076259Sgreen if ((dup2(c_in, STDIN_FILENO) == -1) || 8176259Sgreen (dup2(c_out, STDOUT_FILENO) == -1)) { 8276259Sgreen fprintf(stderr, "dup2: %s\n", strerror(errno)); 8376259Sgreen exit(1); 8476259Sgreen } 8576259Sgreen close(*in); 8676259Sgreen close(*out); 8776259Sgreen close(c_in); 8876259Sgreen close(c_out); 8992555Sdes execv(path, args); 9092555Sdes fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 9176259Sgreen exit(1); 9276259Sgreen } 9376259Sgreen 9476259Sgreen close(c_in); 9576259Sgreen close(c_out); 9676259Sgreen} 9776259Sgreen 9892555Sdesstatic void 9976259Sgreenusage(void) 10076259Sgreen{ 10192555Sdes extern char *__progname; 10298675Sdes 10392555Sdes fprintf(stderr, 10492555Sdes "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 10592555Sdes " [-F config] [-P direct server path] [-S program]\n" 10692555Sdes " [user@]host[:file [file]]\n", __progname); 10776259Sgreen exit(1); 10876259Sgreen} 10976259Sgreen 11076259Sgreenint 11176259Sgreenmain(int argc, char **argv) 11276259Sgreen{ 113113908Sdes int in, out, ch, err; 11476259Sgreen pid_t sshpid; 11576259Sgreen char *host, *userhost, *cp, *file2; 11692555Sdes int debug_level = 0, sshver = 2; 11792555Sdes char *file1 = NULL, *sftp_server = NULL; 11892555Sdes char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 11992555Sdes LogLevel ll = SYSLOG_LEVEL_INFO; 12092555Sdes arglist args; 12176259Sgreen extern int optind; 12276259Sgreen extern char *optarg; 12376259Sgreen 12498937Sdes __progname = get_progname(argv[0]); 12592555Sdes args.list = NULL; 12692555Sdes addargs(&args, "ssh"); /* overwritten with ssh_program */ 12792555Sdes addargs(&args, "-oForwardX11 no"); 12892555Sdes addargs(&args, "-oForwardAgent no"); 12992555Sdes addargs(&args, "-oClearAllForwardings yes"); 13092555Sdes ll = SYSLOG_LEVEL_INFO; 13176259Sgreen infile = stdin; /* Read from STDIN unless changed by -b */ 13276259Sgreen 13392555Sdes while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 13476259Sgreen switch (ch) { 13576259Sgreen case 'C': 13692555Sdes addargs(&args, "-C"); 13776259Sgreen break; 13876259Sgreen case 'v': 13992555Sdes if (debug_level < 3) { 14092555Sdes addargs(&args, "-v"); 14192555Sdes ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 14292555Sdes } 14392555Sdes debug_level++; 14476259Sgreen break; 14592555Sdes case 'F': 14676259Sgreen case 'o': 14792555Sdes addargs(&args, "-%c%s", ch, optarg); 14876259Sgreen break; 14976259Sgreen case '1': 15092555Sdes sshver = 1; 15176259Sgreen if (sftp_server == NULL) 15276259Sgreen sftp_server = _PATH_SFTP_SERVER; 15376259Sgreen break; 15476259Sgreen case 's': 15576259Sgreen sftp_server = optarg; 15676259Sgreen break; 15776259Sgreen case 'S': 15876259Sgreen ssh_program = optarg; 15976259Sgreen break; 16076259Sgreen case 'b': 16176259Sgreen if (infile == stdin) { 16276259Sgreen infile = fopen(optarg, "r"); 16376259Sgreen if (infile == NULL) 16476259Sgreen fatal("%s (%s).", strerror(errno), optarg); 16576259Sgreen } else 16676259Sgreen fatal("Filename already specified."); 167113908Sdes showprogress = 0; 16876259Sgreen break; 16992555Sdes case 'P': 17092555Sdes sftp_direct = optarg; 17192555Sdes break; 17292555Sdes case 'B': 17392555Sdes copy_buffer_len = strtol(optarg, &cp, 10); 17492555Sdes if (copy_buffer_len == 0 || *cp != '\0') 17592555Sdes fatal("Invalid buffer size \"%s\"", optarg); 17692555Sdes break; 17792555Sdes case 'R': 17892555Sdes num_requests = strtol(optarg, &cp, 10); 17992555Sdes if (num_requests == 0 || *cp != '\0') 18098675Sdes fatal("Invalid number of requests \"%s\"", 18192555Sdes optarg); 18292555Sdes break; 18376259Sgreen case 'h': 18476259Sgreen default: 18576259Sgreen usage(); 18676259Sgreen } 18776259Sgreen } 18876259Sgreen 18998675Sdes log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 19098675Sdes 19192555Sdes if (sftp_direct == NULL) { 19292555Sdes if (optind == argc || argc > (optind + 2)) 19392555Sdes usage(); 19476259Sgreen 19592555Sdes userhost = xstrdup(argv[optind]); 19692555Sdes file2 = argv[optind+1]; 19776259Sgreen 19892555Sdes if ((cp = colon(userhost)) != NULL) { 19992555Sdes *cp++ = '\0'; 20092555Sdes file1 = cp; 20192555Sdes } 20276259Sgreen 203113908Sdes if ((host = strrchr(userhost, '@')) == NULL) 20492555Sdes host = userhost; 20592555Sdes else { 20692555Sdes *host++ = '\0'; 20792555Sdes if (!userhost[0]) { 20892555Sdes fprintf(stderr, "Missing username\n"); 20992555Sdes usage(); 21092555Sdes } 21192555Sdes addargs(&args, "-l%s",userhost); 21292555Sdes } 21392555Sdes 21492555Sdes host = cleanhostname(host); 21592555Sdes if (!*host) { 21692555Sdes fprintf(stderr, "Missing hostname\n"); 21776259Sgreen usage(); 21876259Sgreen } 21976259Sgreen 22092555Sdes addargs(&args, "-oProtocol %d", sshver); 22176259Sgreen 22292555Sdes /* no subsystem if the server-spec contains a '/' */ 22392555Sdes if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 22492555Sdes addargs(&args, "-s"); 22576259Sgreen 22692555Sdes addargs(&args, "%s", host); 22798675Sdes addargs(&args, "%s", (sftp_server != NULL ? 22892555Sdes sftp_server : "sftp")); 22992555Sdes args.list[0] = ssh_program; 23076259Sgreen 23192555Sdes fprintf(stderr, "Connecting to %s...\n", host); 23298675Sdes connect_to_server(ssh_program, args.list, &in, &out, 23392555Sdes &sshpid); 23492555Sdes } else { 23592555Sdes args.list = NULL; 23692555Sdes addargs(&args, "sftp-server"); 23776259Sgreen 23892555Sdes fprintf(stderr, "Attaching to %s...\n", sftp_direct); 23998675Sdes connect_to_server(sftp_direct, args.list, &in, &out, 24092555Sdes &sshpid); 24192555Sdes } 24276259Sgreen 243113908Sdes err = interactive_loop(in, out, file1, file2); 24476259Sgreen 24598937Sdes#if !defined(USE_PIPES) 24698937Sdes shutdown(in, SHUT_RDWR); 24798937Sdes shutdown(out, SHUT_RDWR); 24898937Sdes#endif 24998937Sdes 25076259Sgreen close(in); 25176259Sgreen close(out); 25276259Sgreen if (infile != stdin) 25376259Sgreen fclose(infile); 25476259Sgreen 25598675Sdes while (waitpid(sshpid, NULL, 0) == -1) 25698675Sdes if (errno != EINTR) 25798675Sdes fatal("Couldn't wait for ssh process: %s", 25898675Sdes strerror(errno)); 25976259Sgreen 260113908Sdes exit(err == 0 ? 0 : 1); 26176259Sgreen} 262