From a899d9be0cab72dcfe00f100527c52ea598fed70 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Sun, 1 Apr 2012 21:53:04 +0200 Subject: Add enable-in and disable-in options to module config * These can be used to load certain modules in certain programs, or prevent loading in others. * Useful for a key manager like seahorse, so we can load extra modules (think NSS) that other modules shouldn't load. --- p11-kit/modules.c | 75 ++++++++++++++++++++++++++++++++++- p11-kit/p11-kit.h | 2 + p11-kit/private.h | 4 ++ p11-kit/util.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 193 insertions(+), 3 deletions(-) (limited to 'p11-kit') diff --git a/p11-kit/modules.c b/p11-kit/modules.c index 047a2ca..f059097 100644 --- a/p11-kit/modules.c +++ b/p11-kit/modules.c @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -336,6 +337,61 @@ expand_module_path (const char *filename) return path; } +static int +is_list_delimiter (char ch) +{ + return ch == ',' || isspace (ch); +} + +static int +is_string_in_list (const char *list, + const char *string) +{ + const char *where; + + where = strstr (list, string); + if (where == NULL) + return 0; + + /* Has to be at beginning/end of string, and delimiter before/after */ + if (where != list && !is_list_delimiter (*(where - 1))) + return 0; + + where += strlen (string); + return (*where == '\0' || is_list_delimiter (*where)); +} + +static int +is_module_enabled_unlocked (const char *name, + hashmap *config) +{ + const char *progname; + const char *enable_in; + const char *disable_in; + int enable; + + enable_in = _p11_hash_get (config, "enable-in"); + disable_in = _p11_hash_get (config, "disable-in"); + + /* Defaults to enabled if neither of these are set */ + if (!enable_in && !disable_in) + return 1; + + progname = _p11_get_progname_unlocked (); + if (enable_in && disable_in) + _p11_message ("module '%s' has both enable-in and disable-in options", name); + if (enable_in) + enable = (progname != NULL && is_string_in_list (enable_in, progname)); + else if (disable_in) + enable = (progname == NULL || !is_string_in_list (disable_in, progname)); + + _p11_debug ("%s module '%s' running in '%s'", + enable ? "enabled" : "disabled", + name, + progname ? progname : "(null)"); + return enable; +} + static CK_RV take_config_and_load_module_unlocked (char **name, hashmap **config) { @@ -349,6 +405,9 @@ take_config_and_load_module_unlocked (char **name, hashmap **config) assert (config); assert (*config); + if (!is_module_enabled_unlocked (*name, *config)) + return CKR_OK; + module_filename = _p11_hash_get (*config, "module"); if (module_filename == NULL) { _p11_debug ("no module path for module, skipping: %s", *name); @@ -832,8 +891,22 @@ _p11_kit_registered_modules_unlocked (void) if (result) { _p11_hash_iterate (gl.modules, &iter); while (_p11_hash_next (&iter, NULL, (void **)&mod)) { - if (mod->ref_count && mod->name) + + /* + * We don't include unreferenced modules. We don't include + * modules that have been initialized but aren't in the + * registry. These have a NULL name. + * + * In addition we check again that the module isn't disabled + * using enable-in or disable-in. This is because a caller + * can change the progname we recognize the process as after + * having initialized. This is a corner case, but want to make + * sure to cover it. + */ + if (mod->ref_count && mod->name && + is_module_enabled_unlocked (mod->name, mod->config)) { result[i++] = mod->funcs; + } } } diff --git a/p11-kit/p11-kit.h b/p11-kit/p11-kit.h index cf84db6..77cf1b5 100644 --- a/p11-kit/p11-kit.h +++ b/p11-kit/p11-kit.h @@ -80,6 +80,8 @@ char* p11_kit_space_strdup (const unsigned char #ifdef P11_KIT_FUTURE_UNSTABLE_API +void p11_kit_set_progname (const char *progname); + void p11_kit_be_quiet (void); const char* p11_kit_message (void); diff --git a/p11-kit/private.h b/p11-kit/private.h index d23c1e6..36acb7e 100644 --- a/p11-kit/private.h +++ b/p11-kit/private.h @@ -92,4 +92,8 @@ void _p11_kit_clear_message (void); void _p11_kit_default_message (CK_RV rv); +const char * _p11_get_progname_unlocked (void); + +void _p11_set_progname_unlocked (const char *progname); + #endif /* __P11_KIT_PRIVATE_H__ */ diff --git a/p11-kit/util.c b/p11-kit/util.c index c04b636..fd7708a 100644 --- a/p11-kit/util.c +++ b/p11-kit/util.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2011 Collabora Ltd + * Copyright (c) 2012 Stef Walter * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,7 +32,7 @@ * * * CONTRIBUTORS - * Stef Walter + * Stef Walter */ #include "config.h" @@ -246,6 +247,14 @@ _p11_kit_default_message (CK_RV rv) } } +static void +uninit_common (void) +{ + _p11_debug ("uninitializing library"); + + _p11_set_progname_unlocked (NULL); +} + #ifdef OS_UNIX static pthread_key_t thread_local = 0; @@ -277,10 +286,47 @@ _p11_library_init (void) void _p11_library_uninit (void) { + uninit_common (); + pthread_key_delete (thread_local); _p11_mutex_uninit (&_p11_mutex); } +#if defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME) && !HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME +extern char *program_invocation_short_name; +#endif + +#if defined (HAVE___PROGNAME) && !HAVE_DECL___PROGNAME +extern char *__progname; +#endif + +static char * +get_default_progname (void) +{ + const char *name; + +#if defined (HAVE_GETPROGNAME) + name = getprogname(); +#elif defined (HAVE_GETEXECNAME) + const char *p; + name = getexecname(); + p = strrchr (name ? name : "", '/'); + if (p != NULL) + name = p + 1; +#elif defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME) + name = program_invocation_short_name; +#elif defined (HAVE___PROGNAME) + name = __progname; +#else + #error No way to retrieve program name from p11-kit library +#endif + + if (name == NULL) + return NULL; + + return strdup (name); +} + #endif /* OS_UNIX */ #ifdef OS_WIN32 @@ -331,7 +377,7 @@ _p11_library_uninit (void) { LPVOID data; - _p11_debug ("uninitializing library"); + uninit_common (); if (thread_local != TLS_OUT_OF_INDEXES) { data = TlsGetValue (thread_local); @@ -376,4 +422,69 @@ DllMain (HINSTANCE instance, return TRUE; } +extern char **__argv; + +static char * +get_default_progname (void) +{ + const char *name; + const char *p; + char *progname; + size_t length; + + name = __argv[0]; + if (name == NULL) + return NULL; + + p = strrchr (name, '\\'); + if (p != NULL) + name = p + 1; + + progname = strdup (name); + length = strlen (progname); + if (length > 4 && _stricmp(progname + (length - 4), ".exe")) + progname[length - 4] = '\0'; + + return progname; +} + #endif /* OS_WIN32 */ + +/* This is the progname that we think of this process as. */ +char *_p11_my_progname = NULL; + +/** + * p11_kit_set_progname: + * @progname: the program base name + * + * Set the program base name that is used by the enable-in + * and disable-in module configuration options. + * + * Normally this is automatically calculated from the program's argument list. + * You would usually call this before initializing p11-kit modules. + */ +void +p11_kit_set_progname (const char *progname) +{ + _p11_library_init_once (); + + _p11_lock (); + _p11_set_progname_unlocked (progname); + _p11_unlock (); +} + +void +_p11_set_progname_unlocked (const char *progname) +{ + /* We can be called with NULL, to cleanup memory usage */ + free (_p11_my_progname); + _p11_my_progname = progname ? strdup (progname) : NULL; +} + +const char * +_p11_get_progname_unlocked (void) +{ + if (_p11_my_progname == NULL) + _p11_my_progname = get_default_progname (); + return _p11_my_progname; +} -- cgit v1.1