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

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

mercurial