EternalWindows
RAS / 認証情報とプロパティ

アプリケーションは、アカウントの認証情報やエントリのプロパティを 必要とする場合がしばしあると思われます。 たとえば、ダイヤル時にはユーザー名やパスワードが必要になりますし、 相手先の電話番号も指定しなければなりません。 アカウントの認証情報を取得するには、RasGetCredentialsを呼び出します。

DWORD RasGetCredentials(
  LPCTSTR lpszPhonebook,
  LPCTSTR lpszEntry,
  LPRASCREDENTIALS lpCredentials
);

lpszPhonebookは、電話帳ファイルのフルパスを指定します。 lpszEntryは、認証情報を取得したいエントリの名前を指定します。 lpCredentialsは、認証情報を受け取るためのRASCREDENTIALS構造体のアドレスを指定します。 この構造体のszUserNameとszPasswordから認証情報を参照することができます。

基本的にエントリに関する情報は電話帳ファイルに格納されていますが、 アカウントの認証情報については例外だということを覚えておいてください。 ユーザー名は、RasGetCredentialsもしくはRasGetEntryDialParamsのみで取得可能で、 パスワードに関してはパスワードへのハンドルの値が返されるだけです。 この値はパスワードを要求する関数のみが理解できる値であるため、 実際にアプリケーションがパスワード値を確認することはできません。 認証情報以外の情報は、RasGetEntryPropertiesで取得することができます。

DWORD RasGetEntryProperties(
  LPCTSTR lpszPhonebook,
  LPCTSTR lpszEntry,
  LPRASENTRY lpRasEntry,
  LPDWORD lpdwEntryInfoSize,
  LPBYTE lpbDeviceInfo,
  LPDWORD lpdwDeviceInfoSize
);

lpszPhonebookは、電話帳ファイルのフルパスを指定します。 lpszEntryは、プロパティを取得したいエントリの名前を指定します。 lpRasEntryは、RASENTRY構造体のアドレスを指定します。 この構造体にエントリのプロパティが格納されます。 lpdwEntryInfoSizeは、第3引数に指定したバッファのサイズを指定します。 lpbDeviceInfoとlpdwDeviceInfoSizeは、デバイス固有の構成情報に関する引数ですが、 不要な場合はNULLを指定することができます。

今回のプログラムは、RasGetCredentialsで取得した認証情報と RasGetEntryPropertiesで取得したプロパティををリストボックスに表示します。 WM_CREATEで宣言されているszEntryNameに、適切なエントリ名を入力して実行してください。

#include <windows.h>
#include <ras.h>

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

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	TCHAR      szAppName[] = TEXT("sample");
	HWND       hwnd;
	MSG        msg;
	WNDCLASSEX wc;

	wc.cbSize        = sizeof(WNDCLASSEX);
	wc.style         = 0;
	wc.lpfnWndProc   = WindowProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hinst;
	wc.hIcon         = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	wc.hCursor       = (HCURSOR)LoadImage(NULL, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = szAppName;
	wc.hIconSm       = (HICON)LoadImage(NULL, IDI_APPLICATION, IMAGE_ICON, 0, 0, LR_SHARED);
	
	if (RegisterClassEx(&wc) == 0)
		return 0;

	hwnd = CreateWindowEx(0, szAppName, szAppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hinst, NULL);
	if (hwnd == NULL)
		return 0;

	ShowWindow(hwnd, nCmdShow);
	UpdateWindow(hwnd);
	
	while (GetMessage(&msg, NULL, 0, 0) > 0) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return (int)msg.wParam;
}

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	static HWND hwndListBox = NULL;

	switch (uMsg) {

	case WM_CREATE: {
		TCHAR          szEntryName[] = TEXT("EntryName");
		TCHAR          szBuf[256];
		TCHAR          szType[256];
		DWORD          dwEntrySize;
		DWORD          dwResult;
		LPRASENTRY     lpEntry;
		RASCREDENTIALS credentials;

		hwndListBox = CreateWindowEx(0, TEXT("LISTBOX"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL, 0, 0, 0, 0, hwnd, (HMENU)1, ((LPCREATESTRUCT)lParam)->hInstance, NULL);

		credentials.dwSize = sizeof(RASCREDENTIALS);
		credentials.dwMask = RASCM_UserName | RASCM_Password;
		dwResult = RasGetCredentials(NULL, szEntryName, &credentials);
		if (dwResult != 0) {
			RasGetErrorString(dwResult, szBuf, sizeof(szBuf));
			MessageBox(NULL, szBuf, NULL, MB_ICONWARNING);
			return -1;
		}

		wsprintf(szBuf, TEXT("UserName : %s"), credentials.szUserName);
		SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		wsprintf(szBuf, TEXT("Password : %s"), credentials.szPassword);
		SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);

		RasGetEntryProperties(NULL, szEntryName, NULL, &dwEntrySize, NULL, NULL);
		lpEntry = (LPRASENTRY)HeapAlloc(GetProcessHeap(), 0, dwEntrySize);
		lpEntry->dwSize = sizeof(RASENTRY);
		dwResult = RasGetEntryProperties(NULL, szEntryName, lpEntry, &dwEntrySize, NULL, NULL);
		if (dwResult != 0) {
			RasGetErrorString(dwResult, szBuf, sizeof(szBuf));
			MessageBox(NULL, szBuf, NULL, MB_ICONWARNING);
			return -1;
		}

		wsprintf(szBuf, TEXT("LocalPhoneNumber : %s"), lpEntry->szLocalPhoneNumber);
		SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		wsprintf(szBuf, TEXT("DnsServer : %d.%d.%d.%d "), lpEntry->ipaddrDns.a, lpEntry->ipaddrDns.b, lpEntry->ipaddrDns.c, lpEntry->ipaddrDns.d);
		SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		wsprintf(szBuf, TEXT("DeviceType : %s"), lpEntry->szDeviceType);
		SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		wsprintf(szBuf, TEXT("DeviceName : %s"), lpEntry->szDeviceName);
		SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		if (lpEntry->dwType == RASET_Phone)
			lstrcpy(szType, TEXT("電話回線"));
		else if (lpEntry->dwType == RASET_Vpn)
			lstrcpy(szType, TEXT("仮想プライベートネットワーク"));
		else
			;
		wsprintf(szBuf, TEXT("Type : %s "), szType);
		SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)szBuf);
		
		HeapFree(GetProcessHeap(), 0, lpEntry);

		return 0;
	}
	
	case WM_SIZE:
		MoveWindow(hwndListBox, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
		return 0;

	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;

	default:
		break;

	}

	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

