krb5 commit: Add support for loading interposer modules

Greg Hudson ghudson at MIT.EDU
Tue Oct 2 00:57:17 EDT 2012


https://github.com/krb5/krb5/commit/046c9028aa79d5e9c9b1910f93d39a4891609883
commit 046c9028aa79d5e9c9b1910f93d39a4891609883
Author: Simo Sorce <simo at redhat.com>
Date:   Mon Sep 17 22:00:44 2012 -0400

    Add support for loading interposer modules
    
    Extend the syntax of the gss mech config file to allow a module type
    delimited by triangle brackets.  If the module type is "interposer",
    flag the mechanism entry as being an interposer mechanism.  A module
    marked as an interposer is loaded immediately (so it can interpose a
    built-in mechanism) and produces a list of OIDs to interpose.
    Interposer mechanisms are not exposed to applications.
    
    [ghudson at mit.edu: Stylistic changes, commit squashing, commit
    message]

 src/lib/gssapi/mechglue/g_initialize.c |  267 +++++++++++++++++++++++++++++---
 src/lib/gssapi/mechglue/mglueP.h       |    4 +
 2 files changed, 247 insertions(+), 24 deletions(-)

diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
index 13177c2..dc6b8ea 100644
--- a/src/lib/gssapi/mechglue/g_initialize.c
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -53,13 +53,16 @@
 #endif
 
 #define MECH_SYM "gss_mech_initialize"
+#define MECH_INTERPOSER_SYM "gss_mech_interposer"
 
 #ifndef MECH_CONF
 #define	MECH_CONF "/etc/gss/mech"
 #endif
 
 /* Local functions */
-static void addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib, const char *kernMod, const char *modOptions);
+static void addConfigEntry(const char *oidStr, const char *oid,
+			   const char *sharedLib, const char *kernMod,
+			   const char *modOptions, const char *modType);
 static gss_mech_info searchMechList(gss_const_OID);
 static void loadConfigFile(const char *);
 #if defined(_WIN32)
@@ -72,6 +75,7 @@ static void getRegKeyValue(HKEY key, const char *keyPath, const char *valueName,
 static void loadConfigFromRegistry(HKEY keyBase, const char *keyPath);
 #endif
 static void updateMechList(void);
+static void loadInterMech(gss_mech_info aMech);
 static void freeMechList(void);
 
 static OM_uint32 build_mechSet(void);
@@ -339,10 +343,11 @@ build_mechSet(void)
 			      count * sizeof (gss_OID_desc));
 
 		/* now copy each oid element */
-		g_mechSet.count = count;
 		count = 0;
-		mList = g_mechList;
-		while (mList != NULL) {
+		for (mList = g_mechList; mList != NULL; mList = mList->next) {
+			/* Don't expose interposer mechanisms. */
+			if (mList->is_interposer)
+				continue;
 			curItem = &(g_mechSet.elements[count]);
 			curItem->elements = (void*)
 				malloc(mList->mech_type->length);
@@ -364,8 +369,8 @@ build_mechSet(void)
 			}
 			g_OID_copy(curItem, mList->mech_type);
 			count++;
-			mList = mList->next;
 		}
+		g_mechSet.count = count;
 	}
 
 #if 0
@@ -421,13 +426,15 @@ const gss_OID oid;
 static void
 updateMechList(void)
 {
+	gss_mech_info minfo;
+
 #if defined(_WIN32)
 	time_t lastConfModTime = getRegConfigModTime(MECH_KEY);
-	if (g_confFileModTime < lastConfModTime) {
-		g_confFileModTime = lastConfModTime;
-		loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY);
-		loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY);
-	}
+	if (g_confFileModTime >= lastConfModTime)
+		return;
+	g_confFileModTime = lastConfModTime;
+	loadConfigFromRegistry(HKEY_CURRENT_USER, MECH_KEY);
+	loadConfigFromRegistry(HKEY_LOCAL_MACHINE, MECH_KEY);
 #else /* _WIN32 */
 	char *fileName;
 	struct stat fileInfo;
@@ -435,15 +442,19 @@ updateMechList(void)
 	fileName = MECH_CONF;
 
 	/* check if mechList needs updating */
-	if (stat(fileName, &fileInfo) == 0 &&
-		(fileInfo.st_mtime > g_confFileModTime)) {
-		loadConfigFile(fileName);
-		g_confFileModTime = fileInfo.st_mtime;
-	}
-#if 0
-	init_hardcoded();
-#endif
+	if (stat(fileName, &fileInfo) != 0 ||
+	    g_confFileModTime >= fileInfo.st_mtime)
+		return;
+	g_confFileModTime = fileInfo.st_mtime;
+	loadConfigFile(fileName);
 #endif /* !_WIN32 */
+
+	/* Load any unloaded interposer mechanisms immediately, to make sure we
+	 * interpose other mechanisms before they are used. */
+	for (minfo = g_mechList; minfo != NULL; minfo = minfo->next) {
+		if (minfo->is_interposer && minfo->mech == NULL)
+			loadInterMech(minfo);
+	}
 } /* updateMechList */
 
 static void
