2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd 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
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
31 #include "pwmd-error.h"
34 #include "util-misc.h"
40 #include "util-string.h"
46 void cleanup_all_clients (int atfork
);
47 static gpg_error_t
set_pinentry_strings (struct pinentry_s
*pin
, int which
);
50 mem_realloc_cb (void *data
, const void *buffer
, size_t len
)
52 membuf_t
*mem
= (membuf_t
*) data
;
58 p
= xrealloc (mem
->buf
, mem
->len
+ len
);
63 memcpy ((char *) mem
->buf
+ mem
->len
, buffer
, len
);
70 quality_cb (void *data
, const char *line
)
72 struct pinentry_s
*pin
= data
;
77 if (strncmp (line
, "QUALITY ", 8) != 0)
78 return GPG_ERR_INV_ARG
;
80 tmp
= FascistCheck (line
+ 8, CRACKLIB_DICT
);
82 return assuan_send_data (pin
->ctx
, "100", 3);
84 if (!strcmp (tmp
, _("it's WAY too short")))
86 else if (!strcmp (tmp
, _("it is too short")))
88 else if (!strcmp (tmp
, _("it is all whitespace")))
90 else if (!strcmp (tmp
, _("it is based on your username")))
92 else if (!strcmp (tmp
, _("it is based on a dictionary word")))
94 else if (!strcmp (tmp
, _("it is based upon your password entry")))
96 else if (!strcmp (tmp
, _("it's derived from your password entry")))
98 else if (!strcmp (tmp
, _("it is based on a (reversed) dictionary word")))
100 else if (!strcmp (tmp
, _("it is derivable from your password entry")))
104 (tmp
, _("it does not contain enough DIFFERENT characters")))
106 else if (!strcmp (tmp
, _("it is too simplistic/systematic")))
111 snprintf (buf
, sizeof (buf
), "%i", score
);
113 return assuan_send_data (pin
->ctx
, tmp
, strlen (tmp
));
118 assuan_command (struct pinentry_s
*pin
, char **result
, const char *cmd
)
123 pin
->data
.buf
= NULL
;
125 rc
= assuan_transact (pin
->ctx
, cmd
, mem_realloc_cb
, &pin
->data
,
126 pin
->inquire_cb
, pin
->inquire_data
, NULL
, NULL
);
131 xfree (pin
->data
.buf
);
132 pin
->data
.buf
= NULL
;
139 mem_realloc_cb (&pin
->data
, "", 1);
140 *result
= (char *) pin
->data
.buf
;
148 set_pinentry_options (struct pinentry_s
*pin
)
150 char *display
= getenv ("DISPLAY");
151 int have_display
= 0;
152 char *tty
= NULL
, *ttytype
= NULL
;
156 char cmd
[ASSUAN_LINELENGTH
];
158 if (pin
->pinentry_opts
.display
|| display
)
162 tty
= pin
->pinentry_opts
.ttyname
? pin
->pinentry_opts
.ttyname
163 : ttyname (STDOUT_FILENO
);
165 return gpg_error_from_errno (errno
);
168 if (!have_display
&& !tty
)
169 return GPG_ERR_CANCELED
;
173 char *p
= getenv ("TERM");
175 ttytype
= pin
->pinentry_opts
.ttytype
? pin
->pinentry_opts
.ttytype
: p
;
177 return GPG_ERR_ENOTTY
;
180 opt
= have_display
? str_dup ("DISPLAY") : str_dup ("TTYNAME");
181 val
= have_display
? pin
->pinentry_opts
.display
? pin
->pinentry_opts
.display
183 snprintf (cmd
, sizeof (cmd
), "OPTION %s=%s", str_down (opt
), val
);
185 rc
= assuan_command (pin
, &result
, cmd
);
191 snprintf (cmd
, sizeof (cmd
), "OPTION ttytype=%s", ttytype
);
192 rc
= assuan_command (pin
, &result
, cmd
);
197 snprintf (cmd
, sizeof(cmd
), "SETTIMEOUT %i", pin
->pinentry_opts
.timeout
);
198 rc
= assuan_command (pin
, NULL
, cmd
);
199 /* Not all pinentrys support the SETTIMEOUT command. */
200 if (rc
&& gpg_err_source (rc
) == GPG_ERR_SOURCE_PINENTRY
201 && gpg_err_code (rc
) == GPG_ERR_ASS_UNKNOWN_CMD
)
208 #ifdef HAVE_PTHREAD_ATFORK
212 cleanup_all_clients (1);
216 atfork_cb (void *data
, int n
)
220 cleanup_all_clients (1);
225 launch_pinentry (struct pinentry_s
*pin
)
228 assuan_context_t ctx
;
229 static struct assuan_malloc_hooks mhooks
= { xmalloc
, xrealloc
, xfree
};
230 int child_list
[] = { -1 };
232 const char **p
= argv
;
237 if (pin
->pinentry_opts
.display
)
240 *p
++ = pin
->pinentry_opts
.display
;
243 if (pin
->pinentry_opts
.lc_ctype
)
246 *p
++ = pin
->pinentry_opts
.lc_ctype
;
249 if (pin
->pinentry_opts
.lc_messages
)
251 *p
++ = "--lc-messages";
252 *p
++ = pin
->pinentry_opts
.lc_messages
;
256 rc
= assuan_new_ext (&ctx
, GPG_ERR_SOURCE_DEFAULT
, &mhooks
, NULL
, NULL
);
260 tmp
= config_get_string ("global", "pinentry_path");
261 #ifdef HAVE_PTHREAD_ATFORK
262 pthread_atfork (NULL
, NULL
, atfork_cb
);
263 rc
= assuan_pipe_connect (ctx
, tmp
, argv
, child_list
, NULL
, NULL
, 0);
265 rc
= assuan_pipe_connect (ctx
, tmp
, argv
, child_list
, atfork_cb
, NULL
, 0);
272 rc
= set_pinentry_options (pin
);
273 return rc
? rc
: set_pinentry_strings (pin
, pin
->which
);
277 pinentry_command (struct pinentry_s
*pin
, char **result
, const char *cmd
)
282 rc
= launch_pinentry (pin
);
284 return rc
? rc
: assuan_command (pin
, result
, cmd
);
288 set_pinentry_strings (struct pinentry_s
*pin
, int which
)
294 /* The initial prompt from launch_pinentry(). */
297 if (which
== PINENTRY_FAIL_CONFIRM
)
299 title
= str_dup (_("Passphrase mismatch, please try again."));
300 which
= PINENTRY_SAVE
;
302 else if (!pin
->pinentry_opts
.title
)
303 title
= str_asprintf (_("Password Manager Daemon%s%s"),
304 pin
->name
? ": " : "",
305 pin
->name
? pin
->name
: "");
307 title
= str_dup (pin
->pinentry_opts
.title
);
310 if (which
== PINENTRY_SAVE
)
312 rc
= pinentry_command (pin
, NULL
, "SETQUALITYBAR");
316 pin
->inquire_cb
= quality_cb
;
317 pin
->inquire_data
= pin
;
321 if (!pin
->pinentry_opts
.prompt
)
322 pin
->pinentry_opts
.prompt
= str_dup (_("Passphrase:"));
324 if (!pin
->pinentry_opts
.desc
)
325 pin
->pinentry_opts
.desc
= str_asprintf (which
== PINENTRY_OPEN
?
326 _("A passphrase is required to open the file "
327 "\"%s\". Please enter the passphrase below.")
329 _("A passphrase is required to save to the file "
330 "\"%s\". Please enter the passphrase below."),
333 if (which
== PINENTRY_SAVE_CONFIRM
)
334 buf
= str_asprintf ("SETDESC %s",
335 _("Please enter the passphrase again for confirmation."));
337 buf
= str_asprintf ("SETDESC %s", pin
->pinentry_opts
.desc
);
339 rc
= pinentry_command (pin
, NULL
, buf
);
344 buf
= str_asprintf ("SETPROMPT %s", pin
->pinentry_opts
.prompt
);
345 rc
= pinentry_command (pin
, NULL
, buf
);
350 buf
= str_asprintf ("SETERROR %s", title
);
351 rc
= pinentry_command (pin
, NULL
, buf
);
360 pinentry_disconnect (struct pinentry_s
*pin
)
366 assuan_release (pin
->ctx
);
372 do_getpin (struct pinentry_s
*pin
, char **result
)
377 rc
= pinentry_command (pin
, result
, "GETPIN");
382 *result
= str_dup ("");
388 pinentry_getpin (struct pinentry_s
* pin
, char **result
, pinentry_cmd_t which
)
390 gpg_error_t rc
= set_pinentry_strings (pin
, which
);
391 char *result1
= NULL
;
397 rc
= do_getpin (pin
, result
);
401 if (which
== PINENTRY_SAVE
)
405 rc
= set_pinentry_strings (pin
, PINENTRY_SAVE_CONFIRM
);
413 if (strcmp (result1
, *result
))
417 result1
= *result
= NULL
;
418 rc
= set_pinentry_strings (pin
, PINENTRY_FAIL_CONFIRM
);
428 pinentry_disconnect (pin
);
433 pinentry_lock (assuan_context_t ctx
, struct pinentry_s
*pin
)
437 MUTEX_TRYLOCK (ctx
, &pin_mutex
, rc
, pin
->pinentry_opts
.timeout
*10);
446 pinentry_unlock (struct pinentry_s
*pin
)
448 if (pin
->has_lock
== 0)
451 MUTEX_UNLOCK (&pin_mutex
);
456 pinentry_deinit (struct pinentry_s
*pin
)
461 pinentry_unlock (pin
);
464 pinentry_disconnect (pin
);
467 xfree (pin
->filename
);
468 pinentry_free_opts (&pin
->pinentry_opts
);
473 pinentry_init (const char *filename
)
475 struct pinentry_s
*pin
= xcalloc (1, sizeof (struct pinentry_s
));
480 pin
->filename
= str_dup (filename
);
491 pinentry_free_opts (struct pinentry_option_s
*opts
)
495 xfree (opts
->prompt
);
496 xfree (opts
->ttyname
);
497 xfree (opts
->ttytype
);
498 xfree (opts
->display
);
499 xfree (opts
->lc_messages
);
500 xfree (opts
->lc_ctype
);
504 pinentry_merge_options (struct pinentry_option_s
*dst
,
505 struct pinentry_option_s
*src
)
507 dst
->timeout
= src
->timeout
;
512 dst
->title
= str_dup (src
->title
);
518 dst
->desc
= str_dup (src
->desc
);
524 dst
->prompt
= str_dup (src
->prompt
);
529 xfree (dst
->display
);
530 dst
->display
= str_dup (src
->display
);
535 xfree (dst
->ttyname
);
536 dst
->ttyname
= str_dup (src
->ttyname
);
541 xfree (dst
->ttytype
);
542 dst
->ttytype
= str_dup (src
->ttytype
);
547 xfree (dst
->lc_ctype
);
548 dst
->lc_ctype
= str_dup (src
->lc_ctype
);
551 if (src
->lc_messages
)
553 xfree (dst
->lc_messages
);
554 dst
->lc_messages
= str_dup (src
->lc_messages
);