]> andersk Git - gssapi-openssh.git/blobdiff - openssh/session.c
new version: NCSA_GSSAPI_20080403
[gssapi-openssh.git] / openssh / session.c
index 1227af86fdbdca734bc430ac64e1f31a1ad87190..ef308cdecbd258ec20d647d40234be6e47e7a92d 100644 (file)
@@ -1,3 +1,4 @@
+/* $OpenBSD: session.c,v 1.233 2008/03/26 21:28:14 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.181 2004/12/23 17:35:48 markus Exp $");
 
+#include <sys/types.h>
+#include <sys/param.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <grp.h>
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "xmalloc.h"
 #include "ssh.h"
 #include "ssh1.h"
 #include "ssh2.h"
-#include "xmalloc.h"
 #include "sshpty.h"
 #include "packet.h"
 #include "buffer.h"
@@ -46,7 +70,12 @@ RCSID("$OpenBSD: session.c,v 1.181 2004/12/23 17:35:48 markus Exp $");
 #include "uidswap.h"
 #include "compat.h"
 #include "channels.h"
-#include "bufaux.h"
+#include "key.h"
+#include "cipher.h"
+#ifdef GSSAPI
+#include "ssh-gss.h"
+#endif
+#include "hostfile.h"
 #include "auth.h"
 #include "auth-options.h"
 #include "pathnames.h"
@@ -55,17 +84,16 @@ RCSID("$OpenBSD: session.c,v 1.181 2004/12/23 17:35:48 markus Exp $");
 #include "sshlogin.h"
 #include "serverloop.h"
 #include "canohost.h"
+#include "misc.h"
 #include "session.h"
+#include "kex.h"
 #include "monitor_wrap.h"
+#include "sftp.h"
 
 #if defined(KRB5) && defined(USE_AFS)
 #include <kafs.h>
 #endif
 
-#ifdef GSSAPI
-#include "ssh-gss.h"
-#endif
-
 /* func */
 
 Session *session_new(void);
@@ -108,9 +136,13 @@ extern Buffer loginmsg;
 const char *original_command = NULL;
 
 /* data */
-#define MAX_SESSIONS 10
+#define MAX_SESSIONS 20
 Session        sessions[MAX_SESSIONS];
 
+#define SUBSYSTEM_NONE         0
+#define SUBSYSTEM_EXT          1
+#define SUBSYSTEM_INT_SFTP     2
+
 #ifdef HAVE_LOGIN_CAP
 login_cap_t *lc;
 #endif
@@ -179,7 +211,7 @@ auth_input_request_forwarding(struct passwd * pw)
        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)
+       if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
                packet_disconnect("bind: %.100s", strerror(errno));
 
        /* Restore the privileged uid. */
@@ -190,6 +222,7 @@ auth_input_request_forwarding(struct passwd * pw)
                packet_disconnect("listen: %.100s", strerror(errno));
 
        /* Allocate a channel for the authentication agent socket. */
+       /* this shouldn't matter if its hpn or not - cjr */
        nc = channel_new("auth socket",
            SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
            CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
@@ -201,11 +234,11 @@ auth_input_request_forwarding(struct passwd * pw)
 static void
 display_loginmsg(void)
 {
-        if (buffer_len(&loginmsg) > 0) {
-                buffer_append(&loginmsg, "\0", 1);
-                printf("%s", (char *)buffer_ptr(&loginmsg));
-                buffer_clear(&loginmsg);
-        }
+       if (buffer_len(&loginmsg) > 0) {
+               buffer_append(&loginmsg, "\0", 1);
+               printf("%s", (char *)buffer_ptr(&loginmsg));
+               buffer_clear(&loginmsg);
+       }
 }
 
 void
@@ -213,15 +246,6 @@ do_authenticated(Authctxt *authctxt)
 {
        setproctitle("%s", authctxt->pw->pw_name);
 
-       /*
-        * Cancel the alarm we set to limit the time taken for
-        * authentication.
-        */
-       alarm(0);
-       if (startup_pipe != -1) {
-               close(startup_pipe);
-               startup_pipe = -1;
-       }
        /* setup the channel layer */
        if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
                channel_permit_all_opens();
@@ -292,7 +316,7 @@ do_authenticated1(Authctxt *authctxt)
                                    compression_level);
                                break;
                        }
