[BACK]Return to session.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/session.c between version 1.42 and 1.42.2.6

version 1.42, 2000/10/27 07:32:18 version 1.42.2.6, 2001/09/27 00:15:42
Line 9 
Line 9 
  * called by a name other than "ssh" or "Secure Shell".   * called by a name other than "ssh" or "Secure Shell".
  *   *
  * SSH2 support by Markus Friedl.   * SSH2 support by Markus Friedl.
  * Copyright (c) 2000 Markus Friedl. All rights reserved.   * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 35 
Line 35 
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
 #include "xmalloc.h"  
 #include "ssh.h"  #include "ssh.h"
 #include "pty.h"  #include "ssh1.h"
   #include "ssh2.h"
   #include "xmalloc.h"
   #include "sshpty.h"
 #include "packet.h"  #include "packet.h"
 #include "buffer.h"  #include "buffer.h"
 #include "mpaux.h"  #include "mpaux.h"
 #include "servconf.h"  
 #include "uidswap.h"  #include "uidswap.h"
 #include "compat.h"  #include "compat.h"
 #include "channels.h"  #include "channels.h"
 #include "nchan.h"  
   
 #include "bufaux.h"  #include "bufaux.h"
 #include "ssh2.h"  
 #include "auth.h"  #include "auth.h"
 #include "auth-options.h"  #include "auth-options.h"
   #include "pathnames.h"
   #include "log.h"
   #include "servconf.h"
   #include "sshlogin.h"
   #include "serverloop.h"
   #include "canohost.h"
   #include "session.h"
   
 #ifdef HAVE_LOGIN_CAP  
 #include <login_cap.h>  
 #endif  
   
 /* types */  /* types */
   
 #define TTYSZ 64  #define TTYSZ 64
Line 63 
Line 64 
 struct Session {  struct Session {
         int     used;          int     used;
         int     self;          int     self;
         int     extended;          struct passwd *pw;
         struct  passwd *pw;          Authctxt *authctxt;
         pid_t   pid;          pid_t   pid;
         /* tty */          /* tty */
         char    *term;          char    *term;
Line 79 
Line 80 
         int     single_connection;          int     single_connection;
         /* proto 2 */          /* proto 2 */
         int     chanid;          int     chanid;
           int     is_subsystem;
 };  };
   
 /* func */  /* func */
   
 Session *session_new(void);  Session *session_new(void);
 void    session_set_fds(Session *s, int fdin, int fdout, int fderr);  void    session_set_fds(Session *, int, int, int);
 void    session_pty_cleanup(Session *s);  static void     session_pty_cleanup(void *);
 void    session_proctitle(Session *s);  void    session_proctitle(Session *);
 void    do_exec_pty(Session *s, const char *command, struct passwd * pw);  int     session_setup_x11fwd(Session *);
 void    do_exec_no_pty(Session *s, const char *command, struct passwd * pw);  void    do_exec_pty(Session *, const char *);
 void    do_login(Session *s, const char *command);  void    do_exec_no_pty(Session *, const char *);
   void    do_exec(Session *, const char *);
   void    do_login(Session *, const char *);
   void    do_child(Session *, const char *);
   void    do_motd(void);
   int     check_quietlogin(Session *, const char *);
   
 void  static void do_authenticated1(Authctxt *);
 do_child(const char *command, struct passwd * pw, const char *term,  static void do_authenticated2(Authctxt *);
     const char *display, const char *auth_proto,  
     const char *auth_data, const char *ttyname);  
   
   static void session_close(Session *);
   static int session_pty_req(Session *);
   
 /* import */  /* import */
 extern ServerOptions options;  extern ServerOptions options;
 extern char *__progname;  extern char *__progname;
 extern int log_stderr;  extern int log_stderr;
 extern int debug_flag;  extern int debug_flag;
 extern unsigned int utmp_len;  extern u_int utmp_len;
   
 extern int startup_pipe;  extern int startup_pipe;
   extern void destroy_sensitive_data(void);
   
 /* Local Xauthority file. */  
 static char *xauthfile;  
   
 /* original command from peer. */  /* original command from peer. */
 char *original_command = NULL;  const char *original_command = NULL;
   
 /* data */  /* data */
 #define MAX_SESSIONS 10  #define MAX_SESSIONS 10
