/*********************************************************************** * * Copyright (C) 2006 Novell, 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. * * Author: Juan Carlos Luciani * ***********************************************************************/ //===[ Include files ]===================================================== #include "internal.h" //===[ Type definitions ]================================================== // // Normalized Host Name Cache Entry definition // typedef struct _NormalizedHostNameCacheEntry { LIST_ENTRY listEntry; char *pHostName; char *pNormalizedHostName; size_t buffLengthRequired; } NormalizedHostNameCacheEntry, *PNormalizedHostNameCacheEntry; //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== static BOOLEAN hostNameNormalizationInitialized = FALSE; // Normalized host name cache list head static LIST_ENTRY normalizedHostNameCacheListHead; // Synchronization mutex for the normalized host name cache static HANDLE hNormalizedHostNameCacheMutex; // Client configuration file folder char clientConfigFolderPartialPath[] = "Novell\\Casa\\Etc\\Auth"; char clientConfigFolder[MAX_PATH + sizeof(clientConfigFolderPartialPath)]; // Authentication mechanism configuration file folder char mechConfigFolderPartialPath[] = "Novell\\Casa\\Etc\\Auth\\Mechanisms"; char mechConfigFolder[MAX_PATH + sizeof(mechConfigFolderPartialPath)]; // Program files folder char programFilesFolder[MAX_PATH] = {0}; // Path separator char pathCharString[] = "\\"; //++======================================================================= CasaStatus CreateUserMutex( HANDLE *phMutex ) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { #define USER_MUTEX_NAME_FMT_STRING "Global\\CASA_Auth_Mutex_%s" CasaStatus retStatus = CASA_STATUS_SUCCESS; char *pUsername = NULL; DWORD nameLength = 0; DbgTrace(1, "-CreateUserMutex- Start\n", 0); // Get the size of the buffer required to obtain the user name GetUserName(pUsername, &nameLength); if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // Allocate buffer to hold the user name pUsername = (char*) malloc(nameLength); if (pUsername) { // Get the name of the user if (GetUserName(pUsername, &nameLength)) { SECURITY_ATTRIBUTES mutexAttributes; char *pMutexName; // Allocate a buffer to hold the mutex name pMutexName = (char*) malloc(sizeof(USER_MUTEX_NAME_FMT_STRING) + nameLength); if (pMutexName) { // Now lets create a global semaphore for the // user and allow its handle to be inherited. mutexAttributes.nLength = sizeof(mutexAttributes); mutexAttributes.lpSecurityDescriptor = NULL; mutexAttributes.bInheritHandle = TRUE; if (sprintf(pMutexName, USER_MUTEX_NAME_FMT_STRING, pUsername) != -1) { *phMutex = CreateMutex(&mutexAttributes, FALSE, pMutexName); if (*phMutex == NULL) { DbgTrace(0, "-CreateUserMutex- CreateMutex failed, error = %d\n", GetLastError()); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); } } else { DbgTrace(0, "-CreateUserMutex- sprintf failed, error = %d\n", GetLastError()); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); } // Free the buffer used to hold the user mutex name free(pMutexName); } else { DbgTrace(0, "-CreateUserMutex- Buffer allocation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } else { DbgTrace(0, "-CreateUserMutex- GetUserName failed, error = %d\n", GetLastError()); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); } // Free the buffer allocated to hold the user name free(pUsername); } else { DbgTrace(0, "-CreateUserMutex- Buffer allocation error\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } else { DbgTrace(0, "-CreateUserMutex- Unexpected GetUserName error, error = %d\n", GetLastError()); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); } DbgTrace(1, "-CreateUserMutex- End, retStatus\n", retStatus); return retStatus; } //++======================================================================= void AcquireUserMutex( HANDLE hMutex ) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(2, "-AcquireUserMutex- Start\n", 0); WaitForSingleObject(hMutex, INFINITE); DbgTrace(2, "-AcquireUserMutex- End\n", 0); } //++======================================================================= void ReleaseUserMutex( HANDLE hMutex ) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(2, "-ReleaseUserMutex- Start\n", 0); if (ReleaseMutex(hMutex) == 0) { DbgTrace(0, "-ReleaseUserMutex- ReleaseMutex failed, error = %d\n", GetLastError()); } DbgTrace(2, "-ReleaseUserMutex- End\n", 0); } //++======================================================================= void DestroyUserMutex( HANDLE hMutex ) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(2, "-DestroyUserMutex- Start\n", 0); if (CloseHandle(hMutex) == 0) { DbgTrace(0, "-DestroyUserMutex- CloseHandle failed, error = %d\n", GetLastError()); } DbgTrace(2, "-DestroyUserMutex- End\n", 0); } //++======================================================================= LIB_HANDLE OpenLibrary( IN char *pFileName) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { LIB_HANDLE libHandle = NULL; char *pLibPath = NULL; DbgTrace(1, "-OpenLibrary- Start\n", 0); // Check for a partial path to the program files folder if (strlen(pFileName) > strlen("\\Program Files")) { if (_strnicmp(pFileName, "\\Program Files", strlen("\\Program Files")) == 0) { // The file name contains a partial path to the program files folder, // convert it to an absolute path. char *p = pFileName + strlen("\\Program Files"); pLibPath = malloc(strlen(programFilesFolder) + strlen(p) + 1); if (pLibPath) { strcpy(pLibPath, programFilesFolder); strcat(pLibPath, p); } else { DbgTrace(0, "-OpenLibrary- Buffer allocation failure\n", 0); } } else { // Use the path specified pLibPath = pFileName; } } else { // Use the path specified pLibPath = pFileName; } // Proceed if pLibPath has been setup if (pLibPath) { libHandle = LoadLibrary(pLibPath); if (libHandle == NULL) { DbgTrace(0, "-OpenLibrary- Not able to load library, error = %d\n", GetLastError()); } // Free memory allocated for library path if necessary if (pLibPath != pFileName) free(pLibPath); } DbgTrace(1, "-OpenLibrary- End, handle = %08X\n", libHandle); return libHandle; } //++======================================================================= void CloseLibrary( IN LIB_HANDLE libHandle) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { DbgTrace(1, "-CloseLibrary- Start\n", 0); FreeLibrary(libHandle); DbgTrace(1, "-CloseLibrary- End\n", 0); } //++======================================================================= void* GetFunctionPtr( IN LIB_HANDLE libHandle, IN char *pFunctionName) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { void *pFuncPtr; DbgTrace(1, "-GetFunctionPtr- Start\n", 0); pFuncPtr = GetProcAddress(libHandle, pFunctionName); if (pFuncPtr == NULL) { DbgTrace(0, "-GetFunctionPtr- Not able to obtain func ptr, error = %d\n", GetLastError()); } DbgTrace(1, "-GetFunctionPtr- End, pFuncPtr = %08X\n", pFuncPtr); return pFuncPtr; } //++======================================================================= char* NormalizeHostName( IN const char *pHostName) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { char *pNormalizedName = NULL; LIST_ENTRY *pListEntry; NormalizedHostNameCacheEntry *pEntry = NULL; DbgTrace(1, "-NormalizeHostName- Start\n", 0); // Obtain our synchronization mutex WaitForSingleObject(hNormalizedHostNameCacheMutex, INFINITE); // First try to find an entry in the normalized host name cache // for the host name provided. pListEntry = normalizedHostNameCacheListHead.Flink; while (pListEntry != &normalizedHostNameCacheListHead) { // Get pointer to the entry pEntry = CONTAINING_RECORD(pListEntry, NormalizedHostNameCacheEntry, listEntry); // Check if the entry is for the host name if (strcmp(pHostName, pEntry->pHostName) == 0) { // This entry corresponds to the given host name break; } else { // The entry does not correspond to the given host name pEntry = NULL; } // Advance to the next entry pListEntry = pListEntry->Flink; } // Check if we found an entry in our cache for the given host name if (pEntry) { // Entry found, obtain the normalized name from it. pNormalizedName = (char*) malloc(pEntry->buffLengthRequired); if (pNormalizedName) { // Copy the normalized name onto the allocated buffer strcpy(pNormalizedName, pEntry->pNormalizedHostName); } else { DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0); } } else { // An entry was not found in our cache, create one. pEntry = (NormalizedHostNameCacheEntry*) malloc(sizeof(NormalizedHostNameCacheEntry)); if (pEntry) { // Zero the entry memset(pEntry, 0, sizeof(*pEntry)); // Allocate a buffer to hold the host name in the entry pEntry->pHostName = (char*) malloc(strlen(pHostName) + 1); if (pEntry->pHostName) { struct hostent *pLookupResult; struct sockaddr_in sockAddr = {0}; // Copy the host name given into the allocated buffer strcpy(pEntry->pHostName, pHostName); // Now try to resolve the normalized name pLookupResult = gethostbyname(pHostName); if (pLookupResult && pLookupResult->h_addrtype == AF_INET && pLookupResult->h_length > 0 && pLookupResult->h_addr_list[0] != NULL) { char *pDnsHostName = (char*) malloc(NI_MAXHOST + 1); if (pDnsHostName) { // Set up a sockaddr structure sockAddr.sin_family = AF_INET; sockAddr.sin_addr.S_un.S_addr = *((int*) pLookupResult->h_addr_list[0]); // Now try to resolve the name using DNS if (getnameinfo((const struct sockaddr*) &sockAddr, sizeof(sockAddr), pDnsHostName, NI_MAXHOST, NULL, 0, NI_NAMEREQD) == 0) { // We resolved the address to a DNS name, use it as the normalized name. pEntry->buffLengthRequired = strlen(pDnsHostName) + 1; pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired); if (pEntry->pNormalizedHostName) { // Copy the dns name strcpy(pEntry->pNormalizedHostName, pDnsHostName); } else { DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0); } } else { DbgTrace(0, "-NormalizeHostName- getnameInfo failed, error %d\n", WSAGetLastError()); // Not able to resolve the name in DNS, just use the host name as // the normalized name. pEntry->buffLengthRequired = strlen(pHostName) + 1; pEntry->pNormalizedHostName = (char*) malloc(pEntry->buffLengthRequired); if (pEntry->pNormalizedHostName) { // Copy the host name strcpy(pEntry->pNormalizedHostName, pHostName); } else { DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0); } } // Free the buffer allocated to hold the DNS name free(pDnsHostName); } else { DbgTrace(0, "-NormalizeHostName- Buffer allocation failure\n", 0); } } else { DbgTrace(0, "-NormalizeHostName- Name resolution failed, error = %d\n", WSAGetLastError()); } } else { DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0); // Free the space allocated for the entry free(pEntry); } // Proceed based on whether or not we normalized the name if (pEntry->pNormalizedHostName) { // The name was normalized, save the entry in our cache. InsertHeadList(&normalizedHostNameCacheListHead, &pEntry->listEntry); // Return the normalized name present in the entry pNormalizedName = (char*) malloc(pEntry->buffLengthRequired); if (pNormalizedName) { // Copy the normalized name onto the allocated buffer strcpy(pNormalizedName, pEntry->pNormalizedHostName); } else { DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0); } } else { // The host name was not normalized, free allocated resources. if (pEntry->pHostName) free(pEntry->pHostName); free(pEntry); } } else { DbgTrace(0, "-NormalizeHostName- Buffer allocation error\n", 0); } } // Release our synchronization mutex if (ReleaseMutex(hNormalizedHostNameCacheMutex) == 0) { DbgTrace(0, "-NormalizeHostName- ReleaseMutex failed, error\n", 0); } DbgTrace(1, "-NormalizeHostName- End, pNormalizedName = %08X\n", pNormalizedName); return pNormalizedName; } //++======================================================================= CasaStatus InitializeHostNameNormalization(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); int winsockStartupResult; WSADATA winsockData; DbgTrace(1, "-InitializeHostNameNormalization- Start\n", 0); // Initialize winsock if ((winsockStartupResult = WSAStartup(MAKEWORD(2,2), &winsockData)) == 0) { // Initialize the cache list head InitializeListHead(&normalizedHostNameCacheListHead); // Create a cache mutex only applicable to the current process hNormalizedHostNameCacheMutex = CreateMutex(NULL, FALSE, NULL); if (hNormalizedHostNameCacheMutex != NULL) { hostNameNormalizationInitialized = TRUE; retStatus = CASA_STATUS_SUCCESS; } else { DbgTrace(0, "-InitializeHostNameNormalization- CreateMutex failed, error = %d\n", GetLastError()); WSACleanup(); } } else { DbgTrace(0, "-InitializeHostNameNormalization- WSAStartup failed, error = %d\n", winsockStartupResult); } DbgTrace(1, "-InitializeHostNameNormalization- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= void UnInitializeHostNameNormalization(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { LIST_ENTRY *pListEntry; NormalizedHostNameCacheEntry *pEntry = NULL; DbgTrace(1, "-UnInitializeHostNameNormalization- Start\n", 0); // Proceed if initialization succeeded if (hostNameNormalizationInitialized) { // Un-initialize winsock WSACleanup(); // Free up any normalized host names in our cache pListEntry = normalizedHostNameCacheListHead.Flink; while (pListEntry != &normalizedHostNameCacheListHead) { // Get pointer to the entry pEntry = CONTAINING_RECORD(pListEntry, NormalizedHostNameCacheEntry, listEntry); // Remove the entry from the list RemoveEntryList(pListEntry); // Free the entry if (pEntry->pHostName) free(pEntry->pHostName); if (pEntry->pNormalizedHostName) free(pEntry->pNormalizedHostName); free(pEntry); // Try to go to the next entry pListEntry = normalizedHostNameCacheListHead.Flink; } // Forget about being initialized hostNameNormalizationInitialized = FALSE; } DbgTrace(1, "-UnInitializeHostNameNormalization- End\n", 0); } //++======================================================================= //++======================================================================= //++=======================================================================