/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
*/
/*
* // Copyright (C) 2002 Microsoft Corporation
* // All rights reserved.
* //
* // THIS CODE AND INFORMATION IS PROVIDED "AS IS"
* // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
* // OR IMPLIED, INCLUDING BUT NOT LIMITED
* // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
* // AND/OR FITNESS FOR A PARTICULAR PURPOSE.
* //
* // Date - 10/08/2002
* // Author - Sanj Surati
*/
/*
* SPNEGO Token Handler Source File
*
* Contains implementation of SPNEGO Token Handling API.
*/
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <smb/spnego.h>
#include "smbfs_derparse.h"
#include "smbfs_spnegoparse.h"
/* Defined in DERPARSE.C */
extern MECH_OID g_stcMechOIDList [];
/* SPNEGO Token Handler API implementation */
/*
*
* Function:
* smbfs_spnegoInitFromBinary
*
* Parameters:
* [in] pbTokenData - Binary Token Data
* [in] ulLength - Length of binary Token Data
* [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
*
* Returns:
* int Success - SPNEGO_E_SUCCESS
* Failure - SPNEGO API Error code
*
* Comments :
* Initializes a SPNEGO_TOKEN_HANDLE from the supplied
* binary data. Data is copied locally. Returned data structure
* must be freed by calling smbfs_spnegoFreeData().
*
*/
int
smbfs_spnegoInitFromBinary(unsigned char *pbTokenData, unsigned long ulLength,
SPNEGO_TOKEN_HANDLE *phSpnegoToken)
{
int nReturn = SPNEGO_E_INVALID_PARAMETER;
SPNEGO_TOKEN **ppSpnegoToken = (SPNEGO_TOKEN **)phSpnegoToken;
/*
* Pass off to a handler function that allows tighter control over how
* the token structure is handled. In this case, we want the token data
* copied and we want the associated buffer freed.
*/
nReturn = smbfs_InitTokenFromBinary(SPNEGO_TOKEN_INTERNAL_COPYDATA,
SPNEGO_TOKEN_INTERNAL_FLAG_FREEDATA, pbTokenData,
ulLength, ppSpnegoToken);
return (nReturn);
}
/*
*
* Function:
* smbfs_spnegoCreateNegTokenInit
*
* Parameters:
* [in] MechType - MechType to specify in MechTypeList element
* [in] ucContextFlags - Context Flags element value
* [in] pbMechToken - Pointer to binary MechToken Data
* [in] ulMechTokenLen - Length of MechToken Data
* [in] pbMechListMIC - Pointer to binary MechListMIC Data
* [in] ulMechListMICLen - Length of MechListMIC Data
* [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
*
* Returns:
* int Success - SPNEGO_E_SUCCESS
* Failure - SPNEGO API Error code
*
* Comments :
* Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type
* from the supplied parameters. ucContextFlags may be 0 or must be
* a valid flag combination. MechToken data can be NULL - if not, it
* must correspond to the MechType. MechListMIC can also be NULL.
* Returned data structure must be freed by calling smbfs_spnegoFreeData().
*
*/
int
smbfs_spnegoCreateNegTokenInit(SPNEGO_MECH_OID MechType,
unsigned char ucContextFlags, unsigned char *pbMechToken,
unsigned long ulMechTokenLen, unsigned char *pbMechListMIC,
unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE *phSpnegoToken)
{
int nReturn = SPNEGO_E_INVALID_PARAMETER;
long nTokenLength = 0L;
long nInternalTokenLength = 0L;
unsigned char *pbTokenData = NULL;
SPNEGO_TOKEN **ppSpnegoToken = (SPNEGO_TOKEN **)phSpnegoToken;
if (NULL != ppSpnegoToken && smbfs_IsValidMechOid(MechType) &&
smbfs_IsValidContextFlags(ucContextFlags)) {
/* Get the actual token size */
nReturn = smbfs_CalculateMinSpnegoInitTokenSize(ulMechTokenLen,
ulMechListMICLen, MechType, (ucContextFlags != 0L),
&nTokenLength, &nInternalTokenLength);
if (nReturn == SPNEGO_E_SUCCESS) {
/* Allocate a buffer to hold the data. */
pbTokenData = calloc(1, nTokenLength);
if (NULL != pbTokenData) {
/* Now write the token */
nReturn = smbfs_CreateSpnegoInitToken(MechType,
ucContextFlags, pbMechToken, ulMechTokenLen,
pbMechListMIC, ulMechListMICLen,
pbTokenData, nTokenLength,
nInternalTokenLength);
if (nReturn == SPNEGO_E_SUCCESS) {
/*
* This will copy our allocated pointer,
* and ensure that the sructure cleans
* up the data later
*/
nReturn = smbfs_InitTokenFromBinary(\
SPNEGO_TOKEN_INTERNAL_COPYPTR,
SPNEGO_TOKEN_INTERNAL_FLAG_FREEDATA,
pbTokenData, nTokenLength,
ppSpnegoToken);
}
/* Cleanup on failure */
if (SPNEGO_E_SUCCESS != nReturn)
free(pbTokenData);
} else {
nReturn = SPNEGO_E_OUT_OF_MEMORY;
}
} /* If calculated token size */
} /* IF Valid Parameters */
return (nReturn);
}
/*
*
* Function:
* smbfs_spnegoCreateNegTokenTarg
*
* Parameters:
* [in] MechType - MechType to specify in supported MechType elem
* [in] spnegoNegResult - NegResult value
* [in] pbMechToken - Pointer to response MechToken Data
* [in] ulMechTokenLen - Length of MechToken Data
* [in] pbMechListMIC - Pointer to binary MechListMIC Data
* [in] ulMechListMICLen - Length of MechListMIC Data
* [out] phSpnegoToken - SPNEGO_TOKEN_HANDLE pointer
*
* Returns:
* int Success - SPNEGO_E_SUCCESS
* Failure - SPNEGO API Error code
*
* Comments :
* Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type
* from the supplied parameters. MechToken data can be NULL - if not,
* it must correspond to the MechType. MechListMIC can also be NULL.
* Returned data structure must be freed by calling smbfs_spnegoFreeData().
*
*/
int
smbfs_spnegoCreateNegTokenTarg(SPNEGO_MECH_OID MechType,
SPNEGO_NEGRESULT spnegoNegResult, unsigned char *pbMechToken,
unsigned long ulMechTokenLen, unsigned char *pbMechListMIC,
unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE *phSpnegoToken)
{
int nReturn = SPNEGO_E_INVALID_PARAMETER;
long nTokenLength = 0L;
long nInternalTokenLength = 0L;
unsigned char *pbTokenData = NULL;
SPNEGO_TOKEN **ppSpnegoToken = (SPNEGO_TOKEN **)phSpnegoToken;
/*
* spnego_mech_oid_NotUsed and spnego_negresult_NotUsed
* are okay here.
*/
if (NULL != ppSpnegoToken && \
(smbfs_IsValidMechOid(MechType) || \
spnego_mech_oid_NotUsed == MechType) && \
(smbfs_IsValidNegResult(spnegoNegResult) || \
spnego_negresult_NotUsed == spnegoNegResult)) {
/* Get the actual token size */
nReturn = smbfs_CalculateMinSpnegoTargTokenSize(MechType,
spnegoNegResult, ulMechTokenLen, ulMechListMICLen,
&nTokenLength, &nInternalTokenLength);
if (nReturn == SPNEGO_E_SUCCESS) {
/* Allocate a buffer to hold the data. */
pbTokenData = calloc(1, nTokenLength);
if (NULL != pbTokenData) {
/* Now write the token */
nReturn = smbfs_CreateSpnegoTargToken(MechType,
spnegoNegResult, pbMechToken,
ulMechTokenLen, pbMechListMIC,
ulMechListMICLen, pbTokenData,
nTokenLength, nInternalTokenLength);
if (nReturn == SPNEGO_E_SUCCESS) {
/*
* This will copy our allocated pointer,
* and ensure that the sructure cleans
* up the data later.
*/
nReturn = smbfs_InitTokenFromBinary(\
SPNEGO_TOKEN_INTERNAL_COPYPTR,
SPNEGO_TOKEN_INTERNAL_FLAG_FREEDATA,
pbTokenData, nTokenLength,
ppSpnegoToken);
}
/* Cleanup on failure */
if (SPNEGO_E_SUCCESS != nReturn)
free(pbTokenData);
} else {
nReturn = SPNEGO_E_OUT_OF_MEMORY;
}
} /* If calculated token size */
} /* IF Valid Parameters */
return (nReturn);
}
/*
*
* Function:
* smbfs_spnegoTokenGetBinary
*
* Parameters:
* [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
* [out] pbTokenData - Buffer to copy token into
* [in/out] pulDataLen - Length of pbTokenData buffer, filled out
* with actual size used upon function return.
*
* Returns:
* int Success - SPNEGO_E_SUCCESS
* Failure - SPNEGO API Error code
*
* Comments :
* Copies binary SPNEGO token data from hSpnegoToken into the user
* supplied buffer. If pbTokenData is NULL, or the value in pulDataLen
* is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and
* fill out pulDataLen with the minimum required buffer size.
*
*/
int
smbfs_spnegoTokenGetBinary(SPNEGO_TOKEN_HANDLE hSpnegoToken,
unsigned char *pbTokenData, unsigned long *pulDataLen)
{
int nReturn = SPNEGO_E_INVALID_PARAMETER;
SPNEGO_TOKEN *pSpnegoToken = (SPNEGO_TOKEN *)hSpnegoToken;
/* Check parameters - pbTokenData is optional */
if (smbfs_IsValidSpnegoToken(pSpnegoToken) && NULL != pulDataLen) {
/* Check for Buffer too small conditions */
if (NULL == pbTokenData ||
pSpnegoToken->ulBinaryDataLen > *pulDataLen) {
*pulDataLen = pSpnegoToken->ulBinaryDataLen;
nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
} else {
(void) memcpy(pbTokenData, pSpnegoToken->pbBinaryData,
pSpnegoToken->ulBinaryDataLen);
*pulDataLen = pSpnegoToken->ulBinaryDataLen;
nReturn = SPNEGO_E_SUCCESS;
}
} /* IF parameters OK */
return (nReturn);
}
/*
*
* Function:
* smbfs_spnegoFreeData
*
* Parameters:
* [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
*
* Returns:
* void
*
* Comments :
* Frees up resources consumed by hSpnegoToken. The supplied data
* pointer is invalidated by this function.
*
*/
void
smbfs_spnegoFreeData(SPNEGO_TOKEN_HANDLE hSpnegoToken)
{
smbfs_FreeSpnegoToken((SPNEGO_TOKEN *)hSpnegoToken);
}
/*
*
* Function:
* smbfs_spnegoIsMechTypeAvailable
*
* Parameters:
* [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
* [in] MechOID - MechOID to search MechTypeList for
* [out] piMechTypeIndex - Filled out with index in MechTypeList
* element if MechOID is found.
*
* Returns:
* int Success - SPNEGO_E_SUCCESS
* Failure - SPNEGO API Error code
*
* Comments :
* hSpnegoToken must reference a token of type NegTokenInit. The
* function will search the MechTypeList element for an OID corresponding
* to the specified MechOID. If one is found, the index (0 based) will
* be passed into the piMechTypeIndex parameter.
*
*
* Returns the Initial Mech Type in the MechList element in the NegInitToken.
*/
int
smbfs_spnegoIsMechTypeAvailable(SPNEGO_TOKEN_HANDLE hSpnegoToken,
SPNEGO_MECH_OID MechOID, int *piMechTypeIndex)
{
int nReturn = SPNEGO_E_INVALID_PARAMETER;
SPNEGO_TOKEN *pSpnegoToken = (SPNEGO_TOKEN *)hSpnegoToken;
/* Check parameters */
if (smbfs_IsValidSpnegoToken(pSpnegoToken) && NULL != piMechTypeIndex &&
smbfs_IsValidMechOid(MechOID) &&
SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) {
/* Check if MechList is available */
if (pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].\
iElementPresent == SPNEGO_TOKEN_ELEMENT_AVAILABLE) {
/* Locate the MechOID in the list element */
nReturn = smbfs_FindMechOIDInMechList(
&pSpnegoToken->aElementArray\
[SPNEGO_INIT_MECHTYPES_ELEMENT],
MechOID, piMechTypeIndex);
} else {
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
}
} /* IF parameters OK */
return (nReturn);
}
/*
*
* Function:
* smbfs_spnegoGetNegotiationResult
*
* Parameters:
* [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
* [out] pnegResult - Filled out with NegResult value.
*
* Returns:
* int Success - SPNEGO_E_SUCCESS
* Failure - SPNEGO API Error code
*
* Comments :
* hSpnegoToken must reference a token of type NegTokenTarg. The
* function will copy data from the NegResult element into the
* location pointed to by pnegResult. Note that the function will
* fail if the actual NegResult data appears invalid.
*
*/
int
smbfs_spnegoGetNegotiationResult(SPNEGO_TOKEN_HANDLE hSpnegoToken,
SPNEGO_NEGRESULT *pnegResult)
{
int nReturn = SPNEGO_E_INVALID_PARAMETER;
SPNEGO_TOKEN *pSpnegoToken = (SPNEGO_TOKEN *)hSpnegoToken;
/* Check parameters */
if (smbfs_IsValidSpnegoToken(pSpnegoToken) && NULL != pnegResult &&
SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType) {
/* Check if NegResult is available */
if (pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].\
iElementPresent == SPNEGO_TOKEN_ELEMENT_AVAILABLE) {
/* Must be 1 byte long and a valid value */
if (pSpnegoToken->aElementArray\
[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == \
SPNEGO_NEGTARG_MAXLEN_NEGRESULT && \
smbfs_IsValidNegResult(*pSpnegoToken->aElementArray\
[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData)) {
*pnegResult = \
*pSpnegoToken->aElementArray\
[SPNEGO_TARG_NEGRESULT_ELEMENT].\
pbData;
nReturn = SPNEGO_E_SUCCESS;
} else {
nReturn = SPNEGO_E_INVALID_ELEMENT;
}
} else {
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
}
} /* IF parameters OK */
return (nReturn);
}
/*
*
* Function:
* smbfs_spnegoGetMechToken
*
* Parameters:
* [in] hSpnegoToken - Initialized SPNEGO_TOKEN_HANDLE
* [out] pbTokenData - Buffer to copy MechToken into
* [in/out] pulDataLen - Length of pbTokenData buffer, filled out
* with actual size used upon function return.
*
* Returns:
* int Success - SPNEGO_E_SUCCESS
* Failure - SPNEGO API Error code
*
* Comments :
* hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
* The function will copy the MechToken (the initial MechToken if
* NegTokenInit, the response MechToken if NegTokenTarg) from the
* underlying token into the buffer pointed to by pbTokenData. If
* pbTokenData is NULL, or the value in pulDataLen is too small, the
* function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen
* with the minimum required buffer size. The token can then be passed
* to a GSS-API function for processing.
*
*/
int
smbfs_spnegoGetMechToken(SPNEGO_TOKEN_HANDLE hSpnegoToken,
unsigned char *pbTokenData, unsigned long *pulDataLen)
{
int nReturn = SPNEGO_E_INVALID_PARAMETER;
SPNEGO_TOKEN *pSpnegoToken = (SPNEGO_TOKEN *)hSpnegoToken;
SPNEGO_ELEMENT *pSpnegoElement = NULL;
/* Check parameters */
if (smbfs_IsValidSpnegoToken(pSpnegoToken) && NULL != pulDataLen) {
/* Point at the proper Element */
if (SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType) {
pSpnegoElement = &pSpnegoToken->aElementArray\
[SPNEGO_INIT_MECHTOKEN_ELEMENT];
} else {
pSpnegoElement = &pSpnegoToken->aElementArray\
[SPNEGO_TARG_RESPTOKEN_ELEMENT];
}
/* Check if MechType is available */
if (SPNEGO_TOKEN_ELEMENT_AVAILABLE == \
pSpnegoElement->iElementPresent) {
/* Check for Buffer too small conditions */
if (NULL == pbTokenData || \
pSpnegoElement->nDatalength > *pulDataLen) {
*pulDataLen = pSpnegoElement->nDatalength;
nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
} else {
/* Copy Memory */
(void) memcpy(pbTokenData,
pSpnegoElement->pbData,
pSpnegoElement->nDatalength);
*pulDataLen = pSpnegoElement->nDatalength;
nReturn = SPNEGO_E_SUCCESS;
}
} else {
nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
}
} /* IF parameters OK */
return (nReturn);
}