Line 119 
Line 124 
 static login_cap_t *lc;  static login_cap_t *lc;
 #endif  #endif
   
 /*  
  * Remove local Xauthority file.  
  */  
 void  void
 xauthfile_cleanup_proc(void *ignore)  do_authenticated(Authctxt *authctxt)
 {  {
         debug("xauthfile_cleanup_proc called");          /*
            * Cancel the alarm we set to limit the time taken for
         if (xauthfile != NULL) {           * authentication.
                 char *p;           */
                 unlink(xauthfile);          alarm(0);
                 p = strrchr(xauthfile, '/');          if (startup_pipe != -1) {
                 if (p != NULL) {                  close(startup_pipe);
                         *p = '\0';                  startup_pipe = -1;
                         rmdir(xauthfile);  
                 }  
                 xfree(xauthfile);  
                 xauthfile = NULL;  
         }          }
 }  #ifdef HAVE_LOGIN_CAP
           if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) {
 /*                  error("unable to get login class");
  * Function to perform cleanup if we get aborted abnormally (e.g., due to a                  return;
  * dropped connection).  
  */  
 void  
 pty_cleanup_proc(void *session)  
 {  
         Session *s=session;  
         if (s == NULL)  
                 fatal("pty_cleanup_proc: no session");  
         debug("pty_cleanup_proc: %s", s->tty);  
   
         if (s->pid != 0) {  
                 /* Record that the user has logged out. */  
                 record_logout(s->pid, s->tty);  
         }          }
   #ifdef BSD_AUTH
           if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) {
                   packet_disconnect("Approval failure for %s",
                       authctxt->pw->pw_name);
           }
   #endif
   #endif
           /* setup the channel layer */
           if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
                   channel_permit_all_opens();
   
         /* Release the pseudo-tty. */          if (compat20)
         pty_release(s->tty);                  do_authenticated2(authctxt);
           else
                   do_authenticated1(authctxt);
   
           /* remove agent socket */
           if (auth_get_socket_name())
                   auth_sock_cleanup_proc(authctxt->pw);
   #ifdef KRB4
           if (options.kerberos_ticket_cleanup)
                   krb4_cleanup_proc(authctxt);
   #endif
   #ifdef KRB5
           if (options.kerberos_ticket_cleanup)
                   krb5_cleanup_proc(authctxt);
   #endif
 }  }
   
 /*  /*
Line 167 
Line 176 
  * terminals are allocated, X11, TCP/IP, and authentication agent forwardings   * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
  * are requested, etc.   * are requested, etc.
  */   */
 void  static void
 do_authenticated(struct passwd * pw)  do_authenticated1(Authctxt *authctxt)
 {  {
         Session *s;          Session *s;
         int type, fd;  
         int compression_level = 0, enable_compression_after_reply = 0;  
         int have_pty = 0;  
         char *command;          char *command;
         int n_bytes;          int success, type, plen, screen_flag;
         int plen;          int compression_level = 0, enable_compression_after_reply = 0;
         unsigned int proto_len, data_len, dlen;          u_int proto_len, data_len, dlen;
   
         /*  
          * Cancel the alarm we set to limit the time taken for  
          * authentication.  
          */  
         alarm(0);  
         if (startup_pipe != -1) {  
                 close(startup_pipe);  
                 startup_pipe = -1;  
         }  
   
         /*  
          * Inform the channel mechanism that we are the server side and that  
          * the client may request to connect to any port at all. (The user  
          * could do it anyway, and we wouldn\'t know what is permitted except  
          * by the client telling us, so we can equally well trust the client  
          * not to request anything bogus.)  
          */  
         if (!no_port_forwarding_flag && options.allow_tcp_forwarding)  
                 channel_permit_all_opens();  
   
         s = session_new();          s = session_new();
         s->pw = pw;          s->authctxt = authctxt;
           s->pw = authctxt->pw;
   
 #ifdef HAVE_LOGIN_CAP  
         if ((lc = login_getclass(pw->pw_class)) == NULL) {  
                 error("unable to get login class");  
                 return;  
         }  
 #endif  
   
         /*          /*
          * We stay in this loop until the client requests to execute a shell           * We stay in this loop until the client requests to execute a shell
          * or a command.           * or a command.
          */           */
         for (;;) {          for (;;) {
                 int success = 0;                  success = 0;
   
                 /* Get a packet from the client. */                  /* Get a packet from the client. */
                 type = packet_read(&plen);                  type = packet_read(&plen);
Line 235 
Line 215 
                         break;                          break;
   
                 case SSH_CMSG_REQUEST_PTY:                  case SSH_CMSG_REQUEST_PTY:
                         if (no_pty_flag) {                          success = session_pty_req(s);
                                 debug("Allocating a pty not permitted for this authentication.");  
                                 break;  
                         }  
                         if (have_pty)  
                                 packet_disconnect("Protocol error: you already have a pty.");  
   
                         debug("Allocating pty.");  
   
                         /* Allocate a pty and open it. */  
                         if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,  
                             sizeof(s->tty))) {  
                                 error("Failed to allocate pty.");  
                                 break;  
                         }  
                         fatal_add_cleanup(pty_cleanup_proc, (void *)s);  
                         pty_setowner(pw, s->tty);  
   
                         /* Get TERM from the packet.  Note that the value may be of arbitrary length. */  
                         s->term = packet_get_string(&dlen);  
                         packet_integrity_check(dlen, strlen(s->term), type);  
                         /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */  
                         /* Remaining bytes */  
                         n_bytes = plen - (4 + dlen + 4 * 4);  
   
                         if (strcmp(s->term, "") == 0) {  
                                 xfree(s->term);  
                                 s->term = NULL;  
                         }  
                         /* Get window size from the packet. */  
                         s->row = packet_get_int();  
                         s->col = packet_get_int();  
                         s->xpixel = packet_get_int();  
                         s->ypixel = packet_get_int();  
                         pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);  
   
                         /* Get tty modes from the packet. */  
                         tty_parse_modes(s->ttyfd, &n_bytes);  
                         packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);  
   
                         session_proctitle(s);  
   
                         /* Indicate that we now have a pty. */  
                         success = 1;  
                         have_pty = 1;  
                         break;                          break;
   
                 case SSH_CMSG_X11_REQUEST_FORWARDING:                  case SSH_CMSG_X11_REQUEST_FORWARDING:
                         if (!options.x11_forwarding) {  
                                 packet_send_debug("X11 forwarding disabled in server configuration file.");  
                                 break;  
                         }  
                         if (!options.xauth_location) {  
                                 packet_send_debug("No xauth program; cannot forward with spoofing.");  
                                 break;  
                         }  
                         if (no_x11_forwarding_flag) {  
                                 packet_send_debug("X11 forwarding not permitted for this authentication.");  
                                 break;  
                         }  
                         debug("Received request for X11 forwarding with auth spoofing.");  
                         if (s->display != NULL)  
                                 packet_disconnect("Protocol error: X11 display already set.");  
   
                         s->auth_proto = packet_get_string(&proto_len);                          s->auth_proto = packet_get_string(&proto_len);
                         s->auth_data = packet_get_string(&data_len);                          s->auth_data = packet_get_string(&data_len);
                         packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);  
   
                         if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)                          screen_flag = packet_get_protocol_flags() &
                               SSH_PROTOFLAG_SCREEN_NUMBER;
                           debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
   
                           if (packet_remaining() == 4) {
                                   if (!screen_flag)
                                           debug2("Buggy client: "
                                               "X11 screen flag missing");
                                 s->screen = packet_get_int();                                  s->screen = packet_get_int();
                         else                          } else {
                                 s->screen = 0;                                  s->screen = 0;
                         s->display = x11_create_display_inet(s->screen, options.x11_display_offset);  
   
                         if (s->display == NULL)  
                                 break;  
   
                         /* Setup to always have a local .Xauthority. */  
                         xauthfile = xmalloc(MAXPATHLEN);  
                         strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);  
                         temporarily_use_uid(pw->pw_uid);  
                         if (mkdtemp(xauthfile) == NULL) {  
                                 restore_uid();  
                                 error("private X11 dir: mkdtemp %s failed: %s",  
                                     xauthfile, strerror(errno));  
                                 xfree(xauthfile);  
                                 xauthfile = NULL;  
                                 /* XXXX remove listening channels */  
                                 break;  
                         }                          }
                         strlcat(xauthfile, "/cookies", MAXPATHLEN);                          packet_done();
                         fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);                          success = session_setup_x11fwd(s);
                         if (fd >= 0)                          if (!success) {
                                 close(fd);                                  xfree(s->auth_proto);
                         restore_uid();                                  xfree(s->auth_data);
                         fatal_add_cleanup(xauthfile_cleanup_proc, NULL);                                  s->auth_proto = NULL;
                         success = 1;                                  s->auth_data = NULL;
                           }
                         break;                          break;
   
                 case SSH_CMSG_AGENT_REQUEST_FORWARDING:                  case SSH_CMSG_AGENT_REQUEST_FORWARDING:
Line 340 
Line 250 
                                 break;                                  break;
                         }                          }
                         debug("Received authentication agent forwarding request.");                          debug("Received authentication agent forwarding request.");
                         success = auth_input_request_forwarding(pw);                          success = auth_input_request_forwarding(s->pw);
                         break;                          break;
   
                 case SSH_CMSG_PORT_FORWARD_REQUEST:                  case SSH_CMSG_PORT_FORWARD_REQUEST:
Line 353 
Line 263 
                                 break;                                  break;
                         }                          }
                         debug("Received TCP/IP port forwarding request.");                          debug("Received TCP/IP port forwarding request.");
                         channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports);                          channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
                         success = 1;                          success = 1;
                         break;                          break;
   
