Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include "install.h" |
michael@0 | 6 | #include "install-ds.h" |
michael@0 | 7 | #include <prerror.h> |
michael@0 | 8 | #include <prlock.h> |
michael@0 | 9 | #include <prio.h> |
michael@0 | 10 | #include <prmem.h> |
michael@0 | 11 | #include <prprf.h> |
michael@0 | 12 | #include <prsystem.h> |
michael@0 | 13 | #include <prproces.h> |
michael@0 | 14 | |
michael@0 | 15 | #ifdef XP_UNIX |
michael@0 | 16 | /* for chmod */ |
michael@0 | 17 | #include <sys/types.h> |
michael@0 | 18 | #include <sys/stat.h> |
michael@0 | 19 | #endif |
michael@0 | 20 | |
michael@0 | 21 | /*extern "C" {*/ |
michael@0 | 22 | #include <jar.h> |
michael@0 | 23 | /*}*/ |
michael@0 | 24 | |
michael@0 | 25 | extern /*"C"*/ |
michael@0 | 26 | int Pk11Install_AddNewModule(char* moduleName, char* dllPath, |
michael@0 | 27 | unsigned long defaultMechanismFlags, |
michael@0 | 28 | unsigned long cipherEnableFlags); |
michael@0 | 29 | extern /*"C"*/ |
michael@0 | 30 | short Pk11Install_UserVerifyJar(JAR *jar, PRFileDesc *out, |
michael@0 | 31 | PRBool query); |
michael@0 | 32 | extern /*"C"*/ |
michael@0 | 33 | const char* mySECU_ErrorString(PRErrorCode errnum); |
michael@0 | 34 | extern |
michael@0 | 35 | int Pk11Install_yyparse(); |
michael@0 | 36 | |
michael@0 | 37 | #define INSTALL_METAINFO_TAG "Pkcs11_install_script" |
michael@0 | 38 | #define SCRIPT_TEMP_FILE "pkcs11inst.tmp" |
michael@0 | 39 | #define ROOT_MARKER "%root%" |
michael@0 | 40 | #define TEMP_MARKER "%temp%" |
michael@0 | 41 | #define PRINTF_ROOT_MARKER "%%root%%" |
michael@0 | 42 | #define TEMPORARY_DIRECTORY_NAME "pk11inst.dir" |
michael@0 | 43 | #define JAR_BASE_END (JAR_BASE+100) |
michael@0 | 44 | |
michael@0 | 45 | static PRLock* errorHandlerLock=NULL; |
michael@0 | 46 | static Pk11Install_ErrorHandler errorHandler=NULL; |
michael@0 | 47 | static char* PR_Strdup(const char* str); |
michael@0 | 48 | static int rm_dash_r (char *path); |
michael@0 | 49 | static int make_dirs(char *path, int file_perms); |
michael@0 | 50 | static int dir_perms(int perms); |
michael@0 | 51 | |
michael@0 | 52 | static Pk11Install_Error DoInstall(JAR *jar, const char *installDir, |
michael@0 | 53 | const char* tempDir, Pk11Install_Platform *platform, |
michael@0 | 54 | PRFileDesc *feedback, PRBool noverify); |
michael@0 | 55 | |
michael@0 | 56 | static char *errorString[]= { |
michael@0 | 57 | "Operation was successful", /* PK11_INSTALL_NO_ERROR */ |
michael@0 | 58 | "Directory \"%s\" does not exist", /* PK11_INSTALL_DIR_DOESNT_EXIST */ |
michael@0 | 59 | "File \"%s\" does not exist", /* PK11_INSTALL_FILE_DOESNT_EXIST */ |
michael@0 | 60 | "File \"%s\" is not readable", /* PK11_INSTALL_FILE_NOT_READABLE */ |
michael@0 | 61 | "%s", /* PK11_INSTALL_ERROR_STRING */ |
michael@0 | 62 | "Error in JAR file %s: %s", /* PK11_INSTALL_JAR_ERROR */ |
michael@0 | 63 | "No Pkcs11_install_script specified in JAR metainfo file", |
michael@0 | 64 | /* PK11_INSTALL_NO_INSTALLER_SCRIPT */ |
michael@0 | 65 | "Could not delete temporary file \"%s\"", |
michael@0 | 66 | /*PK11_INSTALL_DELETE_TEMP_FILE */ |
michael@0 | 67 | "Could not open temporary file \"%s\"", /*PK11_INSTALL_OPEN_SCRIPT_FILE*/ |
michael@0 | 68 | "%s: %s", /* PK11_INSTALL_SCRIPT_PARSE */ |
michael@0 | 69 | "Error in script: %s", |
michael@0 | 70 | "Unable to obtain system platform information", |
michael@0 | 71 | "Installer script has no information about the current platform (%s)", |
michael@0 | 72 | "Relative directory \"%s\" does not contain "PRINTF_ROOT_MARKER, |
michael@0 | 73 | "Module File \"%s\" not found", |
michael@0 | 74 | "Error occurred installing module \"%s\" into database", |
michael@0 | 75 | "Error extracting \"%s\" from JAR file: %s", |
michael@0 | 76 | "Directory \"%s\" is not writeable", |
michael@0 | 77 | "Could not create directory \"%s\"", |
michael@0 | 78 | "Could not remove directory \"%s\"", |
michael@0 | 79 | "Unable to execute \"%s\"", |
michael@0 | 80 | "Unable to wait for process \"%s\"", |
michael@0 | 81 | "\"%s\" returned error code %d", |
michael@0 | 82 | "User aborted operation", |
michael@0 | 83 | "Unspecified error" |
michael@0 | 84 | }; |
michael@0 | 85 | |
michael@0 | 86 | enum { |
michael@0 | 87 | INSTALLED_FILE_MSG=0, |
michael@0 | 88 | INSTALLED_MODULE_MSG, |
michael@0 | 89 | INSTALLER_SCRIPT_NAME, |
michael@0 | 90 | MY_PLATFORM_IS, |
michael@0 | 91 | USING_PLATFORM, |
michael@0 | 92 | PARSED_INSTALL_SCRIPT, |
michael@0 | 93 | EXEC_FILE_MSG, |
michael@0 | 94 | EXEC_SUCCESS, |
michael@0 | 95 | INSTALLATION_COMPLETE_MSG, |
michael@0 | 96 | USER_ABORT |
michael@0 | 97 | }; |
michael@0 | 98 | |
michael@0 | 99 | static char *msgStrings[] = { |
michael@0 | 100 | "Installed file %s to %s\n", |
michael@0 | 101 | "Installed module \"%s\" into module database\n", |
michael@0 | 102 | "Using installer script \"%s\"\n", |
michael@0 | 103 | "Current platform is %s\n", |
michael@0 | 104 | "Using installation parameters for platform %s\n", |
michael@0 | 105 | "Successfully parsed installation script\n", |
michael@0 | 106 | "Executing \"%s\"...\n", |
michael@0 | 107 | "\"%s\" executed successfully\n", |
michael@0 | 108 | "\nInstallation completed successfully\n", |
michael@0 | 109 | "\nAborting...\n" |
michael@0 | 110 | }; |
michael@0 | 111 | |
michael@0 | 112 | /************************************************************************** |
michael@0 | 113 | * S t r i n g N o d e |
michael@0 | 114 | */ |
michael@0 | 115 | typedef struct StringNode_str { |
michael@0 | 116 | char *str; |
michael@0 | 117 | struct StringNode_str* next; |
michael@0 | 118 | } StringNode; |
michael@0 | 119 | |
michael@0 | 120 | StringNode* StringNode_new() |
michael@0 | 121 | { |
michael@0 | 122 | StringNode* new_this; |
michael@0 | 123 | new_this = (StringNode*)malloc(sizeof(StringNode)); |
michael@0 | 124 | new_this->str=NULL; |
michael@0 | 125 | new_this->next=NULL; |
michael@0 | 126 | return new_this; |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | void StringNode_delete(StringNode* s) |
michael@0 | 130 | { |
michael@0 | 131 | if(s->str) { |
michael@0 | 132 | PR_Free(s->str); |
michael@0 | 133 | s->str=NULL; |
michael@0 | 134 | } |
michael@0 | 135 | } |
michael@0 | 136 | |
michael@0 | 137 | /************************************************************************* |
michael@0 | 138 | * S t r i n g L i s t |
michael@0 | 139 | */ |
michael@0 | 140 | typedef struct StringList_str { |
michael@0 | 141 | StringNode* head; |
michael@0 | 142 | StringNode* tail; |
michael@0 | 143 | } StringList; |
michael@0 | 144 | |
michael@0 | 145 | void StringList_new(StringList* list) |
michael@0 | 146 | { |
michael@0 | 147 | list->head=NULL; |
michael@0 | 148 | list->tail=NULL; |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | void StringList_delete(StringList* list) |
michael@0 | 152 | { |
michael@0 | 153 | StringNode *tmp; |
michael@0 | 154 | while(list->head) { |
michael@0 | 155 | tmp = list->head; |
michael@0 | 156 | list->head = list->head->next; |
michael@0 | 157 | StringNode_delete(tmp); |
michael@0 | 158 | } |
michael@0 | 159 | } |
michael@0 | 160 | |
michael@0 | 161 | void |
michael@0 | 162 | StringList_Append(StringList* list, char* str) |
michael@0 | 163 | { |
michael@0 | 164 | if(!str) { |
michael@0 | 165 | return; |
michael@0 | 166 | } |
michael@0 | 167 | |
michael@0 | 168 | if(!list->tail) { |
michael@0 | 169 | /* This is the first element */ |
michael@0 | 170 | list->head = list->tail = StringNode_new(); |
michael@0 | 171 | } else { |
michael@0 | 172 | list->tail->next = StringNode_new(); |
michael@0 | 173 | list->tail = list->tail->next; |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | list->tail->str = PR_Strdup(str); |
michael@0 | 177 | list->tail->next = NULL; /* just to be sure */ |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | /************************************************************************** |
michael@0 | 181 | * |
michael@0 | 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 |
michael@0 | 183 | * |
michael@0 | 184 | * Sets the error handler to be used by the library. Returns the current |
michael@0 | 185 | * error handler function. |
michael@0 | 186 | */ |
michael@0 | 187 | Pk11Install_ErrorHandler |
michael@0 | 188 | Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler) |
michael@0 | 189 | { |
michael@0 | 190 | Pk11Install_ErrorHandler old; |
michael@0 | 191 | |
michael@0 | 192 | if(!errorHandlerLock) { |
michael@0 | 193 | errorHandlerLock = PR_NewLock(); |
michael@0 | 194 | } |
michael@0 | 195 | |
michael@0 | 196 | PR_Lock(errorHandlerLock); |
michael@0 | 197 | |
michael@0 | 198 | old = errorHandler; |
michael@0 | 199 | errorHandler = handler; |
michael@0 | 200 | |
michael@0 | 201 | PR_Unlock(errorHandlerLock); |
michael@0 | 202 | |
michael@0 | 203 | return old; |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | /************************************************************************** |
michael@0 | 207 | * |
michael@0 | 208 | * P k 1 1 I n s t a l l _ I n i t |
michael@0 | 209 | * |
michael@0 | 210 | * Does initialization that otherwise would be done on the fly. Only |
michael@0 | 211 | * needs to be called by multithreaded apps, before they make any calls |
michael@0 | 212 | * to this library. |
michael@0 | 213 | */ |
michael@0 | 214 | void |
michael@0 | 215 | Pk11Install_Init() |
michael@0 | 216 | { |
michael@0 | 217 | if(!errorHandlerLock) { |
michael@0 | 218 | errorHandlerLock = PR_NewLock(); |
michael@0 | 219 | } |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | /************************************************************************** |
michael@0 | 223 | * |
michael@0 | 224 | * P k 1 1 I n s t a l l _ R e l e a s e |
michael@0 | 225 | * |
michael@0 | 226 | * Releases static data structures used by the library. Don't use the |
michael@0 | 227 | * library after calling this, unless you call Pk11Install_Init() |
michael@0 | 228 | * first. This function doesn't have to be called at all unless you're |
michael@0 | 229 | * really anal about freeing memory before your program exits. |
michael@0 | 230 | */ |
michael@0 | 231 | void |
michael@0 | 232 | Pk11Install_Release() |
michael@0 | 233 | { |
michael@0 | 234 | if(errorHandlerLock) { |
michael@0 | 235 | PR_Free(errorHandlerLock); |
michael@0 | 236 | errorHandlerLock = NULL; |
michael@0 | 237 | } |
michael@0 | 238 | } |
michael@0 | 239 | |
michael@0 | 240 | /************************************************************************* |
michael@0 | 241 | * |
michael@0 | 242 | * e r r o r |
michael@0 | 243 | * |
michael@0 | 244 | * Takes an error code and its arguments, creates the error string, |
michael@0 | 245 | * and sends the string to the handler function if it exists. |
michael@0 | 246 | */ |
michael@0 | 247 | |
michael@0 | 248 | #ifdef OSF1 |
michael@0 | 249 | /* stdarg has already been pulled in from NSPR */ |
michael@0 | 250 | #undef va_start |
michael@0 | 251 | #undef va_end |
michael@0 | 252 | #undef va_arg |
michael@0 | 253 | #include <varargs.h> |
michael@0 | 254 | #else |
michael@0 | 255 | #include <stdarg.h> |
michael@0 | 256 | #endif |
michael@0 | 257 | |
michael@0 | 258 | #ifdef OSF1 |
michael@0 | 259 | static void |
michael@0 | 260 | error(long va_alist, ...) |
michael@0 | 261 | #else |
michael@0 | 262 | static void |
michael@0 | 263 | error(Pk11Install_Error errcode, ...) |
michael@0 | 264 | #endif |
michael@0 | 265 | { |
michael@0 | 266 | |
michael@0 | 267 | va_list ap; |
michael@0 | 268 | char *errstr; |
michael@0 | 269 | Pk11Install_ErrorHandler handler; |
michael@0 | 270 | |
michael@0 | 271 | if(!errorHandlerLock) { |
michael@0 | 272 | errorHandlerLock = PR_NewLock(); |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | PR_Lock(errorHandlerLock); |
michael@0 | 276 | |
michael@0 | 277 | handler = errorHandler; |
michael@0 | 278 | |
michael@0 | 279 | PR_Unlock(errorHandlerLock); |
michael@0 | 280 | |
michael@0 | 281 | if(handler) { |
michael@0 | 282 | #ifdef OSF1 |
michael@0 | 283 | va_start(ap); |
michael@0 | 284 | errstr = PR_vsmprintf(errorString[va_arg(ap, Pk11Install_Error)], ap); |
michael@0 | 285 | #else |
michael@0 | 286 | va_start(ap, errcode); |
michael@0 | 287 | errstr = PR_vsmprintf(errorString[errcode], ap); |
michael@0 | 288 | #endif |
michael@0 | 289 | handler(errstr); |
michael@0 | 290 | PR_smprintf_free(errstr); |
michael@0 | 291 | va_end(ap); |
michael@0 | 292 | } |
michael@0 | 293 | } |
michael@0 | 294 | |
michael@0 | 295 | /************************************************************************* |
michael@0 | 296 | * |
michael@0 | 297 | * j a r _ c a l l b a c k |
michael@0 | 298 | */ |
michael@0 | 299 | static int |
michael@0 | 300 | jar_callback(int status, JAR *foo, const char *bar, char *pathname, |
michael@0 | 301 | char *errortext) { |
michael@0 | 302 | char *string; |
michael@0 | 303 | |
michael@0 | 304 | string = PR_smprintf("JAR error %d: %s in file %s\n", status, errortext, |
michael@0 | 305 | pathname); |
michael@0 | 306 | error(PK11_INSTALL_ERROR_STRING, string); |
michael@0 | 307 | PR_smprintf_free(string); |
michael@0 | 308 | return 0; |
michael@0 | 309 | } |
michael@0 | 310 | |
michael@0 | 311 | /************************************************************************* |
michael@0 | 312 | * |
michael@0 | 313 | * P k 1 1 I n s t a l l _ D o I n s t a l l |
michael@0 | 314 | * |
michael@0 | 315 | * jarFile is the path of a JAR in the PKCS #11 module JAR format. |
michael@0 | 316 | * installDir is the directory relative to which files will be |
michael@0 | 317 | * installed. |
michael@0 | 318 | */ |
michael@0 | 319 | Pk11Install_Error |
michael@0 | 320 | Pk11Install_DoInstall(char *jarFile, const char *installDir, |
michael@0 | 321 | const char *tempDir, PRFileDesc *feedback, short force, PRBool noverify) |
michael@0 | 322 | { |
michael@0 | 323 | JAR *jar; |
michael@0 | 324 | char *installer; |
michael@0 | 325 | unsigned long installer_len; |
michael@0 | 326 | int status; |
michael@0 | 327 | Pk11Install_Error ret; |
michael@0 | 328 | PRBool made_temp_file; |
michael@0 | 329 | Pk11Install_Info installInfo; |
michael@0 | 330 | Pk11Install_Platform *platform; |
michael@0 | 331 | char* errMsg; |
michael@0 | 332 | char sysname[SYS_INFO_BUFFER_LENGTH], release[SYS_INFO_BUFFER_LENGTH], |
michael@0 | 333 | arch[SYS_INFO_BUFFER_LENGTH]; |
michael@0 | 334 | char *myPlatform; |
michael@0 | 335 | |
michael@0 | 336 | jar=NULL; |
michael@0 | 337 | ret = PK11_INSTALL_UNSPECIFIED; |
michael@0 | 338 | made_temp_file=PR_FALSE; |
michael@0 | 339 | errMsg=NULL; |
michael@0 | 340 | Pk11Install_Info_init(&installInfo); |
michael@0 | 341 | |
michael@0 | 342 | /* |
michael@0 | 343 | printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n", |
michael@0 | 344 | jarFile, installDir, tempDir); |
michael@0 | 345 | */ |
michael@0 | 346 | |
michael@0 | 347 | /* |
michael@0 | 348 | * Check out jarFile and installDir for validity |
michael@0 | 349 | */ |
michael@0 | 350 | if( PR_Access(installDir, PR_ACCESS_EXISTS) != PR_SUCCESS ) { |
michael@0 | 351 | error(PK11_INSTALL_DIR_DOESNT_EXIST, installDir); |
michael@0 | 352 | return PK11_INSTALL_DIR_DOESNT_EXIST; |
michael@0 | 353 | } |
michael@0 | 354 | if(!tempDir) { |
michael@0 | 355 | tempDir = "."; |
michael@0 | 356 | } |
michael@0 | 357 | if( PR_Access(tempDir, PR_ACCESS_EXISTS) != PR_SUCCESS ) { |
michael@0 | 358 | error(PK11_INSTALL_DIR_DOESNT_EXIST, tempDir); |
michael@0 | 359 | return PK11_INSTALL_DIR_DOESNT_EXIST; |
michael@0 | 360 | } |
michael@0 | 361 | if( PR_Access(tempDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS ) { |
michael@0 | 362 | error(PK11_INSTALL_DIR_NOT_WRITEABLE, tempDir); |
michael@0 | 363 | return PK11_INSTALL_DIR_NOT_WRITEABLE; |
michael@0 | 364 | } |
michael@0 | 365 | if( (PR_Access(jarFile, PR_ACCESS_EXISTS) != PR_SUCCESS) ) { |
michael@0 | 366 | error(PK11_INSTALL_FILE_DOESNT_EXIST, jarFile); |
michael@0 | 367 | return PK11_INSTALL_FILE_DOESNT_EXIST; |
michael@0 | 368 | } |
michael@0 | 369 | if( PR_Access(jarFile, PR_ACCESS_READ_OK) != PR_SUCCESS ) { |
michael@0 | 370 | error(PK11_INSTALL_FILE_NOT_READABLE, jarFile); |
michael@0 | 371 | return PK11_INSTALL_FILE_NOT_READABLE; |
michael@0 | 372 | } |
michael@0 | 373 | |
michael@0 | 374 | /* |
michael@0 | 375 | * Extract the JAR file |
michael@0 | 376 | */ |
michael@0 | 377 | jar = JAR_new(); |
michael@0 | 378 | JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback); |
michael@0 | 379 | |
michael@0 | 380 | if(noverify) { |
michael@0 | 381 | status = JAR_pass_archive_unverified(jar, jarArchGuess, jarFile, "url"); |
michael@0 | 382 | } else { |
michael@0 | 383 | status = JAR_pass_archive(jar, jarArchGuess, jarFile, "url"); |
michael@0 | 384 | } |
michael@0 | 385 | if( (status < 0) || (jar->valid < 0) ) { |
michael@0 | 386 | if (status >= JAR_BASE && status <= JAR_BASE_END) { |
michael@0 | 387 | error(PK11_INSTALL_JAR_ERROR, jarFile, JAR_get_error(status)); |
michael@0 | 388 | } else { |
michael@0 | 389 | error(PK11_INSTALL_JAR_ERROR, jarFile, |
michael@0 | 390 | mySECU_ErrorString(PORT_GetError())); |
michael@0 | 391 | } |
michael@0 | 392 | ret=PK11_INSTALL_JAR_ERROR; |
michael@0 | 393 | goto loser; |
michael@0 | 394 | } |
michael@0 | 395 | /*printf("passed the archive\n");*/ |
michael@0 | 396 | |
michael@0 | 397 | /* |
michael@0 | 398 | * Show the user security information, allow them to abort or continue |
michael@0 | 399 | */ |
michael@0 | 400 | if( Pk11Install_UserVerifyJar(jar, PR_STDOUT, |
michael@0 | 401 | force?PR_FALSE:PR_TRUE) && !force) { |
michael@0 | 402 | if(feedback) { |
michael@0 | 403 | PR_fprintf(feedback, msgStrings[USER_ABORT]); |
michael@0 | 404 | } |
michael@0 | 405 | ret=PK11_INSTALL_USER_ABORT; |
michael@0 | 406 | goto loser; |
michael@0 | 407 | } |
michael@0 | 408 | |
michael@0 | 409 | /* |
michael@0 | 410 | * Get the name of the installation file |
michael@0 | 411 | */ |
michael@0 | 412 | if( JAR_get_metainfo(jar, NULL, INSTALL_METAINFO_TAG, (void**)&installer, |
michael@0 | 413 | (unsigned long*)&installer_len) ) { |
michael@0 | 414 | error(PK11_INSTALL_NO_INSTALLER_SCRIPT); |
michael@0 | 415 | ret=PK11_INSTALL_NO_INSTALLER_SCRIPT; |
michael@0 | 416 | goto loser; |
michael@0 | 417 | } |
michael@0 | 418 | if(feedback) { |
michael@0 | 419 | PR_fprintf(feedback, msgStrings[INSTALLER_SCRIPT_NAME], installer); |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | /* |
michael@0 | 423 | * Extract the installation file |
michael@0 | 424 | */ |
michael@0 | 425 | if( PR_Access(SCRIPT_TEMP_FILE, PR_ACCESS_EXISTS) == PR_SUCCESS) { |
michael@0 | 426 | if( PR_Delete(SCRIPT_TEMP_FILE) != PR_SUCCESS) { |
michael@0 | 427 | error(PK11_INSTALL_DELETE_TEMP_FILE, SCRIPT_TEMP_FILE); |
michael@0 | 428 | ret=PK11_INSTALL_DELETE_TEMP_FILE; |
michael@0 | 429 | goto loser; |
michael@0 | 430 | } |
michael@0 | 431 | } |
michael@0 | 432 | if(noverify) { |
michael@0 | 433 | status = JAR_extract(jar, installer, SCRIPT_TEMP_FILE); |
michael@0 | 434 | } else { |
michael@0 | 435 | status = JAR_verified_extract(jar, installer, SCRIPT_TEMP_FILE); |
michael@0 | 436 | } |
michael@0 | 437 | if(status) { |
michael@0 | 438 | if (status >= JAR_BASE && status <= JAR_BASE_END) { |
michael@0 | 439 | error(PK11_INSTALL_JAR_EXTRACT, installer, JAR_get_error(status)); |
michael@0 | 440 | } else { |
michael@0 | 441 | error(PK11_INSTALL_JAR_EXTRACT, installer, |
michael@0 | 442 | mySECU_ErrorString(PORT_GetError())); |
michael@0 | 443 | } |
michael@0 | 444 | ret = PK11_INSTALL_JAR_EXTRACT; |
michael@0 | 445 | goto loser; |
michael@0 | 446 | } else { |
michael@0 | 447 | made_temp_file = PR_TRUE; |
michael@0 | 448 | } |
michael@0 | 449 | |
michael@0 | 450 | /* |
michael@0 | 451 | * Parse the installation file into a syntax tree |
michael@0 | 452 | */ |
michael@0 | 453 | Pk11Install_FD = PR_Open(SCRIPT_TEMP_FILE, PR_RDONLY, 0); |
michael@0 | 454 | if(!Pk11Install_FD) { |
michael@0 | 455 | error(PK11_INSTALL_OPEN_SCRIPT_FILE, SCRIPT_TEMP_FILE); |
michael@0 | 456 | ret=PK11_INSTALL_OPEN_SCRIPT_FILE; |
michael@0 | 457 | goto loser; |
michael@0 | 458 | } |
michael@0 | 459 | if(Pk11Install_yyparse()) { |
michael@0 | 460 | error(PK11_INSTALL_SCRIPT_PARSE, installer, |
michael@0 | 461 | Pk11Install_yyerrstr ? Pk11Install_yyerrstr : ""); |
michael@0 | 462 | ret=PK11_INSTALL_SCRIPT_PARSE; |
michael@0 | 463 | goto loser; |
michael@0 | 464 | } |
michael@0 | 465 | |
michael@0 | 466 | #if 0 |
michael@0 | 467 | /* for debugging */ |
michael@0 | 468 | Pk11Install_valueList->Print(0); |
michael@0 | 469 | #endif |
michael@0 | 470 | |
michael@0 | 471 | /* |
michael@0 | 472 | * From the syntax tree, build a semantic structure |
michael@0 | 473 | */ |
michael@0 | 474 | errMsg = Pk11Install_Info_Generate(&installInfo,Pk11Install_valueList); |
michael@0 | 475 | if(errMsg) { |
michael@0 | 476 | error(PK11_INSTALL_SEMANTIC, errMsg); |
michael@0 | 477 | ret=PK11_INSTALL_SEMANTIC; |
michael@0 | 478 | goto loser; |
michael@0 | 479 | } |
michael@0 | 480 | #if 0 |
michael@0 | 481 | installInfo.Print(0); |
michael@0 | 482 | #endif |
michael@0 | 483 | |
michael@0 | 484 | if(feedback) { |
michael@0 | 485 | PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]); |
michael@0 | 486 | } |
michael@0 | 487 | |
michael@0 | 488 | /* |
michael@0 | 489 | * Figure out which platform to use |
michael@0 | 490 | */ |
michael@0 | 491 | { |
michael@0 | 492 | sysname[0] = release[0] = arch[0] = '\0'; |
michael@0 | 493 | |
michael@0 | 494 | if( (PR_GetSystemInfo(PR_SI_SYSNAME, sysname, SYS_INFO_BUFFER_LENGTH) |
michael@0 | 495 | != PR_SUCCESS) || |
michael@0 | 496 | (PR_GetSystemInfo(PR_SI_RELEASE, release, SYS_INFO_BUFFER_LENGTH) |
michael@0 | 497 | != PR_SUCCESS) || |
michael@0 | 498 | (PR_GetSystemInfo(PR_SI_ARCHITECTURE, arch, SYS_INFO_BUFFER_LENGTH) |
michael@0 | 499 | != PR_SUCCESS) ) { |
michael@0 | 500 | error(PK11_INSTALL_SYSINFO); |
michael@0 | 501 | ret=PK11_INSTALL_SYSINFO; |
michael@0 | 502 | goto loser; |
michael@0 | 503 | } |
michael@0 | 504 | myPlatform = PR_smprintf("%s:%s:%s", sysname, release, arch); |
michael@0 | 505 | platform = Pk11Install_Info_GetBestPlatform(&installInfo,myPlatform); |
michael@0 | 506 | if(!platform) { |
michael@0 | 507 | error(PK11_INSTALL_NO_PLATFORM, myPlatform); |
michael@0 | 508 | PR_smprintf_free(myPlatform); |
michael@0 | 509 | ret=PK11_INSTALL_NO_PLATFORM; |
michael@0 | 510 | goto loser; |
michael@0 | 511 | } |
michael@0 | 512 | if(feedback) { |
michael@0 | 513 | PR_fprintf(feedback, msgStrings[MY_PLATFORM_IS], myPlatform); |
michael@0 | 514 | PR_fprintf(feedback, msgStrings[USING_PLATFORM], |
michael@0 | 515 | Pk11Install_PlatformName_GetString(&platform->name)); |
michael@0 | 516 | } |
michael@0 | 517 | PR_smprintf_free(myPlatform); |
michael@0 | 518 | } |
michael@0 | 519 | |
michael@0 | 520 | /* Run the install for that platform */ |
michael@0 | 521 | ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify); |
michael@0 | 522 | if(ret) { |
michael@0 | 523 | goto loser; |
michael@0 | 524 | } |
michael@0 | 525 | |
michael@0 | 526 | ret = PK11_INSTALL_SUCCESS; |
michael@0 | 527 | loser: |
michael@0 | 528 | if(Pk11Install_valueList) { |
michael@0 | 529 | Pk11Install_ValueList_delete(Pk11Install_valueList); |
michael@0 | 530 | PR_Free(Pk11Install_valueList); |
michael@0 | 531 | Pk11Install_valueList = NULL; |
michael@0 | 532 | } |
michael@0 | 533 | if(jar) { |
michael@0 | 534 | JAR_destroy(jar); |
michael@0 | 535 | } |
michael@0 | 536 | if(made_temp_file) { |
michael@0 | 537 | PR_Delete(SCRIPT_TEMP_FILE); |
michael@0 | 538 | } |
michael@0 | 539 | if(errMsg) { |
michael@0 | 540 | PR_smprintf_free(errMsg); |
michael@0 | 541 | } |
michael@0 | 542 | return ret; |
michael@0 | 543 | } |
michael@0 | 544 | |
michael@0 | 545 | /* |
michael@0 | 546 | ///////////////////////////////////////////////////////////////////////// |
michael@0 | 547 | // actually run the installation, copying files to and fro |
michael@0 | 548 | */ |
michael@0 | 549 | static Pk11Install_Error |
michael@0 | 550 | DoInstall(JAR *jar, const char *installDir, const char *tempDir, |
michael@0 | 551 | Pk11Install_Platform *platform, PRFileDesc *feedback, PRBool noverify) |
michael@0 | 552 | { |
michael@0 | 553 | Pk11Install_File *file; |
michael@0 | 554 | Pk11Install_Error ret; |
michael@0 | 555 | char *reldir; |
michael@0 | 556 | char *dest; |
michael@0 | 557 | char *modDest; |
michael@0 | 558 | char *cp; |
michael@0 | 559 | int i; |
michael@0 | 560 | int status; |
michael@0 | 561 | char *tempname, *temp; |
michael@0 | 562 | StringList executables; |
michael@0 | 563 | StringNode *execNode; |
michael@0 | 564 | PRProcessAttr *attr; |
michael@0 | 565 | PRProcess *proc; |
michael@0 | 566 | char *argv[2]; |
michael@0 | 567 | char *envp[1]; |
michael@0 | 568 | int errcode; |
michael@0 | 569 | |
michael@0 | 570 | ret=PK11_INSTALL_UNSPECIFIED; |
michael@0 | 571 | reldir=NULL; |
michael@0 | 572 | dest=NULL; |
michael@0 | 573 | modDest=NULL; |
michael@0 | 574 | tempname=NULL; |
michael@0 | 575 | |
michael@0 | 576 | StringList_new(&executables); |
michael@0 | 577 | /* |
michael@0 | 578 | // Create Temporary directory |
michael@0 | 579 | */ |
michael@0 | 580 | tempname = PR_smprintf("%s/%s", tempDir, TEMPORARY_DIRECTORY_NAME); |
michael@0 | 581 | if( PR_Access(tempname, PR_ACCESS_EXISTS)==PR_SUCCESS ) { |
michael@0 | 582 | /* Left over from previous run? Delete it. */ |
michael@0 | 583 | rm_dash_r(tempname); |
michael@0 | 584 | } |
michael@0 | 585 | if(PR_MkDir(tempname, 0700) != PR_SUCCESS) { |
michael@0 | 586 | error(PK11_INSTALL_CREATE_DIR, tempname); |
michael@0 | 587 | ret = PK11_INSTALL_CREATE_DIR; |
michael@0 | 588 | goto loser; |
michael@0 | 589 | } |
michael@0 | 590 | |
michael@0 | 591 | /* |
michael@0 | 592 | // Install all the files |
michael@0 | 593 | */ |
michael@0 | 594 | for(i=0; i < platform->numFiles; i++) { |
michael@0 | 595 | file = &platform->files[i]; |
michael@0 | 596 | |
michael@0 | 597 | if(file->relativePath) { |
michael@0 | 598 | PRBool foundMarker = PR_FALSE; |
michael@0 | 599 | reldir = PR_Strdup(file->relativePath); |
michael@0 | 600 | |
michael@0 | 601 | /* Replace all the markers with the directories for which they stand */ |
michael@0 | 602 | while(1) { |
michael@0 | 603 | if( (cp=PL_strcasestr(reldir, ROOT_MARKER)) ) { |
michael@0 | 604 | /* Has a %root% marker */ |
michael@0 | 605 | *cp = '\0'; |
michael@0 | 606 | temp = PR_smprintf("%s%s%s", reldir, installDir, |
michael@0 | 607 | cp+strlen(ROOT_MARKER)); |
michael@0 | 608 | PR_Free(reldir); |
michael@0 | 609 | reldir = temp; |
michael@0 | 610 | foundMarker = PR_TRUE; |
michael@0 | 611 | } else if( (cp = PL_strcasestr(reldir, TEMP_MARKER)) ) { |
michael@0 | 612 | /* Has a %temp% marker */ |
michael@0 | 613 | *cp = '\0'; |
michael@0 | 614 | temp = PR_smprintf("%s%s%s", reldir, tempname, |
michael@0 | 615 | cp+strlen(TEMP_MARKER)); |
michael@0 | 616 | PR_Free(reldir); |
michael@0 | 617 | reldir = temp; |
michael@0 | 618 | foundMarker = PR_TRUE; |
michael@0 | 619 | } else { |
michael@0 | 620 | break; |
michael@0 | 621 | } |
michael@0 | 622 | } |
michael@0 | 623 | if(!foundMarker) { |
michael@0 | 624 | /* Has no markers...this isn't really a relative directory */ |
michael@0 | 625 | error(PK11_INSTALL_BOGUS_REL_DIR, file->relativePath); |
michael@0 | 626 | ret = PK11_INSTALL_BOGUS_REL_DIR; |
michael@0 | 627 | goto loser; |
michael@0 | 628 | } |
michael@0 | 629 | dest = reldir; |
michael@0 | 630 | reldir = NULL; |
michael@0 | 631 | } else if(file->absolutePath) { |
michael@0 | 632 | dest = PR_Strdup(file->absolutePath); |
michael@0 | 633 | } |
michael@0 | 634 | |
michael@0 | 635 | /* Remember if this is the module file, we'll need to add it later */ |
michael@0 | 636 | if(i == platform->modFile) { |
michael@0 | 637 | modDest = PR_Strdup(dest); |
michael@0 | 638 | } |
michael@0 | 639 | |
michael@0 | 640 | /* Remember is this is an executable, we'll need to run it later */ |
michael@0 | 641 | if(file->executable) { |
michael@0 | 642 | StringList_Append(&executables,dest); |
michael@0 | 643 | /*executables.Append(dest);*/ |
michael@0 | 644 | } |
michael@0 | 645 | |
michael@0 | 646 | /* Make sure the directory we are targetting exists */ |
michael@0 | 647 | if( make_dirs(dest, file->permissions) ) { |
michael@0 | 648 | ret=PK11_INSTALL_CREATE_DIR; |
michael@0 | 649 | goto loser; |
michael@0 | 650 | } |
michael@0 | 651 | |
michael@0 | 652 | /* Actually extract the file onto the filesystem */ |
michael@0 | 653 | if(noverify) { |
michael@0 | 654 | status = JAR_extract(jar, (char*)file->jarPath, dest); |
michael@0 | 655 | } else { |
michael@0 | 656 | status = JAR_verified_extract(jar, (char*)file->jarPath, dest); |
michael@0 | 657 | } |
michael@0 | 658 | if(status) { |
michael@0 | 659 | if (status >= JAR_BASE && status <= JAR_BASE_END) { |
michael@0 | 660 | error(PK11_INSTALL_JAR_EXTRACT, file->jarPath, |
michael@0 | 661 | JAR_get_error(status)); |
michael@0 | 662 | } else { |
michael@0 | 663 | error(PK11_INSTALL_JAR_EXTRACT, file->jarPath, |
michael@0 | 664 | mySECU_ErrorString(PORT_GetError())); |
michael@0 | 665 | } |
michael@0 | 666 | ret=PK11_INSTALL_JAR_EXTRACT; |
michael@0 | 667 | goto loser; |
michael@0 | 668 | } |
michael@0 | 669 | if(feedback) { |
michael@0 | 670 | PR_fprintf(feedback, msgStrings[INSTALLED_FILE_MSG], |
michael@0 | 671 | file->jarPath, dest); |
michael@0 | 672 | } |
michael@0 | 673 | |
michael@0 | 674 | /* no NSPR command to change permissions? */ |
michael@0 | 675 | #ifdef XP_UNIX |
michael@0 | 676 | chmod(dest, file->permissions); |
michael@0 | 677 | #endif |
michael@0 | 678 | |
michael@0 | 679 | /* Memory clean-up tasks */ |
michael@0 | 680 | if(reldir) { |
michael@0 | 681 | PR_Free(reldir); |
michael@0 | 682 | reldir = NULL; |
michael@0 | 683 | } |
michael@0 | 684 | if(dest) { |
michael@0 | 685 | PR_Free(dest); |
michael@0 | 686 | dest = NULL; |
michael@0 | 687 | } |
michael@0 | 688 | } |
michael@0 | 689 | /* Make sure we found the module file */ |
michael@0 | 690 | if(!modDest) { |
michael@0 | 691 | /* Internal problem here, since every platform is supposed to have |
michael@0 | 692 | a module file */ |
michael@0 | 693 | error(PK11_INSTALL_NO_MOD_FILE, platform->moduleName); |
michael@0 | 694 | ret=PK11_INSTALL_NO_MOD_FILE; |
michael@0 | 695 | goto loser; |
michael@0 | 696 | } |
michael@0 | 697 | |
michael@0 | 698 | /* |
michael@0 | 699 | // Execute any executable files |
michael@0 | 700 | */ |
michael@0 | 701 | { |
michael@0 | 702 | argv[1] = NULL; |
michael@0 | 703 | envp[0] = NULL; |
michael@0 | 704 | for(execNode = executables.head; execNode; execNode = execNode->next) { |
michael@0 | 705 | attr = PR_NewProcessAttr(); |
michael@0 | 706 | argv[0] = PR_Strdup(execNode->str); |
michael@0 | 707 | |
michael@0 | 708 | /* Announce our intentions */ |
michael@0 | 709 | if(feedback) { |
michael@0 | 710 | PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str); |
michael@0 | 711 | } |
michael@0 | 712 | |
michael@0 | 713 | /* start the process */ |
michael@0 | 714 | if( !(proc=PR_CreateProcess(execNode->str, argv, envp, attr)) ) { |
michael@0 | 715 | PR_Free(argv[0]); |
michael@0 | 716 | PR_DestroyProcessAttr(attr); |
michael@0 | 717 | error(PK11_INSTALL_EXEC_FILE, execNode->str); |
michael@0 | 718 | ret=PK11_INSTALL_EXEC_FILE; |
michael@0 | 719 | goto loser; |
michael@0 | 720 | } |
michael@0 | 721 | |
michael@0 | 722 | /* wait for it to finish */ |
michael@0 | 723 | if( PR_WaitProcess(proc, &errcode) != PR_SUCCESS) { |
michael@0 | 724 | PR_Free(argv[0]); |
michael@0 | 725 | PR_DestroyProcessAttr(attr); |
michael@0 | 726 | error(PK11_INSTALL_WAIT_PROCESS, execNode->str); |
michael@0 | 727 | ret=PK11_INSTALL_WAIT_PROCESS; |
michael@0 | 728 | goto loser; |
michael@0 | 729 | } |
michael@0 | 730 | |
michael@0 | 731 | /* What happened? */ |
michael@0 | 732 | if(errcode) { |
michael@0 | 733 | /* process returned an error */ |
michael@0 | 734 | error(PK11_INSTALL_PROC_ERROR, execNode->str, errcode); |
michael@0 | 735 | } else if(feedback) { |
michael@0 | 736 | /* process ran successfully */ |
michael@0 | 737 | PR_fprintf(feedback, msgStrings[EXEC_SUCCESS], execNode->str); |
michael@0 | 738 | } |
michael@0 | 739 | |
michael@0 | 740 | PR_Free(argv[0]); |
michael@0 | 741 | PR_DestroyProcessAttr(attr); |
michael@0 | 742 | } |
michael@0 | 743 | } |
michael@0 | 744 | |
michael@0 | 745 | /* |
michael@0 | 746 | // Add the module |
michael@0 | 747 | */ |
michael@0 | 748 | status = Pk11Install_AddNewModule((char*)platform->moduleName, |
michael@0 | 749 | (char*)modDest, platform->mechFlags, platform->cipherFlags ); |
michael@0 | 750 | |
michael@0 | 751 | if(status != SECSuccess) { |
michael@0 | 752 | error(PK11_INSTALL_ADD_MODULE, platform->moduleName); |
michael@0 | 753 | ret=PK11_INSTALL_ADD_MODULE; |
michael@0 | 754 | goto loser; |
michael@0 | 755 | } |
michael@0 | 756 | if(feedback) { |
michael@0 | 757 | PR_fprintf(feedback, msgStrings[INSTALLED_MODULE_MSG], |
michael@0 | 758 | platform->moduleName); |
michael@0 | 759 | } |
michael@0 | 760 | |
michael@0 | 761 | if(feedback) { |
michael@0 | 762 | PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]); |
michael@0 | 763 | } |
michael@0 | 764 | |
michael@0 | 765 | ret = PK11_INSTALL_SUCCESS; |
michael@0 | 766 | |
michael@0 | 767 | loser: |
michael@0 | 768 | if(reldir) { |
michael@0 | 769 | PR_Free(reldir); |
michael@0 | 770 | } |
michael@0 | 771 | if(dest) { |
michael@0 | 772 | PR_Free(dest); |
michael@0 | 773 | } |
michael@0 | 774 | if(modDest) { |
michael@0 | 775 | PR_Free(modDest); |
michael@0 | 776 | } |
michael@0 | 777 | if(tempname) { |
michael@0 | 778 | PRFileInfo info; |
michael@0 | 779 | if(PR_GetFileInfo(tempname, &info) == PR_SUCCESS) { |
michael@0 | 780 | if(info.type == PR_FILE_DIRECTORY) { |
michael@0 | 781 | /* Recursively remove temporary directory */ |
michael@0 | 782 | if(rm_dash_r(tempname)) { |
michael@0 | 783 | error(PK11_INSTALL_REMOVE_DIR, |
michael@0 | 784 | tempname); |
michael@0 | 785 | ret=PK11_INSTALL_REMOVE_DIR; |
michael@0 | 786 | } |
michael@0 | 787 | |
michael@0 | 788 | } |
michael@0 | 789 | } |
michael@0 | 790 | PR_Free(tempname); |
michael@0 | 791 | } |
michael@0 | 792 | StringList_delete(&executables); |
michael@0 | 793 | return ret; |
michael@0 | 794 | } |
michael@0 | 795 | |
michael@0 | 796 | /* |
michael@0 | 797 | ////////////////////////////////////////////////////////////////////////// |
michael@0 | 798 | */ |
michael@0 | 799 | static char* |
michael@0 | 800 | PR_Strdup(const char* str) |
michael@0 | 801 | { |
michael@0 | 802 | char *tmp = (char*) PR_Malloc(strlen(str)+1); |
michael@0 | 803 | strcpy(tmp, str); |
michael@0 | 804 | return tmp; |
michael@0 | 805 | } |
michael@0 | 806 | |
michael@0 | 807 | /* |
michael@0 | 808 | * r m _ d a s h _ r |
michael@0 | 809 | * |
michael@0 | 810 | * Remove a file, or a directory recursively. |
michael@0 | 811 | * |
michael@0 | 812 | */ |
michael@0 | 813 | static int |
michael@0 | 814 | rm_dash_r (char *path) |
michael@0 | 815 | { |
michael@0 | 816 | PRDir *dir; |
michael@0 | 817 | PRDirEntry *entry; |
michael@0 | 818 | PRFileInfo fileinfo; |
michael@0 | 819 | char filename[240]; |
michael@0 | 820 | |
michael@0 | 821 | if(PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) { |
michael@0 | 822 | /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/ |
michael@0 | 823 | return -1; |
michael@0 | 824 | } |
michael@0 | 825 | if(fileinfo.type == PR_FILE_DIRECTORY) { |
michael@0 | 826 | |
michael@0 | 827 | dir = PR_OpenDir(path); |
michael@0 | 828 | if(!dir) { |
michael@0 | 829 | return -1; |
michael@0 | 830 | } |
michael@0 | 831 | |
michael@0 | 832 | /* Recursively delete all entries in the directory */ |
michael@0 | 833 | while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) { |
michael@0 | 834 | sprintf(filename, "%s/%s", path, entry->name); |
michael@0 | 835 | if(rm_dash_r(filename)) return -1; |
michael@0 | 836 | } |
michael@0 | 837 | |
michael@0 | 838 | if(PR_CloseDir(dir) != PR_SUCCESS) { |
michael@0 | 839 | return -1; |
michael@0 | 840 | } |
michael@0 | 841 | |
michael@0 | 842 | /* Delete the directory itself */ |
michael@0 | 843 | if(PR_RmDir(path) != PR_SUCCESS) { |
michael@0 | 844 | return -1; |
michael@0 | 845 | } |
michael@0 | 846 | } else { |
michael@0 | 847 | if(PR_Delete(path) != PR_SUCCESS) { |
michael@0 | 848 | return -1; |
michael@0 | 849 | } |
michael@0 | 850 | } |
michael@0 | 851 | return 0; |
michael@0 | 852 | } |
michael@0 | 853 | |
michael@0 | 854 | /*************************************************************************** |
michael@0 | 855 | * |
michael@0 | 856 | * m a k e _ d i r s |
michael@0 | 857 | * |
michael@0 | 858 | * Ensure that the directory portion of the path exists. This may require |
michael@0 | 859 | * making the directory, and its parent, and its parent's parent, etc. |
michael@0 | 860 | */ |
michael@0 | 861 | static int |
michael@0 | 862 | make_dirs(char *path, int file_perms) |
michael@0 | 863 | { |
michael@0 | 864 | char *Path; |
michael@0 | 865 | char *start; |
michael@0 | 866 | char *sep; |
michael@0 | 867 | int ret = 0; |
michael@0 | 868 | PRFileInfo info; |
michael@0 | 869 | |
michael@0 | 870 | if(!path) { |
michael@0 | 871 | return 0; |
michael@0 | 872 | } |
michael@0 | 873 | |
michael@0 | 874 | Path = PR_Strdup(path); |
michael@0 | 875 | start = strpbrk(Path, "/\\"); |
michael@0 | 876 | if(!start) { |
michael@0 | 877 | return 0; |
michael@0 | 878 | } |
michael@0 | 879 | start++; /* start right after first slash */ |
michael@0 | 880 | |
michael@0 | 881 | /* Each time through the loop add one more directory. */ |
michael@0 | 882 | while( (sep=strpbrk(start, "/\\")) ) { |
michael@0 | 883 | *sep = '\0'; |
michael@0 | 884 | |
michael@0 | 885 | if( PR_GetFileInfo(Path, &info) != PR_SUCCESS) { |
michael@0 | 886 | /* No such dir, we have to create it */ |
michael@0 | 887 | if( PR_MkDir(Path, dir_perms(file_perms)) != PR_SUCCESS) { |
michael@0 | 888 | error(PK11_INSTALL_CREATE_DIR, Path); |
michael@0 | 889 | ret = PK11_INSTALL_CREATE_DIR; |
michael@0 | 890 | goto loser; |
michael@0 | 891 | } |
michael@0 | 892 | } else { |
michael@0 | 893 | /* something exists by this name, make sure it's a directory */ |
michael@0 | 894 | if( info.type != PR_FILE_DIRECTORY ) { |
michael@0 | 895 | error(PK11_INSTALL_CREATE_DIR, Path); |
michael@0 | 896 | ret = PK11_INSTALL_CREATE_DIR; |
michael@0 | 897 | goto loser; |
michael@0 | 898 | } |
michael@0 | 899 | } |
michael@0 | 900 | |
michael@0 | 901 | /* If this is the lowest directory level, make sure it is writeable */ |
michael@0 | 902 | if(!strpbrk(sep+1, "/\\")) { |
michael@0 | 903 | if( PR_Access(Path, PR_ACCESS_WRITE_OK)!=PR_SUCCESS) { |
michael@0 | 904 | error(PK11_INSTALL_DIR_NOT_WRITEABLE, Path); |
michael@0 | 905 | ret = PK11_INSTALL_DIR_NOT_WRITEABLE; |
michael@0 | 906 | goto loser; |
michael@0 | 907 | } |
michael@0 | 908 | } |
michael@0 | 909 | |
michael@0 | 910 | start = sep+1; /* start after the next slash */ |
michael@0 | 911 | *sep = '/'; |
michael@0 | 912 | } |
michael@0 | 913 | |
michael@0 | 914 | loser: |
michael@0 | 915 | PR_Free(Path); |
michael@0 | 916 | return ret; |
michael@0 | 917 | } |
michael@0 | 918 | |
michael@0 | 919 | /************************************************************************* |
michael@0 | 920 | * d i r _ p e r m s |
michael@0 | 921 | * |
michael@0 | 922 | * Guesses the desired permissions on a directory based on the permissions |
michael@0 | 923 | * of a file that will be stored in it. Give read, write, and |
michael@0 | 924 | * execute to the owner (so we can create the file), read and |
michael@0 | 925 | * execute to anyone who has read permissions on the file, and write |
michael@0 | 926 | * to anyone who has write permissions on the file. |
michael@0 | 927 | */ |
michael@0 | 928 | static int |
michael@0 | 929 | dir_perms(int perms) |
michael@0 | 930 | { |
michael@0 | 931 | int ret = 0; |
michael@0 | 932 | |
michael@0 | 933 | /* owner */ |
michael@0 | 934 | ret |= 0700; |
michael@0 | 935 | |
michael@0 | 936 | /* group */ |
michael@0 | 937 | if(perms & 0040) { |
michael@0 | 938 | /* read on the file -> read and execute on the directory */ |
michael@0 | 939 | ret |= 0050; |
michael@0 | 940 | } |
michael@0 | 941 | if(perms & 0020) { |
michael@0 | 942 | /* write on the file -> write on the directory */ |
michael@0 | 943 | ret |= 0020; |
michael@0 | 944 | } |
michael@0 | 945 | |
michael@0 | 946 | /* others */ |
michael@0 | 947 | if(perms & 0004) { |
michael@0 | 948 | /* read on the file -> read and execute on the directory */ |
michael@0 | 949 | ret |= 0005; |
michael@0 | 950 | } |
michael@0 | 951 | if(perms & 0002) { |
michael@0 | 952 | /* write on the file -> write on the directory */ |
michael@0 | 953 | ret |= 0002; |
michael@0 | 954 | } |
michael@0 | 955 | |
michael@0 | 956 | return ret; |
michael@0 | 957 | } |