LCOV - code coverage report
Current view: top level - agent - command.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 390 1434 27.2 %
Date: 2015-11-05 17:10:59 Functions: 27 57 47.4 %

          Line data    Source code
       1             : /* command.c - gpg-agent command handler
       2             :  * Copyright (C) 2001-2011 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2001-2013 Werner Koch
       4             :  * Copyright (C) 2015 g10 Code GmbH.
       5             :  *
       6             :  * This file is part of GnuPG.
       7             :  *
       8             :  * GnuPG is free software; you can redistribute it and/or modify
       9             :  * it under the terms of the GNU General Public License as published by
      10             :  * the Free Software Foundation; either version 3 of the License, or
      11             :  * (at your option) any later version.
      12             :  *
      13             :  * GnuPG is distributed in the hope that it will be useful,
      14             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :  * GNU General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU General Public License
      19             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : /* FIXME: we should not use the default assuan buffering but setup
      23             :    some buffering in secure mempory to protect session keys etc. */
      24             : 
      25             : #include <config.h>
      26             : 
      27             : #include <errno.h>
      28             : #include <stdio.h>
      29             : #include <stdlib.h>
      30             : #include <string.h>
      31             : #include <ctype.h>
      32             : #include <unistd.h>
      33             : #include <assert.h>
      34             : #include <sys/types.h>
      35             : #include <sys/stat.h>
      36             : #include <dirent.h>
      37             : 
      38             : #include "agent.h"
      39             : #include <assuan.h>
      40             : #include "i18n.h"
      41             : #include "cvt-openpgp.h"
      42             : #include "../common/ssh-utils.h"
      43             : #include "../common/asshelp.h"
      44             : 
      45             : 
      46             : /* Maximum allowed size of the inquired ciphertext.  */
      47             : #define MAXLEN_CIPHERTEXT 4096
      48             : /* Maximum allowed size of the key parameters.  */
      49             : #define MAXLEN_KEYPARAM 1024
      50             : /* Maximum allowed size of key data as used in inquiries (bytes). */
      51             : #define MAXLEN_KEYDATA 4096
      52             : /* The size of the import/export KEK key (in bytes).  */
      53             : #define KEYWRAP_KEYSIZE (128/8)
      54             : 
      55             : /* A shortcut to call assuan_set_error using an gpg_err_code_t and a
      56             :    text string.  */
      57             : #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
      58             : 
      59             : /* Check that the maximum digest length we support has at least the
      60             :    length of the keygrip.  */
      61             : #if MAX_DIGEST_LEN < 20
      62             : #error MAX_DIGEST_LEN shorter than keygrip
      63             : #endif
      64             : 
      65             : /* Data used to associate an Assuan context with local server data.
      66             :    This is this modules local part of the server_control_s struct.  */
      67             : struct server_local_s
      68             : {
      69             :   /* Our Assuan context.  */
      70             :   assuan_context_t assuan_ctx;
      71             : 
      72             :   /* If this flag is true, the passphrase cache is used for signing
      73             :      operations.  It defaults to true but may be set on a per
      74             :      connection base.  The global option opt.ignore_cache_for_signing
      75             :      takes precedence over this flag.  */
      76             :   int use_cache_for_signing;
      77             : 
      78             :   /* An allocated description for the next key operation.  This is
      79             :      used if a pinnetry needs to be popped up.  */
      80             :   char *keydesc;
      81             : 
      82             :   /* Flags to suppress I/O logging during a command.  */
      83             :   int pause_io_logging;
      84             : 
      85             :   /* If this flags is set to true the agent will be terminated after
      86             :      the end of the current session.  */
      87             :   int stopme;
      88             : 
      89             :   /* Flag indicating whether pinentry notifications shall be done. */
      90             :   int allow_pinentry_notify;
      91             : 
      92             :   /* Malloced KEK (Key-Encryption-Key) for the import_key command.  */
      93             :   void *import_key;
      94             : 
      95             :   /* Malloced KEK for the export_key command.  */
      96             :   void *export_key;
      97             : 
      98             :   /* Client is aware of the error code GPG_ERR_FULLY_CANCELED.  */
      99             :   int allow_fully_canceled;
     100             : 
     101             :   /* Last CACHE_NONCE sent as status (malloced).  */
     102             :   char *last_cache_nonce;
     103             : 
     104             :   /* Last PASSWD_NONCE sent as status (malloced). */
     105             :   char *last_passwd_nonce;
     106             : };
     107             : 
     108             : 
     109             : /* An entry for the getval/putval commands. */
     110             : struct putval_item_s
     111             : {
     112             :   struct putval_item_s *next;
     113             :   size_t off;  /* Offset to the value into DATA.  */
     114             :   size_t len;  /* Length of the value.  */
     115             :   char d[1];   /* Key | Nul | value.  */
     116             : };
     117             : 
     118             : 
     119             : /* A list of key value pairs fpr the getval/putval commands.  */
     120             : static struct putval_item_s *putval_list;
     121             : 
     122             : 
     123             : 
     124             : /* To help polling clients, we keep track of the number of certain
     125             :    events.  This structure keeps those counters.  The counters are
     126             :    integers and there should be no problem if they are overflowing as
     127             :    callers need to check only whether a counter changed.  The actual
     128             :    values are not meaningful. */
     129             : struct
     130             : {
     131             :   /* Incremented if any of the other counters below changed. */
     132             :   unsigned int any;
     133             : 
     134             :   /* Incremented if a key is added or removed from the internal privat
     135             :      key database. */
     136             :   unsigned int key;
     137             : 
     138             :   /* Incremented if a change of the card readers stati has been
     139             :      detected. */
     140             :   unsigned int card;
     141             : 
     142             : } eventcounter;
     143             : 
     144             : 
     145             : 
     146             : /*  Local prototypes.  */
     147             : static int command_has_option (const char *cmd, const char *cmdopt);
     148             : 
     149             : 
     150             : 
     151             : 
     152             : /* Release the memory buffer MB but first wipe out the used memory. */
     153             : static void
     154           0 : clear_outbuf (membuf_t *mb)
     155             : {
     156             :   void *p;
     157             :   size_t n;
     158             : 
     159           0 :   p = get_membuf (mb, &n);
     160           0 :   if (p)
     161             :     {
     162           0 :       wipememory (p, n);
     163           0 :       xfree (p);
     164             :     }
     165           0 : }
     166             : 
     167             : 
     168             : /* Write the content of memory buffer MB as assuan data to CTX and
     169             :    wipe the buffer out afterwards. */
     170             : static gpg_error_t
     171         375 : write_and_clear_outbuf (assuan_context_t ctx, membuf_t *mb)
     172             : {
     173             :   gpg_error_t ae;
     174             :   void *p;
     175             :   size_t n;
     176             : 
     177         375 :   p = get_membuf (mb, &n);
     178         375 :   if (!p)
     179           0 :     return out_of_core ();
     180         375 :   ae = assuan_send_data (ctx, p, n);
     181         375 :   memset (p, 0, n);
     182         375 :   xfree (p);
     183         375 :   return ae;
     184             : }
     185             : 
     186             : 
     187             : /* Clear the nonces used to enable the passphrase cache for certain
     188             :    multi-command command sequences.  */
     189             : static void
     190        1172 : clear_nonce_cache (ctrl_t ctrl)
     191             : {
     192        1172 :   if (ctrl->server_local->last_cache_nonce)
     193             :     {
     194           0 :       agent_put_cache (ctrl->server_local->last_cache_nonce,
     195             :                        CACHE_MODE_NONCE, NULL, 0);
     196           0 :       xfree (ctrl->server_local->last_cache_nonce);
     197           0 :       ctrl->server_local->last_cache_nonce = NULL;
     198             :     }
     199        1172 :   if (ctrl->server_local->last_passwd_nonce)
     200             :     {
     201           0 :       agent_put_cache (ctrl->server_local->last_passwd_nonce,
     202             :                        CACHE_MODE_NONCE, NULL, 0);
     203           0 :       xfree (ctrl->server_local->last_passwd_nonce);
     204           0 :       ctrl->server_local->last_passwd_nonce = NULL;
     205             :     }
     206        1172 : }
     207             : 
     208             : 
     209             : /* This function is called by Libassuan whenever thee client sends a
     210             :    reset.  It has been registered similar to the other Assuan
     211             :    commands.  */
     212             : static gpg_error_t
     213         768 : reset_notify (assuan_context_t ctx, char *line)
     214             : {
     215         768 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     216             : 
     217             :   (void) line;
     218             : 
     219         768 :   memset (ctrl->keygrip, 0, 20);
     220         768 :   ctrl->have_keygrip = 0;
     221         768 :   ctrl->digest.valuelen = 0;
     222             : 
     223         768 :   xfree (ctrl->server_local->keydesc);
     224         768 :   ctrl->server_local->keydesc = NULL;
     225             : 
     226         768 :   clear_nonce_cache (ctrl);
     227             : 
     228         768 :   return 0;
     229             : }
     230             : 
     231             : 
     232             : /* Skip over options in LINE.
     233             : 
     234             :    Blanks after the options are also removed.  Options are indicated
     235             :    by two leading dashes followed by a string consisting of non-space
     236             :    characters.  The special option "--" indicates an explicit end of
     237             :    options; all what follows will not be considered an option.  The
     238             :    first no-option string also indicates the end of option parsing. */
     239             : static char *
     240         291 : skip_options (const char *line)
     241             : {
     242         582 :   while (spacep (line))
     243           0 :     line++;
     244         623 :   while ( *line == '-' && line[1] == '-' )
     245             :     {
     246         564 :       while (*line && !spacep (line))
     247         482 :         line++;
     248          82 :       while (spacep (line))
     249           0 :         line++;
     250             :     }
     251         291 :   return (char*)line;
     252             : }
     253             : 
     254             : 
     255             : /* Check whether the option NAME appears in LINE.  An example for a
     256             :    line with options is:
     257             :      --algo=42 --data foo bar
     258             :    This function would then only return true if NAME is "data".  */
     259             : static int
     260          47 : has_option (const char *line, const char *name)
     261             : {
     262             :   const char *s;
     263          47 :   int n = strlen (name);
     264             : 
     265          47 :   s = strstr (line, name);
     266          47 :   if (s && s >= skip_options (line))
     267           0 :     return 0;
     268          47 :   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
     269             : }
     270             : 
     271             : 
     272             : /* Same as has_option but does only test for the name of the option
     273             :    and ignores an argument, i.e. with NAME being "--hash" it would
     274             :    return true for "--hash" as well as for "--hash=foo". */
     275             : static int
     276         120 : has_option_name (const char *line, const char *name)
     277             : {
     278             :   const char *s;
     279         120 :   int n = strlen (name);
     280             : 
     281         120 :   s = strstr (line, name);
     282         120 :   if (s && s >= skip_options (line))
     283           0 :     return 0;
     284         120 :   return (s && (s == line || spacep (s-1))
     285         120 :           && (!s[n] || spacep (s+n) || s[n] == '='));
     286             : }
     287             : 
     288             : 
     289             : /* Return a pointer to the argument of the option with NAME.  If such
     290             :    an option is not given, NULL is retruned. */
     291             : static char *
     292           0 : option_value (const char *line, const char *name)
     293             : {
     294             :   char *s;
     295           0 :   int n = strlen (name);
     296             : 
     297           0 :   s = strstr (line, name);
     298           0 :   if (s && s >= skip_options (line))
     299           0 :     return NULL;
     300           0 :   if (s && (s == line || spacep (s-1))
     301           0 :       && s[n] && (spacep (s+n) || s[n] == '='))
     302             :     {
     303           0 :       s += n + 1;
     304           0 :       s += strspn (s, " ");
     305           0 :       if (*s && !spacep(s))
     306           0 :         return s;
     307             :     }
     308           0 :   return NULL;
     309             : }
     310             : 
     311             : 
     312             : /* Replace all '+' by a blank in the string S. */
     313             : static void
     314         386 : plus_to_blank (char *s)
     315             : {
     316       68248 :   for (; *s; s++)
     317             :     {
     318       67862 :       if (*s == '+')
     319        7583 :         *s = ' ';
     320             :     }
     321         386 : }
     322             : 
     323             : 
     324             : /* Parse a hex string.  Return an Assuan error code or 0 on success and the
     325             :    length of the parsed string in LEN. */
     326             : static int
     327        1432 : parse_hexstring (assuan_context_t ctx, const char *string, size_t *len)
     328             : {
     329             :   const char *p;
     330             :   size_t n;
     331             : 
     332             :   /* parse the hash value */
     333        1432 :   for (p=string, n=0; hexdigitp (p); p++, n++)
     334             :     ;
     335        1432 :   if (*p != ' ' && *p != '\t' && *p)
     336           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
     337        1432 :   if ((n&1))
     338           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "odd number of digits");
     339        1432 :   *len = n;
     340        1432 :   return 0;
     341             : }
     342             : 
     343             : 
     344             : /* Parse the keygrip in STRING into the provided buffer BUF.  BUF must
     345             :    provide space for 20 bytes.  BUF is not changed if the function
     346             :    returns an error. */
     347             : static int
     348        1302 : parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
     349             : {
     350             :   int rc;
     351        1302 :   size_t n = 0;
     352             : 
     353        1302 :   rc = parse_hexstring (ctx, string, &n);
     354        1302 :   if (rc)
     355           0 :     return rc;
     356        1302 :   n /= 2;
     357        1302 :   if (n != 20)
     358           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of keygrip");
     359             : 
     360        1302 :   if (hex2bin (string, buf, 20) < 0)
     361           0 :     return set_error (GPG_ERR_BUG, "hex2bin");
     362             : 
     363        1302 :   return 0;
     364             : }
     365             : 
     366             : 
     367             : /* Write an Assuan status line.  KEYWORD is the first item on the
     368             :    status line.  The following arguments are all separated by a space
     369             :    in the output.  The last argument must be a NULL.  Linefeeds and
     370             :    carriage returns characters (which are not allowed in an Assuan
     371             :    status line) are silently quoted in C-style.  */
     372             : gpg_error_t
     373           0 : agent_write_status (ctrl_t ctrl, const char *keyword, ...)
     374             : {
     375           0 :   gpg_error_t err = 0;
     376             :   va_list arg_ptr;
     377             :   const char *text;
     378           0 :   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
     379             :   char buf[950], *p;
     380             :   size_t n;
     381             : 
     382           0 :   va_start (arg_ptr, keyword);
     383             : 
     384           0 :   p = buf;
     385           0 :   n = 0;
     386           0 :   while ( (text = va_arg (arg_ptr, const char *)) )
     387             :     {
     388           0 :       if (n)
     389             :         {
     390           0 :           *p++ = ' ';
     391           0 :           n++;
     392             :         }
     393           0 :       for ( ; *text && n < DIM (buf)-3; n++, text++)
     394             :         {
     395           0 :           if (*text == '\n')
     396             :             {
     397           0 :               *p++ = '\\';
     398           0 :               *p++ = 'n';
     399             :             }
     400           0 :           else if (*text == '\r')
     401             :             {
     402           0 :               *p++ = '\\';
     403           0 :               *p++ = 'r';
     404             :             }
     405             :           else
     406           0 :             *p++ = *text;
     407             :         }
     408             :     }
     409           0 :   *p = 0;
     410           0 :   err = assuan_write_status (ctx, keyword, buf);
     411             : 
     412           0 :   va_end (arg_ptr);
     413           0 :   return err;
     414             : }
     415             : 
     416             : 
     417             : /* This function is similar to print_assuan_status but takes a CTRL
     418             :    arg instead of an assuan context as first argument.  */
     419             : gpg_error_t
     420           0 : agent_print_status (ctrl_t ctrl, const char *keyword, const char *format, ...)
     421             : {
     422             :   gpg_error_t err;
     423             :   va_list arg_ptr;
     424           0 :   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
     425             : 
     426           0 :   va_start (arg_ptr, format);
     427           0 :   err = vprint_assuan_status (ctx, keyword, format, arg_ptr);
     428           0 :   va_end (arg_ptr);
     429           0 :   return err;
     430             : }
     431             : 
     432             : 
     433             : /* Helper to notify the client about a launched Pinentry.  Because
     434             :    that might disturb some older clients, this is only done if enabled
     435             :    via an option.  Returns an gpg error code. */
     436             : gpg_error_t
     437           0 : agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid)
     438             : {
     439             :   char line[100];
     440             : 
     441           0 :   if (!ctrl || !ctrl->server_local
     442           0 :       || !ctrl->server_local->allow_pinentry_notify)
     443           0 :     return 0;
     444           0 :   snprintf (line, DIM(line)-1, "PINENTRY_LAUNCHED %lu", pid);
     445           0 :   return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
     446             : }
     447             : 
     448             : 
     449             : /* Helper to print a message while leaving a command.  */
     450             : static gpg_error_t
     451         406 : leave_cmd (assuan_context_t ctx, gpg_error_t err)
     452             : {
     453         406 :   if (err)
     454             :     {
     455           2 :       const char *name = assuan_get_command_name (ctx);
     456           2 :       if (!name)
     457           0 :         name = "?";
     458             : 
     459             :       /* Not all users of gpg-agent know about the fully canceled
     460             :          error code; map it back if needed.  */
     461           2 :       if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
     462             :         {
     463           0 :           ctrl_t ctrl = assuan_get_pointer (ctx);
     464             : 
     465           0 :           if (!ctrl->server_local->allow_fully_canceled)
     466           0 :             err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
     467             :         }
     468             : 
     469             :       /* Most code from common/ does not know the error source, thus
     470             :          we fix this here.  */
     471           2 :       if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
     472           0 :         err = gpg_err_make (GPG_ERR_SOURCE_DEFAULT, gpg_err_code (err));
     473             : 
     474           2 :       if (gpg_err_source (err) == GPG_ERR_SOURCE_DEFAULT)
     475           2 :         log_error ("command '%s' failed: %s\n", name,
     476             :                    gpg_strerror (err));
     477             :       else
     478           0 :         log_error ("command '%s' failed: %s <%s>\n", name,
     479             :                    gpg_strerror (err), gpg_strsource (err));
     480             :     }
     481         406 :   return err;
     482             : }
     483             : 
     484             : 
     485             : 
     486             : static const char hlp_geteventcounter[] =
     487             :   "GETEVENTCOUNTER\n"
     488             :   "\n"
     489             :   "Return a a status line named EVENTCOUNTER with the current values\n"
     490             :   "of all event counters.  The values are decimal numbers in the range\n"
     491             :   "0 to UINT_MAX and wrapping around to 0.  The actual values should\n"
     492             :   "not be relied upon, they shall only be used to detect a change.\n"
     493             :   "\n"
     494             :   "The currently defined counters are:\n"
     495             :   "\n"
     496             :   "ANY  - Incremented with any change of any of the other counters.\n"
     497             :   "KEY  - Incremented for added or removed private keys.\n"
     498             :   "CARD - Incremented for changes of the card readers stati.";
     499             : static gpg_error_t
     500           0 : cmd_geteventcounter (assuan_context_t ctx, char *line)
     501             : {
     502           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     503             : 
     504             :   (void)line;
     505             : 
     506           0 :   if (ctrl->restricted)
     507           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
     508             : 
     509           0 :   return agent_print_status (ctrl, "EVENTCOUNTER", "%u %u %u",
     510             :                              eventcounter.any,
     511             :                              eventcounter.key,
     512             :                              eventcounter.card);
     513             : }
     514             : 
     515             : 
     516             : /* This function should be called once for all key removals or
     517             :    additions.  This function is assured not to do any context
     518             :    switches. */
     519             : void
     520          21 : bump_key_eventcounter (void)
     521             : {
     522          21 :   eventcounter.key++;
     523          21 :   eventcounter.any++;
     524          21 : }
     525             : 
     526             : 
     527             : /* This function should be called for all card reader status
     528             :    changes.  This function is assured not to do any context
     529             :    switches. */
     530             : void
     531           0 : bump_card_eventcounter (void)
     532             : {
     533           0 :   eventcounter.card++;
     534           0 :   eventcounter.any++;
     535           0 : }
     536             : 
     537             : 
     538             : 
     539             : 
     540             : static const char hlp_istrusted[] =
     541             :   "ISTRUSTED <hexstring_with_fingerprint>\n"
     542             :   "\n"
     543             :   "Return OK when we have an entry with this fingerprint in our\n"
     544             :   "trustlist";
     545             : static gpg_error_t
     546           0 : cmd_istrusted (assuan_context_t ctx, char *line)
     547             : {
     548           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     549             :   int rc, n, i;
     550             :   char *p;
     551             :   char fpr[41];
     552             : 
     553             :   /* Parse the fingerprint value. */
     554           0 :   for (p=line,n=0; hexdigitp (p); p++, n++)
     555             :     ;
     556           0 :   if (*p || !(n == 40 || n == 32))
     557           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "invalid fingerprint");
     558           0 :   i = 0;
     559           0 :   if (n==32)
     560             :     {
     561           0 :       strcpy (fpr, "00000000");
     562           0 :       i += 8;
     563             :     }
     564           0 :   for (p=line; i < 40; p++, i++)
     565           0 :     fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
     566           0 :   fpr[i] = 0;
     567           0 :   rc = agent_istrusted (ctrl, fpr, NULL);
     568           0 :   if (!rc || gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
     569           0 :     return rc;
     570           0 :   else if (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF )
     571           0 :     return gpg_error (GPG_ERR_NOT_TRUSTED);
     572             :   else
     573           0 :     return leave_cmd (ctx, rc);
     574             : }
     575             : 
     576             : 
     577             : static const char hlp_listtrusted[] =
     578             :   "LISTTRUSTED\n"
     579             :   "\n"
     580             :   "List all entries from the trustlist.";
     581             : static gpg_error_t
     582           0 : cmd_listtrusted (assuan_context_t ctx, char *line)
     583             : {
     584           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     585             :   int rc;
     586             : 
     587             :   (void)line;
     588             : 
     589           0 :   if (ctrl->restricted)
     590           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
     591             : 
     592           0 :   rc = agent_listtrusted (ctx);
     593           0 :   return leave_cmd (ctx, rc);
     594             : }
     595             : 
     596             : 
     597             : static const char hlp_martrusted[] =
     598             :   "MARKTRUSTED <hexstring_with_fingerprint> <flag> <display_name>\n"
     599             :   "\n"
     600             :   "Store a new key in into the trustlist.";
     601             : static gpg_error_t
     602           0 : cmd_marktrusted (assuan_context_t ctx, char *line)
     603             : {
     604           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     605             :   int rc, n, i;
     606             :   char *p;
     607             :   char fpr[41];
     608             :   int flag;
     609             : 
     610           0 :   if (ctrl->restricted)
     611           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
     612             : 
     613             :   /* parse the fingerprint value */
     614           0 :   for (p=line,n=0; hexdigitp (p); p++, n++)
     615             :     ;
     616           0 :   if (!spacep (p) || !(n == 40 || n == 32))
     617           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "invalid fingerprint");
     618           0 :   i = 0;
     619           0 :   if (n==32)
     620             :     {
     621           0 :       strcpy (fpr, "00000000");
     622           0 :       i += 8;
     623             :     }
     624           0 :   for (p=line; i < 40; p++, i++)
     625           0 :     fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
     626           0 :   fpr[i] = 0;
     627             : 
     628           0 :   while (spacep (p))
     629           0 :     p++;
     630           0 :   flag = *p++;
     631           0 :   if ( (flag != 'S' && flag != 'P') || !spacep (p) )
     632           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "invalid flag - must be P or S");
     633           0 :   while (spacep (p))
     634           0 :     p++;
     635             : 
     636           0 :   rc = agent_marktrusted (ctrl, p, fpr, flag);
     637           0 :   return leave_cmd (ctx, rc);
     638             : }
     639             : 
     640             : 
     641             : 
     642             : 
     643             : static const char hlp_havekey[] =
     644             :   "HAVEKEY <hexstrings_with_keygrips>\n"
     645             :   "\n"
     646             :   "Return success if at least one of the secret keys with the given\n"
     647             :   "keygrips is available.";
     648             : static gpg_error_t
     649         930 : cmd_havekey (assuan_context_t ctx, char *line)
     650             : {
     651             :   gpg_error_t err;
     652             :   unsigned char buf[20];
     653             : 
     654             :   do
     655             :     {
     656         930 :       err = parse_keygrip (ctx, line, buf);
     657         930 :       if (err)
     658           0 :         return err;
     659             : 
     660         930 :       if (!agent_key_available (buf))
     661         876 :         return 0; /* Found.  */
     662             : 
     663        2268 :       while (*line && *line != ' ' && *line != '\t')
     664        2160 :         line++;
     665         108 :       while (*line == ' ' || *line == '\t')
     666           0 :         line++;
     667             :     }
     668          54 :   while (*line);
     669             : 
     670             :   /* No leave_cmd() here because errors are expected and would clutter
     671             :      the log.  */
     672          54 :   return gpg_error (GPG_ERR_NO_SECKEY);
     673             : }
     674             : 
     675             : 
     676             : static const char hlp_sigkey[] =
     677             :   "SIGKEY <hexstring_with_keygrip>\n"
     678             :   "SETKEY <hexstring_with_keygrip>\n"
     679             :   "\n"
     680             :   "Set the  key used for a sign or decrypt operation.";
     681             : static gpg_error_t
     682         372 : cmd_sigkey (assuan_context_t ctx, char *line)
     683             : {
     684             :   int rc;
     685         372 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     686             : 
     687         372 :   rc = parse_keygrip (ctx, line, ctrl->keygrip);
     688         372 :   if (rc)
     689           0 :     return rc;
     690         372 :   ctrl->have_keygrip = 1;
     691         372 :   return 0;
     692             : }
     693             : 
     694             : 
     695             : static const char hlp_setkeydesc[] =
     696             :   "SETKEYDESC plus_percent_escaped_string\n"
     697             :   "\n"
     698             :   "Set a description to be used for the next PKSIGN, PKDECRYPT, IMPORT_KEY\n"
     699             :   "or EXPORT_KEY operation if this operation requires a passphrase.  If\n"
     700             :   "this command is not used a default text will be used.  Note, that\n"
     701             :   "this description implictly selects the label used for the entry\n"
     702             :   "box; if the string contains the string PIN (which in general will\n"
     703             :   "not be translated), \"PIN\" is used, otherwise the translation of\n"
     704             :   "\"passphrase\" is used.  The description string should not contain\n"
     705             :   "blanks unless they are percent or '+' escaped.\n"
     706             :   "\n"
     707             :   "The description is only valid for the next PKSIGN, PKDECRYPT,\n"
     708             :   "IMPORT_KEY, EXPORT_KEY, or DELETE_KEY operation.";
     709             : static gpg_error_t
     710         386 : cmd_setkeydesc (assuan_context_t ctx, char *line)
     711             : {
     712         386 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     713             :   char *desc, *p;
     714             : 
     715         386 :   for (p=line; *p == ' '; p++)
     716             :     ;
     717         386 :   desc = p;
     718         386 :   p = strchr (desc, ' ');
     719         386 :   if (p)
     720           0 :     *p = 0; /* We ignore any garbage; we might late use it for other args. */
     721             : 
     722         386 :   if (!*desc)
     723           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
     724             : 
     725             :   /* Note, that we only need to replace the + characters and should
     726             :      leave the other escaping in place because the escaped string is
     727             :      send verbatim to the pinentry which does the unescaping (but not
     728             :      the + replacing) */
     729         386 :   plus_to_blank (desc);
     730             : 
     731         386 :   xfree (ctrl->server_local->keydesc);
     732             : 
     733         386 :   if (ctrl->restricted)
     734             :     {
     735           0 :       ctrl->server_local->keydesc = strconcat
     736           0 :         ((ctrl->restricted == 2
     737             :          ? _("Note: Request from the web browser.")
     738             :          : _("Note: Request from a remote site.")  ), "%0A%0A", desc, NULL);
     739             :     }
     740             :   else
     741         386 :     ctrl->server_local->keydesc = xtrystrdup (desc);
     742         386 :   if (!ctrl->server_local->keydesc)
     743           0 :     return out_of_core ();
     744         386 :   return 0;
     745             : }
     746             : 
     747             : 
     748             : static const char hlp_sethash[] =
     749             :   "SETHASH (--hash=<name>)|(<algonumber>) <hexstring>\n"
     750             :   "\n"
     751             :   "The client can use this command to tell the server about the data\n"
     752             :   "(which usually is a hash) to be signed.";
     753             : static gpg_error_t
     754         120 : cmd_sethash (assuan_context_t ctx, char *line)
     755             : {
     756             :   int rc;
     757             :   size_t n;
     758             :   char *p;
     759         120 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     760             :   unsigned char *buf;
     761             :   char *endp;
     762             :   int algo;
     763             : 
     764             :   /* Parse the alternative hash options which may be used instead of
     765             :      the algo number.  */
     766         120 :   if (has_option_name (line, "--hash"))
     767             :     {
     768           0 :       if (has_option (line, "--hash=sha1"))
     769           0 :         algo = GCRY_MD_SHA1;
     770           0 :       else if (has_option (line, "--hash=sha224"))
     771           0 :         algo = GCRY_MD_SHA224;
     772           0 :       else if (has_option (line, "--hash=sha256"))
     773           0 :         algo = GCRY_MD_SHA256;
     774           0 :       else if (has_option (line, "--hash=sha384"))
     775           0 :         algo = GCRY_MD_SHA384;
     776           0 :       else if (has_option (line, "--hash=sha512"))
     777           0 :         algo = GCRY_MD_SHA512;
     778           0 :       else if (has_option (line, "--hash=rmd160"))
     779           0 :         algo = GCRY_MD_RMD160;
     780           0 :       else if (has_option (line, "--hash=md5"))
     781           0 :         algo = GCRY_MD_MD5;
     782           0 :       else if (has_option (line, "--hash=tls-md5sha1"))
     783           0 :         algo = MD_USER_TLS_MD5SHA1;
     784             :       else
     785           0 :         return set_error (GPG_ERR_ASS_PARAMETER, "invalid hash algorithm");
     786             :     }
     787             :   else
     788         120 :     algo = 0;
     789             : 
     790         120 :   line = skip_options (line);
     791             : 
     792         120 :   if (!algo)
     793             :     {
     794             :       /* No hash option has been given: require an algo number instead  */
     795         120 :       algo = (int)strtoul (line, &endp, 10);
     796         120 :       for (line = endp; *line == ' ' || *line == '\t'; line++)
     797             :         ;
     798         120 :       if (!algo || gcry_md_test_algo (algo))
     799           0 :         return set_error (GPG_ERR_UNSUPPORTED_ALGORITHM, NULL);
     800             :     }
     801         120 :   ctrl->digest.algo = algo;
     802         120 :   ctrl->digest.raw_value = 0;
     803             : 
     804             :   /* Parse the hash value. */
     805         120 :   n = 0;
     806         120 :   rc = parse_hexstring (ctx, line, &n);
     807         120 :   if (rc)
     808           0 :     return rc;
     809         120 :   n /= 2;
     810         120 :   if (algo == MD_USER_TLS_MD5SHA1 && n == 36)
     811             :     ;
     812         120 :   else if (n != 16 && n != 20 && n != 24
     813          31 :            && n != 28 && n != 32 && n != 48 && n != 64)
     814           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "unsupported length of hash");
     815             : 
     816         120 :   if (n > MAX_DIGEST_LEN)
     817           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "hash value to long");
     818             : 
     819         120 :   buf = ctrl->digest.value;
     820         120 :   ctrl->digest.valuelen = n;
     821        3316 :   for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
     822        3196 :     buf[n] = xtoi_2 (p);
     823         120 :   for (; n < ctrl->digest.valuelen; n++)
     824           0 :     buf[n] = 0;
     825         120 :   return 0;
     826             : }
     827             : 
     828             : 
     829             : static const char hlp_pksign[] =
     830             :   "PKSIGN [<options>] [<cache_nonce>]\n"
     831             :   "\n"
     832             :   "Perform the actual sign operation.  Neither input nor output are\n"
     833             :   "sensitive to eavesdropping.";
     834             : static gpg_error_t
     835         120 : cmd_pksign (assuan_context_t ctx, char *line)
     836             : {
     837             :   int rc;
     838         120 :   cache_mode_t cache_mode = CACHE_MODE_NORMAL;
     839         120 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     840             :   membuf_t outbuf;
     841         120 :   char *cache_nonce = NULL;
     842             :   char *p;
     843             : 
     844         120 :   line = skip_options (line);
     845             : 
     846         120 :   p = line;
     847         120 :   for (p=line; *p && *p != ' ' && *p != '\t'; p++)
     848             :     ;
     849         120 :   *p = '\0';
     850         120 :   if (*line)
     851           0 :     cache_nonce = xtrystrdup (line);
     852             : 
     853         120 :   if (opt.ignore_cache_for_signing)
     854           0 :     cache_mode = CACHE_MODE_IGNORE;
     855         120 :   else if (!ctrl->server_local->use_cache_for_signing)
     856           0 :     cache_mode = CACHE_MODE_IGNORE;
     857             : 
     858         120 :   init_membuf (&outbuf, 512);
     859             : 
     860         120 :   rc = agent_pksign (ctrl, cache_nonce, ctrl->server_local->keydesc,
     861             :                      &outbuf, cache_mode);
     862         120 :   if (rc)
     863           0 :     clear_outbuf (&outbuf);
     864             :   else
     865         120 :     rc = write_and_clear_outbuf (ctx, &outbuf);
     866             : 
     867         120 :   xfree (cache_nonce);
     868         120 :   xfree (ctrl->server_local->keydesc);
     869         120 :   ctrl->server_local->keydesc = NULL;
     870         120 :   return leave_cmd (ctx, rc);
     871             : }
     872             : 
     873             : 
     874             : static const char hlp_pkdecrypt[] =
     875             :   "PKDECRYPT [<options>]\n"
     876             :   "\n"
     877             :   "Perform the actual decrypt operation.  Input is not\n"
     878             :   "sensitive to eavesdropping.";
     879             : static gpg_error_t
     880         252 : cmd_pkdecrypt (assuan_context_t ctx, char *line)
     881             : {
     882             :   int rc;
     883         252 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     884             :   unsigned char *value;
     885             :   size_t valuelen;
     886             :   membuf_t outbuf;
     887             :   int padding;
     888             : 
     889             :   (void)line;
     890             : 
     891             :   /* First inquire the data to decrypt */
     892         252 :   rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_CIPHERTEXT);
     893         252 :   if (!rc)
     894         252 :     rc = assuan_inquire (ctx, "CIPHERTEXT",
     895             :                         &value, &valuelen, MAXLEN_CIPHERTEXT);
     896         252 :   if (rc)
     897           0 :     return rc;
     898             : 
     899         252 :   init_membuf (&outbuf, 512);
     900             : 
     901         252 :   rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
     902             :                         value, valuelen, &outbuf, &padding);
     903         252 :   xfree (value);
     904         252 :   if (rc)
     905           0 :     clear_outbuf (&outbuf);
     906             :   else
     907             :     {
     908         252 :       if (padding != -1)
     909           0 :         rc = print_assuan_status (ctx, "PADDING", "%d", padding);
     910             :       else
     911         252 :         rc = 0;
     912         252 :       if (!rc)
     913         252 :         rc = write_and_clear_outbuf (ctx, &outbuf);
     914             :     }
     915         252 :   xfree (ctrl->server_local->keydesc);
     916         252 :   ctrl->server_local->keydesc = NULL;
     917         252 :   return leave_cmd (ctx, rc);
     918             : }
     919             : 
     920             : 
     921             : static const char hlp_genkey[] =
     922             :   "GENKEY [--no-protection] [--preset] [--inq-passwd] [<cache_nonce>]\n"
     923             :   "\n"
     924             :   "Generate a new key, store the secret part and return the public\n"
     925             :   "part.  Here is an example transaction:\n"
     926             :   "\n"
     927             :   "  C: GENKEY\n"
     928             :   "  S: INQUIRE KEYPARAM\n"
     929             :   "  C: D (genkey (rsa (nbits  2048)))\n"
     930             :   "  C: END\n"
     931             :   "  S: D (public-key\n"
     932             :   "  S: D   (rsa (n 326487324683264) (e 10001)))\n"
     933             :   "  S: OK key created\n"
     934             :   "\n"
     935             :   "When the --preset option is used the passphrase for the generated\n"
     936             :   "key will be added to the cache.  When --inq-passwd is used an inquire\n"
     937             :   "with the keyword NEWPASSWD is used to request the passphrase for the\n"
     938             :   "new key.\n";
     939             : static gpg_error_t
     940           3 : cmd_genkey (assuan_context_t ctx, char *line)
     941             : {
     942           3 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     943             :   int rc;
     944             :   int no_protection;
     945             :   unsigned char *value;
     946             :   size_t valuelen;
     947           3 :   unsigned char *newpasswd = NULL;
     948             :   membuf_t outbuf;
     949           3 :   char *cache_nonce = NULL;
     950             :   int opt_preset;
     951             :   int opt_inq_passwd;
     952             :   size_t n;
     953             :   char *p;
     954             : 
     955           3 :   if (ctrl->restricted)
     956           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
     957             : 
     958           3 :   no_protection = has_option (line, "--no-protection");
     959           3 :   opt_preset = has_option (line, "--preset");
     960           3 :   opt_inq_passwd = has_option (line, "--inq-passwd");
     961           3 :   line = skip_options (line);
     962             : 
     963           3 :   p = line;
     964           3 :   for (p=line; *p && *p != ' ' && *p != '\t'; p++)
     965             :     ;
     966           3 :   *p = '\0';
     967           3 :   if (*line)
     968           0 :     cache_nonce = xtrystrdup (line);
     969             : 
     970             :   /* First inquire the parameters */
     971           3 :   rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_KEYPARAM);
     972           3 :   if (!rc)
     973           3 :     rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
     974           3 :   if (rc)
     975           0 :     return rc;
     976             : 
     977           3 :   init_membuf (&outbuf, 512);
     978             : 
     979             :   /* If requested, ask for the password to be used for the key.  If
     980             :      this is not used the regular Pinentry mechanism is used.  */
     981           3 :   if (opt_inq_passwd && !no_protection)
     982             :     {
     983             :       /* (N is used as a dummy) */
     984           0 :       assuan_begin_confidential (ctx);
     985           0 :       rc = assuan_inquire (ctx, "NEWPASSWD", &newpasswd, &n, 256);
     986           0 :       assuan_end_confidential (ctx);
     987           0 :       if (rc)
     988           0 :         goto leave;
     989           0 :       if (!*newpasswd)
     990             :         {
     991             :           /* Empty password given - switch to no-protection mode.  */
     992           0 :           xfree (newpasswd);
     993           0 :           newpasswd = NULL;
     994           0 :           no_protection = 1;
     995             :         }
     996             : 
     997             :     }
     998             : 
     999           3 :   rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
    1000             :                      newpasswd, opt_preset, &outbuf);
    1001             : 
    1002             :  leave:
    1003           3 :   if (newpasswd)
    1004             :     {
    1005             :       /* Assuan_inquire does not allow us to read into secure memory
    1006             :          thus we need to wipe it ourself.  */
    1007           0 :       wipememory (newpasswd, strlen (newpasswd));
    1008           0 :       xfree (newpasswd);
    1009             :     }
    1010           3 :   xfree (value);
    1011           3 :   if (rc)
    1012           0 :     clear_outbuf (&outbuf);
    1013             :   else
    1014           3 :     rc = write_and_clear_outbuf (ctx, &outbuf);
    1015           3 :   xfree (cache_nonce);
    1016           3 :   return leave_cmd (ctx, rc);
    1017             : }
    1018             : 
    1019             : 
    1020             : 
    1021             : 
    1022             : static const char hlp_readkey[] =
    1023             :   "READKEY <hexstring_with_keygrip>\n"
    1024             :   "\n"
    1025             :   "Return the public key for the given keygrip.";
    1026             : static gpg_error_t
    1027           0 : cmd_readkey (assuan_context_t ctx, char *line)
    1028             : {
    1029           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1030             :   int rc;
    1031             :   unsigned char grip[20];
    1032           0 :   gcry_sexp_t s_pkey = NULL;
    1033             : 
    1034           0 :   if (ctrl->restricted)
    1035           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1036             : 
    1037           0 :   rc = parse_keygrip (ctx, line, grip);
    1038           0 :   if (rc)
    1039           0 :     return rc; /* Return immediately as this is already an Assuan error code.*/
    1040             : 
    1041           0 :   rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
    1042           0 :   if (!rc)
    1043             :     {
    1044             :       size_t len;
    1045             :       unsigned char *buf;
    1046             : 
    1047           0 :       len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
    1048           0 :       assert (len);
    1049           0 :       buf = xtrymalloc (len);
    1050           0 :       if (!buf)
    1051           0 :         rc = gpg_error_from_syserror ();
    1052             :       else
    1053             :         {
    1054           0 :           len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, buf, len);
    1055           0 :           assert (len);
    1056           0 :           rc = assuan_send_data (ctx, buf, len);
    1057           0 :           xfree (buf);
    1058             :         }
    1059           0 :       gcry_sexp_release (s_pkey);
    1060             :     }
    1061             : 
    1062           0 :   return leave_cmd (ctx, rc);
    1063             : }
    1064             : 
    1065             : 
    1066             : 
    1067             : static const char hlp_keyinfo[] =
    1068             :   "KEYINFO [--[ssh-]list] [--data] [--ssh-fpr] [--with-ssh] <keygrip>\n"
    1069             :   "\n"
    1070             :   "Return information about the key specified by the KEYGRIP.  If the\n"
    1071             :   "key is not available GPG_ERR_NOT_FOUND is returned.  If the option\n"
    1072             :   "--list is given the keygrip is ignored and information about all\n"
    1073             :   "available keys are returned.  If --ssh-list is given information\n"
    1074             :   "about all keys listed in the sshcontrol are returned.  With --with-ssh\n"
    1075             :   "information from sshcontrol is always added to the info. Unless --data\n"
    1076             :   "is given, the information is returned as a status line using the format:\n"
    1077             :   "\n"
    1078             :   "  KEYINFO <keygrip> <type> <serialno> <idstr> <cached> <protection> <fpr>\n"
    1079             :   "\n"
    1080             :   "KEYGRIP is the keygrip.\n"
    1081             :   "\n"
    1082             :   "TYPE is describes the type of the key:\n"
    1083             :   "    'D' - Regular key stored on disk,\n"
    1084             :   "    'T' - Key is stored on a smartcard (token),\n"
    1085             :   "    'X' - Unknown type,\n"
    1086             :   "    '-' - Key is missing.\n"
    1087             :   "\n"
    1088             :   "SERIALNO is an ASCII string with the serial number of the\n"
    1089             :   "         smartcard.  If the serial number is not known a single\n"
    1090             :   "         dash '-' is used instead.\n"
    1091             :   "\n"
    1092             :   "IDSTR is the IDSTR used to distinguish keys on a smartcard.  If it\n"
    1093             :   "      is not known a dash is used instead.\n"
    1094             :   "\n"
    1095             :   "CACHED is 1 if the passphrase for the key was found in the key cache.\n"
    1096             :   "       If not, a '-' is used instead.\n"
    1097             :   "\n"
    1098             :   "PROTECTION describes the key protection type:\n"
    1099             :   "    'P' - The key is protected with a passphrase,\n"
    1100             :   "    'C' - The key is not protected,\n"
    1101             :   "    '-' - Unknown protection.\n"
    1102             :   "\n"
    1103             :   "FPR returns the formatted ssh-style fingerprint of the key.  It is only\n"
    1104             :   "    printed if the option --ssh-fpr has been used.  It defaults to '-'.\n"
    1105             :   "\n"
    1106             :   "TTL is the TTL in seconds for that key or '-' if n/a.\n"
    1107             :   "\n"
    1108             :   "FLAGS is a word consisting of one-letter flags:\n"
    1109             :   "      'D' - The key has been disabled,\n"
    1110             :   "      'S' - The key is listed in sshcontrol (requires --with-ssh),\n"
    1111             :   "      'c' - Use of the key needs to be confirmed,\n"
    1112             :   "      '-' - No flags given.\n"
    1113             :   "\n"
    1114             :   "More information may be added in the future.";
    1115             : static gpg_error_t
    1116           0 : do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
    1117             :                 int data, int with_ssh_fpr, int in_ssh,
    1118             :                 int ttl, int disabled, int confirm)
    1119             : {
    1120             :   gpg_error_t err;
    1121             :   char hexgrip[40+1];
    1122           0 :   char *fpr = NULL;
    1123             :   int keytype;
    1124           0 :   unsigned char *shadow_info = NULL;
    1125           0 :   char *serialno = NULL;
    1126           0 :   char *idstr = NULL;
    1127             :   const char *keytypestr;
    1128             :   const char *cached;
    1129             :   const char *protectionstr;
    1130             :   char *pw;
    1131           0 :   int missing_key = 0;
    1132             :   char ttlbuf[20];
    1133             :   char flagsbuf[5];
    1134             : 
    1135           0 :   err = agent_key_info_from_file (ctrl, grip, &keytype, &shadow_info);
    1136           0 :   if (err)
    1137             :     {
    1138           0 :       if (in_ssh && gpg_err_code (err) == GPG_ERR_NOT_FOUND)
    1139           0 :         missing_key = 1;
    1140             :       else
    1141             :         goto leave;
    1142             :     }
    1143             : 
    1144             :   /* Reformat the grip so that we use uppercase as good style. */
    1145           0 :   bin2hex (grip, 20, hexgrip);
    1146             : 
    1147           0 :   if (ttl > 0)
    1148           0 :     snprintf (ttlbuf, sizeof ttlbuf, "%d", ttl);
    1149             :   else
    1150           0 :     strcpy (ttlbuf, "-");
    1151             : 
    1152           0 :   *flagsbuf = 0;
    1153           0 :   if (disabled)
    1154           0 :     strcat (flagsbuf, "D");
    1155           0 :   if (in_ssh)
    1156           0 :     strcat (flagsbuf, "S");
    1157           0 :   if (confirm)
    1158           0 :     strcat (flagsbuf, "c");
    1159           0 :   if (!*flagsbuf)
    1160           0 :     strcpy (flagsbuf, "-");
    1161             : 
    1162             : 
    1163           0 :   if (missing_key)
    1164             :     {
    1165           0 :       protectionstr = "-"; keytypestr = "-";
    1166             :     }
    1167             :   else
    1168             :     {
    1169           0 :       switch (keytype)
    1170             :         {
    1171             :         case PRIVATE_KEY_CLEAR:
    1172             :         case PRIVATE_KEY_OPENPGP_NONE:
    1173           0 :           protectionstr = "C"; keytypestr = "D";
    1174           0 :           break;
    1175           0 :         case PRIVATE_KEY_PROTECTED: protectionstr = "P"; keytypestr = "D";
    1176           0 :           break;
    1177           0 :         case PRIVATE_KEY_SHADOWED: protectionstr = "-"; keytypestr = "T";
    1178           0 :           break;
    1179           0 :         default: protectionstr = "-"; keytypestr = "X";
    1180           0 :           break;
    1181             :         }
    1182             :     }
    1183             : 
    1184             :   /* Compute the ssh fingerprint if requested.  */
    1185           0 :   if (with_ssh_fpr)
    1186             :     {
    1187             :       gcry_sexp_t key;
    1188             : 
    1189           0 :       if (!agent_raw_key_from_file (ctrl, grip, &key))
    1190             :         {
    1191           0 :           ssh_get_fingerprint_string (key, &fpr);
    1192           0 :           gcry_sexp_release (key);
    1193             :         }
    1194             :     }
    1195             : 
    1196             :   /* Here we have a little race by doing the cache check separately
    1197             :      from the retrieval function.  Given that the cache flag is only a
    1198             :      hint, it should not really matter.  */
    1199           0 :   pw = agent_get_cache (hexgrip, CACHE_MODE_NORMAL);
    1200           0 :   cached = pw ? "1" : "-";
    1201           0 :   xfree (pw);
    1202             : 
    1203           0 :   if (shadow_info)
    1204             :     {
    1205           0 :       err = parse_shadow_info (shadow_info, &serialno, &idstr, NULL);
    1206           0 :       if (err)
    1207           0 :         goto leave;
    1208             :     }
    1209             : 
    1210           0 :   if (!data)
    1211           0 :     err = agent_write_status (ctrl, "KEYINFO",
    1212             :                               hexgrip,
    1213             :                               keytypestr,
    1214           0 :                               serialno? serialno : "-",
    1215           0 :                               idstr? idstr : "-",
    1216             :                               cached,
    1217             :                               protectionstr,
    1218           0 :                               fpr? fpr : "-",
    1219             :                               ttlbuf,
    1220             :                               flagsbuf,
    1221             :                               NULL);
    1222             :   else
    1223             :     {
    1224             :       char *string;
    1225             : 
    1226           0 :       string = xtryasprintf ("%s %s %s %s %s %s %s %s %s\n",
    1227             :                              hexgrip, keytypestr,
    1228           0 :                              serialno? serialno : "-",
    1229           0 :                              idstr? idstr : "-", cached, protectionstr,
    1230           0 :                              fpr? fpr : "-",
    1231             :                              ttlbuf,
    1232             :                              flagsbuf);
    1233           0 :       if (!string)
    1234           0 :         err = gpg_error_from_syserror ();
    1235             :       else
    1236           0 :         err = assuan_send_data (ctx, string, strlen(string));
    1237           0 :       xfree (string);
    1238             :     }
    1239             : 
    1240             :  leave:
    1241           0 :   xfree (fpr);
    1242           0 :   xfree (shadow_info);
    1243           0 :   xfree (serialno);
    1244           0 :   xfree (idstr);
    1245           0 :   return err;
    1246             : }
    1247             : 
    1248             : 
    1249             : /* Entry int for the command KEYINFO.  This function handles the
    1250             :    command option processing.  For details see hlp_keyinfo above.  */
    1251             : static gpg_error_t
    1252           0 : cmd_keyinfo (assuan_context_t ctx, char *line)
    1253             : {
    1254           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1255             :   int err;
    1256             :   unsigned char grip[20];
    1257           0 :   DIR *dir = NULL;
    1258             :   int list_mode;
    1259             :   int opt_data, opt_ssh_fpr, opt_with_ssh;
    1260           0 :   ssh_control_file_t cf = NULL;
    1261             :   char hexgrip[41];
    1262             :   int disabled, ttl, confirm, is_ssh;
    1263             : 
    1264           0 :   if (ctrl->restricted)
    1265           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1266             : 
    1267           0 :   if (has_option (line, "--ssh-list"))
    1268           0 :     list_mode = 2;
    1269             :   else
    1270           0 :     list_mode = has_option (line, "--list");
    1271           0 :   opt_data = has_option (line, "--data");
    1272           0 :   opt_ssh_fpr = has_option (line, "--ssh-fpr");
    1273           0 :   opt_with_ssh = has_option (line, "--with-ssh");
    1274           0 :   line = skip_options (line);
    1275             : 
    1276           0 :   if (opt_with_ssh || list_mode == 2)
    1277           0 :     cf = ssh_open_control_file ();
    1278             : 
    1279           0 :   if (list_mode == 2)
    1280             :     {
    1281           0 :       if (cf)
    1282             :         {
    1283           0 :           while (!ssh_read_control_file (cf, hexgrip,
    1284             :                                          &disabled, &ttl, &confirm))
    1285             :             {
    1286           0 :               if (hex2bin (hexgrip, grip, 20) < 0 )
    1287           0 :                 continue; /* Bad hex string.  */
    1288           0 :               err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, 1,
    1289             :                                     ttl, disabled, confirm);
    1290           0 :               if (err)
    1291           0 :                 goto leave;
    1292             :             }
    1293             :         }
    1294           0 :       err = 0;
    1295             :     }
    1296           0 :   else if (list_mode)
    1297             :     {
    1298             :       char *dirname;
    1299             :       struct dirent *dir_entry;
    1300             : 
    1301           0 :       dirname = make_filename_try (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, NULL);
    1302           0 :       if (!dirname)
    1303             :         {
    1304           0 :           err = gpg_error_from_syserror ();
    1305           0 :           goto leave;
    1306             :         }
    1307           0 :       dir = opendir (dirname);
    1308           0 :       if (!dir)
    1309             :         {
    1310           0 :           err = gpg_error_from_syserror ();
    1311           0 :           xfree (dirname);
    1312           0 :           goto leave;
    1313             :         }
    1314           0 :       xfree (dirname);
    1315             : 
    1316           0 :       while ( (dir_entry = readdir (dir)) )
    1317             :         {
    1318           0 :           if (strlen (dir_entry->d_name) != 44
    1319           0 :               || strcmp (dir_entry->d_name + 40, ".key"))
    1320           0 :             continue;
    1321           0 :           strncpy (hexgrip, dir_entry->d_name, 40);
    1322           0 :           hexgrip[40] = 0;
    1323             : 
    1324           0 :           if ( hex2bin (hexgrip, grip, 20) < 0 )
    1325           0 :             continue; /* Bad hex string.  */
    1326             : 
    1327           0 :           disabled = ttl = confirm = is_ssh = 0;
    1328           0 :           if (opt_with_ssh)
    1329             :             {
    1330           0 :               err = ssh_search_control_file (cf, hexgrip,
    1331             :                                              &disabled, &ttl, &confirm);
    1332           0 :               if (!err)
    1333           0 :                 is_ssh = 1;
    1334           0 :               else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
    1335           0 :                 goto leave;
    1336             :             }
    1337             : 
    1338           0 :           err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh,
    1339             :                                 ttl, disabled, confirm);
    1340           0 :           if (err)
    1341           0 :             goto leave;
    1342             :         }
    1343           0 :       err = 0;
    1344             :     }
    1345             :   else
    1346             :     {
    1347           0 :       err = parse_keygrip (ctx, line, grip);
    1348           0 :       if (err)
    1349           0 :         goto leave;
    1350           0 :       disabled = ttl = confirm = is_ssh = 0;
    1351           0 :       if (opt_with_ssh)
    1352             :         {
    1353           0 :           err = ssh_search_control_file (cf, line,
    1354             :                                          &disabled, &ttl, &confirm);
    1355           0 :           if (!err)
    1356           0 :             is_ssh = 1;
    1357           0 :           else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
    1358           0 :             goto leave;
    1359             :         }
    1360             : 
    1361           0 :       err = do_one_keyinfo (ctrl, grip, ctx, opt_data, opt_ssh_fpr, is_ssh,
    1362             :                             ttl, disabled, confirm);
    1363             :     }
    1364             : 
    1365             :  leave:
    1366           0 :   ssh_close_control_file (cf);
    1367           0 :   if (dir)
    1368           0 :     closedir (dir);
    1369           0 :   if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
    1370           0 :     leave_cmd (ctx, err);
    1371           0 :   return err;
    1372             : }
    1373             : 
    1374             : 
    1375             : 
    1376             : /* Helper for cmd_get_passphrase.  */
    1377             : static int
    1378           0 : send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
    1379             : {
    1380             :   size_t n;
    1381             :   int rc;
    1382             : 
    1383           0 :   assuan_begin_confidential (ctx);
    1384           0 :   n = strlen (pw);
    1385           0 :   if (via_data)
    1386           0 :     rc = assuan_send_data (ctx, pw, n);
    1387             :   else
    1388             :     {
    1389           0 :       char *p = xtrymalloc_secure (n*2+1);
    1390           0 :       if (!p)
    1391           0 :         rc = gpg_error_from_syserror ();
    1392             :       else
    1393             :         {
    1394           0 :           bin2hex (pw, n, p);
    1395           0 :           rc = assuan_set_okay_line (ctx, p);
    1396           0 :           xfree (p);
    1397             :         }
    1398             :     }
    1399           0 :   return rc;
    1400             : }
    1401             : 
    1402             : 
    1403             : static const char hlp_get_passphrase[] =
    1404             :   "GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n"
    1405             :   "               [--qualitybar] <cache_id>\n"
    1406             :   "               [<error_message> <prompt> <description>]\n"
    1407             :   "\n"
    1408             :   "This function is usually used to ask for a passphrase to be used\n"
    1409             :   "for conventional encryption, but may also be used by programs which\n"
    1410             :   "need specal handling of passphrases.  This command uses a syntax\n"
    1411             :   "which helps clients to use the agent with minimum effort.  The\n"
    1412             :   "agent either returns with an error or with a OK followed by the hex\n"
    1413             :   "encoded passphrase.  Note that the length of the strings is\n"
    1414             :   "implicitly limited by the maximum length of a command.\n"
    1415             :   "\n"
    1416             :   "If the option \"--data\" is used the passphrase is returned by usual\n"
    1417             :   "data lines and not on the okay line.\n"
    1418             :   "\n"
    1419             :   "If the option \"--check\" is used the passphrase constraints checks as\n"
    1420             :   "implemented by gpg-agent are applied.  A check is not done if the\n"
    1421             :   "passphrase has been found in the cache.\n"
    1422             :   "\n"
    1423             :   "If the option \"--no-ask\" is used and the passphrase is not in the\n"
    1424             :   "cache the user will not be asked to enter a passphrase but the error\n"
    1425             :   "code GPG_ERR_NO_DATA is returned.  \n"
    1426             :   "\n"
    1427             :   "If the option \"--qualitybar\" is used a visual indication of the\n"
    1428             :   "entered passphrase quality is shown.  (Unless no minimum passphrase\n"
    1429             :   "length has been configured.)";
    1430             : static gpg_error_t
    1431           0 : cmd_get_passphrase (assuan_context_t ctx, char *line)
    1432             : {
    1433           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1434             :   int rc;
    1435             :   char *pw;
    1436             :   char *response;
    1437           0 :   char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
    1438           0 :   const char *desc2 = _("Please re-enter this passphrase");
    1439             :   char *p;
    1440             :   int opt_data, opt_check, opt_no_ask, opt_qualbar;
    1441           0 :   int opt_repeat = 0;
    1442           0 :   char *entry_errtext = NULL;
    1443             : 
    1444           0 :   if (ctrl->restricted)
    1445           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1446             : 
    1447           0 :   opt_data = has_option (line, "--data");
    1448           0 :   opt_check = has_option (line, "--check");
    1449           0 :   opt_no_ask = has_option (line, "--no-ask");
    1450           0 :   if (has_option_name (line, "--repeat"))
    1451             :     {
    1452           0 :       p = option_value (line, "--repeat");
    1453           0 :       if (p)
    1454           0 :         opt_repeat = atoi (p);
    1455             :       else
    1456           0 :         opt_repeat = 1;
    1457             :     }
    1458           0 :   opt_qualbar = has_option (line, "--qualitybar");
    1459           0 :   line = skip_options (line);
    1460             : 
    1461           0 :   cacheid = line;
    1462           0 :   p = strchr (cacheid, ' ');
    1463           0 :   if (p)
    1464             :     {
    1465           0 :       *p++ = 0;
    1466           0 :       while (*p == ' ')
    1467           0 :         p++;
    1468           0 :       errtext = p;
    1469           0 :       p = strchr (errtext, ' ');
    1470           0 :       if (p)
    1471             :         {
    1472           0 :           *p++ = 0;
    1473           0 :           while (*p == ' ')
    1474           0 :             p++;
    1475           0 :           prompt = p;
    1476           0 :           p = strchr (prompt, ' ');
    1477           0 :           if (p)
    1478             :             {
    1479           0 :               *p++ = 0;
    1480           0 :               while (*p == ' ')
    1481           0 :                 p++;
    1482           0 :               desc = p;
    1483           0 :               p = strchr (desc, ' ');
    1484           0 :               if (p)
    1485           0 :                 *p = 0; /* Ignore trailing garbage. */
    1486             :             }
    1487             :         }
    1488             :     }
    1489           0 :   if (!*cacheid || strlen (cacheid) > 50)
    1490           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
    1491           0 :   if (!desc)
    1492           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
    1493             : 
    1494           0 :   if (!strcmp (cacheid, "X"))
    1495           0 :     cacheid = NULL;
    1496           0 :   if (!strcmp (errtext, "X"))
    1497           0 :     errtext = NULL;
    1498           0 :   if (!strcmp (prompt, "X"))
    1499           0 :     prompt = NULL;
    1500           0 :   if (!strcmp (desc, "X"))
    1501           0 :     desc = NULL;
    1502             : 
    1503           0 :   pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER) : NULL;
    1504           0 :   if (pw)
    1505             :     {
    1506           0 :       rc = send_back_passphrase (ctx, opt_data, pw);
    1507           0 :       xfree (pw);
    1508             :     }
    1509           0 :   else if (opt_no_ask)
    1510           0 :     rc = gpg_error (GPG_ERR_NO_DATA);
    1511             :   else
    1512             :     {
    1513             :       /* Note, that we only need to replace the + characters and
    1514             :          should leave the other escaping in place because the escaped
    1515             :          string is send verbatim to the pinentry which does the
    1516             :          unescaping (but not the + replacing) */
    1517           0 :       if (errtext)
    1518           0 :         plus_to_blank (errtext);
    1519           0 :       if (prompt)
    1520           0 :         plus_to_blank (prompt);
    1521           0 :       if (desc)
    1522           0 :         plus_to_blank (desc);
    1523             : 
    1524             :     next_try:
    1525           0 :       rc = agent_get_passphrase (ctrl, &response, desc, prompt,
    1526           0 :                                  entry_errtext? entry_errtext:errtext,
    1527             :                                  opt_qualbar, cacheid, CACHE_MODE_USER);
    1528           0 :       xfree (entry_errtext);
    1529           0 :       entry_errtext = NULL;
    1530           0 :       if (!rc)
    1531             :         {
    1532             :           int i;
    1533             : 
    1534           0 :           if (opt_check
    1535           0 :               && check_passphrase_constraints (ctrl, response, &entry_errtext))
    1536             :             {
    1537           0 :               xfree (response);
    1538           0 :               goto next_try;
    1539             :             }
    1540           0 :           for (i = 0; i < opt_repeat; i++)
    1541             :             {
    1542             :               char *response2;
    1543             : 
    1544           0 :               if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
    1545           0 :                 break;
    1546             : 
    1547           0 :               rc = agent_get_passphrase (ctrl, &response2, desc2, prompt,
    1548             :                                          errtext, 0,
    1549             :                                          cacheid, CACHE_MODE_USER);
    1550           0 :               if (rc)
    1551           0 :                 break;
    1552           0 :               if (strcmp (response2, response))
    1553             :                 {
    1554           0 :                   xfree (response2);
    1555           0 :                   xfree (response);
    1556           0 :                   entry_errtext = try_percent_escape
    1557           0 :                     (_("does not match - try again"), NULL);
    1558           0 :                   if (!entry_errtext)
    1559             :                     {
    1560           0 :                       rc = gpg_error_from_syserror ();
    1561           0 :                       break;
    1562             :                     }
    1563           0 :                   goto next_try;
    1564             :                 }
    1565           0 :               xfree (response2);
    1566             :             }
    1567           0 :           if (!rc)
    1568             :             {
    1569           0 :               if (cacheid)
    1570           0 :                 agent_put_cache (cacheid, CACHE_MODE_USER, response, 0);
    1571           0 :               rc = send_back_passphrase (ctx, opt_data, response);
    1572             :             }
    1573           0 :           xfree (response);
    1574             :         }
    1575             :     }
    1576             : 
    1577           0 :   return leave_cmd (ctx, rc);
    1578             : }
    1579             : 
    1580             : 
    1581             : static const char hlp_clear_passphrase[] =
    1582             :   "CLEAR_PASSPHRASE [--mode=normal] <cache_id>\n"
    1583             :   "\n"
    1584             :   "may be used to invalidate the cache entry for a passphrase.  The\n"
    1585             :   "function returns with OK even when there is no cached passphrase.\n"
    1586             :   "The --mode=normal option is used to clear an entry for a cacheid\n"
    1587             :   "added by the agent.\n";
    1588             : static gpg_error_t
    1589           0 : cmd_clear_passphrase (assuan_context_t ctx, char *line)
    1590             : {
    1591           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1592           0 :   char *cacheid = NULL;
    1593             :   char *p;
    1594             :   int opt_normal;
    1595             : 
    1596           0 :   if (ctrl->restricted)
    1597           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1598             : 
    1599           0 :   opt_normal = has_option (line, "--mode=normal");
    1600           0 :   line = skip_options (line);
    1601             : 
    1602             :   /* parse the stuff */
    1603           0 :   for (p=line; *p == ' '; p++)
    1604             :     ;
    1605           0 :   cacheid = p;
    1606           0 :   p = strchr (cacheid, ' ');
    1607           0 :   if (p)
    1608           0 :     *p = 0; /* ignore garbage */
    1609           0 :   if (!*cacheid || strlen (cacheid) > 50)
    1610           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
    1611             : 
    1612           0 :   agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
    1613             :                    NULL, 0);
    1614             : 
    1615           0 :   agent_clear_passphrase (ctrl, cacheid,
    1616             :                           opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER);
    1617             : 
    1618           0 :   return 0;
    1619             : }
    1620             : 
    1621             : 
    1622             : static const char hlp_get_confirmation[] =
    1623             :   "GET_CONFIRMATION <description>\n"
    1624             :   "\n"
    1625             :   "This command may be used to ask for a simple confirmation.\n"
    1626             :   "DESCRIPTION is displayed along with a Okay and Cancel button.  This\n"
    1627             :   "command uses a syntax which helps clients to use the agent with\n"
    1628             :   "minimum effort.  The agent either returns with an error or with a\n"
    1629             :   "OK.  Note, that the length of DESCRIPTION is implicitly limited by\n"
    1630             :   "the maximum length of a command. DESCRIPTION should not contain\n"
    1631             :   "any spaces, those must be encoded either percent escaped or simply\n"
    1632             :   "as '+'.";
    1633             : static gpg_error_t
    1634           0 : cmd_get_confirmation (assuan_context_t ctx, char *line)
    1635             : {
    1636           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1637             :   int rc;
    1638           0 :   char *desc = NULL;
    1639             :   char *p;
    1640             : 
    1641           0 :   if (ctrl->restricted)
    1642           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1643             : 
    1644             :   /* parse the stuff */
    1645           0 :   for (p=line; *p == ' '; p++)
    1646             :     ;
    1647           0 :   desc = p;
    1648           0 :   p = strchr (desc, ' ');
    1649           0 :   if (p)
    1650           0 :     *p = 0; /* We ignore any garbage -may be later used for other args. */
    1651             : 
    1652           0 :   if (!*desc)
    1653           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
    1654             : 
    1655           0 :   if (!strcmp (desc, "X"))
    1656           0 :     desc = NULL;
    1657             : 
    1658             :   /* Note, that we only need to replace the + characters and should
    1659             :      leave the other escaping in place because the escaped string is
    1660             :      send verbatim to the pinentry which does the unescaping (but not
    1661             :      the + replacing) */
    1662           0 :   if (desc)
    1663           0 :     plus_to_blank (desc);
    1664             : 
    1665           0 :   rc = agent_get_confirmation (ctrl, desc, NULL, NULL, 0);
    1666           0 :   return leave_cmd (ctx, rc);
    1667             : }
    1668             : 
    1669             : 
    1670             : 
    1671             : static const char hlp_learn[] =
    1672             :   "LEARN [--send] [--sendinfo] [--force]\n"
    1673             :   "\n"
    1674             :   "Learn something about the currently inserted smartcard.  With\n"
    1675             :   "--sendinfo information about the card is returned; with --send\n"
    1676             :   "the available certificates are returned as D lines; with --force\n"
    1677             :   "private key storage will be updated by the result.";
    1678             : static gpg_error_t
    1679           0 : cmd_learn (assuan_context_t ctx, char *line)
    1680             : {
    1681           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1682             :   gpg_error_t err;
    1683             :   int send, sendinfo, force;
    1684             : 
    1685           0 :   send = has_option (line, "--send");
    1686           0 :   sendinfo = send? 1 : has_option (line, "--sendinfo");
    1687           0 :   force = has_option (line, "--force");
    1688             : 
    1689           0 :   if (ctrl->restricted)
    1690           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1691             : 
    1692           0 :   err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
    1693           0 :   return leave_cmd (ctx, err);
    1694             : }
    1695             : 
    1696             : 
    1697             : 
    1698             : static const char hlp_passwd[] =
    1699             :   "PASSWD [--cache-nonce=<c>] [--passwd-nonce=<s>] [--preset]\n"
    1700             :   "       [--verify] <hexkeygrip>\n"
    1701             :   "\n"
    1702             :   "Change the passphrase/PIN for the key identified by keygrip in LINE.  If\n"
    1703             :   "--preset is used then the new passphrase will be added to the cache.\n"
    1704             :   "If --verify is used the command asks for the passphrase and verifies\n"
    1705             :   "that the passphrase valid.\n";
    1706             : static gpg_error_t
    1707           0 : cmd_passwd (assuan_context_t ctx, char *line)
    1708             : {
    1709           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1710             :   gpg_error_t err;
    1711             :   int c;
    1712           0 :   char *cache_nonce = NULL;
    1713           0 :   char *passwd_nonce = NULL;
    1714             :   unsigned char grip[20];
    1715           0 :   gcry_sexp_t s_skey = NULL;
    1716           0 :   unsigned char *shadow_info = NULL;
    1717           0 :   char *passphrase = NULL;
    1718             :   char *pend;
    1719             :   int opt_preset, opt_verify;
    1720             : 
    1721           0 :   if (ctrl->restricted)
    1722           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1723             : 
    1724           0 :   opt_preset = has_option (line, "--preset");
    1725           0 :   cache_nonce = option_value (line, "--cache-nonce");
    1726           0 :   opt_verify = has_option (line, "--verify");
    1727           0 :   if (cache_nonce)
    1728             :     {
    1729           0 :       for (pend = cache_nonce; *pend && !spacep (pend); pend++)
    1730             :         ;
    1731           0 :       c = *pend;
    1732           0 :       *pend = '\0';
    1733           0 :       cache_nonce = xtrystrdup (cache_nonce);
    1734           0 :       *pend = c;
    1735           0 :       if (!cache_nonce)
    1736             :         {
    1737           0 :           err = gpg_error_from_syserror ();
    1738           0 :           goto leave;
    1739             :         }
    1740             :     }
    1741             : 
    1742           0 :   passwd_nonce = option_value (line, "--passwd-nonce");
    1743           0 :   if (passwd_nonce)
    1744             :     {
    1745           0 :       for (pend = passwd_nonce; *pend && !spacep (pend); pend++)
    1746             :         ;
    1747           0 :       c = *pend;
    1748           0 :       *pend = '\0';
    1749           0 :       passwd_nonce = xtrystrdup (passwd_nonce);
    1750           0 :       *pend = c;
    1751           0 :       if (!passwd_nonce)
    1752             :         {
    1753           0 :           err = gpg_error_from_syserror ();
    1754           0 :           goto leave;
    1755             :         }
    1756             :     }
    1757             : 
    1758           0 :   line = skip_options (line);
    1759             : 
    1760           0 :   err = parse_keygrip (ctx, line, grip);
    1761           0 :   if (err)
    1762           0 :     goto leave;
    1763             : 
    1764           0 :   ctrl->in_passwd++;
    1765           0 :   err = agent_key_from_file (ctrl,
    1766             :                              opt_verify? NULL : cache_nonce,
    1767           0 :                              ctrl->server_local->keydesc,
    1768             :                              grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
    1769             :                              &s_skey, &passphrase);
    1770           0 :   if (err)
    1771             :     ;
    1772           0 :   else if (shadow_info)
    1773             :     {
    1774           0 :       log_error ("changing a smartcard PIN is not yet supported\n");
    1775           0 :       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
    1776             :     }
    1777           0 :   else if (opt_verify)
    1778             :     {
    1779             :       /* All done.  */
    1780             :     }
    1781             :   else
    1782             :     {
    1783           0 :       char *newpass = NULL;
    1784             : 
    1785           0 :       if (passwd_nonce)
    1786           0 :         newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
    1787           0 :       err = agent_protect_and_store (ctrl, s_skey, &newpass);
    1788           0 :       if (!err && passphrase)
    1789             :         {
    1790             :           /* A passphrase existed on the old key and the change was
    1791             :              successful.  Return a nonce for that old passphrase to
    1792             :              let the caller try to unprotect the other subkeys with
    1793             :              the same key.  */
    1794           0 :           if (!cache_nonce)
    1795             :             {
    1796             :               char buf[12];
    1797           0 :               gcry_create_nonce (buf, 12);
    1798           0 :               cache_nonce = bin2hex (buf, 12, NULL);
    1799             :             }
    1800           0 :           if (cache_nonce
    1801           0 :               && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
    1802             :                                    passphrase, CACHE_TTL_NONCE))
    1803             :             {
    1804           0 :               assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
    1805           0 :               xfree (ctrl->server_local->last_cache_nonce);
    1806           0 :               ctrl->server_local->last_cache_nonce = cache_nonce;
    1807           0 :               cache_nonce = NULL;
    1808             :             }
    1809           0 :           if (newpass)
    1810             :             {
    1811             :               /* If we have a new passphrase (which might be empty) we
    1812             :                  store it under a passwd nonce so that the caller may
    1813             :                  send that nonce again to use it for another key. */
    1814           0 :               if (!passwd_nonce)
    1815             :                 {
    1816             :                   char buf[12];
    1817           0 :                   gcry_create_nonce (buf, 12);
    1818           0 :                   passwd_nonce = bin2hex (buf, 12, NULL);
    1819             :                 }
    1820           0 :               if (passwd_nonce
    1821           0 :                   && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
    1822             :                                        newpass, CACHE_TTL_NONCE))
    1823             :                 {
    1824           0 :                   assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
    1825           0 :                   xfree (ctrl->server_local->last_passwd_nonce);
    1826           0 :                   ctrl->server_local->last_passwd_nonce = passwd_nonce;
    1827           0 :                   passwd_nonce = NULL;
    1828             :                 }
    1829             :             }
    1830             :         }
    1831           0 :       if (!err && opt_preset)
    1832             :         {
    1833             :           char hexgrip[40+1];
    1834           0 :           bin2hex(grip, 20, hexgrip);
    1835           0 :           err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass,
    1836             :                                  ctrl->cache_ttl_opt_preset);
    1837             :         }
    1838           0 :       xfree (newpass);
    1839             :     }
    1840           0 :   ctrl->in_passwd--;
    1841             : 
    1842           0 :   xfree (ctrl->server_local->keydesc);
    1843           0 :   ctrl->server_local->keydesc = NULL;
    1844             : 
    1845             :  leave:
    1846           0 :   xfree (passphrase);
    1847           0 :   gcry_sexp_release (s_skey);
    1848           0 :   xfree (shadow_info);
    1849           0 :   xfree (cache_nonce);
    1850           0 :   return leave_cmd (ctx, err);
    1851             : }
    1852             : 
    1853             : 
    1854             : static const char hlp_preset_passphrase[] =
    1855             :   "PRESET_PASSPHRASE [--inquire] <string_or_keygrip> <timeout> [<hexstring>]\n"
    1856             :   "\n"
    1857             :   "Set the cached passphrase/PIN for the key identified by the keygrip\n"
    1858             :   "to passwd for the given time, where -1 means infinite and 0 means\n"
    1859             :   "the default (currently only a timeout of -1 is allowed, which means\n"
    1860             :   "to never expire it).  If passwd is not provided, ask for it via the\n"
    1861             :   "pinentry module unless --inquire is passed in which case the passphrase\n"
    1862             :   "is retrieved from the client via a server inquire.\n";
    1863             : static gpg_error_t
    1864          10 : cmd_preset_passphrase (assuan_context_t ctx, char *line)
    1865             : {
    1866          10 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1867             :   int rc;
    1868          10 :   char *grip_clear = NULL;
    1869          10 :   unsigned char *passphrase = NULL;
    1870             :   int ttl;
    1871             :   size_t len;
    1872             :   int opt_inquire;
    1873             : 
    1874          10 :   if (ctrl->restricted)
    1875           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1876             : 
    1877          10 :   if (!opt.allow_preset_passphrase)
    1878           0 :     return set_error (GPG_ERR_NOT_SUPPORTED, "no --allow-preset-passphrase");
    1879             : 
    1880          10 :   opt_inquire = has_option (line, "--inquire");
    1881          10 :   line = skip_options (line);
    1882          10 :   grip_clear = line;
    1883         420 :   while (*line && (*line != ' ' && *line != '\t'))
    1884         400 :     line++;
    1885          10 :   if (!*line)
    1886           0 :     return gpg_error (GPG_ERR_MISSING_VALUE);
    1887          10 :   *line = '\0';
    1888          10 :   line++;
    1889          20 :   while (*line && (*line == ' ' || *line == '\t'))
    1890           0 :     line++;
    1891             : 
    1892             :   /* Currently, only infinite timeouts are allowed.  */
    1893          10 :   ttl = -1;
    1894          10 :   if (line[0] != '-' || line[1] != '1')
    1895           0 :     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
    1896          10 :   line++;
    1897          10 :   line++;
    1898          30 :   while (!(*line != ' ' && *line != '\t'))
    1899          10 :     line++;
    1900             : 
    1901             :   /* Syntax check the hexstring.  */
    1902          10 :   len = 0;
    1903          10 :   rc = parse_hexstring (ctx, line, &len);
    1904          10 :   if (rc)
    1905           0 :     return rc;
    1906          10 :   line[len] = '\0';
    1907             : 
    1908             :   /* If there is a passphrase, use it.  Currently, a passphrase is
    1909             :      required.  */
    1910          10 :   if (*line)
    1911             :     {
    1912          10 :       if (opt_inquire)
    1913             :         {
    1914           0 :           rc = set_error (GPG_ERR_ASS_PARAMETER,
    1915             :                           "both --inquire and passphrase specified");
    1916           0 :           goto leave;
    1917             :         }
    1918             : 
    1919             :       /* Do in-place conversion.  */
    1920          10 :       passphrase = line;
    1921          10 :       if (!hex2str (passphrase, passphrase, strlen (passphrase)+1, NULL))
    1922           0 :         rc = set_error (GPG_ERR_ASS_PARAMETER, "invalid hexstring");
    1923             :     }
    1924           0 :   else if (opt_inquire)
    1925             :     {
    1926             :       /* Note that the passphrase will be truncated at any null byte and the
    1927             :        * limit is 480 characters. */
    1928           0 :       size_t maxlen = 480;
    1929             : 
    1930           0 :       rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%zu", maxlen);
    1931           0 :       if (!rc)
    1932           0 :         rc = assuan_inquire (ctx, "PASSPHRASE", &passphrase, &len, maxlen);
    1933             :     }
    1934             :   else
    1935           0 :     rc = set_error (GPG_ERR_NOT_IMPLEMENTED, "passphrase is required");
    1936             : 
    1937          10 :   if (!rc)
    1938             :     {
    1939          10 :       rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl);
    1940          10 :       if (opt_inquire)
    1941           0 :         xfree (passphrase);
    1942             :     }
    1943             : 
    1944             : leave:
    1945          10 :   return leave_cmd (ctx, rc);
    1946             : }
    1947             : 
    1948             : 
    1949             : 
    1950             : static const char hlp_scd[] =
    1951             :   "SCD <commands to pass to the scdaemon>\n"
    1952             :   " \n"
    1953             :   "This is a general quote command to redirect everything to the\n"
    1954             :   "SCdaemon.";
    1955             : static gpg_error_t
    1956           0 : cmd_scd (assuan_context_t ctx, char *line)
    1957             : {
    1958           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1959             :   int rc;
    1960             : 
    1961           0 :   if (ctrl->restricted)
    1962           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1963             : 
    1964           0 :   rc = divert_generic_cmd (ctrl, line, ctx);
    1965             : 
    1966           0 :   return rc;
    1967             : }
    1968             : 
    1969             : 
    1970             : 
    1971             : static const char hlp_keywrap_key[] =
    1972             :   "KEYWRAP_KEY [--clear] <mode>\n"
    1973             :   "\n"
    1974             :   "Return a key to wrap another key.  For now the key is returned\n"
    1975             :   "verbatim and and thus makes not much sense because an eavesdropper on\n"
    1976             :   "the gpg-agent connection will see the key as well as the wrapped key.\n"
    1977             :   "However, this function may either be equipped with a public key\n"
    1978             :   "mechanism or not used at all if the key is a pre-shared key.  In any\n"
    1979             :   "case wrapping the import and export of keys is a requirement for\n"
    1980             :   "certain cryptographic validations and thus useful.  The key persists\n"
    1981             :   "until a RESET command but may be cleared using the option --clear.\n"
    1982             :   "\n"
    1983             :   "Supported modes are:\n"
    1984             :   "  --import  - Return a key to import a key into gpg-agent\n"
    1985             :   "  --export  - Return a key to export a key from gpg-agent";
    1986             : static gpg_error_t
    1987           7 : cmd_keywrap_key (assuan_context_t ctx, char *line)
    1988             : {
    1989           7 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1990           7 :   gpg_error_t err = 0;
    1991           7 :   int clearopt = has_option (line, "--clear");
    1992             : 
    1993           7 :   if (ctrl->restricted)
    1994           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    1995             : 
    1996           7 :   assuan_begin_confidential (ctx);
    1997           7 :   if (has_option (line, "--import"))
    1998             :     {
    1999           7 :       xfree (ctrl->server_local->import_key);
    2000           7 :       if (clearopt)
    2001           0 :         ctrl->server_local->import_key = NULL;
    2002          14 :       else if (!(ctrl->server_local->import_key =
    2003           7 :                  gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM)))
    2004           0 :         err = gpg_error_from_syserror ();
    2005             :       else
    2006           7 :         err = assuan_send_data (ctx, ctrl->server_local->import_key,
    2007             :                                 KEYWRAP_KEYSIZE);
    2008             :     }
    2009           0 :   else if (has_option (line, "--export"))
    2010             :     {
    2011           0 :       xfree (ctrl->server_local->export_key);
    2012           0 :       if (clearopt)
    2013           0 :         ctrl->server_local->export_key = NULL;
    2014           0 :       else if (!(ctrl->server_local->export_key =
    2015           0 :             gcry_random_bytes (KEYWRAP_KEYSIZE, GCRY_STRONG_RANDOM)))
    2016           0 :         err = gpg_error_from_syserror ();
    2017             :       else
    2018           0 :         err = assuan_send_data (ctx, ctrl->server_local->export_key,
    2019             :                                 KEYWRAP_KEYSIZE);
    2020             :     }
    2021             :   else
    2022           0 :     err = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for MODE");
    2023           7 :   assuan_end_confidential (ctx);
    2024             : 
    2025           7 :   return leave_cmd (ctx, err);
    2026             : }
    2027             : 
    2028             : 
    2029             : 
    2030             : static const char hlp_import_key[] =
    2031             :   "IMPORT_KEY [--unattended] [<cache_nonce>]\n"
    2032             :   "\n"
    2033             :   "Import a secret key into the key store.  The key is expected to be\n"
    2034             :   "encrypted using the current session's key wrapping key (cf. command\n"
    2035             :   "KEYWRAP_KEY) using the AESWRAP-128 algorithm.  This function takes\n"
    2036             :   "no arguments but uses the inquiry \"KEYDATA\" to ask for the actual\n"
    2037             :   "key data.  The unwrapped key must be a canonical S-expression.  The\n"
    2038             :   "option --unattended tries to import the key as-is without any\n"
    2039             :   "re-encryption";
    2040             : static gpg_error_t
    2041          14 : cmd_import_key (assuan_context_t ctx, char *line)
    2042             : {
    2043          14 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2044             :   gpg_error_t err;
    2045             :   int opt_unattended;
    2046          14 :   unsigned char *wrappedkey = NULL;
    2047             :   size_t wrappedkeylen;
    2048          14 :   gcry_cipher_hd_t cipherhd = NULL;
    2049          14 :   unsigned char *key = NULL;
    2050             :   size_t keylen, realkeylen;
    2051          14 :   char *passphrase = NULL;
    2052          14 :   unsigned char *finalkey = NULL;
    2053             :   size_t finalkeylen;
    2054             :   unsigned char grip[20];
    2055          14 :   gcry_sexp_t openpgp_sexp = NULL;
    2056          14 :   char *cache_nonce = NULL;
    2057             :   char *p;
    2058             : 
    2059          14 :   if (ctrl->restricted)
    2060           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2061             : 
    2062          14 :   if (!ctrl->server_local->import_key)
    2063             :     {
    2064           0 :       err = gpg_error (GPG_ERR_MISSING_KEY);
    2065           0 :       goto leave;
    2066             :     }
    2067             : 
    2068          14 :   opt_unattended = has_option (line, "--unattended");
    2069          14 :   line = skip_options (line);
    2070             : 
    2071          14 :   p = line;
    2072          14 :   for (p=line; *p && *p != ' ' && *p != '\t'; p++)
    2073             :     ;
    2074          14 :   *p = '\0';
    2075          14 :   if (*line)
    2076           0 :     cache_nonce = xtrystrdup (line);
    2077             : 
    2078          14 :   assuan_begin_confidential (ctx);
    2079          14 :   err = assuan_inquire (ctx, "KEYDATA",
    2080             :                         &wrappedkey, &wrappedkeylen, MAXLEN_KEYDATA);
    2081          14 :   assuan_end_confidential (ctx);
    2082          14 :   if (err)
    2083           0 :     goto leave;
    2084          14 :   if (wrappedkeylen < 24)
    2085             :     {
    2086           0 :       err = gpg_error (GPG_ERR_INV_LENGTH);
    2087           0 :       goto leave;
    2088             :     }
    2089          14 :   keylen = wrappedkeylen - 8;
    2090          14 :   key = xtrymalloc_secure (keylen);
    2091          14 :   if (!key)
    2092             :     {
    2093           0 :       err = gpg_error_from_syserror ();
    2094           0 :       goto leave;
    2095             :     }
    2096             : 
    2097          14 :   err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
    2098             :                           GCRY_CIPHER_MODE_AESWRAP, 0);
    2099          14 :   if (err)
    2100           0 :     goto leave;
    2101          14 :   err = gcry_cipher_setkey (cipherhd,
    2102          14 :                             ctrl->server_local->import_key, KEYWRAP_KEYSIZE);
    2103          14 :   if (err)
    2104           0 :     goto leave;
    2105          14 :   err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen);
    2106          14 :   if (err)
    2107           0 :     goto leave;
    2108          14 :   gcry_cipher_close (cipherhd);
    2109          14 :   cipherhd = NULL;
    2110          14 :   xfree (wrappedkey);
    2111          14 :   wrappedkey = NULL;
    2112             : 
    2113          14 :   realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
    2114          14 :   if (!realkeylen)
    2115           0 :     goto leave; /* Invalid canonical encoded S-expression.  */
    2116             : 
    2117          14 :   err = keygrip_from_canon_sexp (key, realkeylen, grip);
    2118          14 :   if (err)
    2119             :     {
    2120             :       /* This might be due to an unsupported S-expression format.
    2121             :          Check whether this is openpgp-private-key and trigger that
    2122             :          import code.  */
    2123          14 :       if (!gcry_sexp_sscan (&openpgp_sexp, NULL, key, realkeylen))
    2124             :         {
    2125             :           const char *tag;
    2126             :           size_t taglen;
    2127             : 
    2128          14 :           tag = gcry_sexp_nth_data (openpgp_sexp, 0, &taglen);
    2129          14 :           if (tag && taglen == 19 && !memcmp (tag, "openpgp-private-key", 19))
    2130             :             ;
    2131             :           else
    2132             :             {
    2133           0 :               gcry_sexp_release (openpgp_sexp);
    2134           0 :               openpgp_sexp = NULL;
    2135             :             }
    2136             :         }
    2137          14 :       if (!openpgp_sexp)
    2138           0 :         goto leave; /* Note that ERR is still set.  */
    2139             :     }
    2140             : 
    2141             : 
    2142          14 :   if (openpgp_sexp)
    2143             :     {
    2144             :       /* In most cases the key is encrypted and thus the conversion
    2145             :          function from the OpenPGP format to our internal format will
    2146             :          ask for a passphrase.  That passphrase will be returned and
    2147             :          used to protect the key using the same code as for regular
    2148             :          key import. */
    2149             : 
    2150          14 :       xfree (key);
    2151          14 :       key = NULL;
    2152          28 :       err = convert_from_openpgp (ctrl, openpgp_sexp, grip,
    2153          14 :                                   ctrl->server_local->keydesc, cache_nonce,
    2154             :                                   &key, opt_unattended? NULL : &passphrase);
    2155          14 :       if (err)
    2156           2 :         goto leave;
    2157          12 :       realkeylen = gcry_sexp_canon_len (key, 0, NULL, &err);
    2158          12 :       if (!realkeylen)
    2159           0 :         goto leave; /* Invalid canonical encoded S-expression.  */
    2160          12 :       if (passphrase)
    2161             :         {
    2162           0 :           assert (!opt_unattended);
    2163           0 :           if (!cache_nonce)
    2164             :             {
    2165             :               char buf[12];
    2166           0 :               gcry_create_nonce (buf, 12);
    2167           0 :               cache_nonce = bin2hex (buf, 12, NULL);
    2168             :             }
    2169           0 :           if (cache_nonce
    2170           0 :               && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
    2171             :                                    passphrase, CACHE_TTL_NONCE))
    2172           0 :             assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
    2173             :         }
    2174             :     }
    2175           0 :   else if (opt_unattended)
    2176             :     {
    2177           0 :       err = set_error (GPG_ERR_ASS_PARAMETER,
    2178             :                        "\"--unattended\" may only be used with OpenPGP keys");
    2179           0 :       goto leave;
    2180             :     }
    2181             :   else
    2182             :     {
    2183           0 :       if (!agent_key_available (grip))
    2184           0 :         err = gpg_error (GPG_ERR_EEXIST);
    2185             :       else
    2186             :         {
    2187           0 :           char *prompt = xtryasprintf
    2188           0 :             (_("Please enter the passphrase to protect the "
    2189             :                "imported object within the %s system."), GNUPG_NAME);
    2190           0 :           if (!prompt)
    2191           0 :             err = gpg_error_from_syserror ();
    2192             :           else
    2193           0 :             err = agent_ask_new_passphrase (ctrl, prompt, &passphrase);
    2194           0 :           xfree (prompt);
    2195             :         }
    2196           0 :       if (err)
    2197           0 :         goto leave;
    2198             :     }
    2199             : 
    2200          12 :   if (passphrase)
    2201             :     {
    2202           0 :       err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
    2203             :                            ctrl->s2k_count);
    2204           0 :       if (!err)
    2205           0 :         err = agent_write_private_key (grip, finalkey, finalkeylen, 0);
    2206             :     }
    2207             :   else
    2208          12 :     err = agent_write_private_key (grip, key, realkeylen, 0);
    2209             : 
    2210             :  leave:
    2211          14 :   gcry_sexp_release (openpgp_sexp);
    2212          14 :   xfree (finalkey);
    2213          14 :   xfree (passphrase);
    2214          14 :   xfree (key);
    2215          14 :   gcry_cipher_close (cipherhd);
    2216          14 :   xfree (wrappedkey);
    2217          14 :   xfree (cache_nonce);
    2218          14 :   xfree (ctrl->server_local->keydesc);
    2219          14 :   ctrl->server_local->keydesc = NULL;
    2220          14 :   return leave_cmd (ctx, err);
    2221             : }
    2222             : 
    2223             : 
    2224             : 
    2225             : static const char hlp_export_key[] =
    2226             :   "EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp] <hexstring_with_keygrip>\n"
    2227             :   "\n"
    2228             :   "Export a secret key from the key store.  The key will be encrypted\n"
    2229             :   "using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
    2230             :   "using the AESWRAP-128 algorithm.  The caller needs to retrieve that key\n"
    2231             :   "prior to using this command.  The function takes the keygrip as argument.\n";
    2232             : static gpg_error_t
    2233           0 : cmd_export_key (assuan_context_t ctx, char *line)
    2234             : {
    2235           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2236             :   gpg_error_t err;
    2237             :   unsigned char grip[20];
    2238           0 :   gcry_sexp_t s_skey = NULL;
    2239           0 :   unsigned char *key = NULL;
    2240             :   size_t keylen;
    2241           0 :   gcry_cipher_hd_t cipherhd = NULL;
    2242           0 :   unsigned char *wrappedkey = NULL;
    2243             :   size_t wrappedkeylen;
    2244             :   int openpgp;
    2245             :   char *cache_nonce;
    2246           0 :   char *passphrase = NULL;
    2247           0 :   unsigned char *shadow_info = NULL;
    2248             :   char *pend;
    2249             :   int c;
    2250             : 
    2251           0 :   if (ctrl->restricted)
    2252           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2253             : 
    2254           0 :   openpgp = has_option (line, "--openpgp");
    2255           0 :   cache_nonce = option_value (line, "--cache-nonce");
    2256           0 :   if (cache_nonce)
    2257             :     {
    2258           0 :       for (pend = cache_nonce; *pend && !spacep (pend); pend++)
    2259             :         ;
    2260           0 :       c = *pend;
    2261           0 :       *pend = '\0';
    2262           0 :       cache_nonce = xtrystrdup (cache_nonce);
    2263           0 :       *pend = c;
    2264           0 :       if (!cache_nonce)
    2265             :         {
    2266           0 :           err = gpg_error_from_syserror ();
    2267           0 :           goto leave;
    2268             :         }
    2269             :     }
    2270           0 :   line = skip_options (line);
    2271             : 
    2272           0 :   if (!ctrl->server_local->export_key)
    2273             :     {
    2274           0 :       err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY ?");
    2275           0 :       goto leave;
    2276             :     }
    2277             : 
    2278           0 :   err = parse_keygrip (ctx, line, grip);
    2279           0 :   if (err)
    2280           0 :     goto leave;
    2281             : 
    2282           0 :   if (agent_key_available (grip))
    2283             :     {
    2284           0 :       err = gpg_error (GPG_ERR_NO_SECKEY);
    2285           0 :       goto leave;
    2286             :     }
    2287             : 
    2288             :   /* Get the key from the file.  With the openpgp flag we also ask for
    2289             :      the passphrase so that we can use it to re-encrypt it.  */
    2290           0 :   err = agent_key_from_file (ctrl, cache_nonce,
    2291           0 :                              ctrl->server_local->keydesc, grip,
    2292             :                              &shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
    2293             :                              openpgp ? &passphrase : NULL);
    2294           0 :   if (err)
    2295           0 :     goto leave;
    2296           0 :   if (shadow_info)
    2297             :     {
    2298             :       /* Key is on a smartcard.  */
    2299           0 :       err = gpg_error (GPG_ERR_UNUSABLE_SECKEY);
    2300           0 :       goto leave;
    2301             :     }
    2302             : 
    2303           0 :   if (openpgp)
    2304             :     {
    2305             :       /* The openpgp option changes the key format into the OpenPGP
    2306             :          key transfer format.  The result is already a padded
    2307             :          canonical S-expression.  */
    2308           0 :       if (!passphrase)
    2309             :         {
    2310           0 :           err = agent_ask_new_passphrase
    2311           0 :             (ctrl, _("This key (or subkey) is not protected with a passphrase."
    2312             :                      "  Please enter a new passphrase to export it."),
    2313             :              &passphrase);
    2314           0 :           if (err)
    2315           0 :             goto leave;
    2316             :         }
    2317           0 :       err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen);
    2318           0 :       if (!err && passphrase)
    2319             :         {
    2320           0 :           if (!cache_nonce)
    2321             :             {
    2322             :               char buf[12];
    2323           0 :               gcry_create_nonce (buf, 12);
    2324           0 :               cache_nonce = bin2hex (buf, 12, NULL);
    2325             :             }
    2326           0 :           if (cache_nonce
    2327           0 :               && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
    2328             :                                    passphrase, CACHE_TTL_NONCE))
    2329             :             {
    2330           0 :               assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
    2331           0 :               xfree (ctrl->server_local->last_cache_nonce);
    2332           0 :               ctrl->server_local->last_cache_nonce = cache_nonce;
    2333           0 :               cache_nonce = NULL;
    2334             :             }
    2335             :         }
    2336             :     }
    2337             :   else
    2338             :     {
    2339             :       /* Convert into a canonical S-expression and wrap that.  */
    2340           0 :       err = make_canon_sexp_pad (s_skey, 1, &key, &keylen);
    2341             :     }
    2342           0 :   if (err)
    2343           0 :     goto leave;
    2344           0 :   gcry_sexp_release (s_skey);
    2345           0 :   s_skey = NULL;
    2346             : 
    2347           0 :   err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
    2348             :                           GCRY_CIPHER_MODE_AESWRAP, 0);
    2349           0 :   if (err)
    2350           0 :     goto leave;
    2351           0 :   err = gcry_cipher_setkey (cipherhd,
    2352           0 :                             ctrl->server_local->export_key, KEYWRAP_KEYSIZE);
    2353           0 :   if (err)
    2354           0 :     goto leave;
    2355             : 
    2356           0 :   wrappedkeylen = keylen + 8;
    2357           0 :   wrappedkey = xtrymalloc (wrappedkeylen);
    2358           0 :   if (!wrappedkey)
    2359             :     {
    2360           0 :       err = gpg_error_from_syserror ();
    2361           0 :       goto leave;
    2362             :     }
    2363             : 
    2364           0 :   err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen, key, keylen);
    2365           0 :   if (err)
    2366           0 :     goto leave;
    2367           0 :   xfree (key);
    2368           0 :   key = NULL;
    2369           0 :   gcry_cipher_close (cipherhd);
    2370           0 :   cipherhd = NULL;
    2371             : 
    2372           0 :   assuan_begin_confidential (ctx);
    2373           0 :   err = assuan_send_data (ctx, wrappedkey, wrappedkeylen);
    2374           0 :   assuan_end_confidential (ctx);
    2375             : 
    2376             : 
    2377             :  leave:
    2378           0 :   xfree (cache_nonce);
    2379           0 :   xfree (passphrase);
    2380           0 :   xfree (wrappedkey);
    2381           0 :   gcry_cipher_close (cipherhd);
    2382           0 :   xfree (key);
    2383           0 :   gcry_sexp_release (s_skey);
    2384           0 :   xfree (ctrl->server_local->keydesc);
    2385           0 :   ctrl->server_local->keydesc = NULL;
    2386           0 :   xfree (shadow_info);
    2387             : 
    2388           0 :   return leave_cmd (ctx, err);
    2389             : }
    2390             : 
    2391             : 
    2392             : 
    2393             : static const char hlp_delete_key[] =
    2394             :   "DELETE_KEY [--force] <hexstring_with_keygrip>\n"
    2395             :   "\n"
    2396             :   "Delete a secret key from the key store.\n"
    2397             :   "Unless --force is used the agent asks the user for confirmation.\n";
    2398             : static gpg_error_t
    2399           0 : cmd_delete_key (assuan_context_t ctx, char *line)
    2400             : {
    2401           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2402             :   gpg_error_t err;
    2403             :   int force;
    2404             :   unsigned char grip[20];
    2405             : 
    2406           0 :   if (ctrl->restricted)
    2407           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2408             : 
    2409           0 :   force = has_option (line, "--force");
    2410           0 :   line = skip_options (line);
    2411             : 
    2412           0 :   err = parse_keygrip (ctx, line, grip);
    2413           0 :   if (err)
    2414           0 :     goto leave;
    2415             : 
    2416           0 :   err = agent_delete_key (ctrl, ctrl->server_local->keydesc, grip, force );
    2417           0 :   if (err)
    2418           0 :     goto leave;
    2419             : 
    2420             :  leave:
    2421           0 :   xfree (ctrl->server_local->keydesc);
    2422           0 :   ctrl->server_local->keydesc = NULL;
    2423             : 
    2424           0 :   return leave_cmd (ctx, err);
    2425             : }
    2426             : 
    2427             : 
    2428             : 
    2429             : static const char hlp_keytocard[] =
    2430             :   "KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
    2431             :   "\n";
    2432             : static gpg_error_t
    2433           0 : cmd_keytocard (assuan_context_t ctx, char *line)
    2434             : {
    2435           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2436             :   int force;
    2437           0 :   gpg_error_t err = 0;
    2438             :   unsigned char grip[20];
    2439           0 :   gcry_sexp_t s_skey = NULL;
    2440             :   unsigned char *keydata;
    2441             :   size_t keydatalen, timestamplen;
    2442             :   const char *serialno, *timestamp_str, *id;
    2443           0 :   unsigned char *shadow_info = NULL;
    2444             :   time_t timestamp;
    2445             : 
    2446           0 :   if (ctrl->restricted)
    2447           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2448             : 
    2449           0 :   force = has_option (line, "--force");
    2450           0 :   line = skip_options (line);
    2451             : 
    2452           0 :   err = parse_keygrip (ctx, line, grip);
    2453           0 :   if (err)
    2454           0 :     return err;
    2455             : 
    2456           0 :   if (agent_key_available (grip))
    2457           0 :     return gpg_error (GPG_ERR_NO_SECKEY);
    2458             : 
    2459           0 :   line += 40;
    2460           0 :   while (*line && (*line == ' ' || *line == '\t'))
    2461           0 :     line++;
    2462           0 :   serialno = line;
    2463           0 :   while (*line && (*line != ' ' && *line != '\t'))
    2464           0 :     line++;
    2465           0 :   if (!*line)
    2466           0 :     return gpg_error (GPG_ERR_MISSING_VALUE);
    2467           0 :   *line = '\0';
    2468           0 :   line++;
    2469           0 :   while (*line && (*line == ' ' || *line == '\t'))
    2470           0 :     line++;
    2471           0 :   id = line;
    2472           0 :   while (*line && (*line != ' ' && *line != '\t'))
    2473           0 :     line++;
    2474           0 :   if (!*line)
    2475           0 :     return gpg_error (GPG_ERR_MISSING_VALUE);
    2476           0 :   *line = '\0';
    2477           0 :   line++;
    2478           0 :   while (*line && (*line == ' ' || *line == '\t'))
    2479           0 :     line++;
    2480           0 :   timestamp_str = line;
    2481           0 :   while (*line && (*line != ' ' && *line != '\t'))
    2482           0 :     line++;
    2483           0 :   if (*line)
    2484           0 :     *line = '\0';
    2485           0 :   timestamplen = line - timestamp_str;
    2486           0 :   if (timestamplen != 15)
    2487           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    2488             : 
    2489           0 :   err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip,
    2490             :                              &shadow_info, CACHE_MODE_IGNORE, NULL,
    2491             :                              &s_skey, NULL);
    2492           0 :   if (err)
    2493             :     {
    2494           0 :       xfree (shadow_info);
    2495           0 :       return err;
    2496             :     }
    2497           0 :   if (shadow_info)
    2498             :     {
    2499             :       /* Key is on a smartcard already.  */
    2500           0 :       xfree (shadow_info);
    2501           0 :       gcry_sexp_release (s_skey);
    2502           0 :       return gpg_error (GPG_ERR_UNUSABLE_SECKEY);
    2503             :     }
    2504             : 
    2505           0 :   keydatalen =  gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
    2506           0 :   keydata = xtrymalloc_secure (keydatalen + 30);
    2507           0 :   if (keydata == NULL)
    2508             :     {
    2509           0 :       gcry_sexp_release (s_skey);
    2510           0 :       return gpg_error_from_syserror ();
    2511             :     }
    2512             : 
    2513           0 :   gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
    2514           0 :   gcry_sexp_release (s_skey);
    2515           0 :   keydatalen--;                 /* Decrement for last '\0'.  */
    2516             :   /* Add timestamp "created-at" in the private key */
    2517           0 :   timestamp = isotime2epoch (timestamp_str);
    2518           0 :   snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp);
    2519           0 :   keydatalen += 10 + 19 - 1;
    2520           0 :   err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
    2521           0 :   xfree (keydata);
    2522             : 
    2523           0 :   return leave_cmd (ctx, err);
    2524             : }
    2525             : 
    2526             : 
    2527             : 
    2528             : static const char hlp_getval[] =
    2529             :   "GETVAL <key>\n"
    2530             :   "\n"
    2531             :   "Return the value for KEY from the special environment as created by\n"
    2532             :   "PUTVAL.";
    2533             : static gpg_error_t
    2534           0 : cmd_getval (assuan_context_t ctx, char *line)
    2535             : {
    2536           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2537           0 :   int rc = 0;
    2538           0 :   char *key = NULL;
    2539             :   char *p;
    2540             :   struct putval_item_s *vl;
    2541             : 
    2542           0 :   if (ctrl->restricted)
    2543           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2544             : 
    2545           0 :   for (p=line; *p == ' '; p++)
    2546             :     ;
    2547           0 :   key = p;
    2548           0 :   p = strchr (key, ' ');
    2549           0 :   if (p)
    2550             :     {
    2551           0 :       *p++ = 0;
    2552           0 :       for (; *p == ' '; p++)
    2553             :         ;
    2554           0 :       if (*p)
    2555           0 :         return set_error (GPG_ERR_ASS_PARAMETER, "too many arguments");
    2556             :     }
    2557           0 :   if (!*key)
    2558           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
    2559             : 
    2560             : 
    2561           0 :   for (vl=putval_list; vl; vl = vl->next)
    2562           0 :     if ( !strcmp (vl->d, key) )
    2563           0 :       break;
    2564             : 
    2565           0 :   if (vl) /* Got an entry. */
    2566           0 :     rc = assuan_send_data (ctx, vl->d+vl->off, vl->len);
    2567             :   else
    2568           0 :     return gpg_error (GPG_ERR_NO_DATA);
    2569             : 
    2570           0 :   return leave_cmd (ctx, rc);
    2571             : }
    2572             : 
    2573             : 
    2574             : static const char hlp_putval[] =
    2575             :   "PUTVAL <key> [<percent_escaped_value>]\n"
    2576             :   "\n"
    2577             :   "The gpg-agent maintains a kind of environment which may be used to\n"
    2578             :   "store key/value pairs in it, so that they can be retrieved later.\n"
    2579             :   "This may be used by helper daemons to daemonize themself on\n"
    2580             :   "invocation and register them with gpg-agent.  Callers of the\n"
    2581             :   "daemon's service may now first try connect to get the information\n"
    2582             :   "for that service from gpg-agent through the GETVAL command and then\n"
    2583             :   "try to connect to that daemon.  Only if that fails they may start\n"
    2584             :   "an own instance of the service daemon. \n"
    2585             :   "\n"
    2586             :   "KEY is an an arbitrary symbol with the same syntax rules as keys\n"
    2587             :   "for shell environment variables.  PERCENT_ESCAPED_VALUE is the\n"
    2588             :   "corresponsing value; they should be similar to the values of\n"
    2589             :   "envronment variables but gpg-agent does not enforce any\n"
    2590             :   "restrictions.  If that value is not given any value under that KEY\n"
    2591             :   "is removed from this special environment.";
    2592             : static gpg_error_t
    2593           0 : cmd_putval (assuan_context_t ctx, char *line)
    2594             : {
    2595           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2596           0 :   int rc = 0;
    2597           0 :   char *key = NULL;
    2598           0 :   char *value = NULL;
    2599           0 :   size_t valuelen = 0;
    2600             :   char *p;
    2601             :   struct putval_item_s *vl, *vlprev;
    2602             : 
    2603           0 :   if (ctrl->restricted)
    2604           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2605             : 
    2606           0 :   for (p=line; *p == ' '; p++)
    2607             :     ;
    2608           0 :   key = p;
    2609           0 :   p = strchr (key, ' ');
    2610           0 :   if (p)
    2611             :     {
    2612           0 :       *p++ = 0;
    2613           0 :       for (; *p == ' '; p++)
    2614             :         ;
    2615           0 :       if (*p)
    2616             :         {
    2617           0 :           value = p;
    2618           0 :           p = strchr (value, ' ');
    2619           0 :           if (p)
    2620           0 :             *p = 0;
    2621           0 :           valuelen = percent_plus_unescape_inplace (value, 0);
    2622             :         }
    2623             :     }
    2624           0 :   if (!*key)
    2625           0 :     return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
    2626             : 
    2627             : 
    2628           0 :   for (vl=putval_list,vlprev=NULL; vl; vlprev=vl, vl = vl->next)
    2629           0 :     if ( !strcmp (vl->d, key) )
    2630           0 :       break;
    2631             : 
    2632           0 :   if (vl) /* Delete old entry. */
    2633             :     {
    2634           0 :       if (vlprev)
    2635           0 :         vlprev->next = vl->next;
    2636             :       else
    2637           0 :         putval_list = vl->next;
    2638           0 :       xfree (vl);
    2639             :     }
    2640             : 
    2641           0 :   if (valuelen) /* Add entry. */
    2642             :     {
    2643           0 :       vl = xtrymalloc (sizeof *vl + strlen (key) + valuelen);
    2644           0 :       if (!vl)
    2645           0 :         rc = gpg_error_from_syserror ();
    2646             :       else
    2647             :         {
    2648           0 :           vl->len = valuelen;
    2649           0 :           vl->off = strlen (key) + 1;
    2650           0 :           strcpy (vl->d, key);
    2651           0 :           memcpy (vl->d + vl->off, value, valuelen);
    2652           0 :           vl->next = putval_list;
    2653           0 :           putval_list = vl;
    2654             :         }
    2655             :     }
    2656             : 
    2657           0 :   return leave_cmd (ctx, rc);
    2658             : }
    2659             : 
    2660             : 
    2661             : 
    2662             : 
    2663             : static const char hlp_updatestartuptty[] =
    2664             :   "UPDATESTARTUPTTY\n"
    2665             :   "\n"
    2666             :   "Set startup TTY and X11 DISPLAY variables to the values of this\n"
    2667             :   "session.  This command is useful to pull future pinentries to\n"
    2668             :   "another screen.  It is only required because there is no way in the\n"
    2669             :   "ssh-agent protocol to convey this information.";
    2670             : static gpg_error_t
    2671           0 : cmd_updatestartuptty (assuan_context_t ctx, char *line)
    2672             : {
    2673             :   static const char *names[] =
    2674             :     { "GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
    2675           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2676           0 :   gpg_error_t err = 0;
    2677             :   session_env_t se;
    2678             :   int idx;
    2679           0 :   char *lc_ctype = NULL;
    2680           0 :   char *lc_messages = NULL;
    2681             : 
    2682             :   (void)line;
    2683             : 
    2684           0 :   if (ctrl->restricted)
    2685           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2686             : 
    2687           0 :   se = session_env_new ();
    2688           0 :   if (!se)
    2689           0 :     err = gpg_error_from_syserror ();
    2690             : 
    2691           0 :   for (idx=0; !err && names[idx]; idx++)
    2692             :     {
    2693           0 :       const char *value = session_env_getenv (ctrl->session_env, names[idx]);
    2694           0 :       if (value)
    2695           0 :         err = session_env_setenv (se, names[idx], value);
    2696             :     }
    2697             : 
    2698           0 :   if (!err && ctrl->lc_ctype)
    2699           0 :     if (!(lc_ctype = xtrystrdup (ctrl->lc_ctype)))
    2700           0 :       err = gpg_error_from_syserror ();
    2701             : 
    2702           0 :   if (!err && ctrl->lc_messages)
    2703           0 :     if (!(lc_messages = xtrystrdup (ctrl->lc_messages)))
    2704           0 :       err = gpg_error_from_syserror ();
    2705             : 
    2706           0 :   if (err)
    2707             :     {
    2708           0 :       session_env_release (se);
    2709           0 :       xfree (lc_ctype);
    2710           0 :       xfree (lc_messages);
    2711             :     }
    2712             :   else
    2713             :     {
    2714           0 :       session_env_release (opt.startup_env);
    2715           0 :       opt.startup_env = se;
    2716           0 :       xfree (opt.startup_lc_ctype);
    2717           0 :       opt.startup_lc_ctype = lc_ctype;
    2718           0 :       xfree (opt.startup_lc_messages);
    2719           0 :       opt.startup_lc_messages = lc_messages;
    2720             :     }
    2721             : 
    2722           0 :   return err;
    2723             : }
    2724             : 
    2725             : 
    2726             : 
    2727             : static const char hlp_killagent[] =
    2728             :   "KILLAGENT\n"
    2729             :   "\n"
    2730             :   "Stop the agent.";
    2731             : static gpg_error_t
    2732           1 : cmd_killagent (assuan_context_t ctx, char *line)
    2733             : {
    2734           1 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2735             : 
    2736             :   (void)line;
    2737             : 
    2738           1 :   if (ctrl->restricted)
    2739           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2740             : 
    2741           1 :   ctrl->server_local->stopme = 1;
    2742           1 :   assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
    2743           1 :   return 0;
    2744             : }
    2745             : 
    2746             : 
    2747             : static const char hlp_reloadagent[] =
    2748             :   "RELOADAGENT\n"
    2749             :   "\n"
    2750             :   "This command is an alternative to SIGHUP\n"
    2751             :   "to reload the configuration.";
    2752             : static gpg_error_t
    2753           0 : cmd_reloadagent (assuan_context_t ctx, char *line)
    2754             : {
    2755           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2756             : 
    2757             :   (void)line;
    2758             : 
    2759           0 :   if (ctrl->restricted)
    2760           0 :     return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
    2761             : 
    2762           0 :   agent_sighup_action ();
    2763           0 :   return 0;
    2764             : }
    2765             : 
    2766             : 
    2767             : 
    2768             : static const char hlp_getinfo[] =
    2769             :   "GETINFO <what>\n"
    2770             :   "\n"
    2771             :   "Multipurpose function to return a variety of information.\n"
    2772             :   "Supported values for WHAT are:\n"
    2773             :   "\n"
    2774             :   "  version     - Return the version of the program.\n"
    2775             :   "  pid         - Return the process id of the server.\n"
    2776             :   "  socket_name - Return the name of the socket.\n"
    2777             :   "  ssh_socket_name - Return the name of the ssh socket.\n"
    2778             :   "  scd_running - Return OK if the SCdaemon is already running.\n"
    2779             :   "  s2k_count   - Return the calibrated S2K count.\n"
    2780             :   "  std_env_names   - List the names of the standard environment.\n"
    2781             :   "  std_session_env - List the standard session environment.\n"
    2782             :   "  std_startup_env - List the standard startup environment.\n"
    2783             :   "  cmd_has_option\n"
    2784             :   "              - Returns OK if the command CMD implements the option OPT.\n"
    2785             :   "  restricted  - Returns OK if the connection is in restricted mode.\n";
    2786             : static gpg_error_t
    2787           0 : cmd_getinfo (assuan_context_t ctx, char *line)
    2788             : {
    2789           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2790           0 :   int rc = 0;
    2791             : 
    2792           0 :   if (!strcmp (line, "version"))
    2793             :     {
    2794           0 :       const char *s = VERSION;
    2795           0 :       rc = assuan_send_data (ctx, s, strlen (s));
    2796             :     }
    2797           0 :   else if (!strncmp (line, "cmd_has_option", 14)
    2798           0 :            && (line[14] == ' ' || line[14] == '\t' || !line[14]))
    2799           0 :     {
    2800             :       char *cmd, *cmdopt;
    2801           0 :       line += 14;
    2802           0 :       while (*line == ' ' || *line == '\t')
    2803           0 :         line++;
    2804           0 :       if (!*line)
    2805           0 :         rc = gpg_error (GPG_ERR_MISSING_VALUE);
    2806             :       else
    2807             :         {
    2808           0 :           cmd = line;
    2809           0 :           while (*line && (*line != ' ' && *line != '\t'))
    2810           0 :             line++;
    2811           0 :           if (!*line)
    2812           0 :             rc = gpg_error (GPG_ERR_MISSING_VALUE);
    2813             :           else
    2814             :             {
    2815           0 :               *line++ = 0;
    2816           0 :               while (*line == ' ' || *line == '\t')
    2817           0 :                 line++;
    2818           0 :               if (!*line)
    2819           0 :                 rc = gpg_error (GPG_ERR_MISSING_VALUE);
    2820             :               else
    2821             :                 {
    2822           0 :                   cmdopt = line;
    2823           0 :                   if (!command_has_option (cmd, cmdopt))
    2824           0 :                     rc = gpg_error (GPG_ERR_GENERAL);
    2825             :                 }
    2826             :             }
    2827             :         }
    2828             :     }
    2829           0 :   else if (!strcmp (line, "s2k_count"))
    2830             :     {
    2831             :       char numbuf[50];
    2832             : 
    2833           0 :       snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
    2834           0 :       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
    2835             :     }
    2836           0 :   else if (!strcmp (line, "restricted"))
    2837             :     {
    2838           0 :       rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_GENERAL);
    2839             :     }
    2840           0 :   else if (ctrl->restricted)
    2841             :     {
    2842           0 :       rc = gpg_error (GPG_ERR_FORBIDDEN);
    2843             :     }
    2844             :   /* All sub-commands below are not allowed in restricted mode.  */
    2845           0 :   else if (!strcmp (line, "pid"))
    2846             :     {
    2847             :       char numbuf[50];
    2848             : 
    2849           0 :       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
    2850           0 :       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
    2851             :     }
    2852           0 :   else if (!strcmp (line, "socket_name"))
    2853             :     {
    2854           0 :       const char *s = get_agent_socket_name ();
    2855             : 
    2856           0 :       if (s)
    2857           0 :         rc = assuan_send_data (ctx, s, strlen (s));
    2858             :       else
    2859           0 :         rc = gpg_error (GPG_ERR_NO_DATA);
    2860             :     }
    2861           0 :   else if (!strcmp (line, "ssh_socket_name"))
    2862             :     {
    2863           0 :       const char *s = get_agent_ssh_socket_name ();
    2864             : 
    2865           0 :       if (s)
    2866           0 :         rc = assuan_send_data (ctx, s, strlen (s));
    2867             :       else
    2868           0 :         rc = gpg_error (GPG_ERR_NO_DATA);
    2869             :     }
    2870           0 :   else if (!strcmp (line, "scd_running"))
    2871             :     {
    2872           0 :       rc = agent_scd_check_running ()? 0 : gpg_error (GPG_ERR_GENERAL);
    2873             :     }
    2874           0 :   else if (!strcmp (line, "std_env_names"))
    2875             :     {
    2876             :       int iterator;
    2877             :       const char *name;
    2878             : 
    2879           0 :       iterator = 0;
    2880           0 :       while ((name = session_env_list_stdenvnames (&iterator, NULL)))
    2881             :         {
    2882           0 :           rc = assuan_send_data (ctx, name, strlen (name)+1);
    2883           0 :           if (!rc)
    2884           0 :             rc = assuan_send_data (ctx, NULL, 0);
    2885           0 :           if (rc)
    2886           0 :             break;
    2887             :         }
    2888             :     }
    2889           0 :   else if (!strcmp (line, "std_session_env")
    2890           0 :            || !strcmp (line, "std_startup_env"))
    2891           0 :     {
    2892             :       int iterator;
    2893             :       const char *name, *value;
    2894             :       char *string;
    2895             : 
    2896           0 :       iterator = 0;
    2897           0 :       while ((name = session_env_list_stdenvnames (&iterator, NULL)))
    2898             :         {
    2899           0 :           value = session_env_getenv_or_default
    2900           0 :             (line[5] == 't'? opt.startup_env:ctrl->session_env, name, NULL);
    2901           0 :           if (value)
    2902             :             {
    2903           0 :               string = xtryasprintf ("%s=%s", name, value);
    2904           0 :               if (!string)
    2905           0 :                 rc = gpg_error_from_syserror ();
    2906             :               else
    2907             :                 {
    2908           0 :                   rc = assuan_send_data (ctx, string, strlen (string)+1);
    2909           0 :                   if (!rc)
    2910           0 :                     rc = assuan_send_data (ctx, NULL, 0);
    2911             :                 }
    2912           0 :               if (rc)
    2913           0 :                 break;
    2914             :             }
    2915             :         }
    2916             :     }
    2917             :   else
    2918           0 :     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
    2919           0 :   return rc;
    2920             : }
    2921             : 
    2922             : 
    2923             : 
    2924             : /* This function is called by Libassuan to parse the OPTION command.
    2925             :    It has been registered similar to the other Assuan commands.  */
    2926             : static gpg_error_t
    2927        2977 : option_handler (assuan_context_t ctx, const char *key, const char *value)
    2928             : {
    2929        2977 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    2930        2977 :   gpg_error_t err = 0;
    2931             : 
    2932        2977 :   if (!strcmp (key, "agent-awareness"))
    2933             :     {
    2934             :       /* The value is a version string telling us of which agent
    2935             :          version the caller is aware of.  */
    2936         782 :       ctrl->server_local->allow_fully_canceled =
    2937         391 :         gnupg_compare_version (value, "2.1.0");
    2938             :     }
    2939        2586 :   else if (ctrl->restricted)
    2940             :     {
    2941           0 :       err = gpg_error (GPG_ERR_FORBIDDEN);
    2942             :     }
    2943             :   /* All options below are not allowed in restricted mode.  */
    2944        2586 :   else if (!strcmp (key, "putenv"))
    2945             :     {
    2946             :       /* Change the session's environment to be used for the
    2947             :          Pinentry.  Valid values are:
    2948             :           <NAME>            Delete envvar NAME
    2949             :           <KEY>=            Set envvar NAME to the empty string
    2950             :           <KEY>=<VALUE>     Set envvar NAME to VALUE
    2951             :       */
    2952         393 :       err = session_env_putenv (ctrl->session_env, value);
    2953             :     }
    2954        2193 :   else if (!strcmp (key, "display"))
    2955             :     {
    2956         403 :       err = session_env_setenv (ctrl->session_env, "DISPLAY", value);
    2957             :     }
    2958        1790 :   else if (!strcmp (key, "ttyname"))
    2959             :     {
    2960         315 :       if (!opt.keep_tty)
    2961         315 :         err = session_env_setenv (ctrl->session_env, "GPG_TTY", value);
    2962             :     }
    2963        1475 :   else if (!strcmp (key, "ttytype"))
    2964             :     {
    2965         403 :       if (!opt.keep_tty)
    2966         403 :         err = session_env_setenv (ctrl->session_env, "TERM", value);
    2967             :     }
    2968        1072 :   else if (!strcmp (key, "lc-ctype"))
    2969             :     {
    2970         315 :       if (ctrl->lc_ctype)
    2971           0 :         xfree (ctrl->lc_ctype);
    2972         315 :       ctrl->lc_ctype = xtrystrdup (value);
    2973         315 :       if (!ctrl->lc_ctype)
    2974           0 :         return out_of_core ();
    2975             :     }
    2976         757 :   else if (!strcmp (key, "lc-messages"))
    2977             :     {
    2978         315 :       if (ctrl->lc_messages)
    2979           0 :         xfree (ctrl->lc_messages);
    2980         315 :       ctrl->lc_messages = xtrystrdup (value);
    2981         315 :       if (!ctrl->lc_messages)
    2982           0 :         return out_of_core ();
    2983             :     }
    2984         442 :   else if (!strcmp (key, "xauthority"))
    2985             :     {
    2986           0 :       err = session_env_setenv (ctrl->session_env, "XAUTHORITY", value);
    2987             :     }
    2988         442 :   else if (!strcmp (key, "pinentry-user-data"))
    2989             :     {
    2990          51 :       err = session_env_setenv (ctrl->session_env, "PINENTRY_USER_DATA", value);
    2991             :     }
    2992         391 :   else if (!strcmp (key, "use-cache-for-signing"))
    2993           0 :     ctrl->server_local->use_cache_for_signing = *value? atoi (value) : 0;
    2994         391 :   else if (!strcmp (key, "allow-pinentry-notify"))
    2995         391 :     ctrl->server_local->allow_pinentry_notify = 1;
    2996           0 :   else if (!strcmp (key, "pinentry-mode"))
    2997             :     {
    2998           0 :       int tmp = parse_pinentry_mode (value);
    2999           0 :       if (tmp == -1)
    3000           0 :         err = gpg_error (GPG_ERR_INV_VALUE);
    3001           0 :       else if (tmp == PINENTRY_MODE_LOOPBACK && !opt.allow_loopback_pinentry)
    3002           0 :         err = gpg_error (GPG_ERR_NOT_SUPPORTED);
    3003             :       else
    3004           0 :         ctrl->pinentry_mode = tmp;
    3005             :     }
    3006           0 :   else if (!strcmp (key, "cache-ttl-opt-preset"))
    3007             :     {
    3008           0 :       ctrl->cache_ttl_opt_preset = *value? atoi (value) : 0;
    3009             :     }
    3010           0 :   else if (!strcmp (key, "s2k-count"))
    3011             :     {
    3012           0 :       ctrl->s2k_count = *value? strtoul(value, NULL, 10) : 0;
    3013           0 :       if (ctrl->s2k_count && ctrl->s2k_count < 65536)
    3014             :         {
    3015           0 :           ctrl->s2k_count = 0;
    3016             :         }
    3017             :     }
    3018             :   else
    3019           0 :     err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
    3020             : 
    3021        2977 :   return err;
    3022             : }
    3023             : 
    3024             : 
    3025             : 
    3026             : 
    3027             : /* Called by libassuan after all commands. ERR is the error from the
    3028             :    last assuan operation and not the one returned from the command. */
    3029             : static void
    3030        6352 : post_cmd_notify (assuan_context_t ctx, gpg_error_t err)
    3031             : {
    3032        6352 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    3033             : 
    3034             :   (void)err;
    3035             : 
    3036             :   /* Switch off any I/O monitor controlled logging pausing. */
    3037        6352 :   ctrl->server_local->pause_io_logging = 0;
    3038        6352 : }
    3039             : 
    3040             : 
    3041             : /* This function is called by libassuan for all I/O.  We use it here
    3042             :    to disable logging for the GETEVENTCOUNTER commands.  This is so
    3043             :    that the debug output won't get cluttered by this primitive
    3044             :    command.  */
    3045             : static unsigned int
    3046       20904 : io_monitor (assuan_context_t ctx, void *hook, int direction,
    3047             :             const char *line, size_t linelen)
    3048             : {
    3049       20904 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    3050             : 
    3051             :   (void) hook;
    3052             : 
    3053             :   /* Note that we only check for the uppercase name.  This allows to
    3054             :      see the logging for debugging if using a non-upercase command
    3055             :      name. */
    3056       20904 :   if (ctx && direction == ASSUAN_IO_FROM_PEER
    3057        6890 :       && linelen >= 15
    3058        5088 :       && !strncmp (line, "GETEVENTCOUNTER", 15)
    3059           0 :       && (linelen == 15 || spacep (line+15)))
    3060             :     {
    3061           0 :       ctrl->server_local->pause_io_logging = 1;
    3062             :     }
    3063             : 
    3064       20904 :   return ctrl->server_local->pause_io_logging? ASSUAN_IO_MONITOR_NOLOG : 0;
    3065             : }
    3066             : 
    3067             : 
    3068             : /* Return true if the command CMD implements the option OPT.  */
    3069             : static int
    3070           0 : command_has_option (const char *cmd, const char *cmdopt)
    3071             : {
    3072           0 :   if (!strcmp (cmd, "GET_PASSPHRASE"))
    3073             :     {
    3074           0 :       if (!strcmp (cmdopt, "repeat"))
    3075           0 :           return 1;
    3076             :     }
    3077             : 
    3078           0 :   return 0;
    3079             : }
    3080             : 
    3081             : 
    3082             : /* Tell Libassuan about our commands.  Also register the other Assuan
    3083             :    handlers. */
    3084             : static int
    3085         404 : register_commands (assuan_context_t ctx)
    3086             : {
    3087             :   static struct {
    3088             :     const char *name;
    3089             :     assuan_handler_t handler;
    3090             :     const char * const help;
    3091             :   } table[] = {
    3092             :     { "GETEVENTCOUNTER",cmd_geteventcounter, hlp_geteventcounter },
    3093             :     { "ISTRUSTED",      cmd_istrusted, hlp_istrusted },
    3094             :     { "HAVEKEY",        cmd_havekey,   hlp_havekey },
    3095             :     { "KEYINFO",        cmd_keyinfo,   hlp_keyinfo },
    3096             :     { "SIGKEY",         cmd_sigkey,    hlp_sigkey },
    3097             :     { "SETKEY",         cmd_sigkey,    hlp_sigkey },
    3098             :     { "SETKEYDESC",     cmd_setkeydesc,hlp_setkeydesc },
    3099             :     { "SETHASH",        cmd_sethash,   hlp_sethash },
    3100             :     { "PKSIGN",         cmd_pksign,    hlp_pksign },
    3101             :     { "PKDECRYPT",      cmd_pkdecrypt, hlp_pkdecrypt },
    3102             :     { "GENKEY",         cmd_genkey,    hlp_genkey },
    3103             :     { "READKEY",        cmd_readkey,   hlp_readkey },
    3104             :     { "GET_PASSPHRASE", cmd_get_passphrase, hlp_get_passphrase },
    3105             :     { "PRESET_PASSPHRASE", cmd_preset_passphrase, hlp_preset_passphrase },
    3106             :     { "CLEAR_PASSPHRASE", cmd_clear_passphrase,   hlp_clear_passphrase },
    3107             :     { "GET_CONFIRMATION", cmd_get_confirmation,   hlp_get_confirmation },
    3108             :     { "LISTTRUSTED",    cmd_listtrusted, hlp_listtrusted },
    3109             :     { "MARKTRUSTED",    cmd_marktrusted, hlp_martrusted },
    3110             :     { "LEARN",          cmd_learn,     hlp_learn },
    3111             :     { "PASSWD",         cmd_passwd,    hlp_passwd },
    3112             :     { "INPUT",          NULL },
    3113             :     { "OUTPUT",         NULL },
    3114             :     { "SCD",            cmd_scd,       hlp_scd },
    3115             :     { "KEYWRAP_KEY",    cmd_keywrap_key, hlp_keywrap_key },
    3116             :     { "IMPORT_KEY",     cmd_import_key, hlp_import_key },
    3117             :     { "EXPORT_KEY",     cmd_export_key, hlp_export_key },
    3118             :     { "DELETE_KEY",     cmd_delete_key, hlp_delete_key },
    3119             :     { "GETVAL",         cmd_getval,    hlp_getval },
    3120             :     { "PUTVAL",         cmd_putval,    hlp_putval },
    3121             :     { "UPDATESTARTUPTTY",  cmd_updatestartuptty, hlp_updatestartuptty },
    3122             :     { "KILLAGENT",      cmd_killagent,  hlp_killagent },
    3123             :     { "RELOADAGENT",    cmd_reloadagent,hlp_reloadagent },
    3124             :     { "GETINFO",        cmd_getinfo,   hlp_getinfo },
    3125             :     { "KEYTOCARD",      cmd_keytocard, hlp_keytocard },
    3126             :     { NULL }
    3127             :   };
    3128             :   int i, rc;
    3129             : 
    3130       14140 :   for (i=0; table[i].name; i++)
    3131             :     {
    3132       13736 :       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
    3133             :                                     table[i].help);
    3134       13736 :       if (rc)
    3135           0 :         return rc;
    3136             :     }
    3137         404 :   assuan_register_post_cmd_notify (ctx, post_cmd_notify);
    3138         404 :   assuan_register_reset_notify (ctx, reset_notify);
    3139         404 :   assuan_register_option_handler (ctx, option_handler);
    3140         404 :   return 0;
    3141             : }
    3142             : 
    3143             : 
    3144             : /* Startup the server.  If LISTEN_FD and FD is given as -1, this is a
    3145             :    simple piper server, otherwise it is a regular server.  CTRL is the
    3146             :    control structure for this connection; it has only the basic
    3147             :    intialization. */
    3148             : void
    3149         404 : start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
    3150             : {
    3151             :   int rc;
    3152         404 :   assuan_context_t ctx = NULL;
    3153             : 
    3154         404 :   if (ctrl->restricted)
    3155             :     {
    3156           0 :       if (agent_copy_startup_env (ctrl))
    3157         403 :         return;
    3158             :     }
    3159             : 
    3160         404 :   rc = assuan_new (&ctx);
    3161         404 :   if (rc)
    3162             :     {
    3163           0 :       log_error ("failed to allocate assuan context: %s\n", gpg_strerror (rc));
    3164           0 :       agent_exit (2);
    3165             :     }
    3166             : 
    3167         404 :   if (listen_fd == GNUPG_INVALID_FD && fd == GNUPG_INVALID_FD)
    3168           0 :     {
    3169             :       assuan_fd_t filedes[2];
    3170             : 
    3171           0 :       filedes[0] = assuan_fdopen (0);
    3172           0 :       filedes[1] = assuan_fdopen (1);
    3173           0 :       rc = assuan_init_pipe_server (ctx, filedes);
    3174             :     }
    3175         404 :   else if (listen_fd != GNUPG_INVALID_FD)
    3176             :     {
    3177           0 :       rc = assuan_init_socket_server (ctx, listen_fd, 0);
    3178             :       /* FIXME: Need to call assuan_sock_set_nonce for Windows.  But
    3179             :          this branch is currently not used.  */
    3180             :     }
    3181             :   else
    3182             :     {
    3183         404 :       rc = assuan_init_socket_server (ctx, fd, ASSUAN_SOCKET_SERVER_ACCEPTED);
    3184             :     }
    3185         404 :   if (rc)
    3186             :     {
    3187           0 :       log_error ("failed to initialize the server: %s\n",
    3188             :                  gpg_strerror(rc));
    3189           0 :       agent_exit (2);
    3190             :     }
    3191         404 :   rc = register_commands (ctx);
    3192         404 :   if (rc)
    3193             :     {
    3194           0 :       log_error ("failed to register commands with Assuan: %s\n",
    3195             :                  gpg_strerror(rc));
    3196           0 :       agent_exit (2);
    3197             :     }
    3198             : 
    3199         404 :   assuan_set_pointer (ctx, ctrl);
    3200         404 :   ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
    3201         404 :   ctrl->server_local->assuan_ctx = ctx;
    3202         404 :   ctrl->server_local->use_cache_for_signing = 1;
    3203         404 :   ctrl->digest.raw_value = 0;
    3204             : 
    3205         404 :   assuan_set_io_monitor (ctx, io_monitor, NULL);
    3206             : 
    3207             :   for (;;)
    3208             :     {
    3209         808 :       rc = assuan_accept (ctx);
    3210         808 :       if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
    3211             :         {
    3212             :           break;
    3213             :         }
    3214         404 :       else if (rc)
    3215             :         {
    3216           0 :           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
    3217           0 :           break;
    3218             :         }
    3219             : 
    3220         404 :       rc = assuan_process (ctx);
    3221         404 :       if (rc)
    3222             :         {
    3223           0 :           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
    3224           0 :           continue;
    3225             :         }
    3226         404 :     }
    3227             : 
    3228             :   /* Reset the nonce caches.  */
    3229         404 :   clear_nonce_cache (ctrl);
    3230             : 
    3231             :   /* Reset the SCD if needed. */
    3232         404 :   agent_reset_scd (ctrl);
    3233             : 
    3234             :   /* Reset the pinentry (in case of popup messages). */
    3235         404 :   agent_reset_query (ctrl);
    3236             : 
    3237             :   /* Cleanup.  */
    3238         404 :   assuan_release (ctx);
    3239         404 :   xfree (ctrl->server_local->keydesc);
    3240         404 :   xfree (ctrl->server_local->import_key);
    3241         404 :   xfree (ctrl->server_local->export_key);
    3242         404 :   if (ctrl->server_local->stopme)
    3243           1 :     agent_exit (0);
    3244         403 :   xfree (ctrl->server_local);
    3245         403 :   ctrl->server_local = NULL;
    3246             : }
    3247             : 
    3248             : 
    3249             : /* Helper for the pinentry loopback mode.  It merely passes the
    3250             :    parameters on to the client.  */
    3251             : gpg_error_t
    3252           0 : pinentry_loopback(ctrl_t ctrl, const char *keyword,
    3253             :                   unsigned char **buffer, size_t *size,
    3254             :                   size_t max_length)
    3255             : {
    3256             :   gpg_error_t rc;
    3257           0 :   assuan_context_t ctx = ctrl->server_local->assuan_ctx;
    3258             : 
    3259           0 :   rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%zu", max_length);
    3260           0 :   if (rc)
    3261           0 :     return rc;
    3262             : 
    3263           0 :   assuan_begin_confidential (ctx);
    3264           0 :   rc = assuan_inquire (ctx, keyword, buffer, size, max_length);
    3265           0 :   assuan_end_confidential (ctx);
    3266           0 :   return rc;
    3267             : }

Generated by: LCOV version 1.11