LCOV - code coverage report
Current view: top level - common - get-passphrase.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 83 0.0 %
Date: 2015-11-05 17:10:59 Functions: 0 6 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 <http://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 *homedir;
      51             :   const char *agent_program;
      52             :   const char *lc_ctype;
      53             :   const char *lc_messages;
      54             :   session_env_t session_env;
      55             :   const char *pinentry_user_data;
      56             : } agentargs;
      57             : 
      58             : 
      59             : /* Set local variable to be used for a possible agent startup.  Note
      60             :    that the strings are just pointers and should not anymore be
      61             :    modified by the caller. */
      62             : void
      63           0 : gnupg_prepare_get_passphrase (gpg_err_source_t errsource,
      64             :                               int verbosity,
      65             :                               const char *homedir,
      66             :                               const char *agent_program,
      67             :                               const char *opt_lc_ctype,
      68             :                               const char *opt_lc_messages,
      69             :                               session_env_t session_env)
      70             : {
      71           0 :   agentargs.errsource          = errsource;
      72           0 :   agentargs.verbosity          = verbosity;
      73           0 :   agentargs.homedir            = homedir;
      74           0 :   agentargs.agent_program      = agent_program;
      75           0 :   agentargs.lc_ctype           = opt_lc_ctype;
      76           0 :   agentargs.lc_messages        = opt_lc_messages;
      77           0 :   agentargs.session_env        = session_env;
      78           0 : }
      79             : 
      80             : 
      81             : /* Try to connect to the agent via socket or fork it off and work by
      82             :    pipes.  Handle the server's initial greeting.  */
      83             : static gpg_error_t
      84           0 : start_agent (void)
      85             : {
      86             :   gpg_error_t err;
      87             : 
      88             :   /* Fixme: This code is not thread safe, thus we don't build it with
      89             :      pth.  We will need a context for each thread or serialize the
      90             :      access to the agent.  */
      91           0 :   if (agent_ctx)
      92           0 :     return 0;
      93             : 
      94           0 :   err = start_new_gpg_agent (&agent_ctx,
      95             :                              agentargs.errsource,
      96             :                              agentargs.homedir,
      97             :                              agentargs.agent_program,
      98             :                              agentargs.lc_ctype,
      99             :                              agentargs.lc_messages,
     100             :                              agentargs.session_env,
     101             :                              1, agentargs.verbosity, 0, NULL, NULL);
     102           0 :   if (!err)
     103             :     {
     104             :       /* Tell the agent that we support Pinentry notifications.  No
     105             :          error checking so that it will work with older agents.  */
     106           0 :       assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
     107             :                        NULL, NULL, NULL, NULL, NULL, NULL);
     108             :     }
     109             : 
     110           0 :   return err;
     111             : }
     112             : 
     113             : 
     114             : /* This is the default inquiry callback.  It merely handles the
     115             :    Pinentry notification.  */
     116             : static gpg_error_t
     117           0 : default_inq_cb (void *opaque, const char *line)
     118             : {
     119             :   (void)opaque;
     120             : 
     121           0 :   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
     122             :     {
     123           0 :       gnupg_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
     124             :       /* We do not return errors to avoid breaking other code.  */
     125             :     }
     126             :   else
     127           0 :     log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
     128             : 
     129           0 :   return 0;
     130             : }
     131             : 
     132             : 
     133             : static gpg_error_t
     134           0 : membuf_data_cb (void *opaque, const void *buffer, size_t length)
     135             : {
     136           0 :   membuf_t *data = opaque;
     137             : 
     138           0 :   if (buffer)
     139           0 :     put_membuf (data, buffer, length);
     140           0 :   return 0;
     141             : }
     142             : 
     143             : 
     144             : /* Ask for a passphrase via gpg-agent.  On success the caller needs to
     145             :    free the string stored at R_PASSPHRASE.  On error NULL will be
     146             :    stored at R_PASSPHRASE and an appropriate gpg error code is
     147             :    returned.  With REPEAT set to 1, gpg-agent will ask the user to
     148             :    repeat the just entered passphrase.  CACHE_ID is a gpg-agent style
     149             :    passphrase cache id or NULL.  ERR_MSG is a error message to be
     150             :    presented to the user (e.g. "bad passphrase - try again") or NULL.
     151             :    PROMPT is the prompt string to label the entry box, it may be NULL
     152             :    for a default one.  DESC_MSG is a longer description to be
     153             :    displayed above the entry box, if may be NULL for a default one.
     154             :    If USE_SECMEM is true, the returned passphrase is retruned in
     155             :    secure memory.  The length of all these strings is limited; they
     156             :    need to fit in their encoded form into a standard Assuan line (i.e
     157             :    less then about 950 characters).  All strings shall be UTF-8.  */
     158             : gpg_error_t
     159           0 : gnupg_get_passphrase (const char *cache_id,
     160             :                       const char *err_msg,
     161             :                       const char *prompt,
     162             :                       const char *desc_msg,
     163             :                       int repeat,
     164             :                       int check_quality,
     165             :                       int use_secmem,
     166             :                       char **r_passphrase)
     167             : {
     168             :   gpg_error_t err;
     169             :   char line[ASSUAN_LINELENGTH];
     170           0 :   const char *arg1 = NULL;
     171           0 :   char *arg2 = NULL;
     172           0 :   char *arg3 = NULL;
     173           0 :   char *arg4 = NULL;
     174             :   membuf_t data;
     175             : 
     176           0 :   *r_passphrase = NULL;
     177             : 
     178           0 :   err = start_agent ();
     179           0 :   if (err)
     180           0 :     return err;
     181             : 
     182             :   /* Check that the gpg-agent understands the repeat option.  */
     183           0 :   if (assuan_transact (agent_ctx,
     184             :                        "GETINFO cmd_has_option GET_PASSPHRASE repeat",
     185             :                        NULL, NULL, NULL, NULL, NULL, NULL))
     186           0 :     return gpg_error (GPG_ERR_NOT_SUPPORTED);
     187             : 
     188           0 :   arg1 = cache_id && *cache_id? cache_id:NULL;
     189           0 :   if (err_msg && *err_msg)
     190           0 :     if (!(arg2 = percent_plus_escape (err_msg)))
     191           0 :       goto no_mem;
     192           0 :   if (prompt && *prompt)
     193           0 :     if (!(arg3 = percent_plus_escape (prompt)))
     194           0 :       goto no_mem;
     195           0 :   if (desc_msg && *desc_msg)
     196           0 :     if (!(arg4 = percent_plus_escape (desc_msg)))
     197           0 :       goto no_mem;
     198             : 
     199           0 :   snprintf (line, DIM(line)-1,
     200             :             "GET_PASSPHRASE --data %s--repeat=%d -- %s %s %s %s",
     201             :             check_quality? "--check ":"",
     202             :             repeat,
     203             :             arg1? arg1:"X",
     204             :             arg2? arg2:"X",
     205             :             arg3? arg3:"X",
     206             :             arg4? arg4:"X");
     207           0 :   line[DIM(line)-1] = 0;
     208           0 :   xfree (arg2);
     209           0 :   xfree (arg3);
     210           0 :   xfree (arg4);
     211             : 
     212           0 :   if (use_secmem)
     213           0 :     init_membuf_secure (&data, 64);
     214             :   else
     215           0 :     init_membuf (&data, 64);
     216           0 :   err = assuan_transact (agent_ctx, line,
     217             :                          membuf_data_cb, &data,
     218             :                          default_inq_cb, NULL, NULL, NULL);
     219             : 
     220             :   /* Older Pinentries return the old assuan error code for canceled
     221             :      which gets translated bt libassuan to GPG_ERR_ASS_CANCELED and
     222             :      not to the code for a user cancel.  Fix this here. */
     223           0 :   if (err && gpg_err_source (err)
     224           0 :       && gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
     225           0 :     err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
     226             : 
     227           0 :   if (err)
     228             :     {
     229             :       void *p;
     230             :       size_t n;
     231             : 
     232           0 :       p = get_membuf (&data, &n);
     233           0 :       if (p)
     234           0 :         wipememory (p, n);
     235           0 :       xfree (p);
     236             :     }
     237             :   else
     238             :     {
     239           0 :       put_membuf (&data, "", 1);
     240           0 :       *r_passphrase = get_membuf (&data, NULL);
     241           0 :       if (!*r_passphrase)
     242           0 :         err = gpg_error_from_syserror ();
     243             :     }
     244           0 :   return err;
     245             :  no_mem:
     246           0 :   err = gpg_error_from_syserror ();
     247           0 :   xfree (arg2);
     248           0 :   xfree (arg3);
     249           0 :   xfree (arg4);
     250           0 :   return err;
     251             : }
     252             : 
     253             : 
     254             : /* Flush the passphrase cache with Id CACHE_ID.  */
     255             : gpg_error_t
     256           0 : gnupg_clear_passphrase (const char *cache_id)
     257             : {
     258             :   gpg_error_t err;
     259             :   char line[ASSUAN_LINELENGTH];
     260             : 
     261           0 :   if (!cache_id || !*cache_id)
     262           0 :     return 0;
     263             : 
     264           0 :   err = start_agent ();
     265           0 :   if (err)
     266           0 :     return err;
     267             : 
     268           0 :   snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
     269           0 :   line[DIM(line)-1] = 0;
     270           0 :   return assuan_transact (agent_ctx, line, NULL, NULL,
     271             :                           default_inq_cb, NULL, NULL, NULL);
     272             : }

Generated by: LCOV version 1.11