text: /*+-----------------------------------------------------------------------
  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 MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.
  
  Copyright (C) 1992 - 2000.  Microsoft Corporation.  All rights reserved.
  
  File:        stubs.c
  
  Contents:    user-mode stubs for security API
  
  
  ------------------------------------------------------------------------*/
  #define _NO_KSECDD_IMPORT_
  #include "sampssp.h"
  
  
  SecurityFunctionTableW SecTableW = {SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
                                      EnumerateSecurityPackagesW,
                                      NULL,
                                      AcquireCredentialsHandleW,
                                      FreeCredentialsHandle,
                                      NULL, // LogonUser
                                      InitializeSecurityContextW,
                                      AcceptSecurityContext,
                                      CompleteAuthToken,
                                      DeleteSecurityContext,
                                      ApplyControlToken,
                                      QueryContextAttributesW,
                                      ImpersonateSecurityContext,
                                      RevertSecurityContext,
                                      MakeSignature,
                                      VerifySignature,
                                      FreeContextBuffer,
                                      QuerySecurityPackageInfoW
                                     };
  
  
  PSEC_CONTEXT ContextList;
  PCREDENTIAL CredentialList;
  ULONG NextId;
  TimeStamp Forever = {0x7fffffff,0xfffffff};
  TimeStamp Never = {0,0};
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   LocateContext
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  PSEC_CONTEXT
  LocateContext(ULONG ContextId)
  {
      PSEC_CONTEXT TestContext;
      EnterCriticalSection(&DllCritSect);
  
      TestContext = ContextList;
      while (TestContext != NULL)
      {
          if (TestContext->ContextId == ContextId)
          {
              break;
          }
          TestContext = TestContext->Next;
      }
      LeaveCriticalSection(&DllCritSect);
      return(TestContext);
  
  }
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   DeleteContext
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  BOOLEAN
  DeleteContext(ULONG ContextId)
  {
      PSEC_CONTEXT TestContext, LastContext;
  
      EnterCriticalSection(&DllCritSect);
      TestContext = ContextList;
      LastContext = NULL;
  
      while (TestContext != NULL)
      {
          if (TestContext->ContextId == ContextId)
          {
              break;
          }
          LastContext = TestContext;
          TestContext = TestContext->Next;
      }
      if (TestContext != NULL)
      {
          if (LastContext != NULL)
          {
              LastContext->Next = TestContext->Next;
          }
          else
          {
              assert(ContextList == TestContext);
              ContextList = TestContext->Next;
          }
          LocalFree(TestContext);
      }
      LeaveCriticalSection(&DllCritSect);
      return( TestContext == NULL ? FALSE : TRUE );
  }
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   AddContext
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  VOID
  AddContext(PSEC_CONTEXT Context)
  {
      EnterCriticalSection(&DllCritSect);
      Context->Next = ContextList;
      ContextList = Context;
      LeaveCriticalSection(&DllCritSect);
  }
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   InitSecurityInterfaceW
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  
  PCREDENTIAL
  LocateCredential(ULONG CredentialId)
  {
      PCREDENTIAL TestCredential;
      EnterCriticalSection(&DllCritSect);
  
      TestCredential = CredentialList;
      while (TestCredential != NULL)
      {
          if (TestCredential->CredentialId == CredentialId)
          {
              break;
          }
          TestCredential = TestCredential->Next;
      }
      LeaveCriticalSection(&DllCritSect);
      return(TestCredential);
  
  }
  
  BOOLEAN
  DeleteCredential(ULONG CredentialId)
  {
      PCREDENTIAL TestCredential, LastCredential;
  
      EnterCriticalSection(&DllCritSect);
      TestCredential = CredentialList;
      LastCredential = NULL;
  
      while (TestCredential != NULL)
      {
          if (TestCredential->CredentialId == CredentialId)
          {
              break;
          }
          LastCredential = TestCredential;
          TestCredential = TestCredential->Next;
      }
      if (TestCredential != NULL)
      {
          if (LastCredential != NULL)
          {
              LastCredential->Next = TestCredential->Next;
          }
          else
          {
              assert(CredentialList == TestCredential);
              CredentialList = TestCredential->Next;
          }
          LocalFree(TestCredential);
      }
      LeaveCriticalSection(&DllCritSect);
      return( TestCredential == NULL ? FALSE : TRUE );
  }
  
  VOID
  AddCredential(PCREDENTIAL Credential)
  {
      EnterCriticalSection(&DllCritSect);
      Credential->Next = CredentialList;
      CredentialList = Credential;
      LeaveCriticalSection(&DllCritSect);
  }
  
  ULONG
  GetNewId()
  {
      ULONG NewId;
  
      EnterCriticalSection(&DllCritSect);
      NewId = NextId;
      NextId ++;
      LeaveCriticalSection(&DllCritSect);
      return(NewId);
  
  }
  
  PSecBuffer
  LocateBuffer(PSecBufferDesc Buffer, ULONG MinimumSize)
  {
      ULONG Index;
      if (Buffer == NULL)
      {
          return(NULL);
      }
  
      for (Index = 0; Index < Buffer->cBuffers  ; Index++)
      {
          if (((Buffer->pBuffers[Index].BufferType) & ~SECBUFFER_ATTRMASK)
              == SECBUFFER_TOKEN)
          {
  
              //
              // Do size checking
              //
  
              if (Buffer->pBuffers[Index].cbBuffer < MinimumSize)
              {
                  return(NULL);
              }
              return(&Buffer->pBuffers[Index]);
          }
      }
      return(NULL);
  }
  
  
  
  PSecBuffer
  LocateSecBuffer(PSecBufferDesc Buffer)
  {
      return(LocateBuffer(Buffer, sizeof(MESSAGE)));
  }
  
  
  PSecBuffer
  LocateSigBuffer(PSecBufferDesc Buffer)
  {
      return(LocateBuffer(Buffer, sizeof(SIGNATURE)));
  }
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   InitSecurityInterfaceW
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  PSecurityFunctionTableW SEC_ENTRY
  InitSecurityInterfaceW(VOID)
  {
      InitializeCriticalSection( &DllCritSect );
      return(&SecTableW);
  }
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   AcquireCredentialsHandleW
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  
  SECURITY_STATUS SEC_ENTRY
  AcquireCredentialsHandleW(
      LPWSTR                      pszPrincipal,       // Name of principal
      LPWSTR                      pszPackageName,     // Name of package
      unsigned long               fCredentialUse,     // Flags indicating use
      void SEC_FAR *              pvLogonId,          // Pointer to logon ID
      void SEC_FAR *              pAuthData,          // Package specific data
      SEC_GET_KEY_FN              pGetKeyFn,          // Pointer to GetKey() func
      void SEC_FAR *              pvGetKeyArgument,   // Value to pass to GetKey()
      PCredHandle                 phCredential,       // (out) Cred Handle
      PTimeStamp                  ptsExpiry           // (out) Lifetime (optional)
      )
  {
      PCREDENTIAL NewCredential = NULL;
  
      if ((fCredentialUse & (SECPKG_CRED_BOTH)) == 0)
      {
          return(SEC_E_UNKNOWN_CREDENTIALS);
      }
      NewCredential = (PCREDENTIAL) LocalAlloc(0,sizeof(CREDENTIAL));
      if (NewCredential == NULL)
      {
          return(SEC_E_INSUFFICIENT_MEMORY);
      }
      NewCredential->CredentialId = GetNewId();
      NewCredential->Use = fCredentialUse;
      NewCredential->AuthData = (ULONG *)pAuthData;
      phCredential->dwUpper = NewCredential->CredentialId;
      *ptsExpiry = Forever;
      AddCredential(NewCredential);
      return(SEC_E_OK);
  
  }
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   FreeCredentialsHandle
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  FreeCredentialsHandle(
      PCredHandle                 phCredential        // Handle to free
      )
  {
      if (DeleteCredential(phCredential->dwUpper))
      {
          return(SEC_E_OK);
      }
      else
      {
          return(SEC_E_UNKNOWN_CREDENTIALS);
      }
  }
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   InitializeSecurityContextW
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  InitializeSecurityContextW(
      PCredHandle                 phCredential,       // Cred to base context
      PCtxtHandle                 phContext,          // Existing context (OPT)
      LPWSTR                      pszTargetName,      // Name of target
      unsigned long               fContextReq,        // Context Requirements
      unsigned long               Reserved1,          // Reserved, MBZ
      unsigned long               TargetDataRep,      // Data rep of target
      PSecBufferDesc              pInput,             // Input Buffers
      unsigned long               Reserved2,          // Reserved, MBZ
      PCtxtHandle                 phNewContext,       // (out) New Context handle
      PSecBufferDesc              pOutput,            // (inout) Output Buffers
      unsigned long SEC_FAR *     pfContextAttr,      // (out) Context attrs
      PTimeStamp                  ptsExpiry           // (out) Life span (OPT)
      )
  {
      PCREDENTIAL Credential = NULL;
      PSEC_CONTEXT Context = NULL;
      PMESSAGE Message = NULL;
      PSecBuffer OutputBuffer;
      PSecBuffer InputBuffer;
      MESSAGE SampleMessage;
  
  
      if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
      {
          return(SEC_E_INSUFFICIENT_MEMORY);
      }
  
      OutputBuffer = LocateSecBuffer(pOutput);
      if (OutputBuffer == NULL)
      {
          return(SEC_E_INVALID_TOKEN);
      }
  
      if (phContext == NULL)
      {
  
          Credential = LocateCredential(phCredential->dwUpper);
          if (Credential == NULL)
          {
              return(SEC_E_UNKNOWN_CREDENTIALS);
          }
  
          if ((Credential->Use & SECPKG_CRED_OUTBOUND) == 0)
          {
              return(SEC_E_UNKNOWN_CREDENTIALS);
          }
  
      }
  
      //
      // If the context is NULL, create a new one.
      //
  
      if (phContext == NULL)
      {
          Context = (PSEC_CONTEXT) LocalAlloc(0,sizeof(SEC_CONTEXT));
          if (Context == NULL)
          {
              return(SEC_E_INSUFFICIENT_MEMORY);
          }
          Context->ContextId = GetNewId();
          phNewContext->dwUpper = Context->ContextId;
          Context->CredentialId = phCredential->dwUpper;
          Context->State = FirstInit;
          Context->Nonce = 0;
          Context->ContextFlags = fContextReq;
          *pfContextAttr = fContextReq;
          *ptsExpiry = Forever;
  
          //
          // Build an output token.
          //
  
          Message = (PMESSAGE) OutputBuffer->pvBuffer;
          Message->MessageType = Negotiate;
          memset(Message->Buffer,'x',MESSAGE_SIZE);
          OutputBuffer->cbBuffer = sizeof(MESSAGE);
  
          AddContext(Context);
  
          return(SEC_I_CONTINUE_NEEDED);
  
      } else {
          //
          // This is the second call. Lookup the old context.
          //
  
          Context = LocateContext(phContext->dwUpper);
          if (Context == NULL)
          {
              return(SEC_E_INVALID_HANDLE);
          }
  
          if ((Context->State != FirstInit) &&
              (Context->State != SecondInit))
          {
              return(SEC_E_INVALID_HANDLE);
          }
  
  
          //
          // Build the new output message
          //
  
          if (Context->State == FirstInit)
          {
  
              //
              // Check that the input message is what we expected.
              //
  
              InputBuffer = LocateSecBuffer(pInput);
              if (InputBuffer == NULL)
              {
                  return(SEC_E_INVALID_TOKEN);
              }
              Message = (PMESSAGE) InputBuffer->pvBuffer;
  
              SampleMessage.MessageType = Challenge;
              memset(SampleMessage.Buffer, 'y', MESSAGE_SIZE);
  
              if (memcmp(&SampleMessage,Message,MESSAGE_SIZE) != 0)
              {
                  return(SEC_E_INVALID_TOKEN);
              }
  
              Message = (PMESSAGE) OutputBuffer->pvBuffer;
              Message->MessageType = ChallengeResponse;
              memset(Message->Buffer,'z',MESSAGE_SIZE);
          }
          else
          {
              Message = (PMESSAGE) OutputBuffer->pvBuffer;
              Message->MessageType = ReAuthenticate;
              memset(Message->Buffer,'q',MESSAGE_SIZE);
          }
  
          OutputBuffer->cbBuffer = sizeof(MESSAGE);
          Context->State = SecondInit;
          return(SEC_E_OK);
      }
  }
  
  
  
  //+------------------------------------------- ------------------------------
  //
  //  Function:   AcceptSecurityContext
  //
  //  Synopsis:   Allows a remotely initiated security context between the
  //              application and a remote peer to be established.  To complete
  //              the establishment of context one or more reply tokens may be
  //              required from remote peer.
  //              This function is the server counterpart to the
  //              InitializeSecurityContext API.  The ContextAttributes is a bit
  //              mask representing various context level functions such as
  //              delegation, mutual authentication, confidentiality, replay
  //              detection and sequence detection.  This API is used by the
  //              server side.  When a request comes in, the server uses the
  //              ContextReqFlags parameter to specify what it requires of the
  //              session.  In this fashion, a server can specify that clients
  //              must be capable of using a confidential or integrity checked
  //              session, and fail clients that can't meet that demand.
  //              Alternatively, a server can require nothing, and whatever the
  //              client can provide or requires is returned in the
  //              pfContextAttributes parameter.  For a package that supports 3
  //              leg mutual authentication, the calling sequence would be:
  //              Client provides a token, server calls Accept the first time,
  //              generating a reply token.  The client uses this in a second
  //              call to InitializeSecurityContext, and generates a final token.
  //              This token is then used in the final call to Accept to complete
  //              the session.  Another example would be the LAN Manager/NT
  //              authentication style.  The client connects to negotiate a
  //              protocol.  The server calls Accept to set up a context and
  //              generate a challenge to the client.  The client calls
  //              InitializeSecurityContext and creates a response.  The server
  //              then calls Accept the final time to allow the package to verify
  //              the response is appropriate for the challenge.
  //
  //  Effects:
  //
  //
  //  Arguments:  [phCredential] - Handle to the credentials to be used to
  //              create the context.
  //
  //              [phContext] - Handle to the partially formed context, if
  //              this is a second call (see above) or NULL if this is the first call.
  //
  //              [pInput] - Pointer to the input token.  In the first call
  //              this token can either be NULL or may contain
  //              security package specific information.
  //
  //              [fContextReq] - Requirements of the context, package specific. See
  //              the ASC_REQ_xxx defines in SSPI.H.
  //
  //              [TargetDataRep] - Long indicating the data representation (byte
  //              ordering, etc) on the target.  The constant
  //              SECURITY_NATIVE_DREP may be supplied by the
  //              transport indicating that the native format
  //              is in use.
  //
  //              [phNewContext] - New context handle.  If this is a second
  //              call, this can be same as OldContextHandle.
  //
  //              [pOutput] - Buffer to receive the output token.
  //
  //              [pfContextAttr] - Attributes of the context established. See
  //              the ASC_RET_xxx defines in SSPI.H
  //
  //              [ptsExpiry] - Expiration time of the context.
  //
  //  Requires:
  //
  //  Returns:    STATUS_SUCCESS - Message handled
  //              SEC_I_CALLBACK_NEEDED - Caller should call again later
  //              SEC_E_NO_SPM - Security Support Provider is not running
  //              SEC_E_INVALID_TOKEN - Token improperly formatted
  //              SEC_E_INVALID_HANDLE - Credential/Context Handle is invalid
  //              SEC_E_BUFFER_TOO_SMALL- Buffer for output token isn't big enough
  //              SEC_E_LOGON_DENIED - User is no allowed to logon to this server
  //              SEC_E_INSUFFICIENT_MEMORY - Not enough memory
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  AcceptSecurityContext(
      PCredHandle                 phCredential,       // Cred to base context
      PCtxtHandle                 phContext,          // Existing context (OPT)
      PSecBufferDesc              pInput,             // Input buffer
      unsigned long               fContextReq,        // Context Requirements
      unsigned long               TargetDataRep,      // Target Data Rep
      PCtxtHandle                 phNewContext,       // (out) New context handle
      PSecBufferDesc              pOutput,            // (inout) Output buffers
      unsigned long SEC_FAR *     pfContextAttr,      // (out) Context attributes
      PTimeStamp                  ptsExpiry           // (out) Life span (OPT)
      )
  {
      PCREDENTIAL Credential = NULL;
      PSEC_CONTEXT Context = NULL;
      PMESSAGE Message = NULL;
      PSecBuffer OutputBuffer;
      PSecBuffer InputBuffer;
      MESSAGE SampleMessage;
  
  
      if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
      {
          return(SEC_E_INSUFFICIENT_MEMORY);
      }
  
      InputBuffer = LocateSecBuffer(pInput);
      if (InputBuffer == NULL)
      {
          return(SEC_E_INVALID_TOKEN);
      }
  
      if (phContext == NULL)
      {
  
          Credential = LocateCredential(phCredential->dwUpper);
          if (Credential == NULL)
          {
              return(SEC_E_UNKNOWN_CREDENTIALS);
          }
  
          if ((Credential->Use & SECPKG_CRED_INBOUND) == 0)
          {
              return(SEC_E_UNKNOWN_CREDENTIALS);
          }
  
      }
  
      //
      // If the context is NULL, create a new one.
      //
  
      if (phContext == NULL)
      {
          //
          // Make sure the output buffer exists.
          //
  
          OutputBuffer = LocateSecBuffer(pOutput);
          if (OutputBuffer == NULL)
          {
              return(SEC_E_INVALID_TOKEN);
          }
  
  
  
          //
          // Check that the input message is what we expected.
          //
  
          Message = (PMESSAGE) InputBuffer->pvBuffer;
          SampleMessage.MessageType = Negotiate;
          memset(SampleMessage.Buffer, 'x', MESSAGE_SIZE);
  
          if (memcmp(&SampleMessage,Message,MESSAGE_SIZE) != 0)
          {
              return(SEC_E_INVALID_TOKEN);
          }
  
          //
          // Build a new context.
          //
  
          Context = (PSEC_CONTEXT) LocalAlloc(0,sizeof(SEC_CONTEXT));
          if (Context == NULL)
          {
              return(SEC_E_INSUFFICIENT_MEMORY);
          }
          Context->ContextId = GetNewId();
          phNewContext->dwUpper = Context->ContextId;
          Context->CredentialId = phCredential->dwUpper;
          Context->State = FirstAccept;
          Context->Nonce = 0;
          Context->ContextFlags = fContextReq;
          *pfContextAttr = fContextReq;
          *ptsExpiry = Forever;
  
          //
          // Build an output token.
          //
  
          Message = (PMESSAGE) OutputBuffer->pvBuffer;
          Message->MessageType = Challenge;
          memset(Message->Buffer,'y',MESSAGE_SIZE);
          OutputBuffer->cbBuffer = sizeof(MESSAGE);
  
          AddContext(Context);
  
          return(SEC_I_CONTINUE_NEEDED);
  
      } else {
          //
          // This is the second call. Lookup the old context.
          //
  
          Context = LocateContext(phContext->dwUpper);
          if (Context == NULL)
          {
              return(SEC_E_INVALID_HANDLE);
          }
          if ((Context->State != FirstAccept) &&
              (Context->State != SecondAccept))
          {
              return(SEC_E_INVALID_HANDLE);
          }
  
          Message = (PMESSAGE) InputBuffer->pvBuffer;
  
          //
          // Check that the input message is what we expected.
          //
  
          if (Context->State == FirstAccept)
          {
              SampleMessage.MessageType = ChallengeResponse;
              memset(SampleMessage.Buffer, 'z', MESSAGE_SIZE);
          }
          else
          {
              SampleMessage.MessageType = ReAuthenticate;
              memset(SampleMessage.Buffer, 'q', MESSAGE_SIZE);
          }
  
          if (memcmp(&SampleMessage,Message,MESSAGE_SIZE) != 0)
          {
              return(SEC_E_INVALID_TOKEN);
          }
  
          Context->State = SecondAccept;
          return(SEC_E_OK);
      }
  }
  
  
  
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   DeleteSecurityContext
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  DeleteSecurityContext(
      PCtxtHandle                 phContext           // Context to delete
      )
  {
      if (DeleteContext(phContext->dwUpper))
      {
          return(SEC_E_OK);
      }
      else
      {
          return(SEC_E_INVALID_HANDLE);
      }
  }
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   ApplyControlToken
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  ApplyControlToken(
      PCtxtHandle                 phContext,          // Context to modify
      PSecBufferDesc              pInput              // Input token to apply
      )
  {
      return(SEC_E_UNSUPPORTED_FUNCTION);
  
  }
  
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   EnumerateSecurityPackagesW
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  
  SECURITY_STATUS SEC_ENTRY
  EnumerateSecurityPackagesW(
      unsigned long SEC_FAR *     pcPackages,         // Receives num. packages
      PSecPkgInfoW SEC_FAR *      ppPackageInfo       // Receives array of info
      )
  {
      SECURITY_STATUS SecStatus;
  
      SecStatus = QuerySecurityPackageInfoW(
                      PACKAGE_NAME,
                      ppPackageInfo
                      );
      if (SecStatus == SEC_E_OK)
      {
          *pcPackages = 1;
      }
  
      return(SecStatus);
  }
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   QuerySecurityPackageInfoW
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  QuerySecurityPackageInfoW(
      LPWSTR                      pszPackageName,     // Name of package
      PSecPkgInfoW SEC_FAR *      ppPackageInfo        // Receives package info
      )
  {
      PSecPkgInfoW PackageInfo;
      ULONG PackageInfoSize;
      PUCHAR Where;
  
      if (_wcsicmp(pszPackageName, PACKAGE_NAME))
      {
          return(SEC_E_SECPKG_NOT_FOUND);
      }
  
      PackageInfoSize = sizeof(SecPkgInfoW) +
                          (wcslen(PACKAGE_NAME) + 1 +
                           wcslen(PACKAGE_COMMENT) + 1) * sizeof(WCHAR);
  
      PackageInfo = (PSecPkgInfoW) LocalAlloc(0,PackageInfoSize);
      if (PackageInfo == NULL)
      {
          return(SEC_E_INSUFFICIENT_MEMORY);
      }
      PackageInfo->fCapabilities = PACKAGE_CAPABILITIES;
      PackageInfo->wVersion = PACKAGE_VERSION;
      PackageInfo->wRPCID = PACKAGE_RPCID;
      PackageInfo->cbMaxToken = PACKAGE_MAXTOKEN;
  
      Where = (PUCHAR) (PackageInfo + 1);
      PackageInfo->Name = (LPWSTR) Where;
      Where += (wcslen(PACKAGE_NAME) + 1) * sizeof(WCHAR);
      RtlCopyMemory(PackageInfo->Name, PACKAGE_NAME, sizeof(PACKAGE_NAME));
  
      PackageInfo->Comment = (LPWSTR) Where;
      Where += (wcslen(PACKAGE_COMMENT) + 1) * sizeof(WCHAR);
      RtlCopyMemory(PackageInfo->Comment, PACKAGE_COMMENT, sizeof(PACKAGE_COMMENT));
  
      assert(Where - (PBYTE) PackageInfo == (LONG) PackageInfoSize);
  
      *ppPackageInfo = PackageInfo;
      return(SEC_E_OK);
  }
  
  
  
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   FreeContextBuffer
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  SECURITY_STATUS SEC_ENTRY
  FreeContextBuffer(
      void SEC_FAR *      pvContextBuffer
      )
  {
      LocalFree(pvContextBuffer);
      return(SEC_E_OK);
  }
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   CompleteAuthToken
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  
  SECURITY_STATUS SEC_ENTRY
  CompleteAuthToken(
      PCtxtHandle                 phContext,          // Context to complete
      PSecBufferDesc              pToken              // Token to complete
      )
  {
  
      return(SEC_E_OK);
  
  }
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   ImpersonateSecurityContext
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  ImpersonateSecurityContext(
      PCtxtHandle                 phContext           // Context to impersonate
      )
  {
      return(SEC_E_OK);
  }
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   RevertSecurityContext
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  SECURITY_STATUS SEC_ENTRY
  RevertSecurityContext(
      PCtxtHandle                 phContext           // Context from which to re
      )
  {
      return(SEC_E_OK);
  }
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   QueryContextAttributes
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  
  SECURITY_STATUS SEC_ENTRY
  QueryContextAttributesW(
      PCtxtHandle                 phContext,          // Context to query
      unsigned long               ulAttribute,        // Attribute to query
      void SEC_FAR *              pBuffer             // Buffer for attributes
      )
  {
      PSEC_CONTEXT Context;
      PSecPkgContext_Sizes ContextSizes;
      PSecPkgContext_NamesW ContextNames;
      PSecPkgContext_Lifespan ContextLifespan;
      PSecPkgContext_DceInfo  ContextDceInfo;
  
      Context = LocateContext(phContext->dwUpper);
  
      if (Context == NULL)
      {
          return(SEC_E_INVALID_HANDLE);
      }
  
      switch(ulAttribute) {
      case SECPKG_ATTR_SIZES:
          ContextSizes = (PSecPkgContext_Sizes) pBuffer;
          ContextSizes->cbMaxSignature = PACKAGE_SIGNATURE_SIZE;
          if ((Context->ContextFlags & ISC_REQ_CONFIDENTIALITY) != 0)
          {
              ContextSizes->cbSecurityTrailer = PACKAGE_SIGNATURE_SIZE;
              ContextSizes->cbBlockSize = 1;
          }
          else
          {
              ContextSizes->cbSecurityTrailer = 0;
              ContextSizes->cbBlockSize = 0;
          }
          ContextSizes->cbMaxToken = PACKAGE_MAXTOKEN;
          break;
      case SECPKG_ATTR_NAMES:
          ContextNames = (PSecPkgContext_Names) pBuffer;
          ContextNames->sUserName = (LPWSTR) LocalAlloc(0, sizeof(L"dummy user"));
          if (ContextNames->sUserName == NULL)
          {
              return(SEC_E_INSUFFICIENT_MEMORY);
          }
          RtlCopyMemory(ContextNames->sUserName, L"dummy user", sizeof(L"dummy user"));
          break;
      case SECPKG_ATTR_LIFESPAN:
          ContextLifespan = (PSecPkgContext_Lifespan) pBuffer;
          ContextLifespan->tsStart = Never;
          ContextLifespan->tsExpiry = Forever;
          break;
      case SECPKG_ATTR_DCE_INFO:
          ContextDceInfo = (PSecPkgContext_DceInfo) pBuffer;
          ContextDceInfo->AuthzSvc = 0;
          ContextDceInfo->pPac = (PVOID) LocalAlloc(0,sizeof(L"dummy user"));
          if (ContextDceInfo->pPac == NULL)
          {
              return(SEC_E_INSUFFICIENT_MEMORY);
          }
          RtlCopyMemory((LPWSTR) ContextDceInfo->pPac, L"dummy user", sizeof(L"dummy user"));
  
          break;
      default:
          return(SEC_E_INVALID_TOKEN);
      }
  
      return(SEC_E_OK);
  }
  
  #if 0
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   QueryCredentialsAttributes
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //
  //--------------------------------------------------------------------------
  
  
  
  SECURITY_STATUS SEC_ENTRY
  QueryCredentialsAttributesW(
      PCredHandle                 phCredentials,      // Credentials to query
      unsigned long               ulAttribute,        // Attribute to query
      void SEC_FAR *              pBuffer             // Buffer for attributes
      )
  {
      return( pspPackages[phCredentials->dwLower].pftTableW->QueryCredentialsAttributesW(
                                          phCredentials,
                                          ulAttribute,
                                          pBuffer ) );
  }
  
  #endif
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   MakeSignature
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:  [phContext]     -- context to use
  //              [fQOP]          -- quality of protection to use
  //              [pMessage]      -- message
  //              [MessageSeqNo]  -- sequence number of message
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //--------------------------------------------------------------------------
  SECURITY_STATUS SEC_ENTRY
  MakeSignature(  PCtxtHandle         phContext,
                  ULONG               fQOP,
                  PSecBufferDesc      pMessage,
                  ULONG               MessageSeqNo)
  {
      PSEC_CONTEXT Context;
      PSecBuffer SignatureBuffer;
      PSIGNATURE Signature;
  
      Context = LocateContext(phContext->dwUpper);
      if (Context == NULL)
      {
          return(SEC_E_INVALID_HANDLE);
      }
  
      SignatureBuffer = LocateSigBuffer(pMessage);
      if (SignatureBuffer == NULL)
      {
          return(SEC_E_INVALID_TOKEN);
      }
      Signature = (PSIGNATURE) SignatureBuffer->pvBuffer;
      Signature->MessageId = Context->Nonce++;
      Signature->Tag = PACKAGE_SIGNATURE_TAG;
      SignatureBuffer->cbBuffer = sizeof(SIGNATURE);
      return(SEC_E_OK);
  }
  
  
  
  //+-------------------------------------------------------------------------
  //
  //  Function:   VerifySignature
  //
  //  Synopsis:
  //
  //  Effects:
  //
  //  Arguments:  [phContext]     -- Context performing the unseal
  //              [pMessage]      -- Message to verify
  //              [MessageSeqNo]  -- Sequence number of this message
  //              [pfQOPUsed]     -- quality of protection used
  //
  //  Requires:
  //
  //  Returns:
  //
  //  Notes:
  //
  //--------------------------------------------------------------------------
  SECURITY_STATUS SEC_ENTRY
  VerifySignature(PCtxtHandle     phContext,
                  PSecBufferDesc  pMessage,
                  ULONG           MessageSeqNo,
                  ULONG *         pfQOP)
  {
      PSEC_CONTEXT Context;
      PSecBuffer SignatureBuffer;
      PSIGNATURE Signature;
  
      Context = LocateContext(phContext->dwUpper);
      if (Context == NULL)
      {
          return(SEC_E_INVALID_HANDLE);
      }
  
      SignatureBuffer = LocateSigBuffer(pMessage);
      if (SignatureBuffer == NULL)
      {
          return(SEC_E_INVALID_TOKEN);
      }
      Signature = (PSIGNATURE) SignatureBuffer->pvBuffer;
  
      if (Signature->Tag != PACKAGE_SIGNATURE_TAG)
      {
          return(SEC_E_MESSAGE_ALTERED);
      }
  
      if (Signature->MessageId != Context->Nonce++)
      {
          Context->State = Idle;
          return(SEC_E_OUT_OF_SEQUENCE);
      }
  
      return(SEC_E_OK);
  }
  
  
  
  
  
  