[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.163.2.2 and 1.164

version 1.163.2.2, 2004/08/19 22:37:32 version 1.164, 2003/09/18 08:49:45
Line 42 
Line 42 
 #include "sshpty.h"  #include "sshpty.h"
 #include "packet.h"  #include "packet.h"
 #include "buffer.h"  #include "buffer.h"
 #include "match.h"  #include "mpaux.h"
 #include "uidswap.h"  #include "uidswap.h"
 #include "compat.h"  #include "compat.h"
 #include "channels.h"  #include "channels.h"
Line 58 
Line 58 
 #include "session.h"  #include "session.h"
 #include "monitor_wrap.h"  #include "monitor_wrap.h"
   
 #ifdef KRB5  
 #include <kafs.h>  
 #endif  
   
 #ifdef GSSAPI  #ifdef GSSAPI
 #include "ssh-gss.h"  #include "ssh-gss.h"
 #endif  #endif
Line 70 
Line 66 
   
 Session *session_new(void);  Session *session_new(void);
 void    session_set_fds(Session *, int, int, int);  void    session_set_fds(Session *, int, int, int);
 void    session_pty_cleanup(Session *);  void    session_pty_cleanup(void *);
 void    session_proctitle(Session *);  void    session_proctitle(Session *);
 int     session_setup_x11fwd(Session *);  int     session_setup_x11fwd(Session *);
 void    do_exec_pty(Session *, const char *);  void    do_exec_pty(Session *, const char *);
Line 94 
Line 90 
 extern u_int utmp_len;  extern u_int utmp_len;
 extern int startup_pipe;  extern int startup_pipe;
 extern void destroy_sensitive_data(void);  extern void destroy_sensitive_data(void);
 extern Buffer loginmsg;  
   
 /* original command from peer. */  /* original command from peer. */
 const char *original_command = NULL;  const char *original_command = NULL;
Line 107 
Line 102 
 login_cap_t *lc;  login_cap_t *lc;
 #endif  #endif
   
 static int is_child = 0;  
   
 /* Name and directory of socket for authentication agent forwarding. */  /* Name and directory of socket for authentication agent forwarding. */
 static char *auth_sock_name = NULL;  static char *auth_sock_name = NULL;
 static char *auth_sock_dir = NULL;  static char *auth_sock_dir = NULL;
Line 116 
Line 109 
 /* removes the agent forwarding socket */  /* removes the agent forwarding socket */
   
 static void  static void
 auth_sock_cleanup_proc(struct passwd *pw)  auth_sock_cleanup_proc(void *_pw)
 {  {
           struct passwd *pw = _pw;
   
         if (auth_sock_name != NULL) {          if (auth_sock_name != NULL) {
                 temporarily_use_uid(pw);                  temporarily_use_uid(pw);
                 unlink(auth_sock_name);                  unlink(auth_sock_name);
Line 145 
Line 140 
         /* Allocate a buffer for the socket name, and format the name. */          /* Allocate a buffer for the socket name, and format the name. */
         auth_sock_name = xmalloc(MAXPATHLEN);          auth_sock_name = xmalloc(MAXPATHLEN);
         auth_sock_dir = xmalloc(MAXPATHLEN);          auth_sock_dir = xmalloc(MAXPATHLEN);
         strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);          strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
   
         /* Create private directory for socket */          /* Create private directory for socket */
         if (mkdtemp(auth_sock_dir) == NULL) {          if (mkdtemp(auth_sock_dir) == NULL) {
Line 161 
Line 156 
         snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",          snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",
                  auth_sock_dir, (long) getpid());                   auth_sock_dir, (long) getpid());
   
           /* delete agent socket on fatal() */
           fatal_add_cleanup(auth_sock_cleanup_proc, pw);
   
         /* Create the socket. */          /* Create the socket. */
         sock = socket(AF_UNIX, SOCK_STREAM, 0);          sock = socket(AF_UNIX, SOCK_STREAM, 0);
         if (sock < 0)          if (sock < 0)
Line 178 
Line 176 
         restore_uid();          restore_uid();
   
         /* Start listening on the socket. */          /* Start listening on the socket. */
         if (listen(sock, SSH_LISTEN_BACKLOG) < 0)          if (listen(sock, 5) < 0)
                 packet_disconnect("listen: %.100s", strerror(errno));                  packet_disconnect("listen: %.100s", strerror(errno));
   
         /* Allocate a channel for the authentication agent socket. */          /* Allocate a channel for the authentication agent socket. */
Line 190 
Line 188 
         return 1;          return 1;
 }  }
   
 static void  
 display_loginmsg(void)  
 {  
         if (buffer_len(&loginmsg) > 0) {  
                 buffer_append(&loginmsg, "\0", 1);  
                 printf("%s", (char *)buffer_ptr(&loginmsg));  
                 buffer_clear(&loginmsg);  
         }  
 }  
   
 void  void
 do_authenticated(Authctxt *authctxt)  do_authenticated(Authctxt *authctxt)
Line 223 
Line 212 
         else          else
                 do_authenticated1(authctxt);                  do_authenticated1(authctxt);
   
         do_cleanup(authctxt);          /* remove agent socket */
           if (auth_sock_name != NULL)
                   auth_sock_cleanup_proc(authctxt->pw);
   #ifdef KRB5
           if (options.kerberos_ticket_cleanup)
                   krb5_cleanup_proc(authctxt);
   #endif
 }  }
   
 /*  /*
Line 261 
Line 256 
                         compression_level = packet_get_int();                          compression_level = packet_get_int();
                         packet_check_eom();                          packet_check_eom();
                         if (compression_level < 1 || compression_level > 9) {                          if (compression_level < 1 || compression_level > 9) {
                                 packet_send_debug("Received invalid compression level %d.",                                  packet_send_debug("Received illegal compression level %d.",
                                     compression_level);                                      compression_level);
                                 break;                                  break;
                         }                          }
Line 396 
Line 391 
   
         /* Fork the child. */          /* Fork the child. */
         if ((pid = fork()) == 0) {          if ((pid = fork()) == 0) {
                 is_child = 1;                  fatal_remove_all_cleanups();
   
                 /* Child.  Reinitialize the log since the pid has changed. */                  /* Child.  Reinitialize the log since 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);
Line 461 
Line 456 
         close(perr[1]);          close(perr[1]);
   
         if (compat20) {          if (compat20) {
                 if (s->is_subsystem) {                  session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]);
                         close(perr[0]);  
                         perr[0] = -1;  
                 }  
                 session_set_fds(s, pin[1], pout[0], 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]);
Line 508 
Line 499 
   
         /* Fork the child. */          /* Fork the child. */
         if ((pid = fork()) == 0) {          if ((pid = fork()) == 0) {
                 is_child = 1;                  fatal_remove_all_cleanups();
   
                 /* 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);
Line 596 
Line 587 
                 do_exec_no_pty(s, command);                  do_exec_no_pty(s, command);
   
         original_command = NULL;          original_command = NULL;
   
         /*  
          * Clear loginmsg: it's the child's responsibility to display  
          * it to the user, otherwise multiple sessions may accumulate  
          * multiple copies of the login messages.  
          */  
         buffer_clear(&loginmsg);  
 }  }
   
   
Line 610 
Line 594 
 void  void
 do_login(Session *s, const char *command)  do_login(Session *s, const char *command)
 {  {
           char *time_string;
         socklen_t fromlen;          socklen_t fromlen;
         struct sockaddr_storage from;          struct sockaddr_storage from;
         struct passwd * pw = s->pw;          struct passwd * pw = s->pw;
Line 625 
Line 610 
                 if (getpeername(packet_get_connection_in(),                  if (getpeername(packet_get_connection_in(),
                     (struct sockaddr *) & from, &fromlen) < 0) {                      (struct sockaddr *) & from, &fromlen) < 0) {
                         debug("getpeername: %.100s", strerror(errno));                          debug("getpeername: %.100s", strerror(errno));
                         cleanup_exit(255);                          fatal_cleanup();
                 }                  }
         }          }
   
Line 639 
Line 624 
         if (check_quietlogin(s, command))          if (check_quietlogin(s, command))
                 return;                  return;
   
         display_loginmsg();          if (options.print_lastlog && s->last_login_time != 0) {
                   time_string = ctime(&s->last_login_time);
                   if (strchr(time_string, '\n'))
                           *strchr(time_string, '\n') = 0;
                   if (strcmp(s->hostname, "") == 0)
                           printf("Last login: %s\r\n", time_string);
                   else
                           printf("Last login: %s from %s\r\n", time_string,
                               s->hostname);
           }
   
         do_motd();          do_motd();
 }  }
