diff options
-rw-r--r-- | pinentry/argparse.c | 11 | ||||
-rw-r--r-- | pinentry/argparse.h | 3 | ||||
-rw-r--r-- | pinentry/password-cache.c | 21 | ||||
-rw-r--r-- | pinentry/password-cache.h | 5 | ||||
-rw-r--r-- | pinentry/pinentry.c | 1011 | ||||
-rw-r--r-- | pinentry/pinentry.h | 136 |
6 files changed, 1104 insertions, 83 deletions
diff --git a/pinentry/argparse.c b/pinentry/argparse.c index e31b67e..ee9c08b 100644 --- a/pinentry/argparse.c +++ b/pinentry/argparse.c @@ -26,7 +26,8 @@ * * You should have received a copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; - * if not, see <http://www.gnu.org/licenses/>. + * if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+) */ /* This file may be used as part of GnuPG or standalone. A GnuPG @@ -845,7 +846,7 @@ find_long_option( ARGPARSE_ARGS *arg, /* Would be better if we can do a binary search, but it is not possible to reorder our option table because we would mess up our help strings - What we can do is: Build a nice option - lookup table wehn this function is first invoked */ + lookup table when this function is first invoked */ if( !*keyword ) return -1; for(i=0; opts[i].short_opt; i++ ) @@ -1490,10 +1491,10 @@ strusage( int level ) case 10: #if ARGPARSE_GPL_VERSION == 3 p = ("License GPLv3+: GNU GPL version 3 or later " - "<http://gnu.org/licenses/gpl.html>"); + "<https://www.gnu.org/licenses/gpl.html>"); #else p = ("License GPLv2+: GNU GPL version 2 or later " - "<http://gnu.org/licenses/>"); + "<https://www.gnu.org/licenses/>"); #endif break; case 11: p = "foo"; break; @@ -1515,7 +1516,7 @@ ARGPARSE_STR2(ARGPARSE_GPL_VERSION) "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n\n" "You should have received a copy of the GNU General Public License\n" -"along with this software. If not, see <http://www.gnu.org/licenses/>.\n"; +"along with this software. If not, see <https://www.gnu.org/licenses/>.\n"; break; case 40: /* short and long usage */ case 41: p = ""; break; diff --git a/pinentry/argparse.h b/pinentry/argparse.h index b4dc253..5b652eb 100644 --- a/pinentry/argparse.h +++ b/pinentry/argparse.h @@ -25,7 +25,8 @@ * * You should have received a copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; - * if not, see <http://www.gnu.org/licenses/>. + * if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: (GPL-2.0+ OR LGPL-3.0+) */ #ifndef LIBJNLIB_ARGPARSE_H diff --git a/pinentry/password-cache.c b/pinentry/password-cache.c index 70b33f4..f9523b1 100644 --- a/pinentry/password-cache.c +++ b/pinentry/password-cache.c @@ -14,7 +14,8 @@ General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. + along with this program; if not, see <https://www.gnu.org/licenses/>. + SPDX-License-Identifier: GPL-2.0+ */ #ifdef HAVE_CONFIG_H @@ -83,7 +84,7 @@ password_cache_save (const char *keygrip, const char *password) "stored-by", "GnuPG Pinentry", "keygrip", keygrip, NULL)) { - printf("Failed to cache password for key %s with secret service: %s\n", + fprintf (stderr, "Failed to cache password for key %s with secret service: %s\n", keygrip, error->message); g_error_free (error); @@ -91,12 +92,14 @@ password_cache_save (const char *keygrip, const char *password) free (label); #else + (void) keygrip; + (void) password; return; #endif } char * -password_cache_lookup (const char *keygrip) +password_cache_lookup (const char *keygrip, int *fatal_error) { #ifdef HAVE_LIBSECRET GError *error = NULL; @@ -112,7 +115,10 @@ password_cache_lookup (const char *keygrip) if (error != NULL) { - printf("Failed to lookup password for key %s with secret service: %s\n", + if (fatal_error) + *fatal_error = 1; + + fprintf (stderr, "Failed to lookup password for key %s with secret service: %s\n", keygrip, error->message); g_error_free (error); return NULL; @@ -126,12 +132,14 @@ password_cache_lookup (const char *keygrip) if (password2) strcpy(password2, password); else - printf("secmem_malloc failed: can't copy password!\n"); + fprintf (stderr, "secmem_malloc failed: can't copy password!\n"); secret_password_free (password); return password2; #else + (void) keygrip; + (void) fatal_error; return NULL; #endif } @@ -148,7 +156,7 @@ password_cache_clear (const char *keygrip) "keygrip", keygrip, NULL); if (error != NULL) { - printf("Failed to clear password for key %s with secret service: %s\n", + fprintf (stderr, "Failed to clear password for key %s with secret service: %s\n", keygrip, error->message); g_debug("%s", error->message); g_error_free (error); @@ -158,6 +166,7 @@ password_cache_clear (const char *keygrip) return 1; return 0; #else + (void) keygrip; return -1; #endif } diff --git a/pinentry/password-cache.h b/pinentry/password-cache.h index 0bc8788..d7ccfee 100644 --- a/pinentry/password-cache.h +++ b/pinentry/password-cache.h @@ -14,7 +14,8 @@ General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. + along with this program; if not, see <https://www.gnu.org/licenses/>. + SPDX-License-Identifier: GPL-2.0+ */ #ifndef PASSWORD_CACHE_H @@ -22,7 +23,7 @@ void password_cache_save (const char *key_grip, const char *password); -char *password_cache_lookup (const char *key_grip); +char *password_cache_lookup (const char *key_grip, int *fatal_error); int password_cache_clear (const char *keygrip); diff --git a/pinentry/pinentry.c b/pinentry/pinentry.c index f305a7d..b03b90c 100644 --- a/pinentry/pinentry.c +++ b/pinentry/pinentry.c @@ -1,28 +1,58 @@ /* pinentry.c - The PIN entry support library - Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015 g10 Code GmbH - - This file is part of PINENTRY. - - PINENTRY is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PINENTRY is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. + * Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015, 2016, 2021 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef HAVE_W32CE_SYSTEM +# include <errno.h> +#endif #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <sys/stat.h> #include <unistd.h> #include <assert.h> +#ifndef HAVE_W32_SYSTEM +# include <sys/utsname.h> +#endif +#ifndef HAVE_W32CE_SYSTEM +# include <locale.h> +#endif +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif +#include <limits.h> +#ifdef HAVE_W32CE_SYSTEM +# include <windows.h> +#endif + +#undef WITH_UTF8_CONVERSION +#if defined FALLBACK_CURSES || defined PINENTRY_CURSES || defined PINENTRY_GTK +# include <iconv.h> +# define WITH_UTF8_CONVERSION 1 +#endif #include <assuan.h> +#include <strings.h> #include "memory.h" #include "secmem-util.h" @@ -30,11 +60,39 @@ #include "pinentry.h" #include "password-cache.h" +#ifdef INSIDE_EMACS +# include "pinentry-emacs.h" +#endif +#ifdef FALLBACK_CURSES +# include "pinentry-curses.h" +#endif + +#ifdef HAVE_W32CE_SYSTEM +#define getpid() GetCurrentProcessId () +#endif + /* Keep the name of our program here. */ static char this_pgmname[50]; struct pinentry pinentry; + +static const char *flavor_flag; + +/* Because gtk_init removes the --display arg from the command lines + * and our command line parser is called after gtk_init (so that it + * does not see gtk specific options) we don't have a way to get hold + * of the --display option. Our solution is to remember --display in + * the call to pinentry_have_display and set it then in our + * parser. */ +static char *remember_display; + +/* Flag to remember whether a warning has been printed. */ +#ifdef WITH_UTF8_CONVERSION +static int lc_ctype_unknown_warning; +#endif + + static void pinentry_reset (int use_defaults) { @@ -42,7 +100,8 @@ pinentry_reset (int use_defaults) Don't reset them. */ int grab = pinentry.grab; char *ttyname = pinentry.ttyname; - char *ttytype = pinentry.ttytype; + char *ttytype = pinentry.ttytype_l; + char *ttyalert = pinentry.ttyalert; char *lc_ctype = pinentry.lc_ctype; char *lc_messages = pinentry.lc_messages; int allow_external_password_cache = pinentry.allow_external_password_cache; @@ -50,7 +109,18 @@ pinentry_reset (int use_defaults) char *default_cancel = pinentry.default_cancel; char *default_prompt = pinentry.default_prompt; char *default_pwmngr = pinentry.default_pwmngr; + char *default_cf_visi = pinentry.default_cf_visi; + char *default_tt_visi = pinentry.default_tt_visi; + char *default_tt_hide = pinentry.default_tt_hide; + char *default_capshint = pinentry.default_capshint; char *touch_file = pinentry.touch_file; + unsigned long owner_pid = pinentry.owner_pid; + int owner_uid = pinentry.owner_uid; + char *owner_host = pinentry.owner_host; + int constraints_enforce = pinentry.constraints_enforce; + char *constraints_hint_short = pinentry.constraints_hint_short; + char *constraints_hint_long = pinentry.constraints_hint_long; + char *constraints_error_title = pinentry.constraints_error_title; /* These options are set from the command line. Don't reset them. */ @@ -64,21 +134,33 @@ pinentry_reset (int use_defaults) pinentry_color_t color_so = pinentry.color_so; int color_so_bright = pinentry.color_so_bright; - int timout = pinentry.timeout; + int timeout = pinentry.timeout; + + char *invisible_char = pinentry.invisible_char; + /* Free any allocated memory. */ if (use_defaults) { free (pinentry.ttyname); - free (pinentry.ttytype); + free (pinentry.ttytype_l); + free (pinentry.ttyalert); free (pinentry.lc_ctype); free (pinentry.lc_messages); free (pinentry.default_ok); free (pinentry.default_cancel); free (pinentry.default_prompt); free (pinentry.default_pwmngr); + free (pinentry.default_cf_visi); + free (pinentry.default_tt_visi); + free (pinentry.default_tt_hide); + free (pinentry.default_capshint); free (pinentry.touch_file); + free (pinentry.owner_host); free (pinentry.display); + free (pinentry.constraints_hint_short); + free (pinentry.constraints_hint_long); + free (pinentry.constraints_error_title); } free (pinentry.title); @@ -93,11 +175,18 @@ pinentry_reset (int use_defaults) free (pinentry.repeat_error_string); free (pinentry.quality_bar); free (pinentry.quality_bar_tt); + free (pinentry.formatted_passphrase_hint); free (pinentry.keyinfo); + free (pinentry.specific_err_info); /* Reset the pinentry structure. */ memset (&pinentry, 0, sizeof (pinentry)); + /* Restore options without a default we want to preserve. */ + pinentry.invisible_char = invisible_char; + + /* Restore other options or set defaults. */ + if (use_defaults) { /* Pinentry timeout in seconds. */ @@ -111,13 +200,15 @@ pinentry_reset (int use_defaults) pinentry.color_bg = PINENTRY_COLOR_DEFAULT; pinentry.color_so = PINENTRY_COLOR_DEFAULT; pinentry.color_so_bright = 0; + + pinentry.owner_uid = -1; } - else - /* Restore the options. */ + else /* Restore the options. */ { pinentry.grab = grab; pinentry.ttyname = ttyname; - pinentry.ttytype = ttytype; + pinentry.ttytype_l = ttytype; + pinentry.ttyalert = ttyalert; pinentry.lc_ctype = lc_ctype; pinentry.lc_messages = lc_messages; pinentry.allow_external_password_cache = allow_external_password_cache; @@ -125,7 +216,18 @@ pinentry_reset (int use_defaults) pinentry.default_cancel = default_cancel; pinentry.default_prompt = default_prompt; pinentry.default_pwmngr = default_pwmngr; + pinentry.default_cf_visi = default_cf_visi; + pinentry.default_tt_visi = default_tt_visi; + pinentry.default_tt_hide = default_tt_hide; + pinentry.default_capshint = default_capshint; pinentry.touch_file = touch_file; + pinentry.owner_pid = owner_pid; + pinentry.owner_uid = owner_uid; + pinentry.owner_host = owner_host; + pinentry.constraints_enforce = constraints_enforce; + pinentry.constraints_hint_short = constraints_hint_short; + pinentry.constraints_hint_long = constraints_hint_long; + pinentry.constraints_error_title = constraints_error_title; pinentry.debug = debug; pinentry.display = display; @@ -137,7 +239,7 @@ pinentry_reset (int use_defaults) pinentry.color_so = color_so; pinentry.color_so_bright = color_so_bright; - pinentry.timeout = timout; + pinentry.timeout = timeout; } } @@ -154,7 +256,149 @@ pinentry_assuan_reset_handler (assuan_context_t ctx, char *line) -static int lc_ctype_unknown_warning = 0; +#ifdef WITH_UTF8_CONVERSION +char * +pinentry_utf8_to_local (const char *lc_ctype, const char *text) +{ + iconv_t cd; + const char *input = text; + size_t input_len = strlen (text) + 1; + char *output; + size_t output_len; + char *output_buf; + size_t processed; + char *old_ctype; + char *target_encoding; + + /* If no locale setting could be determined, simply copy the + string. */ + if (!lc_ctype) + { + if (! lc_ctype_unknown_warning) + { + fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n", + this_pgmname); + lc_ctype_unknown_warning = 1; + } + return strdup (text); + } + + old_ctype = strdup (setlocale (LC_CTYPE, NULL)); + if (!old_ctype) + return NULL; + setlocale (LC_CTYPE, lc_ctype); + target_encoding = nl_langinfo (CODESET); + if (!target_encoding) + target_encoding = "?"; + setlocale (LC_CTYPE, old_ctype); + free (old_ctype); + + /* This is overkill, but simplifies the iconv invocation greatly. */ + output_len = input_len * MB_LEN_MAX; + output_buf = output = malloc (output_len); + if (!output) + return NULL; + + cd = iconv_open (target_encoding, "UTF-8"); + if (cd == (iconv_t) -1) + { + fprintf (stderr, "%s: can't convert from UTF-8 to %s: %s\n", + this_pgmname, target_encoding, strerror (errno)); + free (output_buf); + return NULL; + } + processed = iconv (cd, (ICONV_CONST char **)&input, &input_len, + &output, &output_len); + iconv_close (cd); + if (processed == (size_t) -1 || input_len) + { + fprintf (stderr, "%s: error converting from UTF-8 to %s: %s\n", + this_pgmname, target_encoding, strerror (errno)); + free (output_buf); + return NULL; + } + return output_buf; +} +#endif /*WITH_UTF8_CONVERSION*/ + + +/* Convert TEXT which is encoded according to LC_CTYPE to UTF-8. With + SECURE set to true, use secure memory for the returned buffer. + Return NULL on error. */ +#ifdef WITH_UTF8_CONVERSION +char * +pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure) +{ + char *old_ctype; + char *source_encoding; + iconv_t cd; + const char *input = text; + size_t input_len = strlen (text) + 1; + char *output; + size_t output_len; + char *output_buf; + size_t processed; + + /* If no locale setting could be determined, simply copy the + string. */ + if (!lc_ctype) + { + if (! lc_ctype_unknown_warning) + { + fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n", + this_pgmname); + lc_ctype_unknown_warning = 1; + } + output_buf = secure? secmem_malloc (input_len) : malloc (input_len); + if (output_buf) + strcpy (output_buf, input); + return output_buf; + } + + old_ctype = strdup (setlocale (LC_CTYPE, NULL)); + if (!old_ctype) + return NULL; + setlocale (LC_CTYPE, lc_ctype); + source_encoding = nl_langinfo (CODESET); + setlocale (LC_CTYPE, old_ctype); + free (old_ctype); + + /* This is overkill, but simplifies the iconv invocation greatly. */ + output_len = input_len * MB_LEN_MAX; + output_buf = output = secure? secmem_malloc (output_len):malloc (output_len); + if (!output) + return NULL; + + cd = iconv_open ("UTF-8", source_encoding); + if (cd == (iconv_t) -1) + { + fprintf (stderr, "%s: can't convert from %s to UTF-8: %s\n", + this_pgmname, source_encoding? source_encoding : "?", + strerror (errno)); + if (secure) + secmem_free (output_buf); + else + free (output_buf); + return NULL; + } + processed = iconv (cd, (ICONV_CONST char **)&input, &input_len, + &output, &output_len); + iconv_close (cd); + if (processed == (size_t) -1 || input_len) + { + fprintf (stderr, "%s: error converting from %s to UTF-8: %s\n", + this_pgmname, source_encoding? source_encoding : "?", + strerror (errno)); + if (secure) + secmem_free (output_buf); + else + free (output_buf); + return NULL; + } + return output_buf; +} +#endif /*WITH_UTF8_CONVERSION*/ + /* Copy TEXT or TEXTLEN to BUFFER and escape as required. Return a pointer to the end of the new buffer. Note that BUFFER must be @@ -183,6 +427,172 @@ copy_and_escape (char *buffer, const void *text, size_t textlen) } +/* Perform percent unescaping in STRING and return the new valid length + of the string. A terminating Nul character is inserted at the end of + the unescaped string. + */ +static size_t +do_unescape_inplace (char *s) +{ + unsigned char *p, *p0; + + p = p0 = s; + while (*s) + { + if (*s == '%' && s[1] && s[2]) + { + s++; + *p++ = xtoi_2 (s); + s += 2; + } + else + *p++ = *s++; + } + *p = 0; + + return (p - p0); +} + + +/* Return a malloced copy of the commandline for PID. If this is not + * possible NULL is returned. */ +#ifndef HAVE_W32_SYSTEM +static char * +get_cmdline (unsigned long pid) +{ + char buffer[200]; + FILE *fp; + size_t i, n; + + snprintf (buffer, sizeof buffer, "/proc/%lu/cmdline", pid); + buffer[sizeof buffer - 1] = 0; + + fp = fopen (buffer, "rb"); + if (!fp) + return NULL; + n = fread (buffer, 1, sizeof buffer - 1, fp); + if (n < sizeof buffer -1 && ferror (fp)) + { + /* Some error occurred. */ + fclose (fp); + return NULL; + } + fclose (fp); + if (n == 0) + return NULL; + /* Arguments are delimited by Nuls. We should do proper quoting but + * that can be a bit complicated, thus we simply replace the Nuls by + * spaces. */ + for (i=0; i < n; i++) + if (!buffer[i] && i < n-1) + buffer[i] = ' '; + buffer[i] = 0; /* Make sure the last byte is the string terminator. */ + + return strdup (buffer); +} +#endif /*!HAVE_W32_SYSTEM*/ + + +/* Atomically ask the kernel for information about process PID. + * Return a malloc'ed copy of the process name as long as the process + * uid matches UID. If it cannot determine that the process has uid + * UID, it returns NULL. + * + * This is not as informative as get_cmdline, but it verifies that the + * process does belong to the user in question. + */ +#ifndef HAVE_W32_SYSTEM +static char * +get_pid_name_for_uid (unsigned long pid, int uid) +{ + char buffer[400]; + FILE *fp; + size_t end, n; + char *uidstr; + + snprintf (buffer, sizeof buffer, "/proc/%lu/status", pid); + buffer[sizeof buffer - 1] = 0; + + fp = fopen (buffer, "rb"); + if (!fp) + return NULL; + n = fread (buffer, 1, sizeof buffer - 1, fp); + if (n < sizeof buffer -1 && ferror (fp)) + { + /* Some error occurred. */ + fclose (fp); + return NULL; + } + fclose (fp); + if (n == 0) + return NULL; + /* Fixme: Is it specified that "Name" is always the first line? For + * robustness I would prefer to have a real parser here. -wk */ + if (strncmp (buffer, "Name:\t", 6)) + return NULL; + end = strcspn (buffer + 6, "\n") + 6; + buffer[end] = 0; + + /* check that uid matches what we expect */ + uidstr = strstr (buffer + end + 1, "\nUid:\t"); + if (!uidstr) + return NULL; + if (atoi (uidstr + 6) != uid) + return NULL; + + return strdup (buffer + 6); +} +#endif /*!HAVE_W32_SYSTEM*/ + + +/* Return a malloced string with the title. The caller mus free the + * string. If no title is available or the title string has an error + * NULL is returned. */ +char * +pinentry_get_title (pinentry_t pe) +{ + char *title; + + if (pe->title) + title = strdup (pe->title); +#ifndef HAVE_W32_SYSTEM + else if (pe->owner_pid) + { + char buf[200]; + struct utsname utsbuf; + char *pidname = NULL; + char *cmdline = NULL; + + if (pe->owner_host && + !uname (&utsbuf) && utsbuf.nodename && + !strcmp (utsbuf.nodename, pe->owner_host)) + { + pidname = get_pid_name_for_uid (pe->owner_pid, pe->owner_uid); + if (pidname) + cmdline = get_cmdline (pe->owner_pid); + } + + if (pe->owner_host && (cmdline || pidname)) + snprintf (buf, sizeof buf, "[%lu]@%s (%s)", + pe->owner_pid, pe->owner_host, cmdline ? cmdline : pidname); + else if (pe->owner_host) + snprintf (buf, sizeof buf, "[%lu]@%s", + pe->owner_pid, pe->owner_host); + else + snprintf (buf, sizeof buf, "[%lu] <unknown host>", + pe->owner_pid); + buf[sizeof buf - 1] = 0; + free (pidname); + free (cmdline); + title = strdup (buf); + } +#endif /*!HAVE_W32_SYSTEM*/ + else + title = strdup (this_pgmname); + + return title; +} + /* Run a quality inquiry for PASSPHRASE of LENGTH. (We need LENGTH because not all backends might be able to return a proper @@ -259,6 +669,122 @@ pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length) } +/* Run a checkpin inquiry */ +char * +pinentry_inq_checkpin (pinentry_t pin, const char *passphrase, size_t length) +{ + assuan_context_t ctx = pin->ctx_assuan; + const char prefix[] = "INQUIRE CHECKPIN "; + char *command; + char *line; + size_t linelen; + int gotvalue = 0; + char *value = NULL; + int rc; + + if (!ctx) + return 0; /* Can't run the callback. */ + + if (length > 300) + length = 300; /* Limit so that it definitely fits into an Assuan + line. */ + + command = secmem_malloc (strlen (prefix) + 3*length + 1); + if (!command) + return 0; + strcpy (command, prefix); + copy_and_escape (command + strlen(command), passphrase, length); + rc = assuan_write_line (ctx, command); + secmem_free (command); + if (rc) + { + fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); + return 0; + } + + for (;;) + { + do + { + rc = assuan_read_line (ctx, &line, &linelen); + if (rc) + { + fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); + return 0; + } + } + while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' + && (!line[3] || line[3] == ' ')) + break; /* CAN command received*/ + if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (!line[3] || line[3] == ' ')) + break; /* ERR command received*/ + if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) + continue; + gotvalue = 1; + value = strdup (line + 2); + } + + return value; +} + + +/* Run a genpin inquiry */ +char * +pinentry_inq_genpin (pinentry_t pin) +{ + assuan_context_t ctx = pin->ctx_assuan; + const char prefix[] = "INQUIRE GENPIN"; + char *line; + size_t linelen; + int gotvalue = 0; + char *value = NULL; + int rc; + + if (!ctx) + return 0; /* Can't run the callback. */ + + rc = assuan_write_line (ctx, prefix); + if (rc) + { + fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc); + return 0; + } + + for (;;) + { + do + { + rc = assuan_read_line (ctx, &line, &linelen); + if (rc) + { + fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc); + free (value); + return 0; + } + } + while (*line == '#' || !linelen); + if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (!line[3] || line[3] == ' ')) + break; /* END command received*/ + if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N' + && (!line[3] || line[3] == ' ')) + break; /* CAN command received*/ + if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (!line[3] || line[3] == ' ')) + break; /* ERR command received*/ + if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue) + continue; + gotvalue = 1; + value = strdup (line + 2); + } + + return value; +} /* Try to make room for at least LEN bytes in the pinentry. Returns new buffer on success and 0 on failure or when the old buffer is @@ -375,10 +901,54 @@ pinentry_init (const char *pgmname) int pinentry_have_display (int argc, char **argv) { + int found = 0; + for (; argc; argc--, argv++) - if (!strcmp (*argv, "--display") || !strncmp (*argv, "--display=", 10)) - return 1; - return 0; + { + if (!strcmp (*argv, "--display")) + { + if (argv[1] && !remember_display) + { + remember_display = strdup (argv[1]); + if (!remember_display) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + } + found = 1; + break; + } + else if (!strncmp (*argv, "--display=", 10)) + { + if (!remember_display) + { + remember_display = strdup (*argv+10); + if (!remember_display) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + } + found = 1; + break; + } + } + +#ifndef HAVE_W32CE_SYSTEM + { + const char *s; + s = getenv ("DISPLAY"); + if (s && *s) + found = 1; + } +#endif + + return found; } @@ -394,7 +964,7 @@ my_strusage( int level ) case 11: p = this_pgmname; break; case 12: p = "pinentry"; break; case 13: p = PACKAGE_VERSION; break; - case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break; + case 14: p = "Copyright (C) 2016 g10 Code GmbH"; break; case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break; case 1: case 40: @@ -406,8 +976,11 @@ my_strusage( int level ) size_t n = 50 + strlen (this_pgmname); str = malloc (n); if (str) - snprintf (str, n, "Usage: %s [options] (-h for help)", - this_pgmname); + { + snprintf (str, n, "Usage: %s [options] (-h for help)", + this_pgmname); + str[n-1] = 0; + } } p = str; } @@ -494,6 +1067,7 @@ pinentry_parse_opts (int argc, char *argv[]) "Grab keyboard only while window is focused"), ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"), ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"), + ARGPARSE_s_s('a', "ttyalert", "|STRING|Set the alert mode (none, beep or flash)"), ARGPARSE_end() }; ARGPARSE_ARGS pargs = { &argc, &argv, 0 }; @@ -519,6 +1093,9 @@ pinentry_parse_opts (int argc, char *argv[]) pinentry.display = strdup (pargs.r.ret_str); if (!pinentry.display) { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif exit (EXIT_FAILURE); } break; @@ -526,13 +1103,19 @@ pinentry_parse_opts (int argc, char *argv[]) pinentry.ttyname = strdup (pargs.r.ret_str); if (!pinentry.ttyname) { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif exit (EXIT_FAILURE); } break; case 'N': - pinentry.ttytype = strdup (pargs.r.ret_str); - if (!pinentry.ttytype) + pinentry.ttytype_l = strdup (pargs.r.ret_str); + if (!pinentry.ttytype_l) { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif exit (EXIT_FAILURE); } break; @@ -540,6 +1123,9 @@ pinentry_parse_opts (int argc, char *argv[]) pinentry.lc_ctype = strdup (pargs.r.ret_str); if (!pinentry.lc_ctype) { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif exit (EXIT_FAILURE); } break; @@ -547,6 +1133,9 @@ pinentry_parse_opts (int argc, char *argv[]) pinentry.lc_messages = strdup (pargs.r.ret_str); if (!pinentry.lc_messages) { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif exit (EXIT_FAILURE); } break; @@ -570,13 +1159,40 @@ pinentry_parse_opts (int argc, char *argv[]) pinentry.timeout = pargs.r.ret_int; break; + case 'a': + pinentry.ttyalert = strdup (pargs.r.ret_str); + if (!pinentry.ttyalert) + { +#ifndef HAVE_W32CE_SYSTEM + fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno)); +#endif + exit (EXIT_FAILURE); + } + break; + default: pargs.err = ARGPARSE_PRINT_WARNING; break; } } + + if (!pinentry.display && remember_display) + { + pinentry.display = remember_display; + remember_display = NULL; + } +} + + +/* Set the optional flag used with getinfo. */ +void +pinentry_set_flavor_flag (const char *string) +{ + flavor_flag = string; } + + static gpg_error_t option_handler (assuan_context_t ctx, const char *key, const char *value) @@ -589,6 +1205,12 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) pinentry.grab = 1; else if (!strcmp (key, "debug-wait")) { +#ifndef HAVE_W32_SYSTEM + fprintf (stderr, "%s: waiting for debugger - my pid is %u ...\n", + this_pgmname, (unsigned int) getpid()); + sleep (*value?atoi (value):5); + fprintf (stderr, "%s: ... okay\n", this_pgmname); +#endif } else if (!strcmp (key, "display")) { @@ -608,10 +1230,18 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) } else if (!strcmp (key, "ttytype")) { - if (pinentry.ttytype) - free (pinentry.ttytype); - pinentry.ttytype = strdup (value); - if (!pinentry.ttytype) + if (pinentry.ttytype_l) + free (pinentry.ttytype_l); + pinentry.ttytype_l = strdup (value); + if (!pinentry.ttytype_l) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "ttyalert")) + { + if (pinentry.ttyalert) + free (pinentry.ttyalert); + pinentry.ttyalert = strdup (value); + if (!pinentry.ttyalert) return gpg_error_from_syserror (); } else if (!strcmp (key, "lc-ctype")) @@ -630,6 +1260,46 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) if (!pinentry.lc_messages) return gpg_error_from_syserror (); } + else if (!strcmp (key, "owner")) + { + long along; + char *endp; + + free (pinentry.owner_host); + pinentry.owner_host = NULL; + pinentry.owner_uid = -1; + pinentry.owner_pid = 0; + + errno = 0; + along = strtol (value, &endp, 10); + if (along && !errno) + { + pinentry.owner_pid = (unsigned long)along; + if (*endp) + { + errno = 0; + if (*endp == '/') { /* we have a uid */ + endp++; + along = strtol (endp, &endp, 10); + if (along >= 0 && !errno) + pinentry.owner_uid = (int)along; + } + if (endp) + { + while (*endp == ' ') + endp++; + if (*endp) + { + pinentry.owner_host = strdup (endp); + for (endp=pinentry.owner_host; + *endp && *endp != ' '; endp++) + ; + *endp = 0; + } + } + } + } + } else if (!strcmp (key, "parent-wid")) { pinentry.parent_wid = atoi (value); @@ -667,6 +1337,30 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) if (!pinentry.default_pwmngr) return gpg_error_from_syserror (); } + else if (!strcmp (key, "default-cf-visi")) + { + pinentry.default_cf_visi = strdup (value); + if (!pinentry.default_cf_visi) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-tt-visi")) + { + pinentry.default_tt_visi = strdup (value); + if (!pinentry.default_tt_visi) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-tt-hide")) + { + pinentry.default_tt_hide = strdup (value); + if (!pinentry.default_tt_hide) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "default-capshint")) + { + pinentry.default_capshint = strdup (value); + if (!pinentry.default_capshint) + return gpg_error_from_syserror (); + } else if (!strcmp (key, "allow-external-password-cache") && !*value) { pinentry.allow_external_password_cache = 1; @@ -674,7 +1368,59 @@ option_handler (assuan_context_t ctx, const char *key, const char *value) } else if (!strcmp (key, "allow-emacs-prompt") && !*value) { - return gpg_error (GPG_ERR_NOT_SUPPORTED); +#ifdef INSIDE_EMACS + pinentry_enable_emacs_cmd_handler (); +#endif + } + else if (!strcmp (key, "invisible-char")) + { + if (pinentry.invisible_char) + free (pinentry.invisible_char); + pinentry.invisible_char = strdup (value); + if (!pinentry.invisible_char) + return gpg_error_from_syserror (); + } + else if (!strcmp (key, "formatted-passphrase") && !*value) + { + pinentry.formatted_passphrase = 1; + } + else if (!strcmp (key, "formatted-passphrase-hint")) + { + if (pinentry.formatted_passphrase_hint) + free (pinentry.formatted_passphrase_hint); + pinentry.formatted_passphrase_hint = strdup (value); + if (!pinentry.formatted_passphrase_hint) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.formatted_passphrase_hint); + } + else if (!strcmp (key, "constraints-enforce") && !*value) + pinentry.constraints_enforce = 1; + else if (!strcmp (key, "constraints-hint-short")) + { + if (pinentry.constraints_hint_short) + free (pinentry.constraints_hint_short); + pinentry.constraints_hint_short = strdup (value); + if (!pinentry.constraints_hint_short) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.constraints_hint_short); + } + else if (!strcmp (key, "constraints-hint-long")) + { + if (pinentry.constraints_hint_long) + free (pinentry.constraints_hint_long); + pinentry.constraints_hint_long = strdup (value); + if (!pinentry.constraints_hint_long) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.constraints_hint_long); + } + else if (!strcmp (key, "constraints-error-title")) + { + if (pinentry.constraints_error_title) + free (pinentry.constraints_error_title); + pinentry.constraints_error_title = strdup (value); + if (!pinentry.constraints_error_title) + return gpg_error_from_syserror (); + do_unescape_inplace(pinentry.constraints_error_title); } else return gpg_error (GPG_ERR_UNKNOWN_OPTION); @@ -702,6 +1448,28 @@ strcpy_escaped (char *d, const char *s) } +static void +write_status_error (assuan_context_t ctx, pinentry_t pe) +{ + char buf[500]; + const char *pgm; + + pgm = strchr (this_pgmname, '-'); + if (pgm && pgm[1]) + pgm++; + else + pgm = this_pgmname; + + snprintf (buf, sizeof buf, "%s.%s %d %s", + pgm, + pe->specific_err_loc? pe->specific_err_loc : "?", + pe->specific_err, + pe->specific_err_info? pe->specific_err_info : ""); + buf[sizeof buf -1] = 0; + assuan_write_status (ctx, "ERROR", buf); +} + + static gpg_error_t cmd_setdesc (assuan_context_t ctx, char *line) { @@ -947,6 +1715,53 @@ cmd_setqualitybar_tt (assuan_context_t ctx, char *line) return 0; } +/* Set the tooltip to be used for a generate action. */ +static gpg_error_t +cmd_setgenpin_tt (assuan_context_t ctx, char *line) +{ + char *newval; + + (void)ctx; + + if (*line) + { + newval = malloc (strlen (line) + 1); + if (!newval) + return gpg_error_from_syserror (); + + strcpy_escaped (newval, line); + } + else + newval = NULL; + if (pinentry.genpin_tt) + free (pinentry.genpin_tt); + pinentry.genpin_tt = newval; + return 0; +} + +/* Set the label to be used for a generate action. */ +static gpg_error_t +cmd_setgenpin_label (assuan_context_t ctx, char *line) +{ + char *newval; + + (void)ctx; + + if (*line) + { + newval = malloc (strlen (line) + 1); + if (!newval) + return gpg_error_from_syserror (); + + strcpy_escaped (newval, line); + } + else + newval = NULL; + if (pinentry.genpin_label) + free (pinentry.genpin_label); + pinentry.genpin_label = newval; + return 0; +} static gpg_error_t cmd_getpin (assuan_context_t ctx, char *line) @@ -975,10 +1790,14 @@ cmd_getpin (assuan_context_t ctx, char *line) && ! pinentry.error) { char *password; + int give_up_on_password_store = 0; pinentry.tried_password_cache = 1; - password = password_cache_lookup (pinentry.keyinfo); + password = password_cache_lookup (pinentry.keyinfo, &give_up_on_password_store); + if (give_up_on_password_store) + pinentry.allow_external_password_cache = 0; + if (password) /* There is a cached password. Try it. */ { @@ -1016,6 +1835,9 @@ cmd_getpin (assuan_context_t ctx, char *line) } pinentry.locale_err = 0; pinentry.specific_err = 0; + pinentry.specific_err_loc = NULL; + free (pinentry.specific_err_info); + pinentry.specific_err_info = NULL; pinentry.close_button = 0; pinentry.repeat_okay = 0; pinentry.one_button = 0; @@ -1044,7 +1866,14 @@ cmd_getpin (assuan_context_t ctx, char *line) { pinentry_setbuffer_clear (&pinentry); if (pinentry.specific_err) - return pinentry.specific_err; + { + write_status_error (ctx, &pinentry); + + if (gpg_err_code (pinentry.specific_err) == GPG_ERR_FULLY_CANCELED) + assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1); + + return pinentry.specific_err; + } return (pinentry.locale_err ? gpg_error (GPG_ERR_LOCALE_PROBLEM) : gpg_error (GPG_ERR_CANCELED)); @@ -1092,6 +1921,9 @@ cmd_confirm (assuan_context_t ctx, char *line) pinentry.close_button = 0; pinentry.locale_err = 0; pinentry.specific_err = 0; + pinentry.specific_err_loc = NULL; + free (pinentry.specific_err_info); + pinentry.specific_err_info = NULL; pinentry.canceled = 0; pinentry_setbuffer_clear (&pinentry); result = (*pinentry_cmd_handler) (&pinentry); @@ -1104,17 +1936,24 @@ cmd_confirm (assuan_context_t ctx, char *line) if (pinentry.close_button) assuan_write_status (ctx, "BUTTON_INFO", "close"); - if (result) - return 0; + if (result > 0) + return 0; /* OK */ if (pinentry.specific_err) - return pinentry.specific_err; + { + write_status_error (ctx, &pinentry); + + if (gpg_err_code (pinentry.specific_err) == GPG_ERR_FULLY_CANCELED) + assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1); + + return pinentry.specific_err; + } if (pinentry.locale_err) return gpg_error (GPG_ERR_LOCALE_PROBLEM); if (pinentry.one_button) - return 0; + return 0; /* OK */ if (pinentry.canceled) return gpg_error (GPG_ERR_CANCELED); @@ -1130,6 +1969,33 @@ cmd_message (assuan_context_t ctx, char *line) return cmd_confirm (ctx, "--one-button"); } + +/* Return a staically allocated string with information on the mode, + * uid, and gid of DEVICE. On error "?" is returned if DEVICE is + * NULL, "-" is returned. */ +static const char * +device_stat_string (const char *device) +{ +#ifdef HAVE_STAT + static char buf[40]; + struct stat st; + + if (!device || !*device) + return "-"; + + if (stat (device, &st)) + return "?"; /* Error */ + snprintf (buf, sizeof buf, "%lo/%lu/%lu", + (unsigned long)st.st_mode, + (unsigned long)st.st_uid, + (unsigned long)st.st_gid); + return buf; +#else + return "-"; +#endif +} + + /* GETINFO <what> Multipurpose function to return a variety of information. @@ -1137,23 +2003,67 @@ cmd_message (assuan_context_t ctx, char *line) version - Return the version of the program. pid - Return the process id of the server. + flavor - Return information about the used pinentry flavor + ttyinfo - Return DISPLAY, ttyinfo and an emacs pinentry status */ static gpg_error_t cmd_getinfo (assuan_context_t ctx, char *line) { int rc; + const char *s; + char buffer[150]; if (!strcmp (line, "version")) { - const char *s = VERSION; + s = VERSION; rc = assuan_send_data (ctx, s, strlen (s)); } else if (!strcmp (line, "pid")) { - char numbuf[50]; - snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ()); - rc = assuan_send_data (ctx, numbuf, strlen (numbuf)); + snprintf (buffer, sizeof buffer, "%lu", (unsigned long)getpid ()); + buffer[sizeof buffer -1] = 0; + rc = assuan_send_data (ctx, buffer, strlen (buffer)); + } + else if (!strcmp (line, "flavor")) + { + if (!strncmp (this_pgmname, "pinentry-", 9) && this_pgmname[9]) + s = this_pgmname + 9; + else + s = this_pgmname; + + snprintf (buffer, sizeof buffer, "%s%s%s", + s, + flavor_flag? ":":"", + flavor_flag? flavor_flag : ""); + buffer[sizeof buffer -1] = 0; + rc = assuan_send_data (ctx, buffer, strlen (buffer)); + /* if (!rc) */ + /* rc = assuan_write_status (ctx, "FEATURES", "tabbing foo bar"); */ + } + else if (!strcmp (line, "ttyinfo")) + { + char emacs_status[10]; +#ifdef INSIDE_EMACS + snprintf (emacs_status, sizeof emacs_status, + "%d", pinentry_emacs_status ()); +#else + strcpy (emacs_status, "-"); +#endif + snprintf (buffer, sizeof buffer, "%s %s %s %s %lu/%lu %s", + pinentry.ttyname? pinentry.ttyname : "-", + pinentry.ttytype_l? pinentry.ttytype_l : "-", + pinentry.display? pinentry.display : "-", + device_stat_string (pinentry.ttyname), +#ifdef HAVE_DOSISH_SYSTEM + 0l, 0l, +#else + (unsigned long)geteuid (), (unsigned long)getegid (), +#endif + emacs_status + ); + buffer[sizeof buffer -1] = 0; + rc = assuan_send_data (ctx, buffer, strlen (buffer)); } else rc = gpg_error (GPG_ERR_ASS_PARAMETER); @@ -1211,6 +2121,8 @@ register_commands (assuan_context_t ctx) { "MESSAGE", cmd_message }, { "SETQUALITYBAR", cmd_setqualitybar }, { "SETQUALITYBAR_TT", cmd_setqualitybar_tt }, + { "SETGENPIN", cmd_setgenpin_label }, + { "SETGENPIN_TT", cmd_setgenpin_tt }, { "GETINFO", cmd_getinfo }, { "SETTITLE", cmd_settitle }, { "SETTIMEOUT", cmd_settimeout }, @@ -1238,8 +2150,10 @@ pinentry_loop2 (int infd, int outfd) assuan_context_t ctx; /* Extra check to make sure we have dropped privs. */ +#ifndef HAVE_DOSISH_SYSTEM if (getuid() != geteuid()) abort (); +#endif rc = assuan_new (&ctx); if (rc) @@ -1270,6 +2184,9 @@ pinentry_loop2 (int infd, int outfd) } assuan_register_option_handler (ctx, option_handler); +#if 0 + assuan_set_log_stream (ctx, stderr); +#endif assuan_register_reset_notify (ctx, pinentry_assuan_reset_handler); for (;;) diff --git a/pinentry/pinentry.h b/pinentry/pinentry.h index e154ac5..d55a234 100644 --- a/pinentry/pinentry.h +++ b/pinentry/pinentry.h @@ -1,20 +1,21 @@ /* pinentry.h - The interface for the PIN entry support library. - Copyright (C) 2002, 2003, 2010, 2015 g10 Code GmbH - - This file is part of PINENTRY. - - PINENTRY is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - PINENTRY is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see <http://www.gnu.org/licenses/>. + * Copyright (C) 2002, 2003, 2010, 2015, 2021 g10 Code GmbH + * + * This file is part of PINENTRY. + * + * PINENTRY is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * PINENTRY is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. + * SPDX-License-Identifier: GPL-2.0+ */ #ifndef PINENTRY_H @@ -74,7 +75,9 @@ struct pinentry supported. (Assuan: "OPTION ttyname TTYNAME".) */ char *ttyname; /* The type of the terminal. (Assuan: "OPTION ttytype TTYTYPE".) */ - char *ttytype; + char *ttytype_l; + /* Set the alert mode (none, beep or flash). */ + char *ttyalert; /* The LC_CTYPE value for the terminal. (Assuan: "OPTION lc-ctype LC_CTYPE".) */ char *lc_ctype; @@ -91,6 +94,18 @@ struct pinentry /* True if caller should grab the keyboard. (Assuan: "OPTION grab" or "OPTION no-grab".) */ int grab; + + /* The PID of the owner or 0 if not known. The owner is the process + * which actually triggered the the pinentry. For example gpg. */ + unsigned long owner_pid; + + /* The numeric uid (user ID) of the owner process or -1 if not + * known. */ + int owner_uid; + + /* The malloced hostname of the owner or NULL. */ + char *owner_host; + /* The window ID of the parent window over which the pinentry window should be displayed. (Assuan: "OPTION parent-wid WID".) */ int parent_wid; @@ -109,7 +124,7 @@ struct pinentry int canceled; /* The frontend should set this to true if an error with the local - conversion occured. */ + conversion occurred. */ int locale_err; /* The frontend should set this to a gpg-error so that commands are @@ -118,6 +133,13 @@ struct pinentry passphrase or a negative error code. */ int specific_err; + /* The frontend may store a string with the error location here. */ + const char *specific_err_loc; + + /* The frontend may store a malloced string here to emit an ERROR + * status code with this extra info along with SPECIFIC_ERR. */ + char *specific_err_info; + /* The frontend should set this to true if the window close button has been used. This flag is used in addition to a regular return value. */ @@ -148,10 +170,29 @@ struct pinentry "SETQUALITYBAR LABEL".) */ char *quality_bar; - /* The tooltip to be show for the qualitybar. Malloced or NULL. + /* The tooltip to be shown for the qualitybar. Malloced or NULL. (Assuan: "SETQUALITYBAR_TT TOOLTIP".) */ char *quality_bar_tt; + /* If this is not NULL, a generate action should be shown. + There will be an inquiry back to the caller to get such a + PIN. generate action. Malloced or NULL. + (Assuan: "SETGENPIN LABEL" .) */ + char *genpin_label; + + /* The tooltip to be shown for the generate action. Malloced or NULL. + (Assuan: "SETGENPIN_TT TOOLTIP".) */ + char *genpin_tt; + + /* Specifies whether passphrase formatting should be enabled. + (Assuan: "OPTION formatted-passphrase") */ + int formatted_passphrase; + + /* A hint to be shown near the passphrase input field if passphrase + formatting is enabled. Malloced or NULL. + (Assuan: "OPTION formatted-passphrase-hint=HINT".) */ + char *formatted_passphrase_hint; + /* For the curses pinentry, the color of error messages. */ pinentry_color_t color_fg; int color_fg_bright; @@ -171,6 +212,18 @@ struct pinentry /* (Assuan: "OPTION default-pwmngr SAVE_PASSWORD_WITH_PASSWORD_MANAGER?"). */ char *default_pwmngr; + /* (Assuan: "OPTION default-cf-visi + Do you really want to make your passphrase visible?"). */ + char *default_cf_visi; + /* (Assuan: "OPTION default-tt-visi + Make passphrase visible?"). */ + char *default_tt_visi; + /* (Assuan: "OPTION default-tt-hide + Hide passphrase"). */ + char *default_tt_hide; + /* (Assuan: "OPTION default-capshint + Caps Lock is on"). */ + char *default_capshint; /* Whether we are allowed to read the password from an external cache. (Assuan: "OPTION allow-external-password-cache") */ @@ -189,10 +242,35 @@ struct pinentry /* NOTE: If you add any additional fields to this structure, be sure to update the initializer in pinentry/pinentry.c!!! */ - /* For the quality indicator we need to do an inquiry. Thus we need - to save the assuan ctx. */ + /* For the quality indicator and genpin we need to do an inquiry. + Thus we need to save the assuan ctx. */ void *ctx_assuan; + /* An UTF-8 string with an invisible character used to override the + default in some pinentries. Only the first character is + used. */ + char *invisible_char; + + /* Whether the passphrase constraints are enforced by gpg-agent. + (Assuan: "OPTION constraints-enforce") */ + int constraints_enforce; + + /* A short translated hint for the user with the constraints for new + passphrases to be displayed near the passphrase input field. + Malloced or NULL. + (Assuan: "OPTION constraints-hint-short=At least 8 characters".) */ + char *constraints_hint_short; + + /* A longer translated hint for the user with the constraints for new + passphrases to be displayed for example as tooltip. Malloced or NULL. + (Assuan: "OPTION constraints-hint-long=The passphrase must ...".) */ + char *constraints_hint_long; + + /* A short translated title for an error dialog informing the user about + unsatisfied passphrase constraints. Malloced or NULL. + (Assuan: "OPTION constraints-error-title=Passphrase Not Allowed".) */ + char *constraints_error_title; + }; typedef struct pinentry *pinentry_t; @@ -201,7 +279,7 @@ typedef struct pinentry *pinentry_t; PIN. If PIN->pin is zero, request a confirmation, otherwise a PIN entry. On confirmation, the function should return TRUE if confirmed, and FALSE otherwise. On PIN entry, the function should - return -1 if an error occured or the user cancelled the operation + return -1 if an error occurred or the user cancelled the operation and 1 otherwise. */ typedef int (*pinentry_cmd_handler_t) (pinentry_t pin); @@ -227,11 +305,21 @@ char *pinentry_utf8_to_local (const char *lc_ctype, const char *text); Return NULL on error. */ char *pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure); +char *pinentry_get_title (pinentry_t pe); /* Run a quality inquiry for PASSPHRASE of LENGTH. */ int pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length); +/* Run a checkpin inquiry for PASSPHRASE of LENGTH. Returns NULL, if the + passphrase satisfies the constraints. Otherwise, returns a malloced error + string. */ +char *pinentry_inq_checkpin (pinentry_t pin, + const char *passphrase, size_t length); + +/* Run a genpin iquriry. Returns a malloced string or NULL */ +char *pinentry_inq_genpin (pinentry_t pin); + /* Try to make room for at least LEN bytes for the pin in the pinentry PIN. Returns new buffer on success and 0 on failure. */ char *pinentry_setbufferlen (pinentry_t pin, int len); @@ -254,6 +342,10 @@ int pinentry_have_display (int argc, char **argv); or version output is requested. */ void pinentry_parse_opts (int argc, char *argv[]); +/* Set the optional flag used with getinfo. */ +void pinentry_set_flavor_flag (const char *string); + + /* The caller must define this variable to process assuan commands. */ extern pinentry_cmd_handler_t pinentry_cmd_handler; |