Line 361 
Line 271 
                         if (packet_set_maxsize(packet_get_int()) > 0)                          if (packet_set_maxsize(packet_get_int()) > 0)
                                 success = 1;                                  success = 1;
                         break;                          break;
   
   #if defined(AFS) || defined(KRB5)
                   case SSH_CMSG_HAVE_KERBEROS_TGT:
                           if (!options.kerberos_tgt_passing) {
                                   verbose("Kerberos TGT passing disabled.");
                           } else {
                                   char *kdata = packet_get_string(&dlen);
                                   packet_integrity_check(plen, 4 + dlen, type);
   
                                   /* XXX - 0x41, see creds_to_radix version */
                                   if (kdata[0] != 0x41) {
   #ifdef KRB5
                                           krb5_data tgt;
                                           tgt.data = kdata;
                                           tgt.length = dlen;
   
                                           if (auth_krb5_tgt(s->authctxt, &tgt))
                                                   success = 1;
                                           else
                                                   verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user);
   #endif /* KRB5 */
                                   } else {
   #ifdef AFS
                                           if (auth_krb4_tgt(s->authctxt, kdata))
                                                   success = 1;
                                           else
                                                   verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user);
   #endif /* AFS */
                                   }
                                   xfree(kdata);
                           }
                           break;
   #endif /* AFS || KRB5 */
   
   #ifdef AFS
                   case SSH_CMSG_HAVE_AFS_TOKEN:
                           if (!options.afs_token_passing || !k_hasafs()) {
                                   verbose("AFS token passing disabled.");
                           } else {
                                   /* Accept AFS token. */
                                   char *token = packet_get_string(&dlen);
                                   packet_integrity_check(plen, 4 + dlen, type);
   
                                   if (auth_afs_token(s->authctxt, token))
                                           success = 1;
                                   else
                                           verbose("AFS token refused for %.100s",
                                               s->authctxt->user);
                                   xfree(token);
                           }
                           break;
   #endif /* AFS */
   
                 case SSH_CMSG_EXEC_SHELL:                  case SSH_CMSG_EXEC_SHELL:
                 case SSH_CMSG_EXEC_CMD:                  case SSH_CMSG_EXEC_CMD:
                         /* Set interactive/non-interactive mode. */  
                         packet_set_interactive(have_pty || s->display != NULL,  
                             options.keepalives);  
   
                         if (type == SSH_CMSG_EXEC_CMD) {                          if (type == SSH_CMSG_EXEC_CMD) {
                                 command = packet_get_string(&dlen);                                  command = packet_get_string(&dlen);
                                 debug("Exec command '%.500s'", command);                                  debug("Exec command '%.500s'", command);
                                 packet_integrity_check(plen, 4 + dlen, type);                                  do_exec(s, command);
                                   xfree(command);
                         } else {                          } else {
                                 command = NULL;                                  do_exec(s, NULL);
                                 packet_integrity_check(plen, 0, type);  
                         }                          }
                         if (forced_command != NULL) {                          packet_done();
                                 original_command = command;                          session_close(s);
                                 command = forced_command;  
                                 debug("Forced command '%.500s'", forced_command);  
                         }  
                         if (have_pty)  
                                 do_exec_pty(s, command, pw);  
                         else  
                                 do_exec_no_pty(s, command, pw);  
   
                         if (command != NULL)  
                                 xfree(command);  
                         /* Cleanup user's local Xauthority file. */  
                         if (xauthfile)  
                                 xauthfile_cleanup_proc(NULL);  
                         return;                          return;
   
                 default:                  default:
Line 418 
Line 363 
  * setting up file descriptors and such.   * setting up file descriptors and such.
  */   */
 void  void
 do_exec_no_pty(Session *s, const char *command, struct passwd * pw)  do_exec_no_pty(Session *s, const char *command)
 {  {
         int pid;          int pid;
   
Line 491 
Line 436 
 #endif /* USE_PIPES */  #endif /* USE_PIPES */
   
                 /* Do processing for the child (exec command etc). */                  /* Do processing for the child (exec command etc). */
                 do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL);                  do_child(s, command);
                 /* NOTREACHED */                  /* NOTREACHED */
         }          }
         if (pid < 0)          if (pid < 0)
                 packet_disconnect("fork failed: %.100s", strerror(errno));                  packet_disconnect("fork failed: %.100s", strerror(errno));
         s->pid = pid;          s->pid = pid;
           /* Set interactive/non-interactive mode. */
           packet_set_interactive(s->display != NULL);
 #ifdef USE_PIPES  #ifdef USE_PIPES
         /* We are the parent.  Close the child sides of the pipes. */          /* We are the parent.  Close the child sides of the pipes. */
         close(pin[0]);          close(pin[0]);
Line 504 
Line 451 
         close(perr[1]);          close(perr[1]);
   
         if (compat20) {          if (compat20) {
                 session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1);                  session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]);
         } else {          } else {
                 /* Enter the interactive session. */                  /* Enter the interactive session. */
                 server_loop(pid, pin[1], pout[0], perr[0]);                  server_loop(pid, pin[1], pout[0], perr[0]);
                 /* server_loop has closed pin[1], pout[1], and perr[1]. */                  /* server_loop has closed pin[1], pout[0], and perr[0]. */
         }          }
 #else /* USE_PIPES */  #else /* USE_PIPES */
         /* We are the parent.  Close the child sides of the socket pairs. */          /* We are the parent.  Close the child sides of the socket pairs. */