Line 796 
Line 790 
         env[0] = NULL;          env[0] = NULL;
   
 #ifdef GSSAPI  #ifdef GSSAPI
         /* Allow any GSSAPI methods that we've used to alter          /* Allow any GSSAPI methods that we've used to alter
          * the childs environment as they see fit           * the childs environment as they see fit
          */           */
         ssh_gssapi_do_child(&env, &envsize);          ssh_gssapi_do_child(&env, &envsize);
Line 804 
Line 798 
   
         if (!options.use_login) {          if (!options.use_login) {
                 /* Set basic environment. */                  /* Set basic environment. */
                 for (i = 0; i < s->num_env; i++)  
                         child_set_env(&env, &envsize, s->env[i].name,  
                             s->env[i].val);  
   
                 child_set_env(&env, &envsize, "USER", pw->pw_name);                  child_set_env(&env, &envsize, "USER", pw->pw_name);
                 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);                  child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
                 child_set_env(&env, &envsize, "HOME", pw->pw_dir);                  child_set_env(&env, &envsize, "HOME", pw->pw_dir);
Line 940 
Line 930 
                 if (debug_flag) {                  if (debug_flag) {
                         fprintf(stderr,                          fprintf(stderr,
                             "Running %.500s remove %.100s\n",                              "Running %.500s remove %.100s\n",
                             options.xauth_location, s->auth_display);                              options.xauth_location, s->auth_display);
                         fprintf(stderr,                          fprintf(stderr,
                             "%.500s add %.100s %.100s %.100s\n",                              "%.500s add %.100s %.100s %.100s\n",
                             options.xauth_location, s->auth_display,                              options.xauth_location, s->auth_display,
Line 1022 
Line 1012 
 }  }
   
 static void  static void
 do_pwchange(Session *s)  
 {  
         fflush(NULL);  
         fprintf(stderr, "WARNING: Your password has expired.\n");  
         if (s->ttyfd != -1) {  
                 fprintf(stderr,  
                     "You must change your password now and login again!\n");  
                 execl(_PATH_PASSWD_PROG, "passwd", (char *)NULL);  
                 perror("passwd");  
         } else {  
                 fprintf(stderr,  
                     "Password change required but no TTY available.\n");  
         }  
         exit(1);  
 }  
   
 static void  
 launch_login(struct passwd *pw, const char *hostname)  launch_login(struct passwd *pw, const char *hostname)
 {  {
         /* Launch login(1). */          /* Launch login(1). */
Line 1052 
Line 1025 
         exit(1);          exit(1);
 }  }
   
 static void  
 child_close_fds(void)  
 {  
         int i;  
   
         if (packet_get_connection_in() == packet_get_connection_out())  
                 close(packet_get_connection_in());  
         else {  
                 close(packet_get_connection_in());  
                 close(packet_get_connection_out());  
         }  
         /*  
          * Close all descriptors related to channels.  They will still remain  
          * open in the parent.  
          */  
         /* XXX better use close-on-exec? -markus */  
         channel_close_all();  
   
         /*  
          * Close any extra file descriptors.  Note that there may still be  
          * descriptors left by system functions.  They will be closed later.  
          */  
         endpwent();  
   
         /*  
          * Close any extra open file descriptors so that we don\'t have them  
          * hanging around in clients.  Note that we want to do this after  
          * initgroups, because at least on Solaris 2.3 it leaves file  
          * descriptors open.  
          */  
         for (i = 3; i < 64; i++)  
                 close(i);  
 }  
   
 /*  /*
  * Performs common processing for the child, such as setting up the   * Performs common processing for the child, such as setting up the
  * environment, closing extra file descriptors, setting the user and group   * environment, closing extra file descriptors, setting the user and group
Line 1099 
Line 1038 
         char *argv[10];          char *argv[10];
         const char *shell, *shell0, *hostname = NULL;          const char *shell, *shell0, *hostname = NULL;
         struct passwd *pw = s->pw;          struct passwd *pw = s->pw;
           u_int i;
   
         /* remove hostkey from the child's memory */          /* remove hostkey from the child's memory */
         destroy_sensitive_data();          destroy_sensitive_data();
   
         /* Force a password change */  
         if (s->authctxt->force_pwchange) {  
                 do_setusercontext(pw);  
                 child_close_fds();  
                 do_pwchange(s);  
                 exit(1);  
         }  
   
         /* 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 1151 
Line 1083 
          * closed before building the environment, as we call           * closed before building the environment, as we call
          * get_remote_ipaddr there.           * get_remote_ipaddr there.
          */           */
         child_close_fds();          if (packet_get_connection_in() == packet_get_connection_out())
                   close(packet_get_connection_in());
           else {
                   close(packet_get_connection_in());
                   close(packet_get_connection_out());
           }
           /*
            * Close all descriptors related to channels.  They will still remain
            * open in the parent.
            */
           /* XXX better use close-on-exec? -markus */
           channel_close_all();
   
         /*          /*
          * Must take new environment into use so that .ssh/rc,           * Close any extra file descriptors.  Note that there may still be
          * /etc/ssh/sshrc and xauth are run in the proper environment.           * descriptors left by system functions.  They will be closed later.
          */           */
         environ = env;          endpwent();
   
 #ifdef KRB5  
         /*          /*
          * At this point, we check to see if AFS is active and if we have           * Close any extra open file descriptors so that we don\'t have them
          * a valid Kerberos 5 TGT. If so, it seems like a good idea to see           * hanging around in clients.  Note that we want to do this after
          * if we can (and need to) extend the ticket into an AFS token. If           * initgroups, because at least on Solaris 2.3 it leaves file
          * we don't do this, we run into potential problems if the user's           * descriptors open.
          * home directory is in AFS and it's not world-readable.  
          */           */
           for (i = 3; i < 64; i++)
                   close(i);
   
         if (options.kerberos_get_afs_token && k_hasafs() &&          /*
              (s->authctxt->krb5_ctx != NULL)) {           * Must take new environment into use so that .ssh/rc,
                 char cell[64];           * /etc/ssh/sshrc and xauth are run in the proper environment.
            */
           environ = env;
   
                 debug("Getting AFS token");  
   
                 k_setpag();  
   
                 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)  
                         krb5_afslog(s->authctxt->krb5_ctx,  
                             s->authctxt->krb5_fwd_ccache, cell, NULL);  
   
                 krb5_afslog_home(s->authctxt->krb5_ctx,  
                     s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);  
         }  
 #endif  
   
         /* Change current directory to the user\'s home directory. */          /* Change current directory to the user\'s home directory. */
         if (chdir(pw->pw_dir) < 0) {          if (chdir(pw->pw_dir) < 0) {
                 fprintf(stderr, "Could not chdir to home directory %s: %s\n",                  fprintf(stderr, "Could not chdir to home directory %s: %s\n",
Line 1306 
Line 1238 
         }          }
         s->authctxt = authctxt;          s->authctxt = authctxt;
         s->pw = authctxt->pw;          s->pw = authctxt->pw;
         if (s->pw == NULL || !authctxt->valid)          if (s->pw == NULL)
                 fatal("no user for session %d", 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;
Line 1386 
Line 1318 
                 packet_disconnect("Protocol error: you already have a pty.");                  packet_disconnect("Protocol error: you already have a pty.");
                 return 0;                  return 0;
         }          }
           /* Get the time and hostname when the user last logged in. */
           if (options.print_lastlog) {
                   s->hostname[0] = '\0';
                   s->last_login_time = get_last_login_time(s->pw->pw_uid,
                       s->pw->pw_name, s->hostname, sizeof(s->hostname));
           }
   
         s->term = packet_get_string(&len);          s->term = packet_get_string(&len);
   
Line 1422 
Line 1360 
                 n_bytes = packet_remaining();                  n_bytes = packet_remaining();
         tty_parse_modes(s->ttyfd, &n_bytes);          tty_parse_modes(s->ttyfd, &n_bytes);
   
           /*
            * Add a cleanup function to clear the utmp entry and record logout
            * time in case we call fatal() (e.g., the connection gets closed).
            */
           fatal_add_cleanup(session_pty_cleanup, (void *)s);
         if (!use_privsep)          if (!use_privsep)
                 pty_setowner(s->pw, s->tty);                  pty_setowner(s->pw, s->tty);
   
Line 1512 
Line 1455 
 static int  static int
 session_break_req(Session *s)  session_break_req(Session *s)
 {  {
           u_int break_length;
   
         packet_get_int();       /* ignored */          break_length = packet_get_int();        /* ignored */
         packet_check_eom();          packet_check_eom();
   
         if (s->ttyfd == -1 ||          if (s->ttyfd == -1 ||
Line 1523 
Line 1467 
 }  }
   
 static int  static int
 session_env_req(Session *s)  
 {  
         char *name, *val;  
         u_int name_len, val_len, i;  
   
         name = packet_get_string(&name_len);  
         val = packet_get_string(&val_len);  
         packet_check_eom();  
   
         /* Don't set too many environment variables */  
         if (s->num_env > 128) {  
                 debug2("Ignoring env request %s: too many env vars", name);  
                 goto fail;  
         }  
   
         for (i = 0; i < options.num_accept_env; i++) {  
                 if (match_pattern(name, options.accept_env[i])) {  
                         debug2("Setting env %d: %s=%s", s->num_env, name, val);  
                         s->env = xrealloc(s->env, sizeof(*s->env) *  
                             (s->num_env + 1));  
                         s->env[s->num_env].name = name;  
                         s->env[s->num_env].val = val;  
                         s->num_env++;  
                         return (1);  
                 }  
         }  
         debug2("Ignoring env request %s: disallowed name", name);  
   
  fail:  
         xfree(name);  
         xfree(val);  
         return (0);  
 }  
   
 static int  
 session_auth_agent_req(Session *s)  session_auth_agent_req(Session *s)
 {  {
         static int called = 0;          static int called = 0;
Line 1604 
Line 1513 
                         success = session_auth_agent_req(s);                          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);
                 } else if (strcmp(rtype, "env") == 0) {                  } else if (strcmp(rtype, "break") == 0) {
                         success = session_env_req(s);                          success = session_break_req(s);
                 }                  }
         }          }
         if (strcmp(rtype, "window-change") == 0) {          if (strcmp(rtype, "window-change") == 0) {
                 success = session_window_change_req(s);                  success = session_window_change_req(s);
         } else if (strcmp(rtype, "break") == 0) {  
                 success = session_break_req(s);  
         }          }
   
         return success;          return success;
 }  }
   
