BSD Auth: set child environment variables requested by login script [PATCH]

Stefan Krah sfk1 at bigfoot.com
Mon Sep 18 21:14:28 EST 2006


Hello,

in the BSD Authentication system the login script can request environment
variables to be set/unset. The call to auth_close() in auth-passwd.c does
change the current environment, but those changes are lost for the child
environment.

It would be really useful to add some kind of mechanism to get
those changes into the child environment. I've added two possible
solutions. Both solutions only deal with setenv requests.


Please tell me what you think and if there's a chance of adding
the feature.


Stefan Krah



######################################
   Easy way to prepare for testing:
######################################

Index: libexec/login_passwd/login.c
===================================================================
RCS file: /cvs/src/libexec/login_passwd/login.c,v
retrieving revision 1.8
diff -u -r1.8 login.c
--- libexec/login_passwd/login.c        14 Apr 2005 18:33:42 -0000      1.8
+++ libexec/login_passwd/login.c        18 Sep 2006 10:32:00 -0000
@@ -107,6 +107,9 @@
                exit(1);
        }

+       fprintf(back, BI_SETENV " X_BSD_AUTH_SOME_RESOURCE %d\n", 1024);
+       fprintf(back, BI_SETENV " TESTVAR %s\n", "bar");
+
        /*
         * Read password, either as from the terminal or if the
         * response mode is active from the caller program.


######################################
             Solution 1:
######################################

This is a minimal fix that just whitelists variables starting with
X_BSD_AUTH:


Index: usr.bin/ssh/auth-bsdauth.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth-bsdauth.c,v
retrieving revision 1.10
diff -u -r1.10 auth-bsdauth.c
--- usr.bin/ssh/auth-bsdauth.c	3 Aug 2006 03:34:41 -0000	1.10
+++ usr.bin/ssh/auth-bsdauth.c	18 Sep 2006 09:32:20 -0000
@@ -24,6 +24,7 @@
  */
 
 #include <sys/types.h>
+#include <string.h>
 
 #ifdef BSD_AUTH
 #include "xmalloc.h"
@@ -32,10 +33,36 @@
 #include "auth.h"
 #include "log.h"
 #include "buffer.h"
+#include "channels.h"
+#include "session.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+
+/*
+ * Set child environment variables starting with "X_BSD_AUTH".
+ * After the call to auth_close(), these variables are in the
+ * current environment if the login script has requested them.
+ */
+void
+bsdauth_child_set_env(char ***envp, u_int *envsizep)
+{
+	extern char **environ;
+	char name[8*1024]; /* MAXSPOOLSIZE in auth_session_t */
+	char *value;
+	u_int i, namelen;
+
+	for (i = 0; environ[i] != NULL; i++) {
+		namelen = strcspn(environ[i], "=");
+		if (namelen + 1 > sizeof(name))
+			continue;
+		snprintf(name, namelen + 1, "%s", environ[i]);
+		value = environ[i] + namelen + 1;
+		if (strncmp(name, "X_BSD_AUTH", 10) == 0)
+			child_set_env(envp, envsizep, name, value);
+	}
+}
 
 static void *
 bsdauth_init_ctx(Authctxt *authctxt)
Index: usr.bin/ssh/auth.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth.h,v
retrieving revision 1.58
diff -u -r1.58 auth.h
--- usr.bin/ssh/auth.h	18 Aug 2006 09:15:20 -0000	1.58
+++ usr.bin/ssh/auth.h	18 Sep 2006 09:32:23 -0000
@@ -123,6 +123,10 @@
 void	krb5_cleanup_proc(Authctxt *authctxt);
 #endif /* KRB5 */
 
+#ifdef BSD_AUTH
+void	bsdauth_child_set_env(char ***envp, u_int *envsizep);
+#endif
+
 void	do_authentication(Authctxt *);
 void	do_authentication2(Authctxt *);
 
Index: usr.bin/ssh/session.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/session.c,v
retrieving revision 1.219
diff -u -r1.219 session.c
--- usr.bin/ssh/session.c	29 Aug 2006 10:40:19 -0000	1.219
+++ usr.bin/ssh/session.c	18 Sep 2006 09:32:57 -0000
@@ -844,6 +844,9 @@
 		child_set_env(&env, &envsize, "KRB5CCNAME",
 		    s->authctxt->krb5_ticket_file);
 #endif
+#ifdef BSD_AUTH
+	bsdauth_child_set_env(&env, &envsize);
+#endif
 	if (auth_sock_name != NULL)
 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
 		    auth_sock_name);



######################################
             Solution 2:
######################################

This one saves the current environment and lets auth_close() do the changes
on an empty environment. All setenv requests are honored, unsetenv requests
are lost.


Index: usr.bin/ssh/auth-bsdauth.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth-bsdauth.c,v
retrieving revision 1.10
diff -u -r1.10 auth-bsdauth.c
--- usr.bin/ssh/auth-bsdauth.c	2006/08/03 03:34:41	1.10
+++ usr.bin/ssh/auth-bsdauth.c	2006/09/18 09:35:52
@@ -24,6 +24,7 @@
  */
 
 #include <sys/types.h>
+#include <string.h>
 
 #ifdef BSD_AUTH
 #include "xmalloc.h"
@@ -32,10 +33,96 @@
 #include "auth.h"
 #include "log.h"
 #include "buffer.h"
