[PATCH] Add inside-Emacs mode to GUI pinentry programs

Neal H. Walfield neal at walfield.org
Sun Jun 14 12:19:08 CEST 2015


At Sun, 14 Jun 2015 10:24:04 +0900,
Daiki Ueno wrote:
> - the UID value check is now replaced with simple cast to uint32_t,
>   using configure time check

Is this really safe?  Before you caught the error, now we silently
take the value mod 2^32.

> > Thus, if allow-emacs-pinentry is not set (1) and we don't forward the
> > INSIDE_EMACS environment variable (2), then pinentry won't try the
> > emacs pinentry (3).
> >
> > Therefore, teaching pinentry about this option is not required.
> >
> > Does that make sense or do you have another use case in mind that I'm
> > missing?
> 
> As Werner already pointed, (2) is not always the case with the current
> code.
> 
> However, perhaps the above scenario might be actually possible by
> explicitly unsetenv'ing INSIDE_EMACS in gpg-agent, when
> allow-emacs-pinentry is not set in gpg-agent.conf (like we do for
> DISPLAY, when keep-display is not set).

I seem to remember Werner suggesting that this would require a large
change, but if it is easy, I would welcome this approach.

> diff --git a/emacs/pinentry-emacs.c b/emacs/pinentry-emacs.c
> new file mode 100644
> index 0000000..de4ca05
> --- /dev/null
> +++ b/emacs/pinentry-emacs.c
...
> pinentry_cmd_handler_t fallback_cmd_handler;

Is there any reason this isn't marked static?

> +static int
> +initial_emacs_cmd_handler (pinentry_t pe)
> +{
> +  if (pe->allow_emacs_prompt && emacs_socket < 0)
> +    pinentry_emacs_init ();
> +
> +  /* If we have successfully connected to Emacs, substitute
> +     pinentry_cmd_handler to emacs_cmd_handler.  Otherwise, set it
> +     back to fallback_cmd_handler.  */
> +  if (emacs_socket < 0)
> +    pinentry_cmd_handler = fallback_cmd_handler;
> +  else
> +    pinentry_cmd_handler = emacs_cmd_handler;
> +
> +  return (* pinentry_cmd_handler) (pe);
> +}
...
> +int
> +pinentry_emacs_init (void)
> +{
> +  char buffer[256];
> +  assuan_error_t error;
> +
> +  assert (emacs_socket < 0);
> +
> +  /* Check if we can connect to the Emacs server socket.  */
> +  if (!set_socket ("pinentry"))
> +    return 0;
> +
> +  /* Check if the server responds.  */
> +  read_from_emacs (emacs_socket, INITIAL_TIMEOUT, buffer, sizeof (buffer),
> +		   &error);
> +  return error == ASSUAN_No_Error;
> +}

If set_socket is successful, but read_from_emacs fails, then
emacs_socket will be valid (>= 0) and the test in
initial_emacs_cmd_handler will fail.  I think
initial_emacs_cmd_handler either needs to test the return result of
pinentry_emacs_init or pinentry_emacs_init needs to deinit the socket
if emacs doesn't have pinentry support.

> diff --git a/pinentry/pinentry.c b/pinentry/pinentry.c
> index 6f7a62c..9619696 100644
> --- a/pinentry/pinentry.c
> +++ b/pinentry/pinentry.c
> @@ -855,6 +861,13 @@ option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
>        pinentry.allow_external_password_cache = 1;
>        pinentry.tried_password_cache = 0;
>      }
> +  else if (!strcmp (key, "allow-emacs-prompt") && !*value)
> +    {
> +      pinentry.allow_emacs_prompt = 1;
> +#ifdef INSIDE_EMACS
> +      pinentry_enable_emacs_cmd_handler ();
> +#endif
> +    }
>    else
>      return ASSUAN_Invalid_Option;
>    return 0;

pinentry_enable_emacs_cmd_handler can be called multiple times, but
this function isn't designed for this.

  void
  pinentry_enable_emacs_cmd_handler (void)
  {
    const char *envvar;
  
    /* Check if INSIDE_EMACS envvar is set.  */
    envvar = getenv ("INSIDE_EMACS");
    if (!envvar || !*envvar)
      return;
  
    /* Substitute pinentry_cmd_handler to initial_emacs_cmd_handler.  */
    fallback_cmd_handler = pinentry_cmd_handler;
    pinentry_cmd_handler = initial_emacs_cmd_handler;
  }

On the second call, fallback_cmd_handler is set to
initial_emacs_cmd_handler, which is not what we want.  Consider:

  $ INSIDE_EMACS=1 curses/pinentry-curses 
  OK Your orders please
  option allow-emacs-prompt
  OK
  getpin
  stat: No such file or directory
  D 123
  OK
  $ INSIDE_EMACS=1 curses/pinentry-curses 
  OK Your orders please
  option allow-emacs-prompt
  OK
  option allow-emacs-prompt
  OK
  getpin
  stat: No such file or directory
  stat: No such file or directory
  stat: No such file or directory
  ...

Also, since pinentry_enable_emacs_cmd_handler is only called from the
option handler, I don't think we need the field allow_emacs_prompt in
the pinentry structure.

Thanks!

:) Neal



More information about the Gnupg-devel mailing list