pam_env: per-user environment file?

Kees Cook kees at ubuntu.com
Mon Sep 10 19:23:26 UTC 2007


Hi!

Ubuntu has been carrying a patch against PAM to have a ~/.pam_environment
file that is parsed for each user (which allows a way to set environment
variables without regard to how a user logs in (ssh, gdm, etc)).

I've included the patch below.  Is this something that would be
accepted into mainline PAM?

Thanks,

-Kees

---
diff -uNrp Linux-PAM-0.99.8.1~/modules/pam_env/pam_env.c Linux-PAM-0.99.8.1/modules/pam_env/pam_env.c
--- Linux-PAM-0.99.8.1~/modules/pam_env/pam_env.c	2005-12-12 06:45:00.000000000 -0800
+++ Linux-PAM-0.99.8.1/modules/pam_env/pam_env.c	2007-09-10 12:21:14.657766129 -0700
@@ -11,6 +11,9 @@
 #define DEFAULT_ETC_ENVFILE     "/etc/environment"
 #define DEFAULT_READ_ENVFILE    1
 
+#define DEFAULT_USER_ENVFILE    ".pam_environment"
+#define DEFAULT_USER_READ_ENVFILE 1
+
 #include "config.h"
 
 #include <ctype.h>
@@ -75,16 +78,20 @@ static char quote='Z';
 /* argument parsing */
 
 #define PAM_DEBUG_ARG       0x01
