[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.108 and 1.108.2.6

version 1.108, 2001/10/11 13:45:21 version 1.108.2.6, 2002/06/26 18:22:35
Line 56 
Line 56 
 #include "serverloop.h"  #include "serverloop.h"
 #include "canohost.h"  #include "canohost.h"
 #include "session.h"  #include "session.h"
   #include "monitor_wrap.h"
   
 /* types */  
   
 #define TTYSZ 64  
 typedef struct Session Session;  
 struct Session {  
         int     used;  
         int     self;  
         struct passwd *pw;  
         Authctxt *authctxt;  
         pid_t   pid;  
         /* tty */  
         char    *term;  
         int     ptyfd, ttyfd, ptymaster;  
         int     row, col, xpixel, ypixel;  
         char    tty[TTYSZ];  
         /* X11 */  
         char    *display;  
         int     screen;  
         char    *auth_proto;  
         char    *auth_data;  
         int     single_connection;  
         /* proto 2 */  
         int     chanid;  
         int     is_subsystem;  
 };  
   
 /* func */  /* func */
   
 Session *session_new(void);  Session *session_new(void);
 void    session_set_fds(Session *, int, int, int);  void    session_set_fds(Session *, int, int, int);
 static void     session_pty_cleanup(void *);  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 101 
Line 76 
 static void do_authenticated1(Authctxt *);  static void do_authenticated1(Authctxt *);
 static void do_authenticated2(Authctxt *);  static void do_authenticated2(Authctxt *);
   
 static void session_close(Session *);  
 static int session_pty_req(Session *);  static int session_pty_req(Session *);
   
 /* import */  /* import */
Line 121 
Line 95 
 Session sessions[MAX_SESSIONS];  Session sessions[MAX_SESSIONS];
   
 #ifdef HAVE_LOGIN_CAP  #ifdef HAVE_LOGIN_CAP
 static login_cap_t *lc;  login_cap_t *lc;
 #endif  #endif
   
   /* Name and directory of socket for authentication agent forwarding. */
   static char *auth_sock_name = NULL;
   static char *auth_sock_dir = NULL;
   
   /* removes the agent forwarding socket */
   
   static void
   auth_sock_cleanup_proc(void *_pw)
   {
           struct passwd *pw = _pw;
   
           if (auth_sock_name != NULL) {
                   temporarily_use_uid(pw);
                   unlink(auth_sock_name);
                   rmdir(auth_sock_dir);
                   auth_sock_name = NULL;
                   restore_uid();
           }
   }
   
   static int
   auth_input_request_forwarding(struct passwd * pw)
   {
           Channel *nc;
           int sock;
           struct sockaddr_un sunaddr;
   
           if (auth_sock_name != NULL) {
                   error("authentication forwarding requested twice.");
                   return 0;
           }
   
           /* Temporarily drop privileged uid for mkdir/bind. */
           temporarily_use_uid(pw);
   
           /* Allocate a buffer for the socket name, and format the name. */
           auth_sock_name = xmalloc(MAXPATHLEN);
           auth_sock_dir = xmalloc(MAXPATHLEN);
           strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
   
           /* Create private directory for socket */
           if (mkdtemp(auth_sock_dir) == NULL) {
                   packet_send_debug("Agent forwarding disabled: "
                       "mkdtemp() failed: %.100s", strerror(errno));
                   restore_uid();
                   xfree(auth_sock_name);
                   xfree(auth_sock_dir);
                   auth_sock_name = NULL;
                   auth_sock_dir = NULL;
                   return 0;
           }
           snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",
                    auth_sock_dir, (long) getpid());
   
           /* delete agent socket on fatal() */
           fatal_add_cleanup(auth_sock_cleanup_proc, pw);
   
           /* Create the socket. */
           sock = socket(AF_UNIX, SOCK_STREAM, 0);
           if (sock < 0)
                   packet_disconnect("socket: %.100s", strerror(errno));
   
           /* Bind it to the name. */
           memset(&sunaddr, 0, sizeof(sunaddr));
           sunaddr.sun_family = AF_UNIX;
           strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
   
           if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)
                   packet_disconnect("bind: %.100s", strerror(errno));
   
           /* Restore the privileged uid. */
           restore_uid();
   
           /* Start listening on the socket. */
           if (listen(sock, 5) < 0)
                   packet_disconnect("listen: %.100s", strerror(errno));
   
           /* Allocate a channel for the authentication agent socket. */
           nc = channel_new("auth socket",
               SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
               CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
               0, xstrdup("auth socket"), 1);
           strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
           return 1;
   }
   
   
 void  void
 do_authenticated(Authctxt *authctxt)  do_authenticated(Authctxt *authctxt)
 {  {
Line 136 
Line 197 
                 close(startup_pipe);                  close(startup_pipe);
                 startup_pipe = -1;                  startup_pipe = -1;
         }          }
 #ifdef HAVE_LOGIN_CAP  
         if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) {  
                 error("unable to get login class");  
                 return;  
         }  
 #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 */          /* setup the channel layer */
         if (!no_port_forwarding_flag && options.allow_tcp_forwarding)          if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
                 channel_permit_all_opens();                  channel_permit_all_opens();
Line 158 
Line 207 
                 do_authenticated1(authctxt);                  do_authenticated1(authctxt);
   
         /* remove agent socket */          /* remove agent socket */
         if (auth_get_socket_name())          if (auth_sock_name != NULL)
                 auth_sock_cleanup_proc(authctxt->pw);                  auth_sock_cleanup_proc(authctxt->pw);
 #ifdef KRB4  #ifdef KRB4
         if (options.kerberos_ticket_cleanup)          if (options.kerberos_ticket_cleanup)
