xref: /illumos-gate/usr/src/lib/libsmbfs/smb/spnego.c (revision b1e2e3fb17324e9ddf43db264a0c64da7756d9e6)
1 // Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
2 // Copyright (C) 2002 Microsoft Corporation
3 // All rights reserved.
4 //
5 // THIS CODE AND INFORMATION IS PROVIDED "AS IS"
6 // WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
7 // OR IMPLIED, INCLUDING BUT NOT LIMITED
8 // TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
9 // AND/OR FITNESS FOR A PARTICULAR PURPOSE.
10 //
11 // Date    - 10/08/2002
12 // Author  - Sanj Surati
13 
14 /////////////////////////////////////////////////////////////
15 //
16 // SPNEGO.C
17 //
18 // SPNEGO Token Handler Source File
19 //
20 // Contains implementation of SPNEGO Token Handling API
21 // as defined in SPNEGO.H.
22 //
23 /////////////////////////////////////////////////////////////
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <memory.h>
29 #include "spnego.h"
30 #include "derparse.h"
31 #include "spnegoparse.h"
32 
33 //
34 // Defined in DERPARSE.C
35 //
36 
37 extern MECH_OID g_stcMechOIDList [];
38 
39 
40 /**********************************************************************/
41 /**                                                                  **/
42 /**                                                                  **/
43 /**                                                                  **/
44 /**                                                                  **/
45 /**               SPNEGO Token Handler API implementation            **/
46 /**                                                                  **/
47 /**                                                                  **/
48 /**                                                                  **/
49 /**                                                                  **/
50 /**********************************************************************/
51 
52 
53 /////////////////////////////////////////////////////////////////////////////
54 //
55 // Function:
56 //    spnegoInitFromBinary
57 //
58 // Parameters:
59 //    [in]  pbTokenData       -  Binary Token Data
60 //    [in]  ulLength          -  Length of binary Token Data
61 //    [out] phSpnegoToken     -  SPNEGO_TOKEN_HANDLE pointer
62 //
63 // Returns:
64 //    int   Success - SPNEGO_E_SUCCESS
65 //          Failure - SPNEGO API Error code
66 //
67 // Comments :
68 //    Initializes a SPNEGO_TOKEN_HANDLE from the supplied
69 //    binary data.  Data is copied locally.  Returned data structure
70 //    must be freed by calling spnegoFreeData().
71 //
72 ////////////////////////////////////////////////////////////////////////////
73 
74 int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
75 {
76    int            nReturn = SPNEGO_E_INVALID_PARAMETER;
77    SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
78 
79    // Pass off to a handler function that allows tighter control over how the token structure
80    // is handled.  In this case, we want the token data copied and we want the associated buffer
81    // freed.
82    nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYDATA,
83                                  SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, pbTokenData,
84                                  ulLength, ppSpnegoToken );
85 
86    return nReturn;
87 }
88 
89 /////////////////////////////////////////////////////////////////////////////
90 //
91 // Function:
92 //    spnegoCreateNegTokenHint
93 //
94 // Parameters:
95 //    [in]  pMechTypeList     -  List of MechTypes (OIDs) to include
96 //    [in]  MechTypeCnt       -  Length of MechTypes array
97 //    [in]  pbPrincipal       -  Principal name for MechListMIC
98 //    [out] phSpnegoToken     -  SPNEGO_TOKEN_HANDLE pointer
99 //
100 // Returns:
101 //    int   Success - SPNEGO_E_SUCCESS
102 //          Failure - SPNEGO API Error code
103 //
104 // Comments :
105 //    Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type token
106 //    from the supplied parameters.  The token created is the "hint"
107 //    used (for example) in the response to an SMB negotiate protocol.
108 //    Returned data structure must be freed by calling spnegoFreeData().
109 //
110 //    The "hint" tells the client what authentication methods this
111 //    server supports (the ones in the MechTypeList).  The Principal
112 //    name historically was the server's own SPN, but recent versions
113 //    of windows only supply: "not_defined_in_RFC4178@please_ignore"
114 //    So if you want to be nice to your clients, provide the host SPN,
115 //    otherwise provide the bogus SPN string like recent windows.
116 //
117 ////////////////////////////////////////////////////////////////////////////
118 
119 int spnegoCreateNegTokenHint( SPNEGO_MECH_OID *pMechTypeList, int MechTypeCnt,
120 	unsigned char *pbPrincipal, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
121 {
122 	int   nReturn;
123 	long  nTokenLength = 0L;
124 	long  nInternalTokenLength = 0L;
125 	unsigned long ulPrincipalLen;
126 	unsigned char* pbMechListMIC;
127 	unsigned long ulMechListMICLen;
128 	unsigned char* pbTokenData = NULL;
129 	SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
130 
131 	if ( NULL == ppSpnegoToken || NULL == pbPrincipal )
132 		return (SPNEGO_E_INVALID_PARAMETER);
133 
134 	/*
135 	 * Get the actual token size
136 	 */
137 	ulPrincipalLen = strlen((char *)pbPrincipal);
138 	ulMechListMICLen = ASNDerCalcElementLength( ulPrincipalLen, NULL );
139 	nReturn = CalculateMinSpnegoInitTokenSize(
140 		0, /* ulMechTokenLen */
141 		ulMechListMICLen,
142 		pMechTypeList,
143 		MechTypeCnt,
144 		0, /* nReqFlagsAvailable */
145 		&nTokenLength,
146 		&nInternalTokenLength );
147 	if ( nReturn != SPNEGO_E_SUCCESS )
148 		return (nReturn);
149 
150 	// Allocate a buffer to hold the data.
151 	pbTokenData = calloc( 1, nTokenLength );
152 
153 	if ( NULL == pbTokenData )
154 		return ( SPNEGO_E_OUT_OF_MEMORY );
155 
156 	/*
157 	 * Construct the MechListMIC
158 	 */
159 	pbMechListMIC = pbTokenData + (nTokenLength - ulMechListMICLen);
160 	(void) ASNDerWriteElement( pbMechListMIC, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
161 				   GENERALSTR, pbPrincipal, ulPrincipalLen );
162 
163 	// Now write the token
164 	nReturn = CreateSpnegoInitToken(
165 		pMechTypeList,
166 		MechTypeCnt,
167 		0, /* ContextFlags */
168 		NULL, 0, /* MechToken, len */
169 		pbMechListMIC,
170 		ulMechListMICLen,
171 		pbTokenData,
172 		nTokenLength,
173 		nInternalTokenLength );
174 	if ( nReturn != SPNEGO_E_SUCCESS ) {
175 		free( pbTokenData );
176 		return (nReturn);
177 	}
178 
179 	// This will copy our allocated pointer, and ensure that the sructure cleans
180 	// up the data later
181 	nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
182 				       SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
183 				       pbTokenData, nTokenLength, ppSpnegoToken );
184 
185 	// Cleanup on failure
186 	if ( nReturn != SPNEGO_E_SUCCESS ) {
187 		free( pbTokenData );
188 		return (nReturn);
189 	}
190 
191 	return (SPNEGO_E_SUCCESS);
192 }
193 
194 /////////////////////////////////////////////////////////////////////////////
195 //
196 // Function:
197 //    spnegoCreateNegTokenInit
198 //
199 // Parameters:
200 //    [in]  MechType          -  MechType to specify in MechTypeList element
201 //    [in]  ucContextFlags    -  Context Flags element value
202 //    [in]  pbMechToken       -  Pointer to binary MechToken Data
203 //    [in]  ulMechTokenLen    -  Length of MechToken Data
204 //    [in]  pbMechListMIC     -  Pointer to binary MechListMIC Data
205 //    [in]  ulMechListMICLen  -  Length of MechListMIC Data
206 //    [out] phSpnegoToken     -  SPNEGO_TOKEN_HANDLE pointer
207 //
208 // Returns:
209 //    int   Success - SPNEGO_E_SUCCESS
210 //          Failure - SPNEGO API Error code
211 //
212 // Comments :
213 //    Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type
214 //    from the supplied parameters.  ucContextFlags may be 0 or must be
215 //    a valid flag combination.  MechToken data can be NULL - if not, it
216 //    must correspond to the MechType.  MechListMIC can also be NULL.
217 //    Returned data structure must be freed by calling spnegoFreeData().
218 //
219 ////////////////////////////////////////////////////////////////////////////
220 
221 int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
222           unsigned char ucContextFlags, unsigned char* pbMechToken,
223           unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
224           unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
225 {
226    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
227    long  nTokenLength = 0L;
228    long  nInternalTokenLength = 0L;
229    unsigned char* pbTokenData = NULL;
230    SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
231 
232    if ( NULL != ppSpnegoToken &&
233          IsValidMechOid( MechType ) &&
234          IsValidContextFlags( ucContextFlags ) )
235    {
236       // Get the actual token size
237 
238       if ( ( nReturn = CalculateMinSpnegoInitTokenSize( ulMechTokenLen, ulMechListMICLen,
239 							&MechType, 1, ( ucContextFlags != 0L ),
240                                                          &nTokenLength, &nInternalTokenLength ) )
241                         == SPNEGO_E_SUCCESS )
242       {
243          // Allocate a buffer to hold the data.
244          pbTokenData = calloc( 1, nTokenLength );
245 
246          if ( NULL != pbTokenData )
247          {
248 
249             // Now write the token
250             if ( ( nReturn = CreateSpnegoInitToken( &MechType, 1,
251                                                  ucContextFlags, pbMechToken,
252                                                  ulMechTokenLen, pbMechListMIC,
253                                                  ulMechListMICLen, pbTokenData,
254                                                  nTokenLength, nInternalTokenLength ) )
255                               == SPNEGO_E_SUCCESS )
256             {
257 
258                // This will copy our allocated pointer, and ensure that the sructure cleans
259                // up the data later
260                nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
261                                              SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
262                                              pbTokenData, nTokenLength, ppSpnegoToken );
263 
264             }
265 
266             // Cleanup on failure
267             if ( SPNEGO_E_SUCCESS != nReturn )
268             {
269                free( pbTokenData );
270             }
271 
272          }  // IF alloc succeeded
273          else
274          {
275             nReturn = SPNEGO_E_OUT_OF_MEMORY;
276          }
277 
278       }  // If calculated token size
279 
280    }  // IF Valid Parameters
281 
282    return nReturn;
283 }
284 
285 /////////////////////////////////////////////////////////////////////////////
286 //
287 // Function:
288 //    spnegoCreateNegTokenTarg
289 //
290 // Parameters:
291 //    [in]  MechType          -  MechType to specify in supported MechType element
292 //    [in]  spnegoNegResult   -  NegResult value
293 //    [in]  pbMechToken       -  Pointer to response MechToken Data
294 //    [in]  ulMechTokenLen    -  Length of MechToken Data
295 //    [in]  pbMechListMIC     -  Pointer to binary MechListMIC Data
296 //    [in]  ulMechListMICLen  -  Length of MechListMIC Data
297 //    [out] phSpnegoToken     -  SPNEGO_TOKEN_HANDLE pointer
298 //
299 // Returns:
300 //    int   Success - SPNEGO_E_SUCCESS
301 //          Failure - SPNEGO API Error code
302 //
303 // Comments :
304 //    Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type
305 //    from the supplied parameters.  MechToken data can be NULL - if not,
306 //    it must correspond to the MechType.  MechListMIC can also be NULL.
307 //    Returned data structure must be freed by calling spnegoFreeData().
308 //
309 ////////////////////////////////////////////////////////////////////////////
310 
311 int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType,
312           SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
313           unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
314           unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
315 {
316    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
317    long  nTokenLength = 0L;
318    long  nInternalTokenLength = 0L;
319    unsigned char* pbTokenData = NULL;
320    SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
321 
322    //
323    // spnego_mech_oid_NotUsed and spnego_negresult_NotUsed
324    // are okay here, however a valid MechOid is required
325    // if spnego_negresult_success or spnego_negresult_incomplete
326    // is specified.
327    //
328 
329    if ( NULL != ppSpnegoToken &&
330 
331          ( IsValidMechOid( MechType ) ||
332             spnego_mech_oid_NotUsed == MechType ) &&
333 
334          ( IsValidNegResult( spnegoNegResult ) ||
335             spnego_negresult_NotUsed == spnegoNegResult ) )
336    {
337 
338       // Get the actual token size
339 
340       if ( ( nReturn = CalculateMinSpnegoTargTokenSize( MechType, spnegoNegResult, ulMechTokenLen,
341                                                          ulMechListMICLen, &nTokenLength,
342                                                          &nInternalTokenLength ) )
343                         == SPNEGO_E_SUCCESS )
344       {
345          // Allocate a buffer to hold the data.
346          pbTokenData = calloc( 1, nTokenLength );
347 
348          if ( NULL != pbTokenData )
349          {
350 
351             // Now write the token
352             if ( ( nReturn = CreateSpnegoTargToken( MechType,
353                                                  spnegoNegResult, pbMechToken,
354                                                  ulMechTokenLen, pbMechListMIC,
355                                                  ulMechListMICLen, pbTokenData,
356                                                  nTokenLength, nInternalTokenLength ) )
357                               == SPNEGO_E_SUCCESS )
358             {
359 
360                // This will copy our allocated pointer, and ensure that the sructure cleans
361                // up the data later
362                nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
363                                              SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
364                                              pbTokenData, nTokenLength, ppSpnegoToken );
365 
366             }
367 
368             // Cleanup on failure
369             if ( SPNEGO_E_SUCCESS != nReturn )
370             {
371                free( pbTokenData );
372             }
373 
374          }  // IF alloc succeeded
375          else
376          {
377             nReturn = SPNEGO_E_OUT_OF_MEMORY;
378          }
379 
380       }  // If calculated token size
381 
382    }  // IF Valid Parameters
383 
384    return nReturn;
385 }
386 
387 /////////////////////////////////////////////////////////////////////////////
388 //
389 // Function:
390 //    spnegoTokenGetBinary
391 //
392 // Parameters:
393 //    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
394 //    [out]    pbTokenData    -  Buffer to copy token into
395 //    [in/out] pulDataLen     -  Length of pbTokenData buffer, filled out
396 //                               with actual size used upon function return.
397 //
398 // Returns:
399 //    int   Success - SPNEGO_E_SUCCESS
400 //          Failure - SPNEGO API Error code
401 //
402 // Comments :
403 //    Copies binary SPNEGO token data from hSpnegoToken into the user
404 //    supplied buffer.  If pbTokenData is NULL, or the value in pulDataLen
405 //    is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and
406 //    fill out pulDataLen with the minimum required buffer size.
407 //
408 ////////////////////////////////////////////////////////////////////////////
409 
410 int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
411                            unsigned long * pulDataLen )
412 {
413    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
414    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
415 
416    // Check parameters - pbTokenData is optional
417    if (  IsValidSpnegoToken( pSpnegoToken ) &&
418          NULL != pulDataLen )
419    {
420 
421       // Check for Buffer too small conditions
422       if ( NULL == pbTokenData ||
423             pSpnegoToken->ulBinaryDataLen > *pulDataLen )
424       {
425          *pulDataLen = pSpnegoToken->ulBinaryDataLen;
426          nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
427       }
428       else
429       {
430          memcpy( pbTokenData, pSpnegoToken->pbBinaryData, pSpnegoToken->ulBinaryDataLen );
431          *pulDataLen = pSpnegoToken->ulBinaryDataLen;
432          nReturn = SPNEGO_E_SUCCESS;
433       }
434 
435    }  // IF parameters OK
436 
437    return nReturn;;
438 }
439 
440 /////////////////////////////////////////////////////////////////////////////
441 //
442 // Function:
443 //    spnegoFreeData
444 //
445 // Parameters:
446 //    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
447 //
448 // Returns:
449 //    void
450 //
451 // Comments :
452 //    Frees up resources consumed by hSpnegoToken.  The supplied data
453 //    pointer is invalidated by this function.
454 //
455 ////////////////////////////////////////////////////////////////////////////
456 
457 void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken )
458 {
459    FreeSpnegoToken( (SPNEGO_TOKEN*) hSpnegoToken);
460    return;
461 }
462 
463 /////////////////////////////////////////////////////////////////////////////
464 //
465 // Function:
466 //    spnegoGetTokenType
467 //
468 // Parameters:
469 //    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
470 //    [out] piTokenType       -  Filled out with token type value.
471 //
472 // Returns:
473 //    int   Success - SPNEGO_E_SUCCESS
474 //          Failure - SPNEGO API Error code
475 //
476 // Comments :
477 //    The function will analyze hSpnegoToken and return the appropriate
478 //    type in piTokenType.
479 //
480 ////////////////////////////////////////////////////////////////////////////
481 
482 int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType )
483 {
484    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
485    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
486 
487    // Check parameters
488    if (  IsValidSpnegoToken( pSpnegoToken ) &&
489          NULL != piTokenType &&
490          pSpnegoToken)
491    {
492 
493       // Check that the type in the structure makes sense
494       if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
495             SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
496       {
497          *piTokenType = pSpnegoToken->ucTokenType;
498          nReturn = SPNEGO_E_SUCCESS;
499       }
500 
501    }  // IF parameters OK
502 
503    return nReturn;
504 }
505 
506 /////////////////////////////////////////////////////////////////////////////
507 //
508 // Function:
509 //    spnegoIsMechTypeAvailable
510 //
511 // Parameters:
512 //    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
513 //    [in]  MechOID           -  MechOID to search MechTypeList for
514 //    [out] piMechTypeIndex   -  Filled out with index in MechTypeList
515 //                               element if MechOID is found.
516 //
517 // Returns:
518 //    int   Success - SPNEGO_E_SUCCESS
519 //          Failure - SPNEGO API Error code
520 //
521 // Comments :
522 //    hSpnegoToken must reference a token of type NegTokenInit.  The
523 //    function will search the MechTypeList element for an OID corresponding
524 //    to the specified MechOID.  If one is found, the index (0 based) will
525 //    be passed into the piMechTypeIndex parameter.
526 //
527 ////////////////////////////////////////////////////////////////////////////
528 
529 // Returns the Initial Mech Type in the MechList element in the NegInitToken.
530 int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex )
531 {
532    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
533    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
534 
535    // Check parameters
536    if (  IsValidSpnegoToken( pSpnegoToken ) &&
537          NULL != piMechTypeIndex &&
538          IsValidMechOid( MechOID ) &&
539          SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
540    {
541 
542       // Check if MechList is available
543       if ( pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].iElementPresent
544             == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
545       {
546          // Locate the MechOID in the list element
547          nReturn = FindMechOIDInMechList(
548                      &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT],
549                      MechOID, piMechTypeIndex );
550       }
551       else
552       {
553          nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
554       }
555 
556    }  // IF parameters OK
557 
558    return nReturn;;
559 }
560 
561 /////////////////////////////////////////////////////////////////////////////
562 //
563 // Function:
564 //    spnegoGetContextFlags
565 //
566 // Parameters:
567 //    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
568 //    [out] pucContextFlags   -  Filled out with ContextFlags value.
569 //
570 // Returns:
571 //    int   Success - SPNEGO_E_SUCCESS
572 //          Failure - SPNEGO API Error code
573 //
574 // Comments :
575 //    hSpnegoToken must reference a token of type NegTokenInit.  The
576 //    function will copy data from the ContextFlags element into the
577 //    location pucContextFlags points to.  Note that the function will
578 //    fail if the actual ContextFlags data appears invalid.
579 //
580 ////////////////////////////////////////////////////////////////////////////
581 
582 int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags )
583 {
584    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
585    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
586 
587    // Check parameters
588    if (  IsValidSpnegoToken( pSpnegoToken ) &&
589          NULL != pucContextFlags &&
590          SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
591    {
592 
593       // Check if ContextFlags is available
594       if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].iElementPresent
595             == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
596       {
597          // The length should be two, the value should show a 1 bit difference in the difference byte, and
598          // the value must be valid
599          if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].nDatalength == SPNEGO_NEGINIT_MAXLEN_REQFLAGS &&
600                pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[0] == SPNEGO_NEGINIT_REQFLAGS_BITDIFF &&
601                IsValidContextFlags( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1] ) )
602          {
603             *pucContextFlags = pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1];
604             nReturn = SPNEGO_E_SUCCESS;
605          }
606          else
607          {
608             nReturn = SPNEGO_E_INVALID_ELEMENT;
609          }
610 
611       }
612       else
613       {
614          nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
615       }
616 
617    }  // IF parameters OK
618 
619    return nReturn;;
620 }
621 
622 /////////////////////////////////////////////////////////////////////////////
623 //
624 // Function:
625 //    spnegoGetNegotiationResult
626 //
627 // Parameters:
628 //    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
629 //    [out] pnegResult        -  Filled out with NegResult value.
630 //
631 // Returns:
632 //    int   Success - SPNEGO_E_SUCCESS
633 //          Failure - SPNEGO API Error code
634 //
635 // Comments :
636 //    hSpnegoToken must reference a token of type NegTokenTarg.  The
637 //    function will copy data from the NegResult element into the
638 //    location pointed to by pnegResult.  Note that the function will
639 //    fail if the actual NegResult data appears invalid.
640 //
641 ////////////////////////////////////////////////////////////////////////////
642 
643 int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult )
644 {
645    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
646    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
647 
648    // Check parameters
649    if (  IsValidSpnegoToken( pSpnegoToken ) &&
650          NULL != pnegResult &&
651          SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
652    {
653 
654       // Check if NegResult is available
655       if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].iElementPresent
656             == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
657       {
658          // Must be 1 byte long and a valid value
659          if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == SPNEGO_NEGTARG_MAXLEN_NEGRESULT &&
660                IsValidNegResult( *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData ) )
661          {
662             *pnegResult = *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData;
663             nReturn = SPNEGO_E_SUCCESS;
664          }
665          else
666          {
667             nReturn = SPNEGO_E_INVALID_ELEMENT;
668          }
669       }
670       else
671       {
672          nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
673       }
674 
675    }  // IF parameters OK
676 
677    return nReturn;;
678 }
679 
680 /////////////////////////////////////////////////////////////////////////////
681 //
682 // Function:
683 //    spnegoGetSupportedMechType
684 //
685 // Parameters:
686 //    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
687 //    [out] pMechOID          -  Filled out with Supported MechType value.
688 //
689 // Returns:
690 //    int   Success - SPNEGO_E_SUCCESS
691 //          Failure - SPNEGO API Error code
692 //
693 // Comments :
694 //    hSpnegoToken must reference a token of type NegTokenTarg.  The
695 //    function will check the Supported MechType element, and if it
696 //    corresponds to a supported MechType ( spnego_mech_oid_Kerberos_V5_Legacy
697 //    or spnego_mech_oid_Kerberos_V5 ), will set the location pointed
698 //    to by pMechOID equal to the appropriate value.
699 //
700 ////////////////////////////////////////////////////////////////////////////
701 
702 int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID  )
703 {
704    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
705    int   nCtr = 0L;
706    long  nLength = 0L;
707    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
708 
709    // Check parameters
710    if (  IsValidSpnegoToken( pSpnegoToken ) &&
711          NULL != pMechOID &&
712          SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
713    {
714 
715       // Check if MechList is available
716       if ( pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].iElementPresent
717             == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
718       {
719 
720          for ( nCtr = 0;
721                nReturn != SPNEGO_E_SUCCESS &&
722                g_stcMechOIDList[nCtr].eMechanismOID != spnego_mech_oid_NotUsed;
723                nCtr++ )
724          {
725 
726             if ( ( nReturn = ASNDerCheckOID(
727                         pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].pbData,
728                         nCtr,
729                         pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].nDatalength,
730                         &nLength ) ) == SPNEGO_E_SUCCESS )
731             {
732                *pMechOID = nCtr;
733             }
734 
735          }  // For enum MechOIDs
736 
737 
738       }
739       else
740       {
741          nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
742       }
743 
744    }  // IF parameters OK
745 
746    return nReturn;;
747 }
748 
749 /////////////////////////////////////////////////////////////////////////////
750 //
751 // Function:
752 //    spnegoTokenGetMechToken
753 //
754 // Parameters:
755 //    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
756 //    [out]    pbTokenData    -  Buffer to copy MechToken into
757 //    [in/out] pulDataLen     -  Length of pbTokenData buffer, filled out
758 //                               with actual size used upon function return.
759 //
760 // Returns:
761 //    int   Success - SPNEGO_E_SUCCESS
762 //          Failure - SPNEGO API Error code
763 //
764 // Comments :
765 //    hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
766 //    The function will copy the MechToken (the initial MechToken if
767 //    NegTokenInit, the response MechToken if NegTokenTarg) from the
768 //    underlying token into the buffer pointed to by pbTokenData.  If
769 //    pbTokenData is NULL, or the value in pulDataLen is too small, the
770 //    function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen
771 //    with the minimum required buffer size.  The token can then be passed
772 //    to a GSS-API function for processing.
773 //
774 ////////////////////////////////////////////////////////////////////////////
775 
776 int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen )
777 {
778    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
779    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
780    SPNEGO_ELEMENT*   pSpnegoElement = NULL;
781 
782    // Check parameters
783    if (  IsValidSpnegoToken( pSpnegoToken ) &&
784          NULL != pulDataLen )
785    {
786 
787       // Point at the proper Element
788       if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
789       {
790          pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTOKEN_ELEMENT];
791       }
792       else
793       {
794          pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_RESPTOKEN_ELEMENT];
795       }
796 
797       // Check if MechType is available
798       if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent  )
799       {
800          // Check for Buffer too small conditions
801          if ( NULL == pbTokenData ||
802                pSpnegoElement->nDatalength > *pulDataLen )
803          {
804             *pulDataLen = pSpnegoElement->nDatalength;
805             nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
806          }
807          else
808          {
809             // Copy Memory
810             memcpy( pbTokenData, pSpnegoElement->pbData, pSpnegoElement->nDatalength );
811             *pulDataLen = pSpnegoElement->nDatalength;
812             nReturn = SPNEGO_E_SUCCESS;
813          }
814       }
815       else
816       {
817          nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
818       }
819 
820    }  // IF parameters OK
821 
822    return nReturn;;
823 }
824 
825 /////////////////////////////////////////////////////////////////////////////
826 //
827 // Function:
828 //    spnegoTokenGetMechListMIC
829 //
830 // Parameters:
831 //    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
832 //    [out]    pbTokenData    -  Buffer to copy MechListMIC data into
833 //    [in/out] pulDataLen     -  Length of pbTokenData buffer, filled out
834 //                               with actual size used upon function return.
835 //
836 // Returns:
837 //    int   Success - SPNEGO_E_SUCCESS
838 //          Failure - SPNEGO API Error code
839 //
840 // Comments :
841 //    hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
842 //    The function will copy the MechListMIC data from the underlying token
843 //    into the buffer pointed to by pbTokenData.  If pbTokenData is NULL,
844 //    or the value in pulDataLen is too small, the function will return
845 //    SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen with the minimum
846 //    required buffer size.
847 //
848 ////////////////////////////////////////////////////////////////////////////
849 
850 int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen )
851 {
852    int   nReturn = SPNEGO_E_INVALID_PARAMETER;
853    SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
854    SPNEGO_ELEMENT*   pSpnegoElement = NULL;
855 
856    // Check parameters
857    if (  IsValidSpnegoToken( pSpnegoToken ) &&
858          NULL != pulDataLen )
859    {
860 
861       // Point at the proper Element
862       if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
863       {
864          pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHLISTMIC_ELEMENT];
865       }
866       else
867       {
868          pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_MECHLISTMIC_ELEMENT];
869       }
870 
871       // Check if MechType is available
872       if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent  )
873       {
874          // Check for Buffer too small conditions
875          if ( NULL == pbMICData ||
876                pSpnegoElement->nDatalength > *pulDataLen )
877          {
878             *pulDataLen = pSpnegoElement->nDatalength;
879             nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
880          }
881          else
882          {
883             // Copy Memory
884             memcpy( pbMICData, pSpnegoElement->pbData, pSpnegoElement->nDatalength );
885             *pulDataLen = pSpnegoElement->nDatalength;
886             nReturn = SPNEGO_E_SUCCESS;
887          }
888       }
889       else
890       {
891          nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
892       }
893 
894    }  // IF parameters OK
895 
896    return nReturn;;
897 }
898 
899