1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-03-25 22:19:59 +01:00

Merge branch 'master' into STABLE-BRANCH-2-2

--
This commit is contained in:
Werner Koch 2016-07-13 15:11:46 +02:00
commit 4ef62278e3
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
240 changed files with 23772 additions and 1518 deletions

2
.gitignore vendored
View File

@ -59,6 +59,8 @@ doc/faq.raw.xref
doc/gnupg-card-architecture.eps
doc/gnupg-card-architecture.pdf
doc/gnupg-card-architecture.png
doc/gnupg-module-overview.pdf
doc/gnupg-module-overview.png
doc/gnupg.7
doc/gpg-agent.1
doc/gpg-connect-agent.1

View File

@ -30,7 +30,7 @@ List of Copyright holders
Copyright (C) 1999-2003 Symas Corporation.
Copyright (C) 1998-2003 Hallvard B. Furuseth.
Copyright (C) 1992-1996 Regents of the University of Michigan.
Copyright (C) 2000 Dimitrios Souflis
Authors with a FSF copyright assignment
@ -194,6 +194,9 @@ Stefan Tomanek <tomanek@internet-sicherheit.de>
Werner Koch <wk@gnupg.org>
2013-03-29:87620ahchj.fsf@vigenere.g10code.de:
Yann E. MORIN <yann.morin.1998@free.fr>
2016-07-10:20160710093202.GA3688@free.fr:
Other authors
=============
@ -211,6 +214,10 @@ Alexandre Julliard.
The gpg-zip documentation is based on the manpage for gpg-zip, written
by Colin Tuckley and Daniel Leidert for the GNU/Debian distribution.
The test driver is based on TinySCHEME by Dimitrios Souflis and
available under a permissive license. For the terms see the file
tests/gpgscm/LICENSE.TinySCHEME.
Copyright
=========

View File

@ -165,23 +165,25 @@ AC_DEFUN([GNUPG_CHECK_ENDIAN],
# build_NAME and whether --enable-NAME or --disable-NAME is shown with
# ./configure --help
AC_DEFUN([GNUPG_BUILD_PROGRAM],
[build_$1=$2
[m4_define([my_build], [m4_bpatsubst(build_$1, [[^a-zA-Z0-9_]], [_])])
my_build=$2
m4_if([$2],[yes],[
AC_ARG_ENABLE([$1], AC_HELP_STRING([--disable-$1],
[do not build the $1 program]),
build_$1=$enableval, build_$1=$2)
my_build=$enableval, my_build=$2)
],[
AC_ARG_ENABLE([$1], AC_HELP_STRING([--enable-$1],
[build the $1 program]),
build_$1=$enableval, build_$1=$2)
my_build=$enableval, my_build=$2)
])
case "$build_$1" in
case "$my_build" in
no|yes)
;;
*)
AC_MSG_ERROR([only yes or no allowed for feature --enable-$1])
;;
esac
m4_undefine([my_build])
])

View File

