This changes the behaviour of the DSO mechanism for determining an
authorGeoff Thorpe <geoff@openssl.org>
Thu, 26 Oct 2000 17:38:59 +0000 (17:38 +0000)
committerGeoff Thorpe <geoff@openssl.org>
Thu, 26 Oct 2000 17:38:59 +0000 (17:38 +0000)
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
crypto/dso/dso.h
crypto/dso/dso_dl.c
crypto/dso/dso_dlfcn.c
crypto/dso/dso_err.c
crypto/dso/dso_lib.c
crypto/dso/dso_vms.c
crypto/dso/dso_win32.c

index 6ba03c5..d0bc9a8 100644 (file)
@@ -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)).
 
index 2770e3b..add6858 100644 (file)
@@ -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
index 71f4475..6dd1b19 100644 (file)
@@ -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 */
index 07bbf37..279b37b 100644 (file)
@@ -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 */
index a9b758d..0d71346 100644 (file)
@@ -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"},
index fc3d760..0202978 100644 (file)
@@ -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);
+       }
index 948f7a1..bd28453 100644 (file)
@@ -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 */
index 412693d..e7d0a2b 100644 (file)
@@ -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 */