From 9b261c008a395a323e0516f4cd3f3134aa050577 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 8 Jun 2009 19:06:16 +1000 Subject: s4:heimdal: import lorikeet-heimdal-200906080040 (commit 904d0124b46eed7a8ad6e5b73e892ff34b6865ba) Also including the supporting changes required to pass make test A number of heimdal functions and constants have changed since we last imported a tree (for the better, but inconvenient for us). Andrew Bartlett --- source4/heimdal/lib/krb5/keytab.c | 439 ++++++++++++++++++++++++++++++++------ 1 file changed, 369 insertions(+), 70 deletions(-) (limited to 'source4/heimdal/lib/krb5/keytab.c') 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 -- cgit