[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.236 and 1.237

version 1.236, 2008/05/08 12:02:23 version 1.237, 2008/05/08 12:21:16
Line 94 
Line 94 
 void    session_pty_cleanup(Session *);  void    session_pty_cleanup(Session *);
 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 *);  int     do_exec_pty(Session *, const char *);
 void    do_exec_no_pty(Session *, const char *);  int     do_exec_no_pty(Session *, const char *);
 void    do_exec(Session *, const char *);  int     do_exec(Session *, const char *);
 void    do_login(Session *, const char *);  void    do_login(Session *, const char *);
 void    do_child(Session *, const char *);  void    do_child(Session *, const char *);
 void    do_motd(void);  void    do_motd(void);
Line 121 
Line 121 
 const char *original_command = NULL;  const char *original_command = NULL;
   
 /* data */  /* data */
 #define MAX_SESSIONS 10  static int sessions_first_unused = -1;
 Session sessions[MAX_SESSIONS];  static int sessions_nalloc = 0;
   static Session *sessions = NULL;
   
 #define SUBSYSTEM_NONE          0  #define SUBSYSTEM_NONE          0
 #define SUBSYSTEM_EXT           1  #define SUBSYSTEM_EXT           1
Line 154 
Line 155 
 auth_input_request_forwarding(struct passwd * pw)  auth_input_request_forwarding(struct passwd * pw)
 {  {
         Channel *nc;          Channel *nc;
         int sock;          int sock = -1;
         struct sockaddr_un sunaddr;          struct sockaddr_un sunaddr;
   
         if (auth_sock_name != NULL) {          if (auth_sock_name != NULL) {
Line 166 
Line 167 
         temporarily_use_uid(pw);          temporarily_use_uid(pw);
   
         /* 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_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
         auth_sock_dir = xmalloc(MAXPATHLEN);  
         strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);  
   
         /* Create private directory for socket */          /* Create private directory for socket */
         if (mkdtemp(auth_sock_dir) == NULL) {          if (mkdtemp(auth_sock_dir) == NULL) {
                 packet_send_debug("Agent forwarding disabled: "                  packet_send_debug("Agent forwarding disabled: "
                     "mkdtemp() failed: %.100s", strerror(errno));                      "mkdtemp() failed: %.100s", strerror(errno));
                 restore_uid();                  restore_uid();
                 xfree(auth_sock_name);  
                 xfree(auth_sock_dir);                  xfree(auth_sock_dir);
                 auth_sock_name = NULL;  
                 auth_sock_dir = NULL;                  auth_sock_dir = NULL;
                 return 0;                  goto authsock_err;
         }          }
         snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",  
                  auth_sock_dir, (long) getpid());  
   
           xasprintf(&auth_sock_name, "%s/agent.%ld",
               auth_sock_dir, (long) getpid());
   
         /* 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) {
                 packet_disconnect("socket: %.100s", strerror(errno));                  error("socket: %.100s", strerror(errno));
                   restore_uid();
                   goto authsock_err;
           }
   
         /* Bind it to the name. */          /* Bind it to the name. */
         memset(&sunaddr, 0, sizeof(sunaddr));          memset(&sunaddr, 0, sizeof(sunaddr));
         sunaddr.sun_family = AF_UNIX;          sunaddr.sun_family = AF_UNIX;
         strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));          strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
   
         if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)          if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
                 packet_disconnect("bind: %.100s", strerror(errno));                  error("bind: %.100s", strerror(errno));
                   restore_uid();
                   goto authsock_err;
           }
   
         /* Restore the privileged uid. */          /* Restore the privileged uid. */
         restore_uid();          restore_uid();
   
         /* Start listening on the socket. */          /* Start listening on the socket. */
         if (listen(sock, SSH_LISTEN_BACKLOG) < 0)          if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
                 packet_disconnect("listen: %.100s", strerror(errno));                  error("listen: %.100s", strerror(errno));
                   goto authsock_err;
           }
   
         /* Allocate a channel for the authentication agent socket. */          /* Allocate a channel for the authentication agent socket. */
         nc = channel_new("auth socket",          nc = channel_new("auth socket",
Line 211 
Line 217 
             0, "auth socket", 1);              0, "auth socket", 1);
         strlcpy(nc->path, auth_sock_name, sizeof(nc->path));          strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
         return 1;          return 1;
   
    authsock_err:
           if (auth_sock_name != NULL)
                   xfree(auth_sock_name);
           if (auth_sock_dir != NULL) {
                   rmdir(auth_sock_dir);
                   xfree(auth_sock_dir);
           }
           if (sock != -1)
                   close(sock);
           auth_sock_name = NULL;
           auth_sock_dir = NULL;
           return 0;
 }  }
   
 static void  static void
