InitializeSecurityContext (NTLM) 函数

InitializeSecurityContext (NTLM) 函数从凭据句柄启动客户端出站安全上下文。 该函数用于在客户端应用程序和远程对等方之间生成 安全上下文InitializeSecurityContext (NTLM) 返回客户端必须传递给远程对等的令牌,而对等方又通过 AcceptSecurityContext (NTLM) 调用提交到本地安全实现。 所有调用方都应将生成的令牌视为不透明。

通常, InitializeSecurityContext (NTLM) 函数在循环中调用,直到建立足够的 安全上下文

语法

SECURITY_STATUS SEC_Entry InitializeSecurityContext(
  _In_opt_    PCredHandle    phCredential,
  _In_opt_    PCtxtHandle    phContext,
  _In_        SEC_CHAR       *pszTargetName,
  _In_        ULONG          fContextReq,
  _In_        ULONG          Reserved1,
  _In_        ULONG          TargetDataRep,
  _In_opt_    PSecBufferDesc pInput,
  _In_        ULONG          Reserved2,
  _Inout_opt_ PCtxtHandle    phNewContext,
  _Inout_opt_ PSecBufferDesc pOutput,
  _Out_       PULONG         pfContextAttr,
  _Out_opt_   PTimeStamp     ptsExpiry
);

参数

phCredential 认证[in, optional]

AcquireCredentialsHandle (NTLM) 返回的凭据的句柄。 此句柄用于生成 安全上下文InitializeSecurityContext (NTLM) 函数至少需要出站凭据。

phContext[in, optional]

指向 CtxtHandle 结构的指针。 在第一次调用 InitializeSecurityContext (NTLM)时,此指针为 NULL。 在第二次调用中,此参数是指向第一次调用 在 phNewContext 参数中返回的部分格式上下文的句柄的指针。

警告

请勿在 对 InitializeSecurityContext(NTLM)的并发调用中使用相同的上下文句柄。 安全服务提供商中的 API 实现的线程不安全。

psz目标名称[in]

指向以 null 结尾的字符串的指针,该字符串指示服务主体名称(SPN)或目标服务器 的安全上下文

应用程序必须提供有效的 SPN 来帮助缓解重播攻击。

使用完全限定的目标名称,因为林中不支持短名称。

fContextReq (f上下文请求)[in]

指示上下文请求的位标志。 并非所有包都支持所有要求。 用于此参数的标志以ISC_REQ_为前缀,例如ISC_REQ_DELEGATE。 此参数可以是以下一个或多个属性标志。

价值 含义
ISC_REQ_ALLOCATE_MEMORY 安全包为你分配输出缓冲区。 使用完输出缓冲区后,通过调用 FreeContextBuffer 函数释放它们。
ISC_REQ_CONFIDENTIALITY 使用 EncryptMessage 函数加密消息。
ISC_REQ_CONNECTION 安全上下文不会处理格式设置消息。 此值为默认值。
ISC_REQ_EXTENDED_ERROR 发生错误时,将通知远程方。
ISC_REQ_INTEGRITY 使用 EncryptMessageMakeSignature 函数对消息进行签名和验证签名。
ISC_REQ_MUTUAL_AUTH 将满足服务的相互身份验证策略。
谨慎: 这并不一定意味着执行相互身份验证,只是满足服务的身份验证策略。 若要确保执行相互身份验证,请调用 QueryContextAttributes (NTLM) 函数。
ISC_REQ_REPLAY_DETECT 使用 EncryptMessageMakeSignature 函数检测已编码的重播消息。
ISC_REQ_SEQUENCE_DETECT 检测按顺序接收的消息。
ISC_REQ_STREAM 支持面向流的连接。

客户端可能不支持请求的属性。 有关详细信息,请参阅 pfContextAttr 参数。

有关各种属性的进一步说明,请参阅 上下文要求

保留1[in]

此参数是保留的,必须设置为零。

TargetDataRep[in]

目标上的数据表示形式,例如字节顺序。 此参数可为 SECURITY_NATIVE_DREP 或 SECURITY_NETWORK_DREP。

pInput[in, optional]

指向 SecBufferDesc 结构的指针,该结构包含指向作为包输入提供的缓冲区的指针。 除非客户端上下文由服务器启动,否则此参数的值必须在 NULL 对函数的第一次调用中。 在对函数的后续调用或服务器启动客户端上下文时,此参数的值是指向分配有足够内存的缓冲区的指针,用于保存远程计算机返回的令牌。

保留2[in]

