sftp.c revision 98675
1184588Sdfr/* 2184588Sdfr * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 3184588Sdfr * 4184588Sdfr * Redistribution and use in source and binary forms, with or without 5184588Sdfr * modification, are permitted provided that the following conditions 6184588Sdfr * are met: 7184588Sdfr * 1. Redistributions of source code must retain the above copyright 8184588Sdfr * notice, this list of conditions and the following disclaimer. 9184588Sdfr * 2. Redistributions in binary form must reproduce the above copyright 10184588Sdfr * notice, this list of conditions and the following disclaimer in the 11184588Sdfr * documentation and/or other materials provided with the distribution. 12184588Sdfr * 13184588Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14184588Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15184588Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16184588Sdfr * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17184588Sdfr * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18184588Sdfr * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19184588Sdfr * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20184588Sdfr * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21184588Sdfr * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22184588Sdfr * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23184588Sdfr */ 24184588Sdfr 25184588Sdfr#include "includes.h" 26184588Sdfr 27184588SdfrRCSID("$OpenBSD: sftp.c,v 1.29 2002/04/02 17:37:48 markus Exp $"); 28184588Sdfr 29184588Sdfr/* XXX: short-form remote directory listings (like 'ls -C') */ 30184588Sdfr 31184588Sdfr#include "buffer.h" 32184588Sdfr#include "xmalloc.h" 33184588Sdfr#include "log.h" 34184588Sdfr#include "pathnames.h" 35184588Sdfr#include "misc.h" 36184588Sdfr 37184588Sdfr#include "sftp.h" 38184588Sdfr#include "sftp-common.h" 39184588Sdfr#include "sftp-client.h" 40184588Sdfr#include "sftp-int.h" 41184588Sdfr 42184588SdfrFILE* infile; 43184588Sdfrsize_t copy_buffer_len = 32768; 44184588Sdfrsize_t num_requests = 16; 45184588Sdfr 46184588Sdfrstatic void 47184588Sdfrconnect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 48184588Sdfr{ 49184588Sdfr int c_in, c_out; 50184588Sdfr#ifdef USE_PIPES 51184588Sdfr int pin[2], pout[2]; 52184588Sdfr if ((pipe(pin) == -1) || (pipe(pout) == -1)) 53184588Sdfr fatal("pipe: %s", strerror(errno)); 54184588Sdfr *in = pin[0]; 55184588Sdfr *out = pout[1]; 56184588Sdfr c_in = pout[0]; 57184588Sdfr c_out = pin[1]; 58184588Sdfr#else /* USE_PIPES */ 59184588Sdfr int inout[2]; 60184588Sdfr if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 61184588Sdfr fatal("socketpair: %s", strerror(errno)); 62184588Sdfr *in = *out = inout[0]; 63184588Sdfr c_in = c_out = inout[1]; 64184588Sdfr#endif /* USE_PIPES */ 65184588Sdfr 66184588Sdfr if ((*sshpid = fork()) == -1) 67184588Sdfr fatal("fork: %s", strerror(errno)); 68184588Sdfr else if (*sshpid == 0) { 69184588Sdfr if ((dup2(c_in, STDIN_FILENO) == -1) || 70184588Sdfr (dup2(c_out, STDOUT_FILENO) == -1)) { 71184588Sdfr fprintf(stderr, "dup2: %s\n", strerror(errno)); 72184588Sdfr exit(1); 73184588Sdfr } 74184588Sdfr close(*in); 75184588Sdfr close(*out); 76184588Sdfr close(c_in); 77184588Sdfr close(c_out); 78184588Sdfr execv(path, args); 79184588Sdfr fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 80184588Sdfr exit(1); 81184588Sdfr } 82184588Sdfr 83184588Sdfr close(c_in); 84184588Sdfr close(c_out); 85184588Sdfr} 86184588Sdfr 87184588Sdfrstatic void 88184588Sdfrusage(void) 89184588Sdfr{ 90184588Sdfr extern char *__progname; 91184588Sdfr 92184588Sdfr fprintf(stderr, 93184588Sdfr "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 94184588Sdfr " [-F config] [-P direct server path] [-S program]\n" 95184588Sdfr " [user@]host[:file [file]]\n", __progname); 96184588Sdfr exit(1); 97184588Sdfr} 98184588Sdfr 99184588Sdfrint 100184588Sdfrmain(int argc, char **argv) 101184588Sdfr{ 102184588Sdfr int in, out, ch; 103184588Sdfr pid_t sshpid; 104184588Sdfr char *host, *userhost, *cp, *file2; 105184588Sdfr int debug_level = 0, sshver = 2; 106184588Sdfr char *file1 = NULL, *sftp_server = NULL; 107184588Sdfr char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 108184588Sdfr LogLevel ll = SYSLOG_LEVEL_INFO; 109184588Sdfr arglist args; 110184588Sdfr extern int optind; 111184588Sdfr extern char *optarg; 112184588Sdfr 113184588Sdfr args.list = NULL; 114184588Sdfr addargs(&args, "ssh"); /* overwritten with ssh_program */ 115184588Sdfr addargs(&args, "-oFallBackToRsh no"); 116184588Sdfr addargs(&args, "-oForwardX11 no"); 117184588Sdfr addargs(&args, "-oForwardAgent no"); 118184588Sdfr addargs(&args, "-oClearAllForwardings yes"); 119184588Sdfr ll = SYSLOG_LEVEL_INFO; 120184588Sdfr infile = stdin; /* Read from STDIN unless changed by -b */ 121184588Sdfr 122184588Sdfr while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 123184588Sdfr switch (ch) { 124184588Sdfr case 'C': 125184588Sdfr addargs(&args, "-C"); 126184588Sdfr break; 127184588Sdfr case 'v': 128184588Sdfr if (debug_level < 3) { 129184588Sdfr addargs(&args, "-v"); 130184588Sdfr ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 131184588Sdfr } 132184588Sdfr debug_level++; 133184588Sdfr break; 134184588Sdfr case 'F': 135184588Sdfr case 'o': 136184588Sdfr addargs(&args, "-%c%s", ch, optarg); 137184588Sdfr break; 138184588Sdfr case '1': 139184588Sdfr sshver = 1; 140184588Sdfr if (sftp_server == NULL) 141184588Sdfr sftp_server = _PATH_SFTP_SERVER; 142184588Sdfr break; 143184588Sdfr case 's': 144184588Sdfr sftp_server = optarg; 145184588Sdfr break; 146184588Sdfr case 'S': 147184588Sdfr ssh_program = optarg; 148184588Sdfr break; 149184588Sdfr case 'b': 150184588Sdfr if (infile == stdin) { 151184588Sdfr infile = fopen(optarg, "r"); 152184588Sdfr if (infile == NULL) 153184588Sdfr fatal("%s (%s).", strerror(errno), optarg); 154184588Sdfr } else 155184588Sdfr fatal("Filename already specified."); 156184588Sdfr break; 157184588Sdfr case 'P': 158184588Sdfr sftp_direct = optarg; 159184588Sdfr break; 160184588Sdfr case 'B': 161184588Sdfr copy_buffer_len = strtol(optarg, &cp, 10); 162184588Sdfr if (copy_buffer_len == 0 || *cp != '\0') 163184588Sdfr fatal("Invalid buffer size \"%s\"", optarg); 164184588Sdfr break; 165184588Sdfr case 'R': 166184588Sdfr num_requests = strtol(optarg, &cp, 10); 167184588Sdfr if (num_requests == 0 || *cp != '\0') 168184588Sdfr fatal("Invalid number of requests \"%s\"", 169184588Sdfr optarg); 170184588Sdfr break; 171184588Sdfr case 'h': 172184588Sdfr default: 173184588Sdfr usage(); 174184588Sdfr } 175184588Sdfr } 176184588Sdfr 177184588Sdfr log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 178184588Sdfr 179184588Sdfr if (sftp_direct == NULL) { 180184588Sdfr if (optind == argc || argc > (optind + 2)) 181184588Sdfr usage(); 182184588Sdfr 183184588Sdfr userhost = xstrdup(argv[optind]); 184184588Sdfr file2 = argv[optind+1]; 185184588Sdfr 186184588Sdfr if ((cp = colon(userhost)) != NULL) { 187184588Sdfr *cp++ = '\0'; 188184588Sdfr file1 = cp; 189184588Sdfr } 190184588Sdfr 191184588Sdfr if ((host = strchr(userhost, '@')) == NULL) 192184588Sdfr host = userhost; 193184588Sdfr else { 194184588Sdfr *host++ = '\0'; 195184588Sdfr if (!userhost[0]) { 196184588Sdfr fprintf(stderr, "Missing username\n"); 197184588Sdfr usage(); 198184588Sdfr } 199184588Sdfr addargs(&args, "-l%s",userhost); 200184588Sdfr } 201184588Sdfr 202193066Sjamie host = cleanhostname(host); 203184588Sdfr if (!*host) { 204184588Sdfr fprintf(stderr, "Missing hostname\n"); 205184588Sdfr usage(); 206184588Sdfr } 207184588Sdfr 208184588Sdfr addargs(&args, "-oProtocol %d", sshver); 209184588Sdfr 210184588Sdfr /* no subsystem if the server-spec contains a '/' */ 211184588Sdfr if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 212184588Sdfr addargs(&args, "-s"); 213184588Sdfr 214184588Sdfr addargs(&args, "%s", host); 215184588Sdfr addargs(&args, "%s", (sftp_server != NULL ? 216184588Sdfr sftp_server : "sftp")); 217184588Sdfr args.list[0] = ssh_program; 218184588Sdfr 219184588Sdfr fprintf(stderr, "Connecting to %s...\n", host); 220184588Sdfr connect_to_server(ssh_program, args.list, &in, &out, 221184588Sdfr &sshpid); 222184588Sdfr } else { 223184588Sdfr args.list = NULL; 224184588Sdfr addargs(&args, "sftp-server"); 225184588Sdfr 226184588Sdfr fprintf(stderr, "Attaching to %s...\n", sftp_direct); 227184588Sdfr connect_to_server(sftp_direct, args.list, &in, &out, 228184588Sdfr &sshpid); 229184588Sdfr } 230193066Sjamie 231193066Sjamie interactive_loop(in, out, file1, file2); 232184588Sdfr 233184588Sdfr close(in); 234184588Sdfr close(out); 235184588Sdfr if (infile != stdin) 236184588Sdfr fclose(infile); 237184588Sdfr 238184588Sdfr while (waitpid(sshpid, NULL, 0) == -1) 239184588Sdfr if (errno != EINTR) 240184588Sdfr fatal("Couldn't wait for ssh process: %s", 241184588Sdfr strerror(errno)); 242184588Sdfr 243184588Sdfr exit(0); 244184588Sdfr} 245184588Sdfr