从本地用户在 Windows 10 上启动的进程获取域用户凭据的句柄

Getting handles to the credentials of a domain user from a process launched by a local user on Windows 10

背景:

用户想要在本地帐户下启动服务器进程,然后使用域帐户对传入的 Kerberos 连接进行身份验证。

我想写那个服务器的代码

客户代码:

客户端代码很简单,包括对 AcquireCredentialsHandle 的调用,然后是对 InitializeSecurityContext:

的调用
AcquireCredentialsHandle(
    nullptr,
    "Kerberos",
    SECPKG_CRED_OUTBOUND,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    &credentials,
    &lifetime);
InitializeSecurityContext(
    &credentials,
    nullptr,
    "myprotocol/myport",
    ISC_REQ_CONFIDENTIALITY,
    0,
    SECURITY_NATIVE_DREP,
    nullptr,
    0,
    &securityContext,
    &outBufferArray,
    &contextAttributes,
    &lifetime);

请注意代码片段中字符串的简化用法。必须处理 wchar_tconst 正确性的现实有点丑陋。

另请注意,如果适当的凭据存储在控制面板的凭据管理器中,则此代码在由本地用户启动时有效 - 即主机名 domainuser(原文如此。)

服务器代码:

我已经有一个代码可以在 mydomain\domainuser:

启动进程时使用
AcquireCredentialsHandle(
    nullptr,
    "Kerberos",
    SECPKG_CRED_INBOUND,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    &credentials,
    &lifetime);
AcceptSecurityContext(
    &credentials,
    nullptr,
    &inBufferArray,
    attribs,
    SECURITY_NATIVE_DREP,
    &securityContext,
    nullptr,
    &attribs,
    &lifetime);

但是当服务器由 mycomputer\localuser 启动时,对 AcquireCredentialsHandle 的调用失败,代码为 SEC_E_NO_CREDENTIALS

如何在 mycomputer\localuser 启动的进程中获取 mydomain\domainuser 的凭据句柄?

编译代码片段:

#include <string>

#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define SECURITY_WIN32
#include <sspi.h>//Requires linking on Secur32.lib

int main(){
    CredHandle credentials;
    TimeStamp lifetime;
    std::string package="Kerberos";
    std::string principal="myprotocol/domainuser";
    auto res=AcquireCredentialsHandle(
        principal.data(),
        package.data(),
        SECPKG_CRED_INBOUND,
        nullptr,
        nullptr,
        nullptr,
        nullptr,
        &credentials,
        &lifetime);
    if(res==SEC_E_OK){
        std::printf("Success\n");
        FreeCredentialsHandle(&credentials);
        return 0;}
    else{
        std::printf("Failure\n");
        return res;}}

要获取与当前登录会话关联的凭据以外的凭据,请使用备用安全主体的信息填充 SEC_WINNT_AUTH_IDENTITY 结构。使用 pAuthData 参数将结构传递给 AcquireCredentialsHandle 函数。

并且 this micrsoft example 演示了 client-side 调用以获取特定用户帐户的 Digest 凭据:

#include <windows.h>

#ifdef UNICODE
  ClientAuthID.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
  ClientAuthID.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif

void main()
{
    SECURITY_STATUS SecStatus; 
    TimeStamp tsLifetime; 
    CredHandle hCred;
    SEC_WINNT_AUTH_IDENTITY ClientAuthID;
    LPTSTR UserName = TEXT("ASecurityPrinciple");
    LPTSTR DomainName = TEXT("AnAuthenticatingDomain");

    // Initialize the memory.
    ZeroMemory( &ClientAuthID, sizeof(ClientAuthID) );

    // Specify string format for the ClientAuthID structure.


    // Specify an alternate user, domain and password.
      ClientAuthID.User = (unsigned char *) UserName;
      ClientAuthID.UserLength = _tcslen(UserName);

      ClientAuthID.Domain = (unsigned char *) DomainName;
      ClientAuthID.DomainLength = _tcslen(DomainName);

    // Password is an application-defined LPTSTR variable
    // containing the user password.
      ClientAuthID.Password = Password;
      ClientAuthID.PasswordLength = _tcslen(Password);

    // Get the client side credential handle.
    SecStatus = AcquireCredentialsHandle (
      NULL,                  // Default principal.
      WDIGEST_SP_NAME,       // The Digest SSP. 
      SECPKG_CRED_OUTBOUND,  // Client will use the credentials.
      NULL,                  // Do not specify LOGON id.
      &ClientAuthID,         // User information.
      NULL,                  // Not used with Digest SSP.
      NULL,                  // Not used with Digest SSP.
      &hCred,                // Receives the credential handle.
      &tsLifetime            // Receives the credential time limit.
    );
}