from:http://www.4ucode.com/Study/Topic/897394
重介绍两中方法使用AD 用户验证机制,
方法1:SSPI
验证此方法具有不需要任何特殊的权限,以及所有版本的 Windows 上工作的优点。 最终结果使用 SSPI 服务验证凭据的是类似于调用 LogonUser API 与 LOGON32_LOGON_NETWORK 登录类型登录。 这种类型的登录,最大缺点是您不能访问远程网络模拟网络类型登录后的资源。 如果您的应用程序调用 LogonUser 与 LOGON32_LOGON_INTERACTIVE 登录类型来替代方法 Windows NT 无法执行委派,然后 SSPI 登录 / 验证可能不会一种可行的替代方法
要使用 Windows 95、 Windows 98 和 Windows Millennium Edition 上的这种方法,您还必须启用 NTLM 安全服务,通过打开控制面板、 网络、 访问控制,然后选择用户级访问控制。
在 Windows XP 上默认情况下在以下注册表项 ForceGuest 注册表值设置为 1:
在 Windows XP 计算机上的是工作组的成员:
此外,如果启用了来宾帐户则 SSPI 登录可能会成功为来宾用户凭据无效的。 本文中的代码 C 的示例演示了如何可以检查建立的安全上下文的访问令牌。 IsGuest Helper 函数,在示例代码显示了如何验证登录出现为指定的用户或来宾。
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//一下代码是用于AD中用户名、密码的验证
// 执行: ***.exe 域名 登陆账号 如 a.exe test.com.cn test
// 详情请见http://support.microsoft.com/default.aspx?scid=kb;en-us;180548
// 中文 :http://support.microsoft.com/kb/180548
// 中文翻译:http://translate.google.cn/translate?prev=hp&hl=zh-CN&js=n&u=http%3A%2F%2Fsupport.microsoft.com%2Fdefault.aspx%3Fscid%3Dkb%3Ben-us%3B180548&sl=en&tl=zh-CN
// 提醒:如果GUEST账号被启用,输入一个错误的账号(或不存在的账号),返回TRUE
*/
///////////////////////////////////////////////////////////////////////////////
//
// SSPI Authentication Sample
//
// This program demonstrates how to use SSPI to authenticate user credentials.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (C) 2007. Microsoft Corporation. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
#define SECURITY_WIN32
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <conio.h>
#include <sspi.h>
#include <lm.h>
#include <lmcons.h>
// Older versions of WinError.h do not have SEC_I_COMPLETE_NEEDED #define.
// So, in such an SDK environment setup, we will include issperr.h which has the
// definition for SEC_I_COMPLETE_NEEDED. Include issperr.h only if
// SEC_I_COMPLETE_NEEDED is not defined.
#ifndef SEC_I_COMPLETE_NEEDED
#include <issperr.h>
#endif
typedef struct _AUTH_SEQ {
BOOL fInitialized;
BOOL fHaveCredHandle;
BOOL fHaveCtxtHandle;
CredHandle hcred;
struct _SecHandle hctxt;
} AUTH_SEQ, *PAUTH_SEQ;
// Function pointers
ACCEPT_SECURITY_CONTEXT_FN _AcceptSecurityContext = NULL;
ACQUIRE_CREDENTIALS_HANDLE_FN _AcquireCredentialsHandle = NULL;
COMPLETE_AUTH_TOKEN_FN _CompleteAuthToken = NULL;
DELETE_SECURITY_CONTEXT_FN _DeleteSecurityContext = NULL;
FREE_CONTEXT_BUFFER_FN _FreeContextBuffer = NULL;
FREE_CREDENTIALS_HANDLE_FN _FreeCredentialsHandle = NULL;
INITIALIZE_SECURITY_CONTEXT_FN _InitializeSecurityContext = NULL;
QUERY_SECURITY_PACKAGE_INFO_FN _QuerySecurityPackageInfo = NULL;
QUERY_SECURITY_CONTEXT_TOKEN_FN _QuerySecurityContextToken = NULL;
#define CheckAndLocalFree(ptr) \
if (ptr != NULL) \
{ \
LocalFree(ptr); \
ptr = NULL; \
}
#pragma comment(lib, "netapi32.lib")
LPVOID RetrieveTokenInformationClass(
HANDLE hToken,
TOKEN_INFORMATION_CLASS InfoClass,
LPDWORD lpdwSize)
{
LPVOID pInfo = NULL;
BOOL fSuccess = FALSE;
__try
{
*lpdwSize = 0;
//
// Determine the size of the buffer needed
//
GetTokenInformation(
hToken,
InfoClass,
NULL,
*lpdwSize, lpdwSize);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
_tprintf(_T("GetTokenInformation failed with %d\n"), GetLastError());
__leave;
}
//
// Allocate a buffer for getting token information
//
pInfo = LocalAlloc(LPTR, *lpdwSize);
if (pInfo == NULL)
{
_tprintf(_T("LocalAlloc failed with %d\n"), GetLastError());
__leave;
}
if (!GetTokenInformation(
hToken,
InfoClass,
pInfo,
*lpdwSize, lpdwSize))
{
_tprintf(_T("GetTokenInformation failed with %d\n"), GetLastError());
__leave;
}
fSuccess = TRUE;
}
__finally
{
// Free pDomainAndUserName only if failed
// Otherwise, the caller has to free after use
if (fSuccess == FALSE)
{
CheckAndLocalFree(pInfo);
}
}
return pInfo;
}
PSID GetUserSidFromWellKnownRid(DWORD Rid)
{
PUSER_MODALS_INFO_2 umi2;
NET_API_STATUS nas;
UCHAR SubAuthorityCount;
PSID pSid = NULL;
BOOL bSuccess = FALSE; // assume failure
nas = NetUserModalsGet(NULL, 2, (LPBYTE *)&umi2);
if (nas != NERR_Success)
{
printf("NetUserModalsGet failed with error code : [%d]\n", nas);
SetLastError(nas);
return NULL;
}
SubAuthorityCount = *GetSidSubAuthorityCount
(umi2->usrmod2_domain_id);
//
// Allocate storage for new Sid. account domain Sid + account Rid
//
pSid = (PSID)LocalAlloc(LPTR,
GetSidLengthRequired((UCHAR)(SubAuthorityCount + 1)));
if (pSid != NULL)
{
if (InitializeSid(
pSid,
GetSidIdentifierAuthority(umi2->usrmod2_domain_id),
(BYTE)(SubAuthorityCount+1)
))
{
DWORD SubAuthIndex = 0;
//
// Copy existing subauthorities from account domain Sid into
// new Sid
//
for (; SubAuthIndex < SubAuthorityCount ; SubAuthIndex++)
{
*GetSidSubAuthority(pSid, SubAuthIndex) =
*GetSidSubAuthority(umi2->usrmod2_domain_id,
SubAuthIndex);
}
//
// Append Rid to new Sid
//
*GetSidSubAuthority(pSid, SubAuthorityCount) = Rid;
}
}
NetApiBufferFree(umi2);
return pSid;
}
BOOL IsGuest(HANDLE hToken)
{
BOOL fGuest = FALSE;
PSID pGuestSid = NULL;
PSID pUserSid = NULL;
TOKEN_USER *pUserInfo = NULL;
DWORD dwSize = 0;
pGuestSid = GetUserSidFromWellKnownRid(DOMAIN_USER_RID_GUEST);
if (pGuestSid == NULL)
return fGuest;
//
// Get user information
//
pUserInfo = (TOKEN_USER *)RetrieveTokenInformationClass(hToken, TokenUser, &dwSize);
if (pUserInfo != NULL)
{
if (EqualSid(pGuestSid, pUserInfo->User.Sid))
fGuest = TRUE;
}
CheckAndLocalFree(pUserInfo);
CheckAndLocalFree(pGuestSid);
return fGuest;
}
///////////////////////////////////////////////////////////////////////////////
void UnloadSecurityDll(HMODULE hModule) {
if (hModule)
FreeLibrary(hModule);
_AcceptSecurityContext = NULL;
_AcquireCredentialsHandle = NULL;
_CompleteAuthToken = NULL;
_DeleteSecurityContext = NULL;
_FreeContextBuffer = NULL;
_FreeCredentialsHandle = NULL;
_InitializeSecurityContext = NULL;
_QuerySecurityPackageInfo = NULL;
_QuerySecurityContextToken = NULL;
}
///////////////////////////////////////////////////////////////////////////////
HMODULE LoadSecurityDll() {
HMODULE hModule;
BOOL fAllFunctionsLoaded = FALSE;
TCHAR lpszDLL[MAX_PATH];
OSVERSIONINFO VerInfo;
//
// Find out which security DLL to use, depending on
// whether we are on Windows NT or Windows 95, Windows 2000, Windows XP, or Windows Server 2003
// We have to use security.dll on Windows NT 4.0.
// All other operating systems, we have to use Secur32.dll
//
VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (!GetVersionEx (&VerInfo)) // If this fails, something has gone wrong
{
return FALSE;
}
if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
VerInfo.dwMajorVersion == 4 &&
VerInfo.dwMinorVersion == 0)
{
lstrcpy (lpszDLL, _T("security.dll"));
}
else
{
lstrcpy (lpszDLL, _T("secur32.dll"));
}
hModule = LoadLibrary(lpszDLL);
if (!hModule)
return NULL;
__try {
_AcceptSecurityContext = (ACCEPT_SECURITY_CONTEXT_FN)
GetProcAddress(hModule, "AcceptSecurityContext");
if (!_AcceptSecurityContext)
__leave;
#ifdef UNICODE
_AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN)
GetProcAddress(hModule, "AcquireCredentialsHandleW");
#else
_AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN)
GetProcAddress(hModule, "AcquireCredentialsHandleA");
#endif
if (!_AcquireCredentialsHandle)
__leave;
// CompleteAuthToken is not present on Windows 9x Secur32.dll
// Do not check for the availablity of the function if it is NULL;
_CompleteAuthToken = (COMPLETE_AUTH_TOKEN_FN)
GetProcAddress(hModule, "CompleteAuthToken");
_DeleteSecurityContext = (DELETE_SECURITY_CONTEXT_FN)
GetProcAddress(hModule, "DeleteSecurityContext");
if (!_DeleteSecurityContext)
__leave;
_FreeContextBuffer = (FREE_CONTEXT_BUFFER_FN)
GetProcAddress(hModule, "FreeContextBuffer");
if (!_FreeContextBuffer)
__leave;
_FreeCredentialsHandle = (FREE_CREDENTIALS_HANDLE_FN)
GetProcAddress(hModule, "FreeCredentialsHandle");
if (!_FreeCredentialsHandle)
__leave;
#ifdef UNICODE
_InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN)
GetProcAddress(hModule, "InitializeSecurityContextW");
#else
_InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN)
GetProcAddress(hModule, "InitializeSecurityContextA");
#endif
if (!_InitializeSecurityContext)
__leave;
#ifdef UNICODE
_QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN)
GetProcAddress(hModule, "QuerySecurityPackageInfoW");
#else
_QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN)
GetProcAddress(hModule, "QuerySecurityPackageInfoA");
#endif
if (!_QuerySecurityPackageInfo)
__leave;
_QuerySecurityContextToken = (QUERY_SECURITY_CONTEXT_TOKEN_FN)
GetProcAddress(hModule, "QuerySecurityContextToken");
if (!_QuerySecurityContextToken)
__leave;
fAllFunctionsLoaded = TRUE;
} __finally {
if (!fAllFunctionsLoaded) {
UnloadSecurityDll(hModule);
hModule = NULL;
}
}
return hModule;
}
///////////////////////////////////////////////////////////////////////////////
BOOL GenClientContext(PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity,
PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) {
/*++
Routine Description:
Optionally takes an input buffer coming from the server and returns
a buffer of information to send back to the server. Also returns
an indication of whether or not the context is complete.
Return Value:
Returns TRUE if successful; otherwise FALSE.
--*/
SECURITY_STATUS ss;
TimeStamp tsExpiry;
SecBufferDesc sbdOut;
SecBuffer sbOut;
SecBufferDesc sbdIn;
SecBuffer sbIn;
ULONG fContextAttr;
if (!pAS->fInitialized) {
ss = _AcquireCredentialsHandle(NULL, _T("NTLM"),
SECPKG_CRED_OUTBOUND, NULL, pAuthIdentity, NULL, NULL,
&pAS->hcred, &tsExpiry);
if (ss < 0) {
fprintf(stderr, "AcquireCredentialsHandle failed with %08X\n", ss);
return FALSE;
}
pAS->fHaveCredHandle = TRUE;
}
// Prepare output buffer
sbdOut.ulVersion = 0;
sbdOut.cBuffers = 1;
sbdOut.pBuffers = &sbOut;
sbOut.cbBuffer = *pcbOut;
sbOut.BufferType = SECBUFFER_TOKEN;
sbOut.pvBuffer = pOut;
// Prepare input buffer
if (pAS->fInitialized) {
sbdIn.ulVersion = 0;
sbdIn.cBuffers = 1;
sbdIn.pBuffers = &sbIn;
sbIn.cbBuffer = cbIn;
sbIn.BufferType = SECBUFFER_TOKEN;
sbIn.pvBuffer = pIn;
}
ss = _InitializeSecurityContext(&pAS->hcred,
pAS->fInitialized ? &pAS->hctxt : NULL, NULL, 0, 0,
SECURITY_NATIVE_DREP, pAS->fInitialized ? &sbdIn : NULL,
0, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry);
if (ss < 0) {
// <winerror.h>
fprintf(stderr, "InitializeSecurityContext failed with %08X\n", ss);
return FALSE;
}
pAS->fHaveCtxtHandle = TRUE;
// If necessary, complete token
if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) {
if (_CompleteAuthToken) {
ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut);
if (ss < 0) {
fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss);
return FALSE;
}
}
else {
fprintf (stderr, "CompleteAuthToken not supported.\n");
return FALSE;
}
}
*pcbOut = sbOut.cbBuffer;
if (!pAS->fInitialized)
pAS->fInitialized = TRUE;
*pfDone = !(ss == SEC_I_CONTINUE_NEEDED
|| ss == SEC_I_COMPLETE_AND_CONTINUE );
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
BOOL GenServerContext(PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut,
PDWORD pcbOut, PBOOL pfDone) {
/*++
Routine Description:
Takes an input buffer coming from the client and returns a buffer
to be sent to the client. Also returns an indication of whether or
not the context is complete.
Return Value:
Returns TRUE if successful; otherwise FALSE.
--*/
SECURITY_STATUS ss;
TimeStamp tsExpiry;
SecBufferDesc sbdOut;
SecBuffer sbOut;
SecBufferDesc sbdIn;
SecBuffer sbIn;
ULONG fContextAttr;
if (!pAS->fInitialized) {
ss = _AcquireCredentialsHandle(NULL, _T("NTLM"),
SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &pAS->hcred,
&tsExpiry);
if (ss < 0) {
fprintf(stderr, "AcquireCredentialsHandle failed with %08X\n", ss);
return FALSE;
}
pAS->fHaveCredHandle = TRUE;
}
// Prepare output buffer
sbdOut.ulVersion = 0;
sbdOut.cBuffers = 1;
sbdOut.pBuffers = &sbOut;
sbOut.cbBuffer = *pcbOut;
sbOut.BufferType = SECBUFFER_TOKEN;
sbOut.pvBuffer = pOut;
// Prepare input buffer
sbdIn.ulVersion = 0;
sbdIn.cBuffers = 1;
sbdIn.pBuffers = &sbIn;
sbIn.cbBuffer = cbIn;
sbIn.BufferType = SECBUFFER_TOKEN;
sbIn.pvBuffer = pIn;
ss = _AcceptSecurityContext(&pAS->hcred,
pAS->fInitialized ? &pAS->hctxt : NULL, &sbdIn, 0,
SECURITY_NATIVE_DREP, &pAS->hctxt, &sbdOut, &fContextAttr,
&tsExpiry);
if (ss < 0) {
fprintf(stderr, "AcceptSecurityContext failed with %08X\n", ss);
return FALSE;
}
pAS->fHaveCtxtHandle = TRUE;
// If necessary, complete token
if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) {
if (_CompleteAuthToken) {
ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut);
if (ss < 0) {
fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss);
return FALSE;
}
}
else {
fprintf (stderr, "CompleteAuthToken not supported.\n");
return FALSE;
}
}
*pcbOut = sbOut.cbBuffer;
if (!pAS->fInitialized)
pAS->fInitialized = TRUE;
*pfDone = !(ss == SEC_I_CONTINUE_NEEDED
|| ss == SEC_I_COMPLETE_AND_CONTINUE);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
BOOL WINAPI SSPLogonUser(LPTSTR szDomain, LPTSTR szUser, LPTSTR szPassword) {
AUTH_SEQ asServer = {0};
AUTH_SEQ asClient = {0};
BOOL fDone = FALSE;
BOOL fResult = FALSE;
DWORD cbOut = 0;
DWORD cbIn = 0;
DWORD cbMaxToken = 0;
PVOID pClientBuf = NULL;
PVOID pServerBuf = NULL;
PSecPkgInfo pSPI = NULL;
HMODULE hModule = NULL;
SEC_WINNT_AUTH_IDENTITY ai;
__try {
hModule = LoadSecurityDll();
if (!hModule)
__leave;
// Get max token size
_QuerySecurityPackageInfo(_T("NTLM"), &pSPI);
cbMaxToken = pSPI->cbMaxToken;
_FreeContextBuffer(pSPI);
// Allocate buffers for client and server messages
pClientBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken);
pServerBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken);
// Initialize auth identity structure
ZeroMemory(&ai, sizeof(ai));
#if defined(UNICODE) || defined(_UNICODE)
ai.Domain = szDomain;
ai.DomainLength = lstrlen(szDomain);
ai.User = szUser;
ai.UserLength = lstrlen(szUser);
ai.Password = szPassword;
ai.PasswordLength = lstrlen(szPassword);
ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
ai.Domain = (unsigned char *)szDomain;
ai.DomainLength = lstrlen(szDomain);
ai.User = (unsigned char *)szUser;
ai.UserLength = lstrlen(szUser);
ai.Password = (unsigned char *)szPassword;
ai.PasswordLength = lstrlen(szPassword);
ai.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif
// Prepare client message (negotiate) .
cbOut = cbMaxToken;
if (!GenClientContext(&asClient, &ai, NULL, 0, pClientBuf, &cbOut, &fDone))
__leave;
// Prepare server message (challenge) .
cbIn = cbOut;
cbOut = cbMaxToken;
if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
&fDone))
__leave;
// Most likely failure: AcceptServerContext fails with SEC_E_LOGON_DENIED
// in the case of bad szUser or szPassword.
// Unexpected Result: Logon will succeed if you pass in a bad szUser and
// the guest account is enabled in the specified domain.
// Prepare client message (authenticate) .
cbIn = cbOut;
cbOut = cbMaxToken;
if (!GenClientContext(&asClient, &ai, pServerBuf, cbIn, pClientBuf, &cbOut,
&fDone))
__leave;
// Prepare server message (authentication) .
cbIn = cbOut;
cbOut = cbMaxToken;
if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
&fDone))
{
int n = ::GetLastError();
__leave;
}
fResult = TRUE;
{
HANDLE hToken = NULL;
if (_QuerySecurityContextToken(&asServer.hctxt, &hToken) == 0)
{
if (IsGuest(hToken))
{
printf("Logged in as Guest\n");
fResult = FALSE;
}
else
printf("Logged in as the desired user\n");
CloseHandle(hToken);
}
}
} __finally {
// Clean up resources
if (asClient.fHaveCtxtHandle)
_DeleteSecurityContext(&asClient.hctxt);
if (asClient.fHaveCredHandle)
_FreeCredentialsHandle(&asClient.hcred);
if (asServer.fHaveCtxtHandle)
_DeleteSecurityContext(&asServer.hctxt);
if (asServer.fHaveCredHandle)
_FreeCredentialsHandle(&asServer.hcred);
if (hModule)
UnloadSecurityDll(hModule);
HeapFree(GetProcessHeap(), 0, pClientBuf);
HeapFree(GetProcessHeap(), 0, pServerBuf);
}
return fResult;
}
//--------------------------------------------------------------------
// The GetConsoleInput function gets an array of characters from the
// keyboard, while printing only asterisks to the screen.
void GetConsoleInput(TCHAR* strInput, int intMaxChars)
{
char ch;
char minChar = ' ';
minChar++;
ch = getch();
while (ch != '\r')
{
if (ch == '\b' && strlen(strInput) > 0)
{
strInput[strlen(strInput)-1] = '\0';
printf("\b \b");
}
else if (ch >= minChar && (int)strlen(strInput) < intMaxChars)
{
strInput[strlen(strInput)+1] = '\0';
strInput[strlen(strInput)] = ch;
putch('*');
}
ch = getch();
}
putch('\n');
}
void _tmain(int argc, TCHAR **argv)
{
TCHAR password[PWLEN+1];
if (argc != 3)
{
_tprintf(_T("Usage: %s DomainName UserName\n"), argv[0]);
return;
}
_tprintf(_T("Enter password for the specified user : "));
password[0] = 0;
GetConsoleInput(password, PWLEN);
_tprintf(_T("\n"));
// argv[1] - Domain Name
// argv[2] - User Name
if (SSPLogonUser(argv[1], argv[2], password))
{
_tprintf(_T("User Credentials are valid\n"));
}
else
_tprintf(_T("User Credentials are NOT valid\n"));
}
方法2:LogonUser
LogonUser API 后可用和记录 Windows NT 3.51,并通常来验证用户凭据。 此 API 位于 Windows NT、 Windows 2000 和 Windows XP。 遗憾的是,有使用 LogonUser 并不总是方便地满足某些限制。
第一个和这些限制的最大是 Windows NT 和 Windows 2000,调用 LogonUser 的进程必须具有 SE_TCB_NAME 特权 (在用户管理器,这是"作为该操作系统的一部分"右侧)。 SE_TCB_NAME 权限功能非常强大且应不授予任何任意用户只是,使之可以运行需要验证凭据的应用程序。 推荐的方法是从本地系统帐户中运行的服务调用 LogonUser,因为本地系统帐户已有 SE_TCB_NAME 权限
请注意 LogonUser Win32 API 不需要 TCB 权限 Microsoft WindowsServer 2003 中但是,下层兼容性,这是仍最佳方法。
在 Windows XP 上就不再需要的进程具有 SE_TCB_NAME 权限才能调用 LogonUser。 因此,以验证 Windows XP 上的用户的凭据最简单的方法是调用 LogonUser API。
LogonUser 一个其他问题是在 Windows 95、 Windows 98 或 Windows Millennium Edition 未实现 API
//////////////////////////////////////////////////////////////////////////////////////////
// 也可以使用 LogonUser 作为登陆验证,不过需要获取SE_TCB_NAME权限
// 获取的SE_TCB_NAME权限需要当前登陆用户具有相应的权限,设置如下:
// 开始-》运行-》gpedit.msc-》计算机管理-》Windows设置-》安全设置-》本地策略-》用户权利指派-》
// 以操作系统方式操作,在这里添加调用LogonUser的进程的用户,然后重启计算机
HANDLE hdlTokenHandle ;
TOKEN_PRIVILEGES tkp;
//得到当前进程的令牌
OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hdlTokenHandle);
//得到特权的Luid 关机特权 TEXT("SeShutdownPrivilege")
LookupPrivilegeValue(NULL, SE_TCB_NAME, &tkp.Privileges[0].Luid);
//指定一次设置的特权属性的个数
tkp.PrivilegeCount=1;
//虽然用户可能有特权,但其状态缺省是disable的
tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED; ;
AdjustTokenPrivileges(hdlTokenHandle, false, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
HANDLE user;
BOOL returnFlag=LogonUser(TEXT("kendy xxxxx"),TEXT("jehl.internel"),TEXT("xxxxxx"),LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&user);
if (returnFlag)
{
printf("good");
}
else
{
int n = GetLastError();
printf("%d",n);
}