@ -2663,14 +2663,13 @@ static const char hlp_updatestartuptty[] =
static gpg_error_t
cmd_updatestartuptty (assuan_context_t ctx, char *line)
{
static const char *names[] =
{ "GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL };
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0;
session_env_t se;
int idx;
char *lc_ctype = NULL;
char *lc_messages = NULL;
int iterator;
const char *name;
(void)line;
@ -2681,11 +2680,12 @@ cmd_updatestartuptty (assuan_context_t ctx, char *line)
if (!se)
err = gpg_error_from_syserror ();
for (idx=0; !err && names[idx]; idx++)
iterator = 0;
while (!err && (name = session_env_list_stdenvnames (&iterator, NULL)))
{
const char *value = session_env_getenv (ctrl->session_env, names[idx]);
const char *value = session_env_getenv (ctrl->session_env, name);
if (value)
err = session_env_setenv (se, names[idx], value);
err = session_env_setenv (se, name, value);
}
if (!err && ctrl->lc_ctype)

View File

@ -35,7 +35,7 @@
#include "agent.h"
#include "i18n.h"
#include "../common/ssh-utils.h"
#include "../common/private-keys.h"
#include "../common/name-value.h"
#ifndef O_BINARY
#define O_BINARY 0
@ -57,12 +57,12 @@ write_extended_private_key (char *fname, estream_t fp,
const void *buf, size_t len)
{
gpg_error_t err;
pkc_t pk = NULL;
nvc_t pk = NULL;
gcry_sexp_t key = NULL;
int remove = 0;
int line;
err = pkc_parse (&pk, &line, fp);
err = nvc_parse_private_key (&pk, &line, fp);
if (err)
{
log_error ("error parsing '%s' line %d: %s\n",
@ -74,7 +74,7 @@ write_extended_private_key (char *fname, estream_t fp,
if (err)
goto leave;
err = pkc_set_private_key (pk, key);
err = nvc_set_private_key (pk, key);
if (err)
goto leave;
@ -82,7 +82,7 @@ write_extended_private_key (char *fname, estream_t fp,
if (err)
goto leave;
err = pkc_write (pk, fp);
err = nvc_write (pk, fp);
if (err)
{
log_error ("error writing '%s': %s\n", fname, gpg_strerror (err));
@ -117,7 +117,7 @@ write_extended_private_key (char *fname, estream_t fp,
gnupg_remove (fname);
xfree (fname);
gcry_sexp_release (key);
pkc_release (pk);
nvc_release (pk);
return err;
}
@ -687,10 +687,10 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
if (first != '(')
{
/* Key is in extended format. */
pkc_t pk;
nvc_t pk;
int line;
rc = pkc_parse (&pk, &line, fp);
rc = nvc_parse_private_key (&pk, &line, fp);
es_fclose (fp);
if (rc)
@ -698,8 +698,8 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
fname, line, gpg_strerror (rc));
else
{
rc = pkc_get_private_key (pk, result);
pkc_release (pk);
rc = nvc_get_private_key (pk, result);
nvc_release (pk);
if (rc)
log_error ("error getting private key from '%s': %s\n",
fname, gpg_strerror (rc));

View File

@ -109,6 +109,10 @@ w32-release: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
installer-from-source
w32-release-offline: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
CUSTOM_SWDB=1 pkgrep=${HOME}/b pkg10rep=${HOME}/b \
installer-from-source
# Set this to "git" to build from git,

View File

@ -1,5 +1,5 @@
Here is a list with collected copyright notices. For details see the
description of each individual package. [Compiled by wk 2016-04-20]
description of each individual package. [Compiled by wk 2016-06-17]
GnuPG is
@ -18,6 +18,7 @@ GnuPG is
Copyright (C) 1999-2003 Symas Corporation.
Copyright (C) 1998-2003 Hallvard B. Furuseth.
Copyright (C) 1992-1996 Regents of the University of Michigan.
Copyright (C) 2000 Dimitrios Souflis
GnuPG is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@ -111,6 +112,39 @@ ADNS is
Copyright (C) 1991 Massachusetts Institute of Technology
TinySCHEME is part of the GnuPG package and is
Copyright (c) 2000, Dimitrios Souflis
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of Dimitrios Souflis nor the names of the
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
SQLite has
been put into the public-domain by its author D. Richard Hipp:

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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/>.
*/

View File

@ -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;

View File

@ -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],

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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 private_key_container));
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)
{
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)

View File

@ -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 */

View File

@ -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
}

571
common/recsel.c Normal file
View File

@ -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;
}

43
common/recsel.h Normal file
View File

@ -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*/

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -87,6 +87,8 @@ run_test (void)
fail (idx);
else if (strcmp (mbox, testtbl[idx].mbox))
fail (idx);
xfree (mbox);
}
}

View File

@ -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;
@ -524,6 +568,9 @@ main (int argc, char **argv)
switch (command)
{
case TEST:
run_tests ();
run_modification_tests ();
private_key_mode = 1;
run_tests ();
run_modification_tests ();
break;
@ -532,6 +579,11 @@ main (int argc, char **argv)
convert (*argv);
break;
case PARSEKEY:
private_key_mode = 1;
parse (*argv);
break;
case PARSE:
parse (*argv);
break;

405
common/t-recsel.c Normal file
View File

@ -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 "foo@example.org";
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 = foo@example.org");
if (!recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("uid = Foo@example.org");
if (!recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("-c uid = Foo@example.org");
if (recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("uid =~ foo@example.org");
if (!recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("uid =~ Foo@example.org");
if (!recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("-c uid =~ Foo@example.org");
if (recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("uid !~ foo@example.org");
if (recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("uid !~ Foo@example.org");
if (recsel_select (se, test_2_getval, NULL))
fail (0, 0);
FREEEXPR();
ADDEXPR ("-c uid !~ Foo@example.org");
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;
}

View File

@ -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);
}
}

View File

@ -67,6 +67,8 @@ test_strlist_rev (void)
fail (2);
if (s->next->next->next)
fail (2);
free_strlist (s);
}

View File

@ -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

View File

@ -130,6 +130,7 @@ GNUPG_BUILD_PROGRAM(tools, yes)
GNUPG_BUILD_PROGRAM(doc, yes)
GNUPG_BUILD_PROGRAM(symcryptrun, no)
GNUPG_BUILD_PROGRAM(gpgtar, yes)
GNUPG_BUILD_PROGRAM(wks-tools, no)
AC_SUBST(PACKAGE)
AC_SUBST(PACKAGE_GT)
@ -1670,6 +1671,7 @@ AM_CONDITIONAL(BUILD_TOOLS, test "$build_tools" = "yes")
AM_CONDITIONAL(BUILD_DOC, test "$build_doc" = "yes")
AM_CONDITIONAL(BUILD_SYMCRYPTRUN, test "$build_symcryptrun" = "yes")
AM_CONDITIONAL(BUILD_GPGTAR, test "$build_gpgtar" = "yes")
AM_CONDITIONAL(BUILD_WKS_TOOLS, test "$build_wks_tools" = "yes")
AM_CONDITIONAL(ENABLE_CARD_SUPPORT, test "$card_support" = yes)
AM_CONDITIONAL(NO_TRUST_MODELS, test "$use_trust_models" = no)
@ -1903,7 +1905,9 @@ tools/gpg-zip
tools/Makefile
doc/Makefile
tests/Makefile
tests/gpgscm/Makefile
tests/openpgp/Makefile
tests/migrations/Makefile
tests/pkits/Makefile
g10/gpg.w32-manifest
])
@ -1925,6 +1929,7 @@ echo "
G13: $build_g13
Dirmngr: $build_dirmngr
Gpgtar: $build_gpgtar
WKS tools: $build_wks_tools
Protect tool: $show_gnupg_protect_tool_pgm
LDAP wrapper: $show_gnupg_dirmngr_ldap_pgm

View File

@ -744,7 +744,7 @@ http_session_set_log_cb (http_session_t sess,
/* Start a HTTP retrieval and on success store at R_HD a context
pointer for completing the request and to wait for the response.
If HTTPHOST is not NULL it is used hor the Host header instead of a
If HTTPHOST is not NULL it is used for the Host header instead of a
Host header derived from the URL. */
gpg_error_t
http_open (http_t *r_hd, http_req_t reqtype, const char *url,

View File

@ -799,9 +799,10 @@ cmd_dns_cert (assuan_context_t ctx, char *line)
static const char hlp_wkd_get[] =
"WKD_GET <user_id>\n"
"WKD_GET [--submission-address] <user_id>\n"
"\n"
"Return the key for <user_id> from a Web Key Directory.\n";
"Return the key or the submission address for <user_id>\n"
"from a Web Key Directory.";
static gpg_error_t
cmd_wkd_get (assuan_context_t ctx, char *line)
{
@ -812,7 +813,9 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
char sha1buf[20];
char *uri = NULL;
char *encodedhash = NULL;
int opt_submission_addr;
opt_submission_addr = has_option (line, "--submission-address");
line = skip_options (line);
mbox = mailbox_from_userid (line);
@ -831,11 +834,21 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
goto leave;
}
uri = strconcat ("https://",
domain,
"/.well-known/openpgpkey/hu/",
encodedhash,
NULL);
if (opt_submission_addr)
{
uri = strconcat ("https://",
domain,
"/.well-known/openpgpkey/submission-address",
NULL);
}
else
{
uri = strconcat ("https://",
domain,
"/.well-known/openpgpkey/hu/",
encodedhash,
NULL);
}
if (!uri)
{
err = gpg_error_from_syserror ();
@ -848,7 +861,8 @@ cmd_wkd_get (assuan_context_t ctx, char *line)
outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
if (!outfp)
err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
err = set_error (GPG_ERR_ASS_GENERAL,
"error setting up a data stream");
else
{
err = ks_action_fetch (ctrl, uri, outfp);

View File

@ -222,6 +222,8 @@ check_ldap_escape_filter (int test_count, struct test_ldap_escape_filter *test)
test->filter, result, test->result);
fail (test_count * 1000);
}
xfree (result);
}
static void

View File

@ -46,6 +46,8 @@ are
- scd :: The scdaemon component
- ccid :: The CCID driver in scdaemon
- dirmngr :: The dirmngr component
- wks :: The web key service tools
- tools :: Other code in tools
- w32 :: Windows related code
- po :: Translations
- build :: Changes to the build system

View File

@ -32,7 +32,7 @@ helpfiles = help.txt help.be.txt help.ca.txt help.cs.txt \
help.pt_BR.txt help.ro.txt help.ru.txt help.sk.txt \
help.sv.txt help.tr.txt help.zh_CN.txt help.zh_TW.txt
EXTRA_DIST = samplekeys.asc mksamplekeys \
EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem qualified.txt \
gnupg-logo.eps gnupg-logo.pdf gnupg-logo.png gnupg-logo-tr.png \
gnupg-module-overview.png gnupg-module-overview.pdf \
gnupg-card-architecture.png gnupg-card-architecture.pdf \
@ -46,7 +46,7 @@ BUILT_SOURCES = gnupg-module-overview.png gnupg-module-overview.pdf \
info_TEXINFOS = gnupg.texi
dist_pkgdata_DATA = qualified.txt com-certs.pem $(helpfiles)
dist_pkgdata_DATA = $(helpfiles)
nobase_dist_doc_DATA = FAQ DETAILS HACKING DCO TRANSLATE OpenPGP KEYSERVER \
$(examples)

View File

@ -815,7 +815,7 @@ it by adding this to your init script:
@example
unset SSH_AGENT_PID
if [ "$@{gnupg_SSH_AUTH_SOCK_by:-0@}" -ne $$ ]; then
export SSH_AUTH_SOCK="$@{HOME@}/.gnupg/S.gpg-agent.ssh"
export SSH_AUTH_SOCK="$(gpgconf --list-dirs agent-ssh-socket)"
fi
@end example
@end cartouche

View File

@ -233,7 +233,7 @@ read from STDIN. If only a one argument is given, it is expected to
be a complete signature.
With more than 1 argument, the first should be a detached signature
and the remaining files ake up the the signed data. To read the signed
and the remaining files make up the the signed data. To read the signed
data from STDIN, use @samp{-} as the second filename. For security
reasons a detached signature cannot read the signed material from
STDIN without denoting it in the above way.
@ -281,9 +281,10 @@ List all keys from the public keyrings, or just the keys given on the
command line.
Avoid using the output of this command in scripts or other programs as
it is likely to change as GnuPG changes. See @option{--with-colons} for a
machine-parseable key listing command that is appropriate for use in
scripts and other programs.
it is likely to change as GnuPG changes. See @option{--with-colons}
for a machine-parseable key listing command that is appropriate for
use in scripts and other programs. Never use the regular output for
scripts - it is only for human consumption.
@item --list-secret-keys
@itemx -K
@ -291,7 +292,7 @@ scripts and other programs.
List all keys from the secret keyrings, or just the ones given on the
command line. A @code{#} after the letters @code{sec} means that the
secret key is not usable (for example, if it was created via
@option{--export-secret-subkeys}).
@option{--export-secret-subkeys}). See also @option{--list-keys}.
@item --list-sigs
@opindex list-sigs
@ -569,7 +570,7 @@ Use the source, Luke :-). The output format is still subject to change.
@item --enarmor
@item --dearmor
@itemx --dearmor
@opindex enarmor
@opindex dearmor
Pack or unpack an arbitrary input into/from an OpenPGP ASCII armor.
@ -1040,6 +1041,15 @@ the interactive sub-command @code{adduid} of @option{--edit-key} the
white space removed, it is expected to be UTF-8 encoded, and no checks
on its form are applied.
@item --quick-revuid @var{user-id} @var{user-id-to-revoke}
@opindex quick-revuid
This command revokes a User ID on an existing key. It cannot be used
to revoke the last User ID on key (some non-revoked User ID must
remain), with revocation reason ``User ID is no longer valid''. If
you want to specify a different revocation reason, or to supply
supplementary revocation text, you should use the interactive
sub-command @code{revuid} of @option{--edit-key}.
@item --passwd @var{user_id}
@opindex passwd
Change the passphrase of the secret key belonging to the certificate
@ -1361,6 +1371,10 @@ Note that this adds a keyring to the current list. If the intent is to
use the specified keyring alone, use @option{--keyring} along with
@option{--no-default-keyring}.
If the the option @option{--no-keyring} has been used no keyrings will
be used at all.
@item --secret-keyring @code{file}
@opindex secret-keyring
This is an obsolete option and ignored. All secret keys are stored in
@ -2023,6 +2037,22 @@ limited countermeasure against traffic analysis. If this option or
@option{--recipient} is not specified, GnuPG asks for the user ID unless
@option{--default-recipient} is given.
@item --recipient-file @var{file}
@itemx -f
@opindex recipient-file
This option is similar to @option{--recipient} except that it
encrypts to a key stored in the given file. @var{file} must be the
name of a file containing exactly one key. @command{gpg} assumes that
the key in this file is fully valid.
@item --hidden-recipient-file @var{file}
@itemx -F
@opindex hidden-recipient-file
This option is similar to @option{--hidden-recipient} except that it
encrypts to a key stored in the given file. @var{file} must be the
name of a file containing exactly one key. @command{gpg} assumes that
the key in this file is fully valid.
@item --encrypt-to @code{name}
@opindex encrypt-to
Same as @option{--recipient} but this one is intended for use in the
@ -2041,11 +2071,6 @@ recipients given either by use of @option{--recipient} or by the asked user id.
No trust checking is performed for these user ids and even disabled
keys can be used.
@item --encrypt-to-default-key
@opindex encrypt-to-default-key
If the default secret key is taken from @option{--default-key}, then
also encrypt to that key.
@item --no-encrypt-to
@opindex no-encrypt-to
Disable the use of all @option{--encrypt-to} and
@ -2179,6 +2204,18 @@ opposite meaning. The options are:
subkey. Defaults to no for regular @option{--import} and to yes for
keyserver @option{--recv-keys}.
@item import-show
Show a listing of the key as imported right before it is stored.
This can be combined with the option @option{--dry-run} to only look
at keys.
@item import-export
Run the entire import code but instead of storing the key to the
local keyring write it to the output. The export options
@option{export-pka} and @option{export-dane} affect the output. This
option can be used to remove all invalid parts from a key without the
need to store it.
@item merge-only
During import, allow key updates to existing keys, but do not allow
any new keys to be imported. Defaults to no.
@ -2198,6 +2235,47 @@ opposite meaning. The options are:
Defaults to no.
@end table
@item --import-filter @code{@var{name}=@var{expr}}
@itemx --export-filter @code{@var{name}=@var{expr}}
@opindex import-filter
@opindex export-filter
These options define an import/export filter which are applied to the
imported/exported keyblock right before it will be stored/written.
@var{name} defines the type of filter to use, @var{expr} the
expression to evaluate. The option can be used several times which
then appends more expression to the same @var{name}.
@noindent
The available filter types are:
@table @asis
@item keep-uid
This filter will keep a user id packet and its dependent packets in
the keyblock if the expression evaluates to true.
@end table
For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
The property names for the expressions depend on the actual filter
type and are indicated in the following table.
The available properties are:
@table @asis
@item uid
A string with the user id. (keep-uid)
@item mbox
The addr-spec part of a user id with mailbox or the empty string.
(keep-uid)
@item primary
Boolean indicating whether the user id is the primary one. (keep-uid)
@end table
@item --export-options @code{parameters}
@opindex export-options
This is a space or comma delimited string that gives options for
@ -2244,6 +2322,18 @@ opposite meaning. The options are:
most recent self-signature on each user ID. This option is the same as
running the @option{--edit-key} command "minimize" before export except
that the local copy of the key is not modified. Defaults to no.
@item export-pka
Instead of outputting the key material output PKA records suitable
to put into DNS zone files. An ORIGIN line is printed before each
record to allow diverting the records to the corresponding zone file.
@item export-dane
Instead of outputting the key material output OpenPGP DANE records
suitable to put into DNS zone files. An ORIGIN line is printed before
each record to allow diverting the records to the corresponding zone
file.
@end table
@item --with-colons
@ -2463,6 +2553,13 @@ Reset all packet, cipher and digest options to strict RFC-4880
behavior. Note that this is currently the same thing as
@option{--openpgp}.
@item --rfc4880bis
@opindex rfc4880bis
Enable experimental features from proposed updates to RFC-4880. This
option can be used in addition to the other compliance options.
Warning: The behavior may change with any GnuPG release and created
keys or data may not be usable with future GnuPG versions.
@item --rfc2440
@opindex rfc2440
Reset all packet, cipher and digest options to strict RFC-2440
@ -2940,6 +3037,10 @@ and do not provide alternate keyrings via @option{--keyring} or
@option{--secret-keyring}, then GnuPG will still use the default public or
secret keyrings.
@item --no-keyring
@opindex no-keyring
Do not add use any keyrings even if specified as options.
@item --skip-verify
@opindex skip-verify
Skip the signature verification step. This may be
@ -3170,7 +3271,6 @@ current home directory (@pxref{option --homedir}).
@end table
@c man:.RE
Note that on larger installations, it is useful to put predefined files
into the directory @file{@value{SYSCONFSKELDIR}} so that
newly created users start up with a working configuration.
@ -3245,7 +3345,6 @@ files; They all live in in the current home directory (@pxref{option
@end table
@c man:.RE
Operation is further controlled by a few environment variables:
@table @asis
@ -3338,6 +3437,123 @@ user for the filename.
@include specify-user-id.texi
@end ifset
@mansect filter expressions
@chapheading FILTER EXPRESSIONS
The options @option{--import-filter} and @option{--export-filter} use
expressions with this syntax (square brackets indicate an optional
part and curly braces a repetition, white space between the elements
are allowed):
@c man:.RS
@example
[lc] @{[@{flag@}] PROPNAME op VALUE [lc]@}
@end example
@c man:.RE
The name of a property (@var{PROPNAME}) may only consist of letters,
digits and underscores. The description for the filter type
describes which properties are defined. If an undefined property is
used it evaluates to the empty string. Unless otherwise noted, the
@var{VALUE} must always be given and may not be the empty string. No
quoting is defined for the value, thus the value may not contain the
strings @code{&&} or @code{||}, which are used as logical connection
operators. The flag @code{--} can be used to remove this restriction.
Numerical values are computed as long int; standard C notation
applies. @var{lc} is the logical connection operator; either
@code{&&} for a conjunction or @code{||} for a disjunction. A
conjunction is assumed at the begin of an expression. Conjunctions
have higher precedence than disjunctions. If @var{VALUE} starts with
one of the characters used in any @var{op} a space after the
@var{op} is required.
@noindent
The supported operators (@var{op}) are:
@table @asis
@item =~
Substring must match.
@item !~
Substring must not match.
@item =
The full string must match.
@item <>
The full string must not match.
@item ==
The numerical value must match.
@item !=
The numerical value must not match.
@item <=
The numerical value of the field must be LE than the value.
@item <
The numerical value of the field must be LT than the value.
@item >=
The numerical value of the field must be GT than the value.
@item >=
The numerical value of the field must be GE than the value.
@item -n
True if value is not empty (no value allowed).
@item -z
True if value is empty (no value allowed).
@item -t
Alias for "PROPNAME != 0" (no value allowed).
@item -f
Alias for "PROPNAME == 0" (no value allowed).
@end table
@noindent
Values for @var{flag} must be space separated. The supported flags
are:
@table @asis
@item --
@var{VALUE} spans to the end of the expression.
@item -c
The string match in this part is done case-sensitive.
@end table
The filter options concatenate several specifications for a filter of
the same type. For example the four options in this example:
@c man:.RS
@example
--import-option keep-uid="uid =~ Alfa"
--import-option keep-uid="&& uid !~ Test"
--import-option keep-uid="|| uid =~ Alpha"
--import-option keep-uid="uid !~ Test"
@end example
@c man:.RE
@noindent
which is equivalent to
@c man:.RS
@example
--import-option \
keep-uid="uid =~ Alfa" && uid !~ Test" || uid =~ Alpha" && "uid !~ Test"
@end example
@c man:.RE
imports only the user ids of a key containing the strings "Alfa"
or "Alpha" but not the string "test".
@mansect return value
@chapheading RETURN VALUE

View File

@ -140,6 +140,27 @@ get_date_from_files (char **files)
}
/* We need to escape file names for Texinfo. */
static void
print_filename (const char *prefix, const char *name)
{
const char *s;
fputs (prefix, stdout);
for (s=name; *s; s++)
switch (*s)
{
case '@': fputs ("@atchar{}", stdout); break;
case '{': fputs ("@lbracechar{}", stdout); break;
case '}': fputs ("@rbracechar{}", stdout); break;
case ',': fputs ("@comma{}", stdout); break;
case '\\':fputs ("@backslashchar{}", stdout); break;
case '#': fputs ("@hashchar{}", stdout); break;
default: putchar (*s); break;
}
putchar('\n');
}
int
main (int argc, char **argv)
@ -288,17 +309,16 @@ main (int argc, char **argv)
fputs ("\n@c Directories\n\n", stdout);
fputs ("@set BINDIR " GNUPG_BINDIR "\n"
"@set LIBEXECDIR " GNUPG_LIBEXECDIR "\n"
"@set LIBDIR " GNUPG_LIBDIR "\n"
"@set DATADIR " GNUPG_DATADIR "\n"
"@set SYSCONFDIR " GNUPG_SYSCONFDIR "\n"
"@set LOCALSTATEDIR " GNUPG_LOCALSTATEDIR "\n"
"@set LOCALCACHEDIR " GNUPG_LOCALSTATEDIR
/* */ "/cache/" PACKAGE_NAME "\n"
"@set LOCALRUNDIR " GNUPG_LOCALSTATEDIR
/* */ "/run/" PACKAGE_NAME "\n"
, stdout);
print_filename ("@set BINDIR ", GNUPG_BINDIR );
print_filename ("@set LIBEXECDIR ", GNUPG_LIBEXECDIR );
print_filename ("@set LIBDIR ", GNUPG_LIBDIR );
print_filename ("@set DATADIR ", GNUPG_DATADIR );
print_filename ("@set SYSCONFDIR ", GNUPG_SYSCONFDIR );
print_filename ("@set LOCALSTATEDIR ", GNUPG_LOCALSTATEDIR );
print_filename ("@set LOCALCACHEDIR ", (GNUPG_LOCALSTATEDIR
"/cache/" PACKAGE_NAME));
print_filename ("@set LOCALRUNDIR ", (GNUPG_LOCALSTATEDIR
"/run/" PACKAGE_NAME));
p = xstrdup (GNUPG_SYSCONFDIR);
pend = strrchr (p, '/');

View File

@ -280,7 +280,7 @@ Check the options for the component @var{component}.
Update all configuration files with values taken from the global
configuration file (usually @file{/etc/gnupg/gpgconf.conf}).
@item --list-dirs
@item --list-dirs [@var{names}]
Lists the directories used by @command{gpgconf}. One directory is
listed per line, and each line consists of a colon-separated list where
the first field names the directory type (for example @code{sysconfdir})
@ -288,7 +288,9 @@ and the second field contains the percent-escaped directory. Although
they are not directories, the socket file names used by
@command{gpg-agent} and @command{dirmngr} are printed as well. Note
that the socket file names and the @code{homedir} lines are the default
names and they may be overridden by command line switches.
names and they may be overridden by command line switches. If
@var{names} are given only the directories or file names specified by
the list names are printed without any escaping.
@item --list-config [@var{filename}]
List the global configuration file in a colon separated format. If

View File

@ -1,5 +1,5 @@
/* yat2m.c - Yet Another Texi 2 Man converter
* Copyright (C) 2005, 2013, 2015 g10 Code GmbH
* Copyright (C) 2005, 2013, 2015, 2016 g10 Code GmbH
* Copyright (C) 2006, 2008, 2011 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
@ -13,7 +13,7 @@
* 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/>.
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
/*
@ -104,6 +104,29 @@
#include <time.h>
#if __GNUC__
# define MY_GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#else
# define MY_GCC_VERSION 0
#endif
#if MY_GCC_VERSION >= 20500
# define ATTR_PRINTF(f, a) __attribute__ ((format(printf,f,a)))
# define ATTR_NR_PRINTF(f, a) __attribute__ ((noreturn, format(printf,f,a)))
#else
# define ATTR_PRINTF(f, a)
# define ATTR_NR_PRINTF(f, a)
#endif
#if MY_GCC_VERSION >= 30200
# define ATTR_MALLOC __attribute__ ((__malloc__))
#else
# define ATTR_MALLOC
#endif
#define PGM "yat2m"
#define VERSION "1.0"
@ -214,8 +237,16 @@ static const char * const standard_sections[] =
static void proc_texi_buffer (FILE *fp, const char *line, size_t len,
int *table_level, int *eol_action);
static void die (const char *format, ...) ATTR_NR_PRINTF(1,2);
static void err (const char *format, ...) ATTR_PRINTF(1,2);
static void inf (const char *format, ...) ATTR_PRINTF(1,2);
static void *xmalloc (size_t n) ATTR_MALLOC;
static void *xcalloc (size_t n, size_t m) ATTR_MALLOC;
/*-- Functions --*/
/* Print diagnostic message and exit with failure. */
static void
die (const char *format, ...)
@ -558,7 +589,7 @@ get_section_buffer (const char *name)
for (i=0; i < thepage.n_sections; i++)
if (!thepage.sections[i].name)
break;
if (i < thepage.n_sections)
if (thepage.n_sections && i < thepage.n_sections)
sect = thepage.sections + i;
else
{
@ -715,7 +746,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
{ "subsection", 6, "\n.SS " },
{ "chapheading", 0},
{ "item", 2, ".TP\n.B " },
{ "itemx", 2, ".TP\n.B " },
{ "itemx", 2, ".TQ\n.B " },
{ "table", 3 },
{ "itemize", 3 },
{ "bullet", 0, "* " },
@ -762,6 +793,8 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
{
if ((*table_level)-- > 1)
fputs (".RE\n", fp);
else
fputs (".P\n", fp);
}
else if (n >= 7 && !memcmp (s, "example", 7)
&& (!n || s[7] == ' ' || s[7] == '\t' || s[7] == '\n'))
@ -853,7 +886,7 @@ proc_texi_cmd (FILE *fp, const char *command, const char *rest, size_t len,
}
else
inf ("texinfo command '%s' not supported (%.*s)", command,
((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
(int)((s = memchr (rest, '\n', len)), (s? (s-rest) : len)), rest);
}
if (*rest == '{')
@ -965,7 +998,7 @@ proc_texi_buffer (FILE *fp, const char *line, size_t len,
assert (n <= len);
s += n; len -= n;
s--; len++;
in_cmd = 0;
/* in_cmd = 0; -- doc only */
}
}

View File

@ -190,13 +190,18 @@ initialize(void)
is_initialized=1;
}
/****************
* Check whether this is an armored file or not See also
/*
* Check whether this is an armored file. See also
* parse-packet.c for details on this code.
*
* Note that the buffer BUF needs to be at least 2 bytes long. If in
* doubt that the second byte to 0.
*
* Returns: True if it seems to be armored
*/
static int
is_armored( const byte *buf )
is_armored (const byte *buf)
{
int ctb, pkttype;
int indeterminate_length_allowed;
@ -274,15 +279,17 @@ is_armored( const byte *buf )
int
use_armor_filter( IOBUF a )
{
byte buf[1];
byte buf[2];
int n;
/* fixme: there might be a problem with iobuf_peek */
n = iobuf_peek(a, buf, 1 );
n = iobuf_peek (a, buf, 2);
if( n == -1 )
return 0; /* EOF, doesn't matter whether armored or not */
if( !n )
return 1; /* can't check it: try armored */
if (n != 2)
return 0; /* short buffer */
return is_armored(buf);
}
@ -530,7 +537,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
/* (the line is always a C string but maybe longer) */
if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
;
else if( !is_armored( line ) ) {
else if (len >= 2 && !is_armored (line)) {
afx->inp_checked = 1;
afx->inp_bypass = 1;
return 0;
@ -1409,8 +1416,9 @@ unarmor_pump (UnarmorPump x, int c)
switch (x->state) {
case STA_init:
{
byte tmp[1];
byte tmp[2];
tmp[0] = c;
tmp[1] = 0;
if ( is_armored (tmp) )
x->state = c == '-'? STA_first_dash : STA_wait_newline;
else {

View File

@ -635,6 +635,7 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
write_header(out, ctb, calc_plaintext( pt ) );
log_assert (pt->mode == 'b' || pt->mode == 't' || pt->mode == 'u'
|| pt->mode == 'm'
|| pt->mode == 'l' || pt->mode == '1');
iobuf_put(out, pt->mode );
iobuf_put(out, pt->namelen );
@ -972,28 +973,49 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
sig->unhashed = newarea;
}
/****************
/*
* Put all the required stuff from SIG into subpackets of sig.
* PKSK is the signing key.
* Hmmm, should we delete those subpackets which are in a wrong area?
*/
void
build_sig_subpkt_from_sig( PKT_signature *sig )
build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
{
u32 u;
byte buf[8];
byte buf[1+MAX_FINGERPRINT_LEN];
size_t fprlen;
u = sig->keyid[0];
buf[0] = (u >> 24) & 0xff;
buf[1] = (u >> 16) & 0xff;
buf[2] = (u >> 8) & 0xff;
buf[3] = u & 0xff;
u = sig->keyid[1];
buf[4] = (u >> 24) & 0xff;
buf[5] = (u >> 16) & 0xff;
buf[6] = (u >> 8) & 0xff;
buf[7] = u & 0xff;
build_sig_subpkt( sig, SIGSUBPKT_ISSUER, buf, 8 );
/* For v4 keys we need to write the ISSUER subpacket. We do not
* want that for a future v5 format. */
if (pksk->version < 5)
{
u = sig->keyid[0];
buf[0] = (u >> 24) & 0xff;
buf[1] = (u >> 16) & 0xff;
buf[2] = (u >> 8) & 0xff;
buf[3] = u & 0xff;
u = sig->keyid[1];
buf[4] = (u >> 24) & 0xff;
buf[5] = (u >> 16) & 0xff;
buf[6] = (u >> 8) & 0xff;
buf[7] = u & 0xff;
build_sig_subpkt (sig, SIGSUBPKT_ISSUER, buf, 8);
}
/* For a future v5 keys we write the ISSUER_FPR subpacket. We
* also write that for a v4 key is experimental support for
* RFC4880bis is requested. */
if (pksk->version > 4 || opt.flags.rfc4880bis)
{
fingerprint_from_pk (pksk, buf+1, &fprlen);
if (fprlen == 20)
{
buf[0] = pksk->version;
build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21);
}
}
/* Write the timestamp. */
u = sig->timestamp;
buf[0] = (u >> 24) & 0xff;
buf[1] = (u >> 16) & 0xff;

View File

@ -733,28 +733,18 @@ fetch_url (ctrl_t ctrl)
log_error("error retrieving URL from card: %s\n",gpg_strerror(rc));
else
{
struct keyserver_spec *spec=NULL;
rc=agent_scd_getattr("KEY-FPR",&info);
if(rc)
log_error("error retrieving key fingerprint from card: %s\n",
gpg_strerror(rc));
else if (info.pubkey_url && *info.pubkey_url)
{
spec = parse_keyserver_uri (info.pubkey_url, 1);
if(spec && info.fpr1valid)
{
/* This is not perfectly right. Currently, all card
fingerprints are 20 digits, but what about
fingerprints for a future v5 key? We should get the
length from somewhere lower in the code. In any
event, the fpr/keyid is not meaningful for straight
HTTP fetches, but using it allows the card to point
to HKP and LDAP servers as well. */
rc = keyserver_import_fprint (ctrl, info.fpr1, 20, spec);
free_keyserver_spec(spec);
}
}
{
strlist_t sl = NULL;
add_to_strlist (&sl, info.pubkey_url);
rc = keyserver_fetch (ctrl, sl);
free_strlist (sl);
}
else if (info.fpr1valid)
{
rc = keyserver_import_fprint (ctrl, info.fpr1, 20, opt.keyserver);

View File

@ -295,6 +295,10 @@ compress_filter( void *opaque, int control,
static void
release_context (compress_filter_context_t *ctx)
{
xfree(ctx->inbuf);
ctx->inbuf = NULL;
xfree(ctx->outbuf);
ctx->outbuf = NULL;
xfree (ctx);
}

View File

@ -335,7 +335,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
{
/* Note that PT has been initialized above in !no_literal mode. */
pt->timestamp = make_timestamp();
pt->mode = opt.textmode? 't' : 'b';
pt->mode = opt.mimemode? 'm' : opt.textmode? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len;
pt->buf = inp;
@ -674,7 +674,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (!opt.no_literal)
{
pt->timestamp = make_timestamp();
pt->mode = opt.textmode ? 't' : 'b';
pt->mode = opt.mimemode? 'm' : opt.textmode ? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len;
pt->buf = inp;

File diff suppressed because it is too large Load Diff

View File

@ -311,6 +311,7 @@ free_user_id (PKT_user_id *uid)
free_attributes(uid);
xfree (uid->prefs);
xfree (uid->namehash);
xfree (uid->mbox);
xfree (uid);
}

View File

@ -1,7 +1,7 @@
/* getkey.c - Get a key from the database
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2008, 2010 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
* Copyright (C) 2015, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -143,6 +143,11 @@ static void merge_selfsigs (kbnode_t keyblock);
static int lookup (getkey_ctx_t ctx,
kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
int want_secret);
static kbnode_t finish_lookup (kbnode_t keyblock,
unsigned int req_usage, int want_exact,
unsigned int *r_flags);
static void print_status_key_considered (kbnode_t keyblock, unsigned int flags);
#if 0
static void
@ -659,12 +664,9 @@ get_pubkeys (ctrl_t ctrl,
static void
pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
KBNODE found_key)
pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
{
KBNODE a = found_key ? found_key : keyblock;
(void) ctx;
kbnode_t a = found_key ? found_key : keyblock;
log_assert (a->pkt->pkttype == PKT_PUBLIC_KEY
|| a->pkt->pkttype == PKT_PUBLIC_SUBKEY);
@ -749,7 +751,7 @@ get_pubkey (PKT_public_key * pk, u32 * keyid)
rc = lookup (&ctx, &kb, &found_key, 0);
if (!rc)
{
pk_from_block (&ctx, pk, kb, found_key);
pk_from_block (pk, kb, found_key);
}
getkey_end (&ctx);
release_kbnode (kb);
@ -912,7 +914,7 @@ get_seckey (PKT_public_key *pk, u32 *keyid)
err = lookup (&ctx, &keyblock, &found_key, 1);
if (!err)
{
pk_from_block (&ctx, pk, keyblock, found_key);
pk_from_block (pk, keyblock, found_key);
}
getkey_end (&ctx);
release_kbnode (keyblock);
@ -1118,7 +1120,7 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
rc = lookup (ctx, ret_kb, &found_key, want_secret);
if (!rc && pk)
{
pk_from_block (ctx, pk, *ret_kb, found_key);
pk_from_block (pk, *ret_kb, found_key);
}
release_kbnode (help_kb);
@ -1457,6 +1459,53 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
}
/* Get a public key from a file.
*
* PK is the buffer to store the key. The caller needs to make sure
* that PK->REQ_USAGE is valid. PK->REQ_USAGE is passed through to
* the lookup function and is a mask of PUBKEY_USAGE_SIG,
* PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. If this is non-zero, only
* keys with the specified usage will be returned.
*
* FNAME is the file name. That file should contain exactly one
* keyblock.
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
* is not found.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. The caller must release the content of PK by
* calling release_public_key_parts (or, if PK was malloced, using
* free_public_key).
*/
gpg_error_t
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
{
gpg_error_t err;
kbnode_t keyblock;
kbnode_t found_key;
unsigned int infoflags;
err = read_key_from_file (ctrl, fname, &keyblock);
if (!err)
{
/* Warning: node flag bits 0 and 1 should be preserved by
* merge_selfsigs. FIXME: Check whether this still holds. */
merge_selfsigs (keyblock);
found_key = finish_lookup (keyblock, pk->req_usage, 0, &infoflags);
print_status_key_considered (keyblock, infoflags);
if (found_key)
pk_from_block (pk, keyblock, found_key);
else
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
release_kbnode (keyblock);
return err;
}
/* Lookup a key with the specified fingerprint.
*
* If PK is not NULL, the public key of the first result is returned
@ -1513,7 +1562,7 @@ get_pubkey_byfprint (PKT_public_key *pk, kbnode_t *r_keyblock,
memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
rc = lookup (&ctx, &kb, &found_key, 0);
if (!rc && pk)
pk_from_block (&ctx, pk, kb, found_key);
pk_from_block (pk, kb, found_key);
if (!rc && r_keyblock)
{
*r_keyblock = kb;
@ -1903,7 +1952,7 @@ getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
rc = lookup (ctx, ret_keyblock, &found_key, ctx->want_secret);
if (!rc && pk && ret_keyblock)
pk_from_block (ctx, pk, *ret_keyblock, found_key);
pk_from_block (pk, *ret_keyblock, found_key);
return rc;
}
@ -3053,31 +3102,33 @@ merge_selfsigs (KBNODE keyblock)
/* See whether the key satisfies any additional requirements specified
* in CTX. If so, return 1 and set CTX->FOUND_KEY to an appropriate
* key or subkey. Otherwise, return 0 if there was no appropriate
* key.
* in CTX. If so, return the node of an appropriate key or subkey.
* Otherwise, return NULL if there was no appropriate key.
*
* In case the primary key is not required, select a suitable subkey.
* We need the primary key if PUBKEY_USAGE_CERT is set in
* CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
* is set in CTX->REQ_USAGE.
* We need the primary key if PUBKEY_USAGE_CERT is set in REQ_USAGE or
* we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG is set in
* REQ_USAGE.
*
* If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
* are set in CTX->REQ_USAGE, we filter by the key's function.
* Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
* we only return a key if it is (at least) either a signing or a
* are set in REQ_USAGE, we filter by the key's function. Concretely,
* if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then we only
* return a key if it is (at least) either a signing or a
* certification key.
*
* If CTX->REQ_USAGE is set, then we reject any keys that are not good
* If REQ_USAGE is set, then we reject any keys that are not good
* (i.e., valid, not revoked, not expired, etc.). This allows the
* getkey functions to be used for plain key listings.
*
* Sets the matched key's user id field (pk->user_id) to the user id
* that matched the low-level search criteria or NULL. If R_FLAGS is
* not NULL set certain flags for more detailed error reporting. Used
* flags are:
* that matched the low-level search criteria or NULL.
*
* If R_FLAGS is not NULL set certain flags for more detailed error
* reporting. Used flags are:
*
* - LOOKUP_ALL_SUBKEYS_EXPIRED :: All Subkeys are expired or have
* been revoked.
* - LOOKUP_NOT_SELECTED :: No suitable key found
*
* This function needs to handle several different cases:
*
@ -3094,40 +3145,41 @@ merge_selfsigs (KBNODE keyblock)
*
*/
static kbnode_t
finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
unsigned int *r_flags)
{
kbnode_t k;
/* If CTX->EXACT is set, the key or subkey that actually matched the
/* If WANT_EXACT is set, the key or subkey that actually matched the
low-level search criteria. */
kbnode_t foundk = NULL;
/* The user id (if any) that matched the low-level search criteria. */
PKT_user_id *foundu = NULL;
#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
unsigned int req_usage = (ctx->req_usage & USAGE_MASK);
/* Request the primary if we're certifying another key, and also
if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
do not understand signatures made by a signing subkey. PGP 8
does. */
int req_prim = ((ctx->req_usage & PUBKEY_USAGE_CERT)
|| ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG)));
u32 curtime = make_timestamp ();
u32 latest_date;
kbnode_t latest_key;
PKT_public_key *pk;
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
int req_prim;
u32 curtime = make_timestamp ();
if (r_flags)
*r_flags = 0;
#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
req_usage &= USAGE_MASK;
/* Request the primary if we're certifying another key, and also if
* signing data while --pgp6 or --pgp7 is on since pgp 6 and 7 do
* not understand signatures made by a signing subkey. PGP 8 does. */
req_prim = ((req_usage & PUBKEY_USAGE_CERT)
|| ((PGP6 || PGP7) && (req_usage & PUBKEY_USAGE_SIG)));
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
/* For an exact match mark the primary or subkey that matched the
low-level search criteria. */
if (ctx->exact)
if (want_exact)
{
for (k = keyblock; k; k = k->next)
{
@ -3262,7 +3314,7 @@ finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
* primary key, or,
*
* - we're just considering the primary key. */
if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
if ((!latest_key && !want_exact) || foundk == keyblock || req_prim)
{
if (DBG_LOOKUP && !foundk && !req_prim)
log_debug ("\tno suitable subkeys found - trying primary\n");
@ -3300,10 +3352,12 @@ finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
{
if (DBG_LOOKUP)
log_debug ("\tno suitable key found - giving up\n");
if (r_flags)
*r_flags |= LOOKUP_NOT_SELECTED;
return NULL; /* Not found. */
}
found:
found:
if (DBG_LOOKUP)
log_debug ("\tusing key %08lX\n",
(ulong) keyid_from_pk (latest_key->pkt->pkt.public_key, NULL));
@ -3408,12 +3462,10 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
goto skip; /* No secret key available. */
/* Warning: node flag bits 0 and 1 should be preserved by
* merge_selfsigs. For secret keys, premerge transferred the
* keys to the keyblock. */
* merge_selfsigs. */
merge_selfsigs (keyblock);
found_key = finish_lookup (ctx, keyblock, &infoflags);
if (!found_key)
infoflags |= LOOKUP_NOT_SELECTED;
found_key = finish_lookup (keyblock, ctx->req_usage, ctx->exact,
&infoflags);
print_status_key_considered (keyblock, infoflags);
if (found_key)
{

136
g10/gpg.c
View File

@ -81,6 +81,8 @@ enum cmd_and_opt_values
aSym = 'c',
aDecrypt = 'd',
aEncr = 'e',
oRecipientFile = 'f',
oHiddenRecipientFile = 'F',
oInteractive = 'i',
aListKeys = 'k',
oDryRun = 'n',
@ -118,6 +120,7 @@ enum cmd_and_opt_values
aQuickLSignKey,
aQuickAddUid,
aQuickAddKey,
aQuickRevUid,
aListConfig,
aListGcryptConfig,
aGPGConfList,
@ -166,6 +169,7 @@ enum cmd_and_opt_values
aServer,
aTOFUPolicy,
oMimemode,
oTextmode,
oNoTextmode,
oExpert,
@ -216,6 +220,7 @@ enum cmd_and_opt_values
oGnuPG,
oRFC2440,
oRFC4880,
oRFC4880bis,
oOpenPGP,
oPGP6,
oPGP7,
@ -246,6 +251,7 @@ enum cmd_and_opt_values
oNoMDCWarn,
oNoArmor,
oNoDefKeyring,
oNoKeyring,
oNoGreeting,
oNoTTY,
oNoOptions,
@ -298,7 +304,9 @@ enum cmd_and_opt_values
oKeyServer,
oKeyServerOptions,
oImportOptions,
oImportFilter,
oExportOptions,
oExportFilter,
oListOptions,
oVerifyOptions,
oTempDir,
@ -430,6 +438,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aQuickAddUid, "quick-adduid",
N_("quickly add a new user-id")),
ARGPARSE_c (aQuickAddKey, "quick-addkey", "@"),
ARGPARSE_c (aQuickRevUid, "quick-revuid",
N_("quickly revoke a user-id")),
ARGPARSE_c (aFullKeygen, "full-gen-key" ,
N_("full featured key pair generation")),
ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
@ -499,6 +509,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
ARGPARSE_s_s (oHiddenRecipient, "hidden-recipient", "@"),
ARGPARSE_s_s (oRecipientFile, "recipient-file", "@"),
ARGPARSE_s_s (oHiddenRecipientFile, "hidden-recipient-file", "@"),
ARGPARSE_s_s (oRecipient, "remote-user", "@"), /* (old option name) */
ARGPARSE_s_s (oDefRecipient, "default-recipient", "@"),
ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", "@"),
@ -521,7 +533,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_i (oBZ2CompressLevel, "bzip2-compress-level", "@"),
ARGPARSE_s_n (oBZ2DecompressLowmem, "bzip2-decompress-lowmem", "@"),
ARGPARSE_s_n (oTextmodeShort, NULL, "@"),
ARGPARSE_s_n (oMimemode, "mimemode", "@"),
ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")),
ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")),
ARGPARSE_s_n (oNoTextmode, "no-textmode", "@"),
@ -568,7 +581,9 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
ARGPARSE_s_s (oKeyServerOptions, "keyserver-options", "@"),
ARGPARSE_s_s (oImportOptions, "import-options", "@"),
ARGPARSE_s_s (oImportFilter, "import-filter", "@"),
ARGPARSE_s_s (oExportOptions, "export-options", "@"),
ARGPARSE_s_s (oExportFilter, "export-filter", "@"),
ARGPARSE_s_s (oListOptions, "list-options", "@"),
ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"),
@ -599,6 +614,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oGnuPG, "no-pgp8", "@"),
ARGPARSE_s_n (oRFC2440, "rfc2440", "@"),
ARGPARSE_s_n (oRFC4880, "rfc4880", "@"),
ARGPARSE_s_n (oRFC4880bis, "rfc4880bis", "@"),
ARGPARSE_s_n (oOpenPGP, "openpgp", N_("use strict OpenPGP behavior")),
ARGPARSE_s_n (oPGP6, "pgp6", "@"),
ARGPARSE_s_n (oPGP7, "pgp7", "@"),
@ -672,6 +688,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoArmor, "no-armor", "@"),
ARGPARSE_s_n (oNoArmor, "no-armour", "@"),
ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
ARGPARSE_s_n (oNoKeyring, "no-keyring", "@"),
ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
ARGPARSE_s_n (oNoOptions, "no-options", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
@ -2028,6 +2045,7 @@ parse_tofu_db_format (const char *db_format)
}
}
/* This function called to initialized a new control object. It is
assumed that this object has been zeroed out before calling this
function. */
@ -2432,6 +2450,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
case aQuickRevUid:
case aExportOwnerTrust:
case aImportOwnerTrust:
case aRebuildKeydbCaches:
@ -2598,7 +2617,15 @@ main (int argc, char **argv)
}
break;
case oNoArmor: opt.no_armor=1; opt.armor=0; break;
case oNoDefKeyring: default_keyring = 0; break;
case oNoDefKeyring:
if (default_keyring > 0)
default_keyring = 0;
break;
case oNoKeyring:
default_keyring = -1;
break;
case oNoGreeting: nogreeting = 1; break;
case oNoVerbose:
opt.verbose = 0;
@ -2686,6 +2713,9 @@ main (int argc, char **argv)
/* Dummy so that gpg 1.4 conf files can work. Should
eventually be removed. */
break;
case oRFC4880bis:
opt.flags.rfc4880bis = 1;
/* fall thru. */
case oOpenPGP:
case oRFC4880:
/* This is effectively the same as RFC2440, but with
@ -2814,46 +2844,56 @@ main (int argc, char **argv)
else
opt.s2k_count = 0; /* Auto-calibrate when needed. */
break;
case oNoEncryptTo: opt.no_encrypt_to = 1; break;
case oEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
break;
case oHiddenEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT)
| PK_LIST_ENCRYPT_TO|PK_LIST_HIDDEN);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = configfp ? 2 : 1;
break;
case oRecipient: /* store the recipient */
case oRecipient:
case oHiddenRecipient:
case oRecipientFile:
case oHiddenRecipientFile:
/* Store the recipient. Note that we also store the
* option as private data in the flags. This is achieved
* by shifting the option value to the left so to keep
* enough space for the flags. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
if (pargs.r_opt == oHiddenRecipient
|| pargs.r_opt == oHiddenRecipientFile)
sl->flags |= PK_LIST_HIDDEN;
if (pargs.r_opt == oRecipientFile
|| pargs.r_opt == oHiddenRecipientFile)
sl->flags |= PK_LIST_FROM_FILE;
any_explicit_recipient = 1;
break;
case oHiddenRecipient: /* store the recipient with a flag */
case oEncryptTo:
case oHiddenEncryptTo:
/* Store an additional recipient. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
any_explicit_recipient = 1;
if (pargs.r_opt == oHiddenEncryptTo)
sl->flags |= PK_LIST_HIDDEN;
break;
case oNoEncryptTo:
opt.no_encrypt_to = 1;
break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = configfp ? 2 : 1;
break;
case oTrySecretKey:
add_to_strlist2 (&opt.secret_keys_to_try,
pargs.r.ret_str, utf8_strings);
break;
case oMimemode: opt.mimemode = opt.textmode = 1; break;
case oTextmodeShort: opt.textmode = 2; break;
case oTextmode: opt.textmode=1; break;
case oNoTextmode: opt.textmode=0; break;
case oNoTextmode: opt.textmode=opt.mimemode=0; break;
case oExpert: opt.expert = 1; break;
case oNoExpert: opt.expert = 0; break;
case oDefSigExpire:
@ -3022,6 +3062,11 @@ main (int argc, char **argv)
log_error(_("invalid import options\n"));
}
break;
case oImportFilter:
rc = parse_and_set_import_filter (pargs.r.ret_str);
if (rc)
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
break;
case oExportOptions:
if(!parse_export_options(pargs.r.ret_str,&opt.export_options,1))
{
@ -3032,6 +3077,11 @@ main (int argc, char **argv)
log_error(_("invalid export options\n"));
}
break;
case oExportFilter:
rc = parse_and_set_export_filter (pargs.r.ret_str);
if (rc)
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
break;
case oListOptions:
if(!parse_list_options(pargs.r.ret_str))
{
@ -3399,6 +3449,13 @@ main (int argc, char **argv)
if( may_coredump && !opt.quiet )
log_info(_("WARNING: program may create a core file!\n"));
if (opt.flags.rfc4880bis)
log_info ("WARNING: using experimental features from RFC4880bis!\n");
else
{
opt.mimemode = 0; /* This will use text mode instead. */
}
if (eyes_only) {
if (opt.set_filename)
log_info(_("WARNING: %s overrides %s\n"),
@ -3676,14 +3733,15 @@ main (int argc, char **argv)
if( opt.verbose > 1 )
set_packet_list_mode(1);
/* Add the keyrings, but not for some special commands.
We always need to add the keyrings if we are running under
SELinux, this is so that the rings are added to the list of
secured files. */
if( ALWAYS_ADD_KEYRINGS
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest) )
/* Add the keyrings, but not for some special commands. We always
* need to add the keyrings if we are running under SELinux, this
* is so that the rings are added to the list of secured files.
* We do not add any keyring if --no-keyring has been used. */
if (default_keyring >= 0
&& (ALWAYS_ADD_KEYRINGS
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
{
if (!nrings || default_keyring) /* Add default ring. */
if (!nrings || default_keyring > 0) /* Add default ring. */
keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
KEYDB_RESOURCE_FLAG_DEFAULT);
for (sl = nrings; sl; sl = sl->next )
@ -3777,6 +3835,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
case aQuickRevUid:
case aFullKeygen:
case aKeygen:
case aImport:
@ -4196,6 +4255,18 @@ main (int argc, char **argv)
}
break;
case aQuickRevUid:
{
const char *uid, *uidtorev;
if (argc != 2)
wrong_args ("--quick-revuid USER-ID USER-ID-TO-REVOKE");
uid = *argv++; argc--;
uidtorev = *argv++; argc--;
keyedit_quick_revuid (ctrl, uid, uidtorev);
}
break;
case aFastImport:
opt.import_options |= IMPORT_FAST;
case aImport:
@ -4648,7 +4719,6 @@ main (int argc, char **argv)
break;
case aListPackets:
opt.list_packets=2;
default:
if( argc > 1 )
wrong_args(_("[filename]"));
@ -4677,8 +4747,8 @@ main (int argc, char **argv)
}
}
if( cmd == aListPackets ) {
set_packet_list_mode(1);
opt.list_packets=1;
set_packet_list_mode(1);
}
rc = proc_packets (ctrl, NULL, a );
if( rc )

View File

@ -167,6 +167,8 @@ main( int argc, char **argv )
opt.command_fd = -1; /* no command fd */
opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE;
opt.trust_model = TM_ALWAYS;
opt.no_sig_cache = 1;
opt.flags.require_cross_cert = 1;
opt.batch = 1;
opt.weak_digests = NULL;
@ -364,6 +366,17 @@ keyserver_import_keyid (u32 *keyid, void *dummy)
return -1;
}
int
keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
struct keyserver_spec *keyserver)
{
(void)ctrl;
(void)fprint;
(void)fprint_len;
(void)keyserver;
return -1;
}
int
keyserver_import_cert (const char *name)
{
@ -405,6 +418,17 @@ keyserver_import_ldap (const char *name)
return -1;
}
gpg_error_t
read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
{
(void)ctrl;
(void)fname;
(void)r_keyblock;
return -1;
}
/* Stub:
* No encryption here but mainproc links to these functions.
*/

View File

@ -1,6 +1,6 @@
/* import.c - import a key into our key storage.
* Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
* Copyright (C) 2014, 2016 Werner Koch
*
* This file is part of GnuPG.
*
@ -35,9 +35,13 @@
#include "i18n.h"
#include "ttyio.h"
#include "status.h"
#include "recsel.h"
#include "keyserver-internal.h"
#include "call-agent.h"
#include "../common/membuf.h"
#include "../common/init.h"
#include "../common/mbox-util.h"
struct import_stats_s
{
@ -60,6 +64,28 @@ struct import_stats_s
};
/* Node flag to indicate that a user ID or a subkey has a
* valid self-signature. */
#define NODE_GOOD_SELFSIG 1
/* Node flag to indicate that a user ID or subkey has
* an invalid self-signature. */
#define NODE_BAD_SELFSIG 2
/* Node flag to indicate that the node shall be deleted. */
#define NODE_DELETION_MARK 4
/* A node flag used to temporary mark a node. */
#define NODE_FLAG_A 8
/* A global variable to store the selector created from
* --import-filter keep-uid=EXPR.
*
* FIXME: We should put this into the CTRL object but that requires a
* lot more changes right now.
*/
static recsel_expr_t import_keep_uid;
static int import (ctrl_t ctrl,
IOBUF inp, const char* fname, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
@ -68,32 +94,36 @@ static int read_block (IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root,
int *r_v3keys);
static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
static int import_one (ctrl_t ctrl,
const char *fname, kbnode_t keyblock,
kbnode_t keyblock,
struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len,
unsigned int options, int from_sk, int silent,
import_screener_t screener, void *screener_arg);
static int import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
struct import_stats_s *stats, int batch,
unsigned int options, int for_migration,
import_screener_t screener, void *screener_arg);
static int import_revoke_cert( const char *fname, kbnode_t node,
struct import_stats_s *stats);
static int chk_self_sigs (const char *fname, kbnode_t keyblock,
PKT_public_key *pk, u32 *keyid, int *non_self );
static int delete_inv_parts (const char *fname, kbnode_t keyblock,
u32 *keyid, unsigned int options );
static int merge_blocks (const char *fname, kbnode_t keyblock_orig,
static int import_revoke_cert (kbnode_t node, struct import_stats_s *stats);
static int chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self);
static int delete_inv_parts (kbnode_t keyblock,
u32 *keyid, unsigned int options);
static int merge_blocks (kbnode_t keyblock_orig,
kbnode_t keyblock, u32 *keyid,
int *n_uids, int *n_sigs, int *n_subk );
static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
const char *fname, u32 *keyid );
static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
const char *fname, u32 *keyid );
static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
const char *fname, u32 *keyid );
static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
const char *fname, u32 *keyid );
static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs);
static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs);
static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs);
static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
static void
cleanup_import_globals (void)
{
recsel_release (import_keep_uid);
import_keep_uid = NULL;
}
int
parse_import_options(char *str,unsigned int *options,int noisy)
@ -112,6 +142,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
{"fast-import",IMPORT_FAST,NULL,
N_("do not update the trustdb after import")},
{"import-show",IMPORT_SHOW,NULL,
N_("show key during import")},
{"merge-only",IMPORT_MERGE_ONLY,NULL,
N_("only accept updates to existing keys")},
@ -121,6 +154,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
{"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
N_("remove as much as possible from key after import")},
{"import-export", IMPORT_EXPORT, NULL,
N_("run import filters and export key immediately")},
/* Aliases for backward compatibility */
{"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
{"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
@ -137,6 +173,39 @@ parse_import_options(char *str,unsigned int *options,int noisy)
}
/* Parse and set an import filter from string. STRING has the format
* "NAME=EXPR" with NAME being the name of the filter. Spaces before
* and after NAME are not allowed. If this function is all called
* several times all expressions for the same NAME are concatenated.
* Supported filter names are:
*
* - keep-uid :: If the expression evaluates to true for a certain
* user ID packet, that packet and all it dependencies
* will be imported. The expression may use these
* variables:
*
* - uid :: The entire user ID.
* - mbox :: The mail box part of the user ID.
* - primary :: Evaluate to true for the primary user ID.
*/
gpg_error_t
parse_and_set_import_filter (const char *string)
{
gpg_error_t err;
/* Auto register the cleanup function. */
register_mem_cleanup_func (cleanup_import_globals);
if (!strncmp (string, "keep-uid=", 9))
err = recsel_parse_expr (&import_keep_uid, string+9);
else
err = gpg_error (GPG_ERR_INV_NAME);
return err;
}
import_stats_t
import_new_stats_handle (void)
{
@ -151,6 +220,113 @@ import_release_stats_handle (import_stats_t p)
}
/* Read a key from a file. Only the first key in the file is
* considered and stored at R_KEYBLOCK. FNAME is the name of the
* file.
*/
gpg_error_t
read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
{
gpg_error_t err;
iobuf_t inp;
PACKET *pending_pkt = NULL;
kbnode_t keyblock = NULL;
u32 keyid[2];
int v3keys; /* Dummy */
int non_self; /* Dummy */
(void)ctrl;
*r_keyblock = NULL;
inp = iobuf_open (fname);
if (!inp)
err = gpg_error_from_syserror ();
else if (is_secured_file (iobuf_get_fd (inp)))
{
iobuf_close (inp);
inp = NULL;
err = gpg_error (GPG_ERR_EPERM);
}
else
err = 0;
if (err)
{
log_error (_("can't open '%s': %s\n"),
iobuf_is_pipe_filename (fname)? "[stdin]": fname,
gpg_strerror (err));
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
/* Push the armor filter. */
{
armor_filter_context_t *afx;
afx = new_armor_context ();
afx->only_keyblocks = 1;
push_armor_filter (afx, inp);
release_armor_context (afx);
}
/* Read the first non-v3 keyblock. */
while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
{
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
break;
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
release_kbnode (keyblock);
keyblock = NULL;
}
if (err)
{
if (gpg_err_code (err) != GPG_ERR_INV_KEYRING)
log_error (_("error reading '%s': %s\n"),
iobuf_is_pipe_filename (fname)? "[stdin]": fname,
gpg_strerror (err));
goto leave;
}
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
if (!find_next_kbnode (keyblock, PKT_USER_ID))
{
err = gpg_error (GPG_ERR_NO_USER_ID);
goto leave;
}
collapse_uids (&keyblock);
clear_kbnode_flags (keyblock);
if (chk_self_sigs (keyblock, keyid, &non_self))
{
err = gpg_error (GPG_ERR_INV_KEYRING);
goto leave;
}
if (!delete_inv_parts (keyblock, keyid, 0) )
{
err = gpg_error (GPG_ERR_NO_USER_ID);
goto leave;
}
*r_keyblock = keyblock;
keyblock = NULL;
leave:
if (inp)
{
iobuf_close (inp);
/* Must invalidate that ugly cache to actually close the file. */
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
}
release_kbnode (keyblock);
/* FIXME: Do we need to free PENDING_PKT ? */
return err;
}
/*
* Import the public keys from the given filename. Input may be armored.
* This function rejects all keys which are not validly self signed on at
@ -328,16 +504,16 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
{
stats->v3keys += v3keys;
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
rc = import_one (ctrl, fname, keyblock,
rc = import_one (ctrl, keyblock,
stats, fpr, fpr_len, options, 0, 0,
screener, screener_arg);
else if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
rc = import_secret_one (ctrl, fname, keyblock, stats,
rc = import_secret_one (ctrl, keyblock, stats,
opt.batch, options, 0,
screener, screener_arg);
else if (keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
rc = import_revoke_cert( fname, keyblock, stats );
rc = import_revoke_cert (keyblock, stats);
else
{
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
@ -401,7 +577,7 @@ import_old_secring (ctrl_t ctrl, const char *fname)
while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
{
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1,
err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
NULL, NULL);
release_kbnode (keyblock);
if (err)
@ -707,8 +883,8 @@ fix_pks_corruption (kbnode_t keyblock)
}
else
{
sknode->flag |= 1; /* Mark it good so we don't need to
check it again */
/* Mark it good so we don't need to check it again */
sknode->flag |= NODE_GOOD_SELFSIG;
changed = 1;
break;
}
@ -921,6 +1097,74 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
}
/* Helper for apply_keep_uid_filter. */
static const char *
filter_getval (void *cookie, const char *propname)
{
kbnode_t node = cookie;
const char *result;
if (node->pkt->pkttype == PKT_USER_ID)
{
if (!strcmp (propname, "uid"))
result = node->pkt->pkt.user_id->name;
else if (!strcmp (propname, "mbox"))
{
if (!node->pkt->pkt.user_id->mbox)
{
node->pkt->pkt.user_id->mbox
= mailbox_from_userid (node->pkt->pkt.user_id->name);
}
return node->pkt->pkt.user_id->mbox;
}
else if (!strcmp (propname, "primary"))
result = node->pkt->pkt.user_id->is_primary? "1":"0";
else
result = NULL;
}
else
result = NULL;
return result;
}
/*
* Apply the keep-uid filter to the keyblock. The deleted nodes are
* marked and thus the caller should call commit_kbnode afterwards.
* KEYBLOCK must not have any blocks marked as deleted.
*/
static void
apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
{
kbnode_t node;
for (node = keyblock->next; node; node = node->next )
{
if (node->pkt->pkttype == PKT_USER_ID)
{
if (!recsel_select (selector, filter_getval, node))
{
/* log_debug ("keep-uid: deleting '%s'\n", */
/* node->pkt->pkt.user_id->name); */
/* The UID packet and all following packets up to the
* next UID or a subkey. */
delete_kbnode (node);
for (; node->next
&& node->next->pkt->pkttype != PKT_USER_ID
&& node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
&& node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
node = node->next)
delete_kbnode (node->next);
}
/* else */
/* log_debug ("keep-uid: keeping '%s'\n", */
/* node->pkt->pkt.user_id->name); */
}
}
}
/*
* Try to import one keyblock. Return an error only in serious cases,
* but never for an invalid keyblock. It uses log_error to increase
@ -930,13 +1174,13 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
*/
static int
import_one (ctrl_t ctrl,
const char *fname, kbnode_t keyblock, struct import_stats_s *stats,
kbnode_t keyblock, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
int from_sk, int silent,
import_screener_t screener, void *screener_arg)
{
PKT_public_key *pk;
PKT_public_key *pk_orig;
PKT_public_key *pk_orig = NULL;
kbnode_t node, uidnode;
kbnode_t keyblock_orig = NULL;
byte fpr2[MAX_FINGERPRINT_LEN];
@ -949,6 +1193,7 @@ import_one (ctrl_t ctrl,
int non_self = 0;
size_t an;
char pkstrbuf[PUBKEY_STRING_SIZE];
int merge_keys_done = 0;
/* Get the key and print some info about it. */
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@ -1019,26 +1264,28 @@ import_one (ctrl_t ctrl,
log_info (_("key %s: PKS subkey corruption repaired\n"),
keystr_from_pk(pk));
rc = chk_self_sigs( fname, keyblock , pk, keyid, &non_self );
if (rc )
return rc== -1? 0:rc;
if (chk_self_sigs (keyblock, keyid, &non_self))
return 0; /* Invalid keyblock - error already printed. */
/* If we allow such a thing, mark unsigned uids as valid */
if (opt.allow_non_selfsigned_uid)
{
for (node=keyblock; node; node = node->next )
if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
if (node->pkt->pkttype == PKT_USER_ID
&& !(node->flag & NODE_GOOD_SELFSIG)
&& !(node->flag & NODE_BAD_SELFSIG) )
{
char *user=utf8_to_native(node->pkt->pkt.user_id->name,
node->pkt->pkt.user_id->len,0);
node->flag |= 1;
/* Fake a good signature status for the user id. */
node->flag |= NODE_GOOD_SELFSIG;
log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"),
keystr_from_pk(pk),user);
xfree(user);
}
}
if (!delete_inv_parts( fname, keyblock, keyid, options ) )
if (!delete_inv_parts (keyblock, keyid, options ) )
{
if (!silent)
{
@ -1050,6 +1297,46 @@ import_one (ctrl_t ctrl,
return 0;
}
/* Get rid of deleted nodes. */
commit_kbnode (&keyblock);
/* Apply import filter. */
if (import_keep_uid)
{
apply_keep_uid_filter (keyblock, import_keep_uid);
commit_kbnode (&keyblock);
}
/* Show the key in the form it is merged or inserted. We skip this
* if "import-export" is also active without --armor or the output
* file has explicily been given. */
if ((options & IMPORT_SHOW)
&& !((options & IMPORT_EXPORT) && !opt.armor && !opt.outfile))
{
merge_keys_and_selfsig (keyblock);
merge_keys_done = 1;
/* Note that we do not want to show the validity because the key
* has not yet imported. */
list_keyblock_direct (ctrl, keyblock, 0, 0, 1, 1);
es_fflush (es_stdout);
}
/* Write the keyblock to the output and do not actually import. */
if ((options & IMPORT_EXPORT))
{
if (!merge_keys_done)
{
merge_keys_and_selfsig (keyblock);
merge_keys_done = 1;
}
rc = write_keyblock_to_output (keyblock, opt.armor, opt.export_options);
goto leave;
}
if (opt.dry_run)
goto leave;
/* Do we have this key already in one of our pubrings ? */
pk_orig = xmalloc_clear( sizeof *pk_orig );
rc = get_pubkey_byfprint_fast (pk_orig, fpr2, fpr2len);
@ -1170,7 +1457,7 @@ import_one (ctrl_t ctrl,
clear_kbnode_flags( keyblock_orig );
clear_kbnode_flags( keyblock );
n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
rc = merge_blocks( fname, keyblock_orig, keyblock,
rc = merge_blocks (keyblock_orig, keyblock,
keyid, &n_uids, &n_sigs, &n_subk );
if (rc )
{
@ -1258,7 +1545,7 @@ import_one (ctrl_t ctrl,
keydb_release (hd); hd = NULL;
}
leave:
leave:
if (mod_key || new_key || same_key)
{
/* A little explanation for this: we fill in the fingerprint
@ -1429,6 +1716,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
else
{
const char *curvename = openpgp_oid_to_curve (curvestr, 1);
gcry_sexp_release (curve);
err = gcry_sexp_build (&curve, NULL, "(curve %s)",
curvename?curvename:curvestr);
xfree (curvestr);
@ -1654,7 +1942,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
* with the trust calculation.
*/
static int
import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
struct import_stats_s *stats, int batch, unsigned int options,
int for_migration,
import_screener_t screener, void *screener_arg)
@ -1754,7 +2042,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
/* Note that this outputs an IMPORT_OK status message for the
public key block, and below we will output another one for
the secret keys. FIXME? */
import_one (ctrl, fname, pub_keyblock, stats,
import_one (ctrl, pub_keyblock, stats,
NULL, NULL, options, 1, for_migration,
screener, screener_arg);
@ -1822,8 +2110,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
* Import a revocation certificate; this is a single signature packet.
*/
static int
import_revoke_cert (const char *fname, kbnode_t node,
struct import_stats_s *stats)
import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
{
PKT_public_key *pk = NULL;
kbnode_t onode;
@ -1832,8 +2119,6 @@ import_revoke_cert (const char *fname, kbnode_t node,
u32 keyid[2];
int rc = 0;
(void)fname;
log_assert (!node->next );
log_assert (node->pkt->pkttype == PKT_SIGNATURE );
log_assert (node->pkt->pkt.signature->sig_class == 0x20 );
@ -1949,18 +2234,21 @@ import_revoke_cert (const char *fname, kbnode_t node,
}
/*
* Loop over the keyblock and check all self signatures.
* Mark all user-ids with a self-signature by setting flag bit 0.
* Mark all user-ids with an invalid self-signature by setting bit 1.
* This works also for subkeys, here the subkey is marked. Invalid or
* extra subkey sigs (binding or revocation) are marked for deletion.
* non_self is set to true if there are any sigs other than self-sigs
/* Loop over the keyblock and check all self signatures. On return
* the following bis in the node flags are set:
*
* - NODE_GOOD_SELFSIG :: User ID or subkey has a self-signature
* - NODE_BAD_SELFSIG :: Used ID or subkey has an invalid self-signature
* - NODE_DELETION_MARK :: This node shall be deleted
*
* NON_SELF is set to true if there are any sigs other than self-sigs
* in this keyblock.
*
* Returns 0 on success or -1 (but not an error code) if the keyblock
* is invalid.
*/
static int
chk_self_sigs (const char *fname, kbnode_t keyblock,
PKT_public_key *pk, u32 *keyid, int *non_self )
chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self )
{
kbnode_t n, knode = NULL;
PKT_signature *sig;
@ -1968,9 +2256,6 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
u32 bsdate=0, rsdate=0;
kbnode_t bsnode = NULL, rsnode = NULL;
(void)fname;
(void)pk;
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
{
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
@ -2009,7 +2294,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
}
/* If it hasn't been marked valid yet, keep trying. */
if (!(unode->flag&1))
if (!(unode->flag & NODE_GOOD_SELFSIG))
{
rc = check_key_signature (keyblock, n, NULL);
if ( rc )
@ -2029,7 +2314,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
}
}
else
unode->flag |= 1; /* Mark that signature checked. */
unode->flag |= NODE_GOOD_SELFSIG;
}
}
else if (IS_KEY_SIG (sig))
@ -2042,7 +2327,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
_("key %s: unsupported public key algorithm\n"):
_("key %s: invalid direct key signature\n"),
keystr (keyid));
n->flag |= 4;
n->flag |= NODE_DELETION_MARK;
}
}
else if ( IS_SUBKEY_SIG (sig) )
@ -2056,7 +2341,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
if (opt.verbose)
log_info (_("key %s: no subkey for key binding\n"),
keystr (keyid));
n->flag |= 4; /* delete this */
n->flag |= NODE_DELETION_MARK;
}
else
{
@ -2069,19 +2354,19 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
" algorithm\n"):
_("key %s: invalid subkey binding\n"),
keystr (keyid));
n->flag |= 4;
n->flag |= NODE_DELETION_MARK;
}
else
{
/* It's valid, so is it newer? */
if (sig->timestamp >= bsdate)
{
knode->flag |= 1; /* The subkey is valid. */
knode->flag |= NODE_GOOD_SELFSIG; /* Subkey is valid. */
if (bsnode)
{
/* Delete the last binding sig since this
one is newer */
bsnode->flag |= 4;
bsnode->flag |= NODE_DELETION_MARK;
if (opt.verbose)
log_info (_("key %s: removed multiple subkey"
" binding\n"),keystr(keyid));
@ -2091,7 +2376,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
bsdate = sig->timestamp;
}
else
n->flag |= 4; /* older */
n->flag |= NODE_DELETION_MARK; /* older */
}
}
}
@ -2107,7 +2392,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
if (opt.verbose)
log_info (_("key %s: no subkey for key revocation\n"),
keystr(keyid));
n->flag |= 4; /* delete this */
n->flag |= NODE_DELETION_MARK;
}
else
{
@ -2120,7 +2405,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
" key algorithm\n"):
_("key %s: invalid subkey revocation\n"),
keystr(keyid));
n->flag |= 4;
n->flag |= NODE_DELETION_MARK;
}
else
{
@ -2131,7 +2416,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
{
/* Delete the last revocation sig since
this one is newer. */
rsnode->flag |= 4;
rsnode->flag |= NODE_DELETION_MARK;
if (opt.verbose)
log_info (_("key %s: removed multiple subkey"
" revocation\n"),keystr(keyid));
@ -2141,7 +2426,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
rsdate = sig->timestamp;
}
else
n->flag |= 4; /* older */
n->flag |= NODE_DELETION_MARK; /* older */
}
}
}
@ -2151,28 +2436,25 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
}
/****************
* delete all parts which are invalid and those signatures whose
* public key algorithm is not available in this implemenation;
* but consider RSA as valid, because parse/build_packets knows
* about it.
* returns: true if at least one valid user-id is left over.
/* Delete all parts which are invalid and those signatures whose
* public key algorithm is not available in this implemenation; but
* consider RSA as valid, because parse/build_packets knows about it.
*
* Returns: True if at least one valid user-id is left over.
*/
static int
delete_inv_parts( const char *fname, kbnode_t keyblock,
u32 *keyid, unsigned int options)
delete_inv_parts (kbnode_t keyblock, u32 *keyid, unsigned int options)
{
kbnode_t node;
int nvalid=0, uid_seen=0, subkey_seen=0;
(void)fname;
for (node=keyblock->next; node; node = node->next )
{
if (node->pkt->pkttype == PKT_USER_ID)
{
uid_seen = 1;
if ((node->flag & 2) || !(node->flag & 1) )
if ((node->flag & NODE_BAD_SELFSIG)
|| !(node->flag & NODE_GOOD_SELFSIG))
{
if (opt.verbose )
{
@ -2198,7 +2480,8 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
else if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY )
{
if ((node->flag & 2) || !(node->flag & 1) )
if ((node->flag & NODE_BAD_SELFSIG)
|| !(node->flag & NODE_GOOD_SELFSIG))
{
if (opt.verbose )
log_info( _("key %s: skipped subkey\n"),keystr(keyid));
@ -2286,7 +2569,7 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
node->pkt->pkt.signature->sig_class);
delete_kbnode(node);
}
else if ((node->flag & 4) ) /* marked for deletion */
else if ((node->flag & NODE_DELETION_MARK))
delete_kbnode( node );
}
@ -2513,10 +2796,10 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
* the signature's public key yet; verification is done when putting it
* into the trustdb, which is done automagically as soon as this pubkey
* is used.
* Note: We indicate newly inserted packets with flag bit 0
* Note: We indicate newly inserted packets with NODE_FLAG_A.
*/
static int
merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
merge_blocks (kbnode_t keyblock_orig, kbnode_t keyblock,
u32 *keyid, int *n_uids, int *n_sigs, int *n_subk )
{
kbnode_t onode, node;
@ -2549,7 +2832,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
{
kbnode_t n2 = clone_kbnode(node);
insert_kbnode( keyblock_orig, n2, 0 );
n2->flag |= 1;
n2->flag |= NODE_FLAG_A;
++*n_sigs;
if(!opt.quiet)
{
@ -2589,7 +2872,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
{
kbnode_t n2 = clone_kbnode(node);
insert_kbnode( keyblock_orig, n2, 0 );
n2->flag |= 1;
n2->flag |= NODE_FLAG_A;
++*n_sigs;
if(!opt.quiet)
log_info( _("key %s: direct key signature added\n"),
@ -2601,7 +2884,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
/* 3rd: try to merge new certificates in */
for (onode=keyblock_orig->next; onode; onode=onode->next)
{
if (!(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID)
if (!(onode->flag & NODE_FLAG_A) && onode->pkt->pkttype == PKT_USER_ID)
{
/* find the user id in the imported keyblock */
for (node=keyblock->next; node; node=node->next)
@ -2611,7 +2894,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (node ) /* found: merge */
{
rc = merge_sigs( onode, node, n_sigs, fname, keyid );
rc = merge_sigs (onode, node, n_sigs);
if (rc )
return rc;
}
@ -2631,7 +2914,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (!onode ) /* this is a new user id: append */
{
rc = append_uid( keyblock_orig, node, n_sigs, fname, keyid);
rc = append_uid (keyblock_orig, node, n_sigs);
if (rc )
return rc;
++*n_uids;
@ -2653,7 +2936,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (!onode ) /* This is a new subkey: append. */
{
rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
rc = append_key (keyblock_orig, node, n_sigs);
if (rc)
return rc;
++*n_subk;
@ -2669,7 +2952,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (!onode ) /* This is a new subkey: append. */
{
rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
rc = append_key (keyblock_orig, node, n_sigs);
if (rc )
return rc;
++*n_subk;
@ -2680,7 +2963,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
/* 6th: merge subkey certificates */
for (onode=keyblock_orig->next; onode; onode=onode->next)
{
if (!(onode->flag & 1)
if (!(onode->flag & NODE_FLAG_A)
&& (onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| onode->pkt->pkttype == PKT_SECRET_SUBKEY))
{
@ -2695,7 +2978,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
}
if (node) /* Found: merge. */
{
rc = merge_keysigs( onode, node, n_sigs, fname, keyid );
rc = merge_keysigs( onode, node, n_sigs);
if (rc )
return rc;
}
@ -2706,19 +2989,15 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
}
/*
/* Helper function for merge_blocks.
* Append the userid starting with NODE and all signatures to KEYBLOCK.
*/
static int
append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
const char *fname, u32 *keyid )
append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs)
{
kbnode_t n;
kbnode_t n_where = NULL;
(void)fname;
(void)keyid;
log_assert (node->pkt->pkttype == PKT_USER_ID );
/* find the position */
@ -2744,8 +3023,8 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
}
else
add_kbnode( keyblock, n );
n->flag |= 1;
node->flag |= 1;
n->flag |= NODE_FLAG_A;
node->flag |= NODE_FLAG_A;
if (n->pkt->pkttype == PKT_SIGNATURE )
++*n_sigs;
@ -2758,20 +3037,16 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
}
/*
/* Helper function for merge_blocks
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID.
* (how should we handle comment packets here?)
*/
static int
merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
const char *fname, u32 *keyid)
merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs)
{
kbnode_t n, n2;
int found = 0;
(void)fname;
(void)keyid;
log_assert (dst->pkt->pkttype == PKT_USER_ID);
log_assert (src->pkt->pkttype == PKT_USER_ID);
@ -2797,8 +3072,8 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
* one is released first */
n2 = clone_kbnode(n);
insert_kbnode( dst, n2, PKT_SIGNATURE );
n2->flag |= 1;
n->flag |= 1;
n2->flag |= NODE_FLAG_A;
n->flag |= NODE_FLAG_A;
++*n_sigs;
}
}
@ -2807,19 +3082,15 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
}
/*
/* Helper function for merge_blocks
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY.
*/
static int
merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
const char *fname, u32 *keyid)
merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs)
{
kbnode_t n, n2;
int found = 0;
(void)fname;
(void)keyid;
log_assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| dst->pkt->pkttype == PKT_SECRET_SUBKEY);
@ -2858,8 +3129,8 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
* one is released first */
n2 = clone_kbnode(n);
insert_kbnode( dst, n2, PKT_SIGNATURE );
n2->flag |= 1;
n->flag |= 1;
n2->flag |= NODE_FLAG_A;
n->flag |= NODE_FLAG_A;
++*n_sigs;
}
}
@ -2868,19 +3139,15 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
}
/*
/* Helper function for merge_blocks.
* Append the subkey starting with NODE and all signatures to KEYBLOCK.
* Mark all new and copied packets by setting flag bit 0.
*/
static int
append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
const char *fname, u32 *keyid)
append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs)
{
kbnode_t n;
(void)fname;
(void)keyid;
log_assert (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
@ -2890,8 +3157,8 @@ append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
* one is released first */
n = clone_kbnode(node);
add_kbnode( keyblock, n );
n->flag |= 1;
node->flag |= 1;
n->flag |= NODE_FLAG_A;
node->flag |= NODE_FLAG_A;
if (n->pkt->pkttype == PKT_SIGNATURE )
++*n_sigs;

View File

@ -34,18 +34,18 @@
static int cleanup_registered;
static KBNODE unused_nodes;
#if USE_UNUSED_NODES
static void
release_unused_nodes (void)
{
#if USE_UNUSED_NODES
while (unused_nodes)
{
kbnode_t next = unused_nodes->next;
xfree (unused_nodes);
unused_nodes = next;
}
}
#endif /*USE_UNUSED_NODES*/
}
static kbnode_t

View File

@ -937,6 +937,7 @@ keydb_release (KEYDB_HANDLE hd)
}
}
keyblock_cache_clear (hd);
xfree (hd);
}

