home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / security / winnt / httpauth / httpauth.c < prev    next >
C/C++ Source or Header  |  1997-10-08  |  30KB  |  1,212 lines

  1. /*++
  2.  
  3. Copyright 1996-1997 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     httpauth.c
  8.  
  9. Abstract:
  10.  
  11.     Handles authentication sequence ( Basic & SSPI )
  12.  
  13. History:
  14.  
  15.     Created     15-Feb-1996
  16.  
  17.  
  18. Revision History:
  19.  
  20. --*/
  21.  
  22. /************************************************************
  23.  *    Include Headers
  24.  ************************************************************/
  25.  
  26. #include <windows.h>
  27. #include <rpc.h>
  28. #include <winsock.h>
  29. #include <lm.h>
  30.  
  31. #include <stdio.h>
  32. #include <stdarg.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <tchar.h>
  36. #include <fcntl.h>
  37.  
  38. #define SECURITY_WIN32
  39. #include "sspi.h"
  40. #include "issperr.h"
  41.  
  42.  
  43. // declaration for this module
  44.  
  45. #include "httpauth.h"
  46.  
  47. #define SEC_SUCCESS(Status) ((Status) >= 0)
  48. #define STATUS_SUCCESS 0
  49.  
  50.  
  51. // Target name for the security package
  52.  
  53. #define TOKEN_SOURCE_NAME       "InetSvcs"
  54.  
  55.  
  56. // general purpose dynamic buffer structure
  57.  
  58. typedef struct _BUFFER {
  59.     PBYTE pBuf;
  60.     DWORD cLen;
  61. } BUFFER ;
  62.  
  63.  
  64. // structure storing the state of the authentication sequence
  65.  
  66. typedef struct _AUTH_SEQ {
  67.     BOOL _fNewConversation;
  68.     CredHandle _hcred;
  69.     BOOL _fHaveCredHandle;
  70.     DWORD _cbMaxToken;
  71.     BOOL _fHaveCtxtHandle;
  72.     struct _SecHandle  _hctxt;
  73.     BOOL _fUUEncodeData;
  74. } AUTH_SEQ;
  75.  
  76. // entry points in the security DLL
  77.  
  78. typedef struct _SEC_FUNC {
  79.     FREE_CREDENTIALS_HANDLE_FN pFreeCredentialsHandle;
  80.     ACQUIRE_CREDENTIALS_HANDLE_FN pAcquireCredentialsHandle;
  81.     QUERY_SECURITY_PACKAGE_INFO_FN pQuerySecurityPackageInfo;   // A
  82.     FREE_CONTEXT_BUFFER_FN pFreeContextBuffer;
  83.     INITIALIZE_SECURITY_CONTEXT_FN pInitializeSecurityContext;  // A
  84.     COMPLETE_AUTH_TOKEN_FN pCompleteAuthToken;
  85.     ENUMERATE_SECURITY_PACKAGES_FN pEnumerateSecurityPackages;  // A
  86. } SEC_FUNC;
  87.  
  88. // local functions
  89.  
  90. BOOL CrackUserAndDomain(
  91.     CHAR *   pszDomainAndUser,
  92.     CHAR * * ppszUser,
  93.     CHAR * * ppszDomain
  94.     );
  95.  
  96. BOOL AuthConverse(
  97.     AUTH_SEQ *pAS,
  98.     VOID   * pBuffIn,
  99.     DWORD    cbBuffIn,
  100.     BUFFER * pbuffOut,
  101.     DWORD  * pcbBuffOut,
  102.     BOOL   * pfNeedMoreData,
  103.     CHAR   * pszPackage,
  104.     CHAR   * pszUser,
  105.     CHAR   * pszPassword
  106.     );
  107.  
  108. BOOL AuthInit( AUTH_SEQ *pAS );
  109.  
  110. void AuthTerminate( AUTH_SEQ *pAS );
  111.  
  112.  
  113. // uuencode/decode routines declaration
  114. // used to code the authentication blob
  115.  
  116. BOOL uudecode(char   * bufcoded,
  117.               BUFFER * pbuffdecoded,
  118.               DWORD  * pcbDecoded );
  119. BOOL uuencode( BYTE *   bufin,
  120.                DWORD    nbytes,
  121.                BUFFER * pbuffEncoded );
  122.  
  123.  
  124. /************************************************************
  125.  *    Globals for this module
  126.  ************************************************************/
  127.  
  128. static BOOL g_fAuth = FALSE;
  129. static BOOL g_fBasic = FALSE;
  130. static AUTH_SEQ g_Auth;
  131. static HINSTANCE g_hSecLib = NULL;
  132. static SEC_FUNC sfProcs;
  133.  
  134.  
  135. /************************************************************
  136.  *    Helper functions
  137.  ************************************************************/
  138.  
  139. BOOL BufferInit( BUFFER *pB )
  140. {
  141.     pB->pBuf = NULL;
  142.     pB->cLen = 0;
  143.  
  144.     return TRUE;
  145. }
  146.  
  147.  
  148. void BufferTerminate( BUFFER *pB )
  149. {
  150.     if ( pB->pBuf != NULL )
  151.     {
  152.         free( pB->pBuf );
  153.         pB->pBuf = NULL;
  154.         pB->cLen = 0;
  155.     }
  156. }
  157.  
  158.  
  159. PBYTE BufferQueryPtr( BUFFER * pB )
  160. {
  161.     return pB->pBuf;
  162. }
  163.  
  164.  
  165. BOOL BufferResize( BUFFER *pB, DWORD cNewL )
  166. {
  167.     PBYTE pN;
  168.     if ( cNewL > pB->cLen )
  169.     {
  170.         pN = malloc( cNewL );
  171.         if ( pB->pBuf )
  172.         {
  173.             memcpy( pN, pB->pBuf, pB->cLen );
  174.             free( pB->pBuf );
  175.         }
  176.         pB->pBuf = pN;
  177.         pB->cLen = cNewL;
  178.     }
  179.  
  180.     return TRUE;
  181. }
  182.  
  183.  
  184. /************************************************************
  185.  *    Authentication functions
  186.  ************************************************************/
  187.  
  188.  
  189. BOOL 
  190. InitAuthorizationHeader(
  191.     )
  192. /*++
  193.  
  194.  Routine Description:
  195.  
  196.     Initialize the authentication package
  197.  
  198.  Arguments:
  199.  
  200.     None
  201.  
  202.  Return Value:
  203.  
  204.     Returns TRUE is successful; otherwise FALSE is returned.
  205.  
  206. --*/
  207. {
  208.     OSVERSIONINFO   VerInfo;
  209.     UCHAR lpszDLL[MAX_PATH];
  210.  
  211.     //
  212.     //  Find out which security DLL to use, depending on 
  213.     //  whether we are on NT or Win95
  214.     //
  215.     VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  216.     if (!GetVersionEx (&VerInfo))   // If this fails, something has gone wrong
  217.     {
  218.         return FALSE;
  219.     }
  220.  
  221.     if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  222.     {
  223.         strcpy (lpszDLL, "security.dll" );
  224.     }
  225.     else if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  226.     {
  227.         strcpy (lpszDLL, "secur32.dll" );
  228.     }
  229.     else
  230.     {
  231.         return FALSE;
  232.     }
  233.  
  234.     //
  235.     //  Load Security DLL
  236.     //
  237.  
  238.     g_hSecLib = LoadLibrary (lpszDLL);
  239.     if (g_hSecLib == NULL)
  240.     {
  241.         return FALSE;
  242.     }
  243.  
  244.     // Get all entry points we care about
  245.  
  246.     sfProcs.pFreeCredentialsHandle 
  247.             = (FREE_CREDENTIALS_HANDLE_FN) GetProcAddress( 
  248.                     g_hSecLib, 
  249.                     "FreeCredentialsHandle" );
  250.  
  251.     sfProcs.pQuerySecurityPackageInfo 
  252.             = (QUERY_SECURITY_PACKAGE_INFO_FN) GetProcAddress( 
  253.                     g_hSecLib, 
  254.                     "QuerySecurityPackageInfoA" );
  255.  
  256.     sfProcs.pAcquireCredentialsHandle 
  257.             = (ACQUIRE_CREDENTIALS_HANDLE_FN) GetProcAddress(
  258.                     g_hSecLib, 
  259.                     "AcquireCredentialsHandleA" );
  260.  
  261.     sfProcs.pFreeContextBuffer 
  262.             = (FREE_CONTEXT_BUFFER_FN) GetProcAddress( 
  263.                     g_hSecLib, 
  264.                     "FreeContextBuffer" );
  265.  
  266.     sfProcs.pInitializeSecurityContext
  267.             = (INITIALIZE_SECURITY_CONTEXT_FN) GetProcAddress( 
  268.                     g_hSecLib, 
  269.                     "InitializeSecurityContextA" );
  270.  
  271.     sfProcs.pCompleteAuthToken 
  272.             = (COMPLETE_AUTH_TOKEN_FN) GetProcAddress( 
  273.                     g_hSecLib, 
  274.                     "CompleteAuthToken" );
  275.  
  276.     sfProcs.pEnumerateSecurityPackages 
  277.             = (ENUMERATE_SECURITY_PACKAGES_FN) GetProcAddress( 
  278.                     g_hSecLib, 
  279.                     "EnumerateSecurityPackagesA" );
  280.  
  281.     if ( sfProcs.pFreeCredentialsHandle == NULL
  282.             || sfProcs.pQuerySecurityPackageInfo == NULL
  283.             || sfProcs.pAcquireCredentialsHandle == NULL
  284.             || sfProcs.pFreeContextBuffer == NULL
  285.             || sfProcs.pInitializeSecurityContext == NULL 
  286.             || sfProcs.pEnumerateSecurityPackages == NULL )
  287.     {
  288.         FreeLibrary( g_hSecLib );
  289.         g_hSecLib = NULL;
  290.         return FALSE;
  291.     }
  292.  
  293.     g_fAuth = g_fBasic = FALSE;
  294.  
  295.     return TRUE;
  296. }
  297.  
  298.  
  299. void 
  300. TerminateAuthorizationHeader(
  301.     )
  302. /*++
  303.  
  304.  Routine Description:
  305.  
  306.     Terminate the authentication package
  307.  
  308.  Arguments:
  309.  
  310.     None
  311.  
  312.  Return Value:
  313.  
  314.     None
  315.  
  316. --*/
  317. {
  318.     if ( g_fAuth )
  319.     {
  320.         AuthTerminate( &g_Auth );
  321.         g_fAuth = FALSE;
  322.     }
  323.  
  324.     g_fBasic = FALSE;
  325.  
  326.     if ( g_hSecLib != NULL )
  327.     {
  328.         FreeLibrary( g_hSecLib );
  329.         g_hSecLib = NULL;
  330.     }
  331. }
  332.  
  333.  
  334. BOOL 
  335. IsInAuthorizationSequence(
  336.     )
  337. /*++
  338.  
  339.  Routine Description:
  340.  
  341.     Indicates if in authentication sequence
  342.  
  343.  Arguments:
  344.  
  345.     None
  346.  
  347.  Return Value:
  348.  
  349.     Returns TRUE is successful; otherwise FALSE is returned.
  350.  
  351. --*/
  352. {
  353.     return g_fAuth || g_fBasic;
  354. }
  355.  
  356.  
  357. BOOL 
  358. ValidateAuthenticationMethods( 
  359.     PSTR pszMet,
  360.     PSTR pszPreferedMet )
  361. /*++
  362.  
  363.  Routine Description:
  364.  
  365.     Filter the supplied authentication list for supported
  366.     methods ( Basic and all local security packages )
  367.  
  368.  Arguments:
  369.  
  370.     None
  371.  
  372.  Return Value:
  373.  
  374.     Returns TRUE if at least one authentication method supported,
  375.     otherwise FALSE is returned.
  376.  
  377. --*/
  378. {
  379.     PSecPkgInfo pSec;
  380.     ULONG cSec, iS;
  381.     BOOL fValid;
  382.     PSTR p,t;
  383.     SECURITY_STATUS ss;
  384.  
  385.  
  386.     // access local security packages list
  387.  
  388.     if ( (ss = sfProcs.pEnumerateSecurityPackages( &cSec, &pSec )) 
  389.             == STATUS_SUCCESS )
  390.     {
  391.         for ( t = p = pszMet ; *p ; )
  392.         {
  393.             // Valid methods are "Basic" and all security packages
  394.  
  395.             if ( !_stricmp( p , "Basic" ) )
  396.                 fValid = TRUE;
  397.             else for ( iS = 0 ; iS < cSec ; ++iS )
  398.                 if ( !_stricmp( pSec[iS].Name, p ) )
  399.                     break;
  400.  
  401.             if ( fValid )
  402.             {
  403.                 if ( t != p )
  404.                     memmove( t, p, strlen(p)+1 );
  405.                 p += strlen( p ) + 1;
  406.                 t += strlen( t ) + 1;
  407.             }
  408.         }
  409.         *t = '\0';
  410.     }
  411.  
  412.     // check for prefered method
  413.  
  414.     if ( pszPreferedMet != NULL )
  415.     {
  416.         PSTR pP;
  417.  
  418.         for ( pP = strtok( pszPreferedMet, "," ) ;
  419.                 pP != NULL ;
  420.                 pP = strtok( NULL, "," ) )
  421.         {
  422.             // scan list of validated methods for the current
  423.             // prefered method
  424.  
  425.             for ( p = pszMet ; *p ; )
  426.             {
  427.                 if ( !_stricmp( pP, p ) )
  428.                 {
  429.                     memmove( pszMet, p, strlen(p) + 1 );
  430.                     return TRUE;
  431.                 }
  432.                 p += strlen( p ) + 1;
  433.             }
  434.         }
  435.  
  436.         // no method in the prefered method list is supported
  437.  
  438.         return FALSE;
  439.     }
  440.  
  441.     // no prefered method list supplied
  442.  
  443.     return *pszMet ? TRUE : FALSE;
  444. }
  445.  
  446.  
  447. BOOL
  448. AddAuthorizationHeader(
  449.     PSTR pch,       
  450.     PSTR pchSchemes,
  451.     PSTR pchAuthData,
  452.     PSTR pchUserName,
  453.     PSTR pchPassword,
  454.     BOOL *pfNeedMoreData
  455.     )
  456. /*++
  457.  
  458.  Routine Description:
  459.  
  460.     Generates an authentication header to be sent to the server.
  461.     An authentication sequence will be initiated if none is in
  462.     use and at least one of the authentication scheme specified
  463.     in pchSchemes is recognized.
  464.     Otherwise the current authentication sequence will proceed.
  465.  
  466.  Arguments:
  467.  
  468.     pch                 where to append authentication header
  469.     pchSchemes          list of null-delimited authentication methods
  470.     pchAuthData         incoming blob from server
  471.     pchUserName         user name ( possibly prefixed with domain )
  472.     pchPassword         password
  473.     pfNeedMoreData      Out: TRUE if authentication sequence to continue
  474.  
  475.  Return Value:
  476.  
  477.     Returns TRUE is successful; otherwise FALSE is returned.
  478.  
  479. --*/
  480. {
  481.     CHAR   achUserAndPass[256];
  482.     BUFFER buff;
  483.     BOOL fSt = TRUE;
  484.     DWORD cbOut;
  485.  
  486.  
  487.     BufferInit( &buff );
  488.  
  489.     while ( *pchSchemes )
  490.     {
  491.         if ( !stricmp( pchSchemes, "Basic" ))
  492.         {
  493.             // if already in authentication sequence, it failed.
  494.  
  495.             if ( g_fBasic )
  496.             {
  497.                 SetLastError( ERROR_ACCESS_DENIED );
  498.                 fSt = FALSE;
  499.                 break;
  500.             }
  501.  
  502.             strcpy( achUserAndPass, pchUserName );
  503.             strcat( achUserAndPass, ":" );
  504.             strcat( achUserAndPass, pchPassword );
  505.  
  506.             uuencode( (BYTE *) achUserAndPass,
  507.                       strlen( achUserAndPass ),
  508.                       &buff );
  509.             strcat( pch, "Authorization: " );
  510.             strcat( pch, "Basic " );
  511.             strcat( pch, BufferQueryPtr( &buff ));
  512.             strcat( pch, "\r\n");
  513.             g_fBasic = TRUE;
  514.             break;
  515.         }
  516.         else 
  517.         {
  518.             // SSPI package ( assuming methods list have been validated )
  519.  
  520.             if ( !g_fAuth )
  521.             {
  522.                 if ( !AuthInit( &g_Auth ) )
  523.                 {
  524.                     fSt = FALSE;
  525.                     goto ex;
  526.                 }
  527.             }
  528.             else if ( pchAuthData == NULL || *pchAuthData == '\0' )
  529.             {
  530.                 // no blob while in authentication sequence : it failed
  531.  
  532.                 SetLastError( ERROR_ACCESS_DENIED );
  533.                 fSt = FALSE;
  534.                 break;
  535.             }
  536.  
  537.             if ( !AuthConverse( &g_Auth,
  538.                   (void *) pchAuthData,
  539.                   0,
  540.                   &buff,
  541.                   &cbOut,
  542.                   pfNeedMoreData,
  543.                   pchSchemes,
  544.                   pchUserName,
  545.                   pchPassword ))
  546.             {
  547.                 fSt = FALSE;
  548.                 goto ex;
  549.             }
  550.  
  551.             strcat( pch, "Authorization: " );
  552.             strcat( pch, pchSchemes );
  553.             strcat( pch, " " );
  554.             strcat( pch, (CHAR *) BufferQueryPtr( &buff ) );
  555.             strcat( pch, "\r\n" );
  556.             break;
  557.         }
  558.  
  559.         pchSchemes += strlen(pchSchemes) + 1;
  560.     }
  561. ex:
  562.     BufferTerminate( &buff );
  563.  
  564.     return fSt;
  565. }
  566.  
  567.  
  568. BOOL 
  569. AuthInit( 
  570.     AUTH_SEQ *pAS )
  571. /*++
  572.  
  573.  Routine Description:
  574.  
  575.     Initialize a SSP authentication sequence
  576.  
  577.  Arguments:
  578.  
  579.     None
  580.  
  581.  Return Value:
  582.  
  583.     Returns TRUE is successful; otherwise FALSE is returned.
  584.  
  585. --*/
  586. {
  587.     pAS->_fNewConversation = TRUE;
  588.     pAS->_fHaveCredHandle = FALSE;
  589.     pAS->_fHaveCtxtHandle = FALSE;
  590.     pAS->_fUUEncodeData = TRUE;
  591.  
  592.     g_fAuth = TRUE;
  593.  
  594.     return TRUE;
  595. }
  596.  
  597.  
  598. void 
  599. AuthTerminate( 
  600.     AUTH_SEQ *pAS )
  601. /*++
  602.  
  603.  Routine Description:
  604.  
  605.     Terminate a SSP authentication sequence
  606.  
  607.  Arguments:
  608.  
  609.     None
  610.  
  611.  Return Value:
  612.  
  613.     None
  614.  
  615. --*/
  616. {
  617.     if ( pAS->_fHaveCredHandle )
  618.         sfProcs.pFreeCredentialsHandle( &pAS->_hcred );
  619.  
  620.     pAS->_fHaveCredHandle = FALSE;
  621.     pAS->_fHaveCtxtHandle = FALSE;
  622. }
  623.  
  624.  
  625. BOOL 
  626. AuthConverse(
  627.     AUTH_SEQ *pAS,
  628.     VOID   * pBuffIn,
  629.     DWORD    cbBuffIn,
  630.     BUFFER * pbuffOut,
  631.     DWORD  * pcbBuffOut,
  632.     BOOL   * pfNeedMoreData,
  633.     CHAR   * pszPackage,
  634.     CHAR   * pszUser,
  635.     CHAR   * pszPassword
  636.     )
  637. /*++
  638.  
  639. Routine Description:
  640.  
  641.     Initiates or continues a previously initiated authentication conversation
  642.  
  643.     Client calls this first to get the negotiation message which
  644.     it then sends to the server.  The server calls this with the
  645.     client result and sends back the result.  The conversation
  646.     continues until *pfNeedMoreData is FALSE.
  647.  
  648.     On the first call, pszPackage must point to the zero terminated
  649.     authentication package name to be used and pszUser and pszPassword
  650.     should point to the user name and password to authenticated with
  651.     on the client side (server side will always be NULL).
  652.  
  653. Arguments:
  654.  
  655.     pBuffIn - Points to SSP message received from the
  656.         client.  If UUENCODE is used, then this must point to a
  657.         zero terminated uuencoded string (except for the first call).
  658.     cbBuffIn - Number of bytes in pBuffIn or zero if pBuffIn points to a
  659.         zero terminated, uuencoded string.
  660.     pbuffOut - If *pfDone is not set to TRUE, this buffer contains the data
  661.         that should be sent to the other side.  If this is zero, then no
  662.         data needs to be sent.
  663.     pcbBuffOut - Number of bytes in pbuffOut
  664.     pfNeedMoreData - Set to TRUE while this side of the conversation is
  665.         expecting more data from the remote side.
  666.     pszPackage - On the first call points to a zero terminate string indicating
  667.         the security package to use
  668.     pszUser - Specifies user or domain\user the first time the client calls
  669.         this method (client side only)
  670.     pszPassword - Specifies the password for pszUser the first time the
  671.         client calls this method (client side only)
  672.  
  673. Return Value:
  674.  
  675.     TRUE if successful, FALSE otherwise (call GetLastError).  Access is
  676.     denied if FALSE is returned and GetLastError is ERROR_ACCESS_DENIED.
  677.  
  678. --*/
  679. {
  680.     SECURITY_STATUS       ss;
  681.     TimeStamp             Lifetime;
  682.     SecBufferDesc         OutBuffDesc;
  683.     SecBuffer             OutSecBuff;
  684.     SecBufferDesc         InBuffDesc;
  685.     SecBuffer             InSecBuff;
  686.     ULONG                 ContextAttributes;
  687.     BUFFER                buffData;
  688.     BUFFER                buff;
  689.     BOOL                  fSt;
  690.     BOOL                  fReply;
  691.  
  692.     BufferInit( &buffData );
  693.     BufferInit( &buff );
  694.  
  695.     //
  696.     //  Decode the data if there's something to decode
  697.     //
  698.  
  699.     if ( pAS->_fUUEncodeData && pBuffIn )
  700.     {
  701.         if ( !uudecode( (CHAR *) pBuffIn,
  702.                         &buffData,
  703.                         &cbBuffIn ))
  704.         {
  705.             fSt = FALSE;
  706.             goto ex;
  707.         }
  708.  
  709.         pBuffIn = BufferQueryPtr( &buffData );
  710.     }
  711.  
  712.     //
  713.     //  If this is a new conversation, then we need to get the credential
  714.     //  handle and find out the maximum token size
  715.     //
  716.  
  717.     if ( pAS->_fNewConversation )
  718.     {
  719.         SecPkgInfo *              pspkg;
  720.         SEC_WINNT_AUTH_IDENTITY   AuthIdentity;
  721.         SEC_WINNT_AUTH_IDENTITY * pAuthIdentity;
  722.         CHAR *                    pszDomain = NULL;
  723.         CHAR                      szDomainAndUser[DNLEN+UNLEN+2];
  724.  
  725.  
  726.         //
  727.         //  fill out the authentication information
  728.         //
  729.  
  730.         if ( ((pszUser != NULL) ||
  731.               (pszPassword != NULL)) )
  732.         {
  733.             pAuthIdentity = &AuthIdentity;
  734.  
  735.             //
  736.             //  Break out the domain from the username if one was specified
  737.             //
  738.  
  739.             if ( pszUser != NULL )
  740.             {
  741.                 strcpy( szDomainAndUser, pszUser );
  742.                 if ( !CrackUserAndDomain( szDomainAndUser,
  743.                                           &pszUser,
  744.                                           &pszDomain ))
  745.                 {
  746.                     return FALSE;
  747.                 }
  748.             }
  749.  
  750.             memset( &AuthIdentity,
  751.                     0,
  752.                     sizeof( AuthIdentity ));
  753.  
  754.             if ( pszUser != NULL )
  755.             {
  756.                 AuthIdentity.User       = (unsigned char *) pszUser;
  757.                 AuthIdentity.UserLength = strlen( pszUser );
  758.             }
  759.  
  760.             if ( pszPassword != NULL )
  761.             {
  762.                 AuthIdentity.Password       = (unsigned char *) pszPassword;
  763.                 AuthIdentity.PasswordLength = strlen( pszPassword );
  764.             }
  765.  
  766.             if ( pszDomain != NULL )
  767.             {
  768.                 AuthIdentity.Domain       = (unsigned char *) pszDomain;
  769.                 AuthIdentity.DomainLength = strlen( pszDomain );
  770.             }
  771.  
  772.             AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  773.         }
  774.         else
  775.         {
  776.             pAuthIdentity = NULL;
  777.         }
  778.  
  779.         ss = sfProcs.pAcquireCredentialsHandle( NULL,    // New principal
  780.                                        pszPackage,       // Package name
  781.                                        SECPKG_CRED_OUTBOUND,
  782.                                        NULL,             // Logon ID
  783.                                        pAuthIdentity,    // Auth Data
  784.                                        NULL,             // Get key func
  785.                                        NULL,             // Get key arg
  786.                                        &pAS->_hcred,
  787.                                        &Lifetime );
  788.  
  789.         //
  790.         //  Need to determine the max token size for this package
  791.         //
  792.  
  793.         if ( ss == STATUS_SUCCESS )
  794.         {
  795.             pAS->_fHaveCredHandle = TRUE;
  796.             ss = sfProcs.pQuerySecurityPackageInfo( 
  797.                         (char *) pszPackage,
  798.                         &pspkg );
  799.         }
  800.  
  801.         if ( ss != STATUS_SUCCESS )
  802.         {
  803.             SetLastError( ss );
  804.             return FALSE;
  805.         }
  806.  
  807.         pAS->_cbMaxToken = pspkg->cbMaxToken;
  808.  
  809.         sfProcs.pFreeContextBuffer( pspkg );
  810.  
  811.     }
  812.  
  813.     //
  814.     //  Prepare our output buffer.  We use a temporary buffer because
  815.     //  the real output buffer will most likely need to be uuencoded
  816.     //
  817.  
  818.     if ( !BufferResize( &buff, pAS->_cbMaxToken ))
  819.     {
  820.         fSt = FALSE;
  821.         goto ex;
  822.     }
  823.  
  824.     OutBuffDesc.ulVersion = 0;
  825.     OutBuffDesc.cBuffers  = 1;
  826.     OutBuffDesc.pBuffers  = &OutSecBuff;
  827.  
  828.     OutSecBuff.cbBuffer   = pAS->_cbMaxToken;
  829.     OutSecBuff.BufferType = SECBUFFER_TOKEN;
  830.     OutSecBuff.pvBuffer   = BufferQueryPtr( &buff );
  831.  
  832.     //
  833.     //  Prepare our Input buffer - Note the server is expecting the client's
  834.     //  negotiation packet on the first call
  835.     //
  836.  
  837.     if ( pBuffIn )
  838.     {
  839.         InBuffDesc.ulVersion = 0;
  840.         InBuffDesc.cBuffers  = 1;
  841.         InBuffDesc.pBuffers  = &InSecBuff;
  842.  
  843.         InSecBuff.cbBuffer   = cbBuffIn;
  844.         InSecBuff.BufferType = SECBUFFER_TOKEN;
  845.         InSecBuff.pvBuffer   = pBuffIn;
  846.     }
  847.  
  848.     {
  849.         //
  850.         //  will return success when its done but we still
  851.         //  need to send the out buffer if there are bytes to send
  852.         //
  853.  
  854.         ss = sfProcs.pInitializeSecurityContext( 
  855.                                         &pAS->_hcred,
  856.                                         pAS->_fNewConversation ? NULL :
  857.                                                 &pAS->_hctxt,
  858.                                         TOKEN_SOURCE_NAME,
  859.                                         0,
  860.                                         0,
  861.                                         SECURITY_NATIVE_DREP,
  862.                                         pAS->_fNewConversation ? NULL :
  863.                                                 &InBuffDesc,
  864.                                         0,
  865.                                         &pAS->_hctxt,
  866.                                         &OutBuffDesc,
  867.                                         &ContextAttributes,
  868.                                         &Lifetime );
  869.     }
  870.  
  871.     if ( !SEC_SUCCESS( ss ) )
  872.     {
  873.         if ( ss == SEC_E_LOGON_DENIED )
  874.             ss = ERROR_LOGON_FAILURE;
  875.  
  876.         SetLastError( ss );
  877.         fSt = FALSE;
  878.         goto ex;
  879.     }
  880.  
  881.     pAS->_fHaveCtxtHandle = TRUE;
  882.  
  883.     //
  884.     //  Now we just need to complete the token (if requested) and prepare
  885.     //  it for shipping to the other side if needed
  886.     //
  887.  
  888.     fReply = !!OutSecBuff.cbBuffer;
  889.  
  890.     if ( (ss == SEC_I_COMPLETE_NEEDED) ||
  891.          (ss == SEC_I_COMPLETE_AND_CONTINUE) )
  892.     {
  893.         if ( sfProcs.pCompleteAuthToken != NULL )
  894.         {
  895.             ss = sfProcs.pCompleteAuthToken( &pAS->_hctxt,
  896.                                     &OutBuffDesc );
  897.  
  898.             if ( !SEC_SUCCESS( ss ))
  899.             {
  900.                 fSt = FALSE;
  901.                 goto ex;
  902.             }
  903.         }
  904.         else
  905.         {
  906.             // if not supported
  907.  
  908.             fSt = FALSE;
  909.             goto ex;
  910.         }
  911.     }
  912.  
  913.     //
  914.     //  Format or copy to the output buffer if we need to reply
  915.     //
  916.  
  917.     if ( fReply )
  918.     {
  919.         if ( pAS->_fUUEncodeData )
  920.         {
  921.             if ( !uuencode( (BYTE *) OutSecBuff.pvBuffer,
  922.                             OutSecBuff.cbBuffer,
  923.                             pbuffOut ))
  924.             {
  925.                 fSt = FALSE;
  926.                 goto ex;
  927.             }
  928.  
  929.             *pcbBuffOut = strlen( (CHAR *) BufferQueryPtr(pbuffOut) );
  930.         }
  931.         else
  932.         {
  933.             if ( !BufferResize( pbuffOut, OutSecBuff.cbBuffer ))
  934.             {
  935.                 fSt = FALSE;
  936.                 goto ex;
  937.             }
  938.  
  939.             memcpy( BufferQueryPtr(pbuffOut),
  940.                     OutSecBuff.pvBuffer,
  941.                     OutSecBuff.cbBuffer );
  942.  
  943.             *pcbBuffOut = OutSecBuff.cbBuffer;
  944.         }
  945.     }
  946.  
  947.     if ( pAS->_fNewConversation )
  948.         pAS->_fNewConversation = FALSE;
  949.  
  950.     *pfNeedMoreData = ((ss == SEC_I_CONTINUE_NEEDED) ||
  951.                        (ss == SEC_I_COMPLETE_AND_CONTINUE));
  952.  
  953.     fSt = TRUE;
  954.  
  955. ex:
  956.     BufferTerminate( &buffData );
  957.     BufferTerminate( &buff );
  958.  
  959.     return fSt;
  960. }
  961.  
  962.  
  963. BOOL CrackUserAndDomain(
  964.     CHAR *   pszDomainAndUser,
  965.     CHAR * * ppszUser,
  966.     CHAR * * ppszDomain
  967.     )
  968. /*++
  969.  
  970. Routine Description:
  971.  
  972.     Given a user name potentially in the form domain\user, zero terminates
  973.     the domain name and returns pointers to the domain name and the user name
  974.  
  975. Arguments:
  976.  
  977.     pszDomainAndUser - Pointer to user name or domain and user name
  978.     ppszUser - Receives pointer to user portion of name
  979.     ppszDomain - Receives pointer to domain portion of name
  980.  
  981. Return Value:
  982.  
  983.     TRUE if successful, FALSE otherwise (call GetLastError)
  984.  
  985. --*/
  986. {
  987.     static CHAR szDefaultDomain[MAX_COMPUTERNAME_LENGTH+1];
  988.     DWORD cbN;
  989.  
  990.     //
  991.     //  Crack the name into domain/user components.
  992.     //
  993.  
  994.     *ppszDomain = pszDomainAndUser;
  995.     *ppszUser   = strpbrk( pszDomainAndUser, "/\\" );
  996.  
  997.     if( *ppszUser == NULL )
  998.     {
  999.         //
  1000.         //  No domain name specified, just the username so we assume the
  1001.         //  user is on the local machine
  1002.         //
  1003.  
  1004.         if ( !*szDefaultDomain )
  1005.         {
  1006.             cbN = sizeof(szDefaultDomain);
  1007.             GetComputerName( szDefaultDomain, &cbN );
  1008.         }
  1009.  
  1010.         *ppszDomain = szDefaultDomain;
  1011.         *ppszUser   = pszDomainAndUser;
  1012.     }
  1013.     else
  1014.     {
  1015.         //
  1016.         //  Both domain & user specified, skip delimiter.
  1017.         //
  1018.  
  1019.         **ppszUser = '\0';
  1020.         (*ppszUser)++;
  1021.  
  1022.         if( ( **ppszUser == '\0' ) ||
  1023.             ( **ppszUser == '\\' ) ||
  1024.             ( **ppszUser == '/' ) )
  1025.         {
  1026.             //
  1027.             //  Name is of one of the following (invalid) forms:
  1028.             //
  1029.             //      "domain\"
  1030.             //      "domain\\..."
  1031.             //      "domain/..."
  1032.             //
  1033.  
  1034.             SetLastError( ERROR_INVALID_PARAMETER );
  1035.             return FALSE;
  1036.         }
  1037.     }
  1038.  
  1039.     return TRUE;
  1040. }
  1041.  
  1042.  
  1043. /************************************************************
  1044.  *    uuencode/decode functions
  1045.  ************************************************************/
  1046.  
  1047. //
  1048. //  Taken from NCSA HTTP and wwwlib.
  1049. //
  1050. //  NOTE: These conform to RFC1113, which is slightly different then the Unix
  1051. //        uuencode and uudecode!
  1052. //
  1053.  
  1054. const int pr2six[256]={
  1055.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1056.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  1057.     52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  1058.     10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  1059.     28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  1060.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1061.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1062.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1063.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1064.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1065.     64,64,64,64,64,64,64,64,64,64,64,64,64
  1066. };
  1067.  
  1068. char six2pr[64] = {
  1069.     'A','B','C','D','E','F','G','H','I','J','K','L','M',
  1070.     'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  1071.     'a','b','c','d','e','f','g','h','i','j','k','l','m',
  1072.     'n','o','p','q','r','s','t','u','v','w','x','y','z',
  1073.     '0','1','2','3','4','5','6','7','8','9','+','/'
  1074. };
  1075.  
  1076.  
  1077. BOOL 
  1078. uudecode(
  1079.     char   * bufcoded,
  1080.     BUFFER * pbuffdecoded,
  1081.     DWORD  * pcbDecoded )
  1082. /*++
  1083.  
  1084.  Routine Description:
  1085.  
  1086.     uudecode a string of data
  1087.  
  1088.  Arguments:
  1089.  
  1090.     bufcoded            pointer to uuencoded data
  1091.     pbuffdecoded        pointer to output BUFFER structure
  1092.     pcbDecoded          number of decode bytes
  1093.  
  1094.  Return Value:
  1095.  
  1096.     Returns TRUE is successful; otherwise FALSE is returned.
  1097.  
  1098. --*/
  1099. {
  1100.     int nbytesdecoded;
  1101.     char *bufin = bufcoded;
  1102.     unsigned char *bufout;
  1103.     int nprbytes;
  1104.  
  1105.     /* Strip leading whitespace. */
  1106.  
  1107.     while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
  1108.  
  1109.     /* Figure out how many characters are in the input buffer.
  1110.      * If this would decode into more bytes than would fit into
  1111.      * the output buffer, adjust the number of input bytes downwards.
  1112.      */
  1113.     bufin = bufcoded;
  1114.     while(pr2six[*(bufin++)] <= 63);
  1115.     nprbytes = bufin - bufcoded - 1;
  1116.     nbytesdecoded = ((nprbytes+3)/4) * 3;
  1117.  
  1118.     if ( !BufferResize( pbuffdecoded, nbytesdecoded + 4 ))
  1119.         return FALSE;
  1120.  
  1121.     if ( pcbDecoded )
  1122.         *pcbDecoded = nbytesdecoded;
  1123.  
  1124.     bufout = (unsigned char *) BufferQueryPtr(pbuffdecoded);
  1125.  
  1126.     bufin = bufcoded;
  1127.  
  1128.     while (nprbytes > 0) {
  1129.         *(bufout++) =
  1130.             (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  1131.         *(bufout++) =
  1132.             (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  1133.         *(bufout++) =
  1134.             (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  1135.         bufin += 4;
  1136.         nprbytes -= 4;
  1137.     }
  1138.  
  1139.     if(nprbytes & 03) {
  1140.         if(pr2six[bufin[-2]] > 63)
  1141.             nbytesdecoded -= 2;
  1142.         else
  1143.             nbytesdecoded -= 1;
  1144.     }
  1145.  
  1146.     ((CHAR *)BufferQueryPtr(pbuffdecoded))[nbytesdecoded] = '\0';
  1147.  
  1148.     return TRUE;
  1149. }
  1150.  
  1151.  
  1152. BOOL 
  1153. uuencode( 
  1154.     BYTE *   bufin,
  1155.     DWORD    nbytes,
  1156.     BUFFER * pbuffEncoded )
  1157. /*++
  1158.  
  1159.  Routine Description:
  1160.  
  1161.     uuencode a string of data
  1162.  
  1163.  Arguments:
  1164.  
  1165.     bufin           pointer to data to encode
  1166.     nbytes          number of bytes to encode
  1167.     pbuffEncoded    pointer to output BUFFER structure
  1168.  
  1169.  Return Value:
  1170.  
  1171.     Returns TRUE is successful; otherwise FALSE is returned.
  1172.  
  1173. --*/
  1174. {
  1175.    unsigned char *outptr;
  1176.    unsigned int i;
  1177.  
  1178.    //
  1179.    //  Resize the buffer to 133% of the incoming data
  1180.    //
  1181.  
  1182.    if ( !BufferResize( pbuffEncoded, nbytes + ((nbytes + 3) / 3) + 4))
  1183.         return FALSE;
  1184.  
  1185.    outptr = (unsigned char *) BufferQueryPtr(pbuffEncoded);
  1186.  
  1187.    for (i=0; i<nbytes; i += 3) {
  1188.       *(outptr++) = six2pr[*bufin >> 2];            /* c1 */
  1189.       *(outptr++) = six2pr[((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)]; /*c2*/
  1190.       *(outptr++) = six2pr[((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)];/*c3*/
  1191.       *(outptr++) = six2pr[bufin[2] & 077];         /* c4 */
  1192.  
  1193.       bufin += 3;
  1194.    }
  1195.  
  1196.    /* If nbytes was not a multiple of 3, then we have encoded too
  1197.     * many characters.  Adjust appropriately.
  1198.     */
  1199.    if(i == nbytes+1) {
  1200.       /* There were only 2 bytes in that last group */
  1201.       outptr[-1] = '=';
  1202.    } else if(i == nbytes+2) {
  1203.       /* There was only 1 byte in that last group */
  1204.       outptr[-1] = '=';
  1205.       outptr[-2] = '=';
  1206.    }
  1207.  
  1208.    *outptr = '\0';
  1209.  
  1210.    return TRUE;
  1211. }
  1212.