* no-pth.c, Makefile.am: Removed.
[gnupg.git] / agent / query.c
1 /* query.c - fork of the pinentry to query stuff from the user
2  *      Copyright (C) 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <errno.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <sys/stat.h>
30 #ifdef USE_GNU_PTH
31 # include <pth.h>
32 #endif
33
34 #include "agent.h"
35 #include "../assuan/assuan.h"
36
37 #ifdef _POSIX_OPEN_MAX
38 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
39 #else
40 #define MAX_OPEN_FDS 20
41 #endif
42
43 static ASSUAN_CONTEXT entry_ctx = NULL;
44 #ifdef USE_GNU_PTH
45 static pth_mutex_t entry_lock = PTH_MUTEX_INIT;
46 #endif
47
48 /* data to be passed to our callbacks */
49 struct entry_parm_s {
50   int lines;
51   size_t size;
52   char *buffer;
53 };
54
55
56
57 \f
58 static int 
59 unlock_pinentry (int rc)
60 {
61 #ifdef USE_GNU_PTH
62   if (!pth_mutex_release (&entry_lock))
63     {
64       log_error ("failed to release the entry lock\n");
65       if (!rc)
66         rc = GNUPG_Internal_Error;
67     }
68 #endif
69   return rc;
70 }
71
72 /* Fork off the pin entry if this has not already been done.  Note,
73    that this function must always be used to aquire the lock for the
74    pinentry - we will serialize _all_ pinentry calls.
75  */
76 static int
77 start_pinentry (void)
78 {
79   int rc;
80   const char *pgmname;
81   ASSUAN_CONTEXT ctx;
82   const char *argv[5];
83
84 #ifdef USE_GNU_PTH
85   if (!pth_mutex_acquire (&entry_lock, 0, NULL))
86     {
87       log_error ("failed to acquire the entry lock\n");
88       return GNUPG_Internal_Error;
89     }
90 #endif
91
92   if (entry_ctx)
93     return 0; 
94
95   if (opt.verbose)
96     log_info ("no running PIN Entry - starting it\n");
97       
98   if (fflush (NULL))
99     {
100       log_error ("error flushing pending output: %s\n", strerror (errno));
101       return unlock_pinentry (seterr (Write_Error));
102     }
103
104   /* FIXME: change the default location of the program */
105   if (!opt.pinentry_program || !*opt.pinentry_program)
106     opt.pinentry_program = "../../pinentry/kpinentry/kpinentry";
107   if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
108     pgmname = opt.pinentry_program;
109   else
110     pgmname++;
111
112   /* FIXME: We must do this thread specific */
113   argv[0] = pgmname;
114   if (opt.display)
115     {
116       argv[1] = "--display";
117       argv[2] = opt.display;
118       argv[3] = NULL;
119     }
120   else
121     argv[1] = NULL;
122
123   /* connect to the pinentry and perform initial handshaking */
124   rc = assuan_pipe_connect (&ctx, opt.pinentry_program, (char**)argv, 0);
125   if (rc)
126     {
127       log_error ("can't connect to the PIN entry module: %s\n",
128                  assuan_strerror (rc));
129       return unlock_pinentry (seterr (No_PIN_Entry));
130     }
131   entry_ctx = ctx;
132
133   if (DBG_ASSUAN)
134     log_debug ("connection to PIN entry established\n");
135
136   rc = assuan_transact (entry_ctx, 
137                         opt.no_grab? "OPTION no-grab":"OPTION grab",
138                         NULL, NULL, NULL, NULL, NULL, NULL);
139   if (rc)
140     return unlock_pinentry (map_assuan_err (rc));
141   if (opt.ttyname)
142     {
143       char *optstr;
144       if (asprintf (&optstr, "OPTION ttyname=%s", opt.ttyname) < 0 )
145         return unlock_pinentry (GNUPG_Out_Of_Core);
146       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
147                             NULL);
148       free (optstr);
149       if (rc)
150         return unlock_pinentry (map_assuan_err (rc));
151     }
152   if (opt.ttytype)
153     {
154       char *optstr;
155       if (asprintf (&optstr, "OPTION ttytype=%s", opt.ttytype) < 0 )
156         return unlock_pinentry (GNUPG_Out_Of_Core);
157       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
158                             NULL);
159       if (rc)
160         return unlock_pinentry (map_assuan_err (rc));
161     }
162   if (opt.lc_ctype)
163     {
164       char *optstr;
165       if (asprintf (&optstr, "OPTION lc-ctype=%s", opt.lc_ctype) < 0 )
166         return unlock_pinentry (GNUPG_Out_Of_Core);
167       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
168                             NULL);
169       if (rc)
170         return unlock_pinentry (map_assuan_err (rc));
171     }
172   if (opt.lc_messages)
173     {
174       char *optstr;
175       if (asprintf (&optstr, "OPTION lc-messages=%s", opt.lc_messages) < 0 )
176         return unlock_pinentry (GNUPG_Out_Of_Core);
177       rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
178                             NULL);
179       if (rc)
180         return unlock_pinentry (map_assuan_err (rc));
181     }
182   return 0;
183 }
184
185
186 static AssuanError
187 getpin_cb (void *opaque, const void *buffer, size_t length)
188 {
189   struct entry_parm_s *parm = opaque;
190
191   if (!buffer)
192     return 0;
193
194   /* we expect the pin to fit on one line */
195   if (parm->lines || length >= parm->size)
196     return ASSUAN_Too_Much_Data;
197
198   /* fixme: we should make sure that the assuan buffer is allocated in
199      secure memory or read the response byte by byte */
200   memcpy (parm->buffer, buffer, length);
201   parm->buffer[length] = 0;
202   parm->lines++;
203   return 0;
204 }
205
206
207 static int
208 all_digitsp( const char *s)
209 {
210   for (; *s && *s >= '0' && *s <= '9'; s++)
211     ;
212   return !*s;
213 }  
214
215
216 \f
217 /* Call the Entry and ask for the PIN.  We do check for a valid PIN
218    number here and repeat it as long as we have invalid formed
219    numbers. */
220 int
221 agent_askpin (const char *desc_text, const char *start_err_text,
222               struct pin_entry_info_s *pininfo)
223 {
224   int rc;
225   char line[ASSUAN_LINELENGTH];
226   struct entry_parm_s parm;
227   const char *errtext = start_err_text;
228
229   if (opt.batch)
230     return 0; /* fixme: we should return BAD PIN */
231
232   if (!pininfo || pininfo->max_length < 1)
233     return seterr (Invalid_Value);
234   if (!desc_text)
235     desc_text = trans ("Please enter you PIN, so that the secret key "
236                        "can be unlocked for this session");
237   
238   rc = start_pinentry ();
239   if (rc)
240     return rc;
241
242   snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
243   line[DIM(line)-1] = 0;
244   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
245   if (rc)
246     return unlock_pinentry (map_assuan_err (rc));
247
248   rc = assuan_transact (entry_ctx,
249                         pininfo->min_digits? "SETPROMPT PIN:"
250                                            : "SETPROMPT Passphrase:",
251                         NULL, NULL, NULL, NULL, NULL, NULL);
252   if (rc)
253     return unlock_pinentry (map_assuan_err (rc));
254
255   for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
256     {
257       memset (&parm, 0, sizeof parm);
258       parm.size = pininfo->max_length;
259       parm.buffer = pininfo->pin;
260
261       if (errtext)
262         { 
263           /* fixme: should we show the try count? It must be translated */
264           if (start_err_text)
265             {
266               snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
267               start_err_text = NULL;
268             }
269           else
270             snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
271                       errtext, pininfo->failed_tries+1, pininfo->max_tries);
272           line[DIM(line)-1] = 0;
273           rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
274           if (rc)
275             return unlock_pinentry (map_assuan_err (rc));
276           errtext = NULL;
277         }
278       
279       rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
280       if (rc == ASSUAN_Too_Much_Data)
281         errtext = pininfo->min_digits? trans ("PIN too long")
282                                      : trans ("Passphrase too long");
283       else if (rc)
284         return unlock_pinentry (map_assuan_err (rc));
285       if (!errtext && !pininfo->min_digits)
286         return unlock_pinentry (0); /* okay, got a passphrase */
287       if (!errtext && !all_digitsp (pininfo->pin))
288         errtext = trans ("Invalid characters in PIN");
289       if (!errtext && pininfo->max_digits
290           && strlen (pininfo->pin) > pininfo->max_digits)
291         errtext = trans ("PIN too long");
292       if (!errtext
293           && strlen (pininfo->pin) < pininfo->min_digits)
294         errtext = trans ("PIN too short");
295
296       if (!errtext)
297         return unlock_pinentry (0); /* okay, got a PIN */
298     }
299
300   return unlock_pinentry (pininfo->min_digits? GNUPG_Bad_PIN
301                           : GNUPG_Bad_Passphrase);
302 }
303
304
305 \f
306 /* Ask for the passphrase using the supplied arguments.  The
307    passphrase is returned in RETPASS as an hex encoded string to be
308    freed by the caller */
309 int 
310 agent_get_passphrase (char **retpass, const char *desc, const char *prompt,
311                       const char *errtext)
312 {
313
314   int rc;
315   char line[ASSUAN_LINELENGTH];
316   struct entry_parm_s parm;
317   unsigned char *p, *hexstring;
318   int i;
319
320   *retpass = NULL;
321   if (opt.batch)
322     return GNUPG_Bad_Passphrase; 
323
324   rc = start_pinentry ();
325   if (rc)
326     return rc;
327
328   if (desc)
329     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
330   else
331     snprintf (line, DIM(line)-1, "RESET");
332   line[DIM(line)-1] = 0;
333   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
334   if (rc)
335     return unlock_pinentry (map_assuan_err (rc));
336
337   snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt? prompt : "Passphrase");
338   line[DIM(line)-1] = 0;
339   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
340   if (rc)
341     return unlock_pinentry (map_assuan_err (rc));
342
343   if (errtext)
344     {
345       snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
346       line[DIM(line)-1] = 0;
347       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
348       if (rc)
349         return unlock_pinentry (map_assuan_err (rc));
350     }
351
352   memset (&parm, 0, sizeof parm);
353   parm.size = ASSUAN_LINELENGTH/2 - 5;
354   parm.buffer = gcry_malloc_secure (parm.size+10);
355   if (!parm.buffer)
356     return unlock_pinentry (seterr (Out_Of_Core));
357
358   assuan_begin_confidential (entry_ctx);
359   rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
360   if (rc)
361     {
362       xfree (parm.buffer);
363       return unlock_pinentry (map_assuan_err (rc));
364     }
365   
366   hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
367   if (!hexstring)
368     {
369       xfree (parm.buffer);
370       return unlock_pinentry (seterr (Out_Of_Core));
371     }
372
373   for (i=0, p=parm.buffer; *p; p++, i += 2)
374     sprintf (hexstring+i, "%02X", *p);
375   
376   xfree (parm.buffer);
377   *retpass = hexstring;
378   return unlock_pinentry (0);
379 }
380
381
382 \f
383 /* Pop up the PIN-entry, display the text and the prompt and ask the
384    user to confirm this.  We return 0 for success, ie. the used
385    confirmed it, GNUPG_Not_Confirmed for what the text says or an
386    other error. */
387 int 
388 agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
389 {
390   int rc;
391   char line[ASSUAN_LINELENGTH];
392
393   rc = start_pinentry ();
394   if (rc)
395     return rc;
396
397   if (desc)
398     snprintf (line, DIM(line)-1, "SETDESC %s", desc);
399   else
400     snprintf (line, DIM(line)-1, "RESET");
401   line[DIM(line)-1] = 0;
402   rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
403   if (rc)
404     return unlock_pinentry (map_assuan_err (rc));
405
406   if (ok)
407     {
408       snprintf (line, DIM(line)-1, "SETOK %s", ok);
409       line[DIM(line)-1] = 0;
410       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
411       if (rc)
412         return unlock_pinentry (map_assuan_err (rc));
413     }
414   if (cancel)
415     {
416       snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
417       line[DIM(line)-1] = 0;
418       rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
419       if (rc)
420         return unlock_pinentry (map_assuan_err (rc));
421     }
422
423   rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
424   return unlock_pinentry (map_assuan_err (rc));
425 }
426
427
428