EternalWindows
GINA / GINAサンプル

ver1.0の関数を軸としたGINAのサンプルを以下に示します。 関数の実装は、基本的にこれまでの節で示したものと同一になっていますが、 簡単のためにWlxDisplaySASNoticeでは、SASの入力を促すダイアログを表示 しないようにしています。 また、ワークステーションのロックを省略するために、 WlxIsLockOkではFALSEを返すようにしています。 WlxLoggedOutSASで表示しているダイアログはリソースを基にしているため、 リソーススクリプトを開発環境に追加するのを忘れないでください。

#define UNICODE
#include <windows.h>
#include <winwlx.h>
#include "resource.h"

struct GINACONTEXT {
	HANDLE                    hWlx;
	HANDLE                    hToken;
	HINSTANCE                 hinstDll;
	PWLX_MPR_NOTIFY_INFO      pMprNotifyInfo;
	PWLX_DISPATCH_VERSION_1_0 pDispatchTable;
};
typedef struct GINACONTEXT GINACONTEXT;
typedef struct GINACONTEXT *LPGINACONTEXT;

HINSTANCE g_hinstDll = NULL;

INT_PTR CALLBACK LogonProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL GetWinlogonRegistryData(LPWSTR lpszValue, LPVOID lpData, DWORD dwSize);
BOOL SetWinlogonRegistryData(LPWSTR lpszValue, DWORD dwType, LPVOID lpData, DWORD dwSize);
BOOL ReplaceDefaultGina(void);

BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD dwReason, LPVOID lpReserved)
{
	switch (dwReason) {
	
	case DLL_PROCESS_ATTACH:
		g_hinstDll = hinstDll;
		DisableThreadLibraryCalls(hinstDll);
		return TRUE;
	}

	return TRUE;
}

BOOL WINAPI WlxNegotiate(DWORD dwWinLogonVersion, PDWORD pdwDllVersion)
{
	DWORD dwDllVersion = WLX_VERSION_1_0;

	ReplaceDefaultGina();

	if (dwWinLogonVersion < dwDllVersion)
		return FALSE;
	
	*pdwDllVersion = dwDllVersion;

	return TRUE;
}

BOOL WINAPI WlxInitialize(LPWSTR lpWinsta, HANDLE hWlx, PVOID pvReserved, PVOID pWinlogonFunctions, PVOID *pWlxContext)
{
	LPGINACONTEXT lpgc;

	lpgc = (LPGINACONTEXT)LocalAlloc(LPTR, sizeof(GINACONTEXT));
	
	lpgc->hWlx           = hWlx;
	lpgc->hinstDll       = g_hinstDll;
	lpgc->pDispatchTable = (PWLX_DISPATCH_VERSION_1_0)pWinlogonFunctions;

	*pWlxContext = (LPVOID)lpgc;
	
	lpgc->pDispatchTable->WlxUseCtrlAltDel(lpgc->hWlx);

	return TRUE;
}

VOID WINAPI WlxDisplaySASNotice(PVOID pWlxContext)
{
	LPGINACONTEXT lpgc = (LPGINACONTEXT)pWlxContext;

	lpgc->pDispatchTable->WlxSasNotify(lpgc->hWlx, WLX_SAS_TYPE_MAX_MSFT_VALUE + 1);
}

int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType, PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions, PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo, PVOID *pProfile)
{
	int              nResult;
	UINT             i;
	DWORD            dwSize;
	PTOKEN_GROUPS    pTokenGroups;
	TOKEN_STATISTICS tokenStatistics;
	LPGINACONTEXT    lpgc = (LPGINACONTEXT)pWlxContext;

	lpgc->pMprNotifyInfo = pMprNotifyInfo;

	nResult = lpgc->pDispatchTable->WlxDialogBoxParam(lpgc->hWlx, lpgc->hinstDll, MAKEINTRESOURCE(ID_DIALOG), NULL, LogonProc, (LPARAM)lpgc);
	if (nResult == -1)		
		return WLX_SAS_ACTION_SHUTDOWN;
	else if (nResult == WLX_SAS_ACTION_SHUTDOWN || nResult == WLX_SAS_ACTION_NONE)
		return nResult;
	else if (nResult == WLX_SAS_ACTION_LOGON)
		;
	else
		return WLX_SAS_ACTION_NONE;

	*phToken = lpgc->hToken;

	GetTokenInformation(*phToken, TokenStatistics, (PVOID)&tokenStatistics, sizeof(TOKEN_STATISTICS), &dwSize);
	*pAuthenticationId = tokenStatistics.AuthenticationId;
	
	GetTokenInformation(*phToken, TokenGroups, NULL, 0, &dwSize);
	pTokenGroups = (PTOKEN_GROUPS)LocalAlloc(LPTR, dwSize);

	GetTokenInformation(*phToken, TokenGroups, pTokenGroups, dwSize, &dwSize);
	for (i = 0; i < pTokenGroups->GroupCount; i++) {
		if (pTokenGroups->Groups[i].Attributes & SE_GROUP_LOGON_ID) {
			CopySid(GetLengthSid(pLogonSid), pLogonSid, pTokenGroups->Groups[i].Sid);
			break;
		}
	}

	LocalFree(pTokenGroups);
	
	*pProfile = NULL;
	*pdwOptions = 0;

	return WLX_SAS_ACTION_LOGON;
}

