/*********************************************************************** * * 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 ]================================================== #define DEFAULT_RETRY_LIFETIME 5 // seconds //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== // // Debug tracing level // int DebugLevel = 0; // // Operating parameter // bool secureRpcSetting = false; int retryLifetime = DEFAULT_RETRY_LIFETIME; //++======================================================================= static CasaStatus ObtainSessionToken( IN RpcSession *pRpcSession, IN char *pHostName, IN AuthPolicy *pAuthPolicy, INOUT char **ppSessionToken) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L0 //=======================================================================-- { CasaStatus retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); LIST_ENTRY *pListEntry; AuthCacheEntry *pCacheEntry = NULL; DbgTrace(1, "-ObtainSessionToken- Start\n", 0); // Initialize output parameter *ppSessionToken = NULL; // Look in our cache for an entry that matches one of the auth // contexts specified in the AuthPolicy object. pListEntry = pAuthPolicy->authContextListHead.Flink; while (pListEntry != &pAuthPolicy->authContextListHead) { AuthContext *pAuthContext; // Get pointer to AuthContext structure pAuthContext = CONTAINING_RECORD(pListEntry, AuthContext, listEntry); // Try to find a cache entry for the auth context pCacheEntry = FindEntryInAuthCache(pAuthContext->pContext, pHostName); if (pCacheEntry != NULL) { // Cache entry found, update the return status with the information // saved in it and stop looking. retStatus = pCacheEntry->status; break; } // Advance to the next entry pListEntry = pListEntry->Flink; } // If we did not find a cache entry that we can use, then Try to create one. pListEntry = pAuthPolicy->authContextListHead.Flink; while (!CASA_SUCCESS(retStatus) && pListEntry != &pAuthPolicy->authContextListHead) { AuthContext *pAuthContext; char *pAuthMechToken; // Get pointer to AuthContext structure pAuthContext = CONTAINING_RECORD(pListEntry, AuthContext, listEntry); // Get authentication mechanism token retStatus = GetAuthMechToken(pAuthContext, &pAuthMechToken); if (!CASA_SUCCESS(retStatus)) { // We were not able to obtain an authentication mechanism token // for the context. // // Advance to the next entry pListEntry = pListEntry->Flink; continue; } // Create a cache entry for the auth context pCacheEntry = CreateAuthCacheEntry(pAuthContext->pContext, pHostName); if (pCacheEntry) { char *pReqMsg = NULL; char *pRespMsg = NULL; int respLen; int cacheEntryLifetime = retryLifetime; // Initialize to retry in case of failure // Request auth token for the service pReqMsg = BuildAuthenticateMsg(pAuthContext, pAuthMechToken); if (pReqMsg) { // Issue rpc retStatus = Rpc(pRpcSession, pAuthContext->pMechanism, secureRpcSetting, pReqMsg, &pRespMsg, &respLen); if (CASA_SUCCESS(retStatus)) { AuthenticateResp *pAuthenticateResp; // Create Authenticate response object retStatus = CreateAuthenticateResp(pRespMsg, respLen, &pAuthenticateResp); if (CASA_SUCCESS(retStatus)) { // Return the auth token to the caller pCacheEntry->pToken = pAuthenticateResp->pToken; pAuthenticateResp->pToken = NULL; // To keep us from freeing the buffer cacheEntryLifetime = pAuthenticateResp->tokenLifetime; // Free the Authenticate response object RelAuthenticateResp(pAuthenticateResp); } } else { DbgTrace(0, "-ObtainSessionToken- Authenticate Rpc failure, error = %08X\n", retStatus); } } else { DbgTrace(0, "-ObtainSessionToken- Error building Authenticate msg\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } // Add the entry to the cache if successful or if the reason that we failed // was because the server was unavailable. if (CASA_SUCCESS(retStatus) || CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE) { pCacheEntry->status = retStatus; AddEntryToAuthCache(pCacheEntry, cacheEntryLifetime); } else { // Free the entry FreeAuthCacheEntry(pCacheEntry); } } else { DbgTrace(0, "-ObtainSessionToken- Cache entry creation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); // Stop trying after freeing up the buffer associated with // the authentication mechanism token. free(pAuthMechToken); break; } // Free up the buffer associated with the authentication mechanism token free(pAuthMechToken); // Advance to the next entry pListEntry = pListEntry->Flink; } // Return session token if successful if (CASA_SUCCESS(retStatus)) { // Allocate a buffer for the return token *ppSessionToken = (char*) malloc(strlen(pCacheEntry->pToken) + 1); if (*ppSessionToken) { // Copy the token onto the allocated buffer strcpy(*ppSessionToken, pCacheEntry->pToken); } else { DbgTrace(0, "-ObtainSessionToken- Buffer allocation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } DbgTrace(1, "-ObtainSessionToken- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= static CasaStatus ObtainAuthTokenFromServer( IN char *pServiceName, IN char *pHostName, INOUT char **ppAuthToken, INOUT int *pTokenLifetime) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L0 //=======================================================================-- { CasaStatus retStatus = CASA_STATUS_SUCCESS; RpcSession *pRpcSession; DbgTrace(1, "-ObtainAuthTokenFromServer- Start\n", 0); // Initialize output parameter *ppAuthToken = NULL; // Open Rpc Session to the auth service at the specified host pRpcSession = OpenRpcSession(pHostName); if (pRpcSession) { char *pReqMsg = NULL; char *pRespMsg = NULL; int respLen; AuthPolicy *pAuthPolicy = NULL; GetAuthPolicyResp *pGetAuthPolicyResp = NULL; GetAuthTokenResp *pGetAuthTokenResp = NULL; char *pSessionToken = NULL; // Request the auth parameters associated with this service pReqMsg = BuildGetAuthPolicyMsg(pServiceName, pHostName); if (pReqMsg) { // Issue rpc retStatus = Rpc(pRpcSession, "GetAuthPolicy", secureRpcSetting, pReqMsg, &pRespMsg, &respLen); if (CASA_SUCCESS(retStatus)) { // Create GetAuthPolicy response object retStatus = CreateGetAuthPolicyResp(pRespMsg, respLen, &pGetAuthPolicyResp); if (CASA_SUCCESS(retStatus)) { // Create the AuthPolicy object retStatus = CreateAuthPolicy(pGetAuthPolicyResp->pPolicy, pGetAuthPolicyResp->policyLen, &pAuthPolicy); if (CASA_SUCCESS(retStatus)) { // Now try to obtain a session token retStatus = ObtainSessionToken(pRpcSession, pHostName, pAuthPolicy, &pSessionToken); if (CASA_SUCCESS(retStatus)) { // Request auth token for the service free(pReqMsg); pReqMsg = BuildGetAuthTokenMsg(pServiceName, pHostName, pSessionToken); if (pReqMsg) { // Free the previous response msg buffer free(pRespMsg); pRespMsg = NULL; // Issue rpc retStatus = Rpc(pRpcSession, "GetAuthToken", secureRpcSetting, pReqMsg, &pRespMsg, &respLen); if (CASA_SUCCESS(retStatus)) { // Create GetAuthPolicy response object retStatus = CreateGetAuthTokenResp(pRespMsg, respLen, &pGetAuthTokenResp); if (CASA_SUCCESS(retStatus)) { // Return the auth token to the caller *ppAuthToken = pGetAuthTokenResp->pToken; pGetAuthTokenResp->pToken = NULL; // To keep us from freeing the buffer *pTokenLifetime = pGetAuthTokenResp->tokenLifetime; } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- GetAuthToken Rpc failure, error = %08X\n", retStatus); } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Error building GetAuthToken msg\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } else { DbgTrace(1, "-ObtainAuthTokenFromServer- Failed to obtain session token, error = %08X\n", retStatus); } } } } else { DbgTrace(0, "-ObtainAuthTokenFromServer- GetAuthPolicy Rpc failure, error = %08X\n", retStatus); } // Free resources that may be hanging around if (pReqMsg) free(pReqMsg); if (pRespMsg) free(pRespMsg); if (pSessionToken) free(pSessionToken); if (pGetAuthTokenResp) RelGetAuthTokenResp(pGetAuthTokenResp); if (pGetAuthPolicyResp) RelGetAuthPolicyResp(pGetAuthPolicyResp); if (pAuthPolicy) RelAuthPolicy(pAuthPolicy); } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Error building GetAuthPolicy msg\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } // Close the Rpc Session CloseRpcSession(pRpcSession); } else { DbgTrace(0, "-ObtainAuthTokenFromServer- Error opening Rpc session\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } DbgTrace(1, "-ObtainAuthTokenFromServer- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= CasaStatus SSCS_CALL ObtainAuthToken( IN const char *pServiceAtHostName, INOUT char *pAuthTokenBuf, INOUT int *pAuthTokenBufLen) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L0 //=======================================================================-- { CasaStatus retStatus = CASA_STATUS_SUCCESS; char *pParseString; DbgTrace(1, "-ObtainAuthToken- Start\n", 0); // Verify the input parameters if (pServiceAtHostName == NULL || pAuthTokenBufLen == NULL || (*pAuthTokenBufLen != 0 && pAuthTokenBuf == NULL)) { DbgTrace(0, "-ObtainAuthToken- Invalid parameter\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INVALID_PARAMETER); goto exit; } // Allocate space to copy the service name string pParseString = (char*) malloc(strlen(pServiceAtHostName) + 1); if (pParseString) { char *pServiceName, *pHostName; // Space allocated, now copy the string onto it // and parse it into its components. strcpy(pParseString, pServiceAtHostName); pServiceName = strtok(pParseString, "@"); pHostName = strtok(NULL, "@"); if (pHostName == NULL) { DbgTrace(0, "-ObtainAuthToken- Missing host name\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INVALID_PARAMETER); } else { AuthCacheEntry *pCacheEntry; char *pNormalizedHostName; // Normalize the host name pNormalizedHostName = NormalizeHostName(pHostName); if (pNormalizedHostName) { // Start user process synchronization LockUserMutex(); // Try to find a cache entry for the service pCacheEntry = FindEntryInAuthCache(pServiceName, pNormalizedHostName); if (pCacheEntry == NULL) { // No entry found in the cache, create one. pCacheEntry = CreateAuthCacheEntry(pServiceName, pNormalizedHostName); if (pCacheEntry) { int cacheEntryLifetime = retryLifetime; // Initialize to retry in case of failure // Cache entry created, now try to obtain auth token from the CASA Server retStatus = ObtainAuthTokenFromServer(pServiceName, pNormalizedHostName, &pCacheEntry->pToken, &cacheEntryLifetime); // Add the entry to the cache if successful or if the reason that we failed // was because the server was un-available. if (CASA_SUCCESS(retStatus) || CasaStatusCode(retStatus) == CASA_STATUS_AUTH_SERVER_UNAVAILABLE) { pCacheEntry->status = retStatus; AddEntryToAuthCache(pCacheEntry, cacheEntryLifetime); } else { // Free the entry FreeAuthCacheEntry(pCacheEntry); } } else { DbgTrace(0, "-ObtainAuthToken- Cache entry creation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); } } else { // Cache entry found, update the return status with the information saved in it. retStatus = pCacheEntry->status; } // Try to return auth token if we have one to return if (CASA_SUCCESS(retStatus)) { int tokenLen = (int) strlen(pCacheEntry->pToken) + 1; // We have an authentication token, try to return it to the caller. if (pAuthTokenBuf) { // Verify that the supplied buffer is big enough if (*pAuthTokenBufLen >= tokenLen) { // Return the auth token to the caller strcpy(pAuthTokenBuf, pCacheEntry->pToken); } else { DbgTrace(0, "-ObtainAuthToken- The supplied buffer is not large enough", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_BUFFER_OVERFLOW); } // Notify the caller about the token length *pAuthTokenBufLen = tokenLen; } else { // The caller just wants the length of buffer that is required to // obtain the token. *pAuthTokenBufLen = tokenLen; } } // Stop user process synchronization FreeUserMutex(); // Free the space allocated for the normalized host name free(pNormalizedHostName); } else { DbgTrace(0, "-ObtainAuthToken- Host name normalization failed\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_AUTHTOKEN, CASA_STATUS_UNSUCCESSFUL); } } // Free allocated space free(pParseString); } else { DbgTrace(0, "-ObtainAuthToken- Buffer allocation error\n", 0); } exit: DbgTrace(1, "-ObtainAuthToken- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= int InitializeLibrary(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L0 //=======================================================================-- { int retStatus = -1; DbgTrace(1, "-InitializeLibrary- Start\n", 0); // Create user synchronization mutex if (CreateUserMutex() == 0) { // Initialize the auth cache if (CASA_SUCCESS(InitializeAuthCache())) { // Initialize the host name normalization if (CASA_SUCCESS(InitializeHostNameNormalization())) { // Success retStatus = 0; } else { DbgTrace(0, "-InitializeLibrary- Error initializing host name normalization\n", 0); } } else { DbgTrace(0, "-InitializeLibrary- Error initializing the auth cache\n", 0); } } else { DbgTrace(0, "-InitializeLibrary- Error creating mutex for the user\n", 0); } DbgTrace(1, "-InitializeLibrary- End, retStatus = %08X\n", retStatus); return retStatus; }