此参数是保留的,必须设置为零。

phNewContext[in, out, optional]

指向 CtxtHandle 结构的指针。 在第一次调用 InitializeSecurityContext (NTLM)时,此指针将接收新的上下文句柄。 第二次调用时, phNewContext 可以与 phContext 参数中指定的句柄相同。 phNewContext 不应该是 NULL

p输出[in, out, optional]

指向 SecBufferDesc 结构的指针,该结构包含指向接收输出数据的 SecBuffer 结构的指针。 如果缓冲区在输入中被键入为SEC_READWRITE,则会在输出中显示缓冲区。 如果请求(通过ISC_REQ_ALLOCATE_MEMORY),系统将为安全令牌分配缓冲区,并在安全令牌的缓冲区描述符中填写地址。

pfContextAttr 的[out]

指向变量的指针,用于接收一组指示已建立上下文 的属性 的位标志。 有关各种属性的说明,请参阅上下文要求

用于此参数的标志以ISC_RET为前缀,例如ISC_RET_DELEGATE。 有关有效值的列表,请参阅 fContextReq 参数。

在最终函数调用成功返回之前,不要检查与安全性相关的属性。 与安全性无关的属性标志(如ASC_RET_ALLOCATED_MEMORY标志)可以在最终返回之前进行检查。

注释

在与远程对等方协商期间,特定上下文属性可能会更改。

ptsExpiry[out, optional]

指向接收上下文到期时间的 TimeStamp 结构的指针。 建议 安全包 始终在本地时间返回此值。 此参数是可选的,应为短期客户端传递 NULL

返回值

如果函数成功,该函数将返回以下成功代码之一。

返回代码 说明
SEC_E_OK 安全上下文已成功初始化。 不需要另一个 InitializeSecurityContext (NTLM) 调用。 如果函数返回输出令牌,即如果 SECBUFFER_TOKENin pOutput 的长度为非零,则必须将该令牌发送到服务器。
SEC_I_COMPLETE_AND_CONTINUE 客户端必须调用 CompleteAuthToken ,然后将输出传递给服务器。 然后,客户端等待返回的令牌,并在另一个调用中将其传递给 InitializeSecurityContext (NTLM)。
SEC_I_COMPLETE_NEEDED 客户端必须完成消息生成,然后调用 CompleteAuthToken 函数。
SEC_I_CONTINUE_NEEDED 客户端必须将输出令牌发送到服务器并等待返回令牌。 然后,返回的令牌在另一个调用 InitializeSecurityContext (NTLM)中传递。 输出令牌可以为空。

如果函数失败,该函数将返回以下错误代码之一。

返回代码 说明
SEC_E_INSUFFICIENT_MEMORY 没有足够的内存可用于完成请求的操作。
SEC_E_INTERNAL_ERROR 出现未映射到 SSPI 错误代码的错误。
SEC_E_INVALID_HANDLE 传递到函数的句柄无效。
SEC_E_INVALID_TOKEN 错误是由于输入令牌格式不正确,例如在传输过程中损坏的令牌、大小不正确的令牌或传递到错误的 约束委派中的令牌。 如果客户端和服务器未协商适当的 约束委派,则可能会将令牌传递到错误的包。
SEC_E_LOGON_DENIED 登录失败。
SEC_E_NO_AUTHENTICATING_AUTHORITY 无法联系任何机构进行身份验证。 身份验证方的域名可能是错误的,域可能无法访问,或者可能存在信任关系失败。
SEC_E_NO_CREDENTIALS 约束委派中不提供任何凭据。
SEC_E_TARGET_UNKNOWN 无法识别目标。
SEC_E_UNSUPPORTED_FUNCTION fContextReq 参数中指定了无效的上下文属性标志(ISC_REQ_DELEGATE或ISC_REQ_PROMPT_FOR_CREDS)。
SEC_E_WRONG_PRINCIPAL 接收身份验证请求的主体与传递到 pszTargetName 参数的主体不同。 这表示相互身份验证失败。

注解

调用方负责确定最终上下文属性是否足够。 例如,如果请求了机密性,但无法建立,某些应用程序可能会选择立即关闭连接。

如果 安全上下文 的属性不够,客户端必须通过调用 DeleteSecurityContext 函数释放部分创建的上下文。

InitializeSecurityContext (NTLM) 函数由客户端用来初始化出站上下文。

