Implement importing profile from a generic URL

ParseUrl extended to parse generic URLs and parse
the path. DownloadProfile() function re-factored
for reuse with generic URL.

Also:
- INTERNET_FLAG_RELOAD added to the request
  call to force reloading the data from server instead
  of using possibly cached data.
- Input box for URL extended in length to about
   50 characters wide.

Signed-off-by: Selva Nair <selva.nair@gmail.com>
pull/449/head
Selva Nair 3 years ago
parent 480d9e456b
commit e80a39c825

126
as.c

@ -44,7 +44,7 @@
* Profile name is either (sorted in priority order):
* - value of OVPN_ACCESS_SERVER_FRIENDLY_NAME
* - value of OVPN_ACCESS_SERVER_PROFILE
* - URL
* - specified default_name
*
* @param profile profile content
* @param default_name default name for profile if it doesn't contain name
@ -88,9 +88,10 @@ ExtractProfileName(const WCHAR *profile, const WCHAR *default_name, WCHAR *out_n
out_name[out_name_length - 1] = L'\0';
/* sanitize profile name */
const char *reserved = "<>:\"/\\|?*;"; /* remap these and ascii 1 to 31 */
while (*out_name) {
wchar_t c = *out_name;
if (c == L'<' || c == L'>' || c == L':' || c == L'\"' || c == L'/' || c == L'\\' || c == L'|' || c == L'?' || c == L'*')
if (c < 32 || strchr(reserved, c))
*out_name = L'_';
++out_name;
}
@ -111,6 +112,7 @@ struct UrlComponents
{
int port;
WCHAR host[URL_LEN];
WCHAR path[URL_LEN];
bool https;
};
@ -124,27 +126,33 @@ ParseUrl(const WCHAR *url, struct UrlComponents* comps)
{
ZeroMemory(comps, sizeof(struct UrlComponents));
int domain_off = 0;
comps->port = 443;
comps->https = true;
if (wcsbegins(url, L"http://")) {
domain_off = 7;
url += 7;
} else if (wcsbegins(url, L"https://")) {
domain_off = 8;
url +=8;
}
WCHAR* strport = wcsstr(url + domain_off, L":");
WCHAR *strport = wcsstr(url, L":");
WCHAR *pathptr = wcsstr(url, L"/");
if (strport) {
WCHAR* end;
wcsncpy(comps->host, url + domain_off, strport - url - domain_off);
comps->port = wcstol(strport + 1, &end, 10);
wcsncpy_s(comps->host, URL_LEN, url, strport - url);
comps->port = wcstol(strport + 1, NULL, 10);
}
else {
wcscpy(comps->host, url + domain_off);
else if (pathptr)
{
wcsncpy_s(comps->host, URL_LEN, url, pathptr - url);
}
else
{
wcsncpy_s(comps->host, URL_LEN, url, _TRUNCATE);
}
if (comps->host[wcslen(comps->host) - 1] == L'/')
comps->host[wcslen(comps->host) - 1] = L'\0';
if (pathptr)
{
wcsncpy_s(comps->path, URL_LEN, pathptr + 1, _TRUNCATE);
}
}
/**
@ -270,19 +278,38 @@ CRDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
}
/**
* Download profile from AS and save it to a special-named temp file
* Construct the REST URL for AS profile
*
* @param hWnd handle of window which initiated download
* @param host AS hostname, entered by user, might contain protocol and port
* @param autologin should autologin profile be used
* @param comps Pointer to UrlComponents. Value assigned by this function.
*/
static void
GetASUrl(const WCHAR *host, bool autologin, struct UrlComponents *comps)
{
ParseUrl(host, comps);
swprintf(comps->path, URL_LEN, L"/rest/%ls?tls-cryptv2=1&action=import", autologin ? L"GetAutologin" : L"GetUserlogin");
comps->path[URL_LEN - 1] = L'\0';
}
/**
* Download profile from a generic URL and save it to a temp file
*
* @param hWnd handle of window which initiated download
* @param comps pointer to struct UrlComponents describing the URL
* @param username UTF-8 encoded username used for HTTP basic auth
* @param password UTF-8 encoded password used for HTTP basic auth
* @param autologin should autologin profile be used
* @param out_path full path to where profile is downloaded. Value assigned by this function.
* @param out_path_size number of elements in out_path arrray
*
* Filename in out_path is parsed from tags in received data
* with the url hostname as a fallback.
*/
BOOL
DownloadProfile(HANDLE hWnd, const WCHAR *host, const char *username, const char *password_orig,
BOOL autologin, WCHAR *out_path, size_t out_path_size)
static BOOL
DownloadProfile(HANDLE hWnd, const struct UrlComponents *comps, const char *username,
const char *password_orig, WCHAR *out_path, size_t out_path_size)
{
HANDLE hInternet = NULL;
HANDLE hConnect = NULL;
@ -290,9 +317,9 @@ DownloadProfile(HANDLE hWnd, const WCHAR *host, const char *username, const char
BOOL result = FALSE;
char* buf = NULL;
/* need to make copy of password to use it for dynamic response */
char password[USER_PASS_LEN] = { 0 };
strncpy(password, password_orig, USER_PASS_LEN - 1);
password[USER_PASS_LEN - 1] = '\0';
strncpy_s(password, _countof(password), password_orig, _TRUNCATE);
hInternet = InternetOpenW(L"openvpn-gui/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!hInternet) {
@ -300,22 +327,18 @@ DownloadProfile(HANDLE hWnd, const WCHAR *host, const char *username, const char
goto done;
}
struct UrlComponents comps = { 0 };
ParseUrl(host, &comps);
/* wait cursor will be automatically reverted later */
SetCursor(LoadCursorW(0, IDC_WAIT));
hConnect = InternetConnectW(hInternet, comps.host, comps.port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
hConnect = InternetConnectW(hInternet, comps->host, comps->port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if (!hConnect) {
ShowWinInetError(hWnd);
goto done;
}
WCHAR obj_name[URL_LEN] = { 0 };
swprintf(obj_name, URL_LEN, L"/rest/%ls?tls-cryptv2=1&action=import", autologin ? L"GetAutologin" : L"GetUserlogin");
obj_name[URL_LEN - 1] = L'\0';
hRequest = HttpOpenRequestW(hConnect, NULL, obj_name, NULL, NULL, NULL, comps.https ? INTERNET_FLAG_SECURE : 0, 0);
DWORD req_flags = INTERNET_FLAG_RELOAD; /* load from server, do not use cached data */
req_flags |= comps->https ? INTERNET_FLAG_SECURE : 0;
hRequest = HttpOpenRequestW(hConnect, NULL, comps->path, NULL, NULL, NULL, req_flags, 0);
if (!hRequest) {
ShowWinInetError(hWnd);
goto done;
@ -423,7 +446,7 @@ again:
MessageBoxW(hWnd, L"Failed to convert profile content to wchar", _T(PACKAGE_NAME), MB_OK);
goto done;
}
ExtractProfileName(wbuf, comps.host, name, MAX_PATH);
ExtractProfileName(wbuf, comps->host, name, MAX_PATH);
free(wbuf);
/* save profile content into tmp file */
@ -460,38 +483,53 @@ done:
return result;
}
typedef enum {
server_as = 1,
server_generic = 2
} server_type_t;
INT_PTR CALLBACK
ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
WCHAR url[URL_LEN] = {0};
BOOL autologin = FALSE;
server_type_t type;
switch (msg)
{
case WM_INITDIALOG:
type = (server_type_t) lParam;
SetProp(hwndDlg, cfgProp, (HANDLE)lParam);
SetStatusWinIcon(hwndDlg, ID_ICO_APP);
/* disable OK button by default - not disabled in resources */
if (type == server_generic)
{
/* Change window title and hide autologin checkbox */
SetWindowTextW(hwndDlg, LoadLocalizedString(IDS_MENU_IMPORT_URL));
ShowWindow(GetDlgItem(hwndDlg, ID_CHK_AUTOLOGIN), SW_HIDE);
}
/* disable OK button until required data is filled in */
EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
break;
case WM_COMMAND:
type = (server_type_t) GetProp(hwndDlg, cfgProp);
switch (LOWORD(wParam))
{
case ID_EDT_AUTH_USER:
case ID_EDT_AUTH_PASS:
case ID_EDT_URL:
if (HIWORD(wParam) == EN_UPDATE) {
/* enable OK button only if url and username are filled */
/* enable OK button only if url and username (for AS only) are filled */
BOOL enableOK = GetWindowTextLengthW(GetDlgItem(hwndDlg, ID_EDT_URL))
&& GetWindowTextLengthW(GetDlgItem(hwndDlg, ID_EDT_AUTH_USER));
&& (type == server_generic
|| GetWindowTextLengthW(GetDlgItem(hwndDlg, ID_EDT_AUTH_USER)));
EnableWindow(GetDlgItem(hwndDlg, IDOK), enableOK);
}
break;
case IDOK:
autologin = IsDlgButtonChecked(hwndDlg, ID_CHK_AUTOLOGIN) == BST_CHECKED;
GetDlgItemTextW(hwndDlg, ID_EDT_URL, url, _countof(url));
@ -504,7 +542,18 @@ ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa
GetDlgItemTextUtf8(hwndDlg, ID_EDT_AUTH_PASS, &password, &password_len);
WCHAR path[MAX_PATH + 1] = { 0 };
BOOL downloaded = DownloadProfile(hwndDlg, url, username, password, autologin, path, _countof(path));
struct UrlComponents comps = {0};
if (type == server_as)
{
autologin = IsDlgButtonChecked(hwndDlg, ID_CHK_AUTOLOGIN) == BST_CHECKED;
GetASUrl(url, autologin, &comps);
}
else
{
ParseUrl(url, &comps);
}
BOOL downloaded = DownloadProfile(hwndDlg, &comps, username, password, path, _countof(path));
if (username_len != 0)
free(username);
@ -540,5 +589,10 @@ ImportProfileFromURLDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lPa
void ImportConfigFromAS()
{
LocalizedDialogBoxParam(ID_DLG_URL_PROFILE_IMPORT, ImportProfileFromURLDialogFunc, 0);
LocalizedDialogBoxParam(ID_DLG_URL_PROFILE_IMPORT, ImportProfileFromURLDialogFunc, (LPARAM) server_as);
}
void ImportConfigFromURL()
{
LocalizedDialogBoxParam(ID_DLG_URL_PROFILE_IMPORT, ImportProfileFromURLDialogFunc, (LPARAM) server_generic);
}

@ -20,3 +20,4 @@
*/
void ImportConfigFromAS();
void ImportConfigFromURL();

@ -559,6 +559,9 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM
else if (LOWORD(wParam) == IDM_IMPORT_AS) {
ImportConfigFromAS();
}
else if (LOWORD(wParam) == IDM_IMPORT_URL) {
ImportConfigFromURL();
}
else if (LOWORD(wParam) == IDM_SETTINGS) {
ShowSettingsDialog();
}

@ -183,6 +183,7 @@
#define IDS_MENU_RECONNECT 1025
#define IDS_MENU_IMPORT_AS 1026
#define IDS_MENU_IMPORT_FILE 1027
#define IDS_MENU_IMPORT_URL 1028
/* LogViewer Dialog */
#define IDS_ERR_START_LOG_VIEWER 1101

@ -264,14 +264,14 @@ BEGIN
END
/* URL Profile Import Dialog */
ID_DLG_URL_PROFILE_IMPORT DIALOG 6, 18, 160, 95
ID_DLG_URL_PROFILE_IMPORT DIALOG 6, 18, 249, 95
STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | DS_CENTER | DS_SETFOREGROUND
CAPTION "Import Profile from Access Server"
FONT 8, "Microsoft Sans Serif"
LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
BEGIN
LTEXT "U&RL:", 201, 6, 9, 50, 10
EDITTEXT ID_EDT_URL, 60, 6, 94, 12, ES_AUTOHSCROLL
EDITTEXT ID_EDT_URL, 60, 6, 183, 12, ES_AUTOHSCROLL
LTEXT "&Username:", 202, 6, 26, 50, 10
EDITTEXT ID_EDT_AUTH_USER, 60, 23, 94, 12, ES_AUTOHSCROLL
LTEXT "&Password:", ID_LTEXT_PASSWORD, 6, 42, 50, 10
@ -295,6 +295,7 @@ BEGIN
IDS_MENU_SERVICE "OpenVPN Service"
IDS_MENU_IMPORT "Import"
IDS_MENU_IMPORT_AS "Import from Access Server…"
IDS_MENU_IMPORT_URL "Import from URL…"
IDS_MENU_IMPORT_FILE "Import file…"
IDS_MENU_SETTINGS "Settings…"
IDS_MENU_CLOSE "Exit"

@ -220,6 +220,7 @@ CreatePopupMenus()
AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuImport, LoadLocalizedString(IDS_MENU_IMPORT));
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_FILE, LoadLocalizedString(IDS_MENU_IMPORT_FILE));
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_AS, LoadLocalizedString(IDS_MENU_IMPORT_AS));
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_URL, LoadLocalizedString(IDS_MENU_IMPORT_URL));
AppendMenu(hMenu, MF_STRING ,IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
AppendMenu(hMenu, MF_STRING ,IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));
@ -280,6 +281,7 @@ CreatePopupMenus()
AppendMenu(hMenu, MF_POPUP, (UINT_PTR) hMenuImport, LoadLocalizedString(IDS_MENU_IMPORT));
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_FILE, LoadLocalizedString(IDS_MENU_IMPORT_FILE));
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_AS, LoadLocalizedString(IDS_MENU_IMPORT_AS));
AppendMenu(hMenuImport, MF_STRING, IDM_IMPORT_URL, LoadLocalizedString(IDS_MENU_IMPORT_URL));
AppendMenu(hMenu, MF_STRING, IDM_SETTINGS, LoadLocalizedString(IDS_MENU_SETTINGS));
AppendMenu(hMenu, MF_STRING, IDM_CLOSE, LoadLocalizedString(IDS_MENU_CLOSE));

@ -34,6 +34,7 @@
#define IDM_IMPORT 224
#define IDM_IMPORT_FILE 225
#define IDM_IMPORT_AS 226
#define IDM_IMPORT_URL 227
#define IDM_CONNECTMENU 300
#define IDM_DISCONNECTMENU (1 + IDM_CONNECTMENU)

Loading…
Cancel
Save