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