]> granicus.if.org Git - linux-pam/commitdiff
Relevant BUGIDs:
authorThorsten Kukuk <kukuk@thkukuk.de>
Wed, 3 Sep 2008 13:06:22 +0000 (13:06 +0000)
committerThorsten Kukuk <kukuk@thkukuk.de>
Wed, 3 Sep 2008 13:06:22 +0000 (13:06 +0000)
Purpose of commit: new feature

Commit summary:
---------------

2008-09-03  Thorsten Kukuk  <kukuk@thkukuk.de>

        * modules/pam_exec/pam_exec.c: Expose authtok if requested,
        provide environment variable containing service type.
        * modules/pam_exec/pam_exec.8.xml: Document new option.

ChangeLog
modules/pam_exec/pam_exec.8.xml
modules/pam_exec/pam_exec.c

index 03e0691d171d9bb69293ca6bd1d7be833d6b431c..1c22a2aaf4920e5396eea8413cfc15b9e1e0321b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2008-09-03  Thorsten Kukuk  <kukuk@thkukuk.de>
+
+       * modules/pam_exec/pam_exec.c: Expose authtok if requested,
+       provide environment variable containing service type.
+       * modules/pam_exec/pam_exec.8.xml: Document new option.
+
 2008-08-29  Tomas Mraz <t8m@centrum.cz>
 
        * modules/pam_loginuid/pam_loginuid.c(set_loginuid): Uids
index 1ee25cab56d9f9c2adbd992467cce1b1b8ade101..3cbd6af3ea1e15dc427c7d9a09a94770a20ab05b 100644 (file)
@@ -21,6 +21,9 @@
       <arg choice="opt">
        debug
       </arg>
+      <arg choice="opt">
+         expose_authtok
+      </arg>
       <arg choice="opt">
         seteuid
       </arg>
      In addition, the following PAM items are
      exported as environment variables: <emphasis>PAM_RHOST</emphasis>,
      <emphasis>PAM_RUSER</emphasis>, <emphasis>PAM_SERVICE</emphasis>,
-     <emphasis>PAM_TTY</emphasis>, and <emphasis>PAM_USER</emphasis>.
+     <emphasis>PAM_TTY</emphasis>, <emphasis>PAM_USER</emphasis> and
+     <emphasis>PAM_TYPE</emphasis>, which contains one of the module
+     types: <option>account</option>, <option>auth</option>,
+     <option>password</option>, <option>open_session</option> and
+     <option>close_session</option>.
     </para>
 
   </refsect1>
           </listitem>
         </varlistentry>
 
+        <varlistentry>
+          <term>
+            <option>expose_authtok</option>
+          </term>
+          <listitem>
+            <para>
+              During authentication the calling command can read
+              the password from <citerefentry>
+              <refentrytitle>stdin</refentrytitle><manvolnum>3</manvolnum>
+              </citerefentry>.
+            </para>
+          </listitem>
+        </varlistentry>
+
         <varlistentry>
           <term>
             <option>log=<replaceable>file</replaceable></option>
index dce6573001e85c645f09e5cf23ee5a87e3309d64..47e1d5bb1b9ab1b557f13b74d811b7ae4929e73a 100644 (file)
@@ -58,6 +58,7 @@
 #include <security/pam_modules.h>
 #include <security/pam_modutil.h>
 #include <security/pam_ext.h>
