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