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.c44
1 files changed, 32 insertions, 12 deletions
diff --git a/modules/pam_exec/pam_exec.c b/modules/pam_exec/pam_exec.c
index 05dec167..9d2145dc 100644
--- a/modules/pam_exec/pam_exec.c
+++ b/modules/pam_exec/pam_exec.c
@@ -48,6 +48,7 @@
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <signal.h>
#include <security/pam_modules.h>
#include <security/pam_modutil.h>
@@ -105,6 +106,7 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
FILE *stdout_file = NULL;
int retval;
const char *name;
+ struct sigaction newsa, oldsa;
if (argc < 1) {
pam_syslog (pamh, LOG_ERR,
@@ -182,6 +184,7 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
if (retval != PAM_SUCCESS)
{
+ pam_overwrite_string (resp);
_pam_drop (resp);
if (retval == PAM_CONV_AGAIN)
retval = PAM_INCOMPLETE;
@@ -192,6 +195,7 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
{
pam_set_item (pamh, PAM_AUTHTOK, resp);
strncpy (authtok, resp, sizeof(authtok) - 1);
+ pam_overwrite_string (resp);
_pam_drop (resp);
}
}
@@ -200,6 +204,7 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
if (pipe(fds) != 0)
{
+ pam_overwrite_array(authtok);
pam_syslog (pamh, LOG_ERR, "Could not create pipe: %m");
return PAM_SYSTEM_ERR;
}
@@ -210,25 +215,38 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
{
if (pipe(stdout_fds) != 0)
{
+ pam_overwrite_array(authtok);
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_overwrite_array(authtok);
pam_syslog (pamh, LOG_ERR, "Could not fdopen pipe: %m");
return PAM_SYSTEM_ERR;
}
}
if (optargc >= argc) {
+ pam_overwrite_array(authtok);
pam_syslog (pamh, LOG_ERR, "No path given as argument");
return PAM_SERVICE_ERR;
}
+ memset(&newsa, '\0', sizeof(newsa));
+ newsa.sa_handler = SIG_DFL;
+ if (sigaction(SIGCHLD, &newsa, &oldsa) == -1) {
+ pam_overwrite_array(authtok);
+ pam_syslog(pamh, LOG_ERR, "failed to reset SIGCHLD handler: %m");
+ return PAM_SYSTEM_ERR;
+ }
+
pid = fork();
- if (pid == -1)
+ if (pid == -1) {
+ pam_overwrite_array(authtok);
return PAM_SYSTEM_ERR;
+ }
if (pid > 0) /* parent */
{
int status = 0;
@@ -246,6 +264,8 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
close(fds[1]);
}
+ pam_overwrite_array(authtok);
+
if (use_stdout)
{
char buf[4096];
@@ -263,6 +283,7 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
while ((rc = waitpid (pid, &status, 0)) == -1 &&
errno == EINTR);
+ sigaction(SIGCHLD, &oldsa, NULL); /* restore old signal handler */
if (rc == (pid_t)-1)
{
pam_syslog (pamh, LOG_ERR, "waitpid returns with -1: %m");
@@ -305,9 +326,9 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
}
else /* child */
{
- char **arggv;
+ const char **arggv;
int i;
- char **envlist, **tmp;
+ char **envlist;
int envlen, nitems;
char *envstr;
enum pam_modutil_redirect_fd redirect_stdin =
@@ -315,6 +336,8 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
enum pam_modutil_redirect_fd redirect_stdout =
(use_stdout || logfile) ? PAM_MODUTIL_IGNORE_FD : PAM_MODUTIL_NULL_FD;
+ pam_overwrite_array(authtok);
+
/* First, move all the pipes off of stdin, stdout, and stderr, to ensure
* that calls to dup2 won't close them. */
@@ -418,7 +441,7 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
_exit (ENOMEM);
for (i = 0; i < (argc - optargc); i++)
- arggv[i] = strdup(argv[i+optargc]);
+ arggv[i] = argv[i+optargc];
arggv[i] = NULL;
/*
@@ -430,14 +453,12 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
/* nothing */ ;
nitems = PAM_ARRAY_SIZE(env_items);
/* + 2 because of PAM_TYPE and NULL entry */
- tmp = realloc(envlist, (envlen + nitems + 2) * sizeof(*envlist));
- if (tmp == NULL)
+ envlist = realloc(envlist, (envlen + nitems + 2) * sizeof(*envlist));
+ if (envlist == NULL)
{
- free(envlist);
pam_syslog (pamh, LOG_CRIT, "realloc environment failed: %m");
_exit (ENOMEM);
}
- envlist = tmp;
for (i = 0; i < nitems; ++i)
{
const void *item;
@@ -446,7 +467,6 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
continue;
if (asprintf(&envstr, "%s=%s", env_items[i].name, (const char *)item) < 0)
{
- free(envlist);
pam_syslog (pamh, LOG_CRIT, "prepare environment failed: %m");
_exit (ENOMEM);
}
@@ -456,7 +476,6 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
if (asprintf(&envstr, "PAM_TYPE=%s", pam_type) < 0)
{
- free(envlist);
pam_syslog (pamh, LOG_CRIT, "prepare environment failed: %m");
_exit (ENOMEM);
}
@@ -466,10 +485,11 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
if (debug)
pam_syslog (pamh, LOG_DEBUG, "Calling %s ...", arggv[0]);
- execve (arggv[0], arggv, envlist);
+ DIAG_PUSH_IGNORE_CAST_QUAL;
+ execve (arggv[0], (char **) arggv, envlist);
+ DIAG_POP_IGNORE_CAST_QUAL;
i = errno;
pam_syslog (pamh, LOG_ERR, "execve(%s,...) failed: %m", arggv[0]);
- free(envlist);
_exit (i);
}
return PAM_SYSTEM_ERR; /* will never be reached. */