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
	
	 Selva Nair
						Selva Nair