/* * PROGRAM: JRD Access Method * MODULE: flu.cpp * DESCRIPTION: Function Lookup Code * * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy * of the License at http://www.Inprise.com/IPL.html * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express * or implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code was created by Inprise Corporation * and its predecessors. Portions created by Inprise Corporation are * Copyright (C) Inprise Corporation. * * All Rights Reserved. * Contributor(s): ______________________________________. * * 2002.02.15 Sean Leyne - Code Cleanup, removed obsolete "EPSON" define * * 2002-02-23 Sean Leyne - Code Cleanup, removed old M88K and NCR3000 port * * 2002.10.27 Sean Leyne - Code Cleanup, removed obsolete "UNIXWARE" port * * 2002.10.28 Sean Leyne - Completed removal of obsolete "DGUX" port * 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "DecOSF" port * 2002.10.28 Sean Leyne - Code cleanup, removed obsolete "SGI" port * 2002.10.28 Sean Leyne - Completed removal of obsolete "HP700" port * * 2002.11.28 Sean Leyne - Code cleanup, removed obsolete "HM300" port * * 2003.04.12 Alex Peshkoff - Security code cleanup: * 1. Drop EXT_LIB_PATH verification * 2. Drop IB_UDF_DIR & IB_INTL_DIR support * 3. Created common for all platforms search_for_module, * using dir_list and PathUtils. Platform specific * macros defined after ISC_lookup_entrypoint() * for each platform. * */ /* $Id: flu.cpp,v 1.47 2004-08-24 05:16:40 robocop Exp $ */ #include "firebird.h" #include "../common/config/config.h" #include "../common/config/dir_list.h" #include "../jrd/os/path_utils.h" #include "../common/classes/init.h" #include "../jrd/common.h" #include "../jrd/flu.h" #include "../jrd/gdsassert.h" #include "../jrd/flu_proto.h" #include "../jrd/gds_proto.h" #include "../jrd/dls_proto.h" #include "../jrd/err_proto.h" #include "gen/iberror.h" #include /* VMS Specific Stuff */ #ifdef VMS #include #include static int condition_handler(int *, int *, int *); #endif /* HP-UX specific stuff */ #ifdef HP10 #include #include #include #include #endif #if (defined SOLARIS || defined SCO_EV || defined LINUX || defined AIX_PPC || defined SINIXZ || defined FREEBSD) #include #define DYNAMIC_SHARED_LIBRARIES #include #include #endif #ifdef DARWIN #include #include #include #endif #if defined NETBSD #include #define DYNAMIC_SHARED_LIBRARIES #include #endif static void terminate_at_space(char* psz) { while (*psz && *psz != ' ') { ++psz; } if (*psz) { *psz = '\0'; } } /* Windows NT stuff */ #ifdef WIN_NT #define NOUSER #define NOGDI #define NOCRYPT #define NOMCX #define NOIME #ifndef NOMSG #define NOMSG #endif #define NOSERVICE #endif extern "C" { static MOD FLU_modules = 0; /* External function/filter modules */ /* prototypes for private functions */ static MOD search_for_module(const TEXT*, const TEXT*, bool); MOD FLU_lookup_module(TEXT* module) { /************************************** * * F L U _ l o o k u p _ m o d u l e * ************************************** * * Functional description * Lookup external function module descriptor. * **************************************/ #ifndef WIN_NT terminate_at_space(module); #endif const USHORT length = strlen(module); for (MOD mod = FLU_modules; mod; mod = mod->mod_next) { if (mod->mod_length == length && !strcmp(mod->mod_name, module)) { return mod; } } return 0; } void FLU_unregister_module(MOD module) { /************************************** * * F L U _ u n r e g i s t e r _ m o d u l e * ************************************** * * Functional description * Unregister interest in an external function module. * Unload module if it's uninteresting. * **************************************/ /* Module is in-use by other databases.*/ if (--module->mod_use_count > 0) return; /* Unlink from list of active modules, unload it, and release memory. */ for (MOD* mod = &FLU_modules; *mod; mod = &(*mod)->mod_next) { if (*mod == module) { *mod = module->mod_next; break; } } #ifdef HP10 shl_unload(module->mod_handle); #endif #if defined(SOLARIS) || defined(LINUX) || defined(FREEBSD) || defined(NETBSD) || defined (AIX_PPC) || defined(SINIXZ) dlclose(module->mod_handle); #endif #ifdef WIN_NT FreeLibrary(module->mod_handle); #endif #ifdef DARWIN /* Make sure the fini function gets called, if there is one */ NSSymbol symbol = NSLookupSymbolInModule(module->mod_handle, "__fini"); if (symbol != NULL) { void (*fini)(void); fini = (void (*)(void)) NSAddressOfSymbol(symbol); fini(); } NSUnLinkModule (module->mod_handle, 0); #endif gds__free(module); } #ifdef VMS #define LOOKUP FPTR_INT ISC_lookup_entrypoint(TEXT* module, TEXT* name, const TEXT* ib_path_env_var, bool ShowAccessError) { /************************************** * * I S C _ l o o k u p _ e n t r y p o i n t ( V M S ) * ************************************** * * Functional description * Lookup entrypoint of function. * **************************************/ struct dsc$descriptor mod_desc, nam_desc; TEXT absolute_module[MAXPATHLEN]; FPTR_INT function = FUNCTIONS_entrypoint(module, name); if (function) return function; if (ib_path_env_var == NULL) strcpy(absolute_module, module); else if (!gds__validate_lib_path (module, ib_path_env_var, absolute_module, sizeof(absolute_module))) { return NULL; } REPLACE THIS COMPILER ERROR WITH CODE TO VERIFY THAT THE MODULE IS FOUND EITHER IN $INTERBASE:UDF, or $INTERBASE:intl, OR IN ONE OF THE DIRECTORIES NAMED IN EXTERNAL_FUNCTION_DIRECTORY LINES IN ISC_CONFIG.for (p = absolute_module; *p && *p != ' '; p++); ISC_make_desc(absolute_module, &mod_desc, p - absolute_module); const TEXT* p = name; while (*p && *p != ' ') { ++p; } ISC_make_desc(name, &nam_desc, p - name); VAXC$ESTABLISH(condition_handler); if (!(lib$find_image_symbol(&mod_desc, &nam_desc, &function, NULL) & 1)) return NULL; return function; } #endif /* The commented #if which immediately follows has been replaced. The OLD_AIX and OLD_AIX_PPC #if has been added to disable the code segment for current AIX builds. */ /* #if (defined AIX || defined AIX_PPC) */ #if (defined OLD_AIX || defined OLD_AIX_PPC) #define LOOKUP FPTR_INT ISC_lookup_entrypoint(TEXT* module, TEXT* name, const TEXT* ib_path_env_var, bool ShowAccessError) { /************************************** * * I S C _ l o o k u p _ e n t r y p o i n t ( A I X ) * ************************************** * * Functional description * Lookup entrypoint of function. * **************************************/ TEXT absolute_module[MAXPATHLEN]; FPTR_INT function = FUNCTIONS_entrypoint(module, name); if (function) { return function; } terminate_at_space(module); if (ib_path_env_var == NULL) { strcpy(absolute_module, module); } else { if (!gds__validate_lib_path(module, ib_path_env_var, absolute_module, sizeof(absolute_module))) { return NULL; } } REPLACE THIS COMPILER ERROR WITH CODE TO VERIFY THAT THE MODULE IS FOUND EITHER IN $INTERBASE / UDF, OR $INTERBASE / intl, OR IN ONE OF THE DIRECTORIES NAMED IN EXTERNAL_FUNCTION_DIRECTORY LINES IN ISC_CONFIG.function = load(absolute_module, 0, NULL); return function; } #endif #ifdef HP10 #define LOOKUP FPTR_INT ISC_lookup_entrypoint(TEXT* module, TEXT* name, const TEXT* ib_path_env_var, bool ShowAccessError) { /************************************** * * I S C _ l o o k u p _ e n t r y p o i n t ( H P 9 0 0 0 s 7 0 0 ) * ************************************** * * Functional description * Lookup entrypoint of function. * **************************************/ FPTR_INT function = FUNCTIONS_entrypoint(module, name); if (function) { return function; } terminate_at_space(module); terminate_at_space(name); if (!*module || !*name) { return NULL; } // Check if external function module has already been loaded MOD mod = FLU_lookup_module(module); if (!mod) { TEXT absolute_module[MAXPATHLEN]; strcpy(absolute_module, module); const USHORT length = strlen(absolute_module); /* call search_for_module with the supplied name, and if unsuccessful, then with .sl . */ mod = search_for_module(absolute_module, name, false); if (!mod) { strcat(absolute_module, ".sl"); mod = search_for_module(absolute_module, name, ShowAccessError); } if (!mod) { return NULL; } fb_assert(mod->mod_handle); /* fb_assert that we found the module */ mod->mod_use_count = 0; mod->mod_length = length; strcpy(mod->mod_name, module); mod->mod_next = FLU_modules; FLU_modules = mod; } ++mod->mod_use_count; if (shl_findsym(&mod->mod_handle, name, TYPE_PROCEDURE, &function)) return NULL; return function; } #define REQUIRED_MODULE_ACCESS (R_OK | X_OK) #define OPEN_HANDLE(name) shl_load(name.c_str(), BIND_DEFERRED, 0) #endif #ifdef DYNAMIC_SHARED_LIBRARIES #define LOOKUP FPTR_INT ISC_lookup_entrypoint(TEXT* module, TEXT* name, const TEXT* ib_path_env_var, bool ShowAccessError) { /************************************** * * I S C _ l o o k u p _ e n t r y p o i n t ( SVR4 including SOLARIS ) * ************************************** * * Functional description * Lookup entrypoint of function. * **************************************/ FPTR_INT function = FUNCTIONS_entrypoint(module, name); if (function) { return function; } #ifdef NON_DL_COMPATIBLE return NULL; #else terminate_at_space(module); terminate_at_space(name); if (!*module || !*name) { return NULL; } // Check if external function module has already been loaded MOD mod = FLU_lookup_module(module); if (!mod) { TEXT absolute_module[MAXPATHLEN]; strcpy(absolute_module, module); const USHORT length = strlen(absolute_module); /* call search_for_module with the supplied name, and if unsuccessful, then with .so . */ mod = search_for_module(absolute_module, name, false); if (!mod) { strcat(absolute_module, ".so"); mod = search_for_module(absolute_module, name, false); } if (!mod) { // Start looking for "libxxxx.so" module names Firebird::PathName moduleName = "lib"; moduleName += (const char*) absolute_module; mod = search_for_module((TEXT*) moduleName.c_str(), name, ShowAccessError); } if (!mod) { return NULL; } fb_assert(mod->mod_handle); /* fb_assert that we found the module */ mod->mod_use_count = 0; mod->mod_length = length; strcpy(mod->mod_name, module); mod->mod_next = FLU_modules; FLU_modules = mod; } ++mod->mod_use_count; return (FPTR_INT) dlsym(mod->mod_handle, name); #endif /* NON_DL_COMPATIBLE */ } #define REQUIRED_MODULE_ACCESS (R_OK) #define OPEN_HANDLE(name) dlopen(name.c_str(), RTLD_LAZY) #endif #ifdef WIN_NT #define LOOKUP FPTR_INT ISC_lookup_entrypoint(TEXT* module, TEXT* name, const TEXT* ib_path_env_var, bool ShowAccessError) { /************************************** * * I S C _ l o o k u p _ e n t r y p o i n t ( W I N _ N T ) * ************************************** * * Functional description * Lookup entrypoint of function. * If ib_path_env_var is defined, make sure * that the module is in the path defined * by that environment variable. * **************************************/ FPTR_INT function = FUNCTIONS_entrypoint(module, name); if (function) { return function; } terminate_at_space(name); // Check if external function module has already been loaded MOD mod = FLU_lookup_module(module); if (!mod) { TEXT absolute_module[MAXPATHLEN]; // for _access() strcpy(absolute_module, module); const USHORT length = strlen(absolute_module); /* call search_for_module with the supplied name, and if unsuccessful, then with .DLL (if the name did not have a trailing "."). */ mod = search_for_module(absolute_module, name, false); if (!mod) { if ((absolute_module[length - 1] != '.') && stricmp(absolute_module + length - 4, ".DLL")) { strcat(absolute_module, ".DLL"); mod = search_for_module(absolute_module, name, ShowAccessError); } } if (!mod) { return NULL; } fb_assert(mod->mod_handle); /* fb_assert that we found the module */ mod->mod_use_count = 0; mod->mod_length = length; strcpy(mod->mod_name, module); mod->mod_next = FLU_modules; FLU_modules = mod; } ++mod->mod_use_count; // The Borland compiler prefixes an '_' for functions compiled // with the __cdecl calling convention. // TMN: Doesn't all_ ompilers do that? function = (FPTR_INT) GetProcAddress(mod->mod_handle, name); if (!function) { TEXT buffer[128]; buffer[0] = '_'; strcpy(&buffer[1], name); function = (FPTR_INT) GetProcAddress(mod->mod_handle, buffer); } return function; } #define REQUIRED_MODULE_ACCESS 4 #define OPEN_HANDLE(name) AdjustAndLoad(name) HMOD AdjustAndLoad(Firebird::PathName name) { /************************************** * * A d j u s t A n d L o a d ( W I N _ N T ) * ************************************** * * Functional description * Before calling LoadLibrary(), add dot to the end of module * name, to provide stable behaviour (implicit .DLL suffix). * **************************************/ Firebird::PathName suffix = name.length() > 4 ? name.substr(name.length() - 4, 4) : Firebird::PathName(""); if (suffix != ".dll") { if (name[name.length() - 1] != '.') { name += '.'; } } return LoadLibrary(name.c_str()); } #endif #ifdef DARWIN #define LOOKUP NSModule ISC_link_with_module (TEXT*); FPTR_INT ISC_lookup_entrypoint ( TEXT* module, TEXT* name, const TEXT* ib_path_env_var, bool ShowAccessError) { /************************************** * * I S C _ l o o k u p _ e n t r y p o i n t ( D A R W I N ) * ************************************** * * Functional description * Lookup entrypoint of function. * **************************************/ int lastSpace, i; TEXT absolute_module[MAXPATHLEN]; FPTR_INT function = FUNCTIONS_entrypoint (module, name); if (function) return function; /* Remove TRAILING spaces from path names; spaces within the path are valid */ for (i = strlen(module) - 1, lastSpace = 0; i >= 0; i--) if (module[i] == ' ') lastSpace = i; else break; if (module[lastSpace] == ' ') module[lastSpace] = 0; for (i = strlen(name) - 1, lastSpace = 0; i >= 0; i--) if (name[i] == ' ') lastSpace = i; else break; if (name[lastSpace] == ' ') name[lastSpace] = 0; if (!*module || !*name) return NULL; /*printf("names truncated: %s, function %s.\n", module, name);*/ /* Check if external function module has already been loaded */ MOD mod = FLU_lookup_module (module); if (!mod) { strcpy (absolute_module, module); const USHORT length = strlen (absolute_module); /* call search_for_module with the supplied name, and if unsuccessful, then with .so . */ mod = search_for_module (absolute_module, name, false); if (!mod) { strcat (absolute_module, ".so"); mod = search_for_module (absolute_module, name, ShowAccessError); } if (!mod) { /*printf("Couldn't find module: %s\n", absolute_module);*/ return NULL; } fb_assert (mod->mod_handle); /* fb_assert that we found the module */ mod->mod_use_count = 0; mod->mod_length = length; strcpy (mod->mod_name, module); mod->mod_next = FLU_modules; FLU_modules = mod; } /* Look for the symbol and return a pointer to the function if found */ mod->mod_use_count++; NSSymbol symbol = NSLookupSymbolInModule(mod->mod_handle, name); if (symbol == NULL) { /*printf("Failed to find function: %s in module %s, trying _%s\n", name, module, name);*/ strcpy(absolute_module, "_"); strncat(absolute_module, name, sizeof(absolute_module) - 2); symbol = NSLookupSymbolInModule(mod->mod_handle, absolute_module); if (symbol == NULL) { /*printf("Failed to find symbol %s. Giving up.\n", absolute_module);*/ return NULL; } } return (FPTR_INT) NSAddressOfSymbol(symbol); } #define REQUIRED_MODULE_ACCESS (R_OK) #define OPEN_HANDLE(name) ISC_link_with_module(name.c_str()) NSModule ISC_link_with_module ( TEXT *fileName) { /************************************** * * I S C _ l i n k _ w i t h _ m o d u l e ( D A R W I N ) * ************************************** * * Functional description * Given the file system path to a module, load it and link it into * our address space. Assumes all security checks have been * performed. * **************************************/ NSObjectFileImage image; /* Create an object file image from the given path */ const NSObjectFileImageReturnCode retVal = NSCreateObjectFileImageFromFile(fileName, &image); if (retVal != NSObjectFileImageSuccess) { switch (retVal) { case NSObjectFileImageFailure: /*printf("object file setup failure");*/ return NULL; case NSObjectFileImageInappropriateFile: /*printf("not a Mach-O MH_BUNDLE file type");*/ return NULL; case NSObjectFileImageArch: /*printf("no object for this architecture");*/ return NULL; case NSObjectFileImageFormat: /*printf("bad object file format");*/ return NULL; case NSObjectFileImageAccess: /*printf("can't read object file");*/ return NULL; default: /*printf("unknown error from NSCreateObjectFileImageFromFile()");*/ return NULL; } } /* link the image */ NSModule mod_handle = NSLinkModule(image, fileName, NSLINKMODULE_OPTION_PRIVATE); NSDestroyObjectFileImage(image) ; if (mod_handle == NULL) { /*printf("NSLinkModule() failed for dlopen()");*/ return NULL; } NSSymbol initSym = NSLookupSymbolInModule(mod_handle, "__init"); if (initSym != NULL) { void (*init)(void); init = ( void (*)(void)) NSAddressOfSymbol(initSym); init(); } return mod_handle; } #endif #ifndef LOOKUP FPTR_INT ISC_lookup_entrypoint(TEXT* module, TEXT* name, const TEXT* ib_path_env_var, bool ShowAccessError) { /************************************** * * I S C _ l o o k u p _ e n t r y p o i n t ( d e f a u l t ) * ************************************** * * Functional description * Lookup entrypoint of function. * **************************************/ FPTR_INT function = FUNCTIONS_entrypoint(module, name); return function; } #endif #ifdef VMS static int condition_handler(int *sig, int *mech, int *enbl) { /************************************** * * c o n d i t i o n _ h a n d l e r * ************************************** * * Functional description * Ignore signal from "lib$find_symbol". * **************************************/ return SS$_CONTINUE; } #endif namespace { class UdfDirectoryList : public Firebird::DirectoryList { private: const Firebird::PathName getConfigString(void) const { return Firebird::PathName(Config::getUdfAccess()); } public: UdfDirectoryList(MemoryPool& p) : DirectoryList(p) { initialize(); } }; Firebird::InitInstance iUdfDirectoryList; } // The var "name" is not used here. static MOD search_for_module(const TEXT* module_name, const TEXT* name, bool ShowAccessError) { /************************************** * * s e a r c h _ f o r _ m o d u l e * ************************************** * * Functional description * Look for a module (as named in a 'DECLARE EXTERNAL FUNCTION' * statement. * **************************************/ #ifndef REQUIRED_MODULE_ACCESS return NULL; #else Firebird::PathName path, relative; Firebird::PathName absolute_module = module_name; // Search for module name in UdfAccess restricted paths list PathUtils::splitLastComponent(path, relative, absolute_module); if (path.length() == 0 && PathUtils::isRelative(absolute_module)) { relative = absolute_module; iUdfDirectoryList().expandFileName(absolute_module, relative, REQUIRED_MODULE_ACCESS); } // The module name, including directory path, // must satisfy UdfAccess entry in config file. if (!iUdfDirectoryList().isPathInList(absolute_module)) { if (ShowAccessError) { ERR_post(isc_conf_access_denied, isc_arg_string, "UDF library", isc_arg_string, ERR_cstring(absolute_module.c_str()), isc_arg_end); } return NULL; } MOD module = (MOD) gds__alloc(sizeof(mod) + absolute_module.length()); if (!module) { return NULL; } if (!(module->mod_handle = OPEN_HANDLE(absolute_module))) { /* * Temporarily commented - what to do with dlerror() on NT ? #ifdef DEV_BUILD gds__log("%s: %s\n", module_name, dlerror()); #endif */ gds__free(module); return NULL; } return module; #endif //REQUIRED_MODULE_ACCESS } } // extern "C"