AD(Active Directory)用户验证

着重介绍两中方法使用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:

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Lsa

在 Windows XP 计算机上的是工作组的成员:

  • 如果启用了 ForceGuest (设置为 1,SSPI 将总是尝试使用来宾帐户登录。
  • 如果启用了来宾帐户则的 SSPI 登录会为来宾成功输入 任何 用户凭据。
  • 如果禁用来宾帐户的 SSPI 登录将甚至失败有效凭据。
  • 如果禁用 ForceGuest (设置为 0),SSPI 作为指定的用户而将登录。

此外,如果启用了来宾帐户则 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; LPCSTR USER(""); LPCSTR PASS(""); if (LogonUser( (LPCSTR)USER,("a.com.cn"),(LPCSTR)PASS,LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT,&user)) { printf("good"); } else { int n = GetLastError(); printf("error"); }

你可能感兴趣的:(AD(Active Directory)用户验证)