1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
/*
* Heimdal shared module API.
*
* This is the glue required for a Heimdal password quality check via a
* dynamically loaded module. Heimdal's shared module API doesn't have
* separate initialization and shutdown functions, so provide a self-contained
* function that looks up the dictionary path from krb5.conf and does all the
* work. This means that it does memory allocations on every call, which
* isn't ideal, but it's probably not that slow.
*
* Of course, the external Heimdal strength checking program can be used
* instead.
*
* Written by Russ Allbery <eagle@eyrie.org>
* Copyright 2020, 2023 Russ Allbery <eagle@eyrie.org>
* Copyright 2009, 2013
* The Board of Trustees of the Leland Stanford Junior University
*
* SPDX-License-Identifier: MIT
*/
#include <config.h>
#include <portable/krb5.h>
#include <portable/system.h>
#include <errno.h>
#ifdef HAVE_KADM5_KADM5_PWCHECK_H
# include <kadm5/kadm5-pwcheck.h>
#endif
#include <plugin/internal.h>
#include <util/macros.h>
/* Skip this entire file if not building with Heimdal. */
#ifdef HAVE_KRB5_REALM
/*
* Write a Kerberos error string to a message buffer, with an optional
* prefix.
*/
static void
convert_error(krb5_context ctx, krb5_error_code code, const char *prefix,
char *message, size_t length)
{
const char *error;
error = krb5_get_error_message(ctx, code);
if (prefix == NULL)
snprintf(message, length, "%s", error);
else
snprintf(message, length, "%s: %s", prefix, error);
krb5_free_error_message(ctx, error);
}
/*
* This is the single check function that we provide. It does the glue
* required to initialize our checks, convert the Heimdal arguments to the
* strings we expect, and return the result.
*/
static int
heimdal_pwcheck(krb5_context ctx, krb5_principal principal,
krb5_data *password, const char *tuning UNUSED, char *message,
size_t length)
{
krb5_pwqual_moddata data = NULL;
char *pastring;
char *name = NULL;
krb5_error_code code;
/* Convert the password to a C string. */
pastring = malloc(password->length + 1);
if (pastring == NULL) {
snprintf(message, length, "cannot allocate memory: %s",
strerror(errno));
return 1;
}
memcpy(pastring, password->data, password->length);
pastring[password->length] = '\0';
/* Initialize strength checking. */
code = strength_init(ctx, NULL, &data);
if (code != 0) {
convert_error(ctx, code, NULL, message, length);
goto done;
}
/* Convert the principal to a string. */
code = krb5_unparse_name(ctx, principal, &name);
if (code != 0) {
convert_error(ctx, code, "cannot unparse principal", message, length);
goto done;
}
/* Do the password strength check. */
code = strength_check(ctx, data, name, pastring);
if (code != 0)
convert_error(ctx, code, NULL, message, length);
done:
explicit_bzero(pastring, password->length);
free(pastring);
if (name != NULL)
krb5_free_unparsed_name(ctx, name);
if (data != NULL)
strength_close(ctx, data);
return (code == 0) ? 0 : 1;
}
/* The public symbol that Heimdal looks for. */
/* clang-format off */
static struct kadm5_pw_policy_check_func functions[] = {
{"krb5-strength", heimdal_pwcheck},
{NULL, NULL}
};
extern struct kadm5_pw_policy_verifier kadm5_password_verifier;
struct kadm5_pw_policy_verifier kadm5_password_verifier = {
"krb5-strength",
KADM5_PASSWD_VERSION_V1,
"Russ Allbery",
functions
};
/* clang-format on */
#endif /* HAVE_KRB5_REALM */
|