]> andersk Git - openssh.git/blobdiff - session.c
- (dtucker) [session.c] Enable AFS support in conjunction with KRB5 not
[openssh.git] / session.c
index 35328ecbbb2a2fc500e36982648ccde3ec33e721..6a1cb78418e3b0ff3f55f0c4160207ec072c0a08 100644 (file)
--- a/session.c
+++ b/session.c
@@ -33,7 +33,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: session.c,v 1.163 2003/08/31 13:29:05 markus Exp $");
+RCSID("$OpenBSD: session.c,v 1.171 2004/01/13 19:23:15 markus Exp $");
 
 #include "ssh.h"
 #include "ssh1.h"
@@ -58,6 +58,10 @@ RCSID("$OpenBSD: session.c,v 1.163 2003/08/31 13:29:05 markus Exp $");
 #include "session.h"
 #include "monitor_wrap.h"
 
+#ifdef KRB5
+#include <kafs.h>
+#endif
+
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
@@ -66,7 +70,7 @@ RCSID("$OpenBSD: session.c,v 1.163 2003/08/31 13:29:05 markus Exp $");
 
 Session *session_new(void);
 void   session_set_fds(Session *, int, int, int);
-void   session_pty_cleanup(void *);
+void   session_pty_cleanup(Session *);
 void   session_proctitle(Session *);
 int    session_setup_x11fwd(Session *);
 void   do_exec_pty(Session *, const char *);
@@ -106,6 +110,8 @@ Session     sessions[MAX_SESSIONS];
 login_cap_t *lc;
 #endif
 
+static int is_child = 0;
+
 /* Name and directory of socket for authentication agent forwarding. */
 static char *auth_sock_name = NULL;
 static char *auth_sock_dir = NULL;
@@ -113,10 +119,8 @@ static char *auth_sock_dir = NULL;
 /* removes the agent forwarding socket */
 
 static void
-auth_sock_cleanup_proc(void *_pw)
+auth_sock_cleanup_proc(struct passwd *pw)
 {
-       struct passwd *pw = _pw;
-
        if (auth_sock_name != NULL) {
                temporarily_use_uid(pw);
                unlink(auth_sock_name);
@@ -144,7 +148,7 @@ auth_input_request_forwarding(struct passwd * 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);
+       strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
 
        /* Create private directory for socket */
        if (mkdtemp(auth_sock_dir) == NULL) {
@@ -160,9 +164,6 @@ auth_input_request_forwarding(struct passwd * pw)
        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)
@@ -180,7 +181,7 @@ auth_input_request_forwarding(struct passwd * pw)
        restore_uid();
 
        /* Start listening on the socket. */
-       if (listen(sock, 5) < 0)
+       if (listen(sock, SSH_LISTEN_BACKLOG) < 0)
                packet_disconnect("listen: %.100s", strerror(errno));
 
        /* Allocate a channel for the authentication agent socket. */
@@ -207,7 +208,6 @@ do_authenticated(Authctxt *authctxt)
                close(startup_pipe);
                startup_pipe = -1;
        }
-
        /* setup the channel layer */
        if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
                channel_permit_all_opens();
@@ -217,13 +217,7 @@ do_authenticated(Authctxt *authctxt)
        else
                do_authenticated1(authctxt);
 
-       /* remove agent socket */
-       if (auth_sock_name != NULL)
-               auth_sock_cleanup_proc(authctxt->pw);
-#ifdef KRB5
-       if (options.kerberos_ticket_cleanup)
-               krb5_cleanup_proc(authctxt);
-#endif
+       do_cleanup(authctxt);
 }
 
 /*
@@ -405,7 +399,7 @@ do_exec_no_pty(Session *s, const char *command)
 
        /* Fork the child. */
        if ((pid = fork()) == 0) {
-               fatal_remove_all_cleanups();
+               is_child = 1;
 
                /* Child.  Reinitialize the log since the pid has changed. */
                log_init(__progname, options.log_level, options.log_facility, log_stderr);
@@ -531,7 +525,7 @@ do_exec_pty(Session *s, const char *command)
 
        /* Fork the child. */
        if ((pid = fork()) == 0) {
-               fatal_remove_all_cleanups();
+               is_child = 1;
 
                /* Child.  Reinitialize the log because the pid has changed. */
                log_init(__progname, options.log_level, options.log_facility, log_stderr);
@@ -627,7 +621,7 @@ do_pre_login(Session *s)
                if (getpeername(packet_get_connection_in(),
                    (struct sockaddr *) & from, &fromlen) < 0) {
                        debug("getpeername: %.100s", strerror(errno));
-                       fatal_cleanup();
+                       cleanup_exit(255);
                }
        }
 
@@ -687,7 +681,7 @@ do_login(Session *s, const char *command)
                if (getpeername(packet_get_connection_in(),
                    (struct sockaddr *) & from, &fromlen) < 0) {
                        debug("getpeername: %.100s", strerror(errno));
-                       fatal_cleanup();
+                       cleanup_exit(255);
                }
        }
 
