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 27 RCSID("$OpenBSD: sftp.c,v 1.34 2003/01/10 08:19:07 fgsch 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 43 extern char *__progname; 44 #else 45 char *__progname; 46 #endif 47 48 FILE* infile; 49 size_t copy_buffer_len = 32768; 50 size_t num_requests = 16; 51 52 extern int showprogress; 53 54 static void 55 connect_to_server(char *path, char **args, int *in, int *out, pid_t *sshpid) 56 { 57 int c_in, c_out; 58 59 #ifdef USE_PIPES 60 int pin[2], pout[2]; 61 62 if ((pipe(pin) == -1) || (pipe(pout) == -1)) 63 fatal("pipe: %s", strerror(errno)); 64 *in = pin[0]; 65 *out = pout[1]; 66 c_in = pout[0]; 67 c_out = pin[1]; 68 #else /* USE_PIPES */ 69 int inout[2]; 70 71 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) 72 fatal("socketpair: %s", strerror(errno)); 73 *in = *out = inout[0]; 74 c_in = c_out = inout[1]; 75 #endif /* USE_PIPES */ 76 77 if ((*sshpid = fork()) == -1) 78 fatal("fork: %s", strerror(errno)); 79 else if (*sshpid == 0) { 80 if ((dup2(c_in, STDIN_FILENO) == -1) || 81 (dup2(c_out, STDOUT_FILENO) == -1)) { 82 fprintf(stderr, "dup2: %s\n", strerror(errno)); 83 exit(1); 84 } 85 close(*in); 86 close(*out); 87 close(c_in); 88 close(c_out); 89 execv(path, args); 90 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno)); 91 exit(1); 92 } 93 94 close(c_in); 95 close(c_out); 96 } 97 98 static void 99 usage(void) 100 { 101 extern char *__progname; 102 103 fprintf(stderr, 104 "usage: %s [-vC1] [-b batchfile] [-o option] [-s subsystem|path] [-B buffer_size]\n" 105 " [-F config] [-P direct server path] [-S program]\n" 106 " [user@]host[:file [file]]\n", __progname); 107 exit(1); 108 } 109 110 int 111 main(int argc, char **argv) 112 { 113 int in, out, ch, err; 114 pid_t sshpid; 115 char *host, *userhost, *cp, *file2; 116 int debug_level = 0, sshver = 2; 117 char *file1 = NULL, *sftp_server = NULL; 118 char *ssh_program = _PATH_SSH_PROGRAM, *sftp_direct = NULL; 119 LogLevel ll = SYSLOG_LEVEL_INFO; 120 arglist args; 121 extern int optind; 122 extern char *optarg; 123 124 __progname = get_progname(argv[0]); 125 args.list = NULL; 126 addargs(&args, "ssh"); /* overwritten with ssh_program */ 127 addargs(&args, "-oForwardX11 no"); 128 addargs(&args, "-oForwardAgent no"); 129 addargs(&args, "-oClearAllForwardings yes"); 130 ll = SYSLOG_LEVEL_INFO; 131 infile = stdin; /* Read from STDIN unless changed by -b */ 132 133 while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) { 134 switch (ch) { 135 case 'C': 136 addargs(&args, "-C"); 137 break; 138 case 'v': 139 if (debug_level < 3) { 140 addargs(&args, "-v"); 141 ll = SYSLOG_LEVEL_DEBUG1 + debug_level; 142 } 143 debug_level++; 144 break; 145 case 'F': 146 case 'o': 147 addargs(&args, "-%c%s", ch, optarg); 148 break; 149 case '1': 150 sshver = 1; 151 if (sftp_server == NULL) 152 sftp_server = _PATH_SFTP_SERVER; 153 break; 154 case 's': 155 sftp_server = optarg; 156 break; 157 case 'S': 158 ssh_program = optarg; 159 break; 160 case 'b': 161 if (infile == stdin) { 162 infile = fopen(optarg, "r"); 163 if (infile == NULL) 164 fatal("%s (%s).", strerror(errno), optarg); 165 } else 166 fatal("Filename already specified."); 167 showprogress = 0; 168 break; 169 case 'P': 170 sftp_direct = optarg; 171 break; 172 case 'B': 173 copy_buffer_len = strtol(optarg, &cp, 10); 174 if (copy_buffer_len == 0 || *cp != '\0') 175 fatal("Invalid buffer size \"%s\"", optarg); 176 break; 177 case 'R': 178 num_requests = strtol(optarg, &cp, 10); 179 if (num_requests == 0 || *cp != '\0') 180 fatal("Invalid number of requests \"%s\"", 181 optarg); 182 break; 183 case 'h': 184 default: 185 usage(); 186 } 187 } 188 189 log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1); 190 191 if (sftp_direct == NULL) { 192 if (optind == argc || argc > (optind + 2)) 193 usage(); 194 195 userhost = xstrdup(argv[optind]); 196 file2 = argv[optind+1]; 197 198 if ((cp = colon(userhost)) != NULL) { 199 *cp++ = '\0'; 200 file1 = cp; 201 } 202 203 if ((host = strrchr(userhost, '@')) == NULL) 204 host = userhost; 205 else { 206 *host++ = '\0'; 207 if (!userhost[0]) { 208 fprintf(stderr, "Missing username\n"); 209 usage(); 210 } 211 addargs(&args, "-l%s",userhost); 212 } 213 214 host = cleanhostname(host); 215 if (!*host) { 216 fprintf(stderr, "Missing hostname\n"); 217 usage(); 218 } 219 220 addargs(&args, "-oProtocol %d", sshver); 221 222 /* no subsystem if the server-spec contains a '/' */ 223 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL) 224 addargs(&args, "-s"); 225 226 addargs(&args, "%s", host); 227 addargs(&args, "%s", (sftp_server != NULL ? 228 sftp_server : "sftp")); 229 args.list[0] = ssh_program; 230 231 fprintf(stderr, "Connecting to %s...\n", host); 232 connect_to_server(ssh_program, args.list, &in, &out, 233 &sshpid); 234 } else { 235 args.list = NULL; 236 addargs(&args, "sftp-server"); 237 238 fprintf(stderr, "Attaching to %s...\n", sftp_direct); 239 connect_to_server(sftp_direct, args.list, &in, &out, 240 &sshpid); 241 } 242 243 err = interactive_loop(in, out, file1, file2); 244 245 #if !defined(USE_PIPES) 246 shutdown(in, SHUT_RDWR); 247 shutdown(out, SHUT_RDWR); 248 #endif 249 250 close(in); 251 close(out); 252 if (infile != stdin) 253 fclose(infile); 254 255 while (waitpid(sshpid, NULL, 0) == -1) 256 if (errno != EINTR) 257 fatal("Couldn't wait for ssh process: %s", 258 strerror(errno)); 259 260 exit(err == 0 ? 0 : 1); 261 } 262