Line 520 
Line 467 
          * handle the case that fdin and fdout are the same.           * handle the case that fdin and fdout are the same.
          */           */
         if (compat20) {          if (compat20) {
                 session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1);                  session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
         } else {          } else {
                 server_loop(pid, inout[1], inout[1], err[1]);                  server_loop(pid, inout[1], inout[1], err[1]);
                 /* server_loop has closed inout[1] and err[1]. */                  /* server_loop has closed inout[1] and err[1]. */
Line 535 
Line 482 
  * lastlog, and other such operations.   * lastlog, and other such operations.
  */   */
 void  void
 do_exec_pty(Session *s, const char *command, struct passwd * pw)  do_exec_pty(Session *s, const char *command)
 {  {
         int fdout, ptyfd, ttyfd, ptymaster;          int fdout, ptyfd, ttyfd, ptymaster;
         pid_t pid;          pid_t pid;
Line 547 
Line 494 
   
         /* Fork the child. */          /* Fork the child. */
         if ((pid = fork()) == 0) {          if ((pid = fork()) == 0) {
   
                 /* Child.  Reinitialize the log because the pid has changed. */                  /* Child.  Reinitialize the log because the pid has changed. */
                 log_init(__progname, options.log_level, options.log_facility, log_stderr);                  log_init(__progname, options.log_level, options.log_facility, log_stderr);
   
                 /* Close the master side of the pseudo tty. */                  /* Close the master side of the pseudo tty. */
                 close(ptyfd);                  close(ptyfd);
   
Line 576 
Line 523 
                         do_login(s, command);                          do_login(s, command);
   
                 /* Do common processing for the child, such as execing the command. */                  /* Do common processing for the child, such as execing the command. */
                 do_child(command, pw, s->term, s->display, s->auth_proto,                  do_child(s, command);
                     s->auth_data, s->tty);  
                 /* NOTREACHED */                  /* NOTREACHED */
         }          }
         if (pid < 0)          if (pid < 0)
Line 603 
Line 549 
         s->ptymaster = ptymaster;          s->ptymaster = ptymaster;
   
         /* Enter interactive session. */          /* Enter interactive session. */
           packet_set_interactive(1);
         if (compat20) {          if (compat20) {
                 session_set_fds(s, ptyfd, fdout, -1);                  session_set_fds(s, ptyfd, fdout, -1);
         } else {          } else {
                 server_loop(pid, ptyfd, fdout, -1);                  server_loop(pid, ptyfd, fdout, -1);
                 /* server_loop _has_ closed ptyfd and fdout. */                  /* server_loop _has_ closed ptyfd and fdout. */
                 session_pty_cleanup(s);  
         }          }
 }  }
   
 const char *  /*
 get_remote_name_or_ip(void)   * This is called to fork and execute a command.  If another command is
    * to be forced, execute that instead.
    */
   void
   do_exec(Session *s, const char *command)
 {  {
         static const char *remote = "";          if (forced_command) {
         if (utmp_len > 0)                  original_command = command;
                 remote = get_canonical_hostname();                  command = forced_command;
         if (utmp_len == 0 || strlen(remote) > utmp_len)                  debug("Forced command '%.900s'", command);
                 remote = get_remote_ipaddr();          }
         return remote;  
           if (s->ttyfd != -1)
                   do_exec_pty(s, command);
           else
                   do_exec_no_pty(s, command);
   
           original_command = NULL;
 }  }
   
   
 /* administrative, login(1)-like work */  /* administrative, login(1)-like work */
 void  void
 do_login(Session *s, const char *command)  do_login(Session *s, const char *command)
 {  {
         FILE *f;  
         char *time_string;          char *time_string;
         char buf[256];  
         char hostname[MAXHOSTNAMELEN];          char hostname[MAXHOSTNAMELEN];
         socklen_t fromlen;          socklen_t fromlen;
         struct sockaddr_storage from;          struct sockaddr_storage from;
         struct stat st;  
         time_t last_login_time;          time_t last_login_time;
         struct passwd * pw = s->pw;          struct passwd * pw = s->pw;
         pid_t pid = getpid();          pid_t pid = getpid();
Line 653 
Line 607 
         }          }
   
         /* Get the time and hostname when the user last logged in. */          /* Get the time and hostname when the user last logged in. */
         hostname[0] = '\0';          if (options.print_lastlog) {
         last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,                  hostname[0] = '\0';
             hostname, sizeof(hostname));                  last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
                       hostname, sizeof(hostname));
           }
   
         /* Record that there was a login on that tty from the remote host. */          /* Record that there was a login on that tty from the remote host. */
         record_login(pid, s->tty, pw->pw_name, pw->pw_uid,          record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
             get_remote_name_or_ip(), (struct sockaddr *)&from);              get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),
               (struct sockaddr *)&from);
   
         /* Done if .hushlogin exists or a command given. */          if (check_quietlogin(s, command))
         if (command != NULL)  
                 return;                  return;
         snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);  
 #ifdef HAVE_LOGIN_CAP          if (options.print_lastlog && last_login_time != 0) {
         if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)  
 #else  
         if (stat(buf, &st) >= 0)  
 #endif  
                 return;  
         if (last_login_time != 0) {  
                 time_string = ctime(&last_login_time);                  time_string = ctime(&last_login_time);
                 if (strchr(time_string, '\n'))                  if (strchr(time_string, '\n'))
                         *strchr(time_string, '\n') = 0;                          *strchr(time_string, '\n') = 0;
Line 680 
Line 630 
                 else                  else
                         printf("Last login: %s from %s\r\n", time_string, hostname);                          printf("Last login: %s from %s\r\n", time_string, hostname);
         }          }
   
           do_motd();
   }
   
   /*
    * Display the message of the day.
    */
   void
   do_motd(void)
   {
           FILE *f;
           char buf[256];
   
         if (options.print_motd) {          if (options.print_motd) {
 #ifdef HAVE_LOGIN_CAP  #ifdef HAVE_LOGIN_CAP
                 f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",                  f = fopen(login_getcapstr(lc, "welcome", "/etc/motd",
Line 695 
Line 658 
         }          }
 }  }
   
   
 /*  /*
    * Check for quiet login, either .hushlogin or command given.
    */
   int
   check_quietlogin(Session *s, const char *command)
   {
           char buf[256];
           struct passwd *pw = s->pw;
           struct stat st;
   
           /* Return 1 if .hushlogin exists or a command given. */
           if (command != NULL)
                   return 1;
           snprintf(buf, sizeof(buf), "%.200s/.hushlogin", pw->pw_dir);
   #ifdef HAVE_LOGIN_CAP
           if (login_getcapbool(lc, "hushlogin", 0) || stat(buf, &st) >= 0)
                   return 1;
   #else
           if (stat(buf, &st) >= 0)
                   return 1;
   #endif
           return 0;
   }
   
   /*
  * Sets the value of the given variable in the environment.  If the variable   * Sets the value of the given variable in the environment.  If the variable
  * already exists, its value is overriden.   * already exists, its value is overriden.
  */   */
 void  static void
 child_set_env(char ***envp, unsigned int *envsizep, const char *name,  child_set_env(char ***envp, u_int *envsizep, const char *name,
               const char *value)                const char *value)
 {  {
         unsigned int i, namelen;          u_int i, namelen;
         char **env;          char **env;
   
         /*          /*
Line 740 
Line 728 
  * Otherwise, it must consist of empty lines, comments (line starts with '#')   * Otherwise, it must consist of empty lines, comments (line starts with '#')
  * and assignments of the form name=value.  No other forms are allowed.   * and assignments of the form name=value.  No other forms are allowed.
  */   */
 void  static void
 read_environment_file(char ***env, unsigned int *envsize,  read_environment_file(char ***env, u_int *envsize,
                       const char *filename)                        const char *filename)
 {  {
         FILE *f;          FILE *f;
Line 781 
Line 769 
  * ids, and executing the command or shell.   * ids, and executing the command or shell.
  */   */
 void  void
 do_child(const char *command, struct passwd * pw, const char *term,  do_child(Session *s, const char *command)
          const char *display, const char *auth_proto,  
          const char *auth_data, const char *ttyname)  
 {  {
         const char *shell, *hostname = NULL, *cp = NULL;          const char *shell, *hostname = NULL, *cp = NULL;
           struct passwd *pw = s->pw;
         char buf[256];          char buf[256];
         char cmd[1024];          char cmd[1024];
         FILE *f = NULL;          FILE *f = NULL;
         unsigned int envsize, i;          u_int envsize, i;
         char **env;          char **env;
         extern char **environ;          extern char **environ;
         struct stat st;          struct stat st;
         char *argv[10];          char *argv[10];
           int do_xauth;
   
           do_xauth =
               s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
   
           /* remove hostkey from the child's memory */
           destroy_sensitive_data();
   
         /* login(1) is only called if we execute the login shell */          /* login(1) is only called if we execute the login shell */
         if (options.use_login && command != NULL)          if (options.use_login && command != NULL)
                 options.use_login = 0;                  options.use_login = 0;
Line 826 
Line 820 
                             (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {                              (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
                                 perror("unable to set user context");                                  perror("unable to set user context");
                                 exit(1);                                  exit(1);
   
                         }                          }
 #else  #else
                         if (setlogin(pw->pw_name) < 0)                          if (setlogin(pw->pw_name) < 0)
Line 843 
Line 836 
                         endgrent();                          endgrent();
   
                         /* Permanently switch to the desired uid. */                          /* Permanently switch to the desired uid. */
                         permanently_set_uid(pw->pw_uid);                          permanently_set_uid(pw);
 #endif  #endif
                 }                  }
                 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)                  if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
Line 858 
Line 851 
         shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);          shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
 #endif  #endif
   
 #ifdef AFS  
         /* Try to get AFS tokens for the local cell. */  
         if (k_hasafs()) {  
                 char cell[64];  
   
                 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)  
                         krb_afslog(cell, 0);  
   
                 krb_afslog(0, 0);  
         }  
 #endif /* AFS */  
   
         /* Initialize the environment. */          /* Initialize the environment. */
         envsize = 100;          envsize = 100;
         env = xmalloc(envsize * sizeof(char *));          env = xmalloc(envsize * sizeof(char *));
Line 916 
Line 897 
                  get_remote_ipaddr(), get_remote_port(), get_local_port());                   get_remote_ipaddr(), get_remote_port(), get_local_port());
         child_set_env(&env, &envsize, "SSH_CLIENT", buf);          child_set_env(&env, &envsize, "SSH_CLIENT", buf);
   
         if (ttyname)          if (s->ttyfd != -1)
                 child_set_env(&env, &envsize, "SSH_TTY", ttyname);                  child_set_env(&env, &envsize, "SSH_TTY", s->tty);
         if (term)          if (s->term)
                 child_set_env(&env, &envsize, "TERM", term);                  child_set_env(&env, &envsize, "TERM", s->term);
         if (display)          if (s->display)
                 child_set_env(&env, &envsize, "DISPLAY", display);                  child_set_env(&env, &envsize, "DISPLAY", s->display);
         if (original_command)          if (original_command)
                 child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",                  child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
                     original_command);                      original_command);
   
 #ifdef KRB4  #ifdef KRB4
         {          if (s->authctxt->krb4_ticket_file)
                 extern char *ticket;                  child_set_env(&env, &envsize, "KRBTKFILE",
                                 s->authctxt->krb4_ticket_file);
                 if (ticket)  #endif
                         child_set_env(&env, &envsize, "KRBTKFILE", ticket);  #ifdef KRB5
         }          if (s->authctxt->krb5_ticket_file)
 #endif /* KRB4 */                  child_set_env(&env, &envsize, "KRB5CCNAME",
                                 s->authctxt->krb5_ticket_file);
         if (xauthfile)  #endif
                 child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);  
         if (auth_get_socket_name() != NULL)          if (auth_get_socket_name() != NULL)
                 child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,                  child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
                               auth_get_socket_name());                                auth_get_socket_name());
