summaryrefslogtreecommitdiff
path: root/modules/pam_exec/pam_exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_exec/pam_exec.c')
-rw-r--r--modules/pam_exec/pam_exec.c195
1 files changed, 152 insertions, 43 deletions
diff --git a/modules/pam_exec/pam_exec.c b/modules/pam_exec/pam_exec.c
index 14dddd54..7b2e402c 100644
--- a/modules/pam_exec/pam_exec.c
+++ b/modules/pam_exec/pam_exec.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Thorsten Kukuk <kukuk@thkukuk.de>
+ * Copyright (c) 2006, 2008 Thorsten Kukuk <kukuk@thkukuk.de>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -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");
@@ -117,6 +176,28 @@ 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)
@@ -160,17 +241,40 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
{
char **arggv;
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)
{
@@ -183,7 +287,7 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
int err = errno;
pam_syslog (pamh, LOG_ERR, "open of %s failed: %m",
logfile);
- exit (err);
+ _exit (err);
}
if (asprintf (&buffer, "*** %s", ctime (&tm)) > 0)
{
@@ -192,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)
@@ -211,27 +319,24 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
int err = errno;
pam_syslog (pamh, LOG_ERR, "setuid(%lu) failed: %m",
(unsigned long) geteuid ());
- exit (err);
+ _exit (err);
}
if (setsid () == -1)
{
int err = errno;
pam_syslog (pamh, LOG_ERR, "setsid failed: %m");
- exit (err);
+ _exit (err);
}
arggv = calloc (argc + 4, sizeof (char *));
if (arggv == NULL)
- exit (ENOMEM);
+ _exit (ENOMEM);
for (i = 0; i < (argc - optargc); i++)
arggv[i] = strdup(argv[i+optargc]);
arggv[i] = NULL;
- char **envlist, **tmp;
- int envlen, nitems;
-
/*
* Set up the child's environment list. It consists of the PAM
* environment, plus a few hand-picked PAM items.
@@ -240,18 +345,18 @@ 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);
pam_syslog (pamh, LOG_ERR, "realloc environment failed: %m");
- exit (ENOMEM);
+ _exit (ENOMEM);
}
envlist = tmp;
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;
@@ -259,25 +364,29 @@ call_exec (pam_handle_t *pamh, int argc, const char **argv)
{
free(envlist);
pam_syslog (pamh, LOG_ERR, "prepare environment failed: %m");
- exit (ENOMEM);
+ _exit (ENOMEM);
}
envlist[envlen++] = envstr;
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]);
- if (execve (arggv[0], arggv, envlist) == -1)
- {
- int err = errno;
- pam_syslog (pamh, LOG_ERR, "execve(%s,...) failed: %m",
- arggv[0]);
- free(envlist);
- exit (err);
- }
+ execve (arggv[0], arggv, envlist);
+ i = errno;
+ pam_syslog (pamh, LOG_ERR, "execve(%s,...) failed: %m", arggv[0]);
free(envlist);
- exit (1); /* should never be reached. */
+ _exit (i);
}
return PAM_SYSTEM_ERR; /* will never be reached. */
}
@@ -286,7 +395,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 +413,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