summaryrefslogtreecommitdiff
path: root/module/account.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/account.c')
-rw-r--r--module/account.c92
1 files changed, 92 insertions, 0 deletions
diff --git a/module/account.c b/module/account.c
new file mode 100644
index 000000000000..c270c9b97431
--- /dev/null
+++ b/module/account.c
@@ -0,0 +1,92 @@
+/*
+ * Implements the PAM authorization function (pam_acct_mgmt).
+ *
+ * We don't have much to do for account management, but we do recheck the
+ * user's authorization against .k5login (or whatever equivalent we've been
+ * configured for).
+ *
+ * Copyright 2005-2009, 2014, 2020-2021 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2011
+ * The Board of Trustees of the Leland Stanford Junior University
+ * Copyright 2005 Andres Salomon <dilinger@debian.org>
+ * Copyright 1999-2000 Frank Cusack <fcusack@fcusack.com>
+ *
+ * SPDX-License-Identifier: BSD-3-clause or GPL-1+
+ */
+
+/* Get prototypes for the account management functions. */
+#define PAM_SM_ACCOUNT
+
+#include <config.h>
+#include <portable/krb5.h>
+#include <portable/pam.h>
+#include <portable/system.h>
+
+#include <errno.h>
+
+#include <module/internal.h>
+#include <pam-util/args.h>
+#include <pam-util/logging.h>
+
+
+/*
+ * Check the authorization of the user. It's not entirely clear what this
+ * function is supposed to do, but rechecking .k5login and friends makes the
+ * most sense.
+ */
+int
+pamk5_account(struct pam_args *args)
+{
+ struct context *ctx;
+ int retval;
+ const char *name;
+
+ /* If the account was expired, here's where we actually fail. */
+ ctx = args->config->ctx;
+ if (ctx->expired) {
+ pam_syslog(args->pamh, LOG_INFO, "user %s account password is expired",
+ ctx->name);
+ return PAM_NEW_AUTHTOK_REQD;
+ }
+
+ /*
+ * Re-retrieve the user rather than trusting our context; it's conceivable
+ * the application could have changed it. We have to cast &name due to
+ * C's broken type system.
+ *
+ * Use pam_get_item rather than pam_get_user here since the user should be
+ * set by the time we get to this point. If we would have to prompt for a
+ * user, something is definitely broken and we should fail.
+ */
+ retval = pam_get_item(args->pamh, PAM_USER, (PAM_CONST void **) &name);
+ if (retval != PAM_SUCCESS || name == NULL) {
+ putil_err_pam(args, retval, "unable to retrieve user");
+ return PAM_AUTH_ERR;
+ }
+ if (ctx->name != name) {
+ free(ctx->name);
+ ctx->name = strdup(name);
+ args->user = ctx->name;
+ }
+
+ /*
+ * If we have a ticket cache, then we can apply an additional bit of
+ * paranoia. Rather than trusting princ in the context, extract the
+ * principal from the Kerberos ticket cache we actually received and then
+ * validate that. This should make no difference in practice, but it's a
+ * bit more thorough.
+ */
+ if (ctx->cache != NULL) {
+ putil_debug(args, "retrieving principal from cache");
+ if (ctx->princ != NULL) {
+ krb5_free_principal(ctx->context, ctx->princ);
+ ctx->princ = NULL;
+ }
+ retval = krb5_cc_get_principal(ctx->context, ctx->cache, &ctx->princ);
+ if (retval != 0) {
+ putil_err_krb5(args, retval, "cannot get principal from cache");
+ return PAM_AUTH_ERR;
+ }
+ }
+ return pamk5_authorized(args);
+}