source: trunk/third/ssh/ssh.c @ 12743

Revision 12743, 31.9 KB checked in by danw, 26 years ago (diff)
invoke xauth with "-i" to get around an xauth problem under irix
Line 
1/*
2
3ssh.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8                   All rights reserved
9
10Created: Sat Mar 18 16:36:11 1995 ylo
11
12Ssh client program.  This program can be used to log into a remote machine.
13The software supports strong authentication, encryption, and forwarding
14of X11, TCP/IP, and authentication connections.
15
16*/
17
18/*
19 * $Id: ssh.c,v 1.2 1999-03-22 21:03:14 danw Exp $
20 * $Log: not supported by cvs2svn $
21 * Revision 1.1.1.4  1999/03/08 17:43:23  danw
22 * Import of ssh 1.2.26
23 *
24 * Revision 1.31  1998/07/08 00:47:18  kivinen
25 *      Fixed typo (privileged).
26 *
27 * Revision 1.30  1998/05/23  20:25:44  kivinen
28 *      Changed () -> (void). Added check that {ssh,slogin}{,1}{.old}
29 *      are known program names, not host names. Added missing break
30 *      to 'g' option switch clause.
31 *
32 * Revision 1.29  1998/04/17  00:40:07  kivinen
33 *      Fixed -f code so that it will also use setpgid/setpgrp if
34 *      setsid is not available.
35 *
36 * Revision 1.28  1998/03/27 17:27:34  kivinen
37 *      Removed TSS. Take copy of pw struct immediately.
38 *
39 * Revision 1.27  1998/03/27 17:02:23  kivinen
40 *      Added -g option. Combined getpwuid calls to get around linux
41 *      nis bug. Added gateway ports support.
42 *
43 * Revision 1.26  1998/01/02 06:22:47  kivinen
44 *      Added xauthlocation option support.
45 *
46 * Revision 1.25  1997/08/09 21:17:47  ylo
47 *      Fixed out-of-date comment about being back to user's
48 *      permissions.
49 *
50 * Revision 1.24  1997/08/07 16:22:26  kivinen
51 *      Moved privileged port check to add_local_forward function.
52 *
53 * Revision 1.23  1997/04/27 21:55:01  kivinen
54 *      Added F-SECURE stuff.
55 *
56 * Revision 1.22  1997/04/05 22:00:11  kivinen
57 *      Added LIBWRAP stuff at the beginning.
58 *
59 * Revision 1.21  1997/03/27 13:46:23  kivinen
60 *      Fixed typo.
61 *
62 * Revision 1.20  1997/03/27 03:10:56  kivinen
63 *      Added kerberos patches from Glenn Machin.
64 *      Added -V and -k options.
65 *
66 * Revision 1.19  1997/03/26 07:17:17  kivinen
67 *      Fixed usage so it will display only supported encryption
68 *      algorithms.
69 *
70 * Revision 1.18  1997/03/26 05:34:17  kivinen
71 *      Added -P option.
72 *
73 * Revision 1.17  1997/03/19 19:25:30  kivinen
74 *      Added input buffer clearing for error conditions, so packet.c
75 *      can check that buffer must be empty before new packet is read
76 *      in.
77 *
78 * Revision 1.16  1997/03/19 17:43:41  kivinen
79 *      Limit hostname and username to 255 characters.
80 *
81 * Revision 1.15  1996/11/24 08:25:39  kivinen
82 *      Added SSH_NO_{PORT,X11}_FORWARDING support.
83 *
84 * Revision 1.14  1996/11/19 22:46:03  kivinen
85 *      Added parenthes.
86 *
87 * Revision 1.13  1996/11/07 06:52:52  kivinen
88 *      Allow user@host for ssh too. Patch from peter@baileynm.com
89 *      (Peter da Silva).
90 *
91 * Revision 1.12  1996/11/04 22:13:44  kivinen
92 *      Fixed warning message of old agent to be displayed only if
93 *      user really tried to forward agent (agent running and
94 *      forwarding is not disabled).
95 *
96 * Revision 1.11  1996/10/29 22:45:10  kivinen
97 *      log -> log_msg. Added old agent emulation code (disable agent
98 *      forwarding if the other end is too old).
99 *      Added userfile_uninit again. Agent doesn't need it any more.
100 *
101 * Revision 1.10  1996/10/20 16:23:01  ttsalo
102 *       use normal close() to close authentication socket
103 *
104 * Revision 1.9  1996/10/20 16:19:35  ttsalo
105 *      Added global variable 'original_real_uid' and it's initialization
106 *
107 * Revision 1.8  1996/10/04 01:00:13  kivinen
108 *      Commented userfile_uninit out because we might need userfile
109 *      later to open agent connections.
110 *
111 * Revision 1.7  1996/09/08 17:48:12  ttsalo
112 *      Changed authfd's type from int to UserFile
113 *
114 * Revision 1.6  1996/07/29 03:41:23  ylo
115 *      Recognize remsh as a possible name for ssh.
116 *
117 * Revision 1.5  1996/07/15 07:19:47  ylo
118 *      Added passing of -8 to rlogin/rsh when falling back to them.
119 *
120 * Revision 1.4  1996/07/14 23:33:20  ylo
121 *      Pass -n to rsh/rlogin if given to ssh.
122 *
123 * Revision 1.3  1996/05/29 07:41:34  ylo
124 *      Added arguments to userfile_init.
125 *
126 * Revision 1.2  1996/02/25 13:53:24  ylo
127 *      Fixed a bug that caused falling back to rsh to hang.
128 *
129 * Revision 1.1.1.1  1996/02/18 21:38:12  ylo
130 *      Imported ssh-1.2.13.
131 *
132 * Revision 1.17  1995/09/27  02:48:53  ylo
133 *      Added SOCKS support.
134 *
135 * Revision 1.16  1995/09/27  02:16:10  ylo
136 *      Print "rsh" command line if -v.
137 *
138 * Revision 1.15  1995/09/25  00:01:16  ylo
139 *      Moved client main loop to clientloop.c.
140 *
141 * Revision 1.14  1995/09/22  22:23:55  ylo
142 *      Changed argument list of ssh_login.
143 *
144 * Revision 1.13  1995/09/21  17:13:47  ylo
145 *      Don't print "Connection closed" if -q.
146 *
147 * Revision 1.12  1995/09/13  12:03:37  ylo
148 *      Fixed rhosts authentication.
149 *      Moved channel_prepare_select to the correct location (should
150 *      fix channel closes being reported only after a keypress).
151 *
152 * Revision 1.11  1995/09/10  22:47:34  ylo
153 *      Added uidswap stuff (fixes security problems).  Changed to use
154 *      original_real_uid instead of getuid in various places.
155 *      #ifdef'd some SIGWINCH stuff.
156 *
157 * Revision 1.10  1995/09/09  21:26:45  ylo
158 * /m/shadows/u2/users/ylo/ssh/README
159 *
160 * Revision 1.9  1995/08/31  09:23:32  ylo
161 *      Copy struct pw.
162 *
163 * Revision 1.8  1995/08/29  22:33:24  ylo
164 *      Clear IEXTEN when going to raw mode.
165 *
166 * Revision 1.7  1995/08/21  23:28:32  ylo
167 *      Added -q.
168 *      Added dummy syslog facility argument to log_init.
169 *
170 * Revision 1.6  1995/08/18  22:56:33  ylo
171 *      Clarified some error messages.
172 *
173 * Revision 1.5  1995/07/27  00:40:34  ylo
174 *      Added GlobalKnownHostsFile and UserKnownHostsFile.
175 *
176 * Revision 1.4  1995/07/26  23:15:25  ylo
177 *      Removed include version.h.
178 *
179 * Revision 1.3  1995/07/15  13:27:56  ylo
180 *      Fixed a typo in usage().
181 *      Moved -l in running rsh after the host.
182 *
183 * Revision 1.2  1995/07/13  01:40:03  ylo
184 *      Removed "Last modified" header.
185 *      Added cvs log.
186 *
187 * $Endlog$
188 */
189
190#include "includes.h"
191#include "xmalloc.h"
192#include "randoms.h"
193#include "ssh.h"
194#include "packet.h"
195#include "buffer.h"
196#include "authfd.h"
197#include "readconf.h"
198#include "userfile.h"
199#include "emulate.h"
200
201#ifdef LIBWRAP
202#include <tcpd.h>
203#include <syslog.h>
204#ifdef NEED_SYS_SYSLOG_H
205#include <sys/syslog.h>
206#endif /* NEED_SYS_SYSLOG_H */
207int allow_severity = LOG_INFO;
208int deny_severity = LOG_WARNING;
209#endif /* LIBWRAP */
210
211/* Random number generator state.  This is initialized in ssh_login, and
212   left initialized.  This is used both by the packet module and by various
213   other functions. */
214RandomState random_state;
215
216/* Flag indicating whether debug mode is on.  This can be set on the
217   command line. */
218int debug_flag = 0;
219
220/* Flag indicating whether quiet mode is on. */
221int quiet_flag = 0;
222
223/* Flag indicating whether to allocate a pseudo tty.  This can be set on the
224   command line, and is automatically set if no command is given on the command
225   line. */
226int tty_flag = 0;
227
228/* Flag indicating that nothing should be read from stdin.  This can be set
229   on the command line. */
230int stdin_null_flag = 0;
231
232/* Flag indicating whether -8 was given on the command line. */
233int binary_clean_flag = 0;
234
235/* Flag indicating that ssh should fork after authentication.  This is useful
236   so that the pasphrase can be entered manually, and then ssh goes to the
237   background. */
238int fork_after_authentication_flag = 0;
239
240/* General data structure for command line options and options configurable
241   in configuration files.  See readconf.h. */
242Options options;
243
244/* Name of the host we are connecting to.  This is the name given on the
245   command line, or the HostName specified for the user-supplied name
246   in a configuration file. */
247char *host;
248
249#ifdef SIGWINCH
250/* Flag to indicate that we have received a window change signal which has
251   not yet been processed.  This will cause a message indicating the new
252   window size to be sent to the server a little later.  This is volatile
253   because this is updated in a signal handler. */
254volatile int received_window_change_signal = 0;
255#endif /* SIGWINCH */
256
257/* Value of argv[0] (set in the main program). */
258char *av0;
259
260/* Flag indicating whether we have a valid host private key loaded. */
261int host_private_key_loaded = 0;
262
263/* Host private key. */
264RSAPrivateKey host_private_key;
265
266/* Original real uid. */
267uid_t original_real_uid;
268
269
270/* Prints a help message to the user.  This function never returns. */
271void usage(void)
272{
273  fprintf(stderr, "Usage: %s [options] host [command]\n", av0);
274  fprintf(stderr, "Options:\n");
275  fprintf(stderr, "  -l user     Log in using this user name.\n");
276  fprintf(stderr, "  -n          Redirect input from /dev/null.\n");
277  fprintf(stderr, "  -a          Disable authentication agent forwarding.\n");
278#if defined(KERBEROS_TGT_PASSING) && defined(KRB5)
279  fprintf(stderr, "  -k          Disable Kerberos ticket passing.\n");
280#endif /* defined(KERBEROS_TGT_PASSING) && defined(KRB5) */
281#ifndef SSH_NO_X11_FORWARDING
282  fprintf(stderr, "  -x          Disable X11 connection forwarding.\n");
283#endif
284  fprintf(stderr, "  -i file     Identity for RSA authentication (default: ~/.ssh/identity).\n");
285  fprintf(stderr, "  -t          Tty; allocate a tty even if command is given.\n");
286  fprintf(stderr, "  -v          Verbose; display verbose debugging messages.\n");
287  fprintf(stderr, "  -V          Display version number only.\n");
288  fprintf(stderr, "  -q          Quiet; don't display any warning messages.\n");
289  fprintf(stderr, "  -f          Fork into background after authentication.\n");
290  fprintf(stderr, "  -e char     Set escape character; ``none'' = disable (default: ~).\n");
291  fprintf(stderr, "  -c cipher   Select encryption algorithm: "
292#ifdef WITH_DES
293          "``des'', "
294#endif /* WITH_DES */
295#ifdef WITH_ARCFOUR
296          "``arcfour'', "
297#endif /* WITH_ARCFOUR */
298#ifdef WITH_NONE
299          "``none'', "
300#endif /* WITH_NONE */
301#ifdef WITH_IDEA
302          "``idea'', "
303#endif /* WITH_IDEA */
304#ifdef WITH_BLOWFISH
305          "``blowfish'', "
306#endif /* WITH_BLOWFISH */
307          "``3des''\n");
308  fprintf(stderr, "  -p port     Connect to this port.  Server must be on the same port.\n");
309  fprintf(stderr, "  -P          Don't use privileged source port.\n");
310#ifndef SSH_NO_PORT_FORWARDING
311  fprintf(stderr, "  -L listen-port:host:port   Forward local port to remote address\n");
312  fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");
313  fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", av0);
314  fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
315#endif
316  fprintf(stderr, "  -C          Enable compression.\n");
317  fprintf(stderr, "  -g          Allow remote hosts to connect to local port forwardings\n");
318  fprintf(stderr, "  -o 'option' Process the option as if it was read from a configuration file.\n");
319  exit(1);
320}
321
322/* Connects to the given host using rsh (or prints an error message and exits
323   if rsh is not available).  This function never returns. */
324
325void rsh_connect(char *host, char *user, Buffer *command)
326{
327#ifdef RSH_PATH
328  char *args[10];
329  char rsh_program_name[256];
330  char *cp;
331  int i;
332 
333  log_msg("Using rsh.  WARNING: Connection will not be encrypted.");
334
335  /* Switch to the original uid permanently. */
336  if (setuid(getuid()) < 0)
337    fatal("setuid: %s", strerror(errno));
338
339  /* Compute the full path of the suitable rsh/rlogin program. */
340  if (strchr(av0, '/'))
341    cp = strrchr(av0, '/') + 1;
342  else
343    cp = av0;
344  if (strcmp(cp, "rlogin") == 0 || strcmp(cp, "slogin") == 0)
345    {
346      strncpy(rsh_program_name, RSH_PATH, sizeof(rsh_program_name));
347      rsh_program_name[sizeof(rsh_program_name) - 20] = '\0';
348      if (strchr(rsh_program_name, '/'))
349        *strrchr(rsh_program_name, '/') = '\0';
350      sprintf(rsh_program_name + strlen(rsh_program_name), "/rlogin");
351    }
352  else
353    {
354      strncpy(rsh_program_name, RSH_PATH, sizeof(rsh_program_name));
355      rsh_program_name[sizeof(rsh_program_name) - 1] = '\0';
356    }
357
358  /* Build argument list for rsh. */
359  i = 0;
360  args[i++] = rsh_program_name;
361  args[i++] = host;    /* may have to come after user on some systems */
362  if (user)
363    {
364      args[i++] = "-l";
365      args[i++] = user;
366    }
367  if (stdin_null_flag)
368    args[i++] = "-n";
369  if (binary_clean_flag)
370    args[i++] = "-8";
371  if (buffer_len(command) > 0)
372    {
373      buffer_append(command, "\0", 1);
374      args[i++] = buffer_ptr(command);
375    }
376  args[i++] = NULL;
377  if (debug_flag)
378    {
379      for (i = 0; args[i]; i++)
380        {
381          if (i != 0)
382            fprintf(stderr, " ");
383          fprintf(stderr, "%s", args[i]);
384        }
385      fprintf(stderr, "\n");
386    }
387  execv(rsh_program_name, args);
388  perror(rsh_program_name);
389  exit(1);
390#else /* RSH_PATH */
391  fatal("Rsh not available.");
392#endif /* RSH_PATH */
393}
394
395/* Main program for the ssh client. */
396
397int main(int ac, char **av)
398{
399  int i, opt, optind, type, exit_status, ok, fwd_port, fwd_host_port;
400  int authfd;
401  char *optarg, *cp, buf[256];
402  Buffer command;
403  struct stat st;
404  struct passwd *pw, pwcopy;
405  int interactive = 0, dummy;
406  int use_privileged_port = 1;
407  uid_t original_effective_uid;
408#ifdef SIGWINCH
409  struct winsize ws;
410#endif /* SIGWINCH */
411
412  /* Save the original real uid.  It will be needed later (uid-swapping may
413     clobber the real uid).  */
414  original_real_uid = getuid();
415  original_effective_uid = geteuid();
416
417  /* Set signals and core limits so that we cannot dump core.  */
418  signals_prevent_core();
419
420  pw = getpwuid(original_real_uid);
421  if (!pw)
422    {
423      fprintf(stderr, "You don't exist, go away!\n");
424      exit(1);
425    }
426 
427  /* Take a copy of the returned structure. */
428  memset(&pwcopy, 0, sizeof(pwcopy));
429  pwcopy.pw_name = xstrdup(pw->pw_name);
430  pwcopy.pw_passwd = xstrdup(pw->pw_passwd);
431  pwcopy.pw_uid = pw->pw_uid;
432  pwcopy.pw_gid = pw->pw_gid;
433  pwcopy.pw_dir = xstrdup(pw->pw_dir);
434  pwcopy.pw_shell = xstrdup(pw->pw_shell);
435  pw = &pwcopy;
436 
437  /* Start reading files as the specified user.  However, if we are not running
438     suid root, all access can be done locally, and there is no need to
439     initialize explicitly. */
440  if (original_real_uid != original_effective_uid)
441    {
442      userfile_init(pw->pw_name, pw->pw_uid, pw->pw_gid, NULL, NULL);
443    }
444
445#ifdef HAVE_UMASK
446  /* Set our umask to something reasonable, as some files are created with
447     the default umask.  This will make them world-readable but writable
448     only by the owner, which is ok for all files for which we don't set
449     the modes explicitly. */
450  umask(022);
451#endif /* HAVE_UMASK */
452 
453  /* Save our own name. */
454  av0 = av[0];
455
456#ifdef SOCKS
457  /* Initialize SOCKS (the firewall traversal library). */
458  SOCKSinit(av0);
459#endif /* SOCKS */
460
461  /* Set RSA (actually gmp) memory allocation functions. */
462  rsa_set_mp_memory_allocation();
463
464  /* Initialize option structure to indicate that no values have been set. */
465  initialize_options(&options);
466
467  /* Parse command-line arguments. */
468  host = NULL;
469
470  /* If program name is not one of the standard names, use it as host name. */
471  if (strchr(av0, '/'))
472    cp = strrchr(av0, '/') + 1;
473  else
474    cp = av0;
475  if (strcmp(cp, "rsh") != 0 && strcmp(cp, "ssh") != 0 &&
476      strcmp(cp, "rlogin") != 0 && strcmp(cp, "slogin") != 0 &&
477      strcmp(cp, "ssh1") != 0 && strcmp(cp, "slogin1") != 0 &&
478      strcmp(cp, "ssh.old") != 0 && strcmp(cp, "slogin.old") != 0 &&
479      strcmp(cp, "ssh1.old") != 0 && strcmp(cp, "slogin1.old") != 0 &&
480      strcmp(cp, "remsh") != 0)
481    host = cp;
482 
483  for (optind = 1; optind < ac; optind++)
484    {
485      if (av[optind][0] != '-')
486        {
487          if (host)
488            break;
489          host = av[optind];
490         
491          /* allows 'user@host' */
492          if(cp = strchr(host, '@')) {
493            options.user = host;
494            *cp++ = '\0';
495            host = cp;
496          }
497          continue;
498        }
499      opt = av[optind][1];
500      if (!opt)
501        usage();
502      if (strchr("eilcpLRo", opt)) /* options with arguments */
503        {
504          optarg = av[optind] + 2;
505          if (strcmp(optarg, "") == 0)
506            {
507              if (optind >= ac - 1)
508                usage();
509              optarg = av[++optind];
510            }
511        }
512      else
513        {
514          if (av[optind][2])
515            usage();
516          optarg = NULL;
517        }
518      switch (opt)
519        {
520        case 'n':
521          stdin_null_flag = 1;
522          break;
523
524        case 'f':
525          fork_after_authentication_flag = 1;
526          stdin_null_flag = 1;
527          break;
528
529        case 'x':
530          options.forward_x11 = 0;
531          break;
532
533        case 'a':
534          options.forward_agent = 0;
535          break;
536
537        case 'k':
538          options.kerberos_tgt_passing = 0;
539          break;
540         
541        case 'i':
542          if (userfile_stat(original_real_uid, optarg, &st) < 0)
543            {
544              fprintf(stderr, "Warning: Identity file %s does not exist.\n",
545                      optarg);
546              break;
547            }
548          if (options.num_identity_files >= SSH_MAX_IDENTITY_FILES)
549            fatal("Too many identity files specified (max %d)",
550                  SSH_MAX_IDENTITY_FILES);
551          options.identity_files[options.num_identity_files++] =
552            xstrdup(optarg);
553          break;
554
555        case 't':
556          tty_flag = 1;
557          break;
558
559        case 'V':
560#ifdef F_SECURE_COMMERCIAL
561
562#endif /* F_SECURE_COMMERCIAL */
563          fprintf(stderr, "SSH Version %s [%s], protocol version %d.%d.\n",
564                  SSH_VERSION, HOSTTYPE, PROTOCOL_MAJOR, PROTOCOL_MINOR);
565#ifdef RSAREF
566          fprintf(stderr, "Compiled with RSAREF.\n");
567#else /* RSAREF */
568          fprintf(stderr, "Standard version.  Does not use RSAREF.\n");
569#endif /* RSAREF */
570          exit(0);
571         
572        case 'v':
573          debug_flag = 1;
574#ifdef F_SECURE_COMMERCIAL
575
576#endif /* F_SECURE_COMMERCIAL */
577          fprintf(stderr, "SSH Version %s [%s], protocol version %d.%d.\n",
578                  SSH_VERSION, HOSTTYPE, PROTOCOL_MAJOR, PROTOCOL_MINOR);
579#ifdef RSAREF
580          fprintf(stderr, "Compiled with RSAREF.\n");
581#else /* RSAREF */
582          fprintf(stderr, "Standard version.  Does not use RSAREF.\n");
583#endif /* RSAREF */
584          break;
585
586        case 'q':
587          quiet_flag = 1;
588          break;
589
590        case 'e':
591          if (optarg[0] == '^' && optarg[2] == 0 &&
592              (unsigned char)optarg[1] >= 64 && (unsigned char)optarg[1] < 128)
593            options.escape_char = (unsigned char)optarg[1] & 31;
594          else
595            if (strlen(optarg) == 1)
596              options.escape_char = (unsigned char)optarg[0];
597            else
598              if (strcmp(optarg, "none") == 0)
599                options.escape_char = -2;
600              else
601                {
602                  fprintf(stderr, "Bad escape character '%s'.\n", optarg);
603                  exit(1);
604                }
605          break;
606
607        case 'c':
608          options.cipher = cipher_number(optarg);
609          if (options.cipher == -1)
610            {
611              fprintf(stderr, "Unknown cipher type '%s'\n", optarg);
612              exit(1);
613            }
614          break;
615
616        case 'p':
617          options.port = atoi(optarg);
618          if (options.port < 1 || options.port > 65535)
619            {
620              fprintf(stderr, "Bad port %s.\n", optarg);
621              exit(1);
622            }
623          break;
624
625        case 'l':
626          options.user = optarg;
627          break;
628
629        case 'R':
630#ifndef SSH_NO_PORT_FORWARDING
631          if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
632                     &fwd_host_port) != 3)
633            {
634              fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
635              usage();
636              /*NOTREACHED*/
637            }
638          add_remote_forward(&options, fwd_port, buf, fwd_host_port);
639#endif
640          break;
641
642        case 'L':
643#ifndef SSH_NO_PORT_FORWARDING
644          if (sscanf(optarg, "%d:%255[^:]:%d", &fwd_port, buf,
645                     &fwd_host_port) != 3)
646            {
647              fprintf(stderr, "Bad forwarding specification '%s'.\n", optarg);
648              usage();
649              /*NOTREACHED*/
650            }
651          add_local_forward(&options, fwd_port, buf, fwd_host_port);
652#endif
653          break;
654
655        case 'C':
656          options.compression = 1;
657          break;
658
659        case 'o':
660          dummy = 1;
661          process_config_line(&options, host ? host : "", optarg,
662                              "command-line", 0, &dummy);
663          break;
664
665        case '8':
666          /* Ssh is always 8-bit-clean.  This option is only
667             recognized for backwards compatibility with ssh, and is
668             passed to rsh/rlogin if falling back to them. */
669          binary_clean_flag = 1;
670          break;
671
672        case 'P':
673          use_privileged_port = 0;
674          break;
675
676        case 'g':
677          options.gateway_ports = 1;
678          break;
679
680        default:
681          usage();
682        }
683    }
684
685 /* Check that we got a host name. */
686  if (!host)
687    usage();
688
689  /* Initialize the command to execute on remote host. */
690  buffer_init(&command);
691
692  /* Save the command to execute on the remote host in a buffer.  There is
693     no limit on the length of the command, except by the maximum packet
694     size.  Also sets the tty flag if there is no command. */
695  if (optind == ac)
696    {
697      /* No command specified - execute shell on a tty. */
698      tty_flag = 1;
699    }
700  else
701    {
702      /* A command has been specified.  Store it into the buffer. */
703      for (i = optind; i < ac; i++)
704        {
705          if (i > optind)
706            buffer_append(&command, " ", 1);
707          buffer_append(&command, av[i], strlen(av[i]));
708        }
709    }
710
711  /* Cannot fork to background if no command. */
712  if (fork_after_authentication_flag && buffer_len(&command) == 0)
713    fatal("Cannot fork into background without a command to execute.");
714 
715  /* Allocate a tty by default if no command specified. */
716  if (buffer_len(&command) == 0)
717    tty_flag = 1;
718
719  /* Do not allocate a tty if stdin is not a tty. */
720  if (!isatty(fileno(stdin)))
721    {
722      if (tty_flag)
723        fprintf(stderr, "Pseudo-terminal will not be allocated because stdin is not a terminal.\n");
724      tty_flag = 0;
725    }
726
727  /* Initialize "log" output.  Since we are the client all output actually
728     goes to the terminal. */
729  log_init(av[0], 1, debug_flag, quiet_flag, SYSLOG_FACILITY_USER);
730
731  /* Read per-user configuration file. */
732  sprintf(buf, "%.100s/%s", pw->pw_dir, SSH_USER_CONFFILE);
733  read_config_file(original_real_uid, buf, host, &options);
734
735  /* Read systemwide configuration file. */
736  read_config_file(original_real_uid, HOST_CONFIG_FILE, host, &options);
737
738  /* Fill configuration defaults. */
739  fill_default_options(&options);
740  if (options.user == NULL)
741    {
742      options.no_user_given = 1;
743      options.user = xstrdup(pw->pw_name);
744    }
745
746  if (options.hostname != NULL)
747    host = options.hostname;
748
749  /* Limit the hostname and username length to 255 characters */
750  if (strlen(host) > 255 || strlen(options.user) > 255)
751    fatal("Hostname or username is longer than 255 characters.");
752
753  /* Disable rhosts authentication if not running as root. */
754  if (original_effective_uid != UID_ROOT)
755    {
756      options.rhosts_authentication = 0;
757      options.rhosts_rsa_authentication = 0;
758    }
759
760  /* If using rsh has been selected, exec it now (without trying anything
761     else).  Note that we must release privileges first. */
762  if (options.use_rsh)
763    {
764      /* Execute rsh. */
765      userfile_uninit();
766      rsh_connect(host, options.user, &command);
767      fatal("rsh_connect returned");
768    }
769
770  if (use_privileged_port && !options.use_privileged_port)
771    {
772      use_privileged_port = 0;
773    }
774  if (!options.rhosts_authentication && !options.rhosts_rsa_authentication)
775    {
776      use_privileged_port = 0;
777    }
778  /* Open a connection to the remote host.  This needs root privileges if
779     rhosts_authentication is true.  Note that the random_state is not
780     yet used by this call, although a pointer to it is stored, and thus it
781     need not be initialized. */
782  ok = ssh_connect(host, options.port, options.connection_attempts,
783                   !use_privileged_port,
784                   original_real_uid, options.proxy_command, &random_state);
785
786  /* Check if the connection failed, and try "rsh" if appropriate. */
787  if (!ok)
788    {
789      userfile_uninit();
790      if (options.port != 0)
791        log_msg("Secure connection to %.100s on port %d refused%s.",
792            host, options.port,
793            options.fallback_to_rsh ? "; reverting to insecure method" : "");
794      else
795        log_msg("Secure connection to %.100s refused%s.", host,
796            options.fallback_to_rsh ? "; reverting to insecure method" : "");
797
798      if (options.fallback_to_rsh)
799        {
800          rsh_connect(host, options.user, &command);
801          fatal("rsh_connect returned");
802        }
803      exit(1);
804      /*NOTREACHED*/
805    }
806
807  /* Successful connection. */
808  /* Load the host private key in case we will need it later for
809     combined rsa-rhosts authentication.  This must be done before
810     releasing extra privileges, because the file is only readable by
811     root.  */
812  if (ok)
813    {
814      if (load_private_key(geteuid(), HOST_KEY_FILE, "", &host_private_key,
815                           NULL))
816        host_private_key_loaded = 1;
817    }
818
819  /* Create ~/.ssh directory if it doesn\'t already exist. */
820  sprintf(buf, "%.100s/%s", pw->pw_dir, SSH_USER_DIR);
821  if (userfile_stat(original_real_uid, buf, &st) < 0)
822    if (userfile_mkdir(original_real_uid, buf, 0755) < 0)
823      error("Could not create directory '%.200s'.", buf);
824
825  /* Expand ~ in options.identity_files. */
826  for (i = 0; i < options.num_identity_files; i++)
827    options.identity_files[i] =
828      tilde_expand_filename(options.identity_files[i], original_real_uid);
829
830  /* Expand ~ in known host file names. */
831  options.system_hostfile = tilde_expand_filename(options.system_hostfile,
832                                                  original_real_uid);
833  options.user_hostfile = tilde_expand_filename(options.user_hostfile,
834                                                original_real_uid);
835
836  /* Log into the remote system.  This never returns if the login fails.
837     Note: this initializes the random state, and leaves it initialized. */
838  ssh_login(&random_state, host_private_key_loaded, &host_private_key,
839            host, &options, original_real_uid);
840
841  /* We no longer need the host private key.  Clear it now. */
842  if (host_private_key_loaded)
843    rsa_clear_private_key(&host_private_key);
844
845  /* Enable compression if requested. */
846  if (options.compression)
847    {
848      debug("Requesting compression at level %d.", options.compression_level);
849
850      if (options.compression_level < 1 || options.compression_level > 9)
851        fatal("Compression level must be from 1 (fast) to 9 (slow, best).");
852
853      /* Send the request. */
854      packet_start(SSH_CMSG_REQUEST_COMPRESSION);
855      packet_put_int(options.compression_level);
856      packet_send();
857      packet_write_wait();
858      type = packet_read();
859      if (type == SSH_SMSG_SUCCESS)
860        packet_start_compression(options.compression_level);
861      else
862        {
863          packet_get_all();
864          log_msg("Warning: Remote host refused compression.");
865        }
866    }
867
868  /* Allocate a pseudo tty if appropriate. */
869  if (tty_flag)
870    {
871      debug("Requesting pty.");
872
873      /* Start the packet. */
874      packet_start(SSH_CMSG_REQUEST_PTY);
875
876      /* Store TERM in the packet.  There is no limit on the length of the
877         string. */
878      cp = getenv("TERM");
879      if (!cp)
880        cp = "";
881      packet_put_string(cp, strlen(cp));
882
883      /* Store window size in the packet. */
884#ifdef SIGWINCH
885      if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
886        memset(&ws, 0, sizeof(ws));
887      packet_put_int(ws.ws_row);
888      packet_put_int(ws.ws_col);
889      packet_put_int(ws.ws_xpixel);
890      packet_put_int(ws.ws_ypixel);
891#else /* SIGWINCH */
892      packet_put_int(0);
893      packet_put_int(0);
894      packet_put_int(0);
895      packet_put_int(0);
896#endif /* SIGWINCH */
897     
898      /* Store tty modes in the packet. */
899      tty_make_modes(fileno(stdin));
900
901      /* Send the packet, and wait for it to leave. */
902      packet_send();
903      packet_write_wait();
904
905      /* Read response from the server. */
906      type = packet_read();
907      if (type == SSH_SMSG_SUCCESS)
908        interactive = 1;
909      else
910        {
911          packet_get_all();
912          log_msg("Warning: Remote host failed or refused to allocate a pseudo tty.");
913        }
914    }
915
916#ifndef SSH_NO_X11_FORWARDING
917  /* Request X11 forwarding if enabled and DISPLAY is set. */
918  if (options.forward_x11 && getenv("DISPLAY") != NULL)
919    {
920      char line[512], proto[512], data[512];
921      int forwarded = 0, got_data = 0, i;
922      UserFile uf;
923
924#ifdef XAUTH_PATH
925      /* Try to get Xauthority information for the display. */
926      sprintf(line, "%.100s -i list %.200s 2>/dev/null",
927              options.xauth_path, getenv("DISPLAY"));
928      /* Note that we are already running on the user's uid. */
929      uf = userfile_popen(original_real_uid, line, "r");
930      if (uf && userfile_gets(line, sizeof(line), uf) &&
931          sscanf(line, "%*s %s %s", proto, data) == 2)
932        got_data = 1;
933      else
934        debug("Failed to get local xauth data.");
935      if (uf)
936        userfile_pclose(uf);
937#else /* XAUTH_PATH */
938      debug("No xauth data: no xauth program was found at configure time.");
939#endif /* XAUTH_PATH */
940      /* If we didn't get authentication data, just make up some data.  The
941         forwarding code will check the validity of the response anyway, and
942         substitute this data.  The X11 server, however, will ignore this
943         fake data and use whatever authentication mechanisms it was using
944         otherwise for the local connection. */
945      if (!got_data)
946        {
947          strcpy(proto, "MIT-MAGIC-COOKIE-1");
948          for (i = 0; i < 16; i++)
949            sprintf(data + 2 * i, "%02x", random_get_byte(&random_state));
950        }
951
952      /* Got local authentication reasonable information.  Request forwarding
953         with authentication spoofing. */
954      debug("Requesting X11 forwarding with authentication spoofing.");
955      x11_request_forwarding_with_spoofing(&random_state, proto, data);
956
957      /* Read response from the server. */
958      type = packet_read();
959      if (type == SSH_SMSG_SUCCESS)
960        {
961          forwarded = 1;
962          interactive = 1;
963        }
964      else
965        {
966          packet_get_all();
967          log_msg("Warning: Remote host denied X11 forwarding, perhaps xauth program could not be run on the server side.");
968        }
969    }
970#endif /* SSH_NO_X11_FORWARDING */
971
972  /* Tell the packet module whether this is an interactive session. */
973  packet_set_interactive(interactive, options.keepalives);
974
975  if (options.forward_agent)
976    {
977      /* Clear agent forwarding if we don\'t have an agent. */
978      authfd = ssh_get_authentication_fd();
979      if (authfd == -1)
980        options.forward_agent = 0;
981      else
982        close(authfd);
983      if ((emulation_information & EMULATE_OLD_AGENT_BUG) &&
984          options.forward_agent)
985        {
986          log_msg("Warning: Denied agent forwarding because the other end has too old version.");
987          options.forward_agent = 0;
988        }
989    }
990 
991  /* Request authentication agent forwarding if appropriate. */
992  if (options.forward_agent)
993    {
994      debug("Requesting authentication agent forwarding.");
995      auth_request_forwarding();
996     
997      /* Read response from the server. */
998      type = packet_read();
999      if (type != SSH_SMSG_SUCCESS)
1000        {
1001          packet_get_all();
1002          log_msg("Warning: Remote host denied authentication agent forwarding.");
1003        }
1004    }
1005
1006#ifndef SSH_NO_PORT_FORWARDING
1007  /* Initiate local TCP/IP port forwardings. */
1008  for (i = 0; i < options.num_local_forwards; i++)
1009    {
1010      debug("Connections to local port %d forwarded to remote address %.200s:%d",
1011            options.local_forwards[i].port, options.local_forwards[i].host,
1012            options.local_forwards[i].host_port);
1013      channel_request_local_forwarding(options.local_forwards[i].port,
1014                                       options.local_forwards[i].host,
1015                                       options.local_forwards[i].host_port,
1016                                       options.gateway_ports);
1017    }
1018
1019  /* Initiate remote TCP/IP port forwardings. */
1020  for (i = 0; i < options.num_remote_forwards; i++)
1021    {
1022      debug("Connections to remote port %d forwarded to local address %.200s:%d",
1023            options.remote_forwards[i].port, options.remote_forwards[i].host,
1024            options.remote_forwards[i].host_port);
1025      channel_request_remote_forwarding(options.remote_forwards[i].port,
1026                                        options.remote_forwards[i].host,
1027                                        options.remote_forwards[i].host_port);
1028    }
1029#endif /* SSH_NO_PORT_FORWARDING */
1030
1031  /* We will no longer need the forked process that reads files on the
1032     user's uid. */
1033  userfile_uninit();
1034 
1035  /* If requested, fork and let ssh continue in the background. */
1036  if (fork_after_authentication_flag)
1037    {
1038      int ret = fork();
1039      if (ret == -1)
1040        fatal("fork failed: %.100s", strerror(errno));
1041      if (ret != 0)
1042        exit(0);
1043#ifdef HAVE_SETSID
1044      setsid();
1045#else /* HAVE_SETSID */
1046#ifdef HAVE_SETPGID
1047      setpgid(0, 0);
1048#else
1049      setpgrp(0, 0);
1050#endif /* HAVE_SETPGID */
1051#endif /* HAVE_SETSID */
1052      if(tty_flag) {    /* user did combination of -f and -t */
1053        debug("Stopped using local pty.");
1054        tty_flag = 0;   /* no longer have a tty... */
1055      }
1056    }
1057
1058  /* If a command was specified on the command line, execute the command now.
1059     Otherwise request the server to start a shell. */
1060  if (buffer_len(&command) > 0)
1061    {
1062      int len = buffer_len(&command);
1063      if (len > 900)
1064        len = 900;
1065      debug("Sending command: %.*s", len, buffer_ptr(&command));
1066      packet_start(SSH_CMSG_EXEC_CMD);
1067      packet_put_string(buffer_ptr(&command), buffer_len(&command));
1068      packet_send();
1069      packet_write_wait();
1070    }
1071  else
1072    {
1073      debug("Requesting shell.");
1074      packet_start(SSH_CMSG_EXEC_SHELL);
1075      packet_send();
1076      packet_write_wait();
1077    }
1078
1079  /* Enter the interactive session. */
1080  exit_status = client_loop(tty_flag, tty_flag ? options.escape_char : -1);
1081
1082  /* Close the connection to the remote host. */
1083  packet_close();
1084 
1085  /* Exit with the status returned by the program on the remote side. */
1086  exit(exit_status);
1087}
Note: See TracBrowser for help on using the repository browser.