xref: /titanic_44/usr/src/cmd/ssh/sftp/sftp.c (revision 40e5e17b3361b3eea56a9723071c406894a20b78)
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