summaryrefslogtreecommitdiff
path: root/modules/pam_exec/pam_exec.c
diff options
context:
space:
mode:
authorThorsten Kukuk <kukuk@thkukuk.de>2013-09-04 16:40:37 +0200
committerThorsten Kukuk <kukuk@thkukuk.de>2013-09-04 16:40:37 +0200
commitfbd7a2c8e9e3e7b10ba408b28f286cbdeccc5691 (patch)
tree468db0169bbbd1682700564fc097752fe9238473 /modules/pam_exec/pam_exec.c
parentf11cd89316cc051e23ef080aee5c7d823c6dfce2 (diff)
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/pam_exec/pam_exec.c')
-rw-r--r--modules/pam_exec/pam_exec.c108
1 files changed, 95 insertions, 13 deletions
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)
{