diff options
Diffstat (limited to 'modules/pam_keyinit/pam_keyinit.c')
-rw-r--r-- | modules/pam_keyinit/pam_keyinit.c | 136 |
1 files changed, 90 insertions, 46 deletions
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; } |