Skip to content

pam_tcb: Add support for user authentication with SELinux. #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,31 @@
* tcb.spec: Remove -DENABLE_SETFSUGID.
* ci/run-build-and-tests.sh: Likewise.

2021-10-12 Björn Esser <besser82 at fedoraproject.org>

pam_tcb: Allow for authentication if a system policy requires the
root user to acquire special capabilities.
* pam_tcb/support.c (unix_verify_password_plain): Allow the helper
binary to be run as root if e.g. SELinux prevents access to file
storing the hashed user password.
* progs/tcb_chkpwd.c (unix_verify_password): Likewise.
* pam_tcb/support.c (unix_run_helper_binary): Refactor function to
be non-static and to allow for more versatile use.
* pam_tcb/support.h (unix_run_helper_binary): New function.
* pam_tcb/support.c (run_chkpwd_binary): New static function wrapper
around unix_run_helper_binary().
* pam_tcb/support.c (unix_verify_password_plain):
Replace call to unix_run_helper_binary() with run_chkpwd_binary().
* progs/tcb_chkpwd.c: Refactor the helper program to also perform
verifications for the expiration of user accounts.
* pam_tcb/pam_unix_acct.c (pam_sm_acct_mgmt): Perform expiration
verification of a user account through an external helper binary
if the verification fails for insufficient credentials.
* pam_tcb/pam_unix_acct.c (run_chkpwd_binary): New static function
wrapper around unix_run_helper_binary().
* pam_tcb/Makefile: Add custom rule with "CHKPWD_HELPER" macro
definined to compile pam_unix_acct.o.

2021-09-30 Björn Esser <besser82 at fedoraproject.org>

pam_tcb: Fix "-Wpedantic".
Expand Down
4 changes: 4 additions & 0 deletions pam_tcb/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ $(PAM_TCB): $(LIBOBJ) $(PAM_MAP)
.c.o:
$(CC) $(CFLAGS) -fPIC -c $< -o $@

pam_unix_acct.o: pam_unix_acct.c
$(CC) $(CFLAGS) -DCHKPWD_HELPER=\"$(LIBEXECDIR)/chkpwd/tcb_chkpwd\" \
-fPIC -c $< -o $@

support.o: support.c
$(CC) $(CFLAGS) -DCHKPWD_HELPER=\"$(LIBEXECDIR)/chkpwd/tcb_chkpwd\" \
-fPIC -c $< -o $@
Expand Down
31 changes: 31 additions & 0 deletions pam_tcb/pam_unix_acct.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,29 @@ static int acct_shadow(unused pam_handle_t *pamh, const void *void_user)
return ACCT_SUCCESS;
}

/*
* Use an external helper binary to perform account management.
*/
static int run_chkpwd_binary(const char *user)
{
char *argv[] = { CHKPWD_HELPER, "chkacct", NULL };
char config[8] = "shadow\0\0";
int retval_helper;

if (!pam_unix_param.helper)
goto end;

if (unix_run_helper_binary (user, "NULL", pam_unix_param.helper,
argv, config, (void *)&retval_helper,
sizeof(retval_helper)))
goto end;

return retval_helper;

end:
return ACCT_0;
}

/*
* The account management entry point.
*/
Expand Down Expand Up @@ -112,6 +135,14 @@ PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
retval = acct_shadow(pamh, user);
else
retval = _unix_fork(pamh, acct_shadow, user);
if (retval == ACCT_2) {
uid_t uid = getuid();
if (uid == geteuid() && (uid == pw->pw_uid || uid == 0)) {
/* We are not privileged enough perhaps this is the reason? */
D(("running helper binary"));
retval = run_chkpwd_binary(user);
}
}
if (retval > 255) {
daysleft = retval / 256;
retval %= 256;
Expand Down
88 changes: 55 additions & 33 deletions pam_tcb/support.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,29 +279,29 @@ int _unix_blankpasswd(pam_handle_t *pamh, const char *user)
}

/*
* Verify the password of a user.
* Run a helper binary.
*/

