|
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 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(); |
|
36 |
|
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) |
|
44 |
|
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); |
|
51 |
|
52 static Pk11Install_Error DoInstall(JAR *jar, const char *installDir, |
|
53 const char* tempDir, Pk11Install_Platform *platform, |
|
54 PRFileDesc *feedback, PRBool noverify); |
|
55 |
|
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 }; |
|
85 |
|
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 }; |
|
98 |
|
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 }; |
|
111 |
|
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; |
|
119 |
|
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 } |
|
128 |
|
129 void StringNode_delete(StringNode* s) |
|
130 { |
|
131 if(s->str) { |
|
132 PR_Free(s->str); |
|
133 s->str=NULL; |
|
134 } |
|
135 } |
|
136 |
|
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; |
|
144 |
|
145 void StringList_new(StringList* list) |
|
146 { |
|
147 list->head=NULL; |
|
148 list->tail=NULL; |
|
149 } |
|
150 |
|
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 } |
|
160 |
|
161 void |
|
162 StringList_Append(StringList* list, char* str) |
|
163 { |
|
164 if(!str) { |
|
165 return; |
|
166 } |
|
167 |
|
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 } |
|
175 |
|
176 list->tail->str = PR_Strdup(str); |
|
177 list->tail->next = NULL; /* just to be sure */ |
|
178 } |
|
179 |
|
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; |
|
191 |
|
192 if(!errorHandlerLock) { |
|
193 errorHandlerLock = PR_NewLock(); |
|
194 } |
|
195 |
|
196 PR_Lock(errorHandlerLock); |
|
197 |
|
198 old = errorHandler; |
|
199 errorHandler = handler; |
|
200 |
|
201 PR_Unlock(errorHandlerLock); |
|
202 |
|
203 return old; |
|
204 } |
|
205 |
|
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 } |
|
221 |
|
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 } |
|
239 |
|
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 */ |
|
247 |
|
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 |
|
257 |
|
258 #ifdef OSF1 |
|
259 static void |
|
260 error(long va_alist, ...) |
|
261 #else |
|
262 static void |
|
263 error(Pk11Install_Error errcode, ...) |
|
264 #endif |
|
265 { |
|
266 |
|
267 va_list ap; |
|
268 char *errstr; |
|
269 Pk11Install_ErrorHandler handler; |
|
270 |
|
271 if(!errorHandlerLock) { |
|
272 errorHandlerLock = PR_NewLock(); |
|
273 } |
|
274 |
|
275 PR_Lock(errorHandlerLock); |
|
276 |
|
277 handler = errorHandler; |
|
278 |
|
279 PR_Unlock(errorHandlerLock); |
|
280 |
|
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 } |
|
294 |
|
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; |
|
303 |
|
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 } |
|
310 |
|
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; |
|
335 |
|
336 jar=NULL; |
|
337 ret = PK11_INSTALL_UNSPECIFIED; |
|
338 made_temp_file=PR_FALSE; |
|
339 errMsg=NULL; |
|
340 Pk11Install_Info_init(&installInfo); |
|
341 |
|
342 /* |
|
343 printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n", |
|
344 jarFile, installDir, tempDir); |
|
345 */ |
|
346 |
|
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 } |
|
373 |
|
374 /* |
|
375 * Extract the JAR file |
|
376 */ |
|
377 jar = JAR_new(); |
|
378 JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback); |
|
379 |
|
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");*/ |
|
396 |
|
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 } |
|
408 |
|
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 } |
|
421 |
|
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 } |
|
449 |
|
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 } |
|
465 |
|
466 #if 0 |
|
467 /* for debugging */ |
|
468 Pk11Install_valueList->Print(0); |
|
469 #endif |
|
470 |
|
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 |
|
483 |
|
484 if(feedback) { |
|
485 PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]); |
|
486 } |
|
487 |
|
488 /* |
|
489 * Figure out which platform to use |
|
490 */ |
|
491 { |
|
492 sysname[0] = release[0] = arch[0] = '\0'; |
|
493 |
|
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 } |
|
519 |
|
520 /* Run the install for that platform */ |
|
521 ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify); |
|
522 if(ret) { |
|
523 goto loser; |
|
524 } |
|
525 |
|
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 } |
|
544 |
|
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; |
|
569 |
|
570 ret=PK11_INSTALL_UNSPECIFIED; |
|
571 reldir=NULL; |
|
572 dest=NULL; |
|
573 modDest=NULL; |
|
574 tempname=NULL; |
|
575 |
|
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 } |
|
590 |
|
591 /* |
|
592 // Install all the files |
|
593 */ |
|
594 for(i=0; i < platform->numFiles; i++) { |
|
595 file = &platform->files[i]; |
|
596 |
|
597 if(file->relativePath) { |
|
598 PRBool foundMarker = PR_FALSE; |
|
599 reldir = PR_Strdup(file->relativePath); |
|
600 |
|
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 } |
|
634 |
|
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 } |
|
639 |
|
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 } |
|
645 |
|
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 } |
|
651 |
|
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 } |
|
673 |
|
674 /* no NSPR command to change permissions? */ |
|
675 #ifdef XP_UNIX |
|
676 chmod(dest, file->permissions); |
|
677 #endif |
|
678 |
|
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 } |
|
697 |
|
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); |
|
707 |
|
708 /* Announce our intentions */ |
|
709 if(feedback) { |
|
710 PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str); |
|
711 } |
|
712 |
|
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 } |
|
721 |
|
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 } |
|
730 |
|
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 } |
|
739 |
|
740 PR_Free(argv[0]); |
|
741 PR_DestroyProcessAttr(attr); |
|
742 } |
|
743 } |
|
744 |
|
745 /* |
|
746 // Add the module |
|
747 */ |
|
748 status = Pk11Install_AddNewModule((char*)platform->moduleName, |
|
749 (char*)modDest, platform->mechFlags, platform->cipherFlags ); |
|
750 |
|
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 } |
|
760 |
|
761 if(feedback) { |
|
762 PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]); |
|
763 } |
|
764 |
|
765 ret = PK11_INSTALL_SUCCESS; |
|
766 |
|
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 } |
|
787 |
|
788 } |
|
789 } |
|
790 PR_Free(tempname); |
|
791 } |
|
792 StringList_delete(&executables); |
|
793 return ret; |
|
794 } |
|
795 |
|
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 } |
|
806 |
|
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]; |
|
820 |
|
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) { |
|
826 |
|
827 dir = PR_OpenDir(path); |
|
828 if(!dir) { |
|
829 return -1; |
|
830 } |
|
831 |
|
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 } |
|
837 |
|
838 if(PR_CloseDir(dir) != PR_SUCCESS) { |
|
839 return -1; |
|
840 } |
|
841 |
|
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 } |
|
853 |
|
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; |
|
869 |
|
870 if(!path) { |
|
871 return 0; |
|
872 } |
|
873 |
|
874 Path = PR_Strdup(path); |
|
875 start = strpbrk(Path, "/\\"); |
|
876 if(!start) { |
|
877 return 0; |
|
878 } |
|
879 start++; /* start right after first slash */ |
|
880 |
|
881 /* Each time through the loop add one more directory. */ |
|
882 while( (sep=strpbrk(start, "/\\")) ) { |
|
883 *sep = '\0'; |
|
884 |
|
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 } |
|
900 |
|
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 } |
|
909 |
|
910 start = sep+1; /* start after the next slash */ |
|
911 *sep = '/'; |
|
912 } |
|
913 |
|
914 loser: |
|
915 PR_Free(Path); |
|
916 return ret; |
|
917 } |
|
918 |
|
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; |
|
932 |
|
933 /* owner */ |
|
934 ret |= 0700; |
|
935 |
|
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 } |
|
945 |
|
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 } |
|
955 |
|
956 return ret; |
|
957 } |