/[winpt]/trunk/Src/wptPassphraseCB.cpp
ViewVC logotype

Contents of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Fri Sep 30 10:10:16 2005 UTC (19 years, 5 months ago) by twoaday
File size: 10522 byte(s)
Almost finished phase 1 of the WinPT GPGME port.
Still need more cleanup, comments and tests.


1 /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2 * Copyright (C) 2001, 2002, 2003, 2005 Timo Schulz
3 *
4 * This file is part of WinPT.
5 *
6 * WinPT is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * WinPT is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with WinPT; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include <windows.h>
22 #include <ctype.h>
23 #include <io.h>
24
25 #include "../resource.h"
26 #include "wptNLS.h"
27 #include "wptW32API.h"
28 #include "wptVersion.h"
29 #include "wptGPG.h"
30 #include "wptCommonCtl.h"
31 #include "wptContext.h"
32 #include "wptDlgs.h"
33 #include "wptUTF8.h"
34 #include "wptErrors.h"
35 #include "wptTypes.h"
36 #include "wptKeyList.h"
37 #include "wptAgent.h"
38 #include "wptRegistry.h"
39
40
41 #define item_ctrl_id( cmd ) \
42 ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
43
44 #define item_ctrl_id2(cmd) \
45 ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
46
47
48 /* Dialog procedure for the passphrase callback. */
49 static BOOL CALLBACK
50 passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
51 {
52 static passphrase_cb_s * c;
53 gpgme_key_t key;
54 const char *id;
55 char *info;
56 void *ctx = NULL, *item;
57 int n;
58
59 switch( msg ) {
60 case WM_INITDIALOG:
61 c = (passphrase_cb_s *)lparam;
62 if (!c)
63 BUG (0);
64 SetWindowText (dlg, c->title);
65 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
66 SetDlgItemText( dlg, IDC_DECRYPT_LISTINF,
67 _("Encrypted with the following public key(s)") );
68 CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
69 }
70 else if( c->gpg_cmd == GPG_CMD_SIGN )
71 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
72 if (gpgme_op_decrypt_result (c->gpg) != NULL &&
73 c->gpg_cmd == GPG_CMD_DECRYPT) {
74 gpgme_recipient_t r;
75 gpgme_decrypt_result_t res;
76
77 res = gpgme_op_decrypt_result (c->gpg);
78 for (r = res->recipients; r; r = r->next) {
79 get_pubkey (r->keyid, &key);
80 if (key) {
81 char *uid;
82 id = key->uids->uid;
83 if (!id)
84 id = _("Invalid User ID");
85 uid = utf8_to_wincp (id, strlen (id));
86 info = new char [8+strlen (uid) + 4 + strlen (r->keyid) + 2];
87 if (!info)
88 BUG (NULL);
89 sprintf (info, "%s (%s, 0x%s)", uid,
90 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
91 free (uid);
92 free (info);
93 }
94 else {
95 info = new char [32 + strlen (r->keyid) + 2];
96 if (!info)
97 BUG (NULL);
98 sprintf (info, _("Unknown (key ID 0x%s)"),
99 r->keyid? r->keyid+8 : "????????");
100 free (info);
101 }
102 listbox_add_string (GetDlgItem( dlg, IDC_DECRYPT_LIST ), info);
103 }
104 }
105 SetDlgItemText( dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
106 IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
107 _("Please enter your passphrase") );
108 if( c->gpg_cmd == GPG_CMD_DECRYPT ) {
109 SetFocus( GetDlgItem( dlg, IDC_DECRYPT_PWD ) );
110 SetDlgItemText( dlg, IDC_DECRYPT_MSG, c->info );
111 }
112 else {
113 SetFocus( GetDlgItem( dlg, IDC_DECRYPT_SIGN_PWD ) );
114 SetDlgItemText( dlg, IDC_DECRYPT_SIGN_MSG, c->info );
115 }
116 center_window( dlg, NULL );
117 SetForegroundWindow( dlg );
118 set_active_window( dlg );
119 return FALSE;
120
121 case WM_SYSCOMMAND:
122 if( LOWORD( wparam ) == SC_CLOSE ) {
123 SetDlgItemText( dlg, item_ctrl_id( c->gpg_cmd ), "" );
124 c->cancel = 1;
125 EndDialog( dlg, TRUE );
126 }
127 return FALSE;
128
129 case WM_COMMAND:
130 switch( HIWORD( wparam ) ) {
131 case BN_CLICKED:
132 if ( LOWORD( wparam ) == IDC_DECRYPT_HIDE
133 || LOWORD( wparam ) == IDC_DECRYPT_SIGN_HIDE ) {
134 HWND hwnd;
135 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
136 hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
137 SendMessage( hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0 );
138 SetFocus (hwnd);
139 }
140 }
141
142 switch (LOWORD (wparam)) {
143 case IDOK:
144 /* fixme: the item is even cached when the passphrase is not
145 correct, which means that the user needs to delete all
146 cached entries to continue. */
147 if (c->pwd) {
148 delete []c->pwd;
149 c->pwd = NULL;
150 }
151 n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
152 if (!n) {
153 c->pwd = new char[2];
154 strcpy (c->pwd, "");
155 }
156 else {
157 c->pwd = new char[n+1];
158 if (!c->pwd)
159 BUG (NULL);
160 GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, sizeof (c->pwd) -1);
161 }
162 if (reg_prefs.cache_time > 0 && !c->is_card && !strstr (c->keyid, "missing")) {
163 if (agent_get_cache (c->keyid, &item))
164 agent_unlock_cache_entry (&item);
165 else
166 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
167 }
168 EndDialog (dlg, TRUE);
169 return TRUE;
170
171 case IDCANCEL:
172 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "" );
173 c->cancel = 1;
174 EndDialog (dlg, FALSE);
175 return FALSE;
176 }
177 break;
178 }
179
180 return FALSE;
181 }
182
183
184 /* Extract the main keyid from @pass_info.
185 Return value: long main keyid or NULL for an error. */
186 static const char*
187 parse_gpg_keyid (const char *pass_info)
188 {
189 static char keyid[16+1];
190
191 if (strlen (pass_info) < 16)
192 return NULL;
193 /* the format of the desc buffer looks like this:
194 request_keyid[16] main_keyid[16] keytype[1] keylength[4]
195 we use the main keyid to use only one cache entry. */
196 strncpy (keyid, pass_info+17, 16);
197 keyid[16] = 0;
198 return keyid;
199 }
200
201
202 /* Parse the information in @uid_hint and @pass_info to generate
203 a input message for the user in @desc. */
204 static void
205 parse_gpg_description (const char *uid_hint, const char *pass_info,
206 char *desc, int size)
207 {
208 gpgme_pubkey_algo_t algo;
209 char usedkey[16+1], mainkey[16+1];
210 char *uid, *p;
211 int n=0;
212
213 while (p = strsep ((char**)&pass_info, " ")) {
214 switch (n++) {
215 case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
216 case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
217 case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
218 }
219 }
220 uid_hint += 16; /* skip keyid */
221 uid_hint += 1; /* space */
222
223 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
224
225 if (strcmp (usedkey, mainkey))
226 _snprintf (desc, size-1,
227 _("You need a passphrase to unlock the secret key for\n"
228 "user: \"%s\"\n"
229 "%s key, ID %s (main key ID %s)\n"),
230 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
231 else if (!strcmp (usedkey, mainkey))
232 _snprintf (desc, size-1,
233 _("You need a passphrase to unlock the secret key for\n"
234 "user: \"%s\"\n"
235 "%s key, ID %s\n"),
236 uid, get_key_pubalgo (algo), usedkey+8);
237 free (uid);
238 }
239
240
241 static int inline
242 is_hexstring (const char * p)
243 {
244 size_t i;
245
246 for (i=0; i < strlen (p); i++) {
247 if (!isxdigit (p[i]))
248 return -1;
249 }
250 return 0;
251 }
252
253
254 /* Passphrase callback with the ability to support caching. */
255 gpgme_error_t
256 passphrase_cb (void *hook, const char *uid_hint,
257 const char *passphrase_info,
258 int prev_was_bad, int fd)
259 {
260 passphrase_cb_s *c = (passphrase_cb_s*)hook;
261 void *item;
262 const char *keyid, *pass;
263 int rc;
264
265 if (!c)
266 return gpg_error (GPG_ERR_INV_ARG);
267
268 if (passphrase_info) {
269 keyid = parse_gpg_keyid (passphrase_info);
270 pass = agent_get_cache (keyid, &item);
271 if (pass) {
272 agent_unlock_cache_entry (&item);
273 c->pwd_init = 0;
274 write (fd, pass, strlen (pass));
275 write (fd, "\n", 1);
276 return 0;
277 }
278 }
279
280 if (c->pwd_init) {
281 if (keyid && strlen (keyid) == 16)
282 strcpy (c->keyid, keyid+8);
283
284 /* if the desc has a length of 32 and only hex digits, we assume a
285 smart card has been used. */
286 if (uid_hint && strlen (uid_hint) == 32 && !is_hexstring (uid_hint)) {
287 char buf[16];
288 memset (buf, 0, sizeof buf);
289 strncpy (buf, uid_hint+20, 8);
290 _snprintf (c->info, sizeof c->info-1,
291 _("Please enter the PIN to unlock your secret card key\n"
292 "Card: %s"), buf);
293 c->is_card = 1;
294 }
295 else if (uid_hint)
296 parse_gpg_description (uid_hint, passphrase_info,
297 c->info, sizeof c->info - 1);
298 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
299 rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
300 (HWND)c->hwnd, passphrase_callback_proc,
301 (LPARAM)c);
302 }
303 else if (c->gpg_cmd == GPG_CMD_SIGN) {
304 rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
305 (HWND)c->hwnd, passphrase_callback_proc,
306 (LPARAM)c);
307 }
308 if (rc == -1) {
309 write (fd, "\n", 1);
310 return gpg_error (GPG_ERR_EOF);
311 }
312 c->pwd_init = 0;
313 }
314 if (c->cancel) {
315 write (fd, "\n", 1);
316 return gpg_error (GPG_ERR_EOF);
317 }
318
319 write (fd, c->pwd, strlen (c->pwd));
320 write (fd, "\n", 1);
321 return 0;
322 }
323
324
325 /* Initialize the given passphrase callback @cb with the
326 used gpgme context @ctx, the command @cmd and a title
327 @title for the dialog. */
328 void
329 set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
330 int cmd, HWND hwnd, const char *title)
331 {
332 memset (cb, 0, sizeof *cb);
333 cb->gpg_cmd = cmd;
334 cb->is_card = 0;
335 cb->cancel = 0;
336 cb->hwnd = hwnd;
337 cb->pwd_init = 1;
338 free_if_alloc (cb->title);
339 cb->title = m_strdup (title);
340 if (!cb->title)
341 BUG (NULL);
342 gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
343 cb->gpg = ctx;
344 }
345
346
347 /* Release a passphrase callback @ctx. */
348 void
349 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
350 {
351 if (!ctx)
352 return;
353 sfree_if_alloc (ctx->pwd);
354 free_if_alloc (ctx->title);
355 }
356
357 /* Simple check to measure passphrase (@pass) quality.
358 Return value: 0 on success. */
359 int
360 check_passwd_quality (const char *pass, int strict)
361 {
362 int i, nd=0, nc=0, n;
363
364 n = strlen (pass);
365 if (n < 8)
366 return -1;
367
368 for (i=0; i < n; i++) {
369 if (isdigit (pass[i])) nd++;
370 if (isalpha (pass[i])) nc++;
371 }
372
373 if (nd == n || nc == n)
374 return -1;
375
376 return 0;
377 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26