Line 181 
Line 230 
 {  {
         Session *s;          Session *s;
         char *command;          char *command;
         int success, type, plen, screen_flag;          int success, type, screen_flag;
         int compression_level = 0, enable_compression_after_reply = 0;          int enable_compression_after_reply = 0;
         u_int proto_len, data_len, dlen;          u_int proto_len, data_len, dlen, compression_level = 0;
   
         s = session_new();          s = session_new();
         s->authctxt = authctxt;          s->authctxt = authctxt;
Line 197 
Line 246 
                 success = 0;                  success = 0;
   
                 /* Get a packet from the client. */                  /* Get a packet from the client. */
                 type = packet_read(&plen);                  type = packet_read();
   
                 /* Process the packet. */                  /* Process the packet. */
                 switch (type) {                  switch (type) {
                 case SSH_CMSG_REQUEST_COMPRESSION:                  case SSH_CMSG_REQUEST_COMPRESSION:
                         packet_integrity_check(plen, 4, type);  
                         compression_level = packet_get_int();                          compression_level = packet_get_int();
                           packet_check_eom();
                         if (compression_level < 1 || compression_level > 9) {                          if (compression_level < 1 || compression_level > 9) {
                                 packet_send_debug("Received illegal compression level %d.",                                  packet_send_debug("Received illegal compression level %d.",
                                      compression_level);                                      compression_level);
                                 break;                                  break;
                         }                          }
                           if (!options.compression) {
                                   debug2("compression disabled");
                                   break;
                           }
                         /* Enable compression after we have responded with SUCCESS. */                          /* Enable compression after we have responded with SUCCESS. */
                         enable_compression_after_reply = 1;                          enable_compression_after_reply = 1;
                         success = 1;                          success = 1;
Line 234 
Line 287 
                         } else {                          } else {
                                 s->screen = 0;                                  s->screen = 0;
                         }                          }
                         packet_done();                          packet_check_eom();
                         success = session_setup_x11fwd(s);                          success = session_setup_x11fwd(s);
                         if (!success) {                          if (!success) {
                                 xfree(s->auth_proto);                                  xfree(s->auth_proto);
Line 271 
Line 324 
                         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)  #if defined(AFS) || defined(KRB5)
                 case SSH_CMSG_HAVE_KERBEROS_TGT:                  case SSH_CMSG_HAVE_KERBEROS_TGT:
                         if (!options.kerberos_tgt_passing) {                          if (!options.kerberos_tgt_passing) {
                                 verbose("Kerberos TGT passing disabled.");                                  verbose("Kerberos TGT passing disabled.");
                         } else {                          } else {
                                 char *kdata = packet_get_string(&dlen);                                  char *kdata = packet_get_string(&dlen);
                                 packet_integrity_check(plen, 4 + dlen, type);                                  packet_check_eom();
   
                                 /* XXX - 0x41, see creds_to_radix version */                                  /* XXX - 0x41, see creds_to_radix version */
                                 if (kdata[0] != 0x41) {                                  if (kdata[0] != 0x41) {
 #ifdef KRB5  #ifdef KRB5
                                         krb5_data tgt;                                          krb5_data tgt;
                                         tgt.data = kdata;                                          tgt.data = kdata;
                                         tgt.length = dlen;                                          tgt.length = dlen;
   
                                         if (auth_krb5_tgt(s->authctxt, &tgt))                                          if (auth_krb5_tgt(s->authctxt, &tgt))
                                                 success = 1;                                                  success = 1;
                                         else                                          else
Line 304 
Line 357 
                         }                          }
                         break;                          break;
 #endif /* AFS || KRB5 */  #endif /* AFS || KRB5 */
   
 #ifdef AFS  #ifdef AFS
                 case SSH_CMSG_HAVE_AFS_TOKEN:                  case SSH_CMSG_HAVE_AFS_TOKEN:
                         if (!options.afs_token_passing || !k_hasafs()) {                          if (!options.afs_token_passing || !k_hasafs()) {
Line 312 
Line 365 
                         } else {                          } else {
                                 /* Accept AFS token. */                                  /* Accept AFS token. */
                                 char *token = packet_get_string(&dlen);                                  char *token = packet_get_string(&dlen);
                                 packet_integrity_check(plen, 4 + dlen, type);                                  packet_check_eom();
   
                                 if (auth_afs_token(s->authctxt, token))                                  if (auth_afs_token(s->authctxt, token))
                                         success = 1;                                          success = 1;
                                 else                                  else
Line 334 
Line 387 
                         } else {                          } else {
                                 do_exec(s, NULL);                                  do_exec(s, NULL);
                         }                          }
                         packet_done();                          packet_check_eom();
                         session_close(s);                          session_close(s);
                         return;                          return;
   
Line 365 
Line 418 
 void  void
 do_exec_no_pty(Session *s, const char *command)  do_exec_no_pty(Session *s, const char *command)
 {  {
         int pid;          pid_t pid;
   
 #ifdef USE_PIPES  #ifdef USE_PIPES
         int pin[2], pout[2], perr[2];          int pin[2], pout[2], perr[2];
Line 581 
Line 634 
 do_login(Session *s, const char *command)  do_login(Session *s, const char *command)
 {  {
         char *time_string;          char *time_string;
         char hostname[MAXHOSTNAMELEN];  
         socklen_t fromlen;          socklen_t fromlen;
         struct sockaddr_storage from;          struct sockaddr_storage from;
         time_t last_login_time;  
         struct passwd * pw = s->pw;          struct passwd * pw = s->pw;
         pid_t pid = getpid();          pid_t pid = getpid();
   
Line 596 
Line 647 
         if (packet_connection_is_on_socket()) {          if (packet_connection_is_on_socket()) {
                 fromlen = sizeof(from);                  fromlen = sizeof(from);
                 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));
                         fatal_cleanup();                          fatal_cleanup();
                 }                  }
         }          }
   
         /* Get the time and hostname when the user last logged in. */  
         if (options.print_lastlog) {  
                 hostname[0] = '\0';  
                 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,          if (!use_privsep)
             get_remote_name_or_ip(utmp_len, options.reverse_mapping_check),                  record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
             (struct sockaddr *)&from);                      get_remote_name_or_ip(utmp_len,
                       options.verify_reverse_mapping),
                       (struct sockaddr *)&from);
   
         if (check_quietlogin(s, command))          if (check_quietlogin(s, command))
                 return;                  return;
   
         if (options.print_lastlog && last_login_time != 0) {          if (options.print_lastlog && s->last_login_time != 0) {
                 time_string = ctime(&last_login_time);                  time_string = ctime(&s->last_login_time);
                 if (strchr(time_string, '\n'))                  if (strchr(time_string, '\n'))
                         *strchr(time_string, '\n') = 0;                          *strchr(time_string, '\n') = 0;
                 if (strcmp(hostname, "") == 0)                  if (strcmp(s->hostname, "") == 0)
                         printf("Last login: %s\r\n", time_string);                          printf("Last login: %s\r\n", time_string);
                 else                  else
                         printf("Last login: %s from %s\r\n", time_string, hostname);                          printf("Last login: %s from %s\r\n", time_string,
                               s->hostname);
         }          }
   
         do_motd();          do_motd();
Line 685 
Line 732 
  */   */
 static void  static void
 child_set_env(char ***envp, u_int *envsizep, const char *name,  child_set_env(char ***envp, u_int *envsizep, const char *name,
               const char *value)          const char *value)
 {  {
         u_int i, namelen;          u_int i, namelen;
         char **env;          char **env;
Line 706 
Line 753 
         } else {          } else {
                 /* New variable.  Expand if necessary. */                  /* New variable.  Expand if necessary. */
                 if (i >= (*envsizep) - 1) {                  if (i >= (*envsizep) - 1) {
                           if (*envsizep >= 1000)
                                   fatal("child_set_env: too many env vars,"
                                       " skipping: %.100s", name);
                         (*envsizep) += 50;                          (*envsizep) += 50;
                         env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));                          env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
                 }                  }
Line 726 
Line 776 
  */   */
 static void  static void
 read_environment_file(char ***env, u_int *envsize,  read_environment_file(char ***env, u_int *envsize,
                       const char *filename)          const char *filename)
 {  {
         FILE *f;          FILE *f;
         char buf[4096];          char buf[4096];
         char *cp, *value;          char *cp, *value;
           u_int lineno = 0;
   
         f = fopen(filename, "r");          f = fopen(filename, "r");
         if (!f)          if (!f)
                 return;                  return;
   
         while (fgets(buf, sizeof(buf), f)) {          while (fgets(buf, sizeof(buf), f)) {
                   if (++lineno > 1000)
                           fatal("Too many lines in environment file %s", filename);
                 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)                  for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
                         ;                          ;
                 if (!*cp || *cp == '#' || *cp == '\n')                  if (!*cp || *cp == '#' || *cp == '\n')
Line 745 
Line 798 
                         *strchr(cp, '\n') = '\0';                          *strchr(cp, '\n') = '\0';
                 value = strchr(cp, '=');                  value = strchr(cp, '=');
                 if (value == NULL) {                  if (value == NULL) {
                         fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);                          fprintf(stderr, "Bad line %u in %.100s\n", lineno,
                               filename);
                         continue;                          continue;
                 }                  }
                 /*                  /*
Line 759 
Line 813 
         fclose(f);          fclose(f);
 }  }
   
 /*  static char **
  * Performs common processing for the child, such as setting up the  do_setup_env(Session *s, const char *shell)
  * environment, closing extra file descriptors, setting the user and group  
  * ids, and executing the command or shell.  
  */  
 void  
 do_child(Session *s, const char *command)  
 {  {
         const char *shell, *hostname = NULL, *cp = NULL;  
         struct passwd *pw = s->pw;  
         char buf[256];          char buf[256];
         char cmd[1024];          u_int i, envsize;
         FILE *f = NULL;  
         u_int envsize, i;  
         char **env;          char **env;
         extern char **environ;          struct passwd *pw = s->pw;
         struct stat st;  
         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 */  
         if (options.use_login && command != NULL)  
                 options.use_login = 0;  
   
         if (!options.use_login) {  
 #ifdef HAVE_LOGIN_CAP  
                 if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)  
                         f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,  
                             _PATH_NOLOGIN), "r");  
 #else  
                 if (pw->pw_uid)  
                         f = fopen(_PATH_NOLOGIN, "r");  
 #endif  
                 if (f) {  
                         /* /etc/nologin exists.  Print its contents and exit. */  
                         while (fgets(buf, sizeof(buf), f))  
                                 fputs(buf, stderr);  
                         fclose(f);  
                         exit(254);  
                 }  
         }  
         /* Set login name, uid, gid, and groups. */  
         /* Login(1) does this as well, and it needs uid 0 for the "-h"  
            switch, so we let login(1) to this for us. */  
         if (!options.use_login) {  
                 if (getuid() == 0 || geteuid() == 0) {  
 #ifdef HAVE_LOGIN_CAP  
                         if (setusercontext(lc, pw, pw->pw_uid,  
                             (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {  
                                 perror("unable to set user context");  
                                 exit(1);  
                         }  
 #else  
                         if (setlogin(pw->pw_name) < 0)  
                                 error("setlogin failed: %s", strerror(errno));  
                         if (setgid(pw->pw_gid) < 0) {  
                                 perror("setgid");  
                                 exit(1);  
                         }  
                         /* Initialize the group list. */  
                         if (initgroups(pw->pw_name, pw->pw_gid) < 0) {  
                                 perror("initgroups");  
                                 exit(1);  
                         }  
                         endgrent();  
   
                         /* Permanently switch to the desired uid. */  
                         permanently_set_uid(pw);  
 #endif  
                 }  
                 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)  
                         fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);  
         }  
         /*  
          * Get the shell from the password data.  An empty shell field is  
          * legal, and means /bin/sh.  
          */  
         shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;  
 #ifdef HAVE_LOGIN_CAP  
         shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);  
 #endif  
   
         /* Initialize the environment. */          /* Initialize the environment. */
         envsize = 100;          envsize = 100;
         env = xmalloc(envsize * sizeof(char *));          env = xmalloc(envsize * sizeof(char *));
Line 875 
Line 849 
                 child_set_env(&env, &envsize, "TZ", getenv("TZ"));                  child_set_env(&env, &envsize, "TZ", getenv("TZ"));
   
         /* Set custom environment options from RSA authentication. */          /* Set custom environment options from RSA authentication. */
         while (custom_environment) {          if (!options.use_login) {
                 struct envstring *ce = custom_environment;                  while (custom_environment) {
                 char *s = ce->s;                          struct envstring *ce = custom_environment;
                 int i;                          char *s = ce->s;
                 for (i = 0; s[i] != '=' && s[i]; i++);  
                 if (s[i] == '=') {                          for (i = 0; s[i] != '=' && s[i]; i++)
                         s[i] = 0;                                  ;
                         child_set_env(&env, &envsize, s, s + i + 1);                          if (s[i] == '=') {
                                   s[i] = 0;
                                   child_set_env(&env, &envsize, s, s + i + 1);
                           }
                           custom_environment = ce->next;
                           xfree(ce->s);
                           xfree(ce);
                 }                  }
                 custom_environment = ce->next;  
                 xfree(ce->s);  
                 xfree(ce);  
         }          }
   
         snprintf(buf, sizeof buf, "%.50s %d %d",          snprintf(buf, sizeof buf, "%.50s %d %d",
                  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 (s->ttyfd != -1)          if (s->ttyfd != -1)
Line 905 
Line 882 
 #ifdef KRB4  #ifdef KRB4
         if (s->authctxt->krb4_ticket_file)          if (s->authctxt->krb4_ticket_file)
                 child_set_env(&env, &envsize, "KRBTKFILE",                  child_set_env(&env, &envsize, "KRBTKFILE",
                               s->authctxt->krb4_ticket_file);                      s->authctxt->krb4_ticket_file);
 #endif  #endif
 #ifdef KRB5  #ifdef KRB5
         if (s->authctxt->krb5_ticket_file)          if (s->authctxt->krb5_ticket_file)
                 child_set_env(&env, &envsize, "KRB5CCNAME",                  child_set_env(&env, &envsize, "KRB5CCNAME",
                               s->authctxt->krb5_ticket_file);                      s->authctxt->krb5_ticket_file);
 #endif  #endif
         if (auth_get_socket_name() != NULL)          if (auth_sock_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_sock_name);
   
         /* read $HOME/.ssh/environment. */          /* read $HOME/.ssh/environment. */
         if (!options.use_login) {          if (!options.use_login) {
Line 928 
Line 905 
                 for (i = 0; env[i]; i++)                  for (i = 0; env[i]; i++)
                         fprintf(stderr, "  %.200s\n", env[i]);                          fprintf(stderr, "  %.200s\n", env[i]);
         }          }
           return env;
   }
   
   /*
    * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found
    * first in this order).
    */
   static void
   do_rc_files(Session *s, const char *shell)
   {
           FILE *f = NULL;
           char cmd[1024];
           int do_xauth;
           struct stat st;
   
           do_xauth =
               s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
   
           /* 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)
                           fprintf(stderr, "Running %s\n", cmd);
                   f = popen(cmd, "w");
                   if (f) {
                           if (do_xauth)
                                   fprintf(f, "%s %s\n", s->auth_proto,
                                       s->auth_data);
                           pclose(f);
                   } else
                           fprintf(stderr, "Could not run %s\n",
                               _PATH_SSH_USER_RC);
           } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
                   if (debug_flag)
                           fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
                               _PATH_SSH_SYSTEM_RC);
                   f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");
                   if (f) {
                           if (do_xauth)
                                   fprintf(f, "%s %s\n", s->auth_proto,
                                       s->auth_data);
                           pclose(f);
                   } else
                           fprintf(stderr, "Could not run %s\n",
                               _PATH_SSH_SYSTEM_RC);
           } else if (do_xauth && options.xauth_location != NULL) {
                   /* Add authority data to .Xauthority if appropriate. */
                   if (debug_flag) {
                           fprintf(stderr,
                               "Running %.500s add "
                               "%.100s %.100s %.100s\n",
                               options.xauth_location, s->auth_display,
                               s->auth_proto, s->auth_data);
                   }
                   snprintf(cmd, sizeof cmd, "%s -q -",
                       options.xauth_location);
                   f = popen(cmd, "w");
                   if (f) {
                           fprintf(f, "add %s %s %s\n",
                               s->auth_display, s->auth_proto,
                               s->auth_data);
                           pclose(f);
                   } else {
                           fprintf(stderr, "Could not run %s\n",
                               cmd);
                   }
           }
   }
   
   static void
   do_nologin(struct passwd *pw)
   {
           FILE *f = NULL;
           char buf[1024];
   
   #ifdef HAVE_LOGIN_CAP
           if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid)
                   f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN,
                       _PATH_NOLOGIN), "r");
   #else
           if (pw->pw_uid)
                   f = fopen(_PATH_NOLOGIN, "r");
   #endif
           if (f) {
                   /* /etc/nologin exists.  Print its contents and exit. */
                   while (fgets(buf, sizeof(buf), f))
                           fputs(buf, stderr);
                   fclose(f);
                   exit(254);
           }
   }
   
   /* Set login name, uid, gid, and groups. */
   void
   do_setusercontext(struct passwd *pw)
   {
           if (getuid() == 0 || geteuid() == 0) {
   #ifdef HAVE_LOGIN_CAP
                   if (setusercontext(lc, pw, pw->pw_uid,
                       (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
                           perror("unable to set user context");
                           exit(1);
                   }
   #else
                   if (setlogin(pw->pw_name) < 0)
                           error("setlogin failed: %s", strerror(errno));
                   if (setgid(pw->pw_gid) < 0) {
                           perror("setgid");
                           exit(1);
                   }
                   /* Initialize the group list. */
                   if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
                           perror("initgroups");
                           exit(1);
                   }
                   endgrent();
   
                   /* Permanently switch to the desired uid. */
                   permanently_set_uid(pw);
   #endif
           }
           if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
                   fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
   }
   
   static void
   launch_login(struct passwd *pw, const char *hostname)
   {
           /* Launch login(1). */
   
           execl("/usr/bin/login", "login", "-h", hostname,
               "-p", "-f", "--", pw->pw_name, (char *)NULL);
   
           /* Login couldn't be executed, die. */
   
           perror("login");
           exit(1);
   }
   
   /*
    * Performs common processing for the child, such as setting up the
    * environment, closing extra file descriptors, setting the user and group
    * ids, and executing the command or shell.
    */
   void
   do_child(Session *s, const char *command)
   {
           extern char **environ;
           char **env;
           char *argv[10];
           const char *shell, *shell0, *hostname = NULL;
           struct passwd *pw = s->pw;
           u_int i;
   
           /* remove hostkey from the child's memory */
           destroy_sensitive_data();
   
           /* login(1) is only called if we execute the login shell */
           if (options.use_login && command != NULL)
                   options.use_login = 0;
   
           /*
            * Login(1) does this as well, and it needs uid 0 for the "-h"
            * switch, so we let login(1) to this for us.
            */
           if (!options.use_login) {
                   do_nologin(pw);
                   do_setusercontext(pw);
           }
   
           /*
            * Get the shell from the password data.  An empty shell field is
            * legal, and means /bin/sh.
            */
           shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
   #ifdef HAVE_LOGIN_CAP
           shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
   #endif
   
           env = do_setup_env(s, shell);
   
         /* 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(utmp_len,                  hostname = get_remote_name_or_ip(utmp_len,
                     options.reverse_mapping_check);                      options.verify_reverse_mapping);
         /*          /*
          * 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 968 
Line 1127 
                 close(i);                  close(i);
   
         /*          /*
          * Must take new environment into use so that .ssh/rc, /etc/sshrc and           * Must take new environment into use so that .ssh/rc,
          * xauth are run in the proper environment.           * /etc/sshrc and xauth are run in the proper environment.
          */           */
         environ = env;          environ = env;
   
Line 977 
Line 1136 
         /* Try to get AFS tokens for the local cell. */          /* Try to get AFS tokens for the local cell. */
         if (k_hasafs()) {          if (k_hasafs()) {
                 char cell[64];                  char cell[64];
   
                 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)                  if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
                         krb_afslog(cell, 0);                          krb_afslog(cell, 0);
   
                 krb_afslog(0, 0);                  krb_afslog(0, 0);
         }          }
 #endif /* AFS */  #endif /* AFS */
Line 995 
Line 1154 
 #endif  #endif
         }          }
   
         /*          if (!options.use_login)
          * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first                  do_rc_files(s, shell);
          * in this order).  
          */  
         if (!options.use_login) {  
                 /* 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)  
                                 fprintf(stderr, "Running %s\n", cmd);  
                         f = popen(cmd, "w");  
                         if (f) {  
                                 if (do_xauth)  
                                         fprintf(f, "%s %s\n", s->auth_proto,  
                                             s->auth_data);  
                                 pclose(f);  
                         } else  
                                 fprintf(stderr, "Could not run %s\n",  
                                     _PATH_SSH_USER_RC);  
                 } else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {  
                         if (debug_flag)  
                                 fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,  
                                     _PATH_SSH_SYSTEM_RC);  
                         f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w");  
                         if (f) {  
                                 if (do_xauth)  
                                         fprintf(f, "%s %s\n", s->auth_proto,  
                                             s->auth_data);  
                                 pclose(f);  
                         } else  
                                 fprintf(stderr, "Could not run %s\n",  
                                     _PATH_SSH_SYSTEM_RC);  
                 } else if (do_xauth && options.xauth_location != NULL) {  
                         /* Add authority data to .Xauthority if appropriate. */  
                         char *screen = strchr(s->display, ':');  
   
                         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,  
                                             "Adding %.*s/unix%s %s %s\n",  
                                             (int)(screen - s->display),  
                                             s->display, screen,  
                                             s->auth_proto, s->auth_data);  
                         }  
                         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. */  
                 cp = strrchr(shell, '/');  
                 if (cp)  
                         cp++;  
                 else  
                         cp = shell;  
         }  
   
         /* restore SIGPIPE for child */          /* restore SIGPIPE for child */
         signal(SIGPIPE,  SIG_DFL);          signal(SIGPIPE,  SIG_DFL);
   
           if (options.use_login) {
                   launch_login(pw, hostname);
                   /* NEVERREACHED */
           }
   
           /* Get the last component of the shell name. */
           if ((shell0 = strrchr(shell, '/')) != NULL)
                   shell0++;
           else
                   shell0 = shell;
   
         /*          /*
          * 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
          * this is a login shell.           * this is a login shell.
          */           */
         if (!command) {          if (!command) {
                 if (!options.use_login) {                  char argv0[256];
                         char buf[256];  
   
                         /* Start the shell.  Set initial character to '-'. */                  /* Start the shell.  Set initial character to '-'. */
                         buf[0] = '-';                  argv0[0] = '-';
                         strncpy(buf + 1, cp, sizeof(buf) - 1);  
                         buf[sizeof(buf) - 1] = 0;  
   
                         /* Execute the shell. */                  if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1)
                         argv[0] = buf;                      >= sizeof(argv0) - 1) {
                         argv[1] = NULL;                          errno = EINVAL;
                         execve(shell, argv, env);  
   
                         /* Executing the shell failed. */  
                         perror(shell);                          perror(shell);
                         exit(1);                          exit(1);
                   }
   
                 } else {                  /* Execute the shell. */
                         /* Launch login(1). */                  argv[0] = argv0;
                   argv[1] = NULL;
                   execve(shell, argv, env);
   
                         execl("/usr/bin/login", "login", "-h", hostname,                  /* Executing the shell failed. */
                              "-p", "-f", "--", pw->pw_name, (char *)NULL);                  perror(shell);
                   exit(1);
                         /* Login couldn't be executed, die. */  
   
                         perror("login");  
                         exit(1);  
                 }  
         }          }
         /*          /*
          * Execute the command using the user's shell.  This uses the -c           * Execute the command using the user's shell.  This uses the -c
          * option to execute the command.           * option to execute the command.
          */           */
         argv[0] = (char *) cp;          argv[0] = (char *) shell0;
         argv[1] = "-c";          argv[1] = "-c";
         argv[2] = (char *) command;          argv[2] = (char *) command;
         argv[3] = NULL;          argv[3] = NULL;
