mirror of https://github.com/OpenVPN/openvpn-gui
Support pkcs11 token insertion request and pin input
Note: IDS_NFO_TOKEN_PASSWORD_CAPTION and IDS_NFO_TOKEN_PASSWORD_REQUEST strings need translation. TODO: support for selecting pkcs11-id from the GUI Signed-off-by: Selva Nair <selva.nair@gmail.com>pull/91/head
parent
1a5ce44a99
commit
be417bb38f
2
main.c
2
main.c
|
@ -116,6 +116,8 @@ int WINAPI _tWinMain (HINSTANCE hThisInstance,
|
||||||
{ password, OnPassword },
|
{ password, OnPassword },
|
||||||
{ proxy, OnProxy },
|
{ proxy, OnProxy },
|
||||||
{ stop, OnStop },
|
{ stop, OnStop },
|
||||||
|
{ needok, OnNeedOk },
|
||||||
|
{ needstr, OnNeedStr },
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
InitManagement(handler);
|
InitManagement(handler);
|
||||||
|
|
10
manage.c
10
manage.c
|
@ -312,6 +312,16 @@ OnManagement(SOCKET sk, LPARAM lParam)
|
||||||
if (rtmsg_handler[ready])
|
if (rtmsg_handler[ready])
|
||||||
rtmsg_handler[ready](c, pos + 5);
|
rtmsg_handler[ready](c, pos + 5);
|
||||||
}
|
}
|
||||||
|
else if (strncmp(pos, "NEED-OK:", 8) == 0)
|
||||||
|
{
|
||||||
|
if (rtmsg_handler[needok])
|
||||||
|
rtmsg_handler[needok](c, pos + 8);
|
||||||
|
}
|
||||||
|
else if (strncmp(pos, "NEED-STR:", 9) == 0)
|
||||||
|
{
|
||||||
|
if (rtmsg_handler[needstr])
|
||||||
|
rtmsg_handler[needstr](c, pos + 9);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (c->manage.cmd_queue)
|
else if (c->manage.cmd_queue)
|
||||||
{
|
{
|
||||||
|
|
|
@ -301,7 +301,12 @@
|
||||||
/* Save password related messages */
|
/* Save password related messages */
|
||||||
#define IDS_NFO_DELETE_PASS 2001
|
#define IDS_NFO_DELETE_PASS 2001
|
||||||
|
|
||||||
|
/* Token password dialog related */
|
||||||
|
#define IDS_NFO_TOKEN_PASSWORD_CAPTION 2100
|
||||||
|
#define IDS_NFO_TOKEN_PASSWORD_REQUEST 2101
|
||||||
|
|
||||||
/* Timer IDs */
|
/* Timer IDs */
|
||||||
#define IDT_STOP_TIMER 2500 /* Timer used to trigger force termination */
|
#define IDT_STOP_TIMER 2500 /* Timer used to trigger force termination */
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
199
openvpn.c
199
openvpn.c
|
@ -63,6 +63,10 @@ const TCHAR *cfgProp = _T("conn");
|
||||||
#define FLAG_CR_TYPE_CRV1 0x2 /* dynamic challenege */
|
#define FLAG_CR_TYPE_CRV1 0x2 /* dynamic challenege */
|
||||||
#define FLAG_CR_ECHO 0x4 /* echo the response */
|
#define FLAG_CR_ECHO 0x4 /* echo the response */
|
||||||
#define FLAG_CR_RESPONSE 0x8 /* response needed */
|
#define FLAG_CR_RESPONSE 0x8 /* response needed */
|
||||||
|
#define FLAG_PASS_TOKEN 0x10 /* PKCS11 token password needed */
|
||||||
|
#define FLAG_STRING_PKCS11 0x20 /* PKCS11 id needed */
|
||||||
|
#define FLAG_PASS_PKEY 0x40 /* Private key password needed */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
connection_t *c;
|
connection_t *c;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
@ -395,6 +399,16 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
if (param->flags & FLAG_CR_ECHO)
|
if (param->flags & FLAG_CR_ECHO)
|
||||||
SendMessage(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), EM_SETPASSWORDCHAR, 0, 0);
|
SendMessage(GetDlgItem(hwndDlg, ID_EDT_RESPONSE), EM_SETPASSWORDCHAR, 0, 0);
|
||||||
}
|
}
|
||||||
|
else if (param->flags & FLAG_PASS_TOKEN)
|
||||||
|
{
|
||||||
|
SetWindowText(hwndDlg, LoadLocalizedString(IDS_NFO_TOKEN_PASSWORD_CAPTION));
|
||||||
|
SetDlgItemText(hwndDlg, ID_TXT_DESCRIPTION, LoadLocalizedString(IDS_NFO_TOKEN_PASSWORD_REQUEST, param->id));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteStatusLog(param->c, L"GUI> ", L"Unknown password request", false);
|
||||||
|
SetDlgItemText(hwndDlg, ID_TXT_DESCRIPTION, wstr);
|
||||||
|
}
|
||||||
free(wstr);
|
free(wstr);
|
||||||
|
|
||||||
AppendTextToCaption (hwndDlg, param->c->config_name);
|
AppendTextToCaption (hwndDlg, param->c->config_name);
|
||||||
|
@ -407,14 +421,17 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
param = (auth_param_t *) GetProp(hwndDlg, cfgProp);
|
param = (auth_param_t *) GetProp(hwndDlg, cfgProp);
|
||||||
|
const char *template;
|
||||||
|
char *fmt;
|
||||||
switch (LOWORD(wParam))
|
switch (LOWORD(wParam))
|
||||||
{
|
{
|
||||||
case IDOK:
|
case IDOK:
|
||||||
if (param->flags & FLAG_CR_TYPE_CRV1)
|
if (param->flags & FLAG_CR_TYPE_CRV1)
|
||||||
{
|
{
|
||||||
/* send username */
|
/* send username */
|
||||||
const char *template = "username \"Auth\" \"%s\"";
|
template = "username \"Auth\" \"%s\"";
|
||||||
char *fmt = malloc(strlen(template) + strlen(param->user));
|
fmt = malloc(strlen(template) + strlen(param->user));
|
||||||
|
|
||||||
if (fmt)
|
if (fmt)
|
||||||
{
|
{
|
||||||
sprintf(fmt, template, param->user);
|
sprintf(fmt, template, param->user);
|
||||||
|
@ -424,31 +441,33 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
else /* no memory? send an emty username and let it error out */
|
else /* no memory? send an emty username and let it error out */
|
||||||
{
|
{
|
||||||
WriteStatusLog(param->c, L"GUI> ",
|
WriteStatusLog(param->c, L"GUI> ",
|
||||||
L"Out of memory: sending empty username for dynamic CR", false);
|
L"Out of memory: sending a generic username for dynamic CR", false);
|
||||||
ManagementCommand(param->c, "username \"Auth\" \"user\"", NULL, regular);
|
ManagementCommand(param->c, "username \"Auth\" \"user\"", NULL, regular);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send password */
|
/* password template */
|
||||||
template = "password \"Auth\" \"CRV1::%s::%%s\"";
|
template = "password \"Auth\" \"CRV1::%s::%%s\"";
|
||||||
fmt = malloc(strlen(template) + strlen(param->id));
|
|
||||||
if (fmt)
|
|
||||||
{
|
|
||||||
sprintf(fmt, template, param->id);
|
|
||||||
ManagementCommandFromInput(param->c, fmt, hwndDlg, ID_EDT_RESPONSE);
|
|
||||||
free (fmt);
|
|
||||||
}
|
|
||||||
else /* no memory? send an empty password and let it error out. */
|
|
||||||
{
|
|
||||||
WriteStatusLog(param->c, L"GUI> ",
|
|
||||||
L"Out of memory: sending empty password for dynamic CR", false);
|
|
||||||
ManagementCommand(param->c, "password \"Auth\" \"CRV1::0::\"", NULL, regular);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else /* generic password request of type param->id */
|
||||||
{
|
{
|
||||||
/* Unknown request ? */
|
template = "password \"%s\" \"%%s\"";
|
||||||
WriteStatusLog(param->c, L"GUI> ", L"Unknown password reuest ignored", false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt = malloc(strlen(template) + strlen(param->id));
|
||||||
|
if (fmt)
|
||||||
|
{
|
||||||
|
sprintf(fmt, template, param->id);
|
||||||
|
PrintDebug(L"Send passwd to mgmt with format: '%S'", fmt);
|
||||||
|
ManagementCommandFromInput(param->c, fmt, hwndDlg, ID_EDT_RESPONSE);
|
||||||
|
free (fmt);
|
||||||
|
}
|
||||||
|
else /* no memory? send stop signal */
|
||||||
|
{
|
||||||
|
WriteStatusLog(param->c, L"GUI> ",
|
||||||
|
L"Out of memory in password dialog: sending stop signal", false);
|
||||||
|
StopOpenVPN (param->c);
|
||||||
|
}
|
||||||
|
|
||||||
EndDialog(hwndDlg, LOWORD(wParam));
|
EndDialog(hwndDlg, LOWORD(wParam));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -607,6 +626,69 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse password or string request of the form "Need 'What' password/string MSG:message"
|
||||||
|
* and assign param->id = What, param->str = message. Also set param->flags if the type
|
||||||
|
* of the requested info is known. If message is empty param->id is copied to param->str.
|
||||||
|
* Return true on succsess. The caller must free param even when the function fails.
|
||||||
|
*/
|
||||||
|
static BOOL
|
||||||
|
parse_input_request (const char *msg, auth_param_t *param)
|
||||||
|
{
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
char *p = strdup (msg);
|
||||||
|
char *sep[4] = {" ", "'", " ", ""}; /* separators to use to break up msg */
|
||||||
|
char *token[4];
|
||||||
|
|
||||||
|
char *p1 = p;
|
||||||
|
for (int i = 0; i < 4; ++i, p1 = NULL)
|
||||||
|
{
|
||||||
|
token[i] = strtok (p1, sep[i]); /* strtok is thread-safe on Windows */
|
||||||
|
if (!token[i] && i < 3) /* first three tokens required */
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (token[3] && strncmp(token[3], "MSG:", 4) == 0)
|
||||||
|
token[3] += 4;
|
||||||
|
if (!token[3] || !*token[3]) /* use id as the description if none provided */
|
||||||
|
token[3] = token[1];
|
||||||
|
|
||||||
|
PrintDebug (L"Tokens: '%S' '%S' '%S' '%S'", token[0], token[1],
|
||||||
|
token[2], token[3]);
|
||||||
|
|
||||||
|
if (strcmp (token[0], "Need") != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if ((param->id = strdup(token[1])) == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (strcmp(token[2], "password") == 0)
|
||||||
|
{
|
||||||
|
if (strcmp (param->id, "Private Key") == 0)
|
||||||
|
param->flags |= FLAG_PASS_PKEY;
|
||||||
|
else
|
||||||
|
param->flags |= FLAG_PASS_TOKEN;
|
||||||
|
}
|
||||||
|
else if (strcmp(token[2], "string") == 0
|
||||||
|
&& strcmp (param->id, "pkcs11-id-request") == 0)
|
||||||
|
{
|
||||||
|
param->flags |= FLAG_STRING_PKCS11;
|
||||||
|
}
|
||||||
|
|
||||||
|
param->str = strdup (token[3]);
|
||||||
|
if (param->str == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
PrintDebug (L"parse_input_request: id = '%S' str = '%S' flags = %u",
|
||||||
|
param->id, param->str, param->flags);
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free (p);
|
||||||
|
if (!ret)
|
||||||
|
PrintDebug (L"Error parsing password/string request msg: <%S>", msg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle >PASSWORD: request from OpenVPN management interface
|
* Handle >PASSWORD: request from OpenVPN management interface
|
||||||
*/
|
*/
|
||||||
|
@ -690,6 +772,24 @@ OnPassword(connection_t *c, char *msg)
|
||||||
{
|
{
|
||||||
QueryProxyAuth(c, socks);
|
QueryProxyAuth(c, socks);
|
||||||
}
|
}
|
||||||
|
/* All other password requests such as PKCS11 pin */
|
||||||
|
else if (strncmp(msg, "Need '", 6) == 0)
|
||||||
|
{
|
||||||
|
auth_param_t *param = (auth_param_t *) calloc(1, sizeof(auth_param_t));
|
||||||
|
|
||||||
|
if (!param)
|
||||||
|
{
|
||||||
|
WriteStatusLog (c, L"GUI> ", L"Error: Out of memory - ignoring user-auth request", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
param->c = c;
|
||||||
|
if (!parse_input_request (msg, param))
|
||||||
|
{
|
||||||
|
free_auth_param(param);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LocalizedDialogBoxParam(ID_DLG_CHALLENGE_RESPONSE, GenericPassDialogFunc, (LPARAM) param);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1047,6 +1147,65 @@ OnProcess (connection_t *c, UNUSED char *msg)
|
||||||
OnStop (c, NULL);
|
OnStop (c, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when NEED-OK is received
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
OnNeedOk (connection_t *c, char *msg)
|
||||||
|
{
|
||||||
|
char *resp = NULL;
|
||||||
|
WCHAR *wstr = NULL;
|
||||||
|
auth_param_t *param = (auth_param_t *) calloc(1, sizeof(auth_param_t));
|
||||||
|
|
||||||
|
if (!param)
|
||||||
|
{
|
||||||
|
WriteStatusLog(c, L"GUI> ", L"Error: out of memory while processing NEED-OK. Sending stop signal", false);
|
||||||
|
StopOpenVPN(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!parse_input_request(msg, param))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* allocate space for response : "needok param->id cancel/ok" */
|
||||||
|
resp = malloc (strlen(param->id) + strlen("needok \' \' cancel"));
|
||||||
|
wstr = Widen(param->str);
|
||||||
|
|
||||||
|
if (!wstr || !resp)
|
||||||
|
{
|
||||||
|
WriteStatusLog(c, L"GUI> ", L"Error: out of memory while processing NEED-OK. Sending stop signal", false);
|
||||||
|
StopOpenVPN(c);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *fmt;
|
||||||
|
if (MessageBoxW (NULL, wstr, L""PACKAGE_NAME, MB_OKCANCEL) == IDOK)
|
||||||
|
{
|
||||||
|
fmt = "needok \'%s\' ok";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ManagementCommand (c, "auth-retry none", NULL, regular);
|
||||||
|
fmt = "needok \'%s\' cancel";
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf (resp, fmt, param->id);
|
||||||
|
ManagementCommand (c, resp, NULL, regular);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free_auth_param (param);
|
||||||
|
free(wstr);
|
||||||
|
free(resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called when NEED-STR is received
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
OnNeedStr (connection_t *c, UNUSED char *msg)
|
||||||
|
{
|
||||||
|
WriteStatusLog (c, L"GUI> ", L"Error: Received NEED-STR message -- not implemented", false);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close open handles
|
* Close open handles
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,8 @@ void OnLogLine(connection_t *, char *);
|
||||||
void OnStateChange(connection_t *, char *);
|
void OnStateChange(connection_t *, char *);
|
||||||
void OnPassword(connection_t *, char *);
|
void OnPassword(connection_t *, char *);
|
||||||
void OnStop(connection_t *, char *);
|
void OnStop(connection_t *, char *);
|
||||||
|
void OnNeedOk(connection_t *, char *);
|
||||||
|
void OnNeedStr(connection_t *, char *);
|
||||||
|
|
||||||
void DisablePasswordSave(connection_t *);
|
void DisablePasswordSave(connection_t *);
|
||||||
|
|
||||||
|
|
|
@ -84,8 +84,8 @@ typedef struct {
|
||||||
} service_io_t;
|
} service_io_t;
|
||||||
|
|
||||||
#define FLAG_ALLOW_CHANGE_PASSPHRASE (1<<1)
|
#define FLAG_ALLOW_CHANGE_PASSPHRASE (1<<1)
|
||||||
#define FLAG_SAVE_KEY_PASS 1<<4
|
#define FLAG_SAVE_KEY_PASS (1<<4)
|
||||||
#define FLAG_SAVE_AUTH_PASS 1<<5
|
#define FLAG_SAVE_AUTH_PASS (1<<5)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned short major, minor, build, revision;
|
unsigned short major, minor, build, revision;
|
||||||
|
|
|
@ -448,4 +448,9 @@ BEGIN
|
||||||
|
|
||||||
/* save/delete password */
|
/* save/delete password */
|
||||||
IDS_NFO_DELETE_PASS "Press OK to delete saved passwords for config ""%s"""
|
IDS_NFO_DELETE_PASS "Press OK to delete saved passwords for config ""%s"""
|
||||||
|
|
||||||
|
/* Token password related */
|
||||||
|
IDS_NFO_TOKEN_PASSWORD_CAPTION "OpenVPN - Token Password"
|
||||||
|
IDS_NFO_TOKEN_PASSWORD_REQUEST "Input Password/PIN for Token '%S'"
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
Loading…
Reference in New Issue