+#include "channels.h"
+#include "session.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+
+/* copy the current environment. */
+static char **
+bsdauth_env_copy(void)
+{
+	extern char **environ;
+	char **copy, *x;
+	u_int i, len;
+
+	for (i = 0; environ[i] != NULL; i++)
+		;
+	copy = xmalloc((i + 1) * sizeof(char *));
+
+	for (i = 0; environ[i] != NULL; i++) {
+		len = strlen(environ[i]);
+		x = xmalloc(len + 1);
+		strncpy(x, environ[i], len + 1);
+		copy[i] = x;
+	}
+	copy[i] = NULL;
+
+	return copy;
+}
+
+/* free the copy. */
+void
+bsdauth_env_free(Authctxt *authctxt, char **env)
+{
+	u_int i;
+
+	if (env != NULL && authctxt->auth_env_mod != NULL) {
+		for (i = 0; env[i] != NULL; i++)
+			xfree(env[i]);
+		xfree(env);
+	}
+}
+
+/*
+ * Wrapper around auth_close(): auth_close() changes the current environment
+ * as requested by the login script. To catch the setenv requests, we save
+ * the current environment and let auth_close() do the changes on an empty
+ * environment. unsetenv requests are lost.
+ */
+int
+auth_close_do_env(Authctxt *authctxt, auth_session_t *as)
+{
+	extern char **environ;
+	char **env_orig;
+	int ret;
+
+	env_orig = bsdauth_env_copy();
+	environ[0] = NULL;
+
+	ret = auth_close(as);
+
+	/* environ now contains all setenv changes done by auth_close(). */
+	authctxt->auth_env_mod = environ;
+	environ = env_orig;
+
+	return ret;
+}
+
+/* modify the child environment according to login script requests. */
+void
+bsdauth_child_mod_env(Authctxt *authctxt, char ***envp, u_int *envsizep)
+{
+	char **env_mod;
+	char name[8*1024]; /* MAXSPOOLSIZE in auth_session_t */
+	char *value;
+	u_int i, namelen;
+
+	env_mod = authctxt->auth_env_mod;
+
+	if (env_mod != NULL) {
+	        for (i = 0; env_mod[i] != NULL; i++) {
+			namelen = strcspn(env_mod[i], "=");
+			if (namelen + 1 > sizeof(name))
+				continue;
+			snprintf(name, namelen + 1, "%s", env_mod[i]);
+			value = env_mod[i] + namelen + 1;
+			child_set_env(envp, envsizep, name, value);
+		}
+	}
+}
 
 static void *
 bsdauth_init_ctx(Authctxt *authctxt)
Index: usr.bin/ssh/auth-passwd.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth-passwd.c,v
retrieving revision 1.40
diff -u -r1.40 auth-passwd.c
--- usr.bin/ssh/auth-passwd.c	2006/08/03 03:34:41	1.40
+++ usr.bin/ssh/auth-passwd.c	2006/09/18 09:35:52
@@ -144,7 +144,7 @@
 	if (as == NULL)
 		return (0);
 	if (auth_getstate(as) & AUTH_PWEXPIRED) {
-		auth_close(as);
+		auth_close_do_env(authctxt, as);
 		disable_forwarding();
 		authctxt->force_pwchange = 1;
 		return (1);
@@ -153,7 +153,7 @@
 			expire_checked = 1;
 			warn_expiry(authctxt, as);
 		}
-		return (auth_close(as));
+		return (auth_close_do_env(authctxt, as));
 	}
 }
 #else
Index: usr.bin/ssh/auth.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/auth.h,v
retrieving revision 1.58
diff -u -r1.58 auth.h
--- usr.bin/ssh/auth.h	2006/08/18 09:15:20	1.58
+++ usr.bin/ssh/auth.h	2006/09/18 09:35:53
@@ -61,6 +61,7 @@
 	void		*kbdintctxt;
 #ifdef BSD_AUTH
 	auth_session_t	*as;
+	char		**auth_env_mod;  /* env changes requested by login script */
 #endif
 #ifdef KRB5
 	krb5_context	 krb5_ctx;
@@ -122,6 +123,12 @@
 int	auth_krb5_password(Authctxt *authctxt, const char *password);
 void	krb5_cleanup_proc(Authctxt *authctxt);
 #endif /* KRB5 */
+
+#ifdef BSD_AUTH
+int	auth_close_do_env(Authctxt *authctxt, auth_session_t *as);
+void	bsdauth_env_free(Authctxt *authctxt, char **env);
+void	bsdauth_child_mod_env(Authctxt *authctxt, char ***envp, u_int *envsizep);
+#endif
 
 void	do_authentication(Authctxt *);
 void	do_authentication2(Authctxt *);
Index: usr.bin/ssh/session.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/session.c,v
retrieving revision 1.219
diff -u -r1.219 session.c
--- usr.bin/ssh/session.c	2006/08/29 10:40:19	1.219
+++ usr.bin/ssh/session.c	2006/09/18 09:35:56
@@ -844,6 +844,9 @@
 		child_set_env(&env, &envsize, "KRB5CCNAME",
 		    s->authctxt->krb5_ticket_file);
 #endif
+#ifdef BSD_AUTH
+	bsdauth_child_mod_env(s->authctxt, &env, &envsize);
+#endif
 	if (auth_sock_name != NULL)
 		child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
 		    auth_sock_name);
@@ -1128,6 +1131,10 @@
 	 * Must take new environment into use so that .ssh/rc,
 	 * /etc/ssh/sshrc and xauth are run in the proper environment.
 	 */
+#ifdef BSD_AUTH
+	/* environ points to xmalloc'd memory. */
+	bsdauth_env_free(s->authctxt, environ);
+#endif
 	environ = env;
 
 #ifdef KRB5





More information about the openssh-unix-dev mailing list