-                       if (!options.compression) {
+                       if (options.compression == COMP_NONE) {
                                debug2("compression disabled");
                                break;
                        }
@@ -350,7 +374,12 @@ do_authenticated1(Authctxt *authctxt)
                                break;
                        }
                        debug("Received TCP/IP port forwarding request.");
-                       channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
+                       if (channel_input_port_forward_request(s->pw->pw_uid == 0,
+                             options.gateway_ports, options.hpn_disabled,
+                              options.hpn_buffer_size) < 0) {
+                               debug("Port forwarding failed.");
+                               break;
+                       }
                        success = 1;
                        break;
 
@@ -421,11 +450,6 @@ do_exec_no_pty(Session *s, const char *command)
 
        session_proctitle(s);
 
-#if defined(USE_PAM)
-       if (options.use_pam && !use_privsep)
-               do_pam_setcred(1);
-#endif /* USE_PAM */
-
        /* Fork the child. */
        if ((pid = fork()) == 0) {
                is_child = 1;
@@ -556,14 +580,6 @@ do_exec_pty(Session *s, const char *command)
        ptyfd = s->ptyfd;
        ttyfd = s->ttyfd;
 
-#if defined(USE_PAM)
-       if (options.use_pam) {
-               do_pam_set_tty(s->tty);
-               if (!use_privsep)
-                       do_pam_setcred(1);
-       }
-#endif
-
        /* Fork the child. */
        if ((pid = fork()) == 0) {
                is_child = 1;
@@ -660,7 +676,7 @@ do_pre_login(Session *s)
        fromlen = sizeof(from);
        if (packet_connection_is_on_socket()) {
                if (getpeername(packet_get_connection_in(),
-                   (struct sockaddr *) & from, &fromlen) < 0) {
+                   (struct sockaddr *)&from, &fromlen) < 0) {
                        debug("getpeername: %.100s", strerror(errno));
                        cleanup_exit(255);
                }
@@ -679,10 +695,22 @@ do_pre_login(Session *s)
 void
 do_exec(Session *s, const char *command)
 {
-       if (forced_command) {
+       if (options.adm_forced_command) {
+               original_command = command;
+               command = options.adm_forced_command;
+               if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
+                       s->is_subsystem = SUBSYSTEM_INT_SFTP;
+               else if (s->is_subsystem)
+                       s->is_subsystem = SUBSYSTEM_EXT;
+               debug("Forced command (config) '%.900s'", command);
+       } else if (forced_command) {
                original_command = command;
                command = forced_command;
-               debug("Forced command '%.900s'", command);
+               if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
+                       s->is_subsystem = SUBSYSTEM_INT_SFTP;
+               else if (s->is_subsystem)
+                       s->is_subsystem = SUBSYSTEM_EXT;
+               debug("Forced command (key option) '%.900s'", command);
        }
 
 #if defined(SESSION_HOOKS)
@@ -705,14 +733,6 @@ do_exec(Session *s, const char *command)
        }
 #endif
 
-#ifdef GSSAPI
-       if (options.gss_authentication) {
-               temporarily_use_uid(s->pw);
-               ssh_gssapi_storecreds();
-               restore_uid();
-       }
-#endif
-
 #ifdef SSH_AUDIT_EVENTS
        if (command != NULL)
                PRIVSEP(audit_run_command(command));
@@ -724,7 +744,6 @@ do_exec(Session *s, const char *command)
                PRIVSEP(audit_run_command(shell));
        }
 #endif
-
        if (s->ttyfd != -1)
                do_exec_pty(s, command);
        else
@@ -882,7 +901,7 @@ child_set_env(char ***envp, u_int *envsizep, const char *name,
                        if (envsize >= 1000)
                                fatal("child_set_env: too many env vars");
                        envsize += 50;
-                       env = (*envp) = xrealloc(env, envsize * sizeof(char *));
+                       env = (*envp) = xrealloc(env, envsize, sizeof(char *));
                        *envsizep = envsize;
                }
                /* Need to set the NULL pointer at end of array beyond the new slot. */
@@ -920,8 +939,9 @@ read_environment_file(char ***env, u_int *envsize,
                        ;
                if (!*cp || *cp == '#' || *cp == '\n')
                        continue;
-               if (strchr(cp, '\n'))
-                       *strchr(cp, '\n') = '\0';
+
+               cp[strcspn(cp, "\n")] = '\0';
+
                value = strchr(cp, '=');
                if (value == NULL) {
                        fprintf(stderr, "Bad line %u in %.100s\n", lineno,
@@ -1105,7 +1125,8 @@ read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
 }
 #endif /* HAVE_ETC_DEFAULT_LOGIN */
 
-void copy_environment(char **source, char ***env, u_int *envsize)
+void
+copy_environment(char **source, char ***env, u_int *envsize)
 {
        char *var_name, *var_val;
        int i;
@@ -1133,12 +1154,15 @@ do_setup_env(Session *s, const char *shell)
 {
        char buf[256];
        u_int i, envsize;
-       char **env, *laddr, *path = NULL;
+       char **env, *laddr;
        struct passwd *pw = s->pw;
+#ifndef HAVE_LOGIN_CAP
+       char *path = NULL;
+#endif
 
        /* Initialize the environment. */
        envsize = 100;
-       env = xmalloc(envsize * sizeof(char *));
+       env = xcalloc(envsize, sizeof(char *));
        env[0] = NULL;
 
 #ifdef HAVE_CYGWIN
@@ -1348,8 +1372,9 @@ do_rc_files(Session *s, const char *shell)
        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)) {
+       /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
+       if (!s->is_subsystem && options.adm_forced_command == NULL &&
+           !no_user_rc &&  (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)
@@ -1430,10 +1455,72 @@ do_nologin(struct passwd *pw)
        }
 }
 
+/*
+ * Chroot into a directory after checking it for safety: all path components
+ * must be root-owned directories with strict permissions.
+ */
+static void
+safely_chroot(const char *path, uid_t uid)
+{
+       const char *cp;
+       char component[MAXPATHLEN];
+       struct stat st;
+
+       if (*path != '/')
+               fatal("chroot path does not begin at root");
+       if (strlen(path) >= sizeof(component))
+               fatal("chroot path too long");
+
+       /*
+        * Descend the path, checking that each component is a
+        * root-owned directory with strict permissions.
+        */
+       for (cp = path; cp != NULL;) {
+               if ((cp = strchr(cp, '/')) == NULL)
+                       strlcpy(component, path, sizeof(component));
+               else {
+                       cp++;
+                       memcpy(component, path, cp - path);
+                       component[cp - path] = '\0';
+               }
+       
+               debug3("%s: checking '%s'", __func__, component);
+
+               if (stat(component, &st) != 0)
+                       fatal("%s: stat(\"%s\"): %s", __func__,
+                           component, strerror(errno));
+               if (st.st_uid != 0 || (st.st_mode & 022) != 0)
+                       fatal("bad ownership or modes for chroot "
+                           "directory %s\"%s\"", 
+                           cp == NULL ? "" : "component ", component);
+               if (!S_ISDIR(st.st_mode))
+                       fatal("chroot path %s\"%s\" is not a directory",
+                           cp == NULL ? "" : "component ", component);
+
+       }
+
+       if (chdir(path) == -1)
+               fatal("Unable to chdir to chroot path \"%s\": "
+                   "%s", path, strerror(errno));
+       if (chroot(path) == -1)
+               fatal("chroot(\"%s\"): %s", path, strerror(errno));
+       if (chdir("/") == -1)
+               fatal("%s: chdir(/) after chroot: %s",
+                   __func__, strerror(errno));
+       verbose("Changed root directory to \"%s\"", path);
+}
+
 /* Set login name, uid, gid, and groups. */
 void
 do_setusercontext(struct passwd *pw)
 {
+       char *chroot_path, *tmp;
+
+#ifdef WITH_SELINUX
+       /* Cache selinux status for later use */
+       (void)ssh_selinux_enabled();
+#endif
+
 #ifndef HAVE_CYGWIN
        if (getuid() == 0 || geteuid() == 0)
 #endif /* HAVE_CYGWIN */
@@ -1447,21 +1534,13 @@ do_setusercontext(struct passwd *pw)
 # ifdef __bsdi__
                setpgid(0, 0);
 # endif
-#ifdef GSSAPI
-               if (options.gss_authentication) {
-                       temporarily_use_uid(pw);
-                       ssh_gssapi_storecreds();
-                       restore_uid();
-               }
-#endif
 # ifdef USE_PAM
                if (options.use_pam) {
-                       do_pam_session();
-                       do_pam_setcred(0);
+                       do_pam_setcred(use_privsep);
                }
 # endif /* USE_PAM */
                if (setusercontext(lc, pw, pw->pw_uid,
-                   (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) {
+                   (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
                        perror("unable to set user context");
                        exit(1);
                }
@@ -1484,13 +1563,6 @@ do_setusercontext(struct passwd *pw)
                        exit(1);
                }
                endgrent();
-#ifdef GSSAPI
-               if (options.gss_authentication) {
-                       temporarily_use_uid(pw);
-                       ssh_gssapi_storecreds();
-                       restore_uid();
-               }
-#endif
 # ifdef USE_PAM
                /*
                 * PAM credentials may take the form of supplementary groups.
@@ -1498,16 +1570,39 @@ do_setusercontext(struct passwd *pw)
                 * Reestablish them here.
                 */
                if (options.use_pam) {
-                       do_pam_session();
-                       do_pam_setcred(0);
+                       do_pam_setcred(use_privsep);
                }
 # endif /* USE_PAM */
 # if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)
                irix_setusercontext(pw);
-#  endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
+# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
 # ifdef _AIX
                aix_usrinfo(pw);
 # endif /* _AIX */
+# ifdef USE_LIBIAF
+               if (set_id(pw->pw_name) != 0) {
+                       exit(1);
+               }
+# endif /* USE_LIBIAF */
+#endif
+
+               if (options.chroot_directory != NULL &&
+                   strcasecmp(options.chroot_directory, "none") != 0) {
+                        tmp = tilde_expand_filename(options.chroot_directory,
+                           pw->pw_uid);
+                       chroot_path = percent_expand(tmp, "h", pw->pw_dir,
+                           "u", pw->pw_name, (char *)NULL);
+                       safely_chroot(chroot_path, pw->pw_uid);
+                       free(tmp);
+                       free(chroot_path);
+               }
+
+#ifdef HAVE_LOGIN_CAP
+               if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
+                       perror("unable to set user context (setuser)");
+                       exit(1);
+               }
+#else
                /* Permanently switch to the desired uid. */
                permanently_set_uid(pw);
 #endif
@@ -1518,6 +1613,10 @@ do_setusercontext(struct passwd *pw)
 #endif
        if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
                fatal("Failed to set uids to %u.", (u_int) pw->pw_uid);
+
+#ifdef WITH_SELINUX
+       ssh_selinux_setup_exec_context(pw->pw_name);
+#endif
 }
 
 static void
@@ -1588,7 +1687,7 @@ child_close_fds(void)
        endpwent();
 
        /*
-        * Close any extra open file descriptors so that we don\'t have them
+        * Close any extra open file descriptors so that we don't have them
         * hanging around in clients.  Note that we want to do this after
         * initgroups, because at least on Solaris 2.3 it leaves file
         * descriptors open.
@@ -1602,12 +1701,13 @@ child_close_fds(void)
  * environment, closing extra file descriptors, setting the user and group
  * ids, and executing the command or shell.
  */
+#define ARGV_MAX 10
 void
 do_child(Session *s, const char *command)
 {
        extern char **environ;
        char **env;
-       char *argv[10];
+       char *argv[ARGV_MAX];
        const char *shell, *shell0, *hostname = NULL;
        struct passwd *pw = s->pw;
 
@@ -1652,7 +1752,9 @@ do_child(Session *s, const char *command)
                if (!check_quietlogin(s, command))
                        do_motd();
 #else /* HAVE_OSF_SIA */
-               do_nologin(pw);
+               /* When PAM is enabled we rely on it to do the nologin check */
+               if (!options.use_pam)
+                       do_nologin(pw);
                do_setusercontext(pw);
                /*
                 * PAM session modules in do_setusercontext may have
@@ -1665,7 +1767,8 @@ do_child(Session *s, const char *command)
        }
 
 #ifdef USE_PAM
-       if (options.use_pam && !is_pam_session_open()) {
+       if (options.use_pam && !options.use_login && !is_pam_session_open()) {
+               debug3("PAM session not opened, exiting");
                display_loginmsg();
                exit(254);
        }
@@ -1716,7 +1819,7 @@ do_child(Session *s, const char *command)
         */
 
        if (options.kerberos_get_afs_token && k_hasafs() &&
-            (s->authctxt->krb5_ctx != NULL)) {
+           (s->authctxt->krb5_ctx != NULL)) {
                char cell[64];
 
                debug("Getting AFS token");
@@ -1767,7 +1870,7 @@ do_child(Session *s, const char *command)
         }
 #endif
 
-       /* Change current directory to the user\'s home directory. */
+       /* Change current directory to the user's home directory. */
        if (chdir(pw->pw_dir) < 0) {
                fprintf(stderr, "Could not chdir to home directory %s: %s\n",
                    pw->pw_dir, strerror(errno));
@@ -1777,11 +1880,29 @@ do_child(Session *s, const char *command)
 #endif
        }
 
+       closefrom(STDERR_FILENO + 1);
+
        if (!options.use_login)
                do_rc_files(s, shell);
 
        /* restore SIGPIPE for child */
-       signal(SIGPIPE,  SIG_DFL);
+       signal(SIGPIPE, SIG_DFL);
+
+       if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
+               extern int optind, optreset;
+               int i;
+               char *p, *args;
+
+               setproctitle("%s@internal-sftp-server", s->pw->pw_name);
+               args = strdup(command ? command : "sftp-server");
+               for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
+                       if (i < ARGV_MAX - 1)
+                               argv[i++] = p;
+               argv[i] = NULL;
+               optind = optreset = 1;
+               __progname = argv[0];
+               exit(sftp_server_main(i, argv, s->pw));
+       }
 
        if (options.use_login) {
                launch_login(pw, hostname);
@@ -1855,6 +1976,7 @@ session_new(void)
                        s->ttyfd = -1;
                        s->used = 1;
                        s->self = i;
+                       s->x11_chanids = NULL;
                        debug("session_new: session %d", i);
                        return s;
                }
@@ -1927,6 +2049,29 @@ session_by_channel(int id)
        return NULL;
 }
 
+static Session *
+session_by_x11_channel(int id)
+{
+       int i, j;
+
+       for (i = 0; i < MAX_SESSIONS; i++) {
+               Session *s = &sessions[i];
+
+               if (s->x11_chanids == NULL || !s->used)
+                       continue;
+               for (j = 0; s->x11_chanids[j] != -1; j++) {
+                       if (s->x11_chanids[j] == id) {
+                               debug("session_by_x11_channel: session %d "
+                                   "channel %d", s->self, id);
+                               return s;
+                       }
+               }
+       }
+       debug("session_by_x11_channel: unknown channel %d", id);
+       session_dump();
+       return NULL;
+}
+
 static Session *
 session_by_pid(pid_t pid)
 {
@@ -2021,22 +2166,26 @@ session_subsystem_req(Session *s)
        struct stat st;
        u_int len;
        int success = 0;
-       char *cmd, *subsys = packet_get_string(&len);
-       int i;
+       char *prog, *cmd, *subsys = packet_get_string(&len);
+       u_int i;
 
        packet_check_eom();
        logit("subsystem request for %.100s", subsys);
 
        for (i = 0; i < options.num_subsystems; i++) {
                if (strcmp(subsys, options.subsystem_name[i]) == 0) {
-                       cmd = options.subsystem_command[i];
-                       if (stat(cmd, &st) < 0) {
-                               error("subsystem: cannot stat %s: %s", cmd,
+                       prog = options.subsystem_command[i];
+                       cmd = options.subsystem_args[i];
+                       if (!strcmp(INTERNAL_SFTP_NAME, prog)) {
+                               s->is_subsystem = SUBSYSTEM_INT_SFTP;
+                       } else if (stat(prog, &st) < 0) {
+                               error("subsystem: cannot stat %s: %s", prog,
                                    strerror(errno));
                                break;
+                       } else {
+                               s->is_subsystem = SUBSYSTEM_EXT;
                        }
                        debug("subsystem: exec() %s", cmd);
-                       s->is_subsystem = 1;
                        do_exec(s, cmd);
                        success = 1;
                        break;
@@ -2056,6 +2205,11 @@ session_x11_req(Session *s)
 {
        int success;
 
+       if (s->auth_proto != NULL || s->auth_data != NULL) {
+               error("session_x11_req: session %d: "
+                   "x11 forwarding already active", s->self);
+               return 0;
+       }
        s->single_connection = packet_get_char();
        s->auth_proto = packet_get_string(NULL);
        s->auth_data = packet_get_string(NULL);
@@ -2123,8 +2277,8 @@ session_env_req(Session *s)
        for (i = 0; i < options.num_accept_env; i++) {
                if (match_pattern(name, options.accept_env[i])) {
                        debug2("Setting env %d: %s=%s", s->num_env, name, val);
-                       s->env = xrealloc(s->env, sizeof(*s->env) *
-                           (s->num_env + 1));
+                       s->env = xrealloc(s->env, s->num_env + 1,
+                           sizeof(*s->env));
                        s->env[s->num_env].name = name;
                        s->env[s->num_env].val = val;
                        s->num_env++;
@@ -2179,7 +2333,7 @@ session_input_channel_req(Channel *c, const char *rtype)
                } else if (strcmp(rtype, "exec") == 0) {
                        success = session_exec_req(s);
                } else if (strcmp(rtype, "pty-req") == 0) {
-                       success =  session_pty_req(s);
+                       success = session_pty_req(s);
                } else if (strcmp(rtype, "x11-req") == 0) {
                        success = session_x11_req(s);
                } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
@@ -2210,11 +2364,18 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
         */
        if (s->chanid == -1)
                fatal("no channel for session %d", s->self);
+       if(options.hpn_disabled) 
        channel_set_fds(s->chanid,
            fdout, fdin, fderr,
            fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
            1,
            CHAN_SES_WINDOW_DEFAULT);
+       else
+               channel_set_fds(s->chanid,
+                   fdout, fdin, fderr,
+                   fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
+                   1,
+                   options.hpn_buffer_size);
 }
 
 /*
@@ -2280,6 +2441,62 @@ sig2name(int sig)
        return "SIG@openssh.com";
 }
 
+static void
+session_close_x11(int id)
+{
+       Channel *c;
+
+       if ((c = channel_by_id(id)) == NULL) {
+               debug("session_close_x11: x11 channel %d missing", id);
+       } else {
+               /* Detach X11 listener */
+               debug("session_close_x11: detach x11 channel %d", id);
+               channel_cancel_cleanup(id);
+               if (c->ostate != CHAN_OUTPUT_CLOSED)
+                       chan_mark_dead(c);
+       }
+}
+
+static void
+session_close_single_x11(int id, void *arg)
+{
+       Session *s;
+       u_int i;
+
+       debug3("session_close_single_x11: channel %d", id);
+       channel_cancel_cleanup(id);
+       if ((s = session_by_x11_channel(id)) == NULL)
+               fatal("session_close_single_x11: no x11 channel %d", id);
+       for (i = 0; s->x11_chanids[i] != -1; i++) {
+               debug("session_close_single_x11: session %d: "
+                   "closing channel %d", s->self, s->x11_chanids[i]);
+               /*
+                * The channel "id" is already closing, but make sure we
+                * close all of its siblings.
+                */
+               if (s->x11_chanids[i] != id)
+                       session_close_x11(s->x11_chanids[i]);
+       }
+       xfree(s->x11_chanids);
+       s->x11_chanids = NULL;
+       if (s->display) {
+               xfree(s->display);
+               s->display = NULL;
+       }
+       if (s->auth_proto) {
+               xfree(s->auth_proto);
+               s->auth_proto = NULL;
+       }
+       if (s->auth_data) {
+               xfree(s->auth_data);
+               s->auth_data = NULL;
+       }
+       if (s->auth_display) {
+               xfree(s->auth_display);
+               s->auth_display = NULL;
+       }
+}
+
 static void
 session_exit_message(Session *s, int status)
 {
@@ -2299,7 +2516,7 @@ session_exit_message(Session *s, int status)
                channel_request_start(s->chanid, "exit-signal", 0);
                packet_put_cstring(sig2name(WTERMSIG(status)));
 #ifdef WCOREDUMP
-               packet_put_char(WCOREDUMP(status));
+               packet_put_char(WCOREDUMP(status)? 1 : 0);
 #else /* WCOREDUMP */
                packet_put_char(0);
 #endif /* WCOREDUMP */
@@ -2313,7 +2530,14 @@ session_exit_message(Session *s, int status)
 
        /* disconnect channel */
        debug("session_exit_message: release channel %d", s->chanid);
-       channel_cancel_cleanup(s->chanid);
+
+       /*
+        * Adjust cleanup callback attachment to send close messages when
+        * the channel gets EOF. The session will be then be closed
+        * by session_close_by_channel when the childs close their fds.
+        */
+       channel_register_cleanup(c->self, session_close_by_channel, 1);
+
        /*
         * emulate a write failure with 'chan_write_failed', nobody will be
         * interested in data we write.
@@ -2322,13 +2546,12 @@ session_exit_message(Session *s, int status)
         */
        if (c->ostate != CHAN_OUTPUT_CLOSED)
                chan_write_failed(c);
-       s->chanid = -1;
 }
 
 void
 session_close(Session *s)
 {
-       int i;
+       u_int i;
 
        debug("session_close: session %d pid %ld", s->self, (long)s->pid);
        if (s->ttyfd != -1)
@@ -2337,6 +2560,8 @@ session_close(Session *s)
                xfree(s->term);
        if (s->display)
                xfree(s->display);
+       if (s->x11_chanids)
+               xfree(s->x11_chanids);
        if (s->auth_display)
                xfree(s->auth_display);
        if (s->auth_data)
@@ -2344,12 +2569,13 @@ session_close(Session *s)
        if (s->auth_proto)
                xfree(s->auth_proto);
        s->used = 0;
-       for (i = 0; i < s->num_env; i++) {
-               xfree(s->env[i].name);
-               xfree(s->env[i].val);
-       }
-       if (s->env != NULL)
+       if (s->env != NULL) {
+               for (i = 0; i < s->num_env; i++) {
+                       xfree(s->env[i].name);
+                       xfree(s->env[i].val);
+               }
                xfree(s->env);
+       }
        session_proctitle(s);
 }
 
@@ -2364,7 +2590,9 @@ session_close_by_pid(pid_t pid, int status)
        }
        if (s->chanid != -1)
                session_exit_message(s, status);
-       session_close(s);
+       if (s->ttyfd != -1)
+               session_pty_cleanup(s);
+       s->pid = 0;
 }
 
 /*
@@ -2375,6 +2603,8 @@ void
 session_close_by_channel(int id, void *arg)
 {
        Session *s = session_by_channel(id);
+       u_int i;
+
        if (s == NULL) {
                debug("session_close_by_channel: no session for id %d", id);
                return;
@@ -2393,6 +2623,15 @@ session_close_by_channel(int id, void *arg)
        }
        /* detach by removing callback */
        channel_cancel_cleanup(s->chanid);
+
+       /* Close any X11 listeners associated with this session */
+       if (s->x11_chanids != NULL) {
+               for (i = 0; s->x11_chanids[i] != -1; i++) {
+                       session_close_x11(s->x11_chanids[i]);
+                       s->x11_chanids[i] = -1;
+               }
+       }
+
        s->chanid = -1;
        session_close(s);
 }
@@ -2455,6 +2694,7 @@ session_setup_x11fwd(Session *s)
        struct stat st;
        char display[512], auth_display[512];
        char hostname[MAXHOSTNAMELEN];
+       u_int i;
 
        if (no_x11_forwarding_flag) {
                packet_send_debug("X11 forwarding disabled in user configuration file.");
@@ -2480,10 +2720,15 @@ session_setup_x11fwd(Session *s)
        }
        if (x11_create_display_inet(options.x11_display_offset,
            options.x11_use_localhost, s->single_connection,
-           &s->display_number) == -1) {
+           &s->display_number, &s->x11_chanids, 
+           options.hpn_disabled, options.hpn_buffer_size) == -1) {
                debug("x11_create_display_inet failed.");
                return 0;
        }
+       for (i = 0; s->x11_chanids[i] != -1; i++) {
+               channel_register_cleanup(s->x11_chanids[i],
+                   session_close_single_x11, 0);
+       }
 
        /* Set up a suitable value for the DISPLAY variable. */
        if (gethostname(hostname, sizeof(hostname)) < 0)
@@ -2549,6 +2794,17 @@ do_cleanup(Authctxt *authctxt)
 
        if (authctxt == NULL)
                return;
+
+#ifdef USE_PAM
+       if (options.use_pam) {
+               sshpam_cleanup();
+               sshpam_thread_cleanup();
+       }
+#endif
+
+       if (!authctxt->authenticated)
+               return;
+
 #ifdef KRB5
        if (options.kerberos_ticket_cleanup &&
            authctxt->krb5_ctx)
@@ -2560,13 +2816,6 @@ do_cleanup(Authctxt *authctxt)
                ssh_gssapi_cleanup_creds();
 #endif
 
-#ifdef USE_PAM
-       if (options.use_pam) {
-               sshpam_cleanup();
-               sshpam_thread_cleanup();
-       }
-#endif
-
        /* remove agent socket */
        auth_sock_cleanup_proc(authctxt->pw);
 
This page took 0.074796 seconds and 4 git commands to generate.