LCOV - code coverage report
Current view: top level - common - name-value.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 261 316 82.6 %
Date: 2016-11-29 15:00:56 Functions: 24 26 92.3 %

          Line data    Source code
       1             : /* name-value.c - Parser and writer for a name-value format.
       2             :  *      Copyright (C) 2016 g10 Code GmbH
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * This file is free software; you can redistribute it and/or modify
       7             :  * it under the terms of either
       8             :  *
       9             :  *   - the GNU Lesser General Public License as published by the Free
      10             :  *     Software Foundation; either version 3 of the License, or (at
      11             :  *     your option) any later version.
      12             :  *
      13             :  * or
      14             :  *
      15             :  *   - the GNU General Public License as published by the Free
      16             :  *     Software Foundation; either version 2 of the License, or (at
      17             :  *     your option) any later version.
      18             :  *
      19             :  * or both in parallel, as here.
      20             :  *
      21             :  * GnuPG is distributed in the hope that it will be useful,
      22             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      23             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      24             :  * GNU General Public License for more details.
      25             :  *
      26             :  * You should have received a copy of the GNU General Public License
      27             :  * along with this program; if not, see <https://www.gnu.org/licenses/>.
      28             :  */
      29             : 
      30             : /*
      31             :  * This module aso provides features for the extended private key
      32             :  * format of gpg-agent.
      33             :  */
      34             : 
      35             : #include <config.h>
      36             : #include <assert.h>
      37             : #include <gcrypt.h>
      38             : #include <gpg-error.h>
      39             : #include <string.h>
      40             : 
      41             : #include "mischelp.h"
      42             : #include "strlist.h"
      43             : #include "util.h"
      44             : #include "name-value.h"
      45             : 
      46             : struct name_value_container
      47             : {
      48             :   struct name_value_entry *first;
      49             :   struct name_value_entry *last;
      50             :   unsigned int private_key_mode:1;
      51             : };
      52             : 
      53             : 
      54             : struct name_value_entry
      55             : {
      56             :   struct name_value_entry *prev;
      57             :   struct name_value_entry *next;
      58             : 
      59             :   /* The name.  Comments and blank lines have NAME set to NULL.  */
      60             :   char *name;
      61             : 
      62             :   /* The value as stored in the file.  We store it when when we parse
      63             :      a file so that we can reproduce it.  */
      64             :   strlist_t raw_value;
      65             : 
      66             :   /* The decoded value.  */
      67             :   char *value;
      68             : };
      69             : 
      70             : 
      71             : /* Helper */
      72             : static inline gpg_error_t
      73           0 : my_error_from_syserror (void)
      74             : {
      75           0 :   return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
      76             : }
      77             : 
      78             : 
      79             : static inline gpg_error_t
      80           2 : my_error (gpg_err_code_t ec)
      81             : {
      82           2 :   return gpg_err_make (default_errsource, ec);
      83             : }
      84             : 
      85             : 
      86             : 
      87             : 
      88             : /* Allocation and deallocation.  */
      89             : 
      90             : /* Allocate a private key container structure.  */
      91             : nvc_t
      92          22 : nvc_new (void)
      93             : {
      94          22 :   return xtrycalloc (1, sizeof (struct name_value_container));
      95             : }
      96             : 
      97             : 
      98             : /* Allocate a private key container structure for use with private keys.  */
      99             : nvc_t
     100          12 : nvc_new_private_key (void)
     101             : {
     102          12 :   nvc_t nvc = nvc_new ();
     103          12 :   if (nvc)
     104          12 :     nvc->private_key_mode = 1;
     105          12 :   return nvc;
     106             : }
     107             : 
     108             : 
     109             : static void
     110          69 : nve_release (nve_t entry, int private_key_mode)
     111             : {
     112          69 :   if (entry == NULL)
     113          69 :     return;
     114             : 
     115          69 :   xfree (entry->name);
     116          69 :   if (entry->value && private_key_mode)
     117          12 :     wipememory (entry->value, strlen (entry->value));
     118          69 :   xfree (entry->value);
     119          69 :   if (private_key_mode)
     120          36 :     free_strlist_wipe (entry->raw_value);
     121             :   else
     122          33 :     free_strlist (entry->raw_value);
     123          69 :   xfree (entry);
     124             : }
     125             : 
     126             : 
     127             : /* Release a private key container structure.  */
     128             : void
     129          22 : nvc_release (nvc_t pk)
     130             : {
     131             :   nve_t e, next;
     132             : 
     133          22 :   if (pk == NULL)
     134          22 :     return;
     135             : 
     136          83 :   for (e = pk->first; e; e = next)
     137             :     {
     138          61 :       next = e->next;
     139          61 :       nve_release (e, pk->private_key_mode);
     140             :     }
     141             : 
     142          22 :   xfree (pk);
     143             : }
     144             : 
     145             : 
     146             : 
     147             : /* Dealing with names and values.  */
     148             : 
     149             : /* Check whether the given name is valid.  Valid names start with a
     150             :    letter, end with a colon, and contain only alphanumeric characters
     151             :    and the hyphen.  */
     152             : static int
     153          62 : valid_name (const char *name)
     154             : {
     155          62 :   size_t i, len = strlen (name);
     156             : 
     157          62 :   if (! alphap (name) || len == 0 || name[len - 1] != ':')
     158           0 :     return 0;
     159             : 
     160         386 :   for (i = 1; i < len - 1; i++)
     161         324 :     if (! alnump (&name[i]) && name[i] != '-')
     162           0 :       return 0;
     163             : 
     164          62 :   return 1;
     165             : }
     166             : 
     167             : 
     168             : /* Makes sure that ENTRY has a RAW_VALUE.  */
     169             : static gpg_error_t
     170          99 : assert_raw_value (nve_t entry)
     171             : {
     172          99 :   gpg_error_t err = 0;
     173             :   size_t len, offset;
     174             : #define LINELEN 70
     175             :   char buf[LINELEN+3];
     176             : 
     177          99 :   if (entry->raw_value)
     178          80 :     return 0;
     179             : 
     180          19 :   len = strlen (entry->value);
     181          19 :   offset = 0;
     182          65 :   while (len)
     183             :     {
     184          27 :       size_t amount, linelen = LINELEN;
     185             : 
     186             :       /* On the first line we need to subtract space for the name.  */
     187          27 :       if (entry->raw_value == NULL && strlen (entry->name) < linelen)
     188          19 :         linelen -= strlen (entry->name);
     189             : 
     190             :       /* See if the rest of the value fits in this line.  */
     191          27 :       if (len <= linelen)
     192          19 :         amount = len;
     193             :       else
     194             :         {
     195             :           size_t i;
     196             : 
     197             :           /* Find a suitable space to break on.  */
     198          74 :           for (i = linelen - 1; linelen - i < 30 && linelen - i > offset; i--)
     199          72 :             if (ascii_isspace (entry->value[i]))
     200             :               break;
     201             : 
     202           8 :           if (ascii_isspace (entry->value[i]))
     203             :             {
     204             :               /* Found one.  */
     205           6 :               amount = i;
     206             :             }
     207             :           else
     208             :             {
     209             :               /* Just induce a hard break.  */
     210           2 :               amount = linelen;
     211             :             }
     212             :         }
     213             : 
     214          27 :       snprintf (buf, sizeof buf, " %.*s\n", (int) amount,
     215          27 :                 &entry->value[offset]);
     216          27 :       if (append_to_strlist_try (&entry->raw_value, buf) == NULL)
     217             :         {
     218           0 :           err = my_error_from_syserror ();
     219           0 :           goto leave;
     220             :         }
     221             : 
     222          27 :       offset += amount;
     223          27 :       len -= amount;
     224             :     }
     225             : 
     226             :  leave:
     227          19 :   if (err)
     228             :     {
     229           0 :       free_strlist_wipe (entry->raw_value);
     230           0 :       entry->raw_value = NULL;
     231             :     }
     232             : 
     233          19 :   return err;
     234             : #undef LINELEN
     235             : }
     236             : 
     237             : 
     238             : /* Computes the length of the value encoded as continuation.  If
     239             :    *SWALLOW_WS is set, all whitespace at the beginning of S is
     240             :    swallowed.  If START is given, a pointer to the beginning of the
     241             :    value is stored there.  */
     242             : static size_t
     243         104 : continuation_length (const char *s, int *swallow_ws, const char **start)
     244             : {
     245             :   size_t len;
     246             : 
     247         104 :   if (*swallow_ws)
     248             :     {
     249             :       /* The previous line was a blank line and we inserted a newline.
     250             :          Swallow all whitespace at the beginning of this line.  */
     251          16 :       while (ascii_isspace (*s))
     252           8 :         s++;
     253             :     }
     254             :   else
     255             :     {
     256             :       /* Iff a continuation starts with more than one space, it
     257             :          encodes a space.  */
     258         100 :       if (ascii_isspace (*s))
     259         100 :         s++;
     260             :     }
     261             : 
     262             :   /* Strip whitespace at the end.  */
     263         104 :   len = strlen (s);
     264         308 :   while (len > 0 && ascii_isspace (s[len-1]))
     265         100 :     len--;
     266             : 
     267         104 :   if (len == 0)
     268             :     {
     269             :       /* Blank lines encode newlines.  */
     270           4 :       len = 1;
     271           4 :       s = "\n";
     272           4 :       *swallow_ws = 1;
     273             :     }
     274             :   else
     275         100 :     *swallow_ws = 0;
     276             : 
     277         104 :   if (start)
     278          52 :     *start = s;
     279             : 
     280         104 :   return len;
     281             : }
     282             : 
     283             : 
     284             : /* Makes sure that ENTRY has a VALUE.  */
     285             : static gpg_error_t
     286           9 : assert_value (nve_t entry)
     287             : {
     288             :   size_t len;
     289             :   int swallow_ws;
     290             :   strlist_t s;
     291             :   char *p;
     292             : 
     293           9 :   if (entry->value)
     294           0 :     return 0;
     295             : 
     296           9 :   len = 0;
     297           9 :   swallow_ws = 0;
     298          61 :   for (s = entry->raw_value; s; s = s->next)
     299          52 :     len += continuation_length (s->d, &swallow_ws, NULL);
     300             : 
     301             :   /* Add one for the terminating zero.  */
     302           9 :   len += 1;
     303             : 
     304           9 :   entry->value = p = xtrymalloc (len);
     305           9 :   if (entry->value == NULL)
     306           0 :     return my_error_from_syserror ();
     307             : 
     308           9 :   swallow_ws = 0;
     309          61 :   for (s = entry->raw_value; s; s = s->next)
     310             :     {
     311             :       const char *start;
     312          52 :       size_t l = continuation_length (s->d, &swallow_ws, &start);
     313             : 
     314          52 :       memcpy (p, start, l);
     315          52 :       p += l;
     316             :     }
     317             : 
     318           9 :   *p++ = 0;
     319           9 :   assert (p - entry->value == len);
     320             : 
     321           9 :   return 0;
     322             : }
     323             : 
     324             : 
     325             : /* Get the name.  */
     326             : char *
     327           0 : nve_name (nve_t pke)
     328             : {
     329           0 :   return pke->name;
     330             : }
     331             : 
     332             : 
     333             : /* Get the value.  */
     334             : char *
     335           6 : nve_value (nve_t pke)
     336             : {
     337           6 :   if (assert_value (pke))
     338           0 :     return NULL;
     339           6 :   return pke->value;
     340             : }
     341             : 
     342             : 
     343             : 
     344             : /* Adding and modifying values.  */
     345             : 
     346             : /* Add (NAME, VALUE, RAW_VALUE) to PK.  NAME may be NULL for comments
     347             :    and blank lines.  At least one of VALUE and RAW_VALUE must be
     348             :    given.  If PRESERVE_ORDER is not given, entries with the same name
     349             :    are grouped.  NAME, VALUE and RAW_VALUE is consumed.  */
     350             : static gpg_error_t
     351          69 : _nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
     352             :           int preserve_order)
     353             : {
     354          69 :   gpg_error_t err = 0;
     355             :   nve_t e;
     356             : 
     357          69 :   assert (value || raw_value);
     358             : 
     359          69 :   if (name && ! valid_name (name))
     360             :     {
     361           0 :       err = my_error (GPG_ERR_INV_NAME);
     362           0 :       goto leave;
     363             :     }
     364             : 
     365          69 :   if (name
     366          47 :       && pk->private_key_mode
     367          25 :       && !ascii_strcasecmp (name, "Key:")
     368           4 :       && nvc_lookup (pk, "Key:"))
     369             :     {
     370           0 :       err = my_error (GPG_ERR_INV_NAME);
     371           0 :       goto leave;
     372             :     }
     373             : 
     374          69 :   e = xtrycalloc (1, sizeof *e);
     375          69 :   if (e == NULL)
     376             :     {
     377           0 :       err = my_error_from_syserror ();
     378           0 :       goto leave;
     379             :     }
     380             : 
     381          69 :   e->name = name;
     382          69 :   e->value = value;
     383          69 :   e->raw_value = raw_value;
     384             : 
     385          69 :   if (pk->first)
     386             :     {
     387             :       nve_t last;
     388             : 
     389          46 :       if (preserve_order || name == NULL)
     390          40 :         last = pk->last;
     391             :       else
     392             :         {
     393             :           /* See if there is already an entry with NAME.  */
     394           6 :           last = nvc_lookup (pk, name);
     395             : 
     396             :           /* If so, find the last in that block.  */
     397           6 :           if (last)
     398             :             {
     399           4 :               while (last->next)
     400             :                 {
     401           2 :                   nve_t next = last->next;
     402             : 
     403           2 :                   if (next->name && ascii_strcasecmp (next->name, name) == 0)
     404           0 :                     last = next;
     405             :                   else
     406             :                     break;
     407             :                 }
     408             :             }
     409             :           else /* Otherwise, just find the last entry.  */
     410           4 :             last = pk->last;
     411             :         }
     412             : 
     413          46 :       if (last->next)
     414             :         {
     415           2 :           e->prev = last;
     416           2 :           e->next = last->next;
     417           2 :           last->next = e;
     418           2 :           e->next->prev = e;
     419             :         }
     420             :       else
     421             :         {
     422          44 :           e->prev = last;
     423          44 :           last->next = e;
     424          44 :           pk->last = e;
     425             :         }
     426             :     }
     427             :   else
     428          23 :     pk->first = pk->last = e;
     429             : 
     430             :  leave:
     431          69 :   if (err)
     432             :     {
     433           0 :       xfree (name);
     434           0 :       if (value)
     435           0 :         wipememory (value, strlen (value));
     436           0 :       xfree (value);
     437           0 :       free_strlist_wipe (raw_value);
     438             :     }
     439             : 
     440          69 :   return err;
     441             : }
     442             : 
     443             : 
     444             : /* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
     445             :    is not updated but the new entry is appended.  */
     446             : gpg_error_t
     447          11 : nvc_add (nvc_t pk, const char *name, const char *value)
     448             : {
     449             :   char *k, *v;
     450             : 
     451          11 :   k = xtrystrdup (name);
     452          11 :   if (k == NULL)
     453           0 :     return my_error_from_syserror ();
     454             : 
     455          11 :   v = xtrystrdup (value);
     456          11 :   if (v == NULL)
     457             :     {
     458           0 :       xfree (k);
     459           0 :       return my_error_from_syserror ();
     460             :     }
     461             : 
     462          11 :   return _nvc_add (pk, k, v, NULL, 0);
     463             : }
     464             : 
     465             : 
     466             : /* Add (NAME, VALUE) to PK.  If an entry with NAME already exists, it
     467             :    is updated with VALUE.  If multiple entries with NAME exist, the
     468             :    first entry is updated.  */
     469             : gpg_error_t
     470          15 : nvc_set (nvc_t pk, const char *name, const char *value)
     471             : {
     472             :   nve_t e;
     473             : 
     474          15 :   if (! valid_name (name))
     475           0 :     return GPG_ERR_INV_NAME;
     476             : 
     477          15 :   e = nvc_lookup (pk, name);
     478          15 :   if (e)
     479             :     {
     480             :       char *v;
     481             : 
     482           8 :       v = xtrystrdup (value);
     483           8 :       if (v == NULL)
     484           0 :         return my_error_from_syserror ();
     485             : 
     486           8 :       free_strlist_wipe (e->raw_value);
     487           8 :       e->raw_value = NULL;
     488           8 :       if (e->value)
     489           8 :         wipememory (e->value, strlen (e->value));
     490           8 :       xfree (e->value);
     491           8 :       e->value = v;
     492             : 
     493           8 :       return 0;
     494             :     }
     495             :   else
     496           7 :     return nvc_add (pk, name, value);
     497             : }
     498             : 
     499             : 
     500             : /* Delete the given entry from PK.  */
     501             : void
     502           8 : nvc_delete (nvc_t pk, nve_t entry)
     503             : {
     504           8 :   if (entry->prev)
     505           4 :     entry->prev->next = entry->next;
     506             :   else
     507           4 :     pk->first = entry->next;
     508             : 
     509           8 :   if (entry->next)
     510           4 :     entry->next->prev = entry->prev;
     511             :   else
     512           4 :     pk->last = entry->prev;
     513             : 
     514           8 :   nve_release (entry, pk->private_key_mode);
     515           8 : }
     516             : 
     517             : 
     518             : 
     519             : /* Lookup and iteration.  */
     520             : 
     521             : /* Get the first non-comment entry.  */
     522             : nve_t
     523           4 : nvc_first (nvc_t pk)
     524             : {
     525             :   nve_t entry;
     526           6 :   for (entry = pk->first; entry; entry = entry->next)
     527           6 :     if (entry->name)
     528           4 :       return entry;
     529           0 :   return NULL;
     530             : }
     531             : 
     532             : 
     533             : /* Get the first entry with the given name.  */
     534             : nve_t
     535          66 : nvc_lookup (nvc_t pk, const char *name)
     536             : {
     537             :   nve_t entry;
     538         140 :   for (entry = pk->first; entry; entry = entry->next)
     539         125 :     if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
     540          51 :       return entry;
     541          15 :   return NULL;
     542             : }
     543             : 
     544             : 
     545             : /* Get the next non-comment entry.  */
     546             : nve_t
     547           8 : nve_next (nve_t entry)
     548             : {
     549           8 :   for (entry = entry->next; entry; entry = entry->next)
     550           6 :     if (entry->name)
     551           6 :       return entry;
     552           2 :   return NULL;
     553             : }
     554             : 
     555             : 
     556             : /* Get the next entry with the given name.  */
     557             : nve_t
     558           8 : nve_next_value (nve_t entry, const char *name)
     559             : {
     560          10 :   for (entry = entry->next; entry; entry = entry->next)
     561           8 :     if (entry->name && ascii_strcasecmp (entry->name, name) == 0)
     562           6 :       return entry;
     563           2 :   return NULL;
     564             : }
     565             : 
     566             : 
     567             : 
     568             : /* Private key handling.  */
     569             : 
     570             : /* Get the private key.  */
     571             : gpg_error_t
     572           4 : nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp)
     573             : {
     574             :   gpg_error_t err;
     575             :   nve_t e;
     576             : 
     577           4 :   e = pk->private_key_mode? nvc_lookup (pk, "Key:") : NULL;
     578           4 :   if (e == NULL)
     579           1 :     return my_error (GPG_ERR_MISSING_KEY);
     580             : 
     581           3 :   err = assert_value (e);
     582           3 :   if (err)
     583           0 :     return err;
     584             : 
     585           3 :   return gcry_sexp_sscan (retsexp, NULL, e->value, strlen (e->value));
     586             : }
     587             : 
     588             : 
     589             : /* Set the private key.  */
     590             : gpg_error_t
     591           2 : nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp)
     592             : {
     593             :   gpg_error_t err;
     594             :   char *raw, *clean, *p;
     595             :   size_t len, i;
     596             : 
     597           2 :   if (!pk->private_key_mode)
     598           1 :     return my_error (GPG_ERR_MISSING_KEY);
     599             : 
     600           1 :   len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
     601             : 
     602           1 :   raw = xtrymalloc (len);
     603           1 :   if (raw == NULL)
     604           0 :     return my_error_from_syserror ();
     605             : 
     606           1 :   clean = xtrymalloc (len);
     607           1 :   if (clean == NULL)
     608             :     {
     609           0 :       xfree (raw);
     610           0 :       return my_error_from_syserror ();
     611             :     }
     612             : 
     613           1 :   gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, raw, len);
     614             : 
     615             :   /* Strip any whitespace at the end.  */
     616           1 :   i = strlen (raw) - 1;
     617           3 :   while (i && ascii_isspace (raw[i]))
     618             :     {
     619           1 :       raw[i] = 0;
     620           1 :       i--;
     621             :     }
     622             : 
     623             :   /* Replace any newlines with spaces, remove superfluous whitespace.  */
     624           1 :   len = strlen (raw);
     625          14 :   for (p = clean, i = 0; i < len; i++)
     626             :     {
     627          13 :       char c = raw[i];
     628             : 
     629             :       /* Collapse contiguous and superfluous spaces.  */
     630          13 :       if (ascii_isspace (c) && i > 0
     631           1 :           && (ascii_isspace (raw[i-1]) || raw[i-1] == '(' || raw[i-1] == ')'))
     632           0 :         continue;
     633             : 
     634          13 :       if (c == '\n')
     635           0 :         c = ' ';
     636             : 
     637          13 :       *p++ = c;
     638             :     }
     639           1 :   *p = 0;
     640             : 
     641           1 :   err = nvc_set (pk, "Key:", clean);
     642           1 :   xfree (raw);
     643           1 :   xfree (clean);
     644           1 :   return err;
     645             : }
     646             : 
     647             : 
     648             : 
     649             : /* Parsing and serialization.  */
     650             : 
     651             : static gpg_error_t
     652          18 : do_nvc_parse (nvc_t *result, int *errlinep, estream_t stream,
     653             :               int for_private_key)
     654             : {
     655          18 :   gpg_error_t err = 0;
     656             :   gpgrt_ssize_t len;
     657          18 :   char *buf = NULL;
     658          18 :   size_t buf_len = 0;
     659          18 :   char *name = NULL;
     660          18 :   strlist_t raw_value = NULL;
     661             : 
     662          18 :   *result = for_private_key? nvc_new_private_key () : nvc_new ();
     663          18 :   if (*result == NULL)
     664           0 :     return my_error_from_syserror ();
     665             : 
     666          18 :   if (errlinep)
     667           2 :     *errlinep = 0;
     668         163 :   while ((len = es_read_line (stream, &buf, &buf_len, NULL)) > 0)
     669             :     {
     670             :       char *p;
     671         127 :       if (errlinep)
     672          23 :         *errlinep += 1;
     673             : 
     674             :       /* Skip any whitespace.  */
     675         127 :       for (p = buf; *p && ascii_isspace (*p); p++)
     676             :         /* Do nothing.  */;
     677             : 
     678         127 :       if (name && (spacep (buf) || *p == 0))
     679             :         {
     680             :           /* A continuation.  */
     681          69 :           if (append_to_strlist_try (&raw_value, buf) == NULL)
     682             :             {
     683           0 :               err = my_error_from_syserror ();
     684           0 :               goto leave;
     685             :             }
     686          69 :           continue;
     687             :         }
     688             : 
     689             :       /* No continuation.  Add the current entry if any.  */
     690          58 :       if (raw_value)
     691             :         {
     692          40 :           err = _nvc_add (*result, name, NULL, raw_value, 1);
     693          40 :           if (err)
     694           0 :             goto leave;
     695             :         }
     696             : 
     697             :       /* And prepare for the next one.  */
     698          58 :       name = NULL;
     699          58 :       raw_value = NULL;
     700             : 
     701          58 :       if (*p != 0 && *p != '#')
     702             :         {
     703             :           char *colon, *value, tmp;
     704             : 
     705          36 :           colon = strchr (buf, ':');
     706          36 :           if (colon == NULL)
     707             :             {
     708           0 :               err = my_error (GPG_ERR_INV_VALUE);
     709           0 :               goto leave;
     710             :             }
     711             : 
     712          36 :           value = colon + 1;
     713          36 :           tmp = *value;
     714          36 :           *value = 0;
     715          36 :           name = xtrystrdup (p);
     716          36 :           *value = tmp;
     717             : 
     718          36 :           if (name == NULL)
     719             :             {
     720           0 :               err = my_error_from_syserror ();
     721           0 :               goto leave;
     722             :             }
     723             : 
     724          36 :           if (append_to_strlist_try (&raw_value, value) == NULL)
     725             :             {
     726           0 :               err = my_error_from_syserror ();
     727           0 :               goto leave;
     728             :             }
     729          36 :           continue;
     730             :         }
     731             : 
     732          22 :       if (append_to_strlist_try (&raw_value, buf) == NULL)
     733             :         {
     734           0 :           err = my_error_from_syserror ();
     735           0 :           goto leave;
     736             :         }
     737             :     }
     738          18 :   if (len < 0)
     739             :     {
     740           0 :       err = gpg_error_from_syserror ();
     741           0 :       goto leave;
     742             :     }
     743             : 
     744             :   /* Add the final entry.  */
     745          18 :   if (raw_value)
     746          18 :     err = _nvc_add (*result, name, NULL, raw_value, 1);
     747             : 
     748             :  leave:
     749          18 :   gpgrt_free (buf);
     750          18 :   if (err)
     751             :     {
     752           0 :       nvc_release (*result);
     753           0 :       *result = NULL;
     754             :     }
     755             : 
     756          18 :   return err;
     757             : }
     758             : 
     759             : 
     760             : /* Parse STREAM and return a newly allocated name value container
     761             :    structure in RESULT.  If ERRLINEP is given, the line number the
     762             :    parser was last considering is stored there.  */
     763             : gpg_error_t
     764           8 : nvc_parse (nvc_t *result, int *errlinep, estream_t stream)
     765             : {
     766           8 :   return do_nvc_parse (result, errlinep, stream, 0);
     767             : }
     768             : 
     769             : 
     770             : /* Parse STREAM and return a newly allocated name value container
     771             :    structure in RESULT - assuming the extended private key format.  If
     772             :    ERRLINEP is given, the line number the parser was last considering
     773             :    is stored there.  */
     774             : gpg_error_t
     775          10 : nvc_parse_private_key (nvc_t *result, int *errlinep, estream_t stream)
     776             : {
     777          10 :   return do_nvc_parse (result, errlinep, stream, 1);
     778             : }
     779             : 
     780             : 
     781             : /* Write a representation of PK to STREAM.  */
     782             : gpg_error_t
     783          43 : nvc_write (nvc_t pk, estream_t stream)
     784             : {
     785             :   gpg_error_t err;
     786             :   nve_t entry;
     787             :   strlist_t s;
     788             : 
     789         142 :   for (entry = pk->first; entry; entry = entry->next)
     790             :     {
     791          99 :       if (entry->name)
     792          77 :         es_fputs (entry->name, stream);
     793             : 
     794          99 :       err = assert_raw_value (entry);
     795          99 :       if (err)
     796           0 :         return err;
     797             : 
     798         254 :       for (s = entry->raw_value; s; s = s->next)
     799         155 :         es_fputs (s->d, stream);
     800             : 
     801          99 :       if (es_ferror (stream))
     802           0 :         return my_error_from_syserror ();
     803             :     }
     804             : 
     805          43 :   return 0;
     806             : }

Generated by: LCOV version 1.11