/*********************************************************************** * * Copyright (C) 2005-2006 Novell, Inc. 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. * ***********************************************************************/ //===[ Include files ]===================================================== #include "internal.h" //===[ Type definitions ]================================================== //===[ Function prototypes ]=============================================== //===[ Global variables ]================================================== //++======================================================================= CasaStatus SSCS_CALL Krb5AuthTokenIf_GetAuthTokenCredentials( IN const void *pIfInstance, IN const ConfigIf *pServiceConfigIf, INOUT const char *pUserNameBuf, INOUT int *pUserNameBufLen, INOUT const char *pTokenBuf, INOUT int *pTokenBufLen) // // Arguments: // pIfInstance - // Pointer to interface object. // // pServiceConfigIf - // Pointer to service config object 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; OM_uint32 gssMajStat; OM_uint32 gssMinStat; char *pKrbServiceName; DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Start\n", 0); // Validate input parameters if (pIfInstance == NULL || pServiceConfigIf == NULL || pUserNameBufLen == NULL || (pUserNameBuf == NULL && *pUserNameBufLen != 0) || pTokenBufLen == NULL || (pTokenBuf == NULL && *pTokenBufLen != 0)) { DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Invalid input parameter\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_INVALID_PARAMETER); goto exit; } // Map service name to Krb Service Principal Name pKrbServiceName = pServiceConfigIf->getEntryValue(pServiceConfigIf, "KerberosPrincipal"); if (pKrbServiceName) { gss_buffer_desc gssBuffer; gss_name_t gssServiceName; // 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@hostname" 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) { // Now get the username gss_name_t gssClient; gssMajStat = gss_inquire_context(&gssMinStat, gssContext, &gssClient, NULL, NULL, NULL, NULL, NULL, NULL); if (gssMajStat == GSS_S_COMPLETE) { gss_buffer_desc gssDisplayName; gss_OID gssNameType; gssMajStat = gss_display_name(&gssMinStat, gssClient, &gssDisplayName, &gssNameType); if (gssMajStat == GSS_S_COMPLETE) { char *pEncodedToken; int encodedTokenLen; // Base64 encode the token retStatus = EncodeData(gssSendToken.value, gssSendToken.length, &pEncodedToken, &encodedTokenLen); if (CASA_SUCCESS(retStatus)) { // Verify that the caller provided buffers that are big enough if (gssDisplayName.length > *pUserNameBufLen || encodedTokenLen > *pTokenBufLen) { // At least one of the supplied buffers is not big enough DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Insufficient buffer space provided\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_BUFFER_OVERFLOW); } else { // The buffers provided are large enough, copy the data and return the actual sizes. memcpy((void*) pUserNameBuf, gssDisplayName.value, gssDisplayName.length + 1); memcpy((void*) pTokenBuf, pEncodedToken, encodedTokenLen +1); // Success retStatus = CASA_STATUS_SUCCESS; } // Return the actual sizes or the sizes required *pUserNameBufLen = gssDisplayName.length + 1; *pTokenBufLen = encodedTokenLen; // Free the buffer containing the encoded token free(pEncodedToken); } else { DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Encoding failed\n", 0); } // Release the buffer associated with the client display name gss_release_buffer(&gssMinStat, &gssDisplayName); } else { DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Error obtaining display name\n", 0); LogGssStatuses("obtaining display name", gssMajStat, gssMinStat); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_UNSUCCESSFUL); } } else { DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- Error inquiring context\n", 0); LogGssStatuses("inquiring context", gssMajStat, gssMinStat); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_UNSUCCESSFUL); } } else { DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- 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, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- 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); } // Free the krb service principal name free(pKrbServiceName); } else { DbgTrace(0, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- No Kerberos principal name configured\n", 0); retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_CONFIGURATION_ERROR); } exit: DbgTrace(1, "krb5_token -Krb5AuthTokenIf_GetAuthTokenCredentials- End, retStatus = %08X\n", retStatus); return retStatus; } //++======================================================================= //++======================================================================= //++=======================================================================