View File

@ -70,15 +70,16 @@ enum resource_type {
/* Bit flags used with build_pk_list. */
enum
{
PK_LIST_ENCRYPT_TO=1, /* This is an encrypt-to recipient. */
PK_LIST_HIDDEN=2, /* This is a hidden recipient. */
PK_LIST_CONFIG=4 /* Specified via config file. */
PK_LIST_ENCRYPT_TO = 1, /* This is an encrypt-to recipient. */
PK_LIST_HIDDEN = 2, /* This is a hidden recipient. */
PK_LIST_CONFIG = 4, /* Specified via config file. */
PK_LIST_FROM_FILE = 8 /* Take key from file with that name. */
};
/* To store private data in the flags they must be left shifted by
this value. */
/* To store private data in the flags the private data must be left
shifted by this value. */
enum
{
PK_LIST_SHIFT=3
PK_LIST_SHIFT = 4
};
/****************
@ -104,7 +105,7 @@ struct pk_list
{
PK_LIST next;
PKT_public_key *pk;
int flags; /* flag bit 1==throw_keyid */
int flags; /* See PK_LIST_ constants. */
};
/* Structure to hold a list of secret key certificates. */
@ -228,7 +229,8 @@ void release_pk_list (PK_LIST pk_list);
int build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
gpg_error_t find_and_check_key (ctrl_t ctrl,
const char *name, unsigned int use,
int mark_hidden, pk_list_t *pk_list_addr);
int mark_hidden, int from_file,
pk_list_t *pk_list_addr);
int algo_available( preftype_t preftype, int algo,
const union pref_hint *hint );
@ -322,6 +324,10 @@ int get_pubkey_byname (ctrl_t ctrl,
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
int include_unusable, int no_akl );
/* Get a public key directly from file FNAME. */
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
PKT_public_key *pk, const char *fname);
/* Return the public key with the key id KEYID iff the secret key is
* available and store it at PK. */
gpg_error_t get_seckey (PKT_public_key *pk, u32 *keyid);