Line 360 
Line 379 
                         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);
                                 do_exec(s, command);                                  if (do_exec(s, command) != 0)
                                           packet_disconnect(
                                               "command execution failed");
                                 xfree(command);                                  xfree(command);
                         } else {                          } else {
                                 do_exec(s, NULL);                                  if (do_exec(s, NULL) != 0)
                                           packet_disconnect(
                                               "shell execution failed");
                         }                          }
                         packet_check_eom();                          packet_check_eom();
                         session_close(s);                          session_close(s);
Line 393 
Line 416 
  * will call do_child from the child, and server_loop from the parent after   * will call do_child from the child, and server_loop from the parent after
  * setting up file descriptors and such.   * setting up file descriptors and such.
  */   */
 void  int
 do_exec_no_pty(Session *s, const char *command)  do_exec_no_pty(Session *s, const char *command)
 {  {
         pid_t pid;          pid_t pid;
   
         int inout[2], err[2];          int inout[2], err[2];
   
         /* Uses socket pairs to communicate with the program. */          /* Uses socket pairs to communicate with the program. */
         if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||          if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
             socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)                  error("%s: socketpair #1: %.100s", __func__, strerror(errno));
                 packet_disconnect("Could not create socket pairs: %.100s",                  return -1;
                                   strerror(errno));          }
           if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
                   error("%s: socketpair #2: %.100s", __func__, strerror(errno));
                   close(inout[0]);
                   close(inout[1]);
                   return -1;
           }
   
         if (s == NULL)          if (s == NULL)
                 fatal("do_exec_no_pty: no session");                  fatal("do_exec_no_pty: no session");
   
         session_proctitle(s);          session_proctitle(s);
   
         /* Fork the child. */          /* Fork the child. */
         if ((pid = fork()) == 0) {          switch ((pid = fork())) {
           case -1:
                   error("%s: fork: %.100s", __func__, strerror(errno));
                   close(inout[0]);
                   close(inout[1]);
                   close(err[0]);
                   close(err[1]);
                   return -1;
           case 0:
                 is_child = 1;                  is_child = 1;
   
                 /* 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);
   
                 /*                  /*
                  * Create a new session and process group since the 4.4BSD                   * Create a new session and process group since the 4.4BSD
Line 432 
Line 471 
                 close(err[1]);                  close(err[1]);
                 if (dup2(inout[0], 0) < 0)      /* stdin */                  if (dup2(inout[0], 0) < 0)      /* stdin */
                         perror("dup2 stdin");                          perror("dup2 stdin");
                 if (dup2(inout[0], 1) < 0)      /* stdout.  Note: same socket as stdin. */                  if (dup2(inout[0], 1) < 0)      /* stdout (same as stdin) */
                         perror("dup2 stdout");                          perror("dup2 stdout");
                 if (dup2(err[0], 2) < 0)        /* stderr */                  if (dup2(err[0], 2) < 0)        /* stderr */
                         perror("dup2 stderr");                          perror("dup2 stderr");
Line 440 
Line 479 
                 /* Do processing for the child (exec command etc). */                  /* Do processing for the child (exec command etc). */
                 do_child(s, command);                  do_child(s, command);
                 /* NOTREACHED */                  /* NOTREACHED */
           default:
                   break;
         }          }
         if (pid < 0)  
                 packet_disconnect("fork failed: %.100s", strerror(errno));  
         s->pid = pid;          s->pid = pid;
         /* Set interactive/non-interactive mode. */          /* Set interactive/non-interactive mode. */
         packet_set_interactive(s->display != NULL);          packet_set_interactive(s->display != NULL);