BOOL WINAPI WlxActivateUserShell(PVOID pWlxContext, PWSTR pszDesktopName, PWSTR pszMprLogonScript, PVOID pEnvironment)
{
	int                 nLength;
	int                 nProcessCount = 0;
	BOOL                bResult;
	WCHAR               szExe[256];
	WCHAR               szUserinit[1024];
	LPWSTR              lpszBegin, lpszEnd;
	STARTUPINFO         si;
	PROCESS_INFORMATION pi;
	LPGINACONTEXT       lpgc = (LPGINACONTEXT)pWlxContext;
	
	GetWinlogonRegistryData(L"Userinit", szUserinit, sizeof(szUserinit));
	lpszEnd = szUserinit;

	do {
		for (lpszBegin = lpszEnd, nLength = 0; *lpszEnd != ','; lpszEnd++)
			nLength += 1;
		lstrcpyn(szExe, lpszBegin, nLength + 1);
		
		ZeroMemory(&si, sizeof(STARTUPINFO));
		si.cb          = sizeof(STARTUPINFO);
		si.lpTitle     = szExe;
		si.lpDesktop   = pszDesktopName;
		si.wShowWindow = SW_SHOW;

		bResult = CreateProcessAsUser(lpgc->hToken, szExe, NULL, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, pEnvironment, NULL, &si, &pi);
		if (bResult) {
			CloseHandle(pi.hThread);
			CloseHandle(pi.hProcess);
			nProcessCount++;
		}

		lpszEnd++;

	} while (*lpszEnd != '\0');

	VirtualFree(pEnvironment, 0, MEM_RELEASE);

	return nProcessCount > 0;
}

int WINAPI WlxLoggedOnSAS(PVOID pWlxContext, DWORD dwSasType, PVOID pReserved)
{
	int           nId;
	int           nResult;
	LPGINACONTEXT lpgc = (LPGINACONTEXT)pWlxContext;

	if (dwSasType != WLX_SAS_TYPE_CTRL_ALT_DEL)
		return WLX_SAS_ACTION_NONE;
	
	nId = lpgc->pDispatchTable->WlxMessageBox(lpgc->hWlx, NULL, L"「はい」を押すとログオフ、「いいえ」をタスクマネージャを起動します。", L"Windowsのセキュリティ", MB_YESNO);
	if (nId == IDYES)
		nResult = WLX_SAS_ACTION_LOGOFF;
	else if (nId == IDNO)
		nResult = WLX_SAS_ACTION_TASKLIST;
	else
		nResult = WLX_SAS_ACTION_NONE;

	return nResult;
}

VOID WINAPI WlxDisplayLockedNotice(PVOID pWlxContext)
{
	LPGINACONTEXT lpgc = (LPGINACONTEXT)pWlxContext;

	lpgc->pDispatchTable->WlxSasNotify(lpgc->hWlx, WLX_SAS_TYPE_MAX_MSFT_VALUE + 1);
}

int WINAPI WlxWkstaLockedSAS(PVOID pWlxContext, DWORD dwSasType)
{
	return WLX_SAS_ACTION_UNLOCK_WKSTA;
}

BOOL WINAPI WlxIsLockOk(PVOID pWlxContext)
{
	return FALSE;
}

BOOL WINAPI WlxIsLogoffOk(PVOID pWlxContext)
{
	return TRUE;
}

VOID WINAPI WlxLogoff(PVOID pWlxContext)
{

}

VOID WINAPI WlxShutdown(PVOID pWlxContext, DWORD dwShutdownType)
{

}

