LCOV - code coverage report
Current view: top level - agent - command.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 629 1449 43.4 %
Date: 2016-09-12 12:29:17 Functions: 34 54 63.0 %

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

Generated by: LCOV version 1.11