/*********************************************************************** * * 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 ]================================================== //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== //++======================================================================= CasaStatus SSCS_CALL AuthTokenIf_GetAuthToken( IN const void *pIfInstance, IN const char *pContext, IN const char *pMechInfo, IN const char *pHostName, IN void *pCredStoreScope, INOUT char *pTokenBuf, INOUT uint32_t *pTokenBufLen) // // Arguments: // pIfInstance - // Pointer to interface object. // // pContext - // Pointer to null terminated string containing mechanism specific // context information. Another name for context is Authentication // Realm. // // pMechInfo - // Pointer to null terminated string containing mechanism specific // information. This is information is provided by the server to // aid the mechanism to generate an authentication token. For // example, the mechanism information for a Kerberos mechanism // may be the service principal name to which the user will be // authenticating. // // pHostName - // Pointer to null terminated string containing the name of the // host where the ATS resides. // // pCredStoreScope - // Pointer to CASA structure for scoping credential store access // to specific users. This can only be leveraged when running in // the context of System under Windows. // // 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 pUserNameBuf is // not large enough. // // Returns: // Casa Status // // Description: // Get authentication token to authenticate user to specified service. // // L2 //=======================================================================-- { CasaStatus retStatus; char *pKrbServiceName = NULL; SECURITY_STATUS secStatus; TimeStamp expiry; CredHandle hCredentials = {0}; DbgTrace(1, "-AuthTokenIf_GetAuthToken- Start\n", 0); // Validate input parameters if (pIfInstance == NULL || pContext == NULL || pHostName == NULL || pTokenBufLen == NULL || (pTokenBuf == NULL && *pTokenBufLen != 0)) { DbgTrace(0, "-AuthTokenIf_GetAuthToken- Invalid input parameter\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_INVALID_PARAMETER); goto exit; } // Process any mechanism information that may have been provided if (pMechInfo) { // Mechanism information has been provided. Mechanism information // consists of semicolon delimited settings. The settings are formated // using the format settingName=settingvalue. No white space is allowed // as part of the mechanism information. char *pNextSettingToken; char *pSettingValueToken = strtok_s(pMechInfo, ";", &pNextSettingToken); while (pSettingValueToken != NULL) { char *pNextToken; char *pSettingName = strtok_s(pSettingValueToken, "=", &pNextToken); char *pSettingValue = strtok_s(NULL, "=", &pNextToken); if (pSettingValue) { // Process the setting if (strcmpi(pSettingName, "SVC_PRINCIPAL") == 0) { pKrbServiceName = pSettingValue; } } else { printf("Bad setting\n"); } pSettingValueToken = strtok_s(NULL, ";", &pNextSettingToken); } } // Check if we need to construct the service name if (pKrbServiceName == NULL || strlen(pKrbServiceName) == 0) { // The service name will default to host/hostname pKrbServiceName = malloc(5 /*"host/"*/ + strlen(pHostName) + 1 /*'/0'*/); if (pKrbServiceName) { sprintf(pKrbServiceName, "host/%s", pHostName); } else { DbgTrace(0, "-AuthTokenIf_GetAuthToken- Memory allocation failure\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_INSUFFICIENT_RESOURCES); goto exit; } } // Acquire a credential handle for the current user secStatus = AcquireCredentialsHandle(NULL, // no principal name "Kerberos", // package name SECPKG_CRED_OUTBOUND, NULL, // no logon id NULL, // no auth data NULL, // no get key fn NULL, // noget key arg &hCredentials, &expiry); if (secStatus == SEC_E_OK) { CtxtHandle hContext = {0}; SecBuffer sendTok; SecBufferDesc outputDesc; ULONG retFlags; // We acquired the credential, now initialize a security context // so that we can authenticate the user to the specified service. // // First ready an output descriptor so that we can receive the // token buffer. outputDesc.cBuffers = 1; outputDesc.pBuffers = &sendTok; outputDesc.ulVersion = SECBUFFER_VERSION; sendTok.BufferType = SECBUFFER_TOKEN; sendTok.cbBuffer = 0; sendTok.pvBuffer = NULL; // Initialize the security context for the specified service secStatus = InitializeSecurityContext(&hCredentials, NULL, pKrbServiceName, ISC_REQ_ALLOCATE_MEMORY, 0, // reserved SECURITY_NATIVE_DREP, NULL, 0, // reserved &hContext, &outputDesc, &retFlags, &expiry); if (secStatus == SEC_E_OK) { // Make sure that the token is not too large if (sendTok.cbBuffer <= UINT32_MAX) { uint32_t encodedTokenLen; char *pEncodedToken; // The security context was initialized, now return it to the caller after base64 encoding it. retStatus = EncodeData(sendTok.pvBuffer, (const uint32_t) sendTok.cbBuffer, &pEncodedToken, &encodedTokenLen); if (CASA_SUCCESS(retStatus)) { // Verify that the caller provided a buffer that is big enough if (encodedTokenLen > *pTokenBufLen) { // The buffer is not big enough retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_BUFFER_OVERFLOW); } else { // The buffer provided is large enough, copy the data. memcpy((void*) pTokenBuf, pEncodedToken, encodedTokenLen); // Success retStatus = CASA_STATUS_SUCCESS; } // Return the actual size or the size required *pTokenBufLen = encodedTokenLen; // Free the buffer containing the encoded token after clearing // its memory to avoid leaking sensitive information. memset(pEncodedToken, 0, strlen(pEncodedToken)); free(pEncodedToken); } else { DbgTrace(1, "-AuthTokenIf_GetAuthToken- Encoding failed\n", 0); } } else { DbgTrace(0, "-AuthTokenIf_GetAuthToken- GSS Token too large\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_UNSUCCESSFUL); } // Delete the security context DeleteSecurityContext(&hContext); } else { DbgTrace(0, "-AuthTokenIf_GetAuthToken- Failed to initialize the security context, error = %08X\n", secStatus); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_UNSUCCESSFUL); } // Free any buffer associated with the sendToken if (sendTok.pvBuffer) { memset(sendTok.pvBuffer, 0, sendTok.cbBuffer); FreeContextBuffer(sendTok.pvBuffer); } // Free the credential handle obtained FreeCredentialsHandle(&hCredentials); } else { DbgTrace(1, "-AuthTokenIf_GetAuthToken- Failed to obtain the credentials handle, error = %08X\n", secStatus); // Set retStatus based on secStatus if (secStatus == SEC_E_NOT_OWNER || secStatus == SEC_E_NO_CREDENTIALS) { retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_NO_CREDENTIALS); } else { retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_UNSUCCESSFUL); } } exit: // Free buffer holding the Krb Service Name if necessary if (pKrbServiceName && pKrbServiceName != pMechInfo) free(pKrbServiceName); DbgTrace(1, "-AuthTokenIf_GetAuthToken- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= int InitializeLibrary(void) // // Arguments: // // Returns: // // Abstract: // // Notes: // // L2 //=======================================================================-- { int retStatus = 0; DbgTrace(1, "-InitializeLibrary- Start\n", 0); // Nothing to do at this time. DbgTrace(1, "-InitializeLibrary- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= //++======================================================================= //++=======================================================================