INT_PTR CALLBACK LogonProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static LPGINACONTEXT lpgc = NULL;
	
	switch (uMsg) {

	case WM_INITDIALOG: {
		BOOL  bDontDisplayLastUserName = FALSE;
		WCHAR szUserName[256];

		lpgc = (LPGINACONTEXT)lParam;

		GetWinlogonRegistryData(L"DontDisplayLastUserName", &bDontDisplayLastUserName, sizeof(BOOL));
		if (!bDontDisplayLastUserName) {
			GetWinlogonRegistryData(L"DefaultUserName", szUserName, sizeof(szUserName));
			SetDlgItemText(hwndDlg, ID_USERNAME, szUserName);
		}

		return TRUE;
	}

	case WM_COMMAND:
	switch (LOWORD(wParam)) {

	case IDOK: {
		WCHAR szUserName[256];
		WCHAR szPassword[256];
		WCHAR szDomain[256];

		GetDlgItemText(hwndDlg, ID_USERNAME, szUserName, sizeof(szUserName) / sizeof(WCHAR));
		GetDlgItemText(hwndDlg, ID_PASSWORD, szPassword, sizeof(szPassword) / sizeof(WCHAR));
		GetDlgItemText(hwndDlg, ID_DOMAIN, szDomain, sizeof(szDomain) / sizeof(WCHAR));

		if (LogonUser(szUserName, szDomain, szPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &lpgc->hToken)) {
			lpgc->pMprNotifyInfo->pszUserName    = (PWSTR)LocalAlloc(LPTR, (lstrlen(szUserName) + 1) * sizeof(WCHAR));
			lpgc->pMprNotifyInfo->pszPassword    = (PWSTR)LocalAlloc(LPTR, (lstrlen(szPassword) + 1) * sizeof(WCHAR));
			lpgc->pMprNotifyInfo->pszDomain      = (PWSTR)LocalAlloc(LPTR, (lstrlen(szDomain) + 1)  * sizeof(WCHAR));
			lpgc->pMprNotifyInfo->pszOldPassword = NULL;

			lstrcpy(lpgc->pMprNotifyInfo->pszUserName, szUserName);
			lstrcpy(lpgc->pMprNotifyInfo->pszPassword, szPassword);
			lstrcpy(lpgc->pMprNotifyInfo->pszDomain, szDomain);

			SetWinlogonRegistryData(L"DefaultUserName", REG_SZ, szUserName, (lstrlen(szUserName) + 1) * sizeof(WCHAR));

			EndDialog(hwndDlg, WLX_SAS_ACTION_LOGON);
		}
		else {
			lpgc->pDispatchTable->WlxMessageBox(lpgc->hWlx, hwndDlg, L"ログオンに失敗しました。", NULL, MB_ICONWARNING);
			EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
		}

		return TRUE;
	}
		
	case IDCANCEL:
		EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
		return TRUE;

	case ID_SHUTDOWN:
		EndDialog(hwndDlg, WLX_SAS_ACTION_SHUTDOWN);
		return TRUE;

	default:
		break;

	}
	break;
	
	default:
		break;

	}

	return FALSE;
}

BOOL GetWinlogonRegistryData(LPWSTR lpszValue, LPVOID lpData, DWORD dwSize)
{
	HKEY hKey;
	LONG lResult;

	lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_QUERY_VALUE, &hKey);
	if (lResult == ERROR_SUCCESS) {
		lResult = RegQueryValueEx(hKey, lpszValue, NULL, NULL, (LPBYTE)lpData, &dwSize);
		RegCloseKey(hKey);
		return TRUE;
	}
	else
		return FALSE;
}

BOOL SetWinlogonRegistryData(LPWSTR lpszValue, DWORD dwType, LPVOID lpData, DWORD dwSize)
{
	HKEY hKey;
	LONG lResult;

	lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_SET_VALUE, &hKey);
	if (lResult == ERROR_SUCCESS) {
		lResult = RegSetValueEx(hKey, lpszValue, 0, dwType, (LPBYTE)lpData, dwSize);
		RegCloseKey(hKey);
		return TRUE;
	}
	else
		return FALSE;
}

BOOL ReplaceDefaultGina(void)
{
	HKEY hKey;
	LONG lResult;

	lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_SET_VALUE, &hKey);
	if (lResult == ERROR_SUCCESS) {
		RegDeleteValue(hKey, L"GinaDLL");
		RegCloseKey(hKey);
		return TRUE;
	}
	else
		return FALSE;
}

戻る