-#define PAM_NEW_CONF_FILE   0x02
-#define PAM_ENV_SILENT      0x04
-#define PAM_NEW_ENV_FILE    0x10
 
 static int
 _pam_parse (const pam_handle_t *pamh, int argc, const char **argv,
-	    const char **conffile, const char **envfile, int *readenv)
+	    char **conffile, char **envfile, int *readenv,
+	    int *user_read_env, char **user_env_file)
 {
     int ctrl=0;
 
+    /* handle out of memory ; fixme */
+    *user_env_file = strdup(DEFAULT_USER_ENVFILE);
+    *envfile = strdup(DEFAULT_ETC_ENVFILE);
+    *readenv = DEFAULT_READ_ENVFILE;
+    *user_read_env = DEFAULT_USER_READ_ENVFILE;
+    *conffile = strdup(DEFAULT_CONF_FILE);
 
     /* step through arguments */
     for (; argc-- > 0; ++argv) {
@@ -94,25 +101,36 @@ _pam_parse (const pam_handle_t *pamh, in
 	if (!strcmp(*argv,"debug"))
 	    ctrl |= PAM_DEBUG_ARG;
 	else if (!strncmp(*argv,"conffile=",9)) {
-	    *conffile = 9 + *argv;
-	    if (**conffile != '\0') {
-		D(("new Configuration File: %s", *conffile));
-		ctrl |= PAM_NEW_CONF_FILE;
-	    } else {
+	    if (*argv+9 == '\0') {
 		pam_syslog(pamh, LOG_ERR,
 			 "conffile= specification missing argument - ignored");
+	    } else {
+		free(*conffile);
+		*conffile = x_strdup(9+*argv);
+		D(("new Configuration File: %s", *conffile));
 	    }
 	} else if (!strncmp(*argv,"envfile=",8)) {
-	    *envfile = 8 + *argv;
-	    if (**envfile != '\0') {
-		D(("new Env File: %s", *envfile));
-		ctrl |= PAM_NEW_ENV_FILE;
-	    } else {
+	    if (*argv+8 == '\0') {
 		pam_syslog (pamh, LOG_ERR,
 			 "envfile= specification missing argument - ignored");
+	    } else {
+		free(*envfile);
+		*envfile = x_strdup(8+*argv);
+		D(("new Env File: %s", *envfile));
+	    }
+	} else if (!strncmp(*argv,"user_env_file=",13)) {
+	    if (*argv+13 == '\0') {
+		pam_syslog (pamh, LOG_ERR,
+			 "user_env_file= specification missing argument - ignored");
+	    } else {
+		free(*user_env_file);
+		*user_env_file = x_strdup(13+*argv);
+		D(("new User Env File: %s", *user_env_file));
 	    }
 	} else if (!strncmp(*argv,"readenv=",8))
 	    *readenv = atoi(8+*argv);
+	else if (!strncmp(*argv,"user_readenv=",13))
+	    *user_read_env = atoi(13+*argv);
 	else
 	    pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
     }
@@ -121,10 +139,9 @@ _pam_parse (const pam_handle_t *pamh, in
 }
 
 static int
-_parse_config_file(pam_handle_t *pamh, int ctrl, const char *conffile)
+_parse_config_file(pam_handle_t *pamh, const char *file)
 {
     int retval;
-    const char *file;
     char buffer[BUF_SIZE];
     FILE *conf;
     VAR Var, *var=&Var;
@@ -132,12 +149,6 @@ _parse_config_file(pam_handle_t *pamh, i
     var->name=NULL; var->defval=NULL; var->override=NULL;
     D(("Called."));
 
-    if (ctrl & PAM_NEW_CONF_FILE) {
-	file = conffile;
-    } else {
-	file = DEFAULT_CONF_FILE;
-    }
-
     D(("Config file name is: %s", file));
 
     /*
@@ -184,18 +195,12 @@ _parse_config_file(pam_handle_t *pamh, i
 }
 
 static int
-_parse_env_file(pam_handle_t *pamh, int ctrl, const char *env_file)
+_parse_env_file(pam_handle_t *pamh, const char *file)
 {
     int retval=PAM_SUCCESS, i, t;
-    const char *file;
     char buffer[BUF_SIZE], *key, *mark;
     FILE *conf;
 
-    if (ctrl & PAM_NEW_ENV_FILE)
-	file = env_file;
-    else
-	file = DEFAULT_ETC_ENVFILE;
-
     D(("Env file name is: %s", file));
 
     if ((conf = fopen(file,"r")) == NULL) {
@@ -738,23 +743,52 @@ pam_sm_setcred (pam_handle_t *pamh, int 
 		int argc, const char **argv)
 {
   int retval, ctrl, readenv=DEFAULT_READ_ENVFILE;
-  const char *conf_file = NULL, *env_file = NULL;
+  int read_user_env = DEFAULT_USER_READ_ENVFILE;
+  char *conf_file = NULL, *env_file = NULL, *user_env_file = NULL;
 
   /*
    * this module sets environment variables read in from a file
    */
 
   D(("Called."));
-  ctrl = _pam_parse(pamh, argc, argv, &conf_file, &env_file, &readenv);
+  ctrl = _pam_parse(pamh, argc, argv, &conf_file, &env_file, &readenv,
+                    &read_user_env, &user_env_file);
 
-  retval = _parse_config_file(pamh, ctrl, conf_file);
+  retval = _parse_config_file(pamh, conf_file);
 
   if(readenv && retval == PAM_SUCCESS) {
-    retval = _parse_env_file(pamh, ctrl, env_file);
+    retval = _parse_env_file(pamh, env_file);
     if (retval == PAM_IGNORE)
       retval = PAM_SUCCESS;
   }
 
+  if(read_user_env && retval == PAM_SUCCESS) {
+    char *envpath = NULL;
+    struct passwd *user_entry;
+    const char *username;
+    struct stat statbuf;
+
+    username = _pam_get_item_byname(pamh, "PAM_USER");
+
+    user_entry = getpwnam(username);
+    if (!user_entry) {
+      pam_syslog(pamh, LOG_ERR, "No such user!?");
+    }
+    else {
+      if (!(envpath = malloc(strlen(user_entry->pw_dir) + 1 + strlen(user_env_file) + 1))) {
+        pam_syslog(pamh, LOG_ERR, "Malloc failed");
+        return PAM_BUF_ERR;
+      }
+      sprintf(envpath, "%s/%s", user_entry->pw_dir, user_env_file);
+      if (stat(envpath, &statbuf) == 0) {
+        retval = _parse_config_file(pamh, envpath);
+        if (retval == PAM_IGNORE)
+          retval = PAM_SUCCESS;
+      }
+      free(envpath);
+    }
+  }
+
   /* indicate success or failure */
 
   D(("Exit."));
@@ -773,28 +807,9 @@ PAM_EXTERN int
 pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED,
 		     int argc, const char **argv)
 {
-  int retval, ctrl, readenv=DEFAULT_READ_ENVFILE;
-  const char *conf_file = NULL, *env_file = NULL;
-
-  /*
-   * this module sets environment variables read in from a file
-   */
-
-  D(("Called."));
-  ctrl = _pam_parse(pamh, argc, argv, &conf_file, &env_file, &readenv);
-
-  retval = _parse_config_file(pamh, ctrl, conf_file);
-
-  if(readenv && retval == PAM_SUCCESS) {
-    retval = _parse_env_file(pamh, ctrl, env_file);
-    if (retval == PAM_IGNORE)
-      retval = PAM_SUCCESS;
-  }
-
-  /* indicate success or failure */
-
-  D(("Exit."));
-  return retval;
+  /* Function was identical to pam_sm_setcred, so call it instead */
+  D(("Called -- calling pam_sm_setcred instead..."));
+  return pam_sm_setcred(pamh, flags, argc, argv);
 }
 
 PAM_EXTERN int


-- 
Kees Cook




More information about the Pam-list mailing list