Re: [PATCH] pam_exec questions and possible patch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> I'm currently trying to use pam_exec to call a script to synchronize
> my home directories with a central server and have come across a
> couple of issues.
>
> Firstly, does pam_exec make any sense outside of the "session" section
> of pam.conf?

Yes, it makes. Only look at the example section of the manual page.


The example section of the man page unfortunately doesn't make sense to me.

1) make -C /var/yp doesn't have any effect for me because I have no
makefile there and I'm not entirely sure what effect you envision it
having (what program should I assume is being run and what permissions
does it require?)

2) Let's look at what actually happens if we invoke the passwd program
and have a call to some arbitrary pam_exec module with the "seteuid"
specified.

[user]$ passwd

--- The calling process has: Ruid = user, Euid = root (because passwd
has setuid filesystem attribute and is owned by root)
--- After setuid(geteuid()), the pam_exec'ed program will have:  Ruid
= root, Euid = root

I'm not convinced that makes any sense... what's the goal?

3) Let's look at the other scenario
# User runs an executable setuid to something other than root
[user]$ chown user2 testuid
[user]$ chmod u+s testuid
[user]$ testuid

--- The calling process has: Ruid = user, Euid = user2
--- After setuid(geteuid()), the pam_exec'ed program will have: Ruid =
user, Euid = user2 (no change)

> It seems slightly hairy to me, because for instance if
> it's in the auth section a user could cause a program to be executed
> by another user by only unsuccessfully attempting to log in as that
> user.

Only an admin can configure this module, so it depends on what he
allows and what not.

> Secondly, is there any way to distinguish in the exec'ed program that
> the session is being opened or closed?  I've finally created a simple
> patch that defines a PAM_SESSION_ACTION environment variable in the
> executed subprocess so that my script can do the correct actions.
>
> Thirdly, does the seteuid option actually work correctly?

Yes, it does. Please also look at the example section of the manual
page.

> It seems to
> me that it simply sets the effective user id to whatever the effective
> user id already was.

Correct, it sets the effective user id to the one of the calling
application.


Please verify this?  setuid sets the effective user id.  geteuid
returns the effective user id.