static int unix_run_helper_binary(const char *user, const char *pass)
int unix_run_helper_binary(const char *user, const char *pass,
const char *helper_binary, char *const argv[],
const char config[8], void *retval_helper,
size_t retval_size)
{
int retval = PAM_AUTH_ERR, child, fail = 0, status, fds[2], retpipe[2];
int child, retval = 0, status, fds[2], retpipe[2];
sighandler_t sigchld, sigpipe;
int len;
char *argv[] = {CHKPWD_HELPER, NULL};
char *envp[] = {NULL};

D(("called"));

if (!pam_unix_param.helper)
return PAM_AUTH_ERR;

/* create a pipe for the password */
if (pipe(fds)) {
D(("could not make pipe"));
retval = 1;
goto out;
}
if (pipe(retpipe)) {
D(("could not make pipe"));
retval = 1;
goto out_pipe;
}

Expand All @@ -311,6 +311,7 @@ static int unix_run_helper_binary(const char *user, const char *pass)
switch ((child = fork())) {
case -1:
D(("fork failed"));
retval = 1;
goto out_signal;

case 0:
Expand All @@ -327,7 +328,7 @@ static int unix_run_helper_binary(const char *user, const char *pass)
_exit(1);

/* exec binary helper */
execve(pam_unix_param.helper, argv, envp);
execve(helper_binary, argv, envp);

/* should not get here: exit with error */
D(("helper binary is not available"));
Expand All @@ -337,39 +338,29 @@ static int unix_run_helper_binary(const char *user, const char *pass)
/* wait for child */
close(fds[0]);
close(retpipe[1]);
if (on(UNIX__NULLOK)) {
if (write_loop(fds[1], "nullok\0\0", 8) != 8)
fail = 1;
} else {
if (write_loop(fds[1], "nonull\0\0", 8) != 8)
fail = 1;
}
if (write_loop(fds[1], config, 8) != 8)
retval = 1;
len = strlen(user) + 1;
if (write_loop(fds[1], user, len) != len)
fail = 1;
else {
if (write_loop(fds[1], user, len) != len) {
retval = 1;
} else {
len = strlen(pass) + 1;
if (write_loop(fds[1], pass, len) != len)
fail = 1;
retval = 1;
}
pass = NULL;
close(fds[1]);
/* wait for helper to complete */
if (waitpid(child, &status, 0) != child) {
status = 0;
fail = 1;
retval = 1;
}
if (read_loop(retpipe[0], (char *)&retval, sizeof(retval)) !=
sizeof(retval))
fail = 1;
if (read_loop(retpipe[0], (char *)retval_helper, retval_size) !=
(int)retval_size)
retval = 1;
close(retpipe[0]);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
fail = 1;
if (fail)
retval = PAM_AUTH_ERR;
else
retval = (retval == TCB_MAGIC) ?
PAM_SUCCESS : PAM_AUTH_ERR;
retval = 1;
}

out_signal:
Expand All @@ -387,6 +378,37 @@ static int unix_run_helper_binary(const char *user, const char *pass)
return retval;
}

/*
* Verify the password of a user.
*/

static int run_chkpwd_binary(const char *user, const char *pass)
{
char *argv[] = { CHKPWD_HELPER, "chkpwd", NULL };
char config[8];
int retval_helper;

if (!pam_unix_param.helper)
goto end;

if (on(UNIX__NULLOK)) {
memcpy(config, "nullok\0\0", 8);
} else {
memcpy(config, "nonull\0\0", 8);
}

if (unix_run_helper_binary (user, pass, pam_unix_param.helper,
argv, config, (void *)&retval_helper,
sizeof(retval_helper)))
goto end;

if (retval_helper == TCB_MAGIC)
return PAM_SUCCESS;

end:
return PAM_AUTH_ERR;
}

static int check_crypt(pam_handle_t *pamh, const char *pass,
const char *stored_hash)
{
Expand Down Expand Up @@ -475,10 +497,10 @@ static int unix_verify_password_plain(pam_handle_t *pamh,
if (!salt) {
/* we're not faking, we have an existing user, so... */
uid_t uid = getuid();
if (uid == geteuid() && uid == pw->pw_uid && uid != 0) {
/* We are not root perhaps this is the reason? */
if (uid == geteuid() && (uid == pw->pw_uid || uid == 0)) {
/* We are not privileged enough perhaps this is the reason? */
D(("running helper binary"));
retval = unix_run_helper_binary(user, pass);
retval = run_chkpwd_binary(user, pass);
} else {
D(("user's record unavailable"));
pam_syslog(pamh, LOG_ALERT,
Expand Down
4 changes: 4 additions & 0 deletions pam_tcb/support.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,10 @@ extern int _set_ctrl(pam_handle_t *, int flags, int argc, const char **argv);
extern int _unix_blankpasswd(pam_handle_t *, const char *user);
extern int _unix_verify_password(pam_handle_t *, const char *, const char *);
extern int unix_getspnam(struct spwd **, const struct passwd *);
extern int unix_run_helper_binary(const char *user, const char *pass,
const char *helper_binary, char *const argv[],
const char helper_command[8],
void *retval_helper, size_t retval_size);
extern char *crypt_wrapper(pam_handle_t *, const char *, const char *);
extern char *do_crypt(pam_handle_t *, const char *);

Expand Down
Loading
Loading