LCOV - code coverage report
Current view: top level - sm - server.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 8 613 1.3 %
Date: 2016-11-29 15:00:56 Functions: 2 36 5.6 %

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

Generated by: LCOV version 1.11