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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Wed Oct 26 11:20:09 2005 UTC (19 years, 4 months ago) by twoaday
File size: 13235 byte(s)
2005-10-25  Timo Schulz  <twoaday@g10code.com>
                                                                                
        * wptGPGUtil.cpp (create_process): Hide window.
        * wptKeyPropsDlg.cpp (get_photo_tmpname): New.
        * wptClipSignEncDlg.cpp (clip_signenc_dlg_proc): Remove
        static var 'enable'.
        * wptKeygenDlg.cpp (keygen_dlg_proc): Likewise.
        (gpg_genkey_params): Make sure all primary keys are capable
        for signing and certification.
        * wptKeySigDlg.cpp (is_sig): If no item is selected, return 0.
        * wptGPG.cpp (gnupg_access_keyring): Check return value for
        NULL. Noted by Ralf.
        (get_gnupg_prog): Simplified.
        (check_homedir): Fixed. Return 0 when the dir is successfully created.
        * wptKeyManagerDlg.cpp (km_file_import): Use the hourglass to
        indicate a pending GPG process.
        * wptFileManager.cpp (op_begin, op_end): New. Indicate an start
        and and of an operation. For now just the cursor changes.
        (fm_parse_command_line): Remove debug output. Thanks to Ralf again.
        * WinPT.cpp (WinMain): Check if there is already an instance and
        set a variable early as possible.
        (load_gettext): If a previous instance was found, do not output
        any errors. Kudos to Ralf.