Line 456 
Line 496 
          * 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->is_subsystem ? -1 : err[1]);                  session_set_fds(s, inout[1], inout[1],
                       s->is_subsystem ? -1 : err[1]);
                   if (s->is_subsystem)
                           close(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]. */
         }          }
           return 0;
 }  }
   
 /*  /*
Line 469 
Line 513 
  * setting up file descriptors, controlling tty, updating wtmp, utmp,   * setting up file descriptors, controlling tty, updating wtmp, utmp,
  * lastlog, and other such operations.   * lastlog, and other such operations.
  */   */
 void  int
 do_exec_pty(Session *s, const char *command)  do_exec_pty(Session *s, const char *command)
 {  {
         int fdout, ptyfd, ttyfd, ptymaster;          int fdout, ptyfd, ttyfd, ptymaster;
Line 480 
Line 524 
         ptyfd = s->ptyfd;          ptyfd = s->ptyfd;
         ttyfd = s->ttyfd;          ttyfd = s->ttyfd;
   
           /*
            * Create another descriptor of the pty master side for use as the
            * standard input.  We could use the original descriptor, but this
            * simplifies code in server_loop.  The descriptor is bidirectional.
            * Do this before forking (and cleanup in the child) so as to
            * detect and gracefully fail out-of-fd conditions.
            */
           if ((fdout = dup(ptyfd)) < 0) {
                   error("%s: dup #1: %s", __func__, strerror(errno));
                   close(ttyfd);
                   close(ptyfd);
                   return -1;
           }
           /* we keep a reference to the pty master */
           if ((ptymaster = dup(ptyfd)) < 0) {
                   error("%s: dup #2: %s", __func__, strerror(errno));
                   close(ttyfd);
                   close(ptyfd);
                   close(fdout);
                   return -1;
           }
   
         /* Fork the child. */          /* Fork the child. */
         if ((pid = fork()) == 0) {          switch ((pid = fork())) {
           case -1:
                   error("%s: fork: %.100s", __func__, strerror(errno));
                   close(fdout);
                   close(ptymaster);
                   close(ttyfd);
                   close(ptyfd);
                   return -1;
           case 0:
                 is_child = 1;                  is_child = 1;
   
                   close(fdout);
                   close(ptymaster);
   
                 /* 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 507 
Line 585 
                 if (!(options.use_login && command == NULL))                  if (!(options.use_login && command == NULL))
                         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(s, command);                  do_child(s, command);
                 /* NOTREACHED */                  /* NOTREACHED */
           default:
                   break;
         }          }
         if (pid < 0)  
                 packet_disconnect("fork failed: %.100s", strerror(errno));  
         s->pid = pid;          s->pid = pid;
   
         /* Parent.  Close the slave side of the pseudo tty. */          /* Parent.  Close the slave side of the pseudo tty. */
         close(ttyfd);          close(ttyfd);
   
         /*  
          * Create another descriptor of the pty master side for use as the  
          * standard input.  We could use the original descriptor, but this  
          * simplifies code in server_loop.  The descriptor is bidirectional.  
          */  
         fdout = dup(ptyfd);  
         if (fdout < 0)  
                 packet_disconnect("dup #1 failed: %.100s", strerror(errno));  
   
         /* we keep a reference to the pty master */  
         ptymaster = dup(ptyfd);  
         if (ptymaster < 0)  
                 packet_disconnect("dup #2 failed: %.100s", strerror(errno));  
         s->ptymaster = ptymaster;  
   
         /* Enter interactive session. */          /* Enter interactive session. */
           s->ptymaster = ptymaster;
         packet_set_interactive(1);          packet_set_interactive(1);
         if (compat20) {          if (compat20) {
                 session_set_fds(s, ptyfd, fdout, -1);                  session_set_fds(s, ptyfd, fdout, -1);
Line 541 
Line 608 
                 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. */
         }          }
           return 0;
 }  }
   
 /*  /*
  * This is called to fork and execute a command.  If another command is   * This is called to fork and execute a command.  If another command is
  * to be forced, execute that instead.   * to be forced, execute that instead.
  */   */
 void  int
 do_exec(Session *s, const char *command)  do_exec(Session *s, const char *command)
 {  {
           int ret;
   
         if (options.adm_forced_command) {          if (options.adm_forced_command) {
                 original_command = command;                  original_command = command;
                 command = options.adm_forced_command;                  command = options.adm_forced_command;
Line 576 
Line 646 
         }          }
 #endif  #endif
         if (s->ttyfd != -1)          if (s->ttyfd != -1)
                 do_exec_pty(s, command);                  ret = do_exec_pty(s, command);
         else          else
                 do_exec_no_pty(s, command);                  ret = do_exec_no_pty(s, command);
   
         original_command = NULL;          original_command = NULL;
   
Line 588 
Line 658 
          * multiple copies of the login messages.           * multiple copies of the login messages.
          */           */
         buffer_clear(&loginmsg);          buffer_clear(&loginmsg);
   
           return ret;
 }  }
   
   
