diff options
author | Kevin Coffman <kwc@citi.umich.edu> | 2007-03-06 15:31:40 +0000 |
---|---|---|
committer | Kevin Coffman <kwc@citi.umich.edu> | 2007-03-06 15:31:40 +0000 |
commit | 188f315fa1861dc1bafc9f1d0e3662968753f893 (patch) | |
tree | 6f8ad80a5f1d12f3cfdeafb39c9af39a2382648a | |
parent | 6a47113c611c962b01d813ecaf0f2eb7e715cb54 (diff) | |
download | krb5-188f315fa1861dc1bafc9f1d0e3662968753f893.zip krb5-188f315fa1861dc1bafc9f1d0e3662968753f893.tar.gz krb5-188f315fa1861dc1bafc9f1d0e3662968753f893.tar.bz2 |
Allow pkinit to support multiple realms within a single KDC.
Allow per-realm pkinit configuration.
- include/krb5/preauth_plugin.h
Add NULL-terminated realm name list to preauth_server_init_proc interface.
- kdc/kdc_preauth.c
Construct realm name list and pass it to preauth_server_init_proc
(and free it).
- plugins/preauth/pkinit/pkinit.h
Add realmname and name length to kdc (per-realm) plugin context.
Change interface to config/profile routines to pass the realm name.
- plugins/preauth/pkinit/pkinit_crypto_openssl.c
Restructure the init/fini functions a bit.
Make sure OBJ_cleanup() is only called once by using a refcount.
- plugins/preauth/pkinit/pkinit_profile.c
Change routines to pass in realm name rather than depending on
default_realm being set in the context.
- plugins/preauth/pkinit/pkinit_srv.c
Create a plugin context for each realm that should be supported.
Add function to find the correct realm context. Call it at the
beginning of each major preauth function (get_edata,
verify_padata, return_padata).
git-svn-id: svn://anonsvn.mit.edu/krb5/users/coffman/pkinit@19209 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r-- | src/include/krb5/preauth_plugin.h | 4 | ||||
-rw-r--r-- | src/kdc/kdc_preauth.c | 18 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit.h | 14 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 95 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_profile.c | 57 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_srv.c | 233 |
6 files changed, 296 insertions, 125 deletions
diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h index ef12840..f1106e4 100644 --- a/src/include/krb5/preauth_plugin.h +++ b/src/include/krb5/preauth_plugin.h @@ -337,7 +337,9 @@ typedef krb5_error_code /* Preauth plugin initialization function */ typedef krb5_error_code -(*preauth_server_init_proc)(krb5_context context, void **plugin_context); +(*preauth_server_init_proc)(krb5_context context, + void **plugin_context, + const char** realmnames); /* Preauth plugin cleanup function */ typedef void diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index e6c0e55..324b746 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -271,6 +271,7 @@ load_preauth_plugins(krb5_context context) int module_count, i, j, k; void *plugin_context; preauth_server_init_proc server_init_proc = NULL; + char **kdc_realm_names = NULL; memset(&err, 0, sizeof(err)); @@ -320,6 +321,18 @@ load_preauth_plugins(krb5_context context) return ENOMEM; } + /* Build a list of the names of the supported realms for this KDC. + * The list of names is terminated with a NULL. */ + kdc_realm_names = malloc(sizeof(char *) * (kdc_numrealms + 1)); + if (kdc_realm_names == NULL) { + krb5int_free_plugin_dir_data(preauth_plugins_ftables); + return ENOMEM; + } + for (i = 0; i < kdc_numrealms; i++) { + kdc_realm_names[i] = kdc_realmlist[i]->realm_name; + } + kdc_realm_names[i] = NULL; + /* Add the locally-supplied mechanisms to the dynamic list first. */ for (i = 0, k = 0; i < sizeof(static_preauth_systems) / sizeof(static_preauth_systems[0]); @@ -332,7 +345,7 @@ load_preauth_plugins(krb5_context context) plugin_context = NULL; server_init_proc = static_preauth_systems[i].init; if ((server_init_proc != NULL) && - ((*server_init_proc)(context, &plugin_context) != 0)) { + ((*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names) != 0)) { memset(&preauth_systems[k], 0, sizeof(preauth_systems[k])); continue; } @@ -361,7 +374,7 @@ load_preauth_plugins(krb5_context context) server_init_proc = ftable->init_proc; if (server_init_proc != NULL) { krb5_error_code initerr; - initerr = (*server_init_proc)(context, &plugin_context); + initerr = (*server_init_proc)(context, &plugin_context, (const char **)kdc_realm_names); if (initerr) { const char *emsg; emsg = krb5_get_error_message(context, initerr); @@ -400,6 +413,7 @@ load_preauth_plugins(krb5_context context) } krb5int_free_plugin_dir_data(preauth_plugins_ftables); } + free(kdc_realm_names); n_preauth_systems = k; /* Add the end-of-list marker. */ preauth_systems[k].name = "[end]"; diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h index 19dbb53..f8048ba 100644 --- a/src/plugins/preauth/pkinit/pkinit.h +++ b/src/plugins/preauth/pkinit/pkinit.h @@ -177,7 +177,7 @@ struct _pkinit_req_context { }; /* - * KDC's plugin context + * KDC's (per-realm) plugin context */ struct _pkinit_kdc_context { int magic; @@ -185,6 +185,8 @@ struct _pkinit_kdc_context { pkinit_plg_opts *opts; pkinit_identity_crypto_context idctx; pkinit_identity_opts *idopts; + char *realmname; + unsigned int realmname_len; }; /* @@ -675,14 +677,16 @@ void free_krb5_subject_pk_info(krb5_subject_pk_info **in); * Functions in pkinit_profile.c */ krb5_error_code pkinit_kdcdefault_strings - (krb5_context context, const char *option, char ***ret_value); + (krb5_context context, const char *realmname, const char *option, + char ***ret_value); krb5_error_code pkinit_kdcdefault_string - (krb5_context context, const char *option, char **ret_value); + (krb5_context context, const char *realmname, const char *option, + char **ret_value); krb5_error_code pkinit_kdcdefault_boolean - (krb5_context context, const char *option, + (krb5_context context, const char *realmname, const char *option, int default_value, int *ret_value); krb5_error_code pkinit_kdcdefault_integer - (krb5_context context, const char *option, + (krb5_context context, const char *realmname, const char *option, int default_value, int *ret_value); diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c index e9b2669..7922b00 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c @@ -162,24 +162,30 @@ unsigned char pkinit_4096_dhprime[4096/8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +static int pkinit_oids_refs = 0; + const krb5_octet_data dh_oid = { 0, 7, "\x2A\x86\x48\xce\x3e\x02\x01" }; -static krb5_error_code create_identifiers_from_stack(STACK_OF(X509) *sk, krb5_external_principal_identifier *** ids); +static krb5_error_code +create_identifiers_from_stack(STACK_OF(X509) *sk, + krb5_external_principal_identifier *** ids); krb5_error_code pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) { krb5_error_code retval = ENOMEM; - struct _pkinit_plg_crypto_context *ctx = NULL; + pkinit_plg_crypto_context ctx = NULL; /* initialize openssl routines */ openssl_init(); - ctx = (struct _pkinit_plg_crypto_context *)malloc(sizeof(*ctx)); + ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx)); if (ctx == NULL) goto out; memset(ctx, 0, sizeof(*ctx)); + pkiDebug("%s: initializing openssl crypto context at %p\n", + __FUNCTION__, ctx); retval = pkinit_init_pkinit_oids(ctx); if (retval) goto out; @@ -191,10 +197,8 @@ pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) { *cryptoctx = ctx; out: - if (retval) { - free(ctx); - OBJ_cleanup(); - } + if (retval && ctx != NULL) + pkinit_fini_plg_crypto(ctx); return retval; } @@ -202,22 +206,22 @@ out: void pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx) { - struct _pkinit_plg_crypto_context *ctx = cryptoctx; + pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx); - if (ctx == NULL) + if (cryptoctx == NULL) return; - pkinit_fini_pkinit_oids(ctx); - pkinit_fini_dh_params(ctx); - free(ctx); + pkinit_fini_pkinit_oids(cryptoctx); + pkinit_fini_dh_params(cryptoctx); + free(cryptoctx); } krb5_error_code pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx) { krb5_error_code retval = ENOMEM; - struct _pkinit_identity_crypto_context *ctx = NULL; + pkinit_identity_crypto_context ctx = NULL; - ctx = (struct _pkinit_identity_crypto_context *)malloc(sizeof(*ctx)); + ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx)); if (ctx == NULL) goto out; memset(ctx, 0, sizeof(*ctx)); @@ -230,13 +234,13 @@ pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx) if (retval) goto out; - pkiDebug("pkinit_init_identity_crypto: returning ctx at %p\n", ctx); + pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx); *idctx = ctx; out: if (retval) { - free(ctx); - OBJ_cleanup(); + if (ctx) + pkinit_fini_identity_crypto(ctx); } return retval; @@ -245,15 +249,13 @@ out: void pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx) { - struct _pkinit_identity_crypto_context *ctx = idctx; - - if (ctx == NULL) + if (idctx == NULL) return; - pkiDebug("pkinit_fini_identity_crypto: freeing ctx at %p\n", ctx); - pkinit_fini_certs(ctx); - pkinit_fini_pkcs11(ctx); - free(ctx); + pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, idctx); + pkinit_fini_certs(idctx); + pkinit_fini_pkcs11(idctx); + free(idctx); } krb5_error_code @@ -261,9 +263,9 @@ pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx) { krb5_error_code retval = ENOMEM; - struct _pkinit_req_crypto_context *ctx = NULL; + pkinit_req_crypto_context ctx = NULL; - ctx = (struct _pkinit_req_crypto_context *)malloc(sizeof(*ctx)); + ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx)); if (ctx == NULL) goto out; memset(ctx, 0, sizeof(*ctx)); @@ -273,7 +275,7 @@ pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx) *cryptoctx = ctx; - pkiDebug("pkinit_init_req_crypto: returning ctx at %p\n", ctx); + pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx); retval = 0; out: if (retval) @@ -283,20 +285,18 @@ out: } void -pkinit_fini_req_crypto(pkinit_req_crypto_context cryptoctx) +pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx) { - struct _pkinit_req_crypto_context *ctx = cryptoctx; - - if (ctx == NULL) + if (req_cryptoctx == NULL) return; - pkiDebug("pkinit_fini_req_crypto: freeing ctx at %p\n", ctx); - if (ctx->dh != NULL) - DH_free(ctx->dh); - if (ctx->received_cert != NULL) - X509_free(ctx->received_cert); + pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, req_cryptoctx); + if (req_cryptoctx->dh != NULL) + DH_free(req_cryptoctx->dh); + if (req_cryptoctx->received_cert != NULL) + X509_free(req_cryptoctx->received_cert); - free(ctx); + free(req_cryptoctx); } static krb5_error_code @@ -359,7 +359,9 @@ pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx) goto out; ctx->id_kp_serverAuth = (ASN1_OBJECT *)OBJ_nid2obj(tmp); + /* Success */ retval = 0; + pkinit_oids_refs++; out: return retval; @@ -368,7 +370,12 @@ out: static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx) { - OBJ_cleanup(); + if (ctx == NULL) + return; + + /* Only call OBJ_cleanup once! */ + if (--pkinit_oids_refs == 0) + OBJ_cleanup(); } static krb5_error_code @@ -450,6 +457,9 @@ pkinit_init_certs(pkinit_identity_crypto_context ctx) static void pkinit_fini_certs(pkinit_identity_crypto_context ctx) { + if (ctx == NULL) + return; + if (ctx->my_certs != NULL) sk_X509_pop_free(ctx->my_certs, X509_free); @@ -492,6 +502,9 @@ static void pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx) { #ifndef WITHOUT_PKCS11 + if (ctx == NULL) + return; + if (ctx->p11 != NULL) { if (ctx->session) { ctx->p11->C_CloseSession(ctx->session); @@ -1947,7 +1960,7 @@ server_process_dh(krb5_context context, static void openssl_init() { - static int did_init; + static int did_init = 0; if (!did_init) { /* initialize openssl routines */ @@ -2557,7 +2570,6 @@ openssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx) static ASN1_OBJECT * pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type) { - switch (pkcs7_type) { case CMS_SIGN_CLIENT: return cryptoctx->id_pkinit_authData; @@ -3735,7 +3747,8 @@ load_trusted_certifiers(STACK_OF(X509) **trusted_CAs, } static krb5_error_code -create_identifiers_from_stack(STACK_OF(X509) *sk, krb5_external_principal_identifier *** ids) +create_identifiers_from_stack(STACK_OF(X509) *sk, + krb5_external_principal_identifier *** ids) { krb5_error_code retval = ENOMEM; int i = 0, sk_size = sk_X509_num(sk); diff --git a/src/plugins/preauth/pkinit/pkinit_profile.c b/src/plugins/preauth/pkinit/pkinit_profile.c index 0159d63..0cbdf23 100644 --- a/src/plugins/preauth/pkinit/pkinit_profile.c +++ b/src/plugins/preauth/pkinit/pkinit_profile.c @@ -91,8 +91,8 @@ _krb5_conf_boolean(const char *s) * already been established. */ krb5_error_code -pkinit_kdcdefault_strings(krb5_context context, const char *option, - char ***ret_value) +pkinit_kdcdefault_strings(krb5_context context, const char *realmname, + const char *option, char ***ret_value) { profile_t profile = NULL; const char *names[5]; @@ -102,27 +102,26 @@ pkinit_kdcdefault_strings(krb5_context context, const char *option, if (context == NULL) return KV5M_CONTEXT; - if (context->default_realm == NULL) - return EINVAL; - profile = context->profile; - /* - * Try number one: - * - * [realms] - * REALM = { - * option = <value> - * } - */ + if (realmname != NULL) { + /* + * Try number one: + * + * [realms] + * REALM = { + * option = <value> + * } + */ - names[0] = "realms"; - names[1] = context->default_realm; - names[2] = option; - names[3] = 0; - retval = profile_get_values(profile, names, &values); - if (retval == 0 && values != NULL) - goto goodbye; + names[0] = "realms"; + names[1] = realmname; + names[2] = option; + names[3] = 0; + retval = profile_get_values(profile, names, &values); + if (retval == 0 && values != NULL) + goto goodbye; + } /* * Try number two: @@ -149,13 +148,13 @@ goodbye: } krb5_error_code -pkinit_kdcdefault_string(krb5_context context, const char *option, - char **ret_value) +pkinit_kdcdefault_string(krb5_context context, const char *realmname, + const char *option, char **ret_value) { krb5_error_code retval; char **values = NULL; - retval = pkinit_kdcdefault_strings(context, option, &values); + retval = pkinit_kdcdefault_strings(context, realmname, option, &values); if (retval) return retval; @@ -174,13 +173,13 @@ pkinit_kdcdefault_string(krb5_context context, const char *option, } krb5_error_code -pkinit_kdcdefault_boolean(krb5_context context, const char *option, - int default_value, int *ret_value) +pkinit_kdcdefault_boolean(krb5_context context, const char *realmname, + const char *option, int default_value, int *ret_value) { char *string = NULL; krb5_error_code retval; - retval = pkinit_kdcdefault_string(context, option, &string); + retval = pkinit_kdcdefault_string(context, realmname, option, &string); if (retval == 0) { *ret_value = _krb5_conf_boolean(string); @@ -192,13 +191,13 @@ pkinit_kdcdefault_boolean(krb5_context context, const char *option, } krb5_error_code -pkinit_kdcdefault_integer(krb5_context context, const char *option, - int default_value, int *ret_value) +pkinit_kdcdefault_integer(krb5_context context, const char *realmname, + const char *option, int default_value, int *ret_value) { char *string = NULL; krb5_error_code retval; - retval = pkinit_kdcdefault_string(context, option, &string); + retval = pkinit_kdcdefault_string(context, realmname, option, &string); if (retval == 0) { char *endptr; diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c index 56c7e27..4305ac4 100644 --- a/src/plugins/preauth/pkinit/pkinit_srv.c +++ b/src/plugins/preauth/pkinit/pkinit_srv.c @@ -76,13 +76,26 @@ static int pkinit_server_get_flags static krb5_error_code pkinit_init_kdc_req_context (krb5_context, void **blob); + static void pkinit_fini_kdc_req_context (krb5_context context, void *blob); + +static int pkinit_server_plugin_init_realm + (krb5_context context, const char *realmname, + pkinit_kdc_context *pplgctx); + +static void pkinit_server_plugin_fini_realm + (krb5_context context, pkinit_kdc_context plgctx); + static int pkinit_server_plugin_init - (krb5_context context, void **blob); + (krb5_context context, void **blob, const char **realmnames); + static void pkinit_server_plugin_fini (krb5_context context, void *blob); +static pkinit_kdc_context pkinit_find_realm_context + (krb5_context context, void *pa_plugin_context, krb5_principal princ); + static krb5_error_code pkinit_create_edata(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, @@ -132,7 +145,19 @@ pkinit_server_get_edata(krb5_context context, krb5_pa_data * data) { krb5_error_code retval = 0; + pkinit_kdc_context plgctx = NULL; + pkiDebug("pkinit_get_edata: entered!\n"); + + /* + * If we don't have a realm context for the given realm, + * don't tell the client that we support pkinit! + */ + plgctx = pkinit_find_realm_context(context, pa_plugin_context, + request->server); + if (plgctx == NULL) + retval = EINVAL; + return retval; } @@ -155,7 +180,7 @@ pkinit_server_verify_padata(krb5_context context, krb5_pa_pk_as_req_draft9 *reqp9 = NULL; krb5_auth_pack *auth_pack = NULL; krb5_auth_pack_draft9 *auth_pack9 = NULL; - pkinit_kdc_context plgctx = (pkinit_kdc_context)pa_plugin_context; + pkinit_kdc_context plgctx = NULL; pkinit_kdc_req_context reqctx; krb5_preauthtype pa_type; krb5_principal tmp_client; @@ -171,7 +196,12 @@ pkinit_server_verify_padata(krb5_context context, return 0; if (pa_plugin_context == NULL || e_data == NULL) - return -1; + return EINVAL; + + plgctx = pkinit_find_realm_context(context, pa_plugin_context, + request->server); + if (plgctx == NULL) + return 0; scratch.data = data->contents; scratch.length = data->length; @@ -227,7 +257,7 @@ pkinit_server_verify_padata(krb5_context context, pkiDebug("unrecognized pa_type = %d\n", data->pa_type); scratch.data = NULL; scratch.length = 0; - retval = -1; + retval = EINVAL; goto cleanup; } if (retval) { @@ -245,7 +275,6 @@ pkinit_server_verify_padata(krb5_context context, retval = KRB5KDC_ERR_CLIENT_NOT_TRUSTED; goto cleanup; } else { -#if 0 if (tmp_client != NULL) { retval = krb5_principal_compare(context, request->client, tmp_client); @@ -261,7 +290,6 @@ pkinit_server_verify_padata(krb5_context context, retval = KRB5KDC_ERR_CLIENT_NOT_TRUSTED; goto cleanup; } -#endif } retval = verify_id_pkinit_eku(context, plgctx->cryptoctx, reqctx->cryptoctx, @@ -491,7 +519,7 @@ pkinit_server_return_padata(krb5_context context, int num_types; krb5_cksumtype *cksum_types = NULL; - pkinit_kdc_context plgctx = (pkinit_kdc_context)pa_plugin_context; + pkinit_kdc_context plgctx; pkinit_kdc_req_context reqctx; *send_pa = NULL; @@ -500,8 +528,16 @@ pkinit_server_return_padata(krb5_context context, if (pa_request_context == NULL || *pa_request_context == NULL) { pkiDebug("missing request context \n"); - return -1; + return EINVAL; } + + plgctx = pkinit_find_realm_context(context, pa_plugin_context, + request->server); + if (plgctx == NULL) { + pkiDebug("Unable to locate correct realm context\n"); + return ENOENT; + } + pkiDebug("pkinit_return_padata: entered!\n"); reqctx = (pkinit_kdc_req_context)*pa_request_context; @@ -602,7 +638,8 @@ pkinit_server_return_padata(krb5_context context, goto cleanup; } #ifdef DEBUG_ASN1 - print_buffer_bin(encoded_dhkey_info->data, encoded_dhkey_info->length, "/tmp/kdc_dh_key_info"); + print_buffer_bin(encoded_dhkey_info->data, encoded_dhkey_info->length, + "/tmp/kdc_dh_key_info"); #endif switch ((int)padata->pa_type) { @@ -849,43 +886,55 @@ pkinit_init_kdc_profile(krb5_context context, pkinit_kdc_context plgctx) { krb5_error_code retval; - retval = pkinit_kdcdefault_string(context, "pkinit_identity", + pkiDebug("%s: entered for realm %s\n", __FUNCTION__, plgctx->realmname); + retval = pkinit_kdcdefault_string(context, plgctx->realmname, + "pkinit_identity", &plgctx->idopts->identity); if (retval != 0 || NULL == plgctx->idopts->identity) { retval = EINVAL; krb5_set_error_message(context, retval, - "No pkinit_identity supplied for the KDC"); + "No pkinit_identity supplied for realm %s", + plgctx->realmname); goto errout; } - retval = pkinit_kdcdefault_strings(context, "pkinit_anchors", + retval = pkinit_kdcdefault_strings(context, plgctx->realmname, + "pkinit_anchors", &plgctx->idopts->anchors); if (retval != 0 || NULL == plgctx->idopts->anchors) { retval = EINVAL; krb5_set_error_message(context, retval, - "No pkinit_anchors supplied for the KDC"); + "No pkinit_anchors supplied for realm %s", + plgctx->realmname); goto errout; } - pkinit_kdcdefault_strings(context, "pkinit_pool", + pkinit_kdcdefault_strings(context, plgctx->realmname, + "pkinit_pool", &plgctx->idopts->intermediates); - pkinit_kdcdefault_strings(context, "pkinit_revoke", + pkinit_kdcdefault_strings(context, plgctx->realmname, + "pkinit_revoke", &plgctx->idopts->crls); - pkinit_kdcdefault_string(context, "pkinit_kdc_ocsp", + pkinit_kdcdefault_string(context, plgctx->realmname, + "pkinit_kdc_ocsp", &plgctx->idopts->ocsp); - pkinit_kdcdefault_string(context, "pkinit_mappings_file", + pkinit_kdcdefault_string(context, plgctx->realmname, + "pkinit_mappings_file", &plgctx->idopts->dn_mapping_file); - pkinit_kdcdefault_boolean(context, "pkinit_principal_in_certificate", + pkinit_kdcdefault_boolean(context, plgctx->realmname, + "pkinit_principal_in_certificate", 1, &plgctx->opts->princ_in_cert); - pkinit_kdcdefault_boolean(context, "pkinit_allow_proxy_certificate", + pkinit_kdcdefault_boolean(context, plgctx->realmname, + "pkinit_allow_proxy_certificate", 0, &plgctx->opts->allow_proxy_certs); - pkinit_kdcdefault_integer(context, "pkinit_dh_min_bits", + pkinit_kdcdefault_integer(context, plgctx->realmname, + "pkinit_dh_min_bits", 0, &plgctx->opts->dh_min_bits); return 0; @@ -894,33 +943,65 @@ errout: return retval; } +static pkinit_kdc_context +pkinit_find_realm_context(krb5_context context, void *pa_plugin_context, + krb5_principal princ) +{ + int i; + pkinit_kdc_context *realm_contexts = pa_plugin_context; + + if (pa_plugin_context == NULL) + return NULL; + + for (i = 0; realm_contexts[i] != NULL; i++) { + pkinit_kdc_context p = realm_contexts[i]; + + if ((p->realmname_len == princ->realm.length) && + (strncmp(p->realmname, princ->realm.data, p->realmname_len) == 0)) { + pkiDebug("%s: returning context at %p for realm '%s'\n", + __FUNCTION__, p, p->realmname); + return p; + } + } + pkiDebug("%s: unable to find realm context for realm '%.*s'\n", + __FUNCTION__, princ->realm.length, princ->realm.data); + return NULL; +} + static int -pkinit_server_plugin_init(krb5_context context, void **blob) +pkinit_server_plugin_init_realm(krb5_context context, const char *realmname, + pkinit_kdc_context *pplgctx) { krb5_error_code retval = ENOMEM; - struct _pkinit_kdc_context *plgctx = NULL; + pkinit_kdc_context plgctx = NULL; + + *pplgctx = NULL; - plgctx = (struct _pkinit_kdc_context *)calloc(1, sizeof(*plgctx)); + plgctx = (pkinit_kdc_context) calloc(1, sizeof(*plgctx)); if (plgctx == NULL) - return ENOMEM; + goto errout; + + pkiDebug("%s: initializing context at %p for realm '%s'\n", + __FUNCTION__, plgctx, realmname); memset(plgctx, 0, sizeof(*plgctx)); plgctx->magic = PKINIT_CTX_MAGIC; - retval = pkinit_accessor_init(); - if (retval) - goto errout; + plgctx->realmname = strdup(realmname); + if (plgctx->realmname == NULL) + goto errout; + plgctx->realmname_len = strlen(plgctx->realmname); - retval = pkinit_init_plg_opts(&plgctx->opts); + retval = pkinit_init_plg_crypto(&plgctx->cryptoctx); if (retval) - goto errout; + goto errout; - retval = pkinit_init_plg_crypto(&plgctx->cryptoctx); + retval = pkinit_init_plg_opts(&plgctx->opts); if (retval) - goto errout; + goto errout; retval = pkinit_init_identity_crypto(&plgctx->idctx); if (retval) - goto errout; + goto errout; retval = pkinit_init_identity_opts(&plgctx->idopts); if (retval) @@ -932,45 +1013,104 @@ pkinit_server_plugin_init(krb5_context context, void **blob) retval = pkinit_initialize_identity(context, plgctx->idopts, plgctx->idctx); if (retval) - goto errout; + goto errout; + + pkiDebug("%s: returning context at %p for realm '%s'\n", + __FUNCTION__, plgctx, realmname); + *pplgctx = plgctx; + retval = 0; - *blob = plgctx; +errout: + if (retval) + pkinit_server_plugin_fini_realm(context, plgctx); - pkiDebug("%s: returning plgctx at %p\n", __FUNCTION__, plgctx); + return retval; +} + +static int +pkinit_server_plugin_init(krb5_context context, void **blob, + const char **realmnames) +{ + krb5_error_code retval = ENOMEM; + pkinit_kdc_context plgctx, *realm_contexts = NULL; + int i, j, numrealms; + + retval = pkinit_accessor_init(); + if (retval) + return retval; + + /* Determine how many realms we may need to support */ + for (i = 0; realmnames[i] != NULL; i++) {}; + numrealms = i; + + realm_contexts = (pkinit_kdc_context *) + calloc(numrealms+1, sizeof(pkinit_kdc_context)); + if (realm_contexts == NULL) + return ENOMEM; + + for (i = 0, j = 0; i < numrealms; i++) { + pkiDebug("%s: processing realm '%s'\n", __FUNCTION__, realmnames[i]); + retval = pkinit_server_plugin_init_realm(context, realmnames[i], &plgctx); + if (retval == 0 && plgctx != NULL) + realm_contexts[j++] = plgctx; + } + + if (j == 0) { + retval = EINVAL; + krb5_set_error_message(context, retval, "No realms configured " + "correctly for pkinit support"); + goto errout; + } + + *blob = realm_contexts; + retval = 0; + pkiDebug("%s: returning context at %p\n", __FUNCTION__, realm_contexts); errout: if (retval) - pkinit_server_plugin_fini(context, plgctx); + pkinit_server_plugin_fini(context, realm_contexts); return retval; } static void -pkinit_server_plugin_fini(krb5_context context, void *blob) +pkinit_server_plugin_fini_realm(krb5_context context, pkinit_kdc_context plgctx) { - struct _pkinit_kdc_context *plgctx = (struct _pkinit_kdc_context *) blob; - - if (plgctx == NULL || plgctx->magic != PKINIT_CTX_MAGIC) { - pkiDebug("pkinit_lib_fini: got bad plgctx (%p)!\n", plgctx); + if (plgctx == NULL) return; - } - pkiDebug("%s: freeing plgctx at %p\n", __FUNCTION__, plgctx); pkinit_fini_kdc_profile(context, plgctx); pkinit_fini_identity_opts(plgctx->idopts); pkinit_fini_identity_crypto(plgctx->idctx); pkinit_fini_plg_crypto(plgctx->cryptoctx); pkinit_fini_plg_opts(plgctx->opts); + free(plgctx->realmname); free(plgctx); } +static void +pkinit_server_plugin_fini(krb5_context context, void *blob) +{ + pkinit_kdc_context *realm_contexts = blob; + 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 krb5_error_code pkinit_init_kdc_req_context(krb5_context context, void **ctx) { krb5_error_code retval = ENOMEM; - struct _pkinit_kdc_req_context *reqctx = NULL; + pkinit_kdc_req_context reqctx = NULL; - reqctx = (struct _pkinit_kdc_req_context *)malloc(sizeof(*reqctx)); + reqctx = (pkinit_kdc_req_context)malloc(sizeof(*reqctx)); if (reqctx == NULL) return retval; memset(reqctx, 0, sizeof(*reqctx)); @@ -994,8 +1134,7 @@ cleanup: static void pkinit_fini_kdc_req_context(krb5_context context, void *ctx) { - struct _pkinit_kdc_req_context *reqctx = - (struct _pkinit_kdc_req_context *)ctx; + pkinit_kdc_req_context reqctx = (pkinit_kdc_req_context)ctx; if (reqctx == NULL || reqctx->magic != PKINIT_CTX_MAGIC) { pkiDebug("pkinit_fini_kdc_req_context: got bad reqctx (%p)!\n", reqctx); |