1 twoaday 2 /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2 twoaday 23 * Copyright (C) 2001, 2002, 2003, 2005 Timo Schulz
3 twoaday 24 * Copyright (C) 2005 g10 Code GmbH
4 twoaday 2 *
5     * This file is part of WinPT.
6     *
7     * WinPT is free software; you can redistribute it and/or
8     * modify it under the terms of the GNU General Public License
9     * as published by the Free Software Foundation; either version 2
10     * of the License, or (at your option) any later version.
11     *
12     * WinPT is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     * General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with WinPT; if not, write to the Free Software Foundation,
19     * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21    
22     #include <windows.h>
23     #include <ctype.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 twoaday 23 #include "wptKeyList.h"
37 twoaday 2 #include "wptAgent.h"
38     #include "wptRegistry.h"
39    
40 twoaday 25 const char* get_symkey_algo (int algo);
41 twoaday 2
42     #define item_ctrl_id( cmd ) \
43     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
44    
45 twoaday 22 #define item_ctrl_id2(cmd) \
46     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
47 twoaday 2
48 twoaday 22
49 twoaday 26 /* Overwrite passphrase and free memory. */
50     static void
51     burn_passphrase (char **pwd)
52     {
53 twoaday 32 char *pass = *pwd;
54     wipememory (pass, strlen (pass));
55 twoaday 26 delete []pass;
56     *pwd = NULL;
57     }
58    
59    
60 twoaday 23 /* Dialog procedure for the passphrase callback. */
61     static BOOL CALLBACK
62 twoaday 4 passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
63 twoaday 2 {
64     static passphrase_cb_s * c;
65 twoaday 24 gpgme_decrypt_result_t res;
66     gpgme_sign_result_t res_sig;
67 twoaday 2 gpgme_key_t key;
68 twoaday 33 gpgme_recipient_t recip, r;
69 twoaday 25 void *ctx = NULL, *item;
70 twoaday 23 const char *id;
71     char *info;
72     int n;
73 twoaday 2
74 twoaday 24 switch (msg) {
75 twoaday 2 case WM_INITDIALOG:
76     c = (passphrase_cb_s *)lparam;
77 twoaday 4 if (!c)
78     BUG (0);
79     SetWindowText (dlg, c->title);
80     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
81 twoaday 32 SetDlgItemText (dlg, IDC_DECRYPT_LISTINF,
82     _("Encrypted with the following public key(s)"));
83     CheckDlgButton (dlg, IDC_DECRYPT_HIDE, BST_CHECKED);
84 twoaday 2 }
85 twoaday 25 else if (c->gpg_cmd == GPG_CMD_SIGN)
86 twoaday 23 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
87 twoaday 33 if (c->recipients)
88     recip = c->recipients; /* recipients were already extracted. */
89     else {
90 twoaday 25 /* XXX: not all ENCRYPT_TO entries are listed here. */
91 twoaday 33 res = gpgme_op_decrypt_result (c->gpg);
92 twoaday 34 if (res && res->recipients)
93 twoaday 33 recip = res->recipients;
94     }
95     if (recip != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
96 twoaday 23 for (r = res->recipients; r; r = r->next) {
97     get_pubkey (r->keyid, &key);
98     if (key) {
99     char *uid;
100 twoaday 24 id = key->uids->name;
101 twoaday 23 if (!id)
102 twoaday 2 id = _("Invalid User ID");
103 twoaday 23 uid = utf8_to_wincp (id, strlen (id));
104 twoaday 25 info = new char [32+strlen (uid)+1 + 4 + strlen (r->keyid)+1
105     + strlen (key->uids->email)+1];
106 twoaday 23 if (!info)
107     BUG (NULL);
108 twoaday 24 sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
109 twoaday 23 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
110     free (uid);
111 twoaday 24
112 twoaday 2 }
113 twoaday 23 else {
114 twoaday 25 info = new char [32 + strlen (r->keyid)+1 + 4];
115 twoaday 23 if (!info)
116     BUG (NULL);
117 twoaday 25 sprintf (info, _("Unknown key ID (%s, 0x%s)"),
118     get_key_pubalgo (r->pubkey_algo), r->keyid+8);
119 twoaday 23 }
120 twoaday 24 listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
121 twoaday 25 free_if_alloc (info);
122 twoaday 2 }
123     }
124 twoaday 24 else if (c->gpg_cmd == GPG_CMD_DECRYPT)
125     EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
126 twoaday 25 SetDlgItemText (dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
127 twoaday 2 IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
128 twoaday 26 c->bad_pwd? _("Bad passphrase; Enter passphrase again") :
129 twoaday 25 _("Please enter your passphrase"));
130 twoaday 24 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
131     SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
132 twoaday 25 if (res && !res->recipients) {
133     const char *s = _("Symmetric encryption.\n"
134     "%s encrypted data.");
135     const char *alg = get_symkey_algo (c->sym.sym_algo);
136     info = new char[strlen (s) + strlen (alg) + 2];
137     if (!info)
138     BUG (NULL);
139     sprintf (info, s, alg);
140     SetDlgItemText (dlg, IDC_DECRYPT_MSG, info);
141     free_if_alloc (info);
142     }
143 twoaday 24 else
144     SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
145 twoaday 2 }
146     else {
147 twoaday 24 SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
148     SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
149 twoaday 2 }
150 twoaday 24 center_window (dlg, NULL);
151     SetForegroundWindow (dlg);
152     set_active_window (dlg);
153 twoaday 2 return FALSE;
154    
155     case WM_SYSCOMMAND:
156 twoaday 26 if (LOWORD (wparam) == SC_CLOSE) {
157 twoaday 32 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "");
158 twoaday 2 c->cancel = 1;
159 twoaday 26 EndDialog (dlg, TRUE);
160 twoaday 2 }
161 twoaday 24 break;
162 twoaday 2
163     case WM_COMMAND:
164 twoaday 32 switch (HIWORD (wparam)) {
165 twoaday 2 case BN_CLICKED:
166 twoaday 32 if (LOWORD (wparam) == IDC_DECRYPT_HIDE
167     || LOWORD (wparam) == IDC_DECRYPT_SIGN_HIDE) {
168 twoaday 2 HWND hwnd;
169 twoaday 22 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
170     hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
171 twoaday 25 SendMessage (hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0);
172 twoaday 22 SetFocus (hwnd);
173 twoaday 2 }
174     }
175    
176 twoaday 4 switch (LOWORD (wparam)) {
177     case IDOK:
178 twoaday 32 /* XXX: the item is even cached when the passphrase is not
179     correct, which means that the user needs to delete all
180     cached entries to continue. */
181 twoaday 26 if (c->pwd)
182     burn_passphrase (&c->pwd);
183 twoaday 23 n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
184     if (!n) {
185     c->pwd = new char[2];
186 twoaday 26 if (!c->pwd)
187     BUG (NULL);
188 twoaday 23 strcpy (c->pwd, "");
189     }
190     else {
191 twoaday 24 c->pwd = new char[n+2];
192 twoaday 23 if (!c->pwd)
193     BUG (NULL);
194 twoaday 24 GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
195 twoaday 23 }
196 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
197     if (!res)
198     res_sig = gpgme_op_sign_result (c->gpg);
199     if (reg_prefs.cache_time > 0 && !c->is_card &&
200     ((res && res->recipients) || (res_sig && res_sig->signatures))) {
201 twoaday 4 if (agent_get_cache (c->keyid, &item))
202     agent_unlock_cache_entry (&item);
203 twoaday 2 else
204 twoaday 4 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
205 twoaday 2 }
206 twoaday 32 c->cancel = 0;
207 twoaday 4 EndDialog (dlg, TRUE);
208 twoaday 2 return TRUE;
209    
210     case IDCANCEL:
211 twoaday 32 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "");
212 twoaday 2 c->cancel = 1;
213 twoaday 4 EndDialog (dlg, FALSE);
214 twoaday 2 return FALSE;
215     }
216     break;
217     }
218    
219     return FALSE;
220 twoaday 23 }
221 twoaday 2
222    
223 twoaday 23 /* Extract the main keyid from @pass_info.
224     Return value: long main keyid or NULL for an error. */
225     static const char*
226     parse_gpg_keyid (const char *pass_info)
227 twoaday 2 {
228     static char keyid[16+1];
229    
230 twoaday 26 /* XXX: check for leading alpha-chars? */
231 twoaday 23 if (strlen (pass_info) < 16)
232 twoaday 2 return NULL;
233     /* the format of the desc buffer looks like this:
234     request_keyid[16] main_keyid[16] keytype[1] keylength[4]
235     we use the main keyid to use only one cache entry. */
236 twoaday 23 strncpy (keyid, pass_info+17, 16);
237     keyid[16] = 0;
238 twoaday 2 return keyid;
239 twoaday 23 }
240 twoaday 2
241    
242 twoaday 23 /* Parse the information in @uid_hint and @pass_info to generate
243     a input message for the user in @desc. */
244 twoaday 26 static int
245 twoaday 23 parse_gpg_description (const char *uid_hint, const char *pass_info,
246     char *desc, int size)
247 twoaday 2 {
248 twoaday 23 gpgme_pubkey_algo_t algo;
249 twoaday 32 char usedkey[16+1];
250     char mainkey[16+1];
251 twoaday 23 char *uid, *p;
252     int n=0;
253 twoaday 2
254 twoaday 32 /* Each uid_hint contains a long key-ID so it is at least 16 bytes. */
255 twoaday 26 if (strlen (uid_hint) < 17) {
256     *desc = 0;
257     return -1;
258     }
259    
260 twoaday 23 while (p = strsep ((char**)&pass_info, " ")) {
261     switch (n++) {
262     case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
263     case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
264     case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
265 twoaday 2 }
266     }
267 twoaday 23 uid_hint += 16; /* skip keyid */
268     uid_hint += 1; /* space */
269 twoaday 2
270 twoaday 23 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
271 twoaday 2
272 twoaday 23 if (strcmp (usedkey, mainkey))
273     _snprintf (desc, size-1,
274 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
275     "user: \"%s\"\n"
276     "%s key, ID %s (main key ID %s)\n"),
277 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
278     else if (!strcmp (usedkey, mainkey))
279     _snprintf (desc, size-1,
280 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
281     "user: \"%s\"\n"
282     "%s key, ID %s\n"),
283 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8);
284     free (uid);
285 twoaday 26 return 0;
286 twoaday 23 }
287 twoaday 2
288    
289 twoaday 28 /* Extract the serial number from the card ID @id and return it. */
290     const char*
291     extract_serial_no (const char *id)
292     {
293     static char buf[8];
294     char *p;
295    
296     p = strchr (id, '/');
297     if (!p)
298     return NULL;
299     strncpy (buf, id+(p-id)-6, 6);
300     return buf;
301     }
302    
303    
304 twoaday 23 /* Passphrase callback with the ability to support caching. */
305     gpgme_error_t
306     passphrase_cb (void *hook, const char *uid_hint,
307     const char *passphrase_info,
308     int prev_was_bad, int fd)
309     {
310     passphrase_cb_s *c = (passphrase_cb_s*)hook;
311 twoaday 24 HANDLE hd = (HANDLE)fd;
312 twoaday 23 void *item;
313     const char *keyid, *pass;
314 twoaday 24 DWORD n;
315 twoaday 23 int rc;
316 twoaday 2
317 twoaday 23 if (!c)
318     return gpg_error (GPG_ERR_INV_ARG);
319 twoaday 26 c->bad_pwd = prev_was_bad? 1 : 0;
320     if (prev_was_bad && !c->cancel) {
321     if (c->pwd)
322     burn_passphrase (&c->pwd);
323     agent_del_cache (c->keyid);
324     c->pwd_init = 1;
325     }
326 twoaday 2
327 twoaday 23 if (passphrase_info) {
328 twoaday 26 if (strlen (passphrase_info) < 16 &&
329 twoaday 32 !strstr (passphrase_info, "OPENPGP")) {
330     /* assume symetric encryption. */
331 twoaday 25 int n=2;
332     c->sym.sym_algo = atoi (passphrase_info);
333     if (c->sym.sym_algo > 9)
334     n++;
335     /* XXX: be more strict. */
336     c->sym.s2k_mode = atoi (passphrase_info+n);
337     c->sym.s2k_hash = atoi (passphrase_info+n+2);
338     }
339    
340 twoaday 23 keyid = parse_gpg_keyid (passphrase_info);
341 twoaday 24 pass = agent_get_cache (keyid+8, &item);
342 twoaday 23 if (pass) {
343     agent_unlock_cache_entry (&item);
344 twoaday 2 c->pwd_init = 0;
345 twoaday 24 if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
346     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
347     if (!WriteFile (hd, "\n", 1, &n, NULL))
348     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
349 twoaday 23 return 0;
350 twoaday 2 }
351     }
352    
353 twoaday 23 if (c->pwd_init) {
354     if (keyid && strlen (keyid) == 16)
355     strcpy (c->keyid, keyid+8);
356    
357 twoaday 26 /* if @passphrase_info contains 'OPENPGP' we assume a smart card
358     has been used. */
359     if (strstr (passphrase_info, "OPENPGP")) {
360 twoaday 28 const char *s=passphrase_info;
361     while (s && *s && *s != 'D')
362     s++;
363 twoaday 23 _snprintf (c->info, sizeof c->info-1,
364     _("Please enter the PIN to unlock your secret card key\n"
365 twoaday 28 "Card: %s"), extract_serial_no (s));
366 twoaday 2 c->is_card = 1;
367     }
368 twoaday 23 else if (uid_hint)
369     parse_gpg_description (uid_hint, passphrase_info,
370     c->info, sizeof c->info - 1);
371     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
372     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
373     (HWND)c->hwnd, passphrase_callback_proc,
374     (LPARAM)c);
375 twoaday 2 }
376 twoaday 23 else if (c->gpg_cmd == GPG_CMD_SIGN) {
377     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
378     (HWND)c->hwnd, passphrase_callback_proc,
379     (LPARAM)c);
380 twoaday 2 }
381 twoaday 23 if (rc == -1) {
382 twoaday 32 if (!WriteFile (hd, "\n", 1, &n, NULL))
383     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
384 twoaday 26 return 0;
385 twoaday 2 }
386     c->pwd_init = 0;
387     }
388 twoaday 23 if (c->cancel) {
389 twoaday 32 if (!WriteFile (hd, "\n", 1, &n, NULL))
390     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
391 twoaday 26 return 0;
392 twoaday 23 }
393 twoaday 2
394 twoaday 24 WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
395     WriteFile (hd, "\n", 1, &n, NULL);
396 twoaday 23 return 0;
397     }
398 twoaday 2
399    
400 twoaday 23 /* Initialize the given passphrase callback @cb with the
401     used gpgme context @ctx, the command @cmd and a title
402     @title for the dialog. */
403     void
404     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
405     int cmd, HWND hwnd, const char *title)
406     {
407     memset (cb, 0, sizeof *cb);
408     cb->gpg_cmd = cmd;
409 twoaday 26 cb->bad_pwd = 0;
410 twoaday 23 cb->is_card = 0;
411     cb->cancel = 0;
412     cb->hwnd = hwnd;
413     cb->pwd_init = 1;
414     free_if_alloc (cb->title);
415     cb->title = m_strdup (title);
416     if (!cb->title)
417     BUG (NULL);
418     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
419     cb->gpg = ctx;
420     }
421 twoaday 2
422 twoaday 23
423     /* Release a passphrase callback @ctx. */
424 twoaday 2 void
425 twoaday 23 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
426 twoaday 2 {
427 twoaday 33 gpgme_recipient_t r, n;
428    
429 twoaday 23 if (!ctx)
430     return;
431     sfree_if_alloc (ctx->pwd);
432     free_if_alloc (ctx->title);
433 twoaday 33 r = ctx->recipients;
434     while (r) {
435     n = r->next;
436     safe_free (r->keyid);
437     safe_free (r);
438     r = n;
439     }
440 twoaday 23 }
441 twoaday 22
442 twoaday 26
443 twoaday 23 /* Simple check to measure passphrase (@pass) quality.
444     Return value: 0 on success. */
445 twoaday 22 int
446     check_passwd_quality (const char *pass, int strict)
447     {
448     int i, nd=0, nc=0, n;
449    
450     n = strlen (pass);
451     if (n < 8)
452     return -1;
453    
454     for (i=0; i < n; i++) {
455 twoaday 32 if (isdigit (pass[i]))
456     nd++;
457     if (isalpha (pass[i]))
458     nc++;
459 twoaday 22 }
460    
461 twoaday 32 /* check that the passphrase contains letters and numbers. */
462 twoaday 22 if (nd == n || nc == n)
463     return -1;
464    
465     return 0;
466     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26