/*********************************************************************** * File: auth_token.c * Author: Juan Carlos Luciani (jluciani@novell.com) * * Abstract: Implements the CASA Authentication Token credentials API. * * Copyright (C) 2005 Novell, Inc. * * 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 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, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * 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 ]================================================== // // AuthModule definition // typedef struct _AuthModule { LIST_ENTRY listEntry; char *pAuthTypeName; int authTypeNameLen; void *libHandle; AuthTokenIf *pAuthTokenIf; } AuthModule, *PAuthModule; //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== // Debug Level int DebugLevel = 1; // AuthModule List and syncronizing mutex static LIST_ENTRY g_authModuleListHead = {&g_authModuleListHead, &g_authModuleListHead}; static pthread_mutex_t g_authModuleMutex = PTHREAD_MUTEX_INITIALIZER; //++======================================================================= static CasaStatus GetAuthTokenInterface( IN const char *pAuthTypeName, INOUT AuthTokenIf **ppAuthTokenIf) // // Arguments: // // Returns: // // Abstract: // // Notes: // // Environment: // // L2 //=======================================================================-- { CasaStatus retStatus; ConfigIf *pModuleConfigIf; DbgTrace(2, "auth_token -GetAuthTokenInterface- Start\n", 0); // Get the configuration for the module retStatus = GetConfigInterface("/etc/opt/novell/CASA/authtoken.d/modules.d", pAuthTypeName, &pModuleConfigIf); if (CASA_SUCCESS(retStatus) && CasaStatusCode(retStatus) != CASA_STATUS_OBJECT_NOT_FOUND) { LIST_ENTRY *pListEntry; AuthModule *pAuthModule = NULL; int32_t authTypeNameLen = strlen(pAuthTypeName); // Gain exclusive access to our mutex pthread_mutex_lock(&g_authModuleMutex); // Look if we already have the module in our list pListEntry = g_authModuleListHead.Flink; while (pListEntry != &g_authModuleListHead) { // Get pointer to the current entry pAuthModule = CONTAINING_RECORD(pListEntry, AuthModule, listEntry); // Check if this is the module that we need if (pAuthModule->authTypeNameLen == authTypeNameLen && memcmp(pAuthTypeName, pAuthModule->pAuthTypeName, authTypeNameLen) == 0) { // This is the module that we need, stop looking. break; } else { // This is not the module that we are looking for pAuthModule = NULL; } // Advance to the next entry pListEntry = pListEntry->Flink; } // Proceed based on whether or not a module was found if (pAuthModule) { // Module found in our list, provide the caller with its AuthTokenIf // instance after we have incremented its reference count. pAuthModule->pAuthTokenIf->addReference(pAuthModule->pAuthTokenIf); *ppAuthTokenIf = pAuthModule->pAuthTokenIf; // Success retStatus = CASA_STATUS_SUCCESS; } else { // Needed module not found in our list, create an entry. pAuthModule = malloc(sizeof(*pAuthModule)); if (pAuthModule) { // Allocate buffer to contain the authentication type name within the module entry pAuthModule->pAuthTypeName = malloc(authTypeNameLen + 1); if (pAuthModule->pAuthTypeName) { char *pLibraryName; // Initialize the library handle field pAuthModule->libHandle = NULL; // Save the auth type name within the entry strcpy(pAuthModule->pAuthTypeName, pAuthTypeName); pAuthModule->authTypeNameLen = authTypeNameLen; // Obtain the name of the library that we must load pLibraryName = pModuleConfigIf->getEntryValue(pModuleConfigIf, "LibraryName"); if (pLibraryName) { // Load the library pAuthModule->libHandle = dlopen(pLibraryName, RTLD_LAZY); if (pAuthModule->libHandle) { PFN_GetAuthTokenIfRtn pGetAuthTokenIfRtn; // Library has been loaded, now get a pointer to its GetAuthTokenInterface routine pGetAuthTokenIfRtn = dlsym(pAuthModule->libHandle, GET_AUTH_TOKEN_INTERFACE_RTN_SYMBOL); if (pGetAuthTokenIfRtn) { // Now, obtain the modules AuthTokenIf. retStatus = (pGetAuthTokenIfRtn)(pModuleConfigIf, &pAuthModule->pAuthTokenIf); } else { DbgTrace(0, "auth_token -GetAuthTokenInterface- dlsym error = %s\n", dlerror()); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_LIBRARY_LOAD_FAILURE); } } else { DbgTrace(0, "auth_token -GetAuthTokenInterface- dlopen error = %s\n", dlerror()); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); } // Free the buffer holding the library name free(pLibraryName); } else { DbgTrace(0, "auth_token -GetAuthTokenInterface- Library name not configured\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_CONFIGURATION_ERROR); } // Check if we were successful at obtaining the AuthTokenIf instance for the // module. if (CASA_SUCCESS(retStatus)) { // Insert the entry in the list, provide the caller with its AuthTokenIf // instance after we have incremented its reference count. InsertTailList(&g_authModuleListHead, &pAuthModule->listEntry); pAuthModule->pAuthTokenIf->addReference(pAuthModule->pAuthTokenIf); *ppAuthTokenIf = pAuthModule->pAuthTokenIf; } else { // Failed, free resources. free(pAuthModule->pAuthTypeName); if (pAuthModule->libHandle) dlclose(pAuthModule->libHandle); free(pAuthModule); } } else { DbgTrace(0, "auth_token -GetAuthTokenInterface- Unable to allocate buffer\n", 0); // Free buffer allocated for entry free(pAuthModule); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } else { DbgTrace(0, "auth_token -GetAuthTokenInterface- Unable to allocate buffer\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } // Release exclusive access to our mutex pthread_mutex_unlock(&g_authModuleMutex); // Release config interface instance pModuleConfigIf->releaseReference(pModuleConfigIf); } else { DbgTrace(0, "auth_token -GetAuthTokenInterface- Unable to obtain config interface\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_CONFIGURATION_ERROR); } DbgTrace(2, "auth_token -GetAuthTokenInterface- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= CasaStatus SSCS_CALL GetAuthTokenCredentials( IN const char *pServiceName, INOUT const char *pUserNameBuf, INOUT int *pUserNameBufLen, INOUT const char *pTokenBuf, INOUT int *pTokenBufLen) // // Arguments: // pServiceName - // Pointer to NULL terminated string that contains the // name of the service to which the client is trying to // authenticate. // // pUserNameBuf - // Pointer to buffer that will receive a string with the // username that should used when authenticating to the // service. The length of this buffer is specified by the // pUserNameBufLen parameter. Note that the string // returned will be NULL terminated. // // pUserNameBufLen - // Pointer to integer that contains the length of the // buffer pointed at by pUserNameBuf. Upon return of the // function, the integer will contain the actual length // of the username string (including the NULL terminator) // if the function successfully completes or the buffer // length required if the function fails because the buffer // pointed at by either pUserNameBuf or pTokenBuf is not // large enough. // // pTokenBuf - // Pointer to buffer that will receive the authentication // token. The length of this buffer is specified by the // pTokenBufLen parameter. Note that the the authentication // token will be in the form of a NULL terminated string. // // pTokenBufLen - // Pointer to integer that contains the length of the // buffer pointed at by pTokenBuf. Upon return of the // function, the integer will contain the actual length // of the authentication token if the function successfully // completes or the buffer length required if the function // fails because the buffer pointed at by either pUserNameBuf // or pTokenBuf is not large enough. // // Returns: // Casa Status // // Description: // Get authentication token credentials to authenticate user to specified // service. // // L2 //=======================================================================-- { CasaStatus retStatus; ConfigIf *pServiceConfigIf; AuthTokenIf *pAuthTokenIf; DbgTrace(1, "auth_token -GetAuthTokenCredentials- Start\n", 0); // Validate input parameters if (pServiceName == NULL || pUserNameBufLen == NULL || (pUserNameBuf == NULL && *pUserNameBufLen != 0) || pTokenBufLen == NULL || (pTokenBuf == NULL && *pTokenBufLen != 0)) { DbgTrace(0, "auth_token -GetAuthTokenCredentials- Invalid input parameter\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INVALID_PARAMETER); goto exit; } // Check if we have a configuration entry for the service retStatus = GetConfigInterface("/etc/opt/novell/CASA/authtoken.d/services.d", pServiceName, &pServiceConfigIf); if (CASA_SUCCESS(retStatus) && CasaStatusCode(retStatus) != CASA_STATUS_OBJECT_NOT_FOUND) { char *pAuthType; // Obtain the configured authentication type for the service pAuthType = pServiceConfigIf->getEntryValue(pServiceConfigIf, "AuthType"); if (pAuthType) { // Obtain the appropriate token interface for the authentication type retStatus = GetAuthTokenInterface(pAuthType, &pAuthTokenIf); if (CASA_SUCCESS(retStatus)) { // We found a provider for the service, query it for credentials. retStatus = pAuthTokenIf->getAuthTokenCredentials(pAuthTokenIf, pServiceConfigIf, pUserNameBuf, pUserNameBufLen, pTokenBuf, pTokenBufLen); // Release token interface pAuthTokenIf->releaseReference(pAuthTokenIf); } else { // No authentication token interface available for authentication type DbgTrace(0, "auth_token -GetAuthTokenCredentials- Failed to obtain authentication token interface\n", 0); } // Free the buffer holding the authentication type string free(pAuthType); } else { DbgTrace(0, "auth_token -GetAuthTokenCredentials- Authentication type not configured\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_CONFIGURATION_ERROR); } // Release service config interface pServiceConfigIf->releaseReference(pServiceConfigIf); } else { // We are not providing authentication services for the service DbgTrace(1, "auth_token -GetAuthTokenCredentials- Service not configured\n", 0); } exit: DbgTrace(1, "auth_token -GetAuthTokenCredentials- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= CasaStatus SSCS_CALL ValidateAuthTokenCredentials( IN const char *pServiceName, IN const char *pUserName, IN const int userNameLen, IN const char *pTokenBuf, IN const int tokenBufLen) // // Arguments: // pServiceName - // Pointer to NULL terminated string that contains the // name of the service to which the client is trying to // authenticate. // // pUserName - // Pointer to string with the username that is being // authenticated to the service. The length of the name // is specified by the pUserNameLen parameter. Note that // the string does not need to be NULL terminated. // // userNameLen - // Length of the user name contained within the buffer // pointed at by pUserNameBuf (Does not include the NULL // terminator). If this parameter is set to -1 then the // function assumes that the username string is NULL // terminated. // // pTokenBuf - // Pointer to buffer that will receive the authentication // token. The length of this buffer is specified by the // pTokenBufLen parameter. Note that the the authentication // token will be in the form of a NULL terminated string. // // tokenBufLen - // Length of the data contained within the buffer pointed // at by pTokenBuf. // // Returns: // Casa status. // // Description: // Validates authentication token credentials. // // L2 //=======================================================================-- { CasaStatus retStatus; ConfigIf *pServiceConfigIf; AuthTokenIf *pAuthTokenIf; DbgTrace(1, "auth_token -ValidateAuthTokenCredentials- Start\n", 0); // Validate input parameters if (pServiceName == NULL || pUserName == NULL || userNameLen == 0 || pTokenBuf == NULL || tokenBufLen == 0) { DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Invalid input parameter\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INVALID_PARAMETER); goto exit; } // Check if we have a configuration entry for the service retStatus = GetConfigInterface("/etc/opt/novell/CASA/authtoken.d/services.d", pServiceName, &pServiceConfigIf); if (CASA_SUCCESS(retStatus)) { // Check if the configuration entry was not found if (CasaStatusCode(retStatus) != CASA_STATUS_OBJECT_NOT_FOUND) { char *pAuthType; // Obtain the configured authentication type for the service pAuthType = pServiceConfigIf->getEntryValue(pServiceConfigIf, "AuthType"); if (pAuthType) { // Obtain the appropriate token interface for the authentication type retStatus = GetAuthTokenInterface(pAuthType, &pAuthTokenIf); if (CASA_SUCCESS(retStatus)) { // We found a provider for the service, validate the credentials. retStatus = pAuthTokenIf->validateAuthTokenCredentials(pAuthTokenIf, pServiceConfigIf, pUserName, userNameLen, pTokenBuf, tokenBufLen); // Release token interface pAuthTokenIf->releaseReference(pAuthTokenIf); } else { // No authentication token interface available for authentication type DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Failed to obtain authentication token interface\n", 0); } // Free the buffer holding the authentication type string free(pAuthType); } else { DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Authentication type not configured\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_CONFIGURATION_ERROR); } // Release service config interface pServiceConfigIf->releaseReference(pServiceConfigIf); } else { // We need to return an error DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Service not configured\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_CONFIGURATION_ERROR); } } else { DbgTrace(0, "auth_token -ValidateAuthTokenCredentials- Error obtaining service configuration\n", 0); } exit: DbgTrace(1, "auth_token -ValidateAuthTokenCredentials- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= //++======================================================================= //++=======================================================================