Line 955 
Line 934 
         }          }
         /* we have to stash the hostname before we close our socket. */          /* we have to stash the hostname before we close our socket. */
         if (options.use_login)          if (options.use_login)
                 hostname = get_remote_name_or_ip();                  hostname = get_remote_name_or_ip(utmp_len,
                       options.reverse_mapping_check);
         /*          /*
          * Close the connection descriptors; note that this is the child, and           * Close the connection descriptors; note that this is the child, and
          * the server will still have the socket open, and it is important           * the server will still have the socket open, and it is important
Line 1007 
Line 987 
          */           */
         environ = env;          environ = env;
   
   #ifdef AFS
           /* Try to get AFS tokens for the local cell. */
           if (k_hasafs()) {
                   char cell[64];
   
                   if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
                           krb_afslog(cell, 0);
   
                   krb_afslog(0, 0);
           }
   #endif /* AFS */
   
         /*          /*
          * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first           * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
          * in this order).           * in this order).
          */           */
         if (!options.use_login) {          if (!options.use_login) {
                 if (stat(SSH_USER_RC, &st) >= 0) {                  /* ignore _PATH_SSH_USER_RC for subsystems */
                   if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) {
                           snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
                               shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
                         if (debug_flag)                          if (debug_flag)
                                 fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);                                  fprintf(stderr, "Running %s\n", cmd);
                           f = popen(cmd, "w");
                         f = popen("/bin/sh " SSH_USER_RC, "w");  
                         if (f) {                          if (f) {
                                 if (auth_proto != NULL && auth_data != NULL)                                  if (do_xauth)
                                         fprintf(f, "%s %s\n", auth_proto, auth_data);                                          fprintf(f, "%s %s\n", s->auth_proto,
                                               s->auth_data);
                                 pclose(f);                                  pclose(f);
                         } else                          } else
                                 fprintf(stderr, "Could not run %s\n", SSH_USER_RC);                                  fprintf(stderr, "Could not run %s\n",
                 } else if (stat(SSH_SYSTEM_RC, &st) >= 0) {                                      _PATH_SSH_USER_RC);
                   } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
                         if (debug_flag)                          if (debug_flag)
                                 fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);                                  fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
                                       _PATH_SSH_SYSTEM_RC);
                         f = popen("/bin/sh " SSH_SYSTEM_RC, "w");                          f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
                         if (f) {                          if (f) {
                                 if (auth_proto != NULL && auth_data != NULL)                                  if (do_xauth)
                                         fprintf(f, "%s %s\n", auth_proto, auth_data);                                          fprintf(f, "%s %s\n", s->auth_proto,
                                               s->auth_data);
                                 pclose(f);                                  pclose(f);
                         } else                          } else
                                 fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);                                  fprintf(stderr, "Could not run %s\n",
                 } else if (options.xauth_location != NULL) {                                      _PATH_SSH_SYSTEM_RC);
                   } else if (do_xauth && options.xauth_location != NULL) {
                         /* Add authority data to .Xauthority if appropriate. */                          /* Add authority data to .Xauthority if appropriate. */
                         if (auth_proto != NULL && auth_data != NULL) {                          char *screen = strchr(s->display, ':');
                                 char *screen = strchr(display, ':');  
                                 if (debug_flag) {                          if (debug_flag) {
                                   fprintf(stderr,
                                       "Running %.100s add "
                                       "%.100s %.100s %.100s\n",
                                       options.xauth_location, s->display,
                                       s->auth_proto, s->auth_data);
                                   if (screen != NULL)
                                         fprintf(stderr,                                          fprintf(stderr,
                                             "Running %.100s add %.100s %.100s %.100s\n",                                              "Adding %.*s/unix%s %s %s\n",
                                             options.xauth_location, display,                                              (int)(screen - s->display),
                                             auth_proto, auth_data);                                              s->display, screen,
                                         if (screen != NULL)                                              s->auth_proto, s->auth_data);
                                                 fprintf(stderr,  
                                                     "Adding %.*s/unix%s %s %s\n",  
                                                     (int)(screen-display), display,  
                                                     screen, auth_proto, auth_data);  
                                 }  
                                 snprintf(cmd, sizeof cmd, "%s -q -",  
                                     options.xauth_location);  
                                 f = popen(cmd, "w");  
                                 if (f) {  
                                         fprintf(f, "add %s %s %s\n", display,  
                                             auth_proto, auth_data);  
                                         if (screen != NULL)  
                                                 fprintf(f, "add %.*s/unix%s %s %s\n",  
                                                     (int)(screen-display), display,  
                                                     screen, auth_proto, auth_data);  
                                         pclose(f);  
                                 } else {  
                                         fprintf(stderr, "Could not run %s\n",  
                                             cmd);  
                                 }  
                         }                          }
                           snprintf(cmd, sizeof cmd, "%s -q -",
                               options.xauth_location);
                           f = popen(cmd, "w");
                           if (f) {
                                   fprintf(f, "add %s %s %s\n", s->display,
                                       s->auth_proto, s->auth_data);
                                   if (screen != NULL)
                                           fprintf(f, "add %.*s/unix%s %s %s\n",
                                               (int)(screen - s->display),
                                               s->display, screen,
                                               s->auth_proto,
                                               s->auth_data);
                                   pclose(f);
                           } else {
                                   fprintf(stderr, "Could not run %s\n",
                                       cmd);
                           }
                 }                  }
                 /* Get the last component of the shell name. */                  /* Get the last component of the shell name. */
                 cp = strrchr(shell, '/');                  cp = strrchr(shell, '/');
