/*********************************************************************** * * 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 ]================================================== // Mechanism OID gss_OID g_mechOid = GSS_C_NULL_OID; //++======================================================================= void LogGssStatuses( IN char *operation, IN OM_uint32 majorGssStatus, IN OM_uint32 minorGssStatus) // // Arguments: // // Returns: // // Description: // // L2 //=======================================================================-- { OM_uint32 gssMajStat; OM_uint32 gssMinStat; gss_buffer_desc msg = GSS_C_EMPTY_BUFFER; OM_uint32 gssMsgCtx; // Trace the messages associated with the major status gssMsgCtx = 0; while (1) { gssMajStat = gss_display_status(&gssMinStat, majorGssStatus, GSS_C_GSS_CODE, g_mechOid, &gssMsgCtx, &msg); if (gssMajStat != GSS_S_COMPLETE) { DbgTrace(0, "-LogGssStatuses- Error obtaining display status\n", 0); break; } // Trace this message if (msg.value != NULL) { DbgTrace(0, "-LogGssStatuses- GSS-API error %s: ", operation); DbgTrace(0, "%s\n", (char *)msg.value); } if (msg.length != 0) gss_release_buffer(&gssMinStat, &msg); if (!gssMsgCtx) break; } // Trace the messages associated with the minor status gssMsgCtx = 0; while (1) { gssMajStat = gss_display_status(&gssMinStat, minorGssStatus, GSS_C_MECH_CODE, g_mechOid, &gssMsgCtx, &msg); if (gssMajStat != GSS_S_COMPLETE) { DbgTrace(0, "-LogGssStatuses- Error obtaining display status\n", 0); break; } // Trace this message if (msg.value != NULL) { DbgTrace(0, "-LogGssStatuses- GSS-API error %s: ", operation); DbgTrace(0, "%s\n", (char *)msg.value); } if (msg.length != 0) gss_release_buffer(&gssMinStat, &msg); if (!gssMsgCtx) break; } } //++======================================================================= 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. // // pServiceConfigIf - // Pointer to service config object to which the client is trying to // authenticate. // // 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 = (char*) pMechInfo; OM_uint32 gssMajStat; OM_uint32 gssMinStat; gss_buffer_desc gssBuffer; gss_name_t gssServiceName; 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; } // 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); goto exit; } } // Import the service principal name into something that // GSS-API can understand based on its form. gssBuffer.value = (void*) pKrbServiceName; gssBuffer.length = strlen(pKrbServiceName) + 1; if (strchr(pKrbServiceName, '@') != NULL) { // The name is of the form "servicename@realmname" gssMajStat = gss_import_name(&gssMinStat, &gssBuffer, (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, &gssServiceName); } else { // The name is of the form "servicename" gssMajStat = gss_import_name(&gssMinStat, &gssBuffer, (gss_OID) GSS_C_NT_USER_NAME, &gssServiceName); } // Proceed based on the result of the name import operation if (gssMajStat == GSS_S_COMPLETE) { // Establish a context gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT; gss_buffer_desc gssSendToken = {0}; OM_uint32 gssRetFlags; gssMajStat = gss_init_sec_context(&gssMinStat, GSS_C_NO_CREDENTIAL, &gssContext, gssServiceName, g_mechOid, 0, // Flags 0, NULL, // no channel bindings GSS_C_NO_BUFFER, // no token from peer NULL, // ignore mech type &gssSendToken, &gssRetFlags, NULL); // ignore time rec // Proceed based on the result of the gss_init_sec_context operation if (gssMajStat == GSS_S_COMPLETE && gssSendToken.length != 0) { // Make sure that the token is not too large if (gssSendToken.length <= UINT32_MAX) { char *pEncodedToken; uint32_t encodedTokenLen; // The security context was initialized, now return the token to the // caller after base64 encoding it. retStatus = EncodeData(gssSendToken.value, gssSendToken.length, &pEncodedToken, &encodedTokenLen); if (CASA_SUCCESS(retStatus)) { // Verify that the caller provided a buffer that is big enough if (encodedTokenLen > *pTokenBufLen) { // At least one of the supplied buffers is not big enough DbgTrace(1, "-AuthTokenIf_GetAuthToken- Insufficient buffer space provided\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_BUFFER_OVERFLOW); } else { // The buffer provided is large enough, copy the data and return the actual size. 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 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); } } else { DbgTrace(0, "-AuthTokenIf_GetAuthToken- Error initing sec context\n", 0); LogGssStatuses("initializing context", gssMajStat, gssMinStat); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_UNSUCCESSFUL); } // Release send token buffer if necessary if (gssSendToken.length != 0) gss_release_buffer(&gssMinStat, &gssSendToken); // Free context if necessary if (gssContext != GSS_C_NO_CONTEXT) gss_delete_sec_context(&gssMinStat, &gssContext, GSS_C_NO_BUFFER); // Release the buffer associated with the service name gss_release_name(&gssMinStat, &gssServiceName); } else { DbgTrace(0, "-AuthTokenIf_GetAuthToken- Error importing service name\n", 0); LogGssStatuses("importing service name", gssMajStat, gssMinStat); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_OBJECT_NOT_FOUND); } 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; } //++======================================================================= //++======================================================================= //++=======================================================================