+#include <security/_pam_macros.h>
 
 #define ENV_ITEM(n) { (n), #n }
 static struct {
@@ -71,15 +72,20 @@ static struct {
   ENV_ITEM(PAM_RUSER),
 };
 
+
 static int
-call_exec (pam_handle_t *pamh, int argc, const char **argv)
+call_exec (const char *pam_type, pam_handle_t *pamh,
+          int argc, const char **argv)
 {
   int debug = 0;
   int call_setuid = 0;
   int quiet = 0;
+  int expose_authtok = 0;
   int optargc;
   const char *logfile = NULL;
+  const char *authtok = NULL;
   pid_t pid;
+  int fds[2];
 
   if (argc < 1) {
     pam_syslog (pamh, LOG_ERR,
@@ -100,10 +106,63 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
        call_setuid = 1;
       else if (strcasecmp (argv[optargc], "quiet") == 0)
        quiet = 1;
+      else if (strcasecmp (argv[optargc], "expose_authtok") == 0)
+       expose_authtok = 1;
       else
        break; /* Unknown option, assume program to execute. */
     }
 
+  if (expose_authtok == 1)
+    {
+      if (strcmp (pam_type, "auth") != 0)
+       {
+         pam_syslog (pamh, LOG_ERR,
+                     "expose_authtok not supported for type %s", pam_type);
+         expose_authtok = 0;
+       }
+      else
+       {
+         const void *void_pass;
+         int retval;
+
+         retval = pam_get_item (pamh, PAM_AUTHTOK, &void_pass);
+         if (retval != PAM_SUCCESS)
+           {
+             if (debug)
+               pam_syslog (pamh, LOG_DEBUG,
+                           "pam_get_item (PAM_AUTHTOK) failed, return %d",
+                           retval);
+             return retval;
+           }
+         else if (void_pass == NULL)
+           {
+             char *resp = NULL;
+
+             retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF,
+                                  &resp, _("Password: "));
+
+             if (retval != PAM_SUCCESS)
+               {
+                 _pam_drop (resp);
+                 if (retval == PAM_CONV_AGAIN)
+                   retval = PAM_INCOMPLETE;
+                 return retval;
+               }
+
+             pam_set_item (pamh, PAM_AUTHTOK, resp);
+             authtok = strdupa (resp);
+             _pam_drop (resp);
+           }
+         else
+           authtok = void_pass;
+
+         if (pipe(fds) != 0)
+           {
+             pam_syslog (pamh, LOG_ERR, "Could not create pipe: %m");
+             return PAM_SYSTEM_ERR;
+           }
+       }
+    }
 
   if (optargc >= argc) {
     pam_syslog (pamh, LOG_ERR, "No path given as argument");
@@ -118,6 +177,27 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
       int status = 0;
       pid_t retval;
 
+      if (expose_authtok) /* send the password to the child */
+       {
+         if (authtok != NULL)
+           {            /* send the password to the child */
+             if (debug)
+               pam_syslog (pamh, LOG_DEBUG, "send password to child");
+             if (write(fds[1], authtok, strlen(authtok)+1) == -1)
+               pam_syslog (pamh, LOG_ERR,
+                           "sending password to child failed: %m");
+             authtok = NULL;
+           }
+         else
+           {
+             if (write(fds[1], "", 1) == -1)   /* blank password */
+               pam_syslog (pamh, LOG_ERR,
+                           "sending password to child failed: %m");
+           }
+        close(fds[0]);       /* close here to avoid possible SIGPIPE above */
+        close(fds[1]);
+       }
+
       while ((retval = waitpid (pid, &status, 0)) == -1 &&
             errno == EINTR);
       if (retval == (pid_t)-1)
@@ -163,17 +243,38 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
       int i;
       char **envlist, **tmp;
       int envlen, nitems;
+      char *envstr;
 
-      for (i = 0; i < sysconf (_SC_OPEN_MAX); i++)
-       close (i);
+      if (expose_authtok)
+       {
+         /* reopen stdin as pipe */
+         if (dup2(fds[0], STDIN_FILENO) == -1)
+           {
+             int err = errno;
+             pam_syslog (pamh, LOG_ERR, "dup2 of STDIN failed: %m");
+             exit (err);
+           }
 
-      /* New stdin.  */
-      if ((i = open ("/dev/null", O_RDWR)) < 0)
+         for (i = 0; i < sysconf (_SC_OPEN_MAX); i++)
+           {
+             if (i != STDIN_FILENO)
+               close (i);
+           }
+       }
+      else
        {
-         int err = errno;
-         pam_syslog (pamh, LOG_ERR, "open of /dev/null failed: %m");
-         exit (err);
+         for (i = 0; i < sysconf (_SC_OPEN_MAX); i++)
+           close (i);
+
+         /* New stdin.  */
+         if ((i = open ("/dev/null", O_RDWR)) < 0)
+           {
+             int err = errno;
+             pam_syslog (pamh, LOG_ERR, "open of /dev/null failed: %m");
+             exit (err);
+           }
        }
+
       /* New stdout and stderr.  */
       if (logfile)
        {
@@ -195,18 +296,22 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
            }
        }
       else
-       if (dup (i) == -1)
-         {
-           int err = errno;
-           pam_syslog (pamh, LOG_ERR, "dup failed: %m");
-           exit (err);
-         }
+       {
+         /* New stdout/stderr.  */
+         if ((i = open ("/dev/null", O_RDWR)) < 0)
+           {
+             int err = errno;
+             pam_syslog (pamh, LOG_ERR, "open of /dev/null failed: %m");
+             exit (err);
+           }
+       }
+
       if (dup (i) == -1)
-        {
+       {
          int err = errno;
          pam_syslog (pamh, LOG_ERR, "dup failed: %m");
-          exit (err);
-        }
+         exit (err);
+       }
 
       if (call_setuid)
        if (setuid (geteuid ()) == -1)
@@ -240,7 +345,8 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
       for (envlen = 0; envlist[envlen] != NULL; ++envlen)
         /* nothing */ ;
       nitems = sizeof(env_items) / sizeof(*env_items);
-      tmp = realloc(envlist, (envlen + nitems + 1) * sizeof(*envlist));
+      /* + 2 because of PAM_TYPE and NULL entry */
+      tmp = realloc(envlist, (envlen + nitems + 2) * sizeof(*envlist));
       if (tmp == NULL)
       {
         free(envlist);
@@ -251,7 +357,6 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
       for (i = 0; i < nitems; ++i)
       {
         const void *item;
-        char *envstr;
 
         if (pam_get_item(pamh, env_items[i].item, &item) != PAM_SUCCESS || item == NULL)
           continue;
@@ -265,6 +370,15 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
         envlist[envlen] = NULL;
       }
 
+      if (asprintf(&envstr, "PAM_TYPE=%s", pam_type) < 0)
+        {
+          free(envlist);
+          pam_syslog (pamh, LOG_ERR, "prepare environment failed: %m");
+          exit (ENOMEM);
+        }
+      envlist[envlen++] = envstr;
+      envlist[envlen] = NULL;
+
       if (debug)
        pam_syslog (pamh, LOG_DEBUG, "Calling %s ...", arggv[0]);
 
@@ -286,7 +400,7 @@ PAM_EXTERN int
 pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
                     int argc, const char **argv)
 {
-  return call_exec (pamh, argc, argv);
+  return call_exec ("auth", pamh, argc, argv);
 }
 
 PAM_EXTERN int
@@ -304,28 +418,28 @@ pam_sm_chauthtok(pam_handle_t *pamh, int flags,
 {
   if (flags & PAM_PRELIM_CHECK)
     return PAM_SUCCESS;
-  return call_exec (pamh, argc, argv);
+  return call_exec ("password", pamh, argc, argv);
 }
 
 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);
+  return call_exec ("account", pamh, argc, argv);
 }
 
 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);
+  return call_exec ("open_session", pamh, argc, argv);
 }
 
 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);
+  return call_exec ("close_session", pamh, argc, argv);
 }
 
 #ifdef PAM_STATIC