/**************************************************************************** * * Copyright (c) 2001 Novell, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, contact Novell, Inc. * * To contact Novell about this file by physical or electronic mail, you * may find current contact information at www.novell.com. * ****************************************************************************/ /* Product defines */ #define PRODUCT_NAME "Bongo API Library" #define PRODUCT_VERSION "$Revision: 1.6 $" #define PRODUCT_SHORT_NAME "msgapi.nlm" #define CURRENT_PRODUCT_VERSION 3 #define CURRENT_PRODUCT_VERSION_MAJOR 5 #define CURRENT_PRODUCT_VERSION_MINOR 3 #include #include #include #include #include #include #include #include "msgapip.h" #include #include #include #include #define MSGAPI_FLAG_EXITING (1 << 0) #define MSGAPI_FLAG_STANDALONE (1 << 1) #define MSGAPI_FLAG_SUPPORT_CONNMGR (1 << 2) #define MSGAPI_FLAG_CLUSTERED (1 << 3) #define MSGAPI_FLAG_BOUND (1 << 4) #define MSGAPI_FLAG_INTERNET_EMAIL_ADDRESS (1 << 5) #define MSGAPI_FLAG_MONITOR_RUNNING (1 << 6) #define LOOPBACK_ADDRESS 0x0100007F #define EMPTY_CHAR 0x01 #define CONNMGR_STRUCT_SIZE (sizeof(ConnectionManagerCommand) + MAXEMAILNAMESIZE) #define CONNMGR_REPLY_NOT_FOUND 0 #define CONNMGR_REPLY_FOUND 1 #define CONNMGR_REPLY_FOUND_NAME 2 #define CONNMGR_REQ_STORE 0 #define CONNMGR_REQ_CHECK 1 #define CONNMGR_REQ_STORE_NAME 2 #define CONNMGR_REQ_CHECK_NAME 3 enum LibraryStates { LIBRARY_LOADED = 0, LIBRARY_INITIALIZING, LIBRARY_RUNNING, LIBRARY_SHUTTING_DOWN, LIBRARY_SHUTDOWN, LIBRARY_MAX_STATES } MSGAPIState = LIBRARY_LOADED; struct { unsigned long flags; MDBHandle directoryHandle; XplThreadID groupID; struct { XplSemaphore version; XplSemaphore shutdown; XplMutex uid; } sem; struct { unsigned char dn[MDB_MAX_OBJECT_CHARS + 1]; } server; struct { MDBValueStruct *storePaths; MDBValueStruct *storeDNs; struct { MDBValueStruct *names; MDBValueStruct *contexts; struct sockaddr_in *addr; } server; #ifdef PARENTOBJECT_STORE struct { MDBValueStruct *objects; MDBValueStruct *stores; MDBValueSTruct *indices; } parent; #endif } vs; unsigned long connManager; XplRWLock configLock; struct { unsigned char work[XPL_MAX_PATH + 1]; unsigned char nls[XPL_MAX_PATH + 1]; unsigned char dbf[XPL_MAX_PATH + 1]; unsigned char bin[XPL_MAX_PATH + 1]; unsigned char lib[XPL_MAX_PATH + 1]; unsigned char certificate[XPL_MAX_PATH + 1]; unsigned char key[XPL_MAX_PATH + 1]; } paths; struct { unsigned long local; unsigned char string[16]; } address; struct { unsigned char domain[MAXEMAILNAMESIZE + 1]; unsigned long domainLength; } official; XplAtomic useCount; } MsgGlobal; typedef struct _ConnectionManagerCommand { unsigned long request; unsigned long address; unsigned long nameLen; unsigned long counter; unsigned char name[1]; } ConnectionManagerCommand; /* private */ BOOL MsgGetUpdateStatus(char *record, int record_length); /* I tried to remove this, but it's still needed :( * Python server for Dragonfly needs a way to authenticate itself * to the queue... */ void MsgNmapChallenge(const unsigned char *response, unsigned char *reply, size_t length) { unsigned char *ptr; unsigned char *salt; static unsigned char access[NMAP_HASH_SIZE] = { '\0' }; MDBValueStruct *v; xpl_hash_context ctx; MsgGetServerCredential(&access); if (access[0] && reply && (length > 32) && ((ptr = strchr(response, '<')) != NULL)) { salt = ++ptr; if ((ptr = strchr(ptr, '>')) != NULL) { *ptr = '\0'; } XplHashNew(&ctx, XPLHASH_MD5); XplHashWrite(&ctx, salt, strlen(salt)); XplHashWrite(&ctx, access, NMAP_HASH_SIZE); XplHashFinal(&ctx, XPLHASH_LOWERCASE, reply, XPLHASH_MD5_LENGTH); } else if (reply) { *reply = '\0'; } return; } EXPORT const unsigned char * MsgGetServerDN(unsigned char *buffer) { if (buffer) { return(strcpy(buffer, MsgGlobal.server.dn)); } return(MsgGlobal.server.dn); } EXPORT BOOL MsgFindObject(const unsigned char *user, unsigned char *dn, unsigned char *userType, struct sockaddr_in *nmap, MDBValueStruct *v) { BOOL retVal = FALSE; MDBValueStruct *userCtx; MDBValueStruct *types; unsigned long i, j; unsigned char rdn[MDB_MAX_OBJECT_CHARS + 1]; BOOL isUser = FALSE; BOOL isGroup = FALSE; BOOL isResource = FALSE; BOOL isOrgRole = FALSE; BOOL isDynGroup = FALSE; /* FIXME: handle failure to create ValueStructs */ userCtx = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL); types = MDBShareContext(userCtx); XplRWReadLockAcquire(&MsgGlobal.configLock); for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) { MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], userCtx); if (MDBGetObjectDetailsEx(user, types, rdn, dn, userCtx)) { /* determine relevant types now so we don't have to loop throught the list everytime. */ for (j = 0; j < types->Used; j++) { if (strcmp(types->Value[j], C_USER) == 0) { isUser = TRUE; } else if (strcmp(types->Value[j], MSGSRV_C_RESOURCE) == 0) { isResource = TRUE; } else if (strcmp(types->Value[j], MSGSRV_C_GROUP) == 0 || strcmp(types->Value[j], C_GROUP) == 0) { isGroup = TRUE; } else if (strcmp(types->Value[j], MSGSRV_C_ORGANIZATIONAL_ROLE) == 0 || strcmp(types->Value[j], C_ORGANIZATIONAL_ROLE) == 0) { isOrgRole = TRUE; } else if (strcmp(types->Value[j], "dynamicGroup") == 0) { isDynGroup = TRUE; } } if (isUser || isResource) { if (v) { MDBAddValue(rdn, v); } if (nmap) { memcpy(nmap, &MsgGlobal.vs.server.addr[i], sizeof(struct sockaddr_in)); } if (userType) { if (isUser) { strcpy(userType, C_USER); } else if (isResource) { strcpy(userType, MSGSRV_C_RESOURCE); } } retVal = TRUE; } else if (isGroup) { if (v) { MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v); MDBRead(user, A_MEMBER, v); /* This removes any context from a group member's name */ for (j = 0; j < v->Used; j++) { unsigned char *ptr; ptr = strrchr(v->Value[j], '\\'); if (ptr) { memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1); } } } if (userType) { strcpy(userType, C_GROUP); } retVal = TRUE; } else if (isOrgRole) { if (v) { MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v); MDBRead(user, A_ROLE_OCCUPANT, v); /* This removes any context from a the roles name */ for (j = 0; j < v->Used; j++) { unsigned char *ptr; ptr = strrchr(v->Value[j], '\\'); if (ptr) { memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1); } } } if (userType) { strcpy(userType, C_ORGANIZATIONAL_ROLE); } retVal = TRUE; } else if (isDynGroup) { if (v) { MDBSetValueStructContext(MsgGlobal.vs.server.contexts->Value[i], v); MDBRead(user, A_MEMBER, v); /* This removes any context from a group member's name */ for (j = 0; j < v->Used; j++) { unsigned char *ptr; ptr=strrchr(v->Value[j], '\\'); if (ptr) { memmove(v->Value[j], ptr + 1, strlen(ptr + 1) + 1); } } } if (userType) { strcpy(userType, "dynamicGroup"); } retVal = TRUE; } break; } } XplRWReadLockRelease(&MsgGlobal.configLock); MDBDestroyValueStruct(userCtx); MDBDestroyValueStruct(types); return(retVal); } EXPORT BOOL MsgDomainExists(const unsigned char *domain, unsigned char *domainObjectDN) { /* FIXME later; when we handle parent objects */ return(FALSE); } /* * Use these functions to ensure that the correct MDB function is used * for strings or DNs. */ static BOOL MsgMdbWriteAny(const unsigned char *dn, const unsigned char *attribute, MDBValueStruct *v) { if (v->Used > 0 && strchr(v->Value[0], '\\')) { return MDBWriteDN(dn, attribute, v); } return MDBWrite(dn, attribute, v); } static BOOL MsgMdbAddAny(const unsigned char *dn, const unsigned char *attribute, const unsigned char *value, MDBValueStruct *v) { if (v->Used > 0 && strchr(v->Value[0], '\\')) { return MDBAddDN(dn, attribute, value, v); } return MDBAdd(dn, attribute, value, v); } EXPORT BOOL MsgCleanPath(unsigned char *path) { unsigned char *ptr; unsigned char *ptr2; /* This code strips off any server names that might be configured in the Path */ ptr = path; while((ptr = strchr(ptr, '\\')) != NULL) { *ptr = '/'; } ptr=strchr(path, ':'); if (ptr) { *ptr = '\0'; ptr2 = strchr(path, '/'); if (ptr2) { *ptr=':'; memmove(path, ptr2+1, strlen(ptr2+1)+1); } else { *ptr=':'; } } /* If you want all pathnames lowercase, uncomment the following */ #if 0 ptr = path; while (*ptr) { if (isupper(*ptr)) { *ptr = tolower(*ptr); } ptr++; } #endif /* strip off trailing /, to allow other code reliable appending of files by using %s/%s */ ptr = path + strlen(path) - 1; if (*ptr == '/') { *ptr = '\0'; } return(TRUE); } EXPORT void MsgMakePath(unsigned char *path) { unsigned char *ptr = path; unsigned char *ptr2; struct stat sb; ptr = strchr(path, '/'); if (!ptr) ptr=strchr(path, '\\'); while (ptr) { *ptr = '\0'; if (stat(path, &sb) != 0) { XplMakeDir(path); } *ptr = '/'; ptr2 = ptr; ptr = strchr(ptr2 + 1, '/'); if (!ptr) ptr = strchr(ptr2 + 1, '\\'); } if (stat(path, &sb) != 0) { XplMakeDir(path); } } EXPORT const unsigned char * MsgGetDBFDir(char *directory) { if (directory) { strcpy(directory, MsgGlobal.paths.dbf); } return(MsgGlobal.paths.dbf); } EXPORT const unsigned char * MsgGetWorkDir(char *directory) { if (directory) { strcpy(directory, MsgGlobal.paths.work); } return(MsgGlobal.paths.work); } EXPORT const unsigned char * MsgGetNLSDir(char *directory) { if (directory) { strcpy(directory, MsgGlobal.paths.nls); } return(MsgGlobal.paths.nls); } EXPORT const unsigned char * MsgGetBinDir(char *directory) { if (directory) { strcpy(directory, MsgGlobal.paths.bin); } return(MsgGlobal.paths.bin); } EXPORT const unsigned char * MsgGetLibDir(char *directory) { if (directory) { strcpy(directory, MsgGlobal.paths.lib); } return(MsgGlobal.paths.bin); } EXPORT const unsigned char * MsgGetTLSCertPath(char *path) { if (path) { strcpy(path, MsgGlobal.paths.certificate); } return(MsgGlobal.paths.certificate); } EXPORT const unsigned char * MsgGetTLSKeyPath(char *path) { if (path) { strcpy(path, MsgGlobal.paths.key); } return(MsgGlobal.paths.key); } EXPORT unsigned long MsgGetAgentBindIPAddress(void) { if ((MsgGlobal.flags & MSGAPI_FLAG_BOUND)) { return(MsgGlobal.address.local); } else { return(0); } } EXPORT unsigned long MsgGetHostIPAddress(void) { return(MsgGlobal.address.local); } EXPORT const char * MsgGetUnprivilegedUser(void) { if (BONGO_USER[0] == '\0') { return NULL; } else { return BONGO_USER; } } static BOOL LoadContextList(MDBValueStruct *config) { unsigned char emptyString[] = " "; unsigned char storeObjectDn[MDB_MAX_OBJECT_CHARS + 1]; MDBValueStruct *ports; MDBValueStruct *addresses; char storePortText[6]; unsigned long i; unsigned long j; unsigned long count; unsigned long realUsed; ports = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL); if (!ports) { return(FALSE); } addresses = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL); if (!addresses) { MDBDestroyValueStruct(ports); return(FALSE); } MDBFreeValues(MsgGlobal.vs.server.names); MDBFreeValues(MsgGlobal.vs.server.contexts); MDBFreeValues(MsgGlobal.vs.storePaths); MDBFreeValues(MsgGlobal.vs.storeDNs); if (MsgGlobal.vs.server.addr) { MemFree(MsgGlobal.vs.server.addr); MsgGlobal.vs.server.addr = NULL; } /* This puts the local context always first */ sprintf(storeObjectDn, "%s\\%s", MsgGlobal.server.dn, MSGSRV_AGENT_STORE); if(MDBIsObject(storeObjectDn, MsgGlobal.vs.server.contexts)) { MDBReadDN(MsgGlobal.server.dn, MSGSRV_A_CONTEXT, MsgGlobal.vs.server.contexts); if (MDBRead(storeObjectDn, MSGSRV_A_PORT, config)) { strcpy(storePortText, config->Value[0]); MDBFreeValues(config); } else { sprintf(storePortText, "%d", (BONGO_STORE_DEFAULT_PORT)); } for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) { MDBRead(MsgGlobal.server.dn, MSGSRV_A_IP_ADDRESS, addresses); MDBAddValue(storePortText, ports); MDBAddValue(MsgGlobal.server.dn, MsgGlobal.vs.storeDNs); } } #ifdef PARENTOBJECT_STORE /* Read the parent object store configuration */ if (MDBEnumerateObjects(MSGSRV_ROOT"\\"MSGSRV_PARENT_ROOT, MSGSRV_C_PARENTOBJECT, &MsgGlobal.vs.parent.objects)) { for (i=0; iUsed; i++) { /* MsgGlobal.server.dn is absolute, MsgGlobal.vs.server.names->Value isn't */ if (XplStrCaseCmp(MsgGlobal.server.dn + strlen(MsgGlobal.server.dn) - strlen(MsgGlobal.vs.server.names->Value[i]), MsgGlobal.vs.server.names->Value[i]) != 0) { count = MsgGlobal.vs.server.contexts->Used; if ((MDBRead(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_IP_ADDRESS, addresses) > 0) && (MDBReadDN(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_CONTEXT, MsgGlobal.vs.server.contexts) > 0)) { sprintf(storeObjectDn, "%s\\%s", MsgGlobal.vs.server.names->Value[i], MSGSRV_AGENT_STORE); if (MDBRead(storeObjectDn, MSGSRV_A_PORT, config)) { strcpy(storePortText, config->Value[0]); MDBFreeValues(config); } else { sprintf(storePortText, "%d", (BONGO_STORE_DEFAULT_PORT)); } MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs); for (j = count + 1; j < MsgGlobal.vs.server.contexts->Used; j++) { MDBAddValue(addresses->Value[count], addresses); MDBAddValue(storePortText, ports); MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs); } } } } } /* Now check any aliases that might be in the Internet Services container */ realUsed = MsgGlobal.vs.server.names->Used; if (MDBEnumerateObjects(MSGSRV_ROOT, C_ALIAS, NULL, MsgGlobal.vs.server.names)) { unsigned char realDn[MDB_MAX_OBJECT_CHARS + 1]; unsigned char realType[MDB_MAX_ATTRIBUTE_CHARS + 1]; /* Put the local context(s) first */ for (i = realUsed; i < MsgGlobal.vs.server.names->Used; i++) { MDBGetObjectDetails(MsgGlobal.vs.server.names->Value[i], realType, NULL, realDn, MsgGlobal.vs.server.names); /* MsgGlobal.server.dn is absolute, MsgGlobal.vs.server.names->Value isn't */ if ((XplStrCaseCmp(realType, MSGSRV_C_SERVER) == 0) && (XplStrCaseCmp(MsgGlobal.server.dn + strlen(MsgGlobal.server.dn) - strlen(realDn), realDn) != 0)) { count = MsgGlobal.vs.server.contexts->Used; if ((MDBRead(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_IP_ADDRESS, addresses) > 0) && (MDBReadDN(MsgGlobal.vs.server.names->Value[i], MSGSRV_A_CONTEXT, MsgGlobal.vs.server.contexts) > 0)) { sprintf(storeObjectDn, "%s\\%s", MsgGlobal.vs.server.names->Value[i], MSGSRV_AGENT_STORE); if (MDBRead(storeObjectDn, MSGSRV_A_PORT, config)) { strcpy(storePortText, config->Value[0]); MDBFreeValues(config); } else { sprintf(storePortText, "%d", BONGO_STORE_DEFAULT_PORT); } MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs); for (j = count + 1; j < MsgGlobal.vs.server.contexts->Used; j++) { MDBAddValue(addresses->Value[count], addresses); MDBAddValue(storePortText, ports); MDBAddValue(MsgGlobal.vs.server.names->Value[i], MsgGlobal.vs.storeDNs); } } } } } } /* MDBAddValue doesn't add empty values, so fake it */ /* with a ^A in the string */ emptyString[0]=EMPTY_CHAR; /* Now read all the store path values */ for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) { if (MDBRead(MsgGlobal.vs.server.contexts->Value[i], MSGSRV_A_MESSAGE_STORE, MsgGlobal.vs.storePaths) == 0) { /* Add an empty string, no context store specified */ MDBAddValue(emptyString, MsgGlobal.vs.storePaths); } else { MsgCleanPath(MsgGlobal.vs.storePaths->Value[i]); } } /* Initialize addr structure for each context */ MsgGlobal.vs.server.addr = MemMalloc0(MsgGlobal.vs.server.contexts->Used * sizeof(struct sockaddr_in)); if (!MsgGlobal.vs.server.addr) { MDBDestroyValueStruct(ports); return(FALSE); } for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) { MsgGlobal.vs.server.addr[i].sin_addr.s_addr = inet_addr(addresses->Value[i]); MsgGlobal.vs.server.addr[i].sin_port = htons(atol(ports->Value[i])); MsgGlobal.vs.server.addr[i].sin_family = AF_INET; } #if 0 for (i = 0; i < MsgGlobal.vs.server.contexts->Used; i++) { XplConsolePrintf("\rCtx:%-35s IP:%-15s Path:%s\n", MsgGlobal.vs.server.contexts->Value[i], addresses->Value[i], MsgGlobal.vs.storePaths->Value[i]); XplConsolePrintf("\rDN :%-35s\n\n", MsgGlobal.vs.storeDNs->Value[i]); } #endif MDBDestroyValueStruct(addresses); MDBDestroyValueStruct(ports); return(TRUE); } static BOOL MsgLibraryStop(void) { while (MsgGlobal.flags & MSGAPI_FLAG_MONITOR_RUNNING) { XplDelay(1000); } MDBDestroyValueStruct(MsgGlobal.vs.storeDNs); MDBDestroyValueStruct(MsgGlobal.vs.storePaths); MDBDestroyValueStruct(MsgGlobal.vs.server.contexts); MDBDestroyValueStruct(MsgGlobal.vs.server.names); if (MsgGlobal.vs.server.addr) { MemFree(MsgGlobal.vs.server.addr); MsgGlobal.vs.server.addr = NULL; } #ifdef PARENTOBJECT_STORE MDBDestroyValueStruct(MsgGlobal.vs.parent.stores); MDBDestroyValueStruct(MsgGlobal.vs.parent.objects); #endif XplRWLockDestroy(&MsgGlobal.configLock); return(TRUE); } /** * Get a config property from global configuration file. Removes dependency * on NCPServer object in the directory (as well as others). See msgapi.h for * possible properties. */ BOOL MsgGetConfigProperty(unsigned char *Buffer, unsigned char *Property) { int result = FALSE; char line[512]; char *ptr; FILE *fh; int len; char conf_path[FILENAME_MAX]; snprintf(conf_path, FILENAME_MAX, "%s/%s", XPL_DEFAULT_CONF_DIR, MSGSRV_CONFIG_FILENAME); if (!(fh = fopen(conf_path, "r"))) { return result; } while (fgets(line, 512, fh)) { if (line[0] != '#') { if ((ptr = strchr(line, '='))) { *ptr++ = '\0'; len = strlen(ptr); if (!strcmp(line, Property)) { if (ptr[len - 1] == '\n') { ptr[len - 1] = '\0'; } strncpy(Buffer, ptr, MSGSRV_CONFIG_MAX_PROP_CHARS); result = TRUE; break; } } else { break; } } } fclose(fh); return result; } void MsgGetUid(char *buffer, int buflen) { static int serial = 0; static char hostname[512] = ""; int thisSerial; XplMutexLock(MsgGlobal.sem.uid); if (hostname[0] == '\0') { if ((gethostname(hostname, sizeof(hostname) - 1) != 0) || hostname[0] == '\0') { strcpy(hostname, "localhost"); } } thisSerial = serial++; XplMutexUnlock(MsgGlobal.sem.uid); snprintf(buffer, buflen, "%lu.%lu.%d@%s", (unsigned long) time(NULL), (unsigned long) getpid(), thisSerial, hostname); } static BOOL MsgLibraryStart(void) { unsigned long i; struct sockaddr_in server_sockaddr; unsigned char path[XPL_MAX_PATH + 1]; MDBValueStruct *config; XplThreadID ID; /* Prepare later config updates */ XplRWLockInit(&MsgGlobal.configLock); /* Read generic configuration info */ MsgGlobal.flags |= MSGAPI_FLAG_SUPPORT_CONNMGR; // MsgGlobal.flags |= MSGAPI_FLAG_CLUSTERED; // 'BOUND' conflicts with 'CLUSTERED' ? // MsgGlobal.flags |= MSGAPI_FLAG_BOUND; strcpy(MsgGlobal.paths.certificate, XPL_DEFAULT_CERT_PATH); strcpy(MsgGlobal.paths.key, XPL_DEFAULT_KEY_PATH); /* Read "context" related stuff */ MsgGlobal.vs.server.names = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL); MsgGlobal.vs.server.contexts = MDBShareContext(MsgGlobal.vs.server.names); MsgGlobal.vs.storePaths = MDBShareContext(MsgGlobal.vs.server.names); MsgGlobal.vs.storeDNs = MDBShareContext(MsgGlobal.vs.server.names); MsgGlobal.vs.server.addr = NULL; #ifdef PARENTOBJECT_STORE MsgGlobal.vs.parent.objects = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL); MsgGlobal.vs.parent.stores = MDBShareContext(MsgGlobal.vs.parent.objects); #endif server_sockaddr.sin_addr.s_addr=XplGetHostIPAddress(); sprintf(MsgGlobal.address.string,"%d.%d.%d.%d", server_sockaddr.sin_addr.s_net, server_sockaddr.sin_addr.s_host, server_sockaddr.sin_addr.s_lh, server_sockaddr.sin_addr.s_impno); MDBAddValue(MsgGlobal.address.string, MsgGlobal.vs.server.names); if (!(MsgGlobal.flags & MSGAPI_FLAG_CLUSTERED)) { MDBWrite(MsgGlobal.server.dn, MSGSRV_A_IP_ADDRESS, MsgGlobal.vs.server.names); } else { MDBFreeValues(MsgGlobal.vs.server.names); if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_IP_ADDRESS, MsgGlobal.vs.server.names)>0) { strcpy(MsgGlobal.address.string, MsgGlobal.vs.server.names->Value[0]); } } MDBFreeValues(MsgGlobal.vs.server.names); MsgGlobal.address.local = inet_addr(MsgGlobal.address.string); // MDBFreeValues(config); //LoadContextList(config); // MDBDestroyValueStruct(config); return(TRUE); } MDBHandle MsgGetSystemDirectoryHandle(void) { MDBHandle systemHandle; unsigned char buffer[XPL_MAX_PATH + 1]; unsigned char credential[128]; FILE *eclients; memset(credential, 0, sizeof(credential)); sprintf(buffer, "%s/eclients.dat", XPL_DEFAULT_DBF_DIR); eclients = fopen(buffer, "rb"); if (eclients) { fread(credential, sizeof(unsigned char), sizeof(credential), eclients); fclose(eclients); eclients = NULL; } else { XplConsolePrintf("Insufficient privileges; shutting down.\n"); return(NULL); } if (!MsgGetConfigProperty(MsgGlobal.server.dn, MSGSRV_CONFIG_PROP_MESSAGING_SERVER)) { XplConsolePrintf("Messaging server not configured. Shutdown.\n"); return(NULL); } systemHandle = MDBAuthenticate("Bongo", MsgGlobal.server.dn, credential); if (systemHandle == NULL) { XplConsolePrintf("Messaging server credentials are invalid; shutting down.\n"); return(NULL); } return(systemHandle); } BOOL MsgGetBuildVersion(int *version, BOOL *custom) { /* Get the version of this build of bongo. * version - what SVN rev or branch minor this is * custom - whether or not this is a custom build */ int len = 0; char *ptr = BONGO_BUILD_VER; *version = strtol(ptr, NULL, 10); len = strlen(ptr); *custom = FALSE; if (ptr[len] == 'M') *custom = TRUE; return TRUE; } BOOL MsgGetAvailableVersion(int *version) { /* Get the information about latest version of bongo available * version - what SVN rev or branch minor is available */ char record[500]; char *ptr; int v; if (!MsgGetUpdateStatus(record, 499)) return FALSE; ptr = strchr(record, '|'); if (ptr == NULL) return FALSE; *version = strtol(record, &ptr, 10); return TRUE; } BOOL MsgGetUpdateStatus(char *record, int record_length) { char *branch = BONGO_BUILD_BRANCH; char *zone = "revisions.bongo-project.com"; char hostname[256]; XplDnsRecord *result = NULL; int status; snprintf(hostname, 255, "%s.%s", branch, zone); status = XplDnsResolve(hostname, &result, XPL_RR_TXT); switch(status) { case XPL_DNS_SUCCESS: snprintf(record, record_length, "%s", result[0].TXT.txt); MemFree(result); return TRUE; break; default: return FALSE; } } static BOOL MsgReadConfiguration(void) { MDBValueStruct *config; unsigned long i; struct tm *timeStruct; time_t utcTime; long tmp; /* Get Server Time Zone Offset */ tzset(); utcTime = time(NULL); timeStruct = localtime(&utcTime); if (timeStruct) { tmp = (((((((timeStruct->tm_year - 70) * 365) + timeStruct->tm_yday) * 24) + timeStruct->tm_hour) * 60) + timeStruct->tm_min) * 60; timeStruct = gmtime(&utcTime); tmp -= (((((((timeStruct->tm_year - 70) * 365) + timeStruct->tm_yday) * 24) + timeStruct->tm_hour) * 60) + timeStruct->tm_min) * 60; MsgDateSetUTCOffset(tmp); } /* Read operating parameters, this is so complicated because in version 2.5 * we changed the configuration of directories - before 2.5 we would always * append novonyx/mail to any given path, now we don't. The code tries to * automatically detect pre2.5 installs and change the DS attribute... */ config = MDBCreateValueStruct(MsgGlobal.directoryHandle, NULL); if (!config) { XplConsolePrintf("Messaging server out of memory; shutting down.\n"); MDBRelease(MsgGlobal.directoryHandle); MsgGlobal.directoryHandle = NULL; return(FALSE); } strcpy(MsgGlobal.paths.dbf, XPL_DEFAULT_DBF_DIR); MsgMakePath(MsgGlobal.paths.dbf); strcpy(MsgGlobal.paths.bin, XPL_DEFAULT_BIN_DIR); MsgMakePath(MsgGlobal.paths.bin); strcpy(MsgGlobal.paths.lib, XPL_DEFAULT_LIB_DIR); MsgMakePath(MsgGlobal.paths.lib); strcpy(MsgGlobal.paths.work, XPL_DEFAULT_WORK_DIR); MsgMakePath(MsgGlobal.paths.work); strcpy(MsgGlobal.paths.nls, XPL_DEFAULT_NLS_DIR); MsgMakePath(MsgGlobal.paths.nls); strcpy(MsgGlobal.paths.work, XPL_DEFAULT_WORK_DIR); MsgMakePath(MsgGlobal.paths.work); /* Official Name */ if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_OFFICIAL_NAME, config)) { strcpy(MsgGlobal.official.domain, config->Value[0]); MsgGlobal.official.domainLength = strlen(MsgGlobal.official.domain); } MDBFreeValues(config); if (MDBRead(MsgGlobal.server.dn, MSGSRV_A_SERVER_STANDALONE, config)) { if (config->Value[0][0]=='1') { MsgGlobal.flags |= MSGAPI_FLAG_STANDALONE; } } MDBDestroyValueStruct(config); return(TRUE); } static int MsgLibraryInit(void) { MsgGlobal.flags = 0; XplSafeWrite(MsgGlobal.useCount, 0); MsgGlobal.groupID = XplGetThreadGroupID(); MsgGlobal.directoryHandle = NULL; MsgGlobal.connManager = 0x0100007F; MsgGlobal.official.domain[0] = '\0'; MsgGlobal.official.domainLength = 0; XplOpenLocalSemaphore(MsgGlobal.sem.shutdown, 0); XplMutexInit(MsgGlobal.sem.uid); MemoryManagerOpen(NULL); if (!MDBInit()) { MemoryManagerClose(NULL); return 0; } MsgGlobal.directoryHandle = MsgGetSystemDirectoryHandle(); if (!(MsgGlobal.directoryHandle)) { MemoryManagerClose(NULL); return 0; } if (!MsgReadConfiguration()) { XplConsolePrintf("Cannot read configuration. Shutting down.\n"); MemoryManagerClose(NULL); return(0); } MsgLibraryStart(); MsgDateStart(); if (curl_global_init(CURL_GLOBAL_ALL)) { XplConsolePrintf("Could not initialize curl.\r\n"); return 0; } MSGAPIState = LIBRARY_RUNNING; return 1; } static void MsgLibraryShutdown(void) { XplThreadID oldGid; if (MSGAPIState == LIBRARY_RUNNING) { MSGAPIState = LIBRARY_SHUTTING_DOWN; MsgGlobal.flags |= MSGAPI_FLAG_EXITING; oldGid = XplSetThreadGroupID(MsgGlobal.groupID); MsgLibraryStop(); MemoryManagerClose(NULL); MSGAPIState = LIBRARY_SHUTDOWN; XplSetThreadGroupID(oldGid); } return; } MDBHandle MsgDirectoryHandle(void) { return(MsgGlobal.directoryHandle); } BOOL MsgExiting(void) { if (MsgGlobal.flags & MSGAPI_FLAG_EXITING) { return(TRUE); } return(FALSE); } EXPORT BOOL MsgShutdown(void) { XplSafeDecrement(MsgGlobal.useCount); if (XplSafeRead(MsgGlobal.useCount) > 0) { return(FALSE); } MsgLibraryShutdown(); return(TRUE); } EXPORT MDBHandle MsgInit(void) { if (MSGAPIState == LIBRARY_LOADED) { MSGAPIState = LIBRARY_INITIALIZING; if (!MsgLibraryInit()) { return NULL; } } while (MSGAPIState < LIBRARY_RUNNING) { XplDelay(100); } if (MSGAPIState == LIBRARY_RUNNING) { XplSafeIncrement(MsgGlobal.useCount); } return((MSGAPIState == LIBRARY_RUNNING) ? MsgGlobal.directoryHandle : NULL); } EXPORT BOOL MsgSetRecoveryFlag(void) { // FIXME: TODO :) return FALSE; } EXPORT BOOL MsgGetRecoveryFlag(void) { // FIXME: TODO :) return FALSE; } EXPORT BOOL MsgGetServerCredential(char *buffer) { unsigned char credential[4097]; unsigned char file[120]; FILE *credfile; memset(credential, 0, sizeof(credential)); sprintf(file, "%s/credential.dat", XPL_DEFAULT_DBF_DIR); credfile = fopen(file, "rb"); if (credfile) { fread(credential, sizeof(unsigned char), sizeof(credential), credfile); fclose(credfile); credfile = NULL; HashCredential(MsgGlobal.server.dn, credential, buffer); } }