从本地用户在 Windows 10 上启动的进程获取域用户凭据的句柄
Getting handles to the credentials of a domain user from a process launched by a local user on Windows 10
背景:
- 计算机
mycomputer
是 运行 Windows 10 并且已加入域 mydomain.com
.
- 用户在
mycomputer
上使用本地帐户 mycomputer\localuser
登录。
- 用户还知道域帐户
mydomain\domainuser
的密码。
- 服务主体名称
myprotocol/domainuser
已在 Active Directory 中注册并映射到域帐户 mydomain\domainuser
。
- 不允许本地用户
mycomputer\localuser
作为 mydomain\domainuser
启动进程。
用户想要在本地帐户下启动服务器进程,然后使用域帐户对传入的 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_t
和 const
正确性的现实有点丑陋。
另请注意,如果适当的凭据存储在控制面板的凭据管理器中,则此代码在由本地用户启动时有效 - 即主机名 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
。
- 我尝试将调用的第一个参数修改为
"myprotocol/domainuser"
、"domainuser"
、"mydomain\domainuser"
甚至 "domainuser@mydomain.com"
.
- 我尝试使用主机名
mycomputer
甚至 domainuser
. 在控制面板的凭据管理器中添加所需的凭据
如何在 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.
);
}
背景:
- 计算机
mycomputer
是 运行 Windows 10 并且已加入域mydomain.com
. - 用户在
mycomputer
上使用本地帐户mycomputer\localuser
登录。 - 用户还知道域帐户
mydomain\domainuser
的密码。 - 服务主体名称
myprotocol/domainuser
已在 Active Directory 中注册并映射到域帐户mydomain\domainuser
。 - 不允许本地用户
mycomputer\localuser
作为mydomain\domainuser
启动进程。
用户想要在本地帐户下启动服务器进程,然后使用域帐户对传入的 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_t
和 const
正确性的现实有点丑陋。
另请注意,如果适当的凭据存储在控制面板的凭据管理器中,则此代码在由本地用户启动时有效 - 即主机名 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
。
- 我尝试将调用的第一个参数修改为
"myprotocol/domainuser"
、"domainuser"
、"mydomain\domainuser"
甚至"domainuser@mydomain.com"
. - 我尝试使用主机名
mycomputer
甚至domainuser
. 在控制面板的凭据管理器中添加所需的凭据
如何在 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.
);
}