LCOV - code coverage report
Current view: top level - common - simple-pwquery.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 135 278 48.6 %
Date: 2015-11-05 17:10:59 Functions: 7 10 70.0 %

          Line data    Source code
       1             : /* simple-pwquery.c - A simple password query client for gpg-agent
       2             :  *      Copyright (C) 2002, 2004, 2007 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : /* This module is intended as a standalone client implementation to
      21             :    gpg-agent's GET_PASSPHRASE command.  In particular it does not use
      22             :    the Assuan library and can only cope with an already running
      23             :    gpg-agent.  Some stuff is configurable in the header file. */
      24             : 
      25             : #ifdef HAVE_CONFIG_H
      26             : #include <config.h>
      27             : #endif
      28             : #include <stdlib.h>
      29             : #include <stddef.h>
      30             : #include <string.h>
      31             : #include <errno.h>
      32             : #include <unistd.h>
      33             : #ifdef HAVE_W32_SYSTEM
      34             : #include <winsock2.h>
      35             : #else
      36             : #include <sys/socket.h>
      37             : #include <sys/un.h>
      38             : #endif
      39             : #ifdef HAVE_LOCALE_H
      40             : #include <locale.h>
      41             : #endif
      42             : 
      43             : #define GNUPG_COMMON_NEED_AFLOCAL
      44             : #include "../common/mischelp.h"
      45             : #ifdef HAVE_W32_SYSTEM
      46             : #include "../common/w32-afunix.h"
      47             : #endif
      48             : 
      49             : 
      50             : #define SIMPLE_PWQUERY_IMPLEMENTATION 1
      51             : #include "simple-pwquery.h"
      52             : 
      53             : #ifndef _
      54             : #define _(a) (a)
      55             : #endif
      56             : 
      57             : #if !defined (hexdigitp) && !defined (xtoi_2)
      58             : #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
      59             : #define hexdigitp(a) (digitp (a)                     \
      60             :                       || (*(a) >= 'A' && *(a) <= 'F')  \
      61             :                       || (*(a) >= 'a' && *(a) <= 'f'))
      62             : #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
      63             :                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
      64             : #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
      65             : #endif
      66             : 
      67             : 
      68             : /* Name of the socket to be used.  This is a kludge to keep on using
      69             :    the existsing code despite that we only support a standard socket.  */
      70             : static char *default_gpg_agent_info;
      71             : 
      72             : 
      73             : 
      74             : 
      75             : 
      76             : #ifndef HAVE_STPCPY
      77             : static char *
      78             : my_stpcpy(char *a,const char *b)
      79             : {
      80             :     while( *b )
      81             :         *a++ = *b++;
      82             :     *a = 0;
      83             : 
      84             :     return (char*)a;
      85             : }
      86             : #define stpcpy(a,b)  my_stpcpy((a), (b))
      87             : #endif
      88             : 
      89             : 
      90             : 
      91             : /* Write NBYTES of BUF to file descriptor FD. */
      92             : static int
      93          60 : writen (int fd, const void *buf, size_t nbytes)
      94             : {
      95          60 :   size_t nleft = nbytes;
      96             :   int nwritten;
      97             : 
      98         180 :   while (nleft > 0)
      99             :     {
     100             : #ifdef HAVE_W32_SYSTEM
     101             :       nwritten = send (fd, buf, nleft, 0);
     102             : #else
     103          60 :       nwritten = write (fd, buf, nleft);
     104             : #endif
     105          60 :       if (nwritten < 0)
     106             :         {
     107           0 :           if (errno == EINTR)
     108           0 :             nwritten = 0;
     109             :           else {
     110             : #ifdef SPWQ_USE_LOGGING
     111           0 :             log_error ("write failed: %s\n", strerror (errno));
     112             : #endif
     113           0 :             return SPWQ_IO_ERROR;
     114             :           }
     115             :         }
     116          60 :       nleft -= nwritten;
     117          60 :       buf = (const char*)buf + nwritten;
     118             :     }
     119             : 
     120          60 :   return 0;
     121             : }
     122             : 
     123             : 
     124             : /* Read an entire line and return number of bytes read. */
     125             : static int
     126          70 : readline (int fd, char *buf, size_t buflen)
     127             : {
     128          70 :   size_t nleft = buflen;
     129             :   char *p;
     130          70 :   int nread = 0;
     131             : 
     132         140 :   while (nleft > 0)
     133             :     {
     134             : #ifdef HAVE_W32_SYSTEM
     135             :       int n = recv (fd, buf, nleft, 0);
     136             : #else
     137          70 :       int n = read (fd, buf, nleft);
     138             : #endif
     139          70 :       if (n < 0)
     140             :         {
     141           0 :           if (errno == EINTR)
     142           0 :             continue;
     143           0 :           return -(SPWQ_IO_ERROR);
     144             :         }
     145          70 :       else if (!n)
     146             :         {
     147           0 :           return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
     148             :         }
     149          70 :       p = buf;
     150          70 :       nleft -= n;
     151          70 :       buf += n;
     152          70 :       nread += n;
     153             : 
     154          70 :       for (; n && *p != '\n'; n--, p++)
     155             :         ;
     156          70 :       if (n)
     157             :         {
     158          70 :           break; /* At least one full line available - that's enough.
     159             :                     This function is just a simple implementation, so
     160             :                     it is okay to forget about pending bytes.  */
     161             :         }
     162             :     }
     163             : 
     164          70 :   return nread;
     165             : }
     166             : 
     167             : 
     168             : /* Send an option to the agent */
     169             : static int
     170          50 : agent_send_option (int fd, const char *name, const char *value)
     171             : {
     172             :   char buf[200];
     173             :   int nread;
     174             :   char *line;
     175             :   int i;
     176             : 
     177          50 :   line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
     178          50 :   if (!line)
     179           0 :     return SPWQ_OUT_OF_CORE;
     180          50 :   strcpy (stpcpy (stpcpy (stpcpy (
     181          50 :                      stpcpy (line, "OPTION "), name), "="), value), "\n");
     182          50 :   i = writen (fd, line, strlen (line));
     183          50 :   spwq_free (line);
     184          50 :   if (i)
     185           0 :     return i;
     186             : 
     187             :   /* get response */
     188          50 :   nread = readline (fd, buf, DIM(buf)-1);
     189          50 :   if (nread < 0)
     190           0 :     return -nread;
     191          50 :   if (nread < 3)
     192           0 :     return SPWQ_PROTOCOL_ERROR;
     193             : 
     194          50 :   if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
     195          50 :     return 0; /* okay */
     196             : 
     197           0 :   return SPWQ_ERR_RESPONSE;
     198             : }
     199             : 
     200             : 
     201             : /* Send all available options to the agent. */
     202             : static int
     203          10 : agent_send_all_options (int fd)
     204             : {
     205          10 :   char *dft_display = NULL;
     206          10 :   char *dft_ttyname = NULL;
     207          10 :   char *dft_ttytype = NULL;
     208          10 :   char *dft_xauthority = NULL;
     209          10 :   char *dft_pinentry_user_data = NULL;
     210          10 :   int rc = 0;
     211             : 
     212          10 :   dft_display = getenv ("DISPLAY");
     213          10 :   if (dft_display)
     214             :     {
     215          10 :       if ((rc = agent_send_option (fd, "display", dft_display)))
     216           0 :         return rc;
     217             :     }
     218             : 
     219          10 :   dft_ttyname = getenv ("GPG_TTY");
     220             : #if !defined(HAVE_W32_SYSTEM) && !defined(HAVE_BROKEN_TTYNAME)
     221          10 :   if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
     222          10 :     dft_ttyname = ttyname (0);
     223             : #endif
     224          10 :   if (dft_ttyname && *dft_ttyname)
     225             :     {
     226          10 :       if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
     227           0 :         return rc;
     228             :     }
     229             : 
     230          10 :   dft_ttytype = getenv ("TERM");
     231          10 :   if (dft_ttyname && dft_ttytype)
     232             :     {
     233          10 :       if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
     234           0 :         return rc;
     235             :     }
     236             : 
     237             : #if defined(HAVE_SETLOCALE)
     238             :   {
     239          10 :     char *old_lc = NULL;
     240          10 :     char *dft_lc = NULL;
     241             : 
     242             : #if defined(LC_CTYPE)
     243          10 :     old_lc = setlocale (LC_CTYPE, NULL);
     244          10 :     if (old_lc)
     245             :       {
     246          10 :         char *p = spwq_malloc (strlen (old_lc)+1);
     247          10 :         if (!p)
     248           0 :           return SPWQ_OUT_OF_CORE;
     249          10 :         strcpy (p, old_lc);
     250          10 :         old_lc = p;
     251             :       }
     252          10 :     dft_lc = setlocale (LC_CTYPE, "");
     253          10 :     if (dft_ttyname && dft_lc)
     254          10 :       rc = agent_send_option (fd, "lc-ctype", dft_lc);
     255          10 :     if (old_lc)
     256             :       {
     257          10 :         setlocale (LC_CTYPE, old_lc);
     258          10 :         spwq_free (old_lc);
     259             :       }
     260          10 :     if (rc)
     261           0 :       return rc;
     262             : #endif
     263             : 
     264             : #if defined(LC_MESSAGES)
     265          10 :     old_lc = setlocale (LC_MESSAGES, NULL);
     266          10 :     if (old_lc)
     267             :       {
     268          10 :         char *p = spwq_malloc (strlen (old_lc)+1);
     269          10 :         if (!p)
     270           0 :           return SPWQ_OUT_OF_CORE;
     271          10 :         strcpy (p, old_lc);
     272          10 :         old_lc = p;
     273             :       }
     274          10 :     dft_lc = setlocale (LC_MESSAGES, "");
     275          10 :     if (dft_ttyname && dft_lc)
     276          10 :       rc = agent_send_option (fd, "lc-messages", dft_lc);
     277          10 :     if (old_lc)
     278             :       {
     279          10 :         setlocale (LC_MESSAGES, old_lc);
     280          10 :         spwq_free (old_lc);
     281             :       }
     282          10 :     if (rc)
     283           0 :       return rc;
     284             : #endif
     285             :   }
     286             : #endif /*HAVE_SETLOCALE*/
     287             : 
     288             :   /* Send the XAUTHORITY variable.  */
     289          10 :   dft_xauthority = getenv ("XAUTHORITY");
     290          10 :   if (dft_xauthority)
     291             :     {
     292             :       /* We ignore errors here because older gpg-agents don't support
     293             :          this option.  */
     294           0 :       agent_send_option (fd, "xauthority", dft_xauthority);
     295             :     }
     296             : 
     297             :   /* Send the PINENTRY_USER_DATA variable.  */
     298          10 :   dft_pinentry_user_data = getenv ("PINENTRY_USER_DATA");
     299          10 :   if (dft_pinentry_user_data)
     300             :     {
     301             :       /* We ignore errors here because older gpg-agents don't support
     302             :          this option.  */
     303           0 :       agent_send_option (fd, "pinentry-user-data", dft_pinentry_user_data);
     304             :     }
     305             : 
     306          10 :   return 0;
     307             : }
     308             : 
     309             : 
     310             : 
     311             : /* Try to open a connection to the agent, send all options and return
     312             :    the file descriptor for the connection.  Return -1 in case of
     313             :    error. */
     314             : static int
     315          10 : agent_open (int *rfd)
     316             : {
     317             :   int rc;
     318             :   int fd;
     319             :   char *infostr, *p;
     320             :   struct sockaddr_un client_addr;
     321             :   size_t len;
     322             :   char line[200];
     323             :   int nread;
     324             : 
     325          10 :   *rfd = -1;
     326          10 :   infostr = default_gpg_agent_info;
     327          10 :   if ( !infostr || !*infostr )
     328             :     {
     329             : #ifdef SPWQ_USE_LOGGING
     330           0 :       log_error (_("no gpg-agent running in this session\n"));
     331             : #endif
     332           0 :       return SPWQ_NO_AGENT;
     333             :     }
     334          10 :   p = spwq_malloc (strlen (infostr)+1);
     335          10 :   if (!p)
     336           0 :     return SPWQ_OUT_OF_CORE;
     337          10 :   strcpy (p, infostr);
     338          10 :   infostr = p;
     339             : 
     340          10 :   if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr
     341          10 :        || (p-infostr)+1 >= sizeof client_addr.sun_path )
     342             :     {
     343           0 :       return SPWQ_NO_AGENT;
     344             :     }
     345          10 :   *p++ = 0;
     346             : 
     347          30 :   while (*p && *p != PATHSEP_C)
     348          10 :     p++;
     349             : 
     350             : #ifdef HAVE_W32_SYSTEM
     351             :   fd = _w32_sock_new (AF_UNIX, SOCK_STREAM, 0);
     352             : #else
     353          10 :   fd = socket (AF_UNIX, SOCK_STREAM, 0);
     354             : #endif
     355          10 :   if (fd == -1)
     356             :     {
     357             : #ifdef SPWQ_USE_LOGGING
     358           0 :       log_error ("can't create socket: %s\n", strerror(errno) );
     359             : #endif
     360           0 :       return SPWQ_SYS_ERROR;
     361             :     }
     362             : 
     363          10 :   memset (&client_addr, 0, sizeof client_addr);
     364          10 :   client_addr.sun_family = AF_UNIX;
     365          10 :   strcpy (client_addr.sun_path, infostr);
     366          10 :   len = SUN_LEN (&client_addr);
     367             : 
     368             : #ifdef HAVE_W32_SYSTEM
     369             :   rc = _w32_sock_connect (fd, (struct sockaddr*)&client_addr, len );
     370             : #else
     371          10 :   rc = connect (fd, (struct sockaddr*)&client_addr, len );
     372             : #endif
     373          10 :   if (rc == -1)
     374             :     {
     375             : #ifdef SPWQ_USE_LOGGING
     376           0 :       log_error ( _("can't connect to '%s': %s\n"), infostr, strerror (errno));
     377             : #endif
     378           0 :       close (fd );
     379           0 :       return SPWQ_IO_ERROR;
     380             :     }
     381             : 
     382          10 :   nread = readline (fd, line, DIM(line));
     383          20 :   if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
     384          20 :                      && (line[2] == '\n' || line[2] == ' ')) )
     385             :     {
     386             : #ifdef SPWQ_USE_LOGGING
     387           0 :       log_error ( _("communication problem with gpg-agent\n"));
     388             : #endif
     389           0 :       close (fd );
     390           0 :       return SPWQ_PROTOCOL_ERROR;
     391             :     }
     392             : 
     393          10 :   rc = agent_send_all_options (fd);
     394          10 :   if (rc)
     395             :     {
     396             : #ifdef SPWQ_USE_LOGGING
     397           0 :       log_error (_("problem setting the gpg-agent options\n"));
     398             : #endif
     399           0 :       close (fd);
     400           0 :       return rc;
     401             :     }
     402             : 
     403          10 :   *rfd = fd;
     404          10 :   return 0;
     405             : }
     406             : 
     407             : 
     408             : /* Copy text to BUFFER and escape as required.  Return a pointer to
     409             :    the end of the new buffer.  Note that BUFFER must be large enough
     410             :    to keep the entire text; allocataing it 3 times the size of TEXT
     411             :    is sufficient. */
     412             : static char *
     413           0 : copy_and_escape (char *buffer, const char *text)
     414             : {
     415             :   int i;
     416           0 :   const unsigned char *s = (unsigned char *)text;
     417           0 :   char *p = buffer;
     418             : 
     419             : 
     420           0 :   for (i=0; s[i]; i++)
     421             :     {
     422           0 :       if (s[i] < ' ' || s[i] == '+')
     423             :         {
     424           0 :           sprintf (p, "%%%02X", s[i]);
     425           0 :           p += 3;
     426             :         }
     427           0 :       else if (s[i] == ' ')
     428           0 :         *p++ = '+';
     429             :       else
     430           0 :         *p++ = s[i];
     431             :     }
     432           0 :   return p;
     433             : }
     434             : 
     435             : 
     436             : /* Set the name of the default socket to NAME.  */
     437             : int
     438          10 : simple_pw_set_socket (const char *name)
     439             : {
     440          10 :   spwq_free (default_gpg_agent_info);
     441          10 :   if (name)
     442             :     {
     443          10 :       default_gpg_agent_info = spwq_malloc (strlen (name) + 4 + 1);
     444          10 :       if (!default_gpg_agent_info)
     445           0 :         return SPWQ_OUT_OF_CORE;
     446             :       /* We don't know the PID thus we use 0.  */
     447          10 :       strcpy (stpcpy (default_gpg_agent_info, name),
     448             :               PATHSEP_S "0" PATHSEP_S "1");
     449             :     }
     450             :   else
     451           0 :     default_gpg_agent_info = NULL;
     452             : 
     453          10 :   return 0;
     454             : }
     455             : 
     456             : 
     457             : /* Ask the gpg-agent for a passphrase and present the user with a
     458             :    DESCRIPTION, a PROMPT and optionally with a TRYAGAIN extra text.
     459             :    If a CACHEID is not NULL it is used to locate the passphrase in in
     460             :    the cache and store it under this ID.  If OPT_CHECK is true
     461             :    gpg-agent is asked to apply some checks on the passphrase security.
     462             :    If ERRORCODE is not NULL it should point a variable receiving an
     463             :    errorcode; this error code might be 0 if the user canceled the
     464             :    operation.  The function returns NULL to indicate an error.  */
     465             : char *
     466           0 : simple_pwquery (const char *cacheid,
     467             :                 const char *tryagain,
     468             :                 const char *prompt,
     469             :                 const char *description,
     470             :                 int opt_check,
     471             :                 int *errorcode)
     472             : {
     473           0 :   int fd = -1;
     474             :   int nread;
     475           0 :   char *result = NULL;
     476           0 :   char *pw = NULL;
     477             :   char *p;
     478             :   int rc, i;
     479             : 
     480           0 :   rc = agent_open (&fd);
     481           0 :   if (rc)
     482           0 :     goto leave;
     483             : 
     484           0 :   if (!cacheid)
     485           0 :     cacheid = "X";
     486           0 :   if (!tryagain)
     487           0 :     tryagain = "X";
     488           0 :   if (!prompt)
     489           0 :     prompt = "X";
     490           0 :   if (!description)
     491           0 :     description = "X";
     492             : 
     493             :   {
     494             :     char *line;
     495             :     /* We allocate 3 times the needed space so that there is enough
     496             :        space for escaping. */
     497           0 :     line = spwq_malloc (15 + 10
     498             :                         + 3*strlen (cacheid) + 1
     499             :                         + 3*strlen (tryagain) + 1
     500             :                         + 3*strlen (prompt) + 1
     501             :                         + 3*strlen (description) + 1
     502             :                         + 2);
     503           0 :     if (!line)
     504             :       {
     505           0 :         rc = SPWQ_OUT_OF_CORE;
     506           0 :         goto leave;
     507             :       }
     508           0 :     strcpy (line, "GET_PASSPHRASE ");
     509           0 :     p = line+15;
     510           0 :     if (opt_check)
     511           0 :       p = stpcpy (p, "--check ");
     512           0 :     p = copy_and_escape (p, cacheid);
     513           0 :     *p++ = ' ';
     514           0 :     p = copy_and_escape (p, tryagain);
     515           0 :     *p++ = ' ';
     516           0 :     p = copy_and_escape (p, prompt);
     517           0 :     *p++ = ' ';
     518           0 :     p = copy_and_escape (p, description);
     519           0 :     *p++ = '\n';
     520           0 :     rc = writen (fd, line, p - line);
     521           0 :     spwq_free (line);
     522           0 :     if (rc)
     523           0 :       goto leave;
     524             :   }
     525             : 
     526             :   /* get response */
     527           0 :   pw = spwq_secure_malloc (500);
     528           0 :   nread = readline (fd, pw, 499);
     529           0 :   if (nread < 0)
     530             :     {
     531           0 :       rc = -nread;
     532           0 :       goto leave;
     533             :     }
     534           0 :   if (nread < 3)
     535             :     {
     536           0 :       rc = SPWQ_PROTOCOL_ERROR;
     537           0 :       goto leave;
     538             :     }
     539             : 
     540           0 :   if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
     541           0 :     { /* we got a passphrase - convert it back from hex */
     542           0 :       size_t pwlen = 0;
     543             : 
     544           0 :       for (i=3; i < nread && hexdigitp (pw+i); i+=2)
     545           0 :         pw[pwlen++] = xtoi_2 (pw+i);
     546           0 :       pw[pwlen] = 0; /* make a C String */
     547           0 :       result = pw;
     548           0 :       pw = NULL;
     549             :     }
     550           0 :   else if ((nread > 7 && !memcmp (pw, "ERR 111", 7)
     551           0 :             && (pw[7] == ' ' || pw[7] == '\n') )
     552           0 :            || ((nread > 4 && !memcmp (pw, "ERR ", 4)
     553           0 :                 && (strtoul (pw+4, NULL, 0) & 0xffff) == 99)) )
     554             :     {
     555             :       /* 111 is the old Assuan code for canceled which might still
     556             :          be in use by old installations. 99 is GPG_ERR_CANCELED as
     557             :          used by modern gpg-agents; 0xffff is used to mask out the
     558             :          error source.  */
     559             : #ifdef SPWQ_USE_LOGGING
     560           0 :       log_info (_("canceled by user\n") );
     561             : #endif
     562           0 :       *errorcode = 0; /* Special error code to indicate Cancel. */
     563             :     }
     564           0 :   else if (nread > 4 && !memcmp (pw, "ERR ", 4))
     565             :     {
     566           0 :       switch ( (strtoul (pw+4, NULL, 0) & 0xffff) )
     567             :         {
     568           0 :         case 85: rc = SPWQ_NO_PIN_ENTRY;  break;
     569           0 :         default: rc = SPWQ_GENERAL_ERROR; break;
     570             :         }
     571           0 :     }
     572             :   else
     573             :     {
     574             : #ifdef SPWQ_USE_LOGGING
     575           0 :       log_error (_("problem with the agent\n"));
     576             : #endif
     577           0 :       rc = SPWQ_ERR_RESPONSE;
     578             :     }
     579             : 
     580             :  leave:
     581           0 :   if (errorcode)
     582           0 :     *errorcode = rc;
     583           0 :   if (fd != -1)
     584           0 :     close (fd);
     585           0 :   if (pw)
     586           0 :     spwq_secure_free (pw);
     587           0 :   return result;
     588             : }
     589             : 
     590             : 
     591             : /* Ask the gpg-agent to clear the passphrase for the cache ID CACHEID.  */
     592             : int
     593           0 : simple_pwclear (const char *cacheid)
     594             : {
     595             :   char line[500];
     596             :   char *p;
     597             : 
     598             :   /* We need not more than 50 characters for the command and the
     599             :      terminating nul.  */
     600           0 :   if (strlen (cacheid) * 3 > sizeof (line) - 50)
     601           0 :     return SPWQ_PROTOCOL_ERROR;
     602             : 
     603           0 :   strcpy (line, "CLEAR_PASSPHRASE ");
     604           0 :   p = line + 17;
     605           0 :   p = copy_and_escape (p, cacheid);
     606           0 :   *p++ = '\n';
     607           0 :   *p++ = '\0';
     608             : 
     609           0 :   return simple_query (line);
     610             : }
     611             : 
     612             : 
     613             : /* Perform the simple query QUERY (which must be new-line and 0
     614             :    terminated) and return the error code.  */
     615             : int
     616          10 : simple_query (const char *query)
     617             : {
     618          10 :   int fd = -1;
     619             :   int nread;
     620             :   char response[500];
     621             :   int rc;
     622             : 
     623          10 :   rc = agent_open (&fd);
     624          10 :   if (rc)
     625           0 :     goto leave;
     626             : 
     627          10 :   rc = writen (fd, query, strlen (query));
     628          10 :   if (rc)
     629           0 :     goto leave;
     630             : 
     631             :   /* get response */
     632          10 :   nread = readline (fd, response, 499);
     633          10 :   if (nread < 0)
     634             :     {
     635           0 :       rc = -nread;
     636           0 :       goto leave;
     637             :     }
     638          10 :   if (nread < 3)
     639             :     {
     640           0 :       rc = SPWQ_PROTOCOL_ERROR;
     641           0 :       goto leave;
     642             :     }
     643             : 
     644          10 :   if (response[0] == 'O' && response[1] == 'K')
     645             :     /* OK, do nothing.  */;
     646           0 :   else if ((nread > 7 && !memcmp (response, "ERR 111", 7)
     647           0 :             && (response[7] == ' ' || response[7] == '\n') )
     648           0 :            || ((nread > 4 && !memcmp (response, "ERR ", 4)
     649           0 :                 && (strtoul (response+4, NULL, 0) & 0xffff) == 99)) )
     650             :     {
     651             :       /* 111 is the old Assuan code for canceled which might still
     652             :          be in use by old installations. 99 is GPG_ERR_CANCELED as
     653             :          used by modern gpg-agents; 0xffff is used to mask out the
     654             :          error source.  */
     655             : #ifdef SPWQ_USE_LOGGING
     656           0 :       log_info (_("canceled by user\n") );
     657             : #endif
     658             :     }
     659             :   else
     660             :     {
     661             : #ifdef SPWQ_USE_LOGGING
     662           0 :       log_error (_("problem with the agent\n"));
     663             : #endif
     664           0 :       rc = SPWQ_ERR_RESPONSE;
     665             :     }
     666             : 
     667             :  leave:
     668          10 :   if (fd != -1)
     669          10 :     close (fd);
     670          10 :   return rc;
     671             : }

Generated by: LCOV version 1.11