X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fdso%2Fdso_dlfcn.c;h=de88b2fd16d033da6795271e10fe255de4ee6804;hp=93545ecdafb62548d0508728af939cf421d42b7d;hb=74e3931f8438df5bcb980334e1fe4ed19f13c8ef;hpb=bc2aadad842d16d6bdc1bfa2467b60bd7825f371 diff --git a/crypto/dso/dso_dlfcn.c b/crypto/dso/dso_dlfcn.c index 93545ecdaf..de88b2fd16 100644 --- a/crypto/dso/dso_dlfcn.c +++ b/crypto/dso/dso_dlfcn.c @@ -1,4 +1,4 @@ -/* dso_dlfcn.c */ +/* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */ /* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL * project 2000. */ @@ -71,24 +71,37 @@ DSO_METHOD *DSO_METHOD_dlfcn(void) #include #endif -static int dlfcn_load(DSO *dso, char *filename); +/* Part of the hack in "dlfcn_load" ... */ +#define DSO_MAX_TRANSLATED_SIZE 256 + +static int dlfcn_load(DSO *dso); static int dlfcn_unload(DSO *dso); -static int dlfcn_bind(DSO *dso, char *symname, void **symptr); +static void *dlfcn_bind_var(DSO *dso, const char *symname); +static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname); #if 0 static int dlfcn_unbind(DSO *dso, char *symname, void *symptr); 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 char *dlfcn_merger(DSO *dso, const char *filespec1, + const char *filespec2); static DSO_METHOD dso_meth_dlfcn = { "OpenSSL 'dlfcn' shared library method", dlfcn_load, dlfcn_unload, - dlfcn_bind, + dlfcn_bind_var, + dlfcn_bind_func, /* For now, "unbind" doesn't exist */ #if 0 - NULL, /* unbind */ + NULL, /* unbind_var */ + NULL, /* unbind_func */ #endif + NULL, /* ctrl */ + dlfcn_name_converter, + dlfcn_merger, NULL, /* init */ NULL /* finish */ }; @@ -98,28 +111,64 @@ DSO_METHOD *DSO_METHOD_dlfcn(void) return(&dso_meth_dlfcn); } +/* Prior to using the dlopen() function, we should decide on the flag + * we send. There's a few different ways of doing this and it's a + * messy venn-diagram to match up which platforms support what. So + * as we don't have autoconf yet, I'm implementing a hack that could + * be hacked further relatively easily to deal with cases as we find + * them. Initially this is to cope with OpenBSD. */ +#if defined(__OpenBSD__) || defined(__NetBSD__) +# ifdef DL_LAZY +# define DLOPEN_FLAG DL_LAZY +# else +# ifdef RTLD_NOW +# define DLOPEN_FLAG RTLD_NOW +# else +# define DLOPEN_FLAG 0 +# endif +# endif +#else +# define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */ +#endif + /* For this DSO_METHOD, our meth_data STACK will contain; * (i) the handle (void*) returned from dlopen(). */ -static int dlfcn_load(DSO *dso, char *filename) +static int dlfcn_load(DSO *dso) { - void *ptr; + void *ptr = NULL; + /* See applicable comments in dso_dl.c */ + char *filename = DSO_convert_filename(dso, NULL); - ptr = dlopen(filename, RTLD_NOW); + if(filename == NULL) + { + 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); + ERR_add_error_data(4, "filename(", filename, "): ", dlerror()); + 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) { @@ -130,10 +179,7 @@ static int dlfcn_unload(DSO *dso) return(0); } if(sk_num(dso->meth_data) < 1) - { - DSOerr(DSO_F_DLFCN_UNLOAD,DSO_R_STACK_ERROR); - return(0); - } + return(1); ptr = (void *)sk_pop(dso->meth_data); if(ptr == NULL) { @@ -148,34 +194,166 @@ static int dlfcn_unload(DSO *dso) return(1); } -static int dlfcn_bind(DSO *dso, char *symname, void **symptr) +static void *dlfcn_bind_var(DSO *dso, const char *symname) { void *ptr, *sym; - if((dso == NULL) || (symptr == NULL) || (symname == NULL)) + if((dso == NULL) || (symname == NULL)) { - DSOerr(DSO_F_DLFCN_BIND,ERR_R_PASSED_NULL_PARAMETER); - return(0); + DSOerr(DSO_F_DLFCN_BIND_VAR,ERR_R_PASSED_NULL_PARAMETER); + return(NULL); } if(sk_num(dso->meth_data) < 1) { - DSOerr(DSO_F_DLFCN_BIND,DSO_R_STACK_ERROR); - return(0); + DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_STACK_ERROR); + return(NULL); } ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); if(ptr == NULL) { - DSOerr(DSO_F_DLFCN_BIND,DSO_R_NULL_HANDLE); - return(0); + DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_NULL_HANDLE); + return(NULL); } sym = dlsym(ptr, symname); if(sym == NULL) { - DSOerr(DSO_F_DLFCN_BIND,DSO_R_SYM_FAILURE); - return(0); + DSOerr(DSO_F_DLFCN_BIND_VAR,DSO_R_SYM_FAILURE); + ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); + return(NULL); } - *symptr = sym; - return(1); + return(sym); + } + +static DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname) + { + void *ptr; + DSO_FUNC_TYPE sym; + + if((dso == NULL) || (symname == NULL)) + { + DSOerr(DSO_F_DLFCN_BIND_FUNC,ERR_R_PASSED_NULL_PARAMETER); + return(NULL); + } + if(sk_num(dso->meth_data) < 1) + { + DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_STACK_ERROR); + return(NULL); + } + ptr = (void *)sk_value(dso->meth_data, sk_num(dso->meth_data) - 1); + if(ptr == NULL) + { + DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_NULL_HANDLE); + return(NULL); + } + sym = (DSO_FUNC_TYPE)dlsym(ptr, symname); + if(sym == NULL) + { + DSOerr(DSO_F_DLFCN_BIND_FUNC,DSO_R_SYM_FAILURE); + ERR_add_error_data(4, "symname(", symname, "): ", dlerror()); + return(NULL); + } + return(sym); + } + +static char *dlfcn_merger(DSO *dso, const char *filespec1, + const char *filespec2) + { + char *merged; + + if(!filespec1 && !filespec2) + { + DSOerr(DSO_F_DLFCN_MERGER, + ERR_R_PASSED_NULL_PARAMETER); + return(NULL); + } + /* If the first file specification is a rooted path, it rules. + same goes if the second file specification is missing. */ + if (!filespec2 || filespec1[0] == '/') + { + merged = OPENSSL_malloc(strlen(filespec1) + 1); + if(!merged) + { + DSOerr(DSO_F_DLFCN_MERGER, + ERR_R_MALLOC_FAILURE); + return(NULL); + } + strcpy(merged, filespec1); + } + /* If the first file specification is missing, the second one rules. */ + else if (!filespec1) + { + merged = OPENSSL_malloc(strlen(filespec2) + 1); + if(!merged) + { + DSOerr(DSO_F_DLFCN_MERGER, + ERR_R_MALLOC_FAILURE); + return(NULL); + } + strcpy(merged, filespec2); + } + else + /* This part isn't as trivial as it looks. It assumes that + the second file specification really is a directory, and + makes no checks whatsoever. Therefore, the result becomes + the concatenation of filespec2 followed by a slash followed + by filespec1. */ + { + int spec2len, len; + + spec2len = (filespec2 ? strlen(filespec2) : 0); + len = spec2len + (filespec1 ? strlen(filespec1) : 0); + + if(filespec2 && filespec2[spec2len - 1] == '/') + { + spec2len--; + len--; + } + merged = OPENSSL_malloc(len + 2); + if(!merged) + { + DSOerr(DSO_F_DLFCN_MERGER, + ERR_R_MALLOC_FAILURE); + return(NULL); + } + strcpy(merged, filespec2); + merged[spec2len] = '/'; + strcpy(&merged[spec2len + 1], filespec1); + } + return(merged); + } + +static char *dlfcn_name_converter(DSO *dso, const char *filename) + { + char *translated; + int len, rsize, transform; + + len = strlen(filename); + rsize = len + 1; + transform = (strstr(filename, "/") == NULL); + if(transform) + { + /* We will convert this to "%s.so" or "lib%s.so" */ + rsize += 3; /* The length of ".so" */ + if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) + rsize += 3; /* The length of "lib" */ + } + translated = OPENSSL_malloc(rsize); + if(translated == NULL) + { + DSOerr(DSO_F_DLFCN_NAME_CONVERTER, + DSO_R_NAME_TRANSLATION_FAILED); + return(NULL); + } + if(transform) + { + if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0) + sprintf(translated, "lib%s.so", filename); + else + sprintf(translated, "%s.so", filename); + } + else + sprintf(translated, "%s", filename); + return(translated); } #endif /* DSO_DLFCN */