Line 1293 
Line 1365 
         exit(1);          exit(1);
 }  }
   
   void
   session_unused(int id)
   {
           debug3("%s: session id %d unused", __func__, id);
           if (id >= options.max_sessions ||
               id >= sessions_nalloc) {
                   fatal("%s: insane session id %d (max %d nalloc %d)",
                       __func__, id, options.max_sessions, sessions_nalloc);
           }
           bzero(&sessions[id], sizeof(*sessions));
           sessions[id].self = id;
           sessions[id].used = 0;
           sessions[id].chanid = -1;
           sessions[id].ptyfd = -1;
           sessions[id].ttyfd = -1;
           sessions[id].ptymaster = -1;
           sessions[id].x11_chanids = NULL;
           sessions[id].next_unused = sessions_first_unused;
           sessions_first_unused = id;
   }
   
 Session *  Session *
 session_new(void)  session_new(void)
 {  {
         int i;          Session *s, *tmp;
         static int did_init = 0;  
         if (!did_init) {          if (sessions_first_unused == -1) {
                 debug("session_new: init");                  if (sessions_nalloc >= options.max_sessions)
                 for (i = 0; i < MAX_SESSIONS; i++) {                          return NULL;
                         sessions[i].used = 0;                  debug2("%s: allocate (allocated %d max %d)",
                       __func__, sessions_nalloc, options.max_sessions);
                   tmp = xrealloc(sessions, sessions_nalloc + 1,
                       sizeof(*sessions));
                   if (tmp == NULL) {
                           error("%s: cannot allocate %d sessions",
                               __func__, sessions_nalloc + 1);
                           return NULL;
                 }                  }
                 did_init = 1;                  sessions = tmp;
                   session_unused(sessions_nalloc++);
         }          }
         for (i = 0; i < MAX_SESSIONS; i++) {  
                 Session *s = &sessions[i];          if (sessions_first_unused >= sessions_nalloc ||
                 if (! s->used) {              sessions_first_unused < 0) {
                         memset(s, 0, sizeof(*s));                  fatal("%s: insane first_unused %d max %d nalloc %d",
                         s->chanid = -1;                      __func__, sessions_first_unused, options.max_sessions,
                         s->ptyfd = -1;                      sessions_nalloc);
                         s->ttyfd = -1;  
                         s->used = 1;  
                         s->self = i;  
                         s->x11_chanids = NULL;  
                         debug("session_new: session %d", i);  
                         return s;  
                 }  
         }          }
         return NULL;  
           s = &sessions[sessions_first_unused];
           if (s->used) {
                   fatal("%s: session %d already used",
                       __func__, sessions_first_unused);
           }
           sessions_first_unused = s->next_unused;
           s->used = 1;
           s->next_unused = -1;
           debug("session_new: session %d", s->self);
   
           return s;
 }  }
   
 static void  static void
 session_dump(void)  session_dump(void)
 {  {
         int i;          int i;
         for (i = 0; i < MAX_SESSIONS; i++) {          for (i = 0; i < sessions_nalloc; i++) {
                 Session *s = &sessions[i];                  Session *s = &sessions[i];
                 debug("dump: used %d session %d %p channel %d pid %ld",  
                   debug("dump: used %d next_unused %d session %d %p "
                       "channel %d pid %ld",
                     s->used,                      s->used,
                       s->next_unused,
                     s->self,                      s->self,
                     s,                      s,
                     s->chanid,                      s->chanid,
Line 1359 
Line 1467 
 session_by_tty(char *tty)  session_by_tty(char *tty)
 {  {
         int i;          int i;
         for (i = 0; i < MAX_SESSIONS; i++) {          for (i = 0; i < sessions_nalloc; i++) {
                 Session *s = &sessions[i];                  Session *s = &sessions[i];
                 if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {                  if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
                         debug("session_by_tty: session %d tty %s", i, tty);                          debug("session_by_tty: session %d tty %s", i, tty);
Line 1375 
Line 1483 
 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 < sessions_nalloc; 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);
                         return s;                          return s;
                 }                  }
         }          }
Line 1392 
Line 1501 
 {  {
         int i, j;          int i, j;
   
         for (i = 0; i < MAX_SESSIONS; i++) {          for (i = 0; i < sessions_nalloc; i++) {
                 Session *s = &sessions[i];                  Session *s = &sessions[i];
   
                 if (s->x11_chanids == NULL || !s->used)                  if (s->x11_chanids == NULL || !s->used)
Line 1415 
Line 1524 
 {  {
         int i;          int i;
         debug("session_by_pid: pid %ld", (long)pid);          debug("session_by_pid: pid %ld", (long)pid);
         for (i = 0; i < MAX_SESSIONS; i++) {          for (i = 0; i < sessions_nalloc; 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;
Line 1471 
Line 1580 
   
         /* Allocate a pty and open it. */          /* Allocate a pty and open it. */
         debug("Allocating pty.");          debug("Allocating pty.");
         if (!PRIVSEP(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 1524 
Line 1634 
                                 s->is_subsystem = SUBSYSTEM_EXT;                                  s->is_subsystem = SUBSYSTEM_EXT;
                         }                          }
                         debug("subsystem: exec() %s", cmd);                          debug("subsystem: exec() %s", cmd);
                         do_exec(s, cmd);                          success = do_exec(s, cmd) == 0;
                         success = 1;  
                         break;                          break;
                 }                  }
         }          }
Line 1568 
Line 1677 
 session_shell_req(Session *s)  session_shell_req(Session *s)
 {  {
         packet_check_eom();          packet_check_eom();
         do_exec(s, NULL);          return do_exec(s, NULL) == 0;
         return 1;  
 }  }
   
 static int  static int
 session_exec_req(Session *s)  session_exec_req(Session *s)
 {  {
         u_int len;          u_int len, success;
   
         char *command = packet_get_string(&len);          char *command = packet_get_string(&len);
         packet_check_eom();          packet_check_eom();
         do_exec(s, command);          success = do_exec(s, command) == 0;
         xfree(command);          xfree(command);
         return 1;          return success;
 }  }
   
 static int  static int
Line 1590 
Line 1699 
         packet_get_int();       /* ignored */          packet_get_int();       /* ignored */
         packet_check_eom();          packet_check_eom();
   
         if (s->ttyfd == -1 ||          if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0)
             tcsendbreak(s->ttyfd, 0) < 0)  
                 return 0;                  return 0;
         return 1;          return 1;
 }  }
Line 1738 
Line 1846 
          * the pty cleanup, so that another process doesn't get this pty           * the pty cleanup, so that another process doesn't get this pty
          * while we're still cleaning up.           * while we're still cleaning up.
          */           */
         if (close(s->ptymaster) < 0)          if (s->ptymaster != -1 && close(s->ptymaster) < 0)
                 error("close(s->ptymaster/%d): %s", s->ptymaster, 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;
Line 1895 
Line 2004 
                 xfree(s->auth_data);                  xfree(s->auth_data);
         if (s->auth_proto)          if (s->auth_proto)
                 xfree(s->auth_proto);                  xfree(s->auth_proto);
         s->used = 0;  
         if (s->env != NULL) {          if (s->env != NULL) {
                 for (i = 0; i < s->num_env; i++) {                  for (i = 0; i < s->num_env; i++) {
                         xfree(s->env[i].name);                          xfree(s->env[i].name);
Line 1904 
Line 2012 
                 xfree(s->env);                  xfree(s->env);
         }          }
         session_proctitle(s);          session_proctitle(s);
           session_unused(s->self);
 }  }
   
 void  void
Line 1967 
Line 2076 
 session_destroy_all(void (*closefunc)(Session *))  session_destroy_all(void (*closefunc)(Session *))
 {  {
         int i;          int i;
         for (i = 0; i < MAX_SESSIONS; i++) {          for (i = 0; i < sessions_nalloc; i++) {
                 Session *s = &sessions[i];                  Session *s = &sessions[i];
                 if (s->used) {                  if (s->used) {
                         if (closefunc != NULL)                          if (closefunc != NULL)
Line 1984 
Line 2093 
         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 < sessions_nalloc; 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')

Legend:
Removed from v.1.236  
changed lines
  Added in v.1.237