security/nss/cmd/modutil/install.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial