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 }