setuid(geteuid()) seems an obvious no-op to me (unless the calling
application happens to have euid of root, and in that case it's the
real user id that's being set, to root) and a test application I wrote
seems to confirm this.


> My patch changes this by setting the effective
> userid of the subprocess to the user id of the user who's session is
> being created if this option is specified.

This change breaks all available configurations, especially the example
from the manual page.
Please introduce new options, not change existing one.


Ok, I've introduced a new option "run_as_user" that takes an optional
user parameter.  With none specified it sets the uid to the user being
authenticated.  I've also added environment variables to specify each
of the various pam hooks being called so that for instance one shell
script can be used to do all pam related activity you'd like.

One thing I didn't take the time to figure out was how to specify that
the right side of an assignment is optional in docbook.  So it looks
slightly funny with an extra space in the man page.  I'd actually like
it to look like [run_as_user[=_username_]].

Thanks,
Aaron
diff -r -U3 a/modules/pam_exec/pam_exec.8.xml b/modules/pam_exec/pam_exec.8.xml
--- a/modules/pam_exec/pam_exec.8.xml	2006-06-09 12:44:06.000000000 -0400
+++ b/modules/pam_exec/pam_exec.8.xml	2007-03-22 19:36:25.000000000 -0400
@@ -25,6 +25,9 @@
         seteuid
       </arg>
       <arg choice="opt">
+	run_as_user<arg choice="opt">=user</arg>
+      </arg>
+      <arg choice="opt">
         log=<replaceable>file</replaceable>
       </arg>
       <arg choice="plain">
@@ -42,7 +45,11 @@
 
     <para>
       pam_exec is a PAM module that can be used to run
-      an external command.
+      an external command.  
+
+      An environment variable named "PAM_EXEC_ACTION"
+      will be defined to allow writing external
+      applications.
     </para>
 
   </refsect1>
@@ -82,10 +89,34 @@
           </term>
           <listitem>
             <para>
+              Note: This option is probably not what you want and is kept
+                    only for compatibility.
+
+  	      Per default pam_exec.so will execute the external command
+     	      with the real and effective user ID of the calling process.
+
+              Specifying this option will setuid to the effective user id
+              of the calling process.  This will have no effect unless the
+              uid of the calling process has euid of root in which case it
+              will set the real user id of the process to root.
+            </para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term>
+            <option>run_as_user</option>
+          </term>
+          <listitem>
+            <para>
   	      Per default pam_exec.so will execute the external command
-     	      with the real user ID of the calling process.
+     	      with the real and effective user ID of the calling process.
+
               Specifying this option means the command is run
-              with the effective user ID.
+              with the effective user ID of the user being authenticated.
+
+              Note that if the uid of the calling process is root, both
+              the real and effective uids will be set.
             </para>
           </listitem>
         </varlistentry>
@@ -149,6 +180,27 @@
     </para>
   </refsect1>
 
+  <refsect1 id='pam_exec-environment'>
+    <title>ENVIRONMENT</title>
+    <para>
+      <variablelist>
+
+        <varlistentry>
+          <term>PAM_EXEC_ACTION</term>
+          <listitem>
+            <para>
+              Will be set to one of: auth, passwd, account,
+              session_open, session_close depending on the module 
+              service being invoked.  It may be undefined if the system
+              is unable to allocate enough memory.
+            </para>
+          </listitem>
+        </varlistentry>
+
+      </variablelist>
+    </para>
+  </refsect1>
+
   <refsect1 id='pam_exec-examples'>
     <title>EXAMPLES</title>
     <para>
diff -r -U3 a/modules/pam_exec/pam_exec.c b/modules/pam_exec/pam_exec.c
--- a/modules/pam_exec/pam_exec.c	2006-08-29 10:43:25.000000000 -0400
+++ b/modules/pam_exec/pam_exec.c	2007-03-22 17:50:25.000000000 -0400
@@ -45,6 +45,7 @@
 #include <syslog.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <pwd.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -59,13 +60,17 @@
 #include <security/pam_modutil.h>
 #include <security/pam_ext.h>
 
+#define PAM_EXEC_ACTION "PAM_EXEC_ACTION"
+
 static int
 call_exec (pam_handle_t *pamh, int argc, const char **argv)
 {
   int debug = 0;
   int call_setuid = 0;
+  int run_as_user = 0;
   int optargc;
   const char *logfile = NULL;
+  const char* user = NULL;
   pid_t pid;
 
   if (argc < 1) {
@@ -85,6 +90,13 @@
 	logfile = &argv[optargc][4];
       else if (strcasecmp (argv[optargc], "seteuid") == 0)
 	call_setuid = 1;
+      else if (strncasecmp (argv[optargc], "run_as_user=", 12) == 0)
+        {
+          run_as_user = 1;
+          user = &argv[optargc][12];
+        }
+      else if (strcasecmp (argv[optargc], "run_as_user") == 0)
+        run_as_user = 1;
       else
 	break; /* Unknown option, assume program to execute. */
     }
@@ -187,7 +199,34 @@
           exit (err);
         }
 
-      if (call_setuid)
+    /* Set euid to the user id of the user who's session this is */
+      if (run_as_user) 
+        {
+	  struct passwd* pwd;
+	  
+	  if (!user)
+	    pam_get_user(pamh, &user, NULL);
+
+	  pwd = getpwnam(user);
+	  if (!pwd)
+	    {
+	      int err = errno;
+	      pam_syslog (pamh, LOG_ERR, "Couldn't find user (%s): %m", 
+			  user, pam_strerror(pamh, errno));
+	      exit (err);
+	    }
+              
+	  pam_syslog (pamh, LOG_DEBUG, "Calling setuid(%lu) ...", pwd->pw_uid);
+	  if (setuid (pwd->pw_uid) == -1)
+	    {
+	      int err = errno;
+	      pam_syslog (pamh, LOG_ERR, "setuid(%lu) failed: %m",
+			  (unsigned long) pwd->pw_uid);
+	      exit (err);
+	    }
+        }
+      else if (call_setuid)
+	pam_syslog (pamh, LOG_DEBUG, "Calling setuid(%lu) ...", (unsigned long) geteuid() );
 	if (setuid (geteuid ()) == -1)
 	  {
 	    int err = errno;
@@ -226,11 +265,46 @@
   return PAM_SYSTEM_ERR;
 }
 
+static char*
+set_env(pam_handle_t *pamh, const char* sessionAction)
+{
+  char* env;
+  if (asprintf(&env, PAM_EXEC_ACTION "=%s", sessionAction) > 0)
+    {
+      int pamResult = putenv(env);
+      pam_syslog (pamh, LOG_DEBUG, "Tried to set " PAM_EXEC_ACTION " environment variable to '%s', result %d.", sessionAction, pamResult);
+    } else
+       env = NULL;
+
+  return env;
+}
+
+static void
+unset_env(pam_handle_t *pamh, char* env)
+{
+  if (env)
+    {
+      sprintf(env, PAM_EXEC_ACTION);
+    
+      int pamResult = putenv(env);
+      pam_syslog (pamh, LOG_DEBUG, "Tried to unset " PAM_EXEC_ACTION " environment variable, result %d.", pamResult);
+    
+      free(env);
+    }
+}
+
+
 PAM_EXTERN int
 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
 		     int argc, const char **argv)
 {
-  return call_exec (pamh, argc, argv);
+  char* env = set_env(pamh, "auth");
+
+  int result = call_exec (pamh, argc, argv);
+
+  unset_env(pamh, env);
+
+  return result;
 }
 
 PAM_EXTERN int