@@ -798,8 +792,19 @@ void
 child_set_env(char ***envp, u_int *envsizep, const char *name,
        const char *value)
 {
-       u_int i, namelen;
        char **env;
+       u_int envsize;
+       u_int i, namelen;
+
+       /*
+        * If we're passed an uninitialized list, allocate a single null
+        * entry before continuing.
+        */
+       if (*envp == NULL && *envsizep == 0) {
+               *envp = xmalloc(sizeof(char *));
+               *envp[0] = NULL;
+               *envsizep = 1;
+       }
 
        /*
         * Find the slot where the value should be stored.  If the variable
@@ -816,12 +821,13 @@ child_set_env(char ***envp, u_int *envsizep, const char *name,
                xfree(env[i]);
        } else {
                /* New variable.  Expand if necessary. */
-               if (i >= (*envsizep) - 1) {
-                       if (*envsizep >= 1000)
-                               fatal("child_set_env: too many env vars,"
-                                   " skipping: %.100s", name);
-                       (*envsizep) += 50;
-                       env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
+               envsize = *envsizep;
+               if (i >= envsize - 1) {
+                       if (envsize >= 1000)
+                               fatal("child_set_env: too many env vars");
+                       envsize += 50;
+                       env = (*envp) = xrealloc(env, envsize * sizeof(char *));
+                       *envsizep = envsize;
                }
                /* Need to set the NULL pointer at end of array beyond the new slot. */
                env[i + 1] = NULL;
@@ -877,6 +883,61 @@ read_environment_file(char ***env, u_int *envsize,
        fclose(f);
 }
 
+#ifdef HAVE_ETC_DEFAULT_LOGIN
+/*
+ * Return named variable from specified environment, or NULL if not present.
+ */
+static char *
+child_get_env(char **env, const char *name)
+{
+       int i;
+       size_t len;
+
+       len = strlen(name);
+       for (i=0; env[i] != NULL; i++)
+               if (strncmp(name, env[i], len) == 0 && env[i][len] == '=')
+                       return(env[i] + len + 1);
+       return NULL;
+}
+
+/*
+ * Read /etc/default/login.
+ * We pick up the PATH (or SUPATH for root) and UMASK.
+ */
+static void
+read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
+{
+       char **tmpenv = NULL, *var;
+       u_int i, tmpenvsize = 0;
+       u_long mask;
+
+       /*
+        * We don't want to copy the whole file to the child's environment,
+        * so we use a temporary environment and copy the variables we're
+        * interested in.
+        */
+       read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login");
+
+       if (tmpenv == NULL)
+               return;
+
+       if (uid == 0)
+               var = child_get_env(tmpenv, "SUPATH");
+       else
+               var = child_get_env(tmpenv, "PATH");
+       if (var != NULL)
+               child_set_env(env, envsize, "PATH", var);
+
+       if ((var = child_get_env(tmpenv, "UMASK")) != NULL)
+               if (sscanf(var, "%5lo", &mask) == 1)
+                       umask((mode_t)mask);
+
+       for (i = 0; tmpenv[i] != NULL; i++)
+               xfree(tmpenv[i]);
+       xfree(tmpenv);
+}
+#endif /* HAVE_ETC_DEFAULT_LOGIN */
+
 void copy_environment(char **source, char ***env, u_int *envsize)
 {
        char *var_name, *var_val;
@@ -895,7 +956,7 @@ void copy_environment(char **source, char ***env, u_int *envsize)
 
                debug3("Copy environment: %s=%s", var_name, var_val);
                child_set_env(env, envsize, var_name, var_val);
-               
+
                xfree(var_name);
        }
 }
@@ -905,7 +966,7 @@ do_setup_env(Session *s, const char *shell)
 {
        char buf[256];
        u_int i, envsize;
-       char **env, *laddr;
+       char **env, *laddr, *path = NULL;
        struct passwd *pw = s->pw;
 
        /* Initialize the environment. */
@@ -922,7 +983,7 @@ do_setup_env(Session *s, const char *shell)
 #endif
 
 #ifdef GSSAPI
-       /* Allow any GSSAPI methods that we've used to alter 
+       /* Allow any GSSAPI methods that we've used to alter
         * the childs environment as they see fit
         */
        ssh_gssapi_do_child(&env, &envsize);
@@ -949,12 +1010,15 @@ do_setup_env(Session *s, const char *shell)
                 * needed for loading shared libraries. So the path better
                 * remains intact here.
                 */
-#  ifdef SUPERUSER_PATH
-               child_set_env(&env, &envsize, "PATH", 
-                   s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH);
-#  else 
-               child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
-#  endif /* SUPERUSER_PATH */
+#  ifdef HAVE_ETC_DEFAULT_LOGIN
+               read_etc_default_login(&env, &envsize, pw->pw_uid);
+               path = child_get_env(env, "PATH");
+#  endif /* HAVE_ETC_DEFAULT_LOGIN */
+               if (path == NULL || *path == '\0') {
+                       child_set_env(&env, &envsize, "PATH",
+                           s->pw->pw_uid == 0 ?
+                               SUPERUSER_PATH : _PATH_STDPATH);
+               }
 # endif /* HAVE_CYGWIN */
 #endif /* HAVE_LOGIN_CAP */
 
@@ -1034,8 +1098,13 @@ do_setup_env(Session *s, const char *shell)
         * been set by PAM.
         */
        if (options.use_pam) {
-               char **p = fetch_pam_environment();
+               char **p;
+
+               p = fetch_pam_child_environment();
+               copy_environment(p, &env, &envsize);
+               free_pam_environment(p);
 
+               p = fetch_pam_environment();
                copy_environment(p, &env, &envsize);
                free_pam_environment(p);
        }
@@ -1108,7 +1177,7 @@ do_rc_files(Session *s, const char *shell)
                if (debug_flag) {
                        fprintf(stderr,
                            "Running %.500s remove %.100s\n",
-                           options.xauth_location, s->auth_display);
+                           options.xauth_location, s->auth_display);
                        fprintf(stderr,
                            "%.500s add %.100s %.100s %.100s\n",
                            options.xauth_location, s->auth_display,
@@ -1200,7 +1269,7 @@ do_setusercontext(struct passwd *pw)
                endgrent();
 # ifdef USE_PAM
                /*
-                * PAM credentials may take the form of supplementary groups. 
+                * PAM credentials may take the form of supplementary groups.
                 * These will have been wiped by the above initgroups() call.
                 * Reestablish them here.
                 */
@@ -1350,6 +1419,32 @@ do_child(Session *s, const char *command)
         */
        environ = env;
 
+#if defined(KRB5) && defined(AFS)
+       /*
+        * At this point, we check to see if AFS is active and if we have
+        * a valid Kerberos 5 TGT. If so, it seems like a good idea to see
+        * if we can (and need to) extend the ticket into an AFS token. If
+        * we don't do this, we run into potential problems if the user's
+        * home directory is in AFS and it's not world-readable.
+        */
+
+       if (options.kerberos_get_afs_token && k_hasafs() &&
+            (s->authctxt->krb5_ctx != NULL)) {
+               char cell[64];
+
+               debug("Getting AFS token");
+
+               k_setpag();
+
+               if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
+                       krb5_afslog(s->authctxt->krb5_ctx,
+                           s->authctxt->krb5_fwd_ccache, cell, NULL);
+
+               krb5_afslog_home(s->authctxt->krb5_ctx,
+                   s->authctxt->krb5_fwd_ccache, NULL, NULL, pw->pw_dir);
+       }
+#endif
+
        /* Change current directory to the user\'s home directory. */
        if (chdir(pw->pw_dir) < 0) {
                fprintf(stderr, "Could not chdir to home directory %s: %s\n",
@@ -1471,7 +1566,7 @@ session_open(Authctxt *authctxt, int chanid)
        }
        s->authctxt = authctxt;
        s->pw = authctxt->pw;
-       if (s->pw == NULL)
+       if (s->pw == NULL || !authctxt->valid)
                fatal("no user for session %d", s->self);
        debug("session_open: session %d: link with channel %d", s->self, chanid);
        s->chanid = chanid;
@@ -1593,11 +1688,6 @@ session_pty_req(Session *s)
                n_bytes = packet_remaining();
        tty_parse_modes(s->ttyfd, &n_bytes);
 
-       /*
-        * Add a cleanup function to clear the utmp entry and record logout
-        * time in case we call fatal() (e.g., the connection gets closed).
-        */
-       fatal_add_cleanup(session_pty_cleanup, (void *)s);
        if (!use_privsep)
                pty_setowner(s->pw, s->tty);
 
@@ -1779,10 +1869,8 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
  * (e.g., due to a dropped connection).
  */
 void
-session_pty_cleanup2(void *session)
+session_pty_cleanup2(Session *s)
 {
-       Session *s = session;
-
        if (s == NULL) {
                error("session_pty_cleanup: no session");
                return;
@@ -1813,9 +1901,9 @@ session_pty_cleanup2(void *session)
 }
 
 void
-session_pty_cleanup(void *session)
+session_pty_cleanup(Session *s)
 {
-       PRIVSEP(session_pty_cleanup2(session));
+       PRIVSEP(session_pty_cleanup2(s));
 }
 
 static char *
@@ -1888,10 +1976,8 @@ void
 session_close(Session *s)
 {
        debug("session_close: session %d pid %ld", s->self, (long)s->pid);
-       if (s->ttyfd != -1) {
-               fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+       if (s->ttyfd != -1)
                session_pty_cleanup(s);
-       }
        if (s->term)
                xfree(s->term);
        if (s->display)
@@ -1940,10 +2026,8 @@ session_close_by_channel(int id, void *arg)
                 * delay detach of session, but release pty, since
                 * the fd's to the child are already closed
                 */
-               if (s->ttyfd != -1) {
-                       fatal_remove_cleanup(session_pty_cleanup, (void *)s);
+               if (s->ttyfd != -1)
                        session_pty_cleanup(s);
-               }
                return;
        }
        /* detach by removing callback */
@@ -1978,13 +2062,13 @@ session_tty_list(void)
        for (i = 0; i < MAX_SESSIONS; i++) {
                Session *s = &sessions[i];
                if (s->used && s->ttyfd != -1) {
-                       
+
                        if (strncmp(s->tty, "/dev/", 5) != 0) {
                                cp = strrchr(s->tty, '/');
                                cp = (cp == NULL) ? s->tty : cp + 1;
                        } else
                                cp = s->tty + 5;
-                       
+
                        if (buf[0] != '\0')
                                strlcat(buf, ",", sizeof buf);
                        strlcat(buf, cp, sizeof buf);
@@ -2084,8 +2168,51 @@ static void
 do_authenticated2(Authctxt *authctxt)
 {
        server_loop2(authctxt);
-#if defined(GSSAPI)
-       if (options.gss_cleanup_creds)
-               ssh_gssapi_cleanup_creds(NULL);
+}
+
+void
+do_cleanup(Authctxt *authctxt)
+{
+       static int called = 0;
+
+       debug("do_cleanup");
+
+       /* no cleanup if we're in the child for login shell */
+       if (is_child)
+               return;
+
+       /* avoid double cleanup */
+       if (called)
+               return;
+       called = 1;
+
+       if (authctxt == NULL)
+               return;
+#ifdef KRB5
+       if (options.kerberos_ticket_cleanup &&
+           authctxt->krb5_ctx)
+               krb5_cleanup_proc(authctxt);
 #endif
+
+#ifdef GSSAPI
+       if (compat20 && options.gss_cleanup_creds)
+               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);
+
+       /*
+        * Cleanup ptys/utmp only if privsep is disabled,
+        * or if running in monitor.
+        */
+       if (!use_privsep || mm_is_monitor())
+               session_destroy_all(session_pty_cleanup2);
 }
This page took 0.095479 seconds and 4 git commands to generate.