sftp.c revision 98937
1/* 2 * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25#include "includes.h" 26 27RCSID("$OpenBSD: sftp.c,v 1.29 2002/04/02 17:37:48 markus Exp $"); 28 29/* XXX: short-form remote directory listings (like 'ls -C') */ 30 31#include "buffer.h" 32#include "xmalloc.h" 33#include "log.h" 34#include "pathnames.h" 35#include "misc.h" 36 37#include "sftp.h" 38#include "sftp-common.h" 39#include "sftp-client.h" 40#include "sftp-int.h" 41 42#ifdef HAVE___PROGNAME 43extern char *__progname; 44#else 45char *__progname; 46#endif 47 48FILE* infile; 49size_t copy_buffer_len = 32768; 50size_t num_requests = 16; 51 52static void 53connect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 54{ 55 int c_in, c_out; 56#ifdef USE_PIPES 57 int pin[2], pout[2]; 58 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 59 fatal("pipe: %s", strerror(errno)); 60 *in = pin[0]; 61 *out = pout[1]; 62 c_in = pout[0]; 63 c_out = pin[1]; 64#else /* USE_PIPES */ 65 int inout[2]; 66 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 67 fatal("socketpair: %s", strerror(errno)); 68 *in = *out = inout[0]; 69 c_in = c_out = inout[1]; 70#endif /* USE_PIPES */ 71 72 if ((*sshpid = fork()) == -1) 73 fatal("fork: %s", strerror(errno)); 74 else if (*sshpid == 0) { 75 if ((dup2(c_in, STDIN_FILENO) == -1) || 76 (dup2(c_out, STDOUT_FILENO) == -1)) { 77 fprintf(stderr, "dup2: %s\n", strerror(errno)); 78 exit(1); 79 } 80 close(*in); 81 close(*out); 82 close(c_in); 83 close(c_out); 84 execv(path, args); 85 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 86 exit(1); 87 } 88 89 close(c_in); 90 close(c_out); 91} 92 93static void 94usage(void) 95{ 96 extern char *__progname; 97 98 fprintf(stderr, 99 "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 100 " [-F config] [-P direct server path] [-S program]\n" 101 " [user@]host[:file [file]]\n", __progname); 102 exit(1); 103} 104 105int 106main(int argc, char **argv) 107{ 108 int in, out, ch; 109 pid_t sshpid; 110 char *host, *userhost, *cp, *file2; 111 int debug_level = 0, sshver = 2; 112 char *file1 = NULL, *sftp_server = NULL; 113 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 114 LogLevel ll = SYSLOG_LEVEL_INFO; 115 arglist args; 116 extern int optind; 117 extern char *optarg; 118 119 __progname = get_progname(argv[0]); 120 args.list = NULL; 121 addargs(&args, "ssh"); /* overwritten with ssh_program */ 122 addargs(&args, "-oFallBackToRsh no"); 123 addargs(&args, "-oForwardX11 no"); 124 addargs(&args, "-oForwardAgent no"); 125 addargs(&args, "-oClearAllForwardings yes"); 126 ll = SYSLOG_LEVEL_INFO; 127 infile = stdin; /* Read from STDIN unless changed by -b */ 128 129 while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 130 switch (ch) { 131 case 'C': 132 addargs(&args, "-C"); 133 break; 134 case 'v': 135 if (debug_level < 3) { 136 addargs(&args, "-v"); 137 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 138 } 139 debug_level++; 140 break; 141 case 'F': 142 case 'o': 143 addargs(&args, "-%c%s", ch, optarg); 144 break; 145 case '1': 146 sshver = 1; 147 if (sftp_server == NULL) 148 sftp_server = _PATH_SFTP_SERVER; 149 break; 150 case 's': 151 sftp_server = optarg; 152 break; 153 case 'S': 154 ssh_program = optarg; 155 break; 156 case 'b': 157 if (infile == stdin) { 158 infile = fopen(optarg, "r"); 159 if (infile == NULL) 160 fatal("%s (%s).", strerror(errno), optarg); 161 } else 162 fatal("Filename already specified."); 163 break; 164 case 'P': 165 sftp_direct = optarg; 166 break; 167 case 'B': 168 copy_buffer_len = strtol(optarg, &cp, 10); 169 if (copy_buffer_len == 0 || *cp != '\0') 170 fatal("Invalid buffer size \"%s\"", optarg); 171 break; 172 case 'R': 173 num_requests = strtol(optarg, &cp, 10); 174 if (num_requests == 0 || *cp != '\0') 175 fatal("Invalid number of requests \"%s\"", 176 optarg); 177 break; 178 case 'h': 179 default: 180 usage(); 181 } 182 } 183 184 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 185 186 if (sftp_direct == NULL) { 187 if (optind == argc || argc > (optind + 2)) 188 usage(); 189 190 userhost = xstrdup(argv[optind]); 191 file2 = argv[optind+1]; 192 193 if ((cp = colon(userhost)) != NULL) { 194 *cp++ = '\0'; 195 file1 = cp; 196 } 197 198 if ((host = strchr(userhost, '@')) == NULL) 199 host = userhost; 200 else { 201 *host++ = '\0'; 202 if (!userhost[0]) { 203 fprintf(stderr, "Missing username\n"); 204 usage(); 205 } 206 addargs(&args, "-l%s",userhost); 207 } 208 209 host = cleanhostname(host); 210 if (!*host) { 211 fprintf(stderr, "Missing hostname\n"); 212 usage(); 213 } 214 215 addargs(&args, "-oProtocol %d", sshver); 216 217 /* no subsystem if the server-spec contains a '/' */ 218 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 219 addargs(&args, "-s"); 220 221 addargs(&args, "%s", host); 222 addargs(&args, "%s", (sftp_server != NULL ? 223 sftp_server : "sftp")); 224 args.list[0] = ssh_program; 225 226 fprintf(stderr, "Connecting to %s...\n", host); 227 connect_to_server(ssh_program, args.list, &in, &out, 228 &sshpid); 229 } else { 230 args.list = NULL; 231 addargs(&args, "sftp-server"); 232 233 fprintf(stderr, "Attaching to %s...\n", sftp_direct); 234 connect_to_server(sftp_direct, args.list, &in, &out, 235 &sshpid); 236 } 237 238 interactive_loop(in, out, file1, file2); 239 240#if !defined(USE_PIPES) 241 shutdown(in, SHUT_RDWR); 242 shutdown(out, SHUT_RDWR); 243#endif 244 245 close(in); 246 close(out); 247 if (infile != stdin) 248 fclose(infile); 249 250 while (waitpid(sshpid, NULL, 0) == -1) 251 if (errno != EINTR) 252 fatal("Couldn't wait for ssh process: %s", 253 strerror(errno)); 254 255 exit(0); 256} 257