diff options
author | ppkarwasz <piotr.github@karwasz.org> | 2019-11-28 15:33:51 +0100 |
---|---|---|
committer | Tomáš Mráz <t8m@users.noreply.github.com> | 2019-11-28 15:33:51 +0100 |
commit | 3798dfdc346e482c9678dd376e6d1ebe5dd66714 (patch) | |
tree | 2c32fadbf98a3116678c601383d937ddb0ce5ffb | |
parent | 7fbb8592fb75dac96b31a26de7528917060eb589 (diff) | |
download | pam-3798dfdc346e482c9678dd376e6d1ebe5dd66714.tar.gz pam-3798dfdc346e482c9678dd376e6d1ebe5dd66714.tar.bz2 pam-3798dfdc346e482c9678dd376e6d1ebe5dd66714.zip |
Adds an auth module to pam_keyinit (#150)
Adds an auth module to pam_keyinit, whose implementation of
pam_sm_setcred
is identical to the implementation of pam_sm_open_session.
It is useful with PAM applications, which call pam_setcred,
before calling pam_open_session.
* modules/pam_keyinit/pam_keyinit.c: Add an auth module to pam_keyinit.
* modules/pam_keyinit/pam_keyinit.8.xml: Update the manpage
to describe the new functionality.
-rw-r--r-- | modules/pam_keyinit/pam_keyinit.8.xml | 39 | ||||
-rw-r--r-- | modules/pam_keyinit/pam_keyinit.c | 136 |
2 files changed, 114 insertions, 61 deletions
diff --git a/modules/pam_keyinit/pam_keyinit.8.xml b/modules/pam_keyinit/pam_keyinit.8.xml index bcc50964..43189494 100644 --- a/modules/pam_keyinit/pam_keyinit.8.xml +++ b/modules/pam_keyinit/pam_keyinit.8.xml @@ -37,18 +37,32 @@ session keyring other than the user default session keyring. </para> <para> - The session component of the module checks to see if the process's - session keyring is the user default, and, if it is, creates a new - anonymous session keyring with which to replace it. - </para> - <para> - If a new session keyring is created, it will install a link to the user - common keyring in the session keyring so that keys common to the user - will be automatically accessible through it. + The module checks to see if the process's session keyring is the + <citerefentry> + <refentrytitle>user-session-keyring</refentrytitle><manvolnum>7</manvolnum> + </citerefentry>, + and, if it is, creates a new + <citerefentry> + <refentrytitle>session-keyring</refentrytitle><manvolnum>7</manvolnum> + </citerefentry> + with which to replace it. If a new session keyring is created, it will + install a link to the + <citerefentry> + <refentrytitle>user-keyring</refentrytitle><manvolnum>7</manvolnum> + </citerefentry> + in the session keyring so that keys common to the user will be + automatically accessible through it. The session keyring of the invoking + process will thenceforth be inherited by all its children unless they override it. </para> <para> - The session keyring of the invoking process will thenceforth be inherited - by all its children unless they override it. + In order to allow other PAM modules to attach tokens to the keyring, this module + provides both an <emphasis>auth</emphasis> (limited to + <citerefentry> + <refentrytitle>pam_setcred</refentrytitle><manvolnum>3</manvolnum> + </citerefentry> + and a <emphasis>session</emphasis> component. The session keyring is created + in the module called. Moreover this module should be included as early as + possible in a PAM configuration. </para> <para> This module is intended primarily for use by login processes. Be aware @@ -62,11 +76,6 @@ their own permissions system to manage this. </para> <para> - This module should be included as early as possible in a PAM - configuration, so that other PAM modules can attach tokens to the - keyring. - </para> - <para> The keyutils package is used to manipulate keys more directly. This can be obtained from: </para> diff --git a/modules/pam_keyinit/pam_keyinit.c b/modules/pam_keyinit/pam_keyinit.c index b2fa5d95..611c06dc 100644 --- a/modules/pam_keyinit/pam_keyinit.c +++ b/modules/pam_keyinit/pam_keyinit.c @@ -30,11 +30,11 @@ #define KEYCTL_REVOKE 3 /* revoke a key */ #define KEYCTL_LINK 8 /* link a key into a keyring */ -static int my_session_keyring; -static int session_counter; -static int do_revoke; -static int revoke_as_uid; -static int revoke_as_gid; +static int my_session_keyring = 0; +static int session_counter = 0; +static int do_revoke = 0; +static uid_t revoke_as_uid; +static gid_t revoke_as_gid; static int xdebug = 0; static void debug(pam_handle_t *pamh, const char *fmt, ...) @@ -51,24 +51,22 @@ static void debug(pam_handle_t *pamh, const char *fmt, ...) } } -static int error(pam_handle_t *pamh, const char *fmt, ...) +static void error(pam_handle_t *pamh, const char *fmt, ...) __attribute__((format(printf, 2, 3))); -static int error(pam_handle_t *pamh, const char *fmt, ...) +static void error(pam_handle_t *pamh, const char *fmt, ...) { va_list va; va_start(va, fmt); pam_vsyslog(pamh, LOG_ERR, fmt, va); va_end(va); - - return PAM_SESSION_ERR; } /* * initialise the session keyring for this process */ -static int init_keyrings(pam_handle_t *pamh, int force) +static int init_keyrings(pam_handle_t *pamh, int force, int error_ret) { int session, usession, ret; @@ -85,7 +83,7 @@ static int init_keyrings(pam_handle_t *pamh, int force) * installed */ if (errno == ENOSYS) return PAM_SUCCESS; - return PAM_SESSION_ERR; + return error_ret; } usession = syscall(__NR_keyctl, @@ -94,7 +92,7 @@ static int init_keyrings(pam_handle_t *pamh, int force) 0); debug(pamh, "GET SESSION = %d", usession); if (usession < 0) - return PAM_SESSION_ERR; + return error_ret; /* if the user session keyring is our keyring, then we don't * need to do anything if we're not forcing */ @@ -108,7 +106,7 @@ static int init_keyrings(pam_handle_t *pamh, int force) NULL); debug(pamh, "JOIN = %d", ret); if (ret < 0) - return PAM_SESSION_ERR; + return error_ret; my_session_keyring = ret; @@ -118,15 +116,17 @@ static int init_keyrings(pam_handle_t *pamh, int force) KEY_SPEC_USER_KEYRING, KEY_SPEC_SESSION_KEYRING); - return ret < 0 ? PAM_SESSION_ERR : PAM_SUCCESS; + return ret < 0 ? error_ret : PAM_SUCCESS; } /* * revoke the session keyring for this process */ -static void kill_keyrings(pam_handle_t *pamh) +static int kill_keyrings(pam_handle_t *pamh, int error_ret) { - int old_uid, old_gid; + uid_t old_uid; + gid_t old_gid; + int ret = PAM_SUCCESS; /* revoke the session keyring we created earlier */ if (my_session_keyring > 0) { @@ -139,38 +139,45 @@ static void kill_keyrings(pam_handle_t *pamh) /* switch to the real UID and GID so that we have permission to * revoke the key */ - if (revoke_as_gid != old_gid && setregid(-1, revoke_as_gid) < 0) - error(pamh, "Unable to change GID to %d temporarily\n", - revoke_as_gid); + if (revoke_as_gid != old_gid && setregid(-1, revoke_as_gid) < 0) { + error(pamh, "Unable to change GID to %d temporarily\n", revoke_as_gid); + return error_ret; + } - if (revoke_as_uid != old_uid && setresuid(-1, revoke_as_uid, old_uid) < 0) - error(pamh, "Unable to change UID to %d temporarily\n", - revoke_as_uid); + if (revoke_as_uid != old_uid && setresuid(-1, revoke_as_uid, old_uid) < 0) { + error(pamh, "Unable to change UID to %d temporarily\n", revoke_as_uid); + if (getegid() != old_gid && setregid(-1, old_gid) < 0) + error(pamh, "Unable to change GID back to %d\n", old_gid); + return error_ret; + } - syscall(__NR_keyctl, - KEYCTL_REVOKE, - my_session_keyring); + if (syscall(__NR_keyctl, KEYCTL_REVOKE, my_session_keyring) < 0) { + ret = error_ret; + } /* return to the orignal UID and GID (probably root) */ - if (revoke_as_uid != old_uid && setreuid(-1, old_uid) < 0) + if (revoke_as_uid != old_uid && setreuid(-1, old_uid) < 0) { error(pamh, "Unable to change UID back to %d\n", old_uid); + ret = error_ret; + } - if (revoke_as_gid != old_gid && setregid(-1, old_gid) < 0) + if (revoke_as_gid != old_gid && setregid(-1, old_gid) < 0) { error(pamh, "Unable to change GID back to %d\n", old_gid); + ret = error_ret; + } my_session_keyring = 0; } + return ret; } -/* - * open a PAM session by making sure there's a session keyring - */ -int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, - int argc, const char **argv) +static int do_keyinit(pam_handle_t *pamh, int argc, const char **argv, int error_ret) { struct passwd *pw; const char *username; - int ret, old_uid, uid, old_gid, gid, loop, force = 0; + int ret, loop, force = 0; + uid_t old_uid, uid; + gid_t old_gid, gid; for (loop = 0; loop < argc; loop++) { if (strcmp(argv[loop], "force") == 0) @@ -184,10 +191,6 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, /* don't do anything if already created a keyring (will be called * multiple times if mentioned more than once in a pam script) */ - session_counter++; - - debug(pamh, "OPEN %d", session_counter); - if (my_session_keyring > 0) return PAM_SUCCESS; @@ -212,29 +215,70 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, * the right user */ if (gid != old_gid && setregid(gid, -1) < 0) { error(pamh, "Unable to change GID to %d temporarily\n", gid); - return PAM_SESSION_ERR; + return error_ret; } if (uid != old_uid && setreuid(uid, -1) < 0) { error(pamh, "Unable to change UID to %d temporarily\n", uid); if (setregid(old_gid, -1) < 0) error(pamh, "Unable to change GID back to %d\n", old_gid); - return PAM_SESSION_ERR; + return error_ret; } - ret = init_keyrings(pamh, force); + ret = init_keyrings(pamh, force, error_ret); /* return to the orignal UID and GID (probably root) */ - if (uid != old_uid && setreuid(old_uid, -1) < 0) - ret = error(pamh, "Unable to change UID back to %d\n", old_uid); + if (uid != old_uid && setreuid(old_uid, -1) < 0) { + error(pamh, "Unable to change UID back to %d\n", old_uid); + ret = error_ret; + } - if (gid != old_gid && setregid(old_gid, -1) < 0) - ret = error(pamh, "Unable to change GID back to %d\n", old_gid); + if (gid != old_gid && setregid(old_gid, -1) < 0) { + error(pamh, "Unable to change GID back to %d\n", old_gid); + ret = error_ret; + } return ret; } /* + * Dummy + */ +int pam_sm_authenticate(pam_handle_t *pamh UNUSED, int flags UNUSED, + int argc UNUSED, const char **argv UNUSED) +{ + return PAM_IGNORE; +} + +/* + * since setcred and open_session are called in different orders, a + * session ring is invoked by the first of these functions called. + */ +int pam_sm_setcred(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + if (flags & PAM_ESTABLISH_CRED) { + debug(pamh, "ESTABLISH_CRED"); + return do_keyinit(pamh, argc, argv, PAM_CRED_ERR); + } + if (flags & PAM_DELETE_CRED && my_session_keyring > 0 && do_revoke) { + debug(pamh, "DELETE_CRED"); + return kill_keyrings(pamh, PAM_CRED_ERR); + } + return PAM_IGNORE; +} + +int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + session_counter++; + + debug(pamh, "OPEN %d", session_counter); + + return do_keyinit(pamh, argc, argv, PAM_SESSION_ERR); +} + +/* * close a PAM session by revoking the session keyring if requested */ int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, @@ -245,8 +289,8 @@ int pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, session_counter--; - if (session_counter == 0 && my_session_keyring > 0 && do_revoke) - kill_keyrings(pamh); + if (session_counter <= 0 && my_session_keyring > 0 && do_revoke) + kill_keyrings(pamh, PAM_SESSION_ERR); return PAM_SUCCESS; } |