@@ -475,6 +486,8 @@ releaseMechInfo(gss_mech_info *pCf)
 	}
 	if (cf->dl_handle != NULL)
 		krb5int_close_plugin(cf->dl_handle);
+	if (cf->int_mech_type != GSS_C_NO_OID)
+		generic_gss_release_oid(&minor_status, &cf->int_mech_type);
 
 	memset(cf, 0, sizeof(*cf));
 	free(cf);
@@ -671,6 +684,195 @@ build_dynamicMech(void *dl, const gss_OID mech_type)
 	return mech;
 }
 
+#define RESOLVE_GSSI_SYMBOL(_dl, _mech, _psym, _nsym)			\
+	do {								\
+		struct errinfo errinfo;					\
+		memset(&errinfo, 0, sizeof(errinfo));			\
+		if (krb5int_get_plugin_func(_dl,			\
+					    "gssi" #_nsym,		\
+					    (void (**)())&(_mech)->_psym \
+					    ## _nsym,			\
+					    &errinfo) || errinfo.code)	\
+			(_mech)->_psym ## _nsym = NULL;			\
+	} while (0)
+
+/* Build an interposer mechanism function table from dl. */
+static gss_mechanism
+build_interMech(void *dl, const gss_OID mech_type)
+{
+	gss_mechanism mech;
+
+	mech = calloc(1, sizeof(*mech));
+	if (mech == NULL) {
+		return NULL;
+	}
+
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_cred);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _init_sec_context);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _accept_sec_context);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _process_context_token);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_sec_context);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _context_time);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_mic);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _verify_mic);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_status);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _indicate_mechs);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _compare_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_sec_context);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _import_sec_context);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_mech);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_names_for_mech);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_context);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _internal_release_oid);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_size_limit);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _localname);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _authorize_localname);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _duplicate_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _store_cred);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_sec_context_by_oid);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_cred_by_oid);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_sec_context_option);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _set_cred_option);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _mech_invoke);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_aead);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_aead);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _unwrap_iov);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _wrap_iov_length);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _complete_auth_token);
+	/* Services4User (introduced in 1.8) */
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _acquire_cred_impersonate_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _add_cred_impersonate_name);
+	/* Naming extensions (introduced in 1.8) */
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _display_name_ext);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_name);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _get_name_attribute);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_name_attribute);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _delete_name_attribute);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _export_name_composite);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _map_name_to_any);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _release_any_name_mapping);
+	/* RFC 4401 (introduced in 1.8) */
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _pseudo_random);
+	/* RFC 4178 (introduced in 1.8; get_neg_mechs not implemented) */
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _set_neg_mechs);
+	/* draft-ietf-sasl-gs2 */
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_saslname_for_mech);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_mech_for_saslname);
+	/* RFC 5587 */
+	RESOLVE_GSSI_SYMBOL(dl, mech, gss, _inquire_attrs_for_mech);
+	RESOLVE_GSSI_SYMBOL(dl, mech, gssspi, _acquire_cred_with_password);
+
+	mech->mech_type = *mech_type;
+	return mech;
+}
+
+/*
+ * Concatenate an interposer mech OID and a real mech OID to create an
+ * identifier for the interposed mech.  (The concatenation will not be a valid
+ * DER OID encoding, but the OID is only used internally.)
+ */
+static gss_OID
+interposed_oid(gss_OID pre, gss_OID real)
+{
+	gss_OID o;
+
+	o = (gss_OID)malloc(sizeof(gss_OID_desc));
+	if (!o)
+		return NULL;
+
+	o->length = pre->length + real->length;
+	o->elements = malloc(o->length);
+	if (!o->elements) {
+		free(o);
+		return NULL;
+	}
+
+	memcpy(o->elements, pre->elements, pre->length);
+	memcpy(o->elements + pre->length, real->elements, real->length);
+
+	return o;
+}
+
+static void
+loadInterMech(gss_mech_info minfo)
+{
+	struct plugin_file_handle *dl = NULL;
+	struct errinfo errinfo;
+	gss_OID_set (*isym)(const gss_OID);
+	gss_OID_set list;
+	gss_OID oid;
+	OM_uint32 min;
+	gss_mech_info mi;
+	size_t i;
+
+	memset(&errinfo, 0, sizeof(errinfo));
+
+	if (krb5int_open_plugin(minfo->uLibName, &dl, &errinfo) != 0 ||
+	    errinfo.code != 0) {
+#if 0
+		(void) syslog(LOG_INFO, "libgss dlopen(%s): %s\n",
+				aMech->uLibName, dlerror());
+#endif
+		return;
+	}
+
+	if (krb5int_get_plugin_func(dl, MECH_INTERPOSER_SYM,
+				    (void (**)())&isym, &errinfo) != 0)
+		goto cleanup;
+
+	/* Get a list of mechs to interpose. */
+	list = (*isym)(minfo->mech_type);
+	if (!list)
+		goto cleanup;
+	minfo->mech = build_interMech(dl, minfo->mech_type);
+	if (minfo->mech == NULL)
+		goto cleanup;
+	minfo->freeMech = 1;
+
+	/* Add interposer fields for each interposed mech. */
+	for (i = 0; i < list->count; i++) {
+		/* Skip this mech if it doesn't exist or is already
+		 * interposed. */
+		oid = &list->elements[i];
+		mi = searchMechList(oid);
+		if (mi == NULL || mi->int_mech_type != NULL)
+			continue;
+
+		/* Construct a special OID to represent the interposed mech. */
+		mi->int_mech_type = interposed_oid(minfo->mech_type, oid);
+		if (mi->int_mech_type == NULL)
+			continue;
+
+		/* Save an alias to the interposer's function table. */
+		mi->int_mech = minfo->mech;
+	}
+	(void)gss_release_oid_set(&min, &list);
+
+	minfo->dl_handle = dl;
+	dl = NULL;
+
+cleanup:
+#if 0
+	if (aMech->mech == NULL) {
+		(void) syslog(LOG_INFO, "unable to initialize mechanism"
+				" library [%s]\n", aMech->uLibName);
+	}
+#endif
+	if (dl != NULL)
+		krb5int_close_plugin(dl);
+	krb5int_clear_error(&errinfo);
+}
+
 static void
 freeMechList(void)
 {
@@ -834,7 +1036,7 @@ delimit(char *str, char delimiter)
 static void
 loadConfigFile(const char *fileName)
 {
-	char *sharedLib, *kernMod, *modOptions, *oid, *next;
+	char *sharedLib, *kernMod, *modOptions, *modType, *oid, *next;
 	char buffer[BUFSIZ], *oidStr;
 	FILE *confFile;
 
@@ -860,7 +1062,7 @@ loadConfigFile(const char *fileName)
 		next = delimit_ws(sharedLib);
 
 		/* Parse out the kernel module name if present. */
-		if (*next != '\0' && *next != '[') {
+		if (*next != '\0' && *next != '[' && *next != '<') {
 			kernMod = next;
 			next = delimit_ws(kernMod);
 		} else {
@@ -875,7 +1077,16 @@ loadConfigFile(const char *fileName)
 			modOptions = NULL;
 		}
 
-		addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions);
+		/* Parse out the module type if present. */
+		if (*next == '<') {
+			modType = next + 1;
+			next = delimit(modType, '>');
+		} else {
+			modType = NULL;
+		}
+
+		addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,
+			       modType);
 	} /* while */
 	(void) fclose(confFile);
 } /* loadConfigFile */
