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

Generated by: LCOV version 1.11