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

Generated by: LCOV version 1.11