LCOV - code coverage report
Current view: top level - src - engine-g13.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 2 299 0.7 %
Date: 2016-11-29 15:07:43 Functions: 1 17 5.9 %

          Line data    Source code
       1             : /* engine-g13.c - G13 engine.
       2             :    Copyright (C) 2000 Werner Koch (dd9jn)
       3             :    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH
       4             : 
       5             :    This file is part of GPGME.
       6             : 
       7             :    GPGME is free software; you can redistribute it and/or modify it
       8             :    under the terms of the GNU Lesser General Public License as
       9             :    published by the Free Software Foundation; either version 2.1 of
      10             :    the License, or (at your option) any later version.
      11             : 
      12             :    GPGME is distributed in the hope that it will be useful, but
      13             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :    Lesser General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU Lesser General Public
      18             :    License along with this program; if not, write to the Free Software
      19             :    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
      20             :    02111-1307, USA.  */
      21             : 
      22             : #if HAVE_CONFIG_H
      23             : #include <config.h>
      24             : #endif
      25             : 
      26             : #include <stdlib.h>
      27             : #include <string.h>
      28             : #ifdef HAVE_SYS_TYPES_H
      29             : # include <sys/types.h>
      30             : #endif
      31             : #include <assert.h>
      32             : #ifdef HAVE_UNISTD_H
      33             : # include <unistd.h>
      34             : #endif
      35             : #ifdef HAVE_LOCALE_H
      36             : #include <locale.h>
      37             : #endif
      38             : #include <fcntl.h> /* FIXME */
      39             : #include <errno.h>
      40             : 
      41             : #include "gpgme.h"
      42             : #include "util.h"
      43             : #include "ops.h"
      44             : #include "wait.h"
      45             : #include "priv-io.h"
      46             : #include "sema.h"
      47             : 
      48             : #include "assuan.h"
      49             : #include "debug.h"
      50             : 
      51             : #include "engine-backend.h"
      52             : 
      53             : 
      54             : typedef struct
      55             : {
      56             :   int fd;       /* FD we talk about.  */
      57             :   int server_fd;/* Server FD for this connection.  */
      58             :   int dir;      /* Inbound/Outbound, maybe given implicit?  */
      59             :   void *data;   /* Handler-specific data.  */
      60             :   void *tag;    /* ID from the user for gpgme_remove_io_callback.  */
      61             :   char server_fd_str[15]; /* Same as SERVER_FD but as a string.  We
      62             :                              need this because _gpgme_io_fd2str can't
      63             :                              be used on a closed descriptor.  */
      64             : } iocb_data_t;
      65             : 
      66             : 
      67             : struct engine_g13
      68             : {
      69             :   assuan_context_t assuan_ctx;
      70             : 
      71             :   int lc_ctype_set;
      72             :   int lc_messages_set;
      73             : 
      74             :   iocb_data_t status_cb;
      75             : 
      76             :   struct gpgme_io_cbs io_cbs;
      77             : 
      78             :   /* User provided callbacks.  */
      79             :   struct {
      80             :     gpgme_assuan_data_cb_t data_cb;
      81             :     void *data_cb_value;
      82             : 
      83             :     gpgme_assuan_inquire_cb_t inq_cb;
      84             :     void *inq_cb_value;
      85             : 
      86             :     gpgme_assuan_status_cb_t status_cb;
      87             :     void *status_cb_value;
      88             :   } user;
      89             : };
      90             : 
      91             : typedef struct engine_g13 *engine_g13_t;
      92             : 
      93             : 
      94             : static void g13_io_event (void *engine,
      95             :                             gpgme_event_io_t type, void *type_data);
      96             : 
      97             : 
      98             : 
      99             : static char *
     100          79 : g13_get_version (const char *file_name)
     101             : {
     102          79 :   return _gpgme_get_program_version (file_name ? file_name
     103             :                                      : _gpgme_get_default_g13_name ());
     104             : }
     105             : 
     106             : 
     107             : static const char *
     108           0 : g13_get_req_version (void)
     109             : {
     110           0 :   return "2.1.0";
     111             : }
     112             : 
     113             : 
     114             : static void
     115           0 : close_notify_handler (int fd, void *opaque)
     116             : {
     117           0 :   engine_g13_t g13 = opaque;
     118             : 
     119           0 :   assert (fd != -1);
     120           0 :   if (g13->status_cb.fd == fd)
     121             :     {
     122           0 :       if (g13->status_cb.tag)
     123           0 :         (*g13->io_cbs.remove) (g13->status_cb.tag);
     124           0 :       g13->status_cb.fd = -1;
     125           0 :       g13->status_cb.tag = NULL;
     126             :     }
     127           0 : }
     128             : 
     129             : 
     130             : /* This is the default inquiry callback.  We use it to handle the
     131             :    Pinentry notifications.  */
     132             : static gpgme_error_t
     133           0 : default_inq_cb (engine_g13_t g13, const char *keyword, const char *args)
     134             : {
     135             :   gpg_error_t err;
     136             : 
     137           0 :   if (!strcmp (keyword, "PINENTRY_LAUNCHED"))
     138             :     {
     139           0 :       _gpgme_allow_set_foreground_window ((pid_t)strtoul (args, NULL, 10));
     140             :     }
     141             : 
     142           0 :   if (g13->user.inq_cb)
     143             :     {
     144           0 :       gpgme_data_t data = NULL;
     145             : 
     146           0 :       err = g13->user.inq_cb (g13->user.inq_cb_value,
     147             :                                 keyword, args, &data);
     148           0 :       if (!err && data)
     149             :         {
     150             :           /* FIXME: Returning data is not yet implemented.  However we
     151             :              need to allow the caller to cleanup his data object.
     152             :              Thus we run the callback in finish mode immediately.  */
     153           0 :           err = g13->user.inq_cb (g13->user.inq_cb_value,
     154             :                                   NULL, NULL, &data);
     155             :         }
     156             :     }
     157             :   else
     158           0 :     err = 0;
     159             : 
     160           0 :   return err;
     161             : }
     162             : 
     163             : 
     164             : static gpgme_error_t
     165           0 : g13_cancel (void *engine)
     166             : {
     167           0 :   engine_g13_t g13 = engine;
     168             : 
     169           0 :   if (!g13)
     170           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     171             : 
     172           0 :   if (g13->status_cb.fd != -1)
     173           0 :     _gpgme_io_close (g13->status_cb.fd);
     174             : 
     175           0 :   if (g13->assuan_ctx)
     176             :     {
     177           0 :       assuan_release (g13->assuan_ctx);
     178           0 :       g13->assuan_ctx = NULL;
     179             :     }
     180             : 
     181           0 :   return 0;
     182             : }
     183             : 
     184             : 
     185             : static gpgme_error_t
     186           0 : g13_cancel_op (void *engine)
     187             : {
     188           0 :   engine_g13_t g13 = engine;
     189             : 
     190           0 :   if (!g13)
     191           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     192             : 
     193           0 :   if (g13->status_cb.fd != -1)
     194           0 :     _gpgme_io_close (g13->status_cb.fd);
     195             : 
     196           0 :   return 0;
     197             : }
     198             : 
     199             : 
     200             : static void
     201           0 : g13_release (void *engine)
     202             : {
     203           0 :   engine_g13_t g13 = engine;
     204             : 
     205           0 :   if (!g13)
     206           0 :     return;
     207             : 
     208           0 :   g13_cancel (engine);
     209             : 
     210           0 :   free (g13);
     211             : }
     212             : 
     213             : 
     214             : static gpgme_error_t
     215           0 : g13_new (void **engine, const char *file_name, const char *home_dir,
     216             :          const char *version)
     217             : {
     218           0 :   gpgme_error_t err = 0;
     219             :   engine_g13_t g13;
     220             :   const char *pgmname;
     221             :   int argc;
     222             :   const char *argv[5];
     223           0 :   char *dft_display = NULL;
     224             :   char dft_ttyname[64];
     225           0 :   char *env_tty = NULL;
     226           0 :   char *dft_ttytype = NULL;
     227             :   char *optstr;
     228             : 
     229             :   (void)version; /* Not yet used.  */
     230             : 
     231           0 :   g13 = calloc (1, sizeof *g13);
     232           0 :   if (!g13)
     233           0 :     return gpg_error_from_syserror ();
     234             : 
     235           0 :   g13->status_cb.fd = -1;
     236           0 :   g13->status_cb.dir = 1;
     237           0 :   g13->status_cb.tag = 0;
     238           0 :   g13->status_cb.data = g13;
     239             : 
     240           0 :   pgmname = file_name ? file_name : _gpgme_get_default_g13_name ();
     241           0 :   argc = 0;
     242           0 :   argv[argc++] = _gpgme_get_basename (pgmname);
     243           0 :   if (home_dir)
     244             :     {
     245           0 :       argv[argc++] = "--homedir";
     246           0 :       argv[argc++] = home_dir;
     247             :     }
     248           0 :   argv[argc++] = "--server";
     249           0 :   argv[argc++] = NULL;
     250             : 
     251           0 :   err = assuan_new_ext (&g13->assuan_ctx, GPG_ERR_SOURCE_GPGME,
     252             :                         &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
     253             :                         NULL);
     254           0 :   if (err)
     255           0 :     goto leave;
     256           0 :   assuan_ctx_set_system_hooks (g13->assuan_ctx, &_gpgme_assuan_system_hooks);
     257             : 
     258             : #if USE_DESCRIPTOR_PASSING
     259           0 :   err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv,
     260             :                              NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
     261             : #else
     262             :   err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv,
     263             :                              NULL, NULL, NULL, 0);
     264             : #endif
     265           0 :   if (err)
     266           0 :     goto leave;
     267             : 
     268           0 :   err = _gpgme_getenv ("DISPLAY", &dft_display);
     269           0 :   if (err)
     270           0 :     goto leave;
     271           0 :   if (dft_display)
     272             :     {
     273           0 :       if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
     274             :         {
     275           0 :           free (dft_display);
     276           0 :           err = gpg_error_from_syserror ();
     277           0 :           goto leave;
     278             :         }
     279           0 :       free (dft_display);
     280             : 
     281           0 :       err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
     282             :                              NULL, NULL, NULL);
     283           0 :       free (optstr);
     284           0 :       if (err)
     285           0 :         goto leave;
     286             :     }
     287             : 
     288           0 :   err = _gpgme_getenv ("GPG_TTY", &env_tty);
     289           0 :   if (isatty (1) || env_tty || err)
     290             :     {
     291           0 :       int rc = 0;
     292             : 
     293           0 :       if (err)
     294           0 :         goto leave;
     295           0 :       else if (env_tty)
     296             :         {
     297           0 :           snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
     298           0 :           free (env_tty);
     299             :         }
     300             :       else
     301           0 :         rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
     302             : 
     303             :       /* Even though isatty() returns 1, ttyname_r() may fail in many
     304             :          ways, e.g., when /dev/pts is not accessible under chroot.  */
     305           0 :       if (!rc)
     306             :         {
     307           0 :           if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
     308             :             {
     309           0 :               err = gpg_error_from_syserror ();
     310           0 :               goto leave;
     311             :             }
     312           0 :           err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
     313             :                                  NULL, NULL, NULL);
     314           0 :           free (optstr);
     315           0 :           if (err)
     316           0 :             goto leave;
     317             : 
     318           0 :           err = _gpgme_getenv ("TERM", &dft_ttytype);
     319           0 :           if (err)
     320           0 :             goto leave;
     321           0 :           if (dft_ttytype)
     322             :             {
     323           0 :               if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
     324             :                 {
     325           0 :                   free (dft_ttytype);
     326           0 :                   err = gpg_error_from_syserror ();
     327           0 :                   goto leave;
     328             :                 }
     329           0 :               free (dft_ttytype);
     330             : 
     331           0 :               err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
     332             :                                      NULL, NULL, NULL, NULL);
     333           0 :               free (optstr);
     334           0 :               if (err)
     335           0 :                 goto leave;
     336             :             }
     337             :         }
     338             :     }
     339             : 
     340             : #ifdef HAVE_W32_SYSTEM
     341             :   /* Under Windows we need to use AllowSetForegroundWindow.  Tell
     342             :      g13 to tell us when it needs it.  */
     343             :   if (!err)
     344             :     {
     345             :       err = assuan_transact (g13->assuan_ctx, "OPTION allow-pinentry-notify",
     346             :                              NULL, NULL, NULL, NULL, NULL, NULL);
     347             :       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
     348             :         err = 0; /* This is a new feature of g13.  */
     349             :     }
     350             : #endif /*HAVE_W32_SYSTEM*/
     351             : 
     352             :  leave:
     353             : 
     354           0 :   if (err)
     355           0 :     g13_release (g13);
     356             :   else
     357           0 :     *engine = g13;
     358             : 
     359           0 :   return err;
     360             : }
     361             : 
     362             : 
     363             : static gpgme_error_t
     364           0 : g13_set_locale (void *engine, int category, const char *value)
     365             : {
     366           0 :   engine_g13_t g13 = engine;
     367             :   gpgme_error_t err;
     368             :   char *optstr;
     369             :   const char *catstr;
     370             : 
     371             :   /* FIXME: If value is NULL, we need to reset the option to default.
     372             :      But we can't do this.  So we error out here.  G13 needs support
     373             :      for this.  */
     374             :   if (0)
     375             :     ;
     376             : #ifdef LC_CTYPE
     377           0 :   else if (category == LC_CTYPE)
     378             :     {
     379           0 :       catstr = "lc-ctype";
     380           0 :       if (!value && g13->lc_ctype_set)
     381           0 :         return gpg_error (GPG_ERR_INV_VALUE);
     382           0 :       if (value)
     383           0 :         g13->lc_ctype_set = 1;
     384             :     }
     385             : #endif
     386             : #ifdef LC_MESSAGES
     387           0 :   else if (category == LC_MESSAGES)
     388             :     {
     389           0 :       catstr = "lc-messages";
     390           0 :       if (!value && g13->lc_messages_set)
     391           0 :         return gpg_error (GPG_ERR_INV_VALUE);
     392           0 :       if (value)
     393           0 :         g13->lc_messages_set = 1;
     394             :     }
     395             : #endif /* LC_MESSAGES */
     396             :   else
     397           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     398             : 
     399             :   /* FIXME: Reset value to default.  */
     400           0 :   if (!value)
     401           0 :     return 0;
     402             : 
     403           0 :   if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
     404           0 :     err = gpg_error_from_syserror ();
     405             :   else
     406             :     {
     407           0 :       err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
     408             :                              NULL, NULL, NULL, NULL);
     409           0 :       free (optstr);
     410             :     }
     411             : 
     412           0 :   return err;
     413             : }
     414             : 
     415             : 
     416             : #if USE_DESCRIPTOR_PASSING
     417             : static gpgme_error_t
     418           0 : g13_assuan_simple_command (assuan_context_t ctx, const char *cmd,
     419             :                            engine_status_handler_t status_fnc,
     420             :                            void *status_fnc_value)
     421             : {
     422             :   gpg_error_t err;
     423             :   char *line;
     424             :   size_t linelen;
     425             : 
     426             :   (void)status_fnc;
     427             :   (void)status_fnc_value;
     428             : 
     429           0 :   err = assuan_write_line (ctx, cmd);
     430           0 :   if (err)
     431           0 :     return err;
     432             : 
     433             :   do
     434             :     {
     435           0 :       err = assuan_read_line (ctx, &line, &linelen);
     436           0 :       if (err)
     437           0 :         return err;
     438             : 
     439           0 :       if (*line == '#' || !linelen)
     440           0 :         continue;
     441             : 
     442           0 :       if (linelen >= 2
     443           0 :           && line[0] == 'O' && line[1] == 'K'
     444           0 :           && (line[2] == '\0' || line[2] == ' '))
     445           0 :         return 0;
     446           0 :       else if (linelen >= 4
     447           0 :           && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
     448           0 :           && line[3] == ' ')
     449           0 :         err = atoi (&line[4]);
     450           0 :       else if (linelen >= 2
     451           0 :                && line[0] == 'S' && line[1] == ' ')
     452           0 :         {
     453             :           char *rest;
     454             : 
     455           0 :           rest = strchr (line + 2, ' ');
     456           0 :           if (!rest)
     457           0 :             rest = line + linelen; /* set to an empty string */
     458             :           else
     459           0 :             *(rest++) = 0;
     460             : 
     461             :           /* Nothing to do with status lines.  */
     462             :         }
     463             :       else
     464           0 :         err = gpg_error (GPG_ERR_GENERAL);
     465             :     }
     466           0 :   while (!err);
     467             : 
     468           0 :   return err;
     469             : }
     470             : #endif
     471             : 
     472             : 
     473             : static gpgme_error_t
     474           0 : status_handler (void *opaque, int fd)
     475             : {
     476           0 :   struct io_cb_data *data = (struct io_cb_data *) opaque;
     477           0 :   engine_g13_t g13 = (engine_g13_t) data->handler_value;
     478           0 :   gpgme_error_t err = 0;
     479             :   char *line;
     480             :   size_t linelen;
     481             : 
     482             :   do
     483             :     {
     484           0 :       err = assuan_read_line (g13->assuan_ctx, &line, &linelen);
     485           0 :       if (err)
     486             :         {
     487             :           /* Try our best to terminate the connection friendly.  */
     488             :           /*      assuan_write_line (g13->assuan_ctx, "BYE"); */
     489           0 :           TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
     490             :                   "fd 0x%x: error reading assuan line: %s",
     491             :                   fd, gpg_strerror (err));
     492             :         }
     493           0 :       else if (linelen >= 3
     494           0 :                && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
     495           0 :                && (line[3] == '\0' || line[3] == ' '))
     496             :         {
     497           0 :           if (line[3] == ' ')
     498           0 :             err = atoi (&line[4]);
     499           0 :           if (! err)
     500           0 :             err = gpg_error (GPG_ERR_GENERAL);
     501           0 :           TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
     502             :                   "fd 0x%x: ERR line: %s",
     503             :                   fd, err ? gpg_strerror (err) : "ok");
     504             : 
     505             :           /* Command execution errors are not fatal, as we use
     506             :              a session based protocol.  */
     507           0 :           data->op_err = err;
     508             : 
     509             :           /* The caller will do the rest (namely, call cancel_op,
     510             :              which closes status_fd).  */
     511           0 :           return 0;
     512             :         }
     513           0 :       else if (linelen >= 2
     514           0 :                && line[0] == 'O' && line[1] == 'K'
     515           0 :                && (line[2] == '\0' || line[2] == ' '))
     516             :         {
     517           0 :           TRACE1 (DEBUG_CTX, "gpgme:status_handler", g13,
     518             :                   "fd 0x%x: OK line", fd);
     519             : 
     520           0 :           _gpgme_io_close (g13->status_cb.fd);
     521           0 :           return 0;
     522             :         }
     523           0 :       else if (linelen > 2
     524           0 :                && line[0] == 'D' && line[1] == ' ')
     525           0 :         {
     526             :           /* We are using the colon handler even for plain inline data
     527             :              - strange name for that function but for historic reasons
     528             :              we keep it.  */
     529             :           /* FIXME We can't use this for binary data because we
     530             :              assume this is a string.  For the current usage of colon
     531             :              output it is correct.  */
     532           0 :           char *src = line + 2;
     533           0 :           char *end = line + linelen;
     534           0 :           char *dst = src;
     535             : 
     536           0 :           linelen = 0;
     537           0 :           while (src < end)
     538             :             {
     539           0 :               if (*src == '%' && src + 2 < end)
     540             :                 {
     541             :                   /* Handle escaped characters.  */
     542           0 :                   ++src;
     543           0 :                   *dst++ = _gpgme_hextobyte (src);
     544           0 :                   src += 2;
     545             :                 }
     546             :               else
     547           0 :                 *dst++ = *src++;
     548             : 
     549           0 :               linelen++;
     550             :             }
     551             : 
     552           0 :           src = line + 2;
     553           0 :           if (linelen && g13->user.data_cb)
     554           0 :             err = g13->user.data_cb (g13->user.data_cb_value,
     555             :                                        src, linelen);
     556             :           else
     557           0 :             err = 0;
     558             : 
     559           0 :           TRACE2 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
     560             :                   "fd 0x%x: D inlinedata; status from cb: %s",
     561             :                   fd, (g13->user.data_cb ?
     562             :                        (err? gpg_strerror (err):"ok"):"no callback"));
     563             : 
     564             :         }
     565           0 :       else if (linelen > 2
     566           0 :                && line[0] == 'S' && line[1] == ' ')
     567           0 :         {
     568             :           char *src;
     569             :           char *args;
     570             : 
     571           0 :           src = line + 2;
     572           0 :           while (*src == ' ')
     573           0 :             src++;
     574             : 
     575           0 :           args = strchr (line + 2, ' ');
     576           0 :           if (!args)
     577           0 :             args = line + linelen; /* set to an empty string */
     578             :           else
     579           0 :             *(args++) = 0;
     580             : 
     581           0 :           while (*args == ' ')
     582           0 :             args++;
     583             : 
     584           0 :           if (g13->user.status_cb)
     585           0 :             err = g13->user.status_cb (g13->user.status_cb_value,
     586             :                                        src, args);
     587             :           else
     588           0 :             err = 0;
     589             : 
     590           0 :           TRACE3 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
     591             :                   "fd 0x%x: S line (%s) - status from cb: %s",
     592             :                   fd, line+2, (g13->user.status_cb ?
     593             :                                (err? gpg_strerror (err):"ok"):"no callback"));
     594             :         }
     595           0 :       else if (linelen >= 7
     596           0 :                && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
     597           0 :                && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
     598           0 :                && line[6] == 'E'
     599           0 :                && (line[7] == '\0' || line[7] == ' '))
     600             :         {
     601             :           char *src;
     602             :           char *args;
     603             : 
     604           0 :           for (src=line+7; *src == ' '; src++)
     605             :             ;
     606             : 
     607           0 :           args = strchr (src, ' ');
     608           0 :           if (!args)
     609           0 :             args = line + linelen; /* Let it point to an empty string.  */
     610             :           else
     611           0 :             *(args++) = 0;
     612             : 
     613           0 :           while (*args == ' ')
     614           0 :             args++;
     615             : 
     616           0 :           err = default_inq_cb (g13, src, args);
     617           0 :           if (!err)
     618             :             {
     619             :               /* Flush and send END.  */
     620           0 :               err = assuan_send_data (g13->assuan_ctx, NULL, 0);
     621             :             }
     622           0 :           else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
     623             :             {
     624             :               /* Flush and send CANcel.  */
     625           0 :               err = assuan_send_data (g13->assuan_ctx, NULL, 1);
     626             :             }
     627           0 :           assuan_write_line (g13->assuan_ctx, "END");
     628             :         }
     629             :     }
     630           0 :   while (!err && assuan_pending_line (g13->assuan_ctx));
     631             : 
     632           0 :   return err;
     633             : }
     634             : 
     635             : 
     636             : static gpgme_error_t
     637           0 : add_io_cb (engine_g13_t g13, iocb_data_t *iocbd, gpgme_io_cb_t handler)
     638             : {
     639             :   gpgme_error_t err;
     640             : 
     641           0 :   TRACE_BEG2 (DEBUG_ENGINE, "engine-g13:add_io_cb", g13,
     642             :               "fd %d, dir %d", iocbd->fd, iocbd->dir);
     643           0 :   err = (*g13->io_cbs.add) (g13->io_cbs.add_priv,
     644             :                               iocbd->fd, iocbd->dir,
     645             :                               handler, iocbd->data, &iocbd->tag);
     646           0 :   if (err)
     647           0 :     return TRACE_ERR (err);
     648           0 :   if (!iocbd->dir)
     649             :     /* FIXME Kludge around poll() problem.  */
     650           0 :     err = _gpgme_io_set_nonblocking (iocbd->fd);
     651           0 :   return TRACE_ERR (err);
     652             : }
     653             : 
     654             : 
     655             : static gpgme_error_t
     656           0 : start (engine_g13_t g13, const char *command)
     657             : {
     658             :   gpgme_error_t err;
     659             :   assuan_fd_t afdlist[5];
     660             :   int fdlist[5];
     661             :   int nfds;
     662             :   int i;
     663             : 
     664             :   /* We need to know the fd used by assuan for reads.  We do this by
     665             :      using the assumption that the first returned fd from
     666             :      assuan_get_active_fds() is always this one.  */
     667           0 :   nfds = assuan_get_active_fds (g13->assuan_ctx, 0 /* read fds */,
     668             :                                 afdlist, DIM (afdlist));
     669           0 :   if (nfds < 1)
     670           0 :     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
     671             :   /* For now... */
     672           0 :   for (i = 0; i < nfds; i++)
     673           0 :     fdlist[i] = (int) afdlist[i];
     674             : 
     675             :   /* We "duplicate" the file descriptor, so we can close it here (we
     676             :      can't close fdlist[0], as that is closed by libassuan, and
     677             :      closing it here might cause libassuan to close some unrelated FD
     678             :      later).  Alternatively, we could special case status_fd and
     679             :      register/unregister it manually as needed, but this increases
     680             :      code duplication and is more complicated as we can not use the
     681             :      close notifications etc.  A third alternative would be to let
     682             :      Assuan know that we closed the FD, but that complicates the
     683             :      Assuan interface.  */
     684             : 
     685           0 :   g13->status_cb.fd = _gpgme_io_dup (fdlist[0]);
     686           0 :   if (g13->status_cb.fd < 0)
     687           0 :     return gpg_error_from_syserror ();
     688             : 
     689           0 :   if (_gpgme_io_set_close_notify (g13->status_cb.fd,
     690             :                                   close_notify_handler, g13))
     691             :     {
     692           0 :       _gpgme_io_close (g13->status_cb.fd);
     693           0 :       g13->status_cb.fd = -1;
     694           0 :       return gpg_error (GPG_ERR_GENERAL);
     695             :     }
     696             : 
     697           0 :   err = add_io_cb (g13, &g13->status_cb, status_handler);
     698           0 :   if (!err)
     699           0 :     err = assuan_write_line (g13->assuan_ctx, command);
     700             : 
     701           0 :   if (!err)
     702           0 :     g13_io_event (g13, GPGME_EVENT_START, NULL);
     703             : 
     704           0 :   return err;
     705             : }
     706             : 
     707             : 
     708             : #if USE_DESCRIPTOR_PASSING
     709             : static gpgme_error_t
     710           0 : g13_reset (void *engine)
     711             : {
     712           0 :   engine_g13_t g13 = engine;
     713             : 
     714             :   /* We must send a reset because we need to reset the list of
     715             :      signers.  Note that RESET does not reset OPTION commands. */
     716           0 :   return g13_assuan_simple_command (g13->assuan_ctx, "RESET", NULL, NULL);
     717             : }
     718             : #endif
     719             : 
     720             : 
     721             : static gpgme_error_t
     722           0 : g13_transact (void *engine,
     723             :                 const char *command,
     724             :                 gpgme_assuan_data_cb_t data_cb,
     725             :                 void *data_cb_value,
     726             :                 gpgme_assuan_inquire_cb_t inq_cb,
     727             :                 void *inq_cb_value,
     728             :                 gpgme_assuan_status_cb_t status_cb,
     729             :                 void *status_cb_value)
     730             : {
     731           0 :   engine_g13_t g13 = engine;
     732             :   gpgme_error_t err;
     733             : 
     734           0 :   if (!g13 || !command || !*command)
     735           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     736             : 
     737           0 :   g13->user.data_cb = data_cb;
     738           0 :   g13->user.data_cb_value = data_cb_value;
     739           0 :   g13->user.inq_cb = inq_cb;
     740           0 :   g13->user.inq_cb_value = inq_cb_value;
     741           0 :   g13->user.status_cb = status_cb;
     742           0 :   g13->user.status_cb_value = status_cb_value;
     743             : 
     744           0 :   err = start (g13, command);
     745           0 :   return err;
     746             : }
     747             : 
     748             : 
     749             : 
     750             : static void
     751           0 : g13_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
     752             : {
     753           0 :   engine_g13_t g13 = engine;
     754           0 :   g13->io_cbs = *io_cbs;
     755           0 : }
     756             : 
     757             : 
     758             : static void
     759           0 : g13_io_event (void *engine, gpgme_event_io_t type, void *type_data)
     760             : {
     761           0 :   engine_g13_t g13 = engine;
     762             : 
     763           0 :   TRACE3 (DEBUG_ENGINE, "gpgme:g13_io_event", g13,
     764             :           "event %p, type %d, type_data %p",
     765             :           g13->io_cbs.event, type, type_data);
     766           0 :   if (g13->io_cbs.event)
     767           0 :     (*g13->io_cbs.event) (g13->io_cbs.event_priv, type, type_data);
     768           0 : }
     769             : 
     770             : 
     771             : struct engine_ops _gpgme_engine_ops_g13 =
     772             :   {
     773             :     /* Static functions.  */
     774             :     _gpgme_get_default_g13_name,
     775             :     NULL,
     776             :     g13_get_version,
     777             :     g13_get_req_version,
     778             :     g13_new,
     779             : 
     780             :     /* Member functions.  */
     781             :     g13_release,
     782             : #if USE_DESCRIPTOR_PASSING
     783             :     g13_reset,
     784             : #else
     785             :     NULL,                       /* reset */
     786             : #endif
     787             :     NULL,               /* set_status_cb */
     788             :     NULL,               /* set_status_handler */
     789             :     NULL,               /* set_command_handler */
     790             :     NULL,               /* set_colon_line_handler */
     791             :     g13_set_locale,
     792             :     NULL,               /* set_protocol */
     793             :     NULL,               /* decrypt */
     794             :     NULL,               /* decrypt_verify */
     795             :     NULL,               /* delete */
     796             :     NULL,               /* edit */
     797             :     NULL,               /* encrypt */
     798             :     NULL,               /* encrypt_sign */
     799             :     NULL,               /* export */
     800             :     NULL,               /* export_ext */
     801             :     NULL,               /* genkey */
     802             :     NULL,               /* import */
     803             :     NULL,               /* keylist */
     804             :     NULL,               /* keylist_ext */
     805             :     NULL,               /* keysign */
     806             :     NULL,               /* tofu_policy */
     807             :     NULL,               /* sign */
     808             :     NULL,               /* trustlist */
     809             :     NULL,               /* verify */
     810             :     NULL,               /* getauditlog */
     811             :     g13_transact,
     812             :     NULL,               /* conf_load */
     813             :     NULL,               /* conf_save */
     814             :     NULL,               /* query_swdb */
     815             :     g13_set_io_cbs,
     816             :     g13_io_event,
     817             :     g13_cancel,
     818             :     g13_cancel_op,
     819             :     NULL,               /* passwd */
     820             :     NULL,               /* set_pinentry_mode */
     821             :     NULL                /* opspawn */
     822             :   };

Generated by: LCOV version 1.11