LCOV - code coverage report
Current view: top level - sm - server.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 8 626 1.3 %
Date: 2015-11-05 17:10:59 Functions: 2 37 5.4 %

          Line data    Source code
       1             : /* server.c - Server mode and main entry point
       2             :  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
       3             :  *               2010 Free Software Foundation, Inc.
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 3 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * GnuPG is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :  * GNU General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License
      18             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      19             :  */
      20             : 
      21             : #include <config.h>
      22             : #include <errno.h>
      23             : #include <stdio.h>
      24             : #include <stdlib.h>
      25             : #include <string.h>
      26             : #include <stdarg.h>
      27             : #include <ctype.h>
      28             : #include <unistd.h>
      29             : 
      30             : #include "gpgsm.h"
      31             : #include <assuan.h>
      32             : #include "sysutils.h"
      33             : 
      34             : #define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
      35             : 
      36             : 
      37             : /* The filepointer for status message used in non-server mode */
      38             : static FILE *statusfp;
      39             : 
      40             : /* Data used to assuciate an Assuan context with local server data */
      41             : struct server_local_s {
      42             :   assuan_context_t assuan_ctx;
      43             :   int message_fd;
      44             :   int list_internal;
      45             :   int list_external;
      46             :   int list_to_output;           /* Write keylistings to the output fd. */
      47             :   int enable_audit_log;         /* Use an audit log.  */
      48             :   certlist_t recplist;
      49             :   certlist_t signerlist;
      50             :   certlist_t default_recplist; /* As set by main() - don't release. */
      51             :   int allow_pinentry_notify;   /* Set if pinentry notifications should
      52             :                                   be passed back to the client. */
      53             :   int no_encrypt_to;           /* Local version of option.  */
      54             : };
      55             : 
      56             : 
      57             : /* Cookie definition for assuan data line output.  */
      58             : static ssize_t data_line_cookie_write (void *cookie,
      59             :                                        const void *buffer, size_t size);
      60             : static int data_line_cookie_close (void *cookie);
      61             : static es_cookie_io_functions_t data_line_cookie_functions =
      62             :   {
      63             :     NULL,
      64             :     data_line_cookie_write,
      65             :     NULL,
      66             :     data_line_cookie_close
      67             :   };
      68             : 
      69             : 
      70             : 
      71             : static int command_has_option (const char *cmd, const char *cmdopt);
      72             : 
      73             : 
      74             : 
      75             : 
      76             : /* Note that it is sufficient to allocate the target string D as
      77             :    long as the source string S, i.e.: strlen(s)+1; */
      78             : static void
      79           0 : strcpy_escaped_plus (char *d, const char *s)
      80             : {
      81           0 :   while (*s)
      82             :     {
      83           0 :       if (*s == '%' && s[1] && s[2])
      84             :         {
      85           0 :           s++;
      86           0 :           *d++ = xtoi_2 (s);
      87           0 :           s += 2;
      88             :         }
      89           0 :       else if (*s == '+')
      90           0 :         *d++ = ' ', s++;
      91             :       else
      92           0 :         *d++ = *s++;
      93             :     }
      94           0 :   *d = 0;
      95           0 : }
      96             : 
      97             : 
      98             : /* Skip over options.
      99             :    Blanks after the options are also removed. */
     100             : static char *
     101           0 : skip_options (const char *line)
     102             : {
     103           0 :   while (spacep (line))
     104           0 :     line++;
     105           0 :   while ( *line == '-' && line[1] == '-' )
     106             :     {
     107           0 :       while (*line && !spacep (line))
     108           0 :         line++;
     109           0 :       while (spacep (line))
     110           0 :         line++;
     111             :     }
     112           0 :   return (char*)line;
     113             : }
     114             : 
     115             : 
     116             : /* Check whether the option NAME appears in LINE */
     117             : static int
     118           0 : has_option (const char *line, const char *name)
     119             : {
     120             :   const char *s;
     121           0 :   int n = strlen (name);
     122             : 
     123           0 :   s = strstr (line, name);
     124           0 :   if (s && s >= skip_options (line))
     125           0 :     return 0;
     126           0 :   return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
     127             : }
     128             : 
     129             : 
     130             : /* A write handler used by es_fopencookie to write assuan data
     131             :    lines.  */
     132             : static ssize_t
     133           0 : data_line_cookie_write (void *cookie, const void *buffer, size_t size)
     134             : {
     135           0 :   assuan_context_t ctx = cookie;
     136             : 
     137           0 :   if (assuan_send_data (ctx, buffer, size))
     138             :     {
     139           0 :       gpg_err_set_errno (EIO);
     140           0 :       return -1;
     141             :     }
     142             : 
     143           0 :   return size;
     144             : }
     145             : 
     146             : static int
     147           0 : data_line_cookie_close (void *cookie)
     148             : {
     149           0 :   assuan_context_t ctx = cookie;
     150             : 
     151           0 :   if (assuan_send_data (ctx, NULL, 0))
     152             :     {
     153           0 :       gpg_err_set_errno (EIO);
     154           0 :       return -1;
     155             :     }
     156             : 
     157           0 :   return 0;
     158             : }
     159             : 
     160             : 
     161             : static void
     162           0 : close_message_fd (ctrl_t ctrl)
     163             : {
     164           0 :   if (ctrl->server_local->message_fd != -1)
     165             :     {
     166             : #ifdef HAVE_W32CE_SYSTEM
     167             : #warning Is this correct for W32/W32CE?
     168             : #endif
     169           0 :       close (ctrl->server_local->message_fd);
     170           0 :       ctrl->server_local->message_fd = -1;
     171             :     }
     172           0 : }
     173             : 
     174             : 
     175             : /* Start a new audit session if this has been enabled.  */
     176             : static gpg_error_t
     177           0 : start_audit_session (ctrl_t ctrl)
     178             : {
     179           0 :   audit_release (ctrl->audit);
     180           0 :   ctrl->audit = NULL;
     181           0 :   if (ctrl->server_local->enable_audit_log && !(ctrl->audit = audit_new ()) )
     182           0 :     return gpg_error_from_syserror ();
     183             : 
     184           0 :   return 0;
     185             : }
     186             : 
     187             : 
     188             : static gpg_error_t
     189           0 : option_handler (assuan_context_t ctx, const char *key, const char *value)
     190             : {
     191           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     192           0 :   gpg_error_t err = 0;
     193             : 
     194           0 :   if (!strcmp (key, "putenv"))
     195             :     {
     196             :       /* Change the session's environment to be used for the
     197             :          Pinentry.  Valid values are:
     198             :           <NAME>            Delete envvar NAME
     199             :           <KEY>=            Set envvar NAME to the empty string
     200             :           <KEY>=<VALUE>     Set envvar NAME to VALUE
     201             :       */
     202           0 :       err = session_env_putenv (opt.session_env, value);
     203             :     }
     204           0 :   else if (!strcmp (key, "display"))
     205             :     {
     206           0 :       err = session_env_setenv (opt.session_env, "DISPLAY", value);
     207             :     }
     208           0 :   else if (!strcmp (key, "ttyname"))
     209             :     {
     210           0 :       err = session_env_setenv (opt.session_env, "GPG_TTY", value);
     211             :     }
     212           0 :   else if (!strcmp (key, "ttytype"))
     213             :     {
     214           0 :       err = session_env_setenv (opt.session_env, "TERM", value);
     215             :     }
     216           0 :   else if (!strcmp (key, "lc-ctype"))
     217             :     {
     218           0 :       xfree (opt.lc_ctype);
     219           0 :       opt.lc_ctype = xtrystrdup (value);
     220           0 :       if (!opt.lc_ctype)
     221           0 :         err = gpg_error_from_syserror ();
     222             :     }
     223           0 :   else if (!strcmp (key, "lc-messages"))
     224             :     {
     225           0 :       xfree (opt.lc_messages);
     226           0 :       opt.lc_messages = xtrystrdup (value);
     227           0 :       if (!opt.lc_messages)
     228           0 :         err = gpg_error_from_syserror ();
     229             :     }
     230           0 :   else if (!strcmp (key, "xauthority"))
     231             :     {
     232           0 :       err = session_env_setenv (opt.session_env, "XAUTHORITY", value);
     233             :     }
     234           0 :   else if (!strcmp (key, "pinentry-user-data"))
     235             :     {
     236           0 :       err = session_env_setenv (opt.session_env, "PINENTRY_USER_DATA", value);
     237             :     }
     238           0 :   else if (!strcmp (key, "include-certs"))
     239             :     {
     240           0 :       int i = *value? atoi (value) : -1;
     241           0 :       if (ctrl->include_certs < -2)
     242           0 :         err = gpg_error (GPG_ERR_ASS_PARAMETER);
     243             :       else
     244           0 :         ctrl->include_certs = i;
     245             :     }
     246           0 :   else if (!strcmp (key, "list-mode"))
     247             :     {
     248           0 :       int i = *value? atoi (value) : 0;
     249           0 :       if (!i || i == 1) /* default and mode 1 */
     250             :         {
     251           0 :           ctrl->server_local->list_internal = 1;
     252           0 :           ctrl->server_local->list_external = 0;
     253             :         }
     254           0 :       else if (i == 2)
     255             :         {
     256           0 :           ctrl->server_local->list_internal = 0;
     257           0 :           ctrl->server_local->list_external = 1;
     258             :         }
     259           0 :       else if (i == 3)
     260             :         {
     261           0 :           ctrl->server_local->list_internal = 1;
     262           0 :           ctrl->server_local->list_external = 1;
     263             :         }
     264             :       else
     265           0 :         err = gpg_error (GPG_ERR_ASS_PARAMETER);
     266             :     }
     267           0 :   else if (!strcmp (key, "list-to-output"))
     268             :     {
     269           0 :       int i = *value? atoi (value) : 0;
     270           0 :       ctrl->server_local->list_to_output = i;
     271             :     }
     272           0 :   else if (!strcmp (key, "with-validation"))
     273             :     {
     274           0 :       int i = *value? atoi (value) : 0;
     275           0 :       ctrl->with_validation = i;
     276             :     }
     277           0 :   else if (!strcmp (key, "with-secret"))
     278             :     {
     279           0 :       int i = *value? atoi (value) : 0;
     280           0 :       ctrl->with_secret = i;
     281             :     }
     282           0 :   else if (!strcmp (key, "validation-model"))
     283             :     {
     284           0 :       int i = gpgsm_parse_validation_model (value);
     285           0 :       if ( i >= 0 && i <= 2 )
     286           0 :         ctrl->validation_model = i;
     287             :       else
     288           0 :         err = gpg_error (GPG_ERR_ASS_PARAMETER);
     289             :     }
     290           0 :   else if (!strcmp (key, "with-key-data"))
     291             :     {
     292           0 :       opt.with_key_data = 1;
     293             :     }
     294           0 :   else if (!strcmp (key, "enable-audit-log"))
     295             :     {
     296           0 :       int i = *value? atoi (value) : 0;
     297           0 :       ctrl->server_local->enable_audit_log = i;
     298             :     }
     299           0 :   else if (!strcmp (key, "allow-pinentry-notify"))
     300             :     {
     301           0 :       ctrl->server_local->allow_pinentry_notify = 1;
     302             :     }
     303           0 :   else if (!strcmp (key, "with-ephemeral-keys"))
     304             :     {
     305           0 :       int i = *value? atoi (value) : 0;
     306           0 :       ctrl->with_ephemeral_keys = i;
     307             :     }
     308           0 :   else if (!strcmp (key, "no-encrypt-to"))
     309             :     {
     310           0 :       ctrl->server_local->no_encrypt_to = 1;
     311             :     }
     312           0 :   else if (!strcmp (key, "offline"))
     313             :     {
     314             :       /* We ignore this option if gpgsm has been started with
     315             :          --disable-dirmngr (which also sets offline).  */
     316           0 :       if (!opt.disable_dirmngr)
     317             :         {
     318           0 :           int i = *value? !!atoi (value) : 1;
     319           0 :           ctrl->offline = i;
     320             :         }
     321             :     }
     322             :   else
     323           0 :     err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
     324             : 
     325           0 :   return err;
     326             : }
     327             : 
     328             : 
     329             : static gpg_error_t
     330           0 : reset_notify (assuan_context_t ctx, char *line)
     331             : {
     332           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     333             : 
     334             :   (void) line;
     335             : 
     336           0 :   gpgsm_release_certlist (ctrl->server_local->recplist);
     337           0 :   gpgsm_release_certlist (ctrl->server_local->signerlist);
     338           0 :   ctrl->server_local->recplist = NULL;
     339           0 :   ctrl->server_local->signerlist = NULL;
     340           0 :   close_message_fd (ctrl);
     341           0 :   assuan_close_input_fd (ctx);
     342           0 :   assuan_close_output_fd (ctx);
     343           0 :   return 0;
     344             : }
     345             : 
     346             : 
     347             : static gpg_error_t
     348           0 : input_notify (assuan_context_t ctx, char *line)
     349             : {
     350           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     351             : 
     352           0 :   ctrl->autodetect_encoding = 0;
     353           0 :   ctrl->is_pem = 0;
     354           0 :   ctrl->is_base64 = 0;
     355           0 :   if (strstr (line, "--armor"))
     356           0 :     ctrl->is_pem = 1;
     357           0 :   else if (strstr (line, "--base64"))
     358           0 :     ctrl->is_base64 = 1;
     359           0 :   else if (strstr (line, "--binary"))
     360             :     ;
     361             :   else
     362           0 :     ctrl->autodetect_encoding = 1;
     363           0 :   return 0;
     364             : }
     365             : 
     366             : static gpg_error_t
     367           0 : output_notify (assuan_context_t ctx, char *line)
     368             : {
     369           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     370             : 
     371           0 :   ctrl->create_pem = 0;
     372           0 :   ctrl->create_base64 = 0;
     373           0 :   if (strstr (line, "--armor"))
     374           0 :     ctrl->create_pem = 1;
     375           0 :   else if (strstr (line, "--base64"))
     376           0 :     ctrl->create_base64 = 1; /* just the raw output */
     377           0 :   return 0;
     378             : }
     379             : 
     380             : 
     381             : static const char hlp_recipient[] =
     382             :   "RECIPIENT <userID>\n"
     383             :   "\n"
     384             :   "Set the recipient for the encryption.  USERID shall be the\n"
     385             :   "internal representation of the key; the server may accept any other\n"
     386             :   "way of specification [we will support this].  If this is a valid and\n"
     387             :   "trusted recipient the server does respond with OK, otherwise the\n"
     388             :   "return is an ERR with the reason why the recipient can't be used,\n"
     389             :   "the encryption will then not be done for this recipient.  If the\n"
     390             :   "policy is not to encrypt at all if not all recipients are valid, the\n"
     391             :   "client has to take care of this.  All RECIPIENT commands are\n"
     392             :   "cumulative until a RESET or an successful ENCRYPT command.";
     393             : static gpg_error_t
     394           0 : cmd_recipient (assuan_context_t ctx, char *line)
     395             : {
     396           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     397             :   int rc;
     398             : 
     399           0 :   if (!ctrl->audit)
     400           0 :     rc = start_audit_session (ctrl);
     401             :   else
     402           0 :     rc = 0;
     403             : 
     404           0 :   if (!rc)
     405           0 :     rc = gpgsm_add_to_certlist (ctrl, line, 0,
     406           0 :                                 &ctrl->server_local->recplist, 0);
     407           0 :   if (rc)
     408             :     {
     409           0 :       gpgsm_status2 (ctrl, STATUS_INV_RECP,
     410             :                      get_inv_recpsgnr_code (rc), line, NULL);
     411             :     }
     412             : 
     413           0 :   return rc;
     414             : }
     415             : 
     416             : 
     417             : static const char hlp_signer[] =
     418             :   "SIGNER <userID>\n"
     419             :   "\n"
     420             :   "Set the signer's keys for the signature creation.  USERID should\n"
     421             :   "be the internal representation of the key; the server may accept any\n"
     422             :   "other way of specification [we will support this].  If this is a\n"
     423             :   "valid and usable signing key the server does respond with OK,\n"
     424             :   "otherwise it returns an ERR with the reason why the key can't be\n"
     425             :   "used, the signing will then not be done for this key.  If the policy\n"
     426             :   "is not to sign at all if not all signer keys are valid, the client\n"
     427             :   "has to take care of this.  All SIGNER commands are cumulative until\n"
     428             :   "a RESET but they are *not* reset by an SIGN command becuase it can\n"
     429             :   "be expected that set of signers are used for more than one sign\n"
     430             :   "operation.";
     431             : static gpg_error_t
     432           0 : cmd_signer (assuan_context_t ctx, char *line)
     433             : {
     434           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     435             :   int rc;
     436             : 
     437           0 :   rc = gpgsm_add_to_certlist (ctrl, line, 1,
     438           0 :                               &ctrl->server_local->signerlist, 0);
     439           0 :   if (rc)
     440             :     {
     441           0 :       gpgsm_status2 (ctrl, STATUS_INV_SGNR,
     442             :                      get_inv_recpsgnr_code (rc), line, NULL);
     443             :       /* For compatibiliy reasons we also issue the old code after the
     444             :          new one.  */
     445           0 :       gpgsm_status2 (ctrl, STATUS_INV_RECP,
     446             :                      get_inv_recpsgnr_code (rc), line, NULL);
     447             :     }
     448           0 :   return rc;
     449             : }
     450             : 
     451             : 
     452             : static const char hlp_encrypt[] =
     453             :   "ENCRYPT \n"
     454             :   "\n"
     455             :   "Do the actual encryption process. Takes the plaintext from the INPUT\n"
     456             :   "command, writes to the ciphertext to the file descriptor set with\n"
     457             :   "the OUTPUT command, take the recipients form all the recipients set\n"
     458             :   "so far.  If this command fails the clients should try to delete all\n"
     459             :   "output currently done or otherwise mark it as invalid.  GPGSM does\n"
     460             :   "ensure that there won't be any security problem with leftover data\n"
     461             :   "on the output in this case.\n"
     462             :   "\n"
     463             :   "This command should in general not fail, as all necessary checks\n"
     464             :   "have been done while setting the recipients.  The input and output\n"
     465             :   "pipes are closed.";
     466             : static gpg_error_t
     467           0 : cmd_encrypt (assuan_context_t ctx, char *line)
     468             : {
     469           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     470             :   certlist_t cl;
     471             :   int inp_fd, out_fd;
     472             :   estream_t out_fp;
     473             :   int rc;
     474             : 
     475             :   (void)line;
     476             : 
     477           0 :   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
     478           0 :   if (inp_fd == -1)
     479           0 :     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
     480           0 :   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
     481           0 :   if (out_fd == -1)
     482           0 :     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
     483             : 
     484           0 :   out_fp = es_fdopen_nc (out_fd, "w");
     485           0 :   if (!out_fp)
     486           0 :     return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
     487             : 
     488             :   /* Now add all encrypt-to marked recipients from the default
     489             :      list. */
     490           0 :   rc = 0;
     491           0 :   if (!opt.no_encrypt_to && !ctrl->server_local->no_encrypt_to)
     492             :     {
     493           0 :       for (cl=ctrl->server_local->default_recplist; !rc && cl; cl = cl->next)
     494           0 :         if (cl->is_encrypt_to)
     495           0 :           rc = gpgsm_add_cert_to_certlist (ctrl, cl->cert,
     496           0 :                                            &ctrl->server_local->recplist, 1);
     497             :     }
     498           0 :   if (!rc)
     499           0 :     rc = ctrl->audit? 0 : start_audit_session (ctrl);
     500           0 :   if (!rc)
     501           0 :     rc = gpgsm_encrypt (assuan_get_pointer (ctx),
     502           0 :                         ctrl->server_local->recplist,
     503             :                         inp_fd, out_fp);
     504           0 :   es_fclose (out_fp);
     505             : 
     506           0 :   gpgsm_release_certlist (ctrl->server_local->recplist);
     507           0 :   ctrl->server_local->recplist = NULL;
     508             :   /* Close and reset the fd */
     509           0 :   close_message_fd (ctrl);
     510           0 :   assuan_close_input_fd (ctx);
     511           0 :   assuan_close_output_fd (ctx);
     512           0 :   return rc;
     513             : }
     514             : 
     515             : 
     516             : static const char hlp_decrypt[] =
     517             :   "DECRYPT\n"
     518             :   "\n"
     519             :   "This performs the decrypt operation after doing some check on the\n"
     520             :   "internal state. (e.g. that only needed data has been set).  Because\n"
     521             :   "it utilizes the GPG-Agent for the session key decryption, there is\n"
     522             :   "no need to ask the client for a protecting passphrase - GPG-Agent\n"
     523             :   "does take care of this by requesting this from the user.";
     524             : static gpg_error_t
     525           0 : cmd_decrypt (assuan_context_t ctx, char *line)
     526             : {
     527           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     528             :   int inp_fd, out_fd;
     529             :   estream_t out_fp;
     530             :   int rc;
     531             : 
     532             :   (void)line;
     533             : 
     534           0 :   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
     535           0 :   if (inp_fd == -1)
     536           0 :     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
     537           0 :   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
     538           0 :   if (out_fd == -1)
     539           0 :     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
     540             : 
     541           0 :   out_fp = es_fdopen_nc (out_fd, "w");
     542           0 :   if (!out_fp)
     543           0 :     return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
     544             : 
     545           0 :   rc = start_audit_session (ctrl);
     546           0 :   if (!rc)
     547           0 :     rc = gpgsm_decrypt (ctrl, inp_fd, out_fp);
     548           0 :   es_fclose (out_fp);
     549             : 
     550             :   /* Close and reset the fds. */
     551           0 :   close_message_fd (ctrl);
     552           0 :   assuan_close_input_fd (ctx);
     553           0 :   assuan_close_output_fd (ctx);
     554             : 
     555           0 :   return rc;
     556             : }
     557             : 
     558             : 
     559             : static const char hlp_verify[] =
     560             :   "VERIFY\n"
     561             :   "\n"
     562             :   "This does a verify operation on the message send to the input FD.\n"
     563             :   "The result is written out using status lines.  If an output FD was\n"
     564             :   "given, the signed text will be written to that.\n"
     565             :   "\n"
     566             :   "If the signature is a detached one, the server will inquire about\n"
     567             :   "the signed material and the client must provide it.";
     568             : static gpg_error_t
     569           0 : cmd_verify (assuan_context_t ctx, char *line)
     570             : {
     571             :   int rc;
     572           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     573           0 :   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
     574           0 :   int out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
     575           0 :   estream_t out_fp = NULL;
     576             : 
     577             :   (void)line;
     578             : 
     579           0 :   if (fd == -1)
     580           0 :     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
     581             : 
     582           0 :   if (out_fd != -1)
     583             :     {
     584           0 :       out_fp = es_fdopen_nc (out_fd, "w");
     585           0 :       if (!out_fp)
     586           0 :         return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
     587             :     }
     588             : 
     589           0 :   rc = start_audit_session (ctrl);
     590           0 :   if (!rc)
     591           0 :     rc = gpgsm_verify (assuan_get_pointer (ctx), fd,
     592           0 :                        ctrl->server_local->message_fd, out_fp);
     593           0 :   es_fclose (out_fp);
     594             : 
     595             :   /* Close and reset the fd.  */
     596           0 :   close_message_fd (ctrl);
     597           0 :   assuan_close_input_fd (ctx);
     598           0 :   assuan_close_output_fd (ctx);
     599             : 
     600           0 :   return rc;
     601             : }
     602             : 
     603             : 
     604             : static const char hlp_sign[] =
     605             :   "SIGN [--detached]\n"
     606             :   "\n"
     607             :   "Sign the data set with the INPUT command and write it to the sink\n"
     608             :   "set by OUTPUT.  With \"--detached\", a detached signature is\n"
     609             :   "created (surprise).";
     610             : static gpg_error_t
     611           0 : cmd_sign (assuan_context_t ctx, char *line)
     612             : {
     613           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     614             :   int inp_fd, out_fd;
     615             :   estream_t out_fp;
     616             :   int detached;
     617             :   int rc;
     618             : 
     619           0 :   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
     620           0 :   if (inp_fd == -1)
     621           0 :     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
     622           0 :   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
     623           0 :   if (out_fd == -1)
     624           0 :     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
     625             : 
     626           0 :   detached = has_option (line, "--detached");
     627             : 
     628           0 :   out_fp = es_fdopen_nc (out_fd, "w");
     629           0 :   if (!out_fp)
     630           0 :     return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
     631             : 
     632           0 :   rc = start_audit_session (ctrl);
     633           0 :   if (!rc)
     634           0 :     rc = gpgsm_sign (assuan_get_pointer (ctx), ctrl->server_local->signerlist,
     635             :                      inp_fd, detached, out_fp);
     636           0 :   es_fclose (out_fp);
     637             : 
     638             :   /* close and reset the fd */
     639           0 :   close_message_fd (ctrl);
     640           0 :   assuan_close_input_fd (ctx);
     641           0 :   assuan_close_output_fd (ctx);
     642             : 
     643           0 :   return rc;
     644             : }
     645             : 
     646             : 
     647             : static const char hlp_import[] =
     648             :   "IMPORT [--re-import]\n"
     649             :   "\n"
     650             :   "Import the certificates read form the input-fd, return status\n"
     651             :   "message for each imported one.  The import checks the validity of\n"
     652             :   "the certificate but not of the entire chain.  It is possible to\n"
     653             :   "import expired certificates.\n"
     654             :   "\n"
     655             :   "With the option --re-import the input data is expected to a be a LF\n"
     656             :   "separated list of fingerprints.  The command will re-import these\n"
     657             :   "certificates, meaning that they are made permanent by removing\n"
     658             :   "their ephemeral flag.";
     659             : static gpg_error_t
     660           0 : cmd_import (assuan_context_t ctx, char *line)
     661             : {
     662           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     663             :   int rc;
     664           0 :   int fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
     665           0 :   int reimport = has_option (line, "--re-import");
     666             : 
     667             :   (void)line;
     668             : 
     669           0 :   if (fd == -1)
     670           0 :     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
     671             : 
     672           0 :   rc = gpgsm_import (assuan_get_pointer (ctx), fd, reimport);
     673             : 
     674             :   /* close and reset the fd */
     675           0 :   close_message_fd (ctrl);
     676           0 :   assuan_close_input_fd (ctx);
     677           0 :   assuan_close_output_fd (ctx);
     678             : 
     679           0 :   return rc;
     680             : }
     681             : 
     682             : 
     683             : static const char hlp_export[] =
     684             :   "EXPORT [--data [--armor|--base64]] [--secret [--(raw|pkcs12)] [--] <pattern>\n"
     685             :   "\n"
     686             :   "Export the certificates selected by PATTERN.  With --data the output\n"
     687             :   "is returned using Assuan D lines; the default is to use the sink given\n"
     688             :   "by the last \"OUTPUT\" command.  The options --armor or --base64 encode \n"
     689             :   "the output using the PEM respective a plain base-64 format; the default\n"
     690             :   "is a binary format which is only suitable for a single certificate.\n"
     691             :   "With --secret the secret key is exported using the PKCS#8 format,\n"
     692             :   "with --raw using PKCS#1, and with --pkcs12 as full PKCS#12 container.";
     693             : static gpg_error_t
     694           0 : cmd_export (assuan_context_t ctx, char *line)
     695             : {
     696           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     697             :   char *p;
     698             :   strlist_t list, sl;
     699             :   int use_data;
     700             :   int opt_secret;
     701           0 :   int opt_raw = 0;
     702           0 :   int opt_pkcs12 = 0;
     703             : 
     704           0 :   use_data = has_option (line, "--data");
     705           0 :   if (use_data)
     706             :     {
     707             :       /* We need to override any possible setting done by an OUTPUT command. */
     708           0 :       ctrl->create_pem = has_option (line, "--armor");
     709           0 :       ctrl->create_base64 = has_option (line, "--base64");
     710             :     }
     711           0 :   opt_secret = has_option (line, "--secret");
     712           0 :   if (opt_secret)
     713             :     {
     714           0 :       opt_raw = has_option (line, "--raw");
     715           0 :       opt_pkcs12 = has_option (line, "--pkcs12");
     716             :     }
     717             : 
     718           0 :   line = skip_options (line);
     719             : 
     720             :   /* Break the line down into an strlist_t. */
     721           0 :   list = NULL;
     722           0 :   for (p=line; *p; line = p)
     723             :     {
     724           0 :       while (*p && *p != ' ')
     725           0 :         p++;
     726           0 :       if (*p)
     727           0 :         *p++ = 0;
     728           0 :       if (*line)
     729             :         {
     730           0 :           sl = xtrymalloc (sizeof *sl + strlen (line));
     731           0 :           if (!sl)
     732             :             {
     733           0 :               free_strlist (list);
     734           0 :               return out_of_core ();
     735             :             }
     736           0 :           sl->flags = 0;
     737           0 :           strcpy_escaped_plus (sl->d, line);
     738           0 :           sl->next = list;
     739           0 :           list = sl;
     740             :         }
     741             :     }
     742             : 
     743           0 :   if (opt_secret)
     744             :     {
     745           0 :       if (!list || !*list->d)
     746           0 :         return set_error (GPG_ERR_NO_DATA, "No key given");
     747           0 :       if (list->next)
     748           0 :         return set_error (GPG_ERR_TOO_MANY, "Only one key allowed");
     749             :   }
     750             : 
     751           0 :   if (use_data)
     752             :     {
     753             :       estream_t stream;
     754             : 
     755           0 :       stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
     756           0 :       if (!stream)
     757             :         {
     758           0 :           free_strlist (list);
     759           0 :           return set_error (GPG_ERR_ASS_GENERAL,
     760             :                             "error setting up a data stream");
     761             :         }
     762           0 :       if (opt_secret)
     763           0 :         gpgsm_p12_export (ctrl, list->d, stream,
     764           0 :                           opt_raw? 2 : opt_pkcs12 ? 0 : 1);
     765             :       else
     766           0 :         gpgsm_export (ctrl, list, stream);
     767           0 :       es_fclose (stream);
     768             :     }
     769             :   else
     770             :     {
     771           0 :       int fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
     772             :       estream_t out_fp;
     773             : 
     774           0 :       if (fd == -1)
     775             :         {
     776           0 :           free_strlist (list);
     777           0 :           return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
     778             :         }
     779           0 :       out_fp = es_fdopen_nc (fd, "w");
     780           0 :       if (!out_fp)
     781             :         {
     782           0 :           free_strlist (list);
     783           0 :           return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
     784             :         }
     785             : 
     786           0 :       if (opt_secret)
     787           0 :         gpgsm_p12_export (ctrl, list->d, out_fp,
     788           0 :                           opt_raw? 2 : opt_pkcs12 ? 0 : 1);
     789             :       else
     790           0 :         gpgsm_export (ctrl, list, out_fp);
     791           0 :       es_fclose (out_fp);
     792             :     }
     793             : 
     794           0 :   free_strlist (list);
     795             :   /* Close and reset the fds. */
     796           0 :   close_message_fd (ctrl);
     797           0 :   assuan_close_input_fd (ctx);
     798           0 :   assuan_close_output_fd (ctx);
     799           0 :   return 0;
     800             : }
     801             : 
     802             : 
     803             : 
     804             : static const char hlp_delkeys[] =
     805             :   "DELKEYS <patterns>\n"
     806             :   "\n"
     807             :   "Delete the certificates specified by PATTERNS.  Each pattern shall be\n"
     808             :   "a percent-plus escaped certificate specification.  Usually a\n"
     809             :   "fingerprint will be used for this.";
     810             : static gpg_error_t
     811           0 : cmd_delkeys (assuan_context_t ctx, char *line)
     812             : {
     813           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     814             :   char *p;
     815             :   strlist_t list, sl;
     816             :   int rc;
     817             : 
     818             :   /* break the line down into an strlist_t */
     819           0 :   list = NULL;
     820           0 :   for (p=line; *p; line = p)
     821             :     {
     822           0 :       while (*p && *p != ' ')
     823           0 :         p++;
     824           0 :       if (*p)
     825           0 :         *p++ = 0;
     826           0 :       if (*line)
     827             :         {
     828           0 :           sl = xtrymalloc (sizeof *sl + strlen (line));
     829           0 :           if (!sl)
     830             :             {
     831           0 :               free_strlist (list);
     832           0 :               return out_of_core ();
     833             :             }
     834           0 :           sl->flags = 0;
     835           0 :           strcpy_escaped_plus (sl->d, line);
     836           0 :           sl->next = list;
     837           0 :           list = sl;
     838             :         }
     839             :     }
     840             : 
     841           0 :   rc = gpgsm_delete (ctrl, list);
     842           0 :   free_strlist (list);
     843             : 
     844             :   /* close and reset the fd */
     845           0 :   close_message_fd (ctrl);
     846           0 :   assuan_close_input_fd (ctx);
     847           0 :   assuan_close_output_fd (ctx);
     848             : 
     849           0 :   return rc;
     850             : }
     851             : 
     852             : 
     853             : 
     854             : static const char hlp_output[] =
     855             :   "OUTPUT FD[=<n>]\n"
     856             :   "\n"
     857             :   "Set the file descriptor to write the output data to N.  If N is not\n"
     858             :   "given and the operating system supports file descriptor passing, the\n"
     859             :   "file descriptor currently in flight will be used.  See also the\n"
     860             :   "\"INPUT\" and \"MESSAGE\" commands.";
     861             : static const char hlp_input[] =
     862             :   "INPUT FD[=<n>]\n"
     863             :   "\n"
     864             :   "Set the file descriptor to read the input data to N.  If N is not\n"
     865             :   "given and the operating system supports file descriptor passing, the\n"
     866             :   "file descriptor currently in flight will be used.  See also the\n"
     867             :   "\"MESSAGE\" and \"OUTPUT\" commands.";
     868             : static const char hlp_message[] =
     869             :   "MESSAGE FD[=<n>]\n"
     870             :   "\n"
     871             :   "Set the file descriptor to read the message for a detached\n"
     872             :   "signatures to N.  If N is not given and the operating system\n"
     873             :   "supports file descriptor passing, the file descriptor currently in\n"
     874             :   "flight will be used.  See also the \"INPUT\" and \"OUTPUT\" commands.";
     875             : static gpg_error_t
     876           0 : cmd_message (assuan_context_t ctx, char *line)
     877             : {
     878             :   int rc;
     879             :   gnupg_fd_t sysfd;
     880             :   int fd;
     881           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     882             : 
     883           0 :   rc = assuan_command_parse_fd (ctx, line, &sysfd);
     884           0 :   if (rc)
     885           0 :     return rc;
     886             : 
     887             : #ifdef HAVE_W32CE_SYSTEM
     888             :   sysfd = _assuan_w32ce_finish_pipe ((int)sysfd, 0);
     889             :   if (sysfd == INVALID_HANDLE_VALUE)
     890             :     return set_error (gpg_err_code_from_syserror (),
     891             :                       "rvid conversion failed");
     892             : #endif
     893             : 
     894           0 :   fd = translate_sys2libc_fd (sysfd, 0);
     895           0 :   if (fd == -1)
     896           0 :     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
     897           0 :   ctrl->server_local->message_fd = fd;
     898           0 :   return 0;
     899             : }
     900             : 
     901             : 
     902             : 
     903             : static const char hlp_listkeys[] =
     904             :   "LISTKEYS [<patterns>]\n"
     905             :   "LISTSECRETKEYS [<patterns>]\n"
     906             :   "DUMPKEYS [<patterns>]\n"
     907             :   "DUMPSECRETKEYS [<patterns>]\n"
     908             :   "\n"
     909             :   "List all certificates or only those specified by PATTERNS.  Each\n"
     910             :   "pattern shall be a percent-plus escaped certificate specification.\n"
     911             :   "The \"SECRET\" versions of the command filter the output to include\n"
     912             :   "only certificates where the secret key is available or a corresponding\n"
     913             :   "smartcard has been registered.  The \"DUMP\" versions of the command\n"
     914             :   "are only useful for debugging.  The output format is a percent escaped\n"
     915             :   "colon delimited listing as described in the manual.\n"
     916             :   "\n"
     917             :   "These \"OPTION\" command keys effect the output::\n"
     918             :   "\n"
     919             :   "  \"list-mode\" set to 0: List only local certificates (default).\n"
     920             :   "                     1: Ditto.\n"
     921             :   "                     2: List only external certificates.\n"
     922             :   "                     3: List local and external certificates.\n"
     923             :   "\n"
     924             :   "  \"with-validation\" set to true: Validate each certificate.\n"
     925             :   "\n"
     926             :   "  \"with-ephemeral-key\" set to true: Always include ephemeral\n"
     927             :   "                                    certificates.\n"
     928             :   "\n"
     929             :   "  \"list-to-output\" set to true: Write output to the file descriptor\n"
     930             :   "                                given by the last \"OUTPUT\" command.";
     931             : static int
     932           0 : do_listkeys (assuan_context_t ctx, char *line, int mode)
     933             : {
     934           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
     935             :   estream_t fp;
     936             :   char *p;
     937             :   strlist_t list, sl;
     938             :   unsigned int listmode;
     939             :   gpg_error_t err;
     940             : 
     941             :   /* Break the line down into an strlist. */
     942           0 :   list = NULL;
     943           0 :   for (p=line; *p; line = p)
     944             :     {
     945           0 :       while (*p && *p != ' ')
     946           0 :         p++;
     947           0 :       if (*p)
     948           0 :         *p++ = 0;
     949           0 :       if (*line)
     950             :         {
     951           0 :           sl = xtrymalloc (sizeof *sl + strlen (line));
     952           0 :           if (!sl)
     953             :             {
     954           0 :               free_strlist (list);
     955           0 :               return out_of_core ();
     956             :             }
     957           0 :           sl->flags = 0;
     958           0 :           strcpy_escaped_plus (sl->d, line);
     959           0 :           sl->next = list;
     960           0 :           list = sl;
     961             :         }
     962             :     }
     963             : 
     964           0 :   if (ctrl->server_local->list_to_output)
     965             :     {
     966           0 :       int outfd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
     967             : 
     968           0 :       if ( outfd == -1 )
     969           0 :         return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
     970           0 :       fp = es_fdopen_nc (outfd, "w");
     971           0 :       if (!fp)
     972           0 :         return set_error (gpg_err_code_from_syserror (), "es_fdopen() failed");
     973             :     }
     974             :   else
     975             :     {
     976           0 :       fp = es_fopencookie (ctx, "w", data_line_cookie_functions);
     977           0 :       if (!fp)
     978           0 :         return set_error (GPG_ERR_ASS_GENERAL,
     979             :                           "error setting up a data stream");
     980             :     }
     981             : 
     982           0 :   ctrl->with_colons = 1;
     983           0 :   listmode = mode;
     984           0 :   if (ctrl->server_local->list_internal)
     985           0 :     listmode |= (1<<6);
     986           0 :   if (ctrl->server_local->list_external)
     987           0 :     listmode |= (1<<7);
     988           0 :   err = gpgsm_list_keys (assuan_get_pointer (ctx), list, fp, listmode);
     989           0 :   free_strlist (list);
     990           0 :   es_fclose (fp);
     991           0 :   if (ctrl->server_local->list_to_output)
     992           0 :     assuan_close_output_fd (ctx);
     993           0 :   return err;
     994             : }
     995             : 
     996             : static gpg_error_t
     997           0 : cmd_listkeys (assuan_context_t ctx, char *line)
     998             : {
     999           0 :   return do_listkeys (ctx, line, 3);
    1000             : }
    1001             : 
    1002             : static gpg_error_t
    1003           0 : cmd_dumpkeys (assuan_context_t ctx, char *line)
    1004             : {
    1005           0 :   return do_listkeys (ctx, line, 259);
    1006             : }
    1007             : 
    1008             : static gpg_error_t
    1009           0 : cmd_listsecretkeys (assuan_context_t ctx, char *line)
    1010             : {
    1011           0 :   return do_listkeys (ctx, line, 2);
    1012             : }
    1013             : 
    1014             : static gpg_error_t
    1015           0 : cmd_dumpsecretkeys (assuan_context_t ctx, char *line)
    1016             : {
    1017           0 :   return do_listkeys (ctx, line, 258);
    1018             : }
    1019             : 
    1020             : 
    1021             : 
    1022             : static const char hlp_genkey[] =
    1023             :   "GENKEY\n"
    1024             :   "\n"
    1025             :   "Read the parameters in native format from the input fd and write a\n"
    1026             :   "certificate request to the output.";
    1027             : static gpg_error_t
    1028           0 : cmd_genkey (assuan_context_t ctx, char *line)
    1029             : {
    1030           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1031             :   int inp_fd, out_fd;
    1032             :   estream_t in_stream, out_stream;
    1033             :   int rc;
    1034             : 
    1035             :   (void)line;
    1036             : 
    1037           0 :   inp_fd = translate_sys2libc_fd (assuan_get_input_fd (ctx), 0);
    1038           0 :   if (inp_fd == -1)
    1039           0 :     return set_error (GPG_ERR_ASS_NO_INPUT, NULL);
    1040           0 :   out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
    1041           0 :   if (out_fd == -1)
    1042           0 :     return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
    1043             : 
    1044           0 :   in_stream = es_fdopen_nc (inp_fd, "r");
    1045           0 :   if (!in_stream)
    1046           0 :     return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen failed");
    1047             : 
    1048           0 :   out_stream = es_fdopen_nc (out_fd, "w");
    1049           0 :   if (!out_stream)
    1050             :     {
    1051           0 :       es_fclose (in_stream);
    1052           0 :       return set_error (gpg_err_code_from_syserror (), "fdopen() failed");
    1053             :     }
    1054           0 :   rc = gpgsm_genkey (ctrl, in_stream, out_stream);
    1055           0 :   es_fclose (out_stream);
    1056           0 :   es_fclose (in_stream);
    1057             : 
    1058             :   /* close and reset the fds */
    1059           0 :   assuan_close_input_fd (ctx);
    1060           0 :   assuan_close_output_fd (ctx);
    1061             : 
    1062           0 :   return rc;
    1063             : }
    1064             : 
    1065             : 
    1066             : 
    1067             : static const char hlp_getauditlog[] =
    1068             :   "GETAUDITLOG [--data] [--html]\n"
    1069             :   "\n"
    1070             :   "If --data is used, the output is send using D-lines and not to the\n"
    1071             :   "file descriptor given by an OUTPUT command.\n"
    1072             :   "\n"
    1073             :   "If --html is used the output is formated as an XHTML block. This is\n"
    1074             :   "designed to be incorporated into a HTML document.";
    1075             : static gpg_error_t
    1076           0 : cmd_getauditlog (assuan_context_t ctx, char *line)
    1077             : {
    1078           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1079             :   int  out_fd;
    1080             :   estream_t out_stream;
    1081             :   int opt_data, opt_html;
    1082             :   int rc;
    1083             : 
    1084           0 :   opt_data = has_option (line, "--data");
    1085           0 :   opt_html = has_option (line, "--html");
    1086           0 :   line = skip_options (line);
    1087             : 
    1088           0 :   if (!ctrl->audit)
    1089           0 :     return gpg_error (GPG_ERR_NO_DATA);
    1090             : 
    1091           0 :   if (opt_data)
    1092             :     {
    1093           0 :       out_stream = es_fopencookie (ctx, "w", data_line_cookie_functions);
    1094           0 :       if (!out_stream)
    1095           0 :         return set_error (GPG_ERR_ASS_GENERAL,
    1096             :                           "error setting up a data stream");
    1097             :     }
    1098             :   else
    1099             :     {
    1100           0 :       out_fd = translate_sys2libc_fd (assuan_get_output_fd (ctx), 1);
    1101           0 :       if (out_fd == -1)
    1102           0 :         return set_error (GPG_ERR_ASS_NO_OUTPUT, NULL);
    1103             : 
    1104           0 :       out_stream = es_fdopen_nc (out_fd, "w");
    1105           0 :       if (!out_stream)
    1106             :         {
    1107           0 :           return set_error (GPG_ERR_ASS_GENERAL, "es_fdopen() failed");
    1108             :         }
    1109             :     }
    1110             : 
    1111           0 :   audit_print_result (ctrl->audit, out_stream, opt_html);
    1112           0 :   rc = 0;
    1113             : 
    1114           0 :   es_fclose (out_stream);
    1115             : 
    1116             :   /* Close and reset the fd. */
    1117           0 :   if (!opt_data)
    1118           0 :     assuan_close_output_fd (ctx);
    1119           0 :   return rc;
    1120             : }
    1121             : 
    1122             : static const char hlp_getinfo[] =
    1123             :   "GETINFO <what>\n"
    1124             :   "\n"
    1125             :   "Multipurpose function to return a variety of information.\n"
    1126             :   "Supported values for WHAT are:\n"
    1127             :   "\n"
    1128             :   "  version     - Return the version of the program.\n"
    1129             :   "  pid         - Return the process id of the server.\n"
    1130             :   "  agent-check - Return success if the agent is running.\n"
    1131             :   "  cmd_has_option CMD OPT\n"
    1132             :   "              - Returns OK if the command CMD implements the option OPT.\n"
    1133             :   "  offline     - Returns OK if the conenction is in offline mode.";
    1134             : static gpg_error_t
    1135           0 : cmd_getinfo (assuan_context_t ctx, char *line)
    1136             : {
    1137           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1138           0 :   int rc = 0;
    1139             : 
    1140           0 :   if (!strcmp (line, "version"))
    1141             :     {
    1142           0 :       const char *s = VERSION;
    1143           0 :       rc = assuan_send_data (ctx, s, strlen (s));
    1144             :     }
    1145           0 :   else if (!strcmp (line, "pid"))
    1146             :     {
    1147             :       char numbuf[50];
    1148             : 
    1149           0 :       snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
    1150           0 :       rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
    1151             :     }
    1152           0 :   else if (!strcmp (line, "agent-check"))
    1153             :     {
    1154           0 :       rc = gpgsm_agent_send_nop (ctrl);
    1155             :     }
    1156           0 :   else if (!strncmp (line, "cmd_has_option", 14)
    1157           0 :            && (line[14] == ' ' || line[14] == '\t' || !line[14]))
    1158           0 :     {
    1159             :       char *cmd, *cmdopt;
    1160           0 :       line += 14;
    1161           0 :       while (*line == ' ' || *line == '\t')
    1162           0 :         line++;
    1163           0 :       if (!*line)
    1164           0 :         rc = gpg_error (GPG_ERR_MISSING_VALUE);
    1165             :       else
    1166             :         {
    1167           0 :           cmd = line;
    1168           0 :           while (*line && (*line != ' ' && *line != '\t'))
    1169           0 :             line++;
    1170           0 :           if (!*line)
    1171           0 :             rc = gpg_error (GPG_ERR_MISSING_VALUE);
    1172             :           else
    1173             :             {
    1174           0 :               *line++ = 0;
    1175           0 :               while (*line == ' ' || *line == '\t')
    1176           0 :                 line++;
    1177           0 :               if (!*line)
    1178           0 :                 rc = gpg_error (GPG_ERR_MISSING_VALUE);
    1179             :               else
    1180             :                 {
    1181           0 :                   cmdopt = line;
    1182           0 :                   if (!command_has_option (cmd, cmdopt))
    1183           0 :                     rc = gpg_error (GPG_ERR_GENERAL);
    1184             :                 }
    1185             :             }
    1186             :         }
    1187             :     }
    1188           0 :   else if (!strcmp (line, "offline"))
    1189             :     {
    1190           0 :       rc = ctrl->offline? 0 : gpg_error (GPG_ERR_GENERAL);
    1191             :     }
    1192             :   else
    1193           0 :     rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
    1194             : 
    1195           0 :   return rc;
    1196             : }
    1197             : 
    1198             : 
    1199             : static const char hlp_passwd[] =
    1200             :   "PASSWD <userID>\n"
    1201             :   "\n"
    1202             :   "Change the passphrase of the secret key for USERID.";
    1203             : static gpg_error_t
    1204           0 : cmd_passwd (assuan_context_t ctx, char *line)
    1205             : {
    1206           0 :   ctrl_t ctrl = assuan_get_pointer (ctx);
    1207             :   gpg_error_t err;
    1208           0 :   ksba_cert_t cert = NULL;
    1209           0 :   char *grip = NULL;
    1210             : 
    1211           0 :   line = skip_options (line);
    1212             : 
    1213           0 :   err = gpgsm_find_cert (line, NULL, &cert);
    1214           0 :   if (err)
    1215             :     ;
    1216           0 :   else if (!(grip = gpgsm_get_keygrip_hexstring (cert)))
    1217           0 :     err = gpg_error (GPG_ERR_INTERNAL);
    1218             :   else
    1219             :     {
    1220           0 :       char *desc = gpgsm_format_keydesc (cert);
    1221           0 :       err = gpgsm_agent_passwd (ctrl, grip, desc);
    1222           0 :       xfree (desc);
    1223             :     }
    1224             : 
    1225           0 :   xfree (grip);
    1226           0 :   ksba_cert_release (cert);
    1227             : 
    1228           0 :   return err;
    1229             : }
    1230             : 
    1231             : 
    1232             : 
    1233             : /* Return true if the command CMD implements the option OPT.  */
    1234             : static int
    1235           0 : command_has_option (const char *cmd, const char *cmdopt)
    1236             : {
    1237           0 :   if (!strcmp (cmd, "IMPORT"))
    1238             :     {
    1239           0 :       if (!strcmp (cmdopt, "re-import"))
    1240           0 :         return 1;
    1241             :     }
    1242             : 
    1243           0 :   return 0;
    1244             : }
    1245             : 
    1246             : 
    1247             : /* Tell the assuan library about our commands */
    1248             : static int
    1249           0 : register_commands (assuan_context_t ctx)
    1250             : {
    1251             :   static struct {
    1252             :     const char *name;
    1253             :     assuan_handler_t handler;
    1254             :     const char * const help;
    1255             :   } table[] = {
    1256             :     { "RECIPIENT",     cmd_recipient, hlp_recipient },
    1257             :     { "SIGNER",        cmd_signer,    hlp_signer },
    1258             :     { "ENCRYPT",       cmd_encrypt,   hlp_encrypt },
    1259             :     { "DECRYPT",       cmd_decrypt,   hlp_decrypt },
    1260             :     { "VERIFY",        cmd_verify,    hlp_verify },
    1261             :     { "SIGN",          cmd_sign,      hlp_sign },
    1262             :     { "IMPORT",        cmd_import,    hlp_import },
    1263             :     { "EXPORT",        cmd_export,    hlp_export },
    1264             :     { "INPUT",         NULL,          hlp_input },
    1265             :     { "OUTPUT",        NULL,          hlp_output },
    1266             :     { "MESSAGE",       cmd_message,   hlp_message },
    1267             :     { "LISTKEYS",      cmd_listkeys,  hlp_listkeys },
    1268             :     { "DUMPKEYS",      cmd_dumpkeys,  hlp_listkeys },
    1269             :     { "LISTSECRETKEYS",cmd_listsecretkeys, hlp_listkeys },
    1270             :     { "DUMPSECRETKEYS",cmd_dumpsecretkeys, hlp_listkeys },
    1271             :     { "GENKEY",        cmd_genkey,    hlp_genkey },
    1272             :     { "DELKEYS",       cmd_delkeys,   hlp_delkeys },
    1273             :     { "GETAUDITLOG",   cmd_getauditlog,    hlp_getauditlog },
    1274             :     { "GETINFO",       cmd_getinfo,   hlp_getinfo },
    1275             :     { "PASSWD",        cmd_passwd,    hlp_passwd },
    1276             :     { NULL }
    1277             :   };
    1278             :   int i, rc;
    1279             : 
    1280           0 :   for (i=0; table[i].name; i++)
    1281             :     {
    1282           0 :       rc = assuan_register_command (ctx, table[i].name, table[i].handler,
    1283             :                                     table[i].help);
    1284           0 :       if (rc)
    1285           0 :         return rc;
    1286             :     }
    1287           0 :   return 0;
    1288             : }
    1289             : 
    1290             : /* Startup the server. DEFAULT_RECPLIST is the list of recipients as
    1291             :    set from the command line or config file.  We only require those
    1292             :    marked as encrypt-to. */
    1293             : void
    1294           0 : gpgsm_server (certlist_t default_recplist)
    1295             : {
    1296             :   int rc;
    1297             :   assuan_fd_t filedes[2];
    1298             :   assuan_context_t ctx;
    1299             :   struct server_control_s ctrl;
    1300             :   static const char hello[] = ("GNU Privacy Guard's S/M server "
    1301             :                                VERSION " ready");
    1302             : 
    1303           0 :   memset (&ctrl, 0, sizeof ctrl);
    1304           0 :   gpgsm_init_default_ctrl (&ctrl);
    1305             : 
    1306             :   /* We use a pipe based server so that we can work from scripts.
    1307             :      assuan_init_pipe_server will automagically detect when we are
    1308             :      called with a socketpair and ignore FILEDES in this case. */
    1309             : #ifdef HAVE_W32CE_SYSTEM
    1310             :   #define SERVER_STDIN es_fileno(es_stdin)
    1311             :   #define SERVER_STDOUT es_fileno(es_stdout)
    1312             : #else
    1313             : #define SERVER_STDIN 0
    1314             : #define SERVER_STDOUT 1
    1315             : #endif
    1316           0 :   filedes[0] = assuan_fdopen (SERVER_STDIN);
    1317           0 :   filedes[1] = assuan_fdopen (SERVER_STDOUT);
    1318           0 :   rc = assuan_new (&ctx);
    1319           0 :   if (rc)
    1320             :     {
    1321           0 :       log_error ("failed to allocate assuan context: %s\n",
    1322             :                  gpg_strerror (rc));
    1323           0 :       gpgsm_exit (2);
    1324             :     }
    1325             : 
    1326           0 :   rc = assuan_init_pipe_server (ctx, filedes);
    1327           0 :   if (rc)
    1328             :     {
    1329           0 :       log_error ("failed to initialize the server: %s\n",
    1330             :                  gpg_strerror (rc));
    1331           0 :       gpgsm_exit (2);
    1332             :     }
    1333           0 :   rc = register_commands (ctx);
    1334           0 :   if (rc)
    1335             :     {
    1336           0 :       log_error ("failed to the register commands with Assuan: %s\n",
    1337             :                  gpg_strerror(rc));
    1338           0 :       gpgsm_exit (2);
    1339             :     }
    1340           0 :   if (opt.verbose || opt.debug)
    1341           0 :     {
    1342           0 :       char *tmp = NULL;
    1343             : 
    1344             :       /* Fixme: Use the really used socket name.  */
    1345           0 :       if (asprintf (&tmp,
    1346             :                     "Home: %s\n"
    1347             :                     "Config: %s\n"
    1348             :                     "DirmngrInfo: %s\n"
    1349             :                     "%s",
    1350             :                     opt.homedir,
    1351             :                     opt.config_filename,
    1352           0 :                     (dirmngr_user_socket_name ()
    1353             :                      ? dirmngr_user_socket_name ()
    1354             :                      : dirmngr_sys_socket_name ()),
    1355             :                     hello) > 0)
    1356             :         {
    1357           0 :           assuan_set_hello_line (ctx, tmp);
    1358           0 :           free (tmp);
    1359             :         }
    1360             :     }
    1361             :   else
    1362           0 :     assuan_set_hello_line (ctx, hello);
    1363             : 
    1364           0 :   assuan_register_reset_notify (ctx, reset_notify);
    1365           0 :   assuan_register_input_notify (ctx, input_notify);
    1366           0 :   assuan_register_output_notify (ctx, output_notify);
    1367           0 :   assuan_register_option_handler (ctx, option_handler);
    1368             : 
    1369           0 :   assuan_set_pointer (ctx, &ctrl);
    1370           0 :   ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
    1371           0 :   ctrl.server_local->assuan_ctx = ctx;
    1372           0 :   ctrl.server_local->message_fd = -1;
    1373           0 :   ctrl.server_local->list_internal = 1;
    1374           0 :   ctrl.server_local->list_external = 0;
    1375           0 :   ctrl.server_local->default_recplist = default_recplist;
    1376             : 
    1377             :   for (;;)
    1378             :     {
    1379           0 :       rc = assuan_accept (ctx);
    1380           0 :       if (rc == -1)
    1381             :         {
    1382           0 :           break;
    1383             :         }
    1384           0 :       else if (rc)
    1385             :         {
    1386           0 :           log_info ("Assuan accept problem: %s\n", gpg_strerror (rc));
    1387           0 :           break;
    1388             :         }
    1389             : 
    1390           0 :       rc = assuan_process (ctx);
    1391           0 :       if (rc)
    1392             :         {
    1393           0 :           log_info ("Assuan processing failed: %s\n", gpg_strerror (rc));
    1394           0 :           continue;
    1395             :         }
    1396           0 :     }
    1397             : 
    1398           0 :   gpgsm_release_certlist (ctrl.server_local->recplist);
    1399           0 :   ctrl.server_local->recplist = NULL;
    1400           0 :   gpgsm_release_certlist (ctrl.server_local->signerlist);
    1401           0 :   ctrl.server_local->signerlist = NULL;
    1402           0 :   xfree (ctrl.server_local);
    1403             : 
    1404           0 :   audit_release (ctrl.audit);
    1405           0 :   ctrl.audit = NULL;
    1406             : 
    1407           0 :   assuan_release (ctx);
    1408           0 : }
    1409             : 
    1410             : 
    1411             : 
    1412             : gpg_error_t
    1413           9 : gpgsm_status2 (ctrl_t ctrl, int no, ...)
    1414             : {
    1415           9 :   gpg_error_t err = 0;
    1416             :   va_list arg_ptr;
    1417             :   const char *text;
    1418             : 
    1419           9 :   va_start (arg_ptr, no);
    1420             : 
    1421           9 :   if (ctrl->no_server && ctrl->status_fd == -1)
    1422             :     ; /* No status wanted. */
    1423           0 :   else if (ctrl->no_server)
    1424             :     {
    1425           0 :       if (!statusfp)
    1426             :         {
    1427           0 :           if (ctrl->status_fd == 1)
    1428           0 :             statusfp = stdout;
    1429           0 :           else if (ctrl->status_fd == 2)
    1430           0 :             statusfp = stderr;
    1431             :           else
    1432           0 :             statusfp = fdopen (ctrl->status_fd, "w");
    1433             : 
    1434           0 :           if (!statusfp)
    1435             :             {
    1436           0 :               log_fatal ("can't open fd %d for status output: %s\n",
    1437           0 :                          ctrl->status_fd, strerror(errno));
    1438             :             }
    1439             :         }
    1440             : 
    1441           0 :       fputs ("[GNUPG:] ", statusfp);
    1442           0 :       fputs (get_status_string (no), statusfp);
    1443             : 
    1444           0 :       while ( (text = va_arg (arg_ptr, const char*) ))
    1445             :         {
    1446           0 :           putc ( ' ', statusfp );
    1447           0 :           for (; *text; text++)
    1448             :             {
    1449           0 :               if (*text == '\n')
    1450           0 :                 fputs ( "\\n", statusfp );
    1451           0 :               else if (*text == '\r')
    1452           0 :                 fputs ( "\\r", statusfp );
    1453             :               else
    1454           0 :                 putc ( *(const byte *)text,  statusfp );
    1455             :             }
    1456             :         }
    1457           0 :       putc ('\n', statusfp);
    1458           0 :       fflush (statusfp);
    1459             :     }
    1460             :   else
    1461             :     {
    1462           0 :       assuan_context_t ctx = ctrl->server_local->assuan_ctx;
    1463             :       char buf[950], *p;
    1464             :       size_t n;
    1465             : 
    1466           0 :       p = buf;
    1467           0 :       n = 0;
    1468           0 :       while ( (text = va_arg (arg_ptr, const char *)) )
    1469             :         {
    1470           0 :           if (n)
    1471             :             {
    1472           0 :               *p++ = ' ';
    1473           0 :               n++;
    1474             :             }
    1475           0 :           for ( ; *text && n < DIM (buf)-2; n++)
    1476           0 :             *p++ = *text++;
    1477             :         }
    1478           0 :       *p = 0;
    1479           0 :       err = assuan_write_status (ctx, get_status_string (no), buf);
    1480             :     }
    1481             : 
    1482           9 :   va_end (arg_ptr);
    1483           9 :   return err;
    1484             : }
    1485             : 
    1486             : gpg_error_t
    1487           3 : gpgsm_status (ctrl_t ctrl, int no, const char *text)
    1488             : {
    1489           3 :   return gpgsm_status2 (ctrl, no, text, NULL);
    1490             : }
    1491             : 
    1492             : gpg_error_t
    1493           0 : gpgsm_status_with_err_code (ctrl_t ctrl, int no, const char *text,
    1494             :                             gpg_err_code_t ec)
    1495             : {
    1496             :   char buf[30];
    1497             : 
    1498           0 :   sprintf (buf, "%u", (unsigned int)ec);
    1499           0 :   if (text)
    1500           0 :     return gpgsm_status2 (ctrl, no, text, buf, NULL);
    1501             :   else
    1502           0 :     return gpgsm_status2 (ctrl, no, buf, NULL);
    1503             : }
    1504             : 
    1505             : 
    1506             : /* Helper to notify the client about Pinentry events.  Because that
    1507             :    might disturb some older clients, this is only done when enabled
    1508             :    via an option.  Returns an gpg error code. */
    1509             : gpg_error_t
    1510           0 : gpgsm_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line)
    1511             : {
    1512           0 :   if (!ctrl || !ctrl->server_local
    1513           0 :       || !ctrl->server_local->allow_pinentry_notify)
    1514           0 :     return 0;
    1515           0 :   return assuan_inquire (ctrl->server_local->assuan_ctx, line, NULL, NULL, 0);
    1516             : }

Generated by: LCOV version 1.11