From be87785005d256b7f3dacc607ba5ea0a14de8593 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Tue, 12 May 2015 17:07:49 +0200 Subject: [PATCH] Add a GNOME3 pinentry based on gcr. * configure.ac (--enable-pinentry-gnome3): Option to enable the GNOME3 pinentry. (pinentry_gnome_3): Set to yes if enabled and gcr-3 and gcr-base-3 gcr is available. (GNOME3CFLAGS): Define and AC_SUBST. (GNOME3LIBS): Define and AC_SUBST. (GCR_API_SUBJECT_TO_CHANGE): Define. (BUILD_PINENTRY_GNOME_3): Define. * Makefile.am (pinentry_gnome_3): Define. (SUBDIRS): Add ${pinentry_gnome_3}. * gnome3/Makefile.am: New file. * gnome3/pinentry-gnome3.c: New file. --- Makefile.am | 11 +- configure.ac | 62 +++++++++-- gnome3/Makefile.am | 39 +++++++ gnome3/pinentry-gnome3.c | 271 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 370 insertions(+), 13 deletions(-) create mode 100644 gnome3/Makefile.am create mode 100644 gnome3/pinentry-gnome3.c diff --git a/Makefile.am b/Makefile.am index f8f7aac..177f37e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ # Makefile.am -# Copyright (C) 2002, 2012 g10 Code GmbH +# Copyright (C) 2002, 2012, 2015 g10 Code GmbH # # This file is part of PINENTRY. # @@ -46,6 +46,12 @@ else pinentry_gtk_2 = endif +if BUILD_PINENTRY_GNOME_3 +pinentry_gnome_3 = gnome3 +else +pinentry_gnome_3 = +endif + if BUILD_PINENTRY_QT4 pinentry_qt4 = qt4 else @@ -59,7 +65,8 @@ pinentry_w32 = endif SUBDIRS = assuan secmem pinentry ${pinentry_curses} ${pinentry_tty} \ - ${pinentry_gtk_2} ${pinentry_qt4} ${pinentry_w32} doc + ${pinentry_gtk_2} ${pinentry_gnome_3} ${pinentry_qt4} \ + ${pinentry_w32} doc install-exec-local: diff --git a/configure.ac b/configure.ac index c50ce68..9948d1f 100644 --- a/configure.ac +++ b/configure.ac @@ -274,28 +274,34 @@ fi dnl -dnl Check for GTK+-2 pinentry program. +dnl Check for GTK+-2 / GNOME3 pinentry programs. dnl AC_ARG_ENABLE(pinentry-gtk2, AC_HELP_STRING([--enable-pinentry-gtk2], [build GTK+-2 pinentry]), pinentry_gtk_2=$enableval, pinentry_gtk_2=maybe) +AC_ARG_ENABLE(pinentry-gnome3, + AC_HELP_STRING([--enable-pinentry-gnome3], [build GNOME 3 pinentry]), + pinentry_gnome_3=$enableval, pinentry_gnome_3=maybe) + dnl check for pkg-config -if test "$pinentry_gtk_2" != "no"; then +if test "$pinentry_gtk_2" != "no" -o "$pinentry_gnome_3" != "no"; then AC_PATH_PROG(PKG_CONFIG, pkg-config, no) if test x"${PKG_CONFIG}" = xno ; then pinentry_gtk_2=no + pinentry_gnome_3=no fi fi dnl check if the module gtk+-2.0 exists -if test "$pinentry_gtk_2" != "no"; then +if test "$pinentry_gtk_2" != "no" -o "$pinentry_gnome_3" != "no"; then AC_MSG_CHECKING([for gtk+-2]) "${PKG_CONFIG}" --exists gtk+-2.0 if test $? -ne 0 ; then AC_MSG_RESULT([no]) AC_MSG_WARN([pkg-config could not find the module gtk+-2.0]) pinentry_gtk_2=no + pinentry_gnome_3=no else AC_MSG_RESULT([yes]) AC_MSG_CHECKING([gtk+-2 version >= 2.4.0]) @@ -305,17 +311,45 @@ if test "$pinentry_gtk_2" != "no"; then if test $? -ne 0 ; then AC_MSG_WARN([building GTK+-2 pinentry disabled]) pinentry_gtk_2=no + pinentry_gnome_3=no else GTK2CFLAGS=`"${PKG_CONFIG}" --cflags gtk+-2.0` GTK2LIBS=`"${PKG_CONFIG}" --libs gtk+-2.0` AC_SUBST(GTK2CFLAGS) AC_SUBST(GTK2LIBS) - pinentry_gtk_2=yes + if test "$pinentry_gtk_2" != "no" + then + pinentry_gtk_2=yes + fi + if test "$pinentry_gnome_3" != "no" + then + pinentry_gnome_3=yes + fi fi fi fi AM_CONDITIONAL(BUILD_PINENTRY_GTK_2, test "$pinentry_gtk_2" = "yes") +if test "$pinentry_gnome_3" != "no"; then + AC_MSG_CHECKING([for gcr]) + "${PKG_CONFIG}" --exists gcr-3,gcr-base-3 + if test $? -ne 0 ; then + AC_MSG_RESULT([no]) + AC_MSG_WARN([pkg-config could not find the module gcr-3,gcr-base-3]) + pinentry_gnome_3=no + else + AC_MSG_RESULT([yes]) + GNOME3CFLAGS=`"${PKG_CONFIG}" --cflags gcr-3,gcr-base-3` + GNOME3LIBS=`"${PKG_CONFIG}" --libs gcr-3,gcr-base-3` + AC_SUBST(GNOME3CFLAGS) + AC_SUBST(GNOME3LIBS) + AC_DEFINE(GCR_API_SUBJECT_TO_CHANGE, 1, [Nod nod]) + pinentry_gnome_3=yes + fi +fi + +AM_CONDITIONAL(BUILD_PINENTRY_GNOME_3, test "$pinentry_gnome_3" = "yes") + dnl dnl Check for libsecret. dnl @@ -450,16 +484,20 @@ else if test "$pinentry_qt4" = "yes"; then PINENTRY_DEFAULT=pinentry-qt4 else - if test "$pinentry_curses" = "yes"; then - PINENTRY_DEFAULT=pinentry-curses + if test "$pinentry_gnome_3" = "yes"; then + PINENTRY_DEFAULT=pinentry-gnome3 else - if test "$pinentry_tty" = "yes"; then - PINENTRY_DEFAULT=pinentry-tty + if test "$pinentry_curses" = "yes"; then + PINENTRY_DEFAULT=pinentry-curses else - if test "$pinentry_w32" = "yes"; then - PINENTRY_DEFAULT=pinentry-w32 + if test "$pinentry_tty" = "yes"; then + PINENTRY_DEFAULT=pinentry-tty else - AC_MSG_ERROR([[No pinentry enabled.]]) + if test "$pinentry_w32" = "yes"; then + PINENTRY_DEFAULT=pinentry-w32 + else + AC_MSG_ERROR([[No pinentry enabled.]]) + fi fi fi fi @@ -475,6 +513,7 @@ pinentry/Makefile curses/Makefile tty/Makefile gtk+-2/Makefile +gnome3/Makefile qt4/Makefile w32/Makefile doc/Makefile @@ -493,6 +532,7 @@ AC_MSG_NOTICE([ Curses Pinentry ..: $pinentry_curses TTY Pinentry .....: $pinentry_tty GTK+-2 Pinentry ..: $pinentry_gtk_2 + GNOME 3 Pinentry .: $pinentry_gnome_3 Qt4 Pinentry .....: $pinentry_qt4 $pinentry_qt4_clip_msg W32 Pinentry .....: $pinentry_w32 diff --git a/gnome3/Makefile.am b/gnome3/Makefile.am new file mode 100644 index 0000000..78df706 --- /dev/null +++ b/gnome3/Makefile.am @@ -0,0 +1,39 @@ +# Makefile.am - PIN entry GTK+ frontend. +# Copyright (C) 2002, 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +## Process this file with automake to produce Makefile.in + +bin_PROGRAMS = pinentry-gnome3 + +if FALLBACK_CURSES +ncurses_include = $(NCURSES_INCLUDE) +libcurses = ../pinentry/libpinentry-curses.a $(LIBCURSES) $(LIBICONV) +else +ncurses_include = +libcurses = +endif + +AM_CPPFLAGS = $(COMMON_CFLAGS) $(GNOME3CFLAGS) \ + $(ncurses_include) -I$(top_srcdir)/assuan \ + -I$(top_srcdir)/secmem -I$(top_srcdir)/pinentry +LDADD = $(COMMON_LIBS) \ + ../pinentry/libpinentry.a ../assuan/libassuan.a ../secmem/libsecmem.a \ + $(LIBCAP) $(GNOME3LIBS) $(libcurses) + +pinentry_gnome3_SOURCES = pinentry-gnome3.c diff --git a/gnome3/pinentry-gnome3.c b/gnome3/pinentry-gnome3.c new file mode 100644 index 0000000..74ec89c --- /dev/null +++ b/gnome3/pinentry-gnome3.c @@ -0,0 +1,271 @@ +/* pinentry-gnome3.c + Copyright (C) 2015 g10 Code GmbH + + pinentry-gnome-3 is a pinentry application for GNOME 3. It tries + to follow the Gnome Human Interface Guide as close as possible. + + This program 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. + + This program 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#include "assuan.h" + +#include "memory.h" + +#include "pinentry.h" + +#ifdef FALLBACK_CURSES +#include "pinentry-curses.h" +#endif + + +#define PGMNAME "pinentry-gnome3" + +#ifndef VERSION +# define VERSION +#endif + +static gchar * +pinentry_utf8_validate (gchar *text) +{ + gchar *result; + + if (!text) + return NULL; + + if (g_utf8_validate (text, -1, NULL)) + return g_strdup (text); + + /* Failure: Assume that it was encoded in the current locale and + convert it to utf-8. */ + result = g_locale_to_utf8 (text, -1, NULL, NULL, NULL); + if (!result) + { + gchar *p; + + result = p = g_strdup (text); + while (!g_utf8_validate (p, -1, (const gchar **) &p)) + *p = '?'; + } + return result; +} + +static GcrPrompt * +create_prompt (pinentry_t pe, int confirm) +{ + GcrPrompt *prompt; + GError *error = NULL; + char *msg; + + /* Create the prompt. */ + prompt = GCR_PROMPT (gcr_system_prompt_open (-1, NULL, &error)); + if (! prompt) + { + g_warning ("couldn't create prompt for gnupg passphrase: %s", + error->message); + g_error_free (error); + return NULL; + } + + /* Set the messages for the various buttons, etc. */ + if (pe->title) + { + msg = pinentry_utf8_validate (pe->title); + gcr_prompt_set_title (prompt, msg); + g_free (msg); + } + + if (pe->description) + { + msg = pinentry_utf8_validate (pe->description); + gcr_prompt_set_description (prompt, msg); + g_free (msg); + } + + /* An error occured during the last prompt. */ + if (pe->error) + { + msg = pinentry_utf8_validate (pe->error); + gcr_prompt_set_warning (prompt, msg); + g_free (msg); + } + + if (! pe->prompt && confirm) + gcr_prompt_set_message (prompt, "Message"); + else if (! pe->prompt && ! confirm) + gcr_prompt_set_message (prompt, "Enter Passphrase"); + else + { + msg = pinentry_utf8_validate (pe->prompt); + gcr_prompt_set_message (prompt, msg); + g_free (msg); + } + + if (! confirm) + gcr_prompt_set_password_new (prompt, !!pe->repeat_passphrase); + + if (pe->ok || pe->default_ok) + { + msg = pinentry_utf8_validate (pe->ok ?: pe->default_ok); + gcr_prompt_set_continue_label (prompt, msg); + g_free (msg); + } + /* XXX: Disable this button if pe->one_button is set. */ + if (pe->cancel || pe->default_cancel) + { + msg = pinentry_utf8_validate (pe->cancel ?: pe->default_cancel); + gcr_prompt_set_cancel_label (prompt, msg); + g_free (msg); + } + + if (confirm && pe->notok) + { + /* XXX: Add support for the third option. */ + } + + /* XXX: gcr expects a string; we have a int. */ + // gcr_prompt_set_caller_window (prompt, pe->parent_wid); + + if (! confirm && pe->allow_external_password_cache && pe->keyinfo) + { + if (pe->default_pwmngr) + { + msg = pinentry_utf8_validate (pe->default_pwmngr); + gcr_prompt_set_choice_label (prompt, msg); + g_free (msg); + } + else + gcr_prompt_set_choice_label + (prompt, "Automatically unlock this key, whenever I'm logged in"); + } + + return prompt; +} + +static int +gnome3_cmd_handler (pinentry_t pe) +{ + GcrPrompt *prompt = NULL; + GError *error = NULL; + int ret = -1; + + if (pe->pin) + /* Passphrase mode. */ + { + const char *password; + + prompt = create_prompt (pe, 0); + if (! prompt) + /* Something went wrong. */ + { + pe->canceled = 1; + return -1; + } + + /* "The returned password is valid until the next time a method + is called to display another prompt." */ + password = gcr_prompt_password_run (prompt, NULL, &error); + if (error) + /* Error. */ + { + pe->specific_err = ASSUAN_General_Error; + g_error_free (error); + ret = -1; + } + else if (! password && ! error) + /* User cancelled the operation. */ + ret = -1; + else + { + pinentry_setbufferlen (pe, strlen (password) + 1); + if (pe->pin) + strcpy (pe->pin, password); + + if (pe->repeat_passphrase) + pe->repeat_okay = 1; + + ret = 1; + } + } + else + /* Message box mode. */ + { + GcrPromptReply reply; + + prompt = create_prompt (pe, 1); + if (! prompt) + /* Something went wrong. */ + { + pe->canceled = 1; + return -1; + } + + /* XXX: We don't support a third button! */ + + reply = gcr_prompt_confirm_run (prompt, NULL, &error); + if (error) + { + pe->specific_err = ASSUAN_General_Error; + ret = 0; + } + else if (reply == GCR_PROMPT_REPLY_CONTINUE + /* XXX: Hack since gcr doesn't yet support one button + message boxes treat cancel the same as okay. */ + || pe->one_button) + /* Confirmation. */ + ret = 1; + else + /* GCR_PROMPT_REPLY_CANCEL */ + { + pe->canceled = 1; + ret = 0; + } + } + + if (prompt) + g_clear_object (&prompt); + return ret; +} + +pinentry_cmd_handler_t pinentry_cmd_handler = gnome3_cmd_handler; + +int +main (int argc, char *argv[]) +{ + pinentry_init (PGMNAME); + +#ifdef FALLBACK_CURSES + if (pinentry_have_display (argc, argv)) + gtk_init (&argc, &argv); + else + pinentry_cmd_handler = curses_cmd_handler; +#else + gtk_init (&argc, &argv); +#endif + + pinentry_parse_opts (argc, argv); + + if (pinentry_loop ()) + return 1; + + return 0; +} -- 2.1.4