sftp.c revision 76259
167967Sasmodai/* 214053Smpp * Copyright (c) 2001 Damien Miller. All rights reserved. 314053Smpp * 414053Smpp * Redistribution and use in source and binary forms, with or without 514053Smpp * modification, are permitted provided that the following conditions 614053Smpp * are met: 714053Smpp * 1. Redistributions of source code must retain the above copyright 814053Smpp * notice, this list of conditions and the following disclaimer. 914053Smpp * 2. Redistributions in binary form must reproduce the above copyright 1014053Smpp * notice, this list of conditions and the following disclaimer in the 1114053Smpp * documentation and/or other materials provided with the distribution. 1214053Smpp * 1314053Smpp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1414053Smpp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1514053Smpp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1614053Smpp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1714053Smpp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1814053Smpp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1914053Smpp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2014053Smpp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2114053Smpp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2214053Smpp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2314053Smpp */ 2414053Smpp 2514053Smpp#include "includes.h" 2614053Smpp 2714053SmppRCSID("$OpenBSD: sftp.c,v 1.15 2001/04/16 02:31:44 mouring Exp $"); 2814053Smpp 2914053Smpp/* XXX: commandline mode */ 3014053Smpp/* XXX: short-form remote directory listings (like 'ls -C') */ 3150476Speter 3231370Sbde#include "buffer.h" 3314053Smpp#include "xmalloc.h" 34195656Strasz#include "log.h" 35195656Strasz#include "pathnames.h" 3679531Sru 3714053Smpp#include "sftp.h" 3814053Smpp#include "sftp-common.h" 3914053Smpp#include "sftp-client.h" 4059460Sphantom#include "sftp-int.h" 4159460Sphantom 4214053Smpp#include "scp-common.h" 4384306Sru 4484306Sruint use_ssh1 = 0; 4584306Sruchar *ssh_program = _PATH_SSH_PROGRAM; 4614053Smppchar *sftp_server = NULL; 4714053SmppFILE* infile; 4814053Smpp 4967967Sasmodaivoid 5014053Smppconnect_to_server(char **args, int *in, int *out, pid_t *sshpid) 5114053Smpp{ 5214053Smpp int c_in, c_out; 5314053Smpp#ifdef USE_PIPES 5414053Smpp int pin[2], pout[2]; 5514053Smpp if ((pipe(pin) == -1) || (pipe(pout) == -1)) 5614053Smpp fatal("pipe: %s", strerror(errno)); 5714053Smpp *in = pin[0]; 5814053Smpp *out = pout[1]; 5914053Smpp c_in = pout[0]; 6024093Smpp c_out = pin[1]; 6114053Smpp#else /* USE_PIPES */ 6214053Smpp int inout[2]; 6314053Smpp if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 6424093Smpp fatal("socketpair: %s", strerror(errno)); 6524093Smpp *in = *out = inout[0]; 6624093Smpp c_in = c_out = inout[1]; 6714053Smpp#endif /* USE_PIPES */ 6814053Smpp 6914053Smpp if ((*sshpid = fork()) == -1) 7014053Smpp fatal("fork: %s", strerror(errno)); 7114053Smpp else if (*sshpid == 0) { 72108087Sru if ((dup2(c_in, STDIN_FILENO) == -1) || 7314053Smpp (dup2(c_out, STDOUT_FILENO) == -1)) { 74108087Sru fprintf(stderr, "dup2: %s\n", strerror(errno)); 75131504Sru exit(1); 76131504Sru } 7714053Smpp close(*in); 7814053Smpp close(*out); 7914053Smpp close(c_in); 80108087Sru close(c_out); 8114053Smpp execv(ssh_program, args); 82108087Sru fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno)); 83131504Sru exit(1); 84131504Sru } 8514053Smpp 86108087Sru close(c_in); 8714053Smpp close(c_out); 88108087Sru} 89131504Sru 90131504Sruchar ** 9114053Smppmake_ssh_args(char *add_arg) 9214053Smpp{ 9314053Smpp static char **args = NULL; 9414053Smpp static int nargs = 0; 9524093Smpp char debug_buf[4096]; 96108087Sru int i; 9714053Smpp 98108087Sru /* Init args array */ 9957686Ssheldonh if (args == NULL) { 10057686Ssheldonh nargs = 2; 10114053Smpp i = 0; 10214053Smpp args = xmalloc(sizeof(*args) * nargs); 10324093Smpp args[i++] = "ssh"; 10424093Smpp args[i++] = NULL; 10524093Smpp } 10614053Smpp 10714053Smpp /* If asked to add args, then do so and return */ 10824093Smpp if (add_arg) { 10914053Smpp i = nargs++ - 1; 11014053Smpp args = xrealloc(args, sizeof(*args) * nargs); 11114053Smpp args[i++] = add_arg; 11214053Smpp args[i++] = NULL; 11324093Smpp return(NULL); 11424093Smpp } 11524093Smpp 11614053Smpp /* no subsystem if the server-spec contains a '/' */ 11757686Ssheldonh if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 11857686Ssheldonh make_ssh_args("-s"); 11924093Smpp make_ssh_args("-oForwardX11=no"); 12024093Smpp make_ssh_args("-oForwardAgent=no"); 12114053Smpp make_ssh_args(use_ssh1 ? "-oProtocol=1" : "-oProtocol=2"); 12214053Smpp 12314053Smpp /* Otherwise finish up and return the arg array */ 12424093Smpp if (sftp_server != NULL) 125147368Sru make_ssh_args(sftp_server); 12624093Smpp else 12724093Smpp make_ssh_args("sftp"); 12824093Smpp 12914053Smpp /* XXX: overflow - doesn't grow debug_buf */ 13014053Smpp debug_buf[0] = '\0'; 13114053Smpp for(i = 0; args[i]; i++) { 13214053Smpp if (i) 13314053Smpp strlcat(debug_buf, " ", sizeof(debug_buf)); 13414053Smpp 13514053Smpp strlcat(debug_buf, args[i], sizeof(debug_buf)); 13624093Smpp } 13724093Smpp debug("SSH args \"%s\"", debug_buf); 13814053Smpp 139131504Sru return(args); 140131504Sru} 14114053Smpp 14224093Smppvoid 14324093Smppusage(void) 14414053Smpp{ 14524093Smpp fprintf(stderr, "usage: sftp [-1vC] [-b batchfile] [-osshopt=value] [user@]host[:file [file]]\n"); 14614053Smpp exit(1); 14714053Smpp} 14814053Smpp 14914053Smppint 15014053Smppmain(int argc, char **argv) 15114053Smpp{ 15214053Smpp int in, out, ch, debug_level, compress_flag; 15314053Smpp pid_t sshpid; 15414053Smpp char *file1 = NULL; 15514053Smpp char *host, *userhost, *cp, *file2; 15614053Smpp LogLevel ll; 15714053Smpp extern int optind; 15814053Smpp extern char *optarg; 15914053Smpp 16014053Smpp infile = stdin; /* Read from STDIN unless changed by -b */ 16114053Smpp debug_level = compress_flag = 0; 16270481Sru 16314053Smpp while ((ch = getopt(argc, argv, "1hvCo:s:S:b:")) != -1) { 16414053Smpp switch (ch) { 16514053Smpp case 'C': 16614053Smpp compress_flag = 1; 16714053Smpp break; 16814053Smpp case 'v': 16914053Smpp debug_level = MIN(3, debug_level + 1); 17014053Smpp break; 17114053Smpp case 'o': 17214053Smpp make_ssh_args("-o"); 17314053Smpp make_ssh_args(optarg); 174108030Sru break; 17514053Smpp case '1': 176108030Sru use_ssh1 = 1; 17714053Smpp if (sftp_server == NULL) 17814053Smpp sftp_server = _PATH_SFTP_SERVER; 17914053Smpp break; 180108087Sru case 's': 18114053Smpp sftp_server = optarg; 182108087Sru break; 18324093Smpp case 'S': 18424093Smpp ssh_program = optarg; 18514053Smpp break; 18614053Smpp case 'b': 18714053Smpp if (infile == stdin) { 18824093Smpp infile = fopen(optarg, "r"); 189108087Sru if (infile == NULL) 19014053Smpp fatal("%s (%s).", strerror(errno), optarg); 191108087Sru } else 19214053Smpp fatal("Filename already specified."); 19314053Smpp break; 19414053Smpp case 'h': 19514053Smpp default: 19624093Smpp usage(); 19724093Smpp } 19824093Smpp } 19914053Smpp 20031370Sbde if (optind == argc || argc > (optind + 2)) 20114053Smpp usage(); 20214053Smpp 203108087Sru userhost = xstrdup(argv[optind]); 20414053Smpp file2 = argv[optind+1]; 205108087Sru 20614053Smpp if ((cp = colon(userhost)) != NULL) { 20714053Smpp *cp++ = '\0'; 20814053Smpp file1 = cp; 209147368Sru } 21014053Smpp 21124093Smpp if ((host = strchr(userhost, '@')) == NULL) 21224093Smpp host = userhost; 21324093Smpp else { 21414053Smpp *host++ = '\0'; 21570481Sru if (!userhost[0]) { 21614053Smpp fprintf(stderr, "Missing username\n"); 217195656Strasz usage(); 218195656Strasz } 219195656Strasz make_ssh_args("-l"); 22014053Smpp make_ssh_args(userhost); 22124093Smpp } 22249266Smpp 223 host = cleanhostname(host); 224 if (!*host) { 225 fprintf(stderr, "Missing hostname\n"); 226 usage(); 227 } 228 229 /* Set up logging and debug '-d' arguments to ssh */ 230 ll = SYSLOG_LEVEL_INFO; 231 switch (debug_level) { 232 case 1: 233 ll = SYSLOG_LEVEL_DEBUG1; 234 make_ssh_args("-v"); 235 break; 236 case 2: 237 ll = SYSLOG_LEVEL_DEBUG2; 238 make_ssh_args("-v"); 239 make_ssh_args("-v"); 240 break; 241 case 3: 242 ll = SYSLOG_LEVEL_DEBUG3; 243 make_ssh_args("-v"); 244 make_ssh_args("-v"); 245 make_ssh_args("-v"); 246 break; 247 } 248 249 if (compress_flag) 250 make_ssh_args("-C"); 251 252 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 253 254 make_ssh_args(host); 255 256 fprintf(stderr, "Connecting to %s...\n", host); 257 258 connect_to_server(make_ssh_args(NULL), &in, &out, &sshpid); 259 260 interactive_loop(in, out, file1, file2); 261 262 close(in); 263 close(out); 264 if (infile != stdin) 265 fclose(infile); 266 267 if (waitpid(sshpid, NULL, 0) == -1) 268 fatal("Couldn't wait for ssh process: %s", strerror(errno)); 269 270 exit(0); 271} 272