]> andersk Git - openssh.git/blob - sftp.c
- (djm) OpenBSD CVS Sync
[openssh.git] / sftp.c
1 /*
2  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include "includes.h"
18
19 RCSID("$OpenBSD: sftp.c,v 1.43 2004/02/17 07:17:29 djm Exp $");
20
21 #include "buffer.h"
22 #include "xmalloc.h"
23 #include "log.h"
24 #include "pathnames.h"
25 #include "misc.h"
26
27 #include "sftp.h"
28 #include "sftp-common.h"
29 #include "sftp-client.h"
30
31 int interactive_loop(int, int, char *, char *); /* sftp-int.c */
32
33 #ifdef HAVE___PROGNAME
34 extern char *__progname;
35 #else
36 char *__progname;
37 #endif
38
39 FILE* infile;
40 int batchmode = 0;
41 size_t copy_buffer_len = 32768;
42 size_t num_requests = 16;
43 static pid_t sshpid = -1;
44
45 extern int showprogress;
46
47 static void
48 killchild(int signo)
49 {
50         if (sshpid > 1)
51                 kill(sshpid, signo);
52
53         _exit(1);
54 }
55
56 static void
57 connect_to_server(char *path, char **args, int *in, int *out)
58 {
59         int c_in, c_out;
60
61 #ifdef USE_PIPES
62         int pin[2], pout[2];
63
64         if ((pipe(pin) == -1) || (pipe(pout) == -1))
65                 fatal("pipe: %s", strerror(errno));
66         *in = pin[0];
67         *out = pout[1];
68         c_in = pout[0];
69         c_out = pin[1];
70 #else /* USE_PIPES */
71         int inout[2];
72
73         if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1)
74                 fatal("socketpair: %s", strerror(errno));
75         *in = *out = inout[0];
76         c_in = c_out = inout[1];
77 #endif /* USE_PIPES */
78
79         if ((sshpid = fork()) == -1)
80                 fatal("fork: %s", strerror(errno));
81         else if (sshpid == 0) {
82                 if ((dup2(c_in, STDIN_FILENO) == -1) ||
83                     (dup2(c_out, STDOUT_FILENO) == -1)) {
84                         fprintf(stderr, "dup2: %s\n", strerror(errno));
85                         exit(1);
86                 }
87                 close(*in);
88                 close(*out);
89                 close(c_in);
90                 close(c_out);
91                 execv(path, args);
92                 fprintf(stderr, "exec: %s: %s\n", path, strerror(errno));
93                 exit(1);
94         }
95
96         signal(SIGTERM, killchild);
97         signal(SIGINT, killchild);
98         signal(SIGHUP, killchild);
99         close(c_in);
100         close(c_out);
101 }
102
103 static void
104 usage(void)
105 {
106         extern char *__progname;
107
108         fprintf(stderr,
109             "usage: %s [-1Cv] [-B buffer_size] [-b batchfile] [-F ssh_config]\n"
110             "            [-o ssh_option] [-P sftp_server_path] [-R num_requests]\n"
111             "            [-S program] [-s subsystem | sftp_server] host\n"
112             "       %s [[user@]host[:file [file]]]\n"
113             "       %s [[user@]host[:dir[/]]]\n"
114             "       %s -b batchfile [user@]host\n", __progname, __progname, __progname, __progname);
115         exit(1);
116 }
117
118 int
119 main(int argc, char **argv)
120 {
121         int in, out, ch, err;
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 = ssh_get_progname(argv[0]);
132         args.list = NULL;
133         addargs(&args, "ssh");          /* overwritten with ssh_program */
134         addargs(&args, "-oForwardX11 no");
135         addargs(&args, "-oForwardAgent no");
136         addargs(&args, "-oClearAllForwardings yes");
137
138         ll = SYSLOG_LEVEL_INFO;
139         infile = stdin;
140
141         while ((ch = getopt(argc, argv, "1hvCo:s:S:b:B:F:P:R:")) != -1) {
142                 switch (ch) {
143                 case 'C':
144                         addargs(&args, "-C");
145                         break;
146                 case 'v':
147                         if (debug_level < 3) {
148                                 addargs(&args, "-v");
149                                 ll = SYSLOG_LEVEL_DEBUG1 + debug_level;
150                         }
151                         debug_level++;
152                         break;
153                 case 'F':
154                 case 'o':
155                         addargs(&args, "-%c%s", ch, optarg);
156                         break;
157                 case '1':
158                         sshver = 1;
159                         if (sftp_server == NULL)
160                                 sftp_server = _PATH_SFTP_SERVER;
161                         break;
162                 case 's':
163                         sftp_server = optarg;
164                         break;
165                 case 'S':
166                         ssh_program = optarg;
167                         break;
168                 case 'b':
169                         if (batchmode)
170                                 fatal("Batch file already specified.");
171
172                         /* Allow "-" as stdin */
173                         if (strcmp(optarg, "-") != 0 && 
174                            (infile = fopen(optarg, "r")) == NULL)
175                                 fatal("%s (%s).", strerror(errno), optarg);
176                         showprogress = 0;
177                         batchmode = 1;
178                         break;
179                 case 'P':
180                         sftp_direct = optarg;
181                         break;
182                 case 'B':
183                         copy_buffer_len = strtol(optarg, &cp, 10);
184                         if (copy_buffer_len == 0 || *cp != '\0')
185                                 fatal("Invalid buffer size \"%s\"", optarg);
186                         break;
187                 case 'R':
188                         num_requests = strtol(optarg, &cp, 10);
189                         if (num_requests == 0 || *cp != '\0')
190                                 fatal("Invalid number of requests \"%s\"",
191                                     optarg);
192                         break;
193                 case 'h':
194                 default:
195                         usage();
196                 }
197         }
198
199         log_init(argv[0], ll, SYSLOG_FACILITY_USER, 1);
200
201         if (sftp_direct == NULL) {
202                 if (optind == argc || argc > (optind + 2))
203                         usage();
204
205                 userhost = xstrdup(argv[optind]);
206                 file2 = argv[optind+1];
207
208                 if ((host = strrchr(userhost, '@')) == NULL)
209                         host = userhost;
210                 else {
211                         *host++ = '\0';
212                         if (!userhost[0]) {
213                                 fprintf(stderr, "Missing username\n");
214                                 usage();
215                         }
216                         addargs(&args, "-l%s",userhost);
217                 }
218
219                 if ((cp = colon(host)) != NULL) {
220                         *cp++ = '\0';
221                         file1 = cp;
222                 }
223
224                 host = cleanhostname(host);
225                 if (!*host) {
226                         fprintf(stderr, "Missing hostname\n");
227                         usage();
228                 }
229
230                 addargs(&args, "-oProtocol %d", sshver);
231
232                 /* no subsystem if the server-spec contains a '/' */
233                 if (sftp_server == NULL || strchr(sftp_server, '/') == NULL)
234                         addargs(&args, "-s");
235
236                 addargs(&args, "%s", host);
237                 addargs(&args, "%s", (sftp_server != NULL ?
238                     sftp_server : "sftp"));
239                 args.list[0] = ssh_program;
240
241                 if (!batchmode)
242                         fprintf(stderr, "Connecting to %s...\n", host);
243                 connect_to_server(ssh_program, args.list, &in, &out);
244         } else {
245                 args.list = NULL;
246                 addargs(&args, "sftp-server");
247
248                 if (!batchmode)
249                         fprintf(stderr, "Attaching to %s...\n", sftp_direct);
250                 connect_to_server(sftp_direct, args.list, &in, &out);
251         }
252
253         err = interactive_loop(in, out, file1, file2);
254
255 #if !defined(USE_PIPES)
256         shutdown(in, SHUT_RDWR);
257         shutdown(out, SHUT_RDWR);
258 #endif
259
260         close(in);
261         close(out);
262         if (batchmode)
263                 fclose(infile);
264
265         while (waitpid(sshpid, NULL, 0) == -1)
266                 if (errno != EINTR)
267                         fatal("Couldn't wait for ssh process: %s",
268                             strerror(errno));
269
270         exit(err == 0 ? 0 : 1);
271 }
This page took 0.053531 seconds and 5 git commands to generate.