diff options
author | Thorsten Kukuk <kukuk@thkukuk.de> | 2013-09-04 16:40:37 +0200 |
---|---|---|
committer | Thorsten Kukuk <kukuk@thkukuk.de> | 2013-09-04 16:40:37 +0200 |
commit | fbd7a2c8e9e3e7b10ba408b28f286cbdeccc5691 (patch) | |
tree | 468db0169bbbd1682700564fc097752fe9238473 /modules | |
parent | f11cd89316cc051e23ef080aee5c7d823c6dfce2 (diff) | |
download | pam-fbd7a2c8e9e3e7b10ba408b28f286cbdeccc5691.tar.gz pam-fbd7a2c8e9e3e7b10ba408b28f286cbdeccc5691.tar.bz2 pam-fbd7a2c8e9e3e7b10ba408b28f286cbdeccc5691.zip |
Extend pam_exec by stdout and type= options (ticket #8):
* modules/pam_exec/pam_exec.c: Add stdout and type= option
* modules/pam_exec/pam_exec.8.xml: Document new options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/pam_exec/pam_exec.8.xml | 34 | ||||
-rw-r--r-- | modules/pam_exec/pam_exec.c | 108 |
2 files changed, 127 insertions, 15 deletions
diff --git a/modules/pam_exec/pam_exec.8.xml b/modules/pam_exec/pam_exec.8.xml index 4dc2a19d..23793668 100644 --- a/modules/pam_exec/pam_exec.8.xml +++ b/modules/pam_exec/pam_exec.8.xml @@ -31,8 +31,14 @@ quiet </arg> <arg choice="opt"> + stdout + </arg> + <arg choice="opt"> log=<replaceable>file</replaceable> </arg> + <arg choice="opt"> + type=<replaceable>type</replaceable> + </arg> <arg choice="plain"> <replaceable>command</replaceable> </arg> @@ -119,6 +125,28 @@ <varlistentry> <term> + <option>type=<replaceable>type</replaceable></option> + </term> + <listitem> + <para> + Only run the command if the module type matches the given type. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> + <option>stdout</option> + </term> + <listitem> + <para> + Per default the output of the executed command is written to <filename>/dev/null</filename>. With this option, the stdout output of the executed command is redirected to the calling application. It's in the responsibility of this application what happens with the output. The <option>log</option> option is ignored. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> <option>quiet</option> </term> <listitem> @@ -194,7 +222,8 @@ <listitem> <para> <function>pam_setcred</function> was called, which - does not execute the command. + does not execute the command. Or, the value given for the type= + parameter did not match the module type. </para> </listitem> </varlistentry> @@ -236,7 +265,8 @@ <refsect1 id='pam_exec-author'> <title>AUTHOR</title> <para> - pam_exec was written by Thorsten Kukuk <kukuk@thkukuk.de>. + pam_exec was written by Thorsten Kukuk <kukuk@thkukuk.de> and + Josh Triplett <josh@joshtriplett.org>. </para> </refsect1> diff --git a/modules/pam_exec/pam_exec.c b/modules/pam_exec/pam_exec.c index 8b37e95e..b56e4b26 100644 --- a/modules/pam_exec/pam_exec.c +++ b/modules/pam_exec/pam_exec.c @@ -72,6 +72,24 @@ static struct { ENV_ITEM(PAM_RUSER), }; +/* move_fd_to_non_stdio copies the given file descriptor to something other + * than stdin, stdout, or stderr. Assumes that the caller will close all + * unwanted fds after calling. */ +static int +move_fd_to_non_stdio (pam_handle_t *pamh, int fd) +{ + while (fd < 3) + { + fd = dup(fd); + if (fd == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "dup failed: %m"); + _exit (err); + } + } + return fd; +} static int call_exec (const char *pam_type, pam_handle_t *pamh, @@ -81,11 +99,14 @@ call_exec (const char *pam_type, pam_handle_t *pamh, int call_setuid = 0; int quiet = 0; int expose_authtok = 0; + int use_stdout = 0; int optargc; const char *logfile = NULL; const char *authtok = NULL; pid_t pid; int fds[2]; + int stdout_fds[2]; + FILE *stdout_file = NULL; if (argc < 1) { pam_syslog (pamh, LOG_ERR, @@ -100,8 +121,15 @@ call_exec (const char *pam_type, pam_handle_t *pamh, if (strcasecmp (argv[optargc], "debug") == 0) debug = 1; + else if (strcasecmp (argv[optargc], "stdout") == 0) + use_stdout = 1; else if (strncasecmp (argv[optargc], "log=", 4) == 0) logfile = &argv[optargc][4]; + else if (strncasecmp (argv[optargc], "type=", 5) == 0) + { + if (strcmp (pam_type, &argv[optargc][5]) != 0) + return PAM_IGNORE; + } else if (strcasecmp (argv[optargc], "seteuid") == 0) call_setuid = 1; else if (strcasecmp (argv[optargc], "quiet") == 0) @@ -164,6 +192,21 @@ call_exec (const char *pam_type, pam_handle_t *pamh, } } + if (use_stdout) + { + if (pipe(stdout_fds) != 0) + { + pam_syslog (pamh, LOG_ERR, "Could not create pipe: %m"); + return PAM_SYSTEM_ERR; + } + stdout_file = fdopen(stdout_fds[0], "r"); + if (!stdout_file) + { + pam_syslog (pamh, LOG_ERR, "Could not fdopen pipe: %m"); + return PAM_SYSTEM_ERR; + } + } + if (optargc >= argc) { pam_syslog (pamh, LOG_ERR, "No path given as argument"); return PAM_SERVICE_ERR; @@ -198,6 +241,21 @@ call_exec (const char *pam_type, pam_handle_t *pamh, close(fds[1]); } + if (use_stdout) + { + char buf[4096]; + close(stdout_fds[1]); + while (fgets(buf, sizeof(buf), stdout_file) != NULL) + { + size_t len; + len = strlen(buf); + if (buf[len-1] == '\n') + buf[len-1] = '\0'; + pam_info(pamh, "%s", buf); + } + fclose(stdout_file); + } + while ((retval = waitpid (pid, &status, 0)) == -1 && errno == EINTR); if (retval == (pid_t)-1) @@ -245,6 +303,23 @@ call_exec (const char *pam_type, pam_handle_t *pamh, int envlen, nitems; char *envstr; + /* First, move all the pipes off of stdin, stdout, and stderr, to ensure + * that calls to dup2 won't close them. */ + + if (expose_authtok) + { + fds[0] = move_fd_to_non_stdio(pamh, fds[0]); + close(fds[1]); + } + + if (use_stdout) + { + stdout_fds[1] = move_fd_to_non_stdio(pamh, stdout_fds[1]); + close(stdout_fds[0]); + } + + /* Set up stdin. */ + if (expose_authtok) { /* reopen stdin as pipe */ @@ -254,17 +329,10 @@ call_exec (const char *pam_type, pam_handle_t *pamh, pam_syslog (pamh, LOG_ERR, "dup2 of STDIN failed: %m"); _exit (err); } - - for (i = 0; i < sysconf (_SC_OPEN_MAX); i++) - { - if (i != STDIN_FILENO) - close (i); - } } else { - for (i = 0; i < sysconf (_SC_OPEN_MAX); i++) - close (i); + close (STDIN_FILENO); /* New stdin. */ if ((i = open ("/dev/null", O_RDWR)) < 0) @@ -275,12 +343,23 @@ call_exec (const char *pam_type, pam_handle_t *pamh, } } - /* New stdout and stderr. */ - if (logfile) + /* Set up stdout. */ + + if (use_stdout) + { + if (dup2(stdout_fds[1], STDOUT_FILENO) == -1) + { + int err = errno; + pam_syslog (pamh, LOG_ERR, "dup2 to stdout failed: %m"); + _exit (err); + } + } + else if (logfile) { time_t tm = time (NULL); char *buffer = NULL; + close (STDOUT_FILENO); if ((i = open (logfile, O_CREAT|O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) { @@ -297,7 +376,7 @@ call_exec (const char *pam_type, pam_handle_t *pamh, } else { - /* New stdout/stderr. */ + close (STDOUT_FILENO); if ((i = open ("/dev/null", O_RDWR)) < 0) { int err = errno; @@ -306,13 +385,16 @@ call_exec (const char *pam_type, pam_handle_t *pamh, } } - if (dup (i) == -1) + if (dup2 (STDOUT_FILENO, STDERR_FILENO) == -1) { int err = errno; - pam_syslog (pamh, LOG_ERR, "dup failed: %m"); + pam_syslog (pamh, LOG_ERR, "dup2 failed: %m"); _exit (err); } + for (i = 3; i < sysconf (_SC_OPEN_MAX); i++) + close (i); + if (call_setuid) if (setuid (geteuid ()) == -1) { |