2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015,
4 Ben Kibbey <bjk@luxsci.net>
6 This file is part of libpwmd.
8 Libpwmd is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
13 Libpwmd is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Libpwmd. If not, see <http://www.gnu.org/licenses/>.
25 #include <sys/types.h>
41 static gpg_error_t
set_pinentry_strings (pwm_t
* pwm
, pwmd_pinentry_t which
);
44 launch_pinentry (pwm_t
* pwm
)
48 int child_list
[] = { -1 };
50 const char **p
= argv
;
51 static struct assuan_malloc_hooks mhooks
= {
52 pwmd_malloc
, pwmd_realloc
, pwmd_free
55 if (!pwm
->pinentry_display
&& !pwm
->pinentry_tty
)
56 return GPG_ERR_ENOTTY
;
59 *p
++ = pwm
->pinentry_display
? "--display" : "--ttyname";
60 *p
++ = pwm
->pinentry_display
? pwm
->pinentry_display
: pwm
->pinentry_tty
;
62 if (pwm
->pinentry_lcctype
)
65 *p
++ = pwm
->pinentry_lcctype
;
68 if (pwm
->pinentry_lcmessages
)
70 *p
++ = "--lc-messages";
71 *p
++ = pwm
->pinentry_lcmessages
;
76 if (!pwm
->pinentry_display
)
79 *p
++ = pwm
->pinentry_term
? pwm
->pinentry_term
: getenv ("TERM");
83 rc
= assuan_new_ext (&ctx
, GPG_ERR_SOURCE_PINENTRY
, &mhooks
, NULL
, NULL
);
87 rc
= assuan_pipe_connect (ctx
,
88 pwm
->pinentry_path
? pwm
->
89 pinentry_path
: PINENTRY_PATH
, argv
, child_list
,
97 pwm
->pinentry_pid
= assuan_get_pid (ctx
);
99 rc
= set_pinentry_strings (pwm
, 0);
101 _pinentry_disconnect (pwm
);
107 pinentry_command (pwm_t
* pwm
, char **result
, size_t * len
, const char *cmd
)
117 gpg_error_t rc
= launch_pinentry (pwm
);
123 return _assuan_command (pwm
, pwm
->pctx
, result
, len
, cmd
);
128 quality_cb (void *data
, const char *line
)
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")))
143 else if (!strcmp (tmp
, N_("it is too short")))
145 else if (!strcmp (tmp
, N_("it is all whitespace")))
147 else if (!strcmp (tmp
, N_("it is based on your username")))
149 else if (!strcmp (tmp
, N_("it does not contain enough DIFFERENT characters")))
151 else if (!strcmp (tmp
, N_("it is based on a dictionary word")))
153 else if (!strcmp (tmp
, N_("it is based upon your password entry")))
155 else if (!strcmp (tmp
, N_("it's derived from your password entry")))
157 else if (!strcmp (tmp
, N_("it is derived from your password entry")))
159 else if (!strcmp (tmp
, N_("it is based on a (reversed) dictionary word")))
161 else if (!strcmp (tmp
, N_("it is derivable from your password entry")))
163 else if (!strcmp (tmp
, N_("it's derivable from your password entry")))
165 else if (!strcmp (tmp
, N_("it looks like a National Insurance number.")))
167 else if (!strcmp (tmp
, N_("it is too simplistic/systematic")))
172 snprintf (buf
, sizeof (buf
), "%i", score
);
173 return assuan_send_data (pwm
->pctx
, buf
, strlen (buf
));
178 set_pinentry_strings (pwm_t
* pwm
, pwmd_pinentry_t which
)
180 char *tmp
, *desc
= NULL
;
183 if (which
!= PWMD_PINENTRY_USER
)
185 rc
= pinentry_command (pwm
, NULL
, NULL
, "SETERROR ");
190 tmp
= pwmd_malloc (ASSUAN_LINELENGTH
+ 1);
192 return gpg_error_from_errno (ENOMEM
);
194 if (!pwm
->pinentry_prompt
)
196 pwm
->pinentry_prompt
= pwmd_strdup (N_("Passphrase:"));
197 if (!pwm
->pinentry_prompt
)
200 return GPG_ERR_ENOMEM
;
204 if (!pwm
->pinentry_desc
)
206 if (which
== PWMD_PINENTRY_OPEN
|| which
== PWMD_PINENTRY_OPEN_FAILED
)
208 if (pwm
->passphrase_hint
&& pwm
->passphrase_info
)
210 char *hint
= pwmd_strdup (pwm
->passphrase_hint
), *hintp
= hint
;
211 char *info
= pwmd_strdup (pwm
->passphrase_info
), *infop
= info
;
212 char *userid
= strchr (hint
, ' ');
214 if (userid
&& *userid
)
217 infop
= strchr (info
, ' ');
220 char *p
= strchr (++infop
, ' ');
223 infop
[strlen(infop
)-strlen(p
)] = 0;
228 desc
= pwmd_strdup_printf (N_
229 ("Please enter the passphrase to unlock the OpenPGP secret key:%%0A%%0AClient: %s%%0AData file: %s%%0AKey id: %s (0x%s)%%0AMain key ID: 0x%s"), pwm
->name
? pwm
->name
: N_("unknown"), pwm
->filename
, userid
, hintp
, infop
);
235 desc
= pwmd_strdup_printf (N_ ("A passphrase is required to decrypt the encrypted data file \"%s\". Please enter the passphrase below."), pwm
->filename
);
238 else if (which
== PWMD_PINENTRY_SAVE
239 || which
== PWMD_PINENTRY_SAVE_FAILED
)
241 pwmd_strdup_printf (N_
242 ("Please enter the passphrase to use to encrypt the data file \"%s\"."),
244 else if (which
== PWMD_PINENTRY_SAVE_CONFIRM
)
246 pwmd_strdup_printf (N_
247 ("Please re-enter the passphrase for confirmation."),
253 return GPG_ERR_ENOMEM
;
257 if (pwm
->pinentry_desc
)
258 desc
= pwm
->pinentry_desc
;
260 if (which
== PWMD_PINENTRY_USER
)
262 snprintf (tmp
, ASSUAN_LINELENGTH
, "SETERROR %s",
263 pwm
->pinentry_error
? pwm
->pinentry_error
: "");
264 rc
= pinentry_command (pwm
, NULL
, NULL
, tmp
);
271 snprintf (tmp
, ASSUAN_LINELENGTH
, "SETDESC %s",
272 pwm
->pinentry_desc
? pwm
->pinentry_desc
: "");
276 if (which
== PWMD_PINENTRY_SAVE_FAILED
277 || which
== PWMD_PINENTRY_OPEN_FAILED
)
279 if (which
== PWMD_PINENTRY_SAVE_FAILED
)
280 snprintf (tmp
, ASSUAN_LINELENGTH
, "SETERROR %s",
281 N_("Passphrases do not match, try again."));
284 if (pwm
->pinentry_tries
)
286 strcpy (tmp
, "SETERROR ");
287 snprintf (tmp
+ strlen ("SETERROR "), ASSUAN_LINELENGTH
,
288 N_("Bad passphrase (try %i of %i)"),
289 pwm
->pinentry_try
+ 1, pwm
->pinentry_tries
);
292 snprintf (tmp
, ASSUAN_LINELENGTH
, "SETERROR %s",
293 N_("Bad passphrase, try again"));
296 rc
= pinentry_command (pwm
, NULL
, NULL
, tmp
);
304 snprintf (tmp
, ASSUAN_LINELENGTH
, "SETDESC %s", desc
);
306 if (pwm
->pinentry_desc
!= desc
)
310 rc
= pinentry_command (pwm
, NULL
, NULL
, tmp
);
317 snprintf (tmp
, ASSUAN_LINELENGTH
, "SETPROMPT %s", pwm
->pinentry_prompt
);
318 rc
= pinentry_command (pwm
, NULL
, NULL
, tmp
);
322 if (!rc
&& (which
== PWMD_PINENTRY_SAVE
||
323 which
== PWMD_PINENTRY_SAVE_FAILED
))
325 rc
= pinentry_command (pwm
, NULL
, NULL
, "SETQUALITYBAR");
328 pwm
->_inquire_func
= quality_cb
;
329 pwm
->_inquire_data
= pwm
;
334 if (!rc
&& pwm
->pinentry_timeout
>= 0)
338 snprintf(buf
, sizeof(buf
), "SETTIMEOUT %i", pwm
->pinentry_timeout
);
339 rc
= pinentry_command(pwm
, NULL
, NULL
, buf
);
346 _pinentry_disconnect (pwm_t
* pwm
)
349 assuan_release (pwm
->pctx
);
352 pwm
->pinentry_pid
= -1;
356 _getpin (pwm_t
* pwm
, char **result
, size_t * len
, pwmd_pinentry_t which
)
358 gpg_error_t rc
= set_pinentry_strings (pwm
, which
);
362 _pinentry_disconnect (pwm
);
366 rc
= pinentry_command (pwm
, result
, len
,
367 which
== PWMD_PINENTRY_CONFIRM
? "CONFIRM" : "GETPIN");
370 _pinentry_disconnect (pwm
);
372 /* This lets PWMD_OPTION_PINENTRY_TIMEOUT work. Note that it is not
373 * thread safe do to the global variables. */
374 if (gpg_err_code (rc
) == GPG_ERR_EOF
)
375 rc
= GPG_ERR_CANCELED
;
377 else if (which
!= PWMD_PINENTRY_CONFIRM
&& len
&& result
)
380 *len
= strlen (*result
); // remove the null byte
383 *result
= pwmd_malloc (1);
393 _pwmd_getpin (pwm_t
* pwm
, const char *filename
, char **result
,
394 size_t * len
, pwmd_pinentry_t which
)
400 return GPG_ERR_INV_ARG
;
403 if (which
== PWMD_PINENTRY_CLOSE
)
405 _pinentry_disconnect (pwm
);
409 if (!result
&& which
!= PWMD_PINENTRY_CONFIRM
)
410 return GPG_ERR_INV_ARG
;
412 pwm
->filename
= (char *) filename
;
413 rc
= _getpin (pwm
, result
, len
, which
);