对于双腿 安全上下文,调用序列如下所示:

  1. 客户端调用 设置为 phContextNULL 的函数,并使用输入消息填充缓冲区描述符。
  2. 安全包检查参数并构造不透明令牌,并将其放置在缓冲区数组中的 TOKEN 元素中。 如果 fContextReq 参数包含ISC_REQ_ALLOCATE_MEMORY标志, 则安全包 将分配内存并返回 TOKEN 元素中的指针。
  3. 客户端将 pOutput 缓冲区中返回的令牌发送到目标服务器。 然后,服务器在对 AcceptSecurityContext (NTLM) 函数的调用中将令牌作为输入参数传递。
  4. AcceptSecurityContext (NTLM) 可能会返回令牌,如果第一次调用返回SEC_I_CONTINUE_NEEDED,服务器会向客户端发送第二次调用 InitializeSecurityContext (NTLM )。

对于多回合 安全上下文(例如相互身份验证),调用顺序如下所示:

  1. 客户端如前所述调用函数,但包返回SEC_I_CONTINUE_NEEDED成功代码。
  2. 客户端将输出令牌发送到服务器,并等待服务器的回复。
  3. 收到服务器的响应后,客户端会再次调用 InitializeSecurityContext (NTLM),并将 phContext 设置为上次调用返回的句柄。 从服务器收到的令牌在 pInput 参数中提供。
  4. 请勿在对 InitializeSecurityContext (NTLM) 的并发调用中使用 phContext 值。 安全提供商中实现的线程不安全。

如果服务器已成功响应, 则安全包 将返回SEC_E_OK并建立安全会话。

如果函数返回错误响应之一,则不接受服务器的响应,并且未建立会话。

如果函数返回SEC_I_CONTINUE_NEEDED、SEC_I_COMPLETE_NEEDED或SEC_I_COMPLETE_AND_CONTINUE,则重复步骤 2 和 3。

若要初始化 安全上下文,可能需要多次调用此函数,具体取决于基础身份验证机制以及 fContextReq 参数中指定的选项。

fContextReqpfContextAttributes 参数是表示各种上下文属性的位掩码。 有关各种属性的说明,请参阅上下文要求pfContextAttributes 参数在任何成功返回时都有效,但只有在最终成功返回时,才能检查与上下文的安全方面相关的标志。 中间返回可以设置 ISC_RET_ALLOCATED_MEMORY 标志。

如果设置了ISC_REQ_USE_SUPPLIED_CREDS标志, 安全包 必须在 pInput 输入缓冲区中查找SECBUFFER_PKG_PARAMS缓冲区类型。 这不是一般解决方案,但它允许在适当的时候对 安全包 和应用程序进行强配对。

如果指定了ISC_REQ_ALLOCATE_MEMORY,调用方必须通过调用 FreeContextBuffer 函数释放内存。

例如,输入令牌可能是 LAN 管理器的质询。 在这种情况下,输出令牌将是对质询的 NTLM 加密响应。

客户端执行的作取决于此函数的返回代码。 如果返回代码SEC_E_OK,则不会进行第二次 InitializeSecurityContext (NTLM) 调用,并且不需要来自服务器的响应。 如果返回代码SEC_I_CONTINUE_NEEDED,则客户端需要来自服务器的响应令牌,并在第二次调用 InitializeSecurityContext (NTLM)中传递令牌。 SEC_I_COMPLETE_NEEDED返回代码指示客户端必须完成消息生成并调用 CompleteAuthToken 函数。 SEC_I_COMPLETE_AND_CONTINUE代码包含这两个作。

如果 InitializeSecurityContext (NTLM) 在第一次(或仅)调用中返回成功,则调用方最终必须在返回的句柄上调用 DeleteSecurityContext 函数,即使调用在身份验证交换的后续部分失败。

客户端在成功完成后可以再次调用 InitializeSecurityContext (NTLM )。 这向 安全包 指示需要重新身份验证。

内核模式调用方具有以下差异:目标名称是必须使用 VirtualAlloc 在虚拟内存中分配的 Unicode 字符串;不能从池中分配它。 在 pInputpOutput 中传递和提供的缓冲区必须位于虚拟内存中,而不是池中。

要求

要求 价值
支持的最低客户端 Windows XP [仅限桌面应用]
支持的最低服务器 Windows Server 2003 [仅限桌面应用]
标题 Sspi.h(包括 Security.h)
图书馆 Secur32.lib
DLL Secur32.dll

另请参阅

SSPI 函数

AcceptSecurityContext (NTLM)

AcquireCredentialsHandle (NTLM)

完成身份验证令牌

删除SecurityContext

自由上下文缓冲区

秒缓冲区

SecBufferDesc