@@ -971,7 +1182,7 @@ loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath)
 	HKEY hConfigKey;
 	DWORD iSubKey, nSubKeys, maxSubKeyNameLen;
 	char *oidStr = NULL, *oid = NULL, *sharedLib = NULL, *kernMod = NULL;
-	char *modOptions = NULL;
+	char *modOptions = NULL, *modType = NULL;
 	DWORD oidStrLen = 0, oidLen = 0, sharedLibLen = 0, kernModLen = 0;
 	DWORD modOptionsLen = 0;
 	HRESULT rc;
@@ -1016,7 +1227,10 @@ loadConfigFromRegistry(HKEY hBaseKey, const char *keyPath)
 			       &kernModLen);
 		getRegKeyValue(hConfigKey, oidStr, "Options", &modOptions,
 			       &modOptionsLen);
-		addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions);
+		getRegKeyValue(hConfigKey, oidStr, "Type", &modType,
+			       &modTypeLen);
+		addConfigEntry(oidStr, oid, sharedLib, kernMod, modOptions,
+			       modType);
 	}
 cleanup:
 	RegCloseKey(hConfigKey);
@@ -1040,7 +1254,8 @@ cleanup:
 
 static void
 addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,
-	       const char *kernMod, const char *modOptions)
+	       const char *kernMod, const char *modOptions,
+	       const char *modType)
 {
 #if defined(_WIN32)
 	const char *sharedPath;
@@ -1156,6 +1371,10 @@ addConfigEntry(const char *oidStr, const char *oid, const char *sharedLib,
 
 	if (modOptions)
 		aMech->optionStr = strdup(modOptions);
+
+	if (modType && strcmp(modType, "interposer") == 0)
+		aMech->is_interposer = 1;
+
 	/*
 	 * add the new entry to the end of the list - make sure
 	 * that only complete entries are added because other
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index ad0fdf5..21eefdb 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -25,6 +25,7 @@ do {								\
  */
 typedef struct gss_union_ctx_id_struct {
 	struct gss_union_ctx_id_struct *loopback;
+	struct gss_union_ctx_id_struct *interposer;
 	gss_OID			mech_type;
 	gss_ctx_id_t		internal_ctx_id;
 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
@@ -667,6 +668,9 @@ typedef struct gss_mech_config {
 	gss_mechanism mech;		/* mechanism initialization struct */
  	int priority;			/* mechanism preference order */
 	int freeMech;			/* free mech table */
+	int is_interposer;		/* interposer mechanism flag */
+	gss_OID int_mech_type;		/* points to the interposer OID */
+	gss_mechanism int_mech;		/* points to the interposer mech */
 	struct gss_mech_config *next;	/* next element in the list */
 } *gss_mech_info;
 


More information about the cvs-krb5 mailing list