summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2014-01-24 15:32:08 +0000
committerDmitry V. Levin <ldv@altlinux.org>2014-01-27 15:42:11 +0000
commitb0ec5d1e472a0cd74972bfe9575dcf6a3d0cad1c (patch)
treefe7f03043c1a60bfe982936eae981667c3bb27dc /modules
parent47db675c910a065fa9602753a904b050b0322f29 (diff)
Introduce pam_modutil_sanitize_helper_fds
This change introduces pam_modutil_sanitize_helper_fds - a new function that redirects standard descriptors and closes all other descriptors. pam_modutil_sanitize_helper_fds supports three types of input and output redirection: - PAM_MODUTIL_IGNORE_FD: do not redirect at all. - PAM_MODUTIL_PIPE_FD: redirect to a pipe. For stdin, it is implemented by creating a pipe, closing its write end, and redirecting stdin to its read end. Likewise, for stdout/stderr it is implemented by creating a pipe, closing its read end, and redirecting to its write end. Unlike stdin redirection, stdout/stderr redirection to a pipe has a side effect that a process writing to such descriptor should be prepared to handle SIGPIPE appropriately. - PAM_MODUTIL_NULL_FD: redirect to /dev/null. For stdin, it is implemented via PAM_MODUTIL_PIPE_FD because there is no functional difference. For stdout/stderr, it is classic redirection to /dev/null. PAM_MODUTIL_PIPE_FD is usually more suitable due to linux kernel security restrictions, but when the helper process might be writing to the corresponding descriptor and termination of the helper process by SIGPIPE is not desirable, one should choose PAM_MODUTIL_NULL_FD. * libpam/pam_modutil_sanitize.c: New file. * libpam/Makefile.am (libpam_la_SOURCES): Add it. * libpam/include/security/pam_modutil.h (pam_modutil_redirect_fd, pam_modutil_sanitize_helper_fds): New declarations. * libpam/libpam.map (LIBPAM_MODUTIL_1.1.9): New interface. * modules/pam_exec/pam_exec.c (call_exec): Use pam_modutil_sanitize_helper_fds. * modules/pam_mkhomedir/pam_mkhomedir.c (create_homedir): Likewise. * modules/pam_unix/pam_unix_acct.c (_unix_run_verify_binary): Likewise. * modules/pam_unix/pam_unix_passwd.c (_unix_run_update_binary): Likewise. * modules/pam_unix/support.c (_unix_run_helper_binary): Likewise. * modules/pam_xauth/pam_xauth.c (run_coprocess): Likewise. * modules/pam_unix/support.h (MAX_FD_NO): Remove.
Diffstat (limited to 'modules')
-rw-r--r--modules/pam_exec/pam_exec.c34
-rw-r--r--modules/pam_mkhomedir/pam_mkhomedir.c15
-rw-r--r--modules/pam_unix/pam_unix_acct.c23
-rw-r--r--modules/pam_unix/pam_unix_passwd.c20
-rw-r--r--modules/pam_unix/support.c20
-rw-r--r--modules/pam_unix/support.h2
-rw-r--r--modules/pam_xauth/pam_xauth.c26
7 files changed, 57 insertions, 83 deletions
diff --git a/modules/pam_exec/pam_exec.c b/modules/pam_exec/pam_exec.c
index b56e4b26..12c44444 100644
--- a/modules/pam_exec/pam_exec.c
+++ b/modules/pam_exec/pam_exec.c
@@ -302,6 +302,10 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
char **envlist, **tmp;
int envlen, nitems;
char *envstr;
+ enum pam_modutil_redirect_fd redirect_stdin =
+ expose_authtok ? PAM_MODUTIL_IGNORE_FD : PAM_MODUTIL_PIPE_FD;
+ enum pam_modutil_redirect_fd redirect_stdout =
+ (use_stdout || logfile) ? PAM_MODUTIL_IGNORE_FD : PAM_MODUTIL_NULL_FD;
/* First, move all the pipes off of stdin, stdout, and stderr, to ensure
* that calls to dup2 won't close them. */
@@ -330,18 +334,6 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
_exit (err);
}
}
- else
- {
- close (STDIN_FILENO);
-
- /* 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);
- }
- }
/* Set up stdout. */
@@ -374,26 +366,18 @@ call_exec (const char *pam_type, pam_handle_t *pamh,
free (buffer);
}
}
- else
- {
- close (STDOUT_FILENO);
- 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 (dup2 (STDOUT_FILENO, STDERR_FILENO) == -1)
+ if ((use_stdout || logfile) &&
+ dup2 (STDOUT_FILENO, STDERR_FILENO) == -1)
{
int err = errno;
pam_syslog (pamh, LOG_ERR, "dup2 failed: %m");
_exit (err);
}
- for (i = 3; i < sysconf (_SC_OPEN_MAX); i++)
- close (i);
+ if (pam_modutil_sanitize_helper_fds(pamh, redirect_stdin,
+ redirect_stdout, redirect_stdout) < 0)
+ _exit(1);
if (call_setuid)
if (setuid (geteuid ()) == -1)
diff --git a/modules/pam_mkhomedir/pam_mkhomedir.c b/modules/pam_mkhomedir/pam_mkhomedir.c
index a867a738..c9220897 100644
--- a/modules/pam_mkhomedir/pam_mkhomedir.c
+++ b/modules/pam_mkhomedir/pam_mkhomedir.c
@@ -58,8 +58,6 @@
#include <security/pam_modutil.h>
#include <security/pam_ext.h>
-#define MAX_FD_NO 10000
-
/* argument parsing */
#define MKHOMEDIR_DEBUG 020 /* be verbose about things */
#define MKHOMEDIR_QUIET 040 /* keep quiet about things */
@@ -131,18 +129,13 @@ create_homedir (pam_handle_t *pamh, options_t *opt,
/* fork */
child = fork();
if (child == 0) {
- int i;
- struct rlimit rlim;
static char *envp[] = { NULL };
const char *args[] = { NULL, NULL, NULL, NULL, NULL };
- if (getrlimit(RLIMIT_NOFILE, &rlim)==0) {
- if (rlim.rlim_max >= MAX_FD_NO)
- rlim.rlim_max = MAX_FD_NO;
- for (i=0; i < (int)rlim.rlim_max; i++) {
- close(i);
- }
- }
+ if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_PIPE_FD,
+ PAM_MODUTIL_PIPE_FD,
+ PAM_MODUTIL_PIPE_FD) < 0)
+ _exit(PAM_SYSTEM_ERR);
/* exec the mkhomedir helper */
args[0] = MKHOMEDIR_HELPER;
diff --git a/modules/pam_unix/pam_unix_acct.c b/modules/pam_unix/pam_unix_acct.c
index dc505e73..27998451 100644
--- a/modules/pam_unix/pam_unix_acct.c
+++ b/modules/pam_unix/pam_unix_acct.c
@@ -98,24 +98,21 @@ int _unix_run_verify_binary(pam_handle_t *pamh, unsigned int ctrl,
/* fork */
child = fork();
if (child == 0) {
- int i=0;
- struct rlimit rlim;
static char *envp[] = { NULL };
const char *args[] = { NULL, NULL, NULL, NULL };
- /* reopen stdout as pipe */
- dup2(fds[1], STDOUT_FILENO);
-
/* XXX - should really tidy up PAM here too */
- if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
- if (rlim.rlim_max >= MAX_FD_NO)
- rlim.rlim_max = MAX_FD_NO;
- for (i=0; i < (int)rlim.rlim_max; i++) {
- if (i != STDOUT_FILENO) {
- close(i);
- }
- }
+ /* reopen stdout as pipe */
+ if (dup2(fds[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdout");
+ _exit(PAM_AUTHINFO_UNAVAIL);
+ }
+
+ if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_PIPE_FD,
+ PAM_MODUTIL_IGNORE_FD,
+ PAM_MODUTIL_PIPE_FD) < 0) {
+ _exit(PAM_AUTHINFO_UNAVAIL);
}
if (geteuid() == 0) {
diff --git a/modules/pam_unix/pam_unix_passwd.c b/modules/pam_unix/pam_unix_passwd.c
index 5f3a3db3..606071ea 100644
--- a/modules/pam_unix/pam_unix_passwd.c
+++ b/modules/pam_unix/pam_unix_passwd.c
@@ -201,8 +201,6 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const
/* fork */
child = fork();
if (child == 0) {
- int i=0;
- struct rlimit rlim;
static char *envp[] = { NULL };
const char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL };
char buffer[16];
@@ -210,15 +208,15 @@ static int _unix_run_update_binary(pam_handle_t *pamh, unsigned int ctrl, const
/* XXX - should really tidy up PAM here too */
/* reopen stdin as pipe */
- dup2(fds[0], STDIN_FILENO);
-
- if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
- if (rlim.rlim_max >= MAX_FD_NO)
- rlim.rlim_max = MAX_FD_NO;
- for (i=0; i < (int)rlim.rlim_max; i++) {
- if (i != STDIN_FILENO)
- close(i);
- }
+ if (dup2(fds[0], STDIN_FILENO) != STDIN_FILENO) {
+ pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdin");
+ _exit(PAM_AUTHINFO_UNAVAIL);
+ }
+
+ if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_IGNORE_FD,
+ PAM_MODUTIL_PIPE_FD,
+ PAM_MODUTIL_PIPE_FD) < 0) {
+ _exit(PAM_AUTHINFO_UNAVAIL);
}
/* exec binary helper */
diff --git a/modules/pam_unix/support.c b/modules/pam_unix/support.c
index 3a849c81..fdb45c20 100644
--- a/modules/pam_unix/support.c
+++ b/modules/pam_unix/support.c
@@ -564,23 +564,21 @@ static int _unix_run_helper_binary(pam_handle_t *pamh, const char *passwd,
/* fork */
child = fork();
if (child == 0) {
- int i=0;
- struct rlimit rlim;
static char *envp[] = { NULL };
const char *args[] = { NULL, NULL, NULL, NULL };
/* XXX - should really tidy up PAM here too */
/* reopen stdin as pipe */
- dup2(fds[0], STDIN_FILENO);
-
- if (getrlimit(RLIMIT_NOFILE,&rlim)==0) {
- if (rlim.rlim_max >= MAX_FD_NO)
- rlim.rlim_max = MAX_FD_NO;
- for (i=0; i < (int)rlim.rlim_max; i++) {
- if (i != STDIN_FILENO)
- close(i);
- }
+ if (dup2(fds[0], STDIN_FILENO) != STDIN_FILENO) {
+ pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdin");
+ _exit(PAM_AUTHINFO_UNAVAIL);
+ }
+
+ if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_IGNORE_FD,
+ PAM_MODUTIL_PIPE_FD,
+ PAM_MODUTIL_PIPE_FD) < 0) {
+ _exit(PAM_AUTHINFO_UNAVAIL);
}
if (geteuid() == 0) {
diff --git a/modules/pam_unix/support.h b/modules/pam_unix/support.h
index 6f5b2eb6..cd6ddb76 100644
--- a/modules/pam_unix/support.h
+++ b/modules/pam_unix/support.h
@@ -141,8 +141,6 @@ static const UNIX_Ctrls unix_args[UNIX_CTRLS_] =
#define UNIX_DEFAULTS (unix_args[UNIX__NONULL].flag)
-#define MAX_FD_NO 2000000
-
/* use this to free strings. ESPECIALLY password strings */
#define _pam_delete(xx) \
diff --git a/modules/pam_xauth/pam_xauth.c b/modules/pam_xauth/pam_xauth.c
index c7ce55ab..2be43513 100644
--- a/modules/pam_xauth/pam_xauth.c
+++ b/modules/pam_xauth/pam_xauth.c
@@ -128,7 +128,6 @@ run_coprocess(pam_handle_t *pamh, const char *input, char **output,
/* We're the child. */
size_t j;
const char *args[10];
- int maxopened;
/* Drop privileges. */
if (setgid(gid) == -1)
{
@@ -150,19 +149,26 @@ run_coprocess(pam_handle_t *pamh, const char *input, char **output,
(unsigned long) geteuid ());
_exit (err);
}
- /* Initialize the argument list. */
- memset(args, 0, sizeof(args));
/* Set the pipe descriptors up as stdin and stdout, and close
* everything else, including the original values for the
* descriptors. */
- dup2(ipipe[0], STDIN_FILENO);
- dup2(opipe[1], STDOUT_FILENO);
- maxopened = (int)sysconf(_SC_OPEN_MAX);
- for (i = 0; i < maxopened; i++) {
- if ((i != STDIN_FILENO) && (i != STDOUT_FILENO)) {
- close(i);
- }
+ if (dup2(ipipe[0], STDIN_FILENO) != STDIN_FILENO) {
+ int err = errno;
+ pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdin");
+ _exit(err);
}
+ if (dup2(opipe[1], STDOUT_FILENO) != STDOUT_FILENO) {
+ int err = errno;
+ pam_syslog(pamh, LOG_ERR, "dup2 of %s failed: %m", "stdout");
+ _exit(err);
+ }
+ if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_IGNORE_FD,
+ PAM_MODUTIL_IGNORE_FD,
+ PAM_MODUTIL_NULL_FD) < 0) {
+ _exit(1);
+ }
+ /* Initialize the argument list. */
+ memset(args, 0, sizeof(args));
/* Convert the varargs list into a regular array of strings. */
va_start(ap, command);
args[0] = command;