sftp.c revision 76259
1314564Sdim/* 2280461Sdim * Copyright (c) 2001 Damien Miller. All rights reserved. 3353358Sdim * 4353358Sdim * Redistribution and use in source and binary forms, with or without 5353358Sdim * modification, are permitted provided that the following conditions 6280461Sdim * are met: 7280461Sdim * 1. Redistributions of source code must retain the above copyright 8280461Sdim * notice, this list of conditions and the following disclaimer. 9280461Sdim * 2. Redistributions in binary form must reproduce the above copyright 10280461Sdim * notice, this list of conditions and the following disclaimer in the 11280461Sdim * documentation and/or other materials provided with the distribution. 12314564Sdim * 13280461Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14280461Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 15314564Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 16280461Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 17280461Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18280461Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19280461Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 20280461Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21280461Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22280461Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23280461Sdim */ 24280461Sdim 25280461Sdim#include "includes.h" 26280461Sdim 27303239SdimRCSID("$OpenBSD: sftp.c,v 1.15 2001/04/16 02:31:44 mouring Exp $"); 28303239Sdim 29303239Sdim/* XXX: commandline mode */ 30280461Sdim/* XXX: short-form remote directory listings (like 'ls -C') */ 31280461Sdim 32280461Sdim#include "buffer.h" 33303239Sdim#include "xmalloc.h" 34280461Sdim#include "log.h" 35280461Sdim#include "pathnames.h" 36280461Sdim 37280461Sdim#include "sftp.h" 38280461Sdim#include "sftp-common.h" 39280461Sdim#include "sftp-client.h" 40280461Sdim#include "sftp-int.h" 41280461Sdim 42280461Sdim#include "scp-common.h" 43280461Sdim 44280461Sdimint use_ssh1 = 0; 45280461Sdimchar *ssh_program = _PATH_SSH_PROGRAM; 46280461Sdimchar *sftp_server = NULL; 47303239SdimFILE* infile; 48280461Sdim 49280461Sdimvoid 50280461Sdimconnect_to_server(char **args, int *in, int *out, pid_t *sshpid) 51280461Sdim{ 52280461Sdim int c_in, c_out; 53280461Sdim#ifdef USE_PIPES 54303239Sdim int pin[2], pout[2]; 55280461Sdim if ((pipe(pin) == -1) || (pipe(pout) == -1)) 56280461Sdim fatal("pipe: %s", strerror(errno)); 57280461Sdim *in = pin[0]; 58280461Sdim *out = pout[1]; 59280461Sdim c_in = pout[0]; 60280461Sdim c_out = pin[1]; 61280461Sdim#else /* USE_PIPES */ 62280461Sdim int inout[2]; 63280461Sdim if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 64280461Sdim fatal("socketpair: %s", strerror(errno)); 65280461Sdim *in = *out = inout[0]; 66280461Sdim c_in = c_out = inout[1]; 67280461Sdim#endif /* USE_PIPES */ 68280461Sdim 69280461Sdim if ((*sshpid = fork()) == -1) 70280461Sdim fatal("fork: %s", strerror(errno)); 71280461Sdim else if (*sshpid == 0) { 72280461Sdim if ((dup2(c_in, STDIN_FILENO) == -1) || 73280461Sdim (dup2(c_out, STDOUT_FILENO) == -1)) { 74280461Sdim fprintf(stderr, "dup2: %s\n", strerror(errno)); 75280461Sdim exit(1); 76280461Sdim } 77280461Sdim close(*in); 78280461Sdim close(*out); 79280461Sdim close(c_in); 80280461Sdim close(c_out); 81280461Sdim execv(ssh_program, args); 82280461Sdim fprintf(stderr, "exec: %s: %s\n", ssh_program, strerror(errno)); 83280461Sdim exit(1); 84280461Sdim } 85280461Sdim 86280461Sdim close(c_in); 87280461Sdim close(c_out); 88280461Sdim} 89280461Sdim 90280461Sdimchar ** 91280461Sdimmake_ssh_args(char *add_arg) 92280461Sdim{ 93280461Sdim static char **args = NULL; 94280461Sdim static int nargs = 0; 95280461Sdim char debug_buf[4096]; 96280461Sdim int i; 97280461Sdim 98280461Sdim /* Init args array */ 99280461Sdim if (args == NULL) { 100280461Sdim nargs = 2; 101280461Sdim i = 0; 102280461Sdim args = xmalloc(sizeof(*args) * nargs); 103280461Sdim args[i++] = "ssh"; 104280461Sdim args[i++] = NULL; 105280461Sdim } 106280461Sdim 107280461Sdim /* If asked to add args, then do so and return */ 108280461Sdim if (add_arg) { 109314564Sdim i = nargs++ - 1; 110280461Sdim args = xrealloc(args, sizeof(*args) * nargs); 111280461Sdim args[i++] = add_arg; 112280461Sdim args[i++] = NULL; 113280461Sdim return(NULL); 114280461Sdim } 115280461Sdim 116314564Sdim /* no subsystem if the server-spec contains a '/' */ 117280461Sdim if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 118280461Sdim make_ssh_args("-s"); 119 make_ssh_args("-oForwardX11=no"); 120 make_ssh_args("-oForwardAgent=no"); 121 make_ssh_args(use_ssh1 ? "-oProtocol=1" : "-oProtocol=2"); 122 123 /* Otherwise finish up and return the arg array */ 124 if (sftp_server != NULL) 125 make_ssh_args(sftp_server); 126 else 127 make_ssh_args("sftp"); 128 129 /* XXX: overflow - doesn't grow debug_buf */ 130 debug_buf[0] = '\0'; 131 for(i = 0; args[i]; i++) { 132 if (i) 133 strlcat(debug_buf, " ", sizeof(debug_buf)); 134 135 strlcat(debug_buf, args[i], sizeof(debug_buf)); 136 } 137 debug("SSH args \"%s\"", debug_buf); 138 139 return(args); 140} 141 142void 143usage(void) 144{ 145 fprintf(stderr, "usage: sftp [-1vC] [-b batchfile] [-osshopt=value] [user@]host[:file [file]]\n"); 146 exit(1); 147} 148 149int 150main(int argc, char **argv) 151{ 152 int in, out, ch, debug_level, compress_flag; 153 pid_t sshpid; 154 char *file1 = NULL; 155 char *host, *userhost, *cp, *file2; 156 LogLevel ll; 157 extern int optind; 158 extern char *optarg; 159 160 infile = stdin; /* Read from STDIN unless changed by -b */ 161 debug_level = compress_flag = 0; 162 163 while ((ch = getopt(argc, argv, "1hvCo:s:S:b:")) != -1) { 164 switch (ch) { 165 case 'C': 166 compress_flag = 1; 167 break; 168 case 'v': 169 debug_level = MIN(3, debug_level + 1); 170 break; 171 case 'o': 172 make_ssh_args("-o"); 173 make_ssh_args(optarg); 174 break; 175 case '1': 176 use_ssh1 = 1; 177 if (sftp_server == NULL) 178 sftp_server = _PATH_SFTP_SERVER; 179 break; 180 case 's': 181 sftp_server = optarg; 182 break; 183 case 'S': 184 ssh_program = optarg; 185 break; 186 case 'b': 187 if (infile == stdin) { 188 infile = fopen(optarg, "r"); 189 if (infile == NULL) 190 fatal("%s (%s).", strerror(errno), optarg); 191 } else 192 fatal("Filename already specified."); 193 break; 194 case 'h': 195 default: 196 usage(); 197 } 198 } 199 200 if (optind == argc || argc > (optind + 2)) 201 usage(); 202 203 userhost = xstrdup(argv[optind]); 204 file2 = argv[optind+1]; 205 206 if ((cp = colon(userhost)) != NULL) { 207 *cp++ = '\0'; 208 file1 = cp; 209 } 210 211 if ((host = strchr(userhost, '@')) == NULL) 212 host = userhost; 213 else { 214 *host++ = '\0'; 215 if (!userhost[0]) { 216 fprintf(stderr, "Missing username\n"); 217 usage(); 218 } 219 make_ssh_args("-l"); 220 make_ssh_args(userhost); 221 } 222 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