Line 1073 
Line 1074 
                 else                  else
                         cp = shell;                          cp = shell;
         }          }
   
           /* restore SIGPIPE for child */
           signal(SIGPIPE,  SIG_DFL);
   
         /*          /*
          * If we have no command, execute the shell.  In this case, the shell           * If we have no command, execute the shell.  In this case, the shell
          * name to be passed in argv[0] is preceded by '-' to indicate that           * name to be passed in argv[0] is preceded by '-' to indicate that
Line 1082 
Line 1087 
                 if (!options.use_login) {                  if (!options.use_login) {
                         char buf[256];                          char buf[256];
   
                         /*  
                          * Check for mail if we have a tty and it was enabled  
                          * in server options.  
                          */  
                         if (ttyname && options.check_mail) {  
                                 char *mailbox;  
                                 struct stat mailstat;  
                                 mailbox = getenv("MAIL");  
                                 if (mailbox != NULL) {  
                                         if (stat(mailbox, &mailstat) != 0 ||  
                                             mailstat.st_size == 0)  
                                                 printf("No mail.\n");  
                                         else if (mailstat.st_mtime < mailstat.st_atime)  
                                                 printf("You have mail.\n");  
                                         else  
                                                 printf("You have new mail.\n");  
                                 }  
                         }  
                         /* Start the shell.  Set initial character to '-'. */                          /* Start the shell.  Set initial character to '-'. */
                         buf[0] = '-';                          buf[0] = '-';
                         strncpy(buf + 1, cp, sizeof(buf) - 1);                          strncpy(buf + 1, cp, sizeof(buf) - 1);
Line 1118 
Line 1105 
                         /* Launch login(1). */                          /* Launch login(1). */
   
                         execl("/usr/bin/login", "login", "-h", hostname,                          execl("/usr/bin/login", "login", "-h", hostname,
                              "-p", "-f", "--", pw->pw_name, NULL);                               "-p", "-f", "--", pw->pw_name, (char *)NULL);
   
                         /* Login couldn't be executed, die. */                          /* Login couldn't be executed, die. */
   
