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