LCOV - code coverage report
Current view: top level - common - get-passphrase.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 75 0.0 %
Date: 2016-11-29 15:00:56 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /* get-passphrase.c - Ask for a passphrase via the agent
       2             :  * Copyright (C) 2009 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * This file is free software; you can redistribute it and/or modify
       7             :  * it under the terms of either
       8             :  *
       9             :  *   - the GNU Lesser General Public License as published by the Free
      10             :  *     Software Foundation; either version 3 of the License, or (at
      11             :  *     your option) any later version.
      12             :  *
      13             :  * or
      14             :  *
      15             :  *   - the GNU General Public License as published by the Free
      16             :  *     Software Foundation; either version 2 of the License, or (at
      17             :  *     your option) any later version.
      18             :  *
      19             :  * or both in parallel, as here.
      20             :  *
      21             :  * This file is distributed in the hope that it will be useful,
      22             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24             :  * GNU General Public License for more details.
      25             :  *
      26             :  * You should have received a copy of the GNU General Public License
      27             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      28             :  */
      29             : 
      30             : #include <config.h>
      31             : #include <stdio.h>
      32             : #include <stdlib.h>
      33             : #include <string.h>
      34             : #include <assert.h>
      35             : #include <assuan.h>
      36             : 
      37             : #include "util.h"
      38             : #include "i18n.h"
      39             : #include "asshelp.h"
      40             : #include "membuf.h"
      41             : #include "sysutils.h"
      42             : #include "get-passphrase.h"
      43             : 
      44             : /* The context used by this process to ask for the passphrase.  */
      45             : static assuan_context_t agent_ctx;
      46             : static struct
      47             : {
      48             :   gpg_err_source_t errsource;
      49             :   int verbosity;
      50             :   const char *agent_program;
      51             :   const char *lc_ctype;
      52             :   const char *lc_messages;
      53             :   session_env_t session_env;
      54             :   const char *pinentry_user_data;
      55             : } agentargs;
      56             : 
      57             : 
      58             : /* Set local variable to be used for a possible agent startup.  Note
      59             :    that the strings are just pointers and should not anymore be
      60             :    modified by the caller. */
      61             : void
      62           0 : gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
      63             :                               int verbosity,
      64             :                               const char *agent_program,
      65             :                               const char *opt_lc_ctype,
      66             :                               const char *opt_lc_messages,
      67             :                               session_env_t session_env)
      68             : {
      69           0 :   agentargs.errsource          = errsource;
      70           0 :   agentargs.verbosity          = verbosity;
      71           0 :   agentargs.agent_program      = agent_program;
      72           0 :   agentargs.lc_ctype           = opt_lc_ctype;
      73           0 :   agentargs.lc_messages        = opt_lc_messages;
      74           0 :   agentargs.session_env        = session_env;
      75           0 : }
      76             : 
      77             : 
      78             : /* Try to connect to the agent via socket or fork it off and work by
      79             :    pipes.  Handle the server's initial greeting.  */
      80             : static gpg_error_t
      81           0 : start_agent (void)
      82             : {
      83             :   gpg_error_t err;
      84             : 
      85             :   /* Fixme: This code is not thread safe, thus we don't build it with
      86             :      pth.  We will need a context for each thread or serialize the
      87             :      access to the agent.  */
      88           0 :   if (agent_ctx)
      89           0 :     return 0;
      90             : 
      91           0 :   err = start_new_gpg_agent (&agent_ctx,
      92             :                              agentargs.errsource,
      93             :                              agentargs.agent_program,
      94             :                              agentargs.lc_ctype,
      95             :                              agentargs.lc_messages,
      96             :                              agentargs.session_env,
      97             :                              1, agentargs.verbosity, 0, NULL, NULL);
      98           0 :   if (!err)
      99             :     {
     100             :       /* Tell the agent that we support Pinentry notifications.  No
     101             :          error checking so that it will work with older agents.  */
     102           0 :       assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
     103             :                        NULL, NULL, NULL, NULL, NULL, NULL);
     104             :     }
     105             : 
     106           0 :   return err;
     107             : }
     108             : 
     109             : 
     110             : /* This is the default inquiry callback.  It merely handles the
     111             :    Pinentry notification.  */
     112             : static gpg_error_t
     113           0 : default_inq_cb (void *opaque, const char *line)
     114             : {
     115             :   (void)opaque;
     116             : 
     117           0 :   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
     118             :     {
     119           0 :       gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
     120             :       /* We do not return errors to avoid breaking other code.  */
     121             :     }
     122             :   else
     123           0 :     log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
     124             : 
     125           0 :   return 0;
     126             : }
     127             : 
     128             : 
     129             : /* Ask for a passphrase via gpg-agent.  On success the caller needs to
     130             :    free the string stored at R_PASSPHRASE.  On error NULL will be
     131             :    stored at R_PASSPHRASE and an appropriate gpg error code is
     132             :    returned.  With REPEAT set to 1, gpg-agent will ask the user to
     133             :    repeat the just entered passphrase.  CACHE_ID is a gpg-agent style
     134             :    passphrase cache id or NULL.  ERR_MSG is a error message to be
     135             :    presented to the user (e.g. "bad passphrase - try again") or NULL.
     136             :    PROMPT is the prompt string to label the entry box, it may be NULL
     137             :    for a default one.  DESC_MSG is a longer description to be
     138             :    displayed above the entry box, if may be NULL for a default one.
     139             :    If USE_SECMEM is true, the returned passphrase is returned in
     140             :    secure memory.  The length of all these strings is limited; they
     141             :    need to fit in their encoded form into a standard Assuan line (i.e
     142             :    less then about 950 characters).  All strings shall be UTF-8.  */
     143             : gpg_error_t
     144           0 : gnupg_get_passphrase (const char *cache_id,
     145             :                       const char *err_msg,
     146             :                       const char *prompt,
     147             :                       const char *desc_msg,
     148             :                       int repeat,
     149             :                       int check_quality,
     150             :                       int use_secmem,
     151             :                       char **r_passphrase)
     152             : {
     153             :   gpg_error_t err;
     154             :   char line[ASSUAN_LINELENGTH];
     155           0 :   const char *arg1 = NULL;
     156           0 :   char *arg2 = NULL;
     157           0 :   char *arg3 = NULL;
     158           0 :   char *arg4 = NULL;
     159             :   membuf_t data;
     160             : 
     161           0 :   *r_passphrase = NULL;
     162             : 
     163           0 :   err = start_agent ();
     164           0 :   if (err)
     165           0 :     return err;
     166             : 
     167             :   /* Check that the gpg-agent understands the repeat option.  */
     168           0 :   if (assuan_transact (agent_ctx,
     169             :                        "GETINFO cmd_has_option GET_PASSPHRASE repeat",
     170             :                        NULL, NULL, NULL, NULL, NULL, NULL))
     171           0 :     return gpg_error (GPG_ERR_NOT_SUPPORTED);
     172             : 
     173           0 :   arg1 = cache_id && *cache_id? cache_id:NULL;
     174           0 :   if (err_msg && *err_msg)
     175           0 :     if (!(arg2 = percent_plus_escape (err_msg)))
     176           0 :       goto no_mem;
     177           0 :   if (prompt && *prompt)
     178           0 :     if (!(arg3 = percent_plus_escape (prompt)))
     179           0 :       goto no_mem;
     180           0 :   if (desc_msg && *desc_msg)
     181           0 :     if (!(arg4 = percent_plus_escape (desc_msg)))
     182           0 :       goto no_mem;
     183             : 
     184           0 :   snprintf (line, DIM(line),
     185             :             "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s",
     186             :             check_quality? "--check ":"",
     187             :             repeat,
     188             :             arg1? arg1:"X",
     189             :             arg2? arg2:"X",
     190             :             arg3? arg3:"X",
     191             :             arg4? arg4:"X");
     192           0 :   xfree (arg2);
     193           0 :   xfree (arg3);
     194           0 :   xfree (arg4);
     195             : 
     196           0 :   if (use_secmem)
     197           0 :     init_membuf_secure (&data, 64);
     198             :   else
     199           0 :     init_membuf (&data, 64);
     200           0 :   err = assuan_transact (agent_ctx, line,
     201             :                          put_membuf_cb, &data,
     202             :                          default_inq_cb, NULL, NULL, NULL);
     203             : 
     204             :   /* Older Pinentries return the old assuan error code for canceled
     205             :      which gets translated by libassuan to GPG_ERR_ASS_CANCELED and
     206             :      not to the code for a user cancel.  Fix this here. */
     207           0 :   if (err && gpg_err_source (err)
     208           0 :       && gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
     209           0 :     err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
     210             : 
     211           0 :   if (err)
     212             :     {
     213             :       void *p;
     214             :       size_t n;
     215             : 
     216           0 :       p = get_membuf (&data, &n);
     217           0 :       if (p)
     218           0 :         wipememory (p, n);
     219           0 :       xfree (p);
     220             :     }
     221             :   else
     222             :     {
     223           0 :       put_membuf (&data, "", 1);
     224           0 :       *r_passphrase = get_membuf (&data, NULL);
     225           0 :       if (!*r_passphrase)
     226           0 :         err = gpg_error_from_syserror ();
     227             :     }
     228           0 :   return err;
     229             :  no_mem:
     230           0 :   err = gpg_error_from_syserror ();
     231           0 :   xfree (arg2);
     232           0 :   xfree (arg3);
     233           0 :   xfree (arg4);
     234           0 :   return err;
     235             : }
     236             : 
     237             : 
     238             : /* Flush the passphrase cache with Id CACHE_ID.  */
     239             : gpg_error_t
     240           0 : gnupg_clear_passphrase (const char *cache_id)
     241             : {
     242             :   gpg_error_t err;
     243             :   char line[ASSUAN_LINELENGTH];
     244             : 
     245           0 :   if (!cache_id || !*cache_id)
     246           0 :     return 0;
     247             : 
     248           0 :   err = start_agent ();
     249           0 :   if (err)
     250           0 :     return err;
     251             : 
     252           0 :   snprintf (line, DIM(line), "CLEAR_PASSPHRASE %s", cache_id);
     253           0 :   return assuan_transact (agent_ctx, line, NULL, NULL,
     254             :                           default_inq_cb, NULL, NULL, NULL);
     255             : }

Generated by: LCOV version 1.11