diff options
Diffstat (limited to 'source4/heimdal/lib/krb5')
91 files changed, 4331 insertions, 2729 deletions
diff --git a/source4/heimdal/lib/krb5/acache.c b/source4/heimdal/lib/krb5/acache.c index bd0a9846e4..0ecda99348 100644 --- a/source4/heimdal/lib/krb5/acache.c +++ b/source4/heimdal/lib/krb5/acache.c @@ -37,12 +37,8 @@ #include <dlfcn.h> #endif -RCSID("$Id$"); - -/* XXX should we fetch these for each open ? */ static HEIMDAL_MUTEX acc_mutex = HEIMDAL_MUTEX_INITIALIZER; static cc_initialize_func init_func; - #ifdef HAVE_DLOPEN static void *cc_handle; #endif @@ -135,7 +131,7 @@ init_ccapi(krb5_context context) #else HEIMDAL_MUTEX_unlock(&acc_mutex); krb5_set_error_message(context, KRB5_CC_NOSUPP, - N_("no support for shared object", "file, error")); + N_("no support for shared object", "")); return KRB5_CC_NOSUPP; #endif } @@ -342,6 +338,7 @@ make_ccred_from_cred(krb5_context context, addr->length = incred->addresses.val[i].address.length; addr->data = malloc(addr->length); if (addr->data == NULL) { + free(addr); ret = ENOMEM; goto fail; } @@ -490,16 +487,23 @@ acc_resolve(krb5_context context, krb5_ccache *id, const char *res) error = (*a->context->func->open_ccache)(a->context, res, &a->ccache); if (error == ccNoError) { + cc_time_t offset; error = get_cc_name(a); if (error != ccNoError) { acc_close(context, *id); *id = NULL; return translate_cc_error(context, error); } + + error = (*a->ccache->func->get_kdc_time_offset)(a->ccache, + cc_credentials_v5, + &offset); + if (error == 0) + context->kdc_sec_offset = offset; + } else if (error == ccErrCCacheNotFound) { a->ccache = NULL; a->cache_name = NULL; - error = 0; } else { *id = NULL; return translate_cc_error(context, error); @@ -572,6 +576,11 @@ acc_initialize(krb5_context context, name); } + if (error == 0 && context->kdc_sec_offset) + error = (*a->ccache->func->set_kdc_time_offset)(a->ccache, + cc_credentials_v5, + context->kdc_sec_offset); + return translate_cc_error(context, error); } @@ -946,8 +955,10 @@ acc_move(krb5_context context, krb5_ccache from, krb5_ccache to) return translate_cc_error(context, error); } - error = (*ato->ccache->func->move)(afrom->ccache, ato->ccache); + + acc_destroy(context, from); + return translate_cc_error(context, error); } diff --git a/source4/heimdal/lib/krb5/add_et_list.c b/source4/heimdal/lib/krb5/add_et_list.c index f08c0fe718..ccffd93b2c 100644 --- a/source4/heimdal/lib/krb5/add_et_list.c +++ b/source4/heimdal/lib/krb5/add_et_list.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Add a specified list of error messages to the et list in context. * Call func (probably a comerr-generated function) with a pointer to diff --git a/source4/heimdal/lib/krb5/addr_families.c b/source4/heimdal/lib/krb5/addr_families.c index 9e2fb3d63a..f88fb2276a 100644 --- a/source4/heimdal/lib/krb5/addr_families.c +++ b/source4/heimdal/lib/krb5/addr_families.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct addr_operations { int af; krb5_address_type atype; @@ -678,6 +676,9 @@ addrport_print_addr (const krb5_address *addr, char *str, size_t len) krb5_storage *sp; sp = krb5_storage_from_data((krb5_data*)rk_UNCONST(&addr->address)); + if (sp == NULL) + return ENOMEM; + /* for totally obscure reasons, these are not in network byteorder */ krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); @@ -1142,10 +1143,12 @@ krb5_parse_address(krb5_context context, for (a = ai, i = 0; a != NULL; a = a->ai_next) { if (krb5_sockaddr2address (context, ai->ai_addr, &addresses->val[i])) continue; - if(krb5_address_search(context, &addresses->val[i], addresses)) + if(krb5_address_search(context, &addresses->val[i], addresses)) { + krb5_free_address(context, &addresses->val[i]); continue; - addresses->len = i; + } i++; + addresses->len = i; } freeaddrinfo (ai); return 0; @@ -1454,7 +1457,6 @@ krb5_make_addrport (krb5_context context, *p++ = (2 >> 24) & 0xFF; memcpy (p, &port, 2); - p += 2; return 0; } diff --git a/source4/heimdal/lib/krb5/appdefault.c b/source4/heimdal/lib/krb5/appdefault.c index d49fc4997a..383e82dad4 100644 --- a/source4/heimdal/lib/krb5/appdefault.c +++ b/source4/heimdal/lib/krb5/appdefault.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - void KRB5_LIB_FUNCTION krb5_appdefault_boolean(krb5_context context, const char *appname, krb5_const_realm realm, const char *option, diff --git a/source4/heimdal/lib/krb5/asn1_glue.c b/source4/heimdal/lib/krb5/asn1_glue.c index cb86c324fb..59c0fbd64b 100644 --- a/source4/heimdal/lib/krb5/asn1_glue.c +++ b/source4/heimdal/lib/krb5/asn1_glue.c @@ -37,8 +37,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION _krb5_principal2principalname (PrincipalName *p, const krb5_principal from) @@ -52,13 +50,23 @@ _krb5_principalname2krb5_principal (krb5_context context, const PrincipalName from, const Realm realm) { - krb5_principal p = malloc(sizeof(*p)); + krb5_error_code ret; + krb5_principal p; + + p = malloc(sizeof(*p)); if (p == NULL) return ENOMEM; - copy_PrincipalName(&from, &p->name); + ret = copy_PrincipalName(&from, &p->name); + if (ret) { + free(p); + return ret; + } p->realm = strdup(realm); - if (p->realm == NULL) + if (p->realm == NULL) { + free_PrincipalName(&p->name); + free(p); return ENOMEM; + } *principal = p; return 0; } diff --git a/source4/heimdal/lib/krb5/auth_context.c b/source4/heimdal/lib/krb5/auth_context.c index 66eccbbc07..bfc183d168 100644 --- a/source4/heimdal/lib/krb5/auth_context.c +++ b/source4/heimdal/lib/krb5/auth_context.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_auth_con_init(krb5_context context, krb5_auth_context *auth_context) diff --git a/source4/heimdal/lib/krb5/build_ap_req.c b/source4/heimdal/lib/krb5/build_ap_req.c index 92c03cb782..1550239faf 100644 --- a/source4/heimdal/lib/krb5/build_ap_req.c +++ b/source4/heimdal/lib/krb5/build_ap_req.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_build_ap_req (krb5_context context, krb5_enctype enctype, diff --git a/source4/heimdal/lib/krb5/build_auth.c b/source4/heimdal/lib/krb5/build_auth.c index bbf4f274af..bf77fd4e77 100644 --- a/source4/heimdal/lib/krb5/build_auth.c +++ b/source4/heimdal/lib/krb5/build_auth.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code make_etypelist(krb5_context context, krb5_authdata **auth_data) @@ -81,12 +79,14 @@ make_etypelist(krb5_context context, ALLOC(*auth_data, 1); if (*auth_data == NULL) { + free(buf); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } ALLOC_SEQ(*auth_data, 1); if ((*auth_data)->val == NULL) { + free(*auth_data); free(buf); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; diff --git a/source4/heimdal/lib/krb5/cache.c b/source4/heimdal/lib/krb5/cache.c index 80b755cd27..12097470d5 100644 --- a/source4/heimdal/lib/krb5/cache.c +++ b/source4/heimdal/lib/krb5/cache.c @@ -33,7 +33,70 @@ #include "krb5_locl.h" -RCSID("$Id$"); +/** + * @page krb5_ccache_intro The credential cache functions + * @section section_krb5_ccache Kerberos credential caches + * + * krb5_ccache structure holds a Kerberos credential cache. + * + * Heimdal support the follow types of credential caches: + * + * - SCC + * Store the credential in a database + * - FILE + * Store the credential in memory + * - MEMORY + * Store the credential in memory + * - API + * A credential cache server based solution for Mac OS X + * - KCM + * A credential cache server based solution for all platforms + * + * @subsection Example + * + * This is a minimalistic version of klist: +@code +#include <krb5.h> + +int +main (int argc, char **argv) +{ + krb5_context context; + krb5_cc_cursor cursor; + krb5_error_code ret; + krb5_ccache id; + krb5_creds creds; + + if (krb5_init_context (&context) != 0) + errx(1, "krb5_context"); + + ret = krb5_cc_default (context, &id); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_default"); + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_start_seq_get"); + + while((ret = krb5_cc_next_cred(context, id, &cursor, &creds)) == 0){ + char *principal; + + krb5_unparse_name_short(context, creds.server, &principal); + printf("principal: %s\\n", principal); + free(principal); + krb5_free_cred_contents (context, &creds); + } + ret = krb5_cc_end_seq_get(context, id, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_end_seq_get"); + + krb5_cc_close(context, id); + + krb5_free_context(context); + return 0; +} +* @endcode +*/ /** * Add a new ccache type with operations `ops', overwriting any @@ -176,23 +239,6 @@ krb5_cc_resolve(krb5_context context, } /** - * Generate a new ccache of type `ops' in `id'. - * - * @return Return an error code or 0, see krb5_get_error_message(). - * - * @ingroup krb5_ccache - */ - - -krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_gen_new(krb5_context context, - const krb5_cc_ops *ops, - krb5_ccache *id) -{ - return krb5_cc_new_unique(context, ops->prefix, NULL, id); -} - -/** * Generates a new unique ccache of `type` in `id'. If `type' is NULL, * the library chooses the default credential cache type. The supplied * `hint' (that can be NULL) is a string that the credential cache @@ -221,7 +267,12 @@ krb5_cc_new_unique(krb5_context context, const char *type, ret = _krb5_cc_allocate(context, ops, id); if (ret) return ret; - return (*id)->ops->gen_new(context, id); + ret = (*id)->ops->gen_new(context, id); + if (ret) { + free(*id); + *id = NULL; + } + return ret; } /** @@ -676,7 +727,7 @@ krb5_cc_get_principal(krb5_context context, /** * Start iterating over `id', `cursor' is initialized to the - * beginning. + * beginning. Caller must free the cursor with krb5_cc_end_seq_get(). * * @return Return an error code or 0, see krb5_get_error_message(). * @@ -712,32 +763,6 @@ krb5_cc_next_cred (krb5_context context, } /** - * Like krb5_cc_next_cred, but allow for selective retrieval - * - * @ingroup krb5_ccache - */ - - -krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_next_cred_match(krb5_context context, - const krb5_ccache id, - krb5_cc_cursor * cursor, - krb5_creds * creds, - krb5_flags whichfields, - const krb5_creds * mcreds) -{ - krb5_error_code ret; - while (1) { - ret = krb5_cc_next_cred(context, id, cursor, creds); - if (ret) - return ret; - if (mcreds == NULL || krb5_compare_creds(context, whichfields, mcreds, creds)) - return 0; - krb5_free_cred_contents(context, creds); - } -} - -/** * Destroy the cursor `cursor'. * * @ingroup krb5_ccache @@ -806,25 +831,37 @@ krb5_cc_get_flags(krb5_context context, } /** - * Copy the contents of `from' to `to'. + * Copy the contents of `from' to `to' if the given match function + * return true. + * + * @param context A Kerberos 5 context. + * @param from the cache to copy data from. + * @param to the cache to copy data to. + * @param match a match function that should return TRUE if cred argument should be copied, if NULL, all credentials are copied. + * @param matchctx context passed to match function. + * @param matched set to true if there was a credential that matched, may be NULL. + * + * @return Return an error code or 0, see krb5_get_error_message(). * * @ingroup krb5_ccache */ - krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_copy_cache_match(krb5_context context, - const krb5_ccache from, - krb5_ccache to, - krb5_flags whichfields, - const krb5_creds * mcreds, - unsigned int *matched) +krb5_cc_copy_match_f(krb5_context context, + const krb5_ccache from, + krb5_ccache to, + krb5_boolean (*match)(krb5_context, void *, const krb5_creds *), + void *matchctx, + unsigned int *matched) { krb5_error_code ret; krb5_cc_cursor cursor; krb5_creds cred; krb5_principal princ; + if (matched) + *matched = 0; + ret = krb5_cc_get_principal(context, from, &princ); if (ret) return ret; @@ -838,24 +875,26 @@ krb5_cc_copy_cache_match(krb5_context context, krb5_free_principal(context, princ); return ret; } - if (matched) - *matched = 0; - while (ret == 0 && - krb5_cc_next_cred_match(context, from, &cursor, &cred, - whichfields, mcreds) == 0) { - if (matched) - (*matched)++; - ret = krb5_cc_store_cred(context, to, &cred); - krb5_free_cred_contents(context, &cred); + + while ((ret = krb5_cc_next_cred(context, from, &cursor, &cred)) == 0) { + if (match == NULL || (*match)(context, matchctx, &cred) == 0) { + if (matched) + (*matched)++; + ret = krb5_cc_store_cred(context, to, &cred); + if (ret) + break; + } + krb5_free_cred_contents(context, &cred); } krb5_cc_end_seq_get(context, from, &cursor); krb5_free_principal(context, princ); + if (ret == KRB5_CC_END) + ret = 0; return ret; } - /** - * Just like krb5_cc_copy_cache_match, but copy everything. + * Just like krb5_cc_copy_match_f(), but copy everything. * * @ingroup @krb5_ccache */ @@ -865,21 +904,7 @@ krb5_cc_copy_cache(krb5_context context, const krb5_ccache from, krb5_ccache to) { - return krb5_cc_copy_cache_match(context, from, to, 0, NULL, NULL); -} - -/** - * MIT compat glue - * - * @ingroup krb5_ccache - */ - -krb5_error_code KRB5_LIB_FUNCTION -krb5_cc_copy_creds(krb5_context context, - const krb5_ccache from, - krb5_ccache to) -{ - return krb5_cc_copy_cache(context, from, to); + return krb5_cc_copy_match_f(context, from, to, NULL, NULL, NULL); } /** @@ -1057,10 +1082,14 @@ krb5_cc_cache_end_seq_get (krb5_context context, } /** - * Search for a matching credential cache of type `type' that have the + * Search for a matching credential cache that have the * `principal' as the default principal. On success, `id' needs to be * freed with krb5_cc_close() or krb5_cc_destroy(). * + * @param context A Kerberos 5 context + * @param client The principal to search for + * @param id the returned credential cache + * * @return On failure, error code is returned and `id' is set to NULL. * * @ingroup krb5_ccache @@ -1082,7 +1111,7 @@ krb5_cc_cache_match (krb5_context context, if (ret) return ret; - while ((ret = krb5_cccol_cursor_next (context, cursor, &cache)) == 0) { + while (krb5_cccol_cursor_next (context, cursor, &cache) == 0 && cache != NULL) { krb5_principal principal; ret = krb5_cc_get_principal(context, cache, &principal); @@ -1107,7 +1136,7 @@ krb5_cc_cache_match (krb5_context context, krb5_unparse_name(context, client, &str); krb5_set_error_message(context, KRB5_CC_NOTFOUND, - N_("Principal %s not found in a " + N_("Principal %s not found in any " "credential cache", ""), str ? str : "<out of memory>"); if (str) @@ -1178,7 +1207,7 @@ build_conf_principals(krb5_context context, krb5_ccache id, } ret = krb5_make_principal(context, &cred->server, - krb5_principal_get_realm(context, client), + KRB5_REALM_NAME, KRB5_CONF_NAME, name, pname, NULL); free(pname); if (ret) { @@ -1224,7 +1253,7 @@ krb5_is_config_principal(krb5_context context, * @param principal configuration for a specific principal, if * NULL, global for the whole cache. * @param name name under which the configuraion is stored. - * @param data data to store + * @param data data to store, if NULL, configure is removed. * * @ingroup krb5_ccache */ @@ -1246,15 +1275,17 @@ krb5_cc_set_config(krb5_context context, krb5_ccache id, if (ret && ret != KRB5_CC_NOTFOUND) goto out; - /* not that anyone care when this expire */ - cred.times.authtime = time(NULL); - cred.times.endtime = cred.times.authtime + 3600 * 24 * 30; - - ret = krb5_data_copy(&cred.ticket, data->data, data->length); - if (ret) - goto out; - - ret = krb5_cc_store_cred(context, id, &cred); + if (data) { + /* not that anyone care when this expire */ + cred.times.authtime = time(NULL); + cred.times.endtime = cred.times.authtime + 3600 * 24 * 30; + + ret = krb5_data_copy(&cred.ticket, data->data, data->length); + if (ret) + goto out; + + ret = krb5_cc_store_cred(context, id, &cred); + } out: krb5_free_cred_contents (context, &cred); @@ -1345,6 +1376,8 @@ krb5_cccol_cursor_new(krb5_context context, krb5_cccol_cursor *cursor) * @param cache the returned cursor, pointer is set to NULL on failure * and a cache on success. The returned cache needs to be freed * with krb5_cc_close() or destroyed with krb5_cc_destroy(). + * MIT Kerberos behavies slightly diffrent and sets cache to NULL + * when all caches are iterated over and return 0. * * @return Return 0 or and error, KRB5_CC_END is returned at the end * of iteration. See krb5_get_error_message(). @@ -1446,7 +1479,7 @@ krb5_cc_last_change_time(krb5_context context, * and mtime is 0, there was no credentials in the caches. * * @param context A Kerberos 5 context - * @param id The credential cache to probe + * @param type The credential cache to probe, if NULL, all type are traversed. * @param mtime the last modification time, set to 0 on error. * @return Return 0 or and error. See krb5_get_error_message(). @@ -1470,7 +1503,7 @@ krb5_cccol_last_change_time(krb5_context context, if (ret) return ret; - while ((ret = krb5_cccol_cursor_next (context, cursor, &id)) == 0) { + while (krb5_cccol_cursor_next(context, cursor, &id) == 0 && id != NULL) { if (type && strcmp(krb5_cc_get_type(context, id), type) != 0) continue; @@ -1487,3 +1520,106 @@ krb5_cccol_last_change_time(krb5_context context, return 0; } +/** + * Return a friendly name on credential cache. Free the result with krb5_xfree(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_get_friendly_name(krb5_context context, + krb5_ccache id, + char **name) +{ + krb5_error_code ret; + krb5_data data; + + ret = krb5_cc_get_config(context, id, NULL, "FriendlyName", &data); + if (ret) { + krb5_principal principal; + ret = krb5_cc_get_principal(context, id, &principal); + if (ret) + return ret; + ret = krb5_unparse_name(context, principal, name); + krb5_free_principal(context, principal); + } else { + ret = asprintf(name, "%.*s", (int)data.length, (char *)data.data); + krb5_data_free(&data); + if (ret <= 0) { + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + } else + ret = 0; + } + + return ret; +} + +/** + * Set the friendly name on credential cache. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_set_friendly_name(krb5_context context, + krb5_ccache id, + const char *name) +{ + krb5_data data; + + data.data = rk_UNCONST(name); + data.length = strlen(name); + + return krb5_cc_set_config(context, id, NULL, "FriendlyName", &data); +} + +/** + * Get the lifetime of the initial ticket in the cache + * + * Get the lifetime of the initial ticket in the cache, if the initial + * ticket was not found, the error code KRB5_CC_END is returned. + * + * @param context A Kerberos 5 context. + * @param id a credential cache + * @param t the relative lifetime of the initial ticket + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_get_lifetime(krb5_context context, krb5_ccache id, time_t *t) +{ + krb5_cc_cursor cursor; + krb5_error_code ret; + krb5_creds cred; + time_t now; + + *t = 0; + now = time(NULL); + + ret = krb5_cc_start_seq_get(context, id, &cursor); + if (ret) + return ret; + + while ((ret = krb5_cc_next_cred(context, id, &cursor, &cred)) == 0) { + if (cred.flags.b.initial) { + if (now < cred.times.endtime) + *t = cred.times.endtime - now; + krb5_free_cred_contents(context, &cred); + goto out; + } + krb5_free_cred_contents(context, &cred); + } + + out: + krb5_cc_end_seq_get(context, id, &cursor); + + return ret; +} diff --git a/source4/heimdal/lib/krb5/changepw.c b/source4/heimdal/lib/krb5/changepw.c index 91ed9c5ba0..207b86b488 100644 --- a/source4/heimdal/lib/krb5/changepw.c +++ b/source4/heimdal/lib/krb5/changepw.c @@ -31,9 +31,9 @@ * SUCH DAMAGE. */ -#include <krb5_locl.h> +#define KRB5_DEPRECATED -RCSID("$Id$"); +#include <krb5_locl.h> #undef __attribute__ #define __attribute__(X) @@ -82,7 +82,6 @@ chgpw_send_request (krb5_context context, krb5_data passwd_data; size_t len; u_char header[6]; - u_char *p; struct iovec iov[3]; struct msghdr msghdr; @@ -118,13 +117,12 @@ chgpw_send_request (krb5_context context, goto out2; len = 6 + ap_req_data.length + krb_priv_data.length; - p = header; - *p++ = (len >> 8) & 0xFF; - *p++ = (len >> 0) & 0xFF; - *p++ = 0; - *p++ = 1; - *p++ = (ap_req_data.length >> 8) & 0xFF; - *p++ = (ap_req_data.length >> 0) & 0xFF; + header[0] = (len >> 8) & 0xFF; + header[1] = (len >> 0) & 0xFF; + header[2] = 0; + header[3] = 1; + header[4] = (ap_req_data.length >> 8) & 0xFF; + header[5] = (ap_req_data.length >> 0) & 0xFF; memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = NULL; @@ -231,7 +229,7 @@ setpw_send_request (krb5_context context, *p++ = 0xff; *p++ = 0x80; *p++ = (ap_req_data.length >> 8) & 0xFF; - *p++ = (ap_req_data.length >> 0) & 0xFF; + *p = (ap_req_data.length >> 0) & 0xFF; memset(&msghdr, 0, sizeof(msghdr)); msghdr.msg_name = NULL; @@ -693,7 +691,7 @@ krb5_change_password (krb5_context context, int *result_code, krb5_data *result_code_string, krb5_data *result_string) - __attribute__((deprecated)) + KRB5_DEPRECATED { struct kpwd_proc *p = find_chpw_proto("change password"); @@ -711,7 +709,7 @@ krb5_change_password (krb5_context context, #endif /* HEIMDAL_SMALLER */ /** - * Change passwrod using creds. + * Change password using creds. * * @param context a Keberos context * @param creds The initial kadmin/passwd for the principal or an admin principal @@ -767,8 +765,6 @@ krb5_set_password(krb5_context context, return ret; } -#ifndef HEIMDAL_SMALLER - /* * */ @@ -834,8 +830,6 @@ krb5_set_password_using_ccache(krb5_context context, return ret; } -#endif /* !HEIMDAL_SMALLER */ - /* * */ diff --git a/source4/heimdal/lib/krb5/codec.c b/source4/heimdal/lib/krb5/codec.c index bd0dcc5371..ebda3e51f7 100644 --- a/source4/heimdal/lib/krb5/codec.c +++ b/source4/heimdal/lib/krb5/codec.c @@ -31,12 +31,9 @@ * SUCH DAMAGE. */ -#include "krb5_locl.h" - -#undef __attribute__ -#define __attribute__(x) +#define KRB5_DEPRECATED -RCSID("$Id$"); +#include "krb5_locl.h" #ifndef HEIMDAL_SMALLER @@ -46,7 +43,7 @@ krb5_decode_EncTicketPart (krb5_context context, size_t length, EncTicketPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncTicketPart(data, length, t, len); } @@ -57,7 +54,7 @@ krb5_encode_EncTicketPart (krb5_context context, size_t length, EncTicketPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncTicketPart(data, length, t, len); } @@ -68,7 +65,7 @@ krb5_decode_EncASRepPart (krb5_context context, size_t length, EncASRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncASRepPart(data, length, t, len); } @@ -79,7 +76,7 @@ krb5_encode_EncASRepPart (krb5_context context, size_t length, EncASRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncASRepPart(data, length, t, len); } @@ -90,7 +87,7 @@ krb5_decode_EncTGSRepPart (krb5_context context, size_t length, EncTGSRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncTGSRepPart(data, length, t, len); } @@ -101,7 +98,7 @@ krb5_encode_EncTGSRepPart (krb5_context context, size_t length, EncTGSRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncTGSRepPart(data, length, t, len); } @@ -112,7 +109,7 @@ krb5_decode_EncAPRepPart (krb5_context context, size_t length, EncAPRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncAPRepPart(data, length, t, len); } @@ -123,7 +120,7 @@ krb5_encode_EncAPRepPart (krb5_context context, size_t length, EncAPRepPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncAPRepPart(data, length, t, len); } @@ -134,7 +131,7 @@ krb5_decode_Authenticator (krb5_context context, size_t length, Authenticator *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_Authenticator(data, length, t, len); } @@ -145,7 +142,7 @@ krb5_encode_Authenticator (krb5_context context, size_t length, Authenticator *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_Authenticator(data, length, t, len); } @@ -156,7 +153,7 @@ krb5_decode_EncKrbCredPart (krb5_context context, size_t length, EncKrbCredPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_EncKrbCredPart(data, length, t, len); } @@ -167,7 +164,7 @@ krb5_encode_EncKrbCredPart (krb5_context context, size_t length, EncKrbCredPart *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_EncKrbCredPart (data, length, t, len); } @@ -178,7 +175,7 @@ krb5_decode_ETYPE_INFO (krb5_context context, size_t length, ETYPE_INFO *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_ETYPE_INFO(data, length, t, len); } @@ -189,7 +186,7 @@ krb5_encode_ETYPE_INFO (krb5_context context, size_t length, ETYPE_INFO *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_ETYPE_INFO (data, length, t, len); } @@ -200,7 +197,7 @@ krb5_decode_ETYPE_INFO2 (krb5_context context, size_t length, ETYPE_INFO2 *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return decode_ETYPE_INFO2(data, length, t, len); } @@ -211,7 +208,7 @@ krb5_encode_ETYPE_INFO2 (krb5_context context, size_t length, ETYPE_INFO2 *t, size_t *len) - __attribute__((deprecated)) + KRB5_DEPRECATED { return encode_ETYPE_INFO2 (data, length, t, len); } diff --git a/source4/heimdal/lib/krb5/config_file.c b/source4/heimdal/lib/krb5/config_file.c index 75c48a001b..ee226c78a2 100644 --- a/source4/heimdal/lib/krb5/config_file.c +++ b/source4/heimdal/lib/krb5/config_file.c @@ -32,9 +32,6 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); - -#ifndef HAVE_NETINFO /* Gaah! I want a portable funopen */ struct fileptr { @@ -302,21 +299,65 @@ krb5_config_parse_string_multi(krb5_context context, return 0; } +/** + * Parse a configuration file and add the result into res. This + * interface can be used to parse several configuration files into one + * resulting krb5_config_section by calling it repeatably. + * + * @param context a Kerberos 5 context. + * @param fname a file name to a Kerberos configuration file + * @param res the returned result, must be free with krb5_free_config_files(). + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_config_parse_file_multi (krb5_context context, const char *fname, krb5_config_section **res) { const char *str; + char *newfname = NULL; unsigned lineno = 0; krb5_error_code ret; struct fileptr f; + + /** + * If the fname starts with "~/" parse configuration file in the + * current users home directory. The behavior can be disabled and + * enabled by calling krb5_set_home_dir_access(). + */ + if (_krb5_homedir_access(context) && fname[0] == '~' && fname[1] == '/') { + const char *home = NULL; + + if(!issuid()) + home = getenv("HOME"); + + if (home == NULL) { + struct passwd *pw = getpwuid(getuid()); + if(pw != NULL) + home = pw->pw_dir; + } + if (home) { + asprintf(&newfname, "%s%s", home, &fname[1]); + if (newfname == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + fname = newfname; + } + } + f.f = fopen(fname, "r"); f.s = NULL; if(f.f == NULL) { ret = errno; krb5_set_error_message (context, ret, "open %s: %s", fname, strerror(ret)); + if (newfname) + free(newfname); return ret; } @@ -324,8 +365,12 @@ krb5_config_parse_file_multi (krb5_context context, fclose(f.f); if (ret) { krb5_set_error_message (context, ret, "%s:%u: %s", fname, lineno, str); + if (newfname) + free(newfname); return ret; } + if (newfname) + free(newfname); return 0; } @@ -338,8 +383,6 @@ krb5_config_parse_file (krb5_context context, return krb5_config_parse_file_multi(context, fname, res); } -#endif /* !HAVE_NETINFO */ - static void free_binding (krb5_context context, krb5_config_binding *b) { diff --git a/source4/heimdal/lib/krb5/config_file_netinfo.c b/source4/heimdal/lib/krb5/config_file_netinfo.c deleted file mode 100644 index e6993bbb4a..0000000000 --- a/source4/heimdal/lib/krb5/config_file_netinfo.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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 "krb5_locl.h" -RCSID("$Id$"); - -/* - * Netinfo implementation from Luke Howard <lukeh@xedoc.com.au> - */ - -#ifdef HAVE_NETINFO -#include <netinfo/ni.h> -static ni_status -ni_proplist2binding(ni_proplist *pl, krb5_config_section **ret) -{ - int i, j; - krb5_config_section **next = NULL; - - for (i = 0; i < pl->ni_proplist_len; i++) { - if (!strcmp(pl->nipl_val[i].nip_name, "name")) - continue; - - for (j = 0; j < pl->nipl_val[i].nip_val.ni_namelist_len; j++) { - krb5_config_binding *b; - - b = malloc(sizeof(*b)); - if (b == NULL) - return NI_FAILED; - - b->next = NULL; - b->type = krb5_config_string; - b->name = ni_name_dup(pl->nipl_val[i].nip_name); - b->u.string = ni_name_dup(pl->nipl_val[i].nip_val.ninl_val[j]); - - if (next == NULL) { - *ret = b; - } else { - *next = b; - } - next = &b->next; - } - } - return NI_OK; -} - -static ni_status -ni_idlist2binding(void *ni, ni_idlist *idlist, krb5_config_section **ret) -{ - int i; - ni_status nis; - krb5_config_section **next; - - for (i = 0; i < idlist->ni_idlist_len; i++) { - ni_proplist pl; - ni_id nid; - ni_idlist children; - krb5_config_binding *b; - ni_index index; - - nid.nii_instance = 0; - nid.nii_object = idlist->ni_idlist_val[i]; - - nis = ni_read(ni, &nid, &pl); - - if (nis != NI_OK) { - return nis; - } - index = ni_proplist_match(pl, "name", NULL); - b = malloc(sizeof(*b)); - if (b == NULL) return NI_FAILED; - - if (i == 0) { - *ret = b; - } else { - *next = b; - } - - b->type = krb5_config_list; - b->name = ni_name_dup(pl.nipl_val[index].nip_val.ninl_val[0]); - b->next = NULL; - b->u.list = NULL; - - /* get the child directories */ - nis = ni_children(ni, &nid, &children); - if (nis == NI_OK) { - nis = ni_idlist2binding(ni, &children, &b->u.list); - if (nis != NI_OK) { - return nis; - } - } - - nis = ni_proplist2binding(&pl, b->u.list == NULL ? &b->u.list : &b->u.list->next); - ni_proplist_free(&pl); - if (nis != NI_OK) { - return nis; - } - next = &b->next; - } - ni_idlist_free(idlist); - return NI_OK; -} - -krb5_error_code KRB5_LIB_FUNCTION -krb5_config_parse_file (krb5_context context, - const char *fname, - krb5_config_section **res) -{ - void *ni = NULL, *lastni = NULL; - int i; - ni_status nis; - ni_id nid; - ni_idlist children; - - krb5_config_section *s; - int ret; - - s = NULL; - - for (i = 0; i < 256; i++) { - if (i == 0) { - nis = ni_open(NULL, ".", &ni); - } else { - if (lastni != NULL) ni_free(lastni); - lastni = ni; - nis = ni_open(lastni, "..", &ni); - } - if (nis != NI_OK) - break; - nis = ni_pathsearch(ni, &nid, "/locations/kerberos"); - if (nis == NI_OK) { - nis = ni_children(ni, &nid, &children); - if (nis != NI_OK) - break; - nis = ni_idlist2binding(ni, &children, &s); - break; - } - } - - if (ni != NULL) ni_free(ni); - if (ni != lastni && lastni != NULL) ni_free(lastni); - - ret = (nis == NI_OK) ? 0 : -1; - if (ret == 0) { - *res = s; - } else { - *res = NULL; - } - return ret; -} -#endif /* HAVE_NETINFO */ diff --git a/source4/heimdal/lib/krb5/constants.c b/source4/heimdal/lib/krb5/constants.c index b41fb3f663..a3b3d09f41 100644 --- a/source4/heimdal/lib/krb5/constants.c +++ b/source4/heimdal/lib/krb5/constants.c @@ -33,11 +33,16 @@ #include "krb5_locl.h" -RCSID("$Id$"); - KRB5_LIB_VARIABLE const char *krb5_config_file = #ifdef __APPLE__ +"~/Library/Preferences/edu.mit.Kerberos:" "/Library/Preferences/edu.mit.Kerberos:" #endif SYSCONFDIR "/krb5.conf:/etc/krb5.conf"; KRB5_LIB_VARIABLE const char *krb5_defkeyname = KEYTAB_DEFAULT; + +KRB5_LIB_VARIABLE const char *krb5_cc_type_api = "API"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_file = "FILE"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_memory = "MEMORY"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_kcm = "KCM"; +KRB5_LIB_VARIABLE const char *krb5_cc_type_scc = "SCC"; diff --git a/source4/heimdal/lib/krb5/context.c b/source4/heimdal/lib/krb5/context.c index 127dfa117d..fe94135030 100644 --- a/source4/heimdal/lib/krb5/context.c +++ b/source4/heimdal/lib/krb5/context.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <com_err.h> -RCSID("$Id$"); - #define INIT_FIELD(C, T, E, D, F) \ (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), \ "libdefaults", F, NULL) @@ -243,9 +241,7 @@ cc_ops_register(krb5_context context) krb5_cc_register(context, &krb5_acc_ops, TRUE); krb5_cc_register(context, &krb5_fcc_ops, TRUE); krb5_cc_register(context, &krb5_mcc_ops, TRUE); -#ifdef HAVE_SQLITE krb5_cc_register(context, &krb5_scc_ops, TRUE); -#endif #ifdef HAVE_KCM krb5_cc_register(context, &krb5_kcm_ops, TRUE); #endif @@ -310,6 +306,8 @@ krb5_init_context(krb5_context *context) } HEIMDAL_MUTEX_init(p->mutex); + p->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; + ret = krb5_get_default_config_files(&files); if(ret) goto out; @@ -336,7 +334,7 @@ out: * Make a copy for the Kerberos 5 context, allocated krb5_contex shoud * be freed with krb5_free_context(). * - * @param in the Kerberos context to copy + * @param context the Kerberos context to copy * @param out the copy of the Kerberos, set to NULL error. * * @return Returns 0 to indicate success. Otherwise an kerberos et @@ -453,10 +451,10 @@ krb5_free_context(krb5_context context) krb5_set_extra_addresses(context, NULL); krb5_set_ignore_addresses(context, NULL); krb5_set_send_to_kdc_func(context, NULL, NULL); - if (context->mutex != NULL) { - HEIMDAL_MUTEX_destroy(context->mutex); - free(context->mutex); - } + + HEIMDAL_MUTEX_destroy(context->mutex); + free(context->mutex); + memset(context, 0, sizeof(*context)); free(context); } @@ -552,7 +550,7 @@ krb5_prepend_config_files(const char *filelist, char **pq, char ***ret_pp) krb5_free_config_files(pp); return ENOMEM; } - l = strsep_copy(&p, ":", fn, l + 1); + (void)strsep_copy(&p, ":", fn, l + 1); ret = add_file(&pp, &len, fn); if (ret) { krb5_free_config_files(pp); @@ -641,7 +639,8 @@ krb5_get_default_config_files(char ***pfilenames) /** * Free a list of configuration files. * - * @param filenames list to be freed. + * @param filenames list, terminated with a NULL pointer, to be + * freed. NULL is an valid argument. * * @return Returns 0 to indicate success. Otherwise an kerberos et * error code is returned, see krb5_get_error_message(). @@ -653,7 +652,7 @@ void KRB5_LIB_FUNCTION krb5_free_config_files(char **filenames) { char **p; - for(p = filenames; *p != NULL; p++) + for(p = filenames; p && *p != NULL; p++) free(*p); free(filenames); } @@ -1226,3 +1225,115 @@ krb5_set_max_time_skew (krb5_context context, time_t t) { context->max_skew = t; } + +/** + * Init encryption types in len, val with etypes. + * + * @param context Kerberos 5 context. + * @param len output length of val. + * @param val output array of enctypes. + * @param etypes etypes to set val and len to, if NULL, use default enctypes. + + * @return Returns 0 to indicate success. Otherwise an kerberos et + * error code is returned, see krb5_get_error_message(). + * + * @ingroup krb5 + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_etype (krb5_context context, + unsigned *len, + krb5_enctype **val, + const krb5_enctype *etypes) +{ + unsigned int i; + krb5_error_code ret; + krb5_enctype *tmp = NULL; + + ret = 0; + if (etypes == NULL) { + ret = krb5_get_default_in_tkt_etypes(context, &tmp); + if (ret) + return ret; + etypes = tmp; + } + + for (i = 0; etypes[i]; ++i) + ; + *len = i; + *val = malloc(i * sizeof(**val)); + if (i != 0 && *val == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto cleanup; + } + memmove (*val, + etypes, + i * sizeof(*tmp)); +cleanup: + if (tmp != NULL) + free (tmp); + return ret; +} + +/* + * Allow homedir accces + */ + +static HEIMDAL_MUTEX homedir_mutex = HEIMDAL_MUTEX_INITIALIZER; +static krb5_boolean allow_homedir = TRUE; + +krb5_boolean +_krb5_homedir_access(krb5_context context) +{ + krb5_boolean allow; + + /* is never allowed for root */ + if (geteuid() == 0) + return FALSE; + + if (context && (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) == 0) + return FALSE; + + HEIMDAL_MUTEX_lock(&homedir_mutex); + allow = allow_homedir; + HEIMDAL_MUTEX_unlock(&homedir_mutex); + return allow; +} + +/** + * Enable and disable home directory access on either the global state + * or the krb5_context state. By calling krb5_set_home_dir_access() + * with context set to NULL, the global state is configured otherwise + * the state for the krb5_context is modified. + * + * For home directory access to be allowed, both the global state and + * the krb5_context state have to be allowed. + * + * Administrator (root user), never uses the home directory. + * + * @param context a Kerberos 5 context or NULL + * @param allow allow if TRUE home directory + * @return the old value + * + */ + +krb5_boolean +krb5_set_home_dir_access(krb5_context context, krb5_boolean allow) +{ + krb5_boolean old; + if (context) { + old = (context->flags & KRB5_CTX_F_HOMEDIR_ACCESS) ? TRUE : FALSE; + if (allow) + context->flags |= KRB5_CTX_F_HOMEDIR_ACCESS; + else + context->flags &= ~KRB5_CTX_F_HOMEDIR_ACCESS; + } else { + HEIMDAL_MUTEX_lock(&homedir_mutex); + old = allow_homedir; + allow_homedir = allow; + HEIMDAL_MUTEX_unlock(&homedir_mutex); + } + + return old; +} diff --git a/source4/heimdal/lib/krb5/convert_creds.c b/source4/heimdal/lib/krb5/convert_creds.c index fc81d96bec..35454bf983 100644 --- a/source4/heimdal/lib/krb5/convert_creds.c +++ b/source4/heimdal/lib/krb5/convert_creds.c @@ -32,10 +32,10 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); - #include "krb5-v4compat.h" +#ifndef HEIMDAL_SMALLER + static krb5_error_code check_ticket_flags(TicketFlags f) { @@ -204,3 +204,5 @@ krb524_convert_creds_kdc_ccache(krb5_context context, krb5_free_creds (context, v5_creds); return ret; } + +#endif diff --git a/source4/heimdal/lib/krb5/copy_host_realm.c b/source4/heimdal/lib/krb5/copy_host_realm.c index 37e27110b6..7f19ddd3de 100644 --- a/source4/heimdal/lib/krb5/copy_host_realm.c +++ b/source4/heimdal/lib/krb5/copy_host_realm.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Copy the list of realms from `from' to `to'. * diff --git a/source4/heimdal/lib/krb5/crc.c b/source4/heimdal/lib/krb5/crc.c index a900cabbba..eab946541d 100644 --- a/source4/heimdal/lib/krb5/crc.c +++ b/source4/heimdal/lib/krb5/crc.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - static u_long table[256]; #define CRC_GEN 0xEDB88320L diff --git a/source4/heimdal/lib/krb5/creds.c b/source4/heimdal/lib/krb5/creds.c index 087a4850eb..26c0dfbecb 100644 --- a/source4/heimdal/lib/krb5/creds.c +++ b/source4/heimdal/lib/krb5/creds.c @@ -33,23 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - -#undef __attribute__ -#define __attribute__(X) - -#ifndef HEIMDAL_SMALLER - -/* keep this for compatibility with older code */ -krb5_error_code KRB5_LIB_FUNCTION -krb5_free_creds_contents (krb5_context context, krb5_creds *c) - __attribute__((deprecated)) -{ - return krb5_free_cred_contents (context, c); -} - -#endif /* HEIMDAL_SMALLER */ - /** * Free content of krb5_creds. * @@ -235,9 +218,7 @@ krb5_compare_creds(krb5_context context, krb5_flags whichfields, } if (match && (whichfields & KRB5_TC_MATCH_KEYTYPE)) - match = krb5_enctypes_compatible_keys(context, - mcreds->session.keytype, - creds->session.keytype); + match = mcreds->session.keytype == creds->session.keytype; if (match && (whichfields & KRB5_TC_MATCH_FLAGS_EXACT)) match = mcreds->flags.i == creds->flags.i; diff --git a/source4/heimdal/lib/krb5/crypto.c b/source4/heimdal/lib/krb5/crypto.c index bc6512cf1a..9fd2117345 100644 --- a/source4/heimdal/lib/krb5/crypto.c +++ b/source4/heimdal/lib/krb5/crypto.c @@ -31,13 +31,11 @@ * SUCH DAMAGE. */ +#define KRB5_DEPRECATED + #include "krb5_locl.h" -RCSID("$Id$"); #include <pkinit_asn1.h> -#undef __attribute__ -#define __attribute__(X) - #define WEAK_ENCTYPES 1 #ifndef HEIMDAL_SMALLER @@ -164,6 +162,9 @@ static krb5_error_code hmac(krb5_context context, static void free_key_data(krb5_context, struct key_data *, struct encryption_type *); +static void free_key_schedule(krb5_context, + struct key_data *, + struct encryption_type *); static krb5_error_code usage2arcfour (krb5_context, unsigned *); static void xor (DES_cblock *, const unsigned char *); @@ -1158,7 +1159,16 @@ _key_schedule(krb5_context context, { krb5_error_code ret; struct encryption_type *et = _find_enctype(key->key->keytype); - struct key_type *kt = et->keytype; + struct key_type *kt; + + if (et == NULL) { + krb5_set_error_message (context, KRB5_PROG_ETYPE_NOSUPP, + N_("encryption type %d not supported", ""), + key->key->keytype); + return KRB5_PROG_ETYPE_NOSUPP; + } + + kt = et->keytype; if(kt->schedule == NULL) return 0; @@ -1841,14 +1851,25 @@ verify_checksum(krb5_context context, return KRB5KRB_AP_ERR_BAD_INTEGRITY; /* XXX */ } keyed_checksum = (ct->flags & F_KEYED) != 0; - if(keyed_checksum && crypto == NULL) { - krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, - N_("Checksum type %s is keyed but no " - "crypto context (key) was passed in", ""), - ct->name); - return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ - } if(keyed_checksum) { + struct checksum_type *kct; + if (crypto == NULL) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("Checksum type %s is keyed but no " + "crypto context (key) was passed in", ""), + ct->name); + return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ + } + kct = crypto->et->keyed_checksum; + if (kct != NULL && kct->type != ct->type) { + krb5_set_error_message (context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("Checksum type %s is keyed, but " + "the key type %s passed didnt have that checksum " + "type as the keyed type", ""), + ct->name, crypto->et->name); + return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ + } + ret = get_checksum_key(context, crypto, usage, ct, &dkey); if (ret) return ret; @@ -2348,10 +2369,11 @@ AES_PRF(krb5_context context, { const EVP_CIPHER *c = (*crypto->et->keytype->evp)(); EVP_CIPHER_CTX ctx; - /* XXX blksz 1 for cts, so we can't use that */ + EVP_CIPHER_CTX_init(&ctx); /* ivec all zero */ EVP_CipherInit_ex(&ctx, c, NULL, derived->keyvalue.data, NULL, 1); - EVP_Cipher(&ctx, out->data, result.checksum.data, 16); + EVP_Cipher(&ctx, out->data, result.checksum.data, + crypto->et->blocksize); EVP_CIPHER_CTX_cleanup(&ctx); } @@ -2737,17 +2759,6 @@ krb5_cksumtype_valid(krb5_context context, } -/* if two enctypes have compatible keys */ -krb5_boolean KRB5_LIB_FUNCTION -krb5_enctypes_compatible_keys(krb5_context context, - krb5_enctype etype1, - krb5_enctype etype2) -{ - struct encryption_type *e1 = _find_enctype(etype1); - struct encryption_type *e2 = _find_enctype(etype2); - return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; -} - static krb5_boolean derived_crypto(krb5_context context, krb5_crypto crypto) @@ -3147,10 +3158,10 @@ find_iv(krb5_crypto_iov *data, int num_data, int type) * Kerberos encrypted data look like this: * * 1. KRB5_CRYPTO_TYPE_HEADER - * 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in - * any order, however the receiver have to aware of the - * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used headers and - * trailers. + * 2. array [1,...] KRB5_CRYPTO_TYPE_DATA and array [0,...] + * KRB5_CRYPTO_TYPE_SIGN_ONLY in any order, however the receiver + * have to aware of the order. KRB5_CRYPTO_TYPE_SIGN_ONLY is + * commonly used headers and trailers. * 3. KRB5_CRYPTO_TYPE_PADDING, at least on padsize long if padsize > 1 * 4. KRB5_CRYPTO_TYPE_TRAILER */ @@ -3160,17 +3171,23 @@ krb5_encrypt_iov_ivec(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + int num_data, void *ivec) { size_t headersz, trailersz, len; - size_t i, sz, block_sz, pad_sz; + int i; + size_t sz, block_sz, pad_sz; Checksum cksum; unsigned char *p, *q; krb5_error_code ret; struct key_data *dkey; const struct encryption_type *et = crypto->et; - krb5_crypto_iov *tiv, *piv, *hiv; + krb5_crypto_iov *tiv, *piv, *hiv, *div; + + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } if(!derived_crypto(context, crypto)) { krb5_clear_error_message(context); @@ -3180,18 +3197,16 @@ krb5_encrypt_iov_ivec(krb5_context context, headersz = et->confoundersize; trailersz = CHECKSUMSIZE(et->keyed_checksum); - for (len = 0, i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_HEADER && - data[i].flags == KRB5_CRYPTO_TYPE_DATA) { - len += data[i].data.length; - } - } + div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA); + if (div == NULL) + return KRB5_CRYPTO_INTERNAL; + + len = div->data.length; sz = headersz + len; block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ pad_sz = block_sz - sz; - trailersz += pad_sz; /* header */ @@ -3278,13 +3293,9 @@ krb5_encrypt_iov_ivec(krb5_context context, /* XXX replace with EVP_Cipher */ - len = hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_PADDING) - continue; - len += data[i].data.length; - } + len = hiv->data.length + div->data.length; + if (piv) + len += piv->data.length; p = q = malloc(len); if(p == NULL) @@ -3292,13 +3303,9 @@ krb5_encrypt_iov_ivec(krb5_context context, memcpy(q, hiv->data.data, hiv->data.length); q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_PADDING) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; - } + memcpy(q, div->data.data, div->data.length); + q += div->data.length; + memset(q, 0, pad_sz); ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); if(ret) { @@ -3319,16 +3326,15 @@ krb5_encrypt_iov_ivec(krb5_context context, /* now copy data back to buffers */ q = p; + memcpy(hiv->data.data, q, hiv->data.length); q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_PADDING) - continue; - memcpy(data[i].data.data, q, data[i].data.length); - q += data[i].data.length; - } + memcpy(div->data.data, q, div->data.length); + q += div->data.length; + + if (piv) + memcpy(piv->data.data, q, pad_sz); free(p); return ret; @@ -3348,7 +3354,7 @@ krb5_encrypt_iov_ivec(krb5_context context, * @ingroup krb5_crypto * * 1. KRB5_CRYPTO_TYPE_HEADER - * 2. array KRB5_CRYPTO_TYPE_DATA and KRB5_CRYPTO_TYPE_SIGN_ONLY in + * 2. one KRB5_CRYPTO_TYPE_DATA and array [0,...] of KRB5_CRYPTO_TYPE_SIGN_ONLY in * any order, however the receiver have to aware of the * order. KRB5_CRYPTO_TYPE_SIGN_ONLY is commonly used unencrypoted * protocol headers and trailers. The output data will be of same @@ -3360,17 +3366,23 @@ krb5_decrypt_iov_ivec(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + unsigned int num_data, void *ivec) { + unsigned int i; size_t headersz, trailersz, len; - size_t i, sz, block_sz, pad_sz; + size_t sz, block_sz, pad_sz; Checksum cksum; unsigned char *p, *q; krb5_error_code ret; struct key_data *dkey; struct encryption_type *et = crypto->et; - krb5_crypto_iov *tiv, *hiv; + krb5_crypto_iov *tiv, *hiv, *div; + + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } if(!derived_crypto(context, crypto)) { krb5_clear_error_message(context); @@ -3380,9 +3392,13 @@ krb5_decrypt_iov_ivec(krb5_context context, headersz = et->confoundersize; trailersz = CHECKSUMSIZE(et->keyed_checksum); - for (len = 0, i = 0; i < num_data; i++) - if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) + for (len = 0, i = 0; i < num_data; i++) { + if (data[i].flags == KRB5_CRYPTO_TYPE_DATA) { + if (len != 0) + return KRB5_CRYPTO_INTERNAL; len += data[i].data.length; + } + } sz = headersz + len; block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ @@ -3404,7 +3420,9 @@ krb5_decrypt_iov_ivec(krb5_context context, return KRB5_BAD_MSIZE; tiv->data.length = trailersz; - /* body */ + div = find_iv(data, num_data, KRB5_CRYPTO_TYPE_DATA); + if (div == NULL) + return KRB5_CRYPTO_INTERNAL; /* XXX replace with EVP_Cipher */ @@ -3421,12 +3439,7 @@ krb5_decrypt_iov_ivec(krb5_context context, memcpy(q, hiv->data.data, hiv->data.length); q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; - } + memcpy(q, div->data.data, div->data.length); ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); if(ret) { @@ -3445,24 +3458,12 @@ krb5_decrypt_iov_ivec(krb5_context context, return ret; } - /* XXX now copy data back to buffers */ - q = p; - memcpy(hiv->data.data, q, hiv->data.length); - q += hiv->data.length; - len -= hiv->data.length; - - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - if (len < data[i].data.length) - data[i].data.length = len; - memcpy(data[i].data.data, q, data[i].data.length); - q += data[i].data.length; - len -= data[i].data.length; - } + /* copy data back to buffers */ + memcpy(hiv->data.data, p, hiv->data.length); + memcpy(div->data.data, p + hiv->data.length, len - hiv->data.length); free(p); - if (len) - krb5_abortx(context, "data still in the buffer"); + + /* check signature */ len = hiv->data.length; for (i = 0; i < num_data; i++) { @@ -3506,7 +3507,7 @@ krb5_decrypt_iov_ivec(krb5_context context, * @param usage Key usage for this buffer * @param data array of buffers to process * @param num_data length of array - * @param result output data + * @param type output data * * @return Return an error code or 0. * @ingroup krb5_crypto @@ -3517,16 +3518,21 @@ krb5_create_checksum_iov(krb5_context context, krb5_crypto crypto, unsigned usage, krb5_crypto_iov *data, - size_t num_data, + unsigned int num_data, krb5_cksumtype *type) { Checksum cksum; krb5_crypto_iov *civ; krb5_error_code ret; - unsigned int i; + int i; size_t len; char *p, *q; + if (num_data < 0) { + krb5_clear_error_message(context); + return KRB5_CRYPTO_INTERNAL; + } + if(!derived_crypto(context, crypto)) { krb5_clear_error_message(context); return KRB5_CRYPTO_INTERNAL; @@ -3765,18 +3771,6 @@ krb5_generate_random_block(void *buf, size_t len) krb5_abortx(NULL, "Failed to generate random block"); } -static void -DES3_postproc(krb5_context context, - unsigned char *k, size_t len, struct key_data *key) -{ - DES3_random_to_key(context, key->key, k, len); - - if (key->schedule) { - krb5_free_data(context, key->schedule); - key->schedule = NULL; - } -} - static krb5_error_code derive_key(krb5_context context, struct encryption_type *et, @@ -3784,7 +3778,7 @@ derive_key(krb5_context context, const void *constant, size_t len) { - unsigned char *k; + unsigned char *k = NULL; unsigned int nblocks = 0, i; krb5_error_code ret = 0; struct key_type *kt = et->keytype; @@ -3796,15 +3790,16 @@ derive_key(krb5_context context, nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8); k = malloc(nblocks * et->blocksize); if(k == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } ret = _krb5_n_fold(constant, len, k, et->blocksize); if (ret) { - free(k); krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - return ret; + goto out; } + for(i = 0; i < nblocks; i++) { if(i > 0) memcpy(k + i * et->blocksize, @@ -3819,30 +3814,31 @@ derive_key(krb5_context context, size_t res_len = (kt->bits + 7) / 8; if(len != 0 && c == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } memcpy(c, constant, len); (*et->encrypt)(context, key, c, len, 1, 0, NULL); k = malloc(res_len); if(res_len != 0 && k == NULL) { free(c); - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } ret = _krb5_n_fold(c, len, k, res_len); + free(c); if (ret) { - free(k); krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - return ret; + goto out; } - free(c); } /* XXX keytype dependent post-processing */ switch(kt->type) { case KEYTYPE_DES3: - DES3_postproc(context, k, nblocks * et->blocksize, key); + DES3_random_to_key(context, key->key, k, nblocks * et->blocksize); break; case KEYTYPE_AES128: case KEYTYPE_AES256: @@ -3855,12 +3851,15 @@ derive_key(krb5_context context, kt->type); break; } + out: if (key->schedule) { - krb5_free_data(context, key->schedule); + free_key_schedule(context, key, et); key->schedule = NULL; } - memset(k, 0, nblocks * et->blocksize); - free(k); + if (k) { + memset(k, 0, nblocks * et->blocksize); + free(k); + } return ret; } @@ -3983,15 +3982,24 @@ krb5_crypto_init(krb5_context context, } static void +free_key_schedule(krb5_context context, + struct key_data *key, + struct encryption_type *et) +{ + if (et->keytype->cleanup) + (*et->keytype->cleanup)(context, key); + memset(key->schedule->data, 0, key->schedule->length); + krb5_free_data(context, key->schedule); +} + +static void free_key_data(krb5_context context, struct key_data *key, struct encryption_type *et) { krb5_free_keyblock(context, key->key); if(key->schedule) { - if (et->keytype->cleanup) - (*et->keytype->cleanup)(context, key); - memset(key->schedule->data, 0, key->schedule->length); - krb5_free_data(context, key->schedule); + free_key_schedule(context, key, et); + key->schedule = NULL; } } @@ -4154,7 +4162,7 @@ krb5_string_to_key_derived(krb5_context context, return ret; } kd.schedule = NULL; - DES3_postproc (context, tmp, keylen, &kd); /* XXX */ + DES3_random_to_key(context, kd.key, tmp, keylen); memset(tmp, 0, keylen); free(tmp); ret = derive_key(context, @@ -4263,6 +4271,23 @@ krb5_crypto_overhead (krb5_context context, krb5_crypto crypto) return crypto_overhead (context, crypto); } +/** + * Converts the random bytestring to a protocol key according to + * Kerberos crypto frame work. It may be assumed that all the bits of + * the input string are equally random, even though the entropy + * present in the random source may be limited. + * + * @param context Kerberos 5 context + * @param type the enctype resulting key will be of + * @param data input random data to convert to a key + * @param data size of input random data, at least krb5_enctype_keysize() long + * @param data key, output key, free with krb5_free_keyblock_contents() + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_random_to_key(krb5_context context, krb5_enctype type, @@ -4312,7 +4337,7 @@ _krb5_pk_octetstring2key(krb5_context context, size_t keylen, offset; void *keydata; unsigned char counter; - unsigned char shaoutput[20]; + unsigned char shaoutput[SHA_DIGEST_LENGTH]; if(et == NULL) { krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, @@ -4463,9 +4488,9 @@ _krb5_pk_kdf(krb5_context context, size_t keylen, offset; uint32_t counter; unsigned char *keydata; - unsigned char shaoutput[20]; + unsigned char shaoutput[SHA_DIGEST_LENGTH]; - if (der_heim_oid_cmp(oid_id_pkinit_kdf_ah_sha1(), &ai->algorithm) != 0) { + if (der_heim_oid_cmp(&asn1_oid_id_pkinit_kdf_ah_sha1, &ai->algorithm) != 0) { krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP, N_("KDF not supported", "")); return KRB5_PROG_ETYPE_NOSUPP; @@ -4572,118 +4597,131 @@ krb5_crypto_prf(krb5_context context, return (*et->prf)(context, crypto, input, output); } -#ifndef HEIMDAL_SMALLER +static krb5_error_code +krb5_crypto_prfplus(krb5_context context, + const krb5_crypto crypto, + const krb5_data *input, + size_t length, + krb5_data *output) +{ + krb5_error_code ret; + krb5_data input2; + unsigned char i = 1; + unsigned char *p; -static struct key_type *keytypes[] = { - &keytype_null, - &keytype_des, - &keytype_des3_derived, -#ifdef DES3_OLD_ENCTYPE - &keytype_des3, -#endif - &keytype_aes128, - &keytype_aes256, - &keytype_arcfour -}; + krb5_data_zero(&input2); + krb5_data_zero(output); -static int num_keytypes = sizeof(keytypes) / sizeof(keytypes[0]); + krb5_clear_error_message(context); + ret = krb5_data_alloc(output, length); + if (ret) goto out; + ret = krb5_data_alloc(&input2, input->length + 1); + if (ret) goto out; -static struct key_type * -_find_keytype(krb5_keytype type) -{ - int i; - for(i = 0; i < num_keytypes; i++) - if(keytypes[i]->type == type) - return keytypes[i]; - return NULL; -} + krb5_clear_error_message(context); -/* - * First take the configured list of etypes for `keytype' if available, - * else, do `krb5_keytype_to_enctypes'. - */ + memcpy(((unsigned char *)input2.data) + 1, input->data, input->length); -krb5_error_code KRB5_LIB_FUNCTION -krb5_keytype_to_enctypes_default (krb5_context context, - krb5_keytype keytype, - unsigned *len, - krb5_enctype **val) - __attribute__((deprecated)) -{ - unsigned int i, n; - krb5_enctype *ret; + p = output->data; - if (keytype != KEYTYPE_DES || context->etypes_des == NULL) - return krb5_keytype_to_enctypes (context, keytype, len, val); + while (length) { + krb5_data block; - for (n = 0; context->etypes_des[n]; ++n) - ; - ret = malloc (n * sizeof(*ret)); - if (ret == NULL && n != 0) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - for (i = 0; i < n; ++i) - ret[i] = context->etypes_des[i]; - *len = n; - *val = ret; - return 0; -} + ((unsigned char *)input2.data)[0] = i++; -krb5_error_code KRB5_LIB_FUNCTION -krb5_keytype_to_string(krb5_context context, - krb5_keytype keytype, - char **string) - __attribute__((deprecated)) -{ - struct key_type *kt = _find_keytype(keytype); - if(kt == NULL) { - krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, - "key type %d not supported", keytype); - return KRB5_PROG_KEYTYPE_NOSUPP; - } - *string = strdup(kt->name); - if(*string == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = krb5_crypto_prf(context, crypto, &input2, &block); + if (ret) + goto out; + + if (block.length < length) { + memcpy(p, block.data, block.length); + length -= block.length; + } else { + memcpy(p, block.data, length); + length = 0; + } + p += block.length; + krb5_data_free(&block); } + + out: + krb5_data_free(&input2); + if (ret) + krb5_data_free(output); return 0; } +/** + * The FX-CF2 key derivation function, used in FAST and preauth framework. + * + * @param context Kerberos 5 context + * @param crypto1 first key to combine + * @param crypto2 second key to combine + * @param pepper1 factor to combine with first key to garante uniqueness + * @param pepper1 factor to combine with second key to garante uniqueness + * @param enctype the encryption type of the resulting key + * @param res allocated key, free with krb5_free_keyblock_contents() + * + * @return Return an error code or 0. + * + * @ingroup krb5_crypto + */ krb5_error_code KRB5_LIB_FUNCTION -krb5_string_to_keytype(krb5_context context, - const char *string, - krb5_keytype *keytype) - __attribute__((deprecated)) +krb5_crypto_fx_cf2(krb5_context context, + const krb5_crypto crypto1, + const krb5_crypto crypto2, + krb5_data *pepper1, + krb5_data *pepper2, + krb5_enctype enctype, + krb5_keyblock *res) { - char *end; - int i; + krb5_error_code ret; + krb5_data os1, os2; + size_t i, keysize; - for(i = 0; i < num_keytypes; i++) - if(strcasecmp(keytypes[i]->name, string) == 0){ - *keytype = keytypes[i]->type; - return 0; - } + memset(res, 0, sizeof(*res)); - /* check if the enctype is a number */ - *keytype = strtol(string, &end, 0); - if(*end == '\0' && *keytype != 0) { - if (krb5_enctype_valid(context, *keytype) == 0) - return 0; + ret = krb5_enctype_keysize(context, enctype, &keysize); + if (ret) + return ret; + + ret = krb5_data_alloc(&res->keyvalue, keysize); + if (ret) + goto out; + ret = krb5_crypto_prfplus(context, crypto1, pepper1, keysize, &os1); + if (ret) + goto out; + ret = krb5_crypto_prfplus(context, crypto2, pepper2, keysize, &os2); + if (ret) + goto out; + + res->keytype = enctype; + { + unsigned char *p1 = os1.data, *p2 = os2.data, *p3 = res->keyvalue.data; + for (i = 0; i < keysize; i++) + p3[i] = p1[i] ^ p2[i]; } + out: + if (ret) + krb5_data_free(&res->keyvalue); + krb5_data_free(&os1); + krb5_data_free(&os2); - krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, - "key type %s not supported", string); - return KRB5_PROG_KEYTYPE_NOSUPP; + return ret; } + + +#ifndef HEIMDAL_SMALLER + krb5_error_code KRB5_LIB_FUNCTION krb5_keytype_to_enctypes (krb5_context context, krb5_keytype keytype, unsigned *len, krb5_enctype **val) + KRB5_DEPRECATED { int i; unsigned n = 0; @@ -4691,18 +4729,26 @@ krb5_keytype_to_enctypes (krb5_context context, for (i = num_etypes - 1; i >= 0; --i) { if (etypes[i]->keytype->type == keytype - && !(etypes[i]->flags & F_PSEUDO)) + && !(etypes[i]->flags & F_PSEUDO) + && krb5_enctype_valid(context, etypes[i]->type) == 0) ++n; } + if (n == 0) { + krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, + "Keytype have no mapping"); + return KRB5_PROG_KEYTYPE_NOSUPP; + } + ret = malloc(n * sizeof(*ret)); if (ret == NULL && n != 0) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } n = 0; for (i = num_etypes - 1; i >= 0; --i) { if (etypes[i]->keytype->type == keytype - && !(etypes[i]->flags & F_PSEUDO)) + && !(etypes[i]->flags & F_PSEUDO) + && krb5_enctype_valid(context, etypes[i]->type) == 0) ret[n++] = etypes[i]->type; } *len = n; @@ -4710,4 +4756,16 @@ krb5_keytype_to_enctypes (krb5_context context, return 0; } +/* if two enctypes have compatible keys */ +krb5_boolean KRB5_LIB_FUNCTION +krb5_enctypes_compatible_keys(krb5_context context, + krb5_enctype etype1, + krb5_enctype etype2) + KRB5_DEPRECATED +{ + struct encryption_type *e1 = _find_enctype(etype1); + struct encryption_type *e2 = _find_enctype(etype2); + return e1 != NULL && e2 != NULL && e1->keytype == e2->keytype; +} + #endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/data.c b/source4/heimdal/lib/krb5/data.c index d6099c3c6c..993d6058bf 100644 --- a/source4/heimdal/lib/krb5/data.c +++ b/source4/heimdal/lib/krb5/data.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Reset the (potentially uninitalized) krb5_data structure. * @@ -52,7 +50,9 @@ krb5_data_zero(krb5_data *p) /** * Free the content of krb5_data structure, its ok to free a zeroed - * structure. When done, the structure will be zeroed. + * structure (with memset() or krb5_data_zero()). When done, the + * structure will be zeroed. The same function is called + * krb5_free_data_contents() in MIT Kerberos. * * @param p krb5_data to free. * @@ -68,21 +68,6 @@ krb5_data_free(krb5_data *p) } /** - * Same as krb5_data_free(). - * - * @param context Kerberos 5 context. - * @param data krb5_data to free. - * - * @ingroup krb5 - */ - -void KRB5_LIB_FUNCTION -krb5_free_data_contents(krb5_context context, krb5_data *data) -{ - krb5_data_free(data); -} - -/** * Free krb5_data (and its content). * * @param context Kerberos 5 context. diff --git a/source4/heimdal/lib/krb5/eai_to_heim_errno.c b/source4/heimdal/lib/krb5/eai_to_heim_errno.c index 594f998e26..499150f469 100644 --- a/source4/heimdal/lib/krb5/eai_to_heim_errno.c +++ b/source4/heimdal/lib/krb5/eai_to_heim_errno.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - /** * Convert the getaddrinfo() error code to a Kerberos et error code. * diff --git a/source4/heimdal/lib/krb5/error_string.c b/source4/heimdal/lib/krb5/error_string.c index 6374fa17ae..829c080a55 100644 --- a/source4/heimdal/lib/krb5/error_string.c +++ b/source4/heimdal/lib/krb5/error_string.c @@ -33,10 +33,8 @@ #include "krb5_locl.h" -RCSID("$Id$"); - #undef __attribute__ -#define __attribute__(X) +#define __attribute__(x) /** * Clears the error message from the Kerberos 5 context. @@ -172,6 +170,9 @@ krb5_get_error_message(krb5_context context, krb5_error_code code) } HEIMDAL_MUTEX_unlock(context->mutex); + if (code == 0) + return strdup("Success"); + cstr = krb5_get_err_text(context, code); if (cstr) return strdup(cstr); @@ -198,80 +199,3 @@ krb5_free_error_message(krb5_context context, const char *msg) { free(rk_UNCONST(msg)); } - -#ifndef HEIMDAL_SMALLER - -/** - * Free the error message returned by krb5_get_error_string(), - * deprecated, use krb5_free_error_message(). - * - * @param context Kerberos context - * @param msg error message to free - * - * @ingroup krb5_deprecated - */ - -void KRB5_LIB_FUNCTION -krb5_free_error_string(krb5_context context, char *str) - __attribute__((deprecated)) -{ - krb5_free_error_message(context, str); -} - -/** - * Set the error message returned by krb5_get_error_string(), - * deprecated, use krb5_set_error_message(). - * - * @param context Kerberos context - * @param msg error message to free - * - * @ingroup krb5_deprecated - */ - -krb5_error_code KRB5_LIB_FUNCTION -krb5_set_error_string(krb5_context context, const char *fmt, ...) - __attribute__((format (printf, 2, 3))) __attribute__((deprecated)) -{ - va_list ap; - - va_start(ap, fmt); - krb5_vset_error_message (context, 0, fmt, ap); - va_end(ap); - return 0; -} - -/** - * Set the error message returned by krb5_get_error_string(), - * deprecated, use krb5_set_error_message(). - * - * @param context Kerberos context - * @param msg error message to free - * - * @ingroup krb5_deprecated - */ - -krb5_error_code KRB5_LIB_FUNCTION -krb5_vset_error_string(krb5_context context, const char *fmt, va_list args) - __attribute__ ((format (printf, 2, 0))) __attribute__((deprecated)) -{ - krb5_vset_error_message(context, 0, fmt, args); - return 0; -} - -/** - * Clar the error message returned by krb5_get_error_string(), - * deprecated, use krb5_clear_error_message(). - * - * @param context Kerberos context - * - * @ingroup krb5_deprecated - */ - -void KRB5_LIB_FUNCTION -krb5_clear_error_string(krb5_context context) - __attribute__((deprecated)) -{ - krb5_clear_error_message(context); -} - -#endif /* !HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/expand_hostname.c b/source4/heimdal/lib/krb5/expand_hostname.c index a712d9c83a..67988d0d7b 100644 --- a/source4/heimdal/lib/krb5/expand_hostname.c +++ b/source4/heimdal/lib/krb5/expand_hostname.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - static krb5_error_code copy_hostname(krb5_context context, const char *orig_hostname, @@ -50,9 +48,19 @@ copy_hostname(krb5_context context, return 0; } -/* - * Try to make `orig_hostname' into a more canonical one in the newly - * allocated space returned in `new_hostname'. +/** + * krb5_expand_hostname() tries to make orig_hostname into a more + * canonical one in the newly allocated space returned in + * new_hostname. + + * @param context a Keberos context + * @param orig_hostname hostname to canonicalise. + * @param new_hostname output hostname, caller must free hostname with + * krb5_xfree(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support */ krb5_error_code KRB5_LIB_FUNCTION @@ -114,9 +122,22 @@ vanilla_hostname (krb5_context context, return 0; } -/* - * expand `hostname' to a name we believe to be a hostname in newly - * allocated space in `host' and return realms in `realms'. +/** + * krb5_expand_hostname_realms() expands orig_hostname to a name we + * believe to be a hostname in newly allocated space in new_hostname + * and return the realms new_hostname is believed to belong to in + * realms. + * + * @param context a Keberos context + * @param orig_hostname hostname to canonicalise. + * @param new_hostname output hostname, caller must free hostname with + * krb5_xfree(). + * @param realms output possible realms, is an array that is terminated + * with NULL. Caller must free with krb5_free_host_realm(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_support */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/fcache.c b/source4/heimdal/lib/krb5/fcache.c index b745c67e11..f8e74f1ddc 100644 --- a/source4/heimdal/lib/krb5/fcache.c +++ b/source4/heimdal/lib/krb5/fcache.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - typedef struct krb5_fcache{ char *filename; int version; @@ -233,8 +231,8 @@ scrub_file (int fd) * hardlink) */ -static krb5_error_code -erase_file(krb5_context context, const char *filename) +krb5_error_code +_krb5_erase_file(krb5_context context, const char *filename) { int fd; struct stat sb1, sb2; @@ -453,7 +451,7 @@ static krb5_error_code fcc_destroy(krb5_context context, krb5_ccache id) { - erase_file(context, FILENAME(id)); + _krb5_erase_file(context, FILENAME(id)); return 0; } @@ -740,8 +738,10 @@ fcc_remove_cred(krb5_context context, { krb5_error_code ret; krb5_ccache copy, newfile; + char *newname; + int fd; - ret = krb5_cc_gen_new(context, &krb5_mcc_ops, ©); + ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, ©); if (ret) return ret; @@ -757,8 +757,24 @@ fcc_remove_cred(krb5_context context, return ret; } - ret = krb5_cc_gen_new(context, &krb5_fcc_ops, &newfile); + asprintf(&newname, "FILE:%s.XXXXXX", FILENAME(id)); + if (newname == NULL) { + krb5_cc_destroy(context, copy); + return ret; + } + + fd = mkstemp(&newname[5]); + if (fd < 0) { + ret = errno; + krb5_cc_destroy(context, copy); + return ret; + } + close(fd); + + ret = krb5_cc_resolve(context, newname, &newfile); if (ret) { + unlink(&newname[5]); + free(newname); krb5_cc_destroy(context, copy); return ret; } @@ -766,11 +782,18 @@ fcc_remove_cred(krb5_context context, ret = krb5_cc_copy_cache(context, copy, newfile); krb5_cc_destroy(context, copy); if (ret) { + free(newname); krb5_cc_destroy(context, newfile); return ret; } - return krb5_cc_move(context, newfile, id); + ret = rename(&newname[5], FILENAME(id)); + if (ret) + ret = errno; + free(newname); + krb5_cc_close(context, newfile); + + return ret; } static krb5_error_code @@ -822,12 +845,13 @@ fcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id) iter->first = 0; fn = krb5_cc_default_name(context); - if (strncasecmp(fn, "FILE:", 5) != 0) { + if (fn == NULL || strncasecmp(fn, "FILE:", 5) != 0) { ret = _krb5_expand_default_cc_name(context, KRB5_DEFAULT_CCNAME_FILE, &expandedfn); if (ret) return ret; + fn = expandedfn; } ret = krb5_cc_resolve(context, fn, id); if (expandedfn) @@ -900,10 +924,10 @@ fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) fcc_unlock(context, fd1); close(fd1); - erase_file(context, FILENAME(from)); + _krb5_erase_file(context, FILENAME(from)); if (ret) { - erase_file(context, FILENAME(to)); + _krb5_erase_file(context, FILENAME(to)); return ret; } } @@ -913,10 +937,14 @@ fcc_move(krb5_context context, krb5_ccache from, krb5_ccache to) krb5_storage *sp; int fd; ret = init_fcc (context, to, &sp, &fd); - krb5_storage_free(sp); + if (sp) + krb5_storage_free(sp); fcc_unlock(context, fd); close(fd); } + + fcc_destroy(context, from); + return ret; } diff --git a/source4/heimdal/lib/krb5/free.c b/source4/heimdal/lib/krb5/free.c index da1eb1de1c..7f4374374b 100644 --- a/source4/heimdal/lib/krb5/free.c +++ b/source4/heimdal/lib/krb5/free.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_free_kdc_rep(krb5_context context, krb5_kdc_rep *rep) { diff --git a/source4/heimdal/lib/krb5/free_host_realm.c b/source4/heimdal/lib/krb5/free_host_realm.c index 581b61a15b..f6e9f6e247 100644 --- a/source4/heimdal/lib/krb5/free_host_realm.c +++ b/source4/heimdal/lib/krb5/free_host_realm.c @@ -33,10 +33,15 @@ #include "krb5_locl.h" -RCSID("$Id$"); - -/* +/** * Free all memory allocated by `realmlist' + * + * @param context A Kerberos 5 context. + * @param realmlist realmlist to free, NULL is ok + * + * @return a Kerberos error code, always 0. + * + * @ingroup krb5_support */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/generate_seq_number.c b/source4/heimdal/lib/krb5/generate_seq_number.c index 99745b8305..2764f1a914 100644 --- a/source4/heimdal/lib/krb5/generate_seq_number.c +++ b/source4/heimdal/lib/krb5/generate_seq_number.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_generate_seq_number(krb5_context context, const krb5_keyblock *key, diff --git a/source4/heimdal/lib/krb5/generate_subkey.c b/source4/heimdal/lib/krb5/generate_subkey.c index 4ab4b9bf6c..efb6cce288 100644 --- a/source4/heimdal/lib/krb5/generate_subkey.c +++ b/source4/heimdal/lib/krb5/generate_subkey.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_generate_subkey(krb5_context context, const krb5_keyblock *key, diff --git a/source4/heimdal/lib/krb5/get_addrs.c b/source4/heimdal/lib/krb5/get_addrs.c index ce16785319..8f366fa148 100644 --- a/source4/heimdal/lib/krb5/get_addrs.c +++ b/source4/heimdal/lib/krb5/get_addrs.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id: get_addrs.c 23815 2008-09-13 09:21:03Z lha $"); - #ifdef __osf__ /* hate */ struct rtentry; @@ -43,9 +41,7 @@ struct mbuf; #ifdef HAVE_NET_IF_H #include <net/if.h> #endif -#ifdef HAVE_IFADDR_H #include <ifaddrs.h> -#endif static krb5_error_code gethostname_fallback (krb5_context context, krb5_addresses *res) @@ -106,8 +102,6 @@ find_all_addresses (krb5_context context, krb5_addresses *res, int flags) unsigned int num, idx; krb5_addresses ignore_addresses; - res->val = NULL; - if (getifaddrs(&ifa0) == -1) { ret = errno; krb5_set_error_message(context, ret, "getifaddrs: %s", strerror(ret)); @@ -232,13 +226,14 @@ get_addrs_int (krb5_context context, krb5_addresses *res, int flags) { krb5_error_code ret = -1; + res->len = 0; + res->val = NULL; + if (flags & SCAN_INTERFACES) { ret = find_all_addresses (context, res, flags); if(ret || res->len == 0) ret = gethostname_fallback (context, res); } else { - res->len = 0; - res->val = NULL; ret = 0; } diff --git a/source4/heimdal/lib/krb5/get_cred.c b/source4/heimdal/lib/krb5/get_cred.c index 97e0022ee1..e609bcadcc 100644 --- a/source4/heimdal/lib/krb5/get_cred.c +++ b/source4/heimdal/lib/krb5/get_cred.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - /* * Take the `body' and encode it into `padata' using the credentials * in `creds'. @@ -375,17 +373,18 @@ decrypt_tkt_with_subkey (krb5_context context, if (ret) return ret; - ret = krb5_decode_EncASRepPart(context, - data.data, + ret = decode_EncASRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + if (ret) + ret = decode_EncTGSRepPart(data.data, data.length, &dec_rep->enc_part, &size); if (ret) - ret = krb5_decode_EncTGSRepPart(context, - data.data, - data.length, - &dec_rep->enc_part, - &size); + krb5_set_error_message(context, ret, + N_("Failed to decode encpart in ticket", "")); krb5_data_free (&data); return ret; } @@ -477,7 +476,7 @@ get_cred_kdc(krb5_context context, if (len != size) krb5_abortx(context, "internal asn1 error"); - ret = krb5_padata_add(context, &padata, KRB5_PADATA_S4U2SELF, buf, len); + ret = krb5_padata_add(context, &padata, KRB5_PADATA_FOR_USER, buf, len); if (ret) goto out; } @@ -561,7 +560,7 @@ get_cred_kdc(krb5_context context, } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); - } else if(resp.data && ((char*)resp.data)[0] == 4) { + } else if(resp.length > 0 && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_message(context); } else { @@ -1217,6 +1216,10 @@ krb5_get_creds_opt_free(krb5_context context, krb5_get_creds_opt opt) { if (opt->self) krb5_free_principal(context, opt->self); + if (opt->ticket) { + free_Ticket(opt->ticket); + free(opt->ticket); + } memset(opt, 0, sizeof(*opt)); free(opt); } diff --git a/source4/heimdal/lib/krb5/get_default_principal.c b/source4/heimdal/lib/krb5/get_default_principal.c index c804ab9e56..82d0642934 100644 --- a/source4/heimdal/lib/krb5/get_default_principal.c +++ b/source4/heimdal/lib/krb5/get_default_principal.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* * Try to find out what's a reasonable default principal. */ diff --git a/source4/heimdal/lib/krb5/get_default_realm.c b/source4/heimdal/lib/krb5/get_default_realm.c index a2518bbab7..f09df264c1 100644 --- a/source4/heimdal/lib/krb5/get_default_realm.c +++ b/source4/heimdal/lib/krb5/get_default_realm.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* * Return a NULL-terminated list of default realms in `realms'. * Free this memory with krb5_free_host_realm. diff --git a/source4/heimdal/lib/krb5/get_for_creds.c b/source4/heimdal/lib/krb5/get_for_creds.c index a7072a0136..19e48173df 100644 --- a/source4/heimdal/lib/krb5/get_for_creds.c +++ b/source4/heimdal/lib/krb5/get_for_creds.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code add_addrs(krb5_context context, krb5_addresses *addr, diff --git a/source4/heimdal/lib/krb5/get_host_realm.c b/source4/heimdal/lib/krb5/get_host_realm.c index 2ea075f6c5..7d7fef6e1c 100644 --- a/source4/heimdal/lib/krb5/get_host_realm.c +++ b/source4/heimdal/lib/krb5/get_host_realm.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <resolve.h> -RCSID("$Id$"); - /* To automagically find the correct realm of a host (without * [domain_realm] in krb5.conf) add a text record for your domain with * the name of your realm, like this: @@ -51,14 +49,14 @@ RCSID("$Id$"); */ static int -copy_txt_to_realms (struct resource_record *head, +copy_txt_to_realms (struct rk_resource_record *head, krb5_realm **realms) { - struct resource_record *rr; + struct rk_resource_record *rr; unsigned int n, i; for(n = 0, rr = head; rr; rr = rr->next) - if (rr->type == T_TXT) + if (rr->type == rk_ns_t_txt) ++n; if (n == 0) @@ -72,7 +70,7 @@ copy_txt_to_realms (struct resource_record *head, (*realms)[i] = NULL; for (i = 0, rr = head; rr; rr = rr->next) { - if (rr->type == T_TXT) { + if (rr->type == rk_ns_t_txt) { char *tmp; tmp = strdup(rr->u.txt); @@ -96,7 +94,7 @@ dns_find_realm(krb5_context context, { static const char *default_labels[] = { "_kerberos", NULL }; char dom[MAXHOSTNAMELEN]; - struct dns_reply *r; + struct rk_dns_reply *r; const char **labels; char **config_labels; int i, ret; @@ -116,10 +114,10 @@ dns_find_realm(krb5_context context, krb5_config_free_strings(config_labels); return -1; } - r = dns_lookup(dom, "TXT"); + r = rk_dns_lookup(dom, "TXT"); if(r != NULL) { ret = copy_txt_to_realms (r->head, realms); - dns_free_data(r); + rk_dns_free_data(r); if(ret == 0) { if (config_labels) krb5_config_free_strings(config_labels); diff --git a/source4/heimdal/lib/krb5/get_in_tkt.c b/source4/heimdal/lib/krb5/get_in_tkt.c index cc49e16030..84b1ffb71f 100644 --- a/source4/heimdal/lib/krb5/get_in_tkt.c +++ b/source4/heimdal/lib/krb5/get_in_tkt.c @@ -31,529 +31,11 @@ * SUCH DAMAGE. */ -#include "krb5_locl.h" - -RCSID("$Id$"); - -krb5_error_code KRB5_LIB_FUNCTION -krb5_init_etype (krb5_context context, - unsigned *len, - krb5_enctype **val, - const krb5_enctype *etypes) -{ - unsigned int i; - krb5_error_code ret; - krb5_enctype *tmp = NULL; - - ret = 0; - if (etypes == NULL) { - ret = krb5_get_default_in_tkt_etypes(context, - &tmp); - if (ret) - return ret; - etypes = tmp; - } - - for (i = 0; etypes[i]; ++i) - ; - *len = i; - *val = malloc(i * sizeof(**val)); - if (i != 0 && *val == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto cleanup; - } - memmove (*val, - etypes, - i * sizeof(*tmp)); -cleanup: - if (tmp != NULL) - free (tmp); - return ret; -} - -static krb5_error_code -check_server_referral(krb5_context context, - krb5_kdc_rep *rep, - unsigned flags, - krb5_const_principal requested, - krb5_const_principal returned, - const krb5_keyblock const * key) -{ - krb5_error_code ret; - PA_ServerReferralData ref; - krb5_crypto session; - EncryptedData ed; - size_t len; - krb5_data data; - PA_DATA *pa; - int i = 0, cmp; - - if (rep->kdc_rep.padata == NULL) - goto noreferral; - - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, - KRB5_PADATA_SERVER_REFERRAL, &i); - if (pa == NULL) - goto noreferral; - - memset(&ed, 0, sizeof(ed)); - memset(&ref, 0, sizeof(ref)); - - ret = decode_EncryptedData(pa->padata_value.data, - pa->padata_value.length, - &ed, &len); - if (ret) - return ret; - if (len != pa->padata_value.length) { - free_EncryptedData(&ed); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Referral EncryptedData wrong for realm %s", - "realm"), requested->realm); - return KRB5KRB_AP_ERR_MODIFIED; - } - - ret = krb5_crypto_init(context, key, 0, &session); - if (ret) { - free_EncryptedData(&ed); - return ret; - } - - ret = krb5_decrypt_EncryptedData(context, session, - KRB5_KU_PA_SERVER_REFERRAL, - &ed, &data); - free_EncryptedData(&ed); - krb5_crypto_destroy(context, session); - if (ret) - return ret; - - ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len); - if (ret) { - krb5_data_free(&data); - return ret; - } - krb5_data_free(&data); - - if (strcmp(requested->realm, returned->realm) != 0) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("server ref realm mismatch, " - "requested realm %s got back %s", ""), - requested->realm, returned->realm); - return KRB5KRB_AP_ERR_MODIFIED; - } - - if (returned->name.name_string.len == 2 && - strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0) - { - const char *realm = returned->name.name_string.val[1]; - - if (ref.referred_realm == NULL - || strcmp(*ref.referred_realm, realm) != 0) - { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("tgt returned with wrong ref", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - } else if (krb5_principal_compare(context, returned, requested) == 0) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("req princ no same as returned", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - - if (ref.requested_principal_name) { - cmp = _krb5_principal_compare_PrincipalName(context, - requested, - ref.requested_principal_name); - if (!cmp) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("referred principal not same " - "as requested", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - } else if (flags & EXTRACT_TICKET_AS_REQ) { - free_PA_ServerReferralData(&ref); - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Requested principal missing on AS-REQ", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - - free_PA_ServerReferralData(&ref); - - return ret; -noreferral: - if (krb5_principal_compare(context, requested, returned) == FALSE) { - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Not same server principal returned " - "as requested", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - return 0; -} - - -/* - * Verify referral data - */ - - -static krb5_error_code -check_client_referral(krb5_context context, - krb5_kdc_rep *rep, - krb5_const_principal requested, - krb5_const_principal mapped, - krb5_keyblock const * key) -{ - krb5_error_code ret; - PA_ClientCanonicalized canon; - krb5_crypto crypto; - krb5_data data; - PA_DATA *pa; - size_t len; - int i = 0; - - if (rep->kdc_rep.padata == NULL) - goto noreferral; - - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, - KRB5_PADATA_CLIENT_CANONICALIZED, &i); - if (pa == NULL) - goto noreferral; - - ret = decode_PA_ClientCanonicalized(pa->padata_value.data, - pa->padata_value.length, - &canon, &len); - if (ret) { - krb5_set_error_message(context, ret, - N_("Failed to decode ClientCanonicalized " - "from realm %s", ""), requested->realm); - return ret; - } - - ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, - &canon.names, &len, ret); - if (ret) { - free_PA_ClientCanonicalized(&canon); - return ret; - } - if (data.length != len) - krb5_abortx(context, "internal asn.1 error"); - - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret) { - free(data.data); - free_PA_ClientCanonicalized(&canon); - return ret; - } - - ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES, - data.data, data.length, - &canon.canon_checksum); - krb5_crypto_destroy(context, crypto); - free(data.data); - if (ret) { - krb5_set_error_message(context, ret, - N_("Failed to verify client canonicalized " - "data from realm %s", ""), - requested->realm); - free_PA_ClientCanonicalized(&canon); - return ret; - } - - if (!_krb5_principal_compare_PrincipalName(context, - requested, - &canon.names.requested_name)) - { - free_PA_ClientCanonicalized(&canon); - krb5_set_error_message(context, KRB5_PRINC_NOMATCH, - N_("Requested name doesn't match" - " in client referral", "")); - return KRB5_PRINC_NOMATCH; - } - if (!_krb5_principal_compare_PrincipalName(context, - mapped, - &canon.names.mapped_name)) - { - free_PA_ClientCanonicalized(&canon); - krb5_set_error_message(context, KRB5_PRINC_NOMATCH, - N_("Mapped name doesn't match" - " in client referral", "")); - return KRB5_PRINC_NOMATCH; - } - - return 0; - -noreferral: - if (krb5_principal_compare(context, requested, mapped) == FALSE) { - krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - N_("Not same client principal returned " - "as requested", "")); - return KRB5KRB_AP_ERR_MODIFIED; - } - return 0; -} - - +#define KRB5_DEPRECATED -static krb5_error_code -decrypt_tkt (krb5_context context, - krb5_keyblock *key, - krb5_key_usage usage, - krb5_const_pointer decrypt_arg, - krb5_kdc_rep *dec_rep) -{ - krb5_error_code ret; - krb5_data data; - size_t size; - krb5_crypto crypto; - - ret = krb5_crypto_init(context, key, 0, &crypto); - if (ret) - return ret; - - ret = krb5_decrypt_EncryptedData (context, - crypto, - usage, - &dec_rep->kdc_rep.enc_part, - &data); - krb5_crypto_destroy(context, crypto); - - if (ret) - return ret; - - ret = krb5_decode_EncASRepPart(context, - data.data, - data.length, - &dec_rep->enc_part, - &size); - if (ret) - ret = krb5_decode_EncTGSRepPart(context, - data.data, - data.length, - &dec_rep->enc_part, - &size); - krb5_data_free (&data); - if (ret) - return ret; - return 0; -} - -int -_krb5_extract_ticket(krb5_context context, - krb5_kdc_rep *rep, - krb5_creds *creds, - krb5_keyblock *key, - krb5_const_pointer keyseed, - krb5_key_usage key_usage, - krb5_addresses *addrs, - unsigned nonce, - unsigned flags, - krb5_decrypt_proc decrypt_proc, - krb5_const_pointer decryptarg) -{ - krb5_error_code ret; - krb5_principal tmp_principal; - size_t len; - time_t tmp_time; - krb5_timestamp sec_now; - - /* decrypt */ - - if (decrypt_proc == NULL) - decrypt_proc = decrypt_tkt; - - ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); - if (ret) - goto out; - - /* save session key */ - - creds->session.keyvalue.length = 0; - creds->session.keyvalue.data = NULL; - creds->session.keytype = rep->enc_part.key.keytype; - ret = krb5_data_copy (&creds->session.keyvalue, - rep->enc_part.key.keyvalue.data, - rep->enc_part.key.keyvalue.length); - if (ret) { - krb5_clear_error_message(context); - goto out; - } - - /* - * HACK: - * this is really a ugly hack, to support using the Netbios Domain Name - * as realm against windows KDC's, they always return the full realm - * based on the DNS Name. - */ - flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; - flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; - - /* compare client and save */ - ret = _krb5_principalname2krb5_principal (context, - &tmp_principal, - rep->kdc_rep.cname, - rep->kdc_rep.crealm); - if (ret) - goto out; - - /* check client referral and save principal */ - /* anonymous here ? */ - if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { - ret = check_client_referral(context, rep, - creds->client, - tmp_principal, - &creds->session); - if (ret) { - krb5_free_principal (context, tmp_principal); - goto out; - } - } - krb5_free_principal (context, creds->client); - creds->client = tmp_principal; - - /* check server referral and save principal */ - ret = _krb5_principalname2krb5_principal (context, - &tmp_principal, - rep->kdc_rep.ticket.sname, - rep->kdc_rep.ticket.realm); - if (ret) - goto out; - if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ - ret = check_server_referral(context, - rep, - flags, - creds->server, - tmp_principal, - &creds->session); - if (ret) { - krb5_free_principal (context, tmp_principal); - goto out; - } - } - krb5_free_principal(context, creds->server); - creds->server = tmp_principal; - - /* verify names */ - if(flags & EXTRACT_TICKET_MATCH_REALM){ - const char *srealm = krb5_principal_get_realm(context, creds->server); - const char *crealm = krb5_principal_get_realm(context, creds->client); - - if (strcmp(rep->enc_part.srealm, srealm) != 0 || - strcmp(rep->enc_part.srealm, crealm) != 0) - { - ret = KRB5KRB_AP_ERR_MODIFIED; - krb5_clear_error_message(context); - goto out; - } - } - - /* compare nonces */ - - if (nonce != rep->enc_part.nonce) { - ret = KRB5KRB_AP_ERR_MODIFIED; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto out; - } - - /* set kdc-offset */ - - krb5_timeofday (context, &sec_now); - if (rep->enc_part.flags.initial - && context->kdc_sec_offset == 0 - && krb5_config_get_bool (context, NULL, - "libdefaults", - "kdc_timesync", - NULL)) { - context->kdc_sec_offset = rep->enc_part.authtime - sec_now; - krb5_timeofday (context, &sec_now); - } - - /* check all times */ - - if (rep->enc_part.starttime) { - tmp_time = *rep->enc_part.starttime; - } else - tmp_time = rep->enc_part.authtime; - - if (creds->times.starttime == 0 - && abs(tmp_time - sec_now) > context->max_skew) { - ret = KRB5KRB_AP_ERR_SKEW; - krb5_set_error_message (context, ret, - N_("time skew (%d) larger than max (%d)", ""), - abs(tmp_time - sec_now), - (int)context->max_skew); - goto out; - } - - if (creds->times.starttime != 0 - && tmp_time != creds->times.starttime) { - krb5_clear_error_message (context); - ret = KRB5KRB_AP_ERR_MODIFIED; - goto out; - } - - creds->times.starttime = tmp_time; - - if (rep->enc_part.renew_till) { - tmp_time = *rep->enc_part.renew_till; - } else - tmp_time = 0; - - if (creds->times.renew_till != 0 - && tmp_time > creds->times.renew_till) { - krb5_clear_error_message (context); - ret = KRB5KRB_AP_ERR_MODIFIED; - goto out; - } - - creds->times.renew_till = tmp_time; - - creds->times.authtime = rep->enc_part.authtime; - - if (creds->times.endtime != 0 - && rep->enc_part.endtime > creds->times.endtime) { - krb5_clear_error_message (context); - ret = KRB5KRB_AP_ERR_MODIFIED; - goto out; - } - - creds->times.endtime = rep->enc_part.endtime; - - if(rep->enc_part.caddr) - krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); - else if(addrs) - krb5_copy_addresses (context, addrs, &creds->addresses); - else { - creds->addresses.len = 0; - creds->addresses.val = NULL; - } - creds->flags.b = rep->enc_part.flags; - - creds->authdata.len = 0; - creds->authdata.val = NULL; - - /* extract ticket */ - ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, - &rep->kdc_rep.ticket, &len, ret); - if(ret) - goto out; - if (creds->ticket.length != len) - krb5_abortx(context, "internal error in ASN.1 encoder"); - creds->second_ticket.length = 0; - creds->second_ticket.data = NULL; - - -out: - memset (rep->enc_part.key.keyvalue.data, 0, - rep->enc_part.key.keyvalue.length); - return ret; -} +#include "krb5_locl.h" +#ifndef HEIMDAL_SMALLER static krb5_error_code make_pa_enc_timestamp(krb5_context context, PA_DATA *pa, @@ -626,6 +108,8 @@ add_padata(krb5_context context, if(salt == NULL) { /* default to standard salt */ ret = krb5_get_pw_salt (context, client, &salt2); + if (ret) + return ret; salt = &salt2; } if (!enctypes) { @@ -861,11 +345,10 @@ set_ptypes(krb5_context context, *preauth = &preauth2; ALLOC_SEQ(*preauth, 1); (*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP; - krb5_decode_ETYPE_INFO(context, - md.val[i].padata_value.data, - md.val[i].padata_value.length, - &(*preauth)->val[0].info, - NULL); + decode_ETYPE_INFO(md.val[i].padata_value.data, + md.val[i].padata_value.length, + &(*preauth)->val[0].info, + NULL); break; default: break; @@ -891,6 +374,7 @@ krb5_get_in_cred(krb5_context context, krb5_const_pointer decryptarg, krb5_creds *creds, krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED { krb5_error_code ret; AS_REQ a; @@ -1055,6 +539,7 @@ krb5_get_in_tkt(krb5_context context, krb5_creds *creds, krb5_ccache ccache, krb5_kdc_rep *ret_as_reply) + KRB5_DEPRECATED { krb5_error_code ret; @@ -1076,3 +561,5 @@ krb5_get_in_tkt(krb5_context context, ret = krb5_cc_store_cred (context, ccache, creds); return ret; } + +#endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c b/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c deleted file mode 100644 index 0dedbefd2c..0000000000 --- a/source4/heimdal/lib/krb5/get_in_tkt_with_keytab.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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 "krb5_locl.h" - -RCSID("$Id$"); - -krb5_error_code KRB5_LIB_FUNCTION -krb5_keytab_key_proc (krb5_context context, - krb5_enctype enctype, - krb5_salt salt, - krb5_const_pointer keyseed, - krb5_keyblock **key) -{ - krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); - krb5_keytab keytab = args->keytab; - krb5_principal principal = args->principal; - krb5_error_code ret; - krb5_keytab real_keytab; - krb5_keytab_entry entry; - - if(keytab == NULL) - krb5_kt_default(context, &real_keytab); - else - real_keytab = keytab; - - ret = krb5_kt_get_entry (context, real_keytab, principal, - 0, enctype, &entry); - - if (keytab == NULL) - krb5_kt_close (context, real_keytab); - - if (ret) - return ret; - - ret = krb5_copy_keyblock (context, &entry.keyblock, key); - krb5_kt_free_entry(context, &entry); - return ret; -} - -krb5_error_code KRB5_LIB_FUNCTION -krb5_get_in_tkt_with_keytab (krb5_context context, - krb5_flags options, - krb5_addresses *addrs, - const krb5_enctype *etypes, - const krb5_preauthtype *pre_auth_types, - krb5_keytab keytab, - krb5_ccache ccache, - krb5_creds *creds, - krb5_kdc_rep *ret_as_reply) -{ - krb5_keytab_key_proc_args a; - - a.principal = creds->client; - a.keytab = keytab; - - return krb5_get_in_tkt (context, - options, - addrs, - etypes, - pre_auth_types, - krb5_keytab_key_proc, - &a, - NULL, - NULL, - creds, - ccache, - ret_as_reply); -} diff --git a/source4/heimdal/lib/krb5/get_port.c b/source4/heimdal/lib/krb5/get_port.c index c9869eb450..5d0361b816 100644 --- a/source4/heimdal/lib/krb5/get_port.c +++ b/source4/heimdal/lib/krb5/get_port.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - int KRB5_LIB_FUNCTION krb5_getportbyname (krb5_context context, const char *service, diff --git a/source4/heimdal/lib/krb5/heim_err.et b/source4/heimdal/lib/krb5/heim_err.et index 547a14e04c..2e8a0d18d8 100644 --- a/source4/heimdal/lib/krb5/heim_err.et +++ b/source4/heimdal/lib/krb5/heim_err.et @@ -17,6 +17,8 @@ error_code OPNOTSUPP, "Operation not supported" error_code EOF, "End of file" error_code BAD_MKEY, "Failed to get the master key" error_code SERVICE_NOMATCH, "Unacceptable service used" +error_code NOT_SEEKABLE, "File descriptor not seekable" +error_code TOO_BIG, "Offset too large" index 64 prefix HEIM_PKINIT diff --git a/source4/heimdal/lib/krb5/heim_threads.h b/source4/heimdal/lib/krb5/heim_threads.h deleted file mode 100644 index c4f841fb61..0000000000 --- a/source4/heimdal/lib/krb5/heim_threads.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (c) 2003 Kungliga Tekniska Högskolan - * (Royal Institute of Technology, Stockholm, Sweden). - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. 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. - * - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. - */ - -/* $Id$ */ - -/* - * Provide wrapper macros for thread synchronization primitives so we - * can use native thread functions for those operating system that - * supports it. - * - * This is so libkrb5.so (or more importantly, libgssapi.so) can have - * thread support while the program that that dlopen(3)s the library - * don't need to be linked to libpthread. - */ - -#ifndef HEIM_THREADS_H -#define HEIM_THREADS_H 1 - -/* assume headers already included */ - -#if defined(__NetBSD__) && __NetBSD_Version__ >= 106120000 && __NetBSD_Version__< 299001200 && defined(ENABLE_PTHREAD_SUPPORT) - -/* - * NetBSD have a thread lib that we can use that part of libc that - * works regardless if application are linked to pthreads or not. - * NetBSD newer then 2.99.11 just use pthread.h, and the same thing - * will happen. - */ -#include <threadlib.h> - -#define HEIMDAL_MUTEX mutex_t -#define HEIMDAL_MUTEX_INITIALIZER MUTEX_INITIALIZER -#define HEIMDAL_MUTEX_init(m) mutex_init(m, NULL) -#define HEIMDAL_MUTEX_lock(m) mutex_lock(m) -#define HEIMDAL_MUTEX_unlock(m) mutex_unlock(m) -#define HEIMDAL_MUTEX_destroy(m) mutex_destroy(m) - -#define HEIMDAL_RWLOCK rwlock_t -#define HEIMDAL_RWLOCK_INITIALIZER RWLOCK_INITIALIZER -#define HEIMDAL_RWLOCK_init(l) rwlock_init(l, NULL) -#define HEIMDAL_RWLOCK_rdlock(l) rwlock_rdlock(l) -#define HEIMDAL_RWLOCK_wrlock(l) rwlock_wrlock(l) -#define HEIMDAL_RWLOCK_tryrdlock(l) rwlock_tryrdlock(l) -#define HEIMDAL_RWLOCK_trywrlock(l) rwlock_trywrlock(l) -#define HEIMDAL_RWLOCK_unlock(l) rwlock_unlock(l) -#define HEIMDAL_RWLOCK_destroy(l) rwlock_destroy(l) - -#define HEIMDAL_thread_key thread_key_t -#define HEIMDAL_key_create(k,d,r) do { r = thr_keycreate(k,d); } while(0) -#define HEIMDAL_setspecific(k,s,r) do { r = thr_setspecific(k,s); } while(0) -#define HEIMDAL_getspecific(k) thr_getspecific(k) -#define HEIMDAL_key_delete(k) thr_keydelete(k) - -#elif defined(ENABLE_PTHREAD_SUPPORT) && (!defined(__NetBSD__) || __NetBSD_Version__ >= 299001200) - -#include <pthread.h> - -#define HEIMDAL_MUTEX pthread_mutex_t -#define HEIMDAL_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define HEIMDAL_MUTEX_init(m) pthread_mutex_init(m, NULL) -#define HEIMDAL_MUTEX_lock(m) pthread_mutex_lock(m) -#define HEIMDAL_MUTEX_unlock(m) pthread_mutex_unlock(m) -#define HEIMDAL_MUTEX_destroy(m) pthread_mutex_destroy(m) - -#define HEIMDAL_RWLOCK rwlock_t -#define HEIMDAL_RWLOCK_INITIALIZER RWLOCK_INITIALIZER -#define HEIMDAL_RWLOCK_init(l) pthread_rwlock_init(l, NULL) -#define HEIMDAL_RWLOCK_rdlock(l) pthread_rwlock_rdlock(l) -#define HEIMDAL_RWLOCK_wrlock(l) pthread_rwlock_wrlock(l) -#define HEIMDAL_RWLOCK_tryrdlock(l) pthread_rwlock_tryrdlock(l) -#define HEIMDAL_RWLOCK_trywrlock(l) pthread_rwlock_trywrlock(l) -#define HEIMDAL_RWLOCK_unlock(l) pthread_rwlock_unlock(l) -#define HEIMDAL_RWLOCK_destroy(l) pthread_rwlock_destroy(l) - -#define HEIMDAL_thread_key pthread_key_t -#define HEIMDAL_key_create(k,d,r) do { r = pthread_key_create(k,d); } while(0) -#define HEIMDAL_setspecific(k,s,r) do { r = pthread_setspecific(k,s); } while(0) -#define HEIMDAL_getspecific(k) pthread_getspecific(k) -#define HEIMDAL_key_delete(k) pthread_key_delete(k) - -#elif defined(HEIMDAL_DEBUG_THREADS) - -/* no threads support, just do consistency checks */ -#include <stdlib.h> - -#define HEIMDAL_MUTEX int -#define HEIMDAL_MUTEX_INITIALIZER 0 -#define HEIMDAL_MUTEX_init(m) do { (*(m)) = 0; } while(0) -#define HEIMDAL_MUTEX_lock(m) do { if ((*(m))++ != 0) abort(); } while(0) -#define HEIMDAL_MUTEX_unlock(m) do { if ((*(m))-- != 1) abort(); } while(0) -#define HEIMDAL_MUTEX_destroy(m) do {if ((*(m)) != 0) abort(); } while(0) - -#define HEIMDAL_RWLOCK rwlock_t int -#define HEIMDAL_RWLOCK_INITIALIZER 0 -#define HEIMDAL_RWLOCK_init(l) do { } while(0) -#define HEIMDAL_RWLOCK_rdlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_wrlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_tryrdlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_trywrlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_unlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_destroy(l) do { } while(0) - -#define HEIMDAL_internal_thread_key 1 - -#else /* no thread support, no debug case */ - -#define HEIMDAL_MUTEX int -#define HEIMDAL_MUTEX_INITIALIZER 0 -#define HEIMDAL_MUTEX_init(m) do { (void)(m); } while(0) -#define HEIMDAL_MUTEX_lock(m) do { (void)(m); } while(0) -#define HEIMDAL_MUTEX_unlock(m) do { (void)(m); } while(0) -#define HEIMDAL_MUTEX_destroy(m) do { (void)(m); } while(0) - -#define HEIMDAL_RWLOCK rwlock_t int -#define HEIMDAL_RWLOCK_INITIALIZER 0 -#define HEIMDAL_RWLOCK_init(l) do { } while(0) -#define HEIMDAL_RWLOCK_rdlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_wrlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_tryrdlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_trywrlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_unlock(l) do { } while(0) -#define HEIMDAL_RWLOCK_destroy(l) do { } while(0) - -#define HEIMDAL_internal_thread_key 1 - -#endif /* no thread support */ - -#ifdef HEIMDAL_internal_thread_key - -typedef struct heim_thread_key { - void *value; - void (*destructor)(void *); -} heim_thread_key; - -#define HEIMDAL_thread_key heim_thread_key -#define HEIMDAL_key_create(k,d,r) \ - do { (k)->value = NULL; (k)->destructor = (d); r = 0; } while(0) -#define HEIMDAL_setspecific(k,s,r) do { (k).value = s ; r = 0; } while(0) -#define HEIMDAL_getspecific(k) ((k).value) -#define HEIMDAL_key_delete(k) do { (*(k).destructor)((k).value); } while(0) - -#undef HEIMDAL_internal_thread_key -#endif /* HEIMDAL_internal_thread_key */ - -#endif /* HEIM_THREADS_H */ diff --git a/source4/heimdal/lib/krb5/init_creds.c b/source4/heimdal/lib/krb5/init_creds.c index 89ea3004ed..b1bd94d3b9 100644 --- a/source4/heimdal/lib/krb5/init_creds.c +++ b/source4/heimdal/lib/krb5/init_creds.c @@ -36,14 +36,19 @@ #undef __attribute__ #define __attribute__(x) -RCSID("$Id$"); +/** + * @page krb5_init_creds_intro The initial credential handing functions + * @section section_krb5_init_creds Initial credential + * + * Functions to get initial credentials: @ref krb5_credential . + */ -void KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) - __attribute__((deprecated)) -{ - memset (opt, 0, sizeof(*opt)); -} +/** + * Allocate a new krb5_get_init_creds_opt structure, free with + * krb5_get_init_creds_opt_free(). + * + * @ingroup krb5_credential + */ krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_opt_alloc(krb5_context context, @@ -71,67 +76,11 @@ krb5_get_init_creds_opt_alloc(krb5_context context, return 0; } -krb5_error_code -_krb5_get_init_creds_opt_copy(krb5_context context, - const krb5_get_init_creds_opt *in, - krb5_get_init_creds_opt **out) -{ - krb5_get_init_creds_opt *opt; - - *out = NULL; - opt = calloc(1, sizeof(*opt)); - if (opt == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - if (in) - *opt = *in; - if(opt->opt_private == NULL) { - opt->opt_private = calloc(1, sizeof(*opt->opt_private)); - if (opt->opt_private == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - free(opt); - return ENOMEM; - } - opt->opt_private->refcount = 1; - } else - opt->opt_private->refcount++; - *out = opt; - return 0; -} - -void KRB5_LIB_FUNCTION -_krb5_get_init_creds_opt_free_krb5_error(krb5_get_init_creds_opt *opt) -{ - if (opt->opt_private == NULL || opt->opt_private->error == NULL) - return; - free_KRB_ERROR(opt->opt_private->error); - free(opt->opt_private->error); - opt->opt_private->error = NULL; -} - -void KRB5_LIB_FUNCTION -_krb5_get_init_creds_opt_set_krb5_error(krb5_context context, - krb5_get_init_creds_opt *opt, - const KRB_ERROR *error) -{ - krb5_error_code ret; - - if (opt->opt_private == NULL) - return; - - _krb5_get_init_creds_opt_free_krb5_error(opt); - - opt->opt_private->error = malloc(sizeof(*opt->opt_private->error)); - if (opt->opt_private->error == NULL) - return; - ret = copy_KRB_ERROR(error, opt->opt_private->error); - if (ret) { - free(opt->opt_private->error); - opt->opt_private->error = NULL; - } -} - +/** + * Free krb5_get_init_creds_opt structure. + * + * @ingroup krb5_credential + */ void KRB5_LIB_FUNCTION krb5_get_init_creds_opt_free(krb5_context context, @@ -142,7 +91,6 @@ krb5_get_init_creds_opt_free(krb5_context context, if (opt->opt_private->refcount < 1) /* abort ? */ return; if (--opt->opt_private->refcount == 0) { - _krb5_get_init_creds_opt_free_krb5_error(opt); _krb5_get_init_creds_opt_free_pkinit(opt); free(opt->opt_private); } @@ -369,35 +317,6 @@ krb5_get_init_creds_opt_set_pac_request(krb5_context context, } krb5_error_code KRB5_LIB_FUNCTION -krb5_get_init_creds_opt_get_error(krb5_context context, - krb5_get_init_creds_opt *opt, - KRB_ERROR **error) -{ - krb5_error_code ret; - - *error = NULL; - - ret = require_ext_opt(context, opt, "init_creds_opt_get_error"); - if (ret) - return ret; - - if (opt->opt_private->error == NULL) - return 0; - - *error = malloc(sizeof(**error)); - if (*error == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; - } - - ret = copy_KRB_ERROR(opt->opt_private->error, *error); - if (ret) - krb5_clear_error_message(context); - - return 0; -} - -krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_opt_set_addressless(krb5_context context, krb5_get_init_creds_opt *opt, krb5_boolean addressless) @@ -445,3 +364,54 @@ krb5_get_init_creds_opt_set_win2k(krb5_context context, return 0; } + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_init_creds_opt_set_process_last_req(krb5_context context, + krb5_get_init_creds_opt *opt, + krb5_gic_process_last_req func, + void *ctx) +{ + krb5_error_code ret; + ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k"); + if (ret) + return ret; + + opt->opt_private->lr.func = func; + opt->opt_private->lr.ctx = ctx; + + return 0; +} + + +#ifndef HEIMDAL_SMALLER + +void KRB5_LIB_FUNCTION +krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt) + KRB5_DEPRECATED +{ + memset (opt, 0, sizeof(*opt)); +} + +/** + * Deprecated: use the new krb5_init_creds_init() and + * krb5_init_creds_get_error(). + * + * @ingroup krb5_deprecated + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_init_creds_opt_get_error(krb5_context context, + krb5_get_init_creds_opt *opt, + KRB_ERROR **error) + KRB5_DEPRECATED +{ + *error = calloc(1, sizeof(**error)); + if (*error == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } + + return 0; +} + +#endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/init_creds_pw.c b/source4/heimdal/lib/krb5/init_creds_pw.c index 0b75522e9d..0435ab5d3b 100644 --- a/source4/heimdal/lib/krb5/init_creds_pw.c +++ b/source4/heimdal/lib/krb5/init_creds_pw.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,15 +33,13 @@ #include "krb5_locl.h" -RCSID("$Id$"); - typedef struct krb5_get_init_creds_ctx { KDCOptions flags; krb5_creds cred; krb5_addresses *addrs; krb5_enctype *etypes; krb5_preauthtype *pre_auth_types; - const char *in_tkt_service; + char *in_tkt_service; unsigned nonce; unsigned pk_nonce; @@ -49,13 +47,26 @@ typedef struct krb5_get_init_creds_ctx { AS_REQ as_req; int pa_counter; - const char *password; - krb5_s2k_proc key_proc; + /* password and keytab_data is freed on completion */ + char *password; + krb5_keytab_key_proc_args *keytab_data; + + krb5_pointer *keyseed; + krb5_s2k_proc keyproc; krb5_get_init_creds_tristate req_pac; krb5_pk_init_ctx pk_init_ctx; int ic_flags; + + METHOD_DATA md; + KRB_ERROR error; + AS_REP as_rep; + EncKDCRepPart enc_part; + + krb5_prompter_fct prompter; + void *prompter_data; + } krb5_get_init_creds_ctx; static krb5_error_code @@ -74,7 +85,7 @@ default_s2k_func(krb5_context context, krb5_enctype type, opaque = *s2kparms; else krb5_data_zero(&opaque); - + *key = malloc(sizeof(**key)); if (*key == NULL) return ENOMEM; @@ -88,14 +99,24 @@ default_s2k_func(krb5_context context, krb5_enctype type, } static void -free_init_creds_ctx(krb5_context context, krb5_get_init_creds_ctx *ctx) +free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) { if (ctx->etypes) free(ctx->etypes); if (ctx->pre_auth_types) free (ctx->pre_auth_types); + if (ctx->in_tkt_service) + free(ctx->in_tkt_service); + if (ctx->keytab_data) + free(ctx->keytab_data); + krb5_data_free(&ctx->req_buffer); + krb5_free_cred_contents(context, &ctx->cred); + free_METHOD_DATA(&ctx->md); + free_AS_REP(&ctx->as_rep); + free_EncKDCRepPart(&ctx->enc_part); + free_KRB_ERROR(&ctx->error); free_AS_REQ(&ctx->as_req); - memset(&ctx->as_req, 0, sizeof(ctx->as_req)); + memset(ctx, 0, sizeof(*ctx)); } static int @@ -127,11 +148,9 @@ init_cred (krb5_context context, krb5_creds *cred, krb5_principal client, krb5_deltat start_time, - const char *in_tkt_service, krb5_get_init_creds_opt *options) { krb5_error_code ret; - krb5_const_realm client_realm; int tmp; krb5_timestamp now; @@ -148,8 +167,6 @@ init_cred (krb5_context context, goto out; } - client_realm = krb5_principal_get_realm (context, cred->client); - if (start_time) cred->times.starttime = now + start_time; @@ -164,18 +181,6 @@ init_cred (krb5_context context, cred->times.renew_till = now + options->renew_life; } - if (in_tkt_service) { - ret = krb5_parse_name (context, in_tkt_service, &cred->server); - if (ret) - goto out; - krb5_principal_set_realm (context, cred->server, client_realm); - } else { - ret = krb5_make_principal(context, &cred->server, - client_realm, KRB5_TGS_NAME, client_realm, - NULL); - if (ret) - goto out; - } return 0; out: @@ -195,28 +200,71 @@ report_expiration (krb5_context context, time_t now) { char *p; - + asprintf (&p, "%s%s", str, ctime(&now)); (*prompter) (context, data, NULL, p, 0, NULL); free (p); } /* - * Parse the last_req data and show it to the user if it's interesting + * Check the context, and in the case there is a expiration warning, + * use the prompter to print the warning. + * + * @param context A Kerberos 5 context. + * @param options An GIC options structure + * @param ctx The krb5_init_creds_context check for expiration. */ -static void -print_expire (krb5_context context, - krb5_const_realm realm, - krb5_kdc_rep *rep, - krb5_prompter_fct prompter, - krb5_data *data) +static krb5_error_code +process_last_request(krb5_context context, + krb5_get_init_creds_opt *options, + krb5_init_creds_context ctx) { - int i; - LastReq *lr = &rep->enc_part.last_req; + krb5_const_realm realm; + LastReq *lr; + krb5_boolean reported = FALSE; krb5_timestamp sec; time_t t; - krb5_boolean reported = FALSE; + size_t i; + + /* + * First check if there is a API consumer. + */ + + realm = krb5_principal_get_realm (context, ctx->cred.client); + lr = &ctx->enc_part.last_req; + + if (options && options->opt_private && options->opt_private->lr.func) { + krb5_last_req_entry **lre; + + lre = calloc(lr->len + 1, sizeof(**lre)); + if (lre == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + for (i = 0; i < lr->len; i++) { + lre[i] = calloc(1, sizeof(*lre[i])); + if (lre[i] == NULL) + break; + lre[i]->lr_type = lr->val[i].lr_type; + lre[i]->value = lr->val[i].lr_value; + } + + (*options->opt_private->lr.func)(context, lre, + options->opt_private->lr.ctx); + + for (i = 0; i < lr->len; i++) + free(lre[i]); + free(lre); + } + + /* + * Now check if we should prompt the user + */ + + if (ctx->prompter == NULL) + return 0; krb5_timeofday (context, &sec); @@ -229,13 +277,15 @@ print_expire (krb5_context context, if (lr->val[i].lr_value <= t) { switch (abs(lr->val[i].lr_type)) { case LR_PW_EXPTIME : - report_expiration(context, prompter, data, + report_expiration(context, ctx->prompter, + ctx->prompter_data, "Your password will expire at ", lr->val[i].lr_value); reported = TRUE; break; case LR_ACCT_EXPTIME : - report_expiration(context, prompter, data, + report_expiration(context, ctx->prompter, + ctx->prompter_data, "Your account will expire at ", lr->val[i].lr_value); reported = TRUE; @@ -245,12 +295,14 @@ print_expire (krb5_context context, } if (!reported - && rep->enc_part.key_expiration - && *rep->enc_part.key_expiration <= t) { - report_expiration(context, prompter, data, + && ctx->enc_part.key_expiration + && *ctx->enc_part.key_expiration <= t) { + report_expiration(context, ctx->prompter, + ctx->prompter_data, "Your password/account will expire at ", - *rep->enc_part.key_expiration); + *ctx->enc_part.key_expiration); } + return 0; } static krb5_addresses no_addrs = { 0, NULL }; @@ -259,11 +311,10 @@ static krb5_error_code get_init_creds_common(krb5_context context, krb5_principal client, krb5_deltat start_time, - const char *in_tkt_service, krb5_get_init_creds_opt *options, - krb5_get_init_creds_ctx *ctx) + krb5_init_creds_context ctx) { - krb5_get_init_creds_opt default_opt; + krb5_get_init_creds_opt *default_opt = NULL; krb5_error_code ret; krb5_enctype *etypes; krb5_preauthtype *pre_auth_types; @@ -271,37 +322,51 @@ get_init_creds_common(krb5_context context, memset(ctx, 0, sizeof(*ctx)); if (options == NULL) { - krb5_get_init_creds_opt_init (&default_opt); - options = &default_opt; - } else { - _krb5_get_init_creds_opt_free_krb5_error(options); + const char *realm = krb5_principal_get_realm(context, client); + + krb5_get_init_creds_opt_alloc (context, &default_opt); + options = default_opt; + krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options); } if (options->opt_private) { - ctx->password = options->opt_private->password; - ctx->key_proc = options->opt_private->key_proc; + if (options->opt_private->password) { + ret = krb5_init_creds_set_password(context, ctx, + options->opt_private->password); + if (ret) + goto out; + } + + ctx->keyproc = options->opt_private->key_proc; ctx->req_pac = options->opt_private->req_pac; ctx->pk_init_ctx = options->opt_private->pk_init_ctx; ctx->ic_flags = options->opt_private->flags; } else ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET; - if (ctx->key_proc == NULL) - ctx->key_proc = default_s2k_func; + if (ctx->keyproc == NULL) + ctx->keyproc = default_s2k_func; - if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) + /* Enterprise name implicitly turns on canonicalize */ + if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) || + krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL) ctx->flags.canonicalize = 1; ctx->pre_auth_types = NULL; ctx->addrs = NULL; ctx->etypes = NULL; ctx->pre_auth_types = NULL; - ctx->in_tkt_service = in_tkt_service; - ret = init_cred (context, &ctx->cred, client, start_time, - in_tkt_service, options); - if (ret) + ret = init_cred(context, &ctx->cred, client, start_time, options); + if (ret) { + if (default_opt) + krb5_get_init_creds_opt_free(context, default_opt); return ret; + } + + ret = krb5_init_creds_set_service(context, ctx, NULL); + if (ret) + goto out; if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE) ctx->flags.forwardable = options->forwardable; @@ -336,8 +401,9 @@ get_init_creds_common(krb5_context context, etypes = malloc((options->etype_list_length + 1) * sizeof(krb5_enctype)); if (etypes == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } memcpy (etypes, options->etype_list, options->etype_list_length * sizeof(krb5_enctype)); @@ -348,19 +414,24 @@ get_init_creds_common(krb5_context context, pre_auth_types = malloc((options->preauth_list_length + 1) * sizeof(krb5_preauthtype)); if (pre_auth_types == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); - return ENOMEM; + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; } memcpy (pre_auth_types, options->preauth_list, options->preauth_list_length * sizeof(krb5_preauthtype)); pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE; ctx->pre_auth_types = pre_auth_types; } - if (options->flags & KRB5_GET_INIT_CREDS_OPT_SALT) - ; /* XXX */ if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) ctx->flags.request_anonymous = options->anonymous; + if (default_opt) + krb5_get_init_creds_opt_free(context, default_opt); return 0; + out: + if (default_opt) + krb5_get_init_creds_opt_free(context, default_opt); + return ret; } static krb5_error_code @@ -382,18 +453,20 @@ change_password (krb5_context context, krb5_data result_code_string; krb5_data result_string; char *p; - krb5_get_init_creds_opt options; + krb5_get_init_creds_opt *options; memset (&cpw_cred, 0, sizeof(cpw_cred)); - krb5_get_init_creds_opt_init (&options); - krb5_get_init_creds_opt_set_tkt_life (&options, 60); - krb5_get_init_creds_opt_set_forwardable (&options, FALSE); - krb5_get_init_creds_opt_set_proxiable (&options, FALSE); + ret = krb5_get_init_creds_opt_alloc(context, &options); + if (ret) + return ret; + krb5_get_init_creds_opt_set_tkt_life (options, 60); + krb5_get_init_creds_opt_set_forwardable (options, FALSE); + krb5_get_init_creds_opt_set_proxiable (options, FALSE); if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) - krb5_get_init_creds_opt_set_preauth_list (&options, + krb5_get_init_creds_opt_set_preauth_list (options, old_options->preauth_list, - old_options->preauth_list_length); + old_options->preauth_list_length); krb5_data_zero (&result_code_string); krb5_data_zero (&result_string); @@ -406,7 +479,8 @@ change_password (krb5_context context, data, 0, "kadmin/changepw", - &options); + options); + krb5_get_init_creds_opt_free(context, options); if (ret) goto out; @@ -455,7 +529,9 @@ change_password (krb5_context context, (int)result_string.length, result_string.length > 0 ? (char*)result_string.data : ""); - ret = (*prompter) (context, data, NULL, p, 0, NULL); + /* return the result */ + (*prompter) (context, data, NULL, p, 0, NULL); + free (p); if (result_code == 0) { strlcpy (newpw, buf1, newpw_sz); @@ -475,6 +551,7 @@ out: return ret; } + krb5_error_code KRB5_LIB_FUNCTION krb5_keyblock_key_proc (krb5_context context, krb5_keytype type, @@ -485,68 +562,17 @@ krb5_keyblock_key_proc (krb5_context context, return krb5_copy_keyblock (context, keyseed, key); } -krb5_error_code KRB5_LIB_FUNCTION -krb5_get_init_creds_keytab(krb5_context context, - krb5_creds *creds, - krb5_principal client, - krb5_keytab keytab, - krb5_deltat start_time, - const char *in_tkt_service, - krb5_get_init_creds_opt *options) -{ - krb5_get_init_creds_ctx ctx; - krb5_error_code ret; - krb5_keytab_key_proc_args *a; - - ret = get_init_creds_common(context, client, start_time, - in_tkt_service, options, &ctx); - if (ret) - goto out; - - a = malloc (sizeof(*a)); - if (a == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto out; - } - a->principal = ctx.cred.client; - a->keytab = keytab; - - ret = krb5_get_in_cred (context, - KDCOptions2int(ctx.flags), - ctx.addrs, - ctx.etypes, - ctx.pre_auth_types, - NULL, - krb5_keytab_key_proc, - a, - NULL, - NULL, - &ctx.cred, - NULL); - free (a); - - if (ret == 0 && creds) - *creds = ctx.cred; - else - krb5_free_cred_contents (context, &ctx.cred); - - out: - free_init_creds_ctx(context, &ctx); - return ret; -} - /* * */ static krb5_error_code -init_creds_init_as_req (krb5_context context, - KDCOptions opts, - const krb5_creds *creds, - const krb5_addresses *addrs, - const krb5_enctype *etypes, - AS_REQ *a) +init_as_req (krb5_context context, + KDCOptions opts, + const krb5_creds *creds, + const krb5_addresses *addrs, + const krb5_enctype *etypes, + AS_REQ *a) { krb5_error_code ret; @@ -906,7 +932,7 @@ make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md, krb5_crypto_destroy(context, crypto); if (ret) return ret; - + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); free_EncryptedData(&encdata); if (ret) @@ -924,7 +950,7 @@ static krb5_error_code add_enc_ts_padata(krb5_context context, METHOD_DATA *md, krb5_principal client, - krb5_s2k_proc key_proc, + krb5_s2k_proc keyproc, krb5_const_pointer keyseed, krb5_enctype *enctypes, unsigned netypes, @@ -939,6 +965,8 @@ add_enc_ts_padata(krb5_context context, if(salt == NULL) { /* default to standard salt */ ret = krb5_get_pw_salt (context, client, &salt2); + if (ret) + return ret; salt = &salt2; } if (!enctypes) { @@ -951,8 +979,8 @@ add_enc_ts_padata(krb5_context context, for (i = 0; i < netypes; ++i) { krb5_keyblock *key; - ret = (*key_proc)(context, enctypes[i], keyseed, - *salt, s2kparams, &key); + ret = (*keyproc)(context, enctypes[i], keyseed, + *salt, s2kparams, &key); if (ret) continue; ret = make_pa_enc_timestamp (context, md, enctypes[i], key); @@ -973,28 +1001,28 @@ pa_data_to_md_ts_enc(krb5_context context, struct pa_info_data *ppaid, METHOD_DATA *md) { - if (ctx->key_proc == NULL || ctx->password == NULL) + if (ctx->keyproc == NULL || ctx->keyseed == NULL) return 0; if (ppaid) { add_enc_ts_padata(context, md, client, - ctx->key_proc, ctx->password, + ctx->keyproc, ctx->keyseed, &ppaid->etype, 1, &ppaid->salt, ppaid->s2kparams); } else { krb5_salt salt; - + /* make a v5 salted pa-data */ add_enc_ts_padata(context, md, client, - ctx->key_proc, ctx->password, + ctx->keyproc, ctx->keyseed, a->req_body.etype.val, a->req_body.etype.len, NULL, NULL); - + /* make a v4 salted pa-data */ salt.salttype = KRB5_PW_SALT; krb5_data_zero(&salt.saltvalue); add_enc_ts_padata(context, md, client, - ctx->key_proc, ctx->password, + ctx->keyproc, ctx->keyseed, a->req_body.etype.val, a->req_body.etype.len, &salt, NULL); } @@ -1012,7 +1040,7 @@ pa_data_to_key_plain(krb5_context context, { krb5_error_code ret; - ret = (*ctx->key_proc)(context, etype, ctx->password, + ret = (*ctx->keyproc)(context, etype, ctx->keyseed, salt, s2kparams, key); return ret; } @@ -1058,7 +1086,7 @@ pa_data_add_pac_request(krb5_context context, break; case KRB5_INIT_CREDS_TRISTATE_FALSE: req.include_pac = 0; - } + } ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length, &req, &len, ret); @@ -1111,12 +1139,12 @@ process_pa_data_to_md(krb5_context context, } else if (in_md->len != 0) { struct pa_info_data paid, *ppaid; - + memset(&paid, 0, sizeof(paid)); - + paid.etype = ENCTYPE_NULL; ppaid = process_pa_info(context, creds->client, a, &paid, in_md); - + pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md); if (ppaid) free_paid(context, ppaid); @@ -1137,7 +1165,7 @@ process_pa_data_to_key(krb5_context context, krb5_get_init_creds_ctx *ctx, krb5_creds *creds, AS_REQ *a, - krb5_kdc_rep *rep, + AS_REP *rep, const krb5_krbhst_info *hi, krb5_keyblock **key) { @@ -1148,12 +1176,12 @@ process_pa_data_to_key(krb5_context context, memset(&paid, 0, sizeof(paid)); - etype = rep->kdc_rep.enc_part.etype; + etype = rep->enc_part.etype; - if (rep->kdc_rep.padata) { + if (rep->padata) { paid.etype = etype; ppaid = process_pa_info(context, creds->client, a, &paid, - rep->kdc_rep.padata); + rep->padata); } if (ppaid == NULL) { ret = krb5_get_pw_salt (context, creds->client, &paid.salt); @@ -1164,16 +1192,16 @@ process_pa_data_to_key(krb5_context context, } pa = NULL; - if (rep->kdc_rep.padata) { + if (rep->padata) { int idx = 0; - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, + pa = krb5_find_padata(rep->padata->val, + rep->padata->len, KRB5_PADATA_PK_AS_REP, &idx); if (pa == NULL) { idx = 0; - pa = krb5_find_padata(rep->kdc_rep.padata->val, - rep->kdc_rep.padata->len, + pa = krb5_find_padata(rep->padata->val, + rep->padata->len, KRB5_PADATA_PK_AS_REP_19, &idx); } @@ -1193,7 +1221,7 @@ process_pa_data_to_key(krb5_context context, ret = EINVAL; krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", "")); #endif - } else if (ctx->password) + } else if (ctx->keyseed) ret = pa_data_to_key_plain(context, creds->client, ctx, paid.salt, paid.s2kparams, etype, key); else { @@ -1205,109 +1233,340 @@ process_pa_data_to_key(krb5_context context, return ret; } -static krb5_error_code -init_cred_loop(krb5_context context, - krb5_get_init_creds_opt *init_cred_opts, - const krb5_prompter_fct prompter, - void *prompter_data, - krb5_get_init_creds_ctx *ctx, - krb5_creds *creds, - krb5_kdc_rep *ret_as_reply) +/** + * Start a new context to get a new initial credential. + * + * @param context A Kerberos 5 context. + * @param client The Kerberos principal to get the credential for, if + * NULL is given, the default principal is used as determined by + * krb5_get_default_principal(). + * @param prompter + * @param prompter_data + * @param start_time the time the ticket should start to be valid or 0 for now. + * @param options a options structure, can be NULL for default options. + * @param rctx A new allocated free with krb5_init_creds_free(). + * + * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_init(krb5_context context, + krb5_principal client, + krb5_prompter_fct prompter, + void *prompter_data, + krb5_deltat start_time, + krb5_get_init_creds_opt *options, + krb5_init_creds_context *rctx) { + krb5_init_creds_context ctx; krb5_error_code ret; - krb5_kdc_rep rep; - METHOD_DATA md; - krb5_data resp; - size_t len; - size_t size; - krb5_krbhst_info *hi = NULL; - krb5_sendto_ctx stctx = NULL; - - memset(&md, 0, sizeof(md)); - memset(&rep, 0, sizeof(rep)); + *rctx = NULL; - _krb5_get_init_creds_opt_free_krb5_error(init_cred_opts); - - if (ret_as_reply) - memset(ret_as_reply, 0, sizeof(*ret_as_reply)); + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } - ret = init_creds_init_as_req(context, ctx->flags, creds, - ctx->addrs, ctx->etypes, &ctx->as_req); - if (ret) + ret = get_init_creds_common(context, client, start_time, options, ctx); + if (ret) { + free(ctx); return ret; - - ret = krb5_sendto_ctx_alloc(context, &stctx); - if (ret) - goto out; - krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + } /* Set a new nonce. */ krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce)); - ctx->nonce &= 0xffffffff; + ctx->nonce &= 0x7fffffff; /* XXX these just needs to be the same when using Windows PK-INIT */ ctx->pk_nonce = ctx->nonce; - /* - * Increase counter when we want other pre-auth types then - * KRB5_PA_ENC_TIMESTAMP. - */ -#define MAX_PA_COUNTER 3 + ctx->prompter = prompter; + ctx->prompter_data = prompter_data; - ctx->pa_counter = 0; - while (ctx->pa_counter < MAX_PA_COUNTER) { + *rctx = ctx; - ctx->pa_counter++; + return ret; +} - if (ctx->as_req.padata) { - free_METHOD_DATA(ctx->as_req.padata); - free(ctx->as_req.padata); - ctx->as_req.padata = NULL; - } +/** + * Sets the service that the is requested. This call is only neede for + * special initial tickets, by default the a krbtgt is fetched in the default realm. + * + * @param context a Kerberos 5 context. + * @param ctx a krb5_init_creds_context context. + * @param service the service given as a string, for example + * "kadmind/admin". If NULL, the default krbtgt in the clients + * realm is set. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ - /* Set a new nonce. */ - ctx->as_req.req_body.nonce = ctx->nonce; +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_service(krb5_context context, + krb5_init_creds_context ctx, + const char *service) +{ + krb5_const_realm client_realm; + krb5_principal principal; + krb5_error_code ret; + + client_realm = krb5_principal_get_realm (context, ctx->cred.client); - /* fill_in_md_data */ - ret = process_pa_data_to_md(context, creds, &ctx->as_req, ctx, - &md, &ctx->as_req.padata, - prompter, prompter_data); + if (service) { + ret = krb5_parse_name (context, service, &principal); if (ret) - goto out; + return ret; + krb5_principal_set_realm (context, principal, client_realm); + } else { + ret = krb5_make_principal(context, &principal, + client_realm, KRB5_TGS_NAME, client_realm, + NULL); + if (ret) + return ret; + } + krb5_free_principal(context, ctx->cred.server); + ctx->cred.server = principal; - krb5_data_free(&ctx->req_buffer); + return 0; +} - ASN1_MALLOC_ENCODE(AS_REQ, - ctx->req_buffer.data, ctx->req_buffer.length, - &ctx->as_req, &len, ret); - if (ret) - goto out; - if(len != ctx->req_buffer.length) - krb5_abortx(context, "internal error in ASN.1 encoder"); +/** + * Sets the password that will use for the request. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param password the password to use. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ - ret = krb5_sendto_context (context, stctx, &ctx->req_buffer, - creds->client->realm, &resp); - if (ret) - goto out; +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_password(krb5_context context, + krb5_init_creds_context ctx, + const char *password) +{ + if (ctx->password) + memset(ctx->password, 0, strlen(ctx->password)); + if (password) { + ctx->password = strdup(password); + if (ctx->password == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } + ctx->keyseed = (void *) ctx->password; + } else { + ctx->keyseed = NULL; + ctx->password = NULL; + } + + return 0; +} + +static krb5_error_code +keytab_key_proc(krb5_context context, krb5_enctype enctype, + krb5_const_pointer keyseed, + krb5_salt salt, krb5_data *s2kparms, + krb5_keyblock **key) +{ + krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); + krb5_keytab keytab = args->keytab; + krb5_principal principal = args->principal; + krb5_error_code ret; + krb5_keytab real_keytab; + krb5_keytab_entry entry; + + if(keytab == NULL) + krb5_kt_default(context, &real_keytab); + else + real_keytab = keytab; + + ret = krb5_kt_get_entry (context, real_keytab, principal, + 0, enctype, &entry); + + if (keytab == NULL) + krb5_kt_close (context, real_keytab); + + if (ret) + return ret; + + ret = krb5_copy_keyblock (context, &entry.keyblock, key); + krb5_kt_free_entry(context, &entry); + return ret; +} + + +/** + * Set the keytab to use for authentication. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param keytab the keytab to read the key from. + * + * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_keytab(krb5_context context, + krb5_init_creds_context ctx, + krb5_keytab keytab) +{ + krb5_keytab_key_proc_args *a; + + a = malloc(sizeof(*a)); + if (a == NULL) { + krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + return ENOMEM; + } + + a->principal = ctx->cred.client; + a->keytab = keytab; + + ctx->keytab_data = a; + ctx->keyseed = (void *)a; + ctx->keyproc = keytab_key_proc; + + return 0; +} + +static krb5_error_code +keyblock_key_proc(krb5_context context, krb5_enctype enctype, + krb5_const_pointer keyseed, + krb5_salt salt, krb5_data *s2kparms, + krb5_keyblock **key) +{ + return krb5_copy_keyblock (context, keyseed, key); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_set_keyblock(krb5_context context, + krb5_init_creds_context ctx, + krb5_keyblock *keyblock) +{ + ctx->keyseed = (void *)keyblock; + ctx->keyproc = keyblock_key_proc; + + return 0; +} + +/** + * The core loop if krb5_get_init_creds() function family. Create the + * packets and have the caller send them off to the KDC. + * + * If the caller want all work been done for them, use + * krb5_init_creds_get() instead. + * + * @param context a Kerberos 5 context. + * @param ctx ctx krb5_init_creds_context context. + * @param in input data from KDC, first round it should be reset by krb5_data_zer(). + * @param out reply to KDC. + * @param hostinfo KDC address info, first round it can be NULL. + * @param flags status of the round, if 1 is set, continue one more round. + * + * @return 0 for success, or an Kerberos 5 error code, see + * krb5_get_error_message(). + * + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_step(krb5_context context, + krb5_init_creds_context ctx, + krb5_data *in, + krb5_data *out, + krb5_krbhst_info *hostinfo, + unsigned int *flags) +{ + krb5_error_code ret; + size_t len; + size_t size; - memset (&rep, 0, sizeof(rep)); - ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size); + krb5_data_zero(out); + + if (ctx->as_req.req_body.cname == NULL) { + ret = init_as_req(context, ctx->flags, &ctx->cred, + ctx->addrs, ctx->etypes, &ctx->as_req); + if (ret) { + free_init_creds_ctx(context, ctx); + return ret; + } + } + +#define MAX_PA_COUNTER 10 + if (ctx->pa_counter > MAX_PA_COUNTER) { + krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, + N_("Looping %d times while getting " + "initial credentials", ""), + ctx->pa_counter); + return KRB5_GET_IN_TKT_LOOP; + } + ctx->pa_counter++; + + /* Lets process the input packet */ + if (in && in->length) { + krb5_kdc_rep rep; + + memset(&rep, 0, sizeof(rep)); + + ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); if (ret == 0) { - krb5_data_free(&resp); - krb5_clear_error_message(context); - break; + krb5_keyblock *key = NULL; + unsigned eflags = EXTRACT_TICKET_AS_REQ; + + if (ctx->flags.canonicalize) { + eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; + eflags |= EXTRACT_TICKET_MATCH_REALM; + } + if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) + eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + + ret = process_pa_data_to_key(context, ctx, &ctx->cred, + &ctx->as_req, &rep.kdc_rep, hostinfo, &key); + if (ret) { + free_AS_REP(&rep.kdc_rep); + goto out; + } + + ret = _krb5_extract_ticket(context, + &rep, + &ctx->cred, + key, + NULL, + KRB5_KU_AS_REP_ENC_PART, + NULL, + ctx->nonce, + eflags, + NULL, + NULL); + krb5_free_keyblock(context, key); + + *flags = 0; + + if (ret == 0) + ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); + + free_AS_REP(&rep.kdc_rep); + free_EncASRepPart(&rep.enc_part); + + return ret; + } else { /* let's try to parse it as a KRB-ERROR */ - KRB_ERROR error; - ret = krb5_rd_error(context, &resp, &error); - if(ret && resp.data && ((char*)resp.data)[0] == 4) + free_KRB_ERROR(&ctx->error); + + ret = krb5_rd_error(context, in, &ctx->error); + if(ret && in->length && ((char*)in->data)[0] == 4) ret = KRB5KRB_AP_ERR_V4_REPLY; - krb5_data_free(&resp); if (ret) goto out; - ret = krb5_error_from_rd_error(context, &error, creds); + ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); /* * If no preauth was set and KDC requires it, give it one @@ -1315,169 +1574,198 @@ init_cred_loop(krb5_context context, */ if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) { - free_METHOD_DATA(&md); - memset(&md, 0, sizeof(md)); - if (error.e_data) { - ret = decode_METHOD_DATA(error.e_data->data, - error.e_data->length, - &md, + free_METHOD_DATA(&ctx->md); + memset(&ctx->md, 0, sizeof(ctx->md)); + + if (ctx->error.e_data) { + ret = decode_METHOD_DATA(ctx->error.e_data->data, + ctx->error.e_data->length, + &ctx->md, NULL); if (ret) krb5_set_error_message(context, ret, - N_("failed to decode METHOD DATA", "")); + N_("Failed to decode METHOD-DATA", "")); } else { - /* XXX guess what the server want here add add md */ + krb5_set_error_message(context, ret, + N_("Preauth required but no preauth " + "options send by KDC", "")); } - krb5_free_error_contents(context, &error); - if (ret) + } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) { + /* + * Try adapt to timeskrew when we are using pre-auth, and + * if there was a time skew, try again. + */ + krb5_set_real_time(context, ctx->error.stime, -1); + if (context->kdc_sec_offset) + ret = 0; + } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { + /* client referal to a new realm */ + if (ctx->error.crealm) { + krb5_set_error_message(context, ret, + N_("Got a client referral, not but no realm", "")); goto out; - } else { - _krb5_get_init_creds_opt_set_krb5_error(context, - init_cred_opts, - &error); - if (ret_as_reply) - rep.error = error; - else - krb5_free_error_contents(context, &error); - goto out; + } + ret = krb5_principal_set_realm(context, + ctx->cred.client, + *ctx->error.crealm); } + if (ret) + goto out; } } - { - krb5_keyblock *key = NULL; - unsigned flags = EXTRACT_TICKET_AS_REQ; + if (ctx->as_req.padata) { + free_METHOD_DATA(ctx->as_req.padata); + free(ctx->as_req.padata); + ctx->as_req.padata = NULL; + } - if (ctx->flags.request_anonymous) - flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; - if (ctx->flags.canonicalize) { - flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; - flags |= EXTRACT_TICKET_MATCH_REALM; - } - if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) - flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + /* Set a new nonce. */ + ctx->as_req.req_body.nonce = ctx->nonce; + + /* fill_in_md_data */ + ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx, + &ctx->md, &ctx->as_req.padata, + ctx->prompter, ctx->prompter_data); + if (ret) + goto out; - ret = process_pa_data_to_key(context, ctx, creds, - &ctx->as_req, &rep, hi, &key); - if (ret) - goto out; - - ret = _krb5_extract_ticket(context, - &rep, - creds, - key, - NULL, - KRB5_KU_AS_REP_ENC_PART, - NULL, - ctx->nonce, - flags, - NULL, - NULL); - krb5_free_keyblock(context, key); - } -out: - if (stctx) - krb5_sendto_ctx_free(context, stctx); krb5_data_free(&ctx->req_buffer); - free_METHOD_DATA(&md); - memset(&md, 0, sizeof(md)); - if (ret == 0 && ret_as_reply) - *ret_as_reply = rep; - else - krb5_free_kdc_rep (context, &rep); + ASN1_MALLOC_ENCODE(AS_REQ, + ctx->req_buffer.data, ctx->req_buffer.length, + &ctx->as_req, &len, ret); + if (ret) + goto out; + if(len != ctx->req_buffer.length) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + out->data = ctx->req_buffer.data; + out->length = ctx->req_buffer.length; + + *flags = 1; + + return 0; + out: return ret; } +/** + * Extract the newly acquired credentials from krb5_init_creds_context + * context. + * + * @param context A Kerberos 5 context. + * @param ctx + * @param cred credentials, free with krb5_free_cred_contents(). + * + * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message(). + */ + krb5_error_code KRB5_LIB_FUNCTION -krb5_get_init_creds(krb5_context context, - krb5_creds *creds, - krb5_principal client, - krb5_prompter_fct prompter, - void *data, - krb5_deltat start_time, - const char *in_tkt_service, - krb5_get_init_creds_opt *options) +krb5_init_creds_get_creds(krb5_context context, + krb5_init_creds_context ctx, + krb5_creds *cred) { - krb5_get_init_creds_ctx ctx; - krb5_kdc_rep kdc_reply; - krb5_error_code ret; - char buf[BUFSIZ]; - int done; + return krb5_copy_creds_contents(context, &ctx->cred, cred); +} + +/** + * Get the last error from the transaction. + * + * @return Returns 0 or an error code + * + * @ingroup krb5_credential + */ - memset(&kdc_reply, 0, sizeof(kdc_reply)); +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_get_error(krb5_context context, + krb5_init_creds_context ctx, + KRB_ERROR *error) +{ + krb5_error_code ret; - ret = get_init_creds_common(context, client, start_time, - in_tkt_service, options, &ctx); + ret = copy_KRB_ERROR(&ctx->error, error); if (ret) - goto out; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - done = 0; - while(!done) { - memset(&kdc_reply, 0, sizeof(kdc_reply)); - - ret = init_cred_loop(context, - options, - prompter, - data, - &ctx, - &ctx.cred, - &kdc_reply); - - switch (ret) { - case 0 : - done = 1; - break; - case KRB5KDC_ERR_KEY_EXPIRED : - /* try to avoid recursion */ + return ret; +} - /* don't try to change password where then where none */ - if (prompter == NULL || ctx.password == NULL) - goto out; +/** + * Free the krb5_init_creds_context allocated by krb5_init_creds_init(). + * + * @param context A Kerberos 5 context. + * @param ctx The krb5_init_creds_context to free. + * + * @ingroup krb5_credential + */ - krb5_clear_error_message (context); +void KRB5_LIB_FUNCTION +krb5_init_creds_free(krb5_context context, + krb5_init_creds_context ctx) +{ + free_init_creds_ctx(context, ctx); + free(ctx); +} - if (ctx.in_tkt_service != NULL - && strcmp (ctx.in_tkt_service, "kadmin/changepw") == 0) - goto out; +/** + * Get new credentials as setup by the krb5_init_creds_context. + * + * @param context A Kerberos 5 context. + * @param ctx The krb5_init_creds_context to process. + * + * @ingroup krb5_credential + */ - ret = change_password (context, - client, - ctx.password, - buf, - sizeof(buf), - prompter, - data, - options); - if (ret) - goto out; - ctx.password = buf; +krb5_error_code KRB5_LIB_FUNCTION +krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx) +{ + krb5_sendto_ctx stctx = NULL; + krb5_krbhst_info *hostinfo = NULL; + krb5_error_code ret; + krb5_data in, out; + unsigned int flags = 0; + + krb5_data_zero(&in); + krb5_data_zero(&out); + + ret = krb5_sendto_ctx_alloc(context, &stctx); + if (ret) + goto out; + krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + + while (1) { + flags = 0; + ret = krb5_init_creds_step(context, ctx, &in, &out, hostinfo, &flags); + krb5_data_free(&in); + if (ret) + goto out; + + if ((flags & 1) == 0) break; - default: + + ret = krb5_sendto_context (context, stctx, &out, + ctx->cred.client->realm, &in); + if (ret) goto out; - } - } - if (prompter) - print_expire (context, - krb5_principal_get_realm (context, ctx.cred.client), - &kdc_reply, - prompter, - data); + } out: - memset (buf, 0, sizeof(buf)); - free_init_creds_ctx(context, &ctx); - krb5_free_kdc_rep (context, &kdc_reply); - if (ret == 0) - *creds = ctx.cred; - else - krb5_free_cred_contents (context, &ctx.cred); + if (stctx) + krb5_sendto_ctx_free(context, stctx); return ret; } +/** + * Get new credentials using password. + * + * @ingroup krb5_credential + */ + + krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_password(krb5_context context, krb5_creds *creds, @@ -1487,29 +1775,23 @@ krb5_get_init_creds_password(krb5_context context, void *data, krb5_deltat start_time, const char *in_tkt_service, - krb5_get_init_creds_opt *in_options) + krb5_get_init_creds_opt *options) { - krb5_get_init_creds_opt *options; + krb5_init_creds_context ctx; char buf[BUFSIZ]; krb5_error_code ret; + int chpw = 0; - if (in_options == NULL) { - const char *realm = krb5_principal_get_realm(context, client); - ret = krb5_get_init_creds_opt_alloc(context, &options); - if (ret == 0) - krb5_get_init_creds_opt_set_default_flags(context, - NULL, - realm, - options); - } else - ret = _krb5_get_init_creds_opt_copy(context, in_options, &options); + again: + ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx); if (ret) - return ret; + goto out; - if (password == NULL && - options->opt_private->password == NULL && - options->opt_private->pk_init_ctx == NULL) - { + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + if (prompter != NULL && ctx->password == NULL && password == NULL) { krb5_prompt prompt; krb5_data password_data; char *p, *q; @@ -1528,40 +1810,67 @@ krb5_get_init_creds_password(krb5_context context, free (q); if (ret) { memset (buf, 0, sizeof(buf)); - krb5_get_init_creds_opt_free(context, options); ret = KRB5_LIBOS_PWDINTR; krb5_clear_error_message (context); - return ret; + goto out; } password = password_data.data; } - if (options->opt_private->password == NULL) { - ret = krb5_get_init_creds_opt_set_pa_password(context, options, - password, NULL); - if (ret) { - krb5_get_init_creds_opt_free(context, options); - memset(buf, 0, sizeof(buf)); - return ret; - } + if (password) { + ret = krb5_init_creds_set_password(context, ctx, password); + if (ret) + goto out; } - ret = krb5_get_init_creds(context, creds, client, prompter, - data, start_time, in_tkt_service, options); - krb5_get_init_creds_opt_free(context, options); + ret = krb5_init_creds_get(context, ctx); + + if (ret == 0) + process_last_request(context, options, ctx); + + + if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) { + char buf[1024]; + + /* try to avoid recursion */ + if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0) + goto out; + + /* don't try to change password where then where none */ + if (prompter == NULL) + goto out; + + ret = change_password (context, + client, + ctx->password, + buf, + sizeof(buf), + prompter, + data, + options); + if (ret) + goto out; + chpw = 1; + krb5_init_creds_free(context, ctx); + goto again; + } + + out: + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + memset(buf, 0, sizeof(buf)); return ret; } -static krb5_error_code -init_creds_keyblock_key_proc (krb5_context context, - krb5_enctype type, - krb5_salt salt, - krb5_const_pointer keyseed, - krb5_keyblock **key) -{ - return krb5_copy_keyblock (context, keyseed, key); -} +/** + * Get new credentials using keyblock. + * + * @ingroup krb5_credential + */ krb5_error_code KRB5_LIB_FUNCTION krb5_get_init_creds_keyblock(krb5_context context, @@ -1572,33 +1881,80 @@ krb5_get_init_creds_keyblock(krb5_context context, const char *in_tkt_service, krb5_get_init_creds_opt *options) { - struct krb5_get_init_creds_ctx ctx; + krb5_init_creds_context ctx; krb5_error_code ret; - ret = get_init_creds_common(context, client, start_time, - in_tkt_service, options, &ctx); + memset(creds, 0, sizeof(*creds)); + + ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); if (ret) goto out; - ret = krb5_get_in_cred (context, - KDCOptions2int(ctx.flags), - ctx.addrs, - ctx.etypes, - ctx.pre_auth_types, - NULL, - init_creds_keyblock_key_proc, - keyblock, - NULL, - NULL, - &ctx.cred, - NULL); - - if (ret == 0 && creds) - *creds = ctx.cred; - else - krb5_free_cred_contents (context, &ctx.cred); + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + ret = krb5_init_creds_set_keyblock(context, ctx, keyblock); + if (ret) + goto out; + + ret = krb5_init_creds_get(context, ctx); + + if (ret == 0) + process_last_request(context, options, ctx); + + out: + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + + return ret; +} + +/** + * Get new credentials using keytab. + * + * @ingroup krb5_credential + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_init_creds_keytab(krb5_context context, + krb5_creds *creds, + krb5_principal client, + krb5_keytab keytab, + krb5_deltat start_time, + const char *in_tkt_service, + krb5_get_init_creds_opt *options) +{ + krb5_init_creds_context ctx; + krb5_error_code ret; + + memset(creds, 0, sizeof(*creds)); + + ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); + if (ret) + goto out; + + ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); + if (ret) + goto out; + + ret = krb5_init_creds_set_keytab(context, ctx, keytab); + if (ret) + goto out; + + ret = krb5_init_creds_get(context, ctx); + if (ret == 0) + process_last_request(context, options, ctx); out: - free_init_creds_ctx(context, &ctx); + if (ret == 0) + krb5_init_creds_get_creds(context, ctx, creds); + + if (ctx) + krb5_init_creds_free(context, ctx); + return ret; } diff --git a/source4/heimdal/lib/krb5/kcm.c b/source4/heimdal/lib/krb5/kcm.c index 8a8f1efc11..f034341972 100644 --- a/source4/heimdal/lib/krb5/kcm.c +++ b/source4/heimdal/lib/krb5/kcm.c @@ -43,17 +43,24 @@ #include "kcm.h" -RCSID("$Id$"); - typedef struct krb5_kcmcache { char *name; struct sockaddr_un path; char *door_path; } krb5_kcmcache; +typedef struct krb5_kcm_cursor { + unsigned long offset; + unsigned long length; + kcmuuid_t *uuids; +} *krb5_kcm_cursor; + + #define KCMCACHE(X) ((krb5_kcmcache *)(X)->data.data) #define CACHENAME(X) (KCMCACHE(X)->name) -#define KCMCURSOR(C) (*(uint32_t *)(C)) +#define KCMCURSOR(C) ((krb5_kcm_cursor)(C)) + +#ifdef HAVE_DOOR_CREATE static krb5_error_code try_door(krb5_context context, @@ -61,7 +68,6 @@ try_door(krb5_context context, krb5_data *request_data, krb5_data *response_data) { -#ifdef HAVE_DOOR_CREATE door_arg_t arg; int fd; int ret; @@ -91,10 +97,8 @@ try_door(krb5_context context, return ret; return 0; -#else - return KRB5_CC_IO; -#endif } +#endif /* HAVE_DOOR_CREATE */ static krb5_error_code try_unix_socket(krb5_context context, @@ -143,9 +147,11 @@ kcm_send_request(krb5_context context, ret = KRB5_CC_NOSUPP; for (i = 0; i < context->max_retries; i++) { +#ifdef HAVE_DOOR_CREATE ret = try_door(context, k, &request_data, response_data); if (ret == 0 && response_data->length != 0) break; +#endif ret = try_unix_socket(context, k, &request_data, response_data); if (ret == 0 && response_data->length != 0) break; @@ -207,7 +213,8 @@ kcm_alloc(krb5_context context, const char *name, krb5_ccache *id) k = malloc(sizeof(*k)); if (k == NULL) { - krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", "")); + krb5_set_error_message(context, KRB5_CC_NOMEM, + N_("malloc: out of memory", "")); return KRB5_CC_NOMEM; } @@ -309,8 +316,6 @@ kcm_free(krb5_context context, krb5_ccache *id) memset(k, 0, sizeof(*k)); krb5_data_free(&(*id)->data); } - - *id = NULL; } static const char * @@ -609,10 +614,10 @@ kcm_get_first (krb5_context context, krb5_cc_cursor *cursor) { krb5_error_code ret; + krb5_kcm_cursor c; krb5_kcmcache *k = KCMCACHE(id); krb5_storage *request, *response; krb5_data response_data; - int32_t tmp; ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request); if (ret) @@ -625,27 +630,56 @@ kcm_get_first (krb5_context context, } ret = kcm_call(context, k, request, &response, &response_data); - if (ret) { - krb5_storage_free(request); + krb5_storage_free(request); + if (ret) + return ret; + + c = calloc(1, sizeof(*c)); + if (c == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); return ret; } - ret = krb5_ret_int32(response, &tmp); - if (ret || tmp < 0) - ret = KRB5_CC_IO; + while (1) { + ssize_t sret; + kcmuuid_t uuid; + void *ptr; + + sret = krb5_storage_read(response, &uuid, sizeof(uuid)); + if (sret == 0) { + ret = 0; + break; + } else if (sret != sizeof(uuid)) { + ret = EINVAL; + break; + } + + ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1)); + if (ptr == NULL) { + free(c->uuids); + free(c); + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + c->uuids = ptr; + + memcpy(&c->uuids[c->length], &uuid, sizeof(uuid)); + c->length += 1; + } - krb5_storage_free(request); krb5_storage_free(response); krb5_data_free(&response_data); - if (ret) + if (ret) { + free(c->uuids); + free(c); return ret; + } - *cursor = malloc(sizeof(tmp)); - if (*cursor == NULL) - return KRB5_CC_NOMEM; - - KCMCURSOR(*cursor) = tmp; + *cursor = c; return 0; } @@ -666,8 +700,15 @@ kcm_get_next (krb5_context context, { krb5_error_code ret; krb5_kcmcache *k = KCMCACHE(id); + krb5_kcm_cursor c = KCMCURSOR(*cursor); krb5_storage *request, *response; krb5_data response_data; + ssize_t sret; + + again: + + if (c->offset >= c->length) + return KRB5_CC_END; ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request); if (ret) @@ -679,23 +720,26 @@ kcm_get_next (krb5_context context, return ret; } - ret = krb5_store_int32(request, KCMCURSOR(*cursor)); - if (ret) { + sret = krb5_storage_write(request, + &c->uuids[c->offset], + sizeof(c->uuids[c->offset])); + c->offset++; + if (sret != sizeof(c->uuids[c->offset])) { krb5_storage_free(request); - return ret; + krb5_clear_error_message(context); + return ENOMEM; } ret = kcm_call(context, k, request, &response, &response_data); - if (ret) { - krb5_storage_free(request); - return ret; + krb5_storage_free(request); + if (ret == KRB5_CC_END) { + goto again; } ret = krb5_ret_creds(response, creds); if (ret) ret = KRB5_CC_IO; - krb5_storage_free(request); krb5_storage_free(response); krb5_data_free(&response_data); @@ -717,6 +761,7 @@ kcm_end_get (krb5_context context, { krb5_error_code ret; krb5_kcmcache *k = KCMCACHE(id); + krb5_kcm_cursor c = KCMCURSOR(*cursor); krb5_storage *request; ret = kcm_storage_request(context, KCM_OP_END_GET, &request); @@ -729,22 +774,14 @@ kcm_end_get (krb5_context context, return ret; } - ret = krb5_store_int32(request, KCMCURSOR(*cursor)); - if (ret) { - krb5_storage_free(request); - return ret; - } - ret = kcm_call(context, k, request, NULL, NULL); - if (ret) { - krb5_storage_free(request); + krb5_storage_free(request); + if (ret) return ret; - } - krb5_storage_free(request); + free(c->uuids); + free(c); - KCMCURSOR(*cursor) = 0; - free(*cursor); *cursor = NULL; return ret; diff --git a/source4/heimdal/lib/krb5/keyblock.c b/source4/heimdal/lib/krb5/keyblock.c index aa6353d7c8..57ed7875fc 100644 --- a/source4/heimdal/lib/krb5/keyblock.c +++ b/source4/heimdal/lib/krb5/keyblock.c @@ -33,7 +33,13 @@ #include "krb5_locl.h" -RCSID("$Id$"); +/** + * Zero out a keyblock + * + * @param keyblock keyblock to zero out + * + * @ingroup krb5_crypto + */ void KRB5_LIB_FUNCTION krb5_keyblock_zero(krb5_keyblock *keyblock) @@ -42,6 +48,15 @@ krb5_keyblock_zero(krb5_keyblock *keyblock) krb5_data_zero(&keyblock->keyvalue); } +/** + * Free a keyblock's content, also zero out the content of the keyblock. + * + * @param context a Kerberos 5 context + * @param keyblock keyblock content to free, NULL is valid argument + * + * @ingroup krb5_crypto + */ + void KRB5_LIB_FUNCTION krb5_free_keyblock_contents(krb5_context context, krb5_keyblock *keyblock) @@ -54,6 +69,16 @@ krb5_free_keyblock_contents(krb5_context context, } } +/** + * Free a keyblock, also zero out the content of the keyblock, uses + * krb5_free_keyblock_contents() to free the content. + * + * @param context a Kerberos 5 context + * @param keyblock keyblock to free, NULL is valid argument + * + * @ingroup krb5_crypto + */ + void KRB5_LIB_FUNCTION krb5_free_keyblock(krb5_context context, krb5_keyblock *keyblock) @@ -64,6 +89,19 @@ krb5_free_keyblock(krb5_context context, } } +/** + * Copy a keyblock, free the output keyblock with + * krb5_free_keyblock_contents(). + * + * @param context a Kerberos 5 context + * @param inblock the key to copy + * @param to the output key. + * + * @param 0 on success or a Kerberos 5 error code + * + * @ingroup krb5_crypto + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_copy_keyblock_contents (krb5_context context, const krb5_keyblock *inblock, @@ -72,31 +110,62 @@ krb5_copy_keyblock_contents (krb5_context context, return copy_EncryptionKey(inblock, to); } +/** + * Copy a keyblock, free the output keyblock with + * krb5_free_keyblock(). + * + * @param context a Kerberos 5 context + * @param inblock the key to copy + * @param to the output key. + * + * @param 0 on success or a Kerberos 5 error code + * + * @ingroup krb5_crypto + */ + + krb5_error_code KRB5_LIB_FUNCTION krb5_copy_keyblock (krb5_context context, const krb5_keyblock *inblock, krb5_keyblock **to) { + krb5_error_code ret; krb5_keyblock *k; + + *to = NULL; - k = malloc (sizeof(*k)); + k = calloc (1, sizeof(*k)); if (k == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } + + ret = krb5_copy_keyblock_contents (context, inblock, k); + if (ret) { + free(k); + return ret; + } *to = k; - return krb5_copy_keyblock_contents (context, inblock, k); + return 0; } +/** + * Get encryption type of a keyblock. + * + * @ingroup krb5_crypto + */ + krb5_enctype krb5_keyblock_get_enctype(const krb5_keyblock *block) { return block->keytype; } -/* +/** * Fill in `key' with key data of type `enctype' from `data' of length - * `size'. Key should be freed using krb5_free_keyblock_contents. + * `size'. Key should be freed using krb5_free_keyblock_contents(). + * + * @ingroup krb5_crypto */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/keytab.c b/source4/heimdal/lib/krb5/keytab.c index aa7c77ce46..fcc74e847e 100644 --- a/source4/heimdal/lib/krb5/keytab.c +++ b/source4/heimdal/lib/krb5/keytab.c @@ -33,11 +33,114 @@ #include "krb5_locl.h" -RCSID("$Id$"); +/** + * @page krb5_keytab_intro The keytab handing functions + * @section section_krb5_keytab Kerberos Keytabs + * + * See the library functions here: @ref krb5_keytab + * + * Keytabs are long term key storage for servers, their equvalment of + * password files. + * + * Normally the only function that useful for server are to specify + * what keytab to use to other core functions like krb5_rd_req() + * krb5_kt_resolve(), and krb5_kt_close(). + * + * @subsection krb5_keytab_names Keytab names + * + * A keytab name is on the form type:residual. The residual part is + * specific to each keytab-type. + * + * When a keytab-name is resolved, the type is matched with an internal + * list of keytab types. If there is no matching keytab type, + * the default keytab is used. The current default type is FILE. + * + * The default value can be changed in the configuration file + * /etc/krb5.conf by setting the variable + * [defaults]default_keytab_name. + * + * The keytab types that are implemented in Heimdal are: + * - file + * store the keytab in a file, the type's name is FILE . The + * residual part is a filename. For compatibility with other + * Kerberos implemtation WRFILE and JAVA14 is also accepted. WRFILE + * has the same format as FILE. JAVA14 have a format that is + * compatible with older versions of MIT kerberos and SUN's Java + * based installation. They store a truncted kvno, so when the knvo + * excess 255, they are truncted in this format. + * + * - keytab + * store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ), + * the type's name is AFSKEYFILE. The residual part is a filename. + * + * - krb4 + * the keytab is a Kerberos 4 srvtab that is on-the-fly converted to + * a keytab. The type's name is krb4 The residual part is a + * filename. + * + * - memory + * The keytab is stored in a memory segment. This allows sensitive + * and/or temporary data not to be stored on disk. The type's name + * is MEMORY. Each MEMORY keytab is referenced counted by and + * opened by the residual name, so two handles can point to the + * same memory area. When the last user closes the entry, it + * disappears. + * + * + * @subsection krb5_keytab_example Keytab example + * + * This is a minimalistic version of ktutil. + * + * @code +int +main (int argc, char **argv) +{ + krb5_context context; + krb5_keytab keytab; + krb5_kt_cursor cursor; + krb5_keytab_entry entry; + krb5_error_code ret; + char *principal; -/* - * Register a new keytab in `ops' - * Return 0 or an error. + if (krb5_init_context (&context) != 0) + errx(1, "krb5_context"); + + ret = krb5_kt_default (context, &keytab); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_default"); + + ret = krb5_kt_start_seq_get(context, keytab, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_start_seq_get"); + while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){ + krb5_unparse_name_short(context, entry.principal, &principal); + printf("principal: %s\n", principal); + free(principal); + krb5_kt_free_entry(context, &entry); + } + ret = krb5_kt_end_seq_get(context, keytab, &cursor); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_end_seq_get"); + ret = krb5_kt_close(context, keytab); + if (ret) + krb5_err(context, 1, ret, "krb5_kt_close"); + krb5_free_context(context); + return 0; +} + * @endcode + * + */ + + +/** + * Register a new keytab backend. + * + * @param context a Keberos context. + * @param ops a backend to register. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -55,7 +158,8 @@ krb5_kt_register(krb5_context context, tmp = realloc(context->kt_types, (context->num_kt_types + 1) * sizeof(*context->kt_types)); if(tmp == NULL) { - krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); return ENOMEM; } memcpy(&tmp[context->num_kt_types], ops, @@ -65,12 +169,20 @@ krb5_kt_register(krb5_context context, return 0; } -/* +/** * Resolve the keytab name (of the form `type:residual') in `name' * into a keytab in `id'. - * Return 0 or an error + * + * @param context a Keberos context. + * @param name name to resolve + * @param id resulting keytab, free with krb5_kt_close(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ + krb5_error_code KRB5_LIB_FUNCTION krb5_kt_resolve(krb5_context context, const char *name, @@ -120,9 +232,16 @@ krb5_kt_resolve(krb5_context context, return ret; } -/* +/** * copy the name of the default keytab into `name'. - * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. + * + * @param context a Keberos context. + * @param name buffer where the name will be written + * @param namesize length of name + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -135,9 +254,16 @@ krb5_kt_default_name(krb5_context context, char *name, size_t namesize) return 0; } -/* - * copy the name of the default modify keytab into `name'. - * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short. +/** + * Copy the name of the default modify keytab into `name'. + * + * @param context a Keberos context. + * @param name buffer where the name will be written + * @param namesize length of name + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -166,9 +292,15 @@ krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize) return 0; } -/* +/** * Set `id' to the default keytab. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param id the new default keytab. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -177,10 +309,20 @@ krb5_kt_default(krb5_context context, krb5_keytab *id) return krb5_kt_resolve (context, context->default_keytab, id); } -/* +/** * Read the key identified by `(principal, vno, enctype)' from the * keytab in `keyprocarg' (the default if == NULL) into `*key'. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param keyprocarg + * @param principal + * @param vno + * @param enctype + * @param key + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -212,9 +354,18 @@ krb5_kt_read_service_key(krb5_context context, return ret; } -/* +/** * Return the type of the `keytab' in the string `prefix of length * `prefixsize'. + * + * @param context a Keberos context. + * @param keytab the keytab to get the prefix for + * @param prefix prefix buffer + * @param prefixsize length of prefix buffer + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -227,9 +378,17 @@ krb5_kt_get_type(krb5_context context, return 0; } -/* +/** * Retrieve the name of the keytab `keytab' into `name', `namesize' - * Return 0 or an error. + * + * @param context a Keberos context. + * @param keytab the keytab to get the name for. + * @param name name buffer. + * @param namesize size of name buffer. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -241,10 +400,18 @@ krb5_kt_get_name(krb5_context context, return (*keytab->get_name)(context, keytab, name, namesize); } -/* +/** * Retrieve the full name of the keytab `keytab' and store the name in - * `str'. `str' needs to be freed by the caller using free(3). - * Returns 0 or an error. On error, *str is set to NULL. + * `str'. + * + * @param context a Keberos context. + * @param keytab keytab to get name for. + * @param str the name of the keytab name, usee krb5_xfree() to free + * the string. On error, *str is set to NULL. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -275,9 +442,16 @@ krb5_kt_get_full_name(krb5_context context, return 0; } -/* +/** * Finish using the keytab in `id'. All resources will be released, - * even on errors. Return 0 or an error. + * even on errors. + * + * @param context a Keberos context. + * @param id keytab to close. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -292,10 +466,61 @@ krb5_kt_close(krb5_context context, return ret; } +/** + * Destroy (remove) the keytab in `id'. All resources will be released, + * even on errors, does the equvalment of krb5_kt_close() on the resources. + * + * @param context a Keberos context. + * @param id keytab to destroy. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_kt_destroy(krb5_context context, + krb5_keytab id) +{ + krb5_error_code ret; + + ret = (*id->destroy)(context, id); + krb5_kt_close(context, id); + return ret; +} + /* + * Match any aliases in keytab `entry' with `principal'. + */ + +static krb5_boolean +compare_aliseses(krb5_context context, + krb5_keytab_entry *entry, + krb5_const_principal principal) +{ + unsigned int i; + if (entry->aliases == NULL) + return FALSE; + for (i = 0; i < entry->aliases->len; i++) + if (krb5_principal_compare(context, &entry->aliases->val[i], principal)) + return TRUE; + return FALSE; +} + +/** * Compare `entry' against `principal, vno, enctype'. * Any of `principal, vno, enctype' might be 0 which acts as a wildcard. * Return TRUE if they compare the same, FALSE otherwise. + * + * @param context a Keberos context. + * @param entry an entry to match with. + * @param principal principal to match, NULL matches all principals. + * @param vno key version to match, 0 matches all key version numbers. + * @param enctype encryption type to match, 0 matches all encryption types. + * + * @return Return TRUE or match, FALSE if not matched. + * + * @ingroup krb5_keytab */ krb5_boolean KRB5_LIB_FUNCTION @@ -306,7 +531,8 @@ krb5_kt_compare(krb5_context context, krb5_enctype enctype) { if(principal != NULL && - !krb5_principal_compare(context, entry->principal, principal)) + !(krb5_principal_compare(context, entry->principal, principal) || + compare_aliseses(context, entry, principal))) return FALSE; if(vno && vno != entry->vno) return FALSE; @@ -315,11 +541,53 @@ krb5_kt_compare(krb5_context context, return TRUE; } -/* +krb5_error_code +_krb5_kt_principal_not_found(krb5_context context, + krb5_error_code ret, + krb5_keytab id, + krb5_const_principal principal, + krb5_enctype enctype, + int kvno) +{ + char princ[256], kvno_str[25], *kt_name; + char *enctype_str = NULL; + + krb5_unparse_name_fixed (context, principal, princ, sizeof(princ)); + krb5_kt_get_full_name (context, id, &kt_name); + krb5_enctype_to_string(context, enctype, &enctype_str); + + if (kvno) + snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno); + else + kvno_str[0] = '\0'; + + krb5_set_error_message (context, ret, + N_("Failed to find %s%s in keytab %s (%s)", + "principal, kvno, keytab file, enctype"), + princ, + kvno_str, + kt_name ? kt_name : "unknown keytab", + enctype_str ? enctype_str : "unknown enctype"); + free(kt_name); + free(enctype_str); + return ret; +} + + +/** * Retrieve the keytab entry for `principal, kvno, enctype' into `entry' - * from the keytab `id'. - * kvno == 0 is a wildcard and gives the keytab with the highest vno. - * Return 0 or an error. + * from the keytab `id'. Matching is done like krb5_kt_compare(). + * + * @param context a Keberos context. + * @param id a keytab. + * @param principal principal to match, NULL matches all principals. + * @param kvno key version to match, 0 matches all key version numbers. + * @param enctype encryption type to match, 0 matches all encryption types. + * @param entry the returned entry, free with krb5_kt_free_entry(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -365,37 +633,23 @@ krb5_kt_get_entry(krb5_context context, krb5_kt_free_entry(context, &tmp); } krb5_kt_end_seq_get (context, id, &cursor); - if (entry->vno) { - return 0; - } else { - char princ[256], kvno_str[25], *kt_name; - char *enctype_str = NULL; - - krb5_unparse_name_fixed (context, principal, princ, sizeof(princ)); - krb5_kt_get_full_name (context, id, &kt_name); - krb5_enctype_to_string(context, enctype, &enctype_str); - - if (kvno) - snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno); - else - kvno_str[0] = '\0'; - - krb5_set_error_message (context, KRB5_KT_NOTFOUND, - N_("Failed to find %s%s in keytab %s (%s)", - "principal, kvno, keytab file, enctype"), - princ, - kvno_str, - kt_name ? kt_name : "unknown keytab", - enctype_str ? enctype_str : "unknown enctype"); - free(kt_name); - free(enctype_str); - return KRB5_KT_NOTFOUND; - } + if (entry->vno == 0) + return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND, + id, principal, enctype, kvno); + return 0; } -/* +/** * Copy the contents of `in' into `out'. - * Return 0 or an error. */ + * + * @param context a Keberos context. + * @param in the keytab entry to copy. + * @param out the copy of the keytab entry, free with krb5_kt_free_entry(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab + */ krb5_error_code KRB5_LIB_FUNCTION krb5_kt_copy_entry_contents(krb5_context context, @@ -422,8 +676,15 @@ fail: return ret; } -/* +/** * Free the contents of `entry'. + * + * @param context a Keberos context. + * @param entry the entry to free + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -436,9 +697,16 @@ krb5_kt_free_entry(krb5_context context, return 0; } -/* +/** * Set `cursor' to point at the beginning of `id'. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param id a keytab. + * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get(). + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -456,10 +724,18 @@ krb5_kt_start_seq_get(krb5_context context, return (*id->start_seq_get)(context, id, cursor); } -/* - * Get the next entry from `id' pointed to by `cursor' and advance the - * `cursor'. - * Return 0 or an error. +/** + * Get the next entry from keytab, advance the cursor. On last entry + * the function will return KRB5_KT_END. + * + * @param context a Keberos context. + * @param id a keytab. + * @param entry the returned entry, free with krb5_kt_free_entry(). + * @param cursor the cursor of the iteration. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -478,8 +754,16 @@ krb5_kt_next_entry(krb5_context context, return (*id->next_entry)(context, id, entry, cursor); } -/* +/** * Release all resources associated with `cursor'. + * + * @param context a Keberos context. + * @param id a keytab. + * @param cursor the cursor to free. + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -496,9 +780,16 @@ krb5_kt_end_seq_get(krb5_context context, return (*id->end_seq_get)(context, id, cursor); } -/* +/** * Add the entry in `entry' to the keytab `id'. - * Return 0 or an error. + * + * @param context a Keberos context. + * @param id a keytab. + * @param entry the entry to add + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION @@ -516,9 +807,17 @@ krb5_kt_add_entry(krb5_context context, return (*id->add)(context, id,entry); } -/* - * Remove the entry `entry' from the keytab `id'. - * Return 0 or an error. +/** + * Remove an entry from the keytab, matching is done using + * krb5_kt_compare(). + + * @param context a Keberos context. + * @param id a keytab. + * @param entry the entry to remove + * + * @return Return an error code or 0, see krb5_get_error_message(). + * + * @ingroup krb5_keytab */ krb5_error_code KRB5_LIB_FUNCTION diff --git a/source4/heimdal/lib/krb5/keytab_any.c b/source4/heimdal/lib/krb5/keytab_any.c index 7a2d9b9f70..02de8c8028 100644 --- a/source4/heimdal/lib/krb5/keytab_any.c +++ b/source4/heimdal/lib/krb5/keytab_any.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct any_data { krb5_keytab kt; char *name; @@ -253,6 +251,7 @@ const krb5_kt_ops krb5_any_ops = { any_resolve, any_get_name, any_close, + NULL, /* destroy */ NULL, /* get */ any_start_seq_get, any_next_entry, diff --git a/source4/heimdal/lib/krb5/keytab_file.c b/source4/heimdal/lib/krb5/keytab_file.c index f494cac253..819366443f 100644 --- a/source4/heimdal/lib/krb5/keytab_file.c +++ b/source4/heimdal/lib/krb5/keytab_file.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - #define KRB5_KT_VNO_1 1 #define KRB5_KT_VNO_2 2 #define KRB5_KT_VNO KRB5_KT_VNO_2 @@ -332,6 +330,14 @@ fkt_close(krb5_context context, krb5_keytab id) } static krb5_error_code +fkt_destroy(krb5_context context, krb5_keytab id) +{ + struct fkt_data *d = id->data; + _krb5_erase_file(context, d->filename); + return 0; +} + +static krb5_error_code fkt_get_name(krb5_context context, krb5_keytab id, char *name, @@ -445,6 +451,7 @@ fkt_next_entry_int(krb5_context context, int ret; int8_t tmp8; int32_t tmp32; + uint32_t utmp32; off_t pos, curpos; pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); @@ -459,8 +466,8 @@ loop: ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal); if (ret) goto out; - ret = krb5_ret_int32(cursor->sp, &tmp32); - entry->timestamp = tmp32; + ret = krb5_ret_uint32(cursor->sp, &utmp32); + entry->timestamp = utmp32; if (ret) goto out; ret = krb5_ret_int8(cursor->sp, &tmp8); @@ -476,10 +483,19 @@ loop: curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR); if(len + 4 + pos - curpos >= 4) { ret = krb5_ret_int32(cursor->sp, &tmp32); - if (ret == 0 && tmp32 != 0) { + if (ret == 0 && tmp32 != 0) entry->vno = tmp32; - } } + /* there might be a flags field here */ + if(len + 4 + pos - curpos >= 8) { + ret = krb5_ret_uint32(cursor->sp, &utmp32); + if (ret == 0) + entry->flags = tmp32; + } else + entry->flags = 0; + + entry->aliases = NULL; + if(start) *start = pos; if(end) *end = pos + 4 + len; out: @@ -653,6 +669,15 @@ fkt_add_entry(krb5_context context, krb5_storage_free(emem); goto out; } + ret = krb5_store_uint32 (emem, entry->flags); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed storing extended kvno " + "in keytab %s", ""), + d->filename); + krb5_storage_free(emem); + goto out; + } } ret = krb5_storage_to_data(emem, &keytab); @@ -744,6 +769,7 @@ const krb5_kt_ops krb5_fkt_ops = { fkt_resolve, fkt_get_name, fkt_close, + fkt_destroy, NULL, /* get */ fkt_start_seq_get, fkt_next_entry, @@ -757,6 +783,7 @@ const krb5_kt_ops krb5_wrfkt_ops = { fkt_resolve, fkt_get_name, fkt_close, + fkt_destroy, NULL, /* get */ fkt_start_seq_get, fkt_next_entry, @@ -770,6 +797,7 @@ const krb5_kt_ops krb5_javakt_ops = { fkt_resolve_java14, fkt_get_name, fkt_close, + fkt_destroy, NULL, /* get */ fkt_start_seq_get, fkt_next_entry, diff --git a/source4/heimdal/lib/krb5/keytab_keyfile.c b/source4/heimdal/lib/krb5/keytab_keyfile.c index 71d3d89d58..54666c7d44 100644 --- a/source4/heimdal/lib/krb5/keytab_keyfile.c +++ b/source4/heimdal/lib/krb5/keytab_keyfile.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - #ifndef HEIMDAL_SMALLER /* afs keyfile operations --------------------------------------- */ @@ -275,6 +273,8 @@ akf_next_entry(krb5_context context, ret = 0; entry->timestamp = time(NULL); + entry->flags = 0; + entry->aliases = NULL; out: krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET); @@ -440,6 +440,7 @@ const krb5_kt_ops krb5_akf_ops = { akf_resolve, akf_get_name, akf_close, + NULL, /* destroy */ NULL, /* get */ akf_start_seq_get, akf_next_entry, diff --git a/source4/heimdal/lib/krb5/keytab_memory.c b/source4/heimdal/lib/krb5/keytab_memory.c index defd10d67c..73ffa1c67d 100644 --- a/source4/heimdal/lib/krb5/keytab_memory.c +++ b/source4/heimdal/lib/krb5/keytab_memory.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* memory operations -------------------------------------------- */ struct mkt_data { @@ -228,6 +226,7 @@ const krb5_kt_ops krb5_mkt_ops = { mkt_resolve, mkt_get_name, mkt_close, + NULL, /* destroy */ NULL, /* get */ mkt_start_seq_get, mkt_next_entry, diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h index 0ba4e7b54a..13dafacf21 100644 --- a/source4/heimdal/lib/krb5/krb5.h +++ b/source4/heimdal/lib/krb5/krb5.h @@ -51,6 +51,10 @@ #define KRB5KDC_ERR_KEY_EXP KRB5KDC_ERR_KEY_EXPIRED #endif +#ifndef KRB5_DEPRECATED +#define KRB5_DEPRECATED __attribute__((deprecated)) +#endif + /* simple constants */ #ifndef TRUE @@ -92,6 +96,8 @@ typedef Checksum krb5_checksum; typedef ENCTYPE krb5_enctype; +typedef struct krb5_get_init_creds_ctx *krb5_init_creds_context; + typedef heim_octet_string krb5_data; /* PKINIT related forward declarations */ @@ -219,6 +225,8 @@ typedef enum krb5_key_usage { /* Keyusage for the server referral in a TGS req */ KRB5_KU_SAM_ENC_NONCE_SAD = 27, /* Encryption of the SAM-NONCE-OR-SAD field */ + KRB5_KU_PA_PKINIT_KX = 44, + /* Encryption type of the kdc session contribution in pk-init */ KRB5_KU_DIGEST_ENCRYPT = -18, /* Encryption key usage used in the digest encryption field */ KRB5_KU_DIGEST_OPAQUE = -19, @@ -272,13 +280,13 @@ typedef HostAddress krb5_address; typedef HostAddresses krb5_addresses; typedef enum krb5_keytype { - KEYTYPE_NULL = 0, - KEYTYPE_DES = 1, - KEYTYPE_DES3 = 7, - KEYTYPE_AES128 = 17, - KEYTYPE_AES256 = 18, - KEYTYPE_ARCFOUR = 23, - KEYTYPE_ARCFOUR_56 = 24 + KEYTYPE_NULL = ETYPE_NULL, + KEYTYPE_DES = ETYPE_DES_CBC_CRC, + KEYTYPE_DES3 = ETYPE_OLD_DES3_CBC_SHA1, + KEYTYPE_AES128 = ETYPE_AES128_CTS_HMAC_SHA1_96, + KEYTYPE_AES256 = ETYPE_AES256_CTS_HMAC_SHA1_96, + KEYTYPE_ARCFOUR = ETYPE_ARCFOUR_HMAC_MD5, + KEYTYPE_ARCFOUR_56 = ETYPE_ARCFOUR_HMAC_MD5_56 } krb5_keytype; typedef EncryptionKey krb5_keyblock; @@ -317,6 +325,7 @@ typedef const char *krb5_const_realm; /* stupid language */ typedef Principal krb5_principal_data; typedef struct Principal *krb5_principal; typedef const struct Principal *krb5_const_principal; +typedef struct Principals *krb5_principals; typedef time_t krb5_deltat; typedef time_t krb5_timestamp; @@ -478,6 +487,8 @@ typedef struct krb5_keytab_entry { krb5_kvno vno; krb5_keyblock keyblock; uint32_t timestamp; + uint32_t flags; + krb5_principals aliases; } krb5_keytab_entry; typedef struct krb5_kt_cursor { @@ -497,6 +508,7 @@ struct krb5_keytab_data { krb5_error_code (*resolve)(krb5_context, const char*, krb5_keytab); krb5_error_code (*get_name)(krb5_context, krb5_keytab, char*, size_t); krb5_error_code (*close)(krb5_context, krb5_keytab); + krb5_error_code (*destroy)(krb5_context, krb5_keytab); krb5_error_code (*get)(krb5_context, krb5_keytab, krb5_const_principal, krb5_kvno, krb5_enctype, krb5_keytab_entry*); krb5_error_code (*start_seq_get)(krb5_context, krb5_keytab, krb5_kt_cursor*); @@ -593,7 +605,8 @@ typedef EncAPRepPart krb5_ap_rep_enc_part; #define KRB5_TGS_NAME_SIZE (6) #define KRB5_TGS_NAME ("krbtgt") - +#define KRB5_WELLKNOWN_NAME ("WELLKNOWN") +#define KRB5_ANON_NAME ("ANONYMOUS") #define KRB5_DIGEST_NAME ("digest") typedef enum { @@ -636,7 +649,7 @@ typedef krb5_error_code (*krb5_s2k_proc)(krb5_context /*context*/, struct _krb5_get_init_creds_opt_private; -typedef struct _krb5_get_init_creds_opt { +struct _krb5_get_init_creds_opt { krb5_flags flags; krb5_deltat tkt_life; krb5_deltat renew_life; @@ -652,7 +665,9 @@ typedef struct _krb5_get_init_creds_opt { int preauth_list_length; krb5_data *salt; struct _krb5_get_init_creds_opt_private *opt_private; -} krb5_get_init_creds_opt; +}; + +typedef struct _krb5_get_init_creds_opt krb5_get_init_creds_opt; #define KRB5_GET_INIT_CREDS_OPT_TKT_LIFE 0x0001 #define KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE 0x0002 @@ -661,7 +676,7 @@ typedef struct _krb5_get_init_creds_opt { #define KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST 0x0010 #define KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST 0x0020 #define KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST 0x0040 -#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080 +#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080 /* no supported */ #define KRB5_GET_INIT_CREDS_OPT_ANONYMOUS 0x0100 #define KRB5_GET_INIT_CREDS_OPT_DISABLE_TRANSITED_CHECK 0x0200 @@ -727,22 +742,22 @@ enum { typedef krb5_error_code (*krb5_send_to_kdc_func)(krb5_context, void *, krb5_krbhst_info *, - time_t timeout, + time_t, const krb5_data *, krb5_data *); -/* flags for krb5_parse_name_flags */ +/** flags for krb5_parse_name_flags */ enum { - KRB5_PRINCIPAL_PARSE_NO_REALM = 1, - KRB5_PRINCIPAL_PARSE_MUST_REALM = 2, - KRB5_PRINCIPAL_PARSE_ENTERPRISE = 4 + KRB5_PRINCIPAL_PARSE_NO_REALM = 1, /**< Require that there are no realm */ + KRB5_PRINCIPAL_PARSE_REQUIRE_REALM = 2, /**< Require a realm present */ + KRB5_PRINCIPAL_PARSE_ENTERPRISE = 4 /**< Parse as a NT-ENTERPRISE name */ }; -/* flags for krb5_unparse_name_flags */ +/** flags for krb5_unparse_name_flags */ enum { - KRB5_PRINCIPAL_UNPARSE_SHORT = 1, - KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2, - KRB5_PRINCIPAL_UNPARSE_DISPLAY = 4 + KRB5_PRINCIPAL_UNPARSE_SHORT = 1, /**< No realm if it is the default realm */ + KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2, /**< No realm */ + KRB5_PRINCIPAL_UNPARSE_DISPLAY = 4 /**< No quoting */ }; typedef struct krb5_sendto_ctx_data *krb5_sendto_ctx; @@ -787,6 +802,20 @@ typedef struct krb5_crypto_iov { } krb5_crypto_iov; +/* Glue for MIT */ + +typedef struct { + int32_t lr_type; + krb5_timestamp value; +} krb5_last_req_entry; + +typedef krb5_error_code +(*krb5_gic_process_last_req)(krb5_context, krb5_last_req_entry **, void *); + +/* + * + */ + #include <krb5-protos.h> /* variables */ @@ -810,5 +839,11 @@ extern KRB5_LIB_VARIABLE const krb5_kt_ops krb4_fkt_ops; extern KRB5_LIB_VARIABLE const krb5_kt_ops krb5_srvtab_fkt_ops; extern KRB5_LIB_VARIABLE const krb5_kt_ops krb5_any_ops; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_api; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_file; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_memory; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_kcm; +extern KRB5_LIB_VARIABLE const char *krb5_cc_type_scc; + #endif /* __KRB5_H__ */ diff --git a/source4/heimdal/lib/krb5/krb5_ccapi.h b/source4/heimdal/lib/krb5/krb5_ccapi.h index ec0cb3bc0b..5a7fe6a413 100644 --- a/source4/heimdal/lib/krb5/krb5_ccapi.h +++ b/source4/heimdal/lib/krb5/krb5_ccapi.h @@ -38,6 +38,10 @@ #include <krb5-types.h> + #ifdef __APPLE__ +#pragma pack(push,2) +#endif + enum { cc_credentials_v5 = 2 }; @@ -92,7 +96,7 @@ typedef struct cc_credentials_v5_t cc_credentials_v5_t; typedef struct cc_credentials_t *cc_credentials_t; typedef struct cc_credentials_iterator_t *cc_credentials_iterator_t; typedef struct cc_string_t *cc_string_t; -typedef time_t cc_time_t; +typedef cc_uint32 cc_time_t; typedef struct cc_data { cc_uint32 type; @@ -227,4 +231,9 @@ struct cc_context_t { typedef cc_int32 (*cc_initialize_func)(cc_context_t*, cc_int32, cc_int32 *, char const **); +#ifdef __APPLE__ +#pragma pack(pop) +#endif + + #endif /* KRB5_CCAPI_H */ diff --git a/source4/heimdal/lib/krb5/krb5_err.et b/source4/heimdal/lib/krb5/krb5_err.et index c076992d0b..098e04b959 100644 --- a/source4/heimdal/lib/krb5/krb5_err.et +++ b/source4/heimdal/lib/krb5/krb5_err.et @@ -106,7 +106,13 @@ error_code PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED, "Public key encryption not suppo #error_code ERR_KDC_NOT_FOUND, "IAKERB proxy could not find a KDC" #error_code ERR_KDC_NO_RESPONSE, "IAKERB proxy never reeived a response from a KDC" -# 82-127 are reserved +# 82-93 are reserved + +index 94 +error_code INVALID_HASH_ALG, "Invalid OTP digest algorithm" +error_code INVALID_ITERATION_COUNT, "Invalid OTP iteration count" + +# 97-127 are reserved index 128 prefix diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h index ced722f2d9..2d8bc07de3 100644 --- a/source4/heimdal/lib/krb5/krb5_locl.h +++ b/source4/heimdal/lib/krb5/krb5_locl.h @@ -36,9 +36,7 @@ #ifndef __KRB5_LOCL_H__ #define __KRB5_LOCL_H__ -#ifdef HAVE_CONFIG_H #include <config.h> -#endif #include <errno.h> #include <ctype.h> @@ -214,11 +212,14 @@ struct _krb5_get_init_creds_opt_private { krb5_get_init_creds_tristate req_pac; /* PKINIT */ krb5_pk_init_ctx pk_init_ctx; - KRB_ERROR *error; krb5_get_init_creds_tristate addressless; int flags; #define KRB5_INIT_CREDS_CANONICALIZE 1 #define KRB5_INIT_CREDS_NO_C_CANON_CHECK 2 + struct { + krb5_gic_process_last_req func; + void *ctx; + } lr; }; typedef struct krb5_context_data { @@ -261,6 +262,7 @@ typedef struct krb5_context_data { int flags; #define KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME 1 #define KRB5_CTX_F_CHECK_PAC 2 +#define KRB5_CTX_F_HOMEDIR_ACCESS 4 struct send_to_kdc *send_to_kdc; } krb5_context_data; @@ -295,6 +297,7 @@ struct krb5_pk_identity { hx509_context hx509ctx; hx509_verify_ctx verify_ctx; hx509_certs certs; + hx509_cert cert; hx509_certs anchors; hx509_certs certpool; hx509_revoke_ctx revokectx; diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c index 7348ac3f00..e9111abec9 100644 --- a/source4/heimdal/lib/krb5/krbhst.c +++ b/source4/heimdal/lib/krb5/krbhst.c @@ -35,8 +35,6 @@ #include <resolve.h> #include "locate_plugin.h" -RCSID("$Id$"); - static int string_to_proto(const char *string) { @@ -61,8 +59,8 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, const char *proto, const char *service, int port) { char domain[1024]; - struct dns_reply *r; - struct resource_record *rr; + struct rk_dns_reply *r; + struct rk_resource_record *rr; int num_srv; int proto_num; int def_port; @@ -87,32 +85,32 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, snprintf(domain, sizeof(domain), "_%s._%s.%s.", service, proto, realm); - r = dns_lookup(domain, dns_type); + r = rk_dns_lookup(domain, dns_type); if(r == NULL) return KRB5_KDC_UNREACH; for(num_srv = 0, rr = r->head; rr; rr = rr->next) - if(rr->type == T_SRV) + if(rr->type == rk_ns_t_srv) num_srv++; *res = malloc(num_srv * sizeof(**res)); if(*res == NULL) { - dns_free_data(r); + rk_dns_free_data(r); krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); return ENOMEM; } - dns_srv_order(r); + rk_dns_srv_order(r); for(num_srv = 0, rr = r->head; rr; rr = rr->next) - if(rr->type == T_SRV) { + if(rr->type == rk_ns_t_srv) { krb5_krbhst_info *hi; size_t len = strlen(rr->u.srv->target); hi = calloc(1, sizeof(*hi) + len); if(hi == NULL) { - dns_free_data(r); + rk_dns_free_data(r); while(--num_srv >= 0) free((*res)[num_srv]); free(*res); @@ -134,7 +132,7 @@ srv_find_realm(krb5_context context, krb5_krbhst_info ***res, int *count, *count = num_srv; - dns_free_data(r); + rk_dns_free_data(r); return 0; } @@ -948,7 +946,7 @@ gethostlist(krb5_context context, const char *realm, return ENOMEM; } } - (*hostlist)[nhost++] = NULL; + (*hostlist)[nhost] = NULL; krb5_krbhst_free(context, handle); return 0; } diff --git a/source4/heimdal/lib/krb5/locate_plugin.h b/source4/heimdal/lib/krb5/locate_plugin.h index 529488ddfd..b1b1f0ef23 100644 --- a/source4/heimdal/lib/krb5/locate_plugin.h +++ b/source4/heimdal/lib/krb5/locate_plugin.h @@ -36,9 +36,7 @@ #ifndef HEIMDAL_KRB5_LOCATE_PLUGIN_H #define HEIMDAL_KRB5_LOCATE_PLUGIN_H 1 -#include <krb5.h> - -#define KRB5_PLUGIN_LOCATE "resolve" +#define KRB5_PLUGIN_LOCATE "service_locator" enum locate_service_type { locate_service_kdc = 1, diff --git a/source4/heimdal/lib/krb5/log.c b/source4/heimdal/lib/krb5/log.c index 587cf7ed97..31d267320f 100644 --- a/source4/heimdal/lib/krb5/log.c +++ b/source4/heimdal/lib/krb5/log.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct facility { int min; int max; diff --git a/source4/heimdal/lib/krb5/mcache.c b/source4/heimdal/lib/krb5/mcache.c index 752608069d..78ef68db3d 100644 --- a/source4/heimdal/lib/krb5/mcache.c +++ b/source4/heimdal/lib/krb5/mcache.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - typedef struct krb5_mcache { char *name; unsigned int refcnt; diff --git a/source4/heimdal/lib/krb5/misc.c b/source4/heimdal/lib/krb5/misc.c index 4cee5e22e1..e47383880c 100644 --- a/source4/heimdal/lib/krb5/misc.c +++ b/source4/heimdal/lib/krb5/misc.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION _krb5_s4u2self_to_checksumdata(krb5_context context, const PA_S4U2Self *self, diff --git a/source4/heimdal/lib/krb5/mit_glue.c b/source4/heimdal/lib/krb5/mit_glue.c index f8f13922f5..dab5c6046a 100644 --- a/source4/heimdal/lib/krb5/mit_glue.c +++ b/source4/heimdal/lib/krb5/mit_glue.c @@ -31,8 +31,9 @@ * SUCH DAMAGE. */ +#define KRB5_DEPRECATED + #include "krb5_locl.h" -RCSID("$Id$"); #ifndef HEIMDAL_SMALLER @@ -315,8 +316,9 @@ krb5_c_enctype_compare(krb5_context context, krb5_enctype e1, krb5_enctype e2, krb5_boolean *similar) + KRB5_DEPRECATED { - *similar = krb5_enctypes_compatible_keys(context, e1, e2); + *similar = (e1 == e2); return 0; } @@ -370,4 +372,18 @@ krb5_c_prf(krb5_context context, return ret; } +/** + * MIT compat glue + * + * @ingroup krb5_ccache + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_cc_copy_creds(krb5_context context, + const krb5_ccache from, + krb5_ccache to) +{ + return krb5_cc_copy_cache(context, from, to); +} + #endif /* HEIMDAL_SMALLER */ diff --git a/source4/heimdal/lib/krb5/mk_error.c b/source4/heimdal/lib/krb5/mk_error.c index 989aa23d75..f623fc495b 100644 --- a/source4/heimdal/lib/krb5/mk_error.c +++ b/source4/heimdal/lib/krb5/mk_error.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_error(krb5_context context, krb5_error_code error_code, diff --git a/source4/heimdal/lib/krb5/mk_priv.c b/source4/heimdal/lib/krb5/mk_priv.c index 86a6b669b1..40f09ae33f 100644 --- a/source4/heimdal/lib/krb5/mk_priv.c +++ b/source4/heimdal/lib/krb5/mk_priv.c @@ -33,9 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_priv(krb5_context context, krb5_auth_context auth_context, diff --git a/source4/heimdal/lib/krb5/mk_rep.c b/source4/heimdal/lib/krb5/mk_rep.c index bba276183a..8eef0ea652 100644 --- a/source4/heimdal/lib/krb5/mk_rep.c +++ b/source4/heimdal/lib/krb5/mk_rep.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_rep(krb5_context context, krb5_auth_context auth_context, diff --git a/source4/heimdal/lib/krb5/mk_req.c b/source4/heimdal/lib/krb5/mk_req.c index 1570637738..c87fa61293 100644 --- a/source4/heimdal/lib/krb5/mk_req.c +++ b/source4/heimdal/lib/krb5/mk_req.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_mk_req_exact(krb5_context context, krb5_auth_context *auth_context, diff --git a/source4/heimdal/lib/krb5/mk_req_ext.c b/source4/heimdal/lib/krb5/mk_req_ext.c index aba804716c..d130272aa1 100644 --- a/source4/heimdal/lib/krb5/mk_req_ext.c +++ b/source4/heimdal/lib/krb5/mk_req_ext.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code _krb5_mk_req_internal(krb5_context context, krb5_auth_context *auth_context, diff --git a/source4/heimdal/lib/krb5/n-fold.c b/source4/heimdal/lib/krb5/n-fold.c index fa45b09f18..0623f6aae1 100644 --- a/source4/heimdal/lib/krb5/n-fold.c +++ b/source4/heimdal/lib/krb5/n-fold.c @@ -32,8 +32,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - static krb5_error_code rr13(unsigned char *buf, size_t len) { @@ -109,8 +107,10 @@ _krb5_n_fold(const void *str, size_t len, void *key, size_t size) unsigned char *tmp = malloc(maxlen); unsigned char *buf = malloc(len); - if (tmp == NULL || buf == NULL) - return ENOMEM; + if (tmp == NULL || buf == NULL) { + ret = ENOMEM; + goto out; + } memcpy(buf, str, len); memset(key, 0, size); @@ -129,9 +129,13 @@ _krb5_n_fold(const void *str, size_t len, void *key, size_t size) } } while(l != 0); out: - memset(buf, 0, len); - free(buf); - memset(tmp, 0, maxlen); - free(tmp); + if (buf) { + memset(buf, 0, len); + free(buf); + } + if (tmp) { + memset(tmp, 0, maxlen); + free(tmp); + } return ret; } diff --git a/source4/heimdal/lib/krb5/pac.c b/source4/heimdal/lib/krb5/pac.c index 3c55eb3dc3..b66e79960d 100644 --- a/source4/heimdal/lib/krb5/pac.c +++ b/source4/heimdal/lib/krb5/pac.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <wind.h> -RCSID("$Id$"); - struct PAC_INFO_BUFFER { uint32_t type; uint32_t buffersize; @@ -613,6 +611,7 @@ verify_logonname(krb5_context context, ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len); free(ucs2); if (ret) { + free(s); krb5_set_error_message(context, ret, "Failed to convert to UTF-8"); return ret; } diff --git a/source4/heimdal/lib/krb5/padata.c b/source4/heimdal/lib/krb5/padata.c index 022260e709..aa08248ed1 100644 --- a/source4/heimdal/lib/krb5/padata.c +++ b/source4/heimdal/lib/krb5/padata.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - PA_DATA * krb5_find_padata(PA_DATA *val, unsigned len, int type, int *idx) { diff --git a/source4/heimdal/lib/krb5/pkinit.c b/source4/heimdal/lib/krb5/pkinit.c index de5e90a68e..18b5b5e017 100644 --- a/source4/heimdal/lib/krb5/pkinit.c +++ b/source4/heimdal/lib/krb5/pkinit.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - struct krb5_dh_moduli { char *name; unsigned long bits; @@ -60,7 +58,13 @@ struct krb5_pk_cert { struct krb5_pk_init_ctx_data { struct krb5_pk_identity *id; - DH *dh; + enum { USE_RSA, USE_DH, USE_ECDH } keyex; + union { + DH *dh; +#ifdef HAVE_OPENSSL + EC_KEY *eckey; +#endif + } u; krb5_data *clientDHNonce; struct krb5_dh_moduli **m; hx509_peer_info peer; @@ -122,6 +126,45 @@ integer_to_BN(krb5_context context, const char *field, const heim_integer *f) return bn; } +static krb5_error_code +select_dh_group(krb5_context context, DH *dh, unsigned long bits, + struct krb5_dh_moduli **moduli) +{ + const struct krb5_dh_moduli *m; + + if (bits == 0) { + m = moduli[1]; /* XXX */ + if (m == NULL) + m = moduli[0]; /* XXX */ + } else { + int i; + for (i = 0; moduli[i] != NULL; i++) { + if (bits < moduli[i]->bits) + break; + } + if (moduli[i] == NULL) { + krb5_set_error_message(context, EINVAL, + N_("Did not find a DH group parameter " + "matching requirement of %lu bits", ""), + bits); + return EINVAL; + } + m = moduli[i]; + } + + dh->p = integer_to_BN(context, "p", &m->p); + if (dh->p == NULL) + return ENOMEM; + dh->g = integer_to_BN(context, "g", &m->g); + if (dh->g == NULL) + return ENOMEM; + dh->q = integer_to_BN(context, "q", &m->q); + if (dh->q == NULL) + return ENOMEM; + + return 0; +} + struct certfind { const char *type; const heim_oid *oid; @@ -139,12 +182,12 @@ find_cert(krb5_context context, struct krb5_pk_identity *id, struct certfind cf[3] = { { "PKINIT EKU" }, { "MS EKU" }, - { "no" } + { "any (or no)" } }; int i, ret; - cf[0].oid = oid_id_pkekuoid(); - cf[1].oid = oid_id_pkinit_ms_eku(); + cf[0].oid = &asn1_oid_id_pkekuoid; + cf[1].oid = &asn1_oid_id_pkinit_ms_eku; cf[2].oid = NULL; for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) { @@ -159,7 +202,7 @@ find_cert(krb5_context context, struct krb5_pk_identity *id, if (ret == 0) break; pk_copy_error(context, id->hx509ctx, ret, - "Failed cert for finding %s OID", cf[i].type); + "Failed finding certificate with %s OID", cf[i].type); } return ret; } @@ -173,37 +216,22 @@ create_signature(krb5_context context, hx509_peer_info peer, krb5_data *sd_data) { - hx509_cert cert = NULL; - hx509_query *q = NULL; - int ret; - - ret = hx509_query_alloc(id->hx509ctx, &q); - if (ret) { - pk_copy_error(context, id->hx509ctx, ret, - "Allocate query to find signing certificate"); - return ret; - } + int ret, flags = 0; - hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); - hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); - - ret = find_cert(context, id, q, &cert); - hx509_query_free(id->hx509ctx, q); - if (ret) - return ret; + if (id->cert == NULL) + flags |= HX509_CMS_SIGNATURE_NO_SIGNER; ret = hx509_cms_create_signed_1(id->hx509ctx, - 0, + flags, eContentType, eContent->data, eContent->length, NULL, - cert, + id->cert, peer, NULL, id->certs, sd_data); - hx509_cert_free(cert); if (ret) { pk_copy_error(context, id->hx509ctx, ret, "Create CMS signedData"); @@ -222,6 +250,9 @@ cert2epi(hx509_context context, void *ctx, hx509_cert c) void *p; int ret; + if (ids->len > 10) + return 0; + memset(&id, 0, sizeof(id)); ret = hx509_cert_get_subject(c, &subject); @@ -319,7 +350,6 @@ static krb5_error_code build_auth_pack(krb5_context context, unsigned nonce, krb5_pk_init_ctx ctx, - DH *dh, const KDC_REQ_BODY *body, AuthPack *a) { @@ -368,12 +398,49 @@ build_auth_pack(krb5_context context, if (ret) return ret; - if (dh) { - DomainParameters dp; - heim_integer dh_pub_key; + if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) { + const char *moduli_file; + unsigned long dh_min_bits; krb5_data dhbuf; size_t size; + krb5_data_zero(&dhbuf); + + + + moduli_file = krb5_config_get_string(context, NULL, + "libdefaults", + "moduli", + NULL); + + dh_min_bits = + krb5_config_get_int_default(context, NULL, 0, + "libdefaults", + "pkinit_dh_min_bits", + NULL); + + ret = _krb5_parse_moduli(context, moduli_file, &ctx->m); + if (ret) + return ret; + + ctx->u.dh = DH_new(); + if (ctx->u.dh == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } + + ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m); + if (ret) + return ret; + + if (DH_generate_key(ctx->u.dh) != 1) { + krb5_set_error_message(context, ENOMEM, + N_("pkinit: failed to generate DH key", "")); + return ENOMEM; + } + + if (1 /* support_cached_dh */) { ALLOC(a->clientDHNonce, 1); if (a->clientDHNonce == NULL) { @@ -385,7 +452,7 @@ build_auth_pack(krb5_context context, krb5_clear_error_message(context); return ret; } - memset(a->clientDHNonce->data, 0, a->clientDHNonce->length); + RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length); ret = krb5_copy_data(context, a->clientDHNonce, &ctx->clientDHNonce); if (ret) @@ -395,64 +462,135 @@ build_auth_pack(krb5_context context, ALLOC(a->clientPublicValue, 1); if (a->clientPublicValue == NULL) return ENOMEM; - ret = der_copy_oid(oid_id_dhpublicnumber(), - &a->clientPublicValue->algorithm.algorithm); - if (ret) - return ret; - - memset(&dp, 0, sizeof(dp)); - ret = BN_to_integer(context, dh->p, &dp.p); - if (ret) { - free_DomainParameters(&dp); - return ret; - } - ret = BN_to_integer(context, dh->g, &dp.g); - if (ret) { - free_DomainParameters(&dp); - return ret; - } - ret = BN_to_integer(context, dh->q, &dp.q); - if (ret) { - free_DomainParameters(&dp); - return ret; - } - dp.j = NULL; - dp.validationParms = NULL; + if (ctx->keyex == USE_DH) { + DH *dh = ctx->u.dh; + DomainParameters dp; + heim_integer dh_pub_key; - a->clientPublicValue->algorithm.parameters = - malloc(sizeof(*a->clientPublicValue->algorithm.parameters)); - if (a->clientPublicValue->algorithm.parameters == NULL) { + ret = der_copy_oid(&asn1_oid_id_dhpublicnumber, + &a->clientPublicValue->algorithm.algorithm); + if (ret) + return ret; + + memset(&dp, 0, sizeof(dp)); + + ret = BN_to_integer(context, dh->p, &dp.p); + if (ret) { + free_DomainParameters(&dp); + return ret; + } + ret = BN_to_integer(context, dh->g, &dp.g); + if (ret) { + free_DomainParameters(&dp); + return ret; + } + ret = BN_to_integer(context, dh->q, &dp.q); + if (ret) { + free_DomainParameters(&dp); + return ret; + } + dp.j = NULL; + dp.validationParms = NULL; + + a->clientPublicValue->algorithm.parameters = + malloc(sizeof(*a->clientPublicValue->algorithm.parameters)); + if (a->clientPublicValue->algorithm.parameters == NULL) { + free_DomainParameters(&dp); + return ret; + } + + ASN1_MALLOC_ENCODE(DomainParameters, + a->clientPublicValue->algorithm.parameters->data, + a->clientPublicValue->algorithm.parameters->length, + &dp, &size, ret); free_DomainParameters(&dp); - return ret; - } + if (ret) + return ret; + if (size != a->clientPublicValue->algorithm.parameters->length) + krb5_abortx(context, "Internal ASN1 encoder error"); + + ret = BN_to_integer(context, dh->pub_key, &dh_pub_key); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, + &dh_pub_key, &size, ret); + der_free_heim_integer(&dh_pub_key); + if (ret) + return ret; + if (size != dhbuf.length) + krb5_abortx(context, "asn1 internal error"); + } else if (ctx->keyex == USE_ECDH) { +#ifdef HAVE_OPENSSL + ECParameters ecp; + unsigned char *p; + int len; + + /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */ + + ecp.element = choice_ECParameters_namedCurve; + ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1, + &ecp.u.namedCurve); + if (ret) + return ret; - ASN1_MALLOC_ENCODE(DomainParameters, - a->clientPublicValue->algorithm.parameters->data, - a->clientPublicValue->algorithm.parameters->length, - &dp, &size, ret); - free_DomainParameters(&dp); - if (ret) - return ret; - if (size != a->clientPublicValue->algorithm.parameters->length) - krb5_abortx(context, "Internal ASN1 encoder error"); + ALLOC(a->clientPublicValue->algorithm.parameters, 1); + if (a->clientPublicValue->algorithm.parameters == NULL) { + free_ECParameters(&ecp); + return ENOMEM; + } + ASN1_MALLOC_ENCODE(ECParameters, p, len, &ecp, &size, ret); + free_ECParameters(&ecp); + if (ret) + return ret; + if (size != len) + krb5_abortx(context, "asn1 internal error"); + + a->clientPublicValue->algorithm.parameters->data = p; + a->clientPublicValue->algorithm.parameters->length = size; - ret = BN_to_integer(context, dh->pub_key, &dh_pub_key); - if (ret) - return ret; + /* copy in public key */ - ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length, - &dh_pub_key, &size, ret); - der_free_heim_integer(&dh_pub_key); - if (ret) - return ret; - if (size != dhbuf.length) - krb5_abortx(context, "asn1 internal error"); + ret = der_copy_oid(&asn1_oid_id_ecPublicKey, + &a->clientPublicValue->algorithm.algorithm); + if (ret) + return ret; + + ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + if (ctx->u.eckey == NULL) + return ENOMEM; + + ret = EC_KEY_generate_key(ctx->u.eckey); + if (ret != 1) + return EINVAL; + /* encode onto dhkey */ + + len = i2o_ECPublicKey(ctx->u.eckey, NULL); + if (len <= 0) + abort(); + + dhbuf.data = malloc(len); + if (dhbuf.data == NULL) + abort(); + dhbuf.length = len; + p = dhbuf.data; + + len = i2o_ECPublicKey(ctx->u.eckey, &p); + if (len <= 0) + abort(); + + /* XXX verify that this is right with RFC3279 */ +#else + return EINVAL; +#endif + } else + krb5_abortx(context, "internal error"); a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8; a->clientPublicValue->subjectPublicKey.data = dhbuf.data; } - + { a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes)); if (a->supportedCMSTypes == NULL) @@ -546,13 +684,13 @@ pk_mk_padata(krb5_context context, if (buf.length != size) krb5_abortx(context, "internal ASN1 encoder error"); - oid = oid_id_pkcs7_data(); + oid = &asn1_oid_id_pkcs7_data; } else if (ctx->type == PKINIT_27) { AuthPack ap; memset(&ap, 0, sizeof(ap)); - ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap); + ret = build_auth_pack(context, nonce, ctx, req_body, &ap); if (ret) { free_AuthPack(&ap); goto out; @@ -569,7 +707,7 @@ pk_mk_padata(krb5_context context, if (buf.length != size) krb5_abortx(context, "internal ASN1 encoder error"); - oid = oid_id_pkauthdata(); + oid = &asn1_oid_id_pkauthdata; } else krb5_abortx(context, "internal pkinit error"); @@ -579,7 +717,7 @@ pk_mk_padata(krb5_context context, if (ret) goto out; - ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf); + ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf); krb5_data_free(&sd_buf); if (ret) { krb5_set_error_message(context, ret, @@ -648,8 +786,8 @@ pk_mk_padata(krb5_context context, if (ret) free(buf.data); - if (ret == 0 && ctx->type == PKINIT_WIN2K) - krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); + if (ret == 0) + krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0); out: free_ContentInfo(&content_info); @@ -721,14 +859,14 @@ _krb5_pk_mk_padata(krb5_context context, return pk_mk_padata(context, ctx, req_body, nonce, md); } -krb5_error_code KRB5_LIB_FUNCTION -_krb5_pk_verify_sign(krb5_context context, - const void *data, - size_t length, - struct krb5_pk_identity *id, - heim_oid *contentType, - krb5_data *content, - struct krb5_pk_cert **signer) +static krb5_error_code +pk_verify_sign(krb5_context context, + const void *data, + size_t length, + struct krb5_pk_identity *id, + heim_oid *contentType, + krb5_data *content, + struct krb5_pk_cert **signer) { hx509_certs signer_certs; int ret; @@ -737,6 +875,7 @@ _krb5_pk_verify_sign(krb5_context context, ret = hx509_cms_verify_signed(id->hx509ctx, id->verify_ctx, + HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH|HX509_CMS_VS_NO_KU_CHECK, data, length, NULL, @@ -902,7 +1041,7 @@ pk_verify_host(krb5_context context, if (ctx->require_eku) { ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert, - oid_id_pkkdcekuoid(), 0); + &asn1_oid_id_pkkdcekuoid, 0); if (ret) { krb5_set_error_message(context, ret, N_("No PK-INIT KDC EKU in kdc certificate", "")); @@ -915,7 +1054,7 @@ pk_verify_host(krb5_context context, ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx, host->cert, - oid_id_pkinit_san(), + &asn1_oid_id_pkinit_san, &list); if (ret) { krb5_set_error_message(context, ret, @@ -995,16 +1134,20 @@ pk_rd_pa_reply_enckey(krb5_context context, struct krb5_pk_cert *host = NULL; krb5_data content; heim_oid contentType = { 0, NULL }; + int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT; - if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) { + if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) { krb5_set_error_message(context, EINVAL, N_("PKINIT: Invalid content type", "")); return EINVAL; } + if (ctx->type == PKINIT_WIN2K) + flags |= HX509_CMS_UE_ALLOW_WEAK; + ret = hx509_cms_unenvelope(ctx->id->hx509ctx, ctx->id->certs, - HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT, + flags, indata->data, indata->length, NULL, @@ -1042,7 +1185,9 @@ pk_rd_pa_reply_enckey(krb5_context context, heim_octet_string out; ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL); - if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) { + if (ret) + goto out; + if (der_heim_oid_cmp(&type, &asn1_oid_id_pkcs7_signedData)) { ret = EINVAL; /* XXX */ krb5_set_error_message(context, ret, N_("PKINIT: Invalid content type", "")); @@ -1061,13 +1206,13 @@ pk_rd_pa_reply_enckey(krb5_context context, } } - ret = _krb5_pk_verify_sign(context, - content.data, - content.length, - ctx->id, - &contentType, - &content, - &host); + ret = pk_verify_sign(context, + content.data, + content.length, + ctx->id, + &contentType, + &content, + &host); if (ret) goto out; @@ -1079,13 +1224,13 @@ pk_rd_pa_reply_enckey(krb5_context context, #if 0 if (type == PKINIT_WIN2K) { - if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) { + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid"); goto out; } } else { - if (der_heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) { + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid"); goto out; @@ -1131,32 +1276,33 @@ pk_rd_pa_reply_dh(krb5_context context, PA_DATA *pa, krb5_keyblock **key) { - unsigned char *p, *dh_gen_key = NULL; + const unsigned char *p; + unsigned char *dh_gen_key = NULL; struct krb5_pk_cert *host = NULL; BIGNUM *kdc_dh_pubkey = NULL; KDCDHKeyInfo kdc_dh_info; heim_oid contentType = { 0, NULL }; krb5_data content; krb5_error_code ret; - int dh_gen_keylen; + int dh_gen_keylen = 0; size_t size; krb5_data_zero(&content); memset(&kdc_dh_info, 0, sizeof(kdc_dh_info)); - if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) { + if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) { krb5_set_error_message(context, EINVAL, N_("PKINIT: Invalid content type", "")); return EINVAL; } - ret = _krb5_pk_verify_sign(context, - indata->data, - indata->length, - ctx->id, - &contentType, - &content, - &host); + ret = pk_verify_sign(context, + indata->data, + indata->length, + ctx->id, + &contentType, + &content, + &host); if (ret) goto out; @@ -1165,7 +1311,7 @@ pk_rd_pa_reply_dh(krb5_context context, if (ret) goto out; - if (der_heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) { + if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) { ret = KRB5KRB_AP_ERR_MSG_TYPE; krb5_set_error_message(context, ret, N_("pkinit - dh reply contains wrong oid", "")); @@ -1221,7 +1367,7 @@ pk_rd_pa_reply_dh(krb5_context context, p = kdc_dh_info.subjectPublicKey.data; size = (kdc_dh_info.subjectPublicKey.length + 7) / 8; - { + if (ctx->keyex == USE_DH) { DHPublicKey k; ret = decode_DHPublicKey(p, size, &k, NULL); if (ret) { @@ -1237,30 +1383,78 @@ pk_rd_pa_reply_dh(krb5_context context, ret = ENOMEM; goto out; } - } - dh_gen_keylen = DH_size(ctx->dh); - size = BN_num_bytes(ctx->dh->p); - if (size < dh_gen_keylen) - size = dh_gen_keylen; - dh_gen_key = malloc(size); - if (dh_gen_key == NULL) { - ret = ENOMEM; - krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); - goto out; - } - memset(dh_gen_key, 0, size - dh_gen_keylen); + dh_gen_keylen = DH_size(ctx->u.dh); + size = BN_num_bytes(ctx->u.dh->p); + if (size < dh_gen_keylen) + size = dh_gen_keylen; - dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), - kdc_dh_pubkey, ctx->dh); - if (dh_gen_keylen == -1) { - ret = KRB5KRB_ERR_GENERIC; - krb5_set_error_message(context, ret, - N_("PKINIT: Can't compute Diffie-Hellman key", "")); - goto out; - } + dh_gen_key = malloc(size); + if (dh_gen_key == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; + } + memset(dh_gen_key, 0, size - dh_gen_keylen); + + dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen), + kdc_dh_pubkey, ctx->u.dh); + if (dh_gen_keylen == -1) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't compute Diffie-Hellman key", "")); + goto out; + } + } else { +#ifdef HAVE_OPENSSL + const EC_GROUP *group; + EC_KEY *public = NULL; + + group = EC_KEY_get0_group(ctx->u.eckey); + + public = EC_KEY_new(); + if (public == NULL) { + ret = ENOMEM; + goto out; + } + if (EC_KEY_set_group(public, group) != 1) { + EC_KEY_free(public); + ret = ENOMEM; + goto out; + } + if (o2i_ECPublicKey(&public, &p, size) == NULL) { + EC_KEY_free(public); + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't parse ECDH public key", "")); + goto out; + } + + size = (EC_GROUP_get_degree(group) + 7) / 8; + dh_gen_key = malloc(size); + if (dh_gen_key == NULL) { + EC_KEY_free(public); + ret = ENOMEM; + krb5_set_error_message(context, ret, + N_("malloc: out of memory", "")); + goto out; + } + dh_gen_keylen = ECDH_compute_key(dh_gen_key, size, + EC_KEY_get0_public_key(public), ctx->u.eckey, NULL); + EC_KEY_free(public); + if (dh_gen_keylen == -1) { + ret = KRB5KRB_ERR_GENERIC; + krb5_set_error_message(context, ret, + N_("PKINIT: Can't compute ECDH public key", "")); + goto out; + } +#else + ret = EINVAL; +#endif + } + *key = malloc (sizeof (**key)); if (*key == NULL) { ret = ENOMEM; @@ -1286,7 +1480,7 @@ pk_rd_pa_reply_dh(krb5_context context, if (kdc_dh_pubkey) BN_free(kdc_dh_pubkey); if (dh_gen_key) { - memset(dh_gen_key, 0, DH_size(ctx->dh)); + memset(dh_gen_key, 0, dh_gen_keylen); free(dh_gen_key); } if (host) @@ -1343,12 +1537,42 @@ _krb5_pk_rd_pa_reply(krb5_context context, case choice_PA_PK_AS_REP_encKeyPack: os = rep.u.encKeyPack; break; - default: + default: { + PA_PK_AS_REP_BTMM btmm; free_PA_PK_AS_REP(&rep); - krb5_set_error_message(context, EINVAL, - N_("PKINIT: -27 reply " - "invalid content type", "")); - return EINVAL; + memset(&rep, 0, sizeof(rep)); + + ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data, + pa->padata_value.length, + &btmm, + &size); + if (ret) { + krb5_set_error_message(context, EINVAL, + N_("PKINIT: -27 reply " + "invalid content type", "")); + return EINVAL; + } + + if (btmm.dhSignedData || btmm.encKeyPack == NULL) { + free_PA_PK_AS_REP_BTMM(&btmm); + ret = EINVAL; + krb5_set_error_message(context, ret, + N_("DH mode not supported for BTMM mode", "")); + return ret; + } + + /* + * Transform to IETF style PK-INIT reply so that free works below + */ + + rep.element = choice_PA_PK_AS_REP_encKeyPack; + rep.u.encKeyPack.data = btmm.encKeyPack->data; + rep.u.encKeyPack.length = btmm.encKeyPack->length; + btmm.encKeyPack->data = NULL; + btmm.encKeyPack->length = 0; + free_PA_PK_AS_REP_BTMM(&btmm); + os = rep.u.encKeyPack; + } } ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL); @@ -1484,18 +1708,10 @@ hx_pass_prompter(void *data, const hx509_prompt *prompter) return 0; } - -void KRB5_LIB_FUNCTION -_krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id, - int boolean) -{ - hx509_verify_set_proxy_certificate(id->verify_ctx, boolean); -} - - krb5_error_code KRB5_LIB_FUNCTION _krb5_pk_load_id(krb5_context context, struct krb5_pk_identity **ret_id, + int flags, const char *user_id, const char *anchor_id, char * const *chain_list, @@ -1517,7 +1733,7 @@ _krb5_pk_load_id(krb5_context context, return HEIM_PKINIT_NO_VALID_CA; } - if (user_id == NULL) { + if (user_id == NULL && (flags & 4) == 0) { krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY, N_("PKINIT: No user certificate given", "")); return HEIM_PKINIT_NO_PRIVATE_KEY; @@ -1537,6 +1753,11 @@ _krb5_pk_load_id(krb5_context context, goto out; ret = hx509_lock_init(id->hx509ctx, &lock); + if (ret) { + pk_copy_error(context, id->hx509ctx, ret, "Failed init lock"); + goto out; + } + if (password && password[0]) hx509_lock_add_password(lock, password); @@ -1550,11 +1771,15 @@ _krb5_pk_load_id(krb5_context context, goto out; } - ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs); - if (ret) { - pk_copy_error(context, id->hx509ctx, ret, - "Failed to init cert certs"); - goto out; + if (user_id) { + ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs); + if (ret) { + pk_copy_error(context, id->hx509ctx, ret, + "Failed to init cert certs"); + goto out; + } + } else { + id->certs = NULL; } ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors); @@ -1628,50 +1853,12 @@ _krb5_pk_load_id(krb5_context context, } else *ret_id = id; - hx509_lock_free(lock); + if (lock) + hx509_lock_free(lock); return ret; } -static krb5_error_code -select_dh_group(krb5_context context, DH *dh, unsigned long bits, - struct krb5_dh_moduli **moduli) -{ - const struct krb5_dh_moduli *m; - - if (bits == 0) { - m = moduli[1]; /* XXX */ - if (m == NULL) - m = moduli[0]; /* XXX */ - } else { - int i; - for (i = 0; moduli[i] != NULL; i++) { - if (bits < moduli[i]->bits) - break; - } - if (moduli[i] == NULL) { - krb5_set_error_message(context, EINVAL, - N_("Did not find a DH group parameter " - "matching requirement of %lu bits", ""), - bits); - return EINVAL; - } - m = moduli[i]; - } - - dh->p = integer_to_BN(context, "p", &m->p); - if (dh->p == NULL) - return ENOMEM; - dh->g = integer_to_BN(context, "g", &m->g); - if (dh->g == NULL) - return ENOMEM; - dh->q = integer_to_BN(context, "q", &m->q); - if (dh->q == NULL) - return ENOMEM; - - return 0; -} - /* * */ @@ -1752,8 +1939,10 @@ _krb5_parse_moduli_line(krb5_context context, while (isspace((unsigned char)*p)) p++; - if (*p == '#') + if (*p == '#') { + free(m1); return 0; + } ret = EINVAL; p1 = strsep(&p, " \t"); @@ -1764,7 +1953,7 @@ _krb5_parse_moduli_line(krb5_context context, goto out; } m1->name = strdup(p1); - if (p1 == NULL) { + if (m1->name == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memeory", "")); goto out; @@ -2002,12 +2191,22 @@ _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt) if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL) return; ctx = opt->opt_private->pk_init_ctx; - if (ctx->dh) - DH_free(ctx->dh); - ctx->dh = NULL; + switch (ctx->keyex) { + case USE_DH: + DH_free(ctx->u.dh); + break; + case USE_RSA: + break; + case USE_ECDH: +#ifdef HAVE_OPENSSL + EC_KEY_free(ctx->u.eckey); +#endif + break; + } if (ctx->id) { hx509_verify_destroy_ctx(ctx->id->verify_ctx); hx509_certs_free(&ctx->id->certs); + hx509_cert_free(ctx->id->cert); hx509_certs_free(&ctx->id->anchors); hx509_certs_free(&ctx->id->certpool); hx509_context_free(&ctx->id->hx509ctx); @@ -2056,9 +2255,6 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, N_("malloc: out of memory", "")); return ENOMEM; } - opt->opt_private->pk_init_ctx->dh = NULL; - opt->opt_private->pk_init_ctx->id = NULL; - opt->opt_private->pk_init_ctx->clientDHNonce = NULL; opt->opt_private->pk_init_ctx->require_binding = 0; opt->opt_private->pk_init_ctx->require_eku = 1; opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1; @@ -2086,6 +2282,7 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, ret = _krb5_pk_load_id(context, &opt->opt_private->pk_init_ctx->id, + flags, user_id, x509_anchors, pool, @@ -2099,50 +2296,58 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return ret; } - if ((flags & 2) == 0) { - const char *moduli_file; - unsigned long dh_min_bits; - - moduli_file = krb5_config_get_string(context, NULL, - "libdefaults", - "moduli", - NULL); + if (opt->opt_private->pk_init_ctx->id->certs) { + hx509_query *q = NULL; + hx509_cert cert = NULL; + hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx; - dh_min_bits = - krb5_config_get_int_default(context, NULL, 0, - "libdefaults", - "pkinit_dh_min_bits", - NULL); - - ret = _krb5_parse_moduli(context, moduli_file, - &opt->opt_private->pk_init_ctx->m); + ret = hx509_query_alloc(hx509ctx, &q); if (ret) { - _krb5_get_init_creds_opt_free_pkinit(opt); + pk_copy_error(context, hx509ctx, ret, + "Allocate query to find signing certificate"); return ret; } - opt->opt_private->pk_init_ctx->dh = DH_new(); - if (opt->opt_private->pk_init_ctx->dh == NULL) { - _krb5_get_init_creds_opt_free_pkinit(opt); - krb5_set_error_message(context, ENOMEM, - N_("malloc: out of memory", "")); - return ENOMEM; - } - - ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh, - dh_min_bits, - opt->opt_private->pk_init_ctx->m); - if (ret) { - _krb5_get_init_creds_opt_free_pkinit(opt); + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + + ret = find_cert(context, opt->opt_private->pk_init_ctx->id, q, &cert); + hx509_query_free(hx509ctx, q); + if (ret) return ret; - } - if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) { - _krb5_get_init_creds_opt_free_pkinit(opt); - krb5_set_error_message(context, ENOMEM, - N_("pkinit: failed to generate DH key", "")); - return ENOMEM; + opt->opt_private->pk_init_ctx->id->cert = cert; + } else + opt->opt_private->pk_init_ctx->id->cert = NULL; + + if ((flags & 2) == 0) { + hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx; + hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert; + + opt->opt_private->pk_init_ctx->keyex = USE_DH; + + /* + * If its a ECDSA certs, lets select ECDSA as the keyex algorithm. + */ + if (cert) { + AlgorithmIdentifier alg; + + ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg); + if (ret == 0) { + if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0) + opt->opt_private->pk_init_ctx->keyex = USE_ECDH; + free_AlgorithmIdentifier(&alg); + } } + + } else { + opt->opt_private->pk_init_ctx->keyex = USE_RSA; + + if (opt->opt_private->pk_init_ctx->id->certs == NULL) { + krb5_set_error_message(context, EINVAL, + N_("No anonymous pkinit support in RSA mode", "")); + return EINVAL; + } } return 0; @@ -2152,3 +2357,122 @@ krb5_get_init_creds_opt_set_pkinit(krb5_context context, return EINVAL; #endif } + +#ifdef PKINIT + +static int +get_ms_san(hx509_context context, hx509_cert cert, char **upn) +{ + hx509_octet_string_list list; + int ret; + + *upn = NULL; + + ret = hx509_cert_find_subjectAltName_otherName(context, + cert, + &asn1_oid_id_pkinit_ms_san, + &list); + if (ret) + return 0; + + if (list.len > 0 && list.val[0].length > 0) + ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length, + upn, NULL); + else + ret = 1; + hx509_free_octet_string_list(&list); + + return ret; +} + +static int +find_ms_san(hx509_context context, hx509_cert cert, void *ctx) +{ + char *upn; + int ret; + + ret = get_ms_san(context, cert, &upn); + if (ret == 0) + free(upn); + return ret; +} + + + +#endif + +/* + * Private since it need to be redesigned using krb5_get_init_creds() + */ + +krb5_error_code KRB5_LIB_FUNCTION +_krb5_pk_enterprise_cert(krb5_context context, + const char *user_id, + krb5_const_realm realm, + krb5_principal *principal) +{ +#ifdef PKINIT + krb5_error_code ret; + hx509_context hx509ctx; + hx509_certs certs, result; + hx509_cert cert; + hx509_query *q; + char *name; + + *principal = NULL; + + if (user_id == NULL) + return ENOENT; + + ret = hx509_context_init(&hx509ctx); + if (ret) + return ret; + + ret = hx509_certs_init(hx509ctx, user_id, 0, NULL, &certs); + if (ret) { + pk_copy_error(context, hx509ctx, ret, + "Failed to init cert certs"); + return ret; + } + + ret = hx509_query_alloc(hx509ctx, &q); + if (ret) { + hx509_certs_free(&certs); + return ret; + } + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku); + hx509_query_match_cmp_func(q, find_ms_san, NULL); + + ret = hx509_certs_filter(hx509ctx, certs, q, &result); + hx509_query_free(hx509ctx, q); + hx509_certs_free(&certs); + if (ret) + return ret; + + ret = hx509_get_one_cert(hx509ctx, result, &cert); + hx509_certs_free(&result); + if (ret) + return ret; + + ret = get_ms_san(hx509ctx, cert, &name); + if (ret) + return ret; + + ret = krb5_make_principal(context, principal, realm, name, NULL); + free(name); + hx509_context_free(&hx509ctx); + if (ret) + return ret; + + krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL); + + return ret; +#else + krb5_set_error_message(context, EINVAL, + N_("no support for PKINIT compiled in", "")); + return EINVAL; +#endif +} diff --git a/source4/heimdal/lib/krb5/plugin.c b/source4/heimdal/lib/krb5/plugin.c index a71dd8b6f7..844cb7ab88 100644 --- a/source4/heimdal/lib/krb5/plugin.c +++ b/source4/heimdal/lib/krb5/plugin.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); + #ifdef HAVE_DLFCN_H #include <dlfcn.h> #endif @@ -54,7 +54,13 @@ struct plugin { static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER; static struct plugin *registered = NULL; -static const char *plugin_dir = LIBDIR "/plugin/krb5"; +static const char *sysplugin_dirs[] = { + LIBDIR "/plugin/krb5", +#ifdef __APPLE__ + "/System/Library/KerberosPlugins/KerberosFrameworkPlugins", +#endif + NULL +}; /* * @@ -94,8 +100,11 @@ loadlib(krb5_context context, #ifndef RTLD_LAZY #define RTLD_LAZY 0 #endif +#ifndef RTLD_LOCAL +#define RTLD_LOCAL 0 +#endif - (*e)->dsohandle = dlopen(lib, RTLD_LAZY); + (*e)->dsohandle = dlopen(lib, RTLD_LOCAL|RTLD_LAZY); if ((*e)->dsohandle == NULL) { free(*e); *e = NULL; @@ -173,7 +182,6 @@ _krb5_plugin_find(krb5_context context, struct krb5_plugin *e; struct plugin *p; krb5_error_code ret; - char *sysdirs[2] = { NULL, NULL }; char **dirs = NULL, **di; struct dirent *entry; char *path; @@ -205,10 +213,8 @@ _krb5_plugin_find(krb5_context context, dirs = krb5_config_get_strings(context, NULL, "libdefaults", "plugin_dir", NULL); - if (dirs == NULL) { - sysdirs[0] = rk_UNCONST(plugin_dir); - dirs = sysdirs; - } + if (dirs == NULL) + dirs = rk_UNCONST(sysplugin_dirs); for (di = dirs; *di != NULL; di++) { @@ -218,7 +224,23 @@ _krb5_plugin_find(krb5_context context, rk_cloexec(dirfd(d)); while ((entry = readdir(d)) != NULL) { - asprintf(&path, "%s/%s", *di, entry->d_name); + char *n = entry->d_name; + + /* skip . and .. */ + if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0'))) + continue; + + path = NULL; +#ifdef __APPLE__ + { /* support loading bundles on MacOS */ + size_t len = strlen(n); + if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0) + asprintf(&path, "%s/%s/Contents/MacOS/%.*s", *di, n, (int)(len - 7), n); + } +#endif + if (path == NULL) + asprintf(&path, "%s/%s", *di, n); + if (path == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); @@ -234,7 +256,7 @@ _krb5_plugin_find(krb5_context context, } closedir(d); } - if (dirs != sysdirs) + if (dirs != rk_UNCONST(sysplugin_dirs)) krb5_config_free_strings(dirs); #endif /* HAVE_DLOPEN */ @@ -246,7 +268,7 @@ _krb5_plugin_find(krb5_context context, return 0; out: - if (dirs && dirs != sysdirs) + if (dirs != rk_UNCONST(sysplugin_dirs)) krb5_config_free_strings(dirs); if (d) closedir(d); diff --git a/source4/heimdal/lib/krb5/principal.c b/source4/heimdal/lib/krb5/principal.c index f27355f2d8..50b7bb8813 100644 --- a/source4/heimdal/lib/krb5/principal.c +++ b/source4/heimdal/lib/krb5/principal.c @@ -32,7 +32,7 @@ */ /** - * @page page_principal The principal handing functions. + * @page krb5_principal_intro The principal handing functions. * * A Kerberos principal is a email address looking string that * contains to parts separeted by a @. The later part is the kerbero @@ -57,8 +57,6 @@ host/admin@H5L.ORG #include <fnmatch.h> #include "resolve.h" -RCSID("$Id$"); - #define princ_num_comp(P) ((P)->name.name_string.len) #define princ_type(P) ((P)->name.name_type) #define princ_comp(P) ((P)->name.name_string.val) @@ -78,8 +76,6 @@ RCSID("$Id$"); * @ingroup krb5_principal */ - - void KRB5_LIB_FUNCTION krb5_free_principal(krb5_context context, krb5_principal p) @@ -90,6 +86,18 @@ krb5_free_principal(krb5_context context, } } +/** + * Set the type of the principal + * + * @param context A Kerberos context. + * @param principal principal to set the type for + * @param type the new type + * + * @return An krb5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_principal + */ + void KRB5_LIB_FUNCTION krb5_principal_set_type(krb5_context context, krb5_principal principal, @@ -127,8 +135,10 @@ krb5_principal_get_comp_string(krb5_context context, * * @param context Kerberos 5 context * @param principal principal to query + * * @return number of components in string - * @ingroup krb5 + * + * @ingroup krb5_principal */ unsigned int KRB5_LIB_FUNCTION @@ -162,7 +172,7 @@ krb5_parse_name_flags(krb5_context context, *principal = NULL; -#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM) +#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) if ((flags & RFLAGS) == RFLAGS) { krb5_set_error_message(context, KRB5_ERR_NO_SERVICE, @@ -276,7 +286,7 @@ krb5_parse_name_flags(krb5_context context, memcpy(realm, start, q - start); realm[q - start] = 0; }else{ - if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) { + if (flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM) { ret = KRB5_PARSE_MALFORMED; krb5_set_error_message(context, ret, N_("realm NOT found in principal " @@ -524,22 +534,6 @@ krb5_unparse_name_ext(krb5_context context, #endif -krb5_realm * KRB5_LIB_FUNCTION -krb5_princ_realm(krb5_context context, - krb5_principal principal) -{ - return &princ_realm(principal); -} - - -void KRB5_LIB_FUNCTION -krb5_princ_set_realm(krb5_context context, - krb5_principal principal, - krb5_realm *realm) -{ - princ_realm(principal) = *realm; -} - krb5_error_code KRB5_LIB_FUNCTION krb5_principal_set_realm(krb5_context context, krb5_principal principal, @@ -821,6 +815,7 @@ krb5_principal_match(krb5_context context, return TRUE; } +#if defined(KRB4) || !defined(HEIMDAL_SMALLER) static struct v4_name_convert { const char *from; @@ -835,6 +830,10 @@ static struct v4_name_convert { { NULL, NULL } }; +#endif + +#ifdef KRB4 + /* * return the converted instance name of `name' in `realm'. * look in the configuration file and then in the default set above. @@ -925,6 +924,8 @@ krb5_425_conv_principal_ext2(krb5_context context, if(p){ instance = p; ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); + if (ret) + return ret; if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -938,23 +939,23 @@ krb5_425_conv_principal_ext2(krb5_context context, krb5_boolean passed = FALSE; char *inst = NULL; #ifdef USE_RESOLVER - struct dns_reply *r; + struct rk_dns_reply *r; - r = dns_lookup(instance, "aaaa"); + r = rk_dns_lookup(instance, "aaaa"); if (r) { - if (r->head && r->head->type == T_AAAA) { + if (r->head && r->head->type == rk_ns_t_aaaa) { inst = strdup(r->head->domain); passed = TRUE; } - dns_free_data(r); + rk_dns_free_data(r); } else { - r = dns_lookup(instance, "a"); + r = rk_dns_lookup(instance, "a"); if (r) { - if(r->head && r->head->type == T_A) { + if(r->head && r->head->type == rk_ns_t_a) { inst = strdup(r->head->domain); passed = TRUE; } - dns_free_data(r); + rk_dns_free_data(r); } } #else @@ -998,6 +999,8 @@ krb5_425_conv_principal_ext2(krb5_context context, snprintf(host, sizeof(host), "%s.%s", instance, realm); strlwr(host); ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if (ret) + return ret; if((*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -1025,6 +1028,10 @@ krb5_425_conv_principal_ext2(krb5_context context, for(d = domains; d && *d; d++){ snprintf(host, sizeof(host), "%s.%s", instance, *d); ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if (ret) { + krb5_config_free_strings(domains); + return ret; + } if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; krb5_config_free_strings(domains); @@ -1049,6 +1056,8 @@ krb5_425_conv_principal_ext2(krb5_context context, snprintf(host, sizeof(host), "%s.%s", instance, p); local_host: ret = krb5_make_principal(context, &pr, realm, name, host, NULL); + if (ret) + return ret; if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -1075,6 +1084,8 @@ no_host: name = p; ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); + if (ret) + return ret; if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; @@ -1084,51 +1095,9 @@ no_host: return HEIM_ERR_V4_PRINC_NO_CONV; } -static krb5_boolean -convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal) -{ - krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx; - return (*func)(conxtext, principal); -} - -krb5_error_code KRB5_LIB_FUNCTION -krb5_425_conv_principal_ext(krb5_context context, - const char *name, - const char *instance, - const char *realm, - krb5_boolean (*func)(krb5_context, krb5_principal), - krb5_boolean resolve, - krb5_principal *principal) -{ - return krb5_425_conv_principal_ext2(context, - name, - instance, - realm, - func ? convert_func : NULL, - func, - resolve, - principal); -} - - - -krb5_error_code KRB5_LIB_FUNCTION -krb5_425_conv_principal(krb5_context context, - const char *name, - const char *instance, - const char *realm, - krb5_principal *princ) -{ - krb5_boolean resolve = krb5_config_get_bool(context, - NULL, - "libdefaults", - "v4_instance_resolve", - NULL); - - return krb5_425_conv_principal_ext(context, name, instance, realm, - NULL, resolve, princ); -} +#endif /* KRB4 */ +#ifndef HEIMDAL_SMALLER static int check_list(const krb5_config_binding *l, const char *name, const char **out) @@ -1186,6 +1155,7 @@ name_convert(krb5_context context, const char *name, const char *realm, return KRB5_NT_UNKNOWN; /* didn't find it in config file, try built-in list */ +#ifdef KRB4 { struct v4_name_convert *q; for(q = default_v4_name_convert; q->from; q++) { @@ -1195,6 +1165,7 @@ name_convert(krb5_context context, const char *name, const char *realm, } } } +#endif return -1; } @@ -1273,6 +1244,8 @@ krb5_524_conv_principal(krb5_context context, return 0; } +#endif /* !HEIMDAL_SMALLER */ + /** * Create a principal for the service running on hostname. If * KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or diff --git a/source4/heimdal/lib/krb5/prog_setup.c b/source4/heimdal/lib/krb5/prog_setup.c index b368573b8d..4c060973d6 100644 --- a/source4/heimdal/lib/krb5/prog_setup.c +++ b/source4/heimdal/lib/krb5/prog_setup.c @@ -35,8 +35,6 @@ #include <getarg.h> #include <err.h> -RCSID("$Id$"); - void KRB5_LIB_FUNCTION krb5_std_usage(int code, struct getargs *args, int num_args) { diff --git a/source4/heimdal/lib/krb5/prompter_posix.c b/source4/heimdal/lib/krb5/prompter_posix.c index 7d63935423..05deaff525 100644 --- a/source4/heimdal/lib/krb5/prompter_posix.c +++ b/source4/heimdal/lib/krb5/prompter_posix.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - int KRB5_LIB_FUNCTION krb5_prompter_posix (krb5_context context, void *data, diff --git a/source4/heimdal/lib/krb5/rd_cred.c b/source4/heimdal/lib/krb5/rd_cred.c index dc51033019..f41edfa2b5 100644 --- a/source4/heimdal/lib/krb5/rd_cred.c +++ b/source4/heimdal/lib/krb5/rd_cred.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code compare_addrs(krb5_context context, krb5_address *a, @@ -149,15 +147,18 @@ krb5_rd_cred(krb5_context context, goto out; } - ret = krb5_decode_EncKrbCredPart (context, - enc_krb_cred_part_data.data, - enc_krb_cred_part_data.length, - &enc_krb_cred_part, - &len); + ret = decode_EncKrbCredPart(enc_krb_cred_part_data.data, + enc_krb_cred_part_data.length, + &enc_krb_cred_part, + &len); if (enc_krb_cred_part_data.data != cred.enc_part.cipher.data) krb5_data_free(&enc_krb_cred_part_data); - if (ret) + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode " + "encrypte credential part", "")); goto out; + } /* check sender address */ diff --git a/source4/heimdal/lib/krb5/rd_error.c b/source4/heimdal/lib/krb5/rd_error.c index 75ae8b1e8a..1561188fad 100644 --- a/source4/heimdal/lib/krb5/rd_error.c +++ b/source4/heimdal/lib/krb5/rd_error.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_rd_error(krb5_context context, const krb5_data *msg, diff --git a/source4/heimdal/lib/krb5/rd_priv.c b/source4/heimdal/lib/krb5/rd_priv.c index 6778ccad88..fb6cfcee4f 100644 --- a/source4/heimdal/lib/krb5/rd_priv.c +++ b/source4/heimdal/lib/krb5/rd_priv.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_rd_priv(krb5_context context, krb5_auth_context auth_context, diff --git a/source4/heimdal/lib/krb5/rd_rep.c b/source4/heimdal/lib/krb5/rd_rep.c index 010726b180..2d5792cd40 100644 --- a/source4/heimdal/lib/krb5/rd_rep.c +++ b/source4/heimdal/lib/krb5/rd_rep.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_rd_rep(krb5_context context, krb5_auth_context auth_context, @@ -48,7 +46,6 @@ krb5_rd_rep(krb5_context context, krb5_crypto crypto; krb5_data_zero (&data); - ret = 0; ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len); if (ret) @@ -82,13 +79,11 @@ krb5_rd_rep(krb5_context context, krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto out; } - ret = krb5_decode_EncAPRepPart(context, - data.data, - data.length, - *repl, - &len); - if (ret) + ret = decode_EncAPRepPart(data.data, data.length, *repl, &len); + if (ret) { + krb5_set_error_message(context, ret, N_("Failed to decode EncAPRepPart", "")); return ret; + } if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) { if ((*repl)->ctime != auth_context->authenticator->ctime || diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c index a416f90c10..784427fe40 100644 --- a/source4/heimdal/lib/krb5/rd_req.c +++ b/source4/heimdal/lib/krb5/rd_req.c @@ -33,8 +33,6 @@ #include <krb5_locl.h> -RCSID("$Id$"); - static krb5_error_code decrypt_tkt_enc_part (krb5_context context, krb5_keyblock *key, @@ -58,8 +56,11 @@ decrypt_tkt_enc_part (krb5_context context, if (ret) return ret; - ret = krb5_decode_EncTicketPart(context, plain.data, plain.length, - decr_part, &len); + ret = decode_EncTicketPart(plain.data, plain.length, decr_part, &len); + if (ret) + krb5_set_error_message(context, ret, + N_("Failed to decode encrypted " + "ticket part", "")); krb5_data_free (&plain); return ret; } @@ -95,8 +96,8 @@ decrypt_authenticator (krb5_context context, if (ret) return ret; - ret = krb5_decode_Authenticator(context, plain.data, plain.length, - authenticator, &len); + ret = decode_Authenticator(plain.data, plain.length, + authenticator, &len); krb5_data_free (&plain); return ret; } @@ -521,10 +522,20 @@ struct krb5_rd_req_out_ctx_data { krb5_keyblock *keyblock; krb5_flags ap_req_options; krb5_ticket *ticket; + krb5_principal server; }; -/* +/** + * Allocate a krb5_rd_req_in_ctx as an input parameter to + * krb5_rd_req_ctx(). The caller should free the context with + * krb5_rd_req_in_ctx_free() when done with the context. + * + * @param context Keberos 5 context. + * @param ctx in ctx to krb5_rd_req_ctx(). + * + * @return Kerberos 5 error code, see krb5_get_error_message(). * + * @ingroup krb5_auth */ krb5_error_code KRB5_LIB_FUNCTION @@ -540,12 +551,26 @@ krb5_rd_req_in_ctx_alloc(krb5_context context, krb5_rd_req_in_ctx *ctx) return 0; } +/** + * Set the keytab that krb5_rd_req_ctx() will use. + * + * @param context Keberos 5 context. + * @param in in ctx to krb5_rd_req_ctx(). + * @param keytab keytab that krb5_rd_req_ctx() will use, only copy the + * pointer, so the caller must free they keytab after + * krb5_rd_req_in_ctx_free() is called. + * + * @return Kerberos 5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_auth + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_rd_req_in_set_keytab(krb5_context context, krb5_rd_req_in_ctx in, krb5_keytab keytab) { - in->keytab = keytab; /* XXX should make copy */ + in->keytab = keytab; return 0; } @@ -558,7 +583,7 @@ krb5_rd_req_in_set_keytab(krb5_context context, * * @return Kerberos 5 error code, see krb5_get_error_message(). * - * @ingroup krb5 + * @ingroup krb5_auth */ krb5_error_code KRB5_LIB_FUNCTION @@ -605,28 +630,50 @@ krb5_rd_req_out_get_keyblock(krb5_context context, return krb5_copy_keyblock(context, out->keyblock, keyblock); } +/** + * Get the principal that was used in the request from the + * client. Might not match whats in the ticket if krb5_rd_req_ctx() + * searched in the keytab for a matching key. + * + * @param context a Kerberos 5 context. + * @param out a krb5_rd_req_out_ctx from krb5_rd_req_ctx(). + * @param principal return principal, free with krb5_free_principal(). + * + * @ingroup krb5_auth + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_rd_req_out_get_server(krb5_context context, + krb5_rd_req_out_ctx out, + krb5_principal *principal) +{ + return krb5_copy_principal(context, out->server, principal); +} + void KRB5_LIB_FUNCTION krb5_rd_req_in_ctx_free(krb5_context context, krb5_rd_req_in_ctx ctx) { free(ctx); } -krb5_error_code KRB5_LIB_FUNCTION -_krb5_rd_req_out_ctx_alloc(krb5_context context, krb5_rd_req_out_ctx *ctx) -{ - *ctx = calloc(1, sizeof(**ctx)); - if (*ctx == NULL) { - krb5_set_error_message(context, ENOMEM, - N_("malloc: out of memory", "")); - return ENOMEM; - } - return 0; -} +/** + * Free the krb5_rd_req_out_ctx. + * + * @param context Keberos 5 context. + * @param ctx krb5_rd_req_out_ctx context to free. + * + * @ingroup krb5_auth + */ void KRB5_LIB_FUNCTION krb5_rd_req_out_ctx_free(krb5_context context, krb5_rd_req_out_ctx ctx) { - krb5_free_keyblock(context, ctx->keyblock); + if (ctx->ticket) + krb5_free_ticket(context, ctx->ticket); + if (ctx->keyblock) + krb5_free_keyblock(context, ctx->keyblock); + if (ctx->server) + krb5_free_principal(context, ctx->server); free(ctx); } @@ -726,7 +773,6 @@ out: static krb5_error_code get_key_from_keytab(krb5_context context, - krb5_auth_context *auth_context, krb5_ap_req *ap_req, krb5_const_principal server, krb5_keytab keytab, @@ -764,8 +810,28 @@ out: return ret; } -/* +/** + * The core server function that verify application authentication + * requests from clients. + * + * @param context Keberos 5 context. + * @param auth_context the authentication context, can be NULL, then + * default values for the authentication context will used. + * @param inbuf the (AP-REQ) authentication buffer + * + * @param server the server with authenticate as, if NULL the function + * will try to find any avaiable credentintial in the keytab + * that will verify the reply. The function will prefer the + * server the server client specified in the AP-REQ, but if + * there is no mach, it will try all keytab entries for a + * match. This have serious performance issues for larger keytabs. * + * @param inctx control the behavior of the function, if NULL, the + * default behavior is used. + * @param outctx the return outctx, free with krb5_rd_req_out_ctx_free(). + * @return Kerberos 5 error code, see krb5_get_error_message(). + * + * @ingroup krb5_auth */ krb5_error_code KRB5_LIB_FUNCTION @@ -778,12 +844,18 @@ krb5_rd_req_ctx(krb5_context context, { krb5_error_code ret; krb5_ap_req ap_req; - krb5_principal service = NULL; krb5_rd_req_out_ctx o = NULL; + krb5_keytab id = NULL, keytab = NULL; + krb5_principal service = NULL; - ret = _krb5_rd_req_out_ctx_alloc(context, &o); - if (ret) - goto out; + *outctx = NULL; + + o = calloc(1, sizeof(*o)); + if (o == NULL) { + krb5_set_error_message(context, ENOMEM, + N_("malloc: out of memory", "")); + return ENOMEM; + } if (*auth_context == NULL) { ret = krb5_auth_con_init(context, auth_context); @@ -795,15 +867,14 @@ krb5_rd_req_ctx(krb5_context context, if(ret) goto out; - if(server == NULL){ - ret = _krb5_principalname2krb5_principal(context, - &service, - ap_req.ticket.sname, - ap_req.ticket.realm); - if (ret) - goto out; - server = service; - } + /* Save that principal that was in the request */ + ret = _krb5_principalname2krb5_principal(context, + &o->server, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) + goto out; + if (ap_req.ap_options.use_session_key && (*auth_context)->keyblock == NULL) { ret = KRB5KRB_AP_ERR_NOKEY; @@ -813,49 +884,155 @@ krb5_rd_req_ctx(krb5_context context, goto out; } + if (inctx && inctx->keytab) + id = inctx->keytab; + if((*auth_context)->keyblock){ ret = krb5_copy_keyblock(context, (*auth_context)->keyblock, &o->keyblock); if (ret) goto out; - } else if(inctx->keyblock){ + } else if(inctx && inctx->keyblock){ ret = krb5_copy_keyblock(context, inctx->keyblock, &o->keyblock); if (ret) goto out; } else { - krb5_keytab keytab = NULL; - if (inctx && inctx->keytab) - keytab = inctx->keytab; + if(id == NULL) { + krb5_kt_default(context, &keytab); + id = keytab; + } + if (id == NULL) + goto out; + + if (server == NULL) { + ret = _krb5_principalname2krb5_principal(context, + &service, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) + goto out; + server = service; + } ret = get_key_from_keytab(context, - auth_context, &ap_req, server, - keytab, + id, &o->keyblock); - if(ret) - goto out; + if (ret) { + /* If caller specified a server, fail. */ + if (service == NULL) + goto out; + /* Otherwise, fall back to iterating over the keytab. This + * have serious performace issues for larger keytab. + */ + o->keyblock = NULL; + } } - ret = krb5_verify_ap_req2(context, - auth_context, - &ap_req, - server, - o->keyblock, - 0, - &o->ap_req_options, - &o->ticket, - KRB5_KU_AP_REQ_AUTH); + if (o->keyblock) { + /* + * We got an exact keymatch, use that. + */ - if (ret) - goto out; + ret = krb5_verify_ap_req2(context, + auth_context, + &ap_req, + server, + o->keyblock, + 0, + &o->ap_req_options, + &o->ticket, + KRB5_KU_AP_REQ_AUTH); + + if (ret) + goto out; + + } else { + /* + * Interate over keytab to find a key that can decrypt the request. + */ + + krb5_keytab_entry entry; + krb5_kt_cursor cursor; + int done = 0, kvno = 0; + + memset(&cursor, 0, sizeof(cursor)); + + if (ap_req.ticket.enc_part.kvno) + kvno = *ap_req.ticket.enc_part.kvno; + + ret = krb5_kt_start_seq_get(context, id, &cursor); + if (ret) + goto out; + + done = 0; + while (!done) { + krb5_principal p; + + ret = krb5_kt_next_entry(context, id, &entry, &cursor); + if (ret) { + _krb5_kt_principal_not_found(context, ret, id, o->server, + ap_req.ticket.enc_part.etype, + kvno); + goto out; + } + + if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype || + (kvno && kvno != entry.vno)) { + krb5_kt_free_entry (context, &entry); + continue; + } + + ret = krb5_verify_ap_req2(context, + auth_context, + &ap_req, + server, + &entry.keyblock, + 0, + &o->ap_req_options, + &o->ticket, + KRB5_KU_AP_REQ_AUTH); + if (ret) { + krb5_kt_free_entry (context, &entry); + continue; + } + + /* + * Found a match, save the keyblock for PAC processing, + * and update the service principal in the ticket to match + * whatever is in the keytab. + */ + + ret = krb5_copy_keyblock(context, + &entry.keyblock, + &o->keyblock); + if (ret) { + krb5_kt_free_entry (context, &entry); + goto out; + } + + ret = krb5_copy_principal(context, entry.principal, &p); + if (ret) { + krb5_kt_free_entry (context, &entry); + goto out; + } + krb5_free_principal(context, o->ticket->server); + o->ticket->server = p; + + krb5_kt_free_entry (context, &entry); + + done = 1; + } + krb5_kt_end_seq_get (context, id, &cursor); + } /* If there is a PAC, verify its server signature */ - if (inctx->check_pac) { + if (inctx == NULL || inctx->check_pac) { krb5_pac pac; krb5_data data; @@ -878,17 +1055,23 @@ krb5_rd_req_ctx(krb5_context context, krb5_pac_free(context, pac); if (ret) goto out; - } - ret = 0; + } else + ret = 0; } out: + if (ret || outctx == NULL) { krb5_rd_req_out_ctx_free(context, o); } else *outctx = o; free_AP_REQ(&ap_req); - if(service) + + if (service) krb5_free_principal(context, service); + + if (keytab) + krb5_kt_close(context, keytab); + return ret; } diff --git a/source4/heimdal/lib/krb5/replay.c b/source4/heimdal/lib/krb5/replay.c index 25a6da0262..37556cfbc5 100644 --- a/source4/heimdal/lib/krb5/replay.c +++ b/source4/heimdal/lib/krb5/replay.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <vis.h> -RCSID("$Id$"); - struct krb5_rcache_data { char *name; }; diff --git a/source4/heimdal/lib/krb5/send_to_kdc.c b/source4/heimdal/lib/krb5/send_to_kdc.c index 53c4a69a3f..50b42f2f10 100644 --- a/source4/heimdal/lib/krb5/send_to_kdc.c +++ b/source4/heimdal/lib/krb5/send_to_kdc.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "send_to_kdc_plugin.h" -RCSID("$Id$"); - struct send_to_kdc { krb5_send_to_kdc_func func; void *data; @@ -384,8 +382,8 @@ krb5_sendto (krb5_context context, if (context->send_to_kdc) { struct send_to_kdc *s = context->send_to_kdc; - ret = (*s->func)(context, s->data, - hi, context->kdc_timeout, send_data, receive); + ret = (*s->func)(context, s->data, hi, + context->kdc_timeout, send_data, receive); if (ret == 0 && receive->length != 0) goto out; continue; diff --git a/source4/heimdal/lib/krb5/set_default_realm.c b/source4/heimdal/lib/krb5/set_default_realm.c index 6907b11d10..91201eeb53 100644 --- a/source4/heimdal/lib/krb5/set_default_realm.c +++ b/source4/heimdal/lib/krb5/set_default_realm.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* * Convert the simple string `s' into a NULL-terminated and freshly allocated * list in `list'. Return an error code. diff --git a/source4/heimdal/lib/krb5/store-int.h b/source4/heimdal/lib/krb5/store-int.h index 8489f98453..0b7accb860 100644 --- a/source4/heimdal/lib/krb5/store-int.h +++ b/source4/heimdal/lib/krb5/store-int.h @@ -39,6 +39,7 @@ struct krb5_storage_data { ssize_t (*fetch)(struct krb5_storage_data*, void*, size_t); ssize_t (*store)(struct krb5_storage_data*, const void*, size_t); off_t (*seek)(struct krb5_storage_data*, off_t, int); + int (*trunc)(struct krb5_storage_data*, off_t); void (*free)(struct krb5_storage_data*); krb5_flags flags; int eof_code; diff --git a/source4/heimdal/lib/krb5/store.c b/source4/heimdal/lib/krb5/store.c index 47f9abe1de..2ba83ef0d5 100644 --- a/source4/heimdal/lib/krb5/store.c +++ b/source4/heimdal/lib/krb5/store.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997-2006 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V)) #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE) #define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE) @@ -54,12 +52,36 @@ krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags) sp->flags &= ~flags; } +/** + * Return true or false depending on if the storage flags is set or + * not. NB testing for the flag 0 always return true. + * + * @param sp the storage buffer to check flags on + * @param flags The flags to test for + * + * @return true if all the flags are set, false if not. + * + * @ingroup krb5_storage + */ + krb5_boolean KRB5_LIB_FUNCTION krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags) { return (sp->flags & flags) == flags; } +/** + * Set the new byte order of the storage buffer. + * + * @param sp the storage buffer to set the byte order for. + * @param byteorder the new byte order. + * + * The byte order are: KRB5_STORAGE_BYTEORDER_BE, + * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST. + * + * @ingroup krb5_storage + */ + void KRB5_LIB_FUNCTION krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder) { @@ -67,36 +89,121 @@ krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder) sp->flags |= byteorder; } +/** + * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants. + * + * @ingroup krb5_storage + */ + krb5_flags KRB5_LIB_FUNCTION -krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder) +krb5_storage_get_byteorder(krb5_storage *sp) { return sp->flags & KRB5_STORAGE_BYTEORDER_MASK; } +/** + * Seek to a new offset. + * + * @param sp the storage buffer to seek in. + * @param offset the offset to seek + * @param whence relateive searching, SEEK_CUR from the current + * position, SEEK_END from the end, SEEK_SET absolute from the start. + * + * @return The new current offset + * + * @ingroup krb5_storage + */ + off_t KRB5_LIB_FUNCTION krb5_storage_seek(krb5_storage *sp, off_t offset, int whence) { return (*sp->seek)(sp, offset, whence); } +/** + * Truncate the storage buffer in sp to offset. + * + * @param sp the storage buffer to truncate. + * @param offset the offset to truncate too. + * + * @return An Kerberos 5 error code. + * + * @ingroup krb5_storage + */ + +int KRB5_LIB_FUNCTION +krb5_storage_truncate(krb5_storage *sp, off_t offset) +{ + return (*sp->trunc)(sp, offset); +} + +/** + * Read to the storage buffer. + * + * @param sp the storage buffer to read from + * @param buf the buffer to store the data in + * @param len the length to read + * + * @return The length of data read (can be shorter then len), or negative on error. + * + * @ingroup krb5_storage + */ + krb5_ssize_t KRB5_LIB_FUNCTION krb5_storage_read(krb5_storage *sp, void *buf, size_t len) { return sp->fetch(sp, buf, len); } +/** + * Write to the storage buffer. + * + * @param sp the storage buffer to write to + * @param buf the buffer to write to the storage buffer + * @param len the length to write + * + * @return The length of data written (can be shorter then len), or negative on error. + * + * @ingroup krb5_storage + */ + krb5_ssize_t KRB5_LIB_FUNCTION krb5_storage_write(krb5_storage *sp, const void *buf, size_t len) { return sp->store(sp, buf, len); } +/** + * Set the return code that will be used when end of storage is reached. + * + * @param sp the storage + * @param code the error code to return on end of storage + * + * @ingroup krb5_storage + */ + void KRB5_LIB_FUNCTION krb5_storage_set_eof_code(krb5_storage *sp, int code) { sp->eof_code = code; } +/** + * Get the return code that will be used when end of storage is reached. + * + * @param sp the storage + * + * @return storage error code + * + * @ingroup krb5_storage + */ + +int KRB5_LIB_FUNCTION +krb5_storage_get_eof_code(krb5_storage *sp) +{ + return sp->eof_code; +} + krb5_ssize_t KRB5_LIB_FUNCTION _krb5_put_int(void *buffer, unsigned long value, size_t size) { @@ -121,6 +228,16 @@ _krb5_get_int(void *buffer, unsigned long *value, size_t size) return size; } +/** + * Free a krb5 storage. + * + * @param sp the storage to free. + * + * @return An Kerberos 5 error code. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_storage_free(krb5_storage *sp) { @@ -131,15 +248,29 @@ krb5_storage_free(krb5_storage *sp) return 0; } +/** + * Copy the contnent of storage + * + * @param sp the storage to copy to a data + * @param data the copied data, free with krb5_data_free() + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_storage_to_data(krb5_storage *sp, krb5_data *data) { - off_t pos; - size_t size; + off_t pos, size; krb5_error_code ret; pos = sp->seek(sp, 0, SEEK_CUR); + if (pos < 0) + return HEIM_ERR_NOT_SEEKABLE; size = (size_t)sp->seek(sp, 0, SEEK_END); + if (size > (size_t)-1) + return HEIM_ERR_TOO_BIG; ret = krb5_data_alloc (data, size); if (ret) { sp->seek(sp, pos, SEEK_SET); @@ -170,6 +301,18 @@ krb5_store_int(krb5_storage *sp, return 0; } +/** + * Store a int32 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_int32(krb5_storage *sp, int32_t value) @@ -181,6 +324,18 @@ krb5_store_int32(krb5_storage *sp, return krb5_store_int(sp, value, 4); } +/** + * Store a uint32 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_uint32(krb5_storage *sp, uint32_t value) @@ -232,6 +387,18 @@ krb5_ret_uint32(krb5_storage *sp, return ret; } +/** + * Store a int16 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_int16(krb5_storage *sp, int16_t value) @@ -243,6 +410,18 @@ krb5_store_int16(krb5_storage *sp, return krb5_store_int(sp, value, 2); } +/** + * Store a uint16 to storage, byte order is controlled by the settings + * on the storage, see krb5_storage_set_byteorder(). + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_uint16(krb5_storage *sp, uint16_t value) @@ -281,6 +460,17 @@ krb5_ret_uint16(krb5_storage *sp, return ret; } +/** + * Store a int8 to storage. + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_int8(krb5_storage *sp, int8_t value) @@ -293,6 +483,17 @@ krb5_store_int8(krb5_storage *sp, return 0; } +/** + * Store a uint8 to storage. + * + * @param sp the storage to write too + * @param value the value to store + * + * @return 0 for success, or a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_uint8(krb5_storage *sp, uint8_t value) @@ -326,6 +527,17 @@ krb5_ret_uint8(krb5_storage *sp, return ret; } +/** + * Store a data to the storage. + * + * @param sp the storage buffer to write to + * @param data the buffer to store. + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_data(krb5_storage *sp, krb5_data data) @@ -343,6 +555,17 @@ krb5_store_data(krb5_storage *sp, return 0; } +/** + * Parse a data from the storage. + * + * @param sp the storage buffer to read from + * @param data the parsed data + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_ret_data(krb5_storage *sp, krb5_data *data) @@ -594,6 +817,17 @@ krb5_ret_principal(krb5_storage *sp, return 0; } +/** + * Store a keyblock to the storage. + * + * @param sp the storage buffer to write to + * @param p the keyblock to write + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p) { @@ -612,6 +846,17 @@ krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p) return ret; } +/** + * Read a keyblock from the storage. + * + * @param sp the storage buffer to write to + * @param p the keyblock read from storage, free using krb5_free_keyblock() + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p) { @@ -631,6 +876,17 @@ krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p) return ret; } +/** + * Write a times block to storage. + * + * @param sp the storage buffer to write to + * @param times the times block to write. + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_store_times(krb5_storage *sp, krb5_times times) { @@ -645,6 +901,17 @@ krb5_store_times(krb5_storage *sp, krb5_times times) return ret; } +/** + * Read a times block from the storage. + * + * @param sp the storage buffer to write to + * @param times the times block read from storage + * + * @return 0 on success, a Kerberos 5 error code on failure. + * + * @ingroup krb5_storage + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_ret_times(krb5_storage *sp, krb5_times *times) { @@ -903,6 +1170,8 @@ krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds) header |= SC_ADDRESSES; ret = krb5_store_int32(sp, header); + if (ret) + return ret; if (creds->client) { ret = krb5_store_principal(sp, creds->client); diff --git a/source4/heimdal/lib/krb5/store_emem.c b/source4/heimdal/lib/krb5/store_emem.c index 8a587600fd..4be89b6564 100644 --- a/source4/heimdal/lib/krb5/store_emem.c +++ b/source4/heimdal/lib/krb5/store_emem.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - typedef struct emem_storage{ unsigned char *base; size_t size; @@ -67,7 +65,7 @@ emem_store(krb5_storage *sp, const void *data, size_t size) sz *= 2; base = realloc(s->base, sz); if(base == NULL) - return 0; + return -1; s->size = sz; s->base = base; s->ptr = (unsigned char*)base + off; @@ -104,6 +102,34 @@ emem_seek(krb5_storage *sp, off_t offset, int whence) return s->ptr - s->base; } +static int +emem_trunc(krb5_storage *sp, off_t offset) +{ + emem_storage *s = (emem_storage*)sp->data; + /* + * If offset is larget then current size, or current size is + * shrunk more then half of the current size, adjust buffer. + */ + if (offset > s->size || (s->size / 2) > offset) { + void *base; + size_t off; + off = s->ptr - s->base; + base = realloc(s->base, offset); + if(base == NULL) + return ENOMEM; + if (offset > s->size) + memset((char *)base + s->size, 0, offset - s->size); + s->size = offset; + s->base = base; + s->ptr = (unsigned char *)base + off; + } + s->len = offset; + if ((s->ptr - s->base) > offset) + s->ptr = s->base + offset; + return 0; +} + + static void emem_free(krb5_storage *sp) { @@ -112,6 +138,21 @@ emem_free(krb5_storage *sp) free(s->base); } +/** + * Create a elastic (allocating) memory storage backend. Memory is + * allocated on demand. Free returned krb5_storage with + * krb5_storage_free(). + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_fd() + * @sa krb5_storage_from_data() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_emem(void) { @@ -142,6 +183,7 @@ krb5_storage_emem(void) sp->fetch = emem_fetch; sp->store = emem_store; sp->seek = emem_seek; + sp->trunc = emem_trunc; sp->free = emem_free; return sp; } diff --git a/source4/heimdal/lib/krb5/store_fd.c b/source4/heimdal/lib/krb5/store_fd.c index fe3c513ee9..38d67ae4d3 100644 --- a/source4/heimdal/lib/krb5/store_fd.c +++ b/source4/heimdal/lib/krb5/store_fd.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - typedef struct fd_storage { int fd; } fd_storage; @@ -60,12 +58,33 @@ fd_seek(krb5_storage * sp, off_t offset, int whence) return lseek(FD(sp), offset, whence); } +static int +fd_trunc(krb5_storage * sp, off_t offset) +{ + if (ftruncate(FD(sp), offset) == -1) + return errno; + return 0; +} + static void fd_free(krb5_storage * sp) { close(FD(sp)); } +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_data() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_fd(int fd) { @@ -93,6 +112,7 @@ krb5_storage_from_fd(int fd) sp->fetch = fd_fetch; sp->store = fd_store; sp->seek = fd_seek; + sp->trunc = fd_trunc; sp->free = fd_free; return sp; } diff --git a/source4/heimdal/lib/krb5/store_mem.c b/source4/heimdal/lib/krb5/store_mem.c index 5c7cd17fba..db1abc1e90 100644 --- a/source4/heimdal/lib/krb5/store_mem.c +++ b/source4/heimdal/lib/krb5/store_mem.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include "store-int.h" -RCSID("$Id$"); - typedef struct mem_storage{ unsigned char *base; size_t size; @@ -93,6 +91,37 @@ mem_seek(krb5_storage *sp, off_t offset, int whence) return s->ptr - s->base; } +static int +mem_trunc(krb5_storage *sp, off_t offset) +{ + mem_storage *s = (mem_storage*)sp->data; + if(offset > s->size) + return ERANGE; + s->size = offset; + if ((s->ptr - s->base) > offset) + s->ptr = s->base + offset; + return 0; +} + +static int +mem_no_trunc(krb5_storage *sp, off_t offset) +{ + return EINVAL; +} + +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_data() + * @sa krb5_storage_from_fd() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_mem(void *buf, size_t len) { @@ -114,16 +143,43 @@ krb5_storage_from_mem(void *buf, size_t len) sp->fetch = mem_fetch; sp->store = mem_store; sp->seek = mem_seek; + sp->trunc = mem_trunc; sp->free = NULL; return sp; } +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_readonly_mem() + * @sa krb5_storage_from_fd() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_data(krb5_data *data) { return krb5_storage_from_mem(data->data, data->length); } +/** + * + * + * @return A krb5_storage on success, or NULL on out of memory error. + * + * @ingroup krb5_storage + * + * @sa krb5_storage_from_emem() + * @sa krb5_storage_from_mem() + * @sa krb5_storage_from_data() + * @sa krb5_storage_from_fd() + */ + krb5_storage * KRB5_LIB_FUNCTION krb5_storage_from_readonly_mem(const void *buf, size_t len) { @@ -145,6 +201,7 @@ krb5_storage_from_readonly_mem(const void *buf, size_t len) sp->fetch = mem_fetch; sp->store = mem_no_store; sp->seek = mem_seek; + sp->trunc = mem_no_trunc; sp->free = NULL; return sp; } diff --git a/source4/heimdal/lib/krb5/ticket.c b/source4/heimdal/lib/krb5/ticket.c index db78626570..86c4924506 100644 --- a/source4/heimdal/lib/krb5/ticket.c +++ b/source4/heimdal/lib/krb5/ticket.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - krb5_error_code KRB5_LIB_FUNCTION krb5_free_ticket(krb5_context context, krb5_ticket *ticket) @@ -301,3 +299,485 @@ krb5_ticket_get_authorization_data_type(krb5_context context, } return 0; } + +static krb5_error_code +check_server_referral(krb5_context context, + krb5_kdc_rep *rep, + unsigned flags, + krb5_const_principal requested, + krb5_const_principal returned, + krb5_keyblock * key) +{ + krb5_error_code ret; + PA_ServerReferralData ref; + krb5_crypto session; + EncryptedData ed; + size_t len; + krb5_data data; + PA_DATA *pa; + int i = 0, cmp; + + if (rep->kdc_rep.padata == NULL) + goto noreferral; + + pa = krb5_find_padata(rep->kdc_rep.padata->val, + rep->kdc_rep.padata->len, + KRB5_PADATA_SERVER_REFERRAL, &i); + if (pa == NULL) + goto noreferral; + + memset(&ed, 0, sizeof(ed)); + memset(&ref, 0, sizeof(ref)); + + ret = decode_EncryptedData(pa->padata_value.data, + pa->padata_value.length, + &ed, &len); + if (ret) + return ret; + if (len != pa->padata_value.length) { + free_EncryptedData(&ed); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Referral EncryptedData wrong for realm %s", + "realm"), requested->realm); + return KRB5KRB_AP_ERR_MODIFIED; + } + + ret = krb5_crypto_init(context, key, 0, &session); + if (ret) { + free_EncryptedData(&ed); + return ret; + } + + ret = krb5_decrypt_EncryptedData(context, session, + KRB5_KU_PA_SERVER_REFERRAL, + &ed, &data); + free_EncryptedData(&ed); + krb5_crypto_destroy(context, session); + if (ret) + return ret; + + ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len); + if (ret) { + krb5_data_free(&data); + return ret; + } + krb5_data_free(&data); + + if (strcmp(requested->realm, returned->realm) != 0) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("server ref realm mismatch, " + "requested realm %s got back %s", ""), + requested->realm, returned->realm); + return KRB5KRB_AP_ERR_MODIFIED; + } + + if (returned->name.name_string.len == 2 && + strcmp(returned->name.name_string.val[0], KRB5_TGS_NAME) == 0) + { + const char *realm = returned->name.name_string.val[1]; + + if (ref.referred_realm == NULL + || strcmp(*ref.referred_realm, realm) != 0) + { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("tgt returned with wrong ref", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + } else if (krb5_principal_compare(context, returned, requested) == 0) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("req princ no same as returned", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + + if (ref.requested_principal_name) { + cmp = _krb5_principal_compare_PrincipalName(context, + requested, + ref.requested_principal_name); + if (!cmp) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("referred principal not same " + "as requested", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + } else if (flags & EXTRACT_TICKET_AS_REQ) { + free_PA_ServerReferralData(&ref); + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Requested principal missing on AS-REQ", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + + free_PA_ServerReferralData(&ref); + + return ret; +noreferral: + if (krb5_principal_compare(context, requested, returned) == FALSE) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Not same server principal returned " + "as requested", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + return 0; +} + + +/* + * Verify referral data + */ + + +static krb5_error_code +check_client_referral(krb5_context context, + krb5_kdc_rep *rep, + krb5_const_principal requested, + krb5_const_principal mapped, + krb5_keyblock const * key) +{ + krb5_error_code ret; + PA_ClientCanonicalized canon; + krb5_crypto crypto; + krb5_data data; + PA_DATA *pa; + size_t len; + int i = 0; + + if (rep->kdc_rep.padata == NULL) + goto noreferral; + + pa = krb5_find_padata(rep->kdc_rep.padata->val, + rep->kdc_rep.padata->len, + KRB5_PADATA_CLIENT_CANONICALIZED, &i); + if (pa == NULL) + goto noreferral; + + ret = decode_PA_ClientCanonicalized(pa->padata_value.data, + pa->padata_value.length, + &canon, &len); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode ClientCanonicalized " + "from realm %s", ""), requested->realm); + return ret; + } + + ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, + &canon.names, &len, ret); + if (ret) { + free_PA_ClientCanonicalized(&canon); + return ret; + } + if (data.length != len) + krb5_abortx(context, "internal asn.1 error"); + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) { + free(data.data); + free_PA_ClientCanonicalized(&canon); + return ret; + } + + ret = krb5_verify_checksum(context, crypto, KRB5_KU_CANONICALIZED_NAMES, + data.data, data.length, + &canon.canon_checksum); + krb5_crypto_destroy(context, crypto); + free(data.data); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to verify client canonicalized " + "data from realm %s", ""), + requested->realm); + free_PA_ClientCanonicalized(&canon); + return ret; + } + + if (!_krb5_principal_compare_PrincipalName(context, + requested, + &canon.names.requested_name)) + { + free_PA_ClientCanonicalized(&canon); + krb5_set_error_message(context, KRB5_PRINC_NOMATCH, + N_("Requested name doesn't match" + " in client referral", "")); + return KRB5_PRINC_NOMATCH; + } + if (!_krb5_principal_compare_PrincipalName(context, + mapped, + &canon.names.mapped_name)) + { + free_PA_ClientCanonicalized(&canon); + krb5_set_error_message(context, KRB5_PRINC_NOMATCH, + N_("Mapped name doesn't match" + " in client referral", "")); + return KRB5_PRINC_NOMATCH; + } + + return 0; + +noreferral: + if (krb5_principal_compare(context, requested, mapped) == FALSE) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + N_("Not same client principal returned " + "as requested", "")); + return KRB5KRB_AP_ERR_MODIFIED; + } + return 0; +} + + +static krb5_error_code +decrypt_tkt (krb5_context context, + krb5_keyblock *key, + krb5_key_usage usage, + krb5_const_pointer decrypt_arg, + krb5_kdc_rep *dec_rep) +{ + krb5_error_code ret; + krb5_data data; + size_t size; + krb5_crypto crypto; + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + return ret; + + ret = krb5_decrypt_EncryptedData (context, + crypto, + usage, + &dec_rep->kdc_rep.enc_part, + &data); + krb5_crypto_destroy(context, crypto); + + if (ret) + return ret; + + ret = decode_EncASRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + if (ret) + ret = decode_EncTGSRepPart(data.data, + data.length, + &dec_rep->enc_part, + &size); + krb5_data_free (&data); + if (ret) { + krb5_set_error_message(context, ret, + N_("Failed to decode encpart in ticket", "")); + return ret; + } + return 0; +} + +int +_krb5_extract_ticket(krb5_context context, + krb5_kdc_rep *rep, + krb5_creds *creds, + krb5_keyblock *key, + krb5_const_pointer keyseed, + krb5_key_usage key_usage, + krb5_addresses *addrs, + unsigned nonce, + unsigned flags, + krb5_decrypt_proc decrypt_proc, + krb5_const_pointer decryptarg) +{ + krb5_error_code ret; + krb5_principal tmp_principal; + size_t len; + time_t tmp_time; + krb5_timestamp sec_now; + + /* decrypt */ + + if (decrypt_proc == NULL) + decrypt_proc = decrypt_tkt; + + ret = (*decrypt_proc)(context, key, key_usage, decryptarg, rep); + if (ret) + goto out; + + /* save session key */ + + creds->session.keyvalue.length = 0; + creds->session.keyvalue.data = NULL; + creds->session.keytype = rep->enc_part.key.keytype; + ret = krb5_data_copy (&creds->session.keyvalue, + rep->enc_part.key.keyvalue.data, + rep->enc_part.key.keyvalue.length); + if (ret) { + krb5_clear_error_message(context); + goto out; + } + + /* + * HACK: + * this is really a ugly hack, to support using the Netbios Domain Name + * as realm against windows KDC's, they always return the full realm + * based on the DNS Name. + */ + flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; + flags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; + + /* compare client and save */ + ret = _krb5_principalname2krb5_principal (context, + &tmp_principal, + rep->kdc_rep.cname, + rep->kdc_rep.crealm); + if (ret) + goto out; + + /* check client referral and save principal */ + /* anonymous here ? */ + if((flags & EXTRACT_TICKET_ALLOW_CNAME_MISMATCH) == 0) { + ret = check_client_referral(context, rep, + creds->client, + tmp_principal, + &creds->session); + if (ret) { + krb5_free_principal (context, tmp_principal); + goto out; + } + } + krb5_free_principal (context, creds->client); + creds->client = tmp_principal; + + /* check server referral and save principal */ + ret = _krb5_principalname2krb5_principal (context, + &tmp_principal, + rep->kdc_rep.ticket.sname, + rep->kdc_rep.ticket.realm); + if (ret) + goto out; + if((flags & EXTRACT_TICKET_ALLOW_SERVER_MISMATCH) == 0){ + ret = check_server_referral(context, + rep, + flags, + creds->server, + tmp_principal, + &creds->session); + if (ret) { + krb5_free_principal (context, tmp_principal); + goto out; + } + } + krb5_free_principal(context, creds->server); + creds->server = tmp_principal; + + /* verify names */ + if(flags & EXTRACT_TICKET_MATCH_REALM){ + const char *srealm = krb5_principal_get_realm(context, creds->server); + const char *crealm = krb5_principal_get_realm(context, creds->client); + + if (strcmp(rep->enc_part.srealm, srealm) != 0 || + strcmp(rep->enc_part.srealm, crealm) != 0) + { + ret = KRB5KRB_AP_ERR_MODIFIED; + krb5_clear_error_message(context); + goto out; + } + } + + /* compare nonces */ + + if (nonce != rep->enc_part.nonce) { + ret = KRB5KRB_AP_ERR_MODIFIED; + krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); + goto out; + } + + /* set kdc-offset */ + + krb5_timeofday (context, &sec_now); + if (rep->enc_part.flags.initial + && context->kdc_sec_offset == 0 + && krb5_config_get_bool (context, NULL, + "libdefaults", + "kdc_timesync", + NULL)) { + context->kdc_sec_offset = rep->enc_part.authtime - sec_now; + krb5_timeofday (context, &sec_now); + } + + /* check all times */ + + if (rep->enc_part.starttime) { + tmp_time = *rep->enc_part.starttime; + } else + tmp_time = rep->enc_part.authtime; + + if (creds->times.starttime == 0 + && abs(tmp_time - sec_now) > context->max_skew) { + ret = KRB5KRB_AP_ERR_SKEW; + krb5_set_error_message (context, ret, + N_("time skew (%d) larger than max (%d)", ""), + abs(tmp_time - sec_now), + (int)context->max_skew); + goto out; + } + + if (creds->times.starttime != 0 + && tmp_time != creds->times.starttime) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + creds->times.starttime = tmp_time; + + if (rep->enc_part.renew_till) { + tmp_time = *rep->enc_part.renew_till; + } else + tmp_time = 0; + + if (creds->times.renew_till != 0 + && tmp_time > creds->times.renew_till) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + creds->times.renew_till = tmp_time; + + creds->times.authtime = rep->enc_part.authtime; + + if (creds->times.endtime != 0 + && rep->enc_part.endtime > creds->times.endtime) { + krb5_clear_error_message (context); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + creds->times.endtime = rep->enc_part.endtime; + + if(rep->enc_part.caddr) + krb5_copy_addresses (context, rep->enc_part.caddr, &creds->addresses); + else if(addrs) + krb5_copy_addresses (context, addrs, &creds->addresses); + else { + creds->addresses.len = 0; + creds->addresses.val = NULL; + } + creds->flags.b = rep->enc_part.flags; + + creds->authdata.len = 0; + creds->authdata.val = NULL; + + /* extract ticket */ + ASN1_MALLOC_ENCODE(Ticket, creds->ticket.data, creds->ticket.length, + &rep->kdc_rep.ticket, &len, ret); + if(ret) + goto out; + if (creds->ticket.length != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + creds->second_ticket.length = 0; + creds->second_ticket.data = NULL; + + +out: + memset (rep->enc_part.key.keyvalue.data, 0, + rep->enc_part.key.keyvalue.length); + return ret; +} diff --git a/source4/heimdal/lib/krb5/time.c b/source4/heimdal/lib/krb5/time.c index cd786fedde..ed235783a2 100644 --- a/source4/heimdal/lib/krb5/time.c +++ b/source4/heimdal/lib/krb5/time.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /** * Set the absolute time that the caller knows the kdc has so the * kerberos library can calculate the relative diffrence beteen the diff --git a/source4/heimdal/lib/krb5/transited.c b/source4/heimdal/lib/krb5/transited.c index 7e11d5579a..196ef447ee 100644 --- a/source4/heimdal/lib/krb5/transited.c +++ b/source4/heimdal/lib/krb5/transited.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* this is an attempt at one of the most horrible `compression' schemes that has ever been invented; it's so amazingly brain-dead that words can not describe it, and all this just to save a few diff --git a/source4/heimdal/lib/krb5/v4_glue.c b/source4/heimdal/lib/krb5/v4_glue.c index 6911cb20f8..168268ceab 100644 --- a/source4/heimdal/lib/krb5/v4_glue.c +++ b/source4/heimdal/lib/krb5/v4_glue.c @@ -32,7 +32,6 @@ */ #include "krb5_locl.h" -RCSID("$Id$"); #include "krb5-v4compat.h" @@ -217,14 +216,16 @@ write_v4_cc(krb5_context context, const char *tkfile, ret = write(fd, data.data, data.length); if (ret != data.length) ret = KRB5_CC_IO; + else + ret = 0; - krb5_free_data_contents(context, &data); + krb5_data_free(&data); flock(fd, LOCK_UN); free(path); close(fd); - return 0; + return ret; } /* diff --git a/source4/heimdal/lib/krb5/version.c b/source4/heimdal/lib/krb5/version.c index d43b83e26e..a0e750604e 100644 --- a/source4/heimdal/lib/krb5/version.c +++ b/source4/heimdal/lib/krb5/version.c @@ -33,8 +33,6 @@ #include "krb5_locl.h" -RCSID("$Id$"); - /* this is just to get a version stamp in the library file */ #define heimdal_version __heimdal_version diff --git a/source4/heimdal/lib/krb5/warn.c b/source4/heimdal/lib/krb5/warn.c index a00ae80697..58fb73189e 100644 --- a/source4/heimdal/lib/krb5/warn.c +++ b/source4/heimdal/lib/krb5/warn.c @@ -34,8 +34,6 @@ #include "krb5_locl.h" #include <err.h> -RCSID("$Id$"); - static krb5_error_code _warnerr(krb5_context context, int do_errtext, krb5_error_code code, int level, const char *fmt, va_list ap) __attribute__((__format__(__printf__, 5, 0))); @@ -96,6 +94,18 @@ _warnerr(krb5_context context, int do_errtext, #undef __attribute__ #define __attribute__(X) +/** + * Log a warning to the log, default stderr, include the error from + * the last failure. + * + * @param context A Kerberos 5 context. + * @param code error code of the last error + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_vwarn(krb5_context context, krb5_error_code code, const char *fmt, va_list ap) @@ -104,6 +114,16 @@ krb5_vwarn(krb5_context context, krb5_error_code code, return _warnerr(context, 1, code, 1, fmt, ap); } +/** + * Log a warning to the log, default stderr, include the error from + * the last failure. + * + * @param context A Kerberos 5 context. + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ krb5_error_code KRB5_LIB_FUNCTION krb5_warn(krb5_context context, krb5_error_code code, const char *fmt, ...) @@ -113,6 +133,16 @@ krb5_warn(krb5_context context, krb5_error_code code, const char *fmt, ...) return ret; } +/** + * Log a warning to the log, default stderr. + * + * @param context A Kerberos 5 context. + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_vwarnx(krb5_context context, const char *fmt, va_list ap) __attribute__ ((format (printf, 2, 0))) @@ -120,6 +150,15 @@ krb5_vwarnx(krb5_context context, const char *fmt, va_list ap) return _warnerr(context, 0, 0, 1, fmt, ap); } +/** + * Log a warning to the log, default stderr. + * + * @param context A Kerberos 5 context. + * @param fmt message to print + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_warnx(krb5_context context, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))) @@ -128,6 +167,19 @@ krb5_warnx(krb5_context context, const char *fmt, ...) return ret; } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param code error code of the last error + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_verr(krb5_context context, int eval, krb5_error_code code, const char *fmt, va_list ap) @@ -137,6 +189,17 @@ krb5_verr(krb5_context context, int eval, krb5_error_code code, exit(eval); } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ krb5_error_code KRB5_LIB_FUNCTION krb5_err(krb5_context context, int eval, krb5_error_code code, @@ -147,6 +210,17 @@ krb5_err(krb5_context context, int eval, krb5_error_code code, exit(eval); } +/** + * Log a warning to the log, default stderr, and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_verrx(krb5_context context, int eval, const char *fmt, va_list ap) __attribute__ ((noreturn, format (printf, 3, 0))) @@ -155,6 +229,16 @@ krb5_verrx(krb5_context context, int eval, const char *fmt, va_list ap) exit(eval); } +/** + * Log a warning to the log, default stderr, and then exit. + * + * @param context A Kerberos 5 context + * @param eval the exit code to exit with + * @param fmt message to print + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_errx(krb5_context context, int eval, const char *fmt, ...) __attribute__ ((noreturn, format (printf, 3, 4))) @@ -163,6 +247,18 @@ krb5_errx(krb5_context context, int eval, const char *fmt, ...) exit(eval); } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then abort. + * + * @param context A Kerberos 5 context + * @param code error code of the last error + * @param fmt message to print + * @param ap arguments + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_vabort(krb5_context context, krb5_error_code code, const char *fmt, va_list ap) @@ -172,6 +268,16 @@ krb5_vabort(krb5_context context, krb5_error_code code, abort(); } +/** + * Log a warning to the log, default stderr, include bthe error from + * the last failure and then abort. + * + * @param context A Kerberos 5 context + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ krb5_error_code KRB5_LIB_FUNCTION krb5_abort(krb5_context context, krb5_error_code code, const char *fmt, ...) @@ -189,6 +295,16 @@ krb5_vabortx(krb5_context context, const char *fmt, va_list ap) abort(); } +/** + * Log a warning to the log, default stderr, and then abort. + * + * @param context A Kerberos 5 context + * @param code error code of the last error + * @param fmt message to print + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_abortx(krb5_context context, const char *fmt, ...) __attribute__ ((noreturn, format (printf, 2, 3))) @@ -197,6 +313,15 @@ krb5_abortx(krb5_context context, const char *fmt, ...) abort(); } +/** + * Set the default logging facility. + * + * @param context A Kerberos 5 context + * @param fac Facility to use for logging. + * + * @ingroup krb5_error + */ + krb5_error_code KRB5_LIB_FUNCTION krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac) { @@ -204,6 +329,14 @@ krb5_set_warn_dest(krb5_context context, krb5_log_facility *fac) return 0; } +/** + * Get the default logging facility. + * + * @param context A Kerberos 5 context + * + * @ingroup krb5_error + */ + krb5_log_facility * KRB5_LIB_FUNCTION krb5_get_warn_dest(krb5_context context) { |