Line 1148 
Line 1135 
                 debug("session_new: init");                  debug("session_new: init");
                 for(i = 0; i < MAX_SESSIONS; i++) {                  for(i = 0; i < MAX_SESSIONS; i++) {
                         sessions[i].used = 0;                          sessions[i].used = 0;
                         sessions[i].self = i;  
                 }                  }
                 did_init = 1;                  did_init = 1;
         }          }
         for(i = 0; i < MAX_SESSIONS; i++) {          for(i = 0; i < MAX_SESSIONS; i++) {
                 Session *s = &sessions[i];                  Session *s = &sessions[i];
                 if (! s->used) {                  if (! s->used) {
                         s->pid = 0;                          memset(s, 0, sizeof(*s));
                         s->extended = 0;  
                         s->chanid = -1;                          s->chanid = -1;
                         s->ptyfd = -1;                          s->ptyfd = -1;
                         s->ttyfd = -1;                          s->ttyfd = -1;
                         s->term = NULL;  
                         s->pw = NULL;  
                         s->display = NULL;  
                         s->screen = 0;  
                         s->auth_data = NULL;  
                         s->auth_proto = NULL;  
                         s->used = 1;                          s->used = 1;
                         s->pw = NULL;                          s->self = i;
                         debug("session_new: session %d", i);                          debug("session_new: session %d", i);
                         return s;                          return s;
                 }                  }
Line 1175 
Line 1154 
         return NULL;          return NULL;
 }  }
   
 void  static void
 session_dump(void)  session_dump(void)
 {  {
         int i;          int i;
Line 1191 
Line 1170 
 }  }
   
 int  int
 session_open(int chanid)  session_open(Authctxt *authctxt, int chanid)
 {  {
         Session *s = session_new();          Session *s = session_new();
         debug("session_open: channel %d", chanid);          debug("session_open: channel %d", chanid);
Line 1199 
Line 1178 
                 error("no more sessions");                  error("no more sessions");
                 return 0;                  return 0;
         }          }
         s->pw = auth_get_user();          s->authctxt = authctxt;
           s->pw = authctxt->pw;
         if (s->pw == NULL)          if (s->pw == NULL)
                 fatal("no user for session %i", s->self);                  fatal("no user for session %d", s->self);
         debug("session_open: session %d: link with channel %d", s->self, chanid);          debug("session_open: session %d: link with channel %d", s->self, chanid);
         s->chanid = chanid;          s->chanid = chanid;
         return 1;          return 1;
 }  }
   
 Session *  static Session *
 session_by_channel(int id)  session_by_channel(int id)
 {  {
         int i;          int i;
Line 1223 
Line 1203 
         return NULL;          return NULL;
 }  }
   
 Session *  static Session *
 session_by_pid(pid_t pid)  session_by_pid(pid_t pid)
 {  {
         int i;          int i;
Line 1238 
Line 1218 
         return NULL;          return NULL;
 }  }
   
 int  static int
 session_window_change_req(Session *s)  session_window_change_req(Session *s)
 {  {
         s->col = packet_get_int();          s->col = packet_get_int();
Line 1250 
Line 1230 
         return 1;          return 1;
 }  }
   
 int  static int
 session_pty_req(Session *s)  session_pty_req(Session *s)
 {  {
         unsigned int len;          u_int len;
         char *term_modes;       /* encoded terminal modes */          int n_bytes;
   
         if (no_pty_flag)          if (no_pty_flag) {
                   debug("Allocating a pty not permitted for this authentication.");
                 return 0;                  return 0;
         if (s->ttyfd != -1)          }
           if (s->ttyfd != -1) {
                   packet_disconnect("Protocol error: you already have a pty.");
                 return 0;                  return 0;
           }
   
         s->term = packet_get_string(&len);          s->term = packet_get_string(&len);
         s->col = packet_get_int();  
         s->row = packet_get_int();          if (compat20) {
                   s->col = packet_get_int();
                   s->row = packet_get_int();
           } else {
                   s->row = packet_get_int();
                   s->col = packet_get_int();
           }
         s->xpixel = packet_get_int();          s->xpixel = packet_get_int();
         s->ypixel = packet_get_int();          s->ypixel = packet_get_int();
         term_modes = packet_get_string(&len);  
         packet_done();  
   
         if (strcmp(s->term, "") == 0) {          if (strcmp(s->term, "") == 0) {
                 xfree(s->term);                  xfree(s->term);
                 s->term = NULL;                  s->term = NULL;
         }          }
   
         /* Allocate a pty and open it. */          /* Allocate a pty and open it. */
           debug("Allocating pty.");
         if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {          if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
                 xfree(s->term);                  if (s->term)
                           xfree(s->term);
                 s->term = NULL;                  s->term = NULL;
                 s->ptyfd = -1;                  s->ptyfd = -1;
                 s->ttyfd = -1;                  s->ttyfd = -1;
                 error("session_pty_req: session %d alloc failed", s->self);                  error("session_pty_req: session %d alloc failed", s->self);
                 xfree(term_modes);  
                 return 0;                  return 0;
         }          }
         debug("session_pty_req: session %d alloc %s", s->self, s->tty);          debug("session_pty_req: session %d alloc %s", s->self, s->tty);
   
           /* for SSH1 the tty modes length is not given */
           if (!compat20)
                   n_bytes = packet_remaining();
           tty_parse_modes(s->ttyfd, &n_bytes);
   
         /*          /*
          * Add a cleanup function to clear the utmp entry and record logout           * Add a cleanup function to clear the utmp entry and record logout
          * time in case we call fatal() (e.g., the connection gets closed).           * time in case we call fatal() (e.g., the connection gets closed).
          */           */
         fatal_add_cleanup(pty_cleanup_proc, (void *)s);          fatal_add_cleanup(session_pty_cleanup, (void *)s);
         pty_setowner(s->pw, s->tty);          pty_setowner(s->pw, s->tty);
         /* Get window size from the packet. */  
           /* Set window size from the packet. */
         pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);          pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
   
           packet_done();
         session_proctitle(s);          session_proctitle(s);
   
         /* XXX parse and set terminal modes */  
         xfree(term_modes);  
         return 1;          return 1;
 }  }
   
 int  static int
 session_subsystem_req(Session *s)  session_subsystem_req(Session *s)
 {  {
         unsigned int len;          u_int len;
         int success = 0;          int success = 0;
         char *subsys = packet_get_string(&len);          char *subsys = packet_get_string(&len);
         int i;          int i;
Line 1313 
Line 1309 
         for (i = 0; i < options.num_subsystems; i++) {          for (i = 0; i < options.num_subsystems; i++) {
                 if(strcmp(subsys, options.subsystem_name[i]) == 0) {                  if(strcmp(subsys, options.subsystem_name[i]) == 0) {
                         debug("subsystem: exec() %s", options.subsystem_command[i]);                          debug("subsystem: exec() %s", options.subsystem_command[i]);
                         do_exec_no_pty(s, options.subsystem_command[i], s->pw);                          s->is_subsystem = 1;
                           do_exec(s, options.subsystem_command[i]);
                         success = 1;                          success = 1;
                 }                  }
         }          }
Line 1325 
Line 1322 
         return success;          return success;
 }  }
   
 int  static int
 session_x11_req(Session *s)  session_x11_req(Session *s)
 {  {
         int fd;          int success;
         if (no_x11_forwarding_flag) {  
                 debug("X11 forwarding disabled in user configuration file.");  
                 return 0;  
         }  
         if (!options.x11_forwarding) {  
                 debug("X11 forwarding disabled in server configuration file.");  
                 return 0;  
         }  
         if (xauthfile != NULL) {  
                 debug("X11 fwd already started.");  
                 return 0;  
         }  
   
         debug("Received request for X11 forwarding with auth spoofing.");  
         if (s->display != NULL)  
                 packet_disconnect("Protocol error: X11 display already set.");  
   
         s->single_connection = packet_get_char();          s->single_connection = packet_get_char();
         s->auth_proto = packet_get_string(NULL);          s->auth_proto = packet_get_string(NULL);
         s->auth_data = packet_get_string(NULL);          s->auth_data = packet_get_string(NULL);
         s->screen = packet_get_int();          s->screen = packet_get_int();
         packet_done();          packet_done();
   
         s->display = x11_create_display_inet(s->screen, options.x11_display_offset);          success = session_setup_x11fwd(s);
         if (s->display == NULL) {          if (!success) {
                 xfree(s->auth_proto);                  xfree(s->auth_proto);
                 xfree(s->auth_data);                  xfree(s->auth_data);
                 return 0;                  s->auth_proto = NULL;
                   s->auth_data = NULL;
         }          }
         xauthfile = xmalloc(MAXPATHLEN);          return success;
         strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);  
         temporarily_use_uid(s->pw->pw_uid);  
         if (mkdtemp(xauthfile) == NULL) {  
                 restore_uid();  
                 error("private X11 dir: mkdtemp %s failed: %s",  
                     xauthfile, strerror(errno));  
                 xfree(xauthfile);  
                 xauthfile = NULL;  
                 xfree(s->auth_proto);  
                 xfree(s->auth_data);  
                 /* XXXX remove listening channels */  
                 return 0;  
         }  
         strlcat(xauthfile, "/cookies", MAXPATHLEN);  
         fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);  
         if (fd >= 0)  
                 close(fd);  
         restore_uid();  
         fatal_add_cleanup(xauthfile_cleanup_proc, s);  
         return 1;  
 }  }
   
 int  static int
 session_shell_req(Session *s)  session_shell_req(Session *s)
 {  {
         /* if forced_command == NULL, the shell is execed */  
         char *shell = forced_command;  
         packet_done();          packet_done();
         s->extended = 1;          do_exec(s, NULL);
         if (s->ttyfd == -1)  
                 do_exec_no_pty(s, shell, s->pw);  
         else  
                 do_exec_pty(s, shell, s->pw);  
         return 1;          return 1;
 }  }
   
 int  static int
 session_exec_req(Session *s)  session_exec_req(Session *s)
 {  {
         unsigned int len;          u_int len;
         char *command = packet_get_string(&len);          char *command = packet_get_string(&len);
         packet_done();          packet_done();
         if (forced_command) {          do_exec(s, command);
                 original_command = command;          xfree(command);
                 command = forced_command;  
                 debug("Forced command '%.500s'", forced_command);  
         }  
         s->extended = 1;  
         if (s->ttyfd == -1)  
                 do_exec_no_pty(s, command, s->pw);  
         else  
                 do_exec_pty(s, command, s->pw);  
         if (forced_command == NULL)  
                 xfree(command);  
         return 1;          return 1;
 }  }
   
   static int
   session_auth_agent_req(Session *s)
   {
           static int called = 0;
           packet_done();
           if (no_agent_forwarding_flag) {
                   debug("session_auth_agent_req: no_agent_forwarding_flag");
                   return 0;
           }
           if (called) {
                   return 0;
           } else {
                   called = 1;
                   return auth_input_request_forwarding(s->pw);
           }
   }
   
 void  void
 session_input_channel_req(int id, void *arg)  session_input_channel_req(int id, void *arg)
 {  {
         unsigned int len;          u_int len;
         int reply;          int reply;
         int success = 0;          int success = 0;
         char *rtype;          char *rtype;
Line 1440 
Line 1403 
             s->self, id, rtype, reply);              s->self, id, rtype, reply);
   
         /*          /*
          * a session is in LARVAL state until a shell           * a session is in LARVAL state until a shell, a command
          * or programm is executed           * or a subsystem is executed
          */           */
         if (c->type == SSH_CHANNEL_LARVAL) {          if (c->type == SSH_CHANNEL_LARVAL) {
                 if (strcmp(rtype, "shell") == 0) {                  if (strcmp(rtype, "shell") == 0) {
Line 1452 
Line 1415 
                         success =  session_pty_req(s);                          success =  session_pty_req(s);
                 } else if (strcmp(rtype, "x11-req") == 0) {                  } else if (strcmp(rtype, "x11-req") == 0) {
                         success = session_x11_req(s);                          success = session_x11_req(s);
                   } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
                           success = session_auth_agent_req(s);
                 } else if (strcmp(rtype, "subsystem") == 0) {                  } else if (strcmp(rtype, "subsystem") == 0) {
                         success = session_subsystem_req(s);                          success = session_subsystem_req(s);
                 }                  }
Line 1486 
Line 1451 
             1);              1);
 }  }
   
 void  /*
 session_pty_cleanup(Session *s)   * Function to perform pty cleanup. Also called if we get aborted abnormally
    * (e.g., due to a dropped connection).
    */
   static void
   session_pty_cleanup(void *session)
 {  {
         if (s == NULL || s->ttyfd == -1)          Session *s = session;
   
           if (s == NULL) {
                   error("session_pty_cleanup: no session");
                 return;                  return;
           }
           if (s->ttyfd == -1)
                   return;
   
         debug("session_pty_cleanup: session %i release %s", s->self, s->tty);          debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
   
         /* Cancel the cleanup function. */  
         fatal_remove_cleanup(pty_cleanup_proc, (void *)s);  
   
         /* Record that the user has logged out. */          /* Record that the user has logged out. */
         record_logout(s->pid, s->tty);          if (s->pid != 0)
                   record_logout(s->pid, s->tty);
   
         /* Release the pseudo-tty. */          /* Release the pseudo-tty. */
         pty_release(s->tty);          pty_release(s->tty);
Line 1512 
Line 1485 
                 error("close(s->ptymaster): %s", strerror(errno));                  error("close(s->ptymaster): %s", strerror(errno));
 }  }
   
 void  static void
 session_exit_message(Session *s, int status)  session_exit_message(Session *s, int status)
 {  {
         Channel *c;          Channel *c;
Line 1520 
Line 1493 
                 fatal("session_close: no session");                  fatal("session_close: no session");
         c = channel_lookup(s->chanid);          c = channel_lookup(s->chanid);
         if (c == NULL)          if (c == NULL)
                 fatal("session_close: session %d: no channel %d",                  fatal("session_exit_message: session %d: no channel %d",
                     s->self, s->chanid);                      s->self, s->chanid);
         debug("session_exit_message: session %d channel %d pid %d",          debug("session_exit_message: session %d channel %d pid %d",
             s->self, s->chanid, s->pid);              s->self, s->chanid, s->pid);
Line 1557 
Line 1530 
         s->chanid = -1;          s->chanid = -1;
 }  }
   
 void  static void
 session_free(Session *s)  session_close(Session *s)
 {  {
         debug("session_free: session %d pid %d", s->self, s->pid);          debug("session_close: session %d pid %d", s->self, s->pid);
           if (s->ttyfd != -1) {
                   fatal_remove_cleanup(session_pty_cleanup, (void *)s);
                   session_pty_cleanup(s);
           }
         if (s->term)          if (s->term)
                 xfree(s->term);                  xfree(s->term);
         if (s->display)          if (s->display)
Line 1570 
Line 1547 
         if (s->auth_proto)          if (s->auth_proto)
                 xfree(s->auth_proto);                  xfree(s->auth_proto);
         s->used = 0;          s->used = 0;
 }  
   
 void  
 session_close(Session *s)  
 {  
         session_pty_cleanup(s);  
         session_free(s);  
         session_proctitle(s);          session_proctitle(s);
 }  }
   
