LCOV - code coverage report
Current view: top level - src - assuan-inquire.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 3 189 1.6 %
Date: 2016-12-09 14:06:39 Functions: 1 8 12.5 %

          Line data    Source code
       1             : /* assuan-inquire.c - handle inquire stuff
       2             :    Copyright (C) 2001-2003, 2005, 2007, 2009 Free Software Foundation, Inc.
       3             : 
       4             :    This file is part of Assuan.
       5             : 
       6             :    Assuan is free software; you can redistribute it and/or modify it
       7             :    under the terms of the GNU Lesser General Public License as
       8             :    published by the Free Software Foundation; either version 2.1 of
       9             :    the License, or (at your option) any later version.
      10             : 
      11             :    Assuan is distributed in the hope that it will be useful, but
      12             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :    Lesser General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU Lesser General Public
      17             :    License along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #ifdef HAVE_CONFIG_H
      21             : #include <config.h>
      22             : #endif
      23             : 
      24             : #include <stdlib.h>
      25             : #include <stdio.h>
      26             : #include <string.h>
      27             : 
      28             : #include "assuan-defs.h"
      29             : 
      30             : #define digitp(a) ((a) >= '0' && (a) <= '9')
      31             : #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
      32             :                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
      33             : #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
      34             : 
      35             : 
      36             : struct membuf
      37             : {
      38             :   size_t len;
      39             :   size_t size;
      40             :   char *buf;
      41             :   int out_of_core;
      42             :   int too_large;
      43             :   size_t maxlen;
      44             : };
      45             : 
      46             : 
      47             : 
      48             : /* A simple implementation of a dynamic buffer.  Use init_membuf() to
      49             :    create a buffer, put_membuf to append bytes and get_membuf to
      50             :    release and return the buffer.  Allocation errors are detected but
      51             :    only returned at the final get_membuf(), this helps not to clutter
      52             :    the code with out of core checks.  */
      53             : 
      54             : static void
      55           0 : init_membuf (assuan_context_t ctx,
      56             :              struct membuf *mb, int initiallen, size_t maxlen)
      57             : {
      58           0 :   mb->len = 0;
      59           0 :   mb->size = initiallen;
      60           0 :   mb->out_of_core = 0;
      61           0 :   mb->too_large = 0;
      62           0 :   mb->maxlen = maxlen;
      63             :   /* we need to allocate one byte more for get_membuf */
      64           0 :   mb->buf = _assuan_malloc (ctx, initiallen + 1);
      65           0 :   if (!mb->buf)
      66           0 :       mb->out_of_core = 1;
      67           0 : }
      68             : 
      69             : static void
      70           0 : put_membuf (assuan_context_t ctx,
      71             :             struct membuf *mb, const void *buf, size_t len)
      72             : {
      73           0 :   if (mb->out_of_core || mb->too_large)
      74           0 :     return;
      75             : 
      76           0 :   if (mb->maxlen && mb->len + len > mb->maxlen)
      77             :     {
      78           0 :       mb->too_large = 1;
      79           0 :       return;
      80             :     }
      81             : 
      82           0 :   if (mb->len + len >= mb->size)
      83             :     {
      84             :       char *p;
      85             : 
      86           0 :       mb->size += len + 1024;
      87             :       /* we need to allocate one byte more for get_membuf */
      88           0 :       p = _assuan_realloc (ctx, mb->buf, mb->size + 1);
      89           0 :       if (!p)
      90             :         {
      91           0 :           mb->out_of_core = 1;
      92           0 :           return;
      93             :         }
      94           0 :       mb->buf = p;
      95             :     }
      96           0 :   memcpy (mb->buf + mb->len, buf, len);
      97           0 :   mb->len += len;
      98             : }
      99             : 
     100             : static void *
     101           0 : get_membuf (assuan_context_t ctx, struct membuf *mb, size_t *len)
     102             : {
     103             :   char *p;
     104             : 
     105           0 :   if (mb->out_of_core || mb->too_large)
     106             :     {
     107           0 :       _assuan_free (ctx, mb->buf);
     108           0 :       mb->buf = NULL;
     109           0 :       return NULL;
     110             :     }
     111             : 
     112           0 :   mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */
     113           0 :   p = mb->buf;
     114           0 :   *len = mb->len;
     115           0 :   mb->buf = NULL;
     116           0 :   mb->out_of_core = 1; /* don't allow a reuse */
     117           0 :   return p;
     118             : }
     119             : 
     120             : static void
     121           0 : free_membuf (assuan_context_t ctx, struct membuf *mb)
     122             : {
     123           0 :   _assuan_free (ctx, mb->buf);
     124           0 :   mb->buf = NULL;
     125           0 : }
     126             : 
     127             : 
     128             : /**
     129             :  * assuan_inquire:
     130             :  * @ctx: An assuan context
     131             :  * @keyword: The keyword used for the inquire
     132             :  * @r_buffer: Returns an allocated buffer
     133             :  * @r_length: Returns the length of this buffer
     134             :  * @maxlen: If not 0, the size limit of the inquired data.
     135             :  *
     136             :  * A server may use this to send an inquire.  r_buffer, r_length and
     137             :  * maxlen may all be NULL/0 to indicate that no real data is expected.
     138             :  * The returned buffer is guaranteed to have an extra 0-byte after the
     139             :  * length.  Thus it can be used as a string if embedded 0 bytes are
     140             :  * not an issue.
     141             :  *
     142             :  * Return value: 0 on success or an ASSUAN error code
     143             :  **/
     144             : gpg_error_t
     145           0 : assuan_inquire (assuan_context_t ctx, const char *keyword,
     146             :                 unsigned char **r_buffer, size_t *r_length, size_t maxlen)
     147             : {
     148             :   gpg_error_t rc;
     149             :   struct membuf mb;
     150             :   char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
     151             :   unsigned char *line, *p;
     152             :   int linelen;
     153             :   int nodataexpected;
     154             : 
     155           0 :   if (r_buffer)
     156           0 :     *r_buffer = NULL;
     157           0 :   if (r_length)
     158           0 :     *r_length = 0;
     159             : 
     160           0 :   if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
     161           0 :     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
     162           0 :   nodataexpected = !r_buffer && !r_length && !maxlen;
     163           0 :   if (!nodataexpected && (!r_buffer || !r_length))
     164           0 :     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
     165           0 :   if (!ctx->is_server)
     166           0 :     return _assuan_error (ctx, GPG_ERR_ASS_NOT_A_SERVER);
     167           0 :   if (ctx->in_inquire)
     168           0 :     return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);
     169             : 
     170           0 :   ctx->in_inquire = 1;
     171           0 :   if (nodataexpected)
     172           0 :     memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
     173             :   else
     174           0 :     init_membuf (ctx, &mb, maxlen? maxlen:1024, maxlen);
     175             : 
     176           0 :   strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
     177           0 :   rc = assuan_write_line (ctx, cmdbuf);
     178           0 :   if (rc)
     179           0 :     goto out;
     180             : 
     181           0 :   for (;;)
     182             :     {
     183             :       do
     184             :         {
     185             :           do
     186           0 :             rc = _assuan_read_line (ctx);
     187           0 :           while (_assuan_error_is_eagain (ctx, rc));
     188           0 :           if (rc)
     189           0 :             goto out;
     190           0 :           line = (unsigned char *) ctx->inbound.line;
     191           0 :           linelen = ctx->inbound.linelen;
     192             :         }
     193           0 :       while (*line == '#' || !linelen);
     194             : 
     195             :       /* Note: As a convenience for manual testing we allow case
     196             :          insensitive keywords.  */
     197           0 :       if ((line[0] == 'E'||line[0] == 'e')
     198           0 :           && (line[1] == 'N' || line[1] == 'n')
     199           0 :           && (line[2] == 'D' || line[2] == 'd')
     200           0 :           && (!line[3] || line[3] == ' '))
     201             :         break; /* END command received*/
     202           0 :       if ((line[0] == 'C' || line[0] == 'c')
     203           0 :           && (line[1] == 'A' || line[1] == 'a')
     204           0 :           && (line[2] == 'N' || line[2] == 'n'))
     205             :         {
     206           0 :           rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
     207           0 :           goto out;
     208             :         }
     209           0 :       if ((line[0] != 'D' && line[0] != 'd')
     210           0 :           || line[1] != ' ' || nodataexpected)
     211             :         {
     212           0 :           rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
     213           0 :           goto out;
     214             :         }
     215           0 :       if (linelen < 3)
     216           0 :         continue;
     217           0 :       line += 2;
     218           0 :       linelen -= 2;
     219             : 
     220           0 :       if (mb.too_large)
     221           0 :         continue; /* Need to read up the remaining data.  */
     222             : 
     223           0 :       p = line;
     224           0 :       while (linelen)
     225             :         {
     226           0 :           for (;linelen && *p != '%'; linelen--, p++)
     227             :             ;
     228           0 :           put_membuf (ctx, &mb, line, p-line);
     229           0 :           if (linelen > 2)
     230             :             { /* handle escaping */
     231             :               unsigned char tmp[1];
     232           0 :               p++;
     233           0 :               *tmp = xtoi_2 (p);
     234           0 :               p += 2;
     235           0 :               linelen -= 3;
     236           0 :               put_membuf (ctx, &mb, tmp, 1);
     237             :             }
     238           0 :           line = p;
     239             :         }
     240             :     }
     241             : 
     242           0 :   if (!nodataexpected)
     243             :     {
     244           0 :       if (mb.too_large)
     245           0 :         rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA);
     246             :       else
     247             :         {
     248           0 :           *r_buffer = get_membuf (ctx, &mb, r_length);
     249           0 :           if (!*r_buffer)
     250           0 :             rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
     251             :         }
     252             :     }
     253             : 
     254             :  out:
     255           0 :   if (!nodataexpected)
     256           0 :     free_membuf (ctx, &mb);
     257           0 :   ctx->in_inquire = 0;
     258           0 :   return rc;
     259             : }
     260             : 
     261             : 
     262             : void
     263           4 : _assuan_inquire_release (assuan_context_t ctx)
     264             : {
     265           4 :   if (ctx->in_inquire)
     266             :     {
     267           0 :       if (ctx->inquire_membuf)
     268             :         {
     269           0 :           free_membuf (ctx, ctx->inquire_membuf);
     270           0 :           free (ctx->inquire_membuf);
     271             :         }
     272           0 :       ctx->in_inquire = 0;
     273             :     }
     274           4 : }
     275             : 
     276             : 
     277             : gpg_error_t
     278           0 : _assuan_inquire_ext_cb (assuan_context_t ctx)
     279             : {
     280             :   gpg_error_t rc;
     281             :   unsigned char *line;
     282             :   int linelen;
     283             :   struct membuf *mb;
     284             :   unsigned char *p;
     285             : 
     286           0 :   line = (unsigned char *) ctx->inbound.line;
     287           0 :   linelen = ctx->inbound.linelen;
     288           0 :   mb = ctx->inquire_membuf;
     289             : 
     290           0 :   if ((line[0] == 'C' || line[0] == 'c')
     291           0 :       && (line[1] == 'A' || line[1] == 'a')
     292           0 :       && (line[2] == 'N' || line[2] == 'n'))
     293             :     {
     294           0 :       rc = _assuan_error (ctx, GPG_ERR_ASS_CANCELED);
     295           0 :       goto out;
     296             :     }
     297           0 :   if ((line[0] == 'E'||line[0] == 'e')
     298           0 :       && (line[1] == 'N' || line[1] == 'n')
     299           0 :       && (line[2] == 'D' || line[2] == 'd')
     300           0 :       && (!line[3] || line[3] == ' '))
     301             :     {
     302           0 :       rc = 0;
     303           0 :       goto out;
     304             :     }
     305             : 
     306           0 :   if ((line[0] != 'D' && line[0] != 'd') || line[1] != ' ' || mb == NULL)
     307             :     {
     308           0 :       rc = _assuan_error (ctx, GPG_ERR_ASS_UNEXPECTED_CMD);
     309           0 :       goto out;
     310             :     }
     311             : 
     312           0 :   if (linelen < 3)
     313           0 :     return 0;
     314           0 :   line += 2;
     315           0 :   linelen -= 2;
     316             : 
     317           0 :   p = line;
     318           0 :   while (linelen)
     319             :     {
     320           0 :       for (;linelen && *p != '%'; linelen--, p++)
     321             :         ;
     322           0 :       put_membuf (ctx, mb, line, p-line);
     323           0 :       if (linelen > 2)
     324             :         { /* handle escaping */
     325             :           unsigned char tmp[1];
     326           0 :           p++;
     327           0 :           *tmp = xtoi_2 (p);
     328           0 :           p += 2;
     329           0 :           linelen -= 3;
     330           0 :           put_membuf (ctx, mb, tmp, 1);
     331             :         }
     332           0 :       line = p;
     333             :     }
     334           0 :   if (mb->too_large)
     335             :     {
     336           0 :       rc = _assuan_error (ctx, GPG_ERR_ASS_TOO_MUCH_DATA);
     337           0 :       goto out;
     338             :     }
     339             : 
     340           0 :   return 0;
     341             : 
     342             :  out:
     343             :   {
     344           0 :     size_t buf_len = 0;
     345           0 :     unsigned char *buf = NULL;
     346             : 
     347           0 :     if (mb)
     348             :       {
     349           0 :         buf = get_membuf (ctx, mb, &buf_len);
     350           0 :         if (!buf)
     351           0 :           rc = _assuan_error (ctx, gpg_err_code_from_syserror ());
     352           0 :         free_membuf (ctx, mb);
     353           0 :         free (mb);
     354           0 :         ctx->inquire_membuf = NULL;
     355             :       }
     356           0 :     ctx->in_inquire = 0;
     357           0 :     rc = (ctx->inquire_cb) (ctx->inquire_cb_data, rc, buf, buf_len);
     358             :   }
     359           0 :   return rc;
     360             : }
     361             : 
     362             : /**
     363             :  * assuan_inquire_ext:
     364             :  * @ctx: An assuan context
     365             :  * @keyword: The keyword used for the inquire
     366             :  * @maxlen: If not 0, the size limit of the inquired data.
     367             :  * @cb: A callback handler which is invoked after the operation completed.
     368             :  * @cb_data: A user-provided value passed to the callback handler.
     369             :  *
     370             :  * A server may use this to send an inquire.  R_BUFFER, R_LENGTH and
     371             :  * MAXLEN may all be NULL/0 to indicate that no real data is expected.
     372             :  *
     373             :  * Return value: 0 on success or an ASSUAN error code
     374             :  **/
     375             : gpg_error_t
     376           0 : assuan_inquire_ext (assuan_context_t ctx, const char *keyword, size_t maxlen,
     377             :                     gpg_error_t (*cb) (void *cb_data, gpg_error_t rc,
     378             :                                        unsigned char *buf, size_t len),
     379             :                     void *cb_data)
     380             : {
     381             :   gpg_error_t rc;
     382           0 :   struct membuf *mb = NULL;
     383             :   char cmdbuf[LINELENGTH-10]; /* (10 = strlen ("INQUIRE ")+CR,LF) */
     384             : 
     385           0 :   if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
     386           0 :     return _assuan_error (ctx, GPG_ERR_ASS_INV_VALUE);
     387           0 :   if (!ctx->is_server)
     388           0 :     return _assuan_error (ctx, GPG_ERR_ASS_NOT_A_SERVER);
     389           0 :   if (ctx->in_inquire)
     390           0 :     return _assuan_error (ctx, GPG_ERR_ASS_NESTED_COMMANDS);
     391             : 
     392           0 :   mb = malloc (sizeof (struct membuf));
     393           0 :   if (!mb)
     394           0 :     return _assuan_error (ctx, gpg_err_code_from_syserror ());
     395           0 :   init_membuf (ctx, mb, maxlen ? maxlen : 1024, maxlen);
     396             : 
     397           0 :   strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
     398           0 :   rc = assuan_write_line (ctx, cmdbuf);
     399           0 :   if (rc)
     400             :     {
     401           0 :       free_membuf (ctx, mb);
     402           0 :       free (mb);
     403           0 :       return rc;
     404             :     }
     405             : 
     406           0 :   ctx->in_inquire = 1;
     407             : 
     408             :   /* Set up the continuation.  */
     409           0 :   ctx->inquire_cb = cb;
     410           0 :   ctx->inquire_cb_data = cb_data;
     411           0 :   ctx->inquire_membuf = mb;
     412             : 
     413           0 :   return 0;
     414             : }

Generated by: LCOV version 1.12