Add pinentry configure options.
[pwmd.git] / src / pinentry.c
blobb495b414b2c4a1e21cb6e74c7fe644bf78b7908e
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <pwd.h>
26 #include <sys/types.h>
27 #include <signal.h>
28 #include <sys/wait.h>
30 #include "pwmd-error.h"
31 #include <gcrypt.h>
32 #include "mem.h"
33 #include "common.h"
34 #include "commands.h"
35 #include "pinentry.h"
36 #include "util-misc.h"
37 #include "mutex.h"
38 #include "rcfile.h"
39 #include "util-string.h"
41 #ifdef WITH_QUALITY
42 #include <crack.h>
43 #endif
45 static gpg_error_t set_pinentry_strings (struct pinentry_s *pin, int which);
47 static gpg_error_t
48 mem_realloc_cb (void *data, const void *buffer, size_t len)
50 membuf_t *mem = (membuf_t *) data;
51 void *p;
53 if (!buffer)
54 return 0;
56 p = xrealloc (mem->buf, mem->len + len);
57 if (!p)
58 return 1;
60 mem->buf = p;
61 memcpy ((char *) mem->buf + mem->len, buffer, len);
62 mem->len += len;
63 return 0;
66 #ifdef WITH_QUALITY
67 static gpg_error_t
68 quality_cb (void *data, const char *line)
70 struct pinentry_s *pin = data;
71 const char *tmp;
72 int score = 0;
73 char buf[5];
75 if (strncmp (line, "QUALITY ", 8) != 0)
76 return GPG_ERR_INV_ARG;
78 tmp = FascistCheck (line + 8, CRACKLIB_DICT);
79 if (!tmp)
80 return assuan_send_data (pin->ctx, "100", 3);
82 if (!strcmp (tmp, _("it's WAY too short")))
83 score = 10;
84 else if (!strcmp (tmp, _("it is too short")))
85 score = 20;
86 else if (!strcmp (tmp, _("it is all whitespace")))
87 score = 25;
88 else if (!strcmp (tmp, _("it is based on your username")))
89 score = 30;
90 else if (!strcmp (tmp, _("it is based on a dictionary word")))
91 score = 40;
92 else if (!strcmp (tmp, _("it is based upon your password entry")))
93 score = 50;
94 else if (!strcmp (tmp, _("it's derived from your password entry")))
95 score = 50;
96 else if (!strcmp (tmp, _("it is based on a (reversed) dictionary word")))
97 score = 60;
98 else if (!strcmp (tmp, _("it is derivable from your password entry")))
99 score = 70;
100 else
101 if (!strcmp
102 (tmp, _("it does not contain enough DIFFERENT characters")))
103 score = 80;
104 else if (!strcmp (tmp, _("it is too simplistic/systematic")))
105 score = 90;
106 else
107 score = 0;
109 snprintf (buf, sizeof (buf), "%i", score);
110 tmp = buf;
111 return assuan_send_data (pin->ctx, tmp, strlen (tmp));
113 #endif
115 static gpg_error_t
116 assuan_command (struct pinentry_s *pin, char **result, const char *cmd)
118 gpg_error_t rc;
120 pin->data.len = 0;
121 pin->data.buf = NULL;
123 rc = assuan_transact (pin->ctx, cmd, mem_realloc_cb, &pin->data,
124 pin->inquire_cb, pin->inquire_data, NULL, NULL);
125 if (rc)
127 if (pin->data.buf)
129 xfree (pin->data.buf);
130 pin->data.buf = NULL;
133 else
135 if (pin->data.buf)
137 mem_realloc_cb (&pin->data, "", 1);
138 *result = (char *) pin->data.buf;
142 return rc;
145 static gpg_error_t
146 set_pinentry_options (struct pinentry_s *pin)
148 char *display = getenv ("DISPLAY");
149 int have_display = 0;
150 char *tty = NULL, *ttytype = NULL;
151 char *opt, *val;
152 gpg_error_t rc;
153 char *result = NULL;
154 char cmd[ASSUAN_LINELENGTH];
156 if (pin->display || display)
157 have_display = 1;
158 else
160 tty = pin->ttyname ? pin->ttyname : ttyname (STDOUT_FILENO);
161 if (!tty)
162 return gpg_error_from_syserror ();
165 if (!have_display && !tty)
166 return GPG_ERR_CANCELED;
168 if (!have_display)
170 char *p = getenv ("TERM");
172 ttytype = pin->ttytype ? pin->ttytype : p;
173 if (!ttytype)
174 return GPG_ERR_ENOTTY;
177 opt = have_display ? str_dup ("DISPLAY") : str_dup ("TTYNAME");
178 val = have_display ? pin->display ? pin->display : display : tty;
179 snprintf (cmd, sizeof (cmd), "OPTION %s=%s", str_down (opt), val);
180 xfree (opt);
181 rc = assuan_command (pin, &result, cmd);
182 if (rc)
183 return rc;
185 if (!have_display)
187 snprintf (cmd, sizeof (cmd), "OPTION ttytype=%s", ttytype);
188 rc = assuan_command (pin, &result, cmd);
191 return rc;
194 static gpg_error_t
195 launch_pinentry (struct pinentry_s *pin)
197 gpg_error_t rc;
198 assuan_context_t ctx;
199 static struct assuan_malloc_hooks mhooks = { xmalloc, xrealloc, xfree };
200 int child_list[] = { -1 };
201 const char *argv[8];
202 const char **p = argv;
203 char *tmp;
205 *p++ = "pinentry";
207 if (pin->display)
209 *p++ = "--display";
210 *p++ = pin->display;
213 if (pin->lcctype)
215 *p++ = "--lc-ctype";
216 *p++ = pin->lcctype;
219 if (pin->lcmessages)
221 *p++ = "--lc-messages";
222 *p++ = pin->lcmessages;
225 *p = NULL;
226 rc = assuan_new_ext (&ctx, GPG_ERR_SOURCE_DEFAULT, &mhooks, NULL, NULL);
227 if (rc)
228 return rc;
230 tmp = config_get_string ("global", "pinentry_path");
231 rc = assuan_pipe_connect (ctx, pin->path ? pin->path : tmp, argv,
232 child_list, NULL, NULL, 0);
233 xfree (tmp);
234 if (rc)
235 return rc;
237 pin->ctx = ctx;
238 rc = set_pinentry_options (pin);
239 return rc ? rc : set_pinentry_strings (pin, pin->which);
242 static gpg_error_t
243 pinentry_command (struct pinentry_s *pin, char **result, const char *cmd)
245 gpg_error_t rc = 0;
247 if (!pin->ctx)
248 rc = launch_pinentry (pin);
250 return rc ? rc : assuan_command (pin, result, cmd);
253 static gpg_error_t
254 set_pinentry_strings (struct pinentry_s *pin, int which)
256 char *buf;
257 gpg_error_t rc;
258 char *title = NULL;
260 /* The initial prompt from launch_pinentry(). */
261 pin->which = which;
263 #ifdef WITH_QUALITY
264 if (which == PINENTRY_SAVE)
266 rc = pinentry_command (pin, NULL, "SETQUALITYBAR");
267 if (rc)
268 goto done;
270 pin->inquire_cb = quality_cb;
271 pin->inquire_data = pin;
273 #endif
275 if (which == PINENTRY_FAIL_CONFIRM)
277 title = str_dup (_("Passphrase mismatch, please try again."));
278 which = PINENTRY_SAVE;
280 else if (!pin->title)
281 title = str_asprintf (_("Password Manager Daemon%s%s"),
282 pin->name ? ": " : "",
283 pin->name ? pin->name : "");
284 else
285 title = str_dup (pin->title);
287 if (!pin->prompt)
288 pin->prompt = str_dup (_("Passphrase:"));
290 if (!pin->desc)
291 pin->desc = str_asprintf (which == PINENTRY_OPEN ?
292 _("A passphrase is required to open the file "
293 "\"%s\". Please enter the passphrase below.")
295 _("A passphrase is required to save to the file "
296 "\"%s\". Please enter the passphrase below."),
297 pin->filename);
299 if (which == PINENTRY_SAVE_CONFIRM)
300 buf = str_asprintf ("SETDESC %s",
301 _("Please enter the passphrase again for confirmation."));
302 else
303 buf = str_asprintf ("SETDESC %s", pin->desc);
305 rc = pinentry_command (pin, NULL, buf);
306 xfree (buf);
307 if (rc)
308 goto done;
310 buf = str_asprintf ("SETPROMPT %s", pin->prompt);
311 rc = pinentry_command (pin, NULL, buf);
312 xfree (buf);
313 if (rc)
314 goto done;
316 buf = str_asprintf ("SETERROR %s", title);
317 rc = pinentry_command (pin, NULL, buf);
318 xfree (buf);
320 done:
321 free (title);
322 return rc;
325 static void
326 pinentry_disconnect (struct pinentry_s *pin)
328 if (!pin)
329 return;
331 if (pin->ctx)
332 assuan_release (pin->ctx);
334 pin->ctx = NULL;
337 static gpg_error_t
338 do_getpin (struct pinentry_s *pin, char **result)
340 gpg_error_t rc;
342 *result = NULL;
343 rc = pinentry_command (pin, result, "GETPIN");
344 if (rc)
345 return rc;
347 if (!*result)
348 *result = str_dup ("");
350 return rc;
353 gpg_error_t
354 pinentry_getpin (struct pinentry_s * pin, char **result, pinentry_cmd_t which)
356 gpg_error_t rc = set_pinentry_strings (pin, which);
357 char *result1 = NULL;
359 if (rc)
360 goto done;
362 again:
363 rc = do_getpin (pin, result);
364 if (rc)
365 goto done;
367 if (which == PINENTRY_SAVE)
369 if (!result1)
371 rc = set_pinentry_strings (pin, PINENTRY_SAVE_CONFIRM);
372 if (rc)
373 goto done;
375 result1 = str_dup (*result);
376 goto again;
379 if (strcmp (result1, *result))
381 xfree (result1);
382 xfree (*result);
383 result1 = *result = NULL;
384 rc = set_pinentry_strings (pin, PINENTRY_FAIL_CONFIRM);
385 if (rc)
386 goto done;
388 goto again;
392 done:
393 xfree (result1);
394 pinentry_disconnect (pin);
395 return rc;
398 gpg_error_t
399 lock_pin_mutex (struct client_s * client)
401 gpg_error_t rc = 0;
403 MUTEX_TRYLOCK (client->ctx, &pin_mutex, rc, client->pinentry->timeout*10);
405 if (!rc)
406 client->pinentry->has_lock = 1;
408 return rc;
411 void
412 unlock_pin_mutex (struct pinentry_s *pin)
414 if (pin->has_lock == 0)
415 return;
417 MUTEX_UNLOCK (&pin_mutex);
418 pin->has_lock = 0;
421 void
422 pinentry_deinit (struct pinentry_s *pin)
424 if (!pin)
425 return;
427 if (pin->ctx)
428 pinentry_disconnect (pin);
430 if (pin->name)
431 xfree (pin->name);
433 if (pin->ttyname)
434 xfree (pin->ttyname);
436 if (pin->ttytype)
437 xfree (pin->ttytype);
439 if (pin->desc)
440 xfree (pin->desc);
442 if (pin->title)
443 xfree (pin->title);
445 if (pin->prompt)
446 xfree (pin->prompt);
448 if (pin->path)
449 xfree (pin->path);
451 if (pin->display)
452 xfree (pin->display);
454 if (pin->filename)
455 xfree (pin->filename);
457 if (pin->lcctype)
458 xfree (pin->lcctype);
460 if (pin->lcmessages)
461 xfree (pin->lcmessages);
463 xfree (pin);
466 void
467 reset_pin_defaults (struct pinentry_s *pin)
469 pin->enable = -1;
470 pin->timeout = config_get_integer (pin->filename, "pinentry_timeout");
473 void
474 set_pinentry_defaults (struct pinentry_s *pin)
476 FILE *fp;
477 char buf[PATH_MAX];
478 char *p;
480 snprintf (buf, sizeof (buf), "%s/.pwmd/pinentry.conf", get_home_dir ());
481 fp = fopen (buf, "r");
483 if (fp)
485 while ((p = fgets (buf, sizeof (buf), fp)) != NULL)
487 char name[32] = { 0 }, value[256] = { 0 };
489 if (*p == '#')
490 continue;
492 if (p[strlen (p) - 1] == '\n')
493 p[strlen (p) - 1] = 0;
495 if (sscanf (p, " %31[a-zA-Z] = %255s", name, value) != 2)
496 continue;
498 if (strcasecmp ("TTYNAME", name) == 0)
500 if (pin->ttyname)
501 xfree (pin->ttyname);
503 pin->ttyname = str_dup (value);
505 else if (strcasecmp ("TTYTYPE", name) == 0)
507 if (pin->ttytype)
508 xfree (pin->ttytype);
510 pin->ttytype = str_dup (value);
512 else if (strcasecmp ("DISPLAY", name) == 0)
514 if (pin->display)
515 xfree (pin->display);
517 pin->display = str_dup (value);
519 else if (strcasecmp ("PATH", name) == 0)
521 if (pin->path)
522 xfree (pin->path);
524 pin->path = str_dup (value);
526 else if (strcasecmp ("LC_TYPE", name) == 0)
528 if (pin->lcctype)
529 xfree (pin->lcctype);
531 pin->lcctype = str_dup (value);
533 else if (strcasecmp ("LC_MESSAGES", name) == 0)
535 if (pin->lcmessages)
536 xfree (pin->lcmessages);
538 pin->lcmessages = str_dup (value);
542 fclose (fp);
545 reset_pin_defaults (pin);
548 struct pinentry_s *
549 pinentry_init (const char *filename)
551 struct pinentry_s *pin = xcalloc (1, sizeof (struct pinentry_s));
553 if (!pin)
554 return NULL;
556 pin->filename = str_dup (filename);
557 if (!pin->filename)
559 xfree (pin);
560 return NULL;
563 set_pinentry_defaults (pin);
564 return pin;