pwmc: add ".set pinentry-timeout".
[libpwmd.git] / src / pinentry.c
blobce66379ad5646630a77ffd969447e9c308db3741
1 /*
2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of libpwmd.
7 Libpwmd 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 Libpwmd 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 Libpwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <sys/types.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <limits.h>
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #endif
33 #include "pinentry.h"
34 #include "misc.h"
36 #ifdef WITH_QUALITY
37 #include <crack.h>
38 #endif
40 static gpg_error_t set_pinentry_strings (pwm_t * pwm, pwmd_pinentry_t which);
42 static gpg_error_t
43 launch_pinentry (pwm_t * pwm)
45 int rc;
46 assuan_context_t ctx;
47 int child_list[] = { -1 };
48 const char *argv[10];
49 const char **p = argv;
50 static struct assuan_malloc_hooks mhooks = {
51 pwmd_malloc, pwmd_realloc, pwmd_free
54 update_pinentry_settings (pwm);
55 if (!pwm->pinentry_display && !pwm->pinentry_tty)
56 return GPG_ERR_ENOTTY;
58 *p++ = "pinentry";
59 *p++ = pwm->pinentry_display ? "--display" : "--ttyname";
60 *p++ = pwm->pinentry_display ? pwm->pinentry_display : pwm->pinentry_tty;
62 if (pwm->pinentry_lcctype)
64 *p++ = "--lc-ctype";
65 *p++ = pwm->pinentry_lcctype;
68 if (pwm->pinentry_lcmessages)
70 *p++ = "--lc-messages";
71 *p++ = pwm->pinentry_lcmessages;
74 *p = NULL;
76 if (!pwm->pinentry_display)
78 *p++ = "--ttytype";
79 *p++ = pwm->pinentry_term ? pwm->pinentry_term : getenv ("TERM");
80 *p = NULL;
83 rc = assuan_new_ext (&ctx, GPG_ERR_SOURCE_PINENTRY, &mhooks, NULL, NULL);
84 if (rc)
85 return rc;
87 rc = assuan_pipe_connect (ctx,
88 pwm->pinentry_path ? pwm->
89 pinentry_path : PINENTRY_PATH, argv, child_list,
90 NULL, NULL, 0);
91 if (rc)
93 assuan_release (ctx);
94 return rc;
97 pwm->pinentry_pid = assuan_get_pid (ctx);
98 pwm->pctx = ctx;
99 rc = set_pinentry_strings (pwm, 0);
100 if (rc)
101 _pinentry_disconnect (pwm);
103 return rc;
106 static gpg_error_t
107 pinentry_command (pwm_t * pwm, char **result, size_t * len, const char *cmd)
109 if (len)
110 *len = 0;
112 if (result)
113 *result = NULL;
115 if (!pwm->pctx)
117 gpg_error_t rc = launch_pinentry (pwm);
119 if (rc)
120 return rc;
123 return _assuan_command (pwm, pwm->pctx, result, len, cmd);
126 #ifdef WITH_QUALITY
127 static gpg_error_t
128 quality_cb (void *data, const char *line)
130 pwm_t *pwm = data;
131 int score = 0;
132 char buf[5];
133 const char *tmp;
135 if (strncmp (line, "QUALITY ", 8))
136 return GPG_ERR_INV_ARG;
138 if (!(tmp = FascistCheck (line + 8, CRACKLIB_DICT)))
139 return assuan_send_data (pwm->pctx, "100", 3);
141 if (!strcmp (tmp, N_("it is WAY too short")))
142 score = 10;
143 else if (!strcmp (tmp, N_("it is too short")))
144 score = 20;
145 else if (!strcmp (tmp, N_("it is all whitespace")))
146 score = 25;
147 else if (!strcmp (tmp, N_("it is based on your username")))
148 score = 30;
149 else
150 if (!strcmp (tmp, N_("it does not contain enough DIFFERENT characters")))
151 score = 35;
152 else if (!strcmp (tmp, N_("it is based on a dictionary word")))
153 score = 40;
154 else if (!strcmp (tmp, N_("it is based upon your password entry")))
155 score = 50;
156 else if (!strcmp (tmp, N_("it's derived from your password entry")))
157 score = 50;
158 else if (!strcmp (tmp, N_("it is derived from your password entry")))
159 score = 50;
160 else if (!strcmp (tmp, N_("it is based on a (reversed) dictionary word")))
161 score = 60;
162 else if (!strcmp (tmp, N_("it is derivable from your password entry")))
163 score = 70;
164 else if (!strcmp (tmp, N_("it's derivable from your password entry")))
165 score = 70;
166 else if (!strcmp (tmp, N_("it looks like a National Insurance number.")))
167 score = 80;
168 else if (!strcmp (tmp, N_("it is too simplistic/systematic")))
169 score = 90;
170 else
171 score = 0;
173 snprintf (buf, sizeof (buf), "%i", score);
174 return assuan_send_data (pwm->pctx, buf, strlen (buf));
176 #endif
178 static gpg_error_t
179 set_pinentry_strings (pwm_t * pwm, pwmd_pinentry_t which)
181 char *tmp, *desc = NULL;
182 gpg_error_t rc;
184 if (which != PWMD_PINENTRY_USER)
186 rc = pinentry_command (pwm, NULL, NULL, "SETERROR ");
187 if (rc)
188 return rc;
191 tmp = pwmd_malloc (ASSUAN_LINELENGTH + 1);
192 if (!tmp)
193 return gpg_error_from_errno (ENOMEM);
195 if (!pwm->pinentry_prompt)
197 pwm->pinentry_prompt = pwmd_strdup (N_("Passphrase:"));
198 if (!pwm->pinentry_prompt)
200 pwmd_free (tmp);
201 return GPG_ERR_ENOMEM;
205 if (!pwm->pinentry_desc)
207 if (which == PWMD_PINENTRY_OPEN || which == PWMD_PINENTRY_OPEN_FAILED)
208 desc =
209 pwmd_strdup_printf (N_
210 ("A passphrase is required to unlock the secret key for the encrypted data file \"%s\". Please enter the passphrase below."),
211 pwm->filename);
212 else if (which == PWMD_PINENTRY_SAVE
213 || which == PWMD_PINENTRY_SAVE_FAILED)
214 desc =
215 pwmd_strdup_printf (N_
216 ("Please enter the passphrase to use to encrypt the data file \"%s\"."),
217 pwm->filename);
218 else if (which == PWMD_PINENTRY_SAVE_CONFIRM)
219 desc =
220 pwmd_strdup_printf (N_
221 ("Please re-enter the passphrase for confirmation."),
222 pwm->filename);
224 if (!desc)
226 pwmd_free (tmp);
227 return GPG_ERR_ENOMEM;
231 if (pwm->pinentry_desc)
232 desc = pwm->pinentry_desc;
234 if (which == PWMD_PINENTRY_USER)
236 snprintf (tmp, ASSUAN_LINELENGTH, "SETERROR %s",
237 pwm->pinentry_error ? pwm->pinentry_error : "");
238 rc = pinentry_command (pwm, NULL, NULL, tmp);
239 if (rc)
241 pwmd_free (tmp);
242 return rc;
245 snprintf (tmp, ASSUAN_LINELENGTH, "SETDESC %s",
246 pwm->pinentry_desc ? pwm->pinentry_desc : "");
248 else
250 if (which == PWMD_PINENTRY_SAVE_FAILED
251 || which == PWMD_PINENTRY_OPEN_FAILED)
253 if (which == PWMD_PINENTRY_SAVE_FAILED)
254 snprintf (tmp, ASSUAN_LINELENGTH, "SETERROR %s",
255 N_("Passphrases do not match, try again."));
256 else
258 if (pwm->pinentry_tries)
260 strcpy (tmp, "SETERROR ");
261 snprintf (tmp + strlen ("SETERROR "), ASSUAN_LINELENGTH,
262 N_("Bad passphrase (try %i of %i)"),
263 pwm->pinentry_try + 1, pwm->pinentry_tries);
265 else
266 snprintf (tmp, ASSUAN_LINELENGTH, "SETERROR %s",
267 N_("Bad passphrase, try again"));
270 rc = pinentry_command (pwm, NULL, NULL, tmp);
271 if (rc)
273 pwmd_free (tmp);
274 return rc;
278 snprintf (tmp, ASSUAN_LINELENGTH, "SETDESC %s", desc);
280 if (pwm->pinentry_desc != desc)
281 pwmd_free (desc);
284 rc = pinentry_command (pwm, NULL, NULL, tmp);
285 if (rc)
287 pwmd_free (tmp);
288 return rc;
291 snprintf (tmp, ASSUAN_LINELENGTH, "SETPROMPT %s", pwm->pinentry_prompt);
292 rc = pinentry_command (pwm, NULL, NULL, tmp);
293 pwmd_free (tmp);
295 #ifdef WITH_QUALITY
296 if (!rc && (which == PWMD_PINENTRY_SAVE ||
297 which == PWMD_PINENTRY_SAVE_FAILED))
299 rc = pinentry_command (pwm, NULL, NULL, "SETQUALITYBAR");
300 if (!rc)
302 pwm->_inquire_func = quality_cb;
303 pwm->_inquire_data = pwm;
306 #endif
308 if (pwm->pinentry_timeout >= 0)
310 char buf[32];
312 snprintf(buf, sizeof(buf), "SETTIMEOUT %i", pwm->pinentry_timeout);
313 rc = pinentry_command(pwm, NULL, NULL, buf);
316 return rc;
319 void
320 _pinentry_disconnect (pwm_t * pwm)
322 if (pwm->pctx)
323 assuan_release (pwm->pctx);
325 pwm->pctx = NULL;
326 pwm->pinentry_pid = -1;
329 gpg_error_t
330 _getpin (pwm_t * pwm, char **result, size_t * len, pwmd_pinentry_t which)
332 gpg_error_t rc = set_pinentry_strings (pwm, which);
334 if (rc)
336 _pinentry_disconnect (pwm);
337 return rc;
340 rc = pinentry_command (pwm, result, len,
341 which == PWMD_PINENTRY_CONFIRM ? "CONFIRM" : "GETPIN");
342 if (rc)
344 _pinentry_disconnect (pwm);
346 /* This lets PWMD_OPTION_PINENTRY_TIMEOUT work. Note that it is not
347 * thread safe do to the global variables. */
348 if (gpg_err_code (rc) == GPG_ERR_EOF)
349 rc = GPG_ERR_CANCELED;
351 else if (which != PWMD_PINENTRY_CONFIRM && len && result)
353 if (*len)
354 *len = strlen (*result); // remove the null byte
355 else
357 *result = pwmd_malloc (1);
358 *(*result) = 0;
359 *len = 1;
363 return rc;
366 gpg_error_t
367 _pwmd_getpin (pwm_t * pwm, const char *filename, char **result,
368 size_t * len, pwmd_pinentry_t which)
370 gpg_error_t rc;
371 char *p;
373 if (!pwm)
374 return GPG_ERR_INV_ARG;
376 p = pwm->filename;
377 if (which == PWMD_PINENTRY_CLOSE)
379 _pinentry_disconnect (pwm);
380 return 0;
383 if (!result && which != PWMD_PINENTRY_CONFIRM)
384 return GPG_ERR_INV_ARG;
386 pwm->filename = (char *) filename;
387 rc = _getpin (pwm, result, len, which);
388 pwm->filename = p;
389 return rc;