diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/certauth/test/Makefile.in | 20 | ||||
-rw-r--r-- | src/plugins/certauth/test/certauth_test.exports | 2 | ||||
-rw-r--r-- | src/plugins/certauth/test/deps | 14 | ||||
-rw-r--r-- | src/plugins/certauth/test/main.c | 209 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto.h | 4 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 30 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_srv.c | 335 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_trace.h | 5 |
8 files changed, 579 insertions, 40 deletions
diff --git a/src/plugins/certauth/test/Makefile.in b/src/plugins/certauth/test/Makefile.in new file mode 100644 index 0000000..d352408 --- /dev/null +++ b/src/plugins/certauth/test/Makefile.in @@ -0,0 +1,20 @@ +mydir=plugins$(S)certauth$(S)test +BUILDTOP=$(REL)..$(S)..$(S).. + +LIBBASE=certauth_test +LIBMAJOR=0 +LIBMINOR=0 +RELDIR=../plugins/certauth/test +SHLIB_EXPDEPS=$(KRB5_BASE_DEPLIBS) +SHLIB_EXPLIBS=$(KRB5_BASE_LIBS) + +STLIBOBJS=main.o + +SRCS=$(srcdir)/main.c + +all-unix: all-libs +install-unix: +clean-unix:: clean-libs clean-libobjs + +@libnover_frag@ +@libobj_frag@ diff --git a/src/plugins/certauth/test/certauth_test.exports b/src/plugins/certauth/test/certauth_test.exports new file mode 100644 index 0000000..1c8cd24 --- /dev/null +++ b/src/plugins/certauth/test/certauth_test.exports @@ -0,0 +1,2 @@ +certauth_test1_initvt +certauth_test2_initvt diff --git a/src/plugins/certauth/test/deps b/src/plugins/certauth/test/deps new file mode 100644 index 0000000..2974b3b --- /dev/null +++ b/src/plugins/certauth/test/deps @@ -0,0 +1,14 @@ +# +# Generated makefile dependencies follow. +# +main.so main.po $(OUTPRE)main.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/certauth_plugin.h $(top_srcdir)/include/krb5/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + main.c diff --git a/src/plugins/certauth/test/main.c b/src/plugins/certauth/test/main.c new file mode 100644 index 0000000..7ef7377 --- /dev/null +++ b/src/plugins/certauth/test/main.c @@ -0,0 +1,209 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* plugins/certauth/main.c - certauth plugin test modules. */ +/* + * Copyright (C) 2017 by Red Hat, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <k5-int.h> +#include "krb5/certauth_plugin.h" + +struct krb5_certauth_moddata_st { + int initialized; +}; + +/* Test module 1 returns OK with an indicator. */ +static krb5_error_code +test1_authorize(krb5_context context, krb5_certauth_moddata moddata, + const uint8_t *cert, size_t cert_len, + krb5_const_principal princ, const void *opts, + const krb5_db_entry *db_entry, char ***authinds_out) +{ + char **ais = NULL; + + ais = calloc(2, sizeof(*ais)); + assert(ais != NULL); + ais[0] = strdup("test1"); + assert(ais[0] != NULL); + *authinds_out = ais; + return KRB5_PLUGIN_NO_HANDLE; +} + +static void +test_free_ind(krb5_context context, krb5_certauth_moddata moddata, + char **authinds) +{ + size_t i; + + if (authinds == NULL) + return; + for (i = 0; authinds[i] != NULL; i++) + free(authinds[i]); + free(authinds); +} + +/* A basic moddata test. */ +static krb5_error_code +test2_init(krb5_context context, krb5_certauth_moddata *moddata_out) +{ + krb5_certauth_moddata mod; + + mod = calloc(1, sizeof(*mod)); + assert(mod != NULL); + mod->initialized = 1; + *moddata_out = mod; + return 0; +} + +static void +test2_fini(krb5_context context, krb5_certauth_moddata moddata) +{ + free(moddata); +} + +/* Return true if cert appears to contain the CN name, based on a search of the + * DER encoding. */ +static krb5_boolean +has_cn(krb5_context context, const uint8_t *cert, size_t cert_len, + const char *name) +{ + krb5_boolean match = FALSE; + uint8_t name_len, cntag[5] = "\x06\x03\x55\x04\x03"; + const uint8_t *c; + struct k5buf buf; + size_t c_left; + + /* Construct a DER search string of the CN AttributeType encoding followed + * by a UTF8String encoding containing name as the AttributeValue. */ + k5_buf_init_dynamic(&buf); + k5_buf_add_len(&buf, cntag, sizeof(cntag)); + k5_buf_add(&buf, "\x0C"); + assert(strlen(name) < 128); + name_len = strlen(name); + k5_buf_add_len(&buf, &name_len, 1); + k5_buf_add_len(&buf, name, name_len); + assert(k5_buf_status(&buf) == 0); + + /* Check for the CN needle in the certificate haystack. */ + c_left = cert_len; + c = memchr(cert, *cntag, c_left); + while (c != NULL) { + c_left = cert_len - (c - cert); + if (buf.len > c_left) + break; + if (memcmp(c, buf.data, buf.len) == 0) { + match = TRUE; + break; + } + assert(c_left >= 1); + c = memchr(c + 1, *cntag, c_left - 1); + } + + k5_buf_free(&buf); + return match; +} + +/* + * Test module 2 returns OK if princ matches the CN part of the subject name, + * and returns indicators of the module name and princ. + */ +static krb5_error_code +test2_authorize(krb5_context context, krb5_certauth_moddata moddata, + const uint8_t *cert, size_t cert_len, + krb5_const_principal princ, const void *opts, + const krb5_db_entry *db_entry, char ***authinds_out) +{ + krb5_error_code ret; + char *name = NULL, **ais = NULL; + + *authinds_out = NULL; + + assert(moddata != NULL && moddata->initialized); + + ret = krb5_unparse_name_flags(context, princ, + KRB5_PRINCIPAL_UNPARSE_NO_REALM, &name); + if (ret) + goto cleanup; + + if (!has_cn(context, cert, cert_len, name)) { + ret = KRB5KDC_ERR_CERTIFICATE_MISMATCH; + goto cleanup; + } + + /* Create an indicator list with the module name and CN. */ + ais = calloc(3, sizeof(*ais)); + assert(ais != NULL); + ais[0] = strdup("test2"); + ais[1] = strdup(name); + assert(ais[0] != NULL && ais[1] != NULL); + *authinds_out = ais; + + ais = NULL; + +cleanup: + krb5_free_unparsed_name(context, name); + return ret; +} + +krb5_error_code +certauth_test1_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); +krb5_error_code +certauth_test1_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_certauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_certauth_vtable)vtable; + vt->name = "test1"; + vt->authorize = test1_authorize; + vt->free_ind = test_free_ind; + return 0; +} + +krb5_error_code +certauth_test2_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable); +krb5_error_code +certauth_test2_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_certauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_certauth_vtable)vtable; + vt->name = "test2"; + vt->authorize = test2_authorize; + vt->init = test2_init; + vt->fini = test2_fini; + vt->free_ind = test_free_ind; + return 0; +} diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h index b483aff..49b96b8 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto.h +++ b/src/plugins/preauth/pkinit/pkinit_crypto.h @@ -664,4 +664,8 @@ extern const size_t krb5_pkinit_sha512_oid_len; */ extern krb5_data const * const supported_kdf_alg_ids[]; +krb5_error_code +crypto_encode_der_cert(krb5_context context, pkinit_req_crypto_context reqctx, + uint8_t **der_out, size_t *der_len); + #endif /* _PKINIT_CRYPTO_H */ diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c index 2ea2a49..c79edae 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c @@ -2133,6 +2133,7 @@ crypto_retrieve_X509_sans(krb5_context context, if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) { pkiDebug("%s: found no subject alt name extensions\n", __FUNCTION__); + retval = ENOENT; goto cleanup; } num_sans = sk_GENERAL_NAME_num(ialt); @@ -6165,3 +6166,32 @@ crypto_get_deferred_ids(krb5_context context, ret = (const pkinit_deferred_id *)deferred; return ret; } + +/* Return the received certificate as DER-encoded data. */ +krb5_error_code +crypto_encode_der_cert(krb5_context context, pkinit_req_crypto_context reqctx, + uint8_t **der_out, size_t *der_len) +{ + int len; + unsigned char *der, *p; + + *der_out = NULL; + *der_len = 0; + + if (reqctx->received_cert == NULL) + return EINVAL; + p = NULL; + len = i2d_X509(reqctx->received_cert, NULL); + if (len <= 0) + return EINVAL; + p = der = malloc(len); + if (p == NULL) + return ENOMEM; + if (i2d_X509(reqctx->received_cert, &p) <= 0) { + free(p); + return EINVAL; + } + *der_out = der; + *der_len = len; + return 0; +} diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c index b5638a3..731d14e 100644 --- a/src/plugins/preauth/pkinit/pkinit_srv.c +++ b/src/plugins/preauth/pkinit/pkinit_srv.c @@ -31,6 +31,25 @@ #include <k5-int.h> #include "pkinit.h" +#include "krb5/certauth_plugin.h" + +/* Aliases used by the built-in certauth modules */ +struct certauth_req_opts { + krb5_kdcpreauth_callbacks cb; + krb5_kdcpreauth_rock rock; + pkinit_kdc_context plgctx; + pkinit_kdc_req_context reqctx; +}; + +typedef struct certauth_module_handle_st { + struct krb5_certauth_vtable_st vt; + krb5_certauth_moddata moddata; +} *certauth_handle; + +struct krb5_kdcpreauth_moddata_st { + pkinit_kdc_context *realm_contexts; + certauth_handle *certauth_modules; +}; static krb5_error_code pkinit_init_kdc_req_context(krb5_context, pkinit_kdc_req_context *blob); @@ -51,6 +70,34 @@ pkinit_find_realm_context(krb5_context context, krb5_kdcpreauth_moddata moddata, krb5_principal princ); +static void +free_realm_contexts(krb5_context context, pkinit_kdc_context *realm_contexts) +{ + int i; + + if (realm_contexts == NULL) + return; + for (i = 0; realm_contexts[i] != NULL; i++) + pkinit_server_plugin_fini_realm(context, realm_contexts[i]); + pkiDebug("%s: freeing context at %p\n", __FUNCTION__, realm_contexts); + free(realm_contexts); +} + +static void +free_certauth_handles(krb5_context context, certauth_handle *list) +{ + int i; + + if (list == NULL) + return; + for (i = 0; list[i] != NULL; i++) { + if (list[i]->vt.fini != NULL) + list[i]->vt.fini(context, list[i]->moddata); + free(list[i]); + } + free(list); +} + static krb5_error_code pkinit_create_edata(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, @@ -123,7 +170,7 @@ verify_client_san(krb5_context context, pkinit_kdc_req_context reqctx, krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, - krb5_principal client, + krb5_const_principal client, int *valid_san) { krb5_error_code retval; @@ -134,12 +181,15 @@ verify_client_san(krb5_context context, char *client_string = NULL, *san_string; #endif + *valid_san = 0; retval = crypto_retrieve_cert_sans(context, plgctx->cryptoctx, reqctx->cryptoctx, plgctx->idctx, &princs, plgctx->opts->allow_upn ? &upns : NULL, NULL); - if (retval) { + if (retval == ENOENT) { + goto out; + } else if (retval) { pkiDebug("%s: error from retrieve_certificate_sans()\n", __FUNCTION__); retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH; goto out; @@ -273,6 +323,73 @@ out: return retval; } + +/* Run the received, verified certificate through certauth modules, to verify + * that it is authorized to authenticate as client. */ +static krb5_error_code +authorize_cert(krb5_context context, certauth_handle *certauth_modules, + pkinit_kdc_context plgctx, pkinit_kdc_req_context reqctx, + krb5_kdcpreauth_callbacks cb, krb5_kdcpreauth_rock rock, + krb5_principal client) +{ + krb5_error_code ret; + certauth_handle h; + struct certauth_req_opts opts; + krb5_boolean accepted = FALSE; + uint8_t *cert; + size_t i, cert_len; + void *db_ent = NULL; + char **ais = NULL, **ai = NULL; + + /* Re-encode the received certificate into DER, which is extra work, but + * avoids creating an X.509 library dependency in the interface. */ + ret = crypto_encode_der_cert(context, reqctx->cryptoctx, &cert, &cert_len); + if (ret) + goto cleanup; + + /* Set options for the builtin module. */ + opts.plgctx = plgctx; + opts.reqctx = reqctx; + opts.cb = cb; + opts.rock = rock; + + db_ent = cb->client_entry(context, rock); + + /* + * Check the certificate against each certauth module. For the certificate + * to be authorized at least one module must return 0, and no module can an + * error code other than KRB5_PLUGIN_NO_HANDLE (pass). Add indicators from + * modules that return 0 or pass. + */ + ret = KRB5_PLUGIN_NO_HANDLE; + for (i = 0; certauth_modules != NULL && certauth_modules[i] != NULL; i++) { + h = certauth_modules[i]; + ret = h->vt.authorize(context, h->moddata, cert, cert_len, client, + &opts, db_ent, &ais); + if (ret == 0) + accepted = TRUE; + else if (ret != KRB5_PLUGIN_NO_HANDLE) + goto cleanup; + + if (ais != NULL) { + /* Assert authentication indicators from the module. */ + for (ai = ais; *ai != NULL; ai++) { + ret = cb->add_auth_indicator(context, rock, *ai); + if (ret) + goto cleanup; + } + h->vt.free_ind(context, h->moddata, ais); + ais = NULL; + } + } + + ret = accepted ? 0 : KRB5KDC_ERR_CLIENT_NAME_MISMATCH; + +cleanup: + free(cert); + return ret; +} + static void pkinit_server_verify_padata(krb5_context context, krb5_data *req_pkt, @@ -295,7 +412,6 @@ pkinit_server_verify_padata(krb5_context context, pkinit_kdc_req_context reqctx = NULL; krb5_checksum cksum = {0, 0, 0, NULL}; krb5_data *der_req = NULL; - int valid_eku = 0, valid_san = 0; krb5_data k5data; int is_signed = 1; krb5_pa_data **e_data = NULL; @@ -388,27 +504,11 @@ pkinit_server_verify_padata(krb5_context context, goto cleanup; } if (is_signed) { - - retval = verify_client_san(context, plgctx, reqctx, cb, rock, - request->client, &valid_san); - if (retval) - goto cleanup; - if (!valid_san) { - pkiDebug("%s: did not find an acceptable SAN in user " - "certificate\n", __FUNCTION__); - retval = KRB5KDC_ERR_CLIENT_NAME_MISMATCH; - goto cleanup; - } - retval = verify_client_eku(context, plgctx, reqctx, &valid_eku); + retval = authorize_cert(context, moddata->certauth_modules, plgctx, + reqctx, cb, rock, request->client); if (retval) goto cleanup; - if (!valid_eku) { - pkiDebug("%s: did not find an acceptable EKU in user " - "certificate\n", __FUNCTION__); - retval = KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE; - goto cleanup; - } } else { /* !is_signed */ if (!krb5_principal_compare(context, request->client, krb5_anonymous_principal())) { @@ -1245,11 +1345,15 @@ pkinit_find_realm_context(krb5_context context, krb5_principal princ) { int i; - pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata; + pkinit_kdc_context *realm_contexts; if (moddata == NULL) return NULL; + realm_contexts = moddata->realm_contexts; + if (realm_contexts == NULL) + return NULL; + for (i = 0; realm_contexts[i] != NULL; i++) { pkinit_kdc_context p = realm_contexts[i]; @@ -1331,6 +1435,155 @@ errout: return retval; } +static krb5_error_code +pkinit_san_authorize(krb5_context context, krb5_certauth_moddata moddata, + const uint8_t *cert, size_t cert_len, + krb5_const_principal princ, const void *opts, + const krb5_db_entry *db_entry, char ***authinds_out) +{ + krb5_error_code ret; + int valid_san; + const struct certauth_req_opts *req_opts = opts; + + *authinds_out = NULL; + + ret = verify_client_san(context, req_opts->plgctx, req_opts->reqctx, + req_opts->cb, req_opts->rock, princ, &valid_san); + if (ret == ENOENT) + return KRB5_PLUGIN_NO_HANDLE; + else if (ret) + return ret; + + if (!valid_san) { + pkiDebug("%s: did not find an acceptable SAN in user certificate\n", + __FUNCTION__); + return KRB5KDC_ERR_CLIENT_NAME_MISMATCH; + } + + return 0; +} + +static krb5_error_code +pkinit_eku_authorize(krb5_context context, krb5_certauth_moddata moddata, + const uint8_t *cert, size_t cert_len, + krb5_const_principal princ, const void *opts, + const krb5_db_entry *db_entry, char ***authinds_out) +{ + krb5_error_code ret; + int valid_eku; + const struct certauth_req_opts *req_opts = opts; + + *authinds_out = NULL; + + /* Verify the client EKU. */ + ret = verify_client_eku(context, req_opts->plgctx, req_opts->reqctx, + &valid_eku); + if (ret) + return ret; + + if (!valid_eku) { + pkiDebug("%s: did not find an acceptable EKU in user certificate\n", + __FUNCTION__); + return KRB5KDC_ERR_INCONSISTENT_KEY_PURPOSE; + } + + return 0; +} + +static krb5_error_code +certauth_pkinit_san_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_certauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_certauth_vtable)vtable; + vt->name = "pkinit_san"; + vt->authorize = pkinit_san_authorize; + return 0; +} + +static krb5_error_code +certauth_pkinit_eku_initvt(krb5_context context, int maj_ver, int min_ver, + krb5_plugin_vtable vtable) +{ + krb5_certauth_vtable vt; + + if (maj_ver != 1) + return KRB5_PLUGIN_VER_NOTSUPP; + vt = (krb5_certauth_vtable)vtable; + vt->name = "pkinit_eku"; + vt->authorize = pkinit_eku_authorize; + return 0; +} + +static krb5_error_code +load_certauth_plugins(krb5_context context, certauth_handle **handle_out) +{ + krb5_error_code ret; + krb5_plugin_initvt_fn *modules = NULL, *mod; + certauth_handle *list = NULL, h; + size_t count; + + /* Register the builtin modules. */ + ret = k5_plugin_register(context, PLUGIN_INTERFACE_CERTAUTH, + "pkinit_san", certauth_pkinit_san_initvt); + if (ret) + goto cleanup; + + ret = k5_plugin_register(context, PLUGIN_INTERFACE_CERTAUTH, + "pkinit_eku", certauth_pkinit_eku_initvt); + if (ret) + goto cleanup; + + ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_CERTAUTH, &modules); + if (ret) + goto cleanup; + + /* Allocate handle list. */ + for (count = 0; modules[count]; count++); + list = k5calloc(count + 1, sizeof(*list), &ret); + if (list == NULL) + goto cleanup; + + /* Initialize each module, ignoring ones that fail. */ + count = 0; + for (mod = modules; *mod != NULL; mod++) { + h = k5calloc(1, sizeof(*h), &ret); + if (h == NULL) + goto cleanup; + + ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt); + if (ret) { + TRACE_CERTAUTH_VTINIT_FAIL(context, ret); + free(h); + continue; + } + h->moddata = NULL; + if (h->vt.init != NULL) { + ret = h->vt.init(context, &h->moddata); + if (ret) { + TRACE_CERTAUTH_INIT_FAIL(context, h->vt.name, ret); + free(h); + continue; + } + } + list[count++] = h; + list[count] = NULL; + } + list[count] = NULL; + + ret = 0; + *handle_out = list; + list = NULL; + +cleanup: + k5_plugin_free_modules(context, modules); + free_certauth_handles(context, list); + return ret; +} + static int pkinit_server_plugin_init(krb5_context context, krb5_kdcpreauth_moddata *moddata_out, @@ -1338,6 +1591,8 @@ pkinit_server_plugin_init(krb5_context context, { krb5_error_code retval = ENOMEM; pkinit_kdc_context plgctx, *realm_contexts = NULL; + certauth_handle *certauth_modules = NULL; + krb5_kdcpreauth_moddata moddata; size_t i, j; size_t numrealms; @@ -1368,16 +1623,22 @@ pkinit_server_plugin_init(krb5_context context, goto errout; } - *moddata_out = (krb5_kdcpreauth_moddata)realm_contexts; - retval = 0; - pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts); + retval = load_certauth_plugins(context, &certauth_modules); + if (retval) + goto errout; -errout: - if (retval) { - pkinit_server_plugin_fini(context, - (krb5_kdcpreauth_moddata)realm_contexts); - } + moddata = k5calloc(1, sizeof(*moddata), &retval); + if (moddata == NULL) + goto errout; + moddata->realm_contexts = realm_contexts; + moddata->certauth_modules = certauth_modules; + *moddata_out = moddata; + pkiDebug("%s: returning context at %p\n", __FUNCTION__, moddata); + return 0; +errout: + free_realm_contexts(context, realm_contexts); + free_certauth_handles(context, certauth_modules); return retval; } @@ -1405,17 +1666,11 @@ static void pkinit_server_plugin_fini(krb5_context context, krb5_kdcpreauth_moddata moddata) { - pkinit_kdc_context *realm_contexts = (pkinit_kdc_context *)moddata; - int i; - - if (realm_contexts == NULL) + if (moddata == NULL) return; - - for (i = 0; realm_contexts[i] != NULL; i++) { - pkinit_server_plugin_fini_realm(context, realm_contexts[i]); - } - pkiDebug("%s: freeing context at %p\n", __FUNCTION__, realm_contexts); - free(realm_contexts); + free_realm_contexts(context, moddata->realm_contexts); + free_certauth_handles(context, moddata->certauth_modules); + free(moddata); } static krb5_error_code diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h index a3cc9cc..56821f1 100644 --- a/src/plugins/preauth/pkinit/pkinit_trace.h +++ b/src/plugins/preauth/pkinit/pkinit_trace.h @@ -93,4 +93,9 @@ #define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \ TRACE(c, "PKINIT OpenSSL error: {str}", msg) +#define TRACE_CERTAUTH_VTINIT_FAIL(c, ret) \ + TRACE(c, "certauth module failed to init vtable: {kerr}", ret) +#define TRACE_CERTAUTH_INIT_FAIL(c, name, ret) \ + TRACE(c, "certauth module {str} failed to init: {kerr}", name, ret) + #endif /* PKINIT_TRACE_H */ |