]> andersk Git - openssh.git/blob - ssh.c
- Add recommendation to use GNU make to INSTALL document
[openssh.git] / ssh.c
1 /*
2
3 ssh.c
4
5 Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7 Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                    All rights reserved
9
10 Created: Sat Mar 18 16:36:11 1995 ylo
11
12 Ssh client program.  This program can be used to log into a remote machine.
13 The software supports strong authentication, encryption, and forwarding
14 of X11, TCP/IP, and authentication connections.
15
16 Modified to work with SSL by Niels Provos <provos@citi.umich.edu> in Canada.
17
18 */
19
20 #include "includes.h"
21 RCSID("$Id$");
22
23 #include "xmalloc.h"
24 #include "ssh.h"
25 #include "packet.h"
26 #include "buffer.h"
27 #include "authfd.h"
28 #include "readconf.h"
29 #include "uidswap.h"
30
31 #ifdef HAVE___PROGNAME
32 extern char *__progname;
33 #else /* HAVE___PROGNAME */
34 const char *__progname = "ssh";
35 #endif /* HAVE___PROGNAME */
36
37 /* Flag indicating whether debug mode is on.  This can be set on the
38    command line. */
39 int debug_flag = 0;
40
41 /* Flag indicating whether to allocate a pseudo tty.  This can be set on the
42    command line, and is automatically set if no command is given on the command
43    line. */
44 int tty_flag = 0;
45
46 /* Flag indicating that nothing should be read from stdin.  This can be set
47    on the command line. */
48 int stdin_null_flag = 0;
49
50 /* Flag indicating that ssh should fork after authentication.  This is useful
51    so that the pasphrase can be entered manually, and then ssh goes to the
52    background. */
53 int fork_after_authentication_flag = 0;
54
55 /* General data structure for command line options and options configurable
56    in configuration files.  See readconf.h. */
57 Options options;
58
59 /* Name of the host we are connecting to.  This is the name given on the
60    command line, or the HostName specified for the user-supplied name
61    in a configuration file. */
62 char *host;
63
64 /* socket address the host resolves to */
65 struct sockaddr_in hostaddr;
66
67 /* Flag to indicate that we have received a window change signal which has
68    not yet been processed.  This will cause a message indicating the new
69    window size to be sent to the server a little later.  This is volatile
70    because this is updated in a signal handler. */
71 volatile int received_window_change_signal = 0;
72
73 /* Value of argv[0] (set in the main program). */
74 char *av0;
75
76 /* Flag indicating whether we have a valid host private key loaded. */
77 int host_private_key_loaded = 0;
78
79 /* Host private key. */
80 RSA *host_private_key = NULL;
81
82 /* Original real UID. */
83 uid_t original_real_uid;
84
85 /* Prints a help message to the user.  This function never returns. */
86
87 void
88 usage()
89 {
90   fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
91   fprintf(stderr, "Options:\n");
92   fprintf(stderr, "  -l user     Log in using this user name.\n");
93   fprintf(stderr, "  -n          Redirect input from /dev/null.\n");
94   fprintf(stderr, "  -a          Disable authentication agent forwarding.\n");
95 #ifdef AFS
96   fprintf(stderr, "  -k          Disable Kerberos ticket and AFS token forwarding.\n");
97 #endif /* AFS */
98   fprintf(stderr, "  -x          Disable X11 connection forwarding.\n");
99   fprintf(stderr, "  -i file     Identity for RSA authentication (default: ~/.ssh/identity).\n");
100   fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");
101   fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
102   fprintf(stderr, "  -V          Display version number only.\n");
103   fprintf(stderr, "  -P          Don't allocate a privileged port.\n");
104   fprintf(stderr, "  -q          Quiet; don't display any warning messages.\n");
105   fprintf(stderr, "  -f          Fork into background after authentication.\n");
106   fprintf(stderr, "  -e char     Set escape character; ``none'' = disable (default: ~).\n");
107
108   fprintf(stderr, "  -c cipher   Select encryption algorithm: "
109                   "``3des'', "
110                   "``blowfish''\n");
111   fprintf(stderr, "  -p port     Connect to this port.  Server must be on the same port.\n");
112   fprintf(stderr, "  -L listen-port:host:port   Forward local port to remote address\n");
113   fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");
114   fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", av0);
115   fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
116   fprintf(stderr, "  -C          Enable compression.\n");
117   fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");
118   fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");
119   exit(1);
120 }
121
122 /* Connects to the given host using rsh (or prints an error message and exits
123    if rsh is not available).  This function never returns. */
124
125 void
126 rsh_connect(char *host, char *user, Buffer *command)
127 {
128   char *args[10];
129   int i;
130   
131   log("Using rsh.  WARNING: Connection will not be encrypted.");
132   /* Build argument list for rsh. */
133   i = 0;
134   args[i++] = _PATH_RSH;
135   args[i++] = host;    /* may have to come after user on some systems */
136   if (user)
137     {
138       args[i++] = "-l";
139       args[i++] = user;
140     }
141   if (buffer_len(command) > 0)
142     {
143       buffer_append(command, "\0", 1);
144       args[i++] = buffer_ptr(command);
145     }
146   args[i++] = NULL;
147   if (debug_flag)
148     {
149       for (i = 0; args[i]; i++)
150         {
151           if (i != 0)
152             fprintf(stderr, " ");
153           fprintf(stderr, "%s", args[i]);
154         }
155       fprintf(stderr, "\n");
156     }
157   execv(_PATH_RSH, args);
158   perror(_PATH_RSH);
159   exit(1);
160 }
161
162 /* Main program for the ssh client. */
163
164 int
165 main(int ac, char **av)
166 {
167   int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port, authfd;
168   char *optarg, *cp, buf[256];
169   Buffer command;
170   struct winsize ws;
171   struct stat st;
172   struct passwd *pw, pwcopy;
173   int interactive = 0, dummy;
174   uid_t original_effective_uid;
175   int plen;
176
177   /* Save the original real uid.  It will be needed later (uid-swapping may
178      clobber the real uid).  */
179   original_real_uid = getuid();
180   original_effective_uid = geteuid();
181
182   /* If we are installed setuid root be careful to not drop core. */
183   if (original_real_uid != original_effective_uid)
184     {
185       struct rlimit rlim;
186       rlim.rlim_cur = rlim.rlim_max = 0;
187       if (setrlimit(RLIMIT_CORE, &rlim) < 0)
188         fatal("setrlimit failed: %.100s", strerror(errno));
189     }
190
191   /* Use uid-swapping to give up root privileges for the duration of option
192      processing.  We will re-instantiate the rights when we are ready to
193      create the privileged port, and will permanently drop them when the
194      port has been created (actually, when the connection has been made, as
195      we may need to create the port several times). */
196   temporarily_use_uid(original_real_uid);
197
198   /* Set our umask to something reasonable, as some files are created with 
199      the default umask.  This will make them world-readable but writable 
200      only by the owner, which is ok for all files for which we don't set
201      the modes explicitly. */
202   umask(022);
203   
204   /* Save our own name. */
205   av0 = av[0];
206
207   /* Initialize option structure to indicate that no values have been set. */
208   initialize_options(&options);
209
210   /* Parse command-line arguments. */
211   host = NULL;
212
213   /* If program name is not one of the standard names, use it as host name. */
214   if (strchr(av0, '/'))
215     cp = strrchr(av0, '/') + 1;
216   else
217     cp = av0;
218   if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
219       strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0)
220     host = cp;
221   
222   for (optind = 1; optind < ac; optind++)
223     {
224       if (av[optind][0] != '-')
225         {
226           if (host)
227             break;
228           if ((cp = strchr(av[optind], '@'))) {
229             options.user = av[optind];
230             *cp = '\0';
231             host = ++cp;
232           }
233           else
234             host = av[optind];
235           continue;
236         }
237       opt = av[optind][1];
238       if (!opt)
239         usage();
240       if (strchr("eilcpLRo", opt)) /* options with arguments */
241         {
242           optarg = av[optind] + 2;
243           if (strcmp(optarg, "") == 0)
244             {
245               if (optind >= ac - 1)
246                 usage();
247               optarg = av[++optind];
248             }
249         }
250       else
251         {
252           if (av[optind][2])
253             usage();
254           optarg = NULL;
255         }
256       switch (opt)
257         {
258         case 'n':
259           stdin_null_flag = 1;
260           break;
261
262         case 'f':
263           fork_after_authentication_flag = 1;
264           stdin_null_flag = 1;
265           break;
266
267         case 'x':
268           options.forward_x11 = 0;
269           break;
270
271         case 'X':
272           options.forward_x11 = 1;
273           break;
274
275         case 'g':
276           options.gateway_ports = 1;
277           break;
278
279         case 'P':
280           options.use_privileged_port = 0;
281           break;
282
283         case 'a':
284           options.forward_agent = 0;
285           break;
286 #ifdef AFS
287         case 'k':
288           options.kerberos_tgt_passing = 0;
289           options.afs_token_passing = 0;
290           break;
291 #endif
292         case 'i':
293           if (stat(optarg, &st) < 0)
294             {
295               fprintf(stderr, "Warning: Identity file %s does not exist.\n",
296                       optarg);
297               break;
298             }
299           if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
300             fatal("Too many identity files specified (max %d)",
301                   SSH_MAX_IDENTITY_FILES);
302           options.identity_files[options.num_identity_files++] = 
303             xstrdup(optarg);
304           break;
305
306         case 't':
307           tty_flag = 1;
308           break;
309
310         case 'v':
311         case 'V':
312           fprintf(stderr, "SSH Version %s, protocol version %d.%d.\n",
313                   SSH_VERSION, PROTOCOL_MAJOR, PROTOCOL_MINOR);
314           fprintf(stderr, "Compiled with SSL.\n");
315           if (opt == 'V')
316             exit(0);
317           debug_flag = 1;
318           options.log_level = SYSLOG_LEVEL_DEBUG;
319           break;
320
321         case 'q':
322           options.log_level = SYSLOG_LEVEL_QUIET;
323           break;
324
325         case 'e':
326           if (optarg[0] == '^' && optarg[2] == 0 &&
327               (unsigned char)optarg[1] >= 64 && (unsigned char)optarg[1] < 128)
328             options.escape_char = (unsigned char)optarg[1] & 31;
329           else
330             if (strlen(optarg) == 1)
331               options.escape_char = (unsigned char)optarg[0];
332             else
333               if (strcmp(optarg, "none") == 0)
334                 options.escape_char = -2;
335               else
336                 {
337                   fprintf(stderr, "Bad escape character '%s'.\n", optarg);
338                   exit(1);
339                 }
340           break;
341
342         case 'c':
343           options.cipher = cipher_number(optarg);
344           if (options.cipher == -1)
345             {
346               fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
347               exit(1);
348             }
349           break;
350
351         case 'p':
352           options.port = atoi(optarg);
353           if (options.port < 1 || options.port > 65535)
354             {
355               fprintf(stderr, "Bad port %s.\n", optarg);
356               exit(1);
357             }
358           break;
359
360         case 'l':
361           options.user = optarg;
362           break;
363
364         case 'R':
365           if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf, 
366                      &fwd_host_port) != 3)
367             {
368               fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
369               usage();
370               /*NOTREACHED*/
371             }
372           add_remote_forward(&options, fwd_port, buf, fwd_host_port);
373           break;
374
375         case 'L':
376           if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf, 
377                      &fwd_host_port) != 3)
378             {
379               fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
380               usage();
381               /*NOTREACHED*/
382             }
383           add_local_forward(&options, fwd_port, buf, fwd_host_port);
384           break;
385
386         case 'C':
387           options.compression = 1;
388           break;
389
390         case 'o':
391           dummy = 1;
392           if (process_config_line(&options, host ? host : "", optarg,
393                                   "command-line", 0, &dummy) != 0)
394             exit(1);
395           break;
396
397         default:
398           usage();
399         }
400     }
401
402  /* Check that we got a host name. */
403   if (!host)
404     usage();
405
406   /* check if RSA support exists */
407   if (rsa_alive() == 0) {
408
409     fprintf(stderr,
410       "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
411       __progname);
412     exit(1);
413   }
414
415   /* Initialize the command to execute on remote host. */
416   buffer_init(&command);
417
418   /* Save the command to execute on the remote host in a buffer.  There is
419      no limit on the length of the command, except by the maximum packet
420      size.  Also sets the tty flag if there is no command. */
421   if (optind == ac)
422     {
423       /* No command specified - execute shell on a tty. */
424       tty_flag = 1;
425     }
426   else
427     {
428       /* A command has been specified.  Store it into the buffer. */
429       for (i = optind; i < ac; i++)
430         {
431           if (i > optind)
432             buffer_append(&command, " ", 1);
433           buffer_append(&command, av[i], strlen(av[i]));
434         }
435     }
436
437   /* Cannot fork to background if no command. */
438   if (fork_after_authentication_flag && buffer_len(&command) == 0)
439     fatal("Cannot fork into background without a command to execute.");
440   
441   /* Allocate a tty by default if no command specified. */
442   if (buffer_len(&command) == 0)
443     tty_flag = 1;
444
445   /* Do not allocate a tty if stdin is not a tty. */
446   if (!isatty(fileno(stdin)))
447     {
448       if (tty_flag)
449         fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
450       tty_flag = 0;
451     }
452
453   /* Get user data. */
454   pw = getpwuid(original_real_uid);
455   if (!pw)
456     {
457       fprintf(stderr, "You don't exist, go away!\n");
458       exit(1);
459     }
460   
461   /* Take a copy of the returned structure. */
462   memset(&pwcopy, 0, sizeof(pwcopy));
463   pwcopy.pw_name = xstrdup(pw->pw_name);
464   pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
465   pwcopy.pw_uid = pw->pw_uid;
466   pwcopy.pw_gid = pw->pw_gid;
467   pwcopy.pw_dir = xstrdup(pw->pw_dir);
468   pwcopy.pw_shell = xstrdup(pw->pw_shell);
469   pw = &pwcopy;
470
471   /* Initialize "log" output.  Since we are the client all output actually
472      goes to the terminal. */
473   log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
474
475   /* Read per-user configuration file. */
476   snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_CONFFILE);
477   read_config_file(buf, host, &options);
478
479   /* Read systemwide configuration file. */
480   read_config_file(HOST_CONFIG_FILE, host, &options);
481
482   /* Fill configuration defaults. */
483   fill_default_options(&options);
484
485   /* reinit */
486   log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
487
488   if (options.user == NULL)
489     options.user = xstrdup(pw->pw_name);
490
491   if (options.hostname != NULL)
492     host = options.hostname;
493
494   /* Find canonic host name. */
495   if (strchr(host, '.') == 0)
496     {
497       struct hostent *hp = gethostbyname(host);
498       if (hp != 0)
499         {
500           if (strchr(hp->h_name, '.') != 0)
501             host = xstrdup(hp->h_name);
502           else if (hp->h_aliases != 0
503                    && hp->h_aliases[0] != 0
504                    && strchr(hp->h_aliases[0], '.') != 0)
505             host = xstrdup(hp->h_aliases[0]);
506         }
507     }
508
509   /* Disable rhosts authentication if not running as root. */
510   if (original_effective_uid != 0 || !options.use_privileged_port)
511     {
512       options.rhosts_authentication = 0;
513       options.rhosts_rsa_authentication = 0;
514     }
515
516   /* If using rsh has been selected, exec it now (without trying anything
517      else).  Note that we must release privileges first. */
518   if (options.use_rsh)
519     {
520       /* Restore our superuser privileges.  This must be done before
521          permanently setting the uid. */
522       restore_uid();
523
524       /* Switch to the original uid permanently. */
525       permanently_set_uid(original_real_uid);
526
527       /* Execute rsh. */
528       rsh_connect(host, options.user, &command);
529       fatal("rsh_connect returned");
530     }
531
532   /* Restore our superuser privileges. */
533   restore_uid();
534
535   /* Open a connection to the remote host.  This needs root privileges if
536      rhosts_{rsa_}authentication is enabled. */
537
538   ok = ssh_connect(host, &hostaddr, options.port, options.connection_attempts,
539                    !options.rhosts_authentication &&
540                    !options.rhosts_rsa_authentication,
541                    original_real_uid, options.proxy_command);
542
543   /* If we successfully made the connection, load the host private key in
544      case we will need it later for combined rsa-rhosts authentication. 
545      This must be done before releasing extra privileges, because the file
546      is only readable by root. */
547   if (ok)
548     {
549       host_private_key = RSA_new();
550       if (load_private_key(HOST_KEY_FILE, "", host_private_key, NULL))
551         host_private_key_loaded = 1;
552     }
553
554   /* Get rid of any extra privileges that we may have.  We will no longer need
555      them.  Also, extra privileges could make it very hard to read identity
556      files and other non-world-readable files from the user's home directory
557      if it happens to be on a NFS volume where root is mapped to nobody. */
558
559   /* Note that some legacy systems need to postpone the following call to
560      permanently_set_uid() until the private hostkey is destroyed with
561      RSA_free().  Otherwise the calling user could ptrace() the process,
562      read the private hostkey and impersonate the host.  OpenBSD does not
563      allow ptracing of setuid processes. */
564
565   permanently_set_uid(original_real_uid);
566
567   /* Now that we are back to our own permissions, create ~/.ssh directory
568      if it doesn\'t already exist. */
569   snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, SSH_USER_DIR);
570   if (stat(buf, &st) < 0)
571     if (mkdir(buf, 0755) < 0)
572       error("Could not create directory '%.200s'.", buf);
573
574   /* Check if the connection failed, and try "rsh" if appropriate. */
575   if (!ok)
576     {
577       if (options.port != 0)
578         log("Secure connection to %.100s on port %d refused%.100s.", 
579             host, options.port,
580             options.fallback_to_rsh ? "; reverting to insecure method" : "");
581       else
582         log("Secure connection to %.100s refused%.100s.", host,
583             options.fallback_to_rsh ? "; reverting to insecure method" : "");
584
585       if (options.fallback_to_rsh)
586         {
587           rsh_connect(host, options.user, &command);
588           fatal("rsh_connect returned");
589         }
590       exit(1);
591     }
592
593   /* Expand ~ in options.identity_files. */
594   for (i = 0; i < options.num_identity_files; i++)
595     options.identity_files[i] = 
596       tilde_expand_filename(options.identity_files[i], original_real_uid);
597
598   /* Expand ~ in known host file names. */
599   options.system_hostfile = tilde_expand_filename(options.system_hostfile,
600                                                   original_real_uid);
601   options.user_hostfile = tilde_expand_filename(options.user_hostfile,
602                                                 original_real_uid);
603
604   /* Log into the remote system.  This never returns if the login fails. */
605   ssh_login(host_private_key_loaded, host_private_key, 
606             host, &hostaddr, original_real_uid);
607
608   /* We no longer need the host private key.  Clear it now. */
609   if (host_private_key_loaded)
610     RSA_free(host_private_key); /* Destroys contents safely */
611
612   /* Close connection cleanly after attack. */
613   cipher_attack_detected = packet_disconnect;
614
615   /* Enable compression if requested. */
616   if (options.compression)
617     {
618       debug("Requesting compression at level %d.", options.compression_level);
619
620       if (options.compression_level < 1 || options.compression_level > 9)
621         fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
622
623       /* Send the request. */
624       packet_start(SSH_CMSG_REQUEST_COMPRESSION);
625       packet_put_int(options.compression_level);
626       packet_send();
627       packet_write_wait();
628       type = packet_read(&plen);
629       if (type == SSH_SMSG_SUCCESS)
630         packet_start_compression(options.compression_level);
631       else if (type == SSH_SMSG_FAILURE)
632         log("Warning: Remote host refused compression.");
633       else
634         packet_disconnect("Protocol error waiting for compression response.");
635     }
636
637   /* Allocate a pseudo tty if appropriate. */
638   if (tty_flag)
639     {
640       debug("Requesting pty.");
641
642       /* Start the packet. */
643       packet_start(SSH_CMSG_REQUEST_PTY);
644
645       /* Store TERM in the packet.  There is no limit on the length of the
646          string. */
647       cp = getenv("TERM");
648       if (!cp)
649         cp = "";
650       packet_put_string(cp, strlen(cp));
651
652       /* Store window size in the packet. */
653       if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
654         memset(&ws, 0, sizeof(ws));
655       packet_put_int(ws.ws_row);
656       packet_put_int(ws.ws_col);
657       packet_put_int(ws.ws_xpixel);
658       packet_put_int(ws.ws_ypixel);
659       
660       /* Store tty modes in the packet. */
661       tty_make_modes(fileno(stdin));
662
663       /* Send the packet, and wait for it to leave. */
664       packet_send();
665       packet_write_wait();
666
667       /* Read response from the server. */
668       type = packet_read(&plen);
669       if (type == SSH_SMSG_SUCCESS)
670         interactive = 1;
671       else if (type == SSH_SMSG_FAILURE)
672         log("Warning: Remote host failed or refused to allocate a pseudo tty.");
673       else
674         packet_disconnect("Protocol error waiting for pty request response.");
675     }
676
677   /* Request X11 forwarding if enabled and DISPLAY is set. */
678   if (options.forward_x11 && getenv("DISPLAY") != NULL)
679     {
680       char line[512], proto[512], data[512];
681       FILE *f;
682       int forwarded = 0, got_data = 0, i;
683
684 #ifdef XAUTH_PATH
685       /* Try to get Xauthority information for the display. */
686       snprintf(line, sizeof line, "%.100s list %.200s 2>/dev/null", 
687               XAUTH_PATH, getenv("DISPLAY"));
688       f = popen(line, "r");
689       if (f && fgets(line, sizeof(line), f) && 
690           sscanf(line, "%*s %s %s", proto, data) == 2)
691         got_data = 1;
692       if (f)
693         pclose(f);
694 #endif /* XAUTH_PATH */
695       /* If we didn't get authentication data, just make up some data.  The
696          forwarding code will check the validity of the response anyway, and
697          substitute this data.  The X11 server, however, will ignore this
698          fake data and use whatever authentication mechanisms it was using
699          otherwise for the local connection. */
700       if (!got_data)
701         {
702           u_int32_t rand = 0;
703
704           strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto);
705           for (i = 0; i < 16; i++) {
706             if (i % 4 == 0)
707               rand = arc4random();
708             snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff);
709             rand >>= 8;
710           }
711         }
712
713       /* Got local authentication reasonable information.  Request forwarding
714          with authentication spoofing. */
715       debug("Requesting X11 forwarding with authentication spoofing.");
716       x11_request_forwarding_with_spoofing(proto, data);
717
718       /* Read response from the server. */
719       type = packet_read(&plen);
720       if (type == SSH_SMSG_SUCCESS)
721         {
722           forwarded = 1;
723           interactive = 1;
724         }
725       else if (type == SSH_SMSG_FAILURE)
726         log("Warning: Remote host denied X11 forwarding.");
727       else
728         packet_disconnect("Protocol error waiting for X11 forwarding");
729     }
730
731   /* Tell the packet module whether this is an interactive session. */
732   packet_set_interactive(interactive, options.keepalives);
733
734   /* Clear agent forwarding if we don\'t have an agent. */
735   authfd = ssh_get_authentication_socket();
736   if (authfd < 0)
737     options.forward_agent = 0;
738   else
739     ssh_close_authentication_socket(authfd);
740
741   /* Request authentication agent forwarding if appropriate. */
742   if (options.forward_agent)
743     {
744       debug("Requesting authentication agent forwarding.");
745       auth_request_forwarding();
746       
747       /* Read response from the server. */
748       type = packet_read(&plen);
749       packet_integrity_check(plen, 0, type);
750       if (type != SSH_SMSG_SUCCESS)
751         log("Warning: Remote host denied authentication agent forwarding.");
752     }
753
754   /* Initiate local TCP/IP port forwardings. */
755   for (i = 0; i < options.num_local_forwards; i++)
756     {
757       debug("Connections to local port %d forwarded to remote address %.200s:%d",
758             options.local_forwards[i].port, options.local_forwards[i].host, 
759             options.local_forwards[i].host_port);
760       channel_request_local_forwarding(options.local_forwards[i].port,
761                                        options.local_forwards[i].host,
762                                        options.local_forwards[i].host_port);
763     }
764
765   /* Initiate remote TCP/IP port forwardings. */
766   for (i = 0; i < options.num_remote_forwards; i++)
767     {
768       debug("Connections to remote port %d forwarded to local address %.200s:%d",
769             options.remote_forwards[i].port, options.remote_forwards[i].host, 
770             options.remote_forwards[i].host_port);
771       channel_request_remote_forwarding(options.remote_forwards[i].port,
772                                         options.remote_forwards[i].host,
773                                         options.remote_forwards[i].host_port);
774     }
775
776   /* If requested, fork and let ssh continue in the background. */
777   if (fork_after_authentication_flag)
778     {
779       int ret = fork();
780       if (ret == -1)
781         fatal("fork failed: %.100s", strerror(errno));
782       if (ret != 0)
783         exit(0);
784       setsid();
785     }
786
787   /* If a command was specified on the command line, execute the command now.
788      Otherwise request the server to start a shell. */
789   if (buffer_len(&command) > 0)
790     {
791       int len = buffer_len(&command);
792       if (len > 900)
793         len = 900;
794       debug("Sending command: %.*s", len, buffer_ptr(&command));
795       packet_start(SSH_CMSG_EXEC_CMD);
796       packet_put_string(buffer_ptr(&command), buffer_len(&command));
797       packet_send();
798       packet_write_wait();
799     }
800   else
801     {
802       debug("Requesting shell.");
803       packet_start(SSH_CMSG_EXEC_SHELL);
804       packet_send();
805       packet_write_wait();
806     }
807
808   /* Enter the interactive session. */
809   exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
810
811   /* Close the connection to the remote host. */
812   packet_close();
813   
814   /* Exit with the status returned by the program on the remote side. */
815   exit(exit_status);
816 }
This page took 1.198434 seconds and 5 git commands to generate.