Line 1585 
Line 1555 
 {  {
         Session *s = session_by_pid(pid);          Session *s = session_by_pid(pid);
         if (s == NULL) {          if (s == NULL) {
                 debug("session_close_by_pid: no session for pid %d", s->pid);                  debug("session_close_by_pid: no session for pid %d", pid);
                 return;                  return;
         }          }
         if (s->chanid != -1)          if (s->chanid != -1)
Line 1593 
Line 1563 
         session_close(s);          session_close(s);
 }  }
   
   int
   session_have_children(void)
   {
           int i;
   
           for(i = 0; i < MAX_SESSIONS; i++) {
                   Session *s = &sessions[i];
                   if (s->used && s->pid != -1) {
                           debug("session_have_children: id %d pid %d", i, s->pid);
                           return 1;
                   }
           }
           debug("session_have_children: no more children");
           return 0;
   }
   
 /*  /*
  * this is called when a channel dies before   * this is called when a channel dies before
  * the session 'child' itself dies   * the session 'child' itself dies
Line 1621 
Line 1607 
         }          }
 }  }
   
 char *  static char *
 session_tty_list(void)  session_tty_list(void)
 {  {
         static char buf[1024];          static char buf[1024];
Line 1649 
Line 1635 
                 setproctitle("%s@%s", s->pw->pw_name, session_tty_list());                  setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
 }  }
   
 void  int
 do_authenticated2(void)  session_setup_x11fwd(Session *s)
 {  {
         struct passwd *pw;          struct stat st;
   
         /*          if (no_x11_forwarding_flag) {
          * Cancel the alarm we set to limit the time taken for                  packet_send_debug("X11 forwarding disabled in user configuration file.");
          * authentication.                  return 0;
          */  
         alarm(0);  
         if (startup_pipe != -1) {  
                 close(startup_pipe);  
                 startup_pipe = -1;  
         }          }
 #ifdef HAVE_LOGIN_CAP          if (!options.x11_forwarding) {
         pw = auth_get_user();                  debug("X11 forwarding disabled in server configuration file.");
         if ((lc = login_getclass(pw->pw_class)) == NULL) {                  return 0;
                 error("unable to get login class");  
                 return;  
         }          }
 #endif          if (!options.xauth_location ||
         server_loop2();              (stat(options.xauth_location, &st) == -1)) {
         if (xauthfile)                  packet_send_debug("No xauth program; cannot forward with spoofing.");
                 xauthfile_cleanup_proc(NULL);                  return 0;
           }
           if (options.use_login) {
                   packet_send_debug("X11 forwarding disabled; "
                       "not compatible with UseLogin=yes.");
                   return 0;
           }
           if (s->display != NULL) {
                   debug("X11 display already set.");
                   return 0;
           }
           s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
           if (s->display == NULL) {
                   debug("x11_create_display_inet failed.");
                   return 0;
           }
           return 1;
   }
   
   static void
   do_authenticated2(Authctxt *authctxt)
   {
           server_loop2(authctxt);
 }  }

Legend:
Removed from v.1.42  
changed lines
  Added in v.1.42.2.6