Windows 10本地进程获取域用户Kerberos凭证句柄技术问询
Solution: Explicitly Provide Domain Credentials to
AcquireCredentialsHandle The core issue here is that when running as mycomputer\localuser, your process doesn't have access to the cached credentials of mydomain\domainuser by default, and the Windows Credential Manager doesn't supply stored credentials to AcquireCredentialsHandle when using SECPKG_CRED_INBOUND mode. To fix this, you need to explicitly pass the domain user's credentials to the function using the SEC_WINNT_AUTH_IDENTITY_EX structure.
Why Your Original Attempts Failed
- When omitting the identity parameter,
AcquireCredentialsHandletries to use the security context of the running user (localuser), which has no Kerberos credentials linked todomainuser. - Stored credentials in the Credential Manager are designed for outbound authentication (like client-side connections), not for inbound server-side credential acquisition.
- Specifying just the SPN or username without explicit credentials doesn't work because the system can't associate that external identity with the local user's context.
Modified Server Code
Here's how to adjust your code to explicitly provide the domain user's credentials:
#include <string> #define NOMINMAX #define WIN32_LEAN_AND_MEAN #include <windows.h> #define SECURITY_WIN32 #include <sspi.h> #pragma comment(lib, "Secur32.lib") // Link against Secur32.lib int main() { CredHandle credentials; TimeStamp lifetime; std::wstring package = L"Kerberos"; std::wstring principal = L"myprotocol/domainuser"; // Define the domain user's credentials SEC_WINNT_AUTH_IDENTITY_EX authIdentity{}; authIdentity.User = (unsigned short*)L"domainuser"; authIdentity.UserLength = wcslen(L"domainuser"); authIdentity.Domain = (unsigned short*)L"mydomain.com"; authIdentity.DomainLength = wcslen(L"mydomain.com"); authIdentity.Password = (unsigned short*)L"YourDomainUserPassword"; // Replace with actual password authIdentity.PasswordLength = wcslen(L"YourDomainUserPassword"); authIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; auto res = AcquireCredentialsHandleW( principal.c_str(), package.c_str(), SECPKG_CRED_INBOUND, nullptr, &authIdentity, // Pass explicit credentials here nullptr, nullptr, &credentials, &lifetime ); if (res == SEC_E_OK) { std::wprintf(L"Success\n"); FreeCredentialsHandle(&credentials); return 0; } else { std::wprintf(L"Failure, error code: 0x%X\n", res); return res; } }
Key Implementation Notes
- Unicode Compliance: We use wide strings (
wchar_t) andAcquireCredentialsHandleWto match Windows API's native Unicode requirements, which is critical for correct domain and username parsing. - Password Security: Hardcoding plaintext passwords is a major security risk. In production, use secure storage mechanisms like DPAPI (Data Protection API) to retrieve the password instead of embedding it directly in code.
- SPN Validation: Confirm the SPN
myprotocol/domainuseris correctly registered in Active Directory and mapped tomydomain\domainuser. You can verify this with the command:setspn -L mydomain\domainuser - Permissions: The local user
mycomputer\localuserneeds permission to callAcquireCredentialsHandlewith explicit domain credentials (this is allowed by default unless restricted by Group Policy).
Additional Troubleshooting Checks
If you still encounter errors, verify:
- The domain user's password is correct and not expired.
- The local computer can reach the domain controller (test with
ping mydomain.comand check LDAP connectivity). - No duplicate SPNs exist in Active Directory for
myprotocol/domainuser.
内容的提问来源于stack exchange,提问作者Arnaud
相关产品推荐
相关产品推荐

