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