aboutsummaryrefslogtreecommitdiff
path: root/lib/gssapi/mech/gss_mech_switch.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gssapi/mech/gss_mech_switch.c')
-rw-r--r--lib/gssapi/mech/gss_mech_switch.c253
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;
+}