EternalWindows
Credentials Management / 新しい入力

Windows Vistaからは、クレデンシャルを入力するための新しい関数としてCredUIPromptForWindowsCredentialsが登場しました。 この関数は、次のようなダイアログを表示します。

CredUIPromptForCredentialsがネットワークへの接続に使用されるダイアログを表示するのに対し、 CredUIPromptForWindowsCredentialsはWindowsへのログオンに使用される正規のダイアログを表示します。 どちらの関数を使用するかは自由ですが、 リファレンスではCredUIPromptForWindowsCredentialsの使用が推奨されています。

CredUIPromptForWindowsCredentialsのプロトタイプは、次のように定義されています。

DWORD WINAPI CredUIPromptForWindowsCredentials(
  PCREDUI_INFO pUiInfo,
  DWORD dwAuthError,
  ULONG *pulAuthPackage,
  LPCVOID pvInAuthBuffer,
  ULONG ulInAuthBufferSize,
  LPVOID *ppvOutAuthBuffer,
  ULONG *pulOutAuthBufferSize,
  BOOL *pfSave,
  DWORD dwFlags
);

pUiInfoは、ダイアログをカスタマイズするための情報を格納するCREDUI_INFO構造体のアドレスを指定します。 NULLを指定することはできません。 dwAuthErrorは、ダイアログに考慮してもらいたいエラー定数を指定します。 pulAuthPackageは、使用する認証パッケージのIDを格納した変数のアドレスを指定します。 0を指定しても問題ありません。 pvInAuthBufferは、ダイアログの既定値としたいクレデンシャルを格納したバッファを指定します。 既定値を与えたくない場合は、NULLを指定します。 ulInAuthBufferSizeは、pvInAuthBufferのサイズを指定します。 ppvOutAuthBufferは、入力されたクレデンシャルを受け取るバッファを指定します。 pulOutAuthBufferSizeは、ppvOutAuthBufferのサイズを格納した変数のアドレスを指定します。 pfSaveは、クレデンシャルを保存するように選択されたかどうかを受け取る変数のアドレスを指定します。 チェックボックスを表示しない場合は、NULLを指定することができます。 dwFlagsは、定義されている定数を指定します。 関数が成功してOKボタンを押した場合は、ERROR_SUCCESSが返ります。 ダイアログでキャンセルをした場合は、ERROR_CANCELLEDが返ります。

dwFlagsに指定できる定数の一部を次に示します。

定数 意味
CREDUIWIN_GENERIC ユーザー名とパスワードがプレーンテキストとして返されるようにする。
CREDUIWIN_CHECKBOX 「資格情報を記憶する」というチェックボックスを表示する。 チェックされたかどうかは、pfSaveに返された値から確認できる。 pfSaveの初期値によって、既定でチェックしておくことも可能。
CREDUIWIN_IN_CRED_ONLY pvInAuthBufferに格納されているユーザー名を固定し、パスワードのみを入力可能とする。
CREDUIWIN_ENUMERATE_CURRENT_USER 現在のプロセスのユーザー名を固定で表示し、パスワードのみを入力可能とする。 ただし、別のアカウントを使用することも可能。

CREDUIWIN_CHECKBOXを指定するとチェックボックスが表示されるようになりますが、 このチェックボックスにチェックを付けてOKボタンを押しても、 クレデンシャルが自動で保存されるようなことはありません。 アプリケーションはpfSaveの値を確認し、 これがTRUEである場合はクレデンシャルを保存します。

CREDUI_INFO構造体は、次のように定義されています。

typedef struct _CREDUI_INFO {
  DWORD   cbSize;
  HWND    hwndParent;
  PCTSTR  pszMessageText;
  PCTSTR  pszCaptionText;
  HBITMAP hbmBanner;
}CREDUI_INFO, *PCREDUI_INFO;

cbSizeは、この構造体のサイズを指定します。 hwndParentは、ダイアログの親にしたいウインドウハンドルを指定します。 pszMessageTextは、ダイアログに表示したい文字列を指定します。 pszCaptionTextは、ダイアログのタイトルとして表示したい文字列を指定します。 hbmBannerは、ダイアログに表示したいビットマップのハンドルを指定します。 CredUIPromptForWindowsCredentialsでこの構造体を使用する場合は、hbmBannerに必ずNULLを指定します。

CredUIPromptForWindowsCredentialsは、入力されたクレデンシャルをppvOutAuthBufferに格納します。 このバッファからユーザー名などを取得するには、CredUnPackAuthenticationBufferを呼び出します。

BOOL WINAPI CredUnPackAuthenticationBuffer(
  DWORD dwFlags,
  PVOID pAuthBuffer,
  DWORD cbAuthBuffer,
  LPTSTR pszUserName,
  DWORD *pcchMaxUserName,
  LPTSTR pszDomainName,
  DWORD *pcchMaxDomainame,
  LPTSTR pszPassword,
  DWORD *pcchMaxPassword
);

