diff options
Diffstat (limited to 'lib/gssapi/mech/gss_mech_switch.c')
-rw-r--r-- | lib/gssapi/mech/gss_mech_switch.c | 253 |
1 files changed, 198 insertions, 55 deletions
diff --git a/lib/gssapi/mech/gss_mech_switch.c b/lib/gssapi/mech/gss_mech_switch.c index 4d7f298d1961..3151efe4289f 100644 --- a/lib/gssapi/mech/gss_mech_switch.c +++ b/lib/gssapi/mech/gss_mech_switch.c @@ -33,7 +33,7 @@ #define _PATH_GSS_MECH "/etc/gss/mech" #endif -struct _gss_mech_switch_list _gss_mechs = { NULL } ; +struct _gss_mech_switch_list _gss_mechs = { NULL, NULL } ; gss_OID_set _gss_mech_oids; static HEIMDAL_MUTEX _gss_mech_mutex = HEIMDAL_MUTEX_INITIALIZER; @@ -42,15 +42,15 @@ static HEIMDAL_MUTEX _gss_mech_mutex = HEIMDAL_MUTEX_INITIALIZER; * (e.g. 1.2.840.113554.1.2.2) to a gss_OID. */ static int -_gss_string_to_oid(const char* s, gss_OID oid) +_gss_string_to_oid(const char* s, gss_OID *oidp) { int number_count, i, j; size_t byte_count; const char *p, *q; char *res; + gss_OID_desc oid; - oid->length = 0; - oid->elements = NULL; + *oidp = GSS_C_NO_OID; /* * First figure out how many numbers in the oid, then @@ -143,46 +143,66 @@ _gss_string_to_oid(const char* s, gss_OID oid) res = malloc(byte_count); if (!res) return (ENOMEM); - oid->length = byte_count; - oid->elements = res; + oid.length = byte_count; + oid.elements = res; } } + { + OM_uint32 minor_status, tmp; + + if (GSS_ERROR(_gss_intern_oid(&minor_status, &oid, oidp))) { + _gss_free_oid(&tmp, &oid); + return (minor_status); + } + + _gss_free_oid(&tmp, &oid); + } + return (0); } #define SYM(name) \ do { \ - m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ if (!m->gm_mech.gm_ ## name || \ m->gm_mech.gm_ ##name == gss_ ## name) { \ - fprintf(stderr, "can't find symbol gss_" #name "\n"); \ + _gss_mg_log(1, "can't find symbol gss_" #name "\n"); \ goto bad; \ } \ } while (0) #define OPTSYM(name) \ do { \ - m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ if (m->gm_mech.gm_ ## name == gss_ ## name) \ m->gm_mech.gm_ ## name = NULL; \ } while (0) +/* mech exports gssspi_XXX, internally referred to as gss_XXX */ #define OPTSPISYM(name) \ do { \ - m->gm_mech.gm_ ## name = dlsym(so, "gssspi_" #name); \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ +} while (0) + +/* mech exports gssspi_XXX, internally referred to as gssspi_XXX */ +#define OPTSPISPISYM(name) \ +do { \ + m->gm_mech.gm_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ + if (m->gm_mech.gm_ ## name == gssspi_ ## name) \ + m->gm_mech.gm_ ## name = NULL; \ } while (0) #define COMPATSYM(name) \ do { \ - m->gm_mech.gm_compat->gmc_ ## name = dlsym(so, "gss_" #name); \ + m->gm_mech.gm_compat->gmc_ ## name = (_gss_##name##_t *)dlsym(so, "gss_" #name); \ if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \ m->gm_mech.gm_compat->gmc_ ## name = NULL; \ } while (0) #define COMPATSPISYM(name) \ do { \ - m->gm_mech.gm_compat->gmc_ ## name = dlsym(so, "gssspi_" #name);\ + m->gm_mech.gm_compat->gmc_ ## name = (_gss_##name##_t *)dlsym(so, "gssspi_" #name); \ if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \ m->gm_mech.gm_compat->gmc_ ## name = NULL; \ } while (0) @@ -205,9 +225,17 @@ add_builtin(gssapi_mech_interface mech) return ENOMEM; m->gm_so = NULL; m->gm_mech = *mech; - m->gm_mech_oid = mech->gm_mech_oid; /* XXX */ - gss_add_oid_set_member(&minor_status, - &m->gm_mech.gm_mech_oid, &_gss_mech_oids); + _gss_intern_oid(&minor_status, &mech->gm_mech_oid, &m->gm_mech_oid); + if (minor_status) { + free(m); + return minor_status; + } + + if (gss_add_oid_set_member(&minor_status, &m->gm_mech.gm_mech_oid, + &_gss_mech_oids) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } /* pick up the oid sets of names */ @@ -215,13 +243,25 @@ add_builtin(gssapi_mech_interface mech) (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status, &m->gm_mech.gm_mech_oid, &m->gm_name_types); - if (m->gm_name_types == NULL) - gss_create_empty_oid_set(&minor_status, &m->gm_name_types); + if (m->gm_name_types == NULL && + gss_create_empty_oid_set(&minor_status, + &m->gm_name_types) != GSS_S_COMPLETE) { + free(m); + return ENOMEM; + } - HEIM_SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); + HEIM_TAILQ_INSERT_TAIL(&_gss_mechs, m, gm_link); return 0; } +static void +init_mech_switch_list(void *p) +{ + struct _gss_mech_switch_list *mechs = p; + + HEIM_TAILQ_INIT(mechs); +} + /* * Load the mechanisms file (/etc/gss/mech). */ @@ -229,19 +269,24 @@ void _gss_load_mech(void) { OM_uint32 major_status, minor_status; + static heim_base_once_t once = HEIM_BASE_ONCE_INIT; +#ifdef HAVE_DLOPEN FILE *fp; char buf[256]; char *p; char *name, *oid, *lib, *kobj; struct _gss_mech_switch *m; void *so; - gss_OID_desc mech_oid; + gss_OID mech_oid; int found; + const char *conf = secure_getenv("GSS_MECH_CONFIG"); +#endif + heim_base_once_f(&once, &_gss_mechs, init_mech_switch_list); HEIMDAL_MUTEX_lock(&_gss_mech_mutex); - if (HEIM_SLIST_FIRST(&_gss_mechs)) { + if (!HEIM_TAILQ_EMPTY(&_gss_mechs)) { HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); return; } @@ -253,16 +298,20 @@ _gss_load_mech(void) return; } - add_builtin(__gss_krb5_initialize()); - add_builtin(__gss_spnego_initialize()); - add_builtin(__gss_ntlm_initialize()); + if (add_builtin(__gss_krb5_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin Kerberos GSS " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_spnego_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SPNEGO " + "mechanism to the GSS mechanism switch"); + if (add_builtin(__gss_ntlm_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin NTLM " + "mechanism to the GSS mechanism switch"); #ifdef HAVE_DLOPEN - fp = fopen(_PATH_GSS_MECH, "r"); - if (!fp) { - HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); - return; - } + fp = fopen(conf ? conf : _PATH_GSS_MECH, "r"); + if (!fp) + goto out; rk_cloexec_file(fp); while (fgets(buf, sizeof(buf), fp)) { @@ -288,27 +337,18 @@ _gss_load_mech(void) * Check for duplicates, already loaded mechs. */ found = 0; - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { - if (gss_oid_equal(&m->gm_mech.gm_mech_oid, &mech_oid)) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech_oid)) { found = 1; - free(mech_oid.elements); break; } } if (found) continue; -#ifndef RTLD_LOCAL -#define RTLD_LOCAL 0 -#endif - -#ifndef RTLD_GROUP -#define RTLD_GROUP 0 -#endif - so = dlopen(lib, RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP); if (so == NULL) { -/* fprintf(stderr, "dlopen: %s\n", dlerror()); */ + _gss_mg_log(1, "dlopen: %s\n", dlerror()); goto bad; } @@ -319,7 +359,7 @@ _gss_load_mech(void) m->gm_so = so; m->gm_mech_oid = mech_oid; m->gm_mech.gm_name = strdup(name); - m->gm_mech.gm_mech_oid = mech_oid; + m->gm_mech.gm_mech_oid = *mech_oid; m->gm_mech.gm_flags = 0; m->gm_mech.gm_compat = calloc(1, sizeof(struct gss_mech_compat_desc_struct)); if (m->gm_mech.gm_compat == NULL) @@ -341,22 +381,22 @@ _gss_load_mech(void) SYM(verify_mic); SYM(wrap); SYM(unwrap); - SYM(display_status); - SYM(indicate_mechs); + OPTSYM(display_status); + OPTSYM(indicate_mechs); SYM(compare_name); SYM(display_name); SYM(import_name); SYM(export_name); SYM(release_name); - SYM(inquire_cred); + OPTSYM(inquire_cred); SYM(inquire_context); SYM(wrap_size_limit); - SYM(add_cred); - SYM(inquire_cred_by_mech); + OPTSYM(add_cred); + OPTSYM(inquire_cred_by_mech); SYM(export_sec_context); SYM(import_sec_context); - SYM(inquire_names_for_mech); - SYM(inquire_mechs_for_name); + OPTSYM(inquire_names_for_mech); + OPTSYM(inquire_mechs_for_name); SYM(canonicalize_name); SYM(duplicate_name); OPTSYM(inquire_cred_by_oid); @@ -370,8 +410,9 @@ _gss_load_mech(void) OPTSYM(store_cred); OPTSYM(export_cred); OPTSYM(import_cred); + OPTSYM(acquire_cred_from); + OPTSYM(acquire_cred_impersonate_name); #if 0 - OPTSYM(acquire_cred_ext); OPTSYM(iter_creds); OPTSYM(destroy_cred); OPTSYM(cred_hold); @@ -386,11 +427,17 @@ _gss_load_mech(void) OPTSYM(delete_name_attribute); OPTSYM(export_name_composite); OPTSYM(localname); + OPTSYM(duplicate_cred); + OPTSYM(add_cred_from); + OPTSYM(store_cred_into); OPTSPISYM(authorize_localname); + OPTSPISPISYM(query_mechanism_info); + OPTSPISPISYM(query_meta_data); + OPTSPISPISYM(exchange_meta_data); - mi = dlsym(so, "gss_mo_init"); + mi = (_gss_mo_init *)dlsym(so, "gss_mo_init"); if (mi != NULL) { - major_status = mi(&minor_status, &mech_oid, + major_status = mi(&minor_status, mech_oid, &m->gm_mech.gm_mo, &m->gm_mech.gm_mo_num); if (GSS_ERROR(major_status)) goto bad; @@ -411,21 +458,28 @@ _gss_load_mech(void) if (m->gm_name_types == NULL) gss_create_empty_oid_set(&minor_status, &m->gm_name_types); - HEIM_SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); + HEIM_TAILQ_INSERT_TAIL(&_gss_mechs, m, gm_link); continue; bad: if (m != NULL) { free(m->gm_mech.gm_compat); - free(m->gm_mech.gm_mech_oid.elements); + /* do not free OID, it has been interned */ free((char *)m->gm_mech.gm_name); free(m); } - dlclose(so); + if (so != NULL) + dlclose(so); continue; } fclose(fp); + +out: + #endif + if (add_builtin(__gss_sanon_initialize())) + _gss_mg_log(1, "Out of memory while adding builtin SANON " + "mechanism to the GSS mechanism switch"); HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); } @@ -435,9 +489,98 @@ __gss_get_mechanism(gss_const_OID mech) struct _gss_mech_switch *m; _gss_load_mech(); - HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech)) return &m->gm_mech; } return NULL; } + +gss_OID +_gss_mg_support_mechanism(gss_const_OID mech) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech)) + return m->gm_mech_oid; + } + return NULL; +} + +enum mech_name_match { + MATCH_NONE = 0, + MATCH_COMPLETE, + MATCH_PARTIAL +}; + +static enum mech_name_match +match_mech_name(const char *gm_mech_name, + const char *name, + size_t namelen) +{ + if (gm_mech_name == NULL) + return MATCH_NONE; + else if (strcasecmp(gm_mech_name, name) == 0) + return MATCH_COMPLETE; + else if (strncasecmp(gm_mech_name, name, namelen) == 0) + return MATCH_PARTIAL; + else + return MATCH_NONE; +} + +/* + * Return an OID for a built-in or dynamically loaded mechanism. For + * API compatibility with previous versions, we treat "Kerberos 5" + * as an alias for "krb5". Unique partial matches are supported. + */ +GSSAPI_LIB_FUNCTION gss_OID GSSAPI_CALLCONV +gss_name_to_oid(const char *name) +{ + struct _gss_mech_switch *m, *partial = NULL; + gss_OID oid = GSS_C_NO_OID; + size_t namelen = strlen(name); + + if (isdigit((unsigned char)name[0]) && + _gss_string_to_oid(name, &oid) == 0) + return oid; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + enum mech_name_match match; + + match = match_mech_name(m->gm_mech.gm_name, name, namelen); + if (match == MATCH_NONE && + gss_oid_equal(m->gm_mech_oid, GSS_KRB5_MECHANISM)) + match = match_mech_name("Kerberos 5", name, namelen); + + if (match == MATCH_COMPLETE) + return m->gm_mech_oid; + else if (match == MATCH_PARTIAL) { + if (partial) + return NULL; + else + partial = m; + } + } + + if (partial) + return partial->gm_mech_oid; + + return NULL; +} + +GSSAPI_LIB_FUNCTION const char * GSSAPI_LIB_CALL +gss_oid_to_name(gss_const_OID oid) +{ + struct _gss_mech_switch *m; + + _gss_load_mech(); + HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) { + if (gss_oid_equal(m->gm_mech_oid, oid)) + return m->gm_mech.gm_name; + } + + return NULL; +} |