2 * Heimdal shared module API.
4 * This is the glue required for a Heimdal password quality check via a
5 * dynamically loaded module. Heimdal's shared module API doesn't have
6 * separate initialization and shutdown functions, so provide a self-contained
7 * function that looks up the dictionary path from krb5.conf and does all the
8 * work. This means that it does memory allocations on every call, which
9 * isn't ideal, but it's probably not that slow.
11 * Of course, the external Heimdal strength checking program can be used
14 * Written by Russ Allbery <eagle@eyrie.org>
15 * Copyright 2020, 2023 Russ Allbery <eagle@eyrie.org>
16 * Copyright 2009, 2013
17 * The Board of Trustees of the Leland Stanford Junior University
19 * SPDX-License-Identifier: MIT
23 #include <portable/krb5.h>
24 #include <portable/system.h>
27 #ifdef HAVE_KADM5_KADM5_PWCHECK_H
28 # include <kadm5/kadm5-pwcheck.h>
31 #include <plugin/internal.h>
32 #include <util/macros.h>
34 /* Skip this entire file if not building with Heimdal. */
35 #ifdef HAVE_KRB5_REALM
39 * Write a Kerberos error string to a message buffer, with an optional
43 convert_error(krb5_context ctx, krb5_error_code code, const char *prefix,
44 char *message, size_t length)
48 error = krb5_get_error_message(ctx, code);
50 snprintf(message, length, "%s", error);
52 snprintf(message, length, "%s: %s", prefix, error);
53 krb5_free_error_message(ctx, error);
58 * This is the single check function that we provide. It does the glue
59 * required to initialize our checks, convert the Heimdal arguments to the
60 * strings we expect, and return the result.
63 heimdal_pwcheck(krb5_context ctx, krb5_principal principal,
64 krb5_data *password, const char *tuning UNUSED, char *message,
67 krb5_pwqual_moddata data = NULL;
72 /* Convert the password to a C string. */
73 pastring = malloc(password->length + 1);
74 if (pastring == NULL) {
75 snprintf(message, length, "cannot allocate memory: %s",
79 memcpy(pastring, password->data, password->length);
80 pastring[password->length] = '\0';
82 /* Initialize strength checking. */
83 code = strength_init(ctx, NULL, &data);
85 convert_error(ctx, code, NULL, message, length);
89 /* Convert the principal to a string. */
90 code = krb5_unparse_name(ctx, principal, &name);
92 convert_error(ctx, code, "cannot unparse principal", message, length);
96 /* Do the password strength check. */
97 code = strength_check(ctx, data, name, pastring);
99 convert_error(ctx, code, NULL, message, length);
102 explicit_bzero(pastring, password->length);
105 krb5_free_unparsed_name(ctx, name);
107 strength_close(ctx, data);
108 return (code == 0) ? 0 : 1;
111 /* The public symbol that Heimdal looks for. */
112 /* clang-format off */
113 static struct kadm5_pw_policy_check_func functions[] = {
114 {"krb5-strength", heimdal_pwcheck},
117 extern struct kadm5_pw_policy_verifier kadm5_password_verifier;
118 struct kadm5_pw_policy_verifier kadm5_password_verifier = {
120 KADM5_PASSWD_VERSION_V1,
124 /* clang-format on */
126 #endif /* HAVE_KRB5_REALM */