リストボックスに表示されるUserNameとPasswordの行はRasGetCredentials、 それ以降のデータはRasGetEntryPropertiesで取得したものです。 まず、RasGetCredentialsの呼び出しから見ていきます。

credentials.dwSize = sizeof(RASCREDENTIALS);
credentials.dwMask = RASCM_UserName | RASCM_Password;
dwResult = RasGetCredentials(NULL, szEntryName, &credentials);
if (dwResult != 0) {
	RasGetErrorString(dwResult, szBuf, sizeof(szBuf));
	MessageBox(NULL, szBuf, NULL, MB_ICONWARNING);
	return -1;
}

dwSizeメンバは、事前にRASCREDENTIALS構造体のサイズで初期化しておきます。 dwMaskはどのような認証情報を取得したいのかを示す定数を受け取り、 ここではRASCM_UserNameとRASCM_Passwordを指定します。 これにより、szUserNameメンバとszPasswordメンバが初期化されることになります。 ただし、既に述べたようにszPasswordメンバからは実際のパスワードは得られません。 RasGetErrorStringは、RAS関数が失敗した原因を文字列として第2引数に返します。

RasGetEntryProperties(NULL, szEntryName, NULL, &dwEntrySize, NULL, NULL);
lpEntry = (LPRASENTRY)HeapAlloc(GetProcessHeap(), 0, dwEntrySize);
lpEntry->dwSize = sizeof(RASENTRY);
RasGetEntryProperties(NULL, szEntryName, lpEntry, &dwEntrySize, NULL, NULL);

プロパティを表すRASENTRY構造体を初期化する部分です。 1回目のRasGetEntryPropertiesの呼び出しでバッファに必要なサイズを取得し、 その後に確保したバッファをRasGetEntryPropertiesに指定します。 このときには事前に、dwSizeメンバにRASENTRY構造体のサイズを代入しています。

ダイヤルアップ情報とLSAシークレット

ダイヤルアップに必要な情報は、RasGetCredentialsやRasGetEntryDialParamsで取得できますが、 この他にLSAシークレットからもダイヤルアップ情報を参照することができます。 LSAシークレットは、次に示すレジストリキーから参照できます。

HKEY_LOCAL_MACHINE\SECURITY\Policy\Secrets

上記のキーにRasDialParams!SID#0(SIDにはテキスト形式のSIDが入る)という サブキーが存在する場合、そこからダイヤルアップに必要な情報を参照することができます。 また、デフォルトのダイアルアップ情報を格納していると思われる L$_RasDefaultCredentials#0というサブキーが存在することもあります。 LSAシークレットに格納されるデータは事前に暗号化されることになっているため、 レジストリエディタなどから直接データを確認することはできませんが、 LsaRetrievePrivateDataを呼び出せば暗号化される前のデータが手に入ることになります。 ただ、これは他にLSAシークレットに格納されているデータにも言えることですが、 肝心のデータのフォーマットが分からないことには特定の情報を抜き出せませんから、 如何にフォーマットを調べるか、もしくは特定するかが鍵となりそうです。



戻る