void CreateConnection() { const size_t NeedRebootMsgChars = 64; bool doDisableIPSec = false; LPWSTR connTitle = NULL; int typeConnection = (int)SendMessage(hWndComboBox, CB_GETCURSEL, 0, 0); WORD cLoginLength = 0; TCHAR lpszLoginText[maxChars+1] = {0}; WORD cPasswordLength = 0; TCHAR lpszPasswordText[maxChars+1] = {0}; // Получение текста логина и пароля cLoginLength = (WORD)SendMessage(hWndLogin, EM_LINELENGTH, 0, 0); cPasswordLength = (WORD)SendMessage(hWndPassword, EM_LINELENGTH, 0, 0); if (cLoginLength > maxChars) { MessageBox(hwnd, TEXT("Значение поля \"Пользователь\" не должно превышать 20-ти символов."), TEXT("Ошибка"), MB_OK); return; } if (cPasswordLength > maxChars) { MessageBox(hwnd, TEXT("Значение поля \"Пароль\" не должно превышать 20-ти символов."), TEXT("Ошибка"), MB_OK); return; } *((LPWORD)lpszLoginText) = cLoginLength; *((LPWORD)lpszPasswordText) = cPasswordLength; SendMessage(hWndLogin, EM_GETLINE, 0, (LPARAM)lpszLoginText); SendMessage(hWndPassword, EM_GETLINE, 0, (LPARAM)lpszPasswordText); // Корректное окончание строк (null-terminated) lpszLoginText[cLoginLength] = 0; lpszPasswordText[cPasswordLength] = 0; // Первичная проверка версии ОС if (os_ver.dwPlatformId != VER_PLATFORM_WIN32_NT) { MessageBox(hwnd, TEXT("Устаревшая или нераспознанная версия операционной системы"), TEXT("Ошибка"), MB_OK); CloseApplication(); } // Произвести отключение IPSec при успешном создании L2TP соединения if (ver == 51) { // Windows XP? if (typeConnection == 0) { // L2TP? if (isAdmin) { // Администратор? doDisableIPSec = true; } else { MessageBox(hwnd, TEXT("Для создания L2TP соединения в Windows XP\nнеобходимо запустить программу с правами администратора."), TEXT("Уведомление"), MB_OK); return; } } } // Получение размера структуры, независящее от версии ОС. int rasentry_struct_size = sizeof(RASENTRY); /* кусок старого кода, может, пригодится? if ((os_ver.dwMajorVersion == 5 && os_ver.dwMinorVersion == 0) || os_ver.dwMajorVersion <= 4) { // указание для старых ОС размера структуры RASENTRY rasentry_struct_size = 2088; } */ DWORD dwDeviceInfoSize = 0; DWORD dwRasEntryRet = RasGetEntryProperties(NULL, NULL, NULL, (LPDWORD)&rasentry_struct_size, NULL, &dwDeviceInfoSize); if (dwRasEntryRet == ERROR_RASMAN_CANNOT_INITIALIZE) { MessageBox(hwnd, TEXT("Не запущена служба \"Диспетчер подключений удалённого доступа\" (RasMan)\nЗапустите службу и повторите операцию."), TEXT("Уведомление"), MB_OK); return; } // Заполнение структуры настроек соединения RASENTRY rasEntry; ZeroMemory(&rasEntry, sizeof(RASENTRY)); rasEntry.dwSize = rasentry_struct_size; rasEntry.dwfOptions = RASEO_RemoteDefaultGateway | RASEO_ModemLights | RASEO_SecureLocalFiles | RASEO_RequireMsEncryptedPw | RASEO_RequireDataEncryption | RASEO_RequireMsCHAP2 | RASEO_ShowDialingProgress; if (BST_CHECKED == SendMessage(hWndRequestLogin, BM_GETSTATE, 0, 0)) { rasEntry.dwfOptions = rasEntry.dwfOptions | RASEO_PreviewUserPw; } rasEntry.dwfOptions2 = RASEO2_DisableNbtOverIP | RASEO2_ReconnectIfDropped | RASEO2_Internet | RASEO2_DontNegotiateMultilink | RASEO2_SecureClientForMSNet | RASEO2_SecureFileAndPrint; rasEntry.dwRedialCount = 3; rasEntry.dwRedialPause = 60; rasEntry.dwFramingProtocol = RASFP_Ppp; rasEntry.dwfNetProtocols = RASNP_Ip; rasEntry.dwEncryptionType = ET_Optional; // ET_Require switch (typeConnection) { case 1: //PPPoE connTitle = connTitlePPPoE; wcscpy_s(rasEntry.szLocalPhoneNumber, 9, TEXT("in-doors")); wcscpy_s(rasEntry.szDeviceType, 6, RASDT_PPPoE); rasEntry.dwVpnStrategy = VS_Default; rasEntry.dwType = RASET_Broadband; break; case 2: // PPTP connTitle = connTitlePPTP; wcscpy_s(rasEntry.szLocalPhoneNumber, 21, TEXT("internet.in-doors.ru")); wcscpy_s(rasEntry.szDeviceType, 4, RASDT_Vpn); rasEntry.dwVpnStrategy = VS_PptpOnly; rasEntry.dwType = RASET_Vpn; break; case 0: // L2TP default: connTitle = connTitleL2TP; wcscpy_s(rasEntry.szLocalPhoneNumber, 17, TEXT("l2tp.in-doors.ru")); wcscpy_s(rasEntry.szDeviceType, 4, RASDT_Vpn); rasEntry.dwVpnStrategy = VS_L2tpOnly; rasEntry.dwType = RASET_Vpn; break; } //rasEntry.dwDialMode = RASEDM_DialAll; //wcscpy_s(rasEntry.szDeviceName, 21, TEXT("VPN")); //RASDIALPARAMS ras_param; RASCREDENTIALS ras_cred; // Непосредственно - создание соединения. dwRasEntryRet = RasSetEntryProperties(NULL, connTitle, &rasEntry, rasentry_struct_size, NULL, 0); switch (dwRasEntryRet) { case ERROR_ACCESS_DENIED: MessageBox(hwnd, TEXT("Не удалось создать подключение\nRasSetEntryProperties() - ERROR_ACCESS_DENIED"), TEXT("Ошибка"), MB_OK); break; case ERROR_BUFFER_INVALID: MessageBox(hwnd, TEXT("Не удалось создать подключение\nRasSetEntryProperties() - ERROR_BUFFER_INVALID"), TEXT("Ошибка"), MB_OK); break; case ERROR_CANNOT_OPEN_PHONEBOOK: MessageBox(hwnd, TEXT("Не удалось создать подключение\nRasSetEntryProperties() - ERROR_CANNOT_OPEN_PHONEBOOK"), TEXT("Ошибка"), MB_OK); break; case ERROR_INVALID_PARAMETER: MessageBox(hwnd, TEXT("Не удалось создать подключение\nRasSetEntryProperties() - ERROR_INVALID_PARAMETER"), TEXT("Ошибка"), MB_OK); break; case ERROR_SUCCESS: // Указание логина и пароля соединения. Необязательное действие, если используется RasSetCredentials(). /* ZeroMemory(&ras_param, sizeof(RASDIALPARAMS)); ras_param.dwSize = sizeof(RASDIALPARAMS); wcscpy_s(ras_param.szEntryName, wcslen(connTitle)+1, connTitle); wcscpy_s(ras_param.szUserName, 256, lpszLoginText); wcscpy_s(ras_param.szPassword, 256, lpszPasswordText); DWORD dwRasEntryParamsRet = RasSetEntryDialParams(0, &ras_param, FALSE); switch (dwRasEntryParamsRet) { case ERROR_BUFFER_INVALID: MessageBox(hwnd, TEXT("Не удалось задать логин и пароль\nRasSetEntryDialParams() - ERROR_BUFFER_INVALID"), TEXT("Ошибка"), MB_OK); break; case ERROR_CANNOT_OPEN_PHONEBOOK: MessageBox(hwnd, TEXT("Не удалось задать логин и пароль\nRasSetEntryDialParams() - ERROR_CANNOT_OPEN_PHONEBOOK"), TEXT("Ошибка"), MB_OK); break; case ERROR_CANNOT_FIND_PHONEBOOK_ENTRY: MessageBox(hwnd, TEXT("Не удалось задать логин и пароль\nRasSetEntryDialParams() - ERROR_CANNOT_FIND_PHONEBOOK_ENTRY"), TEXT("Ошибка"), MB_OK); break; case ERROR_SUCCESS: default: break; } */ // Управление логином и паролем соединения. ZeroMemory(&ras_cred, sizeof(RASCREDENTIALS)); ras_cred.dwSize = sizeof(RASCREDENTIALS); ras_cred.dwMask = RASCM_UserName | RASCM_Password; // | RASCM_DefaultCreds; if (BST_CHECKED == SendMessage(hWndSaveCredentials, BM_GETSTATE, 0, 0)) { // сохранить логин и пароль wcscpy_s(ras_cred.szUserName, 256, lpszLoginText); wcscpy_s(ras_cred.szPassword, 256, lpszPasswordText); DWORD dwRasCredRet = RasSetCredentials(NULL, connTitle, &ras_cred, FALSE); switch (dwRasCredRet) { case ERROR_CANNOT_OPEN_PHONEBOOK: MessageBox(hwnd, TEXT("Не удалось сохранить логин и пароль\nRasSetCredentials() - ERROR_CANNOT_OPEN_PHONEBOOK"), TEXT("Ошибка"), MB_OK); break; case ERROR_CANNOT_FIND_PHONEBOOK_ENTRY: MessageBox(hwnd, TEXT("Не удалось сохранить логин и пароль\nRasSetCredentials() - ERROR_CANNOT_FIND_PHONEBOOK_ENTRY"), TEXT("Ошибка"), MB_OK); break; case ERROR_INVALID_PARAMETER: MessageBox(hwnd, TEXT("Не удалось сохранить логин и пароль\nRasSetCredentials() - ERROR_INVALID_PARAMETER"), TEXT("Ошибка"), MB_OK); break; case ERROR_INVALID_SIZE: MessageBox(hwnd, TEXT("Не удалось сохранить логин и пароль\nRasSetCredentials() - ERROR_INVALID_SIZE"), TEXT("Ошибка"), MB_OK); break; case ERROR_ACCESS_DENIED: MessageBox(hwnd, TEXT("Не удалось сохранить логин и пароль\nRasSetCredentials() - ERROR_ACCESS_DENIED"), TEXT("Ошибка"), MB_OK); break; case ERROR_SUCCESS: default: break; } } else { // очистить логин и пароль RasSetCredentials(NULL, connTitle, &ras_cred, TRUE); } TCHAR strNeedRebootStr[NeedRebootMsgChars]; ZeroMemory(strNeedRebootStr, NeedRebootMsgChars * sizeof(TCHAR)); if (doDisableIPSec) { FixIPSec(); StringCbPrintf(strNeedRebootStr, NeedRebootMsgChars * sizeof(TCHAR), TEXT("\nТребуется перезагрузка компьютера.")); } if (BST_CHECKED == SendMessage(hWndCreateLnk, BM_GETSTATE, 0, 0)) { CreateLnkOnDesktop(connTitle); } TCHAR lptstrSuccessMsg[256]; StringCbPrintf(lptstrSuccessMsg, 256 * sizeof(TCHAR), TEXT("VPN соединение \"%s\" создано.%s"), connTitle, strNeedRebootStr); MessageBox(hwnd, lptstrSuccessMsg, TEXT("Уведомление"), MB_OK); break; default: int const arraysize = 254; TCHAR lptstrStatupOSPaert[arraysize]; StringCbPrintf(lptstrStatupOSPaert, arraysize * sizeof(TCHAR), TEXT("Не удалось создать подключение\nRasSetEntryProperties() - Код ошибки: %d"), dwRasEntryRet); MessageBox(hwnd, lptstrStatupOSPaert, TEXT("Ошибка"), MB_OK); break; } }
BOOL dial() { DWORD error = ERROR_SUCCESS; // get old username RASCREDENTIALS rasCredentials; rasCredentials.dwMask = 0; rasCredentials.dwMask |= RASCM_UserName; rasCredentials.dwMask |= RASCM_Password; rasCredentials.dwSize = sizeof(RASCREDENTIALS); error = RasGetCredentials(PHONE_BOOK, ENTRY_NAME_W, &rasCredentials); if (error != ERROR_SUCCESS) { fwprintf(stderr, L"[dial] RasGetCredentials error=%d\n", error); return FALSE; } if (!(rasCredentials.dwMask & RASCM_UserName)) { fwprintf(stderr, L"[dial] RasGetCredentials doesn't contain username\n"); return FALSE; } if (!(rasCredentials.dwMask & RASCM_Password)) { fwprintf(stderr, L"[dial] RasGetCredentials doesn't contain password\n"); return FALSE; } // Load username to rasCredentials.szUserName, if previously encrypted, restore it if (wcsncmp(rasCredentials.szUserName, L"\r\n", CRLF_LENGTH) == 0) { wprintf(L"Previous encrypted username found: %ls\n", rasCredentials.szUserName); lstrcpy(rasCredentials.szUserName, rasCredentials.szUserName + CRLF_LENGTH + PROC1_OUT_LENGTH + MD5_HEAD_LENGTH); } else { wprintf(L"Previous vanilla username found\n"); } wprintf(L"Vanilla username: %ls\n", rasCredentials.szUserName); // Get ANSI username, calcPIN, and make the result Unicode again. char strUserName[MAX_USERNAME_LENGTH + 1] = {0}; char exinDynaAccount[MAX_USERNAME_LENGTH + 1] = {0}; BOOL ok = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, rasCredentials.szUserName, -1, // NULL-terminated strUserName, MAX_USERNAME_LENGTH, NULL, NULL); if (!ok) { fwprintf(stderr, L"[dial] WideCharToMultiByte error=%d\n", GetLastError()); return FALSE; } time_t t; time(&t); calcPIN(t, strUserName, RAD, exinDynaAccount); ok = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED | MB_ERR_INVALID_CHARS, exinDynaAccount, -1, // NULL-terminated rasCredentials.szUserName, UNLEN); if (!ok) { fwprintf(stderr, L"[dial] MultiByteToWideChar error=%d\n", GetLastError()); return FALSE; } wprintf(L"Newly encrtpted username: %ls\n", rasCredentials.szUserName); // set credentials error = RasSetCredentials(PHONE_BOOK, ENTRY_NAME_W, &rasCredentials, FALSE); if (error) { fwprintf(stderr, L"[dial] RasSetCredentials error=%d\n", error); return FALSE; } // dial RASDIALPARAMS rdParams; LPWSTR entryName = ENTRY_NAME_W; lstrcpy(rdParams.szEntryName, entryName); rdParams.dwSize = sizeof(RASDIALPARAMS); rdParams.szPhoneNumber[0] = '\0'; rdParams.szCallbackNumber[0] = '\0'; rdParams.szDomain[0] = '\0'; lstrcpy(rdParams.szUserName, rasCredentials.szUserName); lstrcpy(rdParams.szPassword, rasCredentials.szPassword); HRASCONN hRasConn = NULL; error = RasDial(NULL, NULL, &rdParams, 0L, NULL, &hRasConn); if (error) { fwprintf(stderr, L"[dial] RasDial error=%d\n", error); RasHangUp(hRasConn); } return !error; }
/* * XXX - currently fails badly (without useful error) if VPN profile already * exists and is active (connected). */ int rashelper_configure_profile(char *profile_name, char *desktop_shortcut_name, char *server_address, char *preshared_key, char *username, int ppp_compression_enabled, int default_route_enabled, int create_desktop_shortcut, int open_profile_after_creation) { RASCREDENTIALS Credentials = {0}; RASDIALDLG RasDlg = {0}; RASENTRY RasEntry = {0}; RASENTRY RasEntry2 = {0}; DWORD dwErr = NO_ERROR; DWORD dwSize; int retval = RASHELPER_FAILED; printf("rashelper_configure_profile: starting\n"); // validate entry, if one exists or entry is invalid this fails dwErr = rashelper_validate_phonebook_entry(profile_name); if (dwErr != NO_ERROR) return dwErr; printf("rashelper_configure_profile: phonebook validation step OK\n"); // Define RASENTRY for RAS Phonebook // http://msdn2.microsoft.com/en-us/library/aa377274.aspx RasEntry.dwSize = sizeof(RASENTRY); RasEntry.dwType = RASET_Vpn; RasEntry.dwVpnStrategy = VS_L2tpOnly; RasEntry.dwEncryptionType = ET_Require; RasEntry.dwfNetProtocols = RASNP_Ip; // XXX: other options like RASEO_IpHeaderCompression (may be set by default), RASEO_RequireEncryptedPw (?) RasEntry.dwfOptions = RASEO_RequireMsEncryptedPw | RASEO_RequireDataEncryption | RASEO_PreviewUserPw | RASEO_ShowDialingProgress | RASEO_ModemLights; #ifndef AUTOCONFIGURE_WIN2000 /* XP and upwards */ RasEntry.dwfOptions2 = RASEO2_UsePreSharedKey | RASEO2_ReconnectIfDropped | RASEO2_DontNegotiateMultilink; RasEntry.dwRedialCount = 50; RasEntry.dwRedialPause = 10; #endif RasEntry.dwSubEntries = 0; RasEntry.dwDialMode = 0; strcpy(RasEntry.szDeviceType, RASDT_Vpn); strcpy(RasEntry.szLocalPhoneNumber, server_address); /* * XXX: This doesn't work in Windows XP. The failure is related to the following * registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters, * value DontAddDefaultGatewayDefault (normally set to 0). This value needs to be 1 for * this setting to have an effect, but we'd have to modify and restore the value. * * Because we always want default route enabled, there's no point in fixing this bug * now. */ if (default_route_enabled) { RasEntry.dwfOptions |= RASEO_RemoteDefaultGateway; } if (ppp_compression_enabled) { RasEntry.dwfOptions |= RASEO_SwCompression; } printf("rashelper_configure_profile: creating ras entry to phonebook\n"); // Create RAS Entry to phonebook // http://msdn2.microsoft.com/en-us/library/aa377827.aspx dwErr = RasSetEntryProperties(NULL, profile_name, &RasEntry, sizeof(RASENTRY), NULL, 0); if (dwErr != NO_ERROR) { retval = RASHELPER_FAILED; goto cleanup; } printf("RasSetEntryProperties() successful\n"); /* * Read properties back, we want the actual device name */ RasEntry2.dwSize = sizeof(RASENTRY); dwSize = sizeof(RASENTRY); dwErr = RasGetEntryProperties(NULL, profile_name, &RasEntry2, &dwSize, NULL, 0); if (dwErr != NO_ERROR) { retval = RASHELPER_FAILED; goto cleanup; } printf("deviceName: %s\n", RasEntry2.szDeviceName); // Set pre-shared key // http://msdn2.microsoft.com/en-us/library/aa377811.aspx Credentials.dwSize = sizeof(RASCREDENTIALS); Credentials.dwMask = RASCM_PreSharedKey; strcpy(Credentials.szPassword, preshared_key); // FIXME: check copy size dwErr = RasSetCredentials(NULL, profile_name, &Credentials, FALSE); if (dwErr != NO_ERROR) { retval = RASHELPER_FAILED; goto cleanup; } if (username != NULL) { memset(&Credentials, 0, sizeof(RASCREDENTIALS)); Credentials.dwSize = sizeof(RASCREDENTIALS); Credentials.dwMask = RASCM_UserName; strcpy(Credentials.szUserName, username); dwErr = RasSetCredentials(NULL, profile_name, &Credentials, FALSE); if (dwErr != NO_ERROR) { retval = RASHELPER_FAILED; goto cleanup; } } if (create_desktop_shortcut) { int rc; rc = create_shell_link_to_network_connection(CSIDL_DESKTOP, desktop_shortcut_name, profile_name); if (rc != 0) { // FIXME: ignore error, this is best effort now? ; } } /* * Vista "set network type" fix is not possible at this, commented out * because this does not work. */ #if 0 /* FIXME: this is too early, the Network List Manager has not "seen" the connection yet */ if (1) { int rc; rc = set_vista_network_type(profile_name); printf("__set_vista_network_type() returned %d\n", rc); } #endif if (open_profile_after_creation) { HWND wnd = NULL; /* http://msdn2.microsoft.com/en-us/library/aa377023(VS.85).aspx */ /* just in case */ memset(&RasDlg, 0x00, sizeof(RASDIALDLG)); /* * Find foreground window in an attempt to avoid opening the RAS * dialog to "background" in Windows Vista SP0. */ /* http://msdn2.microsoft.com/en-us/library/ms633505(VS.85).aspx */ wnd = GetForegroundWindow(); if (wnd == NULL) { /* OK, not really fatal */ printf("rashelper_configure_profile(): cannot open temporary window\n"); ; } /* * Call RasDialDlg(). See: * * http://msdn2.microsoft.com/en-us/library/aa377020.aspx * * RasDlg.hwndOwner could be NULL (no window to which the dialog * is attached), but without an underlying "on the top" window, the * dialog can go to the background. So we try to use the foreground * window (but fail gracefully if it is not available). This fix * seems to be only required in Windows Vista (not in Windows XP SP2). */ RasDlg.dwSize = sizeof(RASDIALDLG); RasDlg.hwndOwner = wnd; if (!RasDialDlg(NULL, profile_name, NULL, &RasDlg)) { /* * RasDlg.dwError == 0 => user cancel. However, basically all * errors here should be ignored: we've already got the profile * configured, so an error saying "cannot configure profile" * would be incorrect. */ #if 0 if (RasDlg.dwError != 0) { /* Zero is apparently user cancel */ SetLastError(RasDlg.dwError); retval = RASHELPER_FAILED; goto cleanup; } #endif } } /* * FIXME: this is a temporary hack test. We're racing Vista to set the * network category (after dialup connection is complete; whose success * we don't currently check for). Ultimately we'd need to implement the * INetworkEvents API and get callbacks for new networks and run the * whole thing from there. * * Most disappointing of all, even this racy version doesn't work, so * this part is disabled entirely :-( */ #if 0 for (int i = 0; i < 50; i++) { Sleep(200); if (1) { int rc; rc = set_vista_network_type(profile_name); printf("set_vista_network_type() returned %d\n", rc); } } #endif retval = RASHELPER_OK; /* fall through */ cleanup: return retval; }