aboutsummaryrefslogtreecommitdiff
path: root/module/support.c
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2025-04-17 02:13:41 +0000
committerCy Schubert <cy@FreeBSD.org>2025-05-27 16:20:06 +0000
commit24f0b4ca2d565cdbb4fe7839ff28320706bf2386 (patch)
treebc9ce87edb73f767f5580887d0fc8c643b9d7a49 /module/support.c
pam-krb5: Import/add pam-krb5 from eyeire.orgvendor/pam-krb5/4.11vendor/pam-krb5
From https://www.eyrie.org/~eagle/software/pam-krb5/: pam-krb5 provides a Kerberos PAM module that supports authentication, user ticket cache handling, simple authorization (via .k5login or checking Kerberos principals against local usernames), and password changing. It can be configured through either options in the PAM configuration itself or through entries in the system krb5.conf file, and it tries to work around PAM implementation flaws in commonly-used PAM-enabled applications such as OpenSSH and xdm. It supports both PKINIT and FAST to the extent that the underlying Kerberos libraries support these features. The reason for this import is to provide an MIT KRB5 compatible pam_krb5 PAM module. The existing pam_krb5 in FreeBS only works with Heimdal. Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'module/support.c')
-rw-r--r--module/support.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/module/support.c b/module/support.c
new file mode 100644
index 000000000000..79b654ed2f32
--- /dev/null
+++ b/module/support.c
@@ -0,0 +1,141 @@
+/*
+ * Support functions for pam-krb5.
+ *
+ * Some general utility functions used by multiple PAM groups that aren't
+ * associated with any particular chunk of functionality.
+ *
+ * Copyright 2005-2007, 2009, 2020 Russ Allbery <eagle@eyrie.org>
+ * Copyright 2011-2012
+ * 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+
+ */
+
+#include <config.h>
+#include <portable/krb5.h>
+#include <portable/pam.h>
+#include <portable/system.h>
+
+#include <errno.h>
+#include <pwd.h>
+
+#include <module/internal.h>
+#include <pam-util/args.h>
+#include <pam-util/logging.h>
+
+
+/*
+ * Given the PAM arguments and the user we're authenticating, see if we should
+ * ignore that user because they're root or have a low-numbered UID and we
+ * were configured to ignore such users. Returns true if we should ignore
+ * them, false otherwise. Ignores any fully-qualified principal names.
+ */
+int
+pamk5_should_ignore(struct pam_args *args, PAM_CONST char *username)
+{
+ struct passwd *pwd;
+
+ if (args->config->ignore_root && strcmp("root", username) == 0) {
+ putil_debug(args, "ignoring root user");
+ return 1;
+ }
+ if (args->config->minimum_uid > 0 && strchr(username, '@') == NULL) {
+ pwd = pam_modutil_getpwnam(args->pamh, username);
+ if (pwd != NULL && pwd->pw_uid < (uid_t) args->config->minimum_uid) {
+ putil_debug(args, "ignoring low-UID user (%lu < %ld)",
+ (unsigned long) pwd->pw_uid,
+ args->config->minimum_uid);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Verify the user authorization. Call krb5_kuserok if this is a local
+ * account, or do the krb5_aname_to_localname verification if ignore_k5login
+ * was requested. For non-local accounts, the principal must match the
+ * authentication identity.
+ */
+int
+pamk5_authorized(struct pam_args *args)
+{
+ struct context *ctx;
+ krb5_context c;
+ krb5_error_code retval;
+ int status;
+ struct passwd *pwd;
+ char kuser[65]; /* MAX_USERNAME == 65 (MIT Kerberos 1.4.1). */
+
+ if (args == NULL || args->config == NULL || args->config->ctx == NULL
+ || args->config->ctx->context == NULL)
+ return PAM_SERVICE_ERR;
+ ctx = args->config->ctx;
+ if (ctx->name == NULL)
+ return PAM_SERVICE_ERR;
+ c = ctx->context;
+
+ /*
+ * If alt_auth_map was set, authorize the user if the authenticated
+ * principal matches the mapped principal. alt_auth_map essentially
+ * serves as a supplemental .k5login. PAM_SERVICE_ERR indicates fatal
+ * errors that should abort remaining processing; PAM_AUTH_ERR indicates
+ * that it just didn't match, in which case we continue to try other
+ * authorization methods.
+ */
+ if (args->config->alt_auth_map != NULL) {
+ status = pamk5_alt_auth_verify(args);
+ if (status == PAM_SUCCESS || status == PAM_SERVICE_ERR)
+ return status;
+ }
+
+ /*
+ * If the name to which we're authenticating contains @ (is fully
+ * qualified), it must match the principal exactly.
+ */
+ if (strchr(ctx->name, '@') != NULL) {
+ char *principal;
+
+ retval = krb5_unparse_name(c, ctx->princ, &principal);
+ if (retval != 0) {
+ putil_err_krb5(args, retval, "krb5_unparse_name failed");
+ return PAM_SERVICE_ERR;
+ }
+ if (strcmp(principal, ctx->name) != 0) {
+ putil_err(args, "user %s does not match principal %s", ctx->name,
+ principal);
+ krb5_free_unparsed_name(c, principal);
+ return PAM_AUTH_ERR;
+ }
+ krb5_free_unparsed_name(c, principal);
+ return PAM_SUCCESS;
+ }
+
+ /*
+ * Otherwise, apply either krb5_aname_to_localname or krb5_kuserok
+ * depending on the situation.
+ */
+ pwd = pam_modutil_getpwnam(args->pamh, ctx->name);
+ if (args->config->ignore_k5login || pwd == NULL) {
+ retval = krb5_aname_to_localname(c, ctx->princ, sizeof(kuser), kuser);
+ if (retval != 0) {
+ putil_err_krb5(args, retval, "cannot convert principal to user");
+ return PAM_AUTH_ERR;
+ }
+ if (strcmp(kuser, ctx->name) != 0) {
+ putil_err(args, "user %s does not match local name %s", ctx->name,
+ kuser);
+ return PAM_AUTH_ERR;
+ }
+ } else {
+ if (!krb5_kuserok(c, ctx->princ, ctx->name)) {
+ putil_err(args, "krb5_kuserok for user %s failed", ctx->name);
+ return PAM_AUTH_ERR;
+ }
+ }
+
+ return PAM_SUCCESS;
+}