dwFlagsは、通常0を指定します。 pAuthBufferは、クレデンシャルを格納したバッファを指定します。 cbAuthBufferは、pAuthBufferのサイズを指定します。 pszUserNameは、ユーザー名を受け取るバッファを指定します。 pcchMaxUserNameは、pszUserNameのサイズを格納した変数のアドレスを指定します。 pszDomainNameは、ドメイン名を受け取るバッファを指定します。 pcchMaxDomainameは、pszDomainNameのサイズを格納した変数のアドレスを指定します。 pszPasswordは、パスワードを受け取るバッファを指定します。 pcchMaxPasswordは、pszPasswordのサイズを格納した変数のアドレスを指定します。

今回のプログラムは、CredUIPromptForWindowsCredentialsでクレデンシャルを取得します。

#include <windows.h>
#include <wincred.h>

#pragma comment (lib, "credui.lib")

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR       szUserName[256];
	TCHAR       szDomainName[256];
	TCHAR       szPassword[256];
	DWORD       dwUserNameSize = sizeof(szUserName) / sizeof(TCHAR);
	DWORD       dwDomainSize = sizeof(szDomainName) / sizeof(TCHAR);
	DWORD       dwPasswordSize = sizeof(szPassword) / sizeof(TCHAR);
	DWORD       dwResult;
	DWORD       dwOutBufferSize;
	PVOID       pOutBuffer;
	ULONG       uAuthPackage = 0;
	CREDUI_INFO uiInfo;
	HANDLE      hToken;

	uiInfo.cbSize         = sizeof(CREDUI_INFO);
	uiInfo.hwndParent     = NULL;
	uiInfo.pszMessageText = TEXT("message");
	uiInfo.pszCaptionText = TEXT("caption");
	uiInfo.hbmBanner      = NULL;

	dwOutBufferSize = 1024;
	pOutBuffer = (PVOID)LocalAlloc(LPTR, dwOutBufferSize);

	dwResult = CredUIPromptForWindowsCredentials(&uiInfo, 0, &uAuthPackage, NULL, 0, &pOutBuffer, &dwOutBufferSize, NULL, CREDUIWIN_GENERIC);
	if (dwResult != ERROR_SUCCESS) {
		LocalFree(pOutBuffer);
		return 0;
	}
	
	CredUnPackAuthenticationBuffer(0, pOutBuffer, dwOutBufferSize, szUserName, &dwUserNameSize, szDomainName, &dwDomainSize, szPassword, &dwPasswordSize);
	
	szUserName[dwUserNameSize] = '\0';
	szPassword[dwPasswordSize] = '\0';
	MessageBox(NULL, szUserName, szPassword, MB_OK);

	if (LogonUser(szUserName, NULL, szPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken))
		CloseHandle(hToken);
	else
		MessageBox(NULL, TEXT("ログオンに失敗しました。"), NULL, MB_ICONWARNING);
	
	SecureZeroMemory(szPassword, sizeof(szPassword));
	SecureZeroMemory(pOutBuffer, dwOutBufferSize);
	LocalFree(pOutBuffer);

	return 0;
}

CredUIPromptForWindowsCredentialsを呼び出すには、CREDUI_INFO構造体を初期化し、 クレデンシャルを受け取るバッファを確保しておきます。 また、フラグにはCREDUIWIN_GENERICを指定し、 プレーンテキストのユーザー名とパスワードが返されるようにします。 関数が成功したらCredUnPackAuthenticationBufferを呼び出し、 ユーザー名とパスワードをバッファから取得します。 これらの文字列は終端がNULLで終了していないため、明示的にNULL文字を追加します。

CredPackAuthenticationBufferについて

CredUIPromptForWindowsCredentialsで表示されるダイアログに既定値を与えたい場合は、 第4引数のpvInAuthBufferにクレデンシャルを格納したバッファを指定する必要があります。 CredPackAuthenticationBufferを呼び出せば、このようなバッファを作成することができます。

DWORD dwInBufferSize;
PVOID pInBuffer;

dwInBufferSize = 1024;
pInBuffer = (PVOID)LocalAlloc(LPTR, dwInBufferSize);
CredPackAuthenticationBuffer(0, TEXT("user"), TEXT("pass"), (PBYTE)pInBuffer, &dwInBufferSize);

dwResult = CredUIPromptForWindowsCredentials(&uiInfo, 0, &uAuthPackage, pInBuffer, dwInBufferSize, &pOutBuffer, &dwOutBufferSize, NULL, CREDUIWIN_GENERIC);

第1引数は0を指定します。 第2引数はバッファに格納したいユーザー名を指定し、第3引数はパスワードを指定します。 ただし、実際にはパスワードを指定しても、ダイアログには表示されないようです。 第4引数に初期化するバッファを指定し、第5引数にバッファのサイズを格納した変数のアドレスを指定します。



戻る