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

Annotation of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide 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 twoaday 2 /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2 twoaday 23 * Copyright (C) 2001, 2002, 2003, 2005 Timo Schulz
3 twoaday 2 *
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 twoaday 23 #include <io.h>
24 twoaday 2
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     gpgme_key_t key;
54 twoaday 23 const char *id;
55     char *info;
56     void *ctx = NULL, *item;
57     int n;
58 twoaday 2
59     switch( msg ) {
60     case WM_INITDIALOG:
61     c = (passphrase_cb_s *)lparam;
62 twoaday 4 if (!c)
63     BUG (0);
64     SetWindowText (dlg, c->title);
65     if (c->gpg_cmd == GPG_CMD_DECRYPT) {
66 twoaday 2 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 twoaday 23 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 twoaday 2 id = _("Invalid User ID");
85 twoaday 23 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 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     free (info);
101     }
102     listbox_add_string (GetDlgItem( dlg, IDC_DECRYPT_LIST ), info);
103 twoaday 2 }
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 twoaday 23 center_window( dlg, NULL );
117 twoaday 2 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 twoaday 22 int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
136     hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
137 twoaday 4 SendMessage( hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0 );
138 twoaday 22 SetFocus (hwnd);
139 twoaday 2 }
140     }
141    
142 twoaday 4 switch (LOWORD (wparam)) {
143     case IDOK:
144 twoaday 2 /* 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 twoaday 23 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 twoaday 4 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 twoaday 2 else
166 twoaday 4 agent_put_cache (c->keyid, c->pwd, reg_prefs.cache_time);
167 twoaday 2 }
168 twoaday 4 EndDialog (dlg, TRUE);
169 twoaday 2 return TRUE;
170    
171     case IDCANCEL:
172 twoaday 4 SetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), "" );
173 twoaday 2 c->cancel = 1;
174 twoaday 4 EndDialog (dlg, FALSE);
175 twoaday 2 return FALSE;
176     }
177     break;
178     }
179    
180     return FALSE;
181 twoaday 23 }
182 twoaday 2
183    
184 twoaday 23 /* 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 twoaday 2 {
189     static char keyid[16+1];
190    
191 twoaday 23 if (strlen (pass_info) < 16)
192 twoaday 2 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 twoaday 23 strncpy (keyid, pass_info+17, 16);
197     keyid[16] = 0;
198 twoaday 2 return keyid;
199 twoaday 23 }
200 twoaday 2
201    
202 twoaday 23 /* Parse the information in @uid_hint and @pass_info to generate
203     a input message for the user in @desc. */
204 twoaday 2 static void
205 twoaday 23 parse_gpg_description (const char *uid_hint, const char *pass_info,
206     char *desc, int size)
207 twoaday 2 {
208 twoaday 23 gpgme_pubkey_algo_t algo;
209     char usedkey[16+1], mainkey[16+1];
210     char *uid, *p;
211     int n=0;
212 twoaday 2
213 twoaday 23 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 twoaday 2 }
219     }
220 twoaday 23 uid_hint += 16; /* skip keyid */
221     uid_hint += 1; /* space */
222 twoaday 2
223 twoaday 23 uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
224 twoaday 2
225 twoaday 23 if (strcmp (usedkey, mainkey))
226     _snprintf (desc, size-1,
227 twoaday 2 _("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 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
231     else if (!strcmp (usedkey, mainkey))
232     _snprintf (desc, size-1,
233 twoaday 2 _("You need a passphrase to unlock the secret key for\n"
234     "user: \"%s\"\n"
235     "%s key, ID %s\n"),
236 twoaday 23 uid, get_key_pubalgo (algo), usedkey+8);
237     free (uid);
238     }
239 twoaday 2
240    
241     static int inline
242 twoaday 23 is_hexstring (const char * p)
243 twoaday 2 {
244     size_t i;
245 twoaday 23
246     for (i=0; i < strlen (p); i++) {
247     if (!isxdigit (p[i]))
248 twoaday 2 return -1;
249     }
250     return 0;
251     }
252    
253    
254 twoaday 23 /* 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 twoaday 2
265 twoaday 23 if (!c)
266     return gpg_error (GPG_ERR_INV_ARG);
267 twoaday 2
268 twoaday 23 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 twoaday 2 c->pwd_init = 0;
274 twoaday 23 write (fd, pass, strlen (pass));
275     write (fd, "\n", 1);
276     return 0;
277 twoaday 2 }
278     }
279    
280 twoaday 23 if (c->pwd_init) {
281     if (keyid && strlen (keyid) == 16)
282     strcpy (c->keyid, keyid+8);
283    
284 twoaday 2 /* if the desc has a length of 32 and only hex digits, we assume a
285     smart card has been used. */
286 twoaday 23 if (uid_hint && strlen (uid_hint) == 32 && !is_hexstring (uid_hint)) {
287 twoaday 2 char buf[16];
288 twoaday 23 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 twoaday 2 c->is_card = 1;
294     }
295 twoaday 23 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 twoaday 2 }
303 twoaday 23 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 twoaday 2 }
308 twoaday 23 if (rc == -1) {
309     write (fd, "\n", 1);
310     return gpg_error (GPG_ERR_EOF);
311 twoaday 2 }
312     c->pwd_init = 0;
313     }
314 twoaday 23 if (c->cancel) {
315     write (fd, "\n", 1);
316     return gpg_error (GPG_ERR_EOF);
317     }
318 twoaday 2
319 twoaday 23 write (fd, c->pwd, strlen (c->pwd));
320     write (fd, "\n", 1);
321     return 0;
322     }
323 twoaday 2
324    
325 twoaday 23 /* 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 twoaday 2
346 twoaday 23
347     /* Release a passphrase callback @ctx. */
348 twoaday 2 void
349 twoaday 23 release_gpg_passphrase_cb (passphrase_cb_s *ctx)
350 twoaday 2 {
351 twoaday 23 if (!ctx)
352     return;
353     sfree_if_alloc (ctx->pwd);
354     free_if_alloc (ctx->title);
355     }
356 twoaday 22
357 twoaday 23 /* Simple check to measure passphrase (@pass) quality.
358     Return value: 0 on success. */
359 twoaday 22 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