summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/pam_keyinit/pam_keyinit.8.xml39
-rw-r--r--modules/pam_keyinit/pam_keyinit.c136
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;
}