From 51c8dc37dd4d655cf44f07d16dc985627a8e3577 Mon Sep 17 00:00:00 2001 From: Geoff Thorpe Date: Thu, 26 Oct 2000 17:38:59 +0000 Subject: [PATCH] This changes the behaviour of the DSO mechanism for determining an appropriate filename translation on the host system. Apart from this point, users should also note that there's a slight change in the API functions too. The DSO now contains its own to-be-converted filename ("dso->filename"), and at the time the DSO loads the "dso->loaded_filename" value is set to the translated form. As such, this also provides an impicit way of determining if the DSO is currently loaded or not. Except, perhaps, VMS .... :-) The various DSO_METHODs have been updated for this mechanism except VMS which is deliberately broken for now, Richard is going to look at how to fit it in (the source comments in there explain "the issue"). Basically, the new callback scheme allows the filename conversion to (a) be turned off altogether through the use of the DSO_FLAG_NO_NAME_TRANSLATION flag, (b) be handled in the default way using the default DSO_METHOD's converter (c) overriden per-DSO by setting the override callback (d) a mix of (b) and (c) - eg. implement an override callback that; (i) checks if we're win32 "if(strstr(dso->meth->name, "win32"))..." and if so, convert "blah" into "blah32.dll" (the default is otherwise to make it "blah.dll"). (ii) default to the normal behaviour - eg. we're not on win32, so finish with (return dso->meth->dso_name_converter(dso,NULL)). (e) be retried a number of times by writing a new DSO_METHOD where the "dso_load()" handler will call the converter repeatedly. Then the custom converter could use state information in the DSO to suggest different conversions or paths each time it is invoked. --- crypto/dso/README | 24 +++---- crypto/dso/dso.h | 98 +++++++++++++++++++++++---- crypto/dso/dso_dl.c | 73 +++++++++++++++----- crypto/dso/dso_dlfcn.c | 72 +++++++++++++------- crypto/dso/dso_err.c | 12 ++++ crypto/dso/dso_lib.c | 150 ++++++++++++++++++++++++++++++++++++----- crypto/dso/dso_vms.c | 35 +++++++++- crypto/dso/dso_win32.c | 81 ++++++++++++++-------- 8 files changed, 434 insertions(+), 111 deletions(-) diff --git a/crypto/dso/README b/crypto/dso/README index 6ba03c5631..d0bc9a89fb 100644 --- a/crypto/dso/README +++ b/crypto/dso/README @@ -1,16 +1,3 @@ -TODO ----- - -Find a way where name-translation can be done in a way that is -sensitive to particular methods (ie. generic code could still do -different path/filename substitutions on win32 to what it does on -*nix) but doesn't assume some canonical form. Already one case -exists where the "blah -> (libblah.so,blah.dll)" mapping doesn't -suffice. I suspect a callback with an enumerated (or string?) -parameter could be the way to go here ... DSO_ctrl the callback -into place and it can be invoked to handle name translation with -some clue to the calling code as to what kind of system it is. - NOTES ----- @@ -21,4 +8,15 @@ according to their man page, prefer developers to move to that. I'll leave Richard's changes there as I guess dso_dl is needed for HPUX10.20. +There is now a callback scheme in place where filename conversion can +(a) be turned off altogether through the use of the + DSO_FLAG_NO_NAME_TRANSLATION flag, +(b) be handled by default using the default DSO_METHOD's converter +(c) overriden per-DSO by setting the override callback +(d) a mix of (b) and (c) - eg. implement an override callback that; + (i) checks if we're win32 (if(strstr(dso->meth->name, "win32")....) + and if so, convert "blah" into "blah32.dll" (the default is + otherwise to make it "blah.dll"). + (ii) default to the normal behaviour - we're not on win32, eg. + finish with (return dso->meth->dso_name_converter(dso,NULL)). diff --git a/crypto/dso/dso.h b/crypto/dso/dso.h index 2770e3b763..add6858de8 100644 --- a/crypto/dso/dso.h +++ b/crypto/dso/dso.h @@ -70,15 +70,18 @@ extern "C" { #define DSO_CTRL_SET_FLAGS 2 #define DSO_CTRL_OR_FLAGS 3 -/* These flags control the translation of file-names from canonical to - * native. Eg. in the CryptoSwift support, the "dl" and "dlfcn" - * methods will translate "swift" -> "libswift.so" whereas the "win32" - * method will translate "swift" -> "swift.dll". NB: Until I can figure - * out how to be more "conventional" with this, the methods will only - * honour this flag if it looks like it was passed a file without any - * path and if the filename is small enough. - */ -#define DSO_FLAG_NAME_TRANSLATION 0x01 +/* By default, DSO_load() will translate the provided filename into a form + * typical for the platform (more specifically the DSO_METHOD) using the + * dso_name_converter function of the method. Eg. win32 will transform "blah" + * into "blah.dll", and dlfcn will transform it into "libblah.so". The + * behaviour can be overriden by setting the name_converter callback in the DSO + * object (using DSO_set_name_converter()). This callback could even utilise + * the DSO_METHOD's converter too if it only wants to override behaviour for + * one or two possible DSO methods. However, the following flag can be set in a + * DSO to prevent *any* native name-translation at all - eg. if the caller has + * prompted the user for a path to a driver library so the filename should be + * interpreted as-is. */ +#define DSO_FLAG_NO_NAME_TRANSLATION 0x01 /* The following flag controls the translation of symbol names to upper * case. This is currently only being implemented for OpenVMS. @@ -90,11 +93,21 @@ typedef void (*DSO_FUNC_TYPE)(void); typedef struct dso_st DSO; +/* The function prototype used for method functions (or caller-provided + * callbacks) that transform filenames. They are passed a DSO structure pointer + * (or NULL if they are to be used independantly of a DSO object) and a + * filename to transform. They should either return NULL (if there is an error + * condition) or a newly allocated string containing the transformed form that + * the caller will need to free with OPENSSL_free() when done. */ +typedef char* (*DSO_NAME_CONVERTER_FUNC)(DSO *, const char *); + typedef struct dso_meth_st { const char *name; - /* Loads a shared library */ - int (*dso_load)(DSO *dso, const char *filename); + /* Loads a shared library, NB: new DSO_METHODs must ensure that a + * successful load populates the loaded_filename field, and likewise a + * successful unload OPENSSL_frees and NULLs it out. */ + int (*dso_load)(DSO *dso); /* Unloads a shared library */ int (*dso_unload)(DSO *dso); /* Binds a variable */ @@ -117,6 +130,9 @@ typedef struct dso_meth_st /* The generic (yuck) "ctrl()" function. NB: Negative return * values (rather than zero) indicate errors. */ long (*dso_ctrl)(DSO *dso, int cmd, long larg, void *parg); + /* The default DSO_METHOD-specific function for converting filenames to + * a canonical native form. */ + DSO_NAME_CONVERTER_FUNC dso_name_converter; /* [De]Initialisation handlers. */ int (*init)(DSO *dso); @@ -140,6 +156,23 @@ struct dso_st /* For use by applications etc ... use this for your bits'n'pieces, * don't touch meth_data! */ CRYPTO_EX_DATA ex_data; + /* If this callback function pointer is set to non-NULL, then it will + * be used on DSO_load() in place of meth->dso_name_converter. NB: This + * should normally set using DSO_set_name_converter(). */ + DSO_NAME_CONVERTER_FUNC name_converter; + /* This is populated with (a copy of) the platform-independant + * filename used for this DSO. */ + char *filename; + /* This is populated with (a copy of) the translated filename by which + * the DSO was actually loaded. It is NULL iff the DSO is not currently + * loaded. NB: This is here because the filename translation process + * may involve a callback being invoked more than once not only to + * convert to a platform-specific form, but also to try different + * filenames in the process of trying to perform a load. As such, this + * variable can be used to indicate (a) whether this DSO structure + * corresponds to a loaded library or not, and (b) the filename with + * which it was actually loaded. */ + char *loaded_filename; }; @@ -149,8 +182,35 @@ int DSO_free(DSO *dso); int DSO_flags(DSO *dso); int DSO_up(DSO *dso); long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg); - -void DSO_set_default_method(DSO_METHOD *meth); +/* This function sets the DSO's name_converter callback. If it is non-NULL, + * then it will be used instead of the associated DSO_METHOD's function. If + * oldcb is non-NULL then it is set to the function pointer value being + * replaced. Return value is non-zero for success. */ +int DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb, + DSO_NAME_CONVERTER_FUNC *oldcb); +/* These functions can be used to get/set the platform-independant filename + * used for a DSO. NB: set will fail if the DSO is already loaded. */ +const char *DSO_get_filename(DSO *dso); +int DSO_set_filename(DSO *dso, const char *filename); +/* This function will invoke the DSO's name_converter callback to translate a + * filename, or if the callback isn't set it will instead use the DSO_METHOD's + * converter. If "filename" is NULL, the "filename" in the DSO itself will be + * used. If the DSO_FLAG_NO_NAME_TRANSLATION flag is set, then the filename is + * simply duplicated. NB: This function is usually called from within a + * DSO_METHOD during the processing of a DSO_load() call, and is exposed so that + * caller-created DSO_METHODs can do the same thing. A non-NULL return value + * will need to be OPENSSL_free()'d. */ +char *DSO_convert_filename(DSO *dso, const char *filename); +/* If the DSO is currently loaded, this returns the filename that it was loaded + * under, otherwise it returns NULL. So it is also useful as a test as to + * whether the DSO is currently loaded. NB: This will not necessarily return + * the same value as DSO_convert_filename(dso, dso->filename), because the + * DSO_METHOD's load function may have tried a variety of filenames (with + * and/or without the aid of the converters) before settling on the one it + * actually loaded. */ +const char *DSO_get_loaded_filename(DSO *dso); + +void DSO_set_default_method(DSO_METHOD *meth); DSO_METHOD *DSO_get_default_method(void); DSO_METHOD *DSO_get_method(DSO *dso); DSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth); @@ -207,17 +267,24 @@ void ERR_load_DSO_strings(void); #define DSO_F_DLFCN_BIND_FUNC 100 #define DSO_F_DLFCN_BIND_VAR 101 #define DSO_F_DLFCN_LOAD 102 +#define DSO_F_DLFCN_NAME_CONVERTER 123 #define DSO_F_DLFCN_UNLOAD 103 #define DSO_F_DL_BIND_FUNC 104 #define DSO_F_DL_BIND_VAR 105 #define DSO_F_DL_LOAD 106 +#define DSO_F_DL_NAME_CONVERTER 124 #define DSO_F_DL_UNLOAD 107 #define DSO_F_DSO_BIND_FUNC 108 #define DSO_F_DSO_BIND_VAR 109 +#define DSO_F_DSO_CONVERT_FILENAME 126 #define DSO_F_DSO_CTRL 110 #define DSO_F_DSO_FREE 111 +#define DSO_F_DSO_GET_FILENAME 127 +#define DSO_F_DSO_GET_LOADED_FILENAME 128 #define DSO_F_DSO_LOAD 112 #define DSO_F_DSO_NEW_METHOD 113 +#define DSO_F_DSO_SET_FILENAME 129 +#define DSO_F_DSO_SET_NAME_CONVERTER 122 #define DSO_F_DSO_UP 114 #define DSO_F_VMS_BIND_VAR 115 #define DSO_F_VMS_LOAD 116 @@ -225,14 +292,19 @@ void ERR_load_DSO_strings(void); #define DSO_F_WIN32_BIND_FUNC 118 #define DSO_F_WIN32_BIND_VAR 119 #define DSO_F_WIN32_LOAD 120 +#define DSO_F_WIN32_NAME_CONVERTER 125 #define DSO_F_WIN32_UNLOAD 121 /* Reason codes. */ #define DSO_R_CTRL_FAILED 100 +#define DSO_R_DSO_ALREADY_LOADED 110 #define DSO_R_FILENAME_TOO_BIG 101 #define DSO_R_FINISH_FAILED 102 #define DSO_R_LOAD_FAILED 103 +#define DSO_R_NAME_TRANSLATION_FAILED 109 +#define DSO_R_NO_FILENAME 111 #define DSO_R_NULL_HANDLE 104 +#define DSO_R_SET_FILENAME_FAILED 112 #define DSO_R_STACK_ERROR 105 #define DSO_R_SYM_FAILURE 106 #define DSO_R_UNLOAD_FAILED 107 diff --git a/crypto/dso/dso_dl.c b/crypto/dso/dso_dl.c index 71f44752d0..6dd1b19755 100644 --- a/crypto/dso/dso_dl.c +++ b/crypto/dso/dso_dl.c @@ -72,7 +72,7 @@ DSO_METHOD *DSO_METHOD_dl(void) /* Part of the hack in "dl_load" ... */ #define DSO_MAX_TRANSLATED_SIZE 256 -static int dl_load(DSO *dso, const char *filename); +static int dl_load(DSO *dso); static int dl_unload(DSO *dso); static void *dl_bind_var(DSO *dso, const char *symname); static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname); @@ -83,6 +83,7 @@ static int dl_init(DSO *dso); static int dl_finish(DSO *dso); static int dl_ctrl(DSO *dso, int cmd, long larg, void *parg); #endif +static char *dl_name_converter(DSO *dso, const char *filename); static DSO_METHOD dso_meth_dl = { "OpenSSL 'dl' shared library method", @@ -96,6 +97,7 @@ static DSO_METHOD dso_meth_dl = { NULL, /* unbind_func */ #endif NULL, /* ctrl */ + dl_name_converter, NULL, /* init */ NULL /* finish */ }; @@ -111,35 +113,41 @@ DSO_METHOD *DSO_METHOD_dl(void) * type so the cast is safe. */ -static int dl_load(DSO *dso, const char *filename) +static int dl_load(DSO *dso) { - shl_t ptr; - char translated[DSO_MAX_TRANSLATED_SIZE]; - int len; + shl_t ptr = NULL; + /* We don't do any fancy retries or anything, just take the method's + * (or DSO's if it has the callback set) best translation of the + * platform-independant filename and try once with that. */ + char *filename= DSO_convert_filename(dso, NULL); - /* The same comment as in dlfcn_load applies here. bleurgh. */ - len = strlen(filename); - if((dso->flags & DSO_FLAG_NAME_TRANSLATION) && - (len + 6 < DSO_MAX_TRANSLATED_SIZE) && - (strstr(filename, "/") == NULL)) + if(filename == NULL) { - sprintf(translated, "lib%s.so", filename); - ptr = shl_load(translated, BIND_IMMEDIATE, NULL); + DSOerr(DSO_F_DL_LOAD,DSO_R_NO_FILENAME); + goto err; } - else - ptr = shl_load(filename, BIND_IMMEDIATE, NULL); + ptr = shl_load(filename, BIND_IMMEDIATE, NULL); if(ptr == NULL) { DSOerr(DSO_F_DL_LOAD,DSO_R_LOAD_FAILED); - return(0); + goto err; } if(!sk_push(dso->meth_data, (char *)ptr)) { DSOerr(DSO_F_DL_LOAD,DSO_R_STACK_ERROR); - shl_unload(ptr); - return(0); + goto err; } + /* Success, stick the converted filename we've loaded under into the DSO + * (it also serves as the indicator that we are currently loaded). */ + dso->loaded_filename = filename; return(1); +err: + /* Cleanup! */ + if(filename != NULL) + OPENSSL_free(filename); + if(ptr != NULL) + shl_unload(ptr); + return(0); } static int dl_unload(DSO *dso) @@ -224,4 +232,35 @@ static DSO_FUNC_TYPE dl_bind_func(DSO *dso, const char *symname) return((DSO_FUNC_TYPE)sym); } +/* This function is identical to the one in dso_dlfcn.c, but as it is highly + * unlikely that both the "dl" *and* "dlfcn" variants are being compiled at the + * same time, there's no great duplicating the code. Figuring out an elegant way + * to share one copy of the code would be more difficult and would not leave the + * implementations independant. */ +static char *dl_name_converter(DSO *dso, const char *filename) + { + char *translated; + int len, transform; + + len = strlen(filename); + transform = (strstr(filename, "/") == NULL); + if(transform) + /* We will convert this to "lib%s.so" */ + translated = OPENSSL_malloc(len + 7); + else + /* We will simply duplicate filename */ + translated = OPENSSL_malloc(len + 1); + if(translated == NULL) + { + DSOerr(DSO_F_DL_NAME_CONVERTER, + DSO_R_NAME_TRANSLATION_FAILED); + return(NULL); + } + if(transform) + sprintf(translated, "lib%s.so", filename); + else + sprintf(translated, "%s", filename); + return(translated); + } + #endif /* DSO_DL */ diff --git a/crypto/dso/dso_dlfcn.c b/crypto/dso/dso_dlfcn.c index 07bbf37456..279b37b0c8 100644 --- a/crypto/dso/dso_dlfcn.c +++ b/crypto/dso/dso_dlfcn.c @@ -74,7 +74,7 @@ DSO_METHOD *DSO_METHOD_dlfcn(void) /* Part of the hack in "dlfcn_load" ... */ #define DSO_MAX_TRANSLATED_SIZE 256 -static int dlfcn_load(DSO *dso, const char *filename); +static int dlfcn_load(DSO *dso); static int dlfcn_unload(DSO *dso); static void *dlfcn_bind_var(DSO *dso, const char *symname); static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname); @@ -84,6 +84,7 @@ static int dlfcn_init(DSO *dso); static int dlfcn_finish(DSO *dso); static long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg); #endif +static char *dlfcn_name_converter(DSO *dso, const char *filename); static DSO_METHOD dso_meth_dlfcn = { "OpenSSL 'dlfcn' shared library method", @@ -97,6 +98,7 @@ static DSO_METHOD dso_meth_dlfcn = { NULL, /* unbind_func */ #endif NULL, /* ctrl */ + dlfcn_name_converter, NULL, /* init */ NULL /* finish */ }; @@ -130,41 +132,39 @@ DSO_METHOD *DSO_METHOD_dlfcn(void) * (i) the handle (void*) returned from dlopen(). */ -static int dlfcn_load(DSO *dso, const char *filename) +static int dlfcn_load(DSO *dso) { - void *ptr; - char translated[DSO_MAX_TRANSLATED_SIZE]; - int len; + void *ptr = NULL; + /* See applicable comments in dso_dl.c */ + char *filename = DSO_convert_filename(dso, NULL); - /* NB: This is a hideous hack, but I'm not yet sure what - * to replace it with. This attempts to convert any filename, - * that looks like it has no path information, into a - * translated form, e. "blah" -> "libblah.so" */ - len = strlen(filename); - if((dso->flags & DSO_FLAG_NAME_TRANSLATION) && - (len + 6 < DSO_MAX_TRANSLATED_SIZE) && - (strstr(filename, "/") == NULL)) - { - sprintf(translated, "lib%s.so", filename); - ptr = dlopen(translated, DLOPEN_FLAG); - } - else + if(filename == NULL) { - ptr = dlopen(filename, DLOPEN_FLAG); + DSOerr(DSO_F_DLFCN_LOAD,DSO_R_NO_FILENAME); + goto err; } + ptr = dlopen(filename, DLOPEN_FLAG); if(ptr == NULL) { DSOerr(DSO_F_DLFCN_LOAD,DSO_R_LOAD_FAILED); - return(0); + goto err; } if(!sk_push(dso->meth_data, (char *)ptr)) { DSOerr(DSO_F_DLFCN_LOAD,DSO_R_STACK_ERROR); - dlclose(ptr); - return(0); + goto err; } + /* Success */ + dso->loaded_filename = filename; return(1); - } +err: + /* Cleanup! */ + if(filename != NULL) + OPENSSL_free(filename); + if(ptr != NULL) + dlclose(ptr); + return(0); +} static int dlfcn_unload(DSO *dso) { @@ -249,4 +249,30 @@ static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) return(sym); } +static char *dlfcn_name_converter(DSO *dso, const char *filename) + { + char *translated; + int len, transform; + + len = strlen(filename); + transform = (strstr(filename, "/") == NULL); + if(transform) + /* We will convert this to "lib%s.so" */ + translated = OPENSSL_malloc(len + 7); + else + /* We will simply duplicate filename */ + translated = OPENSSL_malloc(len + 1); + if(translated == NULL) + { + DSOerr(DSO_F_DLFCN_NAME_CONVERTER, + DSO_R_NAME_TRANSLATION_FAILED); + return(NULL); + } + if(transform) + sprintf(translated, "lib%s.so", filename); + else + sprintf(translated, "%s", filename); + return(translated); + } + #endif /* DSO_DLFCN */ diff --git a/crypto/dso/dso_err.c b/crypto/dso/dso_err.c index a9b758d1c9..0d7134646e 100644 --- a/crypto/dso/dso_err.c +++ b/crypto/dso/dso_err.c @@ -69,17 +69,24 @@ static ERR_STRING_DATA DSO_str_functs[]= {ERR_PACK(0,DSO_F_DLFCN_BIND_FUNC,0), "DLFCN_BIND_FUNC"}, {ERR_PACK(0,DSO_F_DLFCN_BIND_VAR,0), "DLFCN_BIND_VAR"}, {ERR_PACK(0,DSO_F_DLFCN_LOAD,0), "DLFCN_LOAD"}, +{ERR_PACK(0,DSO_F_DLFCN_NAME_CONVERTER,0), "DLFCN_NAME_CONVERTER"}, {ERR_PACK(0,DSO_F_DLFCN_UNLOAD,0), "DLFCN_UNLOAD"}, {ERR_PACK(0,DSO_F_DL_BIND_FUNC,0), "DL_BIND_FUNC"}, {ERR_PACK(0,DSO_F_DL_BIND_VAR,0), "DL_BIND_VAR"}, {ERR_PACK(0,DSO_F_DL_LOAD,0), "DL_LOAD"}, +{ERR_PACK(0,DSO_F_DL_NAME_CONVERTER,0), "DL_NAME_CONVERTER"}, {ERR_PACK(0,DSO_F_DL_UNLOAD,0), "DL_UNLOAD"}, {ERR_PACK(0,DSO_F_DSO_BIND_FUNC,0), "DSO_bind_func"}, {ERR_PACK(0,DSO_F_DSO_BIND_VAR,0), "DSO_bind_var"}, +{ERR_PACK(0,DSO_F_DSO_CONVERT_FILENAME,0), "DSO_convert_filename"}, {ERR_PACK(0,DSO_F_DSO_CTRL,0), "DSO_ctrl"}, {ERR_PACK(0,DSO_F_DSO_FREE,0), "DSO_free"}, +{ERR_PACK(0,DSO_F_DSO_GET_FILENAME,0), "DSO_get_filename"}, +{ERR_PACK(0,DSO_F_DSO_GET_LOADED_FILENAME,0), "DSO_get_loaded_filename"}, {ERR_PACK(0,DSO_F_DSO_LOAD,0), "DSO_load"}, {ERR_PACK(0,DSO_F_DSO_NEW_METHOD,0), "DSO_new_method"}, +{ERR_PACK(0,DSO_F_DSO_SET_FILENAME,0), "DSO_set_filename"}, +{ERR_PACK(0,DSO_F_DSO_SET_NAME_CONVERTER,0), "DSO_set_name_converter"}, {ERR_PACK(0,DSO_F_DSO_UP,0), "DSO_up"}, {ERR_PACK(0,DSO_F_VMS_BIND_VAR,0), "VMS_BIND_VAR"}, {ERR_PACK(0,DSO_F_VMS_LOAD,0), "VMS_LOAD"}, @@ -87,6 +94,7 @@ static ERR_STRING_DATA DSO_str_functs[]= {ERR_PACK(0,DSO_F_WIN32_BIND_FUNC,0), "WIN32_BIND_FUNC"}, {ERR_PACK(0,DSO_F_WIN32_BIND_VAR,0), "WIN32_BIND_VAR"}, {ERR_PACK(0,DSO_F_WIN32_LOAD,0), "WIN32_LOAD"}, +{ERR_PACK(0,DSO_F_WIN32_NAME_CONVERTER,0), "WIN32_NAME_CONVERTER"}, {ERR_PACK(0,DSO_F_WIN32_UNLOAD,0), "WIN32_UNLOAD"}, {0,NULL} }; @@ -94,10 +102,14 @@ static ERR_STRING_DATA DSO_str_functs[]= static ERR_STRING_DATA DSO_str_reasons[]= { {DSO_R_CTRL_FAILED ,"control command failed"}, +{DSO_R_DSO_ALREADY_LOADED ,"dso already loaded"}, {DSO_R_FILENAME_TOO_BIG ,"filename too big"}, {DSO_R_FINISH_FAILED ,"cleanup method function failed"}, {DSO_R_LOAD_FAILED ,"could not load the shared library"}, +{DSO_R_NAME_TRANSLATION_FAILED ,"name translation failed"}, +{DSO_R_NO_FILENAME ,"no filename"}, {DSO_R_NULL_HANDLE ,"a null shared library handle was used"}, +{DSO_R_SET_FILENAME_FAILED ,"set filename failed"}, {DSO_R_STACK_ERROR ,"the meth_data stack is corrupt"}, {DSO_R_SYM_FAILURE ,"could not bind to the requested symbol name"}, {DSO_R_UNLOAD_FAILED ,"could not unload the shared library"}, diff --git a/crypto/dso/dso_lib.c b/crypto/dso/dso_lib.c index fc3d76034a..0202978fd8 100644 --- a/crypto/dso/dso_lib.c +++ b/crypto/dso/dso_lib.c @@ -164,6 +164,10 @@ int DSO_free(DSO *dso) } sk_free(dso->meth_data); + if(dso->filename != NULL) + OPENSSL_free(dso->filename); + if(dso->loaded_filename != NULL) + OPENSSL_free(dso->loaded_filename); OPENSSL_free(dso); return(1); @@ -192,48 +196,61 @@ DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags) DSO *ret; int allocated = 0; - if(filename == NULL) - { - DSOerr(DSO_F_DSO_LOAD,ERR_R_PASSED_NULL_PARAMETER); - return(NULL); - } if(dso == NULL) { ret = DSO_new_method(meth); if(ret == NULL) { DSOerr(DSO_F_DSO_LOAD,ERR_R_MALLOC_FAILURE); - return(NULL); + goto err; } allocated = 1; } else ret = dso; + /* Don't load if we're currently already loaded */ + if(dso->filename != NULL) + { + DSOerr(DSO_F_DSO_LOAD,DSO_R_DSO_ALREADY_LOADED); + goto err; + } + /* filename can only be NULL if we were passed a dso that already has + * one set. */ + if(filename != NULL) + if(!DSO_set_filename(dso, filename)) + { + DSOerr(DSO_F_DSO_LOAD,DSO_R_SET_FILENAME_FAILED); + goto err; + } + filename = dso->filename; + if(filename == NULL) + { + DSOerr(DSO_F_DSO_LOAD,DSO_R_NO_FILENAME); + goto err; + } /* Bleurgh ... have to check for negative return values for * errors. */ if(DSO_ctrl(ret, DSO_CTRL_SET_FLAGS, flags, NULL) < 0) { DSOerr(DSO_F_DSO_LOAD,DSO_R_CTRL_FAILED); - if(allocated) - DSO_free(ret); - return(NULL); + goto err; } if(ret->meth->dso_load == NULL) { DSOerr(DSO_F_DSO_LOAD,DSO_R_UNSUPPORTED); - if(allocated) - DSO_free(ret); - return(NULL); + goto err; } - if(!ret->meth->dso_load(ret, filename)) + if(!ret->meth->dso_load(ret)) { DSOerr(DSO_F_DSO_LOAD,DSO_R_LOAD_FAILED); - if(allocated) - DSO_free(ret); - return(NULL); + goto err; } /* Load succeeded */ return(ret); +err: + if(allocated) + DSO_free(ret); + return(NULL); } void *DSO_bind_var(DSO *dso, const char *symname) @@ -320,3 +337,104 @@ long DSO_ctrl(DSO *dso, int cmd, long larg, void *parg) } return(dso->meth->dso_ctrl(dso,cmd,larg,parg)); } + +int DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb, + DSO_NAME_CONVERTER_FUNC *oldcb) + { + if(dso == NULL) + { + DSOerr(DSO_F_DSO_SET_NAME_CONVERTER, + ERR_R_PASSED_NULL_PARAMETER); + return(0); + } + if(oldcb) + *oldcb = dso->name_converter; + dso->name_converter = cb; + return(1); + } + +const char *DSO_get_filename(DSO *dso) + { + if(dso == NULL) + { + DSOerr(DSO_F_DSO_GET_FILENAME,ERR_R_PASSED_NULL_PARAMETER); + return(NULL); + } + return(dso->filename); + } + +int DSO_set_filename(DSO *dso, const char *filename) + { + char *copied; + + if((dso == NULL) || (filename == NULL)) + { + DSOerr(DSO_F_DSO_SET_FILENAME,ERR_R_PASSED_NULL_PARAMETER); + return(0); + } + if(dso->loaded_filename) + { + DSOerr(DSO_F_DSO_SET_FILENAME,DSO_R_DSO_ALREADY_LOADED); + return(0); + } + /* We'll duplicate filename */ + copied = OPENSSL_malloc(strlen(filename) + 1); + if(copied == NULL) + { + DSOerr(DSO_F_DSO_SET_FILENAME,ERR_R_MALLOC_FAILURE); + return(0); + } + strcpy(copied, filename); + if(dso->filename) + OPENSSL_free(dso->filename); + dso->filename = copied; + return(1); + } + +char *DSO_convert_filename(DSO *dso, const char *filename) + { + char *result = NULL; + + if(dso == NULL) + { + DSOerr(DSO_F_DSO_CONVERT_FILENAME,ERR_R_PASSED_NULL_PARAMETER); + return(NULL); + } + if(filename == NULL) + filename = dso->filename; + if(filename == NULL) + { + DSOerr(DSO_F_DSO_CONVERT_FILENAME,DSO_R_NO_FILENAME); + return(NULL); + } + if((dso->flags & DSO_FLAG_NO_NAME_TRANSLATION) == 0) + { + if(dso->name_converter != NULL) + result = dso->name_converter(dso, filename); + else if(dso->meth->dso_name_converter != NULL) + result = dso->meth->dso_name_converter(dso, filename); + } + if(result == NULL) + { + result = OPENSSL_malloc(strlen(filename) + 1); + if(result == NULL) + { + DSOerr(DSO_F_DSO_CONVERT_FILENAME, + ERR_R_MALLOC_FAILURE); + return(NULL); + } + strcpy(result, filename); + } + return(result); + } + +const char *DSO_get_loaded_filename(DSO *dso) + { + if(dso == NULL) + { + DSOerr(DSO_F_DSO_GET_LOADED_FILENAME, + ERR_R_PASSED_NULL_PARAMETER); + return(NULL); + } + return(dso->loaded_filename); + } diff --git a/crypto/dso/dso_vms.c b/crypto/dso/dso_vms.c index 948f7a12bd..bd284535f1 100644 --- a/crypto/dso/dso_vms.c +++ b/crypto/dso/dso_vms.c @@ -78,7 +78,7 @@ DSO_METHOD *DSO_METHOD_vms(void) #else #pragma message disable DOLLARID -static int vms_load(DSO *dso, const char *filename); +static int vms_load(DSO *dso); static int vms_unload(DSO *dso); static void *vms_bind_var(DSO *dso, const char *symname); static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname); @@ -89,6 +89,7 @@ static int vms_init(DSO *dso); static int vms_finish(DSO *dso); static long vms_ctrl(DSO *dso, int cmd, long larg, void *parg); #endif +static char *vms_name_converter(DSO *dso); static DSO_METHOD dso_meth_vms = { "OpenSSL 'VMS' shared library method", @@ -102,6 +103,7 @@ static DSO_METHOD dso_meth_vms = { NULL, /* unbind_func */ #endif NULL, /* ctrl */ + vms_name_converter, NULL, /* init */ NULL /* finish */ }; @@ -129,8 +131,9 @@ DSO_METHOD *DSO_METHOD_vms(void) return(&dso_meth_vms); } -static int vms_load(DSO *dso, const char *filename) +static int vms_load(DSO *dso) { +#if 0 DSO_VMS_INTERNAL *p; const char *sp1, *sp2; /* Search result */ @@ -208,6 +211,12 @@ static int vms_load(DSO *dso, const char *filename) return(0); } return(1); +#else + /* See the comments lower down in the vms_name_converter + * "implementation" :-) */ + please_break_compilation(); + return(bother_richard); +#endif } /* Note that this doesn't actually unload the shared image, as there is no @@ -344,4 +353,26 @@ static DSO_FUNC_TYPE vms_bind_func(DSO *dso, const char *symname) return sym; } +static char *vms_name_converter(DSO *dso) + { + /* Implementation note: on VMS is it preferable to do real conversions + * here, or to actually have it performed in-line with the bind calls + * (given that VMS never actually does a load except implicitly within + * the bind functions). Another note: normally (eg. dlfcn), the + * DSO_load call will either load, put the loaded filename into the DSO + * (which marks it effectively as "read-only"), and return success - or + * it will fail. VMS needs to work out what to do - otherwise DSO_load + * will always succeed, but leave the DSO looking unloaded (because the + * loaded_filename will be NULL still) and then real loading (and + * setting of loaded_filename) will only happen during the first bind + * call (which should have error checking anyway to prevent you calling + * it on an "unloaded" DSO - thus giving VMS *serious* grief). Richard, + * what do you think? Is it worth having DSO_load() try to find and pin + * itself to a library file (and populate loaded_filename) even though + * it's unecessary to actually do a load prior to the first bind call? + * I leave it to you ... :-) */ + deliberately_break_compilation_here(); + return(1); + } + #endif /* VMS */ diff --git a/crypto/dso/dso_win32.c b/crypto/dso/dso_win32.c index 412693dda6..e7d0a2be28 100644 --- a/crypto/dso/dso_win32.c +++ b/crypto/dso/dso_win32.c @@ -71,7 +71,7 @@ DSO_METHOD *DSO_METHOD_win32(void) /* Part of the hack in "win32_load" ... */ #define DSO_MAX_TRANSLATED_SIZE 256 -static int win32_load(DSO *dso, const char *filename); +static int win32_load(DSO *dso); static int win32_unload(DSO *dso); static void *win32_bind_var(DSO *dso, const char *symname); static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname); @@ -82,6 +82,7 @@ static int win32_init(DSO *dso); static int win32_finish(DSO *dso); static long win32_ctrl(DSO *dso, int cmd, long larg, void *parg); #endif +static char *win32_name_converter(DSO *dso, const char *filename); static DSO_METHOD dso_meth_win32 = { "OpenSSL 'win32' shared library method", @@ -95,6 +96,7 @@ static DSO_METHOD dso_meth_win32 = { NULL, /* unbind_func */ #endif NULL, /* ctrl */ + win32_name_converter, NULL, /* init */ NULL /* finish */ }; @@ -109,50 +111,47 @@ DSO_METHOD *DSO_METHOD_win32(void) * LoadLibrary(), and copied. */ -static int win32_load(DSO *dso, const char *filename) +static int win32_load(DSO *dso) { - HINSTANCE h, *p; - char translated[DSO_MAX_TRANSLATED_SIZE]; - int len; - - /* NB: This is a hideous hack, but I'm not yet sure what - * to replace it with. This attempts to convert any filename, - * that looks like it has no path information, into a - * translated form, e. "blah" -> "blah.dll" ... I'm more - * comfortable putting hacks into win32 code though ;-) */ - len = strlen(filename); - if((dso->flags & DSO_FLAG_NAME_TRANSLATION) && - (len + 4 < DSO_MAX_TRANSLATED_SIZE) && - (strstr(filename, "/") == NULL) && - (strstr(filename, "\\") == NULL) && - (strstr(filename, ":") == NULL)) + HINSTANCE h = NULL, *p = NULL; + /* See applicable comments from dso_dl.c */ + char *filename = DSO_convert_filename(dso, NULL); + + if(filename == NULL) { - sprintf(translated, "%s.dll", filename); - h = LoadLibrary(translated); + DSOerr(DSO_F_WIN32_LOAD,DSO_R_NO_FILENAME); + goto err; } - else - h = LoadLibrary(filename); + h = LoadLibrary(filename); if(h == NULL) { DSOerr(DSO_F_WIN32_LOAD,DSO_R_LOAD_FAILED); - return(0); + goto err; } p = (HINSTANCE *)OPENSSL_malloc(sizeof(HINSTANCE)); if(p == NULL) { DSOerr(DSO_F_WIN32_LOAD,ERR_R_MALLOC_FAILURE); - FreeLibrary(h); - return(0); + goto err; } *p = h; if(!sk_push(dso->meth_data, (char *)p)) { DSOerr(DSO_F_WIN32_LOAD,DSO_R_STACK_ERROR); - FreeLibrary(h); - OPENSSL_free(p); - return(0); + goto err; } + /* Success */ + dso->loaded_filename = filename; return(1); +err: + /* Cleanup !*/ + if(filename != NULL) + OPENSSL_free(filename); + if(p != NULL) + OPENSSL_free(p); + if(h != NULL) + FreeLibrary(h); + return(0); } static int win32_unload(DSO *dso) @@ -246,4 +245,32 @@ static DSO_FUNC_TYPE win32_bind_func(DSO *dso, const char *symname) return((DSO_FUNC_TYPE)sym); } +static char *win32_name_converter(DSO *dso, const char *filename) + { + char *translated; + int len, transform; + + len = strlen(filename); + transform = ((strstr(filename, "/") == NULL) && + (strstr(filename, "\\") == NULL) && + (strstr(filename, ":") == NULL)); + if(transform) + /* We will convert this to "%s.dll" */ + translated = OPENSSL_malloc(len + 5); + else + /* We will simply duplicate filename */ + translated = OPENSSL_malloc(len + 1); + if(translated == NULL) + { + DSOerr(DSO_F_WIN32_NAME_CONVERTER, + DSO_R_NAME_TRANSLATION_FAILED); + return(NULL); + } + if(transform) + sprintf(translated, "%s.dll", filename); + else + sprintf(translated, "%s", filename); + return(translated); + } + #endif /* WIN32 */ -- 2.25.1