/*********************************************************************** * * Copyright (C) 2005-2006 Novell, Inc. Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * This library 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 * Library Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, Novell, Inc. * * To contact Novell about this file by physical or electronic mail, * you may find current contact information at www.novell.com. * ***********************************************************************/ //===[ Include files ]===================================================== #include "internal.h" //===[ Type definitions ]================================================== // // Config Key object // typedef struct _ConfigKey { LIST_ENTRY listEntry; char *pKeyName; int keyNameLen; char *pValue; int valueLen; } ConfigKey, *pConfigKey; // // Config Interface instance data // typedef struct _ConfigIfInstance { LIST_ENTRY listEntry; int refCount; char *pConfigFolder; int configFolderLen; char *pConfigName; int configNameLen; LIST_ENTRY configKeyListHead; ConfigIf configIf; } ConfigIfInstance, *PConfigIfInstance; //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== // ConfigIf synchronization mutex and variables static pthread_mutex_t g_configIfMutex = PTHREAD_MUTEX_INITIALIZER; static LIST_ENTRY g_configIfListHead = {&g_configIfListHead, &g_configIfListHead}; static int g_numConfigIfObjs = 0; //++======================================================================= static void RemoveWhiteSpaceFromTheEnd( IN const char *pInString) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { char *pLineEnd = (char*) pInString + strlen(pInString) - 1; DbgTrace(3, "auth_token -RemoveWhiteSpaceFromTheEnd- Start\n", 0); while (pLineEnd != pInString) { if (*pLineEnd == '\n' || *pLineEnd == ' ' || *pLineEnd == '\t') { // Strike this character *pLineEnd = '\0'; pLineEnd --; } else { // Found a non-white character break; } } DbgTrace(3, "auth_token -RemoveWhiteSpaceFromTheEnd- End\n", 0); } //++======================================================================= static char* SkipWhiteSpace( IN const char *pInString) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { char *pOutString = (char*) pInString; DbgTrace(3, "auth_token -SkipWhiteSpace- Start\n", 0); while (*pOutString != '\0') { if (*pOutString == '\n' || *pOutString == ' ' || *pOutString == '\t') { // Skip this character pOutString ++; } else { // Found a non-white character break; } } DbgTrace(3, "auth_token -SkipWhiteSpace- End\n", 0); return pOutString; } //++======================================================================= static char* SkipNonWhiteSpace( IN const char *pInString) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { char *pOutString; DbgTrace(3, "auth_token -SkipNonWhiteSpace- Start\n", 0); while (*pOutString != '\0') { if (*pOutString == '\n' || *pOutString == ' ' || *pOutString == '\t') { // Found a white character break; } else { // Skip this character pOutString ++; } } DbgTrace(3, "auth_token -SkipNonWhiteSpace- End\n", 0); return pOutString; } //++======================================================================= static void LowerCaseString( IN char *pDestString, IN const char *pSrcString) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int i; DbgTrace(3, "auth_token -LowerCaseString- Start\n", 0); // Copy the string as lower case for (i = 0; pSrcString[i] != '\0'; i++) { if (isalpha(pSrcString[i])) pDestString[i] = tolower(pSrcString[i]); else pDestString[i] = pSrcString[i]; } // Null terminate the destination string pDestString[i] = '\0'; DbgTrace(3, "auth_token -LowerCaseString- End\n", 0); } //++======================================================================= int SSCS_CALL ConfigIf_AddReference( IN const void *pIfInstance) // // Arguments: // pIfInstance - // Pointer to interface object. // // Returns: // Interface reference count. // // Description: // Increases interface reference count. // // L2 //=======================================================================-- { int refCount; ConfigIfInstance *pConfigIfInstance = CONTAINING_RECORD(pIfInstance, ConfigIfInstance, configIf); DbgTrace(2, "auth_token -ConfigIf_AddReference- Start\n", 0); // Increment the reference count on the object pthread_mutex_lock(&g_configIfMutex); pConfigIfInstance->refCount ++; refCount = pConfigIfInstance->refCount; pthread_mutex_unlock(&g_configIfMutex); DbgTrace(2, "auth_token -ConfigIf_AddReference- End, refCount = %08X\n", refCount); return refCount; } //++======================================================================= void SSCS_CALL ConfigIf_ReleaseReference( IN const void *pIfInstance) // // Arguments: // pIfInstance - // Pointer to interface object. // // Returns: // Nothing. // // Description: // Decreases interface reference count. The interface is deallocated if // the reference count becomes zero. // // L2 //=======================================================================-- { bool freeObj = false; ConfigIfInstance *pConfigIfInstance = CONTAINING_RECORD(pIfInstance, ConfigIfInstance, configIf); DbgTrace(2, "auth_token -ConfigIf_ReleaseReference- Start\n", 0); // Decrement the reference count on the object and determine if it needs to // be released. pthread_mutex_lock(&g_configIfMutex); pConfigIfInstance->refCount --; if (pConfigIfInstance->refCount == 0) { // The object needs to be released, forget about it. freeObj = true; g_numConfigIfObjs --; RemoveEntryList(&pConfigIfInstance->listEntry); } pthread_mutex_unlock(&g_configIfMutex); // Free object if necessary if (freeObj) { // Free all of the config key objects associated with this configuration // interface instance. while (!IsListEmpty(&pConfigIfInstance->configKeyListHead)) { LIST_ENTRY *pListEntry; ConfigKey *pConfigKey; // Get reference to entry at the head of the list pListEntry = pConfigIfInstance->configKeyListHead.Flink; pConfigKey = CONTAINING_RECORD(pListEntry, ConfigKey, listEntry); // Free the buffers associated with the ConfigKey free(pConfigKey->pKeyName); free(pConfigKey->pValue); // Remove the entry from the list RemoveEntryList(&pConfigKey->listEntry); // Finish freeing the ConfigKey free(pConfigKey); } // Free the rest of the buffers associated with the interface instance data free(pConfigIfInstance->pConfigFolder); free(pConfigIfInstance->pConfigName); free(pConfigIfInstance); } DbgTrace(2, "auth_token -ConfigIf_ReleaseReference- End\n", 0); } //++======================================================================= char* SSCS_CALL ConfigIf__GetEntryValue( IN const void *pIfInstance, IN const char *pKeyName) // // Arguments: // pIfInstance - // Pointer to interface object. // // pKeyName - // Pointer to NULL terminated string that contains the // name of the key whose value is being requested. // // Returns: // Pointer to NULL terminated string with value being requested or NULL. // // Description: // Gets value associated with a key for the configuration object. // // L2 //=======================================================================-- { ConfigIfInstance *pConfigIfInstance = CONTAINING_RECORD(pIfInstance, ConfigIfInstance, configIf); char *pValue = NULL; LIST_ENTRY *pListEntry; ConfigKey *pConfigKey; int keyNameLen = strlen(pKeyName); char *pKeyNameLowercase; DbgTrace(2, "auth_token -ConfigIf_GetEntryValue- Start\n", 0); // Allocate enough space to hold lower case version of the key name pKeyNameLowercase = malloc(keyNameLen); if (pKeyNameLowercase) { // Lower case the key name LowerCaseString(pKeyNameLowercase, pKeyName); // Try to find matching ConfigKey pListEntry = pConfigIfInstance->configKeyListHead.Flink; while (pListEntry != &pConfigIfInstance->configKeyListHead) { // Get pointer to the current entry pConfigKey = CONTAINING_RECORD(pListEntry, ConfigKey, listEntry); // Check if we have a match if (pConfigKey->keyNameLen == keyNameLen && memcmp(pKeyNameLowercase, pConfigKey->pKeyName, keyNameLen) == 0) { // We found it, return its value. pValue = malloc(pConfigKey->valueLen + 1); if (pValue) { strcpy(pValue, pConfigKey->pValue); } else { DbgTrace(0, "auth_token -ConfigIf_GetEntryValue- Buffer allocation failure\n", 0); } break; } // Advance to the next entry pListEntry = pListEntry->Flink; } // Free the lower case version of the key name free(pKeyNameLowercase); } else { DbgTrace(0, "auth_token -ConfigIf_GetEntryValue- Buffer allocation failure\n", 0); } DbgTrace(2, "auth_token -ConfigIf_GetEntryValue- End, pValue = %08X\n", (unsigned int) pValue); return pValue; } //++======================================================================= CasaStatus SSCS_CALL GetConfigInterface( IN const char *pConfigFolder, IN const char *pConfigName, INOUT ConfigIf **ppConfigIf) // // Arguments: // pConfigFolder - // Pointer to NULL terminated string that contains the name of // the folder containing the configuration file. // // pConfigName - // Pointer to NULL terminated string containing the name of the // configuration entry. // // ppConfigIf - // Pointer to variable that will receive pointer to ConfigIf // instance. // // Returns: // Casa Status // // Description: // Get configuration interface to specified configuration entry. // // L2 //=======================================================================-- { int configFolderLen = strlen(pConfigFolder); int configNameLen = strlen(pConfigName); ConfigIfInstance *pConfigIfInstance; LIST_ENTRY *pListEntry; CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_INFORMATIONAL, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_OBJECT_NOT_FOUND); DbgTrace(2, "auth_token -GetConfigInterface- Start\n", 0); // Obtain exclusive access to our mutex pthread_mutex_lock(&g_configIfMutex); // Check if we already have an entry in our list for the configuration pListEntry = g_configIfListHead.Flink; while (pListEntry != &g_configIfListHead) { // Get pointer to the current entry pConfigIfInstance = CONTAINING_RECORD(pListEntry, ConfigIfInstance, listEntry); // Check if we have a match if (pConfigIfInstance->configFolderLen == configFolderLen && pConfigIfInstance->configNameLen == configNameLen && memcmp(pConfigFolder, pConfigIfInstance->pConfigFolder, configFolderLen) == 0 && memcmp(pConfigName, pConfigIfInstance->pConfigName, configNameLen) == 0) { // We found it, return the ConfigIf associated with the instance data // after incrementing its reference count. pConfigIfInstance->refCount ++; *ppConfigIf = &pConfigIfInstance->configIf; // Success retStatus = CASA_STATUS_SUCCESS; break; } // Advance to the next entry pListEntry = pListEntry->Flink; } // Proceed to create interface instance data for the configuration if none was found if (retStatus != CASA_STATUS_SUCCESS) { char *pFilePath; // Build a string containing the configuration file path pFilePath = malloc(configFolderLen + 1 + configNameLen + sizeof(".conf")); if (pFilePath) { FILE *pConfigFile; strcpy(pFilePath, pConfigFolder); strcat(pFilePath, "/"); strcat(pFilePath, pConfigName); strcat(pFilePath, ".conf"); // Open the configuration file for reading pConfigFile = fopen(pFilePath, "r"); if (pConfigFile) { // Opened the file, create a ConfigIfInstance object for it. pConfigIfInstance = malloc(sizeof(*pConfigIfInstance)); if (pConfigIfInstance) { // Initialize the list head within the instance data InitializeListHead(&pConfigIfInstance->configKeyListHead); // Initialize the ConfigIf within the instance data pConfigIfInstance->configIf.addReference = ConfigIf_AddReference; pConfigIfInstance->configIf.releaseReference = ConfigIf_ReleaseReference; pConfigIfInstance->configIf.getEntryValue = ConfigIf__GetEntryValue; // Save the ConfigFolder and ConfigName information within the instance data pConfigIfInstance->pConfigFolder = malloc(configFolderLen + 1); if (pConfigIfInstance->pConfigFolder) { strcpy(pConfigIfInstance->pConfigFolder, pConfigFolder); pConfigIfInstance->configFolderLen = configFolderLen; pConfigIfInstance->pConfigName = malloc(configNameLen + 1); if (pConfigIfInstance->pConfigName) { strcpy(pConfigIfInstance->pConfigName, pConfigName); pConfigIfInstance->configNameLen = configNameLen; // Add the instance data into our list and bump up its reference count // since we did that. InsertTailList(&g_configIfListHead, &pConfigIfInstance->listEntry); pConfigIfInstance->refCount = 1; // At this point we want to return success to the caller even if we // experience a read error. retStatus = CASA_STATUS_SUCCESS; // Return the ConfigIf associated with the instance data after // incrementing its reference count. pConfigIfInstance->refCount ++; *ppConfigIf = &pConfigIfInstance->configIf; // Now update the instance data with the information present in the file if (fseek(pConfigFile, 0, SEEK_SET) == 0) { char line[512]; while (fgets(line, sizeof(line), pConfigFile) != NULL) { int lineLength; RemoveWhiteSpaceFromTheEnd(line); lineLength = strlen(line); if (lineLength != 0) { char *pKey; char *pKeyEnd; char *pValue; ConfigKey *pConfigKey; // Attempt to find the key pKey = SkipWhiteSpace(line); // Make sure that we are not dealing with an empty line or a comment if (*pKey == '\0' || *pKey == '#') continue; // Go past the key pKeyEnd = SkipNonWhiteSpace(pKey); // Protect against a malformed line if (*pKeyEnd == '\0') { DbgTrace(0, "auth_token -GetConfigInterface- Key found without value\n", 0); continue; } // Attempt to find the value pValue = SkipWhiteSpace(pKeyEnd); // Protect against a malformed line if (*pValue == '\0') { DbgTrace(0, "auth_token -GetConfigInterface- Key found without value\n", 0); continue; } // Delineate the key *pKeyEnd = '\0'; // Create a ConfigKey object for this key/value pair pConfigKey = malloc(sizeof(*pConfigKey)); if (pConfigKey) { pConfigKey->keyNameLen = strlen(pKey); pConfigKey->pKeyName = malloc(pConfigKey->keyNameLen + 1); if (pConfigKey->pKeyName) { // Save the key name in lower case LowerCaseString(pConfigKey->pKeyName, pKey); pConfigKey->valueLen = strlen(pValue); pConfigKey->pValue = malloc(pConfigKey->valueLen + 1); if (pConfigKey->pValue) { strcpy(pConfigKey->pValue, pValue); // The entry is ready, now associate it with the instance data. InsertTailList(&pConfigIfInstance->configKeyListHead, &pConfigKey->listEntry); } else { DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); free(pConfigKey->pKeyName); free(pConfigKey); } } else { DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); free(pConfigKey); } } else { DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); } } } } else { DbgTrace(0, "auth_token -GetConfigInterface- File seek error, errno = %d\n", errno); } } else { DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); // Free the buffers associated with the instance data free(pConfigIfInstance->pConfigFolder); free(pConfigIfInstance); } } else { DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); // Free the buffer allocated for the instance data free(pConfigIfInstance); } } else { DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation failure\n", 0); } // Close the file fclose(pConfigFile); } else { DbgTrace(1, "auth_token -GetConfigInterface- Unable to open config file, errno = %d\n", errno); } } else { DbgTrace(0, "auth_token -GetConfigInterface- Buffer allocation error\n", 0); } } // Release exclusive access to our mutex pthread_mutex_unlock(&g_configIfMutex); DbgTrace(2, "auth_token -GetConfigInterface- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= //++======================================================================= //++=======================================================================