Skip to content

Commit

Permalink
Add support for Linux-PAM's badly named expose_authtok option.
Browse files Browse the repository at this point in the history
Submitted by:	Thomas Munro <munro@ip9.org>
MFC after:	1 week
Differential Revision:	D16171
  • Loading branch information
dag-erling committed Aug 14, 2018
1 parent fda8dcf commit 90f37b3
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 9 deletions.
5 changes: 4 additions & 1 deletion lib/libpam/modules/pam_exec/pam_exec.8
@@ -1,5 +1,6 @@
.\" Copyright (c) 2001,2003 Networks Associates Technology, Inc.
.\" Copyright (c) 2017 Dag-Erling Smørgrav
.\" Copyright (c) 2018 Thomas Munro
.\" All rights reserved.
.\"
.\" Portions of this software were developed for the FreeBSD Project by
Expand Down Expand Up @@ -33,7 +34,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd March 22, 2017
.Dd August 14, 2018
.Dt PAM_EXEC 8
.Os
.Sh NAME
Expand Down Expand Up @@ -72,6 +73,8 @@ Ignored for compatibility reasons.
.It Cm return_prog_exit_status
Use the program exit status as the return code of the pam_sm_* function.
It must be a valid return value for this function.
.It Cm expose_authtok
Write the authentication token to the program's standard input stream.
.It Cm --
Stop options parsing;
program and its arguments follow.
Expand Down
81 changes: 73 additions & 8 deletions lib/libpam/modules/pam_exec/pam_exec.c
Expand Up @@ -3,6 +3,7 @@
*
* Copyright (c) 2001,2003 Networks Associates Technology, Inc.
* Copyright (c) 2017 Dag-Erling Smørgrav
* Copyright (c) 2018 Thomas Munro
* All rights reserved.
*
* This software was developed for the FreeBSD Project by ThinkSec AS and
Expand Down Expand Up @@ -108,6 +109,7 @@ struct pe_opts {
int return_prog_exit_status;
int capture_stdout;
int capture_stderr;
int expose_authtok;
};

