summaryrefslogtreecommitdiff
path: root/modules/pam_keyinit/pam_keyinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_keyinit/pam_keyinit.c')
-rw-r--r--modules/pam_keyinit/pam_keyinit.c146
1 files changed, 96 insertions, 50 deletions
diff --git a/modules/pam_keyinit/pam_keyinit.c b/modules/pam_keyinit/pam_keyinit.c
index b2fa5d95..92e4953b 100644
--- a/modules/pam_keyinit/pam_keyinit.c
+++ b/modules/pam_keyinit/pam_keyinit.c
@@ -1,4 +1,5 @@
-/* pam_keyinit.c: Initialise the session keyring on login through a PAM module
+/*
+ * pam_keyinit: Initialise the session keyring on login through a PAM module
*
* Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -30,11 +31,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 +52,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 +84,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 +93,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 +107,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 +117,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 +140,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)
+ /* return to the original UID and GID (probably root) */
+ 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 +192,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;
@@ -198,7 +202,8 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED,
pw = pam_modutil_getpwnam(pamh, username);
if (!pw) {
- error(pamh, "Unable to look up user \"%s\"\n", username);
+ pam_syslog(pamh, LOG_NOTICE, "Unable to look up user \"%s\"\n",
+ username);
return PAM_USER_UNKNOWN;
}
@@ -212,29 +217,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);
+ /* return to the original UID and GID (probably root) */
+ 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 +291,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;
}