LCOV - code coverage report
Current view: top level - src - engine-g13.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 291 0.0 %
Date: 2015-11-05 17:14:26 Functions: 0 17 0.0 %

          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           0 : g13_get_version (const char *file_name)
     101             : {
     102           0 :   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             : {
     217           0 :   gpgme_error_t err = 0;
     218             :   engine_g13_t g13;
     219             :   const char *pgmname;
     220             :   int argc;
     221             :   const char *argv[5];
     222           0 :   char *dft_display = NULL;
     223             :   char dft_ttyname[64];
     224           0 :   char *dft_ttytype = NULL;
     225             :   char *optstr;
     226             : 
     227           0 :   g13 = calloc (1, sizeof *g13);
     228           0 :   if (!g13)
     229           0 :     return gpg_error_from_syserror ();
     230             : 
     231           0 :   g13->status_cb.fd = -1;
     232           0 :   g13->status_cb.dir = 1;
     233           0 :   g13->status_cb.tag = 0;
     234           0 :   g13->status_cb.data = g13;
     235             : 
     236           0 :   pgmname = file_name ? file_name : _gpgme_get_default_g13_name ();
     237           0 :   argc = 0;
     238           0 :   argv[argc++] = _gpgme_get_basename (pgmname);
     239           0 :   if (home_dir)
     240             :     {
     241           0 :       argv[argc++] = "--homedir";
     242           0 :       argv[argc++] = home_dir;
     243             :     }
     244           0 :   argv[argc++] = "--server";
     245           0 :   argv[argc++] = NULL;
     246             : 
     247           0 :   err = assuan_new_ext (&g13->assuan_ctx, GPG_ERR_SOURCE_GPGME,
     248             :                         &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
     249             :                         NULL);
     250           0 :   if (err)
     251           0 :     goto leave;
     252           0 :   assuan_ctx_set_system_hooks (g13->assuan_ctx, &_gpgme_assuan_system_hooks);
     253             : 
     254             : #if USE_DESCRIPTOR_PASSING
     255           0 :   err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv,
     256             :                              NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
     257             : #else
     258             :   err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv,
     259             :                              NULL, NULL, NULL, 0);
     260             : #endif
     261           0 :   if (err)
     262           0 :     goto leave;
     263             : 
     264           0 :   err = _gpgme_getenv ("DISPLAY", &dft_display);
     265           0 :   if (err)
     266           0 :     goto leave;
     267           0 :   if (dft_display)
     268             :     {
     269           0 :       if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
     270             :         {
     271           0 :           free (dft_display);
     272           0 :           err = gpg_error_from_syserror ();
     273           0 :           goto leave;
     274             :         }
     275           0 :       free (dft_display);
     276             : 
     277           0 :       err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
     278             :                              NULL, NULL, NULL);
     279           0 :       free (optstr);
     280           0 :       if (err)
     281           0 :         goto leave;
     282             :     }
     283             : 
     284           0 :   if (isatty (1))
     285             :     {
     286             :       int rc;
     287             : 
     288           0 :       rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
     289             : 
     290             :       /* Even though isatty() returns 1, ttyname_r() may fail in many
     291             :          ways, e.g., when /dev/pts is not accessible under chroot.  */
     292           0 :       if (!rc)
     293             :         {
     294           0 :           if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
     295             :             {
     296           0 :               err = gpg_error_from_syserror ();
     297           0 :               goto leave;
     298             :             }
     299           0 :           err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL,
     300             :                                  NULL, NULL, NULL);
     301           0 :           free (optstr);
     302           0 :           if (err)
     303           0 :             goto leave;
     304             : 
     305           0 :           err = _gpgme_getenv ("TERM", &dft_ttytype);
     306           0 :           if (err)
     307           0 :             goto leave;
     308           0 :           if (dft_ttytype)
     309             :             {
     310           0 :               if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
     311             :                 {
     312           0 :                   free (dft_ttytype);
     313           0 :                   err = gpg_error_from_syserror ();
     314           0 :                   goto leave;
     315             :                 }
     316           0 :               free (dft_ttytype);
     317             : 
     318           0 :               err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
     319             :                                      NULL, NULL, NULL, NULL);
     320           0 :               free (optstr);
     321           0 :               if (err)
     322           0 :                 goto leave;
     323             :             }
     324             :         }
     325             :     }
     326             : 
     327             : #ifdef HAVE_W32_SYSTEM
     328             :   /* Under Windows we need to use AllowSetForegroundWindow.  Tell
     329             :      g13 to tell us when it needs it.  */
     330             :   if (!err)
     331             :     {
     332             :       err = assuan_transact (g13->assuan_ctx, "OPTION allow-pinentry-notify",
     333             :                              NULL, NULL, NULL, NULL, NULL, NULL);
     334             :       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
     335             :         err = 0; /* This is a new feature of g13.  */
     336             :     }
     337             : #endif /*HAVE_W32_SYSTEM*/
     338             : 
     339             :  leave:
     340             : 
     341           0 :   if (err)
     342           0 :     g13_release (g13);
     343             :   else
     344           0 :     *engine = g13;
     345             : 
     346           0 :   return err;
     347             : }
     348             : 
     349             : 
     350             : static gpgme_error_t
     351           0 : g13_set_locale (void *engine, int category, const char *value)
     352             : {
     353           0 :   engine_g13_t g13 = engine;
     354             :   gpgme_error_t err;
     355             :   char *optstr;
     356             :   char *catstr;
     357             : 
     358             :   /* FIXME: If value is NULL, we need to reset the option to default.
     359             :      But we can't do this.  So we error out here.  G13 needs support
     360             :      for this.  */
     361             :   if (0)
     362             :     ;
     363             : #ifdef LC_CTYPE
     364           0 :   else if (category == LC_CTYPE)
     365             :     {
     366           0 :       catstr = "lc-ctype";
     367           0 :       if (!value && g13->lc_ctype_set)
     368           0 :         return gpg_error (GPG_ERR_INV_VALUE);
     369           0 :       if (value)
     370           0 :         g13->lc_ctype_set = 1;
     371             :     }
     372             : #endif
     373             : #ifdef LC_MESSAGES
     374           0 :   else if (category == LC_MESSAGES)
     375             :     {
     376           0 :       catstr = "lc-messages";
     377           0 :       if (!value && g13->lc_messages_set)
     378           0 :         return gpg_error (GPG_ERR_INV_VALUE);
     379           0 :       if (value)
     380           0 :         g13->lc_messages_set = 1;
     381             :     }
     382             : #endif /* LC_MESSAGES */
     383             :   else
     384           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     385             : 
     386             :   /* FIXME: Reset value to default.  */
     387           0 :   if (!value)
     388           0 :     return 0;
     389             : 
     390           0 :   if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
     391           0 :     err = gpg_error_from_syserror ();
     392             :   else
     393             :     {
     394           0 :       err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL,
     395             :                              NULL, NULL, NULL, NULL);
     396           0 :       free (optstr);
     397             :     }
     398             : 
     399           0 :   return err;
     400             : }
     401             : 
     402             : 
     403             : #if USE_DESCRIPTOR_PASSING
     404             : static gpgme_error_t
     405           0 : g13_assuan_simple_command (assuan_context_t ctx, char *cmd,
     406             :                            engine_status_handler_t status_fnc,
     407             :                            void *status_fnc_value)
     408             : {
     409             :   gpg_error_t err;
     410             :   char *line;
     411             :   size_t linelen;
     412             : 
     413           0 :   err = assuan_write_line (ctx, cmd);
     414           0 :   if (err)
     415           0 :     return err;
     416             : 
     417             :   do
     418             :     {
     419           0 :       err = assuan_read_line (ctx, &line, &linelen);
     420           0 :       if (err)
     421           0 :         return err;
     422             : 
     423           0 :       if (*line == '#' || !linelen)
     424           0 :         continue;
     425             : 
     426           0 :       if (linelen >= 2
     427           0 :           && line[0] == 'O' && line[1] == 'K'
     428           0 :           && (line[2] == '\0' || line[2] == ' '))
     429           0 :         return 0;
     430           0 :       else if (linelen >= 4
     431           0 :           && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
     432           0 :           && line[3] == ' ')
     433           0 :         err = atoi (&line[4]);
     434           0 :       else if (linelen >= 2
     435           0 :                && line[0] == 'S' && line[1] == ' ')
     436           0 :         {
     437             :           char *rest;
     438             : 
     439           0 :           rest = strchr (line + 2, ' ');
     440           0 :           if (!rest)
     441           0 :             rest = line + linelen; /* set to an empty string */
     442             :           else
     443           0 :             *(rest++) = 0;
     444             : 
     445             :           /* Nothing to do with status lines.  */
     446             :         }
     447             :       else
     448           0 :         err = gpg_error (GPG_ERR_GENERAL);
     449             :     }
     450           0 :   while (!err);
     451             : 
     452           0 :   return err;
     453             : }
     454             : #endif
     455             : 
     456             : 
     457             : static gpgme_error_t
     458           0 : status_handler (void *opaque, int fd)
     459             : {
     460           0 :   struct io_cb_data *data = (struct io_cb_data *) opaque;
     461           0 :   engine_g13_t g13 = (engine_g13_t) data->handler_value;
     462           0 :   gpgme_error_t err = 0;
     463             :   char *line;
     464             :   size_t linelen;
     465             : 
     466             :   do
     467             :     {
     468           0 :       err = assuan_read_line (g13->assuan_ctx, &line, &linelen);
     469           0 :       if (err)
     470             :         {
     471             :           /* Try our best to terminate the connection friendly.  */
     472             :           /*      assuan_write_line (g13->assuan_ctx, "BYE"); */
     473           0 :           TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
     474             :                   "fd 0x%x: error reading assuan line: %s",
     475             :                   fd, gpg_strerror (err));
     476             :         }
     477           0 :       else if (linelen >= 3
     478           0 :                && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
     479           0 :                && (line[3] == '\0' || line[3] == ' '))
     480             :         {
     481           0 :           if (line[3] == ' ')
     482           0 :             err = atoi (&line[4]);
     483           0 :           if (! err)
     484           0 :             err = gpg_error (GPG_ERR_GENERAL);
     485           0 :           TRACE2 (DEBUG_CTX, "gpgme:status_handler", g13,
     486             :                   "fd 0x%x: ERR line: %s",
     487             :                   fd, err ? gpg_strerror (err) : "ok");
     488             : 
     489             :           /* Command execution errors are not fatal, as we use
     490             :              a session based protocol.  */
     491           0 :           data->op_err = err;
     492             : 
     493             :           /* The caller will do the rest (namely, call cancel_op,
     494             :              which closes status_fd).  */
     495           0 :           return 0;
     496             :         }
     497           0 :       else if (linelen >= 2
     498           0 :                && line[0] == 'O' && line[1] == 'K'
     499           0 :                && (line[2] == '\0' || line[2] == ' '))
     500             :         {
     501           0 :           TRACE1 (DEBUG_CTX, "gpgme:status_handler", g13,
     502             :                   "fd 0x%x: OK line", fd);
     503             : 
     504           0 :           _gpgme_io_close (g13->status_cb.fd);
     505           0 :           return 0;
     506             :         }
     507           0 :       else if (linelen > 2
     508           0 :                && line[0] == 'D' && line[1] == ' ')
     509           0 :         {
     510             :           /* We are using the colon handler even for plain inline data
     511             :              - strange name for that function but for historic reasons
     512             :              we keep it.  */
     513             :           /* FIXME We can't use this for binary data because we
     514             :              assume this is a string.  For the current usage of colon
     515             :              output it is correct.  */
     516           0 :           char *src = line + 2;
     517           0 :           char *end = line + linelen;
     518           0 :           char *dst = src;
     519             : 
     520           0 :           linelen = 0;
     521           0 :           while (src < end)
     522             :             {
     523           0 :               if (*src == '%' && src + 2 < end)
     524             :                 {
     525             :                   /* Handle escaped characters.  */
     526           0 :                   ++src;
     527           0 :                   *dst++ = _gpgme_hextobyte (src);
     528           0 :                   src += 2;
     529             :                 }
     530             :               else
     531           0 :                 *dst++ = *src++;
     532             : 
     533           0 :               linelen++;
     534             :             }
     535             : 
     536           0 :           src = line + 2;
     537           0 :           if (linelen && g13->user.data_cb)
     538           0 :             err = g13->user.data_cb (g13->user.data_cb_value,
     539             :                                        src, linelen);
     540             :           else
     541           0 :             err = 0;
     542             : 
     543           0 :           TRACE2 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
     544             :                   "fd 0x%x: D inlinedata; status from cb: %s",
     545             :                   fd, (g13->user.data_cb ?
     546             :                        (err? gpg_strerror (err):"ok"):"no callback"));
     547             : 
     548             :         }
     549           0 :       else if (linelen > 2
     550           0 :                && line[0] == 'S' && line[1] == ' ')
     551           0 :         {
     552             :           char *src;
     553             :           char *args;
     554             : 
     555           0 :           src = line + 2;
     556           0 :           while (*src == ' ')
     557           0 :             src++;
     558             : 
     559           0 :           args = strchr (line + 2, ' ');
     560           0 :           if (!args)
     561           0 :             args = line + linelen; /* set to an empty string */
     562             :           else
     563           0 :             *(args++) = 0;
     564             : 
     565           0 :           while (*args == ' ')
     566           0 :             args++;
     567             : 
     568           0 :           if (g13->user.status_cb)
     569           0 :             err = g13->user.status_cb (g13->user.status_cb_value,
     570             :                                        src, args);
     571             :           else
     572           0 :             err = 0;
     573             : 
     574           0 :           TRACE3 (DEBUG_CTX, "gpgme:g13_status_handler", g13,
     575             :                   "fd 0x%x: S line (%s) - status from cb: %s",
     576             :                   fd, line+2, (g13->user.status_cb ?
     577             :                                (err? gpg_strerror (err):"ok"):"no callback"));
     578             :         }
     579           0 :       else if (linelen >= 7
     580           0 :                && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
     581           0 :                && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
     582           0 :                && line[6] == 'E'
     583           0 :                && (line[7] == '\0' || line[7] == ' '))
     584             :         {
     585             :           char *src;
     586             :           char *args;
     587             : 
     588           0 :           for (src=line+7; *src == ' '; src++)
     589             :             ;
     590             : 
     591           0 :           args = strchr (src, ' ');
     592           0 :           if (!args)
     593           0 :             args = line + linelen; /* Let it point to an empty string.  */
     594             :           else
     595           0 :             *(args++) = 0;
     596             : 
     597           0 :           while (*args == ' ')
     598           0 :             args++;
     599             : 
     600           0 :           err = default_inq_cb (g13, src, args);
     601           0 :           if (!err)
     602             :             {
     603             :               /* Flush and send END.  */
     604           0 :               err = assuan_send_data (g13->assuan_ctx, NULL, 0);
     605             :             }
     606           0 :           else if (gpg_err_code (err) == GPG_ERR_ASS_CANCELED)
     607             :             {
     608             :               /* Flush and send CANcel.  */
     609           0 :               err = assuan_send_data (g13->assuan_ctx, NULL, 1);
     610             :             }
     611           0 :           assuan_write_line (g13->assuan_ctx, "END");
     612             :         }
     613             :     }
     614           0 :   while (!err && assuan_pending_line (g13->assuan_ctx));
     615             : 
     616           0 :   return err;
     617             : }
     618             : 
     619             : 
     620             : static gpgme_error_t
     621           0 : add_io_cb (engine_g13_t g13, iocb_data_t *iocbd, gpgme_io_cb_t handler)
     622             : {
     623             :   gpgme_error_t err;
     624             : 
     625           0 :   TRACE_BEG2 (DEBUG_ENGINE, "engine-g13:add_io_cb", g13,
     626             :               "fd %d, dir %d", iocbd->fd, iocbd->dir);
     627           0 :   err = (*g13->io_cbs.add) (g13->io_cbs.add_priv,
     628             :                               iocbd->fd, iocbd->dir,
     629             :                               handler, iocbd->data, &iocbd->tag);
     630           0 :   if (err)
     631           0 :     return TRACE_ERR (err);
     632           0 :   if (!iocbd->dir)
     633             :     /* FIXME Kludge around poll() problem.  */
     634           0 :     err = _gpgme_io_set_nonblocking (iocbd->fd);
     635           0 :   return TRACE_ERR (err);
     636             : }
     637             : 
     638             : 
     639             : static gpgme_error_t
     640           0 : start (engine_g13_t g13, const char *command)
     641             : {
     642             :   gpgme_error_t err;
     643             :   assuan_fd_t afdlist[5];
     644             :   int fdlist[5];
     645             :   int nfds;
     646             :   int i;
     647             : 
     648             :   /* We need to know the fd used by assuan for reads.  We do this by
     649             :      using the assumption that the first returned fd from
     650             :      assuan_get_active_fds() is always this one.  */
     651           0 :   nfds = assuan_get_active_fds (g13->assuan_ctx, 0 /* read fds */,
     652             :                                 afdlist, DIM (afdlist));
     653           0 :   if (nfds < 1)
     654           0 :     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
     655             :   /* For now... */
     656           0 :   for (i = 0; i < nfds; i++)
     657           0 :     fdlist[i] = (int) afdlist[i];
     658             : 
     659             :   /* We "duplicate" the file descriptor, so we can close it here (we
     660             :      can't close fdlist[0], as that is closed by libassuan, and
     661             :      closing it here might cause libassuan to close some unrelated FD
     662             :      later).  Alternatively, we could special case status_fd and
     663             :      register/unregister it manually as needed, but this increases
     664             :      code duplication and is more complicated as we can not use the
     665             :      close notifications etc.  A third alternative would be to let
     666             :      Assuan know that we closed the FD, but that complicates the
     667             :      Assuan interface.  */
     668             : 
     669           0 :   g13->status_cb.fd = _gpgme_io_dup (fdlist[0]);
     670           0 :   if (g13->status_cb.fd < 0)
     671           0 :     return gpg_error_from_syserror ();
     672             : 
     673           0 :   if (_gpgme_io_set_close_notify (g13->status_cb.fd,
     674             :                                   close_notify_handler, g13))
     675             :     {
     676           0 :       _gpgme_io_close (g13->status_cb.fd);
     677           0 :       g13->status_cb.fd = -1;
     678           0 :       return gpg_error (GPG_ERR_GENERAL);
     679             :     }
     680             : 
     681           0 :   err = add_io_cb (g13, &g13->status_cb, status_handler);
     682           0 :   if (!err)
     683           0 :     err = assuan_write_line (g13->assuan_ctx, command);
     684             : 
     685           0 :   if (!err)
     686           0 :     g13_io_event (g13, GPGME_EVENT_START, NULL);
     687             : 
     688           0 :   return err;
     689             : }
     690             : 
     691             : 
     692             : #if USE_DESCRIPTOR_PASSING
     693             : static gpgme_error_t
     694           0 : g13_reset (void *engine)
     695             : {
     696           0 :   engine_g13_t g13 = engine;
     697             : 
     698             :   /* We must send a reset because we need to reset the list of
     699             :      signers.  Note that RESET does not reset OPTION commands. */
     700           0 :   return g13_assuan_simple_command (g13->assuan_ctx, "RESET", NULL, NULL);
     701             : }
     702             : #endif
     703             : 
     704             : 
     705             : static gpgme_error_t
     706           0 : g13_transact (void *engine,
     707             :                 const char *command,
     708             :                 gpgme_assuan_data_cb_t data_cb,
     709             :                 void *data_cb_value,
     710             :                 gpgme_assuan_inquire_cb_t inq_cb,
     711             :                 void *inq_cb_value,
     712             :                 gpgme_assuan_status_cb_t status_cb,
     713             :                 void *status_cb_value)
     714             : {
     715           0 :   engine_g13_t g13 = engine;
     716             :   gpgme_error_t err;
     717             : 
     718           0 :   if (!g13 || !command || !*command)
     719           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     720             : 
     721           0 :   g13->user.data_cb = data_cb;
     722           0 :   g13->user.data_cb_value = data_cb_value;
     723           0 :   g13->user.inq_cb = inq_cb;
     724           0 :   g13->user.inq_cb_value = inq_cb_value;
     725           0 :   g13->user.status_cb = status_cb;
     726           0 :   g13->user.status_cb_value = status_cb_value;
     727             : 
     728           0 :   err = start (g13, command);
     729           0 :   return err;
     730             : }
     731             : 
     732             : 
     733             : 
     734             : static void
     735           0 : g13_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
     736             : {
     737           0 :   engine_g13_t g13 = engine;
     738           0 :   g13->io_cbs = *io_cbs;
     739           0 : }
     740             : 
     741             : 
     742             : static void
     743           0 : g13_io_event (void *engine, gpgme_event_io_t type, void *type_data)
     744             : {
     745           0 :   engine_g13_t g13 = engine;
     746             : 
     747           0 :   TRACE3 (DEBUG_ENGINE, "gpgme:g13_io_event", g13,
     748             :           "event %p, type %d, type_data %p",
     749             :           g13->io_cbs.event, type, type_data);
     750           0 :   if (g13->io_cbs.event)
     751           0 :     (*g13->io_cbs.event) (g13->io_cbs.event_priv, type, type_data);
     752           0 : }
     753             : 
     754             : 
     755             : struct engine_ops _gpgme_engine_ops_g13 =
     756             :   {
     757             :     /* Static functions.  */
     758             :     _gpgme_get_default_g13_name,
     759             :     NULL,
     760             :     g13_get_version,
     761             :     g13_get_req_version,
     762             :     g13_new,
     763             : 
     764             :     /* Member functions.  */
     765             :     g13_release,
     766             : #if USE_DESCRIPTOR_PASSING
     767             :     g13_reset,
     768             : #else
     769             :     NULL,                       /* reset */
     770             : #endif
     771             :     NULL,               /* set_status_handler */
     772             :     NULL,               /* set_command_handler */
     773             :     NULL,               /* set_colon_line_handler */
     774             :     g13_set_locale,
     775             :     NULL,               /* set_protocol */
     776             :     NULL,               /* decrypt */
     777             :     NULL,               /* decrypt_verify */
     778             :     NULL,               /* delete */
     779             :     NULL,               /* edit */
     780             :     NULL,               /* encrypt */
     781             :     NULL,               /* encrypt_sign */
     782             :     NULL,               /* export */
     783             :     NULL,               /* export_ext */
     784             :     NULL,               /* genkey */
     785             :     NULL,               /* import */
     786             :     NULL,               /* keylist */
     787             :     NULL,               /* keylist_ext */
     788             :     NULL,               /* sign */
     789             :     NULL,               /* trustlist */
     790             :     NULL,               /* verify */
     791             :     NULL,               /* getauditlog */
     792             :     g13_transact,
     793             :     NULL,               /* conf_load */
     794             :     NULL,               /* conf_save */
     795             :     g13_set_io_cbs,
     796             :     g13_io_event,
     797             :     g13_cancel,
     798             :     g13_cancel_op,
     799             :     NULL,               /* passwd */
     800             :     NULL,               /* set_pinentry_mode */
     801             :     NULL                /* opspawn */
     802             :   };

Generated by: LCOV version 1.11