Line 1129 
Line 1218 
         static int did_init = 0;          static int did_init = 0;
         if (!did_init) {          if (!did_init) {
                 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;
                 }                  }
                 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) {
                         memset(s, 0, sizeof(*s));                          memset(s, 0, sizeof(*s));
Line 1154 
Line 1243 
 session_dump(void)  session_dump(void)
 {  {
         int i;          int i;
         for(i = 0; i < MAX_SESSIONS; i++) {          for (i = 0; i < MAX_SESSIONS; i++) {
                 Session *s = &sessions[i];                  Session *s = &sessions[i];
                 debug("dump: used %d session %d %p channel %d pid %d",                  debug("dump: used %d session %d %p channel %d pid %ld",
                     s->used,                      s->used,
                     s->self,                      s->self,
                     s,                      s,
                     s->chanid,                      s->chanid,
                     s->pid);                      (long)s->pid);
         }          }
 }  }
   
Line 1183 
Line 1272 
         return 1;          return 1;
 }  }
   
   Session *
   session_by_tty(char *tty)
   {
           int i;
           for (i = 0; i < MAX_SESSIONS; i++) {
                   Session *s = &sessions[i];
                   if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
                           debug("session_by_tty: session %d tty %s", i, tty);
                           return s;
                   }
           }
           debug("session_by_tty: unknown tty %.100s", tty);
           session_dump();
           return NULL;
   }
   
 static Session *  static Session *
 session_by_channel(int id)  session_by_channel(int id)
 {  {
         int i;          int i;
         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 && s->chanid == id) {                  if (s->used && s->chanid == id) {
                         debug("session_by_channel: session %d channel %d", i, id);                          debug("session_by_channel: session %d channel %d", i, id);
Line 1203 
Line 1308 
 session_by_pid(pid_t pid)  session_by_pid(pid_t pid)
 {  {
         int i;          int i;
         debug("session_by_pid: pid %d", pid);          debug("session_by_pid: pid %ld", (long)pid);
         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 && s->pid == pid)                  if (s->used && s->pid == pid)
                         return s;                          return s;
         }          }
         error("session_by_pid: unknown pid %d", pid);          error("session_by_pid: unknown pid %ld", (long)pid);
         session_dump();          session_dump();
         return NULL;          return NULL;
 }  }