View File

@ -87,6 +87,9 @@ static int real_uids_left (KBNODE keyblock);
static int count_selected_keys (KBNODE keyblock);
static int menu_revsig (KBNODE keyblock);
static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock);
static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
const struct revocation_reason_info *reason,
int *modified);
static int menu_revkey (KBNODE pub_keyblock);
static int menu_revsubkey (KBNODE pub_keyblock);
#ifndef NO_TRUST_MODELS
@ -2937,6 +2940,110 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
keydb_release (kdbhd);
}
/* Unattended revokation of a keyid. USERNAME specifies the
key. UIDTOREV is the user id revoke from the key. */
void
keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd = NULL;
KEYDB_SEARCH_DESC desc;
kbnode_t keyblock = NULL;
kbnode_t node;
int modified = 0;
size_t revlen;
#ifdef HAVE_W32_SYSTEM
/* See keyedit_menu for why we need this. */
check_trustdb_stale (ctrl);
#endif
/* Search the key; we don't want the whole getkey stuff here. */
kdbhd = keydb_new ();
if (!kdbhd)
{
/* Note that keydb_new has already used log_error. */
goto leave;
}
err = classify_user_id (username, &desc, 1);
if (!err)
err = keydb_search (kdbhd, &desc, 1, NULL);
if (!err)
{
err = keydb_get_keyblock (kdbhd, &keyblock);
if (err)
{
log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
goto leave;
}
/* Now with the keyblock retrieved, search again to detect an
ambiguous specification. We need to save the found state so
that we can do an update later. */
keydb_push_found_state (kdbhd);
err = keydb_search (kdbhd, &desc, 1, NULL);
if (!err)
err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0;
keydb_pop_found_state (kdbhd);
if (!err)
{
/* We require the secret primary key to revoke a UID. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
if (!node)
BUG ();
err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
}
}
if (err)
{
log_error (_("secret key \"%s\" not found: %s\n"),
username, gpg_strerror (err));
goto leave;
}
fix_keyblock (&keyblock);
setup_main_keyids (keyblock);
revlen = strlen (uidtorev);
/* find the right UID */
for (node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID
&& revlen == node->pkt->pkt.user_id->len
&& !memcmp (node->pkt->pkt.user_id->name, uidtorev, revlen))
{
struct revocation_reason_info *reason;
reason = get_default_uid_revocation_reason ();
err = core_revuid (ctrl, keyblock, node, reason, &modified);
release_revocation_reason_info (reason);
if (err)
{
log_error (_("User ID revocation failed: %s\n"),
gpg_strerror (err));
goto leave;
}
err = keydb_update_keyblock (kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
goto leave;
}
if (update_trust)
revalidation_mark ();
goto leave;
}
}
leave:
release_kbnode (keyblock);
keydb_release (kdbhd);
}
/* Find a keyblock by fingerprint because only this uniquely
* identifies a key and may thus be used to select a key for
@ -6106,6 +6213,95 @@ reloop: /* (must use this, because we are modifing the list) */
}
/* return 0 if revocation of NODE (which must be a User ID) was
successful, non-zero if there was an error. *modified will be set
to 1 if a change was made. */
static int
core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
const struct revocation_reason_info *reason, int *modified)
{
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
gpg_error_t rc;
if (node->pkt->pkttype != PKT_USER_ID)
{
rc = gpg_error (GPG_ERR_NO_USER_ID);
write_status_error ("keysig", rc);
log_error (_("tried to revoke a non-user ID: %s\n"), gpg_strerror (rc));
return 1;
}
else
{
PKT_user_id *uid = node->pkt->pkt.user_id;
if (uid->is_revoked)
{
char *user = utf8_to_native (uid->name, uid->len, 0);
log_info (_("user ID \"%s\" is already revoked\n"), user);
xfree (user);
}
else
{
PACKET *pkt;
PKT_signature *sig;
struct sign_attrib attrib;
u32 timestamp = make_timestamp ();
if (uid->created >= timestamp)
{
/* Okay, this is a problem. The user ID selfsig was
created in the future, so we need to warn the user and
set our revocation timestamp one second after that so
everything comes out clean. */
log_info (_("WARNING: a user ID signature is dated %d"
" seconds in the future\n"),
uid->created - timestamp);
timestamp = uid->created + 1;
}
memset (&attrib, 0, sizeof attrib);
/* should not need to cast away const here; but
revocation_reason_build_cb needs to take a non-const
void* in order to meet the function signtuare for the
mksubpkt argument to make_keysig_packet */
attrib.reason = (struct revocation_reason_info *)reason;
rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
timestamp, 0,
sign_mk_attrib, &attrib, NULL);
if (rc)
{
write_status_error ("keysig", rc);
log_error (_("signing failed: %s\n"), gpg_strerror (rc));
return 1;
}
else
{
pkt = xmalloc_clear (sizeof *pkt);
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
insert_kbnode (node, new_kbnode (pkt), 0);
#ifndef NO_TRUST_MODELS
/* If the trustdb has an entry for this key+uid then the
trustdb needs an update. */
if (!update_trust
&& ((get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK)
>= TRUST_UNDEFINED))
update_trust = 1;
#endif /*!NO_TRUST_MODELS*/
node->pkt->pkt.user_id->is_revoked = 1;
if (modified)
*modified = 1;
}
}
return 0;
}
}
/* Revoke a user ID (i.e. revoke a user ID selfsig). Return true if
keyblock changed. */
static int
@ -6132,75 +6328,20 @@ menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock)
goto leave;
}
reloop: /* (better this way because we are modifing the keyring) */
reloop: /* (better this way because we are modifying the keyring) */
for (node = pub_keyblock; node; node = node->next)
if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
{
PKT_user_id *uid = node->pkt->pkt.user_id;
if (uid->is_revoked)
{
char *user = utf8_to_native (uid->name, uid->len, 0);
log_info (_("user ID \"%s\" is already revoked\n"), user);
xfree (user);
}
else
{
PACKET *pkt;
PKT_signature *sig;
struct sign_attrib attrib;
u32 timestamp = make_timestamp ();
if (uid->created >= timestamp)
{
/* Okay, this is a problem. The user ID selfsig was
created in the future, so we need to warn the user and
set our revocation timestamp one second after that so
everything comes out clean. */
log_info (_("WARNING: a user ID signature is dated %d"
" seconds in the future\n"),
uid->created - timestamp);
timestamp = uid->created + 1;
}
memset (&attrib, 0, sizeof attrib);
attrib.reason = reason;
int modified = 0;
rc = core_revuid (ctrl, pub_keyblock, node, reason, &modified);
if (rc)
goto leave;
if (modified)
{
node->flag &= ~NODFLG_SELUID;
rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
timestamp, 0,
sign_mk_attrib, &attrib, NULL);
if (rc)
{
write_status_error ("keysig", rc);
log_error (_("signing failed: %s\n"), gpg_strerror (rc));
goto leave;
}
else
{
pkt = xmalloc_clear (sizeof *pkt);
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
insert_kbnode (node, new_kbnode (pkt), 0);
#ifndef NO_TRUST_MODELS
/* If the trustdb has an entry for this key+uid then the
trustdb needs an update. */
if (!update_trust
&& (get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK) >=
TRUST_UNDEFINED)
update_trust = 1;
#endif /*!NO_TRUST_MODELS*/
changed = 1;
node->pkt->pkt.user_id->is_revoked = 1;
goto reloop;
}
}
changed = 1;
goto reloop;
}
}
if (changed)

View File

@ -202,7 +202,7 @@ write_uid( KBNODE root, const char *s )
size_t n = strlen(s);
pkt->pkttype = PKT_USER_ID;
pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
pkt->pkt.user_id->len = n;
pkt->pkt.user_id->ref = 1;
strcpy(pkt->pkt.user_id->name, s);
@ -413,9 +413,9 @@ keygen_set_std_prefs (const char *string,int personal)
if(strlen(string))
{
char *tok,*prefstring;
char *dup, *tok, *prefstring;
prefstring=xstrdup(string); /* need a writable string! */
dup = prefstring = xstrdup (string); /* need a writable string! */
while((tok=strsep(&prefstring," ,")))
{
@ -449,7 +449,7 @@ keygen_set_std_prefs (const char *string,int personal)
}
}
xfree(prefstring);
xfree (dup);
}
if(!rc)
@ -3481,6 +3481,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
xfree( outctrl.pub.newfname );
}
xfree (line);
release_parameter_list( para );
iobuf_close (fp);
release_armor_context (outctrl.pub.afx);
@ -3610,7 +3611,13 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
}
}
if (*algostr || *usagestr || *expirestr)
if (!strcmp (algostr, "test-default"))
{
para = quickgen_set_para (para, 0, PUBKEY_ALGO_EDDSA, 0, "Ed25519", 0);
para = quickgen_set_para (para, 1, PUBKEY_ALGO_ECDH, 0, "Curve25519", 0);
}
else if (*algostr || *usagestr || *expirestr)
{
/* Extended unattended mode. Creates only the primary key. */
int algo;
@ -4340,11 +4347,15 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
gen_standard_revoke (pk, cache_nonce);
/* Get rid of the first empty packet. */
commit_kbnode (&pub_root);
if (!opt.batch)
{
tty_printf (_("public and secret key created and signed.\n") );
tty_printf ("\n");
list_keyblock_direct (ctrl, pub_root, 0, 1, 1);
merge_keys_and_selfsig (pub_root);
list_keyblock_direct (ctrl, pub_root, 0, 1, 1, 1);
}

View File

@ -59,6 +59,7 @@ struct keylist_context
int inv_sigs; /* Counter used if CHECK_SIGS is set. */
int no_key; /* Counter used if CHECK_SIGS is set. */
int oth_err; /* Counter used if CHECK_SIGS is set. */
int no_validity; /* Do not show validity. */
};
@ -920,7 +921,7 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
/* We do not have an export function which allows to pass a
keyblock, thus we need to search the key again. */
err = export_pubkey_buffer (ctrl, hexfpr,
EXPORT_DANE_FORMAT, NULL,
(EXPORT_MINIMAL | EXPORT_CLEAN), NULL,
&dummy_keyblock, &data, &datalen);
release_kbnode (dummy_keyblock);
if (!err)
@ -1052,7 +1053,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
secret = 2; /* Key not found. */
}
check_trustdb_stale (ctrl);
if (!listctx->no_validity)
check_trustdb_stale (ctrl);
/* Print the "pub" line and in KF_NONE mode the fingerprint. */
print_key_line (es_stdout, pk, secret);
@ -1090,7 +1092,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
dump_attribs (uid, pk);
if ((uid->is_revoked || uid->is_expired)
|| (opt.list_options & LIST_SHOW_UID_VALIDITY))
|| ((opt.list_options & LIST_SHOW_UID_VALIDITY)
&& !listctx->no_validity))
{
const char *validity;
@ -1755,14 +1758,17 @@ list_keyblock (ctrl_t ctrl,
}
/* Public function used by keygen to list a keyblock. */
/* Public function used by keygen to list a keyblock. If NO_VALIDITY
* is set the validity of a key is never shown. */
void
list_keyblock_direct (ctrl_t ctrl,
kbnode_t keyblock, int secret, int has_secret, int fpr)
kbnode_t keyblock, int secret, int has_secret, int fpr,
int no_validity)
{
struct keylist_context listctx;
memset (&listctx, 0, sizeof (listctx));
listctx.no_validity = !!no_validity;
list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx);
keylist_context_release (&listctx);
}

View File

@ -240,13 +240,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
struct keyserver_spec *keyserver;
const char *idx;
int count;
char *uri,*options;
char *uri, *duped_uri, *options;
log_assert (string);
keyserver=xmalloc_clear(sizeof(struct keyserver_spec));
uri=xstrdup(string);
duped_uri = uri = xstrdup (string);
options=strchr(uri,' ');
if(options)
@ -434,11 +434,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
goto fail;
}
xfree (duped_uri);
return keyserver;
fail:
free_keyserver_spec(keyserver);
xfree (duped_uri);
return NULL;
}

View File