@@ -246,30 +320,59 @@
 pam_sm_chauthtok(pam_handle_t *pamh, int flags,
 		 int argc, const char **argv)
 {
-  if (flags & PAM_PRELIM_CHECK)
-    return PAM_SUCCESS;
-  return call_exec (pamh, argc, argv);
+  int result;
+  char* env = set_env(pamh, "passwd");
+
+  if (flags & PAM_PRELIM_CHECK) {
+    result = PAM_SUCCESS;
+    goto cleanup;
+  }
+  result = call_exec (pamh, argc, argv);
+
+cleanup:
+  unset_env(pamh, env);
+
+  return result;
 }
 
 PAM_EXTERN int
 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
 		 int argc, const char **argv)
 {
-  return call_exec (pamh, argc, argv);
+  char* env = set_env(pamh, "account");
+
+  int result = call_exec (pamh, argc, argv);
+
+  unset_env(pamh, env);
+
+  return result;
 }
 
 PAM_EXTERN int
 pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
 		    int argc, const char **argv)
 {
-  return call_exec (pamh, argc, argv);
+
+  char* env = set_env(pamh, "session_open");
+
+  int result = call_exec (pamh, argc, argv);
+
+  unset_env(pamh, env);
+
+  return result;
 }
 
 PAM_EXTERN int
 pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED,
 		     int argc, const char **argv)
 {
-  return call_exec (pamh, argc, argv);
+  char* env = set_env(pamh, "session_close");
+
+  int result = call_exec (pamh, argc, argv);
+
+  unset_env(pamh, env);
+
+  return result;
 }
 
 #ifdef PAM_STATIC
_______________________________________________
Pam-list mailing list
Pam-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/pam-list

[Index of Archives]     [Fedora Users]     [Kernel]     [Red Hat Install]     [Linux for the blind]     [Gimp]

  Powered by Linux