tor-browser

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

install.c (27156B)


      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 #include "install.h"
      6 #include "install-ds.h"
      7 #include <prerror.h>
      8 #include <prlock.h>
      9 #include <prio.h>
     10 #include <prmem.h>
     11 #include <prprf.h>
     12 #include <prsystem.h>
     13 #include <prproces.h>
     14 
     15 #ifdef XP_UNIX
     16 /* for chmod */
     17 #include <sys/types.h>
     18 #include <sys/stat.h>
     19 #endif
     20 
     21 /*extern "C" {*/
     22 #include <jar.h>
     23 /*}*/
     24 
     25 extern /*"C"*/
     26    int
     27    Pk11Install_AddNewModule(char *moduleName, char *dllPath,
     28                             unsigned long defaultMechanismFlags,
     29                             unsigned long cipherEnableFlags);
     30 extern /*"C"*/
     31    short
     32    Pk11Install_UserVerifyJar(JAR *jar, PRFileDesc *out,
     33                              PRBool query);
     34 extern /*"C"*/
     35    const char *
     36    mySECU_ErrorString(PRErrorCode errnum);
     37 extern int Pk11Install_yyparse();
     38 
     39 #define INSTALL_METAINFO_TAG "Pkcs11_install_script"
     40 #define SCRIPT_TEMP_FILE "pkcs11inst.tmp"
     41 #define ROOT_MARKER "%root%"
     42 #define TEMP_MARKER "%temp%"
     43 #define PRINTF_ROOT_MARKER "%%root%%"
     44 #define TEMPORARY_DIRECTORY_NAME "pk11inst.dir"
     45 #define JAR_BASE_END (JAR_BASE + 100)
     46 
     47 static PRLock *errorHandlerLock = NULL;
     48 static Pk11Install_ErrorHandler errorHandler = NULL;
     49 static char *PR_Strdup(const char *str);
     50 static int rm_dash_r(char *path);
     51 static int make_dirs(char *path, int file_perms);
     52 static int dir_perms(int perms);
     53 
     54 static Pk11Install_Error DoInstall(JAR *jar, const char *installDir,
     55                                   const char *tempDir, Pk11Install_Platform *platform,
     56                                   PRFileDesc *feedback, PRBool noverify);
     57 
     58 static char *errorString[] = {
     59    "Operation was successful",        /* PK11_INSTALL_NO_ERROR */
     60    "Directory \"%s\" does not exist", /* PK11_INSTALL_DIR_DOESNT_EXIST */
     61    "File \"%s\" does not exist",      /* PK11_INSTALL_FILE_DOESNT_EXIST */
     62    "File \"%s\" is not readable",     /* PK11_INSTALL_FILE_NOT_READABLE */
     63    "%s",                              /* PK11_INSTALL_ERROR_STRING */
     64    "Error in JAR file %s: %s",        /* PK11_INSTALL_JAR_ERROR */
     65    "No Pkcs11_install_script specified in JAR metainfo file",
     66    /* PK11_INSTALL_NO_INSTALLER_SCRIPT */
     67    "Could not delete temporary file \"%s\"",
     68    /*PK11_INSTALL_DELETE_TEMP_FILE */
     69    "Could not open temporary file \"%s\"", /*PK11_INSTALL_OPEN_SCRIPT_FILE*/
     70    "%s: %s",                               /* PK11_INSTALL_SCRIPT_PARSE */
     71    "Error in script: %s",
     72    "Unable to obtain system platform information",
     73    "Installer script has no information about the current platform (%s)",
     74    "Relative directory \"%s\" does not contain " PRINTF_ROOT_MARKER,
     75    "Module File \"%s\" not found",
     76    "Error occurred installing module \"%s\" into database",
     77    "Error extracting \"%s\" from JAR file: %s",
     78    "Directory \"%s\" is not writeable",
     79    "Could not create directory \"%s\"",
     80    "Could not remove directory \"%s\"",
     81    "Unable to execute \"%s\"",
     82    "Unable to wait for process \"%s\"",
     83    "\"%s\" returned error code %d",
     84    "User aborted operation",
     85    "Unspecified error"
     86 };
     87 
     88 enum {
     89    INSTALLED_FILE_MSG = 0,
     90    INSTALLED_MODULE_MSG,
     91    INSTALLER_SCRIPT_NAME,
     92    MY_PLATFORM_IS,
     93    USING_PLATFORM,
     94    PARSED_INSTALL_SCRIPT,
     95    EXEC_FILE_MSG,
     96    EXEC_SUCCESS,
     97    INSTALLATION_COMPLETE_MSG,
     98    USER_ABORT
     99 };
    100 
    101 static char *msgStrings[] = {
    102    "Installed file %s to %s\n",
    103    "Installed module \"%s\" into module database\n",
    104    "Using installer script \"%s\"\n",
    105    "Current platform is %s\n",
    106    "Using installation parameters for platform %s\n",
    107    "Successfully parsed installation script\n",
    108    "Executing \"%s\"...\n",
    109    "\"%s\" executed successfully\n",
    110    "\nInstallation completed successfully\n",
    111    "\nAborting...\n"
    112 };
    113 
    114 /**************************************************************************
    115 * S t r i n g N o d e
    116 */
    117 typedef struct StringNode_str {
    118    char *str;
    119    struct StringNode_str *next;
    120 } StringNode;
    121 
    122 StringNode *
    123 StringNode_new()
    124 {
    125    StringNode *new_this;
    126    new_this = (StringNode *)PR_Malloc(sizeof(StringNode));
    127    PORT_Assert(new_this != NULL);
    128    new_this->str = NULL;
    129    new_this->next = NULL;
    130    return new_this;
    131 }
    132 
    133 void
    134 StringNode_delete(StringNode *s)
    135 {
    136    if (s->str) {
    137        PR_Free(s->str);
    138        s->str = NULL;
    139    }
    140 }
    141 
    142 /*************************************************************************
    143 * S t r i n g L i s t
    144 */
    145 typedef struct StringList_str {
    146    StringNode *head;
    147    StringNode *tail;
    148 } StringList;
    149 
    150 void
    151 StringList_new(StringList *list)
    152 {
    153    list->head = NULL;
    154    list->tail = NULL;
    155 }
    156 
    157 void
    158 StringList_delete(StringList *list)
    159 {
    160    StringNode *tmp;
    161    while (list->head) {
    162        tmp = list->head;
    163        list->head = list->head->next;
    164        StringNode_delete(tmp);
    165    }
    166 }
    167 
    168 void
    169 StringList_Append(StringList *list, char *str)
    170 {
    171    if (!str) {
    172        return;
    173    }
    174 
    175    if (!list->tail) {
    176        /* This is the first element */
    177        list->head = list->tail = StringNode_new();
    178    } else {
    179        list->tail->next = StringNode_new();
    180        list->tail = list->tail->next;
    181    }
    182 
    183    list->tail->str = PR_Strdup(str);
    184    list->tail->next = NULL; /* just to be sure */
    185 }
    186 
    187 /**************************************************************************
    188 *
    189 * P k 1 1 I n s t a l l _ S e t E r r o r H a n d l e r
    190 *
    191 * Sets the error handler to be used by the library.  Returns the current
    192 * error handler function.
    193 */
    194 Pk11Install_ErrorHandler
    195 Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler)
    196 {
    197    Pk11Install_ErrorHandler old;
    198 
    199    if (!errorHandlerLock) {
    200        errorHandlerLock = PR_NewLock();
    201    }
    202 
    203    PR_Lock(errorHandlerLock);
    204 
    205    old = errorHandler;
    206    errorHandler = handler;
    207 
    208    PR_Unlock(errorHandlerLock);
    209 
    210    return old;
    211 }
    212 
    213 /**************************************************************************
    214 *
    215 * P k 1 1 I n s t a l l _ I n i t
    216 *
    217 * Does initialization that otherwise would be done on the fly.  Only
    218 * needs to be called by multithreaded apps, before they make any calls
    219 * to this library.
    220 */
    221 void
    222 Pk11Install_Init()
    223 {
    224    if (!errorHandlerLock) {
    225        errorHandlerLock = PR_NewLock();
    226    }
    227 }
    228 
    229 /**************************************************************************
    230 *
    231 * P k 1 1 I n s t a l l _ R e l e a s e
    232 *
    233 * Releases static data structures used by the library.  Don't use the
    234 * library after calling this, unless you call Pk11Install_Init()
    235 * first.  This function doesn't have to be called at all unless you're
    236 * really anal about freeing memory before your program exits.
    237 */
    238 void
    239 Pk11Install_Release()
    240 {
    241    if (errorHandlerLock) {
    242        PR_Free(errorHandlerLock);
    243        errorHandlerLock = NULL;
    244    }
    245 }
    246 
    247 /*************************************************************************
    248 *
    249 * e r r o r
    250 *
    251 * Takes an error code and its arguments, creates the error string,
    252 * and sends the string to the handler function if it exists.
    253 */
    254 
    255 #include <stdarg.h>
    256 
    257 static void
    258 error(PRErrorCode errcode, ...)
    259 {
    260 
    261    va_list ap;
    262    char *errstr;
    263    Pk11Install_ErrorHandler handler;
    264 
    265    if (!errorHandlerLock) {
    266        errorHandlerLock = PR_NewLock();
    267    }
    268 
    269    PR_Lock(errorHandlerLock);
    270 
    271    handler = errorHandler;
    272 
    273    PR_Unlock(errorHandlerLock);
    274 
    275    if (handler) {
    276        va_start(ap, errcode);
    277        errstr = PR_vsmprintf(errorString[errcode], ap);
    278        handler(errstr);
    279        PR_smprintf_free(errstr);
    280        va_end(ap);
    281    }
    282 }
    283 
    284 /*************************************************************************
    285 *
    286 * j a r _ c a l l b a c k
    287 */
    288 static int
    289 jar_callback(int status, JAR *foo, const char *bar, char *pathname,
    290             char *errortext)
    291 {
    292    char *string;
    293 
    294    string = PR_smprintf("JAR error %d: %s in file %s\n", status, errortext,
    295                         pathname);
    296    error(PK11_INSTALL_ERROR_STRING, string);
    297    PR_smprintf_free(string);
    298    return 0;
    299 }
    300 
    301 /*************************************************************************
    302 *
    303 * P k 1 1 I n s t a l l _ D o I n s t a l l
    304 *
    305 * jarFile is the path of a JAR in the PKCS #11 module JAR format.
    306 * installDir is the directory relative to which files will be
    307 *   installed.
    308 */
    309 Pk11Install_Error
    310 Pk11Install_DoInstall(char *jarFile, const char *installDir,
    311                      const char *tempDir, PRFileDesc *feedback, short force, PRBool noverify)
    312 {
    313    JAR *jar;
    314    char *installer;
    315    unsigned long installer_len;
    316    int status;
    317    Pk11Install_Error ret;
    318    PRBool made_temp_file;
    319    Pk11Install_Info installInfo;
    320    Pk11Install_Platform *platform;
    321    char *errMsg;
    322    char sysname[SYS_INFO_BUFFER_LENGTH], release[SYS_INFO_BUFFER_LENGTH],
    323        arch[SYS_INFO_BUFFER_LENGTH];
    324    char *myPlatform;
    325 
    326    jar = NULL;
    327    ret = PK11_INSTALL_UNSPECIFIED;
    328    made_temp_file = PR_FALSE;
    329    errMsg = NULL;
    330    Pk11Install_Info_init(&installInfo);
    331 
    332    /*
    333    printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n",
    334        jarFile, installDir, tempDir);
    335    */
    336 
    337    /*
    338     * Check out jarFile and installDir for validity
    339     */
    340    if (PR_Access(installDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
    341        error(PK11_INSTALL_DIR_DOESNT_EXIST, installDir);
    342        return PK11_INSTALL_DIR_DOESNT_EXIST;
    343    }
    344    if (!tempDir) {
    345        tempDir = ".";
    346    }
    347    if (PR_Access(tempDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
    348        error(PK11_INSTALL_DIR_DOESNT_EXIST, tempDir);
    349        return PK11_INSTALL_DIR_DOESNT_EXIST;
    350    }
    351    if (PR_Access(tempDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
    352        error(PK11_INSTALL_DIR_NOT_WRITEABLE, tempDir);
    353        return PK11_INSTALL_DIR_NOT_WRITEABLE;
    354    }
    355    if ((PR_Access(jarFile, PR_ACCESS_EXISTS) != PR_SUCCESS)) {
    356        error(PK11_INSTALL_FILE_DOESNT_EXIST, jarFile);
    357        return PK11_INSTALL_FILE_DOESNT_EXIST;
    358    }
    359    if (PR_Access(jarFile, PR_ACCESS_READ_OK) != PR_SUCCESS) {
    360        error(PK11_INSTALL_FILE_NOT_READABLE, jarFile);
    361        return PK11_INSTALL_FILE_NOT_READABLE;
    362    }
    363 
    364    /*
    365     * Extract the JAR file
    366     */
    367    jar = JAR_new();
    368    JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback);
    369 
    370    if (noverify) {
    371        status = JAR_pass_archive_unverified(jar, jarArchGuess, jarFile, "url");
    372    } else {
    373        status = JAR_pass_archive(jar, jarArchGuess, jarFile, "url");
    374    }
    375    if ((status < 0) || (jar->valid < 0)) {
    376        if (status >= JAR_BASE && status <= JAR_BASE_END) {
    377            error(PK11_INSTALL_JAR_ERROR, jarFile, JAR_get_error(status));
    378        } else {
    379            error(PK11_INSTALL_JAR_ERROR, jarFile,
    380                  mySECU_ErrorString(PORT_GetError()));
    381        }
    382        ret = PK11_INSTALL_JAR_ERROR;
    383        goto loser;
    384    }
    385    /*printf("passed the archive\n");*/
    386 
    387    /*
    388     * Show the user security information, allow them to abort or continue
    389     */
    390    if (Pk11Install_UserVerifyJar(jar, PR_STDOUT,
    391                                  force ? PR_FALSE
    392                                        : PR_TRUE) &&
    393        !force) {
    394        if (feedback) {
    395            PR_fprintf(feedback, msgStrings[USER_ABORT]);
    396        }
    397        ret = PK11_INSTALL_USER_ABORT;
    398        goto loser;
    399    }
    400 
    401    /*
    402     * Get the name of the installation file
    403     */
    404    if (JAR_get_metainfo(jar, NULL, INSTALL_METAINFO_TAG, (void **)&installer,
    405                         (unsigned long *)&installer_len)) {
    406        error(PK11_INSTALL_NO_INSTALLER_SCRIPT);
    407        ret = PK11_INSTALL_NO_INSTALLER_SCRIPT;
    408        goto loser;
    409    }
    410    if (feedback) {
    411        PR_fprintf(feedback, msgStrings[INSTALLER_SCRIPT_NAME], installer);
    412    }
    413 
    414    /*
    415     * Extract the installation file
    416     */
    417    if (PR_Access(SCRIPT_TEMP_FILE, PR_ACCESS_EXISTS) == PR_SUCCESS) {
    418        if (PR_Delete(SCRIPT_TEMP_FILE) != PR_SUCCESS) {
    419            error(PK11_INSTALL_DELETE_TEMP_FILE, SCRIPT_TEMP_FILE);
    420            ret = PK11_INSTALL_DELETE_TEMP_FILE;
    421            goto loser;
    422        }
    423    }
    424    if (noverify) {
    425        status = JAR_extract(jar, installer, SCRIPT_TEMP_FILE);
    426    } else {
    427        status = JAR_verified_extract(jar, installer, SCRIPT_TEMP_FILE);
    428    }
    429    if (status) {
    430        if (status >= JAR_BASE && status <= JAR_BASE_END) {
    431            error(PK11_INSTALL_JAR_EXTRACT, installer, JAR_get_error(status));
    432        } else {
    433            error(PK11_INSTALL_JAR_EXTRACT, installer,
    434                  mySECU_ErrorString(PORT_GetError()));
    435        }
    436        ret = PK11_INSTALL_JAR_EXTRACT;
    437        goto loser;
    438    } else {
    439        made_temp_file = PR_TRUE;
    440    }
    441 
    442    /*
    443     * Parse the installation file into a syntax tree
    444     */
    445    Pk11Install_FD = PR_Open(SCRIPT_TEMP_FILE, PR_RDONLY, 0);
    446    if (!Pk11Install_FD) {
    447        error(PK11_INSTALL_OPEN_SCRIPT_FILE, SCRIPT_TEMP_FILE);
    448        ret = PK11_INSTALL_OPEN_SCRIPT_FILE;
    449        goto loser;
    450    }
    451    if (Pk11Install_yyparse()) {
    452        error(PK11_INSTALL_SCRIPT_PARSE, installer,
    453              Pk11Install_yyerrstr ? Pk11Install_yyerrstr : "");
    454        ret = PK11_INSTALL_SCRIPT_PARSE;
    455        goto loser;
    456    }
    457 
    458 #if 0
    459    /* for debugging */
    460    Pk11Install_valueList->Print(0);
    461 #endif
    462 
    463    /*
    464     * From the syntax tree, build a semantic structure
    465     */
    466    errMsg = Pk11Install_Info_Generate(&installInfo, Pk11Install_valueList);
    467    if (errMsg) {
    468        error(PK11_INSTALL_SEMANTIC, errMsg);
    469        ret = PK11_INSTALL_SEMANTIC;
    470        goto loser;
    471    }
    472 #if 0
    473    installInfo.Print(0);
    474 #endif
    475 
    476    if (feedback) {
    477        PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]);
    478    }
    479 
    480    /*
    481     * Figure out which platform to use
    482     */
    483    {
    484        sysname[0] = release[0] = arch[0] = '\0';
    485 
    486        if ((PR_GetSystemInfo(PR_SI_SYSNAME, sysname, SYS_INFO_BUFFER_LENGTH) !=
    487             PR_SUCCESS) ||
    488            (PR_GetSystemInfo(PR_SI_RELEASE, release, SYS_INFO_BUFFER_LENGTH) !=
    489             PR_SUCCESS) ||
    490            (PR_GetSystemInfo(PR_SI_ARCHITECTURE, arch, SYS_INFO_BUFFER_LENGTH) !=
    491             PR_SUCCESS)) {
    492            error(PK11_INSTALL_SYSINFO);
    493            ret = PK11_INSTALL_SYSINFO;
    494            goto loser;
    495        }
    496        myPlatform = PR_smprintf("%s:%s:%s", sysname, release, arch);
    497        platform = Pk11Install_Info_GetBestPlatform(&installInfo, myPlatform);
    498        if (!platform) {
    499            error(PK11_INSTALL_NO_PLATFORM, myPlatform);
    500            PR_smprintf_free(myPlatform);
    501            ret = PK11_INSTALL_NO_PLATFORM;
    502            goto loser;
    503        }
    504        if (feedback) {
    505            PR_fprintf(feedback, msgStrings[MY_PLATFORM_IS], myPlatform);
    506            PR_fprintf(feedback, msgStrings[USING_PLATFORM],
    507                       Pk11Install_PlatformName_GetString(&platform->name));
    508        }
    509        PR_smprintf_free(myPlatform);
    510    }
    511 
    512    /* Run the install for that platform */
    513    ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify);
    514    if (ret) {
    515        goto loser;
    516    }
    517 
    518    ret = PK11_INSTALL_SUCCESS;
    519 loser:
    520    if (Pk11Install_valueList) {
    521        Pk11Install_ValueList_delete(Pk11Install_valueList);
    522        Pk11Install_valueList = NULL;
    523    }
    524    if (jar) {
    525        JAR_destroy(jar);
    526    }
    527    if (made_temp_file) {
    528        PR_Delete(SCRIPT_TEMP_FILE);
    529    }
    530    if (errMsg) {
    531        PR_smprintf_free(errMsg);
    532    }
    533    return ret;
    534 }
    535 
    536 /*
    537 /////////////////////////////////////////////////////////////////////////
    538 // actually run the installation, copying files to and fro
    539 */
    540 static Pk11Install_Error
    541 DoInstall(JAR *jar, const char *installDir, const char *tempDir,
    542          Pk11Install_Platform *platform, PRFileDesc *feedback, PRBool noverify)
    543 {
    544    Pk11Install_File *file;
    545    Pk11Install_Error ret;
    546    char *modDest;
    547    char *cp;
    548    int i;
    549    int status;
    550    char *tempname, *temp;
    551    StringList executables;
    552    StringNode *execNode;
    553    PRProcessAttr *attr;
    554    PRProcess *proc;
    555    char *argv[2];
    556    char *envp[1];
    557    int errcode;
    558 
    559    ret = PK11_INSTALL_UNSPECIFIED;
    560    modDest = NULL;
    561    tempname = NULL;
    562 
    563    StringList_new(&executables);
    564    /*
    565    // Create Temporary directory
    566    */
    567    tempname = PR_smprintf("%s/%s", tempDir, TEMPORARY_DIRECTORY_NAME);
    568    if (PR_Access(tempname, PR_ACCESS_EXISTS) == PR_SUCCESS) {
    569        /* Left over from previous run?  Delete it. */
    570        rm_dash_r(tempname);
    571    }
    572    if (PR_MkDir(tempname, 0700) != PR_SUCCESS) {
    573        error(PK11_INSTALL_CREATE_DIR, tempname);
    574        ret = PK11_INSTALL_CREATE_DIR;
    575        goto loser;
    576    }
    577 
    578    /*
    579    // Install all the files
    580    */
    581    for (i = 0; i < platform->numFiles; i++) {
    582        char *dest;
    583        file = &platform->files[i];
    584 
    585        if (file->relativePath) {
    586            PRBool foundMarker = PR_FALSE;
    587            char *reldir = PR_Strdup(file->relativePath);
    588 
    589            if (!reldir) {
    590                error(PK11_INSTALL_UNSPECIFIED);
    591                goto loser;
    592            }
    593 
    594            /* Replace all the markers with the directories for which they stand */
    595            while (1) {
    596                if ((cp = PL_strcasestr(reldir, ROOT_MARKER))) {
    597                    /* Has a %root% marker  */
    598                    *cp = '\0';
    599                    temp = PR_smprintf("%s%s%s", reldir, installDir,
    600                                       cp + strlen(ROOT_MARKER));
    601                    PR_Free(reldir);
    602                    reldir = temp;
    603                    foundMarker = PR_TRUE;
    604                } else if ((cp = PL_strcasestr(reldir, TEMP_MARKER))) {
    605                    /* Has a %temp% marker */
    606                    *cp = '\0';
    607                    temp = PR_smprintf("%s%s%s", reldir, tempname,
    608                                       cp + strlen(TEMP_MARKER));
    609                    PR_Free(reldir);
    610                    reldir = temp;
    611                    foundMarker = PR_TRUE;
    612                } else {
    613                    break;
    614                }
    615            }
    616            if (!foundMarker) {
    617                /* Has no markers...this isn't really a relative directory */
    618                error(PK11_INSTALL_BOGUS_REL_DIR, file->relativePath);
    619                ret = PK11_INSTALL_BOGUS_REL_DIR;
    620                PR_Free(reldir);
    621                goto loser;
    622            }
    623            dest = reldir;
    624        } else if (file->absolutePath) {
    625            dest = PR_Strdup(file->absolutePath);
    626        } else {
    627            error(PK11_INSTALL_UNSPECIFIED);
    628            goto loser;
    629        }
    630 
    631        /* Remember if this is the module file, we'll need to add it later */
    632        if (i == platform->modFile) {
    633            modDest = PR_Strdup(dest);
    634        }
    635 
    636        /* Remember is this is an executable, we'll need to run it later */
    637        if (file->executable) {
    638            StringList_Append(&executables, dest);
    639            /*executables.Append(dest);*/
    640        }
    641 
    642        /* Make sure the directory we are targetting exists */
    643        if (make_dirs(dest, file->permissions)) {
    644            ret = PK11_INSTALL_CREATE_DIR;
    645            goto loser;
    646        }
    647 
    648        /* Actually extract the file onto the filesystem */
    649        if (noverify) {
    650            status = JAR_extract(jar, (char *)file->jarPath, dest);
    651        } else {
    652            status = JAR_verified_extract(jar, (char *)file->jarPath, dest);
    653        }
    654        if (status) {
    655            if (status >= JAR_BASE && status <= JAR_BASE_END) {
    656                error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
    657                      JAR_get_error(status));
    658            } else {
    659                error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
    660                      mySECU_ErrorString(PORT_GetError()));
    661            }
    662            ret = PK11_INSTALL_JAR_EXTRACT;
    663            goto loser;
    664        }
    665        if (feedback) {
    666            PR_fprintf(feedback, msgStrings[INSTALLED_FILE_MSG],
    667                       file->jarPath, dest);
    668        }
    669 
    670 /* no NSPR command to change permissions? */
    671 #ifdef XP_UNIX
    672        (void)chmod(dest, file->permissions);
    673 #endif
    674 
    675        PR_Free(dest);
    676    }
    677    /* Make sure we found the module file */
    678    if (!modDest) {
    679        /* Internal problem here, since every platform is supposed to have
    680           a module file */
    681        error(PK11_INSTALL_NO_MOD_FILE, platform->moduleName);
    682        ret = PK11_INSTALL_NO_MOD_FILE;
    683        goto loser;
    684    }
    685 
    686    /*
    687    // Execute any executable files
    688    */
    689    {
    690        argv[1] = NULL;
    691        envp[0] = NULL;
    692        for (execNode = executables.head; execNode; execNode = execNode->next) {
    693            attr = PR_NewProcessAttr();
    694            argv[0] = PR_Strdup(execNode->str);
    695 
    696            /* Announce our intentions */
    697            if (feedback) {
    698                PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str);
    699            }
    700 
    701            /* start the process */
    702            if (!(proc = PR_CreateProcess(execNode->str, argv, envp, attr))) {
    703                PR_Free(argv[0]);
    704                PR_DestroyProcessAttr(attr);
    705                error(PK11_INSTALL_EXEC_FILE, execNode->str);
    706                ret = PK11_INSTALL_EXEC_FILE;
    707                goto loser;
    708            }
    709 
    710            /* wait for it to finish */
    711            if (PR_WaitProcess(proc, &errcode) != PR_SUCCESS) {
    712                PR_Free(argv[0]);
    713                PR_DestroyProcessAttr(attr);
    714                error(PK11_INSTALL_WAIT_PROCESS, execNode->str);
    715                ret = PK11_INSTALL_WAIT_PROCESS;
    716                goto loser;
    717            }
    718 
    719            /* What happened? */
    720            if (errcode) {
    721                /* process returned an error */
    722                error(PK11_INSTALL_PROC_ERROR, execNode->str, errcode);
    723            } else if (feedback) {
    724                /* process ran successfully */
    725                PR_fprintf(feedback, msgStrings[EXEC_SUCCESS], execNode->str);
    726            }
    727 
    728            PR_Free(argv[0]);
    729            PR_DestroyProcessAttr(attr);
    730        }
    731    }
    732 
    733    /*
    734    // Add the module
    735    */
    736    status = Pk11Install_AddNewModule((char *)platform->moduleName,
    737                                      (char *)modDest, platform->mechFlags, platform->cipherFlags);
    738 
    739    if (status != SECSuccess) {
    740        error(PK11_INSTALL_ADD_MODULE, platform->moduleName);
    741        ret = PK11_INSTALL_ADD_MODULE;
    742        goto loser;
    743    }
    744    if (feedback) {
    745        PR_fprintf(feedback, msgStrings[INSTALLED_MODULE_MSG],
    746                   platform->moduleName);
    747    }
    748 
    749    if (feedback) {
    750        PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]);
    751    }
    752 
    753    ret = PK11_INSTALL_SUCCESS;
    754 
    755 loser:
    756    if (modDest) {
    757        PR_Free(modDest);
    758    }
    759    if (tempname) {
    760        PRFileInfo info;
    761        if (PR_GetFileInfo(tempname, &info) == PR_SUCCESS) {
    762            if (info.type == PR_FILE_DIRECTORY) {
    763                /* Recursively remove temporary directory */
    764                if (rm_dash_r(tempname)) {
    765                    error(PK11_INSTALL_REMOVE_DIR,
    766                          tempname);
    767                    ret = PK11_INSTALL_REMOVE_DIR;
    768                }
    769            }
    770        }
    771        PR_Free(tempname);
    772    }
    773    StringList_delete(&executables);
    774    return ret;
    775 }
    776 
    777 /*
    778 //////////////////////////////////////////////////////////////////////////
    779 */
    780 static char *
    781 PR_Strdup(const char *str)
    782 {
    783    char *tmp = (char *)PR_Malloc(strlen(str) + 1);
    784    strcpy(tmp, str);
    785    return tmp;
    786 }
    787 
    788 /*
    789 *  r m _ d a s h _ r
    790 *
    791 *  Remove a file, or a directory recursively.
    792 *
    793 */
    794 static int
    795 rm_dash_r(char *path)
    796 {
    797    PRDir *dir;
    798    PRDirEntry *entry;
    799    PRFileInfo fileinfo;
    800    char filename[240];
    801 
    802    if (PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) {
    803        /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/
    804        return -1;
    805    }
    806    if (fileinfo.type == PR_FILE_DIRECTORY) {
    807 
    808        dir = PR_OpenDir(path);
    809        if (!dir) {
    810            return -1;
    811        }
    812 
    813        /* Recursively delete all entries in the directory */
    814        while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
    815            snprintf(filename, sizeof(filename), "%s/%s", path, entry->name);
    816            if (rm_dash_r(filename)) {
    817                PR_CloseDir(dir);
    818                return -1;
    819            }
    820        }
    821 
    822        if (PR_CloseDir(dir) != PR_SUCCESS) {
    823            return -1;
    824        }
    825 
    826        /* Delete the directory itself */
    827        if (PR_RmDir(path) != PR_SUCCESS) {
    828            return -1;
    829        }
    830    } else {
    831        if (PR_Delete(path) != PR_SUCCESS) {
    832            return -1;
    833        }
    834    }
    835    return 0;
    836 }
    837 
    838 /***************************************************************************
    839 *
    840 * m a k e _ d i r s
    841 *
    842 * Ensure that the directory portion of the path exists.  This may require
    843 * making the directory, and its parent, and its parent's parent, etc.
    844 */
    845 static int
    846 make_dirs(char *path, int file_perms)
    847 {
    848    char *Path;
    849    char *start;
    850    char *sep;
    851    int ret = 0;
    852    PRFileInfo info;
    853 
    854    if (!path) {
    855        return 0;
    856    }
    857 
    858    Path = PR_Strdup(path);
    859    start = strpbrk(Path, "/\\");
    860    if (!start) {
    861        return 0;
    862    }
    863    start++; /* start right after first slash */
    864 
    865    /* Each time through the loop add one more directory. */
    866    while ((sep = strpbrk(start, "/\\"))) {
    867        *sep = '\0';
    868 
    869        if (PR_GetFileInfo(Path, &info) != PR_SUCCESS) {
    870            /* No such dir, we have to create it */
    871            if (PR_MkDir(Path, dir_perms(file_perms)) != PR_SUCCESS) {
    872                error(PK11_INSTALL_CREATE_DIR, Path);
    873                ret = PK11_INSTALL_CREATE_DIR;
    874                goto loser;
    875            }
    876        } else {
    877            /* something exists by this name, make sure it's a directory */
    878            if (info.type != PR_FILE_DIRECTORY) {
    879                error(PK11_INSTALL_CREATE_DIR, Path);
    880                ret = PK11_INSTALL_CREATE_DIR;
    881                goto loser;
    882            }
    883        }
    884 
    885        /* If this is the lowest directory level, make sure it is writeable */
    886        if (!strpbrk(sep + 1, "/\\")) {
    887            if (PR_Access(Path, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
    888                error(PK11_INSTALL_DIR_NOT_WRITEABLE, Path);
    889                ret = PK11_INSTALL_DIR_NOT_WRITEABLE;
    890                goto loser;
    891            }
    892        }
    893 
    894        start = sep + 1; /* start after the next slash */
    895        *sep = '/';
    896    }
    897 
    898 loser:
    899    PR_Free(Path);
    900    return ret;
    901 }
    902 
    903 /*************************************************************************
    904 * d i r _ p e r m s
    905 *
    906 * Guesses the desired permissions on a directory based on the permissions
    907 * of a file that will be stored in it. Give read, write, and
    908 * execute to the owner (so we can create the file), read and
    909 * execute to anyone who has read permissions on the file, and write
    910 * to anyone who has write permissions on the file.
    911 */
    912 static int
    913 dir_perms(int perms)
    914 {
    915    int ret = 0;
    916 
    917    /* owner */
    918    ret |= 0700;
    919 
    920    /* group */
    921    if (perms & 0040) {
    922        /* read on the file -> read and execute on the directory */
    923        ret |= 0050;
    924    }
    925    if (perms & 0020) {
    926        /* write on the file -> write on the directory */
    927        ret |= 0020;
    928    }
    929 
    930    /* others */
    931    if (perms & 0004) {
    932        /* read on the file -> read and execute on the directory */
    933        ret |= 0005;
    934    }
    935    if (perms & 0002) {
    936        /* write on the file -> write on the directory */
    937        ret |= 0002;
    938    }
    939 
    940    return ret;
    941 }