@ -289,6 +289,8 @@ void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
const char *newuid);
void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
const char *usagestr, const char *expirestr);
void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
const char *uidtorev);
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
strlist_t uids, strlist_t locusr, int local);
void show_basic_key_info (KBNODE keyblock);
@ -347,6 +349,9 @@ typedef struct import_stats_s *import_stats_t;
typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg);
int parse_import_options(char *str,unsigned int *options,int noisy);
gpg_error_t parse_and_set_import_filter (const char *string);
gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname,
kbnode_t *r_keyblock);
void import_keys (ctrl_t ctrl, char **fnames, int nnames,
import_stats_t stats_hd, unsigned int options);
int import_keys_stream (ctrl_t ctrl, iobuf_t inp, import_stats_t stats_hd,
@ -376,6 +381,7 @@ void export_release_stats (export_stats_t stats);
void export_print_stats (export_stats_t stats);
int parse_export_options(char *str,unsigned int *options,int noisy);
gpg_error_t parse_and_set_export_filter (const char *string);
int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
export_stats_t stats);
@ -390,9 +396,13 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
int cleartext,
char **cache_nonce_addr, const char *hexgrip,
char **cache_nonce_addr,
const char *hexgrip,
PKT_public_key *pk);
gpg_error_t write_keyblock_to_output (kbnode_t keyblock,
int with_armor, unsigned int options);
gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid);
/*-- dearmor.c --*/
@ -407,6 +417,7 @@ int gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr);
int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
struct revocation_reason_info *
ask_revocation_reason( int key_rev, int cert_rev, int hint );
struct revocation_reason_info * get_default_uid_revocation_reason(void);
void release_revocation_reason_info( struct revocation_reason_info *reason );
/*-- keylist.c --*/
@ -415,7 +426,7 @@ void secret_key_list (ctrl_t ctrl, strlist_t list );
void print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock);
void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
int has_secret, int fpr);
int has_secret, int fpr, int no_validity);
void print_fingerprint (estream_t fp, PKT_public_key *pk, int mode);
void print_revokers (estream_t fp, PKT_public_key *pk);
void show_policy_url(PKT_signature *sig,int indent,int mode);

View File

@ -124,8 +124,6 @@ reset_literals_seen(void)
static void
release_list( CTX c )
{
if (!c->list)
return;
proc_tree (c, c->list);
release_kbnode (c->list);
while (c->pkenc_list)
@ -1328,7 +1326,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
/* Stop processing when an invalid packet has been encountered
* but don't do so when we are doing a --list-packets. */
if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
&& opt.list_packets != 2 )
&& opt.list_packets == 0)
break;
continue;
}
@ -1805,19 +1803,26 @@ check_sig_and_print (CTX c, kbnode_t node)
* favor this over the WKD method (to be tried next), because an
* arbitrary keyserver is less subject to web bug like
* monitoring. */
/* if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY */
/* && signature_hash_full_fingerprint (sig) */
/* && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) */
/* && keyserver_any_configured (c->ctrl)) */
/* { */
/* int res; */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& opt.flags.rfc4880bis
&& (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
&& keyserver_any_configured (c->ctrl))
{
int res;
const byte *p;
size_t n;
/* glo_ctrl.in_auto_key_retrieve++; */
/* res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); */
/* glo_ctrl.in_auto_key_retrieve--; */
/* if (!res) */
/* rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); */
/* } */
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
if (p && n == 21 && p[0] == 4)
{
/* v4 packet with a SHA-1 fingerprint. */
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_fprint (c->ctrl, p+1, n-1, opt.keyserver);
glo_ctrl.in_auto_key_retrieve--;
if (!res)
rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
}
}
/* If the above methods didn't work, our next try is to retrieve the
* key from the WKD. */

View File

@ -57,6 +57,7 @@ struct
int dry_run;
int autostart;
int list_only;
int mimemode;
int textmode;
int expert;
const char *def_sig_expire;
@ -80,7 +81,7 @@ struct
int print_pka_records;
int print_dane_records;
int no_armor;
int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
int list_packets; /* Option --list-packets active. */
int def_cipher_algo;
int force_mdc;
int disable_mdc;
@ -235,6 +236,8 @@ struct
unsigned int allow_weak_digest_algos:1;
unsigned int large_rsa:1;
unsigned int disable_signer_uid:1;
/* Flag to enbale experimental features from RFC4880bis. */
unsigned int rfc4880bis:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
@ -332,11 +335,13 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define IMPORT_LOCAL_SIGS (1<<0)
#define IMPORT_REPAIR_PKS_SUBKEY_BUG (1<<1)
#define IMPORT_FAST (1<<2)
#define IMPORT_SHOW (1<<3)
#define IMPORT_MERGE_ONLY (1<<4)
#define IMPORT_MINIMAL (1<<5)
#define IMPORT_CLEAN (1<<6)
#define IMPORT_NO_SECKEY (1<<7)
#define IMPORT_KEEP_OWNERTTRUST (1<<8)
#define IMPORT_EXPORT (1<<9)
#define EXPORT_LOCAL_SIGS (1<<0)
#define EXPORT_ATTRIBUTES (1<<1)
@ -344,7 +349,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define EXPORT_RESET_SUBKEY_PASSWD (1<<3)
#define EXPORT_MINIMAL (1<<4)
#define EXPORT_CLEAN (1<<5)
#define EXPORT_DANE_FORMAT (1<<6)
#define EXPORT_PKA_FORMAT (1<<6)
#define EXPORT_DANE_FORMAT (1<<7)
#define LIST_SHOW_PHOTOS (1<<0)
#define LIST_SHOW_POLICY_URLS (1<<1)

View File

@ -291,9 +291,10 @@ typedef struct
unsigned int ks_modify:1;
unsigned int compacted:1;
} flags;
char *mbox; /* NULL or the result of mailbox_from_userid. */
/* The text contained in the user id packet, which is normally the
name and email address of the key holder (See RFC 4880 5.11).
(Serialized.) */
(Serialized.). For convenience an extra Nul is always appended. */
char name[1];
} PKT_user_id;
@ -764,7 +765,7 @@ gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig( PKT_signature *sig );
void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk);
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
void build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,u32 buflen,

View File

@ -211,7 +211,7 @@ set_packet_list_mode (int mode)
enable the list mode only with a special option. */
if (!listfp)
{
if (opt.list_packets == 2)
if (opt.list_packets)
{
listfp = es_stdout;
if (opt.verbose)
@ -1335,6 +1335,19 @@ dump_sig_subpkt (int hashed, int type, int critical,
(ulong) buf32_to_u32 (buffer),
(ulong) buf32_to_u32 (buffer + 4));
break;
case SIGSUBPKT_ISSUER_FPR:
if (length >= 21)
{
char *tmp;
es_fprintf (listfp, "issuer fpr v%d ", buffer[0]);
tmp = bin2hex (buffer+1, length-1, NULL);
if (tmp)
{
es_fputs (tmp, listfp);
xfree (tmp);
}
}
break;
case SIGSUBPKT_NOTATION:
{
es_fputs ("notation: ", listfp);
@ -1485,6 +1498,10 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
if (n < 8)
break;
return 0;
case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
if (n < 21)
break;
return 0;
case SIGSUBPKT_NOTATION:
/* minimum length needed, and the subpacket must be well-formed
where the name length and value length all fit inside the
@ -1543,6 +1560,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
case SIGSUBPKT_REVOCABLE:
case SIGSUBPKT_REV_KEY:
case SIGSUBPKT_ISSUER: /* issuer key ID */
case SIGSUBPKT_ISSUER_FPR: /* issuer fingerprint */
case SIGSUBPKT_PREF_SYM:
case SIGSUBPKT_PREF_HASH:
case SIGSUBPKT_PREF_COMPR:

View File

@ -775,14 +775,16 @@ expand_id(const char *id,strlist_t *into,unsigned int flags)
}
/* For simplicity, and to avoid potential loops, we only expand once -
you can't make an alias that points to an alias. */
* you can't make an alias that points to an alias. */
static strlist_t
expand_group(strlist_t input)
expand_group (strlist_t input)
{
strlist_t sl,output=NULL,rover;
strlist_t output = NULL;
strlist_t sl, rover;
for(rover=input;rover;rover=rover->next)
if(expand_id(rover->d,&output,rover->flags)==0)
for (rover = input; rover; rover = rover->next)
if (!(rover->flags & PK_LIST_FROM_FILE)
&& !expand_id(rover->d,&output,rover->flags))
{
/* Didn't find any groups, so use the existing string */
sl=add_to_strlist(&output,rover->d);
@ -794,17 +796,18 @@ expand_group(strlist_t input)
/* Helper for build_pk_list to find and check one key. This helper is
also used directly in server mode by the RECIPIENTS command. On
success the new key is added to PK_LIST_ADDR. NAME is the user id
of the key. USE the requested usage and a set MARK_HIDDEN will mark
the key in the updated list as a hidden recipient. */
* also used directly in server mode by the RECIPIENTS command. On
* success the new key is added to PK_LIST_ADDR. NAME is the user id
* of the key. USE the requested usage and a set MARK_HIDDEN will
* mark the key in the updated list as a hidden recipient. If
* FROM_FILE is true, NAME is is not a user ID but the name of a file
* holding a key. */
gpg_error_t
find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
int mark_hidden, pk_list_t *pk_list_addr)
int mark_hidden, int from_file, pk_list_t *pk_list_addr)
{
int rc;
PKT_public_key *pk;
int trustlevel;
if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID);
@ -814,7 +817,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
return gpg_error_from_syserror ();
pk->req_usage = use;
rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name);
else
rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
if (rc)
{
int code;
@ -844,24 +850,28 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
}
/* Key found and usable. Check validity. */
trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
if (!from_file)
{
/* Key has been disabled. */
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
int trustlevel;
if ( !do_we_trust_pre (pk, trustlevel) )
{
/* We don't trust this key. */
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
{
/* Key has been disabled. */
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
if ( !do_we_trust_pre (pk, trustlevel) )
{
/* We don't trust this key. */
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
}
/* Note: do_we_trust may have changed the trustlevel. */
/* Skip the actual key if the key is already present in the
list. */
@ -894,22 +904,24 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
/* This is the central function to collect the keys for recipients.
It is thus used to prepare a public key encryption. encrypt-to
keys, default keys and the keys for the actual recipients are all
collected here. When not in batch mode and no recipient has been
passed on the commandline, the function will also ask for
recipients.
RCPTS is a string list with the recipients; NULL is an allowed
value but not very useful. Group expansion is done on these names;
they may be in any of the user Id formats we can handle. The flags
bits for each string in the string list are used for:
Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
Bit 1 (PK_LIST_HIDDEN) : This is a hidden recipient.
On success a list of keys is stored at the address RET_PK_LIST; the
caller must free this list. On error the value at this address is
not changed.
* It is thus used to prepare a public key encryption. encrypt-to
* keys, default keys and the keys for the actual recipients are all
* collected here. When not in batch mode and no recipient has been
* passed on the commandline, the function will also ask for
* recipients.
*
* RCPTS is a string list with the recipients; NULL is an allowed
* value but not very useful. Group expansion is done on these names;
* they may be in any of the user Id formats we can handle. The flags
* bits for each string in the string list are used for:
*
* - PK_LIST_ENCRYPT_TO :: This is an encrypt-to recipient.
* - PK_LIST_HIDDEN :: This is a hidden recipient.
* - PK_LIST_FROM_FILE :: The argument is a file with a key.
*
* On success a list of keys is stored at the address RET_PK_LIST; the
* caller must free this list. On error the value at this address is
* not changed.
*/
int
build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
@ -1269,6 +1281,7 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
!!(remusr->flags&PK_LIST_HIDDEN),
!!(remusr->flags&PK_LIST_FROM_FILE),
&pk_list);
if (rc)
goto fail;

View File

@ -217,11 +217,16 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
static off_t count = 0;
int err = 0;
int c;
int convert = (pt->mode == 't' || pt->mode == 'u');
int convert;
#ifdef __riscos__
int filetype = 0xfff;
#endif
if (pt->mode == 't' || pt->mode == 'u' || pt->mode == 'm')
convert = pt->mode;
else
convert = 0;
/* Let people know what the plaintext info is. This allows the
receiving program to try and do something different based on the
format code (say, recode UTF-8 to local). */
@ -279,8 +284,10 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
if (mfx->md)
gcry_md_putc (mfx->md, c);
#ifndef HAVE_DOSISH_SYSTEM
if (c == '\r') /* convert to native line ending */
continue; /* fixme: this hack might be too simple */
/* Convert to native line ending. */
/* fixme: this hack might be too simple */
if (c == '\r' && convert != 'm')
continue;
#endif
if (fp)
{
@ -354,7 +361,7 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
if (mfx->md)
gcry_md_putc (mfx->md, c);
#ifndef HAVE_DOSISH_SYSTEM
if (convert && c == '\r')
if (c == '\r' && convert != 'm')
continue; /* fixme: this hack might be too simple */
#endif
if (fp)

View File

@ -862,6 +862,16 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
return reason;
}
struct revocation_reason_info *
get_default_uid_revocation_reason(void)
{
struct revocation_reason_info *reason;
reason = xmalloc( sizeof *reason );
reason->code = 0x20; /* uid is no longer valid */
reason->desc = strdup(""); /* no text */
return reason;
}
void
release_revocation_reason_info( struct revocation_reason_info *reason )
{

View File

@ -177,6 +177,7 @@ output_notify (assuan_context_t ctx, char *line)
/* RECIPIENT [--hidden] <userID>
RECIPIENT [--hidden] --file <filename>
Set the recipient for the encryption. <userID> should be the
internal representation of the key; the server may accept any other
@ -192,9 +193,10 @@ cmd_recipient (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
int hidden;
int hidden, file;
hidden = has_option (line,"--hidden");
file = has_option (line,"--file");
line = skip_options (line);
/* FIXME: Expand groups
@ -204,7 +206,7 @@ cmd_recipient (assuan_context_t ctx, char *line)
remusr = rcpts;
*/
err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden,
err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden, file,
&ctrl->server_local->recplist);
if (err)

View File

@ -156,6 +156,7 @@ mk_notation_policy_etc (PKT_signature *sig,
if (DBG_LOOKUP)
log_debug ("setting Signer's UID to '%s'\n", mbox);
build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox));
xfree (mbox);
}
}
}
@ -604,7 +605,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
* data, it is not possible to know the used length
* without a double read of the file - to avoid that
* we simple use partial length packets. */
if ( ptmode == 't' )
if ( ptmode == 't' || ptmode == 'u' || ptmode == 'm')
filesize = 0;
}
else
@ -627,6 +628,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
log_error ("build_packet(PLAINTEXT) failed: %s\n",
gpg_strerror (rc) );
pt->buf = NULL;
free_packet (&pkt);
}
else {
byte copy_buffer[4096];
@ -690,7 +692,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
if (sig->version >= 4)
{
build_sig_subpkt_from_sig (sig);
build_sig_subpkt_from_sig (sig, pk);
mk_notation_policy_etc (sig, NULL, pk);
}
@ -1031,7 +1033,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
}
else {
rc = write_plaintext_packet (out, inp, fname,
opt.textmode && !outfile ? 't':'b');
opt.textmode && !outfile ?
(opt.mimemode? 'm':'t'):'b');
}
/* catch errors from above */
@ -1335,7 +1338,8 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
/* Pipe data through all filters; i.e. write the signed stuff */
/*(current filters: zip - encrypt - armor)*/
rc = write_plaintext_packet (out, inp, fname, opt.textmode ? 't':'b');
rc = write_plaintext_packet (out, inp, fname,
opt.textmode ? (opt.mimemode?'m':'t'):'b');
if (rc)
goto leave;
@ -1456,7 +1460,7 @@ make_keysig_packet (PKT_signature **ret_sig, PKT_public_key *pk,
sig->expiredate=sig->timestamp+duration;
sig->sig_class = sigclass;
build_sig_subpkt_from_sig( sig );
build_sig_subpkt_from_sig (sig, pksk);
mk_notation_policy_etc (sig, pk, pksk);
/* Crucial that the call to mksubpkt comes LAST before the calls
@ -1559,7 +1563,7 @@ update_keysig_packet( PKT_signature **ret_sig,
automagically lower any sig expiration dates to correctly
correspond to the differences in the timestamps (i.e. the
duration will shrink). */
build_sig_subpkt_from_sig( sig );
build_sig_subpkt_from_sig (sig, pksk);
if (mksubpkt)
rc = (*mksubpkt)(sig, opaque);

View File

@ -59,4 +59,6 @@ do_test (int argc, char *argv[])
rc = keydb_get_keyblock (hd1, &kb1);
TEST_P ("", ! rc);
keydb_release (hd1);
}

View File

@ -27,7 +27,7 @@ do_test (int argc, char *argv[])
int rc;
KEYDB_HANDLE hd1, hd2;
KEYDB_SEARCH_DESC desc1, desc2;
KBNODE kb1, kb2;
KBNODE kb1, kb2, p;
char *uid1;
char *uid2;
char *fname;
@ -75,17 +75,19 @@ do_test (int argc, char *argv[])
if (rc)
ABORT ("Failed to get keyblock for DBFC6AD9");
while (kb1 && kb1->pkt->pkttype != PKT_USER_ID)
kb1 = kb1->next;
if (! kb1)
p = kb1;
while (p && p->pkt->pkttype != PKT_USER_ID)
p = p->next;
if (! p)
ABORT ("DBFC6AD9 has no user id packet");
uid1 = kb1->pkt->pkt.user_id->name;
uid1 = p->pkt->pkt.user_id->name;
while (kb2 && kb2->pkt->pkttype != PKT_USER_ID)
kb2 = kb2->next;
if (! kb2)
p = kb2;
while (p && p->pkt->pkttype != PKT_USER_ID)
p = p->next;
if (! p)
ABORT ("1E42B367 has no user id packet");
uid2 = kb2->pkt->pkt.user_id->name;
uid2 = p->pkt->pkt.user_id->name;
if (verbose)
{
@ -94,4 +96,9 @@ do_test (int argc, char *argv[])
}
TEST_P ("cache consistency", strcmp (uid1, uid2) != 0);
release_kbnode (kb1);
release_kbnode (kb2);
keydb_release (hd1);
keydb_release (hd2);
}

View File

@ -606,5 +606,6 @@ main (int argc, char *argv[])
log_fatal ("Message is too short, nothing to test.\n");
}
xfree (filename);
return failed;
}

View File

@ -176,6 +176,17 @@ keyserver_import_keyid (u32 *keyid, void *dummy)
return -1;
}
int
keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
struct keyserver_spec *keyserver)
{
(void)ctrl;
(void)fprint;
(void)fprint_len;
(void)keyserver;
return -1;
}
int
keyserver_import_cert (const char *name)
{
@ -217,6 +228,15 @@ keyserver_import_ldap (const char *name)
return -1;
}
gpg_error_t
read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
{
(void)ctrl;
(void)fname;
(void)r_keyblock;
return -1;
}
/* Stub:
* No encryption here but mainproc links to these functions.
*/

View File

@ -240,5 +240,6 @@ copy_clearsig_text( IOBUF out, IOBUF inp, gcry_md_hd_t md,
if( truncated )
log_info(_("input line longer than %d characters\n"), MAX_LINELEN );
xfree (buffer);
return 0; /* okay */
}

View File

