1 | /* |
---|
2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
---|
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
---|
4 | * All rights reserved |
---|
5 | * Ssh client program. This program can be used to log into a remote machine. |
---|
6 | * The software supports strong authentication, encryption, and forwarding |
---|
7 | * of X11, TCP/IP, and authentication connections. |
---|
8 | * |
---|
9 | * As far as I am concerned, the code I have written for this software |
---|
10 | * can be used freely for any purpose. Any derived versions of this |
---|
11 | * software must be clearly marked as such, and if the derived work is |
---|
12 | * incompatible with the protocol description in the RFC file, it must be |
---|
13 | * called by a name other than "ssh" or "Secure Shell". |
---|
14 | * |
---|
15 | * Copyright (c) 1999 Niels Provos. All rights reserved. |
---|
16 | * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. |
---|
17 | * |
---|
18 | * Modified to work with SSL by Niels Provos <provos@citi.umich.edu> |
---|
19 | * in Canada (German citizen). |
---|
20 | * |
---|
21 | * Redistribution and use in source and binary forms, with or without |
---|
22 | * modification, are permitted provided that the following conditions |
---|
23 | * are met: |
---|
24 | * 1. Redistributions of source code must retain the above copyright |
---|
25 | * notice, this list of conditions and the following disclaimer. |
---|
26 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
27 | * notice, this list of conditions and the following disclaimer in the |
---|
28 | * documentation and/or other materials provided with the distribution. |
---|
29 | * |
---|
30 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
31 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
32 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
33 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
34 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
35 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
36 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
37 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
38 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
39 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
40 | */ |
---|
41 | |
---|
42 | #include "includes.h" |
---|
43 | RCSID("$OpenBSD: ssh.c,v 1.186 2002/09/19 01:58:18 djm Exp $"); |
---|
44 | |
---|
45 | #include <openssl/evp.h> |
---|
46 | #include <openssl/err.h> |
---|
47 | |
---|
48 | #include "ssh.h" |
---|
49 | #include "ssh1.h" |
---|
50 | #include "ssh2.h" |
---|
51 | #include "compat.h" |
---|
52 | #include "cipher.h" |
---|
53 | #include "xmalloc.h" |
---|
54 | #include "packet.h" |
---|
55 | #include "buffer.h" |
---|
56 | #include "channels.h" |
---|
57 | #include "key.h" |
---|
58 | #include "authfd.h" |
---|
59 | #include "authfile.h" |
---|
60 | #include "pathnames.h" |
---|
61 | #include "clientloop.h" |
---|
62 | #include "log.h" |
---|
63 | #include "readconf.h" |
---|
64 | #include "sshconnect.h" |
---|
65 | #include "tildexpand.h" |
---|
66 | #include "dispatch.h" |
---|
67 | #include "misc.h" |
---|
68 | #include "kex.h" |
---|
69 | #include "mac.h" |
---|
70 | #include "sshtty.h" |
---|
71 | |
---|
72 | #ifdef SMARTCARD |
---|
73 | #include "scard.h" |
---|
74 | #endif |
---|
75 | |
---|
76 | #ifdef HAVE___PROGNAME |
---|
77 | extern char *__progname; |
---|
78 | #else |
---|
79 | char *__progname; |
---|
80 | #endif |
---|
81 | |
---|
82 | /* Flag indicating whether IPv4 or IPv6. This can be set on the command line. |
---|
83 | Default value is AF_UNSPEC means both IPv4 and IPv6. */ |
---|
84 | #ifdef IPV4_DEFAULT |
---|
85 | int IPv4or6 = AF_INET; |
---|
86 | #else |
---|
87 | int IPv4or6 = AF_UNSPEC; |
---|
88 | #endif |
---|
89 | |
---|
90 | /* Flag indicating whether debug mode is on. This can be set on the command line. */ |
---|
91 | int debug_flag = 0; |
---|
92 | |
---|
93 | /* Flag indicating whether a tty should be allocated */ |
---|
94 | int tty_flag = 0; |
---|
95 | int no_tty_flag = 0; |
---|
96 | int force_tty_flag = 0; |
---|
97 | |
---|
98 | /* don't exec a shell */ |
---|
99 | int no_shell_flag = 0; |
---|
100 | |
---|
101 | /* |
---|
102 | * Flag indicating that nothing should be read from stdin. This can be set |
---|
103 | * on the command line. |
---|
104 | */ |
---|
105 | int stdin_null_flag = 0; |
---|
106 | |
---|
107 | /* |
---|
108 | * Flag indicating that ssh should fork after authentication. This is useful |
---|
109 | * so that the passphrase can be entered manually, and then ssh goes to the |
---|
110 | * background. |
---|
111 | */ |
---|
112 | int fork_after_authentication_flag = 0; |
---|
113 | |
---|
114 | /* |
---|
115 | * General data structure for command line options and options configurable |
---|
116 | * in configuration files. See readconf.h. |
---|
117 | */ |
---|
118 | Options options; |
---|
119 | |
---|
120 | /* optional user configfile */ |
---|
121 | char *config = NULL; |
---|
122 | |
---|
123 | /* |
---|
124 | * Name of the host we are connecting to. This is the name given on the |
---|
125 | * command line, or the HostName specified for the user-supplied name in a |
---|
126 | * configuration file. |
---|
127 | */ |
---|
128 | char *host; |
---|
129 | |
---|
130 | /* socket address the host resolves to */ |
---|
131 | struct sockaddr_storage hostaddr; |
---|
132 | |
---|
133 | /* Private host keys. */ |
---|
134 | Sensitive sensitive_data; |
---|
135 | |
---|
136 | /* Original real UID. */ |
---|
137 | uid_t original_real_uid; |
---|
138 | uid_t original_effective_uid; |
---|
139 | |
---|
140 | /* command to be executed */ |
---|
141 | Buffer command; |
---|
142 | |
---|
143 | /* Should we execute a command or invoke a subsystem? */ |
---|
144 | int subsystem_flag = 0; |
---|
145 | |
---|
146 | /* # of replies received for global requests */ |
---|
147 | static int client_global_request_id = 0; |
---|
148 | |
---|
149 | /* pid of proxycommand child process */ |
---|
150 | pid_t proxy_command_pid = 0; |
---|
151 | |
---|
152 | /* Prints a help message to the user. This function never returns. */ |
---|
153 | |
---|
154 | static void |
---|
155 | usage(void) |
---|
156 | { |
---|
157 | fprintf(stderr, "Usage: %s [options] host [command]\n", __progname); |
---|
158 | fprintf(stderr, "Options:\n"); |
---|
159 | fprintf(stderr, " -l user Log in using this user name.\n"); |
---|
160 | fprintf(stderr, " -n Redirect input from " _PATH_DEVNULL ".\n"); |
---|
161 | fprintf(stderr, " -F config Config file (default: ~/%s).\n", |
---|
162 | _PATH_SSH_USER_CONFFILE); |
---|
163 | fprintf(stderr, " -A Enable authentication agent forwarding.\n"); |
---|
164 | fprintf(stderr, " -a Disable authentication agent forwarding (default).\n"); |
---|
165 | #if defined(AFS) || defined(KRB5) |
---|
166 | fprintf(stderr, " -k Disable Kerberos ticket and AFS token forwarding.\n"); |
---|
167 | #endif /* AFS */ |
---|
168 | fprintf(stderr, " -X Enable X11 connection forwarding.\n"); |
---|
169 | fprintf(stderr, " -x Disable X11 connection forwarding (default).\n"); |
---|
170 | fprintf(stderr, " -i file Identity for public key authentication " |
---|
171 | "(default: ~/.ssh/identity)\n"); |
---|
172 | #ifdef SMARTCARD |
---|
173 | fprintf(stderr, " -I reader Set smartcard reader.\n"); |
---|
174 | #endif |
---|
175 | fprintf(stderr, " -t Tty; allocate a tty even if command is given.\n"); |
---|
176 | fprintf(stderr, " -T Do not allocate a tty.\n"); |
---|
177 | fprintf(stderr, " -v Verbose; display verbose debugging messages.\n"); |
---|
178 | fprintf(stderr, " Multiple -v increases verbosity.\n"); |
---|
179 | fprintf(stderr, " -V Display version number only.\n"); |
---|
180 | fprintf(stderr, " -q Quiet; don't display any warning messages.\n"); |
---|
181 | fprintf(stderr, " -f Fork into background after authentication.\n"); |
---|
182 | fprintf(stderr, " -e char Set escape character; ``none'' = disable (default: ~).\n"); |
---|
183 | |
---|
184 | fprintf(stderr, " -c cipher Select encryption algorithm\n"); |
---|
185 | fprintf(stderr, " -m macs Specify MAC algorithms for protocol version 2.\n"); |
---|
186 | fprintf(stderr, " -p port Connect to this port. Server must be on the same port.\n"); |
---|
187 | fprintf(stderr, " -L listen-port:host:port Forward local port to remote address\n"); |
---|
188 | fprintf(stderr, " -R listen-port:host:port Forward remote port to local address\n"); |
---|
189 | fprintf(stderr, " These cause %s to listen for connections on a port, and\n", __progname); |
---|
190 | fprintf(stderr, " forward them to the other side by connecting to host:port.\n"); |
---|
191 | fprintf(stderr, " -D port Enable dynamic application-level port forwarding.\n"); |
---|
192 | fprintf(stderr, " -C Enable compression.\n"); |
---|
193 | fprintf(stderr, " -N Do not execute a shell or command.\n"); |
---|
194 | fprintf(stderr, " -g Allow remote hosts to connect to forwarded ports.\n"); |
---|
195 | fprintf(stderr, " -1 Force protocol version 1.\n"); |
---|
196 | fprintf(stderr, " -2 Force protocol version 2.\n"); |
---|
197 | fprintf(stderr, " -4 Use IPv4 only.\n"); |
---|
198 | fprintf(stderr, " -6 Use IPv6 only.\n"); |
---|
199 | fprintf(stderr, " -o 'option' Process the option as if it was read from a configuration file.\n"); |
---|
200 | fprintf(stderr, " -s Invoke command (mandatory) as SSH2 subsystem.\n"); |
---|
201 | fprintf(stderr, " -b addr Local IP address.\n"); |
---|
202 | exit(1); |
---|
203 | } |
---|
204 | |
---|
205 | static int ssh_session(void); |
---|
206 | static int ssh_session2(void); |
---|
207 | static void load_public_identity_files(void); |
---|
208 | |
---|
209 | /* |
---|
210 | * Main program for the ssh client. |
---|
211 | */ |
---|
212 | int |
---|
213 | main(int ac, char **av) |
---|
214 | { |
---|
215 | int i, opt, exit_status; |
---|
216 | u_short fwd_port, fwd_host_port; |
---|
217 | char sfwd_port[6], sfwd_host_port[6]; |
---|
218 | char *p, *cp, buf[256]; |
---|
219 | struct stat st; |
---|
220 | struct passwd *pw; |
---|
221 | int dummy; |
---|
222 | extern int optind, optreset; |
---|
223 | extern char *optarg; |
---|
224 | |
---|
225 | __progname = get_progname(av[0]); |
---|
226 | init_rng(); |
---|
227 | |
---|
228 | /* |
---|
229 | * Save the original real uid. It will be needed later (uid-swapping |
---|
230 | * may clobber the real uid). |
---|
231 | */ |
---|
232 | original_real_uid = getuid(); |
---|
233 | original_effective_uid = geteuid(); |
---|
234 | |
---|
235 | /* |
---|
236 | * Use uid-swapping to give up root privileges for the duration of |
---|
237 | * option processing. We will re-instantiate the rights when we are |
---|
238 | * ready to create the privileged port, and will permanently drop |
---|
239 | * them when the port has been created (actually, when the connection |
---|
240 | * has been made, as we may need to create the port several times). |
---|
241 | */ |
---|
242 | PRIV_END; |
---|
243 | |
---|
244 | #ifdef HAVE_SETRLIMIT |
---|
245 | /* If we are installed setuid root be careful to not drop core. */ |
---|
246 | if (original_real_uid != original_effective_uid) { |
---|
247 | struct rlimit rlim; |
---|
248 | rlim.rlim_cur = rlim.rlim_max = 0; |
---|
249 | if (setrlimit(RLIMIT_CORE, &rlim) < 0) |
---|
250 | fatal("setrlimit failed: %.100s", strerror(errno)); |
---|
251 | } |
---|
252 | #endif |
---|
253 | /* Get user data. */ |
---|
254 | pw = getpwuid(original_real_uid); |
---|
255 | if (!pw) { |
---|
256 | log("You don't exist, go away!"); |
---|
257 | exit(1); |
---|
258 | } |
---|
259 | /* Take a copy of the returned structure. */ |
---|
260 | pw = pwcopy(pw); |
---|
261 | |
---|
262 | /* |
---|
263 | * Set our umask to something reasonable, as some files are created |
---|
264 | * with the default umask. This will make them world-readable but |
---|
265 | * writable only by the owner, which is ok for all files for which we |
---|
266 | * don't set the modes explicitly. |
---|
267 | */ |
---|
268 | umask(022); |
---|
269 | |
---|
270 | /* Initialize option structure to indicate that no values have been set. */ |
---|
271 | initialize_options(&options); |
---|
272 | |
---|
273 | /* Parse command-line arguments. */ |
---|
274 | host = NULL; |
---|
275 | |
---|
276 | again: |
---|
277 | while ((opt = getopt(ac, av, |
---|
278 | "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:L:NPR:TVX")) != -1) { |
---|
279 | switch (opt) { |
---|
280 | case '1': |
---|
281 | options.protocol = SSH_PROTO_1; |
---|
282 | break; |
---|
283 | case '2': |
---|
284 | options.protocol = SSH_PROTO_2; |
---|
285 | break; |
---|
286 | case '4': |
---|
287 | IPv4or6 = AF_INET; |
---|
288 | break; |
---|
289 | case '6': |
---|
290 | IPv4or6 = AF_INET6; |
---|
291 | break; |
---|
292 | case 'n': |
---|
293 | stdin_null_flag = 1; |
---|
294 | break; |
---|
295 | case 'f': |
---|
296 | fork_after_authentication_flag = 1; |
---|
297 | stdin_null_flag = 1; |
---|
298 | break; |
---|
299 | case 'x': |
---|
300 | options.forward_x11 = 0; |
---|
301 | break; |
---|
302 | case 'X': |
---|
303 | options.forward_x11 = 1; |
---|
304 | break; |
---|
305 | case 'g': |
---|
306 | options.gateway_ports = 1; |
---|
307 | break; |
---|
308 | case 'P': /* deprecated */ |
---|
309 | options.use_privileged_port = 0; |
---|
310 | break; |
---|
311 | case 'a': |
---|
312 | options.forward_agent = 0; |
---|
313 | break; |
---|
314 | case 'A': |
---|
315 | options.forward_agent = 1; |
---|
316 | break; |
---|
317 | #if defined(AFS) || defined(KRB5) || defined(GSSAPI) |
---|
318 | case 'k': |
---|
319 | #ifdef KRB5 |
---|
320 | options.kerberos_tgt_passing = 0; |
---|
321 | #endif |
---|
322 | #ifdef AFS |
---|
323 | options.afs_token_passing = 0; |
---|
324 | #endif |
---|
325 | #ifdef GSSAPI |
---|
326 | options.gss_deleg_creds = 0; |
---|
327 | #endif |
---|
328 | break; |
---|
329 | #endif |
---|
330 | case 'i': |
---|
331 | if (stat(optarg, &st) < 0) { |
---|
332 | fprintf(stderr, "Warning: Identity file %s " |
---|
333 | "does not exist.\n", optarg); |
---|
334 | break; |
---|
335 | } |
---|
336 | if (options.num_identity_files >= |
---|
337 | SSH_MAX_IDENTITY_FILES) |
---|
338 | fatal("Too many identity files specified " |
---|
339 | "(max %d)", SSH_MAX_IDENTITY_FILES); |
---|
340 | options.identity_files[options.num_identity_files++] = |
---|
341 | xstrdup(optarg); |
---|
342 | break; |
---|
343 | case 'I': |
---|
344 | #ifdef SMARTCARD |
---|
345 | options.smartcard_device = xstrdup(optarg); |
---|
346 | #else |
---|
347 | fprintf(stderr, "no support for smartcards.\n"); |
---|
348 | #endif |
---|
349 | break; |
---|
350 | case 't': |
---|
351 | if (tty_flag) |
---|
352 | force_tty_flag = 1; |
---|
353 | tty_flag = 1; |
---|
354 | break; |
---|
355 | case 'v': |
---|
356 | if (0 == debug_flag) { |
---|
357 | debug_flag = 1; |
---|
358 | options.log_level = SYSLOG_LEVEL_DEBUG1; |
---|
359 | } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) { |
---|
360 | options.log_level++; |
---|
361 | break; |
---|
362 | } else |
---|
363 | fatal("Too high debugging level."); |
---|
364 | /* fallthrough */ |
---|
365 | case 'V': |
---|
366 | fprintf(stderr, |
---|
367 | "%s, SSH protocols %d.%d/%d.%d, OpenSSL 0x%8.8lx\n", |
---|
368 | SSH_VERSION, |
---|
369 | PROTOCOL_MAJOR_1, PROTOCOL_MINOR_1, |
---|
370 | PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, |
---|
371 | SSLeay()); |
---|
372 | if (opt == 'V') |
---|
373 | exit(0); |
---|
374 | break; |
---|
375 | case 'q': |
---|
376 | options.log_level = SYSLOG_LEVEL_QUIET; |
---|
377 | break; |
---|
378 | case 'e': |
---|
379 | if (optarg[0] == '^' && optarg[2] == 0 && |
---|
380 | (u_char) optarg[1] >= 64 && |
---|
381 | (u_char) optarg[1] < 128) |
---|
382 | options.escape_char = (u_char) optarg[1] & 31; |
---|
383 | else if (strlen(optarg) == 1) |
---|
384 | options.escape_char = (u_char) optarg[0]; |
---|
385 | else if (strcmp(optarg, "none") == 0) |
---|
386 | options.escape_char = SSH_ESCAPECHAR_NONE; |
---|
387 | else { |
---|
388 | fprintf(stderr, "Bad escape character '%s'.\n", |
---|
389 | optarg); |
---|
390 | exit(1); |
---|
391 | } |
---|
392 | break; |
---|
393 | case 'c': |
---|
394 | if (ciphers_valid(optarg)) { |
---|
395 | /* SSH2 only */ |
---|
396 | options.ciphers = xstrdup(optarg); |
---|
397 | options.cipher = SSH_CIPHER_ILLEGAL; |
---|
398 | } else { |
---|
399 | /* SSH1 only */ |
---|
400 | options.cipher = cipher_number(optarg); |
---|
401 | if (options.cipher == -1) { |
---|
402 | fprintf(stderr, |
---|
403 | "Unknown cipher type '%s'\n", |
---|
404 | optarg); |
---|
405 | exit(1); |
---|
406 | } |
---|
407 | if (options.cipher == SSH_CIPHER_3DES) |
---|
408 | options.ciphers = "3des-cbc"; |
---|
409 | else if (options.cipher == SSH_CIPHER_BLOWFISH) |
---|
410 | options.ciphers = "blowfish-cbc"; |
---|
411 | else |
---|
412 | options.ciphers = (char *)-1; |
---|
413 | } |
---|
414 | break; |
---|
415 | case 'm': |
---|
416 | if (mac_valid(optarg)) |
---|
417 | options.macs = xstrdup(optarg); |
---|
418 | else { |
---|
419 | fprintf(stderr, "Unknown mac type '%s'\n", |
---|
420 | optarg); |
---|
421 | exit(1); |
---|
422 | } |
---|
423 | break; |
---|
424 | case 'p': |
---|
425 | options.port = a2port(optarg); |
---|
426 | if (options.port == 0) { |
---|
427 | fprintf(stderr, "Bad port '%s'\n", optarg); |
---|
428 | exit(1); |
---|
429 | } |
---|
430 | break; |
---|
431 | case 'l': |
---|
432 | options.user = optarg; |
---|
433 | break; |
---|
434 | |
---|
435 | case 'L': |
---|
436 | case 'R': |
---|
437 | if (sscanf(optarg, "%5[0-9]:%255[^:]:%5[0-9]", |
---|
438 | sfwd_port, buf, sfwd_host_port) != 3 && |
---|
439 | sscanf(optarg, "%5[0-9]/%255[^/]/%5[0-9]", |
---|
440 | sfwd_port, buf, sfwd_host_port) != 3) { |
---|
441 | fprintf(stderr, |
---|
442 | "Bad forwarding specification '%s'\n", |
---|
443 | optarg); |
---|
444 | usage(); |
---|
445 | /* NOTREACHED */ |
---|
446 | } |
---|
447 | if ((fwd_port = a2port(sfwd_port)) == 0 || |
---|
448 | (fwd_host_port = a2port(sfwd_host_port)) == 0) { |
---|
449 | fprintf(stderr, |
---|
450 | "Bad forwarding port(s) '%s'\n", optarg); |
---|
451 | exit(1); |
---|
452 | } |
---|
453 | if (opt == 'L') |
---|
454 | add_local_forward(&options, fwd_port, buf, |
---|
455 | fwd_host_port); |
---|
456 | else if (opt == 'R') |
---|
457 | add_remote_forward(&options, fwd_port, buf, |
---|
458 | fwd_host_port); |
---|
459 | break; |
---|
460 | |
---|
461 | case 'D': |
---|
462 | fwd_port = a2port(optarg); |
---|
463 | if (fwd_port == 0) { |
---|
464 | fprintf(stderr, "Bad dynamic port '%s'\n", |
---|
465 | optarg); |
---|
466 | exit(1); |
---|
467 | } |
---|
468 | add_local_forward(&options, fwd_port, "socks4", 0); |
---|
469 | break; |
---|
470 | |
---|
471 | case 'C': |
---|
472 | options.compression = 1; |
---|
473 | break; |
---|
474 | case 'N': |
---|
475 | no_shell_flag = 1; |
---|
476 | no_tty_flag = 1; |
---|
477 | break; |
---|
478 | case 'T': |
---|
479 | no_tty_flag = 1; |
---|
480 | break; |
---|
481 | case 'o': |
---|
482 | dummy = 1; |
---|
483 | if (process_config_line(&options, host ? host : "", |
---|
484 | optarg, "command-line", 0, &dummy) != 0) |
---|
485 | exit(1); |
---|
486 | break; |
---|
487 | case 's': |
---|
488 | subsystem_flag = 1; |
---|
489 | break; |
---|
490 | case 'b': |
---|
491 | options.bind_address = optarg; |
---|
492 | break; |
---|
493 | case 'F': |
---|
494 | config = optarg; |
---|
495 | break; |
---|
496 | default: |
---|
497 | usage(); |
---|
498 | } |
---|
499 | } |
---|
500 | |
---|
501 | ac -= optind; |
---|
502 | av += optind; |
---|
503 | |
---|
504 | if (ac > 0 && !host && **av != '-') { |
---|
505 | if (strchr(*av, '@')) { |
---|
506 | p = xstrdup(*av); |
---|
507 | cp = strchr(p, '@'); |
---|
508 | if (cp == NULL || cp == p) |
---|
509 | usage(); |
---|
510 | options.user = p; |
---|
511 | *cp = '\0'; |
---|
512 | host = ++cp; |
---|
513 | } else |
---|
514 | host = *av; |
---|
515 | ac--, av++; |
---|
516 | if (ac > 0) { |
---|
517 | optind = 0; |
---|
518 | optreset = 1; |
---|
519 | goto again; |
---|
520 | } |
---|
521 | } |
---|
522 | |
---|
523 | /* Check that we got a host name. */ |
---|
524 | if (!host) |
---|
525 | usage(); |
---|
526 | |
---|
527 | SSLeay_add_all_algorithms(); |
---|
528 | ERR_load_crypto_strings(); |
---|
529 | channel_set_af(IPv4or6); |
---|
530 | |
---|
531 | /* Initialize the command to execute on remote host. */ |
---|
532 | buffer_init(&command); |
---|
533 | |
---|
534 | /* |
---|
535 | * Save the command to execute on the remote host in a buffer. There |
---|
536 | * is no limit on the length of the command, except by the maximum |
---|
537 | * packet size. Also sets the tty flag if there is no command. |
---|
538 | */ |
---|
539 | if (!ac) { |
---|
540 | /* No command specified - execute shell on a tty. */ |
---|
541 | tty_flag = 1; |
---|
542 | if (subsystem_flag) { |
---|
543 | fprintf(stderr, |
---|
544 | "You must specify a subsystem to invoke.\n"); |
---|
545 | usage(); |
---|
546 | } |
---|
547 | } else { |
---|
548 | /* A command has been specified. Store it into the buffer. */ |
---|
549 | for (i = 0; i < ac; i++) { |
---|
550 | if (i) |
---|
551 | buffer_append(&command, " ", 1); |
---|
552 | buffer_append(&command, av[i], strlen(av[i])); |
---|
553 | } |
---|
554 | } |
---|
555 | |
---|
556 | /* Cannot fork to background if no command. */ |
---|
557 | if (fork_after_authentication_flag && buffer_len(&command) == 0 && !no_shell_flag) |
---|
558 | fatal("Cannot fork into background without a command to execute."); |
---|
559 | |
---|
560 | /* Allocate a tty by default if no command specified. */ |
---|
561 | if (buffer_len(&command) == 0) |
---|
562 | tty_flag = 1; |
---|
563 | |
---|
564 | /* Force no tty */ |
---|
565 | if (no_tty_flag) |
---|
566 | tty_flag = 0; |
---|
567 | /* Do not allocate a tty if stdin is not a tty. */ |
---|
568 | if (!isatty(fileno(stdin)) && !force_tty_flag) { |
---|
569 | if (tty_flag) |
---|
570 | log("Pseudo-terminal will not be allocated because stdin is not a terminal."); |
---|
571 | tty_flag = 0; |
---|
572 | } |
---|
573 | |
---|
574 | /* |
---|
575 | * Initialize "log" output. Since we are the client all output |
---|
576 | * actually goes to stderr. |
---|
577 | */ |
---|
578 | log_init(av[0], options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level, |
---|
579 | SYSLOG_FACILITY_USER, 1); |
---|
580 | |
---|
581 | /* |
---|
582 | * Read per-user configuration file. Ignore the system wide config |
---|
583 | * file if the user specifies a config file on the command line. |
---|
584 | */ |
---|
585 | if (config != NULL) { |
---|
586 | if (!read_config_file(config, host, &options)) |
---|
587 | fatal("Can't open user config file %.100s: " |
---|
588 | "%.100s", config, strerror(errno)); |
---|
589 | } else { |
---|
590 | snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, |
---|
591 | _PATH_SSH_USER_CONFFILE); |
---|
592 | (void)read_config_file(buf, host, &options); |
---|
593 | |
---|
594 | /* Read systemwide configuration file after use config. */ |
---|
595 | (void)read_config_file(_PATH_HOST_CONFIG_FILE, host, &options); |
---|
596 | } |
---|
597 | |
---|
598 | /* Fill configuration defaults. */ |
---|
599 | fill_default_options(&options); |
---|
600 | |
---|
601 | /* reinit */ |
---|
602 | log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 1); |
---|
603 | |
---|
604 | seed_rng(); |
---|
605 | |
---|
606 | if (options.user == NULL) |
---|
607 | options.user = xstrdup(pw->pw_name); |
---|
608 | |
---|
609 | if (options.hostname != NULL) |
---|
610 | host = options.hostname; |
---|
611 | |
---|
612 | /* Disable rhosts authentication if not running as root. */ |
---|
613 | #ifdef HAVE_CYGWIN |
---|
614 | /* Ignore uid if running under Windows */ |
---|
615 | if (!options.use_privileged_port) { |
---|
616 | #else |
---|
617 | if (original_effective_uid != 0 || !options.use_privileged_port) { |
---|
618 | #endif |
---|
619 | debug("Rhosts Authentication disabled, " |
---|
620 | "originating port will not be trusted."); |
---|
621 | options.rhosts_authentication = 0; |
---|
622 | } |
---|
623 | /* Open a connection to the remote host. */ |
---|
624 | |
---|
625 | if (ssh_connect(host, &hostaddr, options.port, IPv4or6, |
---|
626 | options.connection_attempts, |
---|
627 | #ifdef HAVE_CYGWIN |
---|
628 | options.use_privileged_port, |
---|
629 | #else |
---|
630 | original_effective_uid == 0 && options.use_privileged_port, |
---|
631 | #endif |
---|
632 | options.proxy_command) != 0) |
---|
633 | exit(1); |
---|
634 | |
---|
635 | /* |
---|
636 | * If we successfully made the connection, load the host private key |
---|
637 | * in case we will need it later for combined rsa-rhosts |
---|
638 | * authentication. This must be done before releasing extra |
---|
639 | * privileges, because the file is only readable by root. |
---|
640 | * If we cannot access the private keys, load the public keys |
---|
641 | * instead and try to execute the ssh-keysign helper instead. |
---|
642 | */ |
---|
643 | sensitive_data.nkeys = 0; |
---|
644 | sensitive_data.keys = NULL; |
---|
645 | sensitive_data.external_keysign = 0; |
---|
646 | if (options.rhosts_rsa_authentication || |
---|
647 | options.hostbased_authentication) { |
---|
648 | sensitive_data.nkeys = 3; |
---|
649 | sensitive_data.keys = xmalloc(sensitive_data.nkeys * |
---|
650 | sizeof(Key)); |
---|
651 | |
---|
652 | PRIV_START; |
---|
653 | sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, |
---|
654 | _PATH_HOST_KEY_FILE, "", NULL); |
---|
655 | sensitive_data.keys[1] = key_load_private_type(KEY_DSA, |
---|
656 | _PATH_HOST_DSA_KEY_FILE, "", NULL); |
---|
657 | sensitive_data.keys[2] = key_load_private_type(KEY_RSA, |
---|
658 | _PATH_HOST_RSA_KEY_FILE, "", NULL); |
---|
659 | PRIV_END; |
---|
660 | |
---|
661 | if (options.hostbased_authentication == 1 && |
---|
662 | sensitive_data.keys[0] == NULL && |
---|
663 | sensitive_data.keys[1] == NULL && |
---|
664 | sensitive_data.keys[2] == NULL) { |
---|
665 | sensitive_data.keys[1] = key_load_public( |
---|
666 | _PATH_HOST_DSA_KEY_FILE, NULL); |
---|
667 | sensitive_data.keys[2] = key_load_public( |
---|
668 | _PATH_HOST_RSA_KEY_FILE, NULL); |
---|
669 | sensitive_data.external_keysign = 1; |
---|
670 | } |
---|
671 | } |
---|
672 | /* |
---|
673 | * Get rid of any extra privileges that we may have. We will no |
---|
674 | * longer need them. Also, extra privileges could make it very hard |
---|
675 | * to read identity files and other non-world-readable files from the |
---|
676 | * user's home directory if it happens to be on a NFS volume where |
---|
677 | * root is mapped to nobody. |
---|
678 | */ |
---|
679 | seteuid(original_real_uid); |
---|
680 | setuid(original_real_uid); |
---|
681 | |
---|
682 | /* |
---|
683 | * Now that we are back to our own permissions, create ~/.ssh |
---|
684 | * directory if it doesn\'t already exist. |
---|
685 | */ |
---|
686 | snprintf(buf, sizeof buf, "%.100s%s%.100s", pw->pw_dir, strcmp(pw->pw_dir, "/") ? "/" : "", _PATH_SSH_USER_DIR); |
---|
687 | if (stat(buf, &st) < 0) |
---|
688 | if (mkdir(buf, 0700) < 0) |
---|
689 | error("Could not create directory '%.200s'.", buf); |
---|
690 | |
---|
691 | /* load options.identity_files */ |
---|
692 | load_public_identity_files(); |
---|
693 | |
---|
694 | /* Expand ~ in known host file names. */ |
---|
695 | /* XXX mem-leaks: */ |
---|
696 | options.system_hostfile = |
---|
697 | tilde_expand_filename(options.system_hostfile, original_real_uid); |
---|
698 | options.user_hostfile = |
---|
699 | tilde_expand_filename(options.user_hostfile, original_real_uid); |
---|
700 | options.system_hostfile2 = |
---|
701 | tilde_expand_filename(options.system_hostfile2, original_real_uid); |
---|
702 | options.user_hostfile2 = |
---|
703 | tilde_expand_filename(options.user_hostfile2, original_real_uid); |
---|
704 | |
---|
705 | signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ |
---|
706 | |
---|
707 | /* Log into the remote system. This never returns if the login fails. */ |
---|
708 | ssh_login(&sensitive_data, host, (struct sockaddr *)&hostaddr, pw); |
---|
709 | |
---|
710 | /* We no longer need the private host keys. Clear them now. */ |
---|
711 | if (sensitive_data.nkeys != 0) { |
---|
712 | for (i = 0; i < sensitive_data.nkeys; i++) { |
---|
713 | if (sensitive_data.keys[i] != NULL) { |
---|
714 | /* Destroys contents safely */ |
---|
715 | debug3("clear hostkey %d", i); |
---|
716 | key_free(sensitive_data.keys[i]); |
---|
717 | sensitive_data.keys[i] = NULL; |
---|
718 | } |
---|
719 | } |
---|
720 | xfree(sensitive_data.keys); |
---|
721 | } |
---|
722 | for (i = 0; i < options.num_identity_files; i++) { |
---|
723 | if (options.identity_files[i]) { |
---|
724 | xfree(options.identity_files[i]); |
---|
725 | options.identity_files[i] = NULL; |
---|
726 | } |
---|
727 | if (options.identity_keys[i]) { |
---|
728 | key_free(options.identity_keys[i]); |
---|
729 | options.identity_keys[i] = NULL; |
---|
730 | } |
---|
731 | } |
---|
732 | |
---|
733 | exit_status = compat20 ? ssh_session2() : ssh_session(); |
---|
734 | packet_close(); |
---|
735 | |
---|
736 | /* |
---|
737 | * Send SIGHUP to proxy command if used. We don't wait() in |
---|
738 | * case it hangs and instead rely on init to reap the child |
---|
739 | */ |
---|
740 | if (proxy_command_pid > 1) |
---|
741 | kill(proxy_command_pid, SIGHUP); |
---|
742 | |
---|
743 | return exit_status; |
---|
744 | } |
---|
745 | |
---|
746 | static void |
---|
747 | x11_get_proto(char **_proto, char **_data) |
---|
748 | { |
---|
749 | char line[512]; |
---|
750 | static char proto[512], data[512]; |
---|
751 | FILE *f; |
---|
752 | int got_data = 0, i; |
---|
753 | char *display; |
---|
754 | struct stat st; |
---|
755 | |
---|
756 | *_proto = proto; |
---|
757 | *_data = data; |
---|
758 | proto[0] = data[0] = '\0'; |
---|
759 | if (!options.xauth_location || |
---|
760 | (stat(options.xauth_location, &st) == -1)) { |
---|
761 | debug("No xauth program."); |
---|
762 | } else { |
---|
763 | if ((display = getenv("DISPLAY")) == NULL) { |
---|
764 | debug("x11_get_proto: DISPLAY not set"); |
---|
765 | return; |
---|
766 | } |
---|
767 | /* Try to get Xauthority information for the display. */ |
---|
768 | if (strncmp(display, "localhost:", 10) == 0) |
---|
769 | /* |
---|
770 | * Handle FamilyLocal case where $DISPLAY does |
---|
771 | * not match an authorization entry. For this we |
---|
772 | * just try "xauth list unix:displaynum.screennum". |
---|
773 | * XXX: "localhost" match to determine FamilyLocal |
---|
774 | * is not perfect. |
---|
775 | */ |
---|
776 | snprintf(line, sizeof line, "%s list unix:%s 2>" |
---|
777 | _PATH_DEVNULL, options.xauth_location, display+10); |
---|
778 | else |
---|
779 | snprintf(line, sizeof line, "%s list %.200s 2>" |
---|
780 | _PATH_DEVNULL, options.xauth_location, display); |
---|
781 | debug2("x11_get_proto: %s", line); |
---|
782 | f = popen(line, "r"); |
---|
783 | if (f && fgets(line, sizeof(line), f) && |
---|
784 | sscanf(line, "%*s %511s %511s", proto, data) == 2) |
---|
785 | got_data = 1; |
---|
786 | if (f) |
---|
787 | pclose(f); |
---|
788 | } |
---|
789 | /* |
---|
790 | * If we didn't get authentication data, just make up some |
---|
791 | * data. The forwarding code will check the validity of the |
---|
792 | * response anyway, and substitute this data. The X11 |
---|
793 | * server, however, will ignore this fake data and use |
---|
794 | * whatever authentication mechanisms it was using otherwise |
---|
795 | * for the local connection. |
---|
796 | */ |
---|
797 | if (!got_data) { |
---|
798 | u_int32_t rand = 0; |
---|
799 | |
---|
800 | strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto); |
---|
801 | for (i = 0; i < 16; i++) { |
---|
802 | if (i % 4 == 0) |
---|
803 | rand = arc4random(); |
---|
804 | snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff); |
---|
805 | rand >>= 8; |
---|
806 | } |
---|
807 | } |
---|
808 | } |
---|
809 | |
---|
810 | static void |
---|
811 | ssh_init_forwarding(void) |
---|
812 | { |
---|
813 | int success = 0; |
---|
814 | int i; |
---|
815 | |
---|
816 | /* Initiate local TCP/IP port forwardings. */ |
---|
817 | for (i = 0; i < options.num_local_forwards; i++) { |
---|
818 | debug("Connections to local port %d forwarded to remote address %.200s:%d", |
---|
819 | options.local_forwards[i].port, |
---|
820 | options.local_forwards[i].host, |
---|
821 | options.local_forwards[i].host_port); |
---|
822 | success += channel_setup_local_fwd_listener( |
---|
823 | options.local_forwards[i].port, |
---|
824 | options.local_forwards[i].host, |
---|
825 | options.local_forwards[i].host_port, |
---|
826 | options.gateway_ports); |
---|
827 | } |
---|
828 | if (i > 0 && success == 0) |
---|
829 | error("Could not request local forwarding."); |
---|
830 | |
---|
831 | /* Initiate remote TCP/IP port forwardings. */ |
---|
832 | for (i = 0; i < options.num_remote_forwards; i++) { |
---|
833 | debug("Connections to remote port %d forwarded to local address %.200s:%d", |
---|
834 | options.remote_forwards[i].port, |
---|
835 | options.remote_forwards[i].host, |
---|
836 | options.remote_forwards[i].host_port); |
---|
837 | channel_request_remote_forwarding( |
---|
838 | options.remote_forwards[i].port, |
---|
839 | options.remote_forwards[i].host, |
---|
840 | options.remote_forwards[i].host_port); |
---|
841 | } |
---|
842 | } |
---|
843 | |
---|
844 | static void |
---|
845 | check_agent_present(void) |
---|
846 | { |
---|
847 | if (options.forward_agent) { |
---|
848 | /* Clear agent forwarding if we don\'t have an agent. */ |
---|
849 | if (!ssh_agent_present()) |
---|
850 | options.forward_agent = 0; |
---|
851 | } |
---|
852 | } |
---|
853 | |
---|
854 | static int |
---|
855 | ssh_session(void) |
---|
856 | { |
---|
857 | int type; |
---|
858 | int interactive = 0; |
---|
859 | int have_tty = 0; |
---|
860 | struct winsize ws; |
---|
861 | char *cp; |
---|
862 | |
---|
863 | /* Enable compression if requested. */ |
---|
864 | if (options.compression) { |
---|
865 | debug("Requesting compression at level %d.", options.compression_level); |
---|
866 | |
---|
867 | if (options.compression_level < 1 || options.compression_level > 9) |
---|
868 | fatal("Compression level must be from 1 (fast) to 9 (slow, best)."); |
---|
869 | |
---|
870 | /* Send the request. */ |
---|
871 | packet_start(SSH_CMSG_REQUEST_COMPRESSION); |
---|
872 | packet_put_int(options.compression_level); |
---|
873 | packet_send(); |
---|
874 | packet_write_wait(); |
---|
875 | type = packet_read(); |
---|
876 | if (type == SSH_SMSG_SUCCESS) |
---|
877 | packet_start_compression(options.compression_level); |
---|
878 | else if (type == SSH_SMSG_FAILURE) |
---|
879 | log("Warning: Remote host refused compression."); |
---|
880 | else |
---|
881 | packet_disconnect("Protocol error waiting for compression response."); |
---|
882 | } |
---|
883 | /* Allocate a pseudo tty if appropriate. */ |
---|
884 | if (tty_flag) { |
---|
885 | debug("Requesting pty."); |
---|
886 | |
---|
887 | /* Start the packet. */ |
---|
888 | packet_start(SSH_CMSG_REQUEST_PTY); |
---|
889 | |
---|
890 | /* Store TERM in the packet. There is no limit on the |
---|
891 | length of the string. */ |
---|
892 | cp = getenv("TERM"); |
---|
893 | if (!cp) |
---|
894 | cp = ""; |
---|
895 | packet_put_cstring(cp); |
---|
896 | |
---|
897 | /* Store window size in the packet. */ |
---|
898 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) |
---|
899 | memset(&ws, 0, sizeof(ws)); |
---|
900 | packet_put_int(ws.ws_row); |
---|
901 | packet_put_int(ws.ws_col); |
---|
902 | packet_put_int(ws.ws_xpixel); |
---|
903 | packet_put_int(ws.ws_ypixel); |
---|
904 | |
---|
905 | /* Store tty modes in the packet. */ |
---|
906 | tty_make_modes(fileno(stdin), NULL); |
---|
907 | |
---|
908 | /* Send the packet, and wait for it to leave. */ |
---|
909 | packet_send(); |
---|
910 | packet_write_wait(); |
---|
911 | |
---|
912 | /* Read response from the server. */ |
---|
913 | type = packet_read(); |
---|
914 | if (type == SSH_SMSG_SUCCESS) { |
---|
915 | interactive = 1; |
---|
916 | have_tty = 1; |
---|
917 | } else if (type == SSH_SMSG_FAILURE) |
---|
918 | log("Warning: Remote host failed or refused to allocate a pseudo tty."); |
---|
919 | else |
---|
920 | packet_disconnect("Protocol error waiting for pty request response."); |
---|
921 | } |
---|
922 | /* Request X11 forwarding if enabled and DISPLAY is set. */ |
---|
923 | if (options.forward_x11 && getenv("DISPLAY") != NULL) { |
---|
924 | char *proto, *data; |
---|
925 | /* Get reasonable local authentication information. */ |
---|
926 | x11_get_proto(&proto, &data); |
---|
927 | /* Request forwarding with authentication spoofing. */ |
---|
928 | debug("Requesting X11 forwarding with authentication spoofing."); |
---|
929 | x11_request_forwarding_with_spoofing(0, proto, data); |
---|
930 | |
---|
931 | /* Read response from the server. */ |
---|
932 | type = packet_read(); |
---|
933 | if (type == SSH_SMSG_SUCCESS) { |
---|
934 | interactive = 1; |
---|
935 | } else if (type == SSH_SMSG_FAILURE) { |
---|
936 | log("Warning: Remote host denied X11 forwarding."); |
---|
937 | } else { |
---|
938 | packet_disconnect("Protocol error waiting for X11 forwarding"); |
---|
939 | } |
---|
940 | } |
---|
941 | /* Tell the packet module whether this is an interactive session. */ |
---|
942 | packet_set_interactive(interactive); |
---|
943 | |
---|
944 | /* Request authentication agent forwarding if appropriate. */ |
---|
945 | check_agent_present(); |
---|
946 | |
---|
947 | if (options.forward_agent) { |
---|
948 | debug("Requesting authentication agent forwarding."); |
---|
949 | auth_request_forwarding(); |
---|
950 | |
---|
951 | /* Read response from the server. */ |
---|
952 | type = packet_read(); |
---|
953 | packet_check_eom(); |
---|
954 | if (type != SSH_SMSG_SUCCESS) |
---|
955 | log("Warning: Remote host denied authentication agent forwarding."); |
---|
956 | } |
---|
957 | |
---|
958 | /* Initiate port forwardings. */ |
---|
959 | ssh_init_forwarding(); |
---|
960 | |
---|
961 | /* If requested, let ssh continue in the background. */ |
---|
962 | if (fork_after_authentication_flag) |
---|
963 | if (daemon(1, 1) < 0) |
---|
964 | fatal("daemon() failed: %.200s", strerror(errno)); |
---|
965 | |
---|
966 | /* |
---|
967 | * If a command was specified on the command line, execute the |
---|
968 | * command now. Otherwise request the server to start a shell. |
---|
969 | */ |
---|
970 | if (buffer_len(&command) > 0) { |
---|
971 | int len = buffer_len(&command); |
---|
972 | if (len > 900) |
---|
973 | len = 900; |
---|
974 | debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); |
---|
975 | packet_start(SSH_CMSG_EXEC_CMD); |
---|
976 | packet_put_string(buffer_ptr(&command), buffer_len(&command)); |
---|
977 | packet_send(); |
---|
978 | packet_write_wait(); |
---|
979 | } else { |
---|
980 | debug("Requesting shell."); |
---|
981 | packet_start(SSH_CMSG_EXEC_SHELL); |
---|
982 | packet_send(); |
---|
983 | packet_write_wait(); |
---|
984 | } |
---|
985 | |
---|
986 | /* Enter the interactive session. */ |
---|
987 | return client_loop(have_tty, tty_flag ? |
---|
988 | options.escape_char : SSH_ESCAPECHAR_NONE, 0); |
---|
989 | } |
---|
990 | |
---|
991 | static void |
---|
992 | client_subsystem_reply(int type, u_int32_t seq, void *ctxt) |
---|
993 | { |
---|
994 | int id, len; |
---|
995 | |
---|
996 | id = packet_get_int(); |
---|
997 | len = buffer_len(&command); |
---|
998 | if (len > 900) |
---|
999 | len = 900; |
---|
1000 | packet_check_eom(); |
---|
1001 | if (type == SSH2_MSG_CHANNEL_FAILURE) |
---|
1002 | fatal("Request for subsystem '%.*s' failed on channel %d", |
---|
1003 | len, (u_char *)buffer_ptr(&command), id); |
---|
1004 | } |
---|
1005 | |
---|
1006 | void |
---|
1007 | client_global_request_reply(int type, u_int32_t seq, void *ctxt) |
---|
1008 | { |
---|
1009 | int i; |
---|
1010 | |
---|
1011 | i = client_global_request_id++; |
---|
1012 | if (i >= options.num_remote_forwards) { |
---|
1013 | debug("client_global_request_reply: too many replies %d > %d", |
---|
1014 | i, options.num_remote_forwards); |
---|
1015 | return; |
---|
1016 | } |
---|
1017 | debug("remote forward %s for: listen %d, connect %s:%d", |
---|
1018 | type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", |
---|
1019 | options.remote_forwards[i].port, |
---|
1020 | options.remote_forwards[i].host, |
---|
1021 | options.remote_forwards[i].host_port); |
---|
1022 | if (type == SSH2_MSG_REQUEST_FAILURE) |
---|
1023 | log("Warning: remote port forwarding failed for listen port %d", |
---|
1024 | options.remote_forwards[i].port); |
---|
1025 | } |
---|
1026 | |
---|
1027 | /* request pty/x11/agent/tcpfwd/shell for channel */ |
---|
1028 | static void |
---|
1029 | ssh_session2_setup(int id, void *arg) |
---|
1030 | { |
---|
1031 | int len; |
---|
1032 | int interactive = 0; |
---|
1033 | struct termios tio; |
---|
1034 | |
---|
1035 | debug("ssh_session2_setup: id %d", id); |
---|
1036 | |
---|
1037 | if (tty_flag) { |
---|
1038 | struct winsize ws; |
---|
1039 | char *cp; |
---|
1040 | cp = getenv("TERM"); |
---|
1041 | if (!cp) |
---|
1042 | cp = ""; |
---|
1043 | /* Store window size in the packet. */ |
---|
1044 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) |
---|
1045 | memset(&ws, 0, sizeof(ws)); |
---|
1046 | |
---|
1047 | channel_request_start(id, "pty-req", 0); |
---|
1048 | packet_put_cstring(cp); |
---|
1049 | packet_put_int(ws.ws_col); |
---|
1050 | packet_put_int(ws.ws_row); |
---|
1051 | packet_put_int(ws.ws_xpixel); |
---|
1052 | packet_put_int(ws.ws_ypixel); |
---|
1053 | tio = get_saved_tio(); |
---|
1054 | tty_make_modes(/*ignored*/ 0, &tio); |
---|
1055 | packet_send(); |
---|
1056 | interactive = 1; |
---|
1057 | /* XXX wait for reply */ |
---|
1058 | } |
---|
1059 | if (options.forward_x11 && |
---|
1060 | getenv("DISPLAY") != NULL) { |
---|
1061 | char *proto, *data; |
---|
1062 | /* Get reasonable local authentication information. */ |
---|
1063 | x11_get_proto(&proto, &data); |
---|
1064 | /* Request forwarding with authentication spoofing. */ |
---|
1065 | debug("Requesting X11 forwarding with authentication spoofing."); |
---|
1066 | x11_request_forwarding_with_spoofing(id, proto, data); |
---|
1067 | interactive = 1; |
---|
1068 | /* XXX wait for reply */ |
---|
1069 | } |
---|
1070 | |
---|
1071 | check_agent_present(); |
---|
1072 | if (options.forward_agent) { |
---|
1073 | debug("Requesting authentication agent forwarding."); |
---|
1074 | channel_request_start(id, "auth-agent-req@openssh.com", 0); |
---|
1075 | packet_send(); |
---|
1076 | } |
---|
1077 | |
---|
1078 | len = buffer_len(&command); |
---|
1079 | if (len > 0) { |
---|
1080 | if (len > 900) |
---|
1081 | len = 900; |
---|
1082 | if (subsystem_flag) { |
---|
1083 | debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command)); |
---|
1084 | channel_request_start(id, "subsystem", /*want reply*/ 1); |
---|
1085 | /* register callback for reply */ |
---|
1086 | /* XXX we assume that client_loop has already been called */ |
---|
1087 | dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply); |
---|
1088 | dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply); |
---|
1089 | } else { |
---|
1090 | debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); |
---|
1091 | channel_request_start(id, "exec", 0); |
---|
1092 | } |
---|
1093 | packet_put_string(buffer_ptr(&command), buffer_len(&command)); |
---|
1094 | packet_send(); |
---|
1095 | } else { |
---|
1096 | channel_request_start(id, "shell", 0); |
---|
1097 | packet_send(); |
---|
1098 | } |
---|
1099 | |
---|
1100 | packet_set_interactive(interactive); |
---|
1101 | } |
---|
1102 | |
---|
1103 | /* open new channel for a session */ |
---|
1104 | static int |
---|
1105 | ssh_session2_open(void) |
---|
1106 | { |
---|
1107 | Channel *c; |
---|
1108 | int window, packetmax, in, out, err; |
---|
1109 | |
---|
1110 | if (stdin_null_flag) { |
---|
1111 | in = open(_PATH_DEVNULL, O_RDONLY); |
---|
1112 | } else { |
---|
1113 | in = dup(STDIN_FILENO); |
---|
1114 | } |
---|
1115 | out = dup(STDOUT_FILENO); |
---|
1116 | err = dup(STDERR_FILENO); |
---|
1117 | |
---|
1118 | if (in < 0 || out < 0 || err < 0) |
---|
1119 | fatal("dup() in/out/err failed"); |
---|
1120 | |
---|
1121 | /* enable nonblocking unless tty */ |
---|
1122 | if (!isatty(in)) |
---|
1123 | set_nonblock(in); |
---|
1124 | if (!isatty(out)) |
---|
1125 | set_nonblock(out); |
---|
1126 | if (!isatty(err)) |
---|
1127 | set_nonblock(err); |
---|
1128 | |
---|
1129 | window = CHAN_SES_WINDOW_DEFAULT; |
---|
1130 | packetmax = CHAN_SES_PACKET_DEFAULT; |
---|
1131 | if (tty_flag) { |
---|
1132 | window >>= 1; |
---|
1133 | packetmax >>= 1; |
---|
1134 | } |
---|
1135 | c = channel_new( |
---|
1136 | "session", SSH_CHANNEL_OPENING, in, out, err, |
---|
1137 | window, packetmax, CHAN_EXTENDED_WRITE, |
---|
1138 | xstrdup("client-session"), /*nonblock*/0); |
---|
1139 | |
---|
1140 | debug3("ssh_session2_open: channel_new: %d", c->self); |
---|
1141 | |
---|
1142 | channel_send_open(c->self); |
---|
1143 | if (!no_shell_flag) |
---|
1144 | channel_register_confirm(c->self, ssh_session2_setup); |
---|
1145 | |
---|
1146 | return c->self; |
---|
1147 | } |
---|
1148 | |
---|
1149 | static int |
---|
1150 | ssh_session2(void) |
---|
1151 | { |
---|
1152 | int id = -1; |
---|
1153 | |
---|
1154 | /* XXX should be pre-session */ |
---|
1155 | ssh_init_forwarding(); |
---|
1156 | |
---|
1157 | if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN)) |
---|
1158 | id = ssh_session2_open(); |
---|
1159 | |
---|
1160 | /* If requested, let ssh continue in the background. */ |
---|
1161 | if (fork_after_authentication_flag) |
---|
1162 | if (daemon(1, 1) < 0) |
---|
1163 | fatal("daemon() failed: %.200s", strerror(errno)); |
---|
1164 | |
---|
1165 | return client_loop(tty_flag, tty_flag ? |
---|
1166 | options.escape_char : SSH_ESCAPECHAR_NONE, id); |
---|
1167 | } |
---|
1168 | |
---|
1169 | static void |
---|
1170 | load_public_identity_files(void) |
---|
1171 | { |
---|
1172 | char *filename; |
---|
1173 | int i = 0; |
---|
1174 | Key *public; |
---|
1175 | #ifdef SMARTCARD |
---|
1176 | Key **keys; |
---|
1177 | |
---|
1178 | if (options.smartcard_device != NULL && |
---|
1179 | options.num_identity_files < SSH_MAX_IDENTITY_FILES && |
---|
1180 | (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL ) { |
---|
1181 | int count = 0; |
---|
1182 | for (i = 0; keys[i] != NULL; i++) { |
---|
1183 | count++; |
---|
1184 | memmove(&options.identity_files[1], &options.identity_files[0], |
---|
1185 | sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); |
---|
1186 | memmove(&options.identity_keys[1], &options.identity_keys[0], |
---|
1187 | sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); |
---|
1188 | options.num_identity_files++; |
---|
1189 | options.identity_keys[0] = keys[i]; |
---|
1190 | options.identity_files[0] = xstrdup("smartcard key");; |
---|
1191 | } |
---|
1192 | if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) |
---|
1193 | options.num_identity_files = SSH_MAX_IDENTITY_FILES; |
---|
1194 | i = count; |
---|
1195 | xfree(keys); |
---|
1196 | } |
---|
1197 | #endif /* SMARTCARD */ |
---|
1198 | for (; i < options.num_identity_files; i++) { |
---|
1199 | filename = tilde_expand_filename(options.identity_files[i], |
---|
1200 | original_real_uid); |
---|
1201 | public = key_load_public(filename, NULL); |
---|
1202 | debug("identity file %s type %d", filename, |
---|
1203 | public ? public->type : -1); |
---|
1204 | xfree(options.identity_files[i]); |
---|
1205 | options.identity_files[i] = filename; |
---|
1206 | options.identity_keys[i] = public; |
---|
1207 | } |
---|
1208 | } |
---|