Platform SDK: Logon Authentication

Using AcceptSecurityContext

The AcceptSecurityContext function enables the server to establish a security context between the server and a remote client. The remote client uses the InitializeSecurityContext function to start the process of establishing a security context. The server might need one or more reply tokens from the remote client to completely establish the security context.

TimeStamp       tsExpiry;
SECURITY_STATUS scRet;
SecBufferDesc   InBuffer;
SecBuffer       InBuffers[2];
SecBufferDesc   OutBuffer;
SecBuffer       OutBuffers[1];
BOOL            fInitContext = TRUE;
DWORD           dwSSPIFlags
DWORD           dwSSPIOutFlags;

dwSSPIFlags =   ASC_REQ_SEQUENCE_DETECT  |
                ASC_REQ_REPLAY_DETECT    |
                ASC_REQ_CONFIDENTIALITY  |
                ASC_REQ_EXTENDED_ERROR   |
                ASC_REQ_ALLOCATE_MEMORY  |
                ASC_REQ_STREAM;

if(fClientAuth)
{
    dwSSPIFlags |= ASC_REQ_MUTUAL_AUTH;
}

cbIoBuffer = 0;

scRet = SEC_I_CONTINUE_NEEDED;

while(scRet == SEC_I_CONTINUE_NEEDED  ||
      scRet == SEC_E_INCOMPLETE_MESSAGE) 
{
//--------------------------------------------------------------------
//     If the i/o buffer is empty, or it contains a fragment of a 
//     handshake message, read more data from the client.

    if(0 == cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE)
    {
        BytesRead = ReadDataFromClient(IoBuffer + cbIoBuffer);
        cbIoBuffer += BytesRead;
    }

//--------------------------------------------------------------------
//     Set up the input and output buffers.

    InBuffers[0].pvBuffer    = rgbIoBuffer;
    InBuffers[0].cbBuffer    = cbIoBuffer;
    InBuffers[0].BufferType  = SECBUFFER_TOKEN;

    InBuffers[1].pvBuffer    = NULL;
    InBuffers[1].cbBuffer    = 0;
    InBuffers[1].BufferType  = SECBUFFER_EMPTY;

    InBuffer.cBuffers        = 2;
    InBuffer.pBuffers        = InBuffers;
    InBuffer.ulVersion       = SECBUFFER_VERSION;

    OutBuffers[0].pvBuffer   = NULL;
    OutBuffers[0].BufferType = SECBUFFER_TOKEN;
    OutBuffers[0].cbBuffer   = 0;

    OutBuffer.cBuffers       = 1;
    OutBuffer.pBuffers       = OutBuffers;
    OutBuffer.ulVersion      = SECBUFFER_VERSION;

    scRet = g_SecurityFunc.AcceptSecurityContext(
                    phCred,
                    fInitContext ? NULL : phContext,
                    &InBuffer,
                    dwSSPIFlags,
                    SECURITY_NATIVE_DREP,
                    fInitContext ? phContext : NULL,
                    &OutBuffer,
                    &dwSSPIOutFlags,
                    &tsExpiry);

    fInitContext = FALSE;

//--------------------------------------------------------------------
// If AcceptSecurityContext was successful (or if the error was 
// one of the special extended ones), send the contents 
// of the output buffer to the client.

    if(scRet == SEC_E_OK ||
       scRet == SEC_I_CONTINUE_NEEDED ||
       (FAILED(scRet) && (0 != (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))))
    {
        if(OutBuffers[0].cbBuffer != 0  &&
           OutBuffers[0].pvBuffer != NULL)
        {
            // Send response to client if there is one
            SendToClient(OutBuffers[0].pvBuffer,
                         OutBuffers[0].cbBuffer);

            // Free the output buffer.
            g_SecurityFunc.FreeContextBuffer(OutBuffers[0].pvBuffer);
            OutBuffers[0].pvBuffer = NULL;
        }
    }

    if(scRet == SEC_E_OK)
    {
        if(InBuffers[1].BufferType == SECBUFFER_EXTRA)
        {
            // The extra buffer contains leftover data from the input
            // buffer that was not consumed. Put this data back in the 
            // i/o buffer, so it can get processed later by 
            //DecryptMessage.
            MoveMemory(rgbIoBuffer,
                       (LPBYTE)(rgbIoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer)),
                       InBuffers[1].cbBuffer);
            cbIoBuffer = InBuffers[1].cbBuffer;
        }
        else
        {
            cbIoBuffer = 0;
        }

        // The handshake is over.
        return TRUE;
    }

    if(FAILED(scRet) && (scRet != SEC_E_INCOMPLETE_MESSAGE))
    {
        printf("AcceptSecurityContext failed with error code %lx\n", scRet);
        return FALSE;
    }

    if(scRet != SEC_E_INCOMPLETE_MESSAGE)
    {
        if(InBuffers[1].BufferType == SECBUFFER_EXTRA)
        {
            // The extra buffer contains leftover data from the input
            // buffer that was not consumed. Put this data back in the 
            // i/o buffer, so it can get processed on the next pass.
            MoveMemory(rgbIoBuffer,
                       (LPBYTE)(rgbIoBuffer + (cbIoBuffer - InBuffers[1].cbBuffer)),
                       InBuffers[1].cbBuffer);
            cbIoBuffer = InBuffers[1].cbBuffer;
        }
        else
        {
            cbIoBuffer = 0;
        }
    }

    // Go around again.
    continue;
}