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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (hide annotations)
Sat Oct 8 10:43:08 2005 UTC (19 years, 4 months ago) by twoaday
File size: 11298 byte(s)
Bug fixes to correct some problems introduced by
the MyGPGME to GPGME port.

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    
41     #define item_ctrl_id( cmd ) \
42     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
43    
44 twoaday 22 #define item_ctrl_id2(cmd) \
45     ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
46 twoaday 2
47 twoaday 22
48 twoaday 23 /* Dialog procedure for the passphrase callback. */
49     static BOOL CALLBACK
50 twoaday 4 passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
51 twoaday 2 {
52     static passphrase_cb_s * c;
53 twoaday 24 gpgme_decrypt_result_t res;
54     gpgme_sign_result_t res_sig;
55 twoaday 2 gpgme_key_t key;
56 twoaday 23 const char *id;
57     char *info;
58     void *ctx = NULL, *item;
59     int n;
60 twoaday 2
61 twoaday 24 switch (msg) {
62 twoaday 2 case WM_INITDIALOG:
63     c = (passphrase_cb_s *)lparam;
64 twoaday 4 if (!c)
65     BUG (0);
66     SetWindowText (dlg, c->title);
67     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
68 twoaday 2 SetDlgItemText( dlg, IDC_DECRYPT_LISTINF,
69     _("Encrypted with the following public key(s)") );
70     CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
71     }
72     else if( c->gpg_cmd == GPG_CMD_SIGN )
73 twoaday 23 CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
74 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
75     if (res != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
76 twoaday 23 gpgme_recipient_t r;
77    
78     for (r = res->recipients; r; r = r->next) {
79     get_pubkey (r->keyid, &key);
80     if (key) {
81     char *uid;
82 twoaday 24 id = key->uids->name;
83 twoaday 23 if (!id)
84 twoaday 2 id = _("Invalid User ID");
85 twoaday 23 uid = utf8_to_wincp (id, strlen (id));
86 twoaday 24 info = new char [16+strlen (uid) + 4 + strlen (r->keyid) + strlen (key->uids->email) + 3];
87 twoaday 23 if (!info)
88     BUG (NULL);
89 twoaday 24 sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
90 twoaday 23 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
91     free (uid);
92 twoaday 24
93 twoaday 2 }
94 twoaday 23 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     }
101 twoaday 24 listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
102     free (info);
103 twoaday 2 }
104     }
105 twoaday 24 else if (c->gpg_cmd == GPG_CMD_DECRYPT)
106     EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
107 twoaday 2 SetDlgItemText( dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
108     IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
109     _("Please enter your passphrase") );
110 twoaday 24 if (c->gpg_cmd == GPG_CMD_DECRYPT) {
111     SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
112     if (res && !res->recipients)
113     SetDlgItemText (dlg, IDC_DECRYPT_MSG, _("Symmetric encryption.\n"));
114     else
115     SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
116 twoaday 2 }
117     else {
118 twoaday 24 SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
119     SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
120 twoaday 2 }
121 twoaday 24 center_window (dlg, NULL);
122     SetForegroundWindow (dlg);
123     set_active_window (dlg);
124 twoaday 2 return FALSE;
125    
126     case WM_SYSCOMMAND:
127     if( LOWORD( wparam ) == SC_CLOSE ) {
128     SetDlgItemText( dlg, item_ctrl_id( c->gpg_cmd ), "" );
129     c->cancel = 1;
130     EndDialog( dlg, TRUE );
131     }
132 twoaday 24 break;
133 twoaday 2
134     case WM_COMMAND:
135     switch( HIWORD( wparam ) ) {
136     case BN_CLICKED:
137     if ( LOWORD( wparam ) == IDC_DECRYPT_HIDE
138     || LOWORD( wparam ) == IDC_DECRYPT_SIGN_HIDE ) {
139     HWND hwnd;
140 twoaday 22 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
141     hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
142 twoaday 4 SendMessage( hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0 );
143 twoaday 22 SetFocus (hwnd);
144 twoaday 2 }
145     }
146    
147 twoaday 4 switch (LOWORD (wparam)) {
148     case IDOK:
149 twoaday 2 /* fixme: the item is even cached when the passphrase is not
150     correct, which means that the user needs to delete all
151     cached entries to continue. */
152 twoaday 23 if (c->pwd) {
153     delete []c->pwd;
154     c->pwd = NULL;
155     }
156     n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
157     if (!n) {
158     c->pwd = new char[2];
159     strcpy (c->pwd, "");
160     }
161     else {
162 twoaday 24 c->pwd = new char[n+2];
163 twoaday 23 if (!c->pwd)
164     BUG (NULL);
165 twoaday 24 GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
166 twoaday 23 }
167 twoaday 24 res = gpgme_op_decrypt_result (c->gpg);
168     if (!res)
169     res_sig = gpgme_op_sign_result (c->gpg);
170     if (reg_prefs.cache_time > 0 && !c->is_card &&
171     ((res && res->recipients) || (res_sig && res_sig->signatures))) {
172 twoaday 4 if (agent_get_cache (c->keyid, &item))
173     agent_unlock_cache_entry (&item);
174 twoaday 2 else
175 twoaday 4 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
176 twoaday 2 }
177 twoaday 4 EndDialog (dlg, TRUE);
178 twoaday 2 return TRUE;
179    
180     case IDCANCEL:
181 twoaday 4 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "" );
182 twoaday 2 c->cancel = 1;
183 twoaday 4 EndDialog (dlg, FALSE);
184 twoaday 2 return FALSE;
185     }
186     break;
187     }
188    
189     return FALSE;
190 twoaday 23 }
191 twoaday 2
192    
193 twoaday 23 /* Extract the main keyid from @pass_info.
194     Return value: long main keyid or NULL for an error. */
195     static const char*
196     parse_gpg_keyid (const char *pass_info)
197 twoaday 2 {
198     static char keyid[16+1];
199    
200 twoaday 23 if (strlen (pass_info) < 16)
201 twoaday 2 return NULL;
202     /* the format of the desc buffer looks like this:
203     request_keyid[16] main_keyid[16] keytype[1] keylength[4]
204     we use the main keyid to use only one cache entry. */
205 twoaday 23 strncpy (keyid, pass_info+17, 16);
206     keyid[16] = 0;
207 twoaday 2 return keyid;
208 twoaday 23 }
209 twoaday 2
210    
211 twoaday 23 /* Parse the information in @uid_hint and @pass_info to generate
212     a input message for the user in @desc. */
213 twoaday 2 static void
214 twoaday 23 parse_gpg_description (const char *uid_hint, const char *pass_info,
215     char *desc, int size)
216 twoaday 2 {
217 twoaday 23 gpgme_pubkey_algo_t algo;
218     char usedkey[16+1], mainkey[16+1];
219     char *uid, *p;
220     int n=0;
221 twoaday 2
222 twoaday 23 while (p = strsep ((char**)&pass_info, " ")) {
223     switch (n++) {
224     case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
225     case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
226     case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
227 twoaday 2 }
228     }
229 twoaday 23 uid_hint += 16; /* skip keyid */
230     uid_hint += 1; /* space */
231 twoaday 2
232 twoaday 23 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
233 twoaday 2
234 twoaday 23 if (strcmp (usedkey, mainkey))
235     _snprintf (desc, size-1,
236 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
237     "user: \"%s\"\n"
238     "%s key, ID %s (main key ID %s)\n"),
239 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
240     else if (!strcmp (usedkey, mainkey))
241     _snprintf (desc, size-1,
242 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
243     "user: \"%s\"\n"
244     "%s key, ID %s\n"),
245 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8);
246     free (uid);
247     }
248 twoaday 2
249    
250     static int inline
251 twoaday 23 is_hexstring (const char * p)
252 twoaday 2 {
253     size_t i;
254 twoaday 23
255     for (i=0; i < strlen (p); i++) {
256     if (!isxdigit (p[i]))
257 twoaday 2 return -1;
258     }
259     return 0;
260     }
261    
262    
263 twoaday 23 /* Passphrase callback with the ability to support caching. */
264     gpgme_error_t
265     passphrase_cb (void *hook, const char *uid_hint,
266     const char *passphrase_info,
267     int prev_was_bad, int fd)
268     {
269     passphrase_cb_s *c = (passphrase_cb_s*)hook;
270 twoaday 24 HANDLE hd = (HANDLE)fd;
271 twoaday 23 void *item;
272     const char *keyid, *pass;
273 twoaday 24 DWORD n;
274 twoaday 23 int rc;
275 twoaday 2
276 twoaday 24 /* XXX: pubkey_enc cancel does not quit gpg.exe */
277     /* XXX: handle prev_was_bad case. */
278 twoaday 23 if (!c)
279     return gpg_error (GPG_ERR_INV_ARG);
280 twoaday 2
281 twoaday 23 if (passphrase_info) {
282     keyid = parse_gpg_keyid (passphrase_info);
283 twoaday 24 pass = agent_get_cache (keyid+8, &item);
284 twoaday 23 if (pass) {
285     agent_unlock_cache_entry (&item);
286 twoaday 2 c->pwd_init = 0;
287 twoaday 24 if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
288     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
289     if (!WriteFile (hd, "\n", 1, &n, NULL))
290     log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
291 twoaday 23 return 0;
292 twoaday 2 }
293     }
294    
295 twoaday 23 if (c->pwd_init) {
296     if (keyid && strlen (keyid) == 16)
297     strcpy (c->keyid, keyid+8);
298    
299 twoaday 2 /* if the desc has a length of 32 and only hex digits, we assume a
300     smart card has been used. */
301 twoaday 23 if (uid_hint && strlen (uid_hint) == 32 && !is_hexstring (uid_hint)) {
302 twoaday 2 char buf[16];
303 twoaday 23 memset (buf, 0, sizeof buf);
304     strncpy (buf, uid_hint+20, 8);
305     _snprintf (c->info, sizeof c->info-1,
306     _("Please enter the PIN to unlock your secret card key\n"
307     "Card: %s"), buf);
308 twoaday 2 c->is_card = 1;
309     }
310 twoaday 23 else if (uid_hint)
311     parse_gpg_description (uid_hint, passphrase_info,
312     c->info, sizeof c->info - 1);
313     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
314     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
315     (HWND)c->hwnd, passphrase_callback_proc,
316     (LPARAM)c);
317 twoaday 2 }
318 twoaday 23 else if (c->gpg_cmd == GPG_CMD_SIGN) {
319     rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
320     (HWND)c->hwnd, passphrase_callback_proc,
321     (LPARAM)c);
322 twoaday 2 }
323 twoaday 23 if (rc == -1) {
324 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
325 twoaday 23 return gpg_error (GPG_ERR_EOF);
326 twoaday 2 }
327     c->pwd_init = 0;
328     }
329 twoaday 23 if (c->cancel) {
330 twoaday 24 WriteFile (hd, "\n", 1, &n, NULL);
331 twoaday 23 return gpg_error (GPG_ERR_EOF);
332     }
333 twoaday 2
334 twoaday 24 WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
335     WriteFile (hd, "\n", 1, &n, NULL);
336 twoaday 23 return 0;
337     }
338 twoaday 2
339    
340 twoaday 23 /* Initialize the given passphrase callback @cb with the
341     used gpgme context @ctx, the command @cmd and a title
342     @title for the dialog. */
343     void
344     set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
345     int cmd, HWND hwnd, const char *title)
346     {
347     memset (cb, 0, sizeof *cb);
348     cb->gpg_cmd = cmd;
349     cb->is_card = 0;
350     cb->cancel = 0;
351     cb->hwnd = hwnd;
352     cb->pwd_init = 1;
353     free_if_alloc (cb->title);
354     cb->title = m_strdup (title);
355     if (!cb->title)
356     BUG (NULL);
357     gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
358     cb->gpg = ctx;
359     }
360 twoaday 2
361 twoaday 23
362     /* Release a passphrase callback @ctx. */
363 twoaday 2 void
364 twoaday 23 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
365 twoaday 2 {
366 twoaday 23 if (!ctx)
367     return;
368     sfree_if_alloc (ctx->pwd);
369     free_if_alloc (ctx->title);
370     }
371 twoaday 22
372 twoaday 23 /* Simple check to measure passphrase (@pass) quality.
373     Return value: 0 on success. */
374 twoaday 22 int
375     check_passwd_quality (const char *pass, int strict)
376     {
377     int i, nd=0, nc=0, n;
378    
379     n = strlen (pass);
380     if (n < 8)
381     return -1;
382    
383     for (i=0; i < n; i++) {
384     if (isdigit (pass[i])) nd++;
385     if (isalpha (pass[i])) nc++;
386     }
387    
388     if (nd == n || nc == n)
389     return -1;
390    
391     return 0;
392     }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26