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 },
|
||||
{ proxy, OnProxy },
|
||||
{ stop, OnStop },
|
||||
{ needok, OnNeedOk },
|
||||
{ needstr, OnNeedStr },
|
||||
{ 0, NULL }
|
||||
};
|
||||
InitManagement(handler);
|
||||
|
|
10
manage.c
10
manage.c
|
@ -312,6 +312,16 @@ OnManagement(SOCKET sk, LPARAM lParam)
|
|||
if (rtmsg_handler[ready])
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -301,7 +301,12 @@
|
|||
/* Save password related messages */
|
||||
#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 */
|
||||
#define IDT_STOP_TIMER 2500 /* Timer used to trigger force termination */
|
||||
|
||||
|
||||
#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_ECHO 0x4 /* echo the response */
|
||||
#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 {
|
||||
connection_t *c;
|
||||
unsigned int flags;
|
||||
|
@ -395,6 +399,16 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
if (param->flags & FLAG_CR_ECHO)
|
||||
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);
|
||||
|
||||
AppendTextToCaption (hwndDlg, param->c->config_name);
|
||||
|
@ -407,14 +421,17 @@ GenericPassDialogFunc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
case WM_COMMAND:
|
||||
param = (auth_param_t *) GetProp(hwndDlg, cfgProp);
|
||||
const char *template;
|
||||
char *fmt;
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
if (param->flags & FLAG_CR_TYPE_CRV1)
|
||||
{
|
||||
/* send username */
|
||||
const char *template = "username \"Auth\" \"%s\"";
|
||||
char *fmt = malloc(strlen(template) + strlen(param->user));
|
||||
template = "username \"Auth\" \"%s\"";
|
||||
fmt = malloc(strlen(template) + strlen(param->user));
|
||||
|
||||
if (fmt)
|
||||
{
|
||||
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 */
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* send password */
|
||||
/* password template */
|
||||
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 ? */
|
||||
WriteStatusLog(param->c, L"GUI> ", L"Unknown password reuest ignored", false);
|
||||
template = "password \"%s\" \"%%s\"";
|
||||
}
|
||||
|
||||
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));
|
||||
return TRUE;
|
||||
|
||||
|
@ -607,6 +626,69 @@ out:
|
|||
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
|
||||
*/
|
||||
|
@ -690,6 +772,24 @@ OnPassword(connection_t *c, char *msg)
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
|
|
@ -35,6 +35,8 @@ void OnLogLine(connection_t *, char *);
|
|||
void OnStateChange(connection_t *, char *);
|
||||
void OnPassword(connection_t *, char *);
|
||||
void OnStop(connection_t *, char *);
|
||||
void OnNeedOk(connection_t *, char *);
|
||||
void OnNeedStr(connection_t *, char *);
|
||||
|
||||
void DisablePasswordSave(connection_t *);
|
||||
|
||||
|
|
|
@ -84,8 +84,8 @@ typedef struct {
|
|||
} service_io_t;
|
||||
|
||||
#define FLAG_ALLOW_CHANGE_PASSPHRASE (1<<1)
|
||||
#define FLAG_SAVE_KEY_PASS 1<<4
|
||||
#define FLAG_SAVE_AUTH_PASS 1<<5
|
||||
#define FLAG_SAVE_KEY_PASS (1<<4)
|
||||
#define FLAG_SAVE_AUTH_PASS (1<<5)
|
||||
|
||||
typedef struct {
|
||||
unsigned short major, minor, build, revision;
|
||||
|
|
|
@ -448,4 +448,9 @@ BEGIN
|
|||
|
||||
/* save/delete password */
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue