2feba2710f
1. Enable privileged process ('system' owned) to access logged in user's Kerberos credential cache while authenticating to the ATS. The LUID of the logged in user is an input. This is required by Zenworks. 2. Fix a buffer overflow. A memory buffer was being used after being freed.
400 lines
14 KiB
C
400 lines
14 KiB
C
/***********************************************************************
|
|
*
|
|
* 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 <jluciani@novell.com>
|
|
*
|
|
***********************************************************************/
|
|
|
|
|
|
//===[ Include files ]=====================================================
|
|
|
|
#include "internal.h"
|
|
|
|
//===[ Type definitions ]==================================================
|
|
|
|
//===[ Function prototypes ]===============================================
|
|
|
|
//===[ Global variables ]==================================================
|
|
|
|
#define WINDOWS_LOGIN_ID 1
|
|
|
|
//++=======================================================================
|
|
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;
|
|
bool freeKrbSvcNameBuf = false;
|
|
SECURITY_STATUS secStatus;
|
|
TimeStamp expiry;
|
|
CredHandle hCredentials = {0};
|
|
LUID *pluid = NULL;
|
|
SSCS_EXT_T *ext = (SSCS_EXT_T *)pCredStoreScope;
|
|
|
|
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)
|
|
{
|
|
// Allocate a buffer to hold the mech info so that we can manipulate it
|
|
char *pMechInfoInt = malloc(strlen(pMechInfo) + 1);
|
|
if (pMechInfoInt)
|
|
{
|
|
char *pNextSettingToken;
|
|
char *pSettingValueToken;
|
|
|
|
// Copy the mechanism info to our work buffer
|
|
strcpy(pMechInfoInt, 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.
|
|
pSettingValueToken = strtok_r(pMechInfoInt, ";", &pNextSettingToken);
|
|
while (pSettingValueToken != NULL)
|
|
{
|
|
char *pNextToken;
|
|
char *pSettingName = strtok_r(pSettingValueToken, "=", &pNextToken);
|
|
char *pSettingValue = strtok_r(NULL, "=", &pNextToken);
|
|
if (pSettingValue)
|
|
{
|
|
// Process the setting
|
|
if (stricmp(pSettingName, "SVC_PRINCIPAL") == 0)
|
|
{
|
|
pKrbServiceName = strdup(pSettingValue);
|
|
if (pKrbServiceName == NULL)
|
|
{
|
|
DbgTrace(0, "-AuthTokenIf_GetAuthToken- Memory allocation failure\n", 0);
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_KRB5TOKEN,
|
|
CASA_STATUS_INSUFFICIENT_RESOURCES);
|
|
goto exit;
|
|
}
|
|
freeKrbSvcNameBuf = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-AuthTokenIf_GetAuthToken- Bad setting\n", 0);
|
|
}
|
|
|
|
pSettingValueToken = strtok_r(NULL, ";", &pNextSettingToken);
|
|
}
|
|
|
|
// Free the buffer that we allocated
|
|
free(pMechInfoInt);
|
|
}
|
|
else
|
|
{
|
|
DbgTrace(0, "-AuthTokenIf_GetAuthToken- Buffer allocation failure\n", 0);
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR,
|
|
CASA_FACILITY_PWTOKEN,
|
|
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)
|
|
{
|
|
freeKrbSvcNameBuf = true;
|
|
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;
|
|
}
|
|
}
|
|
if (ext != NULL) {
|
|
char err[128];
|
|
|
|
if ((ext->extID != WINDOWS_LOGIN_ID) || (ext->version != 1)) {
|
|
DbgTrace(0, "-AuthTokenIf_GetAuthToken- Unknown extension ID\n", 0);
|
|
retStatus = CasaStatusBuild(CASA_SEVERITY_ERROR, CASA_FACILITY_KRB5TOKEN, CASA_STATUS_INVALID_PARAMETER);
|
|
goto exit;
|
|
}
|
|
|
|
pluid = (LUID *)ext->ext;
|
|
sprintf(err, "-AuthTokenIf_GetAuthToken- Found luid %d.%d\n", pluid->LowPart, pluid->HighPart);
|
|
DbgTrace(1, err, 0);
|
|
}
|
|
// Acquire a credential handle for the current user
|
|
secStatus = AcquireCredentialsHandle(NULL, // no principal name
|
|
"Kerberos", // package name
|
|
SECPKG_CRED_OUTBOUND,
|
|
pluid,
|
|
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 (freeKrbSvcNameBuf)
|
|
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;
|
|
}
|
|
|
|
|
|
//++=======================================================================
|
|
//++=======================================================================
|
|
//++=======================================================================
|
|
|