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