Line 1640 
Line 1546 
  * (e.g., due to a dropped connection).   * (e.g., due to a dropped connection).
  */   */
 void  void
 session_pty_cleanup2(Session *s)  session_pty_cleanup2(void *session)
 {  {
           Session *s = session;
   
         if (s == NULL) {          if (s == NULL) {
                 error("session_pty_cleanup: no session");                  error("session_pty_cleanup: no session");
                 return;                  return;
Line 1672 
Line 1580 
 }  }
   
 void  void
 session_pty_cleanup(Session *s)  session_pty_cleanup(void *session)
 {  {
         PRIVSEP(session_pty_cleanup2(s));          PRIVSEP(session_pty_cleanup2(session));
 }  }
   
 static char *  static char *
Line 1742 
Line 1650 
 void  void
 session_close(Session *s)  session_close(Session *s)
 {  {
         int i;  
   
         debug("session_close: session %d pid %ld", s->self, (long)s->pid);          debug("session_close: session %d pid %ld", s->self, (long)s->pid);
         if (s->ttyfd != -1)          if (s->ttyfd != -1) {
                   fatal_remove_cleanup(session_pty_cleanup, (void *)s);
                 session_pty_cleanup(s);                  session_pty_cleanup(s);
           }
         if (s->term)          if (s->term)
                 xfree(s->term);                  xfree(s->term);
         if (s->display)          if (s->display)
Line 1758 
Line 1666 
         if (s->auth_proto)          if (s->auth_proto)
                 xfree(s->auth_proto);                  xfree(s->auth_proto);
         s->used = 0;          s->used = 0;
         for (i = 0; i < s->num_env; i++) {  
                 xfree(s->env[i].name);  
                 xfree(s->env[i].val);  
         }  
         if (s->env != NULL)  
                 xfree(s->env);  
         session_proctitle(s);          session_proctitle(s);
 }  }
   
Line 1801 
Line 1703 
                  * delay detach of session, but release pty, since                   * delay detach of session, but release pty, since
                  * the fd's to the child are already closed                   * the fd's to the child are already closed
                  */                   */
                 if (s->ttyfd != -1)                  if (s->ttyfd != -1) {
                           fatal_remove_cleanup(session_pty_cleanup, (void *)s);
                         session_pty_cleanup(s);                          session_pty_cleanup(s);
                   }
                 return;                  return;
         }          }
         /* detach by removing callback */          /* detach by removing callback */