Line 1221 
Line 1326 
         s->row = packet_get_int();          s->row = packet_get_int();
         s->xpixel = packet_get_int();          s->xpixel = packet_get_int();
         s->ypixel = packet_get_int();          s->ypixel = packet_get_int();
         packet_done();          packet_check_eom();
         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);
         return 1;          return 1;
 }  }
Line 1240 
Line 1345 
                 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 1260 
Line 1371 
   
         /* Allocate a pty and open it. */          /* Allocate a pty and open it. */
         debug("Allocating pty.");          debug("Allocating pty.");
         if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {          if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) {
                 if (s->term)                  if (s->term)
                         xfree(s->term);                          xfree(s->term);
                 s->term = NULL;                  s->term = NULL;
Line 1281 
Line 1392 
          * 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(session_pty_cleanup, (void *)s);          fatal_add_cleanup(session_pty_cleanup, (void *)s);
         pty_setowner(s->pw, s->tty);          if (!use_privsep)
                   pty_setowner(s->pw, s->tty);
   
         /* Set 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();          packet_check_eom();
         session_proctitle(s);          session_proctitle(s);
         return 1;          return 1;
 }  }
Line 1300 
Line 1412 
         char *cmd, *subsys = packet_get_string(&len);          char *cmd, *subsys = packet_get_string(&len);
         int i;          int i;
   
         packet_done();          packet_check_eom();
         log("subsystem request for %s", subsys);          log("subsystem request for %.100s", subsys);
   
         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) {
Line 1315 
Line 1427 
                         s->is_subsystem = 1;                          s->is_subsystem = 1;
                         do_exec(s, cmd);                          do_exec(s, cmd);
                         success = 1;                          success = 1;
                           break;
                 }                  }
         }          }
   
         if (!success)          if (!success)
                 log("subsystem request for %s failed, subsystem not found",                  log("subsystem request for %.100s failed, subsystem not found",
                     subsys);                      subsys);
   
         xfree(subsys);          xfree(subsys);
Line 1335 
Line 1448 
         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_check_eom();
   
         success = session_setup_x11fwd(s);          success = session_setup_x11fwd(s);
         if (!success) {          if (!success) {
Line 1350 
Line 1463 
 static int  static int
 session_shell_req(Session *s)  session_shell_req(Session *s)
 {  {
         packet_done();          packet_check_eom();
         do_exec(s, NULL);          do_exec(s, NULL);
         return 1;          return 1;
 }  }
Line 1360 
Line 1473 
 {  {
         u_int len;          u_int len;
         char *command = packet_get_string(&len);          char *command = packet_get_string(&len);
         packet_done();          packet_check_eom();
         do_exec(s, command);          do_exec(s, command);
         xfree(command);          xfree(command);
         return 1;          return 1;
Line 1370 
Line 1483 
 session_auth_agent_req(Session *s)  session_auth_agent_req(Session *s)
 {  {
         static int called = 0;          static int called = 0;
         packet_done();          packet_check_eom();
         if (no_agent_forwarding_flag) {          if (no_agent_forwarding_flag) {
                 debug("session_auth_agent_req: no_agent_forwarding_flag");                  debug("session_auth_agent_req: no_agent_forwarding_flag");
                 return 0;                  return 0;
Line 1383 
Line 1496 
         }          }
 }  }
   
 void  int
 session_input_channel_req(int id, void *arg)  session_input_channel_req(Channel *c, const char *rtype)
 {  {
         u_int len;  
         int reply;  
         int success = 0;          int success = 0;
         char *rtype;  
         Session *s;          Session *s;
         Channel *c;  
   
         rtype = packet_get_string(&len);          if ((s = session_by_channel(c->self)) == NULL) {
         reply = packet_get_char();                  log("session_input_channel_req: no session %d req %.100s",
                       c->self, rtype);
                   return 0;
           }
           debug("session_input_channel_req: session %d req %s", s->self, rtype);
   
         s = session_by_channel(id);  
         if (s == NULL)  
                 fatal("session_input_channel_req: channel %d: no session", id);  
         c = channel_lookup(id);  
         if (c == NULL)  
                 fatal("session_input_channel_req: channel %d: bad channel", id);  
   
         debug("session_input_channel_req: session %d channel %d request %s reply %d",  
             s->self, id, rtype, reply);  
   
         /*          /*
          * a session is in LARVAL state until a shell, a command           * a session is in LARVAL state until a shell, a command
          * or a subsystem is executed           * or a subsystem is executed
Line 1428 
Line 1531 
         if (strcmp(rtype, "window-change") == 0) {          if (strcmp(rtype, "window-change") == 0) {
                 success = session_window_change_req(s);                  success = session_window_change_req(s);
         }          }
           return success;
         if (reply) {  
                 packet_start(success ?  
                     SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);  
                 packet_put_int(c->remote_id);  
                 packet_send();  
         }  
         xfree(rtype);  
 }  }
   
 void  void
Line 1452 
Line 1548 
         channel_set_fds(s->chanid,          channel_set_fds(s->chanid,
             fdout, fdin, fderr,              fdout, fdin, fderr,
             fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,              fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
             1);              1,
               CHAN_SES_WINDOW_DEFAULT);
 }  }
   
 /*  /*
  * Function to perform pty cleanup. Also called if we get aborted abnormally   * Function to perform pty cleanup. Also called if we get aborted abnormally
  * (e.g., due to a dropped connection).   * (e.g., due to a dropped connection).
  */   */
 static void  void
 session_pty_cleanup(void *session)  session_pty_cleanup2(void *session)
 {  {
         Session *s = session;          Session *s = session;
   
Line 1478 
Line 1575 
                 record_logout(s->pid, s->tty);                  record_logout(s->pid, s->tty);
   
         /* Release the pseudo-tty. */          /* Release the pseudo-tty. */
         pty_release(s->tty);          if (getuid() == 0)
                   pty_release(s->tty);
   
         /*          /*
          * Close the server side of the socket pairs.  We must do this after           * Close the server side of the socket pairs.  We must do this after
Line 1486 
Line 1584 
          * while we're still cleaning up.           * while we're still cleaning up.
          */           */
         if (close(s->ptymaster) < 0)          if (close(s->ptymaster) < 0)
                 error("close(s->ptymaster): %s", strerror(errno));                  error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno));
   
         /* unlink pty from session */          /* unlink pty from session */
         s->ttyfd = -1;          s->ttyfd = -1;
 }  }
   
   void
   session_pty_cleanup(void *session)
   {
           PRIVSEP(session_pty_cleanup2(session));
   }
   
 static void  static void
 session_exit_message(Session *s, int status)  session_exit_message(Session *s, int status)
 {  {
         Channel *c;          Channel *c;
         if (s == NULL)  
                 fatal("session_close: no session");          if ((c = channel_lookup(s->chanid)) == NULL)
         c = channel_lookup(s->chanid);  
         if (c == NULL)  
                 fatal("session_exit_message: 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 %ld",
             s->self, s->chanid, s->pid);              s->self, s->chanid, (long)s->pid);
   
         if (WIFEXITED(status)) {          if (WIFEXITED(status)) {
                 channel_request_start(s->chanid,                  channel_request_start(s->chanid, "exit-status", 0);
                     "exit-status", 0);  
                 packet_put_int(WEXITSTATUS(status));                  packet_put_int(WEXITSTATUS(status));
                 packet_send();                  packet_send();
         } else if (WIFSIGNALED(status)) {          } else if (WIFSIGNALED(status)) {
                 channel_request_start(s->chanid,                  channel_request_start(s->chanid, "exit-signal", 0);
                     "exit-signal", 0);  
                 packet_put_int(WTERMSIG(status));                  packet_put_int(WTERMSIG(status));
                 packet_put_char(WCOREDUMP(status));                  packet_put_char(WCOREDUMP(status));
                 packet_put_cstring("");                  packet_put_cstring("");
Line 1537 
Line 1637 
         s->chanid = -1;          s->chanid = -1;
 }  }
   
 static void  void
 session_close(Session *s)  session_close(Session *s)
 {  {
         debug("session_close: session %d pid %d", s->self, 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);                  fatal_remove_cleanup(session_pty_cleanup, (void *)s);
                 session_pty_cleanup(s);                  session_pty_cleanup(s);
Line 1549 
Line 1649 
                 xfree(s->term);                  xfree(s->term);
         if (s->display)          if (s->display)
                 xfree(s->display);                  xfree(s->display);
           if (s->auth_display)
                   xfree(s->auth_display);
         if (s->auth_data)          if (s->auth_data)
                 xfree(s->auth_data);                  xfree(s->auth_data);
         if (s->auth_proto)          if (s->auth_proto)
Line 1562 
Line 1664 
 {  {
         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", pid);                  debug("session_close_by_pid: no session for pid %ld",
                       (long)pid);
                 return;                  return;
         }          }
         if (s->chanid != -1)          if (s->chanid != -1)
Line 1582 
Line 1685 
                 debug("session_close_by_channel: no session for id %d", id);                  debug("session_close_by_channel: no session for id %d", id);
                 return;                  return;
         }          }
         debug("session_close_by_channel: channel %d child %d", id, s->pid);          debug("session_close_by_channel: channel %d child %ld",
               id, (long)s->pid);
         if (s->pid != 0) {          if (s->pid != 0) {
                 debug("session_close_by_channel: channel %d: has child", id);                  debug("session_close_by_channel: channel %d: has child", id);
                 /*                  /*
Line 1602 
Line 1706 
 }  }
   
 void  void
 session_destroy_all(void)  session_destroy_all(void (*closefunc)(Session *))
 {  {
         int i;          int i;
         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) {
                         session_close(s);                          if (closefunc != NULL)
                                   closefunc(s);
                           else
                                   session_close(s);
                   }
         }          }
 }  }
   
Line 1618 
Line 1726 
         static char buf[1024];          static char buf[1024];
         int i;          int i;
         buf[0] = '\0';          buf[0] = '\0';
         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 && s->ttyfd != -1) {                  if (s->used && s->ttyfd != -1) {
                         if (buf[0] != '\0')                          if (buf[0] != '\0')
Line 1644 
Line 1752 
 session_setup_x11fwd(Session *s)  session_setup_x11fwd(Session *s)
 {  {
         struct stat st;          struct stat st;
           char display[512], auth_display[512];
           char hostname[MAXHOSTNAMELEN];
   
         if (no_x11_forwarding_flag) {          if (no_x11_forwarding_flag) {
                 packet_send_debug("X11 forwarding disabled in user configuration file.");                  packet_send_debug("X11 forwarding disabled in user configuration file.");
Line 1667 
Line 1777 
                 debug("X11 display already set.");                  debug("X11 display already set.");
                 return 0;                  return 0;
         }          }
         s->display = x11_create_display_inet(s->screen, options.x11_display_offset);          if (x11_create_display_inet(options.x11_display_offset,
         if (s->display == NULL) {              options.x11_use_localhost, s->single_connection,
               &s->display_number) == -1) {
                 debug("x11_create_display_inet failed.");                  debug("x11_create_display_inet failed.");
                 return 0;                  return 0;
         }          }
   
           /* Set up a suitable value for the DISPLAY variable. */
           if (gethostname(hostname, sizeof(hostname)) < 0)
                   fatal("gethostname: %.100s", strerror(errno));
           /*
            * auth_display must be used as the displayname when the
            * authorization entry is added with xauth(1).  This will be
            * different than the DISPLAY string for localhost displays.
            */
           if (options.x11_use_localhost) {
                   snprintf(display, sizeof display, "localhost:%u.%u",
                       s->display_number, s->screen);
                   snprintf(auth_display, sizeof auth_display, "unix:%u.%u",
                       s->display_number, s->screen);
                   s->display = xstrdup(display);
                   s->auth_display = xstrdup(auth_display);
           } else {
                   snprintf(display, sizeof display, "%.400s:%u.%u", hostname,
                       s->display_number, s->screen);
                   s->display = xstrdup(display);
                   s->auth_display = xstrdup(display);
           }
   
         return 1;          return 1;
 }  }
   

Legend:
Removed from v.1.108  
changed lines
  Added in v.1.108.2.6