@ -1022,17 +1022,18 @@ tdb_get_validity_core (ctrl_t ctrl,
#ifdef USE_TOFU
if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
{
kbnode_t user_id_node = NULL; /* Silence -Wmaybe-uninitialized. */
kbnode_t user_id_node = NULL;
kbnode_t n = NULL; /* Silence -Wmaybe-uninitialized. */
int user_ids = 0;
int user_ids_expired = 0;
/* If the caller didn't supply a user id then iterate over all
uids. */
if (! uid)
user_id_node = get_pubkeyblock (main_pk->keyid);
user_id_node = n = get_pubkeyblock (main_pk->keyid);
while (uid
|| (user_id_node = find_next_kbnode (user_id_node, PKT_USER_ID)))
|| (n = find_next_kbnode (n, PKT_USER_ID)))
{
unsigned int tl;
PKT_user_id *user_id;
@ -1040,7 +1041,7 @@ tdb_get_validity_core (ctrl_t ctrl,
if (uid)
user_id = uid;
else
user_id = user_id_node->pkt->pkt.user_id;
user_id = n->pkt->pkt.user_id;
/* If the user id is revoked or expired, then skip it. */
if (user_id->is_revoked || user_id->is_expired)
@ -1094,6 +1095,7 @@ tdb_get_validity_core (ctrl_t ctrl,
now. */
break;
}
release_kbnode (user_id_node);
}
#endif /*USE_TOFU*/

View File

@ -114,7 +114,7 @@ create_tupledesc (tupledesc_t *r_desc, void *data, size_t datalen)
(*r_desc)->data = data;
(*r_desc)->datalen = datalen;
(*r_desc)->pos = 0;
(*r_desc)->refcount++;
(*r_desc)->refcount = 1;
return 0;
}

View File

@ -661,18 +661,24 @@ create_blob_finish (KEYBOXBLOB blob)
/* do the fixups */
if (blob->fixup_out_of_core)
return gpg_error (GPG_ERR_ENOMEM);
{
xfree (p);
return gpg_error (GPG_ERR_ENOMEM);
}
{
struct fixup_list *fl;
for (fl = blob->fixups; fl; fl = fl->next)
struct fixup_list *fl, *next;
for (fl = blob->fixups; fl; fl = next)
{
assert (fl->off+4 <= n);
p[fl->off+0] = fl->val >> 24;
p[fl->off+1] = fl->val >> 16;
p[fl->off+2] = fl->val >> 8;
p[fl->off+3] = fl->val;
next = fl->next;
xfree (fl);
}
blob->fixups = NULL;
}
/* Compute and store the SHA-1 checksum. */
@ -680,8 +686,12 @@ create_blob_finish (KEYBOXBLOB blob)
pp = xtrymalloc (n);
if ( !pp )
return gpg_error_from_syserror ();
{
xfree (p);
return gpg_error_from_syserror ();
}
memcpy (pp , p, n);
xfree (p);
blob->blob = pp;
blob->bloblen = n;
@ -1000,7 +1010,11 @@ _keybox_release_blob (KEYBOXBLOB blob)
int i;
if (!blob)
return;
/* hmmm: release membuf here?*/
if (blob->buf)
{
size_t len;
xfree (get_membuf (blob->buf, &len));
}
xfree (blob->keys );
xfree (blob->serialbuf);
for (i=0; i < blob->nuids; i++)

View File

@ -1,6 +1,6 @@
EXTRA_DIST = intl.m4 intldir.m4 glibc2.m4 lock.m4 visibility.m4 intmax.m4 longdouble.m4 printf-posix.m4 signed.m4 size_max.m4 wchar_t.m4 wint_t.m4 xsize.m4 codeset.m4 gettext.m4 glibc21.m4 iconv.m4 intdiv0.m4 inttypes.m4 inttypes_h.m4 inttypes-pri.m4 isc-posix.m4 lcmessage.m4 lib-ld.m4 lib-link.m4 lib-prefix.m4 progtest.m4 stdint_h.m4 uintmax_t.m4
EXTRA_DIST += ldap.m4 libcurl.m4 libusb.m4 tar-ustar.m4 readline.m4
EXTRA_DIST += ldap.m4 libcurl.m4 libusb.m4 tar-ustar.m4 readline.m4 pkg.m4
EXTRA_DIST += gnupg-pth.m4

214
m4/pkg.m4 Normal file
View File

@ -0,0 +1,214 @@
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
# serial 1 (pkg-config-0.24)
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
fi
if test -n "$PKG_CONFIG"; then
_pkg_min_version=m4_default([$1], [0.9.0])
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
PKG_CONFIG=""
fi
fi[]dnl
])# PKG_PROG_PKG_CONFIG
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
# only at the first occurence in configure.ac, so if the first place
# it's called might be skipped (such as if it is within an "if", you
# have to call PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
m4_default([$2], [:])
m4_ifvaln([$3], [else
$3])dnl
fi])
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
elif test -n "$PKG_CONFIG"; then
PKG_CHECK_EXISTS([$3],
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes ],
[pkg_failed=yes])
else
pkg_failed=untried
fi[]dnl
])# _PKG_CONFIG
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi[]dnl
])# _PKG_SHORT_ERRORS_SUPPORTED
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
AC_MSG_RESULT([no])
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
m4_default([$4], [AC_MSG_ERROR(
[Package requirements ($2) were not met:
$$1_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
_PKG_TEXT])[]dnl
])
elif test $pkg_failed = untried; then
AC_MSG_RESULT([no])
m4_default([$4], [AC_MSG_FAILURE(
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
_PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
$3
fi[]dnl
])# PKG_CHECK_MODULES
# PKG_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable pkgconfigdir as the location where a module
# should install pkg-config .pc files. By default the directory is
# $libdir/pkgconfig, but the default can be changed by passing
# DIRECTORY. The user can override through the --with-pkgconfigdir
# parameter.
AC_DEFUN([PKG_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([pkgconfigdir],
[AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
[with_pkgconfigdir=]pkg_default)
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_INSTALLDIR
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
# -------------------------
# Substitutes the variable noarch_pkgconfigdir as the location where a
# module should install arch-independent pkg-config .pc files. By
# default the directory is $datadir/pkgconfig, but the default can be
# changed by passing DIRECTORY. The user can override through the
# --with-noarch-pkgconfigdir parameter.
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
m4_pushdef([pkg_description],
[pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
AC_ARG_WITH([noarch-pkgconfigdir],
[AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
[with_noarch_pkgconfigdir=]pkg_default)
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
m4_popdef([pkg_default])
m4_popdef([pkg_description])
]) dnl PKG_NOARCH_INSTALLDIR
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
# -------------------------------------------
# Retrieves the value of the pkg-config variable for the given module.
AC_DEFUN([PKG_CHECK_VAR],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
_PKG_CONFIG([$1], [variable="][$3]["], [$2])
AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])# PKG_CHECK_VAR

View File

@ -975,7 +975,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
handle->max_ifsd = 48;
}
if (handle->id_vendor == VENDOR_GEMPC && handle->id_product == GEMPC_CT30)
if (handle->id_vendor == VENDOR_GEMPC)
{
DEBUGOUT ("enabling product quirk: disable non-null NAD\n");
handle->nonnull_nad = 0;

View File

@ -156,6 +156,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen",
N_("use variable length input for pinpad")),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_end ()
};

View File

@ -25,7 +25,7 @@ else
openpgp =
endif
SUBDIRS = ${openpgp} . pkits
SUBDIRS = gpgscm ${openpgp} . migrations pkits
GPGSM = ../sm/gpgsm
@ -48,12 +48,12 @@ EXTRA_DIST = runtest inittests $(testscripts) ChangeLog-2011 \
samplekeys/cert_g10code_test1.pem \
samplekeys/cert_g10code_theo1.pem
# We used to run $(testscripts) here but these asschk scripts ares not
# completely reliable in all enviromnets and thus we better disable
# them. The tests are anyway way to minimal. We will eventually
# We used to run $(testscripts) here but these asschk scripts are not
# completely reliable in all enviroments and thus we better disable
# them. The tests are anyway way too minimal. We will eventually
# write new tests based on gpg-connect-agent which has a full fledged
# script language and thus makes it far easier to write tests than to
# use the low--level asschk stuff.
# use that low-level asschk stuff.
TESTS =
CLEANFILES = inittests.stamp x y y z out err \

View File

@ -0,0 +1,31 @@
LICENSE TERMS
Copyright (c) 2000, Dimitrios Souflis
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of Dimitrios Souflis nor the names of the
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

59
tests/gpgscm/Makefile.am Normal file
View File

@ -0,0 +1,59 @@
# TinyScheme-based test driver.
#
# Copyright (C) 2016 g10 Code GmbH
#
# 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/>.
EXTRA_DIST = \
LICENSE.TinySCHEME \
Manual.txt \
ffi.scm \
init.scm \
lib.scm \
repl.scm \
t-child.scm \
tests.scm
AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
AM_CFLAGS =
CLEANFILES =
bin_PROGRAMS = gpgscm
noinst_PROGRAMS = t-child
common_libs = ../$(libcommon)
commonpth_libs = ../$(libcommonpth)
gpgscm_CFLAGS = -imacros scheme-config.h \
$(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(GPG_ERROR_CFLAGS)
gpgscm_SOURCES = main.c private.h ffi.c ffi.h ffi-private.h \
scheme-config.h opdefines.h scheme.c scheme.h scheme-private.h
gpgscm_LDADD = $(LDADD) $(common_libs) \
$(NETLIBS) $(LIBICONV) $(LIBREADLINE) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS)
t_child_SOURCES = t-child.c
# Make sure that all libs are build before we use them. This is
# important for things like make -j2.
$(PROGRAMS): $(common_libs)
check-local: gpgscm$(EXEEXT) t-child$(EXEEXT)
EXEEXT=$(EXEEXT) GPGSCM_PATH=$(srcdir) \
./gpgscm$(EXEEXT) $(srcdir)/t-child.scm

444
tests/gpgscm/Manual.txt Normal file
View File

@ -0,0 +1,444 @@
TinySCHEME Version 1.41
"Safe if used as prescribed"
-- Philip K. Dick, "Ubik"
This software is open source, covered by a BSD-style license.
Please read accompanying file COPYING.
-------------------------------------------------------------------------------
This Scheme interpreter is based on MiniSCHEME version 0.85k4
(see miniscm.tar.gz in the Scheme Repository)
Original credits in file MiniSCHEMETribute.txt.
D. Souflis (dsouflis@acm.org)
-------------------------------------------------------------------------------
What is TinyScheme?
-------------------
TinyScheme is a lightweight Scheme interpreter that implements as large
a subset of R5RS as was possible without getting very large and
complicated. It is meant to be used as an embedded scripting interpreter
for other programs. As such, it does not offer IDEs or extensive toolkits
although it does sport a small top-level loop, included conditionally.
A lot of functionality in TinyScheme is included conditionally, to allow
developers freedom in balancing features and footprint.
As an embedded interpreter, it allows multiple interpreter states to
coexist in the same program, without any interference between them.
Programmatically, foreign functions in C can be added and values
can be defined in the Scheme environment. Being a quite small program,
it is easy to comprehend, get to grips with, and use.
Known bugs
----------
TinyScheme is known to misbehave when memory is exhausted.
Things that keep missing, or that need fixing
---------------------------------------------
There are no hygienic macros. No rational or
complex numbers. No unwind-protect and call-with-values.
Maybe (a subset of) SLIB will work with TinySCHEME...
Decent debugging facilities are missing. Only tracing is supported
natively.
Scheme Reference
----------------
If something seems to be missing, please refer to the code and
"init.scm", since some are library functions. Refer to the MiniSCHEME
readme as a last resort.
Environments
(interaction-environment)
See R5RS. In TinySCHEME, immutable list of association lists.
(current-environment)
The environment in effect at the time of the call. An example of its
use and its utility can be found in the sample code that implements
packages in "init.scm":
(macro (package form)
`(apply (lambda ()
,@(cdr form)
(current-environment))))
The environment containing the (local) definitions inside the closure
is returned as an immutable value.
(defined? <symbol>) (defined? <symbol> <environment>)
Checks whether the given symbol is defined in the current (or given)
environment.
Symbols
(gensym)
Returns a new interned symbol each time. Will probably move to the
library when string->symbol is implemented.
Directives
(gc)
Performs garbage collection immediatelly.
(gc-verbose) (gc-verbose <bool>)
The argument (defaulting to #t) controls whether GC produces
visible outcome.
(quit) (quit <num>)
Stops the interpreter and sets the 'retcode' internal field (defaults
to 0). When standalone, 'retcode' is returned as exit code to the OS.
(tracing <num>)
1, turns on tracing. 0 turns it off. (Only when USE_TRACING is 1).
Mathematical functions
Since rationals and complexes are absent, the respective functions
are also missing.
Supported: exp, log, sin, cos, tan, asin, acos, atan, floor, ceiling,
trunc, round and also sqrt and expt when USE_MATH=1.
Number-theoretical quotient, remainder and modulo, gcd, lcm.
Library: exact?, inexact?, odd?, even?, zero?, positive?, negative?,
exact->inexact. inexact->exact is a core function.
Type predicates
boolean?,eof-object?,symbol?,number?,string?,integer?,real?,list?,null?,
char?,port?,input-port?,output-port?,procedure?,pair?,environment?',
vector?. Also closure?, macro?.
Types
Types supported:
Numbers (integers and reals)
Symbols
Pairs
Strings
Characters
Ports
Eof object
Environments
Vectors
Literals
String literals can contain escaped quotes \" as usual, but also
\n, \r, \t, \xDD (hex representations) and \DDD (octal representations).
Note also that it is possible to include literal newlines in string
literals, e.g.
(define s "String with newline here
and here
that can function like a HERE-string")
Character literals contain #\space and #\newline and are supplemented
with #\return and #\tab, with obvious meanings. Hex character
representations are allowed (e.g. #\x20 is #\space).
When USE_ASCII_NAMES is defined, various control characters can be
referred to by their ASCII name.
0 #\nul 17 #\dc1
1 #\soh 18 #\dc2
2 #\stx 19 #\dc3
3 #\etx 20 #\dc4
4 #\eot 21 #\nak
5 #\enq 22 #\syn
6 #\ack 23 #\etv
7 #\bel 24 #\can
8 #\bs 25 #\em
9 #\ht 26 #\sub
10 #\lf 27 #\esc
11 #\vt 28 #\fs
12 #\ff 29 #\gs
13 #\cr 30 #\rs
14 #\so 31 #\us
15 #\si
16 #\dle 127 #\del
Numeric literals support #x #o #b and #d. Flonums are currently read only
in decimal notation. Full grammar will be supported soon.
Quote, quasiquote etc.
As usual.
Immutable values
Immutable pairs cannot be modified by set-car! and set-cdr!.
Immutable strings cannot be modified via string-set!
I/O
As per R5RS, plus String Ports (see below).
current-input-port, current-output-port,
close-input-port, close-output-port, input-port?, output-port?,
open-input-file, open-output-file.
read, write, display, newline, write-char, read-char, peek-char.
char-ready? returns #t only for string ports, because there is no
portable way in stdio to determine if a character is available.
Also open-input-output-file, set-input-port, set-output-port (not R5RS)
Library: call-with-input-file, call-with-output-file,
with-input-from-file, with-output-from-file and
with-input-output-from-to-files, close-port and input-output-port?
(not R5RS).
String Ports: open-input-string, open-output-string, get-output-string,
open-input-output-string. Strings can be used with I/O routines.
Vectors
make-vector, vector, vector-length, vector-ref, vector-set!, list->vector,
vector-fill!, vector->list, vector-equal? (auxiliary function, not R5RS)
Strings
string, make-string, list->string, string-length, string-ref, string-set!,
substring, string->list, string-fill!, string-append, string-copy.
string=?, string<?, string>?, string>?, string<=?, string>=?.
(No string-ci*? yet). string->number, number->string. Also atom->string,
string->atom (not R5RS).
Symbols
symbol->string, string->symbol
Characters
integer->char, char->integer.
char=?, char<?, char>?, char<=?, char>=?.
(No char-ci*?)
Pairs & Lists
cons, car, cdr, list, length, map, for-each, foldr, list-tail,
list-ref, last-pair, reverse, append.
Also member, memq, memv, based on generic-member, assoc, assq, assv
based on generic-assoc.
Streams
head, tail, cons-stream
Control features
Apart from procedure?, also macro? and closure?
map, for-each, force, delay, call-with-current-continuation (or call/cc),
eval, apply. 'Forcing' a value that is not a promise produces the value.
There is no call-with-values, values, nor dynamic-wind. Dynamic-wind in
the presence of continuations would require support from the abstract
machine itself.
Property lists
TinyScheme inherited from MiniScheme property lists for symbols.
put, get.
Dynamically-loaded extensions
(load-extension <filename without extension>)
Loads a DLL declaring foreign procedures. On Unix/Linux, one can make use
of the ld.so.conf file or the LD_RUN_PATH system variable in order to place
the library in a directory other than the current one. Please refer to the
appropriate 'man' page.
Esoteric procedures
(oblist)
Returns the oblist, an immutable list of all the symbols.
(macro-expand <form>)
Returns the expanded form of the macro call denoted by the argument
(define-with-return (<procname> <args>...) <body>)
Like plain 'define', but makes the continuation available as 'return'
inside the procedure. Handy for imperative programs.
(new-segment <num>)
Allocates more memory segments.
defined?
See "Environments"
(get-closure-code <closure>)
Gets the code as scheme data.
(make-closure <code> <environment>)
Makes a new closure in the given environment.
Obsolete procedures
(print-width <object>)
Programmer's Reference
----------------------
The interpreter state is initialized with "scheme_init".
Custom memory allocation routines can be installed with an alternate
initialization function: "scheme_init_custom_alloc".
Files can be loaded with "scheme_load_file". Strings containing Scheme
code can be loaded with "scheme_load_string". It is a good idea to
"scheme_load" init.scm before anything else.
External data for keeping external state (of use to foreign functions)
can be installed with "scheme_set_external_data".
Foreign functions are installed with "assign_foreign". Additional
definitions can be added to the interpreter state, with "scheme_define"
(this is the way HTTP header data and HTML form data are passed to the
Scheme script in the Altera SQL Server). If you wish to define the
foreign function in a specific environment (to enhance modularity),
use "assign_foreign_env".
The procedure "scheme_apply0" has been added with persistent scripts in
mind. Persistent scripts are loaded once, and every time they are needed
to produce HTTP output, appropriate data are passed through global
definitions and function "main" is called to do the job. One could
add easily "scheme_apply1" etc.
The interpreter state should be deinitialized with "scheme_deinit".
DLLs containing foreign functions should define a function named
init_<base-name>. E.g. foo.dll should define init_foo, and bar.so
should define init_bar. This function should assign_foreign any foreign
function contained in the DLL.
The first dynamically loaded extension available for TinyScheme is
a regular expression library. Although it's by no means an
established standard, this library is supposed to be installed in
a directory mirroring its name under the TinyScheme location.
Foreign Functions
-----------------
The user can add foreign functions in C. For example, a function
that squares its argument:
pointer square(scheme *sc, pointer args) {
if(args!=sc->NIL) {
if(sc->isnumber(sc->pair_car(args))) {
double v=sc->rvalue(sc->pair_car(args));
return sc->mk_real(sc,v*v);
}
}
return sc->NIL;
}
Foreign functions are now defined as closures:
sc->interface->scheme_define(
sc,
sc->global_env,
sc->interface->mk_symbol(sc,"square"),
sc->interface->mk_foreign_func(sc, square));
Foreign functions can use the external data in the "scheme" struct
to implement any kind of external state.
External data are set with the following function:
void scheme_set_external_data(scheme *sc, void *p);
As of v.1.17, the canonical way for a foreign function in a DLL to
manipulate Scheme data is using the function pointers in sc->interface.
Standalone
----------
Usage: tinyscheme -?
or: tinyscheme [<file1> <file2> ...]
followed by
-1 <file> [<arg1> <arg2> ...]
-c <Scheme commands> [<arg1> <arg2> ...]
assuming that the executable is named tinyscheme.
Use - in the place of a filename to denote stdin.
The -1 flag is meant for #! usage in shell scripts. If you specify
#! /somewhere/tinyscheme -1
then tinyscheme will be called to process the file. For example, the
following script echoes the Scheme list of its arguments.
#! /somewhere/tinyscheme -1
(display *args*)
The -c flag permits execution of arbitrary Scheme code.
Error Handling
--------------
Errors are recovered from without damage. The user can install his
own handler for system errors, by defining *error-hook*. Defining
to '() gives the default behavior, which is equivalent to "error".
USE_ERROR_HOOK must be defined.
A simple exception handling mechanism can be found in "init.scm".
A new syntactic form is introduced:
(catch <expr returned exceptionally>
<expr1> <expr2> ... <exprN>)
"Catch" establishes a scope spanning multiple call-frames
until another "catch" is encountered.
Exceptions are thrown with:
(throw "message")
If used outside a (catch ...), reverts to (error "message").
Example of use:
(define (foo x) (write x) (newline) (/ x 0))
(catch (begin (display "Error!\n") 0)
(write "Before foo ... ")
(foo 5)
(write "After foo"))
The exception mechanism can be used even by system errors, by
(define *error-hook* throw)
which makes use of the error hook described above.
If necessary, the user can devise his own exception mechanism with
tagged exceptions etc.
Reader extensions
-----------------
When encountering an unknown character after '#', the user-specified
procedure *sharp-hook* (if any), is called to read the expression.
This can be used to extend the reader to handle user-defined constants
or whatever. It should be a procedure without arguments, reading from
the current input port (which will be the load-port).
Colon Qualifiers - Packages
---------------------------
When USE_COLON_HOOK=1:
The lexer now recognizes the construction <qualifier>::<symbol> and
transforms it in the following manner (T is the transformation function):
T(<qualifier>::<symbol>) = (*colon-hook* 'T(<symbol>) <qualifier>)
where <qualifier> is a symbol not containing any double-colons.
As the definition is recursive, qualifiers can be nested.
The user can define his own *colon-hook*, to handle qualified names.
By default, "init.scm" defines *colon-hook* as EVAL. Consequently,
the qualifier must denote a Scheme environment, such as one returned
by (interaction-environment). "Init.scm" defines a new syntantic form,
PACKAGE, as a simple example. It is used like this:
(define toto
(package
(define foo 1)
(define bar +)))
foo ==> Error, "foo" undefined
(eval 'foo) ==> Error, "foo" undefined
(eval 'foo toto) ==> 1
toto::foo ==> 1
((eval 'bar toto) 2 (eval 'foo toto)) ==> 3
(toto::bar 2 toto::foo) ==> 3
(eval (bar 2 foo) toto) ==> 3
If the user installs another package infrastructure, he must define
a new 'package' procedure or macro to retain compatibility with supplied
code.
Note: Older versions used ':' as a qualifier. Unfortunately, the use
of ':' as a pseudo-qualifier in existing code (i.e. SLIB) essentially
precludes its use as a real qualifier.

148
tests/gpgscm/ffi-private.h Normal file
View File

@ -0,0 +1,148 @@
/* FFI interface for TinySCHEME.
*
* Copyright (C) 2016 g10 code GmbH
*
* 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/>.
*/
#ifndef GPGSCM_FFI_PRIVATE_H
#define GPGSCM_FFI_PRIVATE_H
#include <gpg-error.h>
#include "scheme.h"
#include "scheme-private.h"
#define FFI_PROLOG() \
unsigned int ffi_arg_index GPGRT_ATTR_UNUSED = 1; \
int err GPGRT_ATTR_UNUSED = 0 \
int ffi_bool_value (scheme *sc, pointer p);
#define CONVERSION_number(SC, X) (SC)->vptr->ivalue (X)
#define CONVERSION_string(SC, X) (SC)->vptr->string_value (X)
#define CONVERSION_character(SC, X) (SC)->vptr->charvalue (X)
#define CONVERSION_list(SC, X) (X)
#define CONVERSION_bool(SC, X) ffi_bool_value ((SC), (X))
#define CONVERSION_path(SC, X) (((SC)->vptr->is_string (X) \
? (SC)->vptr->string_value \
: (SC)->vptr->symname) (X))
#define IS_A_number(SC, X) (SC)->vptr->is_number (X)
#define IS_A_string(SC, X) (SC)->vptr->is_string (X)
#define IS_A_character(SC, X) (SC)->vptr->is_character (X)
#define IS_A_list(SC, X) (SC)->vptr->is_list ((SC), X)
#define IS_A_bool(SC, X) ((X) == (SC)->F || (X) == (SC)->T)
#define IS_A_path(SC, X) ((SC)->vptr->is_string (X) \
|| (SC)->vptr->is_symbol (X))
#define FFI_ARG_OR_RETURN(SC, CTYPE, TARGET, WANT, ARGS) \
do { \
if ((ARGS) == (SC)->NIL) \
return (SC)->vptr->mk_string ((SC), \
"too few arguments: want " \
#TARGET "("#WANT"/"#CTYPE")\n"); \
if (! IS_A_##WANT ((SC), pair_car (ARGS))) { \
char ffi_error_message[256]; \
snprintf (ffi_error_message, sizeof ffi_error_message, \
"argument %d must be: " #WANT "\n", ffi_arg_index); \
return (SC)->vptr->mk_string ((SC), ffi_error_message); \
} \
TARGET = CONVERSION_##WANT (SC, pair_car (ARGS)); \
ARGS = pair_cdr (ARGS); \
ffi_arg_index += 1; \
} while (0)
#define FFI_ARGS_DONE_OR_RETURN(SC, ARGS) \
do { \
if ((ARGS) != (SC)->NIL) \
return (SC)->vptr->mk_string ((SC), "too many arguments"); \
} while (0)
#define FFI_RETURN_ERR(SC, ERR) \
return _cons ((SC), mk_integer ((SC), (ERR)), (SC)->NIL, 1)
#define FFI_RETURN(SC) FFI_RETURN_ERR (SC, err)
#define FFI_RETURN_POINTER(SC, X) \
return _cons ((SC), mk_integer ((SC), err), \
_cons ((SC), (X), (SC)->NIL, 1), 1)
#define FFI_RETURN_INT(SC, X) \
FFI_RETURN_POINTER ((SC), mk_integer ((SC), (X)))
#define FFI_RETURN_STRING(SC, X) \
FFI_RETURN_POINTER ((SC), mk_string ((SC), (X)))
char *ffi_schemify_name (const char *s, int macro);
void ffi_scheme_eval (scheme *sc, const char *format, ...)
GPGRT_ATTR_PRINTF (2, 3);
pointer ffi_sprintf (scheme *sc, const char *format, ...)
GPGRT_ATTR_PRINTF (2, 3);
#define ffi_define_function_name(SC, NAME, F) \
do { \
char *_fname = ffi_schemify_name ("_" #F, 0); \
scheme_define ((SC), \
(SC)->global_env, \
mk_symbol ((SC), _fname), \
mk_foreign_func ((SC), (do_##F))); \
ffi_scheme_eval ((SC), \
"(define (%s . a) (ffi-apply \"%s\" %s a))", \
(NAME), (NAME), _fname); \
free (_fname); \
} while (0)
#define ffi_define_function(SC, F) \
do { \
char *_name = ffi_schemify_name (#F, 0); \
ffi_define_function_name ((SC), _name, F); \
free (_name); \
} while (0)
#define ffi_define_constant(SC, C) \
do { \
char *_name = ffi_schemify_name (#C, 1); \
scheme_define ((SC), \
(SC)->global_env, \
mk_symbol ((SC), _name), \
mk_integer ((SC), (C))); \
free (_name); \
} while (0)
#define ffi_define(SC, SYM, EXP) \
scheme_define ((SC), (SC)->global_env, mk_symbol ((SC), (SYM)), EXP)
#define ffi_define_variable_pointer(SC, C, P) \
do { \
char *_name = ffi_schemify_name (#C, 0); \
scheme_define ((SC), \
(SC)->global_env, \
mk_symbol ((SC), _name), \
(P)); \
free (_name); \
} while (0)
#define ffi_define_variable_integer(SC, C) \
ffi_define_variable_pointer ((SC), C, (SC)->vptr->mk_integer ((SC), C))
#define ffi_define_variable_string(SC, C) \
ffi_define_variable_pointer ((SC), C, (SC)->vptr->mk_string ((SC), C ?: ""))
gpg_error_t ffi_list2argv (scheme *sc, pointer list,
char ***argv, size_t *len);
gpg_error_t ffi_list2intv (scheme *sc, pointer list,
int **intv, size_t *len);
#endif /* GPGSCM_FFI_PRIVATE_H */

1283
tests/gpgscm/ffi.c Normal file

File diff suppressed because it is too large Load Diff

30
tests/gpgscm/ffi.h Normal file
View File

@ -0,0 +1,30 @@
/* FFI interface for TinySCHEME.
*
* Copyright (C) 2016 g10 code GmbH
*
* 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/>.
*/
#ifndef GPGSCM_FFI_H
#define GPGSCM_FFI_H
#include <gpg-error.h>
#include "scheme.h"
gpg_error_t ffi_init (scheme *sc, const char *argv0,
int argc, const char **argv);
#endif /* GPGSCM_FFI_H */

44
tests/gpgscm/ffi.scm Normal file
View File

@ -0,0 +1,44 @@
;; FFI interface for TinySCHEME.
;;
;; Copyright (C) 2016 g10 Code GmbH
;;
;; 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/>.
;; Foreign function wrapper. Expects F to return a list with the
;; first element being the `error_t' value returned by the foreign
;; function. The error is thrown, or the cdr of the result is
;; returned.
(define (ffi-apply name f args)
(let ((result (apply f args)))
(cond
((string? result)
(ffi-fail name args result))
((not (= (car result) 0))
(ffi-fail name args (strerror (car result))))
((and (= (car result) 0) (pair? (cdr result))) (cadr result))
((= (car result) 0) '())
(else
(throw (list "Result violates FFI calling convention: " result))))))
(define (ffi-fail name args message)
(let ((args' (open-output-string)))
(write (cons (string->symbol name) args) args')
(throw (string-append
(get-output-string args') ": " message))))
;; Pseudo-definitions for foreign functions. Evaluates to no code,
;; but serves as documentation.
(macro (ffi-define form))

723
tests/gpgscm/init.scm Normal file
View File

@ -0,0 +1,723 @@
; Initialization file for TinySCHEME 1.41
; Per R5RS, up to four deep compositions should be defined
(define (caar x) (car (car x)))
(define (cadr x) (car (cdr x)))
(define (cdar x) (cdr (car x)))
(define (cddr x) (cdr (cdr x)))
(define (caaar x) (car (car (car x))))
(define (caadr x) (car (car (cdr x))))
(define (cadar x) (car (cdr (car x))))
(define (caddr x) (car (cdr (cdr x))))
(define (cdaar x) (cdr (car (car x))))
(define (cdadr x) (cdr (car (cdr x))))
(define (cddar x) (cdr (cdr (car x))))
(define (cdddr x) (cdr (cdr (cdr x))))
(define (caaaar x) (car (car (car (car x)))))
(define (caaadr x) (car (car (car (cdr x)))))
(define (caadar x) (car (car (cdr (car x)))))
(define (caaddr x) (car (car (cdr (cdr x)))))
(define (cadaar x) (car (cdr (car (car x)))))
(define (cadadr x) (car (cdr (car (cdr x)))))
(define (caddar x) (car (cdr (cdr (car x)))))
(define (cadddr x) (car (cdr (cdr (cdr x)))))
(define (cdaaar x) (cdr (car (car (car x)))))
(define (cdaadr x) (cdr (car (car (cdr x)))))
(define (cdadar x) (cdr (car (cdr (car x)))))
(define (cdaddr x) (cdr (car (cdr (cdr x)))))
(define (cddaar x) (cdr (cdr (car (car x)))))
(define (cddadr x) (cdr (cdr (car (cdr x)))))
(define (cdddar x) (cdr (cdr (cdr (car x)))))
(define (cddddr x) (cdr (cdr (cdr (cdr x)))))
;;;; Utility to ease macro creation
(define (macro-expand form)
((eval (get-closure-code (eval (car form)))) form))
(define (macro-expand-all form)
(if (macro? form)
(macro-expand-all (macro-expand form))
form))
(define *compile-hook* macro-expand-all)
(macro (unless form)
`(if (not ,(cadr form)) (begin ,@(cddr form))))
(macro (when form)
`(if ,(cadr form) (begin ,@(cddr form))))
; DEFINE-MACRO Contributed by Andy Gaynor
(macro (define-macro dform)
(if (symbol? (cadr dform))
`(macro ,@(cdr dform))
(let ((form (gensym)))
`(macro (,(caadr dform) ,form)
(apply (lambda ,(cdadr dform) ,@(cddr dform)) (cdr ,form))))))
; Utilities for math. Notice that inexact->exact is primitive,
; but exact->inexact is not.
(define exact? integer?)
(define (inexact? x) (and (real? x) (not (integer? x))))
(define (even? n) (= (remainder n 2) 0))
(define (odd? n) (not (= (remainder n 2) 0)))
(define (zero? n) (= n 0))
(define (positive? n) (> n 0))
(define (negative? n) (< n 0))
(define complex? number?)
(define rational? real?)
(define (abs n) (if (>= n 0) n (- n)))
(define (exact->inexact n) (* n 1.0))
(define (<> n1 n2) (not (= n1 n2)))
; min and max must return inexact if any arg is inexact; use (+ n 0.0)
(define (max . lst)
(foldr (lambda (a b)
(if (> a b)
(if (exact? b) a (+ a 0.0))
(if (exact? a) b (+ b 0.0))))
(car lst) (cdr lst)))
(define (min . lst)
(foldr (lambda (a b)
(if (< a b)
(if (exact? b) a (+ a 0.0))
(if (exact? a) b (+ b 0.0))))
(car lst) (cdr lst)))
(define (succ x) (+ x 1))
(define (pred x) (- x 1))
(define gcd
(lambda a
(if (null? a)
0
(let ((aa (abs (car a)))
(bb (abs (cadr a))))
(if (= bb 0)
aa
(gcd bb (remainder aa bb)))))))
(define lcm
(lambda a
(if (null? a)
1
(let ((aa (abs (car a)))
(bb (abs (cadr a))))
(if (or (= aa 0) (= bb 0))
0
(abs (* (quotient aa (gcd aa bb)) bb)))))))
(define (string . charlist)
(list->string charlist))
(define (list->string charlist)
(let* ((len (length charlist))
(newstr (make-string len))
(fill-string!
(lambda (str i len charlist)
(if (= i len)
str
(begin (string-set! str i (car charlist))
(fill-string! str (+ i 1) len (cdr charlist)))))))
(fill-string! newstr 0 len charlist)))
(define (string-fill! s e)
(let ((n (string-length s)))
(let loop ((i 0))
(if (= i n)
s
(begin (string-set! s i e) (loop (succ i)))))))
(define (string->list s)
(let loop ((n (pred (string-length s))) (l '()))
(if (= n -1)
l
(loop (pred n) (cons (string-ref s n) l)))))
(define (string-copy str)
(string-append str))
(define (string->anyatom str pred)
(let* ((a (string->atom str)))
(if (pred a) a
(error "string->xxx: not a xxx" a))))
(define (string->number str . base)
(let ((n (string->atom str (if (null? base) 10 (car base)))))
(if (number? n) n #f)))
(define (anyatom->string n pred)
(if (pred n)
(atom->string n)
(error "xxx->string: not a xxx" n)))
(define (number->string n . base)
(atom->string n (if (null? base) 10 (car base))))
(define (char-cmp? cmp a b)
(cmp (char->integer a) (char->integer b)))
(define (char-ci-cmp? cmp a b)
(cmp (char->integer (char-downcase a)) (char->integer (char-downcase b))))
(define (char=? a b) (char-cmp? = a b))
(define (char<? a b) (char-cmp? < a b))
(define (char>? a b) (char-cmp? > a b))
(define (char<=? a b) (char-cmp? <= a b))
(define (char>=? a b) (char-cmp? >= a b))
(define (char-ci=? a b) (char-ci-cmp? = a b))
(define (char-ci<? a b) (char-ci-cmp? < a b))
(define (char-ci>? a b) (char-ci-cmp? > a b))
(define (char-ci<=? a b) (char-ci-cmp? <= a b))
(define (char-ci>=? a b) (char-ci-cmp? >= a b))
; Note the trick of returning (cmp x y)
(define (string-cmp? chcmp cmp a b)
(let ((na (string-length a)) (nb (string-length b)))
(let loop ((i 0))
(cond
((= i na)
(if (= i nb) (cmp 0 0) (cmp 0 1)))
((= i nb)
(cmp 1 0))
((chcmp = (string-ref a i) (string-ref b i))
(loop (succ i)))
(else
(chcmp cmp (string-ref a i) (string-ref b i)))))))
(define (string=? a b) (string-cmp? char-cmp? = a b))
(define (string<? a b) (string-cmp? char-cmp? < a b))
(define (string>? a b) (string-cmp? char-cmp? > a b))
(define (string<=? a b) (string-cmp? char-cmp? <= a b))
(define (string>=? a b) (string-cmp? char-cmp? >= a b))
(define (string-ci=? a b) (string-cmp? char-ci-cmp? = a b))
(define (string-ci<? a b) (string-cmp? char-ci-cmp? < a b))
(define (string-ci>? a b) (string-cmp? char-ci-cmp? > a b))
(define (string-ci<=? a b) (string-cmp? char-ci-cmp? <= a b))
(define (string-ci>=? a b) (string-cmp? char-ci-cmp? >= a b))
(define (list . x) x)
(define (foldr f x lst)
(if (null? lst)
x
(foldr f (f x (car lst)) (cdr lst))))
(define (unzip1-with-cdr . lists)
(unzip1-with-cdr-iterative lists '() '()))
(define (unzip1-with-cdr-iterative lists cars cdrs)
(if (null? lists)
(cons cars cdrs)
(let ((car1 (caar lists))
(cdr1 (cdar lists)))
(unzip1-with-cdr-iterative
(cdr lists)
(append cars (list car1))
(append cdrs (list cdr1))))))
(define (map proc . lists)
(if (null? lists)
(apply proc)
(if (null? (car lists))
'()
(let* ((unz (apply unzip1-with-cdr lists))
(cars (car unz))
(cdrs (cdr unz)))
(cons (apply proc cars) (apply map (cons proc cdrs)))))))
(define (for-each proc . lists)
(if (null? lists)
(apply proc)
(if (null? (car lists))
#t
(let* ((unz (apply unzip1-with-cdr lists))
(cars (car unz))
(cdrs (cdr unz)))
(apply proc cars) (apply map (cons proc cdrs))))))
(define (list-tail x k)
(if (zero? k)
x
(list-tail (cdr x) (- k 1))))
(define (list-ref x k)
(car (list-tail x k)))
(define (last-pair x)
(if (pair? (cdr x))
(last-pair (cdr x))
x))
(define (head stream) (car stream))
(define (tail stream) (force (cdr stream)))
(define (vector-equal? x y)
(and (vector? x) (vector? y) (= (vector-length x) (vector-length y))
(let ((n (vector-length x)))
(let loop ((i 0))
(if (= i n)
#t
(and (equal? (vector-ref x i) (vector-ref y i))
(loop (succ i))))))))
(define (list->vector x)
(apply vector x))
(define (vector-fill! v e)
(let ((n (vector-length v)))
(let loop ((i 0))
(if (= i n)
v
(begin (vector-set! v i e) (loop (succ i)))))))
(define (vector->list v)
(let loop ((n (pred (vector-length v))) (l '()))
(if (= n -1)
l
(loop (pred n) (cons (vector-ref v n) l)))))
;; The following quasiquote macro is due to Eric S. Tiedemann.
;; Copyright 1988 by Eric S. Tiedemann; all rights reserved.
;;
;; Subsequently modified to handle vectors: D. Souflis
(macro
quasiquote
(lambda (l)
(define (mcons f l r)
(if (and (pair? r)
(eq? (car r) 'quote)
(eq? (car (cdr r)) (cdr f))
(pair? l)
(eq? (car l) 'quote)
(eq? (car (cdr l)) (car f)))
(if (or (procedure? f) (number? f) (string? f))
f
(list 'quote f))
(if (eqv? l vector)
(apply l (eval r))
(list 'cons l r)
)))
(define (mappend f l r)
(if (or (null? (cdr f))
(and (pair? r)
(eq? (car r) 'quote)
(eq? (car (cdr r)) '())))
l
(list 'append l r)))
(define (foo level form)
(cond ((not (pair? form))
(if (or (procedure? form) (number? form) (string? form))
form
(list 'quote form))
)
((eq? 'quasiquote (car form))
(mcons form ''quasiquote (foo (+ level 1) (cdr form))))
(#t (if (zero? level)
(cond ((eq? (car form) 'unquote) (car (cdr form)))
((eq? (car form) 'unquote-splicing)
(error "Unquote-splicing wasn't in a list:"
form))
((and (pair? (car form))
(eq? (car (car form)) 'unquote-splicing))
(mappend form (car (cdr (car form)))
(foo level (cdr form))))
(#t (mcons form (foo level (car form))
(foo level (cdr form)))))
(cond ((eq? (car form) 'unquote)
(mcons form ''unquote (foo (- level 1)
(cdr form))))
((eq? (car form) 'unquote-splicing)
(mcons form ''unquote-splicing
(foo (- level 1) (cdr form))))
(#t (mcons form (foo level (car form))
(foo level (cdr form)))))))))
(foo 0 (car (cdr l)))))
;;;;;Helper for the dynamic-wind definition. By Tom Breton (Tehom)
(define (shared-tail x y)
(let ((len-x (length x))
(len-y (length y)))
(define (shared-tail-helper x y)
(if
(eq? x y)
x
(shared-tail-helper (cdr x) (cdr y))))
(cond
((> len-x len-y)
(shared-tail-helper
(list-tail x (- len-x len-y))
y))
((< len-x len-y)
(shared-tail-helper
x
(list-tail y (- len-y len-x))))
(#t (shared-tail-helper x y)))))
;;;;;Dynamic-wind by Tom Breton (Tehom)
;;Guarded because we must only eval this once, because doing so
;;redefines call/cc in terms of old call/cc
(unless (defined? 'dynamic-wind)
(let
;;These functions are defined in the context of a private list of
;;pairs of before/after procs.
( (*active-windings* '())
;;We'll define some functions into the larger environment, so
;;we need to know it.
(outer-env (current-environment)))
;;Poor-man's structure operations
(define before-func car)
(define after-func cdr)
(define make-winding cons)
;;Manage active windings
(define (activate-winding! new)
((before-func new))
(set! *active-windings* (cons new *active-windings*)))
(define (deactivate-top-winding!)
(let ((old-top (car *active-windings*)))
;;Remove it from the list first so it's not active during its
;;own exit.
(set! *active-windings* (cdr *active-windings*))
((after-func old-top))))
(define (set-active-windings! new-ws)
(unless (eq? new-ws *active-windings*)
(let ((shared (shared-tail new-ws *active-windings*)))
;;Define the looping functions.
;;Exit the old list. Do deeper ones last. Don't do
;;any shared ones.
(define (pop-many)
(unless (eq? *active-windings* shared)
(deactivate-top-winding!)
(pop-many)))
;;Enter the new list. Do deeper ones first so that the
;;deeper windings will already be active. Don't do any
;;shared ones.
(define (push-many new-ws)
(unless (eq? new-ws shared)
(push-many (cdr new-ws))
(activate-winding! (car new-ws))))
;;Do it.
(pop-many)
(push-many new-ws))))
;;The definitions themselves.
(eval
`(define call-with-current-continuation
;;It internally uses the built-in call/cc, so capture it.
,(let ((old-c/cc call-with-current-continuation))
(lambda (func)
;;Use old call/cc to get the continuation.
(old-c/cc
(lambda (continuation)
;;Call func with not the continuation itself
;;but a procedure that adjusts the active
;;windings to what they were when we made
;;this, and only then calls the
;;continuation.
(func
(let ((current-ws *active-windings*))
(lambda (x)
(set-active-windings! current-ws)
(continuation x)))))))))
outer-env)
;;We can't just say "define (dynamic-wind before thunk after)"
;;because the lambda it's defined to lives in this environment,
;;not in the global environment.
(eval
`(define dynamic-wind
,(lambda (before thunk after)
;;Make a new winding
(activate-winding! (make-winding before after))
(let ((result (thunk)))
;;Get rid of the new winding.
(deactivate-top-winding!)
;;The return value is that of thunk.
result)))
outer-env)))
(define call/cc call-with-current-continuation)
;;;;; atom? and equal? written by a.k
;;;; atom?
(define (atom? x)
(not (pair? x)))
;;;; equal?
(define (equal? x y)
(cond
((pair? x)
(and (pair? y)
(equal? (car x) (car y))
(equal? (cdr x) (cdr y))))
((vector? x)
(and (vector? y) (vector-equal? x y)))
((string? x)
(and (string? y) (string=? x y)))
(else (eqv? x y))))
;;;; (do ((var init inc) ...) (endtest result ...) body ...)
;;
(macro do
(lambda (do-macro)
(apply (lambda (do vars endtest . body)
(let ((do-loop (gensym)))
`(letrec ((,do-loop
(lambda ,(map (lambda (x)
(if (pair? x) (car x) x))
`,vars)
(if ,(car endtest)
(begin ,@(cdr endtest))
(begin
,@body
(,do-loop
,@(map (lambda (x)
(cond
((not (pair? x)) x)
((< (length x) 3) (car x))
(else (car (cdr (cdr x))))))
`,vars)))))))
(,do-loop
,@(map (lambda (x)
(if (and (pair? x) (cdr x))
(car (cdr x))
'()))
`,vars)))))
do-macro)))
;;;; generic-member
(define (generic-member cmp obj lst)
(cond
((null? lst) #f)
((cmp obj (car lst)) lst)
(else (generic-member cmp obj (cdr lst)))))
(define (memq obj lst)
(generic-member eq? obj lst))
(define (memv obj lst)
(generic-member eqv? obj lst))
(define (member obj lst)
(generic-member equal? obj lst))
;;;; generic-assoc
(define (generic-assoc cmp obj alst)
(cond
((null? alst) #f)
((cmp obj (caar alst)) (car alst))
(else (generic-assoc cmp obj (cdr alst)))))
(define (assq obj alst)
(generic-assoc eq? obj alst))
(define (assv obj alst)
(generic-assoc eqv? obj alst))
(define (assoc obj alst)
(generic-assoc equal? obj alst))
(define (acons x y z) (cons (cons x y) z))
;;;; Handy for imperative programs
;;;; Used as: (define-with-return (foo x y) .... (return z) ...)
(macro (define-with-return form)
`(define ,(cadr form)
(call/cc (lambda (return) ,@(cddr form)))))
;;;; Simple exception handling
;
; Exceptions are caught as follows:
;
; (catch (do-something to-recover and-return meaningful-value)
; (if-something goes-wrong)
; (with-these calls))
;
; "Catch" establishes a scope spanning multiple call-frames until
; another "catch" is encountered. Within the recovery expression
; the thrown exception is bound to *error*.
;
; Exceptions are thrown with:
;
; (throw "message")
;
; If used outside a (catch ...), reverts to (error "message)
(define *handlers* (list))
(define (push-handler proc)
(set! *handlers* (cons proc *handlers*)))
(define (pop-handler)
(let ((h (car *handlers*)))
(set! *handlers* (cdr *handlers*))
h))
(define (more-handlers?)
(pair? *handlers*))
(define (throw . x)
(if (more-handlers?)
(apply (pop-handler) x)
(apply error x)))
(macro (catch form)
(let ((label (gensym)))
`(call/cc (lambda (exit)
(push-handler (lambda (*error*) (exit ,(cadr form))))
(let ((,label (begin ,@(cddr form))))
(pop-handler)
,label)))))
(define (*error-hook* . args)
(throw args))
;;;;; Definition of MAKE-ENVIRONMENT, to be used with two-argument EVAL
(macro (make-environment form)
`(apply (lambda ()
,@(cdr form)
(current-environment))))
(define-macro (eval-polymorphic x . envl)
(display envl)
(let* ((env (if (null? envl) (current-environment) (eval (car envl))))
(xval (eval x env)))
(if (closure? xval)
(make-closure (get-closure-code xval) env)
xval)))
; Redefine this if you install another package infrastructure
; Also redefine 'package'
(define *colon-hook* eval)
(macro (package form)
`(apply (lambda ()
,@(cdr form)
(current-environment))))
;;;;; I/O
(define (input-output-port? p)
(and (input-port? p) (output-port? p)))
(define (close-port p)
(cond
((input-output-port? p) (close-input-port p) (close-output-port p))
((input-port? p) (close-input-port p))
((output-port? p) (close-output-port p))
(else (throw "Not a port" p))))
(define (call-with-input-file s p)
(let ((inport (open-input-file s)))
(if (eq? inport #f)
#f
(let ((res (p inport)))
(close-input-port inport)
res))))
(define (call-with-output-file s p)
(let ((outport (open-output-file s)))
(if (eq? outport #f)
#f
(let ((res (p outport)))
(close-output-port outport)
res))))
(define (with-input-from-file s p)
(let ((inport (open-input-file s)))
(if (eq? inport #f)
#f
(let ((prev-inport (current-input-port)))
(set-input-port inport)
(let ((res (p)))
(close-input-port inport)
(set-input-port prev-inport)
res)))))
(define (with-output-to-file s p)
(let ((outport (open-output-file s)))
(if (eq? outport #f)
#f
(let ((prev-outport (current-output-port)))
(set-output-port outport)
(let ((res (p)))
(close-output-port outport)
(set-output-port prev-outport)
res)))))
(define (with-input-output-from-to-files si so p)
(let ((inport (open-input-file si))
(outport (open-input-file so)))
(if (not (and inport outport))
(begin
(close-input-port inport)
(close-output-port outport)
#f)
(let ((prev-inport (current-input-port))
(prev-outport (current-output-port)))
(set-input-port inport)
(set-output-port outport)
(let ((res (p)))
(close-input-port inport)
(close-output-port outport)
(set-input-port prev-inport)
(set-output-port prev-outport)
res)))))
; Random number generator (maximum cycle)
(define *seed* 1)
(define (random-next)
(let* ((a 16807) (m 2147483647) (q (quotient m a)) (r (modulo m a)))
(set! *seed*
(- (* a (- *seed*
(* (quotient *seed* q) q)))
(* (quotient *seed* q) r)))
(if (< *seed* 0) (set! *seed* (+ *seed* m)))
*seed*))
;; SRFI-0
;; COND-EXPAND
;; Implemented as a macro
(define *features* '(srfi-0 tinyscheme))
(define-macro (cond-expand . cond-action-list)
(cond-expand-runtime cond-action-list))
(define (cond-expand-runtime cond-action-list)
(if (null? cond-action-list)
#t
(if (cond-eval (caar cond-action-list))
`(begin ,@(cdar cond-action-list))
(cond-expand-runtime (cdr cond-action-list)))))
(define (cond-eval-and cond-list)
(foldr (lambda (x y) (and (cond-eval x) (cond-eval y))) #t cond-list))
(define (cond-eval-or cond-list)
(foldr (lambda (x y) (or (cond-eval x) (cond-eval y))) #f cond-list))
(define (cond-eval condition)
(cond
((symbol? condition)
(if (member condition *features*) #t #f))
((eq? condition #t) #t)
((eq? condition #f) #f)
(else (case (car condition)
((and) (cond-eval-and (cdr condition)))
((or) (cond-eval-or (cdr condition)))
((not) (if (not (null? (cddr condition)))
(error "cond-expand : 'not' takes 1 argument")
(not (cond-eval (cadr condition)))))
(else (error "cond-expand : unknown operator" (car condition)))))))
(gc-verbose #f)

159
tests/gpgscm/lib.scm Normal file
View File

@ -0,0 +1,159 @@
;; Additional library functions for TinySCHEME.
;;
;; Copyright (C) 2016 g10 Code GmbH
;;
;; 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/>.
(macro (assert form)
`(if (not ,(cadr form))
(begin
(display (list "Assertion failed:" (quote ,(cadr form))))
(newline)
(exit 1))))
(assert #t)
(define (filter pred lst)
(cond ((null? lst) '())
((pred (car lst))
(cons (car lst) (filter pred (cdr lst))))
(else (filter pred (cdr lst)))))
(define (any p l)
(cond ((null? l) #f)
((p (car l)) #t)
(else (any p (cdr l)))))
(define (all p l)
(cond ((null? l) #t)
((not (p (car l))) #f)
(else (all p (cdr l)))))
;; Is PREFIX a prefix of S?
(define (string-prefix? s prefix)
(and (>= (string-length s) (string-length prefix))
(string=? prefix (substring s 0 (string-length prefix)))))
(assert (string-prefix? "Scheme" "Sch"))
;; Is SUFFIX a suffix of S?
(define (string-suffix? s suffix)
(and (>= (string-length s) (string-length suffix))
(string=? suffix (substring s (- (string-length s)
(string-length suffix))
(string-length s)))))
(assert (string-suffix? "Scheme" "eme"))
;; Locate the first occurrence of needle in haystack starting at offset.
(ffi-define (string-index haystack needle [offset]))
(assert (= 2 (string-index "Hallo" #\l)))
(assert (= 3 (string-index "Hallo" #\l 3)))
(assert (equal? #f (string-index "Hallo" #\.)))
;; Locate the last occurrence of needle in haystack starting at offset.
(ffi-define (string-rindex haystack needle [offset]))
(assert (= 3 (string-rindex "Hallo" #\l)))
(assert (equal? #f (string-rindex "Hallo" #\a 2)))
(assert (equal? #f (string-rindex "Hallo" #\.)))
;; Split haystack at delimiter at most n times.
(define (string-splitn haystack delimiter n)
(let ((length (string-length haystack)))
(define (split acc delimiter offset n)
(if (>= offset length)
(reverse acc)
(let ((i (string-index haystack delimiter offset)))
(if (or (eq? i #f) (= 0 n))
(reverse (cons (substring haystack offset length) acc))
(split (cons (substring haystack offset i) acc)
delimiter (+ i 1) (- n 1))))))
(split '() delimiter 0 n)))
(assert (= 2 (length (string-splitn "foo:bar:baz" #\: 1))))
(assert (string=? "foo" (car (string-splitn "foo:bar:baz" #\: 1))))
(assert (string=? "bar:baz" (cadr (string-splitn "foo:bar:baz" #\: 1))))
;; Split haystack at delimiter.
(define (string-split haystack delimiter)
(string-splitn haystack delimiter -1))
(assert (= 3 (length (string-split "foo:bar:baz" #\:))))
(assert (string=? "foo" (car (string-split "foo:bar:baz" #\:))))
(assert (string=? "bar" (cadr (string-split "foo:bar:baz" #\:))))
(assert (string=? "baz" (caddr (string-split "foo:bar:baz" #\:))))
;; Trim the prefix of S containing only characters that make PREDICATE
;; true.
(define (string-ltrim predicate s)
(let loop ((s' (string->list s)))
(if (predicate (car s'))
(loop (cdr s'))
(list->string s'))))
(assert (string=? "foo" (string-ltrim char-whitespace? " foo")))
;; Trim the suffix of S containing only characters that make PREDICATE
;; true.
(define (string-rtrim predicate s)
(let loop ((s' (reverse (string->list s))))
(if (predicate (car s'))
(loop (cdr s'))
(list->string (reverse s')))))
(assert (string=? "foo" (string-rtrim char-whitespace? "foo ")))
;; Trim both the prefix and suffix of S containing only characters
;; that make PREDICATE true.
(define (string-trim predicate s)
(string-ltrim predicate (string-rtrim predicate s)))
(assert (string=? "foo" (string-trim char-whitespace? " foo ")))
;; Check if needle is contained in haystack.
(ffi-define (string-contains? haystack needle))
(assert (string-contains? "Hallo" "llo"))
(assert (not (string-contains? "Hallo" "olla")))
;; Read a word from port P.
(define (read-word . p)
(list->string
(let f ()
(let ((c (apply peek-char p)))
(cond
((eof-object? c) '())
((char-alphabetic? c)
(apply read-char p)
(cons c (f)))
(else
(apply read-char p)
'()))))))
;; Read a line from port P.
(define (read-line . p)
(list->string
(let f ()
(let ((c (apply peek-char p)))
(cond
((eof-object? c) '())
((char=? c #\newline)
(apply read-char p)
'())
(else
(apply read-char p)
(cons c (f))))))))
;; Read everything from port P.
(define (read-all . p)
(let loop ((acc (open-output-string)))
(let ((c (apply peek-char p)))
(cond
((eof-object? c) (get-output-string acc))
(else
(write-char (apply read-char p) acc)
(loop acc))))))

288
tests/gpgscm/main.c Normal file
View File

@ -0,0 +1,288 @@
/* TinyScheme-based test driver.
*
* Copyright (C) 2016 g10 code GmbH
*
* 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 <assert.h>
#include <ctype.h>
#include <errno.h>
#include <gcrypt.h>
#include <gpg-error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "private.h"
#include "scheme.h"
#include "ffi.h"
#include "i18n.h"
#include "../../common/argparse.h"
#include "../../common/init.h"
#include "../../common/logging.h"
#include "../../common/strlist.h"
#include "../../common/sysutils.h"
#include "../../common/util.h"
/* The TinyScheme banner. Unfortunately, it isn't in the header
file. */
#define ts_banner "TinyScheme 1.41"
int verbose;
/* Constants to identify the commands and options. */
enum cmd_and_opt_values
{
aNull = 0,
oVerbose = 'v',
};
/* The list of commands and options. */
static ARGPARSE_OPTS opts[] =
{
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_end (),
};
char *scmpath = "";
size_t scmpath_len = 0;
/* Command line parsing. */
static void
parse_arguments (ARGPARSE_ARGS *pargs, ARGPARSE_OPTS *popts)
{
int no_more_options = 0;
while (!no_more_options && optfile_parse (NULL, NULL, NULL, pargs, popts))
{
switch (pargs->r_opt)
{
case oVerbose:
verbose++;
break;
default:
pargs->err = 2;
break;
}
}
}
/* Print usage information and and provide strings for help. */
static const char *
my_strusage( int level )
{
const char *p;
switch (level)
{
case 11: p = "gpgscm (@GNUPG@)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break;
case 1:
case 40:
p = _("Usage: gpgscm [options] [file] (-h for help)");
break;
case 41:
p = _("Syntax: gpgscm [options] [file]\n"
"Execute the given Scheme program, or spawn interactive shell.\n");
break;
default: p = NULL; break;
}
return p;
}
/* Load the Scheme program from FILE_NAME. If FILE_NAME is not an
absolute path, and LOOKUP_IN_PATH is given, then it is qualified
with the values in scmpath until the file is found. */
static gpg_error_t
load (scheme *sc, char *file_name,
int lookup_in_cwd, int lookup_in_path)
{
gpg_error_t err = 0;
size_t n;
const char *directory;
char *qualified_name = file_name;
int use_path;
FILE *h = NULL;
use_path =
lookup_in_path && ! (file_name[0] == '/' || scmpath_len == 0);
if (file_name[0] == '/' || lookup_in_cwd || scmpath_len == 0)
{
h = fopen (file_name, "r");
if (! h)
err = gpg_error_from_syserror ();
}
if (h == NULL && use_path)
for (directory = scmpath, n = scmpath_len; n;
directory += strlen (directory) + 1, n--)
{
if (asprintf (&qualified_name, "%s/%s", directory, file_name) < 0)
return gpg_error_from_syserror ();
h = fopen (qualified_name, "r");
if (h)
break;
if (n > 1)
{
free (qualified_name);
continue; /* Try again! */
}
err = gpg_error_from_syserror ();
}
if (h == NULL)
{
/* Failed and no more elements in scmpath to try. */
fprintf (stderr, "Could not read %s: %s.\n",
qualified_name, gpg_strerror (err));
if (lookup_in_path)
fprintf (stderr,
"Consider using GPGSCM_PATH to specify the location "
"of the Scheme library.\n");
return err;
}
if (verbose > 1)
fprintf (stderr, "Loading %s...\n", qualified_name);
scheme_load_named_file (sc, h, qualified_name);
fclose (h);
if (file_name != qualified_name)
free (qualified_name);
return 0;
}
int
main (int argc, char **argv)
{
gpg_error_t err;
char *argv0;
ARGPARSE_ARGS pargs;
scheme *sc;
char *p;
#if _WIN32
char pathsep = ';';
#else
char pathsep = ':';
#endif
char *script = NULL;
/* Save argv[0] so that we can re-exec. */
argv0 = argv[0];
/* Parse path. */
if (getenv ("GPGSCM_PATH"))
scmpath = getenv ("GPGSCM_PATH");
p = scmpath = strdup (scmpath);
if (p == NULL)
return 2;
if (*p)
scmpath_len++;
for (; *p; p++)
if (*p == pathsep)
*p = 0, scmpath_len++;
set_strusage (my_strusage);
log_set_prefix ("gpgscm", 1);
/* Make sure that our subsystems are ready. */
i18n_init ();
init_common_subsystems (&argc, &argv);
if (!gcry_check_version (GCRYPT_VERSION))
{
fputs ("libgcrypt version mismatch\n", stderr);
exit (2);
}
/* Parse the command line. */
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags = 0;
parse_arguments (&pargs, opts);
if (log_get_errorcount (0))
exit (2);
sc = scheme_init_new_custom_alloc (gcry_malloc, gcry_free);
if (! sc) {
fprintf (stderr, "Could not initialize TinyScheme!\n");
return 2;
}
scheme_set_input_port_file (sc, stdin);
scheme_set_output_port_file (sc, stderr);
if (argc)
{
script = argv[0];
argc--, argv++;
}
err = load (sc, "init.scm", 0, 1);
if (! err)
err = load (sc, "ffi.scm", 0, 1);
if (! err)
err = ffi_init (sc, argv0, argc, (const char **) argv);
if (! err)
err = load (sc, "lib.scm", 0, 1);
if (! err)
err = load (sc, "repl.scm", 0, 1);
if (! err)
err = load (sc, "tests.scm", 0, 1);
if (err)
{
fprintf (stderr, "Error initializing gpgscm: %s.\n",
gpg_strerror (err));
exit (2);
}
if (script == NULL)
{
/* Interactive shell. */
fprintf (stderr, "gpgscm/"ts_banner".\n");
scheme_load_string (sc, "(interactive-repl)");
}
else
{
err = load (sc, script, 1, 1);
if (err)
log_fatal ("%s: %s", script, gpg_strerror (err));
}
scheme_deinit (sc);
xfree (sc);
return EXIT_SUCCESS;
}

195
tests/gpgscm/opdefines.h Normal file
View File

@ -0,0 +1,195 @@
_OP_DEF(opexe_0, "load", 1, 1, TST_STRING, OP_LOAD )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_T0LVL )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_T1LVL )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_READ_INTERNAL )
_OP_DEF(opexe_0, "gensym", 0, 0, 0, OP_GENSYM )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_VALUEPRINT )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_EVAL )
#if USE_TRACING
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_EVAL )
#endif
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_E0ARGS )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_E1ARGS )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_APPLY )
#if USE_TRACING
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_REAL_APPLY )
_OP_DEF(opexe_0, "tracing", 1, 1, TST_NATURAL, OP_TRACING )
#endif
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_DOMACRO )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LAMBDA1 )
_OP_DEF(opexe_0, "make-closure", 1, 2, TST_PAIR TST_ENVIRONMENT, OP_MKCLOSURE )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_QUOTE )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF0 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_DEF1 )
_OP_DEF(opexe_0, "defined?", 1, 2, TST_SYMBOL TST_ENVIRONMENT, OP_DEFP )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_BEGIN )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF0 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_IF1 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET0 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_SET1 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2 )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET0AST )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET1AST )
_OP_DEF(opexe_0, 0, 0, 0, 0, OP_LET2AST )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET0REC )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET1REC )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_LET2REC )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND0 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_COND1 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_DELAY )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND0 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_AND1 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR0 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_OR1 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_C0STREAM )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_C1STREAM )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO0 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_MACRO1 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE0 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE1 )
_OP_DEF(opexe_1, 0, 0, 0, 0, OP_CASE2 )
_OP_DEF(opexe_1, "eval", 1, 2, TST_ANY TST_ENVIRONMENT, OP_PEVAL )
_OP_DEF(opexe_1, "apply", 1, INF_ARG, TST_NONE, OP_PAPPLY )
_OP_DEF(opexe_1, "call-with-current-continuation", 1, 1, TST_NONE, OP_CONTINUATION )
#if USE_MATH
_OP_DEF(opexe_2, "inexact->exact", 1, 1, TST_NUMBER, OP_INEX2EX )
_OP_DEF(opexe_2, "exp", 1, 1, TST_NUMBER, OP_EXP )
_OP_DEF(opexe_2, "log", 1, 1, TST_NUMBER, OP_LOG )
_OP_DEF(opexe_2, "sin", 1, 1, TST_NUMBER, OP_SIN )
_OP_DEF(opexe_2, "cos", 1, 1, TST_NUMBER, OP_COS )
_OP_DEF(opexe_2, "tan", 1, 1, TST_NUMBER, OP_TAN )
_OP_DEF(opexe_2, "asin", 1, 1, TST_NUMBER, OP_ASIN )
_OP_DEF(opexe_2, "acos", 1, 1, TST_NUMBER, OP_ACOS )
_OP_DEF(opexe_2, "atan", 1, 2, TST_NUMBER, OP_ATAN )
_OP_DEF(opexe_2, "sqrt", 1, 1, TST_NUMBER, OP_SQRT )
_OP_DEF(opexe_2, "expt", 2, 2, TST_NUMBER, OP_EXPT )
_OP_DEF(opexe_2, "floor", 1, 1, TST_NUMBER, OP_FLOOR )
_OP_DEF(opexe_2, "ceiling", 1, 1, TST_NUMBER, OP_CEILING )
_OP_DEF(opexe_2, "truncate", 1, 1, TST_NUMBER, OP_TRUNCATE )
_OP_DEF(opexe_2, "round", 1, 1, TST_NUMBER, OP_ROUND )
#endif
_OP_DEF(opexe_2, "+", 0, INF_ARG, TST_NUMBER, OP_ADD )
_OP_DEF(opexe_2, "-", 1, INF_ARG, TST_NUMBER, OP_SUB )
_OP_DEF(opexe_2, "*", 0, INF_ARG, TST_NUMBER, OP_MUL )
_OP_DEF(opexe_2, "/", 1, INF_ARG, TST_NUMBER, OP_DIV )
_OP_DEF(opexe_2, "quotient", 1, INF_ARG, TST_INTEGER, OP_INTDIV )
_OP_DEF(opexe_2, "remainder", 2, 2, TST_INTEGER, OP_REM )
_OP_DEF(opexe_2, "modulo", 2, 2, TST_INTEGER, OP_MOD )
_OP_DEF(opexe_2, "car", 1, 1, TST_PAIR, OP_CAR )
_OP_DEF(opexe_2, "cdr", 1, 1, TST_PAIR, OP_CDR )
_OP_DEF(opexe_2, "cons", 2, 2, TST_NONE, OP_CONS )
_OP_DEF(opexe_2, "set-car!", 2, 2, TST_PAIR TST_ANY, OP_SETCAR )
_OP_DEF(opexe_2, "set-cdr!", 2, 2, TST_PAIR TST_ANY, OP_SETCDR )
_OP_DEF(opexe_2, "char->integer", 1, 1, TST_CHAR, OP_CHAR2INT )
_OP_DEF(opexe_2, "integer->char", 1, 1, TST_NATURAL, OP_INT2CHAR )
_OP_DEF(opexe_2, "char-upcase", 1, 1, TST_CHAR, OP_CHARUPCASE )
_OP_DEF(opexe_2, "char-downcase", 1, 1, TST_CHAR, OP_CHARDNCASE )
_OP_DEF(opexe_2, "symbol->string", 1, 1, TST_SYMBOL, OP_SYM2STR )
_OP_DEF(opexe_2, "atom->string", 1, 2, TST_ANY TST_NATURAL, OP_ATOM2STR )
_OP_DEF(opexe_2, "string->symbol", 1, 1, TST_STRING, OP_STR2SYM )
_OP_DEF(opexe_2, "string->atom", 1, 2, TST_STRING TST_NATURAL, OP_STR2ATOM )
_OP_DEF(opexe_2, "make-string", 1, 2, TST_NATURAL TST_CHAR, OP_MKSTRING )
_OP_DEF(opexe_2, "string-length", 1, 1, TST_STRING, OP_STRLEN )
_OP_DEF(opexe_2, "string-ref", 2, 2, TST_STRING TST_NATURAL, OP_STRREF )
_OP_DEF(opexe_2, "string-set!", 3, 3, TST_STRING TST_NATURAL TST_CHAR, OP_STRSET )
_OP_DEF(opexe_2, "string-append", 0, INF_ARG, TST_STRING, OP_STRAPPEND )
_OP_DEF(opexe_2, "substring", 2, 3, TST_STRING TST_NATURAL, OP_SUBSTR )
_OP_DEF(opexe_2, "vector", 0, INF_ARG, TST_NONE, OP_VECTOR )
_OP_DEF(opexe_2, "make-vector", 1, 2, TST_NATURAL TST_ANY, OP_MKVECTOR )
_OP_DEF(opexe_2, "vector-length", 1, 1, TST_VECTOR, OP_VECLEN )
_OP_DEF(opexe_2, "vector-ref", 2, 2, TST_VECTOR TST_NATURAL, OP_VECREF )
_OP_DEF(opexe_2, "vector-set!", 3, 3, TST_VECTOR TST_NATURAL TST_ANY, OP_VECSET )
_OP_DEF(opexe_3, "not", 1, 1, TST_NONE, OP_NOT )
_OP_DEF(opexe_3, "boolean?", 1, 1, TST_NONE, OP_BOOLP )
_OP_DEF(opexe_3, "eof-object?", 1, 1, TST_NONE, OP_EOFOBJP )
_OP_DEF(opexe_3, "null?", 1, 1, TST_NONE, OP_NULLP )
_OP_DEF(opexe_3, "=", 2, INF_ARG, TST_NUMBER, OP_NUMEQ )
_OP_DEF(opexe_3, "<", 2, INF_ARG, TST_NUMBER, OP_LESS )
_OP_DEF(opexe_3, ">", 2, INF_ARG, TST_NUMBER, OP_GRE )
_OP_DEF(opexe_3, "<=", 2, INF_ARG, TST_NUMBER, OP_LEQ )
_OP_DEF(opexe_3, ">=", 2, INF_ARG, TST_NUMBER, OP_GEQ )
_OP_DEF(opexe_3, "symbol?", 1, 1, TST_ANY, OP_SYMBOLP )
_OP_DEF(opexe_3, "number?", 1, 1, TST_ANY, OP_NUMBERP )
_OP_DEF(opexe_3, "string?", 1, 1, TST_ANY, OP_STRINGP )
_OP_DEF(opexe_3, "integer?", 1, 1, TST_ANY, OP_INTEGERP )
_OP_DEF(opexe_3, "real?", 1, 1, TST_ANY, OP_REALP )
_OP_DEF(opexe_3, "char?", 1, 1, TST_ANY, OP_CHARP )
#if USE_CHAR_CLASSIFIERS
_OP_DEF(opexe_3, "char-alphabetic?", 1, 1, TST_CHAR, OP_CHARAP )
_OP_DEF(opexe_3, "char-numeric?", 1, 1, TST_CHAR, OP_CHARNP )
_OP_DEF(opexe_3, "char-whitespace?", 1, 1, TST_CHAR, OP_CHARWP )
_OP_DEF(opexe_3, "char-upper-case?", 1, 1, TST_CHAR, OP_CHARUP )
_OP_DEF(opexe_3, "char-lower-case?", 1, 1, TST_CHAR, OP_CHARLP )
#endif
_OP_DEF(opexe_3, "port?", 1, 1, TST_ANY, OP_PORTP )
_OP_DEF(opexe_3, "input-port?", 1, 1, TST_ANY, OP_INPORTP )
_OP_DEF(opexe_3, "output-port?", 1, 1, TST_ANY, OP_OUTPORTP )
_OP_DEF(opexe_3, "procedure?", 1, 1, TST_ANY, OP_PROCP )
_OP_DEF(opexe_3, "pair?", 1, 1, TST_ANY, OP_PAIRP )
_OP_DEF(opexe_3, "list?", 1, 1, TST_ANY, OP_LISTP )
_OP_DEF(opexe_3, "environment?", 1, 1, TST_ANY, OP_ENVP )
_OP_DEF(opexe_3, "vector?", 1, 1, TST_ANY, OP_VECTORP )
_OP_DEF(opexe_3, "eq?", 2, 2, TST_ANY, OP_EQ )
_OP_DEF(opexe_3, "eqv?", 2, 2, TST_ANY, OP_EQV )
_OP_DEF(opexe_4, "force", 1, 1, TST_ANY, OP_FORCE )
_OP_DEF(opexe_4, 0, 0, 0, 0, OP_SAVE_FORCED )
_OP_DEF(opexe_4, "write", 1, 2, TST_ANY TST_OUTPORT, OP_WRITE )
_OP_DEF(opexe_4, "write-char", 1, 2, TST_CHAR TST_OUTPORT, OP_WRITE_CHAR )
_OP_DEF(opexe_4, "display", 1, 2, TST_ANY TST_OUTPORT, OP_DISPLAY )
_OP_DEF(opexe_4, "newline", 0, 1, TST_OUTPORT, OP_NEWLINE )
_OP_DEF(opexe_4, "error", 1, INF_ARG, TST_NONE, OP_ERR0 )
_OP_DEF(opexe_4, 0, 0, 0, 0, OP_ERR1 )
_OP_DEF(opexe_4, "reverse", 1, 1, TST_LIST, OP_REVERSE )
_OP_DEF(opexe_4, "list*", 1, INF_ARG, TST_NONE, OP_LIST_STAR )
_OP_DEF(opexe_4, "append", 0, INF_ARG, TST_NONE, OP_APPEND )
#if USE_PLIST
_OP_DEF(opexe_4, "put", 3, 3, TST_NONE, OP_PUT )
_OP_DEF(opexe_4, "get", 2, 2, TST_NONE, OP_GET )
#endif
_OP_DEF(opexe_4, "quit", 0, 1, TST_NUMBER, OP_QUIT )
_OP_DEF(opexe_4, "gc", 0, 0, 0, OP_GC )
_OP_DEF(opexe_4, "gc-verbose", 0, 1, TST_NONE, OP_GCVERB )
_OP_DEF(opexe_4, "new-segment", 0, 1, TST_NUMBER, OP_NEWSEGMENT )
_OP_DEF(opexe_4, "oblist", 0, 0, 0, OP_OBLIST )
_OP_DEF(opexe_4, "current-input-port", 0, 0, 0, OP_CURR_INPORT )
_OP_DEF(opexe_4, "current-output-port", 0, 0, 0, OP_CURR_OUTPORT )
_OP_DEF(opexe_4, "open-input-file", 1, 1, TST_STRING, OP_OPEN_INFILE )
_OP_DEF(opexe_4, "open-output-file", 1, 1, TST_STRING, OP_OPEN_OUTFILE )
_OP_DEF(opexe_4, "open-input-output-file", 1, 1, TST_STRING, OP_OPEN_INOUTFILE )
#if USE_STRING_PORTS
_OP_DEF(opexe_4, "open-input-string", 1, 1, TST_STRING, OP_OPEN_INSTRING )
_OP_DEF(opexe_4, "open-input-output-string", 1, 1, TST_STRING, OP_OPEN_INOUTSTRING )
_OP_DEF(opexe_4, "open-output-string", 0, 1, TST_STRING, OP_OPEN_OUTSTRING )
_OP_DEF(opexe_4, "get-output-string", 1, 1, TST_OUTPORT, OP_GET_OUTSTRING )
#endif
_OP_DEF(opexe_4, "close-input-port", 1, 1, TST_INPORT, OP_CLOSE_INPORT )
_OP_DEF(opexe_4, "close-output-port", 1, 1, TST_OUTPORT, OP_CLOSE_OUTPORT )
_OP_DEF(opexe_4, "interaction-environment", 0, 0, 0, OP_INT_ENV )
_OP_DEF(opexe_4, "current-environment", 0, 0, 0, OP_CURR_ENV )
_OP_DEF(opexe_5, "read", 0, 1, TST_INPORT, OP_READ )
_OP_DEF(opexe_5, "read-char", 0, 1, TST_INPORT, OP_READ_CHAR )
_OP_DEF(opexe_5, "peek-char", 0, 1, TST_INPORT, OP_PEEK_CHAR )
_OP_DEF(opexe_5, "char-ready?", 0, 1, TST_INPORT, OP_CHAR_READY )
_OP_DEF(opexe_5, "set-input-port", 1, 1, TST_INPORT, OP_SET_INPORT )
_OP_DEF(opexe_5, "set-output-port", 1, 1, TST_OUTPORT, OP_SET_OUTPORT )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDSEXPR )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDLIST )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDDOT )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQUOTE )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTE )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDQQUOTEVEC )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUNQUOTE )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDUQTSP )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_RDVEC )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_P0LIST )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_P1LIST )
_OP_DEF(opexe_5, 0, 0, 0, 0, OP_PVECFROM )
_OP_DEF(opexe_6, "length", 1, 1, TST_LIST, OP_LIST_LENGTH )
_OP_DEF(opexe_6, "assq", 2, 2, TST_NONE, OP_ASSQ )
_OP_DEF(opexe_6, "get-closure-code", 1, 1, TST_NONE, OP_GET_CLOSURE )
_OP_DEF(opexe_6, "closure?", 1, 1, TST_NONE, OP_CLOSUREP )
_OP_DEF(opexe_6, "macro?", 1, 1, TST_NONE, OP_MACROP )
#undef _OP_DEF

26
tests/gpgscm/private.h Normal file
View File

@ -0,0 +1,26 @@
/* TinyScheme-based test driver.
*
* Copyright (C) 2016 g10 code GmbH
*
* 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/>.
*/
#ifndef __GPGSCM_PRIVATE_H__
#define __GPGSCM_PRIVATE_H__
extern int verbose;
#endif /* __GPGSCM_PRIVATE_H__ */

50
tests/gpgscm/repl.scm Normal file
View File

@ -0,0 +1,50 @@
;; A read-evaluate-print-loop for gpgscm.
;;
;; Copyright (C) 2016 g10 Code GmbH
;;
;; 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/>.
;; Interactive repl using 'prompt' function. P must be a function
;; that given the current entered prefix returns the prompt to
;; display.
(define (repl p)
(let ((repl-environment (make-environment)))
(call/cc
(lambda (exit)
(let loop ((prefix ""))
(let ((line (prompt (p prefix))))
(if (and (not (eof-object? line)) (= 0 (string-length line)))
(exit (loop prefix)))
(if (not (eof-object? line))
(let* ((next (string-append prefix line))
(c (catch (begin (echo "Parse error:" *error*)
(loop prefix))
(read (open-input-string next)))))
(if (not (eof-object? c))
(begin
(catch (echo "Error:" *error*)
(echo " ===>" (eval c repl-environment)))
(exit (loop ""))))
(exit (loop next))))))))))
(define (prompt-append-prefix prompt prefix)
(string-append prompt (if (> (string-length prefix) 0)
(string-append prefix "...")
"> ")))
;; Default repl run by main.c.
(define (interactive-repl)
(repl (lambda (p) (prompt-append-prefix "gpgscm " p))))

View File

@ -0,0 +1,36 @@
/* TinyScheme configuration.
*
* Copyright (C) 2016 g10 code GmbH
*
* 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/>.
*/
#define STANDALONE 0
#define USE_MATH 0
#define USE_CHAR_CLASSIFIERS 1
#define USE_ASCII_NAMES 1
#define USE_STRING_PORTS 1
#define USE_ERROR_HOOK 1
#define USE_TRACING 1
#define USE_COLON_HOOK 1
#define USE_DL 0
#define USE_PLIST 0
#define USE_INTERFACE 1
#define SHOW_ERROR_LINE 1
#if __MINGW32__
# define USE_STRLWR 0
#endif /* __MINGW32__ */

Some files were not shown because too many files have changed in this diff Show More