tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

genload.c (5358B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /*
      6 * This file is meant to be included by other .c files.
      7 * This file takes a "parameter", the scope which includes this
      8 * code shall declare this variable:
      9 *   const char *NameOfThisSharedLib;
     10 *
     11 * NameOfThisSharedLib:
     12 *   The file name of the shared library that shall be used as the
     13 *   "reference library". The loader will attempt to load the requested
     14 *   library from the same directory as the reference library.
     15 */
     16 
     17 #ifdef XP_UNIX
     18 #include <unistd.h>
     19 #define BL_MAXSYMLINKS 20
     20 
     21 /*
     22 * If 'link' is a symbolic link, this function follows the symbolic links
     23 * and returns the pathname of the ultimate source of the symbolic links.
     24 * If 'link' is not a symbolic link, this function returns NULL.
     25 * The caller should call PR_Free to free the string returned by this
     26 * function.
     27 */
     28 static char*
     29 loader_GetOriginalPathname(const char* link)
     30 {
     31 #ifdef __GLIBC__
     32    char* tmp = realpath(link, NULL);
     33    char* resolved;
     34    if (!tmp)
     35        return NULL;
     36    resolved = PR_Malloc(strlen(tmp) + 1);
     37    strcpy(resolved, tmp); /* This is necessary because PR_Free might not be using free() */
     38    free(tmp);
     39    return resolved;
     40 #else
     41    char* resolved = NULL;
     42    char* input = NULL;
     43    PRUint32 iterations = 0;
     44    PRInt32 len = 0, retlen = 0;
     45    if (!link) {
     46        PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
     47        return NULL;
     48    }
     49    len = PR_MAX(1024, strlen(link) + 1);
     50    resolved = PR_Malloc(len);
     51    input = PR_Malloc(len);
     52    if (!resolved || !input) {
     53        if (resolved) {
     54            PR_Free(resolved);
     55        }
     56        if (input) {
     57            PR_Free(input);
     58        }
     59        return NULL;
     60    }
     61    strcpy(input, link);
     62    while ((iterations++ < BL_MAXSYMLINKS) &&
     63           ((retlen = readlink(input, resolved, len - 1)) > 0)) {
     64        char* tmp = input;
     65        resolved[retlen] = '\0'; /* NULL termination */
     66        input = resolved;
     67        resolved = tmp;
     68    }
     69    PR_Free(resolved);
     70    if (iterations == 1 && retlen < 0) {
     71        PR_Free(input);
     72        input = NULL;
     73    }
     74    return input;
     75 #endif
     76 }
     77 #endif /* XP_UNIX */
     78 
     79 /*
     80 * Load the library with the file name 'name' residing in the same
     81 * directory as the reference library, whose pathname is 'referencePath'.
     82 */
     83 static PRLibrary*
     84 loader_LoadLibInReferenceDir(const char* referencePath, const char* name)
     85 {
     86    PRLibrary* dlh = NULL;
     87    char* fullName = NULL;
     88    char* c;
     89    PRLibSpec libSpec;
     90 
     91    /* Remove the trailing filename from referencePath and add the new one */
     92    c = strrchr(referencePath, PR_GetDirectorySeparator());
     93    if (c) {
     94        size_t referencePathSize = 1 + c - referencePath;
     95        fullName = (char*)PORT_Alloc(strlen(name) + referencePathSize + 1);
     96        if (fullName) {
     97            memcpy(fullName, referencePath, referencePathSize);
     98            strcpy(fullName + referencePathSize, name);
     99 #ifdef DEBUG_LOADER
    100            PR_fprintf(PR_STDOUT, "\nAttempting to load fully-qualified %s\n",
    101                       fullName);
    102 #endif
    103            libSpec.type = PR_LibSpec_Pathname;
    104            libSpec.value.pathname = fullName;
    105            dlh = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
    106            PORT_Free(fullName);
    107        }
    108    }
    109    return dlh;
    110 }
    111 
    112 /*
    113 * We use PR_GetLibraryFilePathname to get the pathname of the loaded
    114 * shared lib that contains this function, and then do a PR_LoadLibrary
    115 * with an absolute pathname for the softoken shared library.
    116 */
    117 
    118 static PRLibrary*
    119 loader_LoadLibrary(const char* nameToLoad)
    120 {
    121    PRLibrary* lib = NULL;
    122    char* fullPath = NULL;
    123    PRLibSpec libSpec;
    124 
    125    /* Get the pathname for nameOfAlreadyLoadedLib, i.e. /usr/lib/libnss3.so
    126     * PR_GetLibraryFilePathname works with either the base library name or a
    127     * function pointer, depending on the platform. We can't query an exported
    128     * symbol such as NSC_GetFunctionList, because on some platforms we can't
    129     * find symbols in loaded implicit dependencies.
    130     * But we can just get the address of this function !
    131     */
    132    fullPath = PR_GetLibraryFilePathname(NameOfThisSharedLib,
    133                                         (PRFuncPtr)&loader_LoadLibrary);
    134 
    135    if (fullPath) {
    136        lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad);
    137 #ifdef XP_UNIX
    138        if (!lib) {
    139            /*
    140             * If fullPath is a symbolic link, resolve the symbolic
    141             * link and try again.
    142             */
    143            char* originalfullPath = loader_GetOriginalPathname(fullPath);
    144            if (originalfullPath) {
    145                PR_Free(fullPath);
    146                fullPath = originalfullPath;
    147                lib = loader_LoadLibInReferenceDir(fullPath, nameToLoad);
    148            }
    149        }
    150 #endif
    151        PR_Free(fullPath);
    152    }
    153    if (!lib) {
    154 #ifdef DEBUG_LOADER
    155        PR_fprintf(PR_STDOUT, "\nAttempting to load %s\n", nameToLoad);
    156 #endif
    157        libSpec.type = PR_LibSpec_Pathname;
    158        libSpec.value.pathname = nameToLoad;
    159        lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL);
    160    }
    161    if (NULL == lib) {
    162 #ifdef DEBUG_LOADER
    163        PR_fprintf(PR_STDOUT, "\nLoading failed : %s.\n", nameToLoad);
    164 #endif
    165    }
    166    return lib;
    167 }