Wed, 31 Dec 2014 06:55:50 +0100
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 }