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:
commit
4ef62278e3
2
.gitignore
vendored
2
.gitignore
vendored
@ -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
|
||||
|
9
AUTHORS
9
AUTHORS
@ -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
|
||||
=========
|
||||
|
10
acinclude.m4
10
acinclude.m4
@ -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])
|
||||
])
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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/>.
|
||||
*/
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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],
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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)
|
@ -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 */
|
@ -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
571
common/recsel.c
Normal 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
43
common/recsel.h
Normal 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*/
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -87,6 +87,8 @@ run_test (void)
|
||||
fail (idx);
|
||||
else if (strcmp (mbox, testtbl[idx].mbox))
|
||||
fail (idx);
|
||||
|
||||
xfree (mbox);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
405
common/t-recsel.c
Normal 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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,8 @@ test_strlist_rev (void)
|
||||
fail (2);
|
||||
if (s->next->next->next)
|
||||
fail (2);
|
||||
|
||||
free_strlist (s);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
242
doc/gpg.texi
242
doc/gpg.texi
@ -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
|
||||
|
||||
|
@ -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, '/');
|
||||
|
@ -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
|
||||
|
45
doc/yat2m.c
45
doc/yat2m.c
@ -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 */
|
||||
}
|
||||
}
|
||||
|
||||
|
22
g10/armor.c
22
g10/armor.c
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
934
g10/export.c
934
g10/export.c
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
|
||||
|
148
g10/getkey.c
148
g10/getkey.c
@ -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
136
g10/gpg.c
@ -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 )
|
||||
|
24
g10/gpgv.c
24
g10/gpgv.c
@ -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.
|
||||
*/
|
||||
|
507
g10/import.c
507
g10/import.c
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -937,6 +937,7 @@ keydb_release (KEYDB_HANDLE hd)
|
||||
}
|
||||
}
|
||||
|
||||
keyblock_cache_clear (hd);
|
||||
xfree (hd);
|
||||
}
|
||||
|
||||
|
22
g10/keydb.h
22
g10/keydb.h
@ -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);
|
||||
|
271
g10/keyedit.c
271
g10/keyedit.c
@ -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)
|
||||
|
23
g10/keygen.c
23
g10/keygen.c
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
15
g10/main.h
15
g10/main.h
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
10
g10/revoke.c
10
g10/revoke.c
@ -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 )
|
||||
{
|
||||
|
@ -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)
|
||||
|
16
g10/sign.c
16
g10/sign.c
@ -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);
|
||||
|
@ -59,4 +59,6 @@ do_test (int argc, char *argv[])
|
||||
|
||||
rc = keydb_get_keyblock (hd1, &kb1);
|
||||
TEST_P ("", ! rc);
|
||||
|
||||
keydb_release (hd1);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -606,5 +606,6 @@ main (int argc, char *argv[])
|
||||
log_fatal ("Message is too short, nothing to test.\n");
|
||||
}
|
||||
|
||||
xfree (filename);
|
||||
return failed;
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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*/
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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++)
|
||||
|
@ -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
214
m4/pkg.m4
Normal 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
|
@ -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;
|
||||
|
@ -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 ()
|
||||
};
|
||||
|
@ -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 \
|
||||
|
31
tests/gpgscm/LICENSE.TinySCHEME
Normal file
31
tests/gpgscm/LICENSE.TinySCHEME
Normal 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
59
tests/gpgscm/Makefile.am
Normal 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
444
tests/gpgscm/Manual.txt
Normal 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
148
tests/gpgscm/ffi-private.h
Normal 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
1283
tests/gpgscm/ffi.c
Normal file
File diff suppressed because it is too large
Load Diff
30
tests/gpgscm/ffi.h
Normal file
30
tests/gpgscm/ffi.h
Normal 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
44
tests/gpgscm/ffi.scm
Normal 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
723
tests/gpgscm/init.scm
Normal 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
159
tests/gpgscm/lib.scm
Normal 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
288
tests/gpgscm/main.c
Normal 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
195
tests/gpgscm/opdefines.h
Normal 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
26
tests/gpgscm/private.h
Normal 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
50
tests/gpgscm/repl.scm
Normal 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))))
|
36
tests/gpgscm/scheme-config.h
Normal file
36
tests/gpgscm/scheme-config.h
Normal 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
Loading…
x
Reference in New Issue
Block a user