aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crypto/dso/README24
-rw-r--r--crypto/dso/dso.h98
-rw-r--r--crypto/dso/dso_dl.c73
-rw-r--r--crypto/dso/dso_dlfcn.c72
-rw-r--r--crypto/dso/dso_err.c12
-rw-r--r--crypto/dso/dso_lib.c150
-rw-r--r--crypto/dso/dso_vms.c35
-rw-r--r--crypto/dso/dso_win32.c81
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. <grimace> */
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 */