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 *
StringNode_new()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
StringNode_delete(StringNode * s)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
StringList_new(StringList * list)151 StringList_new(StringList *list)
152 {
153     list->head = NULL;
154     list->tail = NULL;
155 }
156 
157 void
StringList_delete(StringList * list)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
StringList_Append(StringList * list,char * str)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
Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler)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
Pk11Install_Init()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
Pk11Install_Release()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 #ifdef OSF1
256 /* stdarg has already been pulled in from NSPR */
257 #undef va_start
258 #undef va_end
259 #undef va_arg
260 #include <varargs.h>
261 #else
262 #include <stdarg.h>
263 #endif
264 
265 #ifdef OSF1
266 static void
error(long va_alist,...)267 error(long va_alist, ...)
268 #else
269 static void
270 error(PRErrorCode errcode, ...)
271 #endif
272 {
273 
274     va_list ap;
275     char *errstr;
276     Pk11Install_ErrorHandler handler;
277 
278     if (!errorHandlerLock) {
279         errorHandlerLock = PR_NewLock();
280     }
281 
282     PR_Lock(errorHandlerLock);
283 
284     handler = errorHandler;
285 
286     PR_Unlock(errorHandlerLock);
287 
288     if (handler) {
289 #ifdef OSF1
290         va_start(ap);
291         errstr = PR_vsmprintf(errorString[va_arg(ap, Pk11Install_Error)], ap);
292 #else
293         va_start(ap, errcode);
294         errstr = PR_vsmprintf(errorString[errcode], ap);
295 #endif
296         handler(errstr);
297         PR_smprintf_free(errstr);
298         va_end(ap);
299     }
300 }
301 
302 /*************************************************************************
303  *
304  * j a r _ c a l l b a c k
305  */
306 static int
jar_callback(int status,JAR * foo,const char * bar,char * pathname,char * errortext)307 jar_callback(int status, JAR *foo, const char *bar, char *pathname,
308              char *errortext)
309 {
310     char *string;
311 
312     string = PR_smprintf("JAR error %d: %s in file %s\n", status, errortext,
313                          pathname);
314     error(PK11_INSTALL_ERROR_STRING, string);
315     PR_smprintf_free(string);
316     return 0;
317 }
318 
319 /*************************************************************************
320  *
321  * P k 1 1 I n s t a l l _ D o I n s t a l l
322  *
323  * jarFile is the path of a JAR in the PKCS #11 module JAR format.
324  * installDir is the directory relative to which files will be
325  *   installed.
326  */
327 Pk11Install_Error
Pk11Install_DoInstall(char * jarFile,const char * installDir,const char * tempDir,PRFileDesc * feedback,short force,PRBool noverify)328 Pk11Install_DoInstall(char *jarFile, const char *installDir,
329                       const char *tempDir, PRFileDesc *feedback, short force, PRBool noverify)
330 {
331     JAR *jar;
332     char *installer;
333     unsigned long installer_len;
334     int status;
335     Pk11Install_Error ret;
336     PRBool made_temp_file;
337     Pk11Install_Info installInfo;
338     Pk11Install_Platform *platform;
339     char *errMsg;
340     char sysname[SYS_INFO_BUFFER_LENGTH], release[SYS_INFO_BUFFER_LENGTH],
341         arch[SYS_INFO_BUFFER_LENGTH];
342     char *myPlatform;
343 
344     jar = NULL;
345     ret = PK11_INSTALL_UNSPECIFIED;
346     made_temp_file = PR_FALSE;
347     errMsg = NULL;
348     Pk11Install_Info_init(&installInfo);
349 
350     /*
351     printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n",
352         jarFile, installDir, tempDir);
353     */
354 
355     /*
356      * Check out jarFile and installDir for validity
357      */
358     if (PR_Access(installDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
359         error(PK11_INSTALL_DIR_DOESNT_EXIST, installDir);
360         return PK11_INSTALL_DIR_DOESNT_EXIST;
361     }
362     if (!tempDir) {
363         tempDir = ".";
364     }
365     if (PR_Access(tempDir, PR_ACCESS_EXISTS) != PR_SUCCESS) {
366         error(PK11_INSTALL_DIR_DOESNT_EXIST, tempDir);
367         return PK11_INSTALL_DIR_DOESNT_EXIST;
368     }
369     if (PR_Access(tempDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
370         error(PK11_INSTALL_DIR_NOT_WRITEABLE, tempDir);
371         return PK11_INSTALL_DIR_NOT_WRITEABLE;
372     }
373     if ((PR_Access(jarFile, PR_ACCESS_EXISTS) != PR_SUCCESS)) {
374         error(PK11_INSTALL_FILE_DOESNT_EXIST, jarFile);
375         return PK11_INSTALL_FILE_DOESNT_EXIST;
376     }
377     if (PR_Access(jarFile, PR_ACCESS_READ_OK) != PR_SUCCESS) {
378         error(PK11_INSTALL_FILE_NOT_READABLE, jarFile);
379         return PK11_INSTALL_FILE_NOT_READABLE;
380     }
381 
382     /*
383      * Extract the JAR file
384      */
385     jar = JAR_new();
386     JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback);
387 
388     if (noverify) {
389         status = JAR_pass_archive_unverified(jar, jarArchGuess, jarFile, "url");
390     } else {
391         status = JAR_pass_archive(jar, jarArchGuess, jarFile, "url");
392     }
393     if ((status < 0) || (jar->valid < 0)) {
394         if (status >= JAR_BASE && status <= JAR_BASE_END) {
395             error(PK11_INSTALL_JAR_ERROR, jarFile, JAR_get_error(status));
396         } else {
397             error(PK11_INSTALL_JAR_ERROR, jarFile,
398                   mySECU_ErrorString(PORT_GetError()));
399         }
400         ret = PK11_INSTALL_JAR_ERROR;
401         goto loser;
402     }
403     /*printf("passed the archive\n");*/
404 
405     /*
406      * Show the user security information, allow them to abort or continue
407      */
408     if (Pk11Install_UserVerifyJar(jar, PR_STDOUT,
409                                   force ? PR_FALSE
410                                         : PR_TRUE) &&
411         !force) {
412         if (feedback) {
413             PR_fprintf(feedback, msgStrings[USER_ABORT]);
414         }
415         ret = PK11_INSTALL_USER_ABORT;
416         goto loser;
417     }
418 
419     /*
420      * Get the name of the installation file
421      */
422     if (JAR_get_metainfo(jar, NULL, INSTALL_METAINFO_TAG, (void **)&installer,
423                          (unsigned long *)&installer_len)) {
424         error(PK11_INSTALL_NO_INSTALLER_SCRIPT);
425         ret = PK11_INSTALL_NO_INSTALLER_SCRIPT;
426         goto loser;
427     }
428     if (feedback) {
429         PR_fprintf(feedback, msgStrings[INSTALLER_SCRIPT_NAME], installer);
430     }
431 
432     /*
433      * Extract the installation file
434      */
435     if (PR_Access(SCRIPT_TEMP_FILE, PR_ACCESS_EXISTS) == PR_SUCCESS) {
436         if (PR_Delete(SCRIPT_TEMP_FILE) != PR_SUCCESS) {
437             error(PK11_INSTALL_DELETE_TEMP_FILE, SCRIPT_TEMP_FILE);
438             ret = PK11_INSTALL_DELETE_TEMP_FILE;
439             goto loser;
440         }
441     }
442     if (noverify) {
443         status = JAR_extract(jar, installer, SCRIPT_TEMP_FILE);
444     } else {
445         status = JAR_verified_extract(jar, installer, SCRIPT_TEMP_FILE);
446     }
447     if (status) {
448         if (status >= JAR_BASE && status <= JAR_BASE_END) {
449             error(PK11_INSTALL_JAR_EXTRACT, installer, JAR_get_error(status));
450         } else {
451             error(PK11_INSTALL_JAR_EXTRACT, installer,
452                   mySECU_ErrorString(PORT_GetError()));
453         }
454         ret = PK11_INSTALL_JAR_EXTRACT;
455         goto loser;
456     } else {
457         made_temp_file = PR_TRUE;
458     }
459 
460     /*
461      * Parse the installation file into a syntax tree
462      */
463     Pk11Install_FD = PR_Open(SCRIPT_TEMP_FILE, PR_RDONLY, 0);
464     if (!Pk11Install_FD) {
465         error(PK11_INSTALL_OPEN_SCRIPT_FILE, SCRIPT_TEMP_FILE);
466         ret = PK11_INSTALL_OPEN_SCRIPT_FILE;
467         goto loser;
468     }
469     if (Pk11Install_yyparse()) {
470         error(PK11_INSTALL_SCRIPT_PARSE, installer,
471               Pk11Install_yyerrstr ? Pk11Install_yyerrstr : "");
472         ret = PK11_INSTALL_SCRIPT_PARSE;
473         goto loser;
474     }
475 
476 #if 0
477     /* for debugging */
478     Pk11Install_valueList->Print(0);
479 #endif
480 
481     /*
482      * From the syntax tree, build a semantic structure
483      */
484     errMsg = Pk11Install_Info_Generate(&installInfo, Pk11Install_valueList);
485     if (errMsg) {
486         error(PK11_INSTALL_SEMANTIC, errMsg);
487         ret = PK11_INSTALL_SEMANTIC;
488         goto loser;
489     }
490 #if 0
491     installInfo.Print(0);
492 #endif
493 
494     if (feedback) {
495         PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]);
496     }
497 
498     /*
499      * Figure out which platform to use
500      */
501     {
502         sysname[0] = release[0] = arch[0] = '\0';
503 
504         if ((PR_GetSystemInfo(PR_SI_SYSNAME, sysname, SYS_INFO_BUFFER_LENGTH) !=
505              PR_SUCCESS) ||
506             (PR_GetSystemInfo(PR_SI_RELEASE, release, SYS_INFO_BUFFER_LENGTH) !=
507              PR_SUCCESS) ||
508             (PR_GetSystemInfo(PR_SI_ARCHITECTURE, arch, SYS_INFO_BUFFER_LENGTH) !=
509              PR_SUCCESS)) {
510             error(PK11_INSTALL_SYSINFO);
511             ret = PK11_INSTALL_SYSINFO;
512             goto loser;
513         }
514         myPlatform = PR_smprintf("%s:%s:%s", sysname, release, arch);
515         platform = Pk11Install_Info_GetBestPlatform(&installInfo, myPlatform);
516         if (!platform) {
517             error(PK11_INSTALL_NO_PLATFORM, myPlatform);
518             PR_smprintf_free(myPlatform);
519             ret = PK11_INSTALL_NO_PLATFORM;
520             goto loser;
521         }
522         if (feedback) {
523             PR_fprintf(feedback, msgStrings[MY_PLATFORM_IS], myPlatform);
524             PR_fprintf(feedback, msgStrings[USING_PLATFORM],
525                        Pk11Install_PlatformName_GetString(&platform->name));
526         }
527         PR_smprintf_free(myPlatform);
528     }
529 
530     /* Run the install for that platform */
531     ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify);
532     if (ret) {
533         goto loser;
534     }
535 
536     ret = PK11_INSTALL_SUCCESS;
537 loser:
538     if (Pk11Install_valueList) {
539         Pk11Install_ValueList_delete(Pk11Install_valueList);
540         Pk11Install_valueList = NULL;
541     }
542     if (jar) {
543         JAR_destroy(jar);
544     }
545     if (made_temp_file) {
546         PR_Delete(SCRIPT_TEMP_FILE);
547     }
548     if (errMsg) {
549         PR_smprintf_free(errMsg);
550     }
551     return ret;
552 }
553 
554 /*
555 /////////////////////////////////////////////////////////////////////////
556 // actually run the installation, copying files to and fro
557 */
558 static Pk11Install_Error
DoInstall(JAR * jar,const char * installDir,const char * tempDir,Pk11Install_Platform * platform,PRFileDesc * feedback,PRBool noverify)559 DoInstall(JAR *jar, const char *installDir, const char *tempDir,
560           Pk11Install_Platform *platform, PRFileDesc *feedback, PRBool noverify)
561 {
562     Pk11Install_File *file;
563     Pk11Install_Error ret;
564     char *modDest;
565     char *cp;
566     int i;
567     int status;
568     char *tempname, *temp;
569     StringList executables;
570     StringNode *execNode;
571     PRProcessAttr *attr;
572     PRProcess *proc;
573     char *argv[2];
574     char *envp[1];
575     int errcode;
576 
577     ret = PK11_INSTALL_UNSPECIFIED;
578     modDest = NULL;
579     tempname = NULL;
580 
581     StringList_new(&executables);
582     /*
583     // Create Temporary directory
584     */
585     tempname = PR_smprintf("%s/%s", tempDir, TEMPORARY_DIRECTORY_NAME);
586     if (PR_Access(tempname, PR_ACCESS_EXISTS) == PR_SUCCESS) {
587         /* Left over from previous run?  Delete it. */
588         rm_dash_r(tempname);
589     }
590     if (PR_MkDir(tempname, 0700) != PR_SUCCESS) {
591         error(PK11_INSTALL_CREATE_DIR, tempname);
592         ret = PK11_INSTALL_CREATE_DIR;
593         goto loser;
594     }
595 
596     /*
597     // Install all the files
598     */
599     for (i = 0; i < platform->numFiles; i++) {
600         char *dest;
601         file = &platform->files[i];
602 
603         if (file->relativePath) {
604             PRBool foundMarker = PR_FALSE;
605             char *reldir = PR_Strdup(file->relativePath);
606 
607             if (!reldir) {
608                 error(PK11_INSTALL_UNSPECIFIED);
609                 goto loser;
610             }
611 
612             /* Replace all the markers with the directories for which they stand */
613             while (1) {
614                 if ((cp = PL_strcasestr(reldir, ROOT_MARKER))) {
615                     /* Has a %root% marker  */
616                     *cp = '\0';
617                     temp = PR_smprintf("%s%s%s", reldir, installDir,
618                                        cp + strlen(ROOT_MARKER));
619                     PR_Free(reldir);
620                     reldir = temp;
621                     foundMarker = PR_TRUE;
622                 } else if ((cp = PL_strcasestr(reldir, TEMP_MARKER))) {
623                     /* Has a %temp% marker */
624                     *cp = '\0';
625                     temp = PR_smprintf("%s%s%s", reldir, tempname,
626                                        cp + strlen(TEMP_MARKER));
627                     PR_Free(reldir);
628                     reldir = temp;
629                     foundMarker = PR_TRUE;
630                 } else {
631                     break;
632                 }
633             }
634             if (!foundMarker) {
635                 /* Has no markers...this isn't really a relative directory */
636                 error(PK11_INSTALL_BOGUS_REL_DIR, file->relativePath);
637                 ret = PK11_INSTALL_BOGUS_REL_DIR;
638                 PR_Free(reldir);
639                 goto loser;
640             }
641             dest = reldir;
642         } else if (file->absolutePath) {
643             dest = PR_Strdup(file->absolutePath);
644         } else {
645             error(PK11_INSTALL_UNSPECIFIED);
646             goto loser;
647         }
648 
649         /* Remember if this is the module file, we'll need to add it later */
650         if (i == platform->modFile) {
651             modDest = PR_Strdup(dest);
652         }
653 
654         /* Remember is this is an executable, we'll need to run it later */
655         if (file->executable) {
656             StringList_Append(&executables, dest);
657             /*executables.Append(dest);*/
658         }
659 
660         /* Make sure the directory we are targetting exists */
661         if (make_dirs(dest, file->permissions)) {
662             ret = PK11_INSTALL_CREATE_DIR;
663             goto loser;
664         }
665 
666         /* Actually extract the file onto the filesystem */
667         if (noverify) {
668             status = JAR_extract(jar, (char *)file->jarPath, dest);
669         } else {
670             status = JAR_verified_extract(jar, (char *)file->jarPath, dest);
671         }
672         if (status) {
673             if (status >= JAR_BASE && status <= JAR_BASE_END) {
674                 error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
675                       JAR_get_error(status));
676             } else {
677                 error(PK11_INSTALL_JAR_EXTRACT, file->jarPath,
678                       mySECU_ErrorString(PORT_GetError()));
679             }
680             ret = PK11_INSTALL_JAR_EXTRACT;
681             goto loser;
682         }
683         if (feedback) {
684             PR_fprintf(feedback, msgStrings[INSTALLED_FILE_MSG],
685                        file->jarPath, dest);
686         }
687 
688 /* no NSPR command to change permissions? */
689 #ifdef XP_UNIX
690         (void)chmod(dest, file->permissions);
691 #endif
692 
693         PR_Free(dest);
694     }
695     /* Make sure we found the module file */
696     if (!modDest) {
697         /* Internal problem here, since every platform is supposed to have
698            a module file */
699         error(PK11_INSTALL_NO_MOD_FILE, platform->moduleName);
700         ret = PK11_INSTALL_NO_MOD_FILE;
701         goto loser;
702     }
703 
704     /*
705     // Execute any executable files
706     */
707     {
708         argv[1] = NULL;
709         envp[0] = NULL;
710         for (execNode = executables.head; execNode; execNode = execNode->next) {
711             attr = PR_NewProcessAttr();
712             argv[0] = PR_Strdup(execNode->str);
713 
714             /* Announce our intentions */
715             if (feedback) {
716                 PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str);
717             }
718 
719             /* start the process */
720             if (!(proc = PR_CreateProcess(execNode->str, argv, envp, attr))) {
721                 PR_Free(argv[0]);
722                 PR_DestroyProcessAttr(attr);
723                 error(PK11_INSTALL_EXEC_FILE, execNode->str);
724                 ret = PK11_INSTALL_EXEC_FILE;
725                 goto loser;
726             }
727 
728             /* wait for it to finish */
729             if (PR_WaitProcess(proc, &errcode) != PR_SUCCESS) {
730                 PR_Free(argv[0]);
731                 PR_DestroyProcessAttr(attr);
732                 error(PK11_INSTALL_WAIT_PROCESS, execNode->str);
733                 ret = PK11_INSTALL_WAIT_PROCESS;
734                 goto loser;
735             }
736 
737             /* What happened? */
738             if (errcode) {
739                 /* process returned an error */
740                 error(PK11_INSTALL_PROC_ERROR, execNode->str, errcode);
741             } else if (feedback) {
742                 /* process ran successfully */
743                 PR_fprintf(feedback, msgStrings[EXEC_SUCCESS], execNode->str);
744             }
745 
746             PR_Free(argv[0]);
747             PR_DestroyProcessAttr(attr);
748         }
749     }
750 
751     /*
752     // Add the module
753     */
754     status = Pk11Install_AddNewModule((char *)platform->moduleName,
755                                       (char *)modDest, platform->mechFlags, platform->cipherFlags);
756 
757     if (status != SECSuccess) {
758         error(PK11_INSTALL_ADD_MODULE, platform->moduleName);
759         ret = PK11_INSTALL_ADD_MODULE;
760         goto loser;
761     }
762     if (feedback) {
763         PR_fprintf(feedback, msgStrings[INSTALLED_MODULE_MSG],
764                    platform->moduleName);
765     }
766 
767     if (feedback) {
768         PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]);
769     }
770 
771     ret = PK11_INSTALL_SUCCESS;
772 
773 loser:
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                 }
787             }
788         }
789         PR_Free(tempname);
790     }
791     StringList_delete(&executables);
792     return ret;
793 }
794 
795 /*
796 //////////////////////////////////////////////////////////////////////////
797 */
798 static char *
PR_Strdup(const char * str)799 PR_Strdup(const char *str)
800 {
801     char *tmp = (char *)PR_Malloc(strlen(str) + 1);
802     strcpy(tmp, str);
803     return tmp;
804 }
805 
806 /*
807  *  r m _ d a s h _ r
808  *
809  *  Remove a file, or a directory recursively.
810  *
811  */
812 static int
rm_dash_r(char * path)813 rm_dash_r(char *path)
814 {
815     PRDir *dir;
816     PRDirEntry *entry;
817     PRFileInfo fileinfo;
818     char filename[240];
819 
820     if (PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) {
821         /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/
822         return -1;
823     }
824     if (fileinfo.type == PR_FILE_DIRECTORY) {
825 
826         dir = PR_OpenDir(path);
827         if (!dir) {
828             return -1;
829         }
830 
831         /* Recursively delete all entries in the directory */
832         while ((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
833             sprintf(filename, "%s/%s", path, entry->name);
834             if (rm_dash_r(filename)) {
835                 PR_CloseDir(dir);
836                 return -1;
837             }
838         }
839 
840         if (PR_CloseDir(dir) != PR_SUCCESS) {
841             return -1;
842         }
843 
844         /* Delete the directory itself */
845         if (PR_RmDir(path) != PR_SUCCESS) {
846             return -1;
847         }
848     } else {
849         if (PR_Delete(path) != PR_SUCCESS) {
850             return -1;
851         }
852     }
853     return 0;
854 }
855 
856 /***************************************************************************
857  *
858  * m a k e _ d i r s
859  *
860  * Ensure that the directory portion of the path exists.  This may require
861  * making the directory, and its parent, and its parent's parent, etc.
862  */
863 static int
make_dirs(char * path,int file_perms)864 make_dirs(char *path, int file_perms)
865 {
866     char *Path;
867     char *start;
868     char *sep;
869     int ret = 0;
870     PRFileInfo info;
871 
872     if (!path) {
873         return 0;
874     }
875 
876     Path = PR_Strdup(path);
877     start = strpbrk(Path, "/\\");
878     if (!start) {
879         return 0;
880     }
881     start++; /* start right after first slash */
882 
883     /* Each time through the loop add one more directory. */
884     while ((sep = strpbrk(start, "/\\"))) {
885         *sep = '\0';
886 
887         if (PR_GetFileInfo(Path, &info) != PR_SUCCESS) {
888             /* No such dir, we have to create it */
889             if (PR_MkDir(Path, dir_perms(file_perms)) != PR_SUCCESS) {
890                 error(PK11_INSTALL_CREATE_DIR, Path);
891                 ret = PK11_INSTALL_CREATE_DIR;
892                 goto loser;
893             }
894         } else {
895             /* something exists by this name, make sure it's a directory */
896             if (info.type != PR_FILE_DIRECTORY) {
897                 error(PK11_INSTALL_CREATE_DIR, Path);
898                 ret = PK11_INSTALL_CREATE_DIR;
899                 goto loser;
900             }
901         }
902 
903         /* If this is the lowest directory level, make sure it is writeable */
904         if (!strpbrk(sep + 1, "/\\")) {
905             if (PR_Access(Path, PR_ACCESS_WRITE_OK) != PR_SUCCESS) {
906                 error(PK11_INSTALL_DIR_NOT_WRITEABLE, Path);
907                 ret = PK11_INSTALL_DIR_NOT_WRITEABLE;
908                 goto loser;
909             }
910         }
911 
912         start = sep + 1; /* start after the next slash */
913         *sep = '/';
914     }
915 
916 loser:
917     PR_Free(Path);
918     return ret;
919 }
920 
921 /*************************************************************************
922  * d i r _ p e r m s
923  *
924  * Guesses the desired permissions on a directory based on the permissions
925  * of a file that will be stored in it. Give read, write, and
926  * execute to the owner (so we can create the file), read and
927  * execute to anyone who has read permissions on the file, and write
928  * to anyone who has write permissions on the file.
929  */
930 static int
dir_perms(int perms)931 dir_perms(int perms)
932 {
933     int ret = 0;
934 
935     /* owner */
936     ret |= 0700;
937 
938     /* group */
939     if (perms & 0040) {
940         /* read on the file -> read and execute on the directory */
941         ret |= 0050;
942     }
943     if (perms & 0020) {
944         /* write on the file -> write on the directory */
945         ret |= 0020;
946     }
947 
948     /* others */
949     if (perms & 0004) {
950         /* read on the file -> read and execute on the directory */
951         ret |= 0005;
952     }
953     if (perms & 0002) {
954         /* write on the file -> write on the directory */
955         ret |= 0002;
956     }
957 
958     return ret;
959 }
960