RetroZilla/security/nss/cmd/modutil/install-ds.c
Roy Tam fa0b14bb0c cherry-picked mozilla NSS upstream changes (to rev 50769413, which is on par with 3.21):
bug1009429, bug1216505, bug1208405, bug1216501, bug1216993, bug1216318, bug1218254, bug1219165, bug1211568, bug1220016
2020-01-07 22:06:51 +08:00

1516 lines
40 KiB
C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "install-ds.h"
#include <prmem.h>
#include <plstr.h>
#include <prprf.h>
#include <string.h>
#define PORT_Strcasecmp PL_strcasecmp
#define MODULE_FILE_STRING "ModuleFile"
#define MODULE_NAME_STRING "ModuleName"
#define MECH_FLAGS_STRING "DefaultMechanismFlags"
#define CIPHER_FLAGS_STRING "DefaultCipherFlags"
#define FILES_STRING "Files"
#define FORWARD_COMPATIBLE_STRING "ForwardCompatible"
#define PLATFORMS_STRING "Platforms"
#define RELATIVE_DIR_STRING "RelativePath"
#define ABSOLUTE_DIR_STRING "AbsolutePath"
#define FILE_PERMISSIONS_STRING "FilePermissions"
#define EQUIVALENT_PLATFORM_STRING "EquivalentPlatform"
#define EXECUTABLE_STRING "Executable"
#define DEFAULT_PERMISSIONS 0777
#define PLATFORM_SEPARATOR_CHAR ':'
/* Error codes */
enum {
BOGUS_RELATIVE_DIR=0,
BOGUS_ABSOLUTE_DIR,
BOGUS_FILE_PERMISSIONS,
NO_RELATIVE_DIR,
NO_ABSOLUTE_DIR,
EMPTY_PLATFORM_STRING,
BOGUS_PLATFORM_STRING,
REPEAT_MODULE_FILE,
REPEAT_MODULE_NAME,
BOGUS_MODULE_FILE,
BOGUS_MODULE_NAME,
REPEAT_MECH,
BOGUS_MECH_FLAGS,
REPEAT_CIPHER,
BOGUS_CIPHER_FLAGS,
REPEAT_FILES,
REPEAT_EQUIV,
BOGUS_EQUIV,
EQUIV_TOO_MUCH_INFO,
NO_FILES,
NO_MODULE_FILE,
NO_MODULE_NAME,
NO_PLATFORMS,
EQUIV_LOOP,
UNKNOWN_MODULE_FILE
};
/* Indexed by the above error codes */
static const char *errString[] = {
"%s: Invalid relative directory",
"%s: Invalid absolute directory",
"%s: Invalid file permissions",
"%s: No relative directory specified",
"%s: No absolute directory specified",
"Empty string given for platform name",
"%s: invalid platform string",
"More than one ModuleFile entry given for platform %s",
"More than one ModuleName entry given for platform %s",
"Invalid ModuleFile specification for platform %s",
"Invalid ModuleName specification for platform %s",
"More than one DefaultMechanismFlags entry given for platform %s",
"Invalid DefaultMechanismFlags specification for platform %s",
"More than one DefaultCipherFlags entry given for platform %s",
"Invalid DefaultCipherFlags entry given for platform %s",
"More than one Files entry given for platform %s",
"More than one EquivalentPlatform entry given for platform %s",
"Invalid EquivalentPlatform specification for platform %s",
"Module %s uses an EquivalentPlatform but also specifies its own"
" information",
"No Files specification in module %s",
"No ModuleFile specification in module %s",
"No ModuleName specification in module %s",
"No Platforms specification in installer script",
"Platform %s has an equivalency loop",
"Module file \"%s\" in platform \"%s\" does not exist"
};
static char* PR_Strdup(const char* str);
#define PAD(x) {int i; for(i=0;i<x;i++) printf(" ");}
#define PADINC 4
Pk11Install_File*
Pk11Install_File_new()
{
Pk11Install_File* new_this;
new_this = (Pk11Install_File*)PR_Malloc(sizeof(Pk11Install_File));
Pk11Install_File_init(new_this);
return new_this;
}
void
Pk11Install_File_init(Pk11Install_File* _this)
{
_this->jarPath=NULL;
_this->relativePath=NULL;
_this->absolutePath=NULL;
_this->executable=PR_FALSE;
_this->permissions=0;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: ~Pk11Install_File
// Class: Pk11Install_File
// Notes: Destructor.
*/
void
Pk11Install_File_delete(Pk11Install_File* _this)
{
Pk11Install_File_Cleanup(_this);
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Cleanup
// Class: Pk11Install_File
*/
void
Pk11Install_File_Cleanup(Pk11Install_File* _this)
{
if(_this->jarPath) {
PR_Free(_this->jarPath);
_this->jarPath = NULL;
}
if(_this->relativePath) {
PR_Free(_this->relativePath);
_this->relativePath = NULL;
}
if(_this->absolutePath) {
PR_Free(_this->absolutePath);
_this->absolutePath = NULL;
}
_this->permissions = 0;
_this->executable = PR_FALSE;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Generate
// Class: Pk11Install_File
// Notes: Creates a file data structure from a syntax tree.
// Returns: NULL for success, otherwise an error message.
*/
char*
Pk11Install_File_Generate(Pk11Install_File* _this,
const Pk11Install_Pair *pair)
{
Pk11Install_ListIter *iter;
Pk11Install_Value *val;
Pk11Install_Pair *subpair;
Pk11Install_ListIter *subiter;
Pk11Install_Value *subval;
char* errStr;
char *endp;
PRBool gotPerms;
iter=NULL;
subiter=NULL;
errStr=NULL;
gotPerms=PR_FALSE;
/* Clear out old values */
Pk11Install_File_Cleanup(_this);
_this->jarPath = PR_Strdup(pair->key);
/* Go through all the pairs under this file heading */
iter = Pk11Install_ListIter_new(pair->list);
for( ; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) {
if(val->type == PAIR_VALUE) {
subpair = val->pair;
/* Relative directory */
if(!PORT_Strcasecmp(subpair->key, RELATIVE_DIR_STRING)) {
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE)){
errStr = PR_smprintf(errString[BOGUS_RELATIVE_DIR],
_this->jarPath);
goto loser;
}
_this->relativePath = PR_Strdup(subval->string);
Pk11Install_ListIter_delete(subiter);
subiter = NULL;
/* Absolute directory */
} else if( !PORT_Strcasecmp(subpair->key, ABSOLUTE_DIR_STRING)) {
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE)){
errStr = PR_smprintf(errString[BOGUS_ABSOLUTE_DIR],
_this->jarPath);
goto loser;
}
_this->absolutePath = PR_Strdup(subval->string);
Pk11Install_ListIter_delete(subiter);
subiter = NULL;
/* file permissions */
} else if( !PORT_Strcasecmp(subpair->key,
FILE_PERMISSIONS_STRING)) {
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE) ||
!subval->string || !subval->string[0]){
errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
_this->jarPath);
goto loser;
}
_this->permissions = (int) strtol(subval->string, &endp, 8);
if(*endp != '\0') {
errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS],
_this->jarPath);
goto loser;
}
gotPerms = PR_TRUE;
Pk11Install_ListIter_delete(subiter);
subiter = NULL;
}
} else {
if(!PORT_Strcasecmp(val->string, EXECUTABLE_STRING)) {
_this->executable = PR_TRUE;
}
}
}
/* Default permission value */
if(!gotPerms) {
_this->permissions = DEFAULT_PERMISSIONS;
}
/* Make sure we got all the information */
if(!_this->relativePath && !_this->absolutePath) {
errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
goto loser;
}
#if 0
if(!_this->relativePath ) {
errStr = PR_smprintf(errString[NO_RELATIVE_DIR], _this->jarPath);
goto loser;
}
if(!_this->absolutePath) {
errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath);
goto loser;
}
#endif
loser:
if(iter) {
Pk11Install_ListIter_delete(iter);
PR_Free(iter);
}
if(subiter) {
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
}
return errStr;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Print
// Class: Pk11Install_File
*/
void
Pk11Install_File_Print(Pk11Install_File* _this, int pad)
{
PAD(pad); printf("jarPath: %s\n",
_this->jarPath ? _this->jarPath : "<NULL>");
PAD(pad); printf("relativePath: %s\n",
_this->relativePath ? _this->relativePath: "<NULL>");
PAD(pad); printf("absolutePath: %s\n",
_this->absolutePath ? _this->absolutePath: "<NULL>");
PAD(pad); printf("permissions: %o\n", _this->permissions);
}
Pk11Install_PlatformName*
Pk11Install_PlatformName_new()
{
Pk11Install_PlatformName* new_this;
new_this = (Pk11Install_PlatformName*)
PR_Malloc(sizeof(Pk11Install_PlatformName));
Pk11Install_PlatformName_init(new_this);
return new_this;
}
void
Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this)
{
_this->OS = NULL;
_this->verString = NULL;
_this->numDigits = 0;
_this->arch = NULL;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: ~Pk11Install_PlatformName
// Class: Pk11Install_PlatformName
*/
void
Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this)
{
Pk11Install_PlatformName_Cleanup(_this);
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Cleanup
// Class: Pk11Install_PlatformName
*/
void
Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this)
{
if(_this->OS) {
PR_Free(_this->OS);
_this->OS = NULL;
}
if(_this->verString) {
int i;
for (i=0; i<_this->numDigits; i++) {
PR_Free(_this->verString[i]);
}
PR_Free(_this->verString);
_this->verString = NULL;
}
if(_this->arch) {
PR_Free(_this->arch);
_this->arch = NULL;
}
_this->numDigits = 0;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Generate
// Class: Pk11Install_PlatformName
// Notes: Extracts the information from a platform string.
*/
char*
Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this,
const char *str)
{
char *errStr;
char *copy;
char *end, *start; /* start and end of a section (OS, version, arch)*/
char *pend, *pstart; /* start and end of one portion of version*/
char *endp; /* used by strtol*/
int periods, i;
errStr=NULL;
copy=NULL;
if(!str) {
errStr = PR_smprintf(errString[EMPTY_PLATFORM_STRING]);
goto loser;
}
copy = PR_Strdup(str);
/*
// Get the OS
*/
end = strchr(copy, PLATFORM_SEPARATOR_CHAR);
if(!end || end==copy) {
errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
goto loser;
}
*end = '\0';
_this->OS = PR_Strdup(copy);
/*
// Get the digits of the version of form: x.x.x (arbitrary number of digits)
*/
start = end+1;
end = strchr(start, PLATFORM_SEPARATOR_CHAR);
if(!end) {
errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
goto loser;
}
*end = '\0';
if(end!=start) {
/* Find out how many periods*/
periods = 0;
pstart = start;
while( (pend=strchr(pstart, '.')) ) {
periods++;
pstart = pend+1;
}
_this->numDigits= 1+ periods;
_this->verString = (char**)PR_Malloc(sizeof(char*)*_this->numDigits);
pstart = start;
i = 0;
/* Get the digits before each period*/
while( (pend=strchr(pstart, '.')) ) {
if(pend == pstart) {
errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
goto loser;
}
*pend = '\0';
_this->verString[i] = PR_Strdup(pstart);
endp = pend;
if(endp==pstart || (*endp != '\0')) {
errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
goto loser;
}
pstart = pend+1;
i++;
}
/* Last digit comes after the last period*/
if(*pstart == '\0') {
errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
goto loser;
}
_this->verString[i] = PR_Strdup(pstart);
/*
if(endp==pstart || (*endp != '\0')) {
errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
goto loser;
}
*/
} else {
_this->verString = NULL;
_this->numDigits = 0;
}
/*
// Get the architecture
*/
start = end+1;
if( strchr(start, PLATFORM_SEPARATOR_CHAR) ) {
errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str);
goto loser;
}
_this->arch = PR_Strdup(start);
if(copy) {
PR_Free(copy);
}
return NULL;
loser:
if(_this->OS) {
PR_Free(_this->OS);
_this->OS = NULL;
}
if(_this->verString) {
for (i=0; i<_this->numDigits; i++) {
PR_Free(_this->verString[i]);
}
PR_Free(_this->verString);
_this->verString = NULL;
}
_this->numDigits = 0;
if(_this->arch) {
PR_Free(_this->arch);
_this->arch = NULL;
}
if(copy) {
PR_Free(copy);
}
return errStr;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: operator ==
// Class: Pk11Install_PlatformName
// Returns: PR_TRUE if the platform have the same OS, arch, and version
*/
PRBool
Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this,
Pk11Install_PlatformName* cmp)
{
int i;
if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
return PR_FALSE;
}
if( PORT_Strcasecmp(_this->OS, cmp->OS) ||
PORT_Strcasecmp(_this->arch, cmp->arch) ||
_this->numDigits != cmp->numDigits ) {
return PR_FALSE;
}
for(i=0; i < _this->numDigits; i++) {
if(PORT_Strcasecmp(_this->verString[i], cmp->verString[i])) {
return PR_FALSE;
}
}
return PR_TRUE;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: operator <=
// Class: Pk11Install_PlatformName
// Returns: PR_TRUE if the platform have the same OS and arch and a lower
// or equal release.
*/
PRBool
Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this,
Pk11Install_PlatformName* cmp)
{
return (Pk11Install_PlatformName_equal(_this,cmp) ||
Pk11Install_PlatformName_lt(_this,cmp)) ? PR_TRUE : PR_FALSE;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: operator <
// Class: Pk11Install_PlatformName
// Returns: PR_TRUE if the platform have the same OS and arch and a greater
// release.
*/
PRBool
Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this,
Pk11Install_PlatformName* cmp)
{
int i, scmp;
if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) {
return PR_FALSE;
}
if( PORT_Strcasecmp(_this->OS, cmp->OS) ) {
return PR_FALSE;
}
if( PORT_Strcasecmp(_this->arch, cmp->arch) ) {
return PR_FALSE;
}
for(i=0; (i < _this->numDigits) && (i < cmp->numDigits); i++) {
scmp = PORT_Strcasecmp(_this->verString[i], cmp->verString[i]);
if (scmp > 0) {
return PR_FALSE;
} else if (scmp < 0) {
return PR_TRUE;
}
}
/* All the digits they have in common are the same. */
if(_this->numDigits < cmp->numDigits) {
return PR_TRUE;
}
return PR_FALSE;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: GetString
// Class: Pk11Install_PlatformName
// Returns: String composed of OS, release, and architecture separated
// by the separator char. Memory is allocated by this function
// but is the responsibility of the caller to de-allocate.
*/
char*
Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this)
{
char *ret;
char *ver;
char *OS_;
char *arch_;
OS_=NULL;
arch_=NULL;
OS_ = _this->OS ? _this->OS : "";
arch_ = _this->arch ? _this->arch : "";
ver = Pk11Install_PlatformName_GetVerString(_this);
ret = PR_smprintf("%s%c%s%c%s", OS_, PLATFORM_SEPARATOR_CHAR, ver,
PLATFORM_SEPARATOR_CHAR, arch_);
PR_Free(ver);
return ret;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: GetVerString
// Class: Pk11Install_PlatformName
// Returns: The version string for this platform, in the form x.x.x with an
// arbitrary number of digits. Memory allocated by function,
// must be de-allocated by caller.
*/
char*
Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this)
{
char *tmp;
char *ret;
int i;
char buf[80];
tmp = (char*)PR_Malloc(80*_this->numDigits+1);
tmp[0] = '\0';
for(i=0; i < _this->numDigits-1; i++) {
sprintf(buf, "%s.", _this->verString[i]);
strcat(tmp, buf);
}
if(i < _this->numDigits) {
sprintf(buf, "%s", _this->verString[i]);
strcat(tmp, buf);
}
ret = PR_Strdup(tmp);
free(tmp);
return ret;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Print
// Class: Pk11Install_PlatformName
*/
void
Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad)
{
PAD(pad); printf("OS: %s\n", _this->OS ? _this->OS : "<NULL>");
PAD(pad); printf("Digits: ");
if(_this->numDigits == 0) {
printf("None\n");
} else {
printf("%s\n", Pk11Install_PlatformName_GetVerString(_this));
}
PAD(pad); printf("arch: %s\n", _this->arch ? _this->arch : "<NULL>");
}
Pk11Install_Platform*
Pk11Install_Platform_new()
{
Pk11Install_Platform* new_this;
new_this = (Pk11Install_Platform*)PR_Malloc(sizeof(Pk11Install_Platform));
Pk11Install_Platform_init(new_this);
return new_this;
}
void
Pk11Install_Platform_init(Pk11Install_Platform* _this)
{
Pk11Install_PlatformName_init(&_this->name);
Pk11Install_PlatformName_init(&_this->equivName);
_this->equiv = NULL;
_this->usesEquiv = PR_FALSE;
_this->moduleFile = NULL;
_this->moduleName = NULL;
_this->modFile = -1;
_this->mechFlags = 0;
_this->cipherFlags = 0;
_this->files = NULL;
_this->numFiles = 0;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: ~Pk11Install_Platform
// Class: Pk11Install_Platform
*/
void
Pk11Install_Platform_delete(Pk11Install_Platform* _this)
{
Pk11Install_Platform_Cleanup(_this);
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Cleanup
// Class: Pk11Install_Platform
*/
void
Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this)
{
int i;
if(_this->moduleFile) {
PR_Free(_this->moduleFile);
_this->moduleFile = NULL;
}
if(_this->moduleName) {
PR_Free(_this->moduleName);
_this->moduleName = NULL;
}
if(_this->files) {
for (i=0;i<_this->numFiles;i++) {
Pk11Install_File_delete(&_this->files[i]);
}
PR_Free(_this->files);
_this->files = NULL;
}
_this->equiv = NULL;
_this->usesEquiv = PR_FALSE;
_this->modFile = -1;
_this->numFiles = 0;
_this->mechFlags = _this->cipherFlags = 0;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Generate
// Class: Pk11Install_Platform
// Notes: Creates a platform data structure from a syntax tree.
// Returns: NULL for success, otherwise an error message.
*/
char*
Pk11Install_Platform_Generate(Pk11Install_Platform* _this,
const Pk11Install_Pair *pair)
{
char* errStr;
char* endptr;
char* tmp;
int i;
Pk11Install_ListIter *iter;
Pk11Install_Value *val;
Pk11Install_Value *subval;
Pk11Install_Pair *subpair;
Pk11Install_ListIter *subiter;
PRBool gotModuleFile, gotModuleName, gotMech,
gotCipher, gotFiles, gotEquiv;
errStr=NULL;
iter=subiter=NULL;
val=subval=NULL;
subpair=NULL;
gotModuleFile=gotModuleName=gotMech=gotCipher=gotFiles=gotEquiv=PR_FALSE;
Pk11Install_Platform_Cleanup(_this);
errStr = Pk11Install_PlatformName_Generate(&_this->name,pair->key);
if(errStr) {
tmp = PR_smprintf("%s: %s", pair->key, errStr);
PR_smprintf_free(errStr);
errStr = tmp;
goto loser;
}
iter = Pk11Install_ListIter_new(pair->list);
for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) {
if(val->type==PAIR_VALUE) {
subpair = val->pair;
if( !PORT_Strcasecmp(subpair->key, MODULE_FILE_STRING)) {
if(gotModuleFile) {
errStr = PR_smprintf(errString[REPEAT_MODULE_FILE],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE)) {
errStr = PR_smprintf(errString[BOGUS_MODULE_FILE],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
_this->moduleFile = PR_Strdup(subval->string);
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
subiter = NULL;
gotModuleFile = PR_TRUE;
} else if(!PORT_Strcasecmp(subpair->key, MODULE_NAME_STRING)){
if(gotModuleName) {
errStr = PR_smprintf(errString[REPEAT_MODULE_NAME],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE)) {
errStr = PR_smprintf(errString[BOGUS_MODULE_NAME],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
_this->moduleName = PR_Strdup(subval->string);
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
subiter = NULL;
gotModuleName = PR_TRUE;
} else if(!PORT_Strcasecmp(subpair->key, MECH_FLAGS_STRING)) {
endptr=NULL;
if(gotMech) {
errStr = PR_smprintf(errString[REPEAT_MECH],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE)) {
errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
_this->mechFlags = strtol(subval->string, &endptr, 0);
if(*endptr!='\0' || (endptr==subval->string) ) {
errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
subiter=NULL;
gotMech = PR_TRUE;
} else if(!PORT_Strcasecmp(subpair->key,CIPHER_FLAGS_STRING)) {
endptr=NULL;
if(gotCipher) {
errStr = PR_smprintf(errString[REPEAT_CIPHER],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE)) {
errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
_this->cipherFlags = strtol(subval->string, &endptr, 0);
if(*endptr!='\0' || (endptr==subval->string) ) {
errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
subiter=NULL;
gotCipher = PR_TRUE;
} else if(!PORT_Strcasecmp(subpair->key, FILES_STRING)) {
if(gotFiles) {
errStr = PR_smprintf(errString[REPEAT_FILES],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
subiter = Pk11Install_ListIter_new(subpair->list);
_this->numFiles = subpair->list->numPairs;
_this->files = (Pk11Install_File*)
PR_Malloc(sizeof(Pk11Install_File)*_this->numFiles);
for(i=0; i < _this->numFiles; i++,
Pk11Install_ListIter_nextItem(subiter)) {
Pk11Install_File_init(&_this->files[i]);
val = subiter->current;
if(val && (val->type==PAIR_VALUE)) {
errStr = Pk11Install_File_Generate(&_this->files[i],val->pair);
if(errStr) {
tmp = PR_smprintf("%s: %s",
Pk11Install_PlatformName_GetString(&_this->name),errStr);
PR_smprintf_free(errStr);
errStr = tmp;
goto loser;
}
}
}
gotFiles = PR_TRUE;
} else if(!PORT_Strcasecmp(subpair->key,
EQUIVALENT_PLATFORM_STRING)) {
if(gotEquiv) {
errStr = PR_smprintf(errString[REPEAT_EQUIV],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
subiter = Pk11Install_ListIter_new(subpair->list);
subval = subiter->current;
if(!subval || (subval->type != STRING_VALUE) ) {
errStr = PR_smprintf(errString[BOGUS_EQUIV],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
errStr = Pk11Install_PlatformName_Generate(&_this->equivName,
subval->string);
if(errStr) {
tmp = PR_smprintf("%s: %s",
Pk11Install_PlatformName_GetString(&_this->name), errStr);
tmp = PR_smprintf("%s: %s",
Pk11Install_PlatformName_GetString(&_this->name), errStr);
PR_smprintf_free(errStr);
errStr = tmp;
goto loser;
}
_this->usesEquiv = PR_TRUE;
}
}
}
/* Make sure we either have an EquivalentPlatform or all the other info */
if(_this->usesEquiv &&
(gotFiles || gotModuleFile || gotModuleName || gotMech || gotCipher)) {
errStr = PR_smprintf(errString[EQUIV_TOO_MUCH_INFO],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
if(!gotFiles && !_this->usesEquiv) {
errStr = PR_smprintf(errString[NO_FILES],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
if(!gotModuleFile && !_this->usesEquiv) {
errStr= PR_smprintf(errString[NO_MODULE_FILE],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
if(!gotModuleName && !_this->usesEquiv) {
errStr = PR_smprintf(errString[NO_MODULE_NAME],
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
/* Point the modFile pointer to the correct file */
if(gotModuleFile) {
for(i=0; i < _this->numFiles; i++) {
if(!PORT_Strcasecmp(_this->moduleFile, _this->files[i].jarPath) ) {
_this->modFile = i;
break;
}
}
if(_this->modFile==-1) {
errStr = PR_smprintf(errString[UNKNOWN_MODULE_FILE],
_this->moduleFile,
Pk11Install_PlatformName_GetString(&_this->name));
goto loser;
}
}
loser:
if(iter) {
PR_Free(iter);
}
if(subiter) {
PR_Free(subiter);
}
return errStr;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Print
// Class: Pk11Install_Platform
*/
void
Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad)
{
int i;
PAD(pad); printf("Name:\n");
Pk11Install_PlatformName_Print(&_this->name,pad+PADINC);
PAD(pad); printf("equivName:\n");
Pk11Install_PlatformName_Print(&_this->equivName,pad+PADINC);
PAD(pad);
if(_this->usesEquiv) {
printf("Uses equiv, which points to:\n");
Pk11Install_Platform_Print(_this->equiv,pad+PADINC);
} else {
printf("Doesn't use equiv\n");
}
PAD(pad);
printf("Module File: %s\n", _this->moduleFile ? _this->moduleFile
: "<NULL>");
PAD(pad); printf("mechFlags: %lx\n", _this->mechFlags);
PAD(pad); printf("cipherFlags: %lx\n", _this->cipherFlags);
PAD(pad); printf("Files:\n");
for(i=0; i < _this->numFiles; i++) {
Pk11Install_File_Print(&_this->files[i],pad+PADINC);
PAD(pad); printf("--------------------\n");
}
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Pk11Install_Info
// Class: Pk11Install_Info
*/
Pk11Install_Info*
Pk11Install_Info_new()
{
Pk11Install_Info* new_this;
new_this = (Pk11Install_Info*)PR_Malloc(sizeof(Pk11Install_Info));
Pk11Install_Info_init(new_this);
return new_this;
}
void
Pk11Install_Info_init(Pk11Install_Info* _this)
{
_this->platforms = NULL;
_this->numPlatforms = 0;
_this->forwardCompatible = NULL;
_this->numForwardCompatible = 0;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: ~Pk11Install_Info
// Class: Pk11Install_Info
*/
void
Pk11Install_Info_delete(Pk11Install_Info* _this)
{
Pk11Install_Info_Cleanup(_this);
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Cleanup
// Class: Pk11Install_Info
*/
void
Pk11Install_Info_Cleanup(Pk11Install_Info* _this)
{
int i;
if(_this->platforms) {
for (i=0;i<_this->numPlatforms;i++) {
Pk11Install_Platform_delete(&_this->platforms[i]);
}
PR_Free(&_this->platforms);
_this->platforms = NULL;
_this->numPlatforms = 0;
}
if(_this->forwardCompatible) {
for (i=0;i<_this->numForwardCompatible;i++) {
Pk11Install_PlatformName_delete(&_this->forwardCompatible[i]);
}
PR_Free(&_this->forwardCompatible);
_this->numForwardCompatible = 0;
}
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Generate
// Class: Pk11Install_Info
// Takes: Pk11Install_ValueList *list, the top-level list
// resulting from parsing an installer file.
// Returns: char*, NULL if successful, otherwise an error string.
// Caller is responsible for freeing memory.
*/
char*
Pk11Install_Info_Generate(Pk11Install_Info* _this,
const Pk11Install_ValueList *list)
{
char *errStr;
Pk11Install_ListIter *iter;
Pk11Install_Value *val;
Pk11Install_Pair *pair;
Pk11Install_ListIter *subiter;
Pk11Install_Value *subval;
Pk11Install_Platform *first, *second;
int i, j;
errStr=NULL;
iter=subiter=NULL;
Pk11Install_Info_Cleanup(_this);
iter = Pk11Install_ListIter_new(list);
for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) {
if(val->type == PAIR_VALUE) {
pair = val->pair;
if(!PORT_Strcasecmp(pair->key, FORWARD_COMPATIBLE_STRING)) {
subiter = Pk11Install_ListIter_new(pair->list);
_this->numForwardCompatible = pair->list->numStrings;
_this->forwardCompatible = (Pk11Install_PlatformName*)
PR_Malloc(sizeof(Pk11Install_PlatformName)*
_this->numForwardCompatible);
for(i=0; i < _this->numForwardCompatible; i++,
Pk11Install_ListIter_nextItem(subiter)) {
subval = subiter->current;
if(subval->type == STRING_VALUE) {
errStr = Pk11Install_PlatformName_Generate(
&_this->forwardCompatible[i], subval->string);
if(errStr) {
goto loser;
}
}
}
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
subiter = NULL;
} else if(!PORT_Strcasecmp(pair->key, PLATFORMS_STRING)) {
subiter = Pk11Install_ListIter_new(pair->list);
_this->numPlatforms = pair->list->numPairs;
_this->platforms = (Pk11Install_Platform*)
PR_Malloc(sizeof(Pk11Install_Platform)*
_this->numPlatforms);
for(i=0; i < _this->numPlatforms; i++,
Pk11Install_ListIter_nextItem(subiter)) {
Pk11Install_Platform_init(&_this->platforms[i]);
subval = subiter->current;
if(subval->type == PAIR_VALUE) {
errStr = Pk11Install_Platform_Generate(&_this->platforms[i],subval->pair);
if(errStr) {
goto loser;
}
}
}
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
subiter = NULL;
}
}
}
if(_this->numPlatforms == 0) {
errStr = PR_smprintf(errString[NO_PLATFORMS]);
goto loser;
}
/*
//
// Now process equivalent platforms
//
// First the naive pass
*/
for(i=0; i < _this->numPlatforms; i++) {
if(_this->platforms[i].usesEquiv) {
_this->platforms[i].equiv = NULL;
for(j=0; j < _this->numPlatforms; j++) {
if (Pk11Install_PlatformName_equal(&_this->platforms[i].equivName,
&_this->platforms[j].name)) {
if(i==j) {
errStr = PR_smprintf(errString[EQUIV_LOOP],
Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
goto loser;
}
_this->platforms[i].equiv = &_this->platforms[j];
break;
}
}
if(_this->platforms[i].equiv == NULL) {
errStr = PR_smprintf(errString[BOGUS_EQUIV],
Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
goto loser;
}
}
}
/*
// Now the intelligent pass, which will also detect loops.
// We will send two pointers through the linked list of equivalent
// platforms. Both start with the current node. "first" traverses
// two nodes for each iteration. "second" lags behind, only traversing
// one node per iteration. Eventually one of two things will happen:
// first will hit the end of the list (a platform that doesn't use
// an equivalency), or first will equal second if there is a loop.
*/
for(i=0; i < _this->numPlatforms; i++) {
if(_this->platforms[i].usesEquiv) {
second = _this->platforms[i].equiv;
if(!second->usesEquiv) {
/* The first link is the terminal node */
continue;
}
first = second->equiv;
while(first->usesEquiv) {
if(first == second) {
errStr = PR_smprintf(errString[EQUIV_LOOP],
Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
goto loser;
}
first = first->equiv;
if(!first->usesEquiv) {
break;
}
if(first == second) {
errStr = PR_smprintf(errString[EQUIV_LOOP],
Pk11Install_PlatformName_GetString(&_this->platforms[i].name));
goto loser;
}
second = second->equiv;
first = first->equiv;
}
_this->platforms[i].equiv = first;
}
}
loser:
if(iter) {
Pk11Install_ListIter_delete(iter);
PR_Free(iter);
iter = NULL;
}
if(subiter) {
Pk11Install_ListIter_delete(subiter);
PR_Free(subiter);
subiter = NULL;
}
return errStr;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: GetBestPlatform
// Class: Pk11Install_Info
// Takes: char *myPlatform, the platform we are currently running
// on.
*/
Pk11Install_Platform*
Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char *myPlatform)
{
Pk11Install_PlatformName plat;
char *errStr;
int i, j;
errStr=NULL;
Pk11Install_PlatformName_init(&plat);
if( (errStr=Pk11Install_PlatformName_Generate(&plat, myPlatform)) ) {
PR_smprintf_free(errStr);
return NULL;
}
/* First try real platforms */
for(i=0; i < _this->numPlatforms; i++) {
if(Pk11Install_PlatformName_equal(&_this->platforms[i].name,&plat)) {
if(_this->platforms[i].equiv) {
return _this->platforms[i].equiv;
}
else {
return &_this->platforms[i];
}
}
}
/* Now try forward compatible platforms */
for(i=0; i < _this->numForwardCompatible; i++) {
if(Pk11Install_PlatformName_lteq(&_this->forwardCompatible[i],&plat)) {
break;
}
}
if(i == _this->numForwardCompatible) {
return NULL;
}
/* Got a forward compatible name, find the actual platform. */
for(j=0; j < _this->numPlatforms; j++) {
if(Pk11Install_PlatformName_equal(&_this->platforms[j].name,
&_this->forwardCompatible[i])) {
if(_this->platforms[j].equiv) {
return _this->platforms[j].equiv;
} else {
return &_this->platforms[j];
}
}
}
return NULL;
}
/*
//////////////////////////////////////////////////////////////////////////
// Method: Print
// Class: Pk11Install_Info
*/
void
Pk11Install_Info_Print(Pk11Install_Info* _this, int pad)
{
int i;
PAD(pad); printf("Forward Compatible:\n");
for(i = 0; i < _this->numForwardCompatible; i++) {
Pk11Install_PlatformName_Print(&_this->forwardCompatible[i],pad+PADINC);
PAD(pad); printf("-------------------\n");
}
PAD(pad); printf("Platforms:\n");
for( i = 0; i < _this->numPlatforms; i++) {
Pk11Install_Platform_Print(&_this->platforms[i],pad+PADINC);
PAD(pad); printf("-------------------\n");
}
}
/*
//////////////////////////////////////////////////////////////////////////
*/
static char*
PR_Strdup(const char* str)
{
char *tmp;
tmp = (char*) PR_Malloc((unsigned int)(strlen(str)+1));
strcpy(tmp, str);
return tmp;
}
/* The global value list, the top of the tree */
Pk11Install_ValueList* Pk11Install_valueList=NULL;
/****************************************************************************/
void
Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this,
Pk11Install_Value *item)
{
_this->numItems++;
if (item->type == STRING_VALUE) {
_this->numStrings++;
} else {
_this->numPairs++;
}
item->next = _this->head;
_this->head = item;
}
/****************************************************************************/
Pk11Install_ListIter*
Pk11Install_ListIter_new_default()
{
Pk11Install_ListIter* new_this;
new_this = (Pk11Install_ListIter*)
PR_Malloc(sizeof(Pk11Install_ListIter));
Pk11Install_ListIter_init(new_this);
return new_this;
}
/****************************************************************************/
void
Pk11Install_ListIter_init(Pk11Install_ListIter* _this)
{
_this->list = NULL;
_this->current = NULL;
}
/****************************************************************************/
Pk11Install_ListIter*
Pk11Install_ListIter_new(const Pk11Install_ValueList *_list)
{
Pk11Install_ListIter* new_this;
new_this = (Pk11Install_ListIter*)
PR_Malloc(sizeof(Pk11Install_ListIter));
new_this->list = _list;
new_this->current = _list->head;
return new_this;
}
/****************************************************************************/
void
Pk11Install_ListIter_delete(Pk11Install_ListIter* _this)
{
_this->list=NULL;
_this->current=NULL;
}
/****************************************************************************/
void
Pk11Install_ListIter_reset(Pk11Install_ListIter* _this)
{
if(_this->list) {
_this->current = _this->list->head;
}
}
/*************************************************************************/
Pk11Install_Value*
Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this)
{
if(_this->current) {
_this->current = _this->current->next;
}
return _this->current;
}
/****************************************************************************/
Pk11Install_ValueList*
Pk11Install_ValueList_new()
{
Pk11Install_ValueList* new_this;
new_this = (Pk11Install_ValueList*)
PR_Malloc(sizeof(Pk11Install_ValueList));
new_this->numItems = 0;
new_this->numPairs = 0;
new_this->numStrings = 0;
new_this->head = NULL;
return new_this;
}
/****************************************************************************/
void
Pk11Install_ValueList_delete(Pk11Install_ValueList* _this)
{
Pk11Install_Value *tmp;
Pk11Install_Value *list;
list = _this->head;
while(list != NULL) {
tmp = list;
list = list->next;
PR_Free(tmp);
}
PR_Free(_this);
}
/****************************************************************************/
Pk11Install_Value*
Pk11Install_Value_new_default()
{
Pk11Install_Value* new_this;
new_this = (Pk11Install_Value*)PR_Malloc(sizeof(Pk11Install_Value));
new_this->type = STRING_VALUE;
new_this->string = NULL;
new_this->pair = NULL;
new_this->next = NULL;
return new_this;
}
/****************************************************************************/
Pk11Install_Value*
Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr)
{
Pk11Install_Value* new_this;
new_this = Pk11Install_Value_new_default();
new_this->type = _type;
if(_type == STRING_VALUE) {
new_this->pair = NULL;
new_this->string = ptr.string;
} else {
new_this->string = NULL;
new_this->pair = ptr.pair;
}
return new_this;
}
/****************************************************************************/
void
Pk11Install_Value_delete(Pk11Install_Value* _this)
{
if(_this->type == STRING_VALUE) {
PR_Free(_this->string);
} else {
PR_Free(_this->pair);
}
}
/****************************************************************************/
Pk11Install_Pair*
Pk11Install_Pair_new_default()
{
return Pk11Install_Pair_new(NULL,NULL);
}
/****************************************************************************/
Pk11Install_Pair*
Pk11Install_Pair_new(char *_key, Pk11Install_ValueList *_list)
{
Pk11Install_Pair* new_this;
new_this = (Pk11Install_Pair*)PR_Malloc(sizeof(Pk11Install_Pair));
new_this->key = _key;
new_this->list = _list;
return new_this;
}
/****************************************************************************/
void
Pk11Install_Pair_delete(Pk11Install_Pair* _this)
{
PR_Free(_this->key);
Pk11Install_ValueList_delete(_this->list);
}
/*************************************************************************/
void
Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad)
{
while (_this) {
/*PAD(pad); printf("**Pair\n");
PAD(pad); printf("***Key====\n");*/
PAD(pad); printf("%s {\n", _this->key);
/*PAD(pad); printf("====\n");*/
/*PAD(pad); printf("***ValueList\n");*/
Pk11Install_ValueList_Print(_this->list,pad+PADINC);
PAD(pad); printf("}\n");
}
}
/*************************************************************************/
void
Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad)
{
Pk11Install_Value *v;
/*PAD(pad);printf("**Value List**\n");*/
for(v = _this->head; v != NULL; v=v->next) {
Pk11Install_Value_Print(v,pad);
}
}
/*************************************************************************/
void
Pk11Install_Value_Print(Pk11Install_Value* _this, int pad)
{
/*PAD(pad); printf("**Value, type=%s\n",
type==STRING_VALUE ? "string" : "pair");*/
if(_this->type==STRING_VALUE) {
/*PAD(pad+PADINC); printf("====\n");*/
PAD(pad); printf("%s\n", _this->string);
/*PAD(pad+PADINC); printf("====\n");*/
} else {
Pk11Install_Pair_Print(_this->pair,pad+PADINC);
}
}