diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/Makefile.am | 8 | ||||
-rw-r--r-- | common/argparse.c | 2 | ||||
-rw-r--r-- | common/b64dec.c | 79 | ||||
-rw-r--r-- | common/b64enc.c | 20 | ||||
-rw-r--r-- | common/ccparray.c | 1 | ||||
-rw-r--r-- | common/exechelp-posix.c | 1 | ||||
-rw-r--r-- | common/exectool.c | 25 | ||||
-rw-r--r-- | common/gettime.c | 33 | ||||
-rw-r--r-- | common/gettime.h | 1 | ||||
-rw-r--r-- | common/init.c | 4 | ||||
-rw-r--r-- | common/iobuf.c | 5 | ||||
-rw-r--r-- | common/name-value.c (renamed from common/private-keys.c) | 183 | ||||
-rw-r--r-- | common/name-value.h (renamed from common/private-keys.h) | 61 | ||||
-rw-r--r-- | common/openpgpdefs.h | 1 | ||||
-rw-r--r-- | common/recsel.c | 571 | ||||
-rw-r--r-- | common/recsel.h | 43 | ||||
-rw-r--r-- | common/simple-pwquery.c | 6 | ||||
-rw-r--r-- | common/stringhelp.c | 2 | ||||
-rw-r--r-- | common/t-convert.c | 2 | ||||
-rw-r--r-- | common/t-gettime.c | 6 | ||||
-rw-r--r-- | common/t-iobuf.c | 15 | ||||
-rw-r--r-- | common/t-mbox-util.c | 2 | ||||
-rw-r--r-- | common/t-name-value.c (renamed from common/t-private-keys.c) | 230 | ||||
-rw-r--r-- | common/t-recsel.c | 405 | ||||
-rw-r--r-- | common/t-stringhelp.c | 7 | ||||
-rw-r--r-- | common/t-strlist.c | 2 | ||||
-rw-r--r-- | common/zb32.c | 2 |
27 files changed, 1472 insertions, 245 deletions
diff --git a/common/Makefile.am b/common/Makefile.am index 884c966a3..6f9d96d9a 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -91,7 +91,8 @@ common_sources = \ call-gpg.c call-gpg.h \ exectool.c exectool.h \ server-help.c server-help.h \ - private-keys.c private-keys.h + name-value.c name-value.h \ + recsel.c recsel.h if HAVE_W32_SYSTEM common_sources += w32-reg.c w32-afunix.c w32-afunix.h @@ -157,7 +158,7 @@ module_tests = t-stringhelp t-timestuff \ t-convert t-percent t-gettime t-sysutils t-sexputil \ t-session-env t-openpgp-oid t-ssh-utils \ t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \ - t-private-keys t-ccparray + t-name-value t-ccparray t-recsel if !HAVE_W32CE_SYSTEM module_tests += t-exechelp endif @@ -206,8 +207,9 @@ t_zb32_LDADD = $(t_common_ldadd) t_mbox_util_LDADD = $(t_common_ldadd) t_iobuf_LDADD = $(t_common_ldadd) t_strlist_LDADD = $(t_common_ldadd) -t_private_keys_LDADD = $(t_common_ldadd) +t_name_value_LDADD = $(t_common_ldadd) t_ccparray_LDADD = $(t_common_ldadd) +t_recsel_LDADD = $(t_common_ldadd) # System specific test if HAVE_W32_SYSTEM diff --git a/common/argparse.c b/common/argparse.c index 00cde23da..240fdce30 100644 --- a/common/argparse.c +++ b/common/argparse.c @@ -699,6 +699,8 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno, } if (!set_opt_arg (arg, opts[idx].flags, p)) xfree (buffer); + else + gpgrt_annotate_leaked_object (buffer); } } break; diff --git a/common/b64dec.c b/common/b64dec.c index 3e02e4afa..c84c35ada 100644 --- a/common/b64dec.c +++ b/common/b64dec.c @@ -1,29 +1,20 @@ /* b64dec.c - Simple Base64 decoder. * Copyright (C) 2008, 2011 Free Software Foundation, Inc. + * Copyright (C) 2008, 2011, 2016 g10 Code GmbH * * This file is part of GnuPG. * * This file is free software; you can redistribute it and/or modify - * it under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ @@ -61,7 +52,7 @@ static unsigned char const asctobin[128] = enum decoder_states { - s_init, s_idle, s_lfseen, s_begin, + s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin, s_b64_0, s_b64_1, s_b64_2, s_b64_3, s_waitendtitle, s_waitend }; @@ -71,26 +62,18 @@ enum decoder_states /* Initialize the context for the base64 decoder. If TITLE is NULL a plain base64 decoding is done. If it is the empty string the decoder will skip everything until a "-----BEGIN " line has been - seen, decoding ends at a "----END " line. - - Not yet implemented: If TITLE is either "PGP" or begins with "PGP " - the PGP armor lines are skipped as well. */ + seen, decoding ends at a "----END " line. */ gpg_error_t b64dec_start (struct b64state *state, const char *title) { memset (state, 0, sizeof *state); if (title) { - if (!strncmp (title, "PGP", 3) && (!title[3] || title[3] == ' ')) - state->lasterr = gpg_error (GPG_ERR_NOT_IMPLEMENTED); + state->title = xtrystrdup (title); + if (!state->title) + state->lasterr = gpg_error_from_syserror (); else - { - state->title = xtrystrdup (title); - if (!state->title) - state->lasterr = gpg_error_from_syserror (); - else - state->idx = s_init; - } + state->idx = s_init; } else state->idx = s_b64_0; @@ -123,6 +106,7 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length, for (s=d=buffer; length && !state->stop_seen; length--, s++) { + again: switch (ds) { case s_idle: @@ -136,12 +120,42 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length, ds = s_lfseen; case s_lfseen: if (*s != "-----BEGIN "[pos]) - ds = s_idle; + { + ds = s_idle; + goto again; + } else if (pos == 10) - ds = s_begin; + { + pos = 0; + ds = s_beginseen; + } + else + pos++; + break; + case s_beginseen: + if (*s != "PGP "[pos]) + ds = s_begin; /* Not a PGP armor. */ + else if (pos == 3) + ds = s_waitheader; else pos++; break; + case s_waitheader: + if (*s == '\n') + ds = s_waitblank; + break; + case s_waitblank: + if (*s == '\n') + ds = s_b64_0; /* blank line found. */ + else if (*s == ' ' || *s == '\r' || *s == '\t') + ; /* Ignore spaces. */ + else + { + /* Armor header line. Note that we don't care that our + * FSM accepts a header prefixed with spaces. */ + ds = s_waitheader; /* Wait for next header. */ + } + break; case s_begin: if (*s == '\n') ds = s_b64_0; @@ -229,10 +243,11 @@ b64dec_proc (struct b64state *state, void *buffer, size_t length, gpg_error_t b64dec_finish (struct b64state *state) { + xfree (state->title); + state->title = NULL; + if (state->lasterr) return state->lasterr; - xfree (state->title); - state->title = NULL; return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0; } diff --git a/common/b64enc.c b/common/b64enc.c index 9101d9819..af861fcbc 100644 --- a/common/b64enc.c +++ b/common/b64enc.c @@ -1,30 +1,22 @@ /* b64enc.c - Simple Base64 encoder. * Copyright (C) 2001, 2003, 2004, 2008, 2010, * 2011 Free Software Foundation, Inc. + * Copyright (C) 2001, 2003, 2004, 2008, 2010, + * 2011 g10 Code GmbH * * This file is part of GnuPG. * * This file is free software; you can redistribute it and/or modify - * it under the terms of either - * - * - the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at - * your option) any later version. - * - * or - * - * - the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * or both in parallel, as here. + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. * * This file is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, see <http://www.gnu.org/licenses/>. */ diff --git a/common/ccparray.c b/common/ccparray.c index 490dbf5c0..d3c28333c 100644 --- a/common/ccparray.c +++ b/common/ccparray.c @@ -114,6 +114,7 @@ ccparray_put (ccparray_t *cpa, const char *value) } for (n=0; n < cpa->size; n++) newarray[n] = cpa->array[n]; + xfree (cpa->array); cpa->array = newarray; cpa->size = newsize; diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c index aefb6539c..b1b56f30c 100644 --- a/common/exechelp-posix.c +++ b/common/exechelp-posix.c @@ -523,6 +523,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[], { /* This is the child. */ gcry_control (GCRYCTL_TERM_SECMEM); + es_fclose (infp); es_fclose (outfp); es_fclose (errfp); do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1], diff --git a/common/exectool.c b/common/exectool.c index 897450e1e..b43e7cb01 100644 --- a/common/exectool.c +++ b/common/exectool.c @@ -224,7 +224,7 @@ static gpg_error_t copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink) { gpg_error_t err; - size_t nwritten; + size_t nwritten = 0; if (c->nread == 0) { @@ -390,7 +390,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[], /* Now read as long as we have something to poll. We continue reading even after EOF or error on stdout so that we get the other error messages or remaining outut. */ - while (!fds[1].ignore && !fds[2].ignore) + while (! (fds[1].ignore && fds[2].ignore)) { count = es_poll (fds, DIM(fds), -1); if (count == -1) @@ -465,20 +465,25 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[], pgmname, gpg_strerror (err)); goto leave; } + + if (es_feof (fds[1].stream)) + { + err = copy_buffer_flush (&cpbuf_out, output); + if (err) + { + log_error ("error reading data from '%s': %s\n", + pgmname, gpg_strerror (err)); + goto leave; + } + + fds[1].ignore = 1; /* ready. */ + } } if (fds[2].got_read) read_and_log_stderr (&fderrstate, fds + 2); } - err = copy_buffer_flush (&cpbuf_out, output); - if (err) - { - log_error ("error reading data from '%s': %s\n", - pgmname, gpg_strerror (err)); - goto leave; - } - read_and_log_stderr (&fderrstate, NULL); /* Flush. */ es_fclose (infp); infp = NULL; es_fclose (extrafp); extrafp = NULL; diff --git a/common/gettime.c b/common/gettime.c index 115f7256d..dd9c1968c 100644 --- a/common/gettime.c +++ b/common/gettime.c @@ -723,6 +723,39 @@ asctimestamp (u32 stamp) } +/* Return the timestamp STAMP in RFC-2822 format. This is always done + * in the C locale. We return the gmtime to avoid computing the + * timezone. The caller must release the returned string. + * + * Example: "Mon, 27 Jun 2016 1:42:00 +0000". + */ +char * +rfctimestamp (u32 stamp) +{ + time_t atime = stamp; + struct tm tmbuf, *tp; + + + if (IS_INVALID_TIME_T (atime)) + { + gpg_err_set_errno (EINVAL); + return NULL; + } + + tp = gnupg_gmtime (&atime, &tmbuf); + if (!tp) + return NULL; + return xtryasprintf ("%.3s, %02d %.3s %04d %02d:%02d:%02d +0000", + ("SunMonTueWedThuFriSat" + (tp->tm_wday%7)*3), + tp->tm_mday, + ("JanFebMarAprMayJunJulAugSepOctNovDec" + + (tp->tm_mon%12)*3), + tp->tm_year + 1900, + tp->tm_hour, + tp->tm_min, + tp->tm_sec); +} + static int days_per_year (int y) diff --git a/common/gettime.h b/common/gettime.h index cbc257ada..08cb3b176 100644 --- a/common/gettime.h +++ b/common/gettime.h @@ -59,6 +59,7 @@ const char *strtimevalue (u32 stamp); const char *strtimestamp (u32 stamp); /* GMT */ const char *isotimestamp (u32 stamp); /* GMT */ const char *asctimestamp (u32 stamp); /* localized */ +char *rfctimestamp (u32 stamp); /* RFC format, malloced. */ gpg_error_t add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds); gpg_error_t add_days_to_isotime (gnupg_isotime_t atime, int ndays); gpg_error_t check_isotime (const gnupg_isotime_t atime); diff --git a/common/init.c b/common/init.c index c68a4e631..c406ffe58 100644 --- a/common/init.c +++ b/common/init.c @@ -106,6 +106,10 @@ register_mem_cleanup_func (void (*func)(void)) { mem_cleanup_item_t item; + for (item = mem_cleanup_list; item; item = item->next) + if (item->func == func) + return; /* Function has already been registered. */ + item = malloc (sizeof *item); if (item) { diff --git a/common/iobuf.c b/common/iobuf.c index c8ec00f7f..f3d67b474 100644 --- a/common/iobuf.c +++ b/common/iobuf.c @@ -2530,9 +2530,6 @@ iobuf_get_fname_nonnull (iobuf_t a) void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len) { - block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx); - - ctx->use = a->use; if (!len) /* Disable partial body length mode. */ { @@ -2546,6 +2543,8 @@ iobuf_set_partial_body_length_mode (iobuf_t a, size_t len) else /* Enabled partial body length mode. */ { + block_filter_ctx_t *ctx = xcalloc (1, sizeof *ctx); + ctx->use = a->use; ctx->partial = 1; ctx->size = 0; ctx->first_c = len; diff --git a/common/private-keys.c b/common/name-value.c index 4cf7d227c..0b32a4442 100644 --- a/common/private-keys.c +++ b/common/name-value.c @@ -1,4 +1,4 @@ -/* private-keys.c - Parser and writer for the extended private key format. +/* name-value.c - Parser and writer for a name-value format. * Copyright (C) 2016 g10 Code GmbH * * This file is part of GnuPG. @@ -27,28 +27,34 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ +/* + * This module aso provides features for the extended private key + * format of gpg-agent. + */ + #include <config.h> #include <assert.h> #include <gcrypt.h> #include <gpg-error.h> #include <string.h> -#include "private-keys.h" #include "mischelp.h" #include "strlist.h" #include "util.h" +#include "name-value.h" -struct private_key_container +struct name_value_container { - struct private_key_entry *first; - struct private_key_entry *last; + struct name_value_entry *first; + struct name_value_entry *last; + unsigned int private_key_mode:1; }; -struct private_key_entry +struct name_value_entry { - struct private_key_entry *prev; - struct private_key_entry *next; + struct name_value_entry *prev; + struct name_value_entry *next; /* The name. Comments and blank lines have NAME set to NULL. */ char *name; @@ -70,38 +76,59 @@ my_error_from_syserror (void) } +static inline gpg_error_t +my_error (gpg_err_code_t ec) +{ + return gpg_err_make (default_errsource, ec); +} + + /* Allocation and deallocation. */ /* Allocate a private key container structure. */ -pkc_t -pkc_new (void) +nvc_t +nvc_new (void) +{ + return xtrycalloc (1, sizeof (struct name_value_container)); +} + + +/* Allocate a private key container structure for use with private keys. */ +nvc_t +nvc_new_private_key (void) { - return xtrycalloc (1, sizeof (struct private_key_container)); + nvc_t nvc = nvc_new (); + if (nvc) + nvc->private_key_mode = 1; + return nvc; } static void -pke_release (pke_t entry) +nve_release (nve_t entry, int private_key_mode) { if (entry == NULL) return; xfree (entry->name); - if (entry->value) + if (entry->value && private_key_mode) wipememory (entry->value, strlen (entry->value)); xfree (entry->value); - free_strlist_wipe (entry->raw_value); + if (private_key_mode) + free_strlist_wipe (entry->raw_value); + else + free_strlist (entry->raw_value); xfree (entry); } /* Release a private key container structure. */ void -pkc_release (pkc_t pk) +nvc_release (nvc_t pk) { - pke_t e, next; + nve_t e, next; if (pk == NULL) return; @@ -109,7 +136,7 @@ pkc_release (pkc_t pk) for (e = pk->first; e; e = next) { next = e->next; - pke_release (e); + nve_release (e, pk->private_key_mode); } xfree (pk); @@ -140,7 +167,7 @@ valid_name (const char *name) /* Makes sure that ENTRY has a RAW_VALUE. */ static gpg_error_t -assert_raw_value (pke_t entry) +assert_raw_value (nve_t entry) { gpg_error_t err = 0; size_t len, offset; @@ -256,7 +283,7 @@ continuation_length (const char *s, int *swallow_ws, const char **start) /* Makes sure that ENTRY has a VALUE. */ static gpg_error_t -assert_value (pke_t entry) +assert_value (nve_t entry) { size_t len; int swallow_ws; @@ -297,7 +324,7 @@ assert_value (pke_t entry) /* Get the name. */ char * -pke_name (pke_t pke) +nve_name (nve_t pke) { return pke->name; } @@ -305,7 +332,7 @@ pke_name (pke_t pke) /* Get the value. */ char * -pke_value (pke_t pke) +nve_value (nve_t pke) { if (assert_value (pke)) return NULL; @@ -321,23 +348,26 @@ pke_value (pke_t pke) given. If PRESERVE_ORDER is not given, entries with the same name are grouped. NAME, VALUE and RAW_VALUE is consumed. */ static gpg_error_t -_pkc_add (pkc_t pk, char *name, char *value, strlist_t raw_value, +_nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value, int preserve_order) { gpg_error_t err = 0; - pke_t e; + nve_t e; assert (value || raw_value); if (name && ! valid_name (name)) { - err = gpg_error (GPG_ERR_INV_NAME); + err = my_error (GPG_ERR_INV_NAME); goto leave; } - if (name && ascii_strcasecmp (name, "Key:") == 0 && pkc_lookup (pk, "Key:")) + if (name + && pk->private_key_mode + && !ascii_strcasecmp (name, "Key:") + && nvc_lookup (pk, "Key:")) { - err = gpg_error (GPG_ERR_INV_NAME); + err = my_error (GPG_ERR_INV_NAME); goto leave; } @@ -354,21 +384,21 @@ _pkc_add (pkc_t pk, char *name, char *value, strlist_t raw_value, if (pk->first) { - pke_t last; + nve_t last; if (preserve_order || name == NULL) last = pk->last; else { /* See if there is already an entry with NAME. */ - last = pkc_lookup (pk, name); + last = nvc_lookup (pk, name); /* If so, find the last in that block. */ if (last) { while (last->next) { - pke_t next = last->next; + nve_t next = last->next; if (next->name && ascii_strcasecmp (next->name, name) == 0) last = next; @@ -414,7 +444,7 @@ _pkc_add (pkc_t pk, char *name, char *value, strlist_t raw_value, /* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it is not updated but the new entry is appended. */ gpg_error_t -pkc_add (pkc_t pk, const char *name, const char *value) +nvc_add (nvc_t pk, const char *name, const char *value) { char *k, *v; @@ -429,7 +459,7 @@ pkc_add (pkc_t pk, const char *name, const char *value) return my_error_from_syserror (); } - return _pkc_add (pk, k, v, NULL, 0); + return _nvc_add (pk, k, v, NULL, 0); } @@ -437,14 +467,14 @@ pkc_add (pkc_t pk, const char *name, const char *value) is updated with VALUE. If multiple entries with NAME exist, the first entry is updated. */ gpg_error_t -pkc_set (pkc_t pk, const char *name, const char *value) +nvc_set (nvc_t pk, const char *name, const char *value) { - pke_t e; + nve_t e; if (! valid_name (name)) return GPG_ERR_INV_NAME; - e = pkc_lookup (pk, name); + e = nvc_lookup (pk, name); if (e) { char *v; @@ -463,13 +493,13 @@ pkc_set (pkc_t pk, const char *name, const char *value) return 0; } else - return pkc_add (pk, name, value); + return nvc_add (pk, name, value); } /* Delete the given entry from PK. */ void -pkc_delete (pkc_t pk, pke_t entry) +nvc_delete (nvc_t pk, nve_t entry) { if (entry->prev) entry->prev->next = entry->next; @@ -481,7 +511,7 @@ pkc_delete (pkc_t pk, pke_t entry) else pk->last = entry->prev; - pke_release (entry); + nve_release (entry, pk->private_key_mode); } @@ -489,10 +519,10 @@ pkc_delete (pkc_t pk, pke_t entry) /* Lookup and iteration. */ /* Get the first non-comment entry. */ -pke_t -pkc_first (pkc_t pk) +nve_t +nvc_first (nvc_t pk) { - pke_t entry; + nve_t entry; for (entry = pk->first; entry; entry = entry->next) if (entry->name) return entry; @@ -501,10 +531,10 @@ pkc_first (pkc_t pk) /* Get the first entry with the given name. */ -pke_t -pkc_lookup (pkc_t pk, const char *name) +nve_t +nvc_lookup (nvc_t pk, const char *name) { - pke_t entry; + nve_t entry; for (entry = pk->first; entry; entry = entry->next) if (entry->name && ascii_strcasecmp (entry->name, name) == 0) return entry; @@ -513,8 +543,8 @@ pkc_lookup (pkc_t pk, const char *name) /* Get the next non-comment entry. */ -pke_t -pke_next (pke_t entry) +nve_t +nve_next (nve_t entry) { for (entry = entry->next; entry; entry = entry->next) if (entry->name) @@ -524,8 +554,8 @@ pke_next (pke_t entry) /* Get the next entry with the given name. */ -pke_t -pke_next_value (pke_t entry, const char *name) +nve_t +nve_next_value (nve_t entry, const char *name) { for (entry = entry->next; entry; entry = entry->next) if (entry->name && ascii_strcasecmp (entry->name, name) == 0) @@ -539,14 +569,14 @@ pke_next_value (pke_t entry, const char *name) /* Get the private key. */ gpg_error_t -pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp) +nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp) { gpg_error_t err; - pke_t e; + nve_t e; - e = pkc_lookup (pk, "Key:"); + e = pk->private_key_mode? nvc_lookup (pk, "Key:") : NULL; if (e == NULL) - return gpg_error (GPG_ERR_MISSING_KEY); + return my_error (GPG_ERR_MISSING_KEY); err = assert_value (e); if (err) @@ -558,12 +588,15 @@ pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp) /* Set the private key. */ gpg_error_t -pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp) +nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp) { gpg_error_t err; char *raw, *clean, *p; size_t len, i; + if (!pk->private_key_mode) + return my_error (GPG_ERR_MISSING_KEY); + len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0); raw = xtrymalloc (len); @@ -605,7 +638,7 @@ pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp) } *p = 0; - err = pkc_set (pk, "Key:", clean); + err = nvc_set (pk, "Key:", clean); xfree (raw); xfree (clean); return err; @@ -615,11 +648,9 @@ pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp) /* Parsing and serialization. */ -/* Parse STREAM and return a newly allocated private key container - structure in RESULT. If ERRLINEP is given, the line number the - parser was last considering is stored there. */ -gpg_error_t -pkc_parse (pkc_t *result, int *errlinep, estream_t stream) +static gpg_error_t +do_nvc_parse (nvc_t *result, int *errlinep, estream_t stream, + int for_private_key) { gpg_error_t err = 0; gpgrt_ssize_t len; @@ -628,8 +659,7 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream) char *name = NULL; strlist_t raw_value = NULL; - - *result = pkc_new (); + *result = for_private_key? nvc_new_private_key () : nvc_new (); if (*result == NULL) return my_error_from_syserror (); @@ -659,7 +689,7 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream) /* No continuation. Add the current entry if any. */ if (raw_value) { - err = _pkc_add (*result, name, NULL, raw_value, 1); + err = _nvc_add (*result, name, NULL, raw_value, 1); if (err) goto leave; } @@ -675,7 +705,7 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream) colon = strchr (buf, ':'); if (colon == NULL) { - err = gpg_error (GPG_ERR_INV_VALUE); + err = my_error (GPG_ERR_INV_VALUE); goto leave; } @@ -708,13 +738,13 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream) /* Add the final entry. */ if (raw_value) - err = _pkc_add (*result, name, NULL, raw_value, 1); + err = _nvc_add (*result, name, NULL, raw_value, 1); leave: gpgrt_free (buf); if (err) { - pkc_release (*result); + nvc_release (*result); *result = NULL; } @@ -722,12 +752,33 @@ pkc_parse (pkc_t *result, int *errlinep, estream_t stream) } +/* Parse STREAM and return a newly allocated name value container + structure in RESULT. If ERRLINEP is given, the line number the + parser was last considering is stored there. */ +gpg_error_t +nvc_parse (nvc_t *result, int *errlinep, estream_t stream) +{ + return do_nvc_parse (result, errlinep, stream, 0); +} + + +/* Parse STREAM and return a newly allocated name value container + structure in RESULT - assuming the extended private key format. If + ERRLINEP is given, the line number the parser was last considering + is stored there. */ +gpg_error_t +nvc_parse_private_key (nvc_t *result, int *errlinep, estream_t stream) +{ + return do_nvc_parse (result, errlinep, stream, 1); +} + + /* Write a representation of PK to STREAM. */ gpg_error_t -pkc_write (pkc_t pk, estream_t stream) +nvc_write (nvc_t pk, estream_t stream) { gpg_error_t err; - pke_t entry; + nve_t entry; strlist_t s; for (entry = pk->first; entry; entry = entry->next) diff --git a/common/private-keys.h b/common/name-value.h index d21e94f7c..f5f17e6de 100644 --- a/common/private-keys.h +++ b/common/name-value.h @@ -1,4 +1,4 @@ -/* private-keys.h - Parser and writer for the extended private key format. +/* name-value.h - Parser and writer for a name-value format. * Copyright (C) 2016 g10 Code GmbH * * This file is part of GnuPG. @@ -27,46 +27,50 @@ * along with this program; if not, see <http://www.gnu.org/licenses/>. */ -#ifndef GNUPG_COMMON_PRIVATE_KEYS_H -#define GNUPG_COMMON_PRIVATE_KEYS_H +#ifndef GNUPG_COMMON_NAME_VALUE_H +#define GNUPG_COMMON_NAME_VALUE_H -struct private_key_container; -typedef struct private_key_container *pkc_t; +struct name_value_container; +typedef struct name_value_container *nvc_t; -struct private_key_entry; -typedef struct private_key_entry *pke_t; +struct name_value_entry; +typedef struct name_value_entry *nve_t; /* Memory management, and dealing with entries. */ -/* Allocate a private key container structure. */ -pkc_t pkc_new (void); +/* Allocate a name value container structure. */ +nvc_t nvc_new (void); -/* Release a private key container structure. */ -void pkc_release (pkc_t pk); +/* Allocate a name value container structure for use with the extended + * private key format. */ +nvc_t nvc_new_private_key (void); + +/* Release a name value container structure. */ +void nvc_release (nvc_t pk); /* Get the name. */ -char *pke_name (pke_t pke); +char *nve_name (nve_t pke); /* Get the value. */ -char *pke_value (pke_t pke); +char *nve_value (nve_t pke); /* Lookup and iteration. */ /* Get the first non-comment entry. */ -pke_t pkc_first (pkc_t pk); +nve_t nvc_first (nvc_t pk); /* Get the first entry with the given name. */ -pke_t pkc_lookup (pkc_t pk, const char *name); +nve_t nvc_lookup (nvc_t pk, const char *name); /* Get the next non-comment entry. */ -pke_t pke_next (pke_t entry); +nve_t nve_next (nve_t entry); /* Get the next entry with the given name. */ -pke_t pke_next_value (pke_t entry, const char *name); +nve_t nve_next_value (nve_t entry, const char *name); @@ -74,25 +78,25 @@ pke_t pke_next_value (pke_t entry, const char *name); /* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it is not updated but the new entry is appended. */ -gpg_error_t pkc_add (pkc_t pk, const char *name, const char *value); +gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value); /* Add (NAME, VALUE) to PK. If an entry with NAME already exists, it is updated with VALUE. If multiple entries with NAME exist, the first entry is updated. */ -gpg_error_t pkc_set (pkc_t pk, const char *name, const char *value); +gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value); /* Delete the given entry from PK. */ -void pkc_delete (pkc_t pk, pke_t pke); +void nvc_delete (nvc_t pk, nve_t pke); /* Private key handling. */ /* Get the private key. */ -gpg_error_t pkc_get_private_key (pkc_t pk, gcry_sexp_t *retsexp); +gpg_error_t nvc_get_private_key (nvc_t pk, gcry_sexp_t *retsexp); /* Set the private key. */ -gpg_error_t pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp); +gpg_error_t nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp); @@ -101,9 +105,16 @@ gpg_error_t pkc_set_private_key (pkc_t pk, gcry_sexp_t sexp); /* Parse STREAM and return a newly allocated private key container structure in RESULT. If ERRLINEP is given, the line number the parser was last considering is stored there. */ -gpg_error_t pkc_parse (pkc_t *result, int *errlinep, estream_t stream); +gpg_error_t nvc_parse (nvc_t *result, int *errlinep, estream_t stream); + +/* Parse STREAM and return a newly allocated name value container + structure in RESULT - assuming the extended private key format. If + ERRLINEP is given, the line number the parser was last considering + is stored there. */ +gpg_error_t nvc_parse_private_key (nvc_t *result, int *errlinep, + estream_t stream); /* Write a representation of PK to STREAM. */ -gpg_error_t pkc_write (pkc_t pk, estream_t stream); +gpg_error_t nvc_write (nvc_t pk, estream_t stream); -#endif /* GNUPG_COMMON_PRIVATE_KEYS_H */ +#endif /* GNUPG_COMMON_NAME_VALUE_H */ diff --git a/common/openpgpdefs.h b/common/openpgpdefs.h index f8b86e1bd..2c0ace2a5 100644 --- a/common/openpgpdefs.h +++ b/common/openpgpdefs.h @@ -115,6 +115,7 @@ typedef enum SIGSUBPKT_FEATURES = 30, /* Feature flags. */ SIGSUBPKT_SIGNATURE = 32, /* Embedded signature. */ + SIGSUBPKT_ISSUER_FPR = 33, /* EXPERIMENTAL: Issuer fingerprint. */ SIGSUBPKT_FLAG_CRITICAL = 128 } diff --git a/common/recsel.c b/common/recsel.c new file mode 100644 index 000000000..5dc685fe9 --- /dev/null +++ b/common/recsel.c @@ -0,0 +1,571 @@ +/* recsel.c - Record selection + * Copyright (C) 2014, 2016 Werner Koch + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "util.h" +#include "recsel.h" + +/* Select operators. */ +typedef enum + { + SELECT_SAME, + SELECT_SUB, + SELECT_NONEMPTY, + SELECT_ISTRUE, + SELECT_EQ, /* Numerically equal. */ + SELECT_LE, + SELECT_GE, + SELECT_LT, + SELECT_GT + } select_op_t; + + +/* Definition for a select expression. */ +struct recsel_expr_s +{ + recsel_expr_t next; + select_op_t op; /* Operation code. */ + unsigned int not:1; /* Negate operators. */ + unsigned int disjun:1;/* Start of a disjunction. */ + unsigned int xcase:1; /* String match is case sensitive. */ + const char *value; /* (Points into NAME.) */ + long numvalue; /* strtol of VALUE. */ + char name[1]; /* Name of the property. */ +}; + + +/* Helper */ +static inline gpg_error_t +my_error_from_syserror (void) +{ + return gpg_err_make (default_errsource, gpg_err_code_from_syserror ()); +} + +/* Helper */ +static inline gpg_error_t +my_error (gpg_err_code_t ec) +{ + return gpg_err_make (default_errsource, ec); +} + + +/* This is a case-sensitive version of our memistr. I wonder why no + * standard function memstr exists but I better do not use the name + * memstr to avoid future conflicts. + * + * FIXME: Move this to a stringhelp.c + */ +static const char * +my_memstr (const void *buffer, size_t buflen, const char *sub) +{ + const unsigned char *buf = buffer; + const unsigned char *t = (const unsigned char *)buf; + const unsigned char *s = (const unsigned char *)sub; + size_t n = buflen; + + for ( ; n ; t++, n-- ) + { + if (*t == *s) + { + for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--) + ; + if (!*s) + return (const char*)buf; + t = (const unsigned char *)buf; + s = (const unsigned char *)sub ; + n = buflen; + } + } + return NULL; +} + + +/* Return a pointer to the next logical connection operator or NULL if + * none. */ +static char * +find_next_lc (char *string) +{ + char *p1, *p2; + + p1 = strchr (string, '&'); + if (p1 && p1[1] != '&') + p1 = NULL; + p2 = strchr (string, '|'); + if (p2 && p2[1] != '|') + p2 = NULL; + if (p1 && !p2) + return p1; + if (!p1) + return p2; + return p1 < p2 ? p1 : p2; +} + + +/* Parse an expression. The expression syntax is: + * + * [<lc>] {{<flag>} PROPNAME <op> VALUE [<lc>]} + * + * A [] indicates an optional part, a {} a repetition. PROPNAME and + * VALUE may not be the empty string. White space between the + * elements is ignored. Numerical values are computed as long int; + * standard C notation applies. <lc> is the logical connection + * operator; either "&&" for a conjunction or "||" for a disjunction. + * A conjunction is assumed at the begin of an expression and + * conjunctions have higher precedence than disjunctions. If VALUE + * starts with one of the characters used in any <op> a space after + * the <op> is required. A VALUE is terminated by an <lc> unless the + * "--" <flag> is used in which case the VALUE spans to the end of the + * expression. <op> may be any of + * + * =~ Substring must match + * !~ Substring must not match + * = The full string must match + * <> The full string must not match + * == The numerical value must match + * != The numerical value must not match + * <= The numerical value of the field must be LE than the value. + * < The numerical value of the field must be LT than the value. + * >= The numerical value of the field must be GT than the value. + * >= The numerical value of the field must be GE than the value. + * -n True if value is not empty (no VALUE parameter allowed). + * -z True if value is empty (no VALUE parameter allowed). + * -t Alias for "PROPNAME != 0" (no VALUE parameter allowed). + * -f Alias for "PROPNAME == 0" (no VALUE parameter allowed). + * + * Values for <flag> must be space separated and any of: + * + * -- VALUE spans to the end of the expression. + * -c The string match in this part is done case-sensitive. + * + * For example four calls to recsel_parse_expr() with these values for + * EXPR + * + * "uid =~ Alfa" + * "&& uid !~ Test" + * "|| uid =~ Alpha" + * "uid !~ Test" + * + * or the equivalent expression + * + * "uid =~ Alfa" && uid !~ Test" || uid =~ Alpha" && "uid !~ Test" + * + * are making a selector for records where the "uid" property contains + * the strings "Alfa" or "Alpha" but not the String "test". + * + * The caller must pass the address of a selector variable to this + * function and initialize the value of the function to NULL before + * the first call. recset_release needs to be called to free the + * selector. + */ +gpg_error_t +recsel_parse_expr (recsel_expr_t *selector, const char *expression) +{ + recsel_expr_t se_head = NULL; + recsel_expr_t se, se2; + char *expr_buffer; + char *expr; + char *s0, *s; + int toend = 0; + int xcase = 0; + int disjun = 0; + char *next_lc = NULL; + + while (*expression == ' ' || *expression == '\t') + expression++; + + expr_buffer = xtrystrdup (expression); + if (!expr_buffer) + return my_error_from_syserror (); + expr = expr_buffer; + + if (*expr == '|' && expr[1] == '|') + { + disjun = 1; + expr += 2; + } + else if (*expr == '&' && expr[1] == '&') + expr += 2; + + next_term: + while (*expr == ' ' || *expr == '\t') + expr++; + + while (*expr == '-') + { + switch (*++expr) + { + case '-': toend = 1; break; + case 'c': xcase = 1; break; + default: + log_error ("invalid flag '-%c' in expression\n", *expr); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_INV_FLAG); + } + expr++; + while (*expr == ' ' || *expr == '\t') + expr++; + } + + next_lc = toend? NULL : find_next_lc (expr); + if (next_lc) + *next_lc = 0; /* Terminate this term. */ + + se = xtrymalloc (sizeof *se + strlen (expr)); + if (!se) + return my_error_from_syserror (); + strcpy (se->name, expr); + se->next = NULL; + se->not = 0; + se->disjun = disjun; + se->xcase = xcase; + + if (!se_head) + se_head = se; + else + { + for (se2 = se_head; se2->next; se2 = se2->next) + ; + se2->next = se; + } + + + s = strpbrk (expr, "=<>!~-"); + if (!s || s == expr ) + { + log_error ("no field name given in expression\n"); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_NO_NAME); + } + s0 = s; + + if (!strncmp (s, "=~", 2)) + { + se->op = SELECT_SUB; + s += 2; + } + else if (!strncmp (s, "!~", 2)) + { + se->op = SELECT_SUB; + se->not = 1; + s += 2; + } + else if (!strncmp (s, "<>", 2)) + { + se->op = SELECT_SAME; + se->not = 1; + s += 2; + } + else if (!strncmp (s, "==", 2)) + { + se->op = SELECT_EQ; + s += 2; + } + else if (!strncmp (s, "!=", 2)) + { + se->op = SELECT_EQ; + se->not = 1; + s += 2; + } + else if (!strncmp (s, "<=", 2)) + { + se->op = SELECT_LE; + s += 2; + } + else if (!strncmp (s, ">=", 2)) + { + se->op = SELECT_GE; + s += 2; + } + else if (!strncmp (s, "<", 1)) + { + se->op = SELECT_LT; + s += 1; + } + else if (!strncmp (s, ">", 1)) + { + se->op = SELECT_GT; + s += 1; + } + else if (!strncmp (s, "=", 1)) + { + se->op = SELECT_SAME; + s += 1; + } + else if (!strncmp (s, "-z", 2)) + { + se->op = SELECT_NONEMPTY; + se->not = 1; + s += 2; + } + else if (!strncmp (s, "-n", 2)) + { + se->op = SELECT_NONEMPTY; + s += 2; + } + else if (!strncmp (s, "-f", 2)) + { + se->op = SELECT_ISTRUE; + se->not = 1; + s += 2; + } + else if (!strncmp (s, "-t", 2)) + { + se->op = SELECT_ISTRUE; + s += 2; + } + else + { + log_error ("invalid operator in expression\n"); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_INV_OP); + } + + /* We require that a space is used if the value starts with any of + the operator characters. */ + if (se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE) + ; + else if (strchr ("=<>!~", *s)) + { + log_error ("invalid operator in expression\n"); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_INV_OP); + } + + while (*s == ' ' || *s == '\t') + s++; + + if (se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE) + { + if (*s) + { + log_error ("value given for -n or -z\n"); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_SYNTAX); + } + } + else + { + if (!*s) + { + log_error ("no value given in expression\n"); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_MISSING_VALUE); + } + } + + se->name[s0 - expr] = 0; + trim_spaces (se->name); + if (!se->name[0]) + { + log_error ("no field name given in expression\n"); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_NO_NAME); + } + + trim_spaces (se->name + (s - expr)); + se->value = se->name + (s - expr); + if (!se->value[0] && !(se->op == SELECT_NONEMPTY || se->op == SELECT_ISTRUE)) + { + log_error ("no value given in expression\n"); + recsel_release (se_head); + xfree (expr_buffer); + return my_error (GPG_ERR_MISSING_VALUE); + } + + se->numvalue = strtol (se->value, NULL, 0); + + if (next_lc) + { + disjun = next_lc[1] == '|'; + expr = next_lc + 2; + goto next_term; + } + + /* Read:y Append to passes last selector. */ + if (!*selector) + *selector = se_head; + else + { + for (se2 = *selector; se2->next; se2 = se2->next) + ; + se2->next = se_head; + } + + xfree (expr_buffer); + return 0; +} + + +void +recsel_release (recsel_expr_t a) +{ + while (a) + { + recsel_expr_t tmp = a->next; + xfree (a); + a = tmp; + } +} + + +void +recsel_dump (recsel_expr_t selector) +{ + recsel_expr_t se; + + log_debug ("--- Begin selectors ---\n"); + for (se = selector; se; se = se->next) + { + log_debug ("%s %s %s %s '%s'\n", + se==selector? " ": (se->disjun? "||":"&&"), + se->xcase? "-c":" ", + se->name, + se->op == SELECT_SAME? (se->not? "<>":"= "): + se->op == SELECT_SUB? (se->not? "!~":"=~"): + se->op == SELECT_NONEMPTY?(se->not? "-z":"-n"): + se->op == SELECT_ISTRUE? (se->not? "-f":"-t"): + se->op == SELECT_EQ? (se->not? "!=":"=="): + se->op == SELECT_LT? "< ": + se->op == SELECT_LE? "<=": + se->op == SELECT_GT? "> ": + se->op == SELECT_GE? ">=":"[oops]", + se->value); + } + log_debug ("--- End selectors ---\n"); +} + + +/* Return true if the record RECORD has been selected. The GETVAL + * function is called with COOKIE and the NAME of a property used in + * the expression. */ +int +recsel_select (recsel_expr_t selector, + const char *(*getval)(void *cookie, const char *propname), + void *cookie) +{ + recsel_expr_t se; + const char *value; + size_t selen, valuelen; + long numvalue; + int result = 1; + + se = selector; + while (se) + { + value = getval? getval (cookie, se->name) : NULL; + if (!value) + value = ""; + + if (!*value) + { + /* Field is empty. */ + result = 0; + } + else /* Field has a value. */ + { + valuelen = strlen (value); + numvalue = strtol (value, NULL, 0); + selen = strlen (se->value); + + switch (se->op) + { + case SELECT_SAME: + if (se->xcase) + result = (valuelen==selen && !memcmp (value,se->value,selen)); + else + result = (valuelen==selen && !memicmp (value,se->value,selen)); + break; + case SELECT_SUB: + if (se->xcase) + result = !!my_memstr (value, valuelen, se->value); + else + result = !!memistr (value, valuelen, se->value); + break; + case SELECT_NONEMPTY: + result = !!valuelen; + break; + case SELECT_ISTRUE: + result = !!numvalue; + break; + case SELECT_EQ: + result = (numvalue == se->numvalue); + break; + case SELECT_GT: + result = (numvalue > se->numvalue); + break; + case SELECT_GE: + result = (numvalue >= se->numvalue); + break; + case SELECT_LT: + result = (numvalue < se->numvalue); + break; + case SELECT_LE: + result = (numvalue <= se->numvalue); + break; + } + } + + if (se->not) + result = !result; + + if (result) + { + /* This expression evaluated to true. See wether there are + remaining expressions in this conjunction. */ + if (!se->next || se->next->disjun) + break; /* All expressions are true. Return True. */ + se = se->next; /* Test the next. */ + } + else + { + /* This expression evaluated to false and thus the + * conjuction evaluates to false. We skip over the + * remaining expressions of this conjunction and continue + * with the next disjunction if any. */ + do + se = se->next; + while (se && !se->disjun); + } + } + + return result; +} diff --git a/common/recsel.h b/common/recsel.h new file mode 100644 index 000000000..be67afcbe --- /dev/null +++ b/common/recsel.h @@ -0,0 +1,43 @@ +/* recsel.c - Record selection + * Copyright (C) 2016 Werner Koch + * + * This file is part of GnuPG. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either + * + * - the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at + * your option) any later version. + * + * or + * + * - the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * or both in parallel, as here. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ +#ifndef GNUPG_COMMON_RECSEL_H +#define GNUPG_COMMON_RECSEL_H + +struct recsel_expr_s; +typedef struct recsel_expr_s *recsel_expr_t; + +gpg_error_t recsel_parse_expr (recsel_expr_t *selector, const char *expr); +void recsel_release (recsel_expr_t a); +void recsel_dump (recsel_expr_t selector); +int recsel_select (recsel_expr_t selector, + const char *(*getval)(void *cookie, const char *propname), + void *cookie); + + +#endif /*GNUPG_COMMON_RECSEL_H*/ diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c index bdad14093..708b1573d 100644 --- a/common/simple-pwquery.c +++ b/common/simple-pwquery.c @@ -340,6 +340,7 @@ agent_open (int *rfd) if ( !(p = strchr ( infostr, PATHSEP_C)) || p == infostr || (p-infostr)+1 >= sizeof client_addr.sun_path ) { + spwq_free (infostr); return SPWQ_NO_AGENT; } *p++ = 0; @@ -357,12 +358,14 @@ agent_open (int *rfd) #ifdef SPWQ_USE_LOGGING log_error ("can't create socket: %s\n", strerror(errno) ); #endif + spwq_free (infostr); return SPWQ_SYS_ERROR; } memset (&client_addr, 0, sizeof client_addr); client_addr.sun_family = AF_UNIX; strcpy (client_addr.sun_path, infostr); + spwq_free (infostr); len = SUN_LEN (&client_addr); #ifdef HAVE_W32_SYSTEM @@ -373,7 +376,8 @@ agent_open (int *rfd) if (rc == -1) { #ifdef SPWQ_USE_LOGGING - log_error ( _("can't connect to '%s': %s\n"), infostr, strerror (errno)); + log_error (_("can't connect to '%s': %s\n"), + client_addr.sun_path, strerror (errno)); #endif close (fd ); return SPWQ_IO_ERROR; diff --git a/common/stringhelp.c b/common/stringhelp.c index 0e96c9e54..95912e0b2 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -538,6 +538,7 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr) home_buffer = xtrymalloc (n); if (!home_buffer) { + xfree (home); xfree (name); return NULL; } @@ -556,6 +557,7 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr) else strcpy (stpcpy (stpcpy (p, home), "/"), name); + xfree (home); xfree (name); name = home_buffer; /* Let's do a simple compression to catch the most common diff --git a/common/t-convert.c b/common/t-convert.c index ad33dff9b..68824e0cd 100644 --- a/common/t-convert.c +++ b/common/t-convert.c @@ -234,6 +234,7 @@ test_bin2hex (void) fail (0); else if (strcmp (p, hexstuff)) fail (0); + xfree (p); p = bin2hex (stuff, (size_t)(-1), NULL); if (p) @@ -266,6 +267,7 @@ test_bin2hexcolon (void) fail (0); else if (strcmp (p, hexstuff)) fail (0); + xfree (p); p = bin2hexcolon (stuff, (size_t)(-1), NULL); if (p) diff --git a/common/t-gettime.c b/common/t-gettime.c index 9b3139d48..8a222b7e4 100644 --- a/common/t-gettime.c +++ b/common/t-gettime.c @@ -54,6 +54,12 @@ test_isotime2epoch (void) { "20070629T160000 ", 1183132800 }, { "20070629T160000\n", 1183132800 }, { "20070629T160000.", INVALID }, +#if SIZEOF_TIME_T > 4 + { "21060207T062815", (time_t)0x0ffffffff }, + { "21060207T062816", (time_t)0x100000000 }, + { "21060207T062817", (time_t)0x100000001 }, + { "21060711T120001", (time_t)4308292801 }, +#endif /*SIZEOF_TIME_T > 4*/ { NULL, 0 } }; int idx; diff --git a/common/t-iobuf.c b/common/t-iobuf.c index 2835df4d2..0e6f508a5 100644 --- a/common/t-iobuf.c +++ b/common/t-iobuf.c @@ -190,6 +190,8 @@ main (int argc, char *argv[]) n ++; } assert (n == 10 + (strlen (content) - 10) / 2); + + iobuf_close (iobuf); } @@ -266,6 +268,8 @@ main (int argc, char *argv[]) /* The string should have been truncated (max_len == 0). */ assert (max_len == 0); free (buffer); + + iobuf_close (iobuf); } { @@ -279,10 +283,12 @@ main (int argc, char *argv[]) int c; int n; int lastc = 0; + struct content_filter_state *state; iobuf = iobuf_temp_with_content (content, strlen(content)); rc = iobuf_push_filter (iobuf, - content_filter, content_filter_new (content2)); + content_filter, + state=content_filter_new (content2)); assert (rc == 0); n = 0; @@ -309,6 +315,9 @@ main (int argc, char *argv[]) /* printf ("%d: '%c' (%d)\n", n, c, c); */ } } + + iobuf_close (iobuf); + free (state); } /* Write some data to a temporary filter. Push a new filter. The @@ -346,6 +355,8 @@ main (int argc, char *argv[]) assert (n == strlen (content) + 2 * (strlen (content2) + 1)); assert (strcmp (buffer, "0123456789aabbcc") == 0); + + iobuf_close (iobuf); } { @@ -373,6 +384,8 @@ main (int argc, char *argv[]) assert (n == 2); assert (buffer[0] == '3'); assert (buffer[1] == '7'); + + iobuf_close (iobuf); } return 0; diff --git a/common/t-mbox-util.c b/common/t-mbox-util.c index dfa4ada2a..ff48f6c5d 100644 --- a/common/t-mbox-util.c +++ b/common/t-mbox-util.c @@ -87,6 +87,8 @@ run_test (void) fail (idx); else if (strcmp (mbox, testtbl[idx].mbox)) fail (idx); + + xfree (mbox); } } diff --git a/common/t-private-keys.c b/common/t-name-value.c index 1027e70cf..3b01431d4 100644 --- a/common/t-private-keys.c +++ b/common/t-name-value.c @@ -1,4 +1,4 @@ -/* t-private-keys.c - Module test for private-keys.c +/* t-name-value.c - Module test for name-value.c * Copyright (C) 2016 g10 Code GmbH * * This file is part of GnuPG. @@ -26,82 +26,102 @@ #include <sys/stat.h> #include "util.h" -#include "private-keys.h" +#include "name-value.h" static int verbose; +static int private_key_mode; + + +static nvc_t +my_nvc_new (void) +{ + if (private_key_mode) + return nvc_new_private_key (); + else + return nvc_new (); +} + void -test_getting_values (pkc_t pk) +test_getting_values (nvc_t pk) { - pke_t e; + nve_t e; - e = pkc_lookup (pk, "Comment:"); + e = nvc_lookup (pk, "Comment:"); assert (e); /* Names are case-insensitive. */ - e = pkc_lookup (pk, "comment:"); + e = nvc_lookup (pk, "comment:"); assert (e); - e = pkc_lookup (pk, "COMMENT:"); + e = nvc_lookup (pk, "COMMENT:"); assert (e); - e = pkc_lookup (pk, "SomeOtherName:"); + e = nvc_lookup (pk, "SomeOtherName:"); assert (e); } void -test_key_extraction (pkc_t pk) +test_key_extraction (nvc_t pk) { gpg_error_t err; gcry_sexp_t key; - err = pkc_get_private_key (pk, &key); - assert (err == 0); - assert (key); + if (private_key_mode) + { + err = nvc_get_private_key (pk, &key); + assert (err == 0); + assert (key); - if (verbose) - gcry_sexp_dump (key); + if (verbose) + gcry_sexp_dump (key); - gcry_sexp_release (key); + gcry_sexp_release (key); + } + else + { + err = nvc_get_private_key (pk, &key); + assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY); + } } void -test_iteration (pkc_t pk) +test_iteration (nvc_t pk) { int i; - pke_t e; + nve_t e; i = 0; - for (e = pkc_first (pk); e; e = pke_next (e)) + for (e = nvc_first (pk); e; e = nve_next (e)) i++; assert (i == 4); i = 0; - for (e = pkc_lookup (pk, "Comment:"); + for (e = nvc_lookup (pk, "Comment:"); e; - e = pke_next_value (e, "Comment:")) + e = nve_next_value (e, "Comment:")) i++; assert (i == 3); } void -test_whitespace (pkc_t pk) +test_whitespace (nvc_t pk) { - pke_t e; + nve_t e; - e = pkc_lookup (pk, "One:"); + e = nvc_lookup (pk, "One:"); assert (e); - assert (strcmp (pke_value (e), "WithoutWhitespace") == 0); + assert (strcmp (nve_value (e), "WithoutWhitespace") == 0); - e = pkc_lookup (pk, "Two:"); + e = nvc_lookup (pk, "Two:"); assert (e); - assert (strcmp (pke_value (e), "With Whitespace") == 0); + assert (strcmp (nve_value (e), "With Whitespace") == 0); - e = pkc_lookup (pk, "Three:"); + e = nvc_lookup (pk, "Three:"); assert (e); - assert (strcmp (pke_value (e), + assert (strcmp (nve_value (e), "Blank lines in continuations encode newlines.\n" "Next paragraph.") == 0); } @@ -110,7 +130,7 @@ test_whitespace (pkc_t pk) struct { char *value; - void (*test_func) (pkc_t); + void (*test_func) (nvc_t); } tests[] = { { @@ -193,7 +213,7 @@ struct static char * -pkc_to_string (pkc_t pk) +nvc_to_string (nvc_t pk) { gpg_error_t err; char *buf; @@ -203,7 +223,7 @@ pkc_to_string (pkc_t pk) sink = es_fopenmem (0, "rw"); assert (sink); - err = pkc_write (pk, sink); + err = nvc_write (pk, sink); assert (err == 0); len = es_ftell (sink); @@ -226,7 +246,7 @@ void run_tests (void) { gpg_error_t err; - pkc_t pk; + nvc_t pk; int i; for (i = 0; i < DIM (tests); i++) @@ -240,17 +260,20 @@ run_tests (void) 0, dummy_realloc, dummy_free, "r"); assert (source); - err = pkc_parse (&pk, NULL, source); + if (private_key_mode) + err = nvc_parse_private_key (&pk, NULL, source); + else + err = nvc_parse (&pk, NULL, source); assert (err == 0); assert (pk); if (verbose) { - err = pkc_write (pk, es_stderr); + err = nvc_write (pk, es_stderr); assert (err == 0); } - buf = pkc_to_string (pk); + buf = nvc_to_string (pk); assert (memcmp (tests[i].value, buf, len) == 0); es_fclose (source); @@ -259,7 +282,7 @@ run_tests (void) if (tests[i].test_func) tests[i].test_func (pk); - pkc_release (pk); + nvc_release (pk); } } @@ -268,106 +291,115 @@ void run_modification_tests (void) { gpg_error_t err; - pkc_t pk; + nvc_t pk; gcry_sexp_t key; char *buf; - pk = pkc_new (); + pk = my_nvc_new (); assert (pk); - pkc_set (pk, "Foo:", "Bar"); - buf = pkc_to_string (pk); + nvc_set (pk, "Foo:", "Bar"); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Bar\n") == 0); xfree (buf); - pkc_set (pk, "Foo:", "Baz"); - buf = pkc_to_string (pk); + nvc_set (pk, "Foo:", "Baz"); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Baz\n") == 0); xfree (buf); - pkc_set (pk, "Bar:", "Bazzel"); - buf = pkc_to_string (pk); + nvc_set (pk, "Bar:", "Bazzel"); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0); xfree (buf); - pkc_add (pk, "Foo:", "Bar"); - buf = pkc_to_string (pk); + nvc_add (pk, "Foo:", "Bar"); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0); xfree (buf); - pkc_add (pk, "DontExistYet:", "Bar"); - buf = pkc_to_string (pk); + nvc_add (pk, "DontExistYet:", "Bar"); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\nDontExistYet: Bar\n") == 0); xfree (buf); - pkc_delete (pk, pkc_lookup (pk, "DontExistYet:")); - buf = pkc_to_string (pk); + nvc_delete (pk, nvc_lookup (pk, "DontExistYet:")); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Baz\nFoo: Bar\nBar: Bazzel\n") == 0); xfree (buf); - pkc_delete (pk, pke_next_value (pkc_lookup (pk, "Foo:"), "Foo:")); - buf = pkc_to_string (pk); + nvc_delete (pk, nve_next_value (nvc_lookup (pk, "Foo:"), "Foo:")); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Baz\nBar: Bazzel\n") == 0); xfree (buf); - pkc_delete (pk, pkc_lookup (pk, "Foo:")); - buf = pkc_to_string (pk); + nvc_delete (pk, nvc_lookup (pk, "Foo:")); + buf = nvc_to_string (pk); assert (strcmp (buf, "Bar: Bazzel\n") == 0); xfree (buf); - pkc_delete (pk, pkc_first (pk)); - buf = pkc_to_string (pk); + nvc_delete (pk, nvc_first (pk)); + buf = nvc_to_string (pk); assert (strcmp (buf, "") == 0); xfree (buf); - pkc_set (pk, "Foo:", "A really long value spanning across multiple lines" + nvc_set (pk, "Foo:", "A really long value spanning across multiple lines" " that has to be wrapped at a convenient space."); - buf = pkc_to_string (pk); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: A really long value spanning across multiple" " lines that has to be\n wrapped at a convenient space.\n") == 0); xfree (buf); - pkc_set (pk, "Foo:", "XA really long value spanning across multiple lines" + nvc_set (pk, "Foo:", "XA really long value spanning across multiple lines" " that has to be wrapped at a convenient space."); - buf = pkc_to_string (pk); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: XA really long value spanning across multiple" " lines that has to\n be wrapped at a convenient space.\n") == 0); xfree (buf); - pkc_set (pk, "Foo:", "XXXXA really long value spanning across multiple lines" + nvc_set (pk, "Foo:", "XXXXA really long value spanning across multiple lines" " that has to be wrapped at a convenient space."); - buf = pkc_to_string (pk); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: XXXXA really long value spanning across multiple" " lines that has\n to be wrapped at a convenient space.\n") == 0); xfree (buf); - pkc_set (pk, "Foo:", "Areallylongvaluespanningacrossmultiplelines" + nvc_set (pk, "Foo:", "Areallylongvaluespanningacrossmultiplelines" "thathastobewrappedataconvenientspacethatisnotthere."); - buf = pkc_to_string (pk); + buf = nvc_to_string (pk); assert (strcmp (buf, "Foo: Areallylongvaluespanningacrossmultiplelinesthat" "hastobewrappedataco\n nvenientspacethatisnotthere.\n") == 0); xfree (buf); - pkc_release (pk); + nvc_release (pk); - pk = pkc_new (); + pk = my_nvc_new (); assert (pk); err = gcry_sexp_build (&key, NULL, "(hello world)"); assert (err == 0); assert (key); - err = pkc_set_private_key (pk, key); + if (private_key_mode) + { + err = nvc_set_private_key (pk, key); + assert (err == 0); + + buf = nvc_to_string (pk); + assert (strcmp (buf, "Key: (hello world)\n") == 0); + xfree (buf); + } + else + { + err = nvc_set_private_key (pk, key); + assert (gpg_err_code (err) == GPG_ERR_MISSING_KEY); + } gcry_sexp_release (key); - assert (err == 0); - buf = pkc_to_string (pk); - assert (strcmp (buf, "Key: (hello world)\n") == 0); - xfree (buf); - pkc_release (pk); + nvc_release (pk); } @@ -380,7 +412,7 @@ convert (const char *fname) char *buf; size_t buflen; struct stat st; - pkc_t pk; + nvc_t pk; source = es_fopen (fname, "rb"); if (source == NULL) @@ -403,13 +435,13 @@ convert (const char *fname) exit (1); } - pk = pkc_new (); + pk = my_nvc_new (); assert (pk); - err = pkc_set_private_key (pk, key); + err = nvc_set_private_key (pk, key); assert (err == 0); - err = pkc_write (pk, es_stdout); + err = nvc_write (pk, es_stdout); assert (err == 0); return; @@ -426,8 +458,8 @@ parse (const char *fname) gpg_error_t err; estream_t source; char *buf; - pkc_t pk_a, pk_b; - pke_t e; + nvc_t pk_a, pk_b; + nve_t e; int line; source = es_fopen (fname, "rb"); @@ -437,7 +469,10 @@ parse (const char *fname) exit (1); } - err = pkc_parse (&pk_a, &line, source); + if (private_key_mode) + err = nvc_parse_private_key (&pk_a, &line, source); + else + err = nvc_parse (&pk_a, &line, source); if (err) { fprintf (stderr, "failed to parse %s line %d: %s\n", @@ -445,36 +480,36 @@ parse (const char *fname) exit (1); } - buf = pkc_to_string (pk_a); + buf = nvc_to_string (pk_a); xfree (buf); - pk_b = pkc_new (); + pk_b = my_nvc_new (); assert (pk_b); - for (e = pkc_first (pk_a); e; e = pke_next (e)) + for (e = nvc_first (pk_a); e; e = nve_next (e)) { gcry_sexp_t key = NULL; - if (strcasecmp (pke_name (e), "Key:") == 0) + if (private_key_mode && !strcasecmp (nve_name (e), "Key:")) { - err = pkc_get_private_key (pk_a, &key); + err = nvc_get_private_key (pk_a, &key); if (err) key = NULL; } if (key) { - err = pkc_set_private_key (pk_b, key); + err = nvc_set_private_key (pk_b, key); assert (err == 0); } else { - err = pkc_add (pk_b, pke_name (e), pke_value (e)); + err = nvc_add (pk_b, nve_name (e), nve_value (e)); assert (err == 0); } } - buf = pkc_to_string (pk_b); + buf = nvc_to_string (pk_b); if (verbose) fprintf (stdout, "%s", buf); xfree (buf); @@ -487,7 +522,8 @@ print_usage (void) fprintf (stderr, "usage: t-private-keys [--verbose]" " [--convert <private-key-file>" - " || --parse <extended-private-key-file>]\n"); + " || --parse-key <extended-private-key-file>" + " || --parse <file> ]\n"); exit (2); } @@ -495,7 +531,7 @@ print_usage (void) int main (int argc, char **argv) { - enum { TEST, CONVERT, PARSE } command = TEST; + enum { TEST, CONVERT, PARSE, PARSEKEY } command = TEST; if (argc) { argc--; argv++; } @@ -513,6 +549,14 @@ main (int argc, char **argv) print_usage (); } + if (argc && !strcmp (argv[0], "--parse-key")) + { + command = PARSEKEY; + argc--; argv++; + if (argc != 1) + print_usage (); + } + if (argc && !strcmp (argv[0], "--parse")) { command = PARSE; @@ -526,12 +570,20 @@ main (int argc, char **argv) case TEST: run_tests (); run_modification_tests (); + private_key_mode = 1; + run_tests (); + run_modification_tests (); break; case CONVERT: convert (*argv); break; + case PARSEKEY: + private_key_mode = 1; + parse (*argv); + break; + case PARSE: parse (*argv); break; diff --git a/common/t-recsel.c b/common/t-recsel.c new file mode 100644 index 000000000..fe2a7b9d0 --- /dev/null +++ b/common/t-recsel.c @@ -0,0 +1,405 @@ +/* t-recsel.c - Module test for recsel.c + * Copyright (C) 2016 Werner Koch + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "util.h" +#include "init.h" +#include "recsel.h" + +#define PGM "t-recsel" + +#define pass() do { ; } while(0) +#define fail(a,e) do { log_error ("line %d: test %d failed: %s\n", \ + __LINE__, (a), gpg_strerror ((e))); \ + exit (1); \ + } while(0) + +static int verbose; +static int debug; + + +#define FREEEXPR() do { recsel_release (se); se = NULL; } while (0) +#define ADDEXPR(a) do { \ + err = recsel_parse_expr (&se, (a)); \ + if (err) \ + fail (0, err); \ + } while (0) + + +static const char * +test_1_getval (void *cookie, const char *name) +{ + if (strcmp (name, "uid")) + fail (0, 0); + return cookie; +} + +static void +run_test_1 (void) +{ + static const char *expr[] = { + "uid =~ Alfa", + "&& uid !~ Test ", + "|| uid =~ Alpha", + " uid !~ Test" + }; + gpg_error_t err; + recsel_expr_t se = NULL; + int i; + + for (i=0; i < DIM (expr); i++) + { + err = recsel_parse_expr (&se, expr[i]); + if (err) + fail (i, err); + } + + if (debug) + recsel_dump (se); + + /* The example from recsel.c in several variants. */ + if (!recsel_select (se, test_1_getval, "Alfa")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, "Alpha")) + fail (0, 0); + if (recsel_select (se, test_1_getval, "Alfa Test")) + fail (0, 0); + if (recsel_select (se, test_1_getval, "Alpha Test")) + fail (0, 0); + + /* Some modified versions from above. */ + if (!recsel_select (se, test_1_getval, " AlfA Tes")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, " AlfA Tes ")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, " Tes AlfA")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, "TesAlfA")) + fail (0, 0); + + /* Simple cases. */ + if (recsel_select (se, NULL, NULL)) + fail (0, 0); + if (recsel_select (se, test_1_getval, NULL)) + fail (0, 0); + if (recsel_select (se, test_1_getval, "")) + fail (0, 0); + + FREEEXPR(); +} + + +/* Same as test1 but using a combined expression.. */ +static void +run_test_1b (void) +{ + gpg_error_t err; + recsel_expr_t se = NULL; + + err = recsel_parse_expr + (&se, "uid =~ Alfa && uid !~ Test || uid =~ Alpha && uid !~ Test" ); + if (err) + fail (0, err); + + if (debug) + recsel_dump (se); + + /* The example from recsel.c in several variants. */ + if (!recsel_select (se, test_1_getval, "Alfa")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, "Alpha")) + fail (0, 0); + if (recsel_select (se, test_1_getval, "Alfa Test")) + fail (0, 0); + if (recsel_select (se, test_1_getval, "Alpha Test")) + fail (0, 0); + + /* Some modified versions from above. */ + if (!recsel_select (se, test_1_getval, " AlfA Tes")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, " AlfA Tes ")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, " Tes AlfA")) + fail (0, 0); + if (!recsel_select (se, test_1_getval, "TesAlfA")) + fail (0, 0); + + /* Simple cases. */ + if (recsel_select (se, NULL, NULL)) + fail (0, 0); + if (recsel_select (se, test_1_getval, NULL)) + fail (0, 0); + if (recsel_select (se, test_1_getval, "")) + fail (0, 0); + + FREEEXPR(); +} + + +static const char * +test_2_getval (void *cookie, const char *name) +{ + if (!strcmp (name, "uid")) + return "[email protected]"; + else if (!strcmp (name, "keyid")) + return "0x12345678"; + else if (!strcmp (name, "zero")) + return "0"; + else if (!strcmp (name, "one")) + return "1"; + else if (!strcmp (name, "blanks")) + return " "; + else if (!strcmp (name, "letters")) + return "abcde"; + else + return cookie; +} + +static void +run_test_2 (void) +{ + gpg_error_t err; + recsel_expr_t se = NULL; + + ADDEXPR ("uid = [email protected]"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("uid = [email protected]"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("-c uid = [email protected]"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("uid =~ [email protected]"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("uid =~ [email protected]"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("-c uid =~ [email protected]"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("uid !~ [email protected]"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("uid !~ [email protected]"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("-c uid !~ [email protected]"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("uid =~ @"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("uid =~ @"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("keyid == 0x12345678"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("keyid != 0x12345678"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("keyid >= 0x12345678"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("keyid <= 0x12345678"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("keyid > 0x12345677"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("keyid < 0x12345679"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("keyid > 0x12345678"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("keyid < 0x12345678"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + + FREEEXPR(); + ADDEXPR ("uid -n"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("uid -z"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("nothing -z"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("nothing -n"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("blanks -n"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("blanks -z"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("letters -n"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("letters -z"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + + FREEEXPR(); + ADDEXPR ("nothing -f"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("nothing -t"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("zero -f"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("zero -t"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("one -t"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("one -f"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("blanks -f"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("blanks -t"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + FREEEXPR(); + ADDEXPR ("letter -f"); + if (!recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + FREEEXPR(); + ADDEXPR ("letters -t"); + if (recsel_select (se, test_2_getval, NULL)) + fail (0, 0); + + + FREEEXPR(); +} + + + +int +main (int argc, char **argv) +{ + int last_argc = -1; + + log_set_prefix (PGM, GPGRT_LOG_WITH_PREFIX); + init_common_subsystems (&argc, &argv); + + if (argc) + { argc--; argv++; } + while (argc && last_argc != argc ) + { + last_argc = argc; + if (!strcmp (*argv, "--")) + { + argc--; argv++; + break; + } + else if (!strcmp (*argv, "--help")) + { + fputs ("usage: " PGM " [options]\n" + "Options:\n" + " --verbose print timings etc.\n" + " --debug flyswatter\n", + stdout); + exit (0); + } + else if (!strcmp (*argv, "--verbose")) + { + verbose++; + argc--; argv++; + } + else if (!strcmp (*argv, "--debug")) + { + verbose += 2; + debug++; + argc--; argv++; + } + else if (!strncmp (*argv, "--", 2)) + { + log_error ("unknown option '%s'\n", *argv); + exit (2); + } + } + + run_test_1 (); + run_test_1b (); + run_test_2 (); + /* Fixme: We should add test for complex conditions. */ + + return 0; +} diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c index 4f4555e14..ccadf0222 100644 --- a/common/t-stringhelp.c +++ b/common/t-stringhelp.c @@ -223,6 +223,7 @@ test_strconcat (void) fail (0); else if (errno != EINVAL) fail (0); + xfree (out); #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */ out = strconcat (NULL); @@ -232,6 +233,8 @@ test_strconcat (void) out = strconcat (NULL, NULL); if (!out || *out) fail (1); + xfree (out); + out = strconcat ("", NULL); if (!out || *out) fail (1); @@ -283,6 +286,7 @@ test_xstrconcat (void) "1", "2", "3", "4", "5", "6", "7", NULL); if (!out) fail (0); + xfree (out); #if __GNUC__ < 4 /* gcc 4.0 has a sentinel attribute. */ out = xstrconcat (NULL); @@ -292,6 +296,8 @@ test_xstrconcat (void) out = xstrconcat (NULL, NULL); if (!out) fail (1); + xfree (out); + out = xstrconcat ("", NULL); if (!out || *out) fail (1); @@ -534,6 +540,7 @@ test_strsplit (void) fail (tidx * 1000 + i + 1); } + xfree (fields); xfree (s2); } } diff --git a/common/t-strlist.c b/common/t-strlist.c index b03390593..e49d5a724 100644 --- a/common/t-strlist.c +++ b/common/t-strlist.c @@ -67,6 +67,8 @@ test_strlist_rev (void) fail (2); if (s->next->next->next) fail (2); + + free_strlist (s); } diff --git a/common/zb32.c b/common/zb32.c index 05aa0eac8..54bd5d4fd 100644 --- a/common/zb32.c +++ b/common/zb32.c @@ -35,7 +35,7 @@ #include <assert.h> #include "util.h" - +#include "zb32.h" /* Zooko's base32 variant. See RFC-6189 and http://philzimmermann.com/docs/human-oriented-base-32-encoding.txt |