Line 1919 
Line 1823 
 do_authenticated2(Authctxt *authctxt)  do_authenticated2(Authctxt *authctxt)
 {  {
         server_loop2(authctxt);          server_loop2(authctxt);
 }  #if defined(GSSAPI)
           if (options.gss_cleanup_creds)
 void                  ssh_gssapi_cleanup_creds(NULL);
 do_cleanup(Authctxt *authctxt)  
 {  
         static int called = 0;  
   
         debug("do_cleanup");  
   
         /* no cleanup if we're in the child for login shell */  
         if (is_child)  
                 return;  
   
         /* avoid double cleanup */  
         if (called)  
                 return;  
         called = 1;  
   
         if (authctxt == NULL)  
                 return;  
 #ifdef KRB5  
         if (options.kerberos_ticket_cleanup &&  
             authctxt->krb5_ctx)  
                 krb5_cleanup_proc(authctxt);  
 #endif  #endif
   
 #ifdef GSSAPI  
         if (compat20 && options.gss_cleanup_creds)  
                 ssh_gssapi_cleanup_creds();  
 #endif  
   
         /* remove agent socket */  
         auth_sock_cleanup_proc(authctxt->pw);  
   
         /*  
          * Cleanup ptys/utmp only if privsep is disabled,  
          * or if running in monitor.  
          */  
         if (!use_privsep || mm_is_monitor())  
                 session_destroy_all(session_pty_cleanup2);  
 }  }

Legend:
Removed from v.1.163.2.2  
changed lines
  Added in v.1.164