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