static int
Expand Down Expand Up @@ -135,6 +137,8 @@ parse_options(const char *func, int *argc, const char **argv[],
options->capture_stderr = 1;
} else if (strcmp((*argv)[i], "return_prog_exit_status") == 0) {
options->return_prog_exit_status = 1;
} else if (strcmp((*argv)[i], "expose_authtok") == 0) {
options->expose_authtok = 1;
} else {
if (strcmp((*argv)[i], "--") == 0) {
(*argc)--;
Expand All @@ -158,19 +162,22 @@ _pam_exec(pam_handle_t *pamh,
struct pe_opts *options)
{
char buf[PAM_MAX_MSG_SIZE];
struct pollfd pfd[3];
struct pollfd pfd[4];
const void *item;
char **envlist, *envstr, *resp, **tmp;
ssize_t rlen;
ssize_t rlen, wlen;
int envlen, extralen, i;
int pam_err, serrno, status;
int chout[2], cherr[2], pd;
nfds_t nfds;
int chin[2], chout[2], cherr[2], pd;
nfds_t nfds, nreadfds;
pid_t pid;
const char *authtok;
size_t authtok_size;
int rc;

pd = -1;
pid = 0;
chout[0] = chout[1] = cherr[0] = cherr[1] = -1;
chin[0] = chin[1] = chout[0] = chout[1] = cherr[0] = cherr[1] = -1;
envlist = NULL;

#define OUT(ret) do { pam_err = (ret); goto out; } while (0)
Expand Down Expand Up @@ -235,6 +242,25 @@ _pam_exec(pam_handle_t *pamh,
openpam_log(PAM_LOG_DEBUG, "envlen = %d extralen = %d envlist = %p",
envlen, extralen, envlist);

/* set up pipe and get authtok if requested */
if (options->expose_authtok) {
if (pipe(chin) != 0) {
openpam_log(PAM_LOG_ERROR, "%s: pipe(): %m", func);
OUT(PAM_SYSTEM_ERR);
}
if (fcntl(chin[1], F_SETFL, O_NONBLOCK)) {
openpam_log(PAM_LOG_ERROR, "%s: fcntl(): %m", func);
OUT(PAM_SYSTEM_ERR);
}
rc = pam_get_authtok(pamh, PAM_AUTHTOK, &authtok, NULL);
if (rc == PAM_SUCCESS) {
authtok_size = strlen(authtok);
} else {
openpam_log(PAM_LOG_ERROR, "%s: pam_get_authtok(): %s", func,
pam_strerror(pamh, rc));
OUT(PAM_SYSTEM_ERR);
}
}
/* set up pipes if capture was requested */
if (options->capture_stdout) {
if (pipe(chout) != 0) {
Expand Down Expand Up @@ -269,9 +295,13 @@ _pam_exec(pam_handle_t *pamh,

if ((pid = pdfork(&pd, 0)) == 0) {
/* child */
if ((chout[0] >= 0 && close(chout[0]) != 0) ||
if ((chin[1] >= 0 && close(chin[1]) != 0) ||
(chout[0] >= 0 && close(chout[0]) != 0) ||
(cherr[0] >= 0 && close(cherr[0]) != 0)) {
openpam_log(PAM_LOG_ERROR, "%s: close(): %m", func);
} else if (chin[0] >= 0 &&
dup2(chin[0], STDIN_FILENO) != STDIN_FILENO) {
openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
} else if (dup2(chout[1], STDOUT_FILENO) != STDOUT_FILENO ||
dup2(cherr[1], STDERR_FILENO) != STDERR_FILENO) {
openpam_log(PAM_LOG_ERROR, "%s: dup2(): %m", func);
Expand All @@ -288,7 +318,9 @@ _pam_exec(pam_handle_t *pamh,
openpam_log(PAM_LOG_ERROR, "%s: pdfork(): %m", func);
OUT(PAM_SYSTEM_ERR);
}
/* use poll() to watch the process and stdout / stderr */
/* use poll() to watch the process and stdin / stdout / stderr */
if (chin[0] >= 0)
close(chin[0]);
if (chout[1] >= 0)
close(chout[1]);
if (cherr[1] >= 0)
Expand All @@ -297,15 +329,23 @@ _pam_exec(pam_handle_t *pamh,
pfd[0].fd = pd;
pfd[0].events = POLLHUP;
nfds = 1;
nreadfds = 0;
if (options->capture_stdout) {
pfd[nfds].fd = chout[0];
pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
nfds++;
nreadfds++;
}
if (options->capture_stderr) {
pfd[nfds].fd = cherr[0];
pfd[nfds].events = POLLIN|POLLERR|POLLHUP;
nfds++;
nreadfds++;
}
if (options->expose_authtok) {
pfd[nfds].fd = chin[1];
pfd[nfds].events = POLLOUT|POLLERR|POLLHUP;
nfds++;
}

/* loop until the process exits */
Expand All @@ -314,7 +354,8 @@ _pam_exec(pam_handle_t *pamh,
openpam_log(PAM_LOG_ERROR, "%s: poll(): %m", func);
OUT(PAM_SYSTEM_ERR);
}
for (i = 1; i < nfds; ++i) {
/* are the stderr / stdout pipes ready for reading? */
for (i = 1; i < 1 + nreadfds; ++i) {
if ((pfd[i].revents & POLLIN) == 0)
continue;
if ((rlen = read(pfd[i].fd, buf, sizeof(buf) - 1)) < 0) {
Expand All @@ -328,6 +369,26 @@ _pam_exec(pam_handle_t *pamh,
(void)pam_prompt(pamh, pfd[i].fd == chout[0] ?
PAM_TEXT_INFO : PAM_ERROR_MSG, &resp, "%s", buf);
}
/* is the stdin pipe ready for writing? */
if (options->expose_authtok && authtok_size > 0 &&
(pfd[nfds - 1].revents & POLLOUT) != 0) {
if ((wlen = write(chin[1], authtok, authtok_size)) < 0) {
if (errno == EAGAIN)
continue;
openpam_log(PAM_LOG_ERROR, "%s: write(): %m",
func);
OUT(PAM_SYSTEM_ERR);
} else {
authtok += wlen;
authtok_size -= wlen;
if (authtok_size == 0) {
/* finished writing; close and forget the pipe */
close(chin[1]);
chin[1] = -1;
nfds--;
}
}
}
} while (pfd[0].revents == 0);

/* the child process has exited */
Expand Down Expand Up @@ -364,6 +425,10 @@ _pam_exec(pam_handle_t *pamh,
serrno = errno;
if (pd >= 0)
close(pd);
if (chin[0] >= 0)
close(chin[0]);
if (chin[1] >= 0)
close(chin[1]);
if (chout[0] >= 0)
close(chout[0]);
if (chout[1] >= 0)
Expand Down

0 comments on commit 90f37b3

Please sign in to comment.