mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
This commit was manufactured by cvs2svn to create branch
'GNUPG-1-9-BRANCH'.
This commit is contained in:
parent
a3d4ac6f3e
commit
7250331472
77 changed files with 58548 additions and 0 deletions
8238
g10/ChangeLog
Normal file
8238
g10/ChangeLog
Normal file
File diff suppressed because it is too large
Load diff
123
g10/Makefile.am
Normal file
123
g10/Makefile.am
Normal file
|
@ -0,0 +1,123 @@
|
|||
# Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
# 2003 Free Software Foundation, Inc.
|
||||
#
|
||||
# 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 2 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, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
|
||||
EXTRA_DIST = options.skel
|
||||
# it seems that we can't use this with automake 1.5
|
||||
#OMIT_DEPENDENCIES = zlib.h zconf.h
|
||||
libexecdir = @libexecdir@/@PACKAGE@
|
||||
if ! HAVE_DOSISH_SYSTEM
|
||||
AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
|
||||
endif
|
||||
needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
|
||||
|
||||
#noinst_PROGRAMS = gpgd
|
||||
bin_PROGRAMS = gpg gpgv
|
||||
|
||||
common_source = \
|
||||
global.h \
|
||||
build-packet.c \
|
||||
compress.c \
|
||||
filter.h \
|
||||
free-packet.c \
|
||||
getkey.c \
|
||||
keydb.c keydb.h \
|
||||
keyring.c keyring.h \
|
||||
seskey.c \
|
||||
kbnode.c \
|
||||
main.h \
|
||||
mainproc.c \
|
||||
armor.c \
|
||||
mdfilter.c \
|
||||
textfilter.c \
|
||||
progress.c \
|
||||
misc.c \
|
||||
options.h \
|
||||
openfile.c \
|
||||
keyid.c \
|
||||
packet.h \
|
||||
parse-packet.c \
|
||||
comment.c \
|
||||
status.c \
|
||||
status.h \
|
||||
plaintext.c \
|
||||
sig-check.c \
|
||||
keylist.c \
|
||||
signal.c
|
||||
|
||||
gpg_SOURCES = g10.c \
|
||||
$(common_source) \
|
||||
pkclist.c \
|
||||
skclist.c \
|
||||
pubkey-enc.c \
|
||||
passphrase.c \
|
||||
seckey-cert.c \
|
||||
encr-data.c \
|
||||
cipher.c \
|
||||
encode.c \
|
||||
sign.c \
|
||||
verify.c \
|
||||
revoke.c \
|
||||
decrypt.c \
|
||||
keyedit.c \
|
||||
dearmor.c \
|
||||
import.c \
|
||||
export.c \
|
||||
trustdb.c \
|
||||
trustdb.h \
|
||||
tdbdump.c \
|
||||
tdbio.c \
|
||||
tdbio.h \
|
||||
delkey.c \
|
||||
keygen.c \
|
||||
pipemode.c \
|
||||
helptext.c \
|
||||
keyserver.c \
|
||||
keyserver-internal.h \
|
||||
photoid.c photoid.h \
|
||||
exec.c exec.h
|
||||
|
||||
gpgv_SOURCES = gpgv.c \
|
||||
$(common_source) \
|
||||
verify.c
|
||||
|
||||
#gpgd_SOURCES = gpgd.c \
|
||||
# ks-proto.h \
|
||||
# ks-proto.c \
|
||||
# ks-db.c \
|
||||
# ks-db.h \
|
||||
# $(common_source)
|
||||
|
||||
LDADD = $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@
|
||||
# gpg gets LIBOBJS to add in mkdtemp if the platform doesn't have it
|
||||
gpg_LDADD = @LIBOBJS@ $(LDADD) @DLLIBS@ @EGDLIBS@
|
||||
|
||||
$(PROGRAMS): $(needed_libs)
|
||||
|
||||
install-data-local:
|
||||
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
|
||||
$(INSTALL_DATA) $(srcdir)/options.skel \
|
||||
$(DESTDIR)$(pkgdatadir)/options.skel
|
||||
@set -e;\
|
||||
if test -f $(DESTDIR)$(bindir)/gpgm ; then \
|
||||
echo "removing obsolete gpgm binary" ; \
|
||||
rm $(DESTDIR)$(bindir)/gpgm ; \
|
||||
fi
|
1336
g10/armor.c
Normal file
1336
g10/armor.c
Normal file
File diff suppressed because it is too large
Load diff
1196
g10/build-packet.c
Normal file
1196
g10/build-packet.c
Normal file
File diff suppressed because it is too large
Load diff
152
g10/cipher.c
Normal file
152
g10/cipher.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* cipher.c - En-/De-ciphering filter
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "filter.h"
|
||||
#include "packet.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
|
||||
|
||||
#define MIN_PARTIAL_SIZE 512
|
||||
|
||||
|
||||
static void
|
||||
write_header( cipher_filter_context_t *cfx, IOBUF a )
|
||||
{
|
||||
PACKET pkt;
|
||||
PKT_encrypted ed;
|
||||
byte temp[18];
|
||||
unsigned blocksize;
|
||||
unsigned nprefix;
|
||||
|
||||
blocksize = cipher_get_blocksize( cfx->dek->algo );
|
||||
if( blocksize < 8 || blocksize > 16 )
|
||||
log_fatal("unsupported blocksize %u\n", blocksize );
|
||||
|
||||
memset( &ed, 0, sizeof ed );
|
||||
ed.len = cfx->datalen;
|
||||
ed.extralen = blocksize+2;
|
||||
ed.new_ctb = !ed.len && !RFC1991;
|
||||
if( cfx->dek->use_mdc ) {
|
||||
ed.mdc_method = DIGEST_ALGO_SHA1;
|
||||
cfx->mdc_hash = md_open( DIGEST_ALGO_SHA1, 0 );
|
||||
if ( DBG_HASHING )
|
||||
md_start_debug( cfx->mdc_hash, "creatmdc" );
|
||||
}
|
||||
|
||||
{
|
||||
char buf[20];
|
||||
|
||||
sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo);
|
||||
write_status_text (STATUS_BEGIN_ENCRYPTION, buf);
|
||||
}
|
||||
|
||||
init_packet( &pkt );
|
||||
pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
|
||||
pkt.pkt.encrypted = &ed;
|
||||
if( build_packet( a, &pkt ))
|
||||
log_bug("build_packet(ENCR_DATA) failed\n");
|
||||
nprefix = blocksize;
|
||||
randomize_buffer( temp, nprefix, 1 );
|
||||
temp[nprefix] = temp[nprefix-2];
|
||||
temp[nprefix+1] = temp[nprefix-1];
|
||||
print_cipher_algo_note( cfx->dek->algo );
|
||||
cfx->cipher_hd = cipher_open( cfx->dek->algo,
|
||||
cfx->dek->use_mdc? CIPHER_MODE_CFB
|
||||
: CIPHER_MODE_AUTO_CFB, 1 );
|
||||
/* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/
|
||||
cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
|
||||
cipher_setiv( cfx->cipher_hd, NULL, 0 );
|
||||
/* log_hexdump( "prefix", temp, nprefix+2 ); */
|
||||
if( cfx->mdc_hash ) /* hash the "IV" */
|
||||
md_write( cfx->mdc_hash, temp, nprefix+2 );
|
||||
cipher_encrypt( cfx->cipher_hd, temp, temp, nprefix+2);
|
||||
cipher_sync( cfx->cipher_hd );
|
||||
iobuf_write(a, temp, nprefix+2);
|
||||
cfx->header=1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* This filter is used to en/de-cipher data with a conventional algorithm
|
||||
*/
|
||||
int
|
||||
cipher_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
cipher_filter_context_t *cfx = opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
|
||||
rc = -1; /* not yet used */
|
||||
}
|
||||
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
|
||||
assert(a);
|
||||
if( !cfx->header ) {
|
||||
write_header( cfx, a );
|
||||
}
|
||||
if( cfx->mdc_hash )
|
||||
md_write( cfx->mdc_hash, buf, size );
|
||||
cipher_encrypt( cfx->cipher_hd, buf, buf, size);
|
||||
if( iobuf_write( a, buf, size ) )
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
if( cfx->mdc_hash ) {
|
||||
byte *hash;
|
||||
int hashlen = md_digest_length( md_get_algo( cfx->mdc_hash ) );
|
||||
byte temp[22];
|
||||
|
||||
assert( hashlen == 20 );
|
||||
/* we must hash the prefix of the MDC packet here */
|
||||
temp[0] = 0xd3;
|
||||
temp[1] = 0x14;
|
||||
md_putc( cfx->mdc_hash, temp[0] );
|
||||
md_putc( cfx->mdc_hash, temp[1] );
|
||||
|
||||
md_final( cfx->mdc_hash );
|
||||
hash = md_read( cfx->mdc_hash, 0 );
|
||||
memcpy(temp+2, hash, 20);
|
||||
cipher_encrypt( cfx->cipher_hd, temp, temp, 22 );
|
||||
md_close( cfx->mdc_hash ); cfx->mdc_hash = NULL;
|
||||
if( iobuf_write( a, temp, 22 ) )
|
||||
log_error("writing MDC packet failed\n" );
|
||||
}
|
||||
cipher_close(cfx->cipher_hd);
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC ) {
|
||||
*(char**)buf = "cipher_filter";
|
||||
}
|
||||
return rc;
|
||||
}
|
324
g10/compress.c
Normal file
324
g10/compress.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
/* compress.c - compress filter
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <zlib.h>
|
||||
#ifdef __riscos__
|
||||
# include "zlib-riscos.h"
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "packet.h"
|
||||
#include "filter.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
|
||||
static void
|
||||
init_compress( compress_filter_context_t *zfx, z_stream *zs )
|
||||
{
|
||||
int rc;
|
||||
int level;
|
||||
|
||||
#ifdef __riscos__
|
||||
static int zlib_initialized = 0;
|
||||
|
||||
if (!zlib_initialized)
|
||||
zlib_initialized = riscos_load_module("ZLib", zlib_path, 1);
|
||||
#endif
|
||||
|
||||
if( opt.compress >= 0 && opt.compress <= 9 )
|
||||
level = opt.compress;
|
||||
else if( opt.compress == -1 )
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
else if( opt.compress == 10 ) /* remove this ! */
|
||||
level = 0;
|
||||
else {
|
||||
log_error("invalid compression level; using default level\n");
|
||||
level = Z_DEFAULT_COMPRESSION;
|
||||
}
|
||||
|
||||
|
||||
if( (rc = zfx->algo == 1? deflateInit2( zs, level, Z_DEFLATED,
|
||||
-13, 8, Z_DEFAULT_STRATEGY)
|
||||
: deflateInit( zs, level )
|
||||
) != Z_OK ) {
|
||||
log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
|
||||
rc == Z_MEM_ERROR ? "out of core" :
|
||||
rc == Z_VERSION_ERROR ? "invalid lib version" :
|
||||
"unknown error" );
|
||||
}
|
||||
|
||||
zfx->outbufsize = 8192;
|
||||
zfx->outbuf = m_alloc( zfx->outbufsize );
|
||||
}
|
||||
|
||||
static int
|
||||
do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
|
||||
{
|
||||
int zrc;
|
||||
unsigned n;
|
||||
|
||||
do {
|
||||
#ifndef __riscos__
|
||||
zs->next_out = zfx->outbuf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_out = (Bytef *) zfx->outbuf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_out = zfx->outbufsize;
|
||||
if( DBG_FILTER )
|
||||
log_debug("enter deflate: avail_in=%u, avail_out=%u, flush=%d\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out, flush );
|
||||
zrc = deflate( zs, flush );
|
||||
if( zrc == Z_STREAM_END && flush == Z_FINISH )
|
||||
;
|
||||
else if( zrc != Z_OK ) {
|
||||
if( zs->msg )
|
||||
log_fatal("zlib deflate problem: %s\n", zs->msg );
|
||||
else
|
||||
log_fatal("zlib deflate problem: rc=%d\n", zrc );
|
||||
}
|
||||
n = zfx->outbufsize - zs->avail_out;
|
||||
if( DBG_FILTER )
|
||||
log_debug("leave deflate: "
|
||||
"avail_in=%u, avail_out=%u, n=%u, zrc=%d\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out,
|
||||
(unsigned)n, zrc );
|
||||
|
||||
if( iobuf_write( a, zfx->outbuf, n ) ) {
|
||||
log_debug("deflate: iobuf_write failed\n");
|
||||
return G10ERR_WRITE_FILE;
|
||||
}
|
||||
} while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
|
||||
{
|
||||
int rc;
|
||||
|
||||
/****************
|
||||
* PGP uses a windowsize of 13 bits. Using a negative value for
|
||||
* it forces zlib not to expect a zlib header. This is a
|
||||
* undocumented feature Peter Gutmann told me about.
|
||||
*
|
||||
* We must use 15 bits for the inflator because CryptoEx uses 15
|
||||
* bits thus the output would get scrambled w/o error indication
|
||||
* if we would use 13 bits. For the uncompressing this does not
|
||||
* matter at all.
|
||||
*/
|
||||
if( (rc = zfx->algo == 1? inflateInit2( zs, -15)
|
||||
: inflateInit( zs )) != Z_OK ) {
|
||||
log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
|
||||
rc == Z_MEM_ERROR ? "out of core" :
|
||||
rc == Z_VERSION_ERROR ? "invalid lib version" :
|
||||
"unknown error" );
|
||||
}
|
||||
|
||||
zfx->inbufsize = 2048;
|
||||
zfx->inbuf = m_alloc( zfx->inbufsize );
|
||||
zs->avail_in = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
|
||||
IOBUF a, size_t *ret_len )
|
||||
{
|
||||
int zrc;
|
||||
int rc=0;
|
||||
size_t n;
|
||||
int nread, count;
|
||||
int refill = !zs->avail_in;
|
||||
|
||||
if( DBG_FILTER )
|
||||
log_debug("begin inflate: avail_in=%u, avail_out=%u, inbuf=%u\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out,
|
||||
(unsigned)zfx->inbufsize );
|
||||
do {
|
||||
if( zs->avail_in < zfx->inbufsize && refill ) {
|
||||
n = zs->avail_in;
|
||||
if( !n )
|
||||
#ifndef __riscos__
|
||||
zs->next_in = zfx->inbuf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_in = (Bytef *) zfx->inbuf;
|
||||
#endif /* __riscos__ */
|
||||
count = zfx->inbufsize - n;
|
||||
nread = iobuf_read( a, zfx->inbuf + n, count );
|
||||
if( nread == -1 ) nread = 0;
|
||||
n += nread;
|
||||
/* If we use the undocumented feature to suppress
|
||||
* the zlib header, we have to give inflate an
|
||||
* extra dummy byte to read */
|
||||
if( nread < count && zfx->algo == 1 ) {
|
||||
*(zfx->inbuf + n) = 0xFF; /* is it really needed ? */
|
||||
zfx->algo1hack = 1;
|
||||
n++;
|
||||
}
|
||||
zs->avail_in = n;
|
||||
}
|
||||
refill = 1;
|
||||
if( DBG_FILTER )
|
||||
log_debug("enter inflate: avail_in=%u, avail_out=%u\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out);
|
||||
#ifdef Z_SYNC_FLUSH
|
||||
zrc = inflate( zs, Z_SYNC_FLUSH );
|
||||
#else
|
||||
zrc = inflate( zs, Z_PARTIAL_FLUSH );
|
||||
#endif
|
||||
if( DBG_FILTER )
|
||||
log_debug("leave inflate: avail_in=%u, avail_out=%u, zrc=%d\n",
|
||||
(unsigned)zs->avail_in, (unsigned)zs->avail_out, zrc);
|
||||
if( zrc == Z_STREAM_END )
|
||||
rc = -1; /* eof */
|
||||
else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
|
||||
if( zs->msg )
|
||||
log_fatal("zlib inflate problem: %s\n", zs->msg );
|
||||
else
|
||||
log_fatal("zlib inflate problem: rc=%d\n", zrc );
|
||||
}
|
||||
} while( zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR );
|
||||
*ret_len = zfx->outbufsize - zs->avail_out;
|
||||
if( DBG_FILTER )
|
||||
log_debug("do_uncompress: returning %u bytes\n", (unsigned)*ret_len );
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
compress_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
compress_filter_context_t *zfx = opaque;
|
||||
z_stream *zs = zfx->opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) {
|
||||
if( !zfx->status ) {
|
||||
zs = zfx->opaque = m_alloc_clear( sizeof *zs );
|
||||
init_uncompress( zfx, zs );
|
||||
zfx->status = 1;
|
||||
}
|
||||
|
||||
#ifndef __riscos__
|
||||
zs->next_out = buf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_out = (Bytef *) buf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_out = size;
|
||||
zfx->outbufsize = size; /* needed only for calculation */
|
||||
rc = do_uncompress( zfx, zs, a, ret_len );
|
||||
}
|
||||
else if( control == IOBUFCTRL_FLUSH ) {
|
||||
if( !zfx->status ) {
|
||||
PACKET pkt;
|
||||
PKT_compressed cd;
|
||||
|
||||
if( !zfx->algo )
|
||||
zfx->algo = DEFAULT_COMPRESS_ALGO;
|
||||
if( zfx->algo != 1 && zfx->algo != 2 )
|
||||
BUG();
|
||||
memset( &cd, 0, sizeof cd );
|
||||
cd.len = 0;
|
||||
cd.algorithm = zfx->algo;
|
||||
init_packet( &pkt );
|
||||
pkt.pkttype = PKT_COMPRESSED;
|
||||
pkt.pkt.compressed = &cd;
|
||||
if( build_packet( a, &pkt ))
|
||||
log_bug("build_packet(PKT_COMPRESSED) failed\n");
|
||||
zs = zfx->opaque = m_alloc_clear( sizeof *zs );
|
||||
init_compress( zfx, zs );
|
||||
zfx->status = 2;
|
||||
}
|
||||
|
||||
#ifndef __riscos__
|
||||
zs->next_in = buf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_in = (Bytef *) buf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_in = size;
|
||||
rc = do_compress( zfx, zs, Z_NO_FLUSH, a );
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
if( zfx->status == 1 ) {
|
||||
inflateEnd(zs);
|
||||
m_free(zs);
|
||||
zfx->opaque = NULL;
|
||||
m_free(zfx->outbuf); zfx->outbuf = NULL;
|
||||
}
|
||||
else if( zfx->status == 2 ) {
|
||||
#ifndef __riscos__
|
||||
zs->next_in = buf;
|
||||
#else /* __riscos__ */
|
||||
zs->next_in = (Bytef *) buf;
|
||||
#endif /* __riscos__ */
|
||||
zs->avail_in = 0;
|
||||
do_compress( zfx, zs, Z_FINISH, a );
|
||||
deflateEnd(zs);
|
||||
m_free(zs);
|
||||
zfx->opaque = NULL;
|
||||
m_free(zfx->outbuf); zfx->outbuf = NULL;
|
||||
}
|
||||
if (zfx->release)
|
||||
zfx->release (zfx);
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC )
|
||||
*(char**)buf = "compress_filter";
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
release_context (compress_filter_context_t *ctx)
|
||||
{
|
||||
m_free (ctx);
|
||||
}
|
||||
|
||||
/****************
|
||||
* Handle a compressed packet
|
||||
*/
|
||||
int
|
||||
handle_compressed( void *procctx, PKT_compressed *cd,
|
||||
int (*callback)(IOBUF, void *), void *passthru )
|
||||
{
|
||||
compress_filter_context_t *cfx;
|
||||
int rc;
|
||||
|
||||
if( cd->algorithm < 1 || cd->algorithm > 2 )
|
||||
return G10ERR_COMPR_ALGO;
|
||||
cfx = m_alloc_clear (sizeof *cfx);
|
||||
cfx->algo = cd->algorithm;
|
||||
cfx->release = release_context;
|
||||
iobuf_push_filter( cd->buf, compress_filter, cfx );
|
||||
if( callback )
|
||||
rc = callback(cd->buf, passthru );
|
||||
else
|
||||
rc = proc_packets(procctx, cd->buf);
|
||||
cd->buf = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
141
g10/decrypt.c
Normal file
141
g10/decrypt.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/* decrypt.c - verify signed data
|
||||
* Copyright (C) 1998,1999,2000,2001,2002,2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Assume that the input is an encrypted message and decrypt
|
||||
* (and if signed, verify the signature on) it.
|
||||
* This command differs from the default operation, as it never
|
||||
* writes to the filename which is included in the file and it
|
||||
* rejects files which don't begin with an encrypted message.
|
||||
*/
|
||||
|
||||
int
|
||||
decrypt_message( const char *filename )
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
int rc;
|
||||
int no_out=0;
|
||||
|
||||
/* open the message file */
|
||||
fp = iobuf_open(filename);
|
||||
if( !fp ) {
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(filename));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
|
||||
handle_progress (&pfx, fp, filename);
|
||||
|
||||
if( !opt.no_armor ) {
|
||||
if( use_armor_filter( fp ) ) {
|
||||
memset( &afx, 0, sizeof afx);
|
||||
iobuf_push_filter( fp, armor_filter, &afx );
|
||||
}
|
||||
}
|
||||
|
||||
if( !opt.outfile ) {
|
||||
no_out = 1;
|
||||
opt.outfile = "-";
|
||||
}
|
||||
rc = proc_encryption_packets( NULL, fp );
|
||||
if( no_out )
|
||||
opt.outfile = NULL;
|
||||
iobuf_close(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
decrypt_messages(int nfiles, char **files)
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
char *p, *output = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (opt.outfile)
|
||||
{
|
||||
log_error(_("--output doesn't work for this command\n"));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
while (nfiles--)
|
||||
{
|
||||
print_file_status(STATUS_FILE_START, *files, 3);
|
||||
output = make_outfile_name(*files);
|
||||
if (!output)
|
||||
goto next_file;
|
||||
fp = iobuf_open(*files);
|
||||
if (!fp)
|
||||
{
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(*files));
|
||||
goto next_file;
|
||||
}
|
||||
|
||||
handle_progress (&pfx, fp, *files);
|
||||
|
||||
if (!opt.no_armor)
|
||||
{
|
||||
if (use_armor_filter(fp))
|
||||
{
|
||||
memset(&afx, 0, sizeof afx);
|
||||
iobuf_push_filter(fp, armor_filter, &afx);
|
||||
}
|
||||
}
|
||||
rc = proc_packets(NULL, fp);
|
||||
iobuf_close(fp);
|
||||
if (rc)
|
||||
log_error("%s: decryption failed: %s\n", print_fname_stdin(*files),
|
||||
g10_errstr(rc));
|
||||
p = get_last_passphrase();
|
||||
set_next_passphrase(p);
|
||||
m_free (p);
|
||||
|
||||
next_file:
|
||||
/* Note that we emit file_done even after an error. */
|
||||
write_status( STATUS_FILE_DONE );
|
||||
m_free(output);
|
||||
files++;
|
||||
}
|
||||
set_next_passphrase(NULL);
|
||||
}
|
||||
|
811
g10/encode.c
Normal file
811
g10/encode.c
Normal file
|
@ -0,0 +1,811 @@
|
|||
/* encode.c - encode data
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
* 2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "filter.h"
|
||||
#include "trustdb.h"
|
||||
#include "i18n.h"
|
||||
#include "status.h"
|
||||
|
||||
static int encode_simple( const char *filename, int mode, int compat );
|
||||
static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out );
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Encode FILENAME with only the symmetric cipher. Take input from
|
||||
* stdin if FILENAME is NULL.
|
||||
*/
|
||||
int
|
||||
encode_symmetric( const char *filename )
|
||||
{
|
||||
int compat = 1;
|
||||
|
||||
#if 0
|
||||
/* We don't want to use it because older gnupg version can't
|
||||
handle it and we can presume that a lot of scripts are running
|
||||
with the expert mode set. Some time in the future we might
|
||||
want to allow for it. */
|
||||
if ( opt.expert )
|
||||
compat = 0; /* PGP knows how to handle this mode. */
|
||||
#endif
|
||||
return encode_simple( filename, 1, compat );
|
||||
}
|
||||
|
||||
/****************
|
||||
* Encode FILENAME as a literal data packet only. Take input from
|
||||
* stdin if FILENAME is NULL.
|
||||
*/
|
||||
int
|
||||
encode_store( const char *filename )
|
||||
{
|
||||
return encode_simple( filename, 0, 1 );
|
||||
}
|
||||
|
||||
static void
|
||||
encode_sesskey( DEK *dek, DEK **ret_dek, byte *enckey )
|
||||
{
|
||||
CIPHER_HANDLE hd;
|
||||
DEK *c;
|
||||
byte buf[33];
|
||||
|
||||
assert ( dek->keylen < 32 );
|
||||
|
||||
c = m_alloc_clear( sizeof *c );
|
||||
c->keylen = dek->keylen;
|
||||
c->algo = dek->algo;
|
||||
make_session_key( c );
|
||||
/*log_hexdump( "thekey", c->key, c->keylen );*/
|
||||
|
||||
buf[0] = c->algo;
|
||||
memcpy( buf + 1, c->key, c->keylen );
|
||||
|
||||
hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
|
||||
cipher_setkey( hd, dek->key, dek->keylen );
|
||||
cipher_setiv( hd, NULL, 0 );
|
||||
cipher_encrypt( hd, buf, buf, c->keylen + 1 );
|
||||
cipher_close( hd );
|
||||
|
||||
memcpy( enckey, buf, c->keylen + 1 );
|
||||
wipememory( buf, sizeof buf ); /* burn key */
|
||||
*ret_dek = c;
|
||||
}
|
||||
|
||||
/* We try very hard to use a MDC */
|
||||
static int
|
||||
use_mdc(PK_LIST pk_list,int algo)
|
||||
{
|
||||
/* --force-mdc overrides --disable-mdc */
|
||||
if(opt.force_mdc)
|
||||
return 1;
|
||||
|
||||
if(opt.disable_mdc)
|
||||
return 0;
|
||||
|
||||
/* Do the keys really support MDC? */
|
||||
|
||||
if(select_mdc_from_pklist(pk_list))
|
||||
return 1;
|
||||
|
||||
/* The keys don't support MDC, so now we do a bit of a hack - if any
|
||||
of the AESes or TWOFISH are in the prefs, we assume that the user
|
||||
can handle a MDC. This is valid for PGP 7, which can handle MDCs
|
||||
though it will not generate them. 2440bis allows this, by the
|
||||
way. */
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_AES,NULL)==CIPHER_ALGO_AES)
|
||||
return 1;
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_AES192,NULL)==CIPHER_ALGO_AES192)
|
||||
return 1;
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_AES256,NULL)==CIPHER_ALGO_AES256)
|
||||
return 1;
|
||||
|
||||
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
CIPHER_ALGO_TWOFISH,NULL)==CIPHER_ALGO_TWOFISH)
|
||||
return 1;
|
||||
|
||||
/* Last try. Use MDC for the modern ciphers. */
|
||||
|
||||
if(cipher_get_blocksize(algo)!=8)
|
||||
return 1;
|
||||
|
||||
return 0; /* No MDC */
|
||||
}
|
||||
|
||||
static int
|
||||
encode_simple( const char *filename, int mode, int compat )
|
||||
{
|
||||
IOBUF inp, out;
|
||||
PACKET pkt;
|
||||
DEK *dek = NULL;
|
||||
PKT_plaintext *pt = NULL;
|
||||
STRING2KEY *s2k = NULL;
|
||||
byte enckey[33];
|
||||
int rc = 0;
|
||||
int seskeylen = 0;
|
||||
u32 filesize;
|
||||
cipher_filter_context_t cfx;
|
||||
armor_filter_context_t afx;
|
||||
compress_filter_context_t zfx;
|
||||
text_filter_context_t tfx;
|
||||
progress_filter_context_t pfx;
|
||||
int do_compress = opt.compress && !RFC1991;
|
||||
|
||||
memset( &cfx, 0, sizeof cfx);
|
||||
memset( &afx, 0, sizeof afx);
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
memset( &tfx, 0, sizeof tfx);
|
||||
init_packet(&pkt);
|
||||
|
||||
/* prepare iobufs */
|
||||
if( !(inp = iobuf_open(filename)) ) {
|
||||
log_error(_("%s: can't open: %s\n"), filename? filename: "[stdin]",
|
||||
strerror(errno) );
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
|
||||
handle_progress (&pfx, inp, filename);
|
||||
|
||||
if( opt.textmode )
|
||||
iobuf_push_filter( inp, text_filter, &tfx );
|
||||
|
||||
/* Due the the fact that we use don't use an IV to encrypt the
|
||||
session key we can't use the new mode with RFC1991 because
|
||||
it has no S2K salt. RFC1991 always uses simple S2K. */
|
||||
if ( RFC1991 && !compat )
|
||||
compat = 1;
|
||||
|
||||
cfx.dek = NULL;
|
||||
if( mode ) {
|
||||
s2k = m_alloc_clear( sizeof *s2k );
|
||||
s2k->mode = RFC1991? 0:opt.s2k_mode;
|
||||
s2k->hash_algo = opt.s2k_digest_algo;
|
||||
cfx.dek = passphrase_to_dek( NULL, 0,
|
||||
default_cipher_algo(), s2k, 2,
|
||||
NULL, NULL);
|
||||
if( !cfx.dek || !cfx.dek->keylen ) {
|
||||
rc = G10ERR_PASSPHRASE;
|
||||
m_free(cfx.dek);
|
||||
m_free(s2k);
|
||||
iobuf_close(inp);
|
||||
log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
if (!compat && s2k->mode != 1 && s2k->mode != 3) {
|
||||
compat = 1;
|
||||
log_info (_("can't use a symmetric ESK packet "
|
||||
"due to the S2K mode\n"));
|
||||
}
|
||||
|
||||
if ( !compat ) {
|
||||
seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
|
||||
encode_sesskey( cfx.dek, &dek, enckey );
|
||||
m_free( cfx.dek ); cfx.dek = dek;
|
||||
}
|
||||
|
||||
cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
|
||||
}
|
||||
|
||||
if (opt.compress == -1 && cfx.dek && cfx.dek->use_mdc &&
|
||||
is_file_compressed(filename, &rc))
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info(_("`%s' already compressed\n"), filename);
|
||||
do_compress = 0;
|
||||
}
|
||||
|
||||
if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
|
||||
iobuf_cancel(inp);
|
||||
m_free(cfx.dek);
|
||||
m_free(s2k);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if( opt.armor )
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
#ifdef ENABLE_COMMENT_PACKETS
|
||||
else {
|
||||
write_comment( out, "#created by GNUPG v" VERSION " ("
|
||||
PRINTABLE_OS_NAME ")");
|
||||
if( opt.comment_string )
|
||||
write_comment( out, opt.comment_string );
|
||||
}
|
||||
#endif
|
||||
if( s2k && !RFC1991 ) {
|
||||
PKT_symkey_enc *enc = m_alloc_clear( sizeof *enc + seskeylen + 1 );
|
||||
enc->version = 4;
|
||||
enc->cipher_algo = cfx.dek->algo;
|
||||
enc->s2k = *s2k;
|
||||
if ( !compat && seskeylen ) {
|
||||
enc->seskeylen = seskeylen + 1; /* algo id */
|
||||
memcpy( enc->seskey, enckey, seskeylen + 1 );
|
||||
}
|
||||
pkt.pkttype = PKT_SYMKEY_ENC;
|
||||
pkt.pkt.symkey_enc = enc;
|
||||
if( (rc = build_packet( out, &pkt )) )
|
||||
log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
|
||||
m_free(enc);
|
||||
}
|
||||
|
||||
if (!opt.no_literal) {
|
||||
/* setup the inner packet */
|
||||
if( filename || opt.set_filename ) {
|
||||
char *s = make_basename( opt.set_filename ? opt.set_filename
|
||||
: filename,
|
||||
iobuf_get_real_fname( inp ) );
|
||||
pt = m_alloc( sizeof *pt + strlen(s) - 1 );
|
||||
pt->namelen = strlen(s);
|
||||
memcpy(pt->name, s, pt->namelen );
|
||||
m_free(s);
|
||||
}
|
||||
else { /* no filename */
|
||||
pt = m_alloc( sizeof *pt - 1 );
|
||||
pt->namelen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note that PGP 5 has problems decrypting symmetrically encrypted
|
||||
data if the file length is in the inner packet. It works when
|
||||
only partial length headers are use. In the past, we always
|
||||
used partial body length here, but since PGP 2, PGP 6, and PGP
|
||||
7 need the file length, and nobody should be using PGP 5
|
||||
nowadays anyway, this is now set to the file length. Note also
|
||||
that this only applies to the RFC-1991 style symmetric
|
||||
messages, and not the RFC-2440 style. PGP 6 and 7 work with
|
||||
either partial length or fixed length with the new style
|
||||
messages. */
|
||||
|
||||
if (filename && *filename && !(*filename == '-' && !filename[1])
|
||||
&& !opt.textmode ) {
|
||||
off_t tmpsize;
|
||||
|
||||
if ( !(tmpsize = iobuf_get_filelength(inp)) )
|
||||
log_info(_("%s: WARNING: empty file\n"), filename );
|
||||
/* We can't encode the length of very large files because
|
||||
OpenPGP uses only 32 bit for file sizes. So if the the
|
||||
size of a file is larger than 2^32 minus some bytes for
|
||||
packet headers, we switch to partial length encoding. */
|
||||
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
|
||||
filesize = tmpsize;
|
||||
else
|
||||
filesize = 0;
|
||||
}
|
||||
else
|
||||
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
|
||||
|
||||
if (!opt.no_literal) {
|
||||
pt->timestamp = make_timestamp();
|
||||
pt->mode = opt.textmode? 't' : 'b';
|
||||
pt->len = filesize;
|
||||
pt->new_ctb = !pt->len && !RFC1991;
|
||||
pt->buf = inp;
|
||||
pkt.pkttype = PKT_PLAINTEXT;
|
||||
pkt.pkt.plaintext = pt;
|
||||
cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cfx.datalen = filesize && !do_compress ? filesize : 0;
|
||||
pkt.pkttype = 0;
|
||||
pkt.pkt.generic = NULL;
|
||||
}
|
||||
|
||||
/* register the cipher filter */
|
||||
if( mode )
|
||||
iobuf_push_filter( out, cipher_filter, &cfx );
|
||||
/* register the compress filter */
|
||||
if( do_compress )
|
||||
{
|
||||
if (cfx.dek && cfx.dek->use_mdc)
|
||||
zfx.new_ctb = 1;
|
||||
zfx.algo=default_compress_algo();
|
||||
iobuf_push_filter( out, compress_filter, &zfx );
|
||||
}
|
||||
|
||||
/* do the work */
|
||||
if (!opt.no_literal) {
|
||||
if( (rc = build_packet( out, &pkt )) )
|
||||
log_error("build_packet failed: %s\n", g10_errstr(rc) );
|
||||
}
|
||||
else {
|
||||
/* user requested not to create a literal packet,
|
||||
* so we copy the plain data */
|
||||
byte copy_buffer[4096];
|
||||
int bytes_copied;
|
||||
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
|
||||
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
log_error("copying input to output failed: %s\n", g10_errstr(rc) );
|
||||
break;
|
||||
}
|
||||
wipememory(copy_buffer, 4096); /* burn buffer */
|
||||
}
|
||||
|
||||
/* finish the stuff */
|
||||
iobuf_close(inp);
|
||||
if (rc)
|
||||
iobuf_cancel(out);
|
||||
else {
|
||||
iobuf_close(out); /* fixme: check returncode */
|
||||
if (mode)
|
||||
write_status( STATUS_END_ENCRYPTION );
|
||||
}
|
||||
if (pt)
|
||||
pt->buf = NULL;
|
||||
free_packet(&pkt);
|
||||
m_free(cfx.dek);
|
||||
m_free(s2k);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Encrypt the file with the given userids (or ask if none
|
||||
* is supplied).
|
||||
*/
|
||||
int
|
||||
encode_crypt( const char *filename, STRLIST remusr )
|
||||
{
|
||||
IOBUF inp = NULL, out = NULL;
|
||||
PACKET pkt;
|
||||
PKT_plaintext *pt = NULL;
|
||||
int rc = 0, rc2 = 0;
|
||||
u32 filesize;
|
||||
cipher_filter_context_t cfx;
|
||||
armor_filter_context_t afx;
|
||||
compress_filter_context_t zfx;
|
||||
text_filter_context_t tfx;
|
||||
progress_filter_context_t pfx;
|
||||
PK_LIST pk_list,work_list;
|
||||
int do_compress = opt.compress && !RFC1991;
|
||||
|
||||
|
||||
memset( &cfx, 0, sizeof cfx);
|
||||
memset( &afx, 0, sizeof afx);
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
memset( &tfx, 0, sizeof tfx);
|
||||
init_packet(&pkt);
|
||||
|
||||
if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
|
||||
return rc;
|
||||
|
||||
if(PGP2) {
|
||||
for(work_list=pk_list; work_list; work_list=work_list->next)
|
||||
if(!(is_RSA(work_list->pk->pubkey_algo) &&
|
||||
nbits_from_pk(work_list->pk)<=2048))
|
||||
{
|
||||
log_info(_("you can only encrypt to RSA keys of 2048 bits or "
|
||||
"less in --pgp2 mode\n"));
|
||||
compliance_failure();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare iobufs */
|
||||
if( !(inp = iobuf_open(filename)) ) {
|
||||
log_error(_("can't open %s: %s\n"), filename? filename: "[stdin]",
|
||||
strerror(errno) );
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
goto leave;
|
||||
}
|
||||
else if( opt.verbose )
|
||||
log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
|
||||
|
||||
handle_progress (&pfx, inp, filename);
|
||||
|
||||
if( opt.textmode )
|
||||
iobuf_push_filter( inp, text_filter, &tfx );
|
||||
|
||||
if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
|
||||
goto leave;
|
||||
|
||||
|
||||
if( opt.armor )
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
#ifdef ENABLE_COMMENT_PACKETS
|
||||
else {
|
||||
write_comment( out, "#created by GNUPG v" VERSION " ("
|
||||
PRINTABLE_OS_NAME ")");
|
||||
if( opt.comment_string )
|
||||
write_comment( out, opt.comment_string );
|
||||
}
|
||||
#endif
|
||||
/* create a session key */
|
||||
cfx.dek = m_alloc_secure_clear (sizeof *cfx.dek);
|
||||
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
|
||||
cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL);
|
||||
/* The only way select_algo_from_prefs can fail here is when
|
||||
mixing v3 and v4 keys, as v4 keys have an implicit
|
||||
preference entry for 3DES, and the pk_list cannot be empty.
|
||||
In this case, use 3DES anyway as it's the safest choice -
|
||||
perhaps the v3 key is being used in an OpenPGP
|
||||
implementation and we know that the implementation behind
|
||||
any v4 key can handle 3DES. */
|
||||
if( cfx.dek->algo == -1 ) {
|
||||
cfx.dek->algo = CIPHER_ALGO_3DES;
|
||||
|
||||
if( PGP2 ) {
|
||||
log_info(_("unable to use the IDEA cipher for all of the keys "
|
||||
"you are encrypting to.\n"));
|
||||
compliance_failure();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!opt.expert &&
|
||||
select_algo_from_prefs(pk_list,PREFTYPE_SYM,
|
||||
opt.def_cipher_algo,NULL)!=opt.def_cipher_algo)
|
||||
log_info(_("forcing symmetric cipher %s (%d) "
|
||||
"violates recipient preferences\n"),
|
||||
cipher_algo_to_string(opt.def_cipher_algo),
|
||||
opt.def_cipher_algo);
|
||||
|
||||
cfx.dek->algo = opt.def_cipher_algo;
|
||||
}
|
||||
|
||||
cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo);
|
||||
|
||||
/* Only do the is-file-already-compressed check if we are using a
|
||||
MDC. This forces compressed files to be re-compressed if we do
|
||||
not have a MDC to give some protection against chosen
|
||||
ciphertext attacks. */
|
||||
|
||||
if (opt.compress == -1 && cfx.dek->use_mdc &&
|
||||
is_file_compressed(filename, &rc2) )
|
||||
{
|
||||
if (opt.verbose)
|
||||
log_info(_("`%s' already compressed\n"), filename);
|
||||
do_compress = 0;
|
||||
}
|
||||
if (rc2)
|
||||
{
|
||||
rc = rc2;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
make_session_key( cfx.dek );
|
||||
if( DBG_CIPHER )
|
||||
log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
|
||||
|
||||
rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
|
||||
if( rc )
|
||||
goto leave;
|
||||
|
||||
if (!opt.no_literal) {
|
||||
/* setup the inner packet */
|
||||
if( filename || opt.set_filename ) {
|
||||
char *s = make_basename( opt.set_filename ? opt.set_filename
|
||||
: filename,
|
||||
iobuf_get_real_fname( inp ) );
|
||||
pt = m_alloc( sizeof *pt + strlen(s) - 1 );
|
||||
pt->namelen = strlen(s);
|
||||
memcpy(pt->name, s, pt->namelen );
|
||||
m_free(s);
|
||||
}
|
||||
else { /* no filename */
|
||||
pt = m_alloc( sizeof *pt - 1 );
|
||||
pt->namelen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (filename && *filename && !(*filename == '-' && !filename[1])
|
||||
&& !opt.textmode ) {
|
||||
off_t tmpsize;
|
||||
|
||||
if ( !(tmpsize = iobuf_get_filelength(inp)) )
|
||||
log_info(_("%s: WARNING: empty file\n"), filename );
|
||||
/* We can't encode the length of very large files because
|
||||
OpenPGP uses only 32 bit for file sizes. So if the the
|
||||
size of a file is larger than 2^32 minus some bytes for
|
||||
packet headers, we switch to partial length encoding. */
|
||||
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
|
||||
filesize = tmpsize;
|
||||
else
|
||||
filesize = 0;
|
||||
}
|
||||
else
|
||||
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
|
||||
|
||||
if (!opt.no_literal) {
|
||||
pt->timestamp = make_timestamp();
|
||||
pt->mode = opt.textmode ? 't' : 'b';
|
||||
pt->len = filesize;
|
||||
pt->new_ctb = !pt->len && !RFC1991;
|
||||
pt->buf = inp;
|
||||
pkt.pkttype = PKT_PLAINTEXT;
|
||||
pkt.pkt.plaintext = pt;
|
||||
cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
|
||||
}
|
||||
else
|
||||
cfx.datalen = filesize && !do_compress ? filesize : 0;
|
||||
|
||||
/* register the cipher filter */
|
||||
iobuf_push_filter( out, cipher_filter, &cfx );
|
||||
|
||||
/* register the compress filter */
|
||||
if( do_compress ) {
|
||||
int compr_algo = opt.def_compress_algo;
|
||||
|
||||
if(compr_algo==-1)
|
||||
{
|
||||
if((compr_algo=
|
||||
select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
|
||||
compr_algo=DEFAULT_COMPRESS_ALGO;
|
||||
/* Theoretically impossible to get here since uncompressed
|
||||
is implicit. */
|
||||
}
|
||||
else if(!opt.expert &&
|
||||
select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
|
||||
compr_algo,NULL)!=compr_algo)
|
||||
log_info(_("forcing compression algorithm %s (%d) "
|
||||
"violates recipient preferences\n"),
|
||||
compress_algo_to_string(compr_algo),compr_algo);
|
||||
|
||||
/* algo 0 means no compression */
|
||||
if( compr_algo )
|
||||
{
|
||||
if (cfx.dek && cfx.dek->use_mdc)
|
||||
zfx.new_ctb = 1;
|
||||
zfx.algo = compr_algo;
|
||||
iobuf_push_filter( out, compress_filter, &zfx );
|
||||
}
|
||||
}
|
||||
|
||||
/* do the work */
|
||||
if (!opt.no_literal) {
|
||||
if( (rc = build_packet( out, &pkt )) )
|
||||
log_error("build_packet failed: %s\n", g10_errstr(rc) );
|
||||
}
|
||||
else {
|
||||
/* user requested not to create a literal packet, so we copy
|
||||
the plain data */
|
||||
byte copy_buffer[4096];
|
||||
int bytes_copied;
|
||||
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
|
||||
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
log_error("copying input to output failed: %s\n",
|
||||
g10_errstr(rc) );
|
||||
break;
|
||||
}
|
||||
wipememory(copy_buffer, 4096); /* burn buffer */
|
||||
}
|
||||
|
||||
/* finish the stuff */
|
||||
leave:
|
||||
iobuf_close(inp);
|
||||
if( rc )
|
||||
iobuf_cancel(out);
|
||||
else {
|
||||
iobuf_close(out); /* fixme: check returncode */
|
||||
write_status( STATUS_END_ENCRYPTION );
|
||||
}
|
||||
if( pt )
|
||||
pt->buf = NULL;
|
||||
free_packet(&pkt);
|
||||
m_free(cfx.dek);
|
||||
release_pk_list( pk_list );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Filter to do a complete public key encryption.
|
||||
*/
|
||||
int
|
||||
encrypt_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
encrypt_filter_context_t *efx = opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
|
||||
BUG(); /* not used */
|
||||
}
|
||||
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
|
||||
if( !efx->header_okay ) {
|
||||
efx->cfx.dek = m_alloc_secure_clear( sizeof *efx->cfx.dek );
|
||||
|
||||
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
|
||||
efx->cfx.dek->algo =
|
||||
select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,-1,NULL);
|
||||
if( efx->cfx.dek->algo == -1 ) {
|
||||
/* because 3DES is implicitly in the prefs, this can only
|
||||
* happen if we do not have any public keys in the list */
|
||||
efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!opt.expert &&
|
||||
select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,
|
||||
opt.def_cipher_algo,
|
||||
NULL)!=opt.def_cipher_algo)
|
||||
log_info(_("forcing symmetric cipher %s (%d) "
|
||||
"violates recipient preferences\n"),
|
||||
cipher_algo_to_string(opt.def_cipher_algo),
|
||||
opt.def_cipher_algo);
|
||||
|
||||
efx->cfx.dek->algo = opt.def_cipher_algo;
|
||||
}
|
||||
|
||||
efx->cfx.dek->use_mdc = use_mdc(efx->pk_list,efx->cfx.dek->algo);
|
||||
|
||||
make_session_key( efx->cfx.dek );
|
||||
if( DBG_CIPHER )
|
||||
log_hexdump("DEK is: ",
|
||||
efx->cfx.dek->key, efx->cfx.dek->keylen );
|
||||
|
||||
rc = write_pubkey_enc_from_list( efx->pk_list, efx->cfx.dek, a );
|
||||
if( rc )
|
||||
return rc;
|
||||
|
||||
iobuf_push_filter( a, cipher_filter, &efx->cfx );
|
||||
|
||||
efx->header_okay = 1;
|
||||
}
|
||||
rc = iobuf_write( a, buf, size );
|
||||
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC ) {
|
||||
*(char**)buf = "encrypt_filter";
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Write pubkey-enc packets from the list of PKs to OUT.
|
||||
*/
|
||||
static int
|
||||
write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
|
||||
{
|
||||
PACKET pkt;
|
||||
PKT_public_key *pk;
|
||||
PKT_pubkey_enc *enc;
|
||||
int rc;
|
||||
|
||||
for( ; pk_list; pk_list = pk_list->next ) {
|
||||
MPI frame;
|
||||
|
||||
pk = pk_list->pk;
|
||||
|
||||
print_pubkey_algo_note( pk->pubkey_algo );
|
||||
enc = m_alloc_clear( sizeof *enc );
|
||||
enc->pubkey_algo = pk->pubkey_algo;
|
||||
keyid_from_pk( pk, enc->keyid );
|
||||
enc->throw_keyid = (opt.throw_keyid || (pk_list->flags&1));
|
||||
|
||||
if(opt.throw_keyid && (PGP2 || PGP6 || PGP7 || PGP8))
|
||||
{
|
||||
log_info(_("you may not use %s while in %s mode\n"),
|
||||
"--throw-keyid",compliance_option_string());
|
||||
compliance_failure();
|
||||
}
|
||||
|
||||
/* Okay, what's going on: We have the session key somewhere in
|
||||
* the structure DEK and want to encode this session key in
|
||||
* an integer value of n bits. pubkey_nbits gives us the
|
||||
* number of bits we have to use. We then encode the session
|
||||
* key in some way and we get it back in the big intger value
|
||||
* FRAME. Then we use FRAME, the public key PK->PKEY and the
|
||||
* algorithm number PK->PUBKEY_ALGO and pass it to pubkey_encrypt
|
||||
* which returns the encrypted value in the array ENC->DATA.
|
||||
* This array has a size which depends on the used algorithm
|
||||
* (e.g. 2 for ElGamal). We don't need frame anymore because we
|
||||
* have everything now in enc->data which is the passed to
|
||||
* build_packet()
|
||||
*/
|
||||
frame = encode_session_key( dek, pubkey_nbits( pk->pubkey_algo,
|
||||
pk->pkey ) );
|
||||
rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
|
||||
mpi_free( frame );
|
||||
if( rc )
|
||||
log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
|
||||
else {
|
||||
if( opt.verbose ) {
|
||||
char *ustr = get_user_id_string_printable (enc->keyid);
|
||||
log_info(_("%s/%s encrypted for: \"%s\"\n"),
|
||||
pubkey_algo_to_string(enc->pubkey_algo),
|
||||
cipher_algo_to_string(dek->algo), ustr );
|
||||
m_free(ustr);
|
||||
}
|
||||
/* and write it */
|
||||
init_packet(&pkt);
|
||||
pkt.pkttype = PKT_PUBKEY_ENC;
|
||||
pkt.pkt.pubkey_enc = enc;
|
||||
rc = build_packet( out, &pkt );
|
||||
if( rc )
|
||||
log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc));
|
||||
}
|
||||
free_pubkey_enc(enc);
|
||||
if( rc )
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
encode_crypt_files(int nfiles, char **files, STRLIST remusr)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (opt.outfile)
|
||||
{
|
||||
log_error(_("--output doesn't work for this command\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nfiles)
|
||||
{
|
||||
char line[2048];
|
||||
unsigned int lno = 0;
|
||||
while ( fgets(line, DIM(line), stdin) )
|
||||
{
|
||||
lno++;
|
||||
if (!*line || line[strlen(line)-1] != '\n')
|
||||
{
|
||||
log_error("input line %u too long or missing LF\n", lno);
|
||||
return;
|
||||
}
|
||||
line[strlen(line)-1] = '\0';
|
||||
print_file_status(STATUS_FILE_START, line, 2);
|
||||
if ( (rc = encode_crypt(line, remusr)) )
|
||||
log_error("%s: encryption failed: %s\n",
|
||||
print_fname_stdin(line), g10_errstr(rc) );
|
||||
write_status( STATUS_FILE_DONE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (nfiles--)
|
||||
{
|
||||
print_file_status(STATUS_FILE_START, *files, 2);
|
||||
if ( (rc = encode_crypt(*files, remusr)) )
|
||||
log_error("%s: encryption failed: %s\n",
|
||||
print_fname_stdin(*files), g10_errstr(rc) );
|
||||
write_status( STATUS_FILE_DONE );
|
||||
files++;
|
||||
}
|
||||
}
|
||||
}
|
619
g10/exec.c
Normal file
619
g10/exec.c
Normal file
|
@ -0,0 +1,619 @@
|
|||
/* exec.c - generic call-a-program code
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#ifndef EXEC_TEMPFILE_ONLY
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "options.h"
|
||||
#include "memory.h"
|
||||
#include "i18n.h"
|
||||
#include "iobuf.h"
|
||||
#include "util.h"
|
||||
#include "exec.h"
|
||||
|
||||
#ifdef NO_EXEC
|
||||
int exec_write(struct exec_info **info,const char *program,
|
||||
const char *args_in,const char *name,int writeonly,int binary)
|
||||
{
|
||||
log_error(_("no remote program execution supported\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
int exec_read(struct exec_info *info) { return G10ERR_GENERAL; }
|
||||
int exec_finish(struct exec_info *info) { return G10ERR_GENERAL; }
|
||||
int set_exec_path(const char *path,int method) { return G10ERR_GENERAL; }
|
||||
|
||||
#else /* ! NO_EXEC */
|
||||
|
||||
#ifndef HAVE_MKDTEMP
|
||||
char *mkdtemp(char *template);
|
||||
#endif
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
/* This is a nicer system() for windows that waits for programs to
|
||||
return before returning control to the caller. I hate helpful
|
||||
computers. */
|
||||
static int win_system(const char *command)
|
||||
{
|
||||
PROCESS_INFORMATION pi;
|
||||
STARTUPINFO si;
|
||||
char *string;
|
||||
|
||||
/* We must use a copy of the command as CreateProcess modifies this
|
||||
argument. */
|
||||
string=m_strdup(command);
|
||||
|
||||
memset(&pi,0,sizeof(pi));
|
||||
memset(&si,0,sizeof(si));
|
||||
si.cb=sizeof(si);
|
||||
|
||||
if(!CreateProcess(NULL,string,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
|
||||
return -1;
|
||||
|
||||
/* Wait for the child to exit */
|
||||
WaitForSingleObject(pi.hProcess,INFINITE);
|
||||
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
m_free(string);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* method==0 to replace current $PATH, and 1 to append to current
|
||||
$PATH. */
|
||||
int set_exec_path(const char *path,int method)
|
||||
{
|
||||
char *p,*curpath=NULL;
|
||||
size_t curlen=0;
|
||||
|
||||
if(method==1 && (curpath=getenv("PATH")))
|
||||
curlen=strlen(curpath)+1;
|
||||
|
||||
p=m_alloc(5+curlen+strlen(path)+1);
|
||||
strcpy(p,"PATH=");
|
||||
|
||||
if(curpath)
|
||||
{
|
||||
strcat(p,curpath);
|
||||
strcat(p,":");
|
||||
}
|
||||
|
||||
strcat(p,path);
|
||||
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("set_exec_path method %d: %s\n",method,p);
|
||||
|
||||
/* Notice that path is never freed. That is intentional due to the
|
||||
way putenv() works. This leaks a few bytes if we call
|
||||
set_exec_path multiple times. */
|
||||
|
||||
if(putenv(p)!=0)
|
||||
return G10ERR_GENERAL;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Makes a temp directory and filenames */
|
||||
static int make_tempdir(struct exec_info *info)
|
||||
{
|
||||
char *tmp=opt.temp_dir,*namein=info->name,*nameout;
|
||||
|
||||
if(!namein)
|
||||
namein=info->binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
|
||||
|
||||
nameout=info->binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt";
|
||||
|
||||
/* Make up the temp dir and files in case we need them */
|
||||
|
||||
if(tmp==NULL)
|
||||
{
|
||||
#if defined (__MINGW32__)
|
||||
tmp=m_alloc(256);
|
||||
if(GetTempPath(256,tmp)==0)
|
||||
strcpy(tmp,"c:\\windows\\temp");
|
||||
else
|
||||
{
|
||||
int len=strlen(tmp);
|
||||
|
||||
/* GetTempPath may return with \ on the end */
|
||||
while(len>0 && tmp[len-1]=='\\')
|
||||
{
|
||||
tmp[len-1]='\0';
|
||||
len--;
|
||||
}
|
||||
}
|
||||
#else /* More unixish systems */
|
||||
tmp=getenv("TMPDIR");
|
||||
if(tmp==NULL)
|
||||
{
|
||||
tmp=getenv("TMP");
|
||||
if(tmp==NULL)
|
||||
{
|
||||
#ifdef __riscos__
|
||||
tmp="<Wimp$ScrapDir>.GnuPG";
|
||||
mkdir(tmp,0700); /* Error checks occur later on */
|
||||
#else
|
||||
tmp="/tmp";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
info->tempdir=m_alloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
|
||||
|
||||
sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
m_free(tmp);
|
||||
#endif
|
||||
|
||||
if(mkdtemp(info->tempdir)==NULL)
|
||||
log_error(_("can't create directory `%s': %s\n"),
|
||||
info->tempdir,strerror(errno));
|
||||
else
|
||||
{
|
||||
info->madedir=1;
|
||||
|
||||
info->tempfile_in=m_alloc(strlen(info->tempdir)+
|
||||
strlen(DIRSEP_S)+strlen(namein)+1);
|
||||
sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
|
||||
|
||||
if(!info->writeonly)
|
||||
{
|
||||
info->tempfile_out=m_alloc(strlen(info->tempdir)+
|
||||
strlen(DIRSEP_S)+strlen(nameout)+1);
|
||||
sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
|
||||
}
|
||||
}
|
||||
|
||||
return info->madedir?0:G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
/* Expands %i and %o in the args to the full temp files within the
|
||||
temp directory. */
|
||||
static int expand_args(struct exec_info *info,const char *args_in)
|
||||
{
|
||||
const char *ch=args_in;
|
||||
unsigned int size,len;
|
||||
|
||||
info->use_temp_files=0;
|
||||
info->keep_temp_files=0;
|
||||
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("expanding string \"%s\"\n",args_in);
|
||||
|
||||
size=100;
|
||||
info->command=m_alloc(size);
|
||||
len=0;
|
||||
info->command[0]='\0';
|
||||
|
||||
while(*ch!='\0')
|
||||
{
|
||||
if(*ch=='%')
|
||||
{
|
||||
char *append=NULL;
|
||||
|
||||
ch++;
|
||||
|
||||
switch(*ch)
|
||||
{
|
||||
case 'O':
|
||||
info->keep_temp_files=1;
|
||||
/* fall through */
|
||||
|
||||
case 'o': /* out */
|
||||
if(!info->madedir)
|
||||
{
|
||||
if(make_tempdir(info))
|
||||
goto fail;
|
||||
}
|
||||
append=info->tempfile_out;
|
||||
info->use_temp_files=1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
info->keep_temp_files=1;
|
||||
/* fall through */
|
||||
|
||||
case 'i': /* in */
|
||||
if(!info->madedir)
|
||||
{
|
||||
if(make_tempdir(info))
|
||||
goto fail;
|
||||
}
|
||||
append=info->tempfile_in;
|
||||
info->use_temp_files=1;
|
||||
break;
|
||||
|
||||
case '%':
|
||||
append="%";
|
||||
break;
|
||||
}
|
||||
|
||||
if(append)
|
||||
{
|
||||
size_t applen=strlen(append);
|
||||
|
||||
if(applen+len>size-1)
|
||||
{
|
||||
if(applen<100)
|
||||
applen=100;
|
||||
|
||||
size+=applen;
|
||||
info->command=m_realloc(info->command,size);
|
||||
}
|
||||
|
||||
strcat(info->command,append);
|
||||
len+=strlen(append);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(len==size-1) /* leave room for the \0 */
|
||||
{
|
||||
size+=100;
|
||||
info->command=m_realloc(info->command,size);
|
||||
}
|
||||
|
||||
info->command[len++]=*ch;
|
||||
info->command[len]='\0';
|
||||
}
|
||||
|
||||
ch++;
|
||||
}
|
||||
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("args expanded to \"%s\", use %d, keep %d\n",
|
||||
info->command,info->use_temp_files,info->keep_temp_files);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
||||
m_free(info->command);
|
||||
info->command=NULL;
|
||||
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
/* Either handles the tempfile creation, or the fork/exec. If it
|
||||
returns ok, then info->tochild is a FILE * that can be written to.
|
||||
The rules are: if there are no args, then it's a fork/exec/pipe.
|
||||
If there are args, but no tempfiles, then it's a fork/exec/pipe via
|
||||
shell -c. If there are tempfiles, then it's a system. */
|
||||
|
||||
int exec_write(struct exec_info **info,const char *program,
|
||||
const char *args_in,const char *name,int writeonly,int binary)
|
||||
{
|
||||
int ret=G10ERR_GENERAL;
|
||||
|
||||
if(opt.exec_disable && !opt.no_perm_warn)
|
||||
{
|
||||
log_info(_("external program calls are disabled due to unsafe "
|
||||
"options file permissions\n"));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
|
||||
/* There should be no way to get to this spot while still carrying
|
||||
setuid privs. Just in case, bomb out if we are. */
|
||||
if(getuid()!=geteuid())
|
||||
BUG();
|
||||
#endif
|
||||
|
||||
if(program==NULL && args_in==NULL)
|
||||
BUG();
|
||||
|
||||
*info=m_alloc_clear(sizeof(struct exec_info));
|
||||
|
||||
if(name)
|
||||
(*info)->name=m_strdup(name);
|
||||
(*info)->binary=binary;
|
||||
(*info)->writeonly=writeonly;
|
||||
|
||||
/* Expand the args, if any */
|
||||
if(args_in && expand_args(*info,args_in))
|
||||
goto fail;
|
||||
|
||||
#ifdef EXEC_TEMPFILE_ONLY
|
||||
if(!(*info)->use_temp_files)
|
||||
{
|
||||
log_error(_("this platform requires temp files when calling external "
|
||||
"programs\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#else /* !EXEC_TEMPFILE_ONLY */
|
||||
|
||||
/* If there are no args, or there are args, but no temp files, we
|
||||
can use fork/exec/pipe */
|
||||
if(args_in==NULL || (*info)->use_temp_files==0)
|
||||
{
|
||||
int to[2],from[2];
|
||||
|
||||
if(pipe(to)==-1)
|
||||
goto fail;
|
||||
|
||||
if(pipe(from)==-1)
|
||||
{
|
||||
close(to[0]);
|
||||
close(to[1]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(((*info)->child=fork())==-1)
|
||||
{
|
||||
close(to[0]);
|
||||
close(to[1]);
|
||||
close(from[0]);
|
||||
close(from[1]);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if((*info)->child==0)
|
||||
{
|
||||
char *shell=getenv("SHELL");
|
||||
|
||||
if(shell==NULL)
|
||||
shell="/bin/sh";
|
||||
|
||||
/* I'm the child */
|
||||
|
||||
/* If the program isn't going to respond back, they get to
|
||||
keep their stdout/stderr */
|
||||
if(!(*info)->writeonly)
|
||||
{
|
||||
/* implied close of STDERR */
|
||||
if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
|
||||
_exit(1);
|
||||
|
||||
/* implied close of STDOUT */
|
||||
close(from[0]);
|
||||
if(dup2(from[1],STDOUT_FILENO)==-1)
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* implied close of STDIN */
|
||||
close(to[1]);
|
||||
if(dup2(to[0],STDIN_FILENO)==-1)
|
||||
_exit(1);
|
||||
|
||||
if(args_in==NULL)
|
||||
{
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("execlp: %s\n",program);
|
||||
|
||||
execlp(program,program,(void *)NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("execlp: %s -c %s\n",shell,(*info)->command);
|
||||
|
||||
execlp(shell,shell,"-c",(*info)->command,(void *)NULL);
|
||||
}
|
||||
|
||||
/* If we get this far the exec failed. Clean up and return. */
|
||||
|
||||
log_error(_("unable to execute %s \"%s\": %s\n"),
|
||||
args_in==NULL?"program":"shell",
|
||||
args_in==NULL?program:shell,
|
||||
strerror(errno));
|
||||
|
||||
/* This mimics the POSIX sh behavior - 127 means "not found"
|
||||
from the shell. */
|
||||
if(errno==ENOENT)
|
||||
_exit(127);
|
||||
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
/* I'm the parent */
|
||||
|
||||
close(to[0]);
|
||||
|
||||
(*info)->tochild=fdopen(to[1],binary?"wb":"w");
|
||||
if((*info)->tochild==NULL)
|
||||
{
|
||||
close(to[1]);
|
||||
ret=G10ERR_WRITE_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close(from[1]);
|
||||
|
||||
(*info)->fromchild=iobuf_fdopen(from[0],"r");
|
||||
if((*info)->fromchild==NULL)
|
||||
{
|
||||
close(from[0]);
|
||||
ret=G10ERR_READ_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* fd iobufs are cached?! */
|
||||
iobuf_ioctl((*info)->fromchild,3,1,NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* !EXEC_TEMPFILE_ONLY */
|
||||
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("using temp file `%s'\n",(*info)->tempfile_in);
|
||||
|
||||
/* It's not fork/exec/pipe, so create a temp file */
|
||||
(*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
|
||||
if((*info)->tochild==NULL)
|
||||
{
|
||||
log_error(_("can't create `%s': %s\n"),
|
||||
(*info)->tempfile_in,strerror(errno));
|
||||
ret=G10ERR_WRITE_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exec_read(struct exec_info *info)
|
||||
{
|
||||
int ret=G10ERR_GENERAL;
|
||||
|
||||
fclose(info->tochild);
|
||||
info->tochild=NULL;
|
||||
|
||||
if(info->use_temp_files)
|
||||
{
|
||||
if(DBG_EXTPROG)
|
||||
log_debug("system() command is %s\n",info->command);
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
info->progreturn=win_system(info->command);
|
||||
#else
|
||||
info->progreturn=system(info->command);
|
||||
#endif
|
||||
|
||||
if(info->progreturn==-1)
|
||||
{
|
||||
log_error(_("system error while calling external program: %s\n"),
|
||||
strerror(errno));
|
||||
info->progreturn=127;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#if defined(WIFEXITED) && defined(WEXITSTATUS)
|
||||
if(WIFEXITED(info->progreturn))
|
||||
info->progreturn=WEXITSTATUS(info->progreturn);
|
||||
else
|
||||
{
|
||||
log_error(_("unnatural exit of external program\n"));
|
||||
info->progreturn=127;
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
/* If we don't have the macros, do the best we can. */
|
||||
info->progreturn = (info->progreturn & 0xff00) >> 8;
|
||||
#endif
|
||||
|
||||
/* 127 is the magic value returned from system() to indicate
|
||||
that the shell could not be executed, or from /bin/sh to
|
||||
indicate that the program could not be executed. */
|
||||
|
||||
if(info->progreturn==127)
|
||||
{
|
||||
log_error(_("unable to execute external program\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(!info->writeonly)
|
||||
{
|
||||
info->fromchild=iobuf_open(info->tempfile_out);
|
||||
if(info->fromchild==NULL)
|
||||
{
|
||||
log_error(_("unable to read external program response: %s\n"),
|
||||
strerror(errno));
|
||||
ret=G10ERR_READ_FILE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Do not cache this iobuf on close */
|
||||
iobuf_ioctl(info->fromchild,3,1,NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int exec_finish(struct exec_info *info)
|
||||
{
|
||||
int ret=info->progreturn;
|
||||
|
||||
if(info->fromchild)
|
||||
iobuf_close(info->fromchild);
|
||||
|
||||
if(info->tochild)
|
||||
fclose(info->tochild);
|
||||
|
||||
#ifndef EXEC_TEMPFILE_ONLY
|
||||
if(info->child>0)
|
||||
{
|
||||
if(waitpid(info->child,&info->progreturn,0)!=0 &&
|
||||
WIFEXITED(info->progreturn))
|
||||
ret=WEXITSTATUS(info->progreturn);
|
||||
else
|
||||
{
|
||||
log_error(_("unnatural exit of external program\n"));
|
||||
ret=127;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(info->madedir && !info->keep_temp_files)
|
||||
{
|
||||
if(info->tempfile_in)
|
||||
{
|
||||
if(unlink(info->tempfile_in)==-1)
|
||||
log_info(_("WARNING: unable to remove tempfile (%s) `%s': %s\n"),
|
||||
"in",info->tempfile_in,strerror(errno));
|
||||
}
|
||||
|
||||
if(info->tempfile_out)
|
||||
{
|
||||
if(unlink(info->tempfile_out)==-1)
|
||||
log_info(_("WARNING: unable to remove tempfile (%s) `%s': %s\n"),
|
||||
"out",info->tempfile_out,strerror(errno));
|
||||
}
|
||||
|
||||
if(rmdir(info->tempdir)==-1)
|
||||
log_info(_("WARNING: unable to remove temp directory `%s': %s\n"),
|
||||
info->tempdir,strerror(errno));
|
||||
}
|
||||
|
||||
m_free(info->command);
|
||||
m_free(info->name);
|
||||
m_free(info->tempdir);
|
||||
m_free(info->tempfile_in);
|
||||
m_free(info->tempfile_out);
|
||||
m_free(info);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* ! NO_EXEC */
|
43
g10/exec.h
Normal file
43
g10/exec.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/* exec.h
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef _EXEC_H_
|
||||
#define _EXEC_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include "iobuf.h"
|
||||
|
||||
struct exec_info
|
||||
{
|
||||
int progreturn,binary,writeonly,madedir,use_temp_files,keep_temp_files;
|
||||
pid_t child;
|
||||
FILE *tochild;
|
||||
IOBUF fromchild;
|
||||
char *command,*name,*tempdir,*tempfile_in,*tempfile_out;
|
||||
};
|
||||
|
||||
int exec_write(struct exec_info **info,const char *program,
|
||||
const char *args_in,const char *name,int writeonly,int binary);
|
||||
int exec_read(struct exec_info *info);
|
||||
int exec_finish(struct exec_info *info);
|
||||
int set_exec_path(const char *path,int method);
|
||||
|
||||
#endif /* !_EXEC_H_ */
|
396
g10/export.c
Normal file
396
g10/export.c
Normal file
|
@ -0,0 +1,396 @@
|
|||
/* export.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
|
||||
static int do_export( STRLIST users, int secret, unsigned int options );
|
||||
static int do_export_stream( IOBUF out, STRLIST users, int secret,
|
||||
KBNODE *keyblock_out, unsigned int options,
|
||||
int *any );
|
||||
|
||||
int
|
||||
parse_export_options(char *str,unsigned int *options)
|
||||
{
|
||||
struct parse_options export_opts[]=
|
||||
{
|
||||
{"include-non-rfc",EXPORT_INCLUDE_NON_RFC},
|
||||
{"include-local-sigs",EXPORT_INCLUDE_LOCAL_SIGS},
|
||||
{"include-attributes",EXPORT_INCLUDE_ATTRIBUTES},
|
||||
{"include-sensitive-revkeys",EXPORT_INCLUDE_SENSITIVE_REVKEYS},
|
||||
{NULL,0}
|
||||
/* add tags for include revoked and disabled? */
|
||||
};
|
||||
|
||||
return parse_options(str,options,export_opts);
|
||||
}
|
||||
|
||||
/****************
|
||||
* Export the public keys (to standard out or --output).
|
||||
* Depending on opt.armor the output is armored.
|
||||
* options are defined in main.h.
|
||||
* If USERS is NULL, the complete ring will be exported. */
|
||||
int
|
||||
export_pubkeys( STRLIST users, unsigned int options )
|
||||
{
|
||||
return do_export( users, 0, options );
|
||||
}
|
||||
|
||||
/****************
|
||||
* Export to an already opened stream; return -1 if no keys have
|
||||
* been exported
|
||||
*/
|
||||
int
|
||||
export_pubkeys_stream( IOBUF out, STRLIST users,
|
||||
KBNODE *keyblock_out, unsigned int options )
|
||||
{
|
||||
int any, rc;
|
||||
|
||||
rc = do_export_stream( out, users, 0, keyblock_out, options, &any );
|
||||
if( !rc && !any )
|
||||
rc = -1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
export_seckeys( STRLIST users )
|
||||
{
|
||||
return do_export( users, 1, 0 );
|
||||
}
|
||||
|
||||
int
|
||||
export_secsubkeys( STRLIST users )
|
||||
{
|
||||
return do_export( users, 2, 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
do_export( STRLIST users, int secret, unsigned int options )
|
||||
{
|
||||
IOBUF out = NULL;
|
||||
int any, rc;
|
||||
armor_filter_context_t afx;
|
||||
compress_filter_context_t zfx;
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
|
||||
rc = open_outfile( NULL, 0, &out );
|
||||
if( rc )
|
||||
return rc;
|
||||
|
||||
if( opt.armor ) {
|
||||
afx.what = secret?5:1;
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
}
|
||||
if( opt.compress_keys && opt.compress )
|
||||
iobuf_push_filter( out, compress_filter, &zfx );
|
||||
rc = do_export_stream( out, users, secret, NULL, options, &any );
|
||||
|
||||
if( rc || !any )
|
||||
iobuf_cancel(out);
|
||||
else
|
||||
iobuf_close(out);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* If keyblock_out is non-NULL, AND the exit code is zero, then it
|
||||
contains a pointer to the first keyblock found and exported. No
|
||||
other keyblocks are exported. The caller must free it. */
|
||||
static int
|
||||
do_export_stream( IOBUF out, STRLIST users, int secret,
|
||||
KBNODE *keyblock_out, unsigned int options, int *any )
|
||||
{
|
||||
int rc = 0;
|
||||
PACKET pkt;
|
||||
KBNODE keyblock = NULL;
|
||||
KBNODE kbctx, node;
|
||||
size_t ndesc, descindex;
|
||||
KEYDB_SEARCH_DESC *desc = NULL;
|
||||
KEYDB_HANDLE kdbhd;
|
||||
STRLIST sl;
|
||||
|
||||
*any = 0;
|
||||
init_packet( &pkt );
|
||||
kdbhd = keydb_new (secret);
|
||||
|
||||
if (!users) {
|
||||
ndesc = 1;
|
||||
desc = m_alloc_clear ( ndesc * sizeof *desc);
|
||||
desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
|
||||
}
|
||||
else {
|
||||
for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
|
||||
;
|
||||
desc = m_alloc ( ndesc * sizeof *desc);
|
||||
|
||||
for (ndesc=0, sl=users; sl; sl = sl->next) {
|
||||
if (classify_user_id (sl->d, desc+ndesc))
|
||||
ndesc++;
|
||||
else
|
||||
log_error (_("key `%s' not found: %s\n"),
|
||||
sl->d, g10_errstr (G10ERR_INV_USER_ID));
|
||||
}
|
||||
|
||||
/* it would be nice to see which of the given users did
|
||||
actually match one in the keyring. To implement this we
|
||||
need to have a found flag for each entry in desc and to set
|
||||
this we must check all those entries after a match to mark
|
||||
all matched one - currently we stop at the first match. To
|
||||
do this we need an extra flag to enable this feature so */
|
||||
}
|
||||
|
||||
while (!(rc = keydb_search2 (kdbhd, desc, ndesc, &descindex))) {
|
||||
int sha1_warned=0,skip_until_subkey=0;
|
||||
u32 sk_keyid[2];
|
||||
|
||||
if (!users)
|
||||
desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
|
||||
|
||||
/* read the keyblock */
|
||||
rc = keydb_get_keyblock (kdbhd, &keyblock );
|
||||
if( rc ) {
|
||||
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* do not export keys which are incompatible with rfc2440 */
|
||||
if( !(options&EXPORT_INCLUDE_NON_RFC) &&
|
||||
(node = find_kbnode( keyblock, PKT_PUBLIC_KEY )) ) {
|
||||
PKT_public_key *pk = node->pkt->pkt.public_key;
|
||||
if( pk->version == 3 && pk->pubkey_algo > 3 ) {
|
||||
log_info(_("key %08lX: not a rfc2440 key - skipped\n"),
|
||||
(ulong)keyid_from_pk( pk, NULL) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
node=find_kbnode( keyblock, PKT_SECRET_KEY );
|
||||
if(node)
|
||||
{
|
||||
PKT_secret_key *sk=node->pkt->pkt.secret_key;
|
||||
|
||||
keyid_from_sk(sk,sk_keyid);
|
||||
|
||||
/* we can't apply GNU mode 1001 on an unprotected key */
|
||||
if( secret == 2 && !sk->is_protected )
|
||||
{
|
||||
log_info(_("key %08lX: not protected - skipped\n"),
|
||||
(ulong)sk_keyid[1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* no v3 keys with GNU mode 1001 */
|
||||
if( secret == 2 && sk->version == 3 )
|
||||
{
|
||||
log_info(_("key %08lX: PGP 2.x style key - skipped\n"),
|
||||
(ulong)sk_keyid[1]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* and write it */
|
||||
for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
|
||||
if( skip_until_subkey )
|
||||
{
|
||||
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype==PKT_SECRET_SUBKEY)
|
||||
skip_until_subkey=0;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
/* don't export any comment packets but those in the
|
||||
* secret keyring */
|
||||
if( !secret && node->pkt->pkttype == PKT_COMMENT )
|
||||
continue;
|
||||
|
||||
/* make sure that ring_trust packets never get exported */
|
||||
if (node->pkt->pkttype == PKT_RING_TRUST)
|
||||
continue;
|
||||
|
||||
/* If exact is set, then we only export what was requested
|
||||
(plus the primary key, if the user didn't specifically
|
||||
request it) */
|
||||
if(desc[descindex].exact
|
||||
&& (node->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
||||
|| node->pkt->pkttype==PKT_SECRET_SUBKEY))
|
||||
{
|
||||
u32 kid[2];
|
||||
byte fpr[MAX_FINGERPRINT_LEN];
|
||||
size_t fprlen;
|
||||
|
||||
switch(desc[descindex].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
|
||||
keyid_from_pk(node->pkt->pkt.public_key,kid);
|
||||
else
|
||||
keyid_from_sk(node->pkt->pkt.secret_key,kid);
|
||||
break;
|
||||
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
|
||||
fingerprint_from_pk(node->pkt->pkt.public_key,
|
||||
fpr,&fprlen);
|
||||
else
|
||||
fingerprint_from_sk(node->pkt->pkt.secret_key,
|
||||
fpr,&fprlen);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(desc[descindex].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
if (desc[descindex].u.kid[1] != kid[1])
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
if (desc[descindex].u.kid[0] != kid[0]
|
||||
|| desc[descindex].u.kid[1] != kid[1])
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR16:
|
||||
if (memcmp (desc[descindex].u.fpr, fpr, 16))
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
if (memcmp (desc[descindex].u.fpr, fpr, 20))
|
||||
skip_until_subkey=1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(skip_until_subkey)
|
||||
continue;
|
||||
}
|
||||
|
||||
if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
||||
/* do not export packets which are marked as not exportable */
|
||||
if( !(options&EXPORT_INCLUDE_LOCAL_SIGS) &&
|
||||
!node->pkt->pkt.signature->flags.exportable )
|
||||
continue; /* not exportable */
|
||||
|
||||
/* Do not export packets with a "sensitive" revocation
|
||||
key unless the user wants us to. Note that we do
|
||||
export these when issuing the actual revocation (see
|
||||
revoke.c). */
|
||||
if( !(options&EXPORT_INCLUDE_SENSITIVE_REVKEYS) &&
|
||||
node->pkt->pkt.signature->revkey ) {
|
||||
int i;
|
||||
|
||||
for(i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
|
||||
if(node->pkt->pkt.signature->revkey[i]->class & 0x40)
|
||||
break;
|
||||
|
||||
if(i<node->pkt->pkt.signature->numrevkeys)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't export attribs? */
|
||||
if( !(options&EXPORT_INCLUDE_ATTRIBUTES) &&
|
||||
node->pkt->pkttype == PKT_USER_ID &&
|
||||
node->pkt->pkt.user_id->attrib_data ) {
|
||||
/* Skip until we get to something that is not an attrib
|
||||
or a signature on an attrib */
|
||||
while(kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) {
|
||||
kbctx=kbctx->next;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) {
|
||||
/* we don't want to export the secret parts of the
|
||||
* primary key, this is done by using GNU protection mode 1001
|
||||
*/
|
||||
int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode;
|
||||
node->pkt->pkt.secret_key->protect.s2k.mode = 1001;
|
||||
rc = build_packet( out, node->pkt );
|
||||
node->pkt->pkt.secret_key->protect.s2k.mode = save_mode;
|
||||
}
|
||||
else {
|
||||
/* Warn the user if the secret key or any of the secret
|
||||
subkeys are protected with SHA1 and we have
|
||||
simple_sk_checksum set. */
|
||||
if(!sha1_warned && opt.simple_sk_checksum &&
|
||||
(node->pkt->pkttype==PKT_SECRET_KEY ||
|
||||
node->pkt->pkttype==PKT_SECRET_SUBKEY) &&
|
||||
node->pkt->pkt.secret_key->protect.sha1chk)
|
||||
{
|
||||
/* I hope this warning doesn't confuse people. */
|
||||
log_info(_("WARNING: secret key %08lX does not have a "
|
||||
"simple SK checksum\n"),(ulong)sk_keyid[1]);
|
||||
|
||||
sha1_warned=1;
|
||||
}
|
||||
|
||||
rc = build_packet( out, node->pkt );
|
||||
}
|
||||
|
||||
if( rc ) {
|
||||
log_error("build_packet(%d) failed: %s\n",
|
||||
node->pkt->pkttype, g10_errstr(rc) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
++*any;
|
||||
if(keyblock_out)
|
||||
{
|
||||
*keyblock_out=keyblock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( rc == -1 )
|
||||
rc = 0;
|
||||
|
||||
leave:
|
||||
m_free(desc);
|
||||
keydb_release (kdbhd);
|
||||
if(rc || keyblock_out==NULL)
|
||||
release_kbnode( keyblock );
|
||||
if( !*any )
|
||||
log_info(_("WARNING: nothing exported\n"));
|
||||
return rc;
|
||||
}
|
154
g10/filter.h
Normal file
154
g10/filter.h
Normal file
|
@ -0,0 +1,154 @@
|
|||
/* filter.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_FILTER_H
|
||||
#define G10_FILTER_H
|
||||
|
||||
#include "types.h"
|
||||
#include "cipher.h"
|
||||
|
||||
typedef struct {
|
||||
MD_HANDLE md; /* catch all */
|
||||
MD_HANDLE md2; /* if we want to calculate an alternate hash */
|
||||
size_t maxbuf_size;
|
||||
} md_filter_context_t;
|
||||
|
||||
typedef struct {
|
||||
/* these fields may be initialized */
|
||||
int what; /* what kind of armor headers to write */
|
||||
int only_keyblocks; /* skip all headers but ".... key block" */
|
||||
const char *hdrlines; /* write these headerlines */
|
||||
|
||||
/* these fileds must be initialized to zero */
|
||||
int no_openpgp_data; /* output flag: "No valid OpenPGP data found" */
|
||||
|
||||
/* the following fields must be initialized to zero */
|
||||
int inp_checked; /* set if the input has been checked */
|
||||
int inp_bypass; /* set if the input is not armored */
|
||||
int in_cleartext; /* clear text message */
|
||||
int not_dash_escaped; /* clear text is not dash escaped */
|
||||
int hashes; /* detected hash algorithms */
|
||||
int faked; /* we are faking a literal data packet */
|
||||
int truncated; /* number of truncated lines */
|
||||
int qp_detected;
|
||||
int pgp2mode;
|
||||
|
||||
byte *buffer; /* malloced buffer */
|
||||
unsigned buffer_size; /* and size of this buffer */
|
||||
unsigned buffer_len; /* used length of the buffer */
|
||||
unsigned buffer_pos; /* read position */
|
||||
|
||||
byte radbuf[4];
|
||||
int idx, idx2;
|
||||
u32 crc;
|
||||
|
||||
int status; /* an internal state flag */
|
||||
int cancel;
|
||||
int any_data; /* any valid armored data seen */
|
||||
int pending_lf; /* used together with faked */
|
||||
} armor_filter_context_t;
|
||||
|
||||
struct unarmor_pump_s;
|
||||
typedef struct unarmor_pump_s *UnarmorPump;
|
||||
|
||||
|
||||
struct compress_filter_context_s {
|
||||
int status;
|
||||
void *opaque; /* (used for z_stream) */
|
||||
byte *inbuf;
|
||||
unsigned inbufsize;
|
||||
byte *outbuf;
|
||||
unsigned outbufsize;
|
||||
int algo; /* compress algo */
|
||||
int algo1hack;
|
||||
int new_ctb;
|
||||
void (*release)(struct compress_filter_context_s*);
|
||||
};
|
||||
typedef struct compress_filter_context_s compress_filter_context_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
DEK *dek;
|
||||
u32 datalen;
|
||||
CIPHER_HANDLE cipher_hd;
|
||||
int header;
|
||||
MD_HANDLE mdc_hash;
|
||||
byte enchash[20];
|
||||
int create_mdc; /* flag will be set by the cipher filter */
|
||||
} cipher_filter_context_t;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
byte *buffer; /* malloced buffer */
|
||||
unsigned buffer_size; /* and size of this buffer */
|
||||
unsigned buffer_len; /* used length of the buffer */
|
||||
unsigned buffer_pos; /* read position */
|
||||
int truncated; /* number of truncated lines */
|
||||
int not_dash_escaped;
|
||||
int escape_from;
|
||||
MD_HANDLE md;
|
||||
int pending_lf;
|
||||
int pending_esc;
|
||||
} text_filter_context_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *what; /* description */
|
||||
u32 last_time; /* last time reported */
|
||||
unsigned long last; /* last amount reported */
|
||||
unsigned long offset; /* current amount */
|
||||
unsigned long total; /* total amount */
|
||||
} progress_filter_context_t;
|
||||
|
||||
/* encrypt_filter_context_t defined in main.h */
|
||||
|
||||
/*-- mdfilter.c --*/
|
||||
int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len);
|
||||
void free_md_filter_context( md_filter_context_t *mfx );
|
||||
|
||||
/*-- armor.c --*/
|
||||
int use_armor_filter( IOBUF a );
|
||||
int armor_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
UnarmorPump unarmor_pump_new (void);
|
||||
void unarmor_pump_release (UnarmorPump x);
|
||||
int unarmor_pump (UnarmorPump x, int c);
|
||||
|
||||
/*-- compress.c --*/
|
||||
int compress_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
|
||||
/*-- cipher.c --*/
|
||||
int cipher_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
|
||||
/*-- textfilter.c --*/
|
||||
int text_filter( void *opaque, int control,
|
||||
IOBUF chain, byte *buf, size_t *ret_len);
|
||||
int copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
|
||||
int escape_dash, int escape_from, int pgp2mode );
|
||||
|
||||
/*-- progress.c --*/
|
||||
int progress_filter (void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len);
|
||||
void handle_progress (progress_filter_context_t *pfx,
|
||||
IOBUF inp, const char *name);
|
||||
|
||||
#endif /*G10_FILTER_H*/
|
542
g10/free-packet.c
Normal file
542
g10/free-packet.c
Normal file
|
@ -0,0 +1,542 @@
|
|||
/* free-packet.c - cleanup stuff for packets
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
|
||||
* Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "packet.h"
|
||||
#include "iobuf.h"
|
||||
#include "mpi.h"
|
||||
#include "util.h"
|
||||
#include "cipher.h"
|
||||
#include "memory.h"
|
||||
#include "options.h"
|
||||
|
||||
void
|
||||
free_symkey_enc( PKT_symkey_enc *enc )
|
||||
{
|
||||
m_free(enc);
|
||||
}
|
||||
|
||||
void
|
||||
free_pubkey_enc( PKT_pubkey_enc *enc )
|
||||
{
|
||||
int n, i;
|
||||
n = pubkey_get_nenc( enc->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(enc->data[0]);
|
||||
for(i=0; i < n; i++ )
|
||||
mpi_free( enc->data[i] );
|
||||
m_free(enc);
|
||||
}
|
||||
|
||||
void
|
||||
free_seckey_enc( PKT_signature *sig )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
n = pubkey_get_nsig( sig->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(sig->data[0]);
|
||||
for(i=0; i < n; i++ )
|
||||
mpi_free( sig->data[i] );
|
||||
|
||||
m_free(sig->revkey);
|
||||
m_free(sig->hashed);
|
||||
m_free(sig->unhashed);
|
||||
m_free(sig);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
release_public_key_parts( PKT_public_key *pk )
|
||||
{
|
||||
int n, i;
|
||||
n = pubkey_get_npkey( pk->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(pk->pkey[0]);
|
||||
for(i=0; i < n; i++ ) {
|
||||
mpi_free( pk->pkey[i] );
|
||||
pk->pkey[i] = NULL;
|
||||
}
|
||||
if (pk->prefs) {
|
||||
m_free (pk->prefs);
|
||||
pk->prefs = NULL;
|
||||
}
|
||||
if (pk->user_id) {
|
||||
free_user_id (pk->user_id);
|
||||
pk->user_id = NULL;
|
||||
}
|
||||
if (pk->revkey) {
|
||||
m_free(pk->revkey);
|
||||
pk->revkey=NULL;
|
||||
pk->numrevkeys=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_public_key( PKT_public_key *pk )
|
||||
{
|
||||
release_public_key_parts( pk );
|
||||
m_free(pk);
|
||||
}
|
||||
|
||||
|
||||
static subpktarea_t *
|
||||
cp_subpktarea (subpktarea_t *s )
|
||||
{
|
||||
subpktarea_t *d;
|
||||
|
||||
if( !s )
|
||||
return NULL;
|
||||
d = m_alloc (sizeof (*d) + s->size - 1 );
|
||||
d->size = s->size;
|
||||
d->len = s->len;
|
||||
memcpy (d->data, s->data, s->len);
|
||||
return d;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a copy of the preferences
|
||||
*/
|
||||
prefitem_t *
|
||||
copy_prefs (const prefitem_t *prefs)
|
||||
{
|
||||
size_t n;
|
||||
prefitem_t *new;
|
||||
|
||||
if (!prefs)
|
||||
return NULL;
|
||||
|
||||
for (n=0; prefs[n].type; n++)
|
||||
;
|
||||
new = m_alloc ( sizeof (*new) * (n+1));
|
||||
for (n=0; prefs[n].type; n++) {
|
||||
new[n].type = prefs[n].type;
|
||||
new[n].value = prefs[n].value;
|
||||
}
|
||||
new[n].type = PREFTYPE_NONE;
|
||||
new[n].value = 0;
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
PKT_public_key *
|
||||
copy_public_key ( PKT_public_key *d, PKT_public_key *s)
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( !d )
|
||||
d = m_alloc(sizeof *d);
|
||||
memcpy( d, s, sizeof *d );
|
||||
d->user_id = scopy_user_id (s->user_id);
|
||||
d->prefs = copy_prefs (s->prefs);
|
||||
n = pubkey_get_npkey( s->pubkey_algo );
|
||||
if( !n )
|
||||
d->pkey[0] = mpi_copy(s->pkey[0]);
|
||||
else {
|
||||
for(i=0; i < n; i++ )
|
||||
d->pkey[i] = mpi_copy( s->pkey[i] );
|
||||
}
|
||||
if( !s->revkey && s->numrevkeys )
|
||||
BUG();
|
||||
if( s->numrevkeys ) {
|
||||
d->revkey = m_alloc(sizeof(struct revocation_key)*s->numrevkeys);
|
||||
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
|
||||
}
|
||||
else
|
||||
d->revkey = NULL;
|
||||
return d;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Replace all common parts of a sk by the one from the public key.
|
||||
* This is a hack and a better solution will be to just store the real secret
|
||||
* parts somewhere and don't duplicate all the other stuff.
|
||||
*/
|
||||
void
|
||||
copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
|
||||
{
|
||||
sk->expiredate = pk->expiredate;
|
||||
sk->pubkey_algo = pk->pubkey_algo;
|
||||
sk->pubkey_usage= pk->pubkey_usage;
|
||||
sk->req_usage = pk->req_usage;
|
||||
sk->req_algo = pk->req_algo;
|
||||
sk->has_expired = pk->has_expired;
|
||||
sk->is_revoked = pk->is_revoked;
|
||||
sk->is_valid = pk->is_valid;
|
||||
sk->main_keyid[0]= pk->main_keyid[0];
|
||||
sk->main_keyid[1]= pk->main_keyid[1];
|
||||
sk->keyid[0] = pk->keyid[0];
|
||||
sk->keyid[1] = pk->keyid[1];
|
||||
}
|
||||
|
||||
PKT_signature *
|
||||
copy_signature( PKT_signature *d, PKT_signature *s )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( !d )
|
||||
d = m_alloc(sizeof *d);
|
||||
memcpy( d, s, sizeof *d );
|
||||
n = pubkey_get_nsig( s->pubkey_algo );
|
||||
if( !n )
|
||||
d->data[0] = mpi_copy(s->data[0]);
|
||||
else {
|
||||
for(i=0; i < n; i++ )
|
||||
d->data[i] = mpi_copy( s->data[i] );
|
||||
}
|
||||
d->hashed = cp_subpktarea (s->hashed);
|
||||
d->unhashed = cp_subpktarea (s->unhashed);
|
||||
if(s->numrevkeys)
|
||||
{
|
||||
d->revkey=NULL;
|
||||
d->numrevkeys=0;
|
||||
parse_revkeys(d);
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shallow copy of the user ID
|
||||
*/
|
||||
PKT_user_id *
|
||||
scopy_user_id (PKT_user_id *s)
|
||||
{
|
||||
if (s)
|
||||
s->ref++;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
release_secret_key_parts( PKT_secret_key *sk )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
n = pubkey_get_nskey( sk->pubkey_algo );
|
||||
if( !n )
|
||||
mpi_free(sk->skey[0]);
|
||||
for(i=0; i < n; i++ ) {
|
||||
mpi_free( sk->skey[i] );
|
||||
sk->skey[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
free_secret_key( PKT_secret_key *sk )
|
||||
{
|
||||
release_secret_key_parts( sk );
|
||||
m_free(sk);
|
||||
}
|
||||
|
||||
PKT_secret_key *
|
||||
copy_secret_key( PKT_secret_key *d, PKT_secret_key *s )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( !d )
|
||||
d = m_alloc(sizeof *d);
|
||||
memcpy( d, s, sizeof *d );
|
||||
n = pubkey_get_nskey( s->pubkey_algo );
|
||||
if( !n )
|
||||
d->skey[0] = mpi_copy(s->skey[0]);
|
||||
else {
|
||||
for(i=0; i < n; i++ )
|
||||
d->skey[i] = mpi_copy( s->skey[i] );
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
void
|
||||
free_comment( PKT_comment *rem )
|
||||
{
|
||||
m_free(rem);
|
||||
}
|
||||
|
||||
void
|
||||
free_attributes(PKT_user_id *uid)
|
||||
{
|
||||
m_free(uid->attribs);
|
||||
m_free(uid->attrib_data);
|
||||
|
||||
uid->attribs=NULL;
|
||||
uid->attrib_data=NULL;
|
||||
uid->attrib_len=0;
|
||||
}
|
||||
|
||||
void
|
||||
free_user_id (PKT_user_id *uid)
|
||||
{
|
||||
assert (uid->ref > 0);
|
||||
if (--uid->ref)
|
||||
return;
|
||||
|
||||
free_attributes(uid);
|
||||
m_free (uid->prefs);
|
||||
m_free (uid->namehash);
|
||||
m_free (uid);
|
||||
}
|
||||
|
||||
void
|
||||
free_compressed( PKT_compressed *zd )
|
||||
{
|
||||
if( zd->buf ) { /* have to skip some bytes */
|
||||
/* don't have any information about the length, so
|
||||
* we assume this is the last packet */
|
||||
while( iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )
|
||||
;
|
||||
}
|
||||
m_free(zd);
|
||||
}
|
||||
|
||||
void
|
||||
free_encrypted( PKT_encrypted *ed )
|
||||
{
|
||||
if( ed->buf ) { /* have to skip some bytes */
|
||||
if( iobuf_in_block_mode(ed->buf) ) {
|
||||
while( iobuf_read( ed->buf, NULL, 1<<30 ) != -1 )
|
||||
;
|
||||
}
|
||||
else {
|
||||
while( ed->len ) { /* skip the packet */
|
||||
int n = iobuf_read( ed->buf, NULL, ed->len );
|
||||
if( n == -1 )
|
||||
ed->len = 0;
|
||||
else
|
||||
ed->len -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_free(ed);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
free_plaintext( PKT_plaintext *pt )
|
||||
{
|
||||
if( pt->buf ) { /* have to skip some bytes */
|
||||
if( iobuf_in_block_mode(pt->buf) ) {
|
||||
while( iobuf_read( pt->buf, NULL, 1<<30 ) != -1 )
|
||||
;
|
||||
}
|
||||
else {
|
||||
while( pt->len ) { /* skip the packet */
|
||||
int n = iobuf_read( pt->buf, NULL, pt->len );
|
||||
if( n == -1 )
|
||||
pt->len = 0;
|
||||
else
|
||||
pt->len -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_free(pt);
|
||||
}
|
||||
|
||||
/****************
|
||||
* Free the packet in pkt.
|
||||
*/
|
||||
void
|
||||
free_packet( PACKET *pkt )
|
||||
{
|
||||
if( !pkt || !pkt->pkt.generic )
|
||||
return;
|
||||
|
||||
if( DBG_MEMORY )
|
||||
log_debug("free_packet() type=%d\n", pkt->pkttype );
|
||||
|
||||
switch( pkt->pkttype ) {
|
||||
case PKT_SIGNATURE:
|
||||
free_seckey_enc( pkt->pkt.signature );
|
||||
break;
|
||||
case PKT_PUBKEY_ENC:
|
||||
free_pubkey_enc( pkt->pkt.pubkey_enc );
|
||||
break;
|
||||
case PKT_SYMKEY_ENC:
|
||||
free_symkey_enc( pkt->pkt.symkey_enc );
|
||||
break;
|
||||
case PKT_PUBLIC_KEY:
|
||||
case PKT_PUBLIC_SUBKEY:
|
||||
free_public_key( pkt->pkt.public_key );
|
||||
break;
|
||||
case PKT_SECRET_KEY:
|
||||
case PKT_SECRET_SUBKEY:
|
||||
free_secret_key( pkt->pkt.secret_key );
|
||||
break;
|
||||
case PKT_COMMENT:
|
||||
free_comment( pkt->pkt.comment );
|
||||
break;
|
||||
case PKT_USER_ID:
|
||||
free_user_id( pkt->pkt.user_id );
|
||||
break;
|
||||
case PKT_COMPRESSED:
|
||||
free_compressed( pkt->pkt.compressed);
|
||||
break;
|
||||
case PKT_ENCRYPTED:
|
||||
case PKT_ENCRYPTED_MDC:
|
||||
free_encrypted( pkt->pkt.encrypted );
|
||||
break;
|
||||
case PKT_PLAINTEXT:
|
||||
free_plaintext( pkt->pkt.plaintext );
|
||||
break;
|
||||
default:
|
||||
m_free( pkt->pkt.generic );
|
||||
break;
|
||||
}
|
||||
pkt->pkt.generic = NULL;
|
||||
}
|
||||
|
||||
/****************
|
||||
* returns 0 if they match.
|
||||
*/
|
||||
int
|
||||
cmp_public_keys( PKT_public_key *a, PKT_public_key *b )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( a->timestamp != b->timestamp )
|
||||
return -1;
|
||||
if( a->version < 4 && a->expiredate != b->expiredate )
|
||||
return -1;
|
||||
if( a->pubkey_algo != b->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_npkey( b->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( a->pkey[i], b->pkey[i] ) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Returns 0 if they match.
|
||||
* We only compare the public parts.
|
||||
*/
|
||||
int
|
||||
cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( a->timestamp != b->timestamp )
|
||||
return -1;
|
||||
if( a->version < 4 && a->expiredate != b->expiredate )
|
||||
return -1;
|
||||
if( a->pubkey_algo != b->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_npkey( b->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( a->skey[i], b->skey[i] ) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Returns 0 if they match.
|
||||
*/
|
||||
int
|
||||
cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( pk->timestamp != sk->timestamp )
|
||||
return -1;
|
||||
if( pk->version < 4 && pk->expiredate != sk->expiredate )
|
||||
return -1;
|
||||
if( pk->pubkey_algo != sk->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_npkey( pk->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( pk->pkey[i] , sk->skey[i] ) )
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
cmp_signatures( PKT_signature *a, PKT_signature *b )
|
||||
{
|
||||
int n, i;
|
||||
|
||||
if( a->keyid[0] != b->keyid[0] )
|
||||
return -1;
|
||||
if( a->keyid[1] != b->keyid[1] )
|
||||
return -1;
|
||||
if( a->pubkey_algo != b->pubkey_algo )
|
||||
return -1;
|
||||
|
||||
n = pubkey_get_nsig( a->pubkey_algo );
|
||||
if( !n )
|
||||
return -1; /* can't compare due to unknown algorithm */
|
||||
for(i=0; i < n; i++ ) {
|
||||
if( mpi_cmp( a->data[i] , b->data[i] ) )
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Returns: true if the user ids do not match
|
||||
*/
|
||||
int
|
||||
cmp_user_ids( PKT_user_id *a, PKT_user_id *b )
|
||||
{
|
||||
int res=1;
|
||||
|
||||
if( a == b )
|
||||
return 0;
|
||||
|
||||
if( a->attrib_data && b->attrib_data )
|
||||
{
|
||||
res = a->attrib_len - b->attrib_len;
|
||||
if( !res )
|
||||
res = memcmp( a->attrib_data, b->attrib_data, a->attrib_len );
|
||||
}
|
||||
else if( !a->attrib_data && !b->attrib_data )
|
||||
{
|
||||
res = a->len - b->len;
|
||||
if( !res )
|
||||
res = memcmp( a->name, b->name, a->len );
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
2611
g10/getkey.c
Normal file
2611
g10/getkey.c
Normal file
File diff suppressed because it is too large
Load diff
396
g10/gpgv.c
Normal file
396
g10/gpgv.c
Normal file
|
@ -0,0 +1,396 @@
|
|||
/* gpgv.c - The GnuPG signature verify utility
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#include <fcntl.h> /* for setmode() */
|
||||
#endif
|
||||
|
||||
#define INCLUDED_BY_MAIN_MODULE 1
|
||||
#include "packet.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "keydb.h"
|
||||
#include "trustdb.h"
|
||||
#include "mpi.h"
|
||||
#include "cipher.h"
|
||||
#include "filter.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
#include "status.h"
|
||||
#include "g10defs.h"
|
||||
|
||||
|
||||
enum cmd_and_opt_values { aNull = 0,
|
||||
oQuiet = 'q',
|
||||
oVerbose = 'v',
|
||||
oBatch = 500,
|
||||
oKeyring,
|
||||
oIgnoreTimeConflict,
|
||||
oStatusFD,
|
||||
oLoggerFD,
|
||||
oHomedir,
|
||||
aTest };
|
||||
|
||||
|
||||
static ARGPARSE_OPTS opts[] = {
|
||||
|
||||
{ 301, NULL, 0, N_("@\nOptions:\n ") },
|
||||
|
||||
{ oVerbose, "verbose", 0, N_("verbose") },
|
||||
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
|
||||
{ oKeyring, "keyring" ,2, N_("take the keys from this keyring")},
|
||||
{ oIgnoreTimeConflict, "ignore-time-conflict", 0,
|
||||
N_("make timestamp conflicts only a warning") },
|
||||
{ oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
|
||||
{ oLoggerFD, "logger-fd",1, "@" },
|
||||
{ oHomedir, "homedir", 2, "@" }, /* defaults to "~/.gnupg" */
|
||||
|
||||
{0} };
|
||||
|
||||
|
||||
|
||||
int g10_errors_seen = 0;
|
||||
|
||||
#ifdef __riscos__
|
||||
RISCOS_GLOBAL_STATICS("GnuPG (gpgv) Heap")
|
||||
#endif /* __riscos__ */
|
||||
|
||||
const char *
|
||||
strusage( int level )
|
||||
{
|
||||
const char *p;
|
||||
switch( level ) {
|
||||
case 11: p = "gpgv (GnuPG)";
|
||||
break;
|
||||
case 13: p = VERSION; break;
|
||||
case 17: p = PRINTABLE_OS_NAME; break;
|
||||
case 19: p =
|
||||
_("Please report bugs to <gnupg-bugs@gnu.org>.\n");
|
||||
break;
|
||||
case 1:
|
||||
case 40: p =
|
||||
_("Usage: gpgv [options] [files] (-h for help)");
|
||||
break;
|
||||
case 41: p =
|
||||
_("Syntax: gpg [options] [files]\n"
|
||||
"Check signatures against known trusted keys\n");
|
||||
break;
|
||||
|
||||
default: p = default_strusage(level);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
i18n_init(void)
|
||||
{
|
||||
#ifdef USE_SIMPLE_GETTEXT
|
||||
set_gettext_file( PACKAGE );
|
||||
#else
|
||||
#ifdef ENABLE_NLS
|
||||
#ifdef HAVE_LC_MESSAGES
|
||||
setlocale( LC_TIME, "" );
|
||||
setlocale( LC_MESSAGES, "" );
|
||||
#else
|
||||
setlocale( LC_ALL, "" );
|
||||
#endif
|
||||
bindtextdomain( PACKAGE, G10_LOCALEDIR );
|
||||
textdomain( PACKAGE );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main( int argc, char **argv )
|
||||
{
|
||||
ARGPARSE_ARGS pargs;
|
||||
int rc=0;
|
||||
STRLIST sl;
|
||||
STRLIST nrings=NULL;
|
||||
unsigned configlineno;
|
||||
|
||||
#ifdef __riscos__
|
||||
riscos_global_defaults();
|
||||
#endif /* __riscos__ */
|
||||
|
||||
log_set_name("gpgv");
|
||||
init_signals();
|
||||
i18n_init();
|
||||
opt.command_fd = -1; /* no command fd */
|
||||
opt.pgp2_workarounds = 1;
|
||||
opt.keyserver_options.auto_key_retrieve = 1;
|
||||
opt.trust_model = TM_ALWAYS;
|
||||
opt.batch = 1;
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
|
||||
#else
|
||||
opt.homedir = getenv("GNUPGHOME");
|
||||
#endif
|
||||
if( !opt.homedir || !*opt.homedir ) {
|
||||
opt.homedir = GNUPG_HOMEDIR;
|
||||
}
|
||||
tty_no_terminal(1);
|
||||
tty_batchmode(1);
|
||||
disable_dotlock();
|
||||
|
||||
set_native_charset (NULL); /* Try to auto set the character set */
|
||||
|
||||
pargs.argc = &argc;
|
||||
pargs.argv = &argv;
|
||||
pargs.flags= 1; /* do not remove the args */
|
||||
while( optfile_parse( NULL, NULL, &configlineno, &pargs, opts) ) {
|
||||
switch( pargs.r_opt ) {
|
||||
case oQuiet: opt.quiet = 1; break;
|
||||
case oVerbose: g10_opt_verbose++;
|
||||
opt.verbose++; opt.list_sigs=1; break;
|
||||
case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
|
||||
case oStatusFD: set_status_fd( pargs.r.ret_int ); break;
|
||||
case oLoggerFD: log_set_logfile( NULL, pargs.r.ret_int ); break;
|
||||
case oHomedir: opt.homedir = pargs.r.ret_str; break;
|
||||
case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
|
||||
default : pargs.err = 2; break;
|
||||
}
|
||||
}
|
||||
|
||||
if( log_get_errorcount(0) )
|
||||
g10_exit(2);
|
||||
|
||||
g10_opt_homedir = opt.homedir;
|
||||
|
||||
if( opt.verbose > 1 )
|
||||
set_packet_list_mode(1);
|
||||
|
||||
if( !nrings ) /* no keyring given: use default one */
|
||||
keydb_add_resource ("trustedkeys" EXTSEP_S "gpg", 0, 0);
|
||||
for(sl = nrings; sl; sl = sl->next )
|
||||
keydb_add_resource (sl->d, 0, 0 );
|
||||
|
||||
FREE_STRLIST(nrings);
|
||||
|
||||
if( (rc = verify_signatures( argc, argv ) ))
|
||||
log_error("verify signatures failed: %s\n", g10_errstr(rc) );
|
||||
|
||||
/* cleanup */
|
||||
g10_exit(0);
|
||||
return 8; /*NEVER REACHED*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
g10_exit( int rc )
|
||||
{
|
||||
rc = rc? rc : log_get_errorcount(0)? 2 :
|
||||
g10_errors_seen? 1 : 0;
|
||||
exit(rc );
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* We have to override the trustcheck from pkclist.c becuase
|
||||
* this utility assumes that all keys in the keyring are trustworthy
|
||||
*/
|
||||
int
|
||||
check_signatures_trust( PKT_signature *sig )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* We don't have the trustdb , so we have to provide some stub functions
|
||||
* instead
|
||||
*/
|
||||
|
||||
int
|
||||
cache_disabled_value(PKT_public_key *pk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
|
||||
unsigned int
|
||||
get_validity (PKT_public_key *pk, PKT_user_id *uid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
trust_value_to_string (unsigned int value)
|
||||
{
|
||||
return "err";
|
||||
}
|
||||
|
||||
/* Stub: */
|
||||
int
|
||||
get_ownertrust_info (PKT_public_key *pk)
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
|
||||
unsigned int
|
||||
get_ownertrust (PKT_public_key *pk)
|
||||
{
|
||||
return TRUST_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* Because we only work with trusted keys, it does not make sense to
|
||||
* get them from a keyserver
|
||||
*/
|
||||
int
|
||||
keyserver_import_keyid( u32 *keyid, void *dummy )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Stub:
|
||||
* No encryption here but mainproc links to these functions.
|
||||
*/
|
||||
int
|
||||
get_session_key( PKT_pubkey_enc *k, DEK *dek )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
/* Stub: */
|
||||
int
|
||||
get_override_session_key( DEK *dek, const char *string )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
/* Stub: */
|
||||
int
|
||||
decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
|
||||
/* Stub:
|
||||
* No interactive commnds, so we don't need the helptexts
|
||||
*/
|
||||
void
|
||||
display_online_help( const char *keyword )
|
||||
{
|
||||
}
|
||||
|
||||
/* Stub:
|
||||
* We don't use secret keys, but getkey.c links to this
|
||||
*/
|
||||
int
|
||||
check_secret_key( PKT_secret_key *sk, int n )
|
||||
{
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
/* Stub:
|
||||
* No secret key, so no passphrase needed
|
||||
*/
|
||||
DEK *
|
||||
passphrase_to_dek( u32 *keyid, int pubkey_algo,
|
||||
int cipher_algo, STRING2KEY *s2k, int mode,
|
||||
const char *tmp, int *canceled)
|
||||
{
|
||||
if (canceled)
|
||||
*canceled = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Stubs to avoid linking to photoid.c */
|
||||
void show_photos(const struct user_attribute *attrs,int count,PKT_public_key *pk) {}
|
||||
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len) {return 0;}
|
||||
char *image_type_to_string(byte type,int string) {return NULL;}
|
||||
|
||||
/* Stubs to void linking to ../cipher/cipher.c */
|
||||
int string_to_cipher_algo( const char *string ) { return 0; }
|
||||
const char *cipher_algo_to_string( int algo ) { return "?";}
|
||||
void disable_cipher_algo( int algo ) {}
|
||||
int check_cipher_algo( int algo ) { return -1;}
|
||||
unsigned int cipher_get_keylen( int algo ) { return 0; }
|
||||
unsigned int cipher_get_blocksize( int algo ) {return 0;}
|
||||
CIPHER_HANDLE cipher_open( int algo, int mode, int secure ) { return NULL;}
|
||||
void cipher_close( CIPHER_HANDLE c ) {}
|
||||
int cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ) { return -1;}
|
||||
void cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ){}
|
||||
void cipher_encrypt( CIPHER_HANDLE c, byte *outbuf,
|
||||
byte *inbuf, unsigned nbytes ) {}
|
||||
void cipher_decrypt( CIPHER_HANDLE c, byte *outbuf,
|
||||
byte *inbuf, unsigned nbytes ) {}
|
||||
void cipher_sync( CIPHER_HANDLE c ) {}
|
||||
|
||||
/* Stubs to avoid linking to ../cipher/random.c */
|
||||
void random_dump_stats(void) {}
|
||||
int quick_random_gen( int onoff ) { return -1;}
|
||||
void randomize_buffer( byte *buffer, size_t length, int level ) {}
|
||||
int random_is_faked() { return -1;}
|
||||
byte *get_random_bits( size_t nbits, int level, int secure ) { return NULL;}
|
||||
void set_random_seed_file( const char *name ) {}
|
||||
void update_random_seed_file() {}
|
||||
void fast_random_poll() {}
|
||||
|
||||
/* Stubs to avoid linking of ../cipher/primegen.c */
|
||||
void register_primegen_progress ( void (*cb)( void *, int), void *cb_data ) {}
|
||||
MPI generate_secret_prime( unsigned nbits ) { return NULL;}
|
||||
MPI generate_public_prime( unsigned nbits ) { return NULL;}
|
||||
MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
|
||||
MPI g, MPI **ret_factors ) { return NULL;}
|
||||
|
||||
/* Do not link to ../cipher/rndlinux.c */
|
||||
void rndlinux_constructor(void) {}
|
||||
|
||||
|
||||
/* Stubs to avoid linking to ../util/ttyio.c */
|
||||
int tty_batchmode( int onoff ) { return 0; }
|
||||
void tty_printf( const char *fmt, ... ) { }
|
||||
void tty_print_string( byte *p, size_t n ) { }
|
||||
void tty_print_utf8_string( byte *p, size_t n ) {}
|
||||
void tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) {}
|
||||
char *tty_get( const char *prompt ) { return NULL;}
|
||||
char *tty_get_hidden( const char *prompt ) {return NULL; }
|
||||
void tty_kill_prompt(void) {}
|
||||
int tty_get_answer_is_yes( const char *prompt ) {return 0;}
|
||||
int tty_no_terminal(int onoff) {return 0;}
|
||||
|
||||
/* We do not do any locking, so use these stubs here */
|
||||
void disable_dotlock(void) {}
|
||||
DOTLOCK create_dotlock( const char *file_to_lock ) { return NULL; }
|
||||
int make_dotlock( DOTLOCK h, long timeout ) { return 0;}
|
||||
int release_dotlock( DOTLOCK h ) {return 0;}
|
||||
void remove_lockfiles(void) {}
|
1879
g10/import.c
Normal file
1879
g10/import.c
Normal file
File diff suppressed because it is too large
Load diff
399
g10/kbnode.c
Normal file
399
g10/kbnode.c
Normal file
|
@ -0,0 +1,399 @@
|
|||
/* kbnode.c - keyblock node utility functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "packet.h"
|
||||
#include "keydb.h"
|
||||
|
||||
#define USE_UNUSED_NODES 1
|
||||
|
||||
static KBNODE unused_nodes;
|
||||
|
||||
static KBNODE
|
||||
alloc_node(void)
|
||||
{
|
||||
KBNODE n;
|
||||
|
||||
n = unused_nodes;
|
||||
if( n )
|
||||
unused_nodes = n->next;
|
||||
else
|
||||
n = m_alloc( sizeof *n );
|
||||
n->next = NULL;
|
||||
n->pkt = NULL;
|
||||
n->flag = 0;
|
||||
n->private_flag=0;
|
||||
n->recno = 0;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
free_node( KBNODE n )
|
||||
{
|
||||
if( n ) {
|
||||
#if USE_UNUSED_NODES
|
||||
n->next = unused_nodes;
|
||||
unused_nodes = n;
|
||||
#else
|
||||
m_free( n );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
KBNODE
|
||||
new_kbnode( PACKET *pkt )
|
||||
{
|
||||
KBNODE n = alloc_node();
|
||||
n->pkt = pkt;
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
KBNODE
|
||||
clone_kbnode( KBNODE node )
|
||||
{
|
||||
KBNODE n = alloc_node();
|
||||
|
||||
n->pkt = node->pkt;
|
||||
n->private_flag = node->private_flag | 2; /* mark cloned */
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
release_kbnode( KBNODE n )
|
||||
{
|
||||
KBNODE n2;
|
||||
|
||||
while( n ) {
|
||||
n2 = n->next;
|
||||
if( !is_cloned_kbnode(n) ) {
|
||||
free_packet( n->pkt );
|
||||
m_free( n->pkt );
|
||||
}
|
||||
free_node( n );
|
||||
n = n2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Delete NODE.
|
||||
* Note: This only works with walk_kbnode!!
|
||||
*/
|
||||
void
|
||||
delete_kbnode( KBNODE node )
|
||||
{
|
||||
node->private_flag |= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Append NODE to ROOT. ROOT must exist!
|
||||
*/
|
||||
void
|
||||
add_kbnode( KBNODE root, KBNODE node )
|
||||
{
|
||||
KBNODE n1;
|
||||
|
||||
for(n1=root; n1->next; n1 = n1->next)
|
||||
;
|
||||
n1->next = node;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Insert NODE into the list after root but before a packet which is not of
|
||||
* type PKTTYPE
|
||||
* (only if PKTTYPE != 0)
|
||||
*/
|
||||
void
|
||||
insert_kbnode( KBNODE root, KBNODE node, int pkttype )
|
||||
{
|
||||
if( !pkttype ) {
|
||||
node->next = root->next;
|
||||
root->next = node;
|
||||
}
|
||||
else {
|
||||
KBNODE n1;
|
||||
|
||||
for(n1=root; n1->next; n1 = n1->next)
|
||||
if( pkttype != n1->next->pkt->pkttype ) {
|
||||
node->next = n1->next;
|
||||
n1->next = node;
|
||||
return;
|
||||
}
|
||||
/* no such packet, append */
|
||||
node->next = NULL;
|
||||
n1->next = node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Find the previous node (if PKTTYPE = 0) or the previous node
|
||||
* with pkttype PKTTYPE in the list starting with ROOT of NODE.
|
||||
*/
|
||||
KBNODE
|
||||
find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
|
||||
{
|
||||
KBNODE n1;
|
||||
|
||||
for (n1=NULL; root && root != node; root = root->next ) {
|
||||
if (!pkttype ||root->pkt->pkttype == pkttype)
|
||||
n1 = root;
|
||||
}
|
||||
return n1;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Ditto, but find the next packet. The behaviour is trivial if
|
||||
* PKTTYPE is 0 but if it is specified, the next node with a packet
|
||||
* of this type is returned. The function has some knowledge about
|
||||
* the valid ordering of packets: e.g. if the next signature packet
|
||||
* is requested, the function will not return one if it encounters
|
||||
* a user-id.
|
||||
*/
|
||||
KBNODE
|
||||
find_next_kbnode( KBNODE node, int pkttype )
|
||||
{
|
||||
for( node=node->next ; node; node = node->next ) {
|
||||
if( !pkttype )
|
||||
return node;
|
||||
else if( pkttype == PKT_USER_ID
|
||||
&& ( node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_KEY ) )
|
||||
return NULL;
|
||||
else if( pkttype == PKT_SIGNATURE
|
||||
&& ( node->pkt->pkttype == PKT_USER_ID
|
||||
|| node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_SECRET_KEY ) )
|
||||
return NULL;
|
||||
else if( node->pkt->pkttype == pkttype )
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
KBNODE
|
||||
find_kbnode( KBNODE node, int pkttype )
|
||||
{
|
||||
for( ; node; node = node->next ) {
|
||||
if( node->pkt->pkttype == pkttype )
|
||||
return node;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Walk through a list of kbnodes. This function returns
|
||||
* the next kbnode for each call; before using the function the first
|
||||
* time, the caller must set CONTEXT to NULL (This has simply the effect
|
||||
* to start with ROOT).
|
||||
*/
|
||||
KBNODE
|
||||
walk_kbnode( KBNODE root, KBNODE *context, int all )
|
||||
{
|
||||
KBNODE n;
|
||||
|
||||
do {
|
||||
if( !*context ) {
|
||||
*context = root;
|
||||
n = root;
|
||||
}
|
||||
else {
|
||||
n = (*context)->next;
|
||||
*context = n;
|
||||
}
|
||||
} while( !all && n && is_deleted_kbnode(n) );
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
clear_kbnode_flags( KBNODE n )
|
||||
{
|
||||
for( ; n; n = n->next ) {
|
||||
n->flag = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Commit changes made to the kblist at ROOT. Note that ROOT my change,
|
||||
* and it is therefore passed by reference.
|
||||
* The function has the effect of removing all nodes marked as deleted.
|
||||
* returns true if any node has been changed
|
||||
*/
|
||||
int
|
||||
commit_kbnode( KBNODE *root )
|
||||
{
|
||||
KBNODE n, nl;
|
||||
int changed = 0;
|
||||
|
||||
for( n = *root, nl=NULL; n; n = nl->next ) {
|
||||
if( is_deleted_kbnode(n) ) {
|
||||
if( n == *root )
|
||||
*root = nl = n->next;
|
||||
else
|
||||
nl->next = n->next;
|
||||
if( !is_cloned_kbnode(n) ) {
|
||||
free_packet( n->pkt );
|
||||
m_free( n->pkt );
|
||||
}
|
||||
free_node( n );
|
||||
changed = 1;
|
||||
}
|
||||
else
|
||||
nl = n;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
void
|
||||
remove_kbnode( KBNODE *root, KBNODE node )
|
||||
{
|
||||
KBNODE n, nl;
|
||||
|
||||
for( n = *root, nl=NULL; n; n = nl->next ) {
|
||||
if( n == node ) {
|
||||
if( n == *root )
|
||||
*root = nl = n->next;
|
||||
else
|
||||
nl->next = n->next;
|
||||
if( !is_cloned_kbnode(n) ) {
|
||||
free_packet( n->pkt );
|
||||
m_free( n->pkt );
|
||||
}
|
||||
free_node( n );
|
||||
}
|
||||
else
|
||||
nl = n;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
|
||||
*/
|
||||
void
|
||||
move_kbnode( KBNODE *root, KBNODE node, KBNODE where )
|
||||
{
|
||||
KBNODE tmp, prev;
|
||||
|
||||
if( !root || !*root || !node )
|
||||
return; /* sanity check */
|
||||
for( prev = *root; prev && prev->next != node; prev = prev->next )
|
||||
;
|
||||
if( !prev )
|
||||
return; /* node is not in the list */
|
||||
|
||||
if( !where ) { /* move node before root */
|
||||
if( node == *root ) /* move to itself */
|
||||
return;
|
||||
prev->next = node->next;
|
||||
node->next = *root;
|
||||
*root = node;
|
||||
return;
|
||||
}
|
||||
/* move it after where */
|
||||
if( node == where )
|
||||
return;
|
||||
tmp = node->next;
|
||||
node->next = where->next;
|
||||
where->next = node;
|
||||
prev->next = tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
dump_kbnode( KBNODE node )
|
||||
{
|
||||
for(; node; node = node->next ) {
|
||||
const char *s;
|
||||
switch( node->pkt->pkttype ) {
|
||||
case 0: s="empty"; break;
|
||||
case PKT_PUBLIC_KEY: s="public-key"; break;
|
||||
case PKT_SECRET_KEY: s="secret-key"; break;
|
||||
case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
|
||||
case PKT_PUBKEY_ENC: s="public-enc"; break;
|
||||
case PKT_SIGNATURE: s="signature"; break;
|
||||
case PKT_ONEPASS_SIG: s="onepass-sig"; break;
|
||||
case PKT_USER_ID: s="user-id"; break;
|
||||
case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
|
||||
case PKT_COMMENT: s="comment"; break;
|
||||
case PKT_RING_TRUST: s="trust"; break;
|
||||
case PKT_PLAINTEXT: s="plaintext"; break;
|
||||
case PKT_COMPRESSED: s="compressed"; break;
|
||||
case PKT_ENCRYPTED: s="encrypted"; break;
|
||||
case PKT_GPG_CONTROL: s="gpg-control"; break;
|
||||
default: s="unknown"; break;
|
||||
}
|
||||
fprintf(stderr, "node %p %02x/%02x type=%s",
|
||||
node, node->flag, node->private_flag, s);
|
||||
if( node->pkt->pkttype == PKT_USER_ID ) {
|
||||
PKT_user_id *uid = node->pkt->pkt.user_id;
|
||||
fputs(" \"", stderr);
|
||||
print_string( stderr, uid->name, uid->len, 0 );
|
||||
fprintf (stderr, "\" %c%c%c%c\n",
|
||||
uid->is_expired? 'e':'.',
|
||||
uid->is_revoked? 'r':'.',
|
||||
uid->created? 'v':'.',
|
||||
uid->is_primary? 'p':'.' );
|
||||
}
|
||||
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
||||
fprintf(stderr, " class=%02x keyid=%08lX ts=%lu\n",
|
||||
node->pkt->pkt.signature->sig_class,
|
||||
(ulong)node->pkt->pkt.signature->keyid[1],
|
||||
(ulong)node->pkt->pkt.signature->timestamp);
|
||||
}
|
||||
else if( node->pkt->pkttype == PKT_GPG_CONTROL ) {
|
||||
fprintf(stderr, " ctrl=%d len=%u\n",
|
||||
node->pkt->pkt.gpg_control->control,
|
||||
(unsigned int)node->pkt->pkt.gpg_control->datalen);
|
||||
}
|
||||
else if( node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
||||
PKT_public_key *pk = node->pkt->pkt.public_key;
|
||||
fprintf(stderr, " keyid=%08lX a=%d u=%d %c%c%c%c\n",
|
||||
(ulong)keyid_from_pk( pk, NULL ),
|
||||
pk->pubkey_algo, pk->pubkey_usage,
|
||||
pk->has_expired? 'e':'.',
|
||||
pk->is_revoked? 'r':'.',
|
||||
pk->is_valid? 'v':'.',
|
||||
pk->mdc_feature? 'm':'.');
|
||||
}
|
||||
else
|
||||
fputs("\n", stderr);
|
||||
}
|
||||
}
|
724
g10/keydb.c
Normal file
724
g10/keydb.c
Normal file
|
@ -0,0 +1,724 @@
|
|||
/* keydb.c - key database dispatcher
|
||||
* Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "options.h"
|
||||
#include "main.h" /*try_make_homedir ()*/
|
||||
#include "packet.h"
|
||||
#include "keyring.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
static int active_handles;
|
||||
|
||||
typedef enum {
|
||||
KEYDB_RESOURCE_TYPE_NONE = 0,
|
||||
KEYDB_RESOURCE_TYPE_KEYRING
|
||||
} KeydbResourceType;
|
||||
#define MAX_KEYDB_RESOURCES 40
|
||||
|
||||
struct resource_item {
|
||||
KeydbResourceType type;
|
||||
union {
|
||||
KEYRING_HANDLE kr;
|
||||
} u;
|
||||
void *token;
|
||||
int secret;
|
||||
};
|
||||
|
||||
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
|
||||
static int used_resources;
|
||||
static void *primary_keyring=NULL;
|
||||
|
||||
struct keydb_handle {
|
||||
int locked;
|
||||
int found;
|
||||
int current;
|
||||
int used; /* items in active */
|
||||
struct resource_item active[MAX_KEYDB_RESOURCES];
|
||||
};
|
||||
|
||||
|
||||
static int lock_all (KEYDB_HANDLE hd);
|
||||
static void unlock_all (KEYDB_HANDLE hd);
|
||||
|
||||
|
||||
/*
|
||||
* Register a resource (which currently may only be a keyring file).
|
||||
* The first keyring which is added by this function is
|
||||
* created if it does not exist.
|
||||
* Note: this function may be called before secure memory is
|
||||
* available.
|
||||
* Flag 1 == force
|
||||
* Flag 2 == default
|
||||
*/
|
||||
int
|
||||
keydb_add_resource (const char *url, int flags, int secret)
|
||||
{
|
||||
static int any_secret, any_public;
|
||||
const char *resname = url;
|
||||
IOBUF iobuf = NULL;
|
||||
char *filename = NULL;
|
||||
int force=(flags&1);
|
||||
int rc = 0;
|
||||
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
|
||||
void *token;
|
||||
|
||||
/* Do we have an URL?
|
||||
* gnupg-ring:filename := this is a plain keyring
|
||||
* filename := See what is is, but create as plain keyring.
|
||||
*/
|
||||
if (strlen (resname) > 11) {
|
||||
if (!strncmp( resname, "gnupg-ring:", 11) ) {
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
resname += 11;
|
||||
}
|
||||
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
|
||||
else if (strchr (resname, ':')) {
|
||||
log_error ("invalid key resource URL `%s'\n", url );
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
}
|
||||
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
|
||||
}
|
||||
|
||||
if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
|
||||
if (strchr(resname, DIRSEP_C) )
|
||||
filename = make_filename (resname, NULL);
|
||||
else
|
||||
filename = make_filename (opt.homedir, resname, NULL);
|
||||
}
|
||||
else
|
||||
filename = m_strdup (resname);
|
||||
|
||||
if (!force)
|
||||
force = secret? !any_secret : !any_public;
|
||||
|
||||
/* see whether we can determine the filetype */
|
||||
if (rt == KEYDB_RESOURCE_TYPE_NONE) {
|
||||
FILE *fp = fopen( filename, "rb" );
|
||||
|
||||
if (fp) {
|
||||
u32 magic;
|
||||
|
||||
if (fread( &magic, 4, 1, fp) == 1 ) {
|
||||
if (magic == 0x13579ace || magic == 0xce9a5713)
|
||||
; /* GDBM magic - no more support */
|
||||
else
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
}
|
||||
else /* maybe empty: assume ring */
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
fclose( fp );
|
||||
}
|
||||
else /* no file yet: create ring */
|
||||
rt = KEYDB_RESOURCE_TYPE_KEYRING;
|
||||
}
|
||||
|
||||
switch (rt) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
log_error ("unknown type of key resource `%s'\n", url );
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
if (access(filename, F_OK))
|
||||
{ /* file does not exist */
|
||||
mode_t oldmask;
|
||||
char *last_slash_in_filename;
|
||||
|
||||
if (!force)
|
||||
{
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
last_slash_in_filename = strrchr (filename, DIRSEP_C);
|
||||
*last_slash_in_filename = 0;
|
||||
if (access(filename, F_OK))
|
||||
{ /* On the first time we try to create the default
|
||||
homedir and check again. */
|
||||
static int tried;
|
||||
|
||||
if (!tried)
|
||||
{
|
||||
tried = 1;
|
||||
try_make_homedir (filename);
|
||||
}
|
||||
if (access (filename, F_OK))
|
||||
{
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
*last_slash_in_filename = DIRSEP_C;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
*last_slash_in_filename = DIRSEP_C;
|
||||
|
||||
oldmask=umask(077);
|
||||
iobuf = iobuf_create (filename);
|
||||
umask(oldmask);
|
||||
if (!iobuf)
|
||||
{
|
||||
log_error ( _("error creating keyring `%s': %s\n"),
|
||||
filename, strerror(errno));
|
||||
rc = G10ERR_OPEN_FILE;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!opt.quiet)
|
||||
log_info (_("keyring `%s' created\n"), filename);
|
||||
iobuf_close (iobuf);
|
||||
iobuf = NULL;
|
||||
/* must invalidate that ugly cache */
|
||||
iobuf_ioctl (NULL, 2, 0, (char*)filename);
|
||||
} /* end file creation */
|
||||
|
||||
if(keyring_register_filename (filename, secret, &token))
|
||||
{
|
||||
if (used_resources >= MAX_KEYDB_RESOURCES)
|
||||
rc = G10ERR_RESOURCE_LIMIT;
|
||||
else
|
||||
{
|
||||
if(flags&2)
|
||||
primary_keyring=token;
|
||||
all_resources[used_resources].type = rt;
|
||||
all_resources[used_resources].u.kr = NULL; /* Not used here */
|
||||
all_resources[used_resources].token = token;
|
||||
all_resources[used_resources].secret = secret;
|
||||
used_resources++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This keyring was already registered, so ignore it.
|
||||
However, we can still mark it as primary even if it was
|
||||
already registered. */
|
||||
if(flags&2)
|
||||
primary_keyring=token;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error ("resource type of `%s' not supported\n", url);
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* fixme: check directory permissions and print a warning */
|
||||
|
||||
leave:
|
||||
if (rc)
|
||||
log_error ("keyblock resource `%s': %s\n", filename, g10_errstr(rc));
|
||||
else if (secret)
|
||||
any_secret = 1;
|
||||
else
|
||||
any_public = 1;
|
||||
m_free (filename);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
KEYDB_HANDLE
|
||||
keydb_new (int secret)
|
||||
{
|
||||
KEYDB_HANDLE hd;
|
||||
int i, j;
|
||||
|
||||
hd = m_alloc_clear (sizeof *hd);
|
||||
hd->found = -1;
|
||||
|
||||
assert (used_resources <= MAX_KEYDB_RESOURCES);
|
||||
for (i=j=0; i < used_resources; i++)
|
||||
{
|
||||
if (!all_resources[i].secret != !secret)
|
||||
continue;
|
||||
switch (all_resources[i].type)
|
||||
{
|
||||
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
hd->active[j].type = all_resources[i].type;
|
||||
hd->active[j].token = all_resources[i].token;
|
||||
hd->active[j].secret = all_resources[i].secret;
|
||||
hd->active[j].u.kr = keyring_new (all_resources[i].token, secret);
|
||||
if (!hd->active[j].u.kr) {
|
||||
m_free (hd);
|
||||
return NULL; /* fixme: release all previously allocated handles*/
|
||||
}
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hd->used = j;
|
||||
|
||||
active_handles++;
|
||||
return hd;
|
||||
}
|
||||
|
||||
void
|
||||
keydb_release (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hd)
|
||||
return;
|
||||
assert (active_handles > 0);
|
||||
active_handles--;
|
||||
|
||||
unlock_all (hd);
|
||||
for (i=0; i < hd->used; i++) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
keyring_release (hd->active[i].u.kr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_free (hd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the name of the current resource. This is function first
|
||||
* looks for the last found found, then for the current search
|
||||
* position, and last returns the first available resource. The
|
||||
* returned string is only valid as long as the handle exists. This
|
||||
* function does only return NULL if no handle is specified, in all
|
||||
* other error cases an empty string is returned.
|
||||
*/
|
||||
const char *
|
||||
keydb_get_resource_name (KEYDB_HANDLE hd)
|
||||
{
|
||||
int idx;
|
||||
const char *s = NULL;
|
||||
|
||||
if (!hd)
|
||||
return NULL;
|
||||
|
||||
if ( hd->found >= 0 && hd->found < hd->used)
|
||||
idx = hd->found;
|
||||
else if ( hd->current >= 0 && hd->current < hd->used)
|
||||
idx = hd->current;
|
||||
else
|
||||
idx = 0;
|
||||
|
||||
switch (hd->active[idx].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
s = NULL;
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
s = keyring_get_resource_name (hd->active[idx].u.kr);
|
||||
break;
|
||||
}
|
||||
|
||||
return s? s: "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
lock_all (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
for (i=0; !rc && i < hd->used; i++) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_lock (hd->active[i].u.kr, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
/* revert the already set locks */
|
||||
for (i--; i >= 0; i--) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
keyring_lock (hd->active[i].u.kr, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
hd->locked = 1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
unlock_all (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hd->locked)
|
||||
return;
|
||||
|
||||
for (i=hd->used-1; i >= 0; i--) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
keyring_lock (hd->active[i].u.kr, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hd->locked = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the last found keyring. Caller must free it.
|
||||
* The returned keyblock has the kbode flag bit 0 set for the node with
|
||||
* the public key used to locate the keyblock or flag bit 1 set for
|
||||
* the user ID node.
|
||||
*/
|
||||
int
|
||||
keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if ( hd->found < 0 || hd->found >= hd->used)
|
||||
return -1; /* nothing found */
|
||||
|
||||
switch (hd->active[hd->found].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* update the current keyblock with KB
|
||||
*/
|
||||
int
|
||||
keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if ( hd->found < 0 || hd->found >= hd->used)
|
||||
return -1; /* nothing found */
|
||||
|
||||
if( opt.dry_run )
|
||||
return 0;
|
||||
|
||||
rc = lock_all (hd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (hd->active[hd->found].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_all (hd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Insert a new KB into one of the resources.
|
||||
*/
|
||||
int
|
||||
keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb)
|
||||
{
|
||||
int rc = -1;
|
||||
int idx;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if( opt.dry_run )
|
||||
return 0;
|
||||
|
||||
if ( hd->found >= 0 && hd->found < hd->used)
|
||||
idx = hd->found;
|
||||
else if ( hd->current >= 0 && hd->current < hd->used)
|
||||
idx = hd->current;
|
||||
else
|
||||
return G10ERR_GENERAL;
|
||||
|
||||
rc = lock_all (hd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (hd->active[idx].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_all (hd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The current keyblock will be deleted.
|
||||
*/
|
||||
int
|
||||
keydb_delete_keyblock (KEYDB_HANDLE hd)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
if ( hd->found < 0 || hd->found >= hd->used)
|
||||
return -1; /* nothing found */
|
||||
|
||||
if( opt.dry_run )
|
||||
return 0;
|
||||
|
||||
rc = lock_all (hd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (hd->active[hd->found].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
rc = G10ERR_GENERAL; /* oops */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
|
||||
break;
|
||||
}
|
||||
|
||||
unlock_all (hd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Locate the default writable key resource, so that the next
|
||||
* operation (which is only relevant for inserts) will be done on this
|
||||
* resource.
|
||||
*/
|
||||
int
|
||||
keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* If we have a primary set, try that one first */
|
||||
if(primary_keyring)
|
||||
{
|
||||
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
||||
{
|
||||
if(hd->active[hd->current].token==primary_keyring)
|
||||
{
|
||||
if(keyring_is_writable (hd->active[hd->current].token))
|
||||
return 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = keydb_search_reset (hd); /* this does reset hd->current */
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
|
||||
{
|
||||
switch (hd->active[hd->current].type)
|
||||
{
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
BUG();
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
if (keyring_is_writable (hd->active[hd->current].token))
|
||||
return 0; /* found (hd->current is set to it) */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rebuild the caches of all key resources.
|
||||
*/
|
||||
void
|
||||
keydb_rebuild_caches (void)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
for (i=0; i < used_resources; i++)
|
||||
{
|
||||
if (all_resources[i].secret)
|
||||
continue;
|
||||
switch (all_resources[i].type)
|
||||
{
|
||||
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_rebuild_cache (all_resources[i].token);
|
||||
if (rc)
|
||||
log_error (_("failed to rebuild keyring cache: %s\n"),
|
||||
g10_errstr (rc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Start the next search on this handle right at the beginning
|
||||
*/
|
||||
int
|
||||
keydb_search_reset (KEYDB_HANDLE hd)
|
||||
{
|
||||
int i, rc = 0;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
hd->current = 0;
|
||||
hd->found = -1;
|
||||
/* and reset all resources */
|
||||
for (i=0; !rc && i < hd->used; i++) {
|
||||
switch (hd->active[i].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_search_reset (hd->active[i].u.kr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search through all keydb resources, starting at the current position,
|
||||
* for a keyblock which contains one of the keys described in the DESC array.
|
||||
*/
|
||||
int
|
||||
keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (!hd)
|
||||
return G10ERR_INV_ARG;
|
||||
|
||||
while (rc == -1 && hd->current >= 0 && hd->current < hd->used) {
|
||||
switch (hd->active[hd->current].type) {
|
||||
case KEYDB_RESOURCE_TYPE_NONE:
|
||||
BUG(); /* we should never see it here */
|
||||
break;
|
||||
case KEYDB_RESOURCE_TYPE_KEYRING:
|
||||
rc = keyring_search (hd->active[hd->current].u.kr, desc,
|
||||
ndesc, descindex);
|
||||
break;
|
||||
}
|
||||
if (rc == -1) /* EOF -> switch to next resource */
|
||||
hd->current++;
|
||||
else if (!rc)
|
||||
hd->found = hd->current;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_first (KEYDB_HANDLE hd)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_FIRST;
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_next (KEYDB_HANDLE hd)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_NEXT;
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
|
||||
desc.u.kid[0] = kid[0];
|
||||
desc.u.kid[1] = kid[1];
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
||||
|
||||
int
|
||||
keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
|
||||
{
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
memset (&desc, 0, sizeof desc);
|
||||
desc.mode = KEYDB_SEARCH_MODE_FPR;
|
||||
memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
|
||||
return keydb_search (hd, &desc, 1);
|
||||
}
|
278
g10/keydb.h
Normal file
278
g10/keydb.h
Normal file
|
@ -0,0 +1,278 @@
|
|||
/* keydb.h - Key database
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_KEYDB_H
|
||||
#define G10_KEYDB_H
|
||||
|
||||
#include "types.h"
|
||||
#include "global.h"
|
||||
#include "packet.h"
|
||||
#include "cipher.h"
|
||||
|
||||
/* What qualifies as a certification (rather than a signature?) */
|
||||
#define IS_CERT(s) (IS_KEY_SIG(s) || IS_UID_SIG(s) || IS_SUBKEY_SIG(s) \
|
||||
|| IS_KEY_REV(s) || IS_UID_REV(s) || IS_SUBKEY_REV(s))
|
||||
#define IS_SIG(s) (!IS_CERT(s))
|
||||
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
|
||||
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
|
||||
#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
|
||||
#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
|
||||
#define IS_UID_REV(s) ((s)->sig_class == 0x30)
|
||||
#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
|
||||
|
||||
struct getkey_ctx_s;
|
||||
typedef struct getkey_ctx_s *GETKEY_CTX;
|
||||
|
||||
/****************
|
||||
* A Keyblock is all packets which form an entire certificate;
|
||||
* i.e. the public key, certificate, trust packets, user ids,
|
||||
* signatures, and subkey.
|
||||
*
|
||||
* This structure is also used to bind arbitrary packets together.
|
||||
*/
|
||||
|
||||
struct kbnode_struct {
|
||||
KBNODE next;
|
||||
PACKET *pkt;
|
||||
int flag;
|
||||
int private_flag;
|
||||
ulong recno; /* used while updating the trustdb */
|
||||
};
|
||||
|
||||
#define is_deleted_kbnode(a) ((a)->private_flag & 1)
|
||||
#define is_cloned_kbnode(a) ((a)->private_flag & 2)
|
||||
|
||||
|
||||
enum resource_type {
|
||||
rt_UNKNOWN = 0,
|
||||
rt_RING = 1
|
||||
};
|
||||
|
||||
|
||||
/****************
|
||||
* A data structre to hold information about the external position
|
||||
* of a keyblock.
|
||||
*/
|
||||
struct keyblock_pos_struct {
|
||||
int resno; /* resource number */
|
||||
enum resource_type rt;
|
||||
off_t offset; /* position information */
|
||||
unsigned count; /* length of the keyblock in packets */
|
||||
IOBUF fp; /* used by enum_keyblocks */
|
||||
int secret; /* working on a secret keyring */
|
||||
PACKET *pkt; /* ditto */
|
||||
int valid;
|
||||
};
|
||||
typedef struct keyblock_pos_struct KBPOS;
|
||||
|
||||
/* structure to hold a couple of public key certificates */
|
||||
typedef struct pk_list *PK_LIST;
|
||||
struct pk_list {
|
||||
PK_LIST next;
|
||||
PKT_public_key *pk;
|
||||
int flags; /* flag bit 1==throw_keyid */
|
||||
};
|
||||
|
||||
/* structure to hold a couple of secret key certificates */
|
||||
typedef struct sk_list *SK_LIST;
|
||||
struct sk_list {
|
||||
SK_LIST next;
|
||||
PKT_secret_key *sk;
|
||||
int mark; /* not used */
|
||||
};
|
||||
|
||||
/* structure to collect all information which can be used to
|
||||
* identify a public key */
|
||||
typedef struct pubkey_find_info *PUBKEY_FIND_INFO;
|
||||
struct pubkey_find_info {
|
||||
u32 keyid[2];
|
||||
unsigned nbits;
|
||||
byte pubkey_algo;
|
||||
byte fingerprint[MAX_FINGERPRINT_LEN];
|
||||
char userid[1];
|
||||
};
|
||||
|
||||
|
||||
typedef struct keydb_handle *KEYDB_HANDLE;
|
||||
|
||||
typedef enum {
|
||||
KEYDB_SEARCH_MODE_NONE,
|
||||
KEYDB_SEARCH_MODE_EXACT,
|
||||
KEYDB_SEARCH_MODE_SUBSTR,
|
||||
KEYDB_SEARCH_MODE_MAIL,
|
||||
KEYDB_SEARCH_MODE_MAILSUB,
|
||||
KEYDB_SEARCH_MODE_MAILEND,
|
||||
KEYDB_SEARCH_MODE_WORDS,
|
||||
KEYDB_SEARCH_MODE_SHORT_KID,
|
||||
KEYDB_SEARCH_MODE_LONG_KID,
|
||||
KEYDB_SEARCH_MODE_FPR16,
|
||||
KEYDB_SEARCH_MODE_FPR20,
|
||||
KEYDB_SEARCH_MODE_FPR,
|
||||
KEYDB_SEARCH_MODE_FIRST,
|
||||
KEYDB_SEARCH_MODE_NEXT
|
||||
} KeydbSearchMode;
|
||||
|
||||
struct keydb_search_desc {
|
||||
KeydbSearchMode mode;
|
||||
int (*skipfnc)(void *,u32*);
|
||||
void *skipfncvalue;
|
||||
union {
|
||||
const char *name;
|
||||
char fpr[MAX_FINGERPRINT_LEN];
|
||||
u32 kid[2];
|
||||
} u;
|
||||
int exact;
|
||||
};
|
||||
|
||||
/*-- keydb.c --*/
|
||||
|
||||
/*
|
||||
Flag 1 == force
|
||||
Flag 2 == default
|
||||
*/
|
||||
int keydb_add_resource (const char *url, int flags, int secret);
|
||||
KEYDB_HANDLE keydb_new (int secret);
|
||||
void keydb_release (KEYDB_HANDLE hd);
|
||||
const char *keydb_get_resource_name (KEYDB_HANDLE hd);
|
||||
int keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
|
||||
int keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb);
|
||||
int keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb);
|
||||
int keydb_delete_keyblock (KEYDB_HANDLE hd);
|
||||
int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved);
|
||||
void keydb_rebuild_caches (void);
|
||||
int keydb_search_reset (KEYDB_HANDLE hd);
|
||||
#define keydb_search(a,b,c) keydb_search2((a),(b),(c),NULL)
|
||||
int keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex);
|
||||
int keydb_search_first (KEYDB_HANDLE hd);
|
||||
int keydb_search_next (KEYDB_HANDLE hd);
|
||||
int keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
|
||||
int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
|
||||
|
||||
|
||||
/*-- pkclist.c --*/
|
||||
void show_revocation_reason( PKT_public_key *pk, int mode );
|
||||
int check_signatures_trust( PKT_signature *sig );
|
||||
void release_pk_list( PK_LIST pk_list );
|
||||
int build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned use );
|
||||
int algo_available( preftype_t preftype, int algo, void *hint );
|
||||
int select_algo_from_prefs( PK_LIST pk_list, int preftype,
|
||||
int request, void *hint );
|
||||
int select_mdc_from_pklist (PK_LIST pk_list);
|
||||
|
||||
/*-- skclist.c --*/
|
||||
void release_sk_list( SK_LIST sk_list );
|
||||
int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list,
|
||||
int unlock, unsigned use );
|
||||
|
||||
/*-- passphrase.h --*/
|
||||
int have_static_passphrase(void);
|
||||
void read_passphrase_from_fd( int fd );
|
||||
void passphrase_clear_cache ( u32 *keyid, int algo );
|
||||
DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo,
|
||||
int cipher_algo, STRING2KEY *s2k, int mode,
|
||||
const char *tryagain_text, int *canceled);
|
||||
void set_next_passphrase( const char *s );
|
||||
char *get_last_passphrase(void);
|
||||
|
||||
/*-- getkey.c --*/
|
||||
int classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc);
|
||||
void cache_public_key( PKT_public_key *pk );
|
||||
void getkey_disable_caches(void);
|
||||
int get_pubkey( PKT_public_key *pk, u32 *keyid );
|
||||
int get_pubkey_fast ( PKT_public_key *pk, u32 *keyid );
|
||||
KBNODE get_pubkeyblock( u32 *keyid );
|
||||
int get_pubkey_byname( PKT_public_key *pk, const char *name,
|
||||
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
|
||||
int include_disabled );
|
||||
int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk,
|
||||
STRLIST names, KBNODE *ret_keyblock );
|
||||
int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
|
||||
void get_pubkey_end( GETKEY_CTX ctx );
|
||||
int get_seckey( PKT_secret_key *sk, u32 *keyid );
|
||||
int get_primary_seckey( PKT_secret_key *sk, u32 *keyid );
|
||||
int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint,
|
||||
size_t fprint_len );
|
||||
int get_pubkey_byfprint_fast (PKT_public_key *pk,
|
||||
const byte *fprint, size_t fprint_len);
|
||||
int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
|
||||
size_t fprint_len );
|
||||
int get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid );
|
||||
int seckey_available( u32 *keyid );
|
||||
int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
|
||||
int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,
|
||||
STRLIST names, KBNODE *ret_keyblock );
|
||||
int get_seckey_byfprint( PKT_secret_key *sk,
|
||||
const byte *fprint, size_t fprint_len);
|
||||
int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock );
|
||||
void get_seckey_end( GETKEY_CTX ctx );
|
||||
int enum_secret_keys( void **context, PKT_secret_key *sk,
|
||||
int with_subkeys, int with_spm );
|
||||
void merge_keys_and_selfsig( KBNODE keyblock );
|
||||
char*get_user_id_string( u32 *keyid );
|
||||
char*get_user_id_string_printable( u32 *keyid );
|
||||
char*get_long_user_id_string( u32 *keyid );
|
||||
char*get_user_id( u32 *keyid, size_t *rn );
|
||||
char*get_user_id_printable( u32 *keyid );
|
||||
KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
|
||||
|
||||
/*-- keyid.c --*/
|
||||
int pubkey_letter( int algo );
|
||||
u32 keyid_from_sk( PKT_secret_key *sk, u32 *keyid );
|
||||
u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid );
|
||||
u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
|
||||
u32 keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid );
|
||||
byte *namehash_from_uid(PKT_user_id *uid);
|
||||
unsigned nbits_from_pk( PKT_public_key *pk );
|
||||
unsigned nbits_from_sk( PKT_secret_key *sk );
|
||||
const char *datestr_from_pk( PKT_public_key *pk );
|
||||
const char *datestr_from_sk( PKT_secret_key *sk );
|
||||
const char *datestr_from_sig( PKT_signature *sig );
|
||||
const char *expirestr_from_pk( PKT_public_key *pk );
|
||||
const char *expirestr_from_sk( PKT_secret_key *sk );
|
||||
const char *expirestr_from_sig( PKT_signature *sig );
|
||||
|
||||
const char *colon_strtime (u32 t);
|
||||
const char *colon_datestr_from_pk (PKT_public_key *pk);
|
||||
const char *colon_datestr_from_sk (PKT_secret_key *sk);
|
||||
const char *colon_datestr_from_sig (PKT_signature *sig);
|
||||
const char *colon_expirestr_from_sig (PKT_signature *sig);
|
||||
|
||||
byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len );
|
||||
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
|
||||
|
||||
/*-- kbnode.c --*/
|
||||
KBNODE new_kbnode( PACKET *pkt );
|
||||
KBNODE clone_kbnode( KBNODE node );
|
||||
void release_kbnode( KBNODE n );
|
||||
void delete_kbnode( KBNODE node );
|
||||
void add_kbnode( KBNODE root, KBNODE node );
|
||||
void insert_kbnode( KBNODE root, KBNODE node, int pkttype );
|
||||
void move_kbnode( KBNODE *root, KBNODE node, KBNODE where );
|
||||
void remove_kbnode( KBNODE *root, KBNODE node );
|
||||
KBNODE find_prev_kbnode( KBNODE root, KBNODE node, int pkttype );
|
||||
KBNODE find_next_kbnode( KBNODE node, int pkttype );
|
||||
KBNODE find_kbnode( KBNODE node, int pkttype );
|
||||
KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
|
||||
void clear_kbnode_flags( KBNODE n );
|
||||
int commit_kbnode( KBNODE *root );
|
||||
void dump_kbnode( KBNODE node );
|
||||
|
||||
#endif /*G10_KEYDB_H*/
|
3672
g10/keyedit.c
Normal file
3672
g10/keyedit.c
Normal file
File diff suppressed because it is too large
Load diff
2523
g10/keygen.c
Normal file
2523
g10/keygen.c
Normal file
File diff suppressed because it is too large
Load diff
518
g10/keyid.c
Normal file
518
g10/keyid.c
Normal file
|
@ -0,0 +1,518 @@
|
|||
/* keyid.c - key ID and fingerprint handling
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "packet.h"
|
||||
#include "options.h"
|
||||
#include "mpi.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
int
|
||||
pubkey_letter( int algo )
|
||||
{
|
||||
switch( algo ) {
|
||||
case PUBKEY_ALGO_RSA: return 'R' ;
|
||||
case PUBKEY_ALGO_RSA_E: return 'r' ;
|
||||
case PUBKEY_ALGO_RSA_S: return 's' ;
|
||||
case PUBKEY_ALGO_ELGAMAL_E: return 'g';
|
||||
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
|
||||
case PUBKEY_ALGO_DSA: return 'D' ;
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
|
||||
static MD_HANDLE
|
||||
do_fingerprint_md( PKT_public_key *pk )
|
||||
{
|
||||
MD_HANDLE md;
|
||||
unsigned n;
|
||||
unsigned nb[PUBKEY_MAX_NPKEY];
|
||||
unsigned nn[PUBKEY_MAX_NPKEY];
|
||||
byte *pp[PUBKEY_MAX_NPKEY];
|
||||
int i;
|
||||
int npkey = pubkey_get_npkey( pk->pubkey_algo );
|
||||
|
||||
md = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0);
|
||||
n = pk->version < 4 ? 8 : 6;
|
||||
for(i=0; i < npkey; i++ ) {
|
||||
nb[i] = mpi_get_nbits(pk->pkey[i]);
|
||||
pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
|
||||
n += 2 + nn[i];
|
||||
}
|
||||
|
||||
md_putc( md, 0x99 ); /* ctb */
|
||||
md_putc( md, n >> 8 ); /* 2 byte length header */
|
||||
md_putc( md, n );
|
||||
if( pk->version < 4 )
|
||||
md_putc( md, 3 );
|
||||
else
|
||||
md_putc( md, 4 );
|
||||
|
||||
{ u32 a = pk->timestamp;
|
||||
md_putc( md, a >> 24 );
|
||||
md_putc( md, a >> 16 );
|
||||
md_putc( md, a >> 8 );
|
||||
md_putc( md, a );
|
||||
}
|
||||
if( pk->version < 4 ) {
|
||||
u16 a;
|
||||
|
||||
if( pk->expiredate )
|
||||
a = (u16)((pk->expiredate - pk->timestamp) / 86400L);
|
||||
else
|
||||
a = 0;
|
||||
md_putc( md, a >> 8 );
|
||||
md_putc( md, a );
|
||||
}
|
||||
md_putc( md, pk->pubkey_algo );
|
||||
for(i=0; i < npkey; i++ ) {
|
||||
md_putc( md, nb[i]>>8);
|
||||
md_putc( md, nb[i] );
|
||||
md_write( md, pp[i], nn[i] );
|
||||
m_free(pp[i]);
|
||||
}
|
||||
md_final( md );
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
static MD_HANDLE
|
||||
do_fingerprint_md_sk( PKT_secret_key *sk )
|
||||
{
|
||||
PKT_public_key pk;
|
||||
int npkey = pubkey_get_npkey( sk->pubkey_algo ); /* npkey is correct! */
|
||||
int i;
|
||||
|
||||
pk.pubkey_algo = sk->pubkey_algo;
|
||||
pk.version = sk->version;
|
||||
pk.timestamp = sk->timestamp;
|
||||
pk.expiredate = sk->expiredate;
|
||||
pk.pubkey_algo = sk->pubkey_algo;
|
||||
for( i=0; i < npkey; i++ )
|
||||
pk.pkey[i] = sk->skey[i];
|
||||
return do_fingerprint_md( &pk );
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Get the keyid from the secret key and put it into keyid
|
||||
* if this is not NULL. Return the 32 low bits of the keyid.
|
||||
*/
|
||||
u32
|
||||
keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
|
||||
{
|
||||
u32 lowbits;
|
||||
u32 dummy_keyid[2];
|
||||
|
||||
if( !keyid )
|
||||
keyid = dummy_keyid;
|
||||
|
||||
if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
|
||||
lowbits = pubkey_get_npkey(sk->pubkey_algo) ?
|
||||
mpi_get_keyid( sk->skey[0], keyid ) : 0; /* take n */
|
||||
}
|
||||
else {
|
||||
const byte *dp;
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md_sk(sk);
|
||||
dp = md_read( md, 0 );
|
||||
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
lowbits = keyid[1];
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
return lowbits;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Get the keyid from the public key and put it into keyid
|
||||
* if this is not NULL. Return the 32 low bits of the keyid.
|
||||
*/
|
||||
u32
|
||||
keyid_from_pk( PKT_public_key *pk, u32 *keyid )
|
||||
{
|
||||
u32 lowbits;
|
||||
u32 dummy_keyid[2];
|
||||
|
||||
if( !keyid )
|
||||
keyid = dummy_keyid;
|
||||
|
||||
if( pk->keyid[0] || pk->keyid[1] ) {
|
||||
keyid[0] = pk->keyid[0];
|
||||
keyid[1] = pk->keyid[1];
|
||||
lowbits = keyid[1];
|
||||
}
|
||||
else if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
|
||||
lowbits = pubkey_get_npkey(pk->pubkey_algo) ?
|
||||
mpi_get_keyid( pk->pkey[0], keyid ) : 0 ; /* from n */
|
||||
pk->keyid[0] = keyid[0];
|
||||
pk->keyid[1] = keyid[1];
|
||||
}
|
||||
else {
|
||||
const byte *dp;
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md(pk);
|
||||
dp = md_read( md, 0 );
|
||||
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
lowbits = keyid[1];
|
||||
md_close(md);
|
||||
pk->keyid[0] = keyid[0];
|
||||
pk->keyid[1] = keyid[1];
|
||||
}
|
||||
|
||||
return lowbits;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Get the keyid from the fingerprint. This function is simple for most
|
||||
* keys, but has to do a keylookup for old stayle keys.
|
||||
*/
|
||||
u32
|
||||
keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid )
|
||||
{
|
||||
u32 dummy_keyid[2];
|
||||
|
||||
if( !keyid )
|
||||
keyid = dummy_keyid;
|
||||
|
||||
if( fprint_len != 20 ) {
|
||||
/* This is special as we have to lookup the key first */
|
||||
PKT_public_key pk;
|
||||
int rc;
|
||||
|
||||
memset( &pk, 0, sizeof pk );
|
||||
rc = get_pubkey_byfprint( &pk, fprint, fprint_len );
|
||||
if( rc ) {
|
||||
log_error("Oops: keyid_from_fingerprint: no pubkey\n");
|
||||
keyid[0] = 0;
|
||||
keyid[1] = 0;
|
||||
}
|
||||
else
|
||||
keyid_from_pk( &pk, keyid );
|
||||
}
|
||||
else {
|
||||
const byte *dp = fprint;
|
||||
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
}
|
||||
|
||||
return keyid[1];
|
||||
}
|
||||
|
||||
|
||||
u32
|
||||
keyid_from_sig( PKT_signature *sig, u32 *keyid )
|
||||
{
|
||||
if( keyid ) {
|
||||
keyid[0] = sig->keyid[0];
|
||||
keyid[1] = sig->keyid[1];
|
||||
}
|
||||
return sig->keyid[1];
|
||||
}
|
||||
|
||||
byte *
|
||||
namehash_from_uid(PKT_user_id *uid)
|
||||
{
|
||||
if(uid->namehash==NULL)
|
||||
{
|
||||
uid->namehash=m_alloc(20);
|
||||
|
||||
if(uid->attrib_data)
|
||||
rmd160_hash_buffer(uid->namehash,uid->attrib_data,uid->attrib_len);
|
||||
else
|
||||
rmd160_hash_buffer(uid->namehash,uid->name,uid->len);
|
||||
}
|
||||
|
||||
return uid->namehash;
|
||||
}
|
||||
|
||||
/****************
|
||||
* return the number of bits used in the pk
|
||||
*/
|
||||
unsigned
|
||||
nbits_from_pk( PKT_public_key *pk )
|
||||
{
|
||||
return pubkey_nbits( pk->pubkey_algo, pk->pkey );
|
||||
}
|
||||
|
||||
/****************
|
||||
* return the number of bits used in the sk
|
||||
*/
|
||||
unsigned
|
||||
nbits_from_sk( PKT_secret_key *sk )
|
||||
{
|
||||
return pubkey_nbits( sk->pubkey_algo, sk->skey );
|
||||
}
|
||||
|
||||
static const char *
|
||||
mk_datestr (char *buffer, time_t atime)
|
||||
{
|
||||
struct tm *tp;
|
||||
|
||||
if ( atime < 0 ) /* 32 bit time_t and after 2038-01-19 */
|
||||
strcpy (buffer, "????" "-??" "-??"); /* mark this as invalid */
|
||||
else {
|
||||
tp = gmtime (&atime);
|
||||
sprintf (buffer,"%04d-%02d-%02d",
|
||||
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/****************
|
||||
* return a string with the creation date of the pk
|
||||
* Note: this is alloced in a static buffer.
|
||||
* Format is: yyyy-mm-dd
|
||||
*/
|
||||
const char *
|
||||
datestr_from_pk( PKT_public_key *pk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime = pk->timestamp;
|
||||
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
datestr_from_sk( PKT_secret_key *sk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime = sk->timestamp;
|
||||
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
datestr_from_sig( PKT_signature *sig )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime = sig->timestamp;
|
||||
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
expirestr_from_pk( PKT_public_key *pk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime;
|
||||
|
||||
if( !pk->expiredate )
|
||||
return _("never ");
|
||||
atime = pk->expiredate;
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
expirestr_from_sk( PKT_secret_key *sk )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime;
|
||||
|
||||
if( !sk->expiredate )
|
||||
return _("never ");
|
||||
atime = sk->expiredate;
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
expirestr_from_sig( PKT_signature *sig )
|
||||
{
|
||||
static char buffer[11+5];
|
||||
time_t atime;
|
||||
|
||||
if(!sig->expiredate)
|
||||
return _("never ");
|
||||
atime=sig->expiredate;
|
||||
return mk_datestr (buffer, atime);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_strtime (u32 t)
|
||||
{
|
||||
if (!t)
|
||||
return "";
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)t);
|
||||
return buf;
|
||||
}
|
||||
return strtimestamp(t);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_datestr_from_pk (PKT_public_key *pk)
|
||||
{
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)pk->timestamp);
|
||||
return buf;
|
||||
}
|
||||
return datestr_from_pk (pk);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_datestr_from_sk (PKT_secret_key *sk)
|
||||
{
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)sk->timestamp);
|
||||
return buf;
|
||||
}
|
||||
return datestr_from_sk (sk);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_datestr_from_sig (PKT_signature *sig)
|
||||
{
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)sig->timestamp);
|
||||
return buf;
|
||||
}
|
||||
return datestr_from_sig (sig);
|
||||
}
|
||||
|
||||
const char *
|
||||
colon_expirestr_from_sig (PKT_signature *sig)
|
||||
{
|
||||
if(!sig->expiredate)
|
||||
return "";
|
||||
if (opt.fixed_list_mode) {
|
||||
static char buf[15];
|
||||
sprintf (buf, "%lu", (ulong)sig->expiredate);
|
||||
return buf;
|
||||
}
|
||||
return expirestr_from_sig (sig);
|
||||
}
|
||||
|
||||
|
||||
/**************** .
|
||||
* Return a byte array with the fingerprint for the given PK/SK
|
||||
* The length of the array is returned in ret_len. Caller must free
|
||||
* the array or provide an array of length MAX_FINGERPRINT_LEN.
|
||||
*/
|
||||
|
||||
byte *
|
||||
fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len )
|
||||
{
|
||||
byte *p, *buf;
|
||||
const byte *dp;
|
||||
size_t len;
|
||||
unsigned int n;
|
||||
|
||||
if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
|
||||
/* RSA in version 3 packets is special */
|
||||
MD_HANDLE md;
|
||||
|
||||
md = md_open( DIGEST_ALGO_MD5, 0);
|
||||
if( pubkey_get_npkey( pk->pubkey_algo ) > 1 ) {
|
||||
p = buf = mpi_get_buffer( pk->pkey[0], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
p = buf = mpi_get_buffer( pk->pkey[1], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
}
|
||||
md_final(md);
|
||||
if( !array )
|
||||
array = m_alloc( 16 );
|
||||
len = 16;
|
||||
memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md(pk);
|
||||
dp = md_read( md, 0 );
|
||||
len = md_digest_length( md_get_algo( md ) );
|
||||
assert( len <= MAX_FINGERPRINT_LEN );
|
||||
if( !array )
|
||||
array = m_alloc( len );
|
||||
memcpy(array, dp, len );
|
||||
pk->keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
|
||||
pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
*ret_len = len;
|
||||
return array;
|
||||
}
|
||||
|
||||
byte *
|
||||
fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len )
|
||||
{
|
||||
byte *p, *buf;
|
||||
const char *dp;
|
||||
size_t len;
|
||||
unsigned n;
|
||||
|
||||
if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
|
||||
/* RSA in version 3 packets is special */
|
||||
MD_HANDLE md;
|
||||
|
||||
md = md_open( DIGEST_ALGO_MD5, 0);
|
||||
if( pubkey_get_npkey( sk->pubkey_algo ) > 1 ) {
|
||||
p = buf = mpi_get_buffer( sk->skey[0], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
p = buf = mpi_get_buffer( sk->skey[1], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(buf);
|
||||
}
|
||||
md_final(md);
|
||||
if( !array )
|
||||
array = m_alloc( 16 );
|
||||
len = 16;
|
||||
memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
MD_HANDLE md;
|
||||
md = do_fingerprint_md_sk(sk);
|
||||
dp = md_read( md, 0 );
|
||||
len = md_digest_length( md_get_algo( md ) );
|
||||
assert( len <= MAX_FINGERPRINT_LEN );
|
||||
if( !array )
|
||||
array = m_alloc( len );
|
||||
memcpy(array, dp, len );
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
*ret_len = len;
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
|
1287
g10/keylist.c
Normal file
1287
g10/keylist.c
Normal file
File diff suppressed because it is too large
Load diff
1573
g10/keyring.c
Normal file
1573
g10/keyring.c
Normal file
File diff suppressed because it is too large
Load diff
46
g10/keyring.h
Normal file
46
g10/keyring.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* keyring.h - Keyring operations
|
||||
* Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef GPG_KEYRING_H
|
||||
#define GPG_KEYRING_H 1
|
||||
|
||||
#include "global.h"
|
||||
|
||||
|
||||
typedef struct keyring_handle *KEYRING_HANDLE;
|
||||
|
||||
int keyring_register_filename (const char *fname, int secret, void **ptr);
|
||||
int keyring_is_writable (void *token);
|
||||
|
||||
KEYRING_HANDLE keyring_new (void *token, int secret);
|
||||
void keyring_release (KEYRING_HANDLE hd);
|
||||
const char *keyring_get_resource_name (KEYRING_HANDLE hd);
|
||||
int keyring_lock (KEYRING_HANDLE hd, int yes);
|
||||
int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb);
|
||||
int keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb);
|
||||
int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb);
|
||||
int keyring_locate_writable (KEYRING_HANDLE hd);
|
||||
int keyring_delete_keyblock (KEYRING_HANDLE hd);
|
||||
int keyring_search_reset (KEYRING_HANDLE hd);
|
||||
int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
||||
size_t ndesc, size_t *descindex);
|
||||
int keyring_rebuild_cache (void *);
|
||||
|
||||
#endif /*GPG_KEYRING_H*/
|
1378
g10/keyserver.c
Normal file
1378
g10/keyserver.c
Normal file
File diff suppressed because it is too large
Load diff
241
g10/main.h
Normal file
241
g10/main.h
Normal file
|
@ -0,0 +1,241 @@
|
|||
/* main.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_MAIN_H
|
||||
#define G10_MAIN_H
|
||||
#include "types.h"
|
||||
#include "iobuf.h"
|
||||
#include "mpi.h"
|
||||
#include "cipher.h"
|
||||
#include "keydb.h"
|
||||
|
||||
/* It could be argued that the default cipher should be 3DES rather
|
||||
than CAST5, and the default compression should be 0
|
||||
(i.e. uncompressed) rather than 1 (zip). */
|
||||
#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5
|
||||
#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1
|
||||
#define DEFAULT_COMPRESS_ALGO 1
|
||||
|
||||
typedef struct {
|
||||
int header_okay;
|
||||
PK_LIST pk_list;
|
||||
cipher_filter_context_t cfx;
|
||||
} encrypt_filter_context_t;
|
||||
|
||||
struct groupitem
|
||||
{
|
||||
char *name;
|
||||
STRLIST values;
|
||||
struct groupitem *next;
|
||||
};
|
||||
|
||||
/*-- g10.c --*/
|
||||
extern int g10_errors_seen;
|
||||
|
||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
|
||||
void g10_exit(int rc) __attribute__ ((noreturn));
|
||||
#else
|
||||
void g10_exit(int rc);
|
||||
#endif
|
||||
void print_pubkey_algo_note( int algo );
|
||||
void print_cipher_algo_note( int algo );
|
||||
void print_digest_algo_note( int algo );
|
||||
|
||||
/*-- armor.c --*/
|
||||
char *make_radix64_string( const byte *data, size_t len );
|
||||
|
||||
/*-- misc.c --*/
|
||||
void trap_unaligned(void);
|
||||
int disable_core_dumps(void);
|
||||
u16 checksum_u16( unsigned n );
|
||||
u16 checksum( byte *p, unsigned n );
|
||||
u16 checksum_mpi( MPI a );
|
||||
u32 buffer_to_u32( const byte *buffer );
|
||||
const byte *get_session_marker( size_t *rlen );
|
||||
int openpgp_cipher_test_algo( int algo );
|
||||
int openpgp_pk_test_algo( int algo, unsigned int usage_flags );
|
||||
int openpgp_pk_algo_usage ( int algo );
|
||||
int openpgp_md_test_algo( int algo );
|
||||
|
||||
#ifdef USE_IDEA
|
||||
void idea_cipher_warn( int show );
|
||||
#else
|
||||
#define idea_cipher_warn(a)
|
||||
#endif
|
||||
|
||||
struct expando_args
|
||||
{
|
||||
PKT_public_key *pk;
|
||||
PKT_secret_key *sk;
|
||||
byte imagetype;
|
||||
};
|
||||
|
||||
char *pct_expando(const char *string,struct expando_args *args);
|
||||
int hextobyte( const char *s );
|
||||
void deprecated_warning(const char *configname,unsigned int configlineno,
|
||||
const char *option,const char *repl1,const char *repl2);
|
||||
const char *compress_algo_to_string(int algo);
|
||||
int string_to_compress_algo(const char *string);
|
||||
int check_compress_algo(int algo);
|
||||
int default_cipher_algo(void);
|
||||
int default_compress_algo(void);
|
||||
const char *compliance_option_string(void);
|
||||
void compliance_failure(void);
|
||||
|
||||
struct parse_options
|
||||
{
|
||||
char *name;
|
||||
unsigned int bit;
|
||||
};
|
||||
|
||||
int parse_options(char *str,unsigned int *options,struct parse_options *opts);
|
||||
|
||||
/*-- helptext.c --*/
|
||||
void display_online_help( const char *keyword );
|
||||
|
||||
/*-- encode.c --*/
|
||||
int encode_symmetric( const char *filename );
|
||||
int encode_store( const char *filename );
|
||||
int encode_crypt( const char *filename, STRLIST remusr );
|
||||
void encode_crypt_files(int nfiles, char **files, STRLIST remusr);
|
||||
int encrypt_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len);
|
||||
|
||||
|
||||
/*-- sign.c --*/
|
||||
int complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md );
|
||||
int sign_file( STRLIST filenames, int detached, STRLIST locusr,
|
||||
int do_encrypt, STRLIST remusr, const char *outfile );
|
||||
int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
|
||||
int sign_symencrypt_file (const char *fname, STRLIST locusr);
|
||||
|
||||
/*-- sig-check.c --*/
|
||||
int check_revocation_keys (PKT_public_key *pk, PKT_signature *sig);
|
||||
int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
|
||||
int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
|
||||
int *is_selfsig, u32 *r_expiredate, int *r_expired );
|
||||
|
||||
/*-- delkey.c --*/
|
||||
int delete_keys( STRLIST names, int secret, int allow_both );
|
||||
|
||||
/*-- keyedit.c --*/
|
||||
void keyedit_menu( const char *username, STRLIST locusr, STRLIST cmds,
|
||||
int sign_mode );
|
||||
void show_basic_key_info (KBNODE keyblock);
|
||||
|
||||
/*-- keygen.c --*/
|
||||
u32 ask_expire_interval(int object);
|
||||
u32 ask_expiredate(void);
|
||||
void generate_keypair( const char *fname );
|
||||
int keygen_set_std_prefs (const char *string,int personal);
|
||||
PKT_user_id *keygen_get_std_prefs (void);
|
||||
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
|
||||
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
|
||||
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
|
||||
int keygen_add_revkey(PKT_signature *sig, void *opaque);
|
||||
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
|
||||
|
||||
/*-- openfile.c --*/
|
||||
int overwrite_filep( const char *fname );
|
||||
char *make_outfile_name( const char *iname );
|
||||
char *ask_outfile_name( const char *name, size_t namelen );
|
||||
int open_outfile( const char *iname, int mode, IOBUF *a );
|
||||
IOBUF open_sigfile( const char *iname, progress_filter_context_t *pfx );
|
||||
void try_make_homedir( const char *fname );
|
||||
|
||||
/*-- seskey.c --*/
|
||||
void make_session_key( DEK *dek );
|
||||
MPI encode_session_key( DEK *dek, unsigned nbits );
|
||||
MPI encode_md_value( int pubkey_algo, MD_HANDLE md,
|
||||
int hash_algo, unsigned nbits, int v3compathack );
|
||||
|
||||
/*-- comment.c --*/
|
||||
KBNODE make_comment_node( const char *s );
|
||||
KBNODE make_mpi_comment_node( const char *s, MPI a );
|
||||
|
||||
/*-- import.c --*/
|
||||
int parse_import_options(char *str,unsigned int *options);
|
||||
void import_keys( char **fnames, int nnames,
|
||||
void *stats_hd, unsigned int options );
|
||||
int import_keys_stream( IOBUF inp,
|
||||
void *stats_hd, unsigned int options );
|
||||
void *import_new_stats_handle (void);
|
||||
void import_release_stats_handle (void *p);
|
||||
void import_print_stats (void *hd);
|
||||
|
||||
int collapse_uids( KBNODE *keyblock );
|
||||
|
||||
/*-- export.c --*/
|
||||
int parse_export_options(char *str,unsigned int *options);
|
||||
int export_pubkeys( STRLIST users, unsigned int options );
|
||||
int export_pubkeys_stream( IOBUF out, STRLIST users,
|
||||
KBNODE *keyblock_out, unsigned int options );
|
||||
int export_seckeys( STRLIST users );
|
||||
int export_secsubkeys( STRLIST users );
|
||||
|
||||
/* dearmor.c --*/
|
||||
int dearmor_file( const char *fname );
|
||||
int enarmor_file( const char *fname );
|
||||
|
||||
/*-- revoke.c --*/
|
||||
struct revocation_reason_info;
|
||||
int gen_revoke( const char *uname );
|
||||
int gen_desig_revoke( const char *uname );
|
||||
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 );
|
||||
void release_revocation_reason_info( struct revocation_reason_info *reason );
|
||||
|
||||
/*-- keylist.c --*/
|
||||
void public_key_list( STRLIST list );
|
||||
void secret_key_list( STRLIST list );
|
||||
void reorder_keyblock (KBNODE keyblock);
|
||||
void list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque );
|
||||
void print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode);
|
||||
void show_policy_url(PKT_signature *sig,int indent,int mode);
|
||||
void show_notation(PKT_signature *sig,int indent,int mode);
|
||||
void dump_attribs(const PKT_user_id *uid,
|
||||
PKT_public_key *pk,PKT_secret_key *sk);
|
||||
void set_attrib_fd(int fd);
|
||||
void print_seckey_info (PKT_secret_key *sk);
|
||||
void print_pubkey_info (PKT_public_key *pk);
|
||||
|
||||
/*-- verify.c --*/
|
||||
void print_file_status( int status, const char *name, int what );
|
||||
int verify_signatures( int nfiles, char **files );
|
||||
int verify_files( int nfiles, char **files );
|
||||
|
||||
/*-- decrypt.c --*/
|
||||
int decrypt_message( const char *filename );
|
||||
void decrypt_messages(int nfiles, char **files);
|
||||
|
||||
/*-- plaintext.c --*/
|
||||
int hash_datafiles( MD_HANDLE md, MD_HANDLE md2,
|
||||
STRLIST files, const char *sigfilename, int textmode );
|
||||
|
||||
/*-- pipemode.c --*/
|
||||
void run_in_pipemode (void);
|
||||
|
||||
/*-- signal.c --*/
|
||||
void init_signals(void);
|
||||
void pause_on_sigusr( int which );
|
||||
void block_all_signals(void);
|
||||
void unblock_all_signals(void);
|
||||
|
||||
#endif /*G10_MAIN_H*/
|
1681
g10/mainproc.c
Normal file
1681
g10/mainproc.c
Normal file
File diff suppressed because it is too large
Load diff
678
g10/misc.c
Normal file
678
g10/misc.c
Normal file
|
@ -0,0 +1,678 @@
|
|||
/* misc.c - miscellaneous functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "photoid.h"
|
||||
#include "options.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
const char *g10m_revision_string(int);
|
||||
const char *g10c_revision_string(int);
|
||||
const char *g10u_revision_string(int);
|
||||
|
||||
#ifdef __GNUC__
|
||||
volatile
|
||||
#endif
|
||||
void
|
||||
pull_in_libs(void)
|
||||
{
|
||||
g10m_revision_string(0);
|
||||
g10c_revision_string(0);
|
||||
g10u_revision_string(0);
|
||||
}
|
||||
|
||||
|
||||
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
||||
static int
|
||||
setsysinfo(unsigned long op, void *buffer, unsigned long size,
|
||||
int *start, void *arg, unsigned long flag)
|
||||
{
|
||||
return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
|
||||
}
|
||||
|
||||
void
|
||||
trap_unaligned(void)
|
||||
{
|
||||
unsigned int buf[2];
|
||||
|
||||
buf[0] = SSIN_UACPROC;
|
||||
buf[1] = UAC_SIGBUS | UAC_NOPRINT;
|
||||
setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
|
||||
}
|
||||
#else
|
||||
void
|
||||
trap_unaligned(void)
|
||||
{ /* dummy */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
disable_core_dumps()
|
||||
{
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
return 0;
|
||||
#else
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
struct rlimit limit;
|
||||
|
||||
limit.rlim_cur = 0;
|
||||
limit.rlim_max = 0;
|
||||
if( !setrlimit( RLIMIT_CORE, &limit ) )
|
||||
return 0;
|
||||
if( errno != EINVAL && errno != ENOSYS )
|
||||
log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
|
||||
#endif
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
u16
|
||||
checksum_u16( unsigned n )
|
||||
{
|
||||
u16 a;
|
||||
|
||||
a = (n >> 8) & 0xff;
|
||||
a += n & 0xff;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
u16
|
||||
checksum( byte *p, unsigned n )
|
||||
{
|
||||
u16 a;
|
||||
|
||||
for(a=0; n; n-- )
|
||||
a += *p++;
|
||||
return a;
|
||||
}
|
||||
|
||||
u16
|
||||
checksum_mpi( MPI a )
|
||||
{
|
||||
u16 csum;
|
||||
byte *buffer;
|
||||
unsigned nbytes;
|
||||
unsigned nbits;
|
||||
|
||||
buffer = mpi_get_buffer( a, &nbytes, NULL );
|
||||
nbits = mpi_get_nbits(a);
|
||||
csum = checksum_u16( nbits );
|
||||
csum += checksum( buffer, nbytes );
|
||||
m_free( buffer );
|
||||
return csum;
|
||||
}
|
||||
|
||||
u32
|
||||
buffer_to_u32( const byte *buffer )
|
||||
{
|
||||
unsigned long a;
|
||||
a = *buffer << 24;
|
||||
a |= buffer[1] << 16;
|
||||
a |= buffer[2] << 8;
|
||||
a |= buffer[3];
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
no_exp_algo(void)
|
||||
{
|
||||
static int did_note = 0;
|
||||
|
||||
if( !did_note ) {
|
||||
did_note = 1;
|
||||
log_info(_("Experimental algorithms should not be used!\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_pubkey_algo_note( int algo )
|
||||
{
|
||||
if( algo >= 100 && algo <= 110 )
|
||||
no_exp_algo();
|
||||
}
|
||||
|
||||
void
|
||||
print_cipher_algo_note( int algo )
|
||||
{
|
||||
if( algo >= 100 && algo <= 110 )
|
||||
no_exp_algo();
|
||||
else if( algo == CIPHER_ALGO_3DES
|
||||
|| algo == CIPHER_ALGO_CAST5
|
||||
|| algo == CIPHER_ALGO_BLOWFISH
|
||||
|| algo == CIPHER_ALGO_TWOFISH
|
||||
|| algo == CIPHER_ALGO_RIJNDAEL
|
||||
|| algo == CIPHER_ALGO_RIJNDAEL192
|
||||
|| algo == CIPHER_ALGO_RIJNDAEL256
|
||||
)
|
||||
;
|
||||
else {
|
||||
static int did_note = 0;
|
||||
|
||||
if( !did_note ) {
|
||||
did_note = 1;
|
||||
log_info(_("this cipher algorithm is deprecated; "
|
||||
"please use a more standard one!\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
print_digest_algo_note( int algo )
|
||||
{
|
||||
if( algo >= 100 && algo <= 110 )
|
||||
no_exp_algo();
|
||||
}
|
||||
|
||||
|
||||
/* Return a string which is used as a kind of process ID */
|
||||
const byte *
|
||||
get_session_marker( size_t *rlen )
|
||||
{
|
||||
static byte marker[SIZEOF_UNSIGNED_LONG*2];
|
||||
static int initialized;
|
||||
|
||||
if ( !initialized ) {
|
||||
volatile ulong aa, bb; /* we really want the uninitialized value */
|
||||
ulong a, b;
|
||||
|
||||
initialized = 1;
|
||||
/* also this marker is guessable it is not easy to use this
|
||||
* for a faked control packet because an attacker does not
|
||||
* have enough control about the time the verification does
|
||||
* take place. Of course, we can add just more random but
|
||||
* than we need the random generator even for verification
|
||||
* tasks - which does not make sense. */
|
||||
a = aa ^ (ulong)getpid();
|
||||
b = bb ^ (ulong)time(NULL);
|
||||
memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
|
||||
memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
|
||||
}
|
||||
*rlen = sizeof(marker);
|
||||
return marker;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Wrapper around the libgcrypt function with addional checks on
|
||||
* openPGP contraints for the algo ID.
|
||||
*/
|
||||
int
|
||||
openpgp_cipher_test_algo( int algo )
|
||||
{
|
||||
if( algo < 0 || algo > 110 )
|
||||
return G10ERR_CIPHER_ALGO;
|
||||
return check_cipher_algo(algo);
|
||||
}
|
||||
|
||||
int
|
||||
openpgp_pk_test_algo( int algo, unsigned int usage_flags )
|
||||
{
|
||||
if( algo < 0 || algo > 110 )
|
||||
return G10ERR_PUBKEY_ALGO;
|
||||
return check_pubkey_algo2( algo, usage_flags );
|
||||
}
|
||||
|
||||
int
|
||||
openpgp_pk_algo_usage ( int algo )
|
||||
{
|
||||
int use = 0;
|
||||
|
||||
/* they are hardwired in gpg 1.0 */
|
||||
switch ( algo ) {
|
||||
case PUBKEY_ALGO_RSA:
|
||||
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_E:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_RSA_S:
|
||||
use = PUBKEY_USAGE_SIG;
|
||||
break;
|
||||
case PUBKEY_ALGO_ELGAMAL_E:
|
||||
use = PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
case PUBKEY_ALGO_DSA:
|
||||
use = PUBKEY_USAGE_SIG;
|
||||
break;
|
||||
case PUBKEY_ALGO_ELGAMAL:
|
||||
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return use;
|
||||
}
|
||||
|
||||
int
|
||||
openpgp_md_test_algo( int algo )
|
||||
{
|
||||
if( algo < 0 || algo > 110 )
|
||||
return G10ERR_DIGEST_ALGO;
|
||||
return check_digest_algo(algo);
|
||||
}
|
||||
|
||||
#ifdef USE_IDEA
|
||||
/* Special warning for the IDEA cipher */
|
||||
void
|
||||
idea_cipher_warn(int show)
|
||||
{
|
||||
static int warned=0;
|
||||
|
||||
if(!warned || show)
|
||||
{
|
||||
log_info(_("the IDEA cipher plugin is not present\n"));
|
||||
log_info(_("please see http://www.gnupg.org/why-not-idea.html "
|
||||
"for more information\n"));
|
||||
warned=1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Expand %-strings. Returns a string which must be m_freed. Returns
|
||||
NULL if the string cannot be expanded (too large). */
|
||||
char *
|
||||
pct_expando(const char *string,struct expando_args *args)
|
||||
{
|
||||
const char *ch=string;
|
||||
int idx=0,maxlen=0,done=0;
|
||||
u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0};
|
||||
char *ret=NULL;
|
||||
|
||||
if(args->pk)
|
||||
keyid_from_pk(args->pk,pk_keyid);
|
||||
|
||||
if(args->sk)
|
||||
keyid_from_sk(args->sk,sk_keyid);
|
||||
|
||||
if(!args->pk && args->sk)
|
||||
keyid_from_sk(args->sk,pk_keyid);
|
||||
|
||||
while(*ch!='\0')
|
||||
{
|
||||
char *str=NULL;
|
||||
|
||||
if(!done)
|
||||
{
|
||||
/* 8192 is way bigger than we'll need here */
|
||||
if(maxlen>=8192)
|
||||
goto fail;
|
||||
|
||||
maxlen+=1024;
|
||||
ret=m_realloc(ret,maxlen);
|
||||
}
|
||||
|
||||
done=0;
|
||||
|
||||
if(*ch=='%')
|
||||
{
|
||||
switch(*(ch+1))
|
||||
{
|
||||
case 's': /* short key id */
|
||||
if(idx+8<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX",(ulong)sk_keyid[1]);
|
||||
idx+=8;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S': /* long key id */
|
||||
if(idx+16<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX%08lX",
|
||||
(ulong)sk_keyid[0],(ulong)sk_keyid[1]);
|
||||
idx+=16;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'k': /* short key id */
|
||||
if(idx+8<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX",(ulong)pk_keyid[1]);
|
||||
idx+=8;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'K': /* long key id */
|
||||
if(idx+16<maxlen)
|
||||
{
|
||||
sprintf(&ret[idx],"%08lX%08lX",
|
||||
(ulong)pk_keyid[0],(ulong)pk_keyid[1]);
|
||||
idx+=16;
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'f': /* fingerprint */
|
||||
{
|
||||
byte array[MAX_FINGERPRINT_LEN];
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
if(args->pk)
|
||||
fingerprint_from_pk(args->pk,array,&len);
|
||||
else
|
||||
memset(array,0, (len=MAX_FINGERPRINT_LEN));
|
||||
|
||||
if(idx+(len*2)<maxlen)
|
||||
{
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
sprintf(&ret[idx],"%02X",array[i]);
|
||||
idx+=2;
|
||||
}
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 't': /* e.g. "jpg" */
|
||||
str=image_type_to_string(args->imagetype,0);
|
||||
/* fall through */
|
||||
|
||||
case 'T': /* e.g. "image/jpeg" */
|
||||
if(str==NULL)
|
||||
str=image_type_to_string(args->imagetype,2);
|
||||
|
||||
if(idx+strlen(str)<maxlen)
|
||||
{
|
||||
strcpy(&ret[idx],str);
|
||||
idx+=strlen(str);
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case '%':
|
||||
if(idx+1<maxlen)
|
||||
{
|
||||
ret[idx++]='%';
|
||||
ret[idx]='\0';
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Any unknown %-keys (like %i, %o, %I, and %O) are
|
||||
passed through for later expansion. Note this also
|
||||
handles the case where the last character in the
|
||||
string is a '%' - the terminating \0 will end up here
|
||||
and properly terminate the string. */
|
||||
default:
|
||||
if(idx+2<maxlen)
|
||||
{
|
||||
ret[idx++]='%';
|
||||
ret[idx++]=*(ch+1);
|
||||
ret[idx]='\0';
|
||||
done=1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(done)
|
||||
ch++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(idx+1<maxlen)
|
||||
{
|
||||
ret[idx++]=*ch;
|
||||
ret[idx]='\0';
|
||||
done=1;
|
||||
}
|
||||
}
|
||||
|
||||
if(done)
|
||||
ch++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
m_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
hextobyte( const char *s )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( *s >= '0' && *s <= '9' )
|
||||
c = 16 * (*s - '0');
|
||||
else if( *s >= 'A' && *s <= 'F' )
|
||||
c = 16 * (10 + *s - 'A');
|
||||
else if( *s >= 'a' && *s <= 'f' )
|
||||
c = 16 * (10 + *s - 'a');
|
||||
else
|
||||
return -1;
|
||||
s++;
|
||||
if( *s >= '0' && *s <= '9' )
|
||||
c += *s - '0';
|
||||
else if( *s >= 'A' && *s <= 'F' )
|
||||
c += 10 + *s - 'A';
|
||||
else if( *s >= 'a' && *s <= 'f' )
|
||||
c += 10 + *s - 'a';
|
||||
else
|
||||
return -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
deprecated_warning(const char *configname,unsigned int configlineno,
|
||||
const char *option,const char *repl1,const char *repl2)
|
||||
{
|
||||
if(configname)
|
||||
{
|
||||
if(strncmp("--",option,2)==0)
|
||||
option+=2;
|
||||
|
||||
if(strncmp("--",repl1,2)==0)
|
||||
repl1+=2;
|
||||
|
||||
log_info(_("%s:%d: deprecated option \"%s\"\n"),
|
||||
configname,configlineno,option);
|
||||
}
|
||||
else
|
||||
log_info(_("WARNING: \"%s\" is a deprecated option\n"),option);
|
||||
|
||||
log_info(_("please use \"%s%s\" instead\n"),repl1,repl2);
|
||||
}
|
||||
|
||||
const char *
|
||||
compress_algo_to_string(int algo)
|
||||
{
|
||||
const char *s="?";
|
||||
|
||||
switch(algo)
|
||||
{
|
||||
case 0:
|
||||
s="Uncompressed";
|
||||
break;
|
||||
|
||||
case 1:
|
||||
s="ZIP";
|
||||
break;
|
||||
|
||||
case 2:
|
||||
s="ZLIB";
|
||||
break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
string_to_compress_algo(const char *string)
|
||||
{
|
||||
if(ascii_strcasecmp(string,"uncompressed")==0)
|
||||
return 0;
|
||||
else if(ascii_strcasecmp(string,"zip")==0)
|
||||
return 1;
|
||||
else if(ascii_strcasecmp(string,"zlib")==0)
|
||||
return 2;
|
||||
else if(ascii_strcasecmp(string,"z0")==0)
|
||||
return 0;
|
||||
else if(ascii_strcasecmp(string,"z1")==0)
|
||||
return 1;
|
||||
else if(ascii_strcasecmp(string,"z2")==0)
|
||||
return 2;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
check_compress_algo(int algo)
|
||||
{
|
||||
if(algo>=0 && algo<=2)
|
||||
return 0;
|
||||
|
||||
return G10ERR_COMPR_ALGO;
|
||||
}
|
||||
|
||||
int
|
||||
default_cipher_algo(void)
|
||||
{
|
||||
if(opt.def_cipher_algo)
|
||||
return opt.def_cipher_algo;
|
||||
else if(opt.personal_cipher_prefs)
|
||||
return opt.personal_cipher_prefs[0].value;
|
||||
else
|
||||
return opt.s2k_cipher_algo;
|
||||
}
|
||||
|
||||
/* There is no default_digest_algo function, but see
|
||||
sign.c:hash_for */
|
||||
|
||||
int
|
||||
default_compress_algo(void)
|
||||
{
|
||||
if(opt.def_compress_algo!=-1)
|
||||
return opt.def_compress_algo;
|
||||
else if(opt.personal_compress_prefs)
|
||||
return opt.personal_compress_prefs[0].value;
|
||||
else
|
||||
return DEFAULT_COMPRESS_ALGO;
|
||||
}
|
||||
|
||||
const char *
|
||||
compliance_option_string(void)
|
||||
{
|
||||
switch(opt.compliance)
|
||||
{
|
||||
case CO_RFC2440:
|
||||
return "--openpgp";
|
||||
case CO_PGP2:
|
||||
return "--pgp2";
|
||||
case CO_PGP6:
|
||||
return "--pgp6";
|
||||
case CO_PGP7:
|
||||
return "--pgp7";
|
||||
case CO_PGP8:
|
||||
return "--pgp8";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
compliance_string(void)
|
||||
{
|
||||
switch(opt.compliance)
|
||||
{
|
||||
case CO_RFC2440:
|
||||
return "OpenPGP";
|
||||
case CO_PGP2:
|
||||
return "PGP 2.x";
|
||||
case CO_PGP6:
|
||||
return "PGP 6.x";
|
||||
case CO_PGP7:
|
||||
return "PGP 7.x";
|
||||
case CO_PGP8:
|
||||
return "PGP 8.x";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
compliance_failure(void)
|
||||
{
|
||||
log_info(_("this message may not be usable by %s\n"),compliance_string());
|
||||
opt.compliance=CO_GNUPG;
|
||||
}
|
||||
|
||||
int
|
||||
parse_options(char *str,unsigned int *options,struct parse_options *opts)
|
||||
{
|
||||
char *tok;
|
||||
|
||||
while((tok=strsep(&str," ,")))
|
||||
{
|
||||
int i,rev=0;
|
||||
|
||||
if(tok[0]=='\0')
|
||||
continue;
|
||||
|
||||
if(ascii_strncasecmp("no-",tok,3)==0)
|
||||
{
|
||||
rev=1;
|
||||
tok+=3;
|
||||
}
|
||||
|
||||
for(i=0;opts[i].name;i++)
|
||||
{
|
||||
if(ascii_strcasecmp(opts[i].name,tok)==0)
|
||||
{
|
||||
if(rev)
|
||||
*options&=~opts[i].bit;
|
||||
else
|
||||
*options|=opts[i].bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!opts[i].name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
389
g10/openfile.c
Normal file
389
g10/openfile.c
Normal file
|
@ -0,0 +1,389 @@
|
|||
/* openfile.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "ttyio.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
#ifdef USE_ONLY_8DOT3
|
||||
#define SKELEXT ".skl"
|
||||
#else
|
||||
#define SKELEXT EXTSEP_S "skel"
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_DRIVE_LETTERS) || defined (__riscos__)
|
||||
#define CMP_FILENAME(a,b) ascii_strcasecmp( (a), (b) )
|
||||
#else
|
||||
#define CMP_FILENAME(a,b) strcmp( (a), (b) )
|
||||
#endif
|
||||
|
||||
#ifdef MKDIR_TAKES_ONE_ARG
|
||||
#undef mkdir
|
||||
#define mkdir(a,b) mkdir(a)
|
||||
#endif
|
||||
|
||||
/* FIXME: Implement opt.interactive. */
|
||||
|
||||
/****************
|
||||
* Check whether FNAME exists and ask if it's okay to overwrite an
|
||||
* existing one.
|
||||
* Returns: True: it's okay to overwrite or the file does not exist
|
||||
* False: Do not overwrite
|
||||
*/
|
||||
int
|
||||
overwrite_filep( const char *fname )
|
||||
{
|
||||
if( !fname || (*fname == '-' && !fname[1]) )
|
||||
return 1; /* writing to stdout is always okay */
|
||||
|
||||
if( access( fname, F_OK ) )
|
||||
return 1; /* does not exist */
|
||||
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
if ( !strcmp ( fname, "/dev/null" ) )
|
||||
return 1; /* does not do any harm */
|
||||
#endif
|
||||
|
||||
/* fixme: add some backup stuff in case of overwrite */
|
||||
if( opt.answer_yes )
|
||||
return 1;
|
||||
if( opt.answer_no || opt.batch )
|
||||
return 0; /* do not overwrite */
|
||||
|
||||
tty_printf(_("File `%s' exists. "), fname);
|
||||
if( cpr_get_answer_is_yes("openfile.overwrite.okay",
|
||||
_("Overwrite (y/N)? ")) )
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Strip know extensions from iname and return a newly allocated
|
||||
* filename. Return NULL if we can't do that.
|
||||
*/
|
||||
char *
|
||||
make_outfile_name( const char *iname )
|
||||
{
|
||||
size_t n;
|
||||
|
||||
if( (!iname || (*iname=='-' && !iname[1]) ))
|
||||
return m_strdup("-");
|
||||
|
||||
n = strlen(iname);
|
||||
if( n > 4 && ( !CMP_FILENAME(iname+n-4, EXTSEP_S "gpg")
|
||||
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "pgp")
|
||||
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "sig")
|
||||
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "asc") ) ) {
|
||||
char *buf = m_strdup( iname );
|
||||
buf[n-4] = 0;
|
||||
return buf;
|
||||
}
|
||||
else if( n > 5 && !CMP_FILENAME(iname+n-5, EXTSEP_S "sign") ) {
|
||||
char *buf = m_strdup( iname );
|
||||
buf[n-5] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
log_info(_("%s: unknown suffix\n"), iname );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Ask for a outputfilename and use the given one as default.
|
||||
* Return NULL if no file has been given or it is not possible to
|
||||
* ask the user.
|
||||
*/
|
||||
char *
|
||||
ask_outfile_name( const char *name, size_t namelen )
|
||||
{
|
||||
size_t n;
|
||||
const char *s;
|
||||
char *prompt;
|
||||
char *fname;
|
||||
char *defname;
|
||||
|
||||
if( opt.batch )
|
||||
return NULL;
|
||||
|
||||
s = _("Enter new filename");
|
||||
|
||||
n = strlen(s) + namelen + 10;
|
||||
defname = name && namelen? make_printable_string( name, namelen, 0): NULL;
|
||||
prompt = m_alloc(n);
|
||||
if( defname )
|
||||
sprintf(prompt, "%s [%s]: ", s, defname );
|
||||
else
|
||||
sprintf(prompt, "%s: ", s );
|
||||
fname = cpr_get("openfile.askoutname", prompt );
|
||||
cpr_kill_prompt();
|
||||
m_free(prompt);
|
||||
if( !*fname ) {
|
||||
m_free( fname ); fname = NULL;
|
||||
fname = defname; defname = NULL;
|
||||
}
|
||||
m_free(defname);
|
||||
if (fname)
|
||||
trim_spaces (fname);
|
||||
return fname;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Make an output filename for the inputfile INAME.
|
||||
* Returns an IOBUF and an errorcode
|
||||
* Mode 0 = use ".gpg"
|
||||
* 1 = use ".asc"
|
||||
* 2 = use ".sig"
|
||||
*/
|
||||
int
|
||||
open_outfile( const char *iname, int mode, IOBUF *a )
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
*a = NULL;
|
||||
if( (!iname || (*iname=='-' && !iname[1])) && !opt.outfile ) {
|
||||
if( !(*a = iobuf_create(NULL)) ) {
|
||||
log_error(_("%s: can't open: %s\n"), "[stdout]", strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
}
|
||||
else if( opt.verbose )
|
||||
log_info(_("writing to stdout\n"));
|
||||
}
|
||||
else {
|
||||
char *buf = NULL;
|
||||
const char *name;
|
||||
|
||||
if( opt.dry_run )
|
||||
name = "/dev/null";
|
||||
else if( opt.outfile )
|
||||
name = opt.outfile;
|
||||
else {
|
||||
#ifdef USE_ONLY_8DOT3
|
||||
if (opt.mangle_dos_filenames)
|
||||
{
|
||||
/* It is quite common DOS system to have only one dot in a
|
||||
* a filename So if we have something like this, we simple
|
||||
* replace the suffix execpt in cases where the suffix is
|
||||
* larger than 3 characters and not the same as.
|
||||
* We should really map the filenames to 8.3 but this tends to
|
||||
* be more complicated and is probaly a duty of the filesystem
|
||||
*/
|
||||
char *dot;
|
||||
const char *newsfx = mode==1 ? ".asc" :
|
||||
mode==2 ? ".sig" : ".gpg";
|
||||
|
||||
buf = m_alloc(strlen(iname)+4+1);
|
||||
strcpy(buf,iname);
|
||||
dot = strchr(buf, '.' );
|
||||
if ( dot && dot > buf && dot[1] && strlen(dot) <= 4
|
||||
&& CMP_FILENAME(newsfx, dot) )
|
||||
{
|
||||
strcpy(dot, newsfx );
|
||||
}
|
||||
else if ( dot && !dot[1] ) /* don't duplicate a dot */
|
||||
strcpy( dot, newsfx+1 );
|
||||
else
|
||||
strcat ( buf, newsfx );
|
||||
}
|
||||
if (!buf)
|
||||
#endif /* USE_ONLY_8DOT3 */
|
||||
{
|
||||
buf = m_alloc(strlen(iname)+4+1);
|
||||
strcpy(stpcpy(buf,iname), mode==1 ? EXTSEP_S "asc" :
|
||||
mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg");
|
||||
}
|
||||
name = buf;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
while( !overwrite_filep (name) )
|
||||
{
|
||||
char *tmp = ask_outfile_name (NULL, 0);
|
||||
if ( !tmp || !*tmp )
|
||||
{
|
||||
m_free (tmp);
|
||||
rc = G10ERR_FILE_EXISTS;
|
||||
break;
|
||||
}
|
||||
m_free (buf);
|
||||
name = buf = tmp;
|
||||
}
|
||||
|
||||
if( !rc )
|
||||
{
|
||||
if( !(*a = iobuf_create( name )) )
|
||||
{
|
||||
log_error(_("%s: can't create: %s\n"), name, strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
}
|
||||
else if( opt.verbose )
|
||||
log_info(_("writing to `%s'\n"), name );
|
||||
}
|
||||
m_free(buf);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Try to open a file without the extension ".sig" or ".asc"
|
||||
* Return NULL if such a file is not available.
|
||||
*/
|
||||
IOBUF
|
||||
open_sigfile( const char *iname, progress_filter_context_t *pfx )
|
||||
{
|
||||
IOBUF a = NULL;
|
||||
size_t len;
|
||||
|
||||
if( iname && !(*iname == '-' && !iname[1]) ) {
|
||||
len = strlen(iname);
|
||||
if( len > 4 && ( !strcmp(iname + len - 4, EXTSEP_S "sig")
|
||||
|| ( len > 5 && !strcmp(iname + len - 5, EXTSEP_S "sign") )
|
||||
|| !strcmp(iname + len - 4, EXTSEP_S "asc")) ) {
|
||||
char *buf;
|
||||
buf = m_strdup(iname);
|
||||
buf[len-(buf[len-1]=='n'?5:4)] = 0 ;
|
||||
a = iobuf_open( buf );
|
||||
if( a && opt.verbose )
|
||||
log_info(_("assuming signed data in `%s'\n"), buf );
|
||||
if (a && pfx)
|
||||
handle_progress (pfx, a, buf);
|
||||
m_free(buf);
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Copy the option file skeleton to the given directory.
|
||||
*/
|
||||
static void
|
||||
copy_options_file( const char *destdir )
|
||||
{
|
||||
const char *datadir = GNUPG_DATADIR;
|
||||
char *fname;
|
||||
FILE *src, *dst;
|
||||
int linefeeds=0;
|
||||
int c;
|
||||
mode_t oldmask;
|
||||
int esc = 0;
|
||||
int any_option = 0;
|
||||
|
||||
if( opt.dry_run )
|
||||
return;
|
||||
|
||||
fname = m_alloc( strlen(datadir) + strlen(destdir) + 15 );
|
||||
strcpy(stpcpy(fname, datadir), DIRSEP_S "options" SKELEXT );
|
||||
src = fopen( fname, "r" );
|
||||
if( !src ) {
|
||||
log_error(_("%s: can't open: %s\n"), fname, strerror(errno) );
|
||||
m_free(fname);
|
||||
return;
|
||||
}
|
||||
strcpy(stpcpy(fname, destdir), DIRSEP_S "gpg" EXTSEP_S "conf" );
|
||||
oldmask=umask(077);
|
||||
dst = fopen( fname, "w" );
|
||||
umask(oldmask);
|
||||
if( !dst ) {
|
||||
log_error(_("%s: can't create: %s\n"), fname, strerror(errno) );
|
||||
fclose( src );
|
||||
m_free(fname);
|
||||
return;
|
||||
}
|
||||
|
||||
while( (c=getc(src)) != EOF ) {
|
||||
if( linefeeds < 3 ) {
|
||||
if( c == '\n' )
|
||||
linefeeds++;
|
||||
}
|
||||
else {
|
||||
putc( c, dst );
|
||||
if (c== '\n')
|
||||
esc = 1;
|
||||
else if (esc == 1) {
|
||||
if (c == ' ' || c == '\t')
|
||||
;
|
||||
else if (c == '#')
|
||||
esc = 2;
|
||||
else
|
||||
any_option = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose( dst );
|
||||
fclose( src );
|
||||
log_info(_("new configuration file `%s' created\n"), fname );
|
||||
if (any_option)
|
||||
log_info (_("WARNING: options in `%s'"
|
||||
" are not yet active during this run\n"),
|
||||
fname);
|
||||
m_free(fname);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
try_make_homedir( const char *fname )
|
||||
{
|
||||
const char *defhome = GNUPG_HOMEDIR;
|
||||
|
||||
/* Create the directory only if the supplied directory name
|
||||
* is the same as the default one. This way we avoid to create
|
||||
* arbitrary directories when a non-default homedirectory is used.
|
||||
* To cope with HOME, we do compare only the suffix if we see that
|
||||
* the default homedir does start with a tilde.
|
||||
*/
|
||||
if( opt.dry_run || opt.no_homedir_creation )
|
||||
return;
|
||||
|
||||
if ( ( *defhome == '~'
|
||||
&& ( strlen(fname) >= strlen (defhome+1)
|
||||
&& !strcmp(fname+strlen(fname)-strlen(defhome+1),
|
||||
defhome+1 ) ))
|
||||
|| ( *defhome != '~'
|
||||
&& !compare_filenames( fname, defhome ) )
|
||||
) {
|
||||
if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
|
||||
log_fatal( _("%s: can't create directory: %s\n"),
|
||||
fname, strerror(errno) );
|
||||
else if( !opt.quiet )
|
||||
log_info( _("%s: directory created\n"), fname );
|
||||
copy_options_file( fname );
|
||||
/* log_info(_("you have to start GnuPG again, " */
|
||||
/* "so it can read the new configuration file\n") ); */
|
||||
/* g10_exit(1); */
|
||||
}
|
||||
}
|
241
g10/options.h
Normal file
241
g10/options.h
Normal file
|
@ -0,0 +1,241 @@
|
|||
/* options.h
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
|
||||
* 2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
#ifndef G10_OPTIONS_H
|
||||
#define G10_OPTIONS_H
|
||||
|
||||
#include <types.h>
|
||||
#include "main.h"
|
||||
#include "packet.h"
|
||||
|
||||
#undef ENABLE_COMMENT_PACKETS /* don't create comment packets */
|
||||
|
||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||
/* Norcraft can't cope with common symbols */
|
||||
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
|
||||
#define EXTERN_UNLESS_MAIN_MODULE extern
|
||||
#else
|
||||
#define EXTERN_UNLESS_MAIN_MODULE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
EXTERN_UNLESS_MAIN_MODULE
|
||||
struct {
|
||||
int verbose;
|
||||
int quiet;
|
||||
unsigned debug;
|
||||
int armor;
|
||||
int compress;
|
||||
char *outfile;
|
||||
int dry_run;
|
||||
int list_only;
|
||||
int textmode;
|
||||
int expert;
|
||||
int ask_sig_expire;
|
||||
int ask_cert_expire;
|
||||
int batch; /* run in batch mode */
|
||||
int answer_yes; /* answer yes on most questions */
|
||||
int answer_no; /* answer no on most questions */
|
||||
int check_sigs; /* check key signatures */
|
||||
int with_colons;
|
||||
int with_key_data;
|
||||
int with_fingerprint; /* opt --with-fingerprint active */
|
||||
int fingerprint; /* list fingerprints */
|
||||
int list_sigs; /* list signatures */
|
||||
int no_armor;
|
||||
int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
|
||||
int def_cipher_algo;
|
||||
int force_v3_sigs;
|
||||
int force_v4_certs;
|
||||
int force_mdc;
|
||||
int disable_mdc;
|
||||
int def_digest_algo;
|
||||
int cert_digest_algo;
|
||||
int def_compress_algo;
|
||||
const char *def_secret_key;
|
||||
char *def_recipient;
|
||||
int def_recipient_self;
|
||||
int def_cert_check_level;
|
||||
int sk_comments;
|
||||
int no_version;
|
||||
int marginals_needed;
|
||||
int completes_needed;
|
||||
int max_cert_depth;
|
||||
const char *homedir;
|
||||
|
||||
char *display; /* 5 options to be passed to the gpg-agent */
|
||||
char *ttyname;
|
||||
char *ttytype;
|
||||
char *lc_ctype;
|
||||
char *lc_messages;
|
||||
|
||||
int skip_verify;
|
||||
int compress_keys;
|
||||
int compress_sigs;
|
||||
/* TM_CLASSIC must be zero to accomodate trustdbs generated before
|
||||
we started storing the trust model inside the trustdb. */
|
||||
enum {TM_CLASSIC=0, TM_PGP=1, TM_ALWAYS, TM_AUTO} trust_model;
|
||||
unsigned int force_ownertrust;
|
||||
enum
|
||||
{
|
||||
CO_GNUPG=0, CO_RFC2440, CO_RFC1991, CO_PGP2, CO_PGP6, CO_PGP7, CO_PGP8
|
||||
} compliance;
|
||||
int pgp2_workarounds;
|
||||
unsigned int emulate_bugs; /* bug emulation flags EMUBUG_xxxx */
|
||||
int shm_coprocess;
|
||||
const char *set_filename;
|
||||
const char *comment_string;
|
||||
int throw_keyid;
|
||||
const char *photo_viewer;
|
||||
int s2k_mode;
|
||||
int s2k_digest_algo;
|
||||
int s2k_cipher_algo;
|
||||
int simple_sk_checksum; /* create the deprecated rfc2440 secret
|
||||
key protection*/
|
||||
int not_dash_escaped;
|
||||
int escape_from;
|
||||
int lock_once;
|
||||
char *keyserver_uri;
|
||||
char *keyserver_scheme;
|
||||
char *keyserver_host;
|
||||
char *keyserver_port;
|
||||
char *keyserver_opaque;
|
||||
struct
|
||||
{
|
||||
int verbose;
|
||||
int include_revoked;
|
||||
int include_disabled;
|
||||
int include_subkeys;
|
||||
int honor_http_proxy;
|
||||
int broken_http_proxy;
|
||||
int use_temp_files;
|
||||
int keep_temp_files;
|
||||
int fake_v3_keyids;
|
||||
int auto_key_retrieve;
|
||||
int try_dns_srv;
|
||||
unsigned int import_options;
|
||||
unsigned int export_options;
|
||||
STRLIST other;
|
||||
} keyserver_options;
|
||||
int exec_disable;
|
||||
int exec_path_set;
|
||||
unsigned int import_options;
|
||||
unsigned int export_options;
|
||||
unsigned int list_options;
|
||||
unsigned int verify_options;
|
||||
char *def_preference_list;
|
||||
prefitem_t *personal_cipher_prefs;
|
||||
prefitem_t *personal_digest_prefs;
|
||||
prefitem_t *personal_compress_prefs;
|
||||
int no_perm_warn;
|
||||
int no_mdc_warn;
|
||||
char *temp_dir;
|
||||
int no_encrypt_to;
|
||||
int interactive;
|
||||
STRLIST sig_notation_data;
|
||||
STRLIST cert_notation_data;
|
||||
STRLIST sig_policy_url;
|
||||
STRLIST cert_policy_url;
|
||||
int use_embedded_filename;
|
||||
int allow_non_selfsigned_uid;
|
||||
int allow_freeform_uid;
|
||||
int no_literal;
|
||||
ulong set_filesize;
|
||||
int fast_list_mode;
|
||||
int fixed_list_mode;
|
||||
int ignore_time_conflict;
|
||||
int ignore_valid_from;
|
||||
int ignore_crc_error;
|
||||
int ignore_mdc_error;
|
||||
int command_fd;
|
||||
const char *override_session_key;
|
||||
int show_session_key;
|
||||
int use_agent;
|
||||
const char *gpg_agent_info;
|
||||
int merge_only;
|
||||
int try_all_secrets;
|
||||
int no_expensive_trust_checks;
|
||||
int no_sig_cache;
|
||||
int no_sig_create_check;
|
||||
int no_auto_check_trustdb;
|
||||
int preserve_permissions;
|
||||
int no_homedir_creation;
|
||||
struct groupitem *grouplist;
|
||||
int strict;
|
||||
int mangle_dos_filenames;
|
||||
int enable_progress_filter;
|
||||
} opt;
|
||||
|
||||
|
||||
#define EMUBUG_MDENCODE 4
|
||||
|
||||
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
|
||||
#define DBG_MPI_VALUE 2 /* debug mpi details */
|
||||
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
|
||||
/* (may reveal sensitive data) */
|
||||
#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
|
||||
#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
|
||||
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
|
||||
#define DBG_CACHE_VALUE 64 /* debug the cacheing */
|
||||
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
|
||||
#define DBG_TRUST_VALUE 256 /* debug the trustdb */
|
||||
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
|
||||
#define DBG_EXTPROG_VALUE 1024 /* debug external program calls */
|
||||
|
||||
|
||||
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
|
||||
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
|
||||
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
|
||||
#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
|
||||
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
|
||||
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
|
||||
|
||||
#define GNUPG (opt.compliance==CO_GNUPG)
|
||||
#define RFC1991 (opt.compliance==CO_RFC1991 || opt.compliance==CO_PGP2)
|
||||
#define RFC2440 (opt.compliance==CO_RFC2440)
|
||||
#define PGP2 (opt.compliance==CO_PGP2)
|
||||
#define PGP6 (opt.compliance==CO_PGP6)
|
||||
#define PGP7 (opt.compliance==CO_PGP7)
|
||||
#define PGP8 (opt.compliance==CO_PGP8)
|
||||
|
||||
/* Various option flags */
|
||||
|
||||
#define IMPORT_ALLOW_LOCAL_SIGS 1
|
||||
#define IMPORT_REPAIR_PKS_SUBKEY_BUG 2
|
||||
#define IMPORT_FAST_IMPORT 4
|
||||
#define IMPORT_SK2PK 8
|
||||
|
||||
#define EXPORT_INCLUDE_NON_RFC 1
|
||||
#define EXPORT_INCLUDE_LOCAL_SIGS 2
|
||||
#define EXPORT_INCLUDE_ATTRIBUTES 4
|
||||
#define EXPORT_INCLUDE_SENSITIVE_REVKEYS 8
|
||||
|
||||
#define LIST_SHOW_PHOTOS 1
|
||||
#define LIST_SHOW_POLICY 2
|
||||
#define LIST_SHOW_NOTATION 4
|
||||
#define LIST_SHOW_KEYRING 8
|
||||
#define LIST_SHOW_VALIDITY 16
|
||||
#define LIST_SHOW_LONG_KEYID 32
|
||||
|
||||
#define VERIFY_SHOW_PHOTOS 1
|
||||
#define VERIFY_SHOW_POLICY 2
|
||||
#define VERIFY_SHOW_NOTATION 4
|
||||
|
||||
#endif /*G10_OPTIONS_H*/
|
208
g10/options.skel
Normal file
208
g10/options.skel
Normal file
|
@ -0,0 +1,208 @@
|
|||
# These first three lines are not copied to the gpg.conf file in
|
||||
# the users home directory.
|
||||
# $Id$
|
||||
# Options for GnuPG
|
||||
# Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; as a special exception the author gives
|
||||
# unlimited permission to copy and/or distribute it, with or without
|
||||
# modifications, as long as this notice is preserved.
|
||||
#
|
||||
# This file is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
# Unless you specify which option file to use (with the command line
|
||||
# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf
|
||||
# by default.
|
||||
#
|
||||
# An options file can contain any long options which are available in
|
||||
# GnuPG. If the first non white space character of a line is a '#',
|
||||
# this line is ignored. Empty lines are also ignored.
|
||||
#
|
||||
# See the man page for a list of options.
|
||||
|
||||
# Uncomment the following option to get rid of the copyright notice
|
||||
|
||||
#no-greeting
|
||||
|
||||
# If you have more than 1 secret key in your keyring, you may want to
|
||||
# uncomment the following option and set your preferred keyid.
|
||||
|
||||
#default-key 621CC013
|
||||
|
||||
# If you do not pass a recipient to gpg, it will ask for one. Using
|
||||
# this option you can encrypt to a default key. Key validation will
|
||||
# not be done in this case. The second form uses the default key as
|
||||
# default recipient.
|
||||
|
||||
#default-recipient some-user-id
|
||||
#default-recipient-self
|
||||
|
||||
# By default GnuPG creates version 3 signatures for data files. This
|
||||
# is not strictly OpenPGP compliant but PGP 6 and most versions of PGP
|
||||
# 7 require them. To disable this behavior, you may use this option
|
||||
# or --openpgp.
|
||||
|
||||
#no-force-v3-sigs
|
||||
|
||||
# Because some mailers change lines starting with "From " to ">From "
|
||||
# it is good to handle such lines in a special way when creating
|
||||
# cleartext signatures; all other PGP versions do it this way too.
|
||||
# To enable full OpenPGP compliance you may want to use this option.
|
||||
|
||||
#no-escape-from-lines
|
||||
|
||||
# If you do not use the Latin-1 (ISO-8859-1) charset, you should tell
|
||||
# GnuPG which is the native character set. Please check the man page
|
||||
# for supported character sets. This character set is only used for
|
||||
# metadata and not for the actual message which does not undergo any
|
||||
# translation. Note that future version of GnuPG will change to UTF-8
|
||||
# as default character set.
|
||||
|
||||
#charset utf-8
|
||||
|
||||
# Group names may be defined like this:
|
||||
# group mynames = paige 0x12345678 joe patti
|
||||
#
|
||||
# Any time "mynames" is a recipient (-r or --recipient), it will be
|
||||
# expanded to the names "paige", "joe", and "patti", and the key ID
|
||||
# "0x12345678". Note there is only one level of expansion - you
|
||||
# cannot make an group that points to another group. Note also that
|
||||
# if there are spaces in the recipient name, this will appear as two
|
||||
# recipients. In these cases it is better to use the key ID.
|
||||
|
||||
#group mynames = paige 0x12345678 joe patti
|
||||
|
||||
# Some old Windows platforms require 8.3 filenames. If your system
|
||||
# can handle long filenames, uncomment this.
|
||||
|
||||
#no-mangle-dos-filenames
|
||||
|
||||
# Lock the file only once for the lifetime of a process. If you do
|
||||
# not define this, the lock will be obtained and released every time
|
||||
# it is needed - normally this is not needed.
|
||||
|
||||
#lock-once
|
||||
|
||||
# GnuPG can send and receive keys to and from a keyserver. These
|
||||
# servers can be HKP, email, or LDAP (if GnuPG is built with LDAP
|
||||
# support).
|
||||
#
|
||||
# Example HKP keyserver:
|
||||
# x-hkp://pgp.mit.edu
|
||||
#
|
||||
# Example email keyserver:
|
||||
# mailto:pgp-public-keys@keys.nl.pgp.net
|
||||
#
|
||||
# Example LDAP keyservers:
|
||||
# ldap://pgp.surfnet.nl:11370
|
||||
# ldap://keyserver.pgp.com
|
||||
#
|
||||
# Regular URL syntax applies, and you can set an alternate port
|
||||
# through the usual method:
|
||||
# x-hkp://keyserver.example.net:22742
|
||||
#
|
||||
# If you have problems connecting to a HKP server through a buggy http
|
||||
# proxy, you can use keyserver option broken-http-proxy (see below),
|
||||
# but first you should make sure that you have read the man page
|
||||
# regarding proxies (keyserver option honor-http-proxy)
|
||||
#
|
||||
# Most users just set the name and type of their preferred keyserver.
|
||||
# Most servers do synchronize with each other and DNS round-robin may
|
||||
# give you a quasi-random server each time.
|
||||
|
||||
#keyserver x-hkp://pgp.mit.edu
|
||||
#keyserver mailto:pgp-public-keys@keys.nl.pgp.net
|
||||
#keyserver ldap://pgp.surfnet.nl:11370
|
||||
#keyserver ldap://keyserver.pgp.com
|
||||
|
||||
# Common options for keyserver functions:
|
||||
#
|
||||
# include-disabled = when searching, include keys marked as "disabled"
|
||||
# on the keyserver (not all keyservers support this).
|
||||
#
|
||||
# no-include-revoked = when searching, do not include keys marked as
|
||||
# "revoked" on the keyserver.
|
||||
#
|
||||
# verbose = show more information as the keys are fetched.
|
||||
# Can be used more than once to increase the amount
|
||||
# of information shown.
|
||||
#
|
||||
# use-temp-files = use temporary files instead of a pipe to talk to the
|
||||
# keyserver. Some platforms (Win32 for one) always
|
||||
# have this on.
|
||||
#
|
||||
# keep-temp-files = do not delete temporary files after using them
|
||||
# (really only useful for debugging)
|
||||
#
|
||||
# honor-http-proxy = if the keyserver uses HTTP, honor the http_proxy
|
||||
# environment variable
|
||||
#
|
||||
# broken-http-proxy = try to work around a buggy HTTP proxy
|
||||
#
|
||||
# auto-key-retrieve = automatically fetch keys as needed from the keyserver
|
||||
# when verifying signatures or when importing keys that
|
||||
# have been revoked by a revocation key that is not
|
||||
# present on the keyring.
|
||||
#
|
||||
# no-include-attributes = do not include attribute IDs (aka "photo IDs")
|
||||
# when sending keys to the keyserver.
|
||||
|
||||
#keyserver-options auto-key-retrieve
|
||||
|
||||
# Uncomment this line to display photo user IDs in key listings and
|
||||
# when a signature from a key with a photo is verified.
|
||||
|
||||
#show-photos
|
||||
|
||||
# Use this program to display photo user IDs
|
||||
#
|
||||
# %i is expanded to a temporary file that contains the photo.
|
||||
# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
|
||||
# %k is expanded to the key ID of the key.
|
||||
# %K is expanded to the long OpenPGP key ID of the key.
|
||||
# %t is expanded to the extension of the image (e.g. "jpg").
|
||||
# %T is expanded to the MIME type of the image (e.g. "image/jpeg").
|
||||
# %f is expanded to the fingerprint of the key.
|
||||
# %% is %, of course.
|
||||
#
|
||||
# If %i or %I are not present, then the photo is supplied to the
|
||||
# viewer on standard input. If your platform supports it, standard
|
||||
# input is the best way to do this as it avoids the time and effort in
|
||||
# generating and then cleaning up a secure temp file.
|
||||
#
|
||||
# The default program is "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin"
|
||||
# On Mac OS X and Windows, the default is to use your regular JPEG image
|
||||
# viewer.
|
||||
#
|
||||
# Some other viewers:
|
||||
# photo-viewer "qiv %i"
|
||||
# photo-viewer "ee %i"
|
||||
# photo-viewer "display -title 'KeyID 0x%k'"
|
||||
#
|
||||
# This one saves a copy of the photo ID in your home directory:
|
||||
# photo-viewer "cat > ~/photoid-for-key-%k.%t"
|
||||
#
|
||||
# Use your MIME handler to view photos:
|
||||
# photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG"
|
||||
|
||||
# Passphrase agent
|
||||
#
|
||||
# We support the old experimental passphrase agent protocol as well as
|
||||
# the new Assuan based one (currently available in the "newpg" package
|
||||
# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent,
|
||||
# you have to run an agent as daemon and use the option
|
||||
#
|
||||
# use-agent
|
||||
#
|
||||
# which tries to use the agent but will fallback to the regular mode
|
||||
# if there is a problem connecting to the agent. The normal way to
|
||||
# locate the agent is by looking at the environment variable
|
||||
# GPG_AGENT_INFO which should have been set during gpg-agent startup.
|
||||
# In certain situations the use of this variable is not possible, thus
|
||||
# the option
|
||||
#
|
||||
# --gpg-agent-info=<path>:<pid>:1
|
||||
#
|
||||
# may be used to override it.
|
510
g10/packet.h
Normal file
510
g10/packet.h
Normal file
|
@ -0,0 +1,510 @@
|
|||
/* packet.h - packet definitions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
|
||||
* Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_PACKET_H
|
||||
#define G10_PACKET_H
|
||||
|
||||
#include "types.h"
|
||||
#include "iobuf.h"
|
||||
#include "mpi.h"
|
||||
#include "cipher.h"
|
||||
#include "filter.h"
|
||||
#include "global.h"
|
||||
|
||||
#define DEBUG_PARSE_PACKET 1
|
||||
|
||||
typedef enum {
|
||||
PKT_NONE =0,
|
||||
PKT_PUBKEY_ENC =1, /* public key encrypted packet */
|
||||
PKT_SIGNATURE =2, /* secret key encrypted packet */
|
||||
PKT_SYMKEY_ENC =3, /* session key packet (OpenPGP)*/
|
||||
PKT_ONEPASS_SIG =4, /* one pass sig packet (OpenPGP)*/
|
||||
PKT_SECRET_KEY =5, /* secret key */
|
||||
PKT_PUBLIC_KEY =6, /* public key */
|
||||
PKT_SECRET_SUBKEY =7, /* secret subkey (OpenPGP) */
|
||||
PKT_COMPRESSED =8, /* compressed data packet */
|
||||
PKT_ENCRYPTED =9, /* conventional encrypted data */
|
||||
PKT_MARKER =10, /* marker packet (OpenPGP) */
|
||||
PKT_PLAINTEXT =11, /* plaintext data with filename and mode */
|
||||
PKT_RING_TRUST =12, /* keyring trust packet */
|
||||
PKT_USER_ID =13, /* user id packet */
|
||||
PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */
|
||||
PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */
|
||||
PKT_ATTRIBUTE =17, /* PGP's attribute packet */
|
||||
PKT_ENCRYPTED_MDC =18, /* integrity protected encrypted data */
|
||||
PKT_MDC =19, /* manipulation detection code packet */
|
||||
PKT_COMMENT =61, /* new comment packet (private) */
|
||||
PKT_GPG_CONTROL =63 /* internal control packet */
|
||||
} pkttype_t;
|
||||
|
||||
typedef struct packet_struct PACKET;
|
||||
|
||||
/* PKT_GPG_CONTROL types */
|
||||
typedef enum {
|
||||
CTRLPKT_CLEARSIGN_START = 1,
|
||||
CTRLPKT_PIPEMODE = 2,
|
||||
CTRLPKT_PLAINTEXT_MARK =3
|
||||
} ctrlpkttype_t;
|
||||
|
||||
typedef enum {
|
||||
PREFTYPE_NONE = 0,
|
||||
PREFTYPE_SYM = 1,
|
||||
PREFTYPE_HASH = 2,
|
||||
PREFTYPE_ZIP = 3
|
||||
} preftype_t;
|
||||
|
||||
typedef struct {
|
||||
byte type;
|
||||
byte value;
|
||||
} prefitem_t;
|
||||
|
||||
typedef struct {
|
||||
int mode;
|
||||
byte hash_algo;
|
||||
byte salt[8];
|
||||
u32 count;
|
||||
} STRING2KEY;
|
||||
|
||||
typedef struct {
|
||||
byte version;
|
||||
byte cipher_algo; /* cipher algorithm used */
|
||||
STRING2KEY s2k;
|
||||
byte seskeylen; /* keylength in byte or 0 for no seskey */
|
||||
byte seskey[1];
|
||||
} PKT_symkey_enc;
|
||||
|
||||
typedef struct {
|
||||
u32 keyid[2]; /* 64 bit keyid */
|
||||
byte version;
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte throw_keyid;
|
||||
MPI data[PUBKEY_MAX_NENC];
|
||||
} PKT_pubkey_enc;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32 keyid[2]; /* 64 bit keyid */
|
||||
byte sig_class; /* sig classification */
|
||||
byte digest_algo; /* algorithm used for digest */
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte last; /* a stupid flag */
|
||||
} PKT_onepass_sig;
|
||||
|
||||
|
||||
typedef struct {
|
||||
size_t size; /* allocated */
|
||||
size_t len; /* used */
|
||||
byte data[1];
|
||||
} subpktarea_t;
|
||||
|
||||
struct revocation_key {
|
||||
byte class;
|
||||
byte algid;
|
||||
byte fpr[MAX_FINGERPRINT_LEN];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ulong local_id; /* internal use, valid if > 0 */
|
||||
struct {
|
||||
unsigned checked:1; /* signature has been checked */
|
||||
unsigned valid:1; /* signature is good (if checked is set) */
|
||||
unsigned unknown_critical:1;
|
||||
unsigned exportable:1;
|
||||
unsigned revocable:1;
|
||||
unsigned policy_url:1; /* Policy URL is present */
|
||||
unsigned notation:1; /* At least one notation is present */
|
||||
unsigned expired:1;
|
||||
} flags;
|
||||
u32 keyid[2]; /* 64 bit keyid */
|
||||
u32 timestamp; /* signature made */
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
byte version;
|
||||
byte sig_class; /* sig classification, append for MD calculation*/
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
/* (PUBKEY_ALGO_xxx) */
|
||||
byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
|
||||
byte trust_depth;
|
||||
byte trust_value;
|
||||
const byte *trust_regexp;
|
||||
struct revocation_key **revkey;
|
||||
int numrevkeys;
|
||||
subpktarea_t *hashed; /* all subpackets with hashed data (v4 only) */
|
||||
subpktarea_t *unhashed; /* ditto for unhashed data */
|
||||
byte digest_start[2]; /* first 2 bytes of the digest */
|
||||
MPI data[PUBKEY_MAX_NSIG];
|
||||
} PKT_signature;
|
||||
|
||||
#define ATTRIB_IMAGE 1
|
||||
|
||||
/* This is the cooked form of attributes */
|
||||
struct user_attribute {
|
||||
byte type;
|
||||
const byte *data;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int ref; /* reference counter */
|
||||
int len; /* length of the name */
|
||||
struct user_attribute *attribs;
|
||||
int numattribs;
|
||||
byte *attrib_data; /* if this is not NULL, the packet is an attribute */
|
||||
unsigned long attrib_len;
|
||||
byte *namehash;
|
||||
int help_key_usage;
|
||||
u32 help_key_expire;
|
||||
int help_full_count;
|
||||
int help_marginal_count;
|
||||
int is_primary; /* 2 if set via the primary flag, 1 if calculated */
|
||||
int is_revoked;
|
||||
int is_expired;
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
prefitem_t *prefs; /* list of preferences (may be NULL)*/
|
||||
int mdc_feature;
|
||||
int ks_modify;
|
||||
u32 created; /* according to the self-signature */
|
||||
byte selfsigversion;
|
||||
char name[1];
|
||||
} PKT_user_id;
|
||||
|
||||
|
||||
/****************
|
||||
* Note about the pkey/skey elements: We assume that the secret keys
|
||||
* has the same elemts as the public key at the begin of the array, so
|
||||
* that npkey < nskey and it is possible to compare the secret and
|
||||
* public keys by comparing the first npkey elements of pkey againts skey.
|
||||
*/
|
||||
typedef struct {
|
||||
u32 timestamp; /* key made */
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
u32 max_expiredate; /* must not expire past this date */
|
||||
byte hdrbytes; /* number of header bytes */
|
||||
byte version;
|
||||
byte selfsigversion; /* highest version of all of the self-sigs */
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte pubkey_usage; /* for now only used to pass it to getkey() */
|
||||
byte req_usage; /* hack to pass a request to getkey() */
|
||||
byte req_algo; /* Ditto */
|
||||
u32 has_expired; /* set to the expiration date if expired */
|
||||
int is_revoked; /* key has been revoked */
|
||||
int is_valid; /* key (especially subkey) is valid */
|
||||
int dont_cache; /* do not cache this */
|
||||
ulong local_id; /* internal use, valid if > 0 */
|
||||
u32 main_keyid[2]; /* keyid of the primary key */
|
||||
u32 keyid[2]; /* calculated by keyid_from_pk() */
|
||||
byte is_primary;
|
||||
byte is_disabled; /* 0 for unset, 1 for enabled, 2 for disabled. */
|
||||
prefitem_t *prefs; /* list of preferences (may be NULL) */
|
||||
int mdc_feature; /* mdc feature set */
|
||||
PKT_user_id *user_id; /* if != NULL: found by that uid */
|
||||
struct revocation_key *revkey;
|
||||
int numrevkeys;
|
||||
u32 trust_timestamp;
|
||||
byte trust_depth;
|
||||
byte trust_value;
|
||||
const byte *trust_regexp;
|
||||
MPI pkey[PUBKEY_MAX_NPKEY];
|
||||
} PKT_public_key;
|
||||
|
||||
/* Evaluates as true if the pk is disabled, and false if it isn't. If
|
||||
there is no disable value cached, fill one in. */
|
||||
#define pk_is_disabled(a) (((a)->is_disabled)?((a)->is_disabled==2):(cache_disabled_value((a))))
|
||||
|
||||
typedef struct {
|
||||
u32 timestamp; /* key made */
|
||||
u32 expiredate; /* expires at this date or 0 if not at all */
|
||||
u32 max_expiredate; /* must not expire past this date */
|
||||
byte hdrbytes; /* number of header bytes */
|
||||
byte version;
|
||||
byte pubkey_algo; /* algorithm used for public key scheme */
|
||||
byte pubkey_usage;
|
||||
byte req_usage;
|
||||
byte req_algo;
|
||||
u32 has_expired; /* set to the expiration date if expired */
|
||||
int is_revoked; /* key has been revoked */
|
||||
int is_valid; /* key (especially subkey) is valid */
|
||||
u32 main_keyid[2]; /* keyid of the primary key */
|
||||
u32 keyid[2];
|
||||
byte is_primary;
|
||||
byte is_protected; /* The secret info is protected and must */
|
||||
/* be decrypted before use, the protected */
|
||||
/* MPIs are simply (void*) pointers to memory */
|
||||
/* and should never be passed to a mpi_xxx() */
|
||||
struct {
|
||||
byte algo; /* cipher used to protect the secret information*/
|
||||
byte sha1chk; /* SHA1 is used instead of a 16 bit checksum */
|
||||
STRING2KEY s2k;
|
||||
byte ivlen; /* used length of the iv */
|
||||
byte iv[16]; /* initialization vector for CFB mode */
|
||||
} protect;
|
||||
MPI skey[PUBKEY_MAX_NSKEY];
|
||||
u16 csum; /* checksum */
|
||||
} PKT_secret_key;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int len; /* length of data */
|
||||
char data[1];
|
||||
} PKT_comment;
|
||||
|
||||
typedef struct {
|
||||
u32 len; /* reserved */
|
||||
byte new_ctb;
|
||||
byte algorithm;
|
||||
IOBUF buf; /* IOBUF reference */
|
||||
} PKT_compressed;
|
||||
|
||||
typedef struct {
|
||||
u32 len; /* length of encrypted data */
|
||||
int extralen; /* this is (blocksize+2) */
|
||||
byte new_ctb; /* uses a new CTB */
|
||||
byte mdc_method; /* > 0: integrity protected encrypted data packet */
|
||||
IOBUF buf; /* IOBUF reference */
|
||||
} PKT_encrypted;
|
||||
|
||||
typedef struct {
|
||||
byte hash[20];
|
||||
} PKT_mdc;
|
||||
|
||||
typedef struct {
|
||||
unsigned int trustval;
|
||||
unsigned int sigcache;
|
||||
} PKT_ring_trust;
|
||||
|
||||
typedef struct {
|
||||
u32 len; /* length of encrypted data */
|
||||
IOBUF buf; /* IOBUF reference */
|
||||
byte new_ctb;
|
||||
byte is_partial; /* partial length encoded */
|
||||
int mode;
|
||||
u32 timestamp;
|
||||
int namelen;
|
||||
char name[1];
|
||||
} PKT_plaintext;
|
||||
|
||||
typedef struct {
|
||||
int control;
|
||||
size_t datalen;
|
||||
char data[1];
|
||||
} PKT_gpg_control;
|
||||
|
||||
/* combine all packets into a union */
|
||||
struct packet_struct {
|
||||
pkttype_t pkttype;
|
||||
union {
|
||||
void *generic;
|
||||
PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */
|
||||
PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */
|
||||
PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */
|
||||
PKT_signature *signature; /* PKT_SIGNATURE */
|
||||
PKT_public_key *public_key; /* PKT_PUBLIC_[SUB)KEY */
|
||||
PKT_secret_key *secret_key; /* PKT_SECRET_[SUB]KEY */
|
||||
PKT_comment *comment; /* PKT_COMMENT */
|
||||
PKT_user_id *user_id; /* PKT_USER_ID */
|
||||
PKT_compressed *compressed; /* PKT_COMPRESSED */
|
||||
PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */
|
||||
PKT_mdc *mdc; /* PKT_MDC */
|
||||
PKT_ring_trust *ring_trust; /* PKT_RING_TRUST */
|
||||
PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
|
||||
PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */
|
||||
} pkt;
|
||||
};
|
||||
|
||||
#define init_packet(a) do { (a)->pkttype = 0; \
|
||||
(a)->pkt.generic = NULL; \
|
||||
} while(0)
|
||||
|
||||
typedef enum {
|
||||
SIGSUBPKT_TEST_CRITICAL=-3,
|
||||
SIGSUBPKT_LIST_UNHASHED=-2,
|
||||
SIGSUBPKT_LIST_HASHED =-1,
|
||||
SIGSUBPKT_NONE = 0,
|
||||
SIGSUBPKT_SIG_CREATED = 2, /* signature creation time */
|
||||
SIGSUBPKT_SIG_EXPIRE = 3, /* signature expiration time */
|
||||
SIGSUBPKT_EXPORTABLE = 4, /* exportable */
|
||||
SIGSUBPKT_TRUST = 5, /* trust signature */
|
||||
SIGSUBPKT_REGEXP = 6, /* regular expression */
|
||||
SIGSUBPKT_REVOCABLE = 7, /* revocable */
|
||||
SIGSUBPKT_KEY_EXPIRE = 9, /* key expiration time */
|
||||
SIGSUBPKT_ARR =10, /* additional recipient request */
|
||||
SIGSUBPKT_PREF_SYM =11, /* preferred symmetric algorithms */
|
||||
SIGSUBPKT_REV_KEY =12, /* revocation key */
|
||||
SIGSUBPKT_ISSUER =16, /* issuer key ID */
|
||||
SIGSUBPKT_NOTATION =20, /* notation data */
|
||||
SIGSUBPKT_PREF_HASH =21, /* preferred hash algorithms */
|
||||
SIGSUBPKT_PREF_COMPR =22, /* preferred compression algorithms */
|
||||
SIGSUBPKT_KS_FLAGS =23, /* key server preferences */
|
||||
SIGSUBPKT_PREF_KS =24, /* preferred key server */
|
||||
SIGSUBPKT_PRIMARY_UID =25, /* primary user id */
|
||||
SIGSUBPKT_POLICY =26, /* policy URL */
|
||||
SIGSUBPKT_KEY_FLAGS =27, /* key flags */
|
||||
SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */
|
||||
SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */
|
||||
SIGSUBPKT_FEATURES =30, /* feature flags */
|
||||
|
||||
SIGSUBPKT_FLAG_CRITICAL=128
|
||||
} sigsubpkttype_t;
|
||||
|
||||
|
||||
/*-- mainproc.c --*/
|
||||
int proc_packets( void *ctx, IOBUF a );
|
||||
int proc_signature_packets( void *ctx, IOBUF a,
|
||||
STRLIST signedfiles, const char *sigfile );
|
||||
int proc_encryption_packets( void *ctx, IOBUF a );
|
||||
int list_packets( IOBUF a );
|
||||
|
||||
/*-- parse-packet.c --*/
|
||||
int set_packet_list_mode( int mode );
|
||||
|
||||
#if DEBUG_PARSE_PACKET
|
||||
int dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid,
|
||||
const char* file, int lineno );
|
||||
int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt,
|
||||
const char* file, int lineno );
|
||||
int dbg_copy_all_packets( IOBUF inp, IOBUF out,
|
||||
const char* file, int lineno );
|
||||
int dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff,
|
||||
const char* file, int lineno );
|
||||
int dbg_skip_some_packets( IOBUF inp, unsigned n,
|
||||
const char* file, int lineno );
|
||||
#define search_packet( a,b,c,d ) \
|
||||
dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ )
|
||||
#define parse_packet( a, b ) \
|
||||
dbg_parse_packet( (a), (b), __FILE__, __LINE__ )
|
||||
#define copy_all_packets( a,b ) \
|
||||
dbg_copy_all_packets((a),(b), __FILE__, __LINE__ )
|
||||
#define copy_some_packets( a,b,c ) \
|
||||
dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ )
|
||||
#define skip_some_packets( a,b ) \
|
||||
dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
|
||||
#else
|
||||
int search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid );
|
||||
int parse_packet( IOBUF inp, PACKET *ret_pkt);
|
||||
int copy_all_packets( IOBUF inp, IOBUF out );
|
||||
int copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff );
|
||||
int skip_some_packets( IOBUF inp, unsigned n );
|
||||
#endif
|
||||
|
||||
const byte *enum_sig_subpkt ( const subpktarea_t *subpkts,
|
||||
sigsubpkttype_t reqtype,
|
||||
size_t *ret_n, int *start, int *critical );
|
||||
const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
|
||||
sigsubpkttype_t reqtype,
|
||||
size_t *ret_n );
|
||||
const byte *parse_sig_subpkt2 ( PKT_signature *sig,
|
||||
sigsubpkttype_t reqtype,
|
||||
size_t *ret_n );
|
||||
int parse_one_sig_subpkt( const byte *buffer, size_t n, int type );
|
||||
void parse_revkeys(PKT_signature *sig);
|
||||
int parse_attribute_subpkts(PKT_user_id *uid);
|
||||
void make_attribute_uidname(PKT_user_id *uid, size_t max_namelen);
|
||||
PACKET *create_gpg_control ( ctrlpkttype_t type,
|
||||
const byte *data,
|
||||
size_t datalen );
|
||||
|
||||
/*-- build-packet.c --*/
|
||||
int build_packet( IOBUF inp, PACKET *pkt );
|
||||
u32 calc_packet_length( PACKET *pkt );
|
||||
void hash_public_key( MD_HANDLE md, PKT_public_key *pk );
|
||||
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 );
|
||||
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,
|
||||
const void *header,u32 headerlen);
|
||||
|
||||
/*-- free-packet.c --*/
|
||||
void free_symkey_enc( PKT_symkey_enc *enc );
|
||||
void free_pubkey_enc( PKT_pubkey_enc *enc );
|
||||
void free_seckey_enc( PKT_signature *enc );
|
||||
int digest_algo_from_sig( PKT_signature *sig );
|
||||
void release_public_key_parts( PKT_public_key *pk );
|
||||
void free_public_key( PKT_public_key *key );
|
||||
void release_secret_key_parts( PKT_secret_key *sk );
|
||||
void free_secret_key( PKT_secret_key *sk );
|
||||
void free_attributes(PKT_user_id *uid);
|
||||
void free_user_id( PKT_user_id *uid );
|
||||
void free_comment( PKT_comment *rem );
|
||||
void free_packet( PACKET *pkt );
|
||||
prefitem_t *copy_prefs (const prefitem_t *prefs);
|
||||
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
|
||||
void copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
|
||||
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
|
||||
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
|
||||
PKT_user_id *scopy_user_id (PKT_user_id *sd );
|
||||
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
|
||||
int cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b );
|
||||
int cmp_signatures( PKT_signature *a, PKT_signature *b );
|
||||
int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
|
||||
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
|
||||
|
||||
|
||||
/*-- sig-check.c --*/
|
||||
int signature_check( PKT_signature *sig, MD_HANDLE digest );
|
||||
int signature_check2( PKT_signature *sig, MD_HANDLE digest,
|
||||
u32 *r_expiredate, int *r_expired );
|
||||
|
||||
/*-- seckey-cert.c --*/
|
||||
int is_secret_key_protected( PKT_secret_key *sk );
|
||||
int check_secret_key( PKT_secret_key *sk, int retries );
|
||||
int protect_secret_key( PKT_secret_key *sk, DEK *dek );
|
||||
|
||||
/*-- pubkey-enc.c --*/
|
||||
int get_session_key( PKT_pubkey_enc *k, DEK *dek );
|
||||
int get_override_session_key( DEK *dek, const char *string );
|
||||
|
||||
/*-- compress.c --*/
|
||||
int handle_compressed( void *ctx, PKT_compressed *cd,
|
||||
int (*callback)(IOBUF, void *), void *passthru );
|
||||
|
||||
/*-- encr-data.c --*/
|
||||
int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek );
|
||||
|
||||
/*-- plaintext.c --*/
|
||||
int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
|
||||
int nooutput, int clearsig );
|
||||
int ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
|
||||
const char *inname, int textmode );
|
||||
|
||||
/*-- comment.c --*/
|
||||
int write_comment( IOBUF out, const char *s );
|
||||
|
||||
/*-- sign.c --*/
|
||||
int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
|
||||
PKT_user_id *uid, PKT_public_key *subpk,
|
||||
PKT_secret_key *sk, int sigclass, int digest_algo,
|
||||
int sigversion, u32 timestamp, u32 duration,
|
||||
int (*mksubpkt)(PKT_signature *, void *),
|
||||
void *opaque );
|
||||
int update_keysig_packet( PKT_signature **ret_sig,
|
||||
PKT_signature *orig_sig,
|
||||
PKT_public_key *pk,
|
||||
PKT_user_id *uid,
|
||||
PKT_public_key *subpk,
|
||||
PKT_secret_key *sk,
|
||||
int (*mksubpkt)(PKT_signature *, void *),
|
||||
void *opaque );
|
||||
|
||||
/*-- keygen.c --*/
|
||||
PKT_user_id *generate_user_id(void);
|
||||
|
||||
#endif /*G10_PACKET_H*/
|
2281
g10/parse-packet.c
Normal file
2281
g10/parse-packet.c
Normal file
File diff suppressed because it is too large
Load diff
1238
g10/passphrase.c
Normal file
1238
g10/passphrase.c
Normal file
File diff suppressed because it is too large
Load diff
333
g10/photoid.c
Normal file
333
g10/photoid.c
Normal file
|
@ -0,0 +1,333 @@
|
|||
/* photoid.c - photo ID handling code
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef __MINGW32__
|
||||
# include <windows.h>
|
||||
# ifndef VER_PLATFORM_WIN32_WINDOWS
|
||||
# define VER_PLATFORM_WIN32_WINDOWS 1
|
||||
# endif
|
||||
#endif
|
||||
#include "packet.h"
|
||||
#include "status.h"
|
||||
#include "exec.h"
|
||||
#include "keydb.h"
|
||||
#include "util.h"
|
||||
#include "i18n.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "photoid.h"
|
||||
|
||||
/* Generate a new photo id packet, or return NULL if canceled */
|
||||
PKT_user_id *generate_photo_id(PKT_public_key *pk)
|
||||
{
|
||||
PKT_user_id *uid;
|
||||
int error=1,i;
|
||||
unsigned int len;
|
||||
char *filename=NULL;
|
||||
byte *photo=NULL;
|
||||
byte header[16];
|
||||
IOBUF file;
|
||||
|
||||
header[0]=0x10; /* little side of photo header length */
|
||||
header[1]=0; /* big side of photo header length */
|
||||
header[2]=1; /* 1 == version of photo header */
|
||||
header[3]=1; /* 1 == JPEG */
|
||||
|
||||
for(i=4;i<16;i++) /* The reserved bytes */
|
||||
header[i]=0;
|
||||
|
||||
#define EXTRA_UID_NAME_SPACE 71
|
||||
uid=m_alloc_clear(sizeof(*uid)+71);
|
||||
|
||||
printf(_("\nPick an image to use for your photo ID. "
|
||||
"The image must be a JPEG file.\n"
|
||||
"Remember that the image is stored within your public key. "
|
||||
"If you use a\n"
|
||||
"very large picture, your key will become very large as well!\n"
|
||||
"Keeping the image close to 240x288 is a good size to use.\n"));
|
||||
|
||||
while(photo==NULL)
|
||||
{
|
||||
printf("\n");
|
||||
|
||||
m_free(filename);
|
||||
|
||||
filename=cpr_get("photoid.jpeg.add",
|
||||
_("Enter JPEG filename for photo ID: "));
|
||||
|
||||
if(strlen(filename)==0)
|
||||
goto scram;
|
||||
|
||||
file=iobuf_open(filename);
|
||||
if(!file)
|
||||
{
|
||||
log_error(_("Unable to open photo \"%s\": %s\n"),
|
||||
filename,strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
len=iobuf_get_filelength(file);
|
||||
if(len>6144)
|
||||
{
|
||||
printf("This JPEG is really large (%d bytes) !\n",len);
|
||||
if(!cpr_get_answer_is_yes("photoid.jpeg.size",
|
||||
_("Are you sure you want to use it (y/N)? ")))
|
||||
{
|
||||
iobuf_close(file);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
photo=m_alloc(len);
|
||||
iobuf_read(file,photo,len);
|
||||
iobuf_close(file);
|
||||
|
||||
/* Is it a JPEG? */
|
||||
if(photo[0]!=0xFF || photo[1]!=0xD8 ||
|
||||
photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
|
||||
{
|
||||
log_error(_("\"%s\" is not a JPEG file\n"),filename);
|
||||
m_free(photo);
|
||||
photo=NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Build the packet */
|
||||
build_attribute_subpkt(uid,1,photo,len,header,16);
|
||||
parse_attribute_subpkts(uid);
|
||||
make_attribute_uidname(uid, EXTRA_UID_NAME_SPACE);
|
||||
|
||||
/* Showing the photo is not safe when noninteractive since the
|
||||
"user" may not be able to dismiss a viewer window! */
|
||||
if(opt.command_fd==-1)
|
||||
{
|
||||
show_photos(uid->attribs,uid->numattribs,pk,NULL);
|
||||
switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
|
||||
_("Is this photo correct (y/N/q)? ")))
|
||||
{
|
||||
case -1:
|
||||
goto scram;
|
||||
case 0:
|
||||
free_attributes(uid);
|
||||
m_free(photo);
|
||||
photo=NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error=0;
|
||||
uid->ref=1;
|
||||
|
||||
scram:
|
||||
m_free(filename);
|
||||
m_free(photo);
|
||||
|
||||
if(error)
|
||||
{
|
||||
free_attributes(uid);
|
||||
m_free(uid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return uid;
|
||||
}
|
||||
|
||||
/* Returns 0 for error, 1 for valid */
|
||||
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
|
||||
{
|
||||
u16 headerlen;
|
||||
|
||||
if(attr->len<3)
|
||||
return 0;
|
||||
|
||||
/* For historical reasons (i.e. "oops!"), the header length is
|
||||
little endian. */
|
||||
headerlen=(attr->data[1]<<8) | attr->data[0];
|
||||
|
||||
if(headerlen>attr->len)
|
||||
return 0;
|
||||
|
||||
if(type && attr->len>=4)
|
||||
{
|
||||
if(attr->data[2]==1) /* header version 1 */
|
||||
*type=attr->data[3];
|
||||
else
|
||||
*type=0;
|
||||
}
|
||||
|
||||
*len=attr->len-headerlen;
|
||||
|
||||
if(*len==0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* style==0 for extension, 1 for name, 2 for MIME type. Remember that
|
||||
the "name" style string could be used in a user ID name field, so
|
||||
make sure it is not too big (see parse-packet.c:parse_attribute).
|
||||
Extensions should be 3 characters long for the best cross-platform
|
||||
compatibility. */
|
||||
char *image_type_to_string(byte type,int style)
|
||||
{
|
||||
char *string;
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 1: /* jpeg */
|
||||
if(style==0)
|
||||
string="jpg";
|
||||
else if(style==1)
|
||||
string="jpeg";
|
||||
else
|
||||
string="image/jpeg";
|
||||
break;
|
||||
|
||||
default:
|
||||
if(style==0)
|
||||
string="bin";
|
||||
else if(style==1)
|
||||
string="unknown";
|
||||
else
|
||||
string="image/x-unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER)
|
||||
static const char *get_default_photo_command(void)
|
||||
{
|
||||
#if defined(__MINGW32__)
|
||||
OSVERSIONINFO osvi;
|
||||
|
||||
memset(&osvi,0,sizeof(osvi));
|
||||
osvi.dwOSVersionInfoSize=sizeof(osvi);
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
|
||||
return "start /w %i";
|
||||
else
|
||||
return "cmd /c start /w %i";
|
||||
#elif defined(__APPLE__)
|
||||
/* OS X. This really needs more than just __APPLE__. */
|
||||
return "open %I";
|
||||
#elif defined(__riscos__)
|
||||
return "Filer_Run %I";
|
||||
#else
|
||||
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void show_photos(const struct user_attribute *attrs,
|
||||
int count,PKT_public_key *pk,PKT_secret_key *sk)
|
||||
{
|
||||
#ifndef DISABLE_PHOTO_VIEWER
|
||||
int i;
|
||||
struct expando_args args;
|
||||
u32 len;
|
||||
u32 kid[2]={0,0};
|
||||
|
||||
memset(&args,0,sizeof(args));
|
||||
args.pk=pk;
|
||||
args.sk=sk;
|
||||
|
||||
if(pk)
|
||||
keyid_from_pk(pk,kid);
|
||||
else if(sk)
|
||||
keyid_from_sk(sk,kid);
|
||||
|
||||
for(i=0;i<count;i++)
|
||||
if(attrs[i].type==ATTRIB_IMAGE &&
|
||||
parse_image_header(&attrs[i],&args.imagetype,&len))
|
||||
{
|
||||
char *command,*name;
|
||||
struct exec_info *spawn;
|
||||
int offset=attrs[i].len-len;
|
||||
|
||||
#ifdef FIXED_PHOTO_VIEWER
|
||||
opt.photo_viewer=FIXED_PHOTO_VIEWER;
|
||||
#else
|
||||
if(!opt.photo_viewer)
|
||||
opt.photo_viewer=get_default_photo_command();
|
||||
#endif
|
||||
|
||||
/* make command grow */
|
||||
command=pct_expando(opt.photo_viewer,&args);
|
||||
if(!command)
|
||||
goto fail;
|
||||
|
||||
name=m_alloc(16+strlen(EXTSEP_S)+
|
||||
strlen(image_type_to_string(args.imagetype,0))+1);
|
||||
|
||||
/* Make the filename. Notice we are not using the image
|
||||
encoding type for more than cosmetics. Most external image
|
||||
viewers can handle a multitude of types, and even if one
|
||||
cannot understand a particular type, we have no way to know
|
||||
which. The spec permits this, by the way. -dms */
|
||||
|
||||
#ifdef USE_ONLY_8DOT3
|
||||
sprintf(name,"%08lX" EXTSEP_S "%s",(ulong)kid[1],
|
||||
image_type_to_string(args.imagetype,0));
|
||||
#else
|
||||
sprintf(name,"%08lX%08lX" EXTSEP_S "%s",(ulong)kid[0],(ulong)kid[1],
|
||||
image_type_to_string(args.imagetype,0));
|
||||
#endif
|
||||
|
||||
if(exec_write(&spawn,NULL,command,name,1,1)!=0)
|
||||
{
|
||||
m_free(name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef __riscos__
|
||||
riscos_set_filetype_by_mimetype(spawn->tempfile_in,
|
||||
image_type_to_string(args.imagetype,2));
|
||||
#endif
|
||||
|
||||
m_free(name);
|
||||
|
||||
fwrite(&attrs[i].data[offset],attrs[i].len-offset,1,spawn->tochild);
|
||||
|
||||
if(exec_read(spawn)!=0)
|
||||
{
|
||||
exec_finish(spawn);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(exec_finish(spawn)!=0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
fail:
|
||||
log_error(_("unable to display photo ID!\n"));
|
||||
#endif
|
||||
}
|
34
g10/photoid.h
Normal file
34
g10/photoid.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* photoid.h
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/* Photo ID functions */
|
||||
|
||||
#ifndef _PHOTOID_H_
|
||||
#define _PHOTOID_H_
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
PKT_user_id *generate_photo_id(PKT_public_key *pk);
|
||||
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len);
|
||||
char *image_type_to_string(byte type,int style);
|
||||
void show_photos(const struct user_attribute *attrs,
|
||||
int count,PKT_public_key *pk,PKT_secret_key *sk);
|
||||
|
||||
#endif /* !_PHOTOID_H_ */
|
1376
g10/pkclist.c
Normal file
1376
g10/pkclist.c
Normal file
File diff suppressed because it is too large
Load diff
446
g10/plaintext.c
Normal file
446
g10/plaintext.c
Normal file
|
@ -0,0 +1,446 @@
|
|||
/* plaintext.c - process plaintext packets
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#include <fcntl.h> /* for setmode() */
|
||||
#endif
|
||||
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "ttyio.h"
|
||||
#include "filter.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Handle a plaintext packet. If MFX is not NULL, update the MDs
|
||||
* Note: we should use the filter stuff here, but we have to add some
|
||||
* easy mimic to set a read limit, so we calculate only the
|
||||
* bytes from the plaintext.
|
||||
*/
|
||||
int
|
||||
handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
|
||||
int nooutput, int clearsig )
|
||||
{
|
||||
char *fname = NULL;
|
||||
FILE *fp = NULL;
|
||||
int rc = 0;
|
||||
int c;
|
||||
int convert = pt->mode == 't';
|
||||
#ifdef __riscos__
|
||||
int filetype = 0xfff;
|
||||
#endif
|
||||
|
||||
/* create the filename as C string */
|
||||
if( nooutput )
|
||||
;
|
||||
else if( opt.outfile ) {
|
||||
fname = m_alloc( strlen( opt.outfile ) + 1);
|
||||
strcpy(fname, opt.outfile );
|
||||
}
|
||||
else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) {
|
||||
log_info(_("data not saved; use option \"--output\" to save it\n"));
|
||||
nooutput = 1;
|
||||
}
|
||||
else if( !opt.use_embedded_filename ) {
|
||||
fname = make_outfile_name( iobuf_get_real_fname(pt->buf) );
|
||||
if( !fname )
|
||||
fname = ask_outfile_name( pt->name, pt->namelen );
|
||||
if( !fname ) {
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fname = make_printable_string( pt->name, pt->namelen, 0 );
|
||||
}
|
||||
|
||||
if( nooutput )
|
||||
;
|
||||
else if( !*fname || (*fname=='-' && !fname[1])) {
|
||||
/* no filename or "-" given; write to stdout */
|
||||
fp = stdout;
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
setmode ( fileno(fp) , O_BINARY );
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
while( !overwrite_filep (fname) ) {
|
||||
char *tmp = ask_outfile_name (NULL, 0);
|
||||
if ( !tmp || !*tmp ) {
|
||||
m_free (tmp);
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
m_free (fname);
|
||||
fname = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef __riscos__
|
||||
if( fp || nooutput )
|
||||
;
|
||||
else if( !(fp = fopen(fname,"wb")) ) {
|
||||
log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
#else /* __riscos__ */
|
||||
/* Convert all '.' in fname to '/' -- we don't create directories! */
|
||||
for( c=0; fname[c]; ++c )
|
||||
if( fname[c] == '.' )
|
||||
fname[c] = '/';
|
||||
|
||||
if( fp || nooutput )
|
||||
;
|
||||
else {
|
||||
fp = fopen(fname,"wb");
|
||||
if( !fp ) {
|
||||
log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
|
||||
rc = G10ERR_CREATE_FILE;
|
||||
if (errno == 106)
|
||||
log_info("Do output file and input file have the same name?\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* If there's a ,xxx extension in the embedded filename,
|
||||
use that, else check whether the user input (in fname)
|
||||
has a ,xxx appended, then use that in preference */
|
||||
if( (c = riscos_get_filetype_from_string( pt->name,
|
||||
pt->namelen )) != -1 )
|
||||
filetype = c;
|
||||
if( (c = riscos_get_filetype_from_string( fname,
|
||||
strlen(fname) )) != -1 )
|
||||
filetype = c;
|
||||
riscos_set_filetype_by_number(fname, filetype);
|
||||
}
|
||||
#endif /* __riscos__ */
|
||||
|
||||
if( !pt->is_partial ) {
|
||||
/* we have an actual length (which might be zero). */
|
||||
assert( !clearsig );
|
||||
if( convert ) { /* text mode */
|
||||
for( ; pt->len; pt->len-- ) {
|
||||
if( (c = iobuf_get(pt->buf)) == -1 ) {
|
||||
log_error("Problem reading source (%u bytes remaining)\n",
|
||||
(unsigned)pt->len);
|
||||
rc = G10ERR_READ_FILE;
|
||||
goto leave;
|
||||
}
|
||||
if( mfx->md )
|
||||
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 */
|
||||
#endif
|
||||
if( fp ) {
|
||||
if( putc( c, fp ) == EOF ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* binary mode */
|
||||
byte *buffer = m_alloc( 32768 );
|
||||
while( pt->len ) {
|
||||
int len = pt->len > 32768 ? 32768 : pt->len;
|
||||
len = iobuf_read( pt->buf, buffer, len );
|
||||
if( len == -1 ) {
|
||||
log_error("Problem reading source (%u bytes remaining)\n",
|
||||
(unsigned)pt->len);
|
||||
rc = G10ERR_READ_FILE;
|
||||
m_free( buffer );
|
||||
goto leave;
|
||||
}
|
||||
if( mfx->md )
|
||||
md_write( mfx->md, buffer, len );
|
||||
if( fp ) {
|
||||
if( fwrite( buffer, 1, len, fp ) != len ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
m_free( buffer );
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
pt->len -= len;
|
||||
}
|
||||
m_free( buffer );
|
||||
}
|
||||
}
|
||||
else if( !clearsig ) {
|
||||
if( convert ) { /* text mode */
|
||||
while( (c = iobuf_get(pt->buf)) != -1 ) {
|
||||
if( mfx->md )
|
||||
md_putc(mfx->md, c );
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
if( convert && c == '\r' )
|
||||
continue; /* fixme: this hack might be too simple */
|
||||
#endif
|
||||
if( fp ) {
|
||||
if( putc( c, fp ) == EOF ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* binary mode */
|
||||
byte *buffer = m_alloc( 32768 );
|
||||
int eof;
|
||||
for( eof=0; !eof; ) {
|
||||
/* Why do we check for len < 32768:
|
||||
* If we won't, we would practically read 2 EOFs but
|
||||
* the first one has already popped the block_filter
|
||||
* off and therefore we don't catch the boundary.
|
||||
* So, always assume EOF if iobuf_read returns less bytes
|
||||
* then requested */
|
||||
int len = iobuf_read( pt->buf, buffer, 32768 );
|
||||
if( len == -1 )
|
||||
break;
|
||||
if( len < 32768 )
|
||||
eof = 1;
|
||||
if( mfx->md )
|
||||
md_write( mfx->md, buffer, len );
|
||||
if( fp ) {
|
||||
if( fwrite( buffer, 1, len, fp ) != len ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
m_free( buffer );
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_free( buffer );
|
||||
}
|
||||
pt->buf = NULL;
|
||||
}
|
||||
else { /* clear text signature - don't hash the last cr,lf */
|
||||
int state = 0;
|
||||
|
||||
while( (c = iobuf_get(pt->buf)) != -1 ) {
|
||||
if( fp ) {
|
||||
if( putc( c, fp ) == EOF ) {
|
||||
log_error("Error writing to `%s': %s\n",
|
||||
fname, strerror(errno) );
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if( !mfx->md )
|
||||
continue;
|
||||
if( state == 2 ) {
|
||||
md_putc(mfx->md, '\r' );
|
||||
md_putc(mfx->md, '\n' );
|
||||
state = 0;
|
||||
}
|
||||
if( !state ) {
|
||||
if( c == '\r' )
|
||||
state = 1;
|
||||
else if( c == '\n' )
|
||||
state = 2;
|
||||
else
|
||||
md_putc(mfx->md, c );
|
||||
}
|
||||
else if( state == 1 ) {
|
||||
if( c == '\n' )
|
||||
state = 2;
|
||||
else {
|
||||
md_putc(mfx->md, '\r' );
|
||||
if( c == '\r' )
|
||||
state = 1;
|
||||
else {
|
||||
state = 0;
|
||||
md_putc(mfx->md, c );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pt->buf = NULL;
|
||||
}
|
||||
|
||||
if( fp && fp != stdout && fclose(fp) ) {
|
||||
log_error("Error closing `%s': %s\n", fname, strerror(errno) );
|
||||
fp = NULL;
|
||||
rc = G10ERR_WRITE_FILE;
|
||||
goto leave;
|
||||
}
|
||||
fp = NULL;
|
||||
|
||||
leave:
|
||||
if( fp && fp != stdout )
|
||||
fclose(fp);
|
||||
m_free(fname);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void
|
||||
do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
|
||||
{
|
||||
text_filter_context_t tfx;
|
||||
int c;
|
||||
|
||||
if( textmode ) {
|
||||
memset( &tfx, 0, sizeof tfx);
|
||||
iobuf_push_filter( fp, text_filter, &tfx );
|
||||
}
|
||||
if( md2 ) { /* work around a strange behaviour in pgp2 */
|
||||
/* It seems that at least PGP5 converts a single CR to a CR,LF too */
|
||||
int lc = -1;
|
||||
while( (c = iobuf_get(fp)) != -1 ) {
|
||||
if( c == '\n' && lc == '\r' )
|
||||
md_putc(md2, c);
|
||||
else if( c == '\n' ) {
|
||||
md_putc(md2, '\r');
|
||||
md_putc(md2, c);
|
||||
}
|
||||
else if( c != '\n' && lc == '\r' ) {
|
||||
md_putc(md2, '\n');
|
||||
md_putc(md2, c);
|
||||
}
|
||||
else
|
||||
md_putc(md2, c);
|
||||
|
||||
if( md )
|
||||
md_putc(md, c );
|
||||
lc = c;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while( (c = iobuf_get(fp)) != -1 ) {
|
||||
if( md )
|
||||
md_putc(md, c );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Ask for the detached datafile and calculate the digest from it.
|
||||
* INFILE is the name of the input file.
|
||||
*/
|
||||
int
|
||||
ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
|
||||
const char *inname, int textmode )
|
||||
{
|
||||
progress_filter_context_t pfx;
|
||||
char *answer = NULL;
|
||||
IOBUF fp;
|
||||
int rc = 0;
|
||||
|
||||
fp = open_sigfile( inname, &pfx ); /* open default file */
|
||||
|
||||
if( !fp && !opt.batch ) {
|
||||
int any=0;
|
||||
tty_printf(_("Detached signature.\n"));
|
||||
do {
|
||||
m_free(answer);
|
||||
answer = cpr_get("detached_signature.filename",
|
||||
_("Please enter name of data file: "));
|
||||
cpr_kill_prompt();
|
||||
if( any && !*answer ) {
|
||||
rc = G10ERR_READ_FILE;
|
||||
goto leave;
|
||||
}
|
||||
fp = iobuf_open(answer);
|
||||
if( !fp && errno == ENOENT ) {
|
||||
tty_printf("No such file, try again or hit enter to quit.\n");
|
||||
any++;
|
||||
}
|
||||
else if( !fp ) {
|
||||
log_error("can't open `%s': %s\n", answer, strerror(errno) );
|
||||
rc = G10ERR_READ_FILE;
|
||||
goto leave;
|
||||
}
|
||||
} while( !fp );
|
||||
}
|
||||
|
||||
if( !fp ) {
|
||||
if( opt.verbose )
|
||||
log_info(_("reading stdin ...\n"));
|
||||
fp = iobuf_open( NULL );
|
||||
assert(fp);
|
||||
}
|
||||
do_hash( md, md2, fp, textmode );
|
||||
iobuf_close(fp);
|
||||
|
||||
leave:
|
||||
m_free(answer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Hash the given files and append the hash to hash context md.
|
||||
* If FILES is NULL, hash stdin.
|
||||
*/
|
||||
int
|
||||
hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files,
|
||||
const char *sigfilename, int textmode )
|
||||
{
|
||||
progress_filter_context_t pfx;
|
||||
IOBUF fp;
|
||||
STRLIST sl;
|
||||
|
||||
if( !files ) {
|
||||
/* check whether we can open the signed material */
|
||||
fp = open_sigfile( sigfilename, &pfx );
|
||||
if( fp ) {
|
||||
do_hash( md, md2, fp, textmode );
|
||||
iobuf_close(fp);
|
||||
return 0;
|
||||
}
|
||||
log_error (_("no signed data\n"));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
|
||||
|
||||
for (sl=files; sl; sl = sl->next ) {
|
||||
fp = iobuf_open( sl->d );
|
||||
if( !fp ) {
|
||||
log_error(_("can't open signed data `%s'\n"),
|
||||
print_fname_stdin(sl->d));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
handle_progress (&pfx, fp, sl->d);
|
||||
do_hash( md, md2, fp, textmode );
|
||||
iobuf_close(fp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
117
g10/progress.c
Normal file
117
g10/progress.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* progress.c
|
||||
* Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "iobuf.h"
|
||||
#include "filter.h"
|
||||
#include "status.h"
|
||||
#include "util.h"
|
||||
#include "options.h"
|
||||
|
||||
/****************
|
||||
* The filter is used to report progress to the user.
|
||||
*/
|
||||
int
|
||||
progress_filter (void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
int rc = 0;
|
||||
progress_filter_context_t *pfx = opaque;
|
||||
|
||||
if (control == IOBUFCTRL_INIT)
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
pfx->last = 0;
|
||||
pfx->offset = 0;
|
||||
pfx->last_time = make_timestamp ();
|
||||
|
||||
sprintf (buffer, "%.20s ? %lu %lu",
|
||||
pfx->what? pfx->what : "?",
|
||||
pfx->offset,
|
||||
pfx->total);
|
||||
write_status_text (STATUS_PROGRESS, buffer);
|
||||
}
|
||||
else if (control == IOBUFCTRL_UNDERFLOW)
|
||||
{
|
||||
u32 timestamp = make_timestamp ();
|
||||
int len = iobuf_read (a, buf, *ret_len);
|
||||
|
||||
if (len >= 0)
|
||||
{
|
||||
pfx->offset += len;
|
||||
*ret_len = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ret_len = 0;
|
||||
rc = -1;
|
||||
}
|
||||
if ((len == -1 && pfx->offset != pfx->last)
|
||||
|| timestamp - pfx->last_time > 0)
|
||||
{
|
||||
char buffer[50];
|
||||
|
||||
sprintf (buffer, "%.20s ? %lu %lu",
|
||||
pfx->what? pfx->what : "?",
|
||||
pfx->offset,
|
||||
pfx->total);
|
||||
write_status_text (STATUS_PROGRESS, buffer);
|
||||
|
||||
pfx->last = pfx->offset;
|
||||
pfx->last_time = timestamp;
|
||||
}
|
||||
}
|
||||
else if (control == IOBUFCTRL_FREE)
|
||||
{
|
||||
/* Note, that we must always dealloc resources of a filter
|
||||
within the filter handler and not anywhere else. (We set it
|
||||
to NULL and check all uses just in case.) */
|
||||
m_free (pfx->what);
|
||||
pfx->what = NULL;
|
||||
}
|
||||
else if (control == IOBUFCTRL_DESC)
|
||||
*(char**)buf = "progress_filter";
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
|
||||
{
|
||||
off_t filesize = 0;
|
||||
|
||||
if (!opt.enable_progress_filter)
|
||||
return;
|
||||
|
||||
if (!is_status_enabled ())
|
||||
return;
|
||||
|
||||
if (name && *name && !(*name == '-' && !name[1]))
|
||||
filesize = iobuf_get_filelength (inp);
|
||||
else if (opt.set_filesize)
|
||||
filesize = opt.set_filesize;
|
||||
|
||||
/* register the progress filter */
|
||||
pfx->what = m_strdup (name ? name : "stdin");
|
||||
pfx->total = filesize;
|
||||
iobuf_push_filter (inp, progress_filter, pfx);
|
||||
}
|
690
g10/revoke.c
Normal file
690
g10/revoke.c
Normal file
|
@ -0,0 +1,690 @@
|
|||
/* revoke.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "ttyio.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
struct revocation_reason_info {
|
||||
int code;
|
||||
char *desc;
|
||||
};
|
||||
|
||||
|
||||
int
|
||||
revocation_reason_build_cb( PKT_signature *sig, void *opaque )
|
||||
{
|
||||
struct revocation_reason_info *reason = opaque;
|
||||
char *ud = NULL;
|
||||
byte *buffer;
|
||||
size_t buflen = 1;
|
||||
|
||||
if(!reason)
|
||||
return 0;
|
||||
|
||||
if( reason->desc ) {
|
||||
ud = native_to_utf8( reason->desc );
|
||||
buflen += strlen(ud);
|
||||
}
|
||||
buffer = m_alloc( buflen );
|
||||
*buffer = reason->code;
|
||||
if( ud ) {
|
||||
memcpy(buffer+1, ud, strlen(ud) );
|
||||
m_free( ud );
|
||||
}
|
||||
|
||||
build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
|
||||
m_free( buffer );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Outputs a minimal pk (as defined by 2440) from a keyblock. A
|
||||
minimal pk consists of the public key packet and a user ID. We try
|
||||
and pick a user ID that has a uid signature, and include it if
|
||||
possible. */
|
||||
static int
|
||||
export_minimal_pk(IOBUF out,KBNODE keyblock,
|
||||
PKT_signature *revsig,PKT_signature *revkey)
|
||||
{
|
||||
KBNODE node;
|
||||
PACKET pkt;
|
||||
PKT_user_id *uid=NULL;
|
||||
PKT_signature *selfsig=NULL;
|
||||
u32 keyid[2];
|
||||
int rc;
|
||||
|
||||
node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
|
||||
if(!node)
|
||||
{
|
||||
log_error(_("key incomplete\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
keyid_from_pk(node->pkt->pkt.public_key,keyid);
|
||||
|
||||
pkt=*node->pkt;
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
init_packet(&pkt);
|
||||
pkt.pkttype=PKT_SIGNATURE;
|
||||
|
||||
/* the revocation itself, if any. 2440 likes this to come first. */
|
||||
if(revsig)
|
||||
{
|
||||
pkt.pkt.signature=revsig;
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* If a revkey in a 1F sig is present, include it too */
|
||||
if(revkey)
|
||||
{
|
||||
pkt.pkt.signature=revkey;
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
while(!selfsig)
|
||||
{
|
||||
KBNODE signode;
|
||||
|
||||
node=find_next_kbnode(node,PKT_USER_ID);
|
||||
if(!node)
|
||||
{
|
||||
/* We're out of user IDs - none were self-signed. */
|
||||
if(uid)
|
||||
break;
|
||||
else
|
||||
{
|
||||
log_error(_("key %08lX incomplete\n"),(ulong)keyid[1]);
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
}
|
||||
|
||||
if(node->pkt->pkt.user_id->attrib_data)
|
||||
continue;
|
||||
|
||||
uid=node->pkt->pkt.user_id;
|
||||
signode=node;
|
||||
|
||||
while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
|
||||
{
|
||||
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
|
||||
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
|
||||
IS_UID_SIG(signode->pkt->pkt.signature))
|
||||
{
|
||||
selfsig=signode->pkt->pkt.signature;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pkt.pkttype=PKT_USER_ID;
|
||||
pkt.pkt.user_id=uid;
|
||||
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
if(selfsig)
|
||||
{
|
||||
pkt.pkttype=PKT_SIGNATURE;
|
||||
pkt.pkt.signature=selfsig;
|
||||
|
||||
rc=build_packet(out,&pkt);
|
||||
if(rc)
|
||||
{
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Generate a revocation certificate for UNAME via a designated revoker
|
||||
*/
|
||||
int
|
||||
gen_desig_revoke( const char *uname )
|
||||
{
|
||||
int rc = 0;
|
||||
armor_filter_context_t afx;
|
||||
PKT_public_key *pk = NULL;
|
||||
PKT_secret_key *sk = NULL;
|
||||
PKT_signature *sig = NULL;
|
||||
IOBUF out = NULL;
|
||||
struct revocation_reason_info *reason = NULL;
|
||||
KEYDB_HANDLE kdbhd;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
KBNODE keyblock=NULL,node;
|
||||
u32 keyid[2];
|
||||
int i,any=0;
|
||||
|
||||
if( opt.batch ) {
|
||||
log_error(_("sorry, can't do this in batch mode\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
|
||||
kdbhd = keydb_new (0);
|
||||
classify_user_id (uname, &desc);
|
||||
rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
|
||||
if (rc) {
|
||||
log_error (_("key `%s' not found: %s\n"),uname, g10_errstr (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = keydb_get_keyblock (kdbhd, &keyblock );
|
||||
if( rc ) {
|
||||
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* To parse the revkeys */
|
||||
merge_keys_and_selfsig(keyblock);
|
||||
|
||||
/* get the key from the keyblock */
|
||||
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
||||
if( !node )
|
||||
BUG ();
|
||||
|
||||
pk=node->pkt->pkt.public_key;
|
||||
|
||||
keyid_from_pk(pk,keyid);
|
||||
|
||||
/* Are we a designated revoker for this key? */
|
||||
|
||||
if(!pk->revkey && pk->numrevkeys)
|
||||
BUG();
|
||||
|
||||
for(i=0;i<pk->numrevkeys;i++)
|
||||
{
|
||||
if(sk)
|
||||
free_secret_key(sk);
|
||||
|
||||
sk=m_alloc_clear(sizeof(*sk));
|
||||
|
||||
rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
|
||||
|
||||
/* We have the revocation key */
|
||||
if(!rc)
|
||||
{
|
||||
PKT_signature *revkey = NULL;
|
||||
|
||||
any = 1;
|
||||
|
||||
print_pubkey_info (pk);
|
||||
tty_printf ("\n");
|
||||
|
||||
tty_printf (_("To be revoked by:\n"));
|
||||
print_seckey_info (sk);
|
||||
|
||||
if(pk->revkey[i].class&0x40)
|
||||
tty_printf(_("(This is a sensitive revocation key)\n"));
|
||||
tty_printf("\n");
|
||||
|
||||
if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
|
||||
_("Create a revocation certificate for this key? ")) )
|
||||
continue;
|
||||
|
||||
/* get the reason for the revocation (this is always v4) */
|
||||
reason = ask_revocation_reason( 1, 0, 1 );
|
||||
if( !reason )
|
||||
continue;
|
||||
|
||||
rc = check_secret_key( sk, 0 );
|
||||
if( rc )
|
||||
continue;
|
||||
|
||||
if( !opt.armor )
|
||||
tty_printf(_("ASCII armored output forced.\n"));
|
||||
|
||||
if( (rc = open_outfile( NULL, 0, &out )) )
|
||||
goto leave;
|
||||
|
||||
afx.what = 1;
|
||||
afx.hdrlines = "Comment: A revocation certificate should follow\n";
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
|
||||
/* create it */
|
||||
rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
|
||||
0, 0, 0,
|
||||
revocation_reason_build_cb, reason );
|
||||
if( rc ) {
|
||||
log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Spit out a minimal pk as well, since otherwise there is
|
||||
no way to know which key to attach this revocation to.
|
||||
Also include the direct key signature that contains
|
||||
this revocation key. We're allowed to include
|
||||
sensitive revocation keys along with a revocation, as
|
||||
this may be the only time the recipient has seen it.
|
||||
Note that this means that if we have multiple different
|
||||
sensitive revocation keys in a given direct key
|
||||
signature, we're going to include them all here. This
|
||||
is annoying, but the good outweighs the bad, since
|
||||
without including this a sensitive revoker can't really
|
||||
do their job. People should not include multiple
|
||||
sensitive revocation keys in one signature: 2440 says
|
||||
"Note that it may be appropriate to isolate this
|
||||
subpacket within a separate signature so that it is not
|
||||
combined with other subpackets that need to be
|
||||
exported." -dms */
|
||||
|
||||
while(!revkey)
|
||||
{
|
||||
KBNODE signode;
|
||||
|
||||
signode=find_next_kbnode(node,PKT_SIGNATURE);
|
||||
if(!signode)
|
||||
break;
|
||||
|
||||
node=signode;
|
||||
|
||||
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
|
||||
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
|
||||
IS_KEY_SIG(signode->pkt->pkt.signature))
|
||||
{
|
||||
int j;
|
||||
|
||||
for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
|
||||
{
|
||||
if(pk->revkey[i].class==
|
||||
signode->pkt->pkt.signature->revkey[j]->class &&
|
||||
pk->revkey[i].algid==
|
||||
signode->pkt->pkt.signature->revkey[j]->algid &&
|
||||
memcmp(pk->revkey[i].fpr,
|
||||
signode->pkt->pkt.signature->revkey[j]->fpr,
|
||||
MAX_FINGERPRINT_LEN)==0)
|
||||
{
|
||||
revkey=signode->pkt->pkt.signature;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!revkey)
|
||||
BUG();
|
||||
|
||||
rc=export_minimal_pk(out,keyblock,sig,revkey);
|
||||
if(rc)
|
||||
goto leave;
|
||||
|
||||
/* and issue a usage notice */
|
||||
tty_printf(_("Revocation certificate created.\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!any)
|
||||
log_error(_("no revocation keys found for `%s'\n"),uname);
|
||||
|
||||
leave:
|
||||
if( pk )
|
||||
free_public_key( pk );
|
||||
if( sk )
|
||||
free_secret_key( sk );
|
||||
if( sig )
|
||||
free_seckey_enc( sig );
|
||||
|
||||
if( rc )
|
||||
iobuf_cancel(out);
|
||||
else
|
||||
iobuf_close(out);
|
||||
release_revocation_reason_info( reason );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Generate a revocation certificate for UNAME
|
||||
*/
|
||||
int
|
||||
gen_revoke( const char *uname )
|
||||
{
|
||||
int rc = 0;
|
||||
armor_filter_context_t afx;
|
||||
PACKET pkt;
|
||||
PKT_secret_key *sk; /* used as pointer into a kbnode */
|
||||
PKT_public_key *pk = NULL;
|
||||
PKT_signature *sig = NULL;
|
||||
u32 sk_keyid[2];
|
||||
IOBUF out = NULL;
|
||||
KBNODE keyblock = NULL, pub_keyblock = NULL;
|
||||
KBNODE node;
|
||||
KEYDB_HANDLE kdbhd;
|
||||
struct revocation_reason_info *reason = NULL;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
|
||||
if( opt.batch ) {
|
||||
log_error(_("sorry, can't do this in batch mode\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
init_packet( &pkt );
|
||||
|
||||
/* search the userid:
|
||||
* We don't want the whole getkey stuff here but the entire keyblock
|
||||
*/
|
||||
kdbhd = keydb_new (1);
|
||||
classify_user_id (uname, &desc);
|
||||
rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
|
||||
if (rc) {
|
||||
log_error (_("secret key `%s' not found: %s\n"),
|
||||
uname, g10_errstr (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = keydb_get_keyblock (kdbhd, &keyblock );
|
||||
if( rc ) {
|
||||
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* get the keyid from the keyblock */
|
||||
node = find_kbnode( keyblock, PKT_SECRET_KEY );
|
||||
if( !node )
|
||||
BUG ();
|
||||
|
||||
/* fixme: should make a function out of this stuff,
|
||||
* it's used all over the source */
|
||||
sk = node->pkt->pkt.secret_key;
|
||||
keyid_from_sk( sk, sk_keyid );
|
||||
print_seckey_info (sk);
|
||||
|
||||
pk = m_alloc_clear( sizeof *pk );
|
||||
|
||||
/* FIXME: We should get the public key direct from the secret one */
|
||||
|
||||
pub_keyblock=get_pubkeyblock(sk_keyid);
|
||||
if(!pub_keyblock)
|
||||
{
|
||||
log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
|
||||
if(!node)
|
||||
BUG();
|
||||
|
||||
pk=node->pkt->pkt.public_key;
|
||||
|
||||
if( cmp_public_secret_key( pk, sk ) ) {
|
||||
log_error(_("public key does not match secret key!\n") );
|
||||
rc = G10ERR_GENERAL;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
tty_printf("\n");
|
||||
if( !cpr_get_answer_is_yes("gen_revoke.okay",
|
||||
_("Create a revocation certificate for this key? ")) ){
|
||||
rc = 0;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if(sk->version>=4 || opt.force_v4_certs) {
|
||||
/* get the reason for the revocation */
|
||||
reason = ask_revocation_reason( 1, 0, 1 );
|
||||
if( !reason ) { /* user decided to cancel */
|
||||
rc = 0;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
switch( is_secret_key_protected( sk ) ) {
|
||||
case -1:
|
||||
log_error(_("unknown protection algorithm\n"));
|
||||
rc = G10ERR_PUBKEY_ALGO;
|
||||
break;
|
||||
case 0:
|
||||
tty_printf(_("NOTE: This key is not protected!\n"));
|
||||
break;
|
||||
default:
|
||||
rc = check_secret_key( sk, 0 );
|
||||
break;
|
||||
}
|
||||
if( rc )
|
||||
goto leave;
|
||||
|
||||
|
||||
if( !opt.armor )
|
||||
tty_printf(_("ASCII armored output forced.\n"));
|
||||
|
||||
if( (rc = open_outfile( NULL, 0, &out )) )
|
||||
goto leave;
|
||||
|
||||
afx.what = 1;
|
||||
afx.hdrlines = "Comment: A revocation certificate should follow\n";
|
||||
iobuf_push_filter( out, armor_filter, &afx );
|
||||
|
||||
/* create it */
|
||||
rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
|
||||
opt.force_v4_certs?4:0, 0, 0,
|
||||
revocation_reason_build_cb, reason );
|
||||
if( rc ) {
|
||||
log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if(PGP2 || PGP6 || PGP7 || PGP8)
|
||||
{
|
||||
/* Use a minimal pk for PGPx mode, since PGP can't import bare
|
||||
revocation certificates. */
|
||||
rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
|
||||
if(rc)
|
||||
goto leave;
|
||||
}
|
||||
else
|
||||
{
|
||||
init_packet( &pkt );
|
||||
pkt.pkttype = PKT_SIGNATURE;
|
||||
pkt.pkt.signature = sig;
|
||||
|
||||
rc = build_packet( out, &pkt );
|
||||
if( rc ) {
|
||||
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* and issue a usage notice */
|
||||
tty_printf(_("Revocation certificate created.\n\n"
|
||||
"Please move it to a medium which you can hide away; if Mallory gets\n"
|
||||
"access to this certificate he can use it to make your key unusable.\n"
|
||||
"It is smart to print this certificate and store it away, just in case\n"
|
||||
"your media become unreadable. But have some caution: The print system of\n"
|
||||
"your machine might store the data and make it available to others!\n"));
|
||||
|
||||
leave:
|
||||
if( sig )
|
||||
free_seckey_enc( sig );
|
||||
release_kbnode( keyblock );
|
||||
release_kbnode( pub_keyblock );
|
||||
keydb_release (kdbhd);
|
||||
if( rc )
|
||||
iobuf_cancel(out);
|
||||
else
|
||||
iobuf_close(out);
|
||||
release_revocation_reason_info( reason );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct revocation_reason_info *
|
||||
ask_revocation_reason( int key_rev, int cert_rev, int hint )
|
||||
{
|
||||
int code=-1;
|
||||
char *description = NULL;
|
||||
struct revocation_reason_info *reason;
|
||||
const char *text_0 = _("No reason specified");
|
||||
const char *text_1 = _("Key has been compromised");
|
||||
const char *text_2 = _("Key is superseded");
|
||||
const char *text_3 = _("Key is no longer used");
|
||||
const char *text_4 = _("User ID is no longer valid");
|
||||
const char *code_text = NULL;
|
||||
|
||||
do {
|
||||
code=-1;
|
||||
m_free(description);
|
||||
description = NULL;
|
||||
|
||||
tty_printf(_("Please select the reason for the revocation:\n"));
|
||||
tty_printf( " 0 = %s\n", text_0 );
|
||||
if( key_rev )
|
||||
tty_printf(" 1 = %s\n", text_1 );
|
||||
if( key_rev )
|
||||
tty_printf(" 2 = %s\n", text_2 );
|
||||
if( key_rev )
|
||||
tty_printf(" 3 = %s\n", text_3 );
|
||||
if( cert_rev )
|
||||
tty_printf(" 4 = %s\n", text_4 );
|
||||
tty_printf( " Q = %s\n", _("Cancel") );
|
||||
if( hint )
|
||||
tty_printf(_("(Probably you want to select %d here)\n"), hint );
|
||||
|
||||
while(code==-1) {
|
||||
int n;
|
||||
char *answer = cpr_get("ask_revocation_reason.code",
|
||||
_("Your decision? "));
|
||||
trim_spaces( answer );
|
||||
cpr_kill_prompt();
|
||||
if( *answer == 'q' || *answer == 'Q')
|
||||
return NULL; /* cancel */
|
||||
if( hint && !*answer )
|
||||
n = hint;
|
||||
else if(!isdigit( *answer ) )
|
||||
n = -1;
|
||||
else
|
||||
n = atoi(answer);
|
||||
m_free(answer);
|
||||
if( n == 0 ) {
|
||||
code = 0x00; /* no particular reason */
|
||||
code_text = text_0;
|
||||
}
|
||||
else if( key_rev && n == 1 ) {
|
||||
code = 0x02; /* key has been compromised */
|
||||
code_text = text_1;
|
||||
}
|
||||
else if( key_rev && n == 2 ) {
|
||||
code = 0x01; /* key is superseded */
|
||||
code_text = text_2;
|
||||
}
|
||||
else if( key_rev && n == 3 ) {
|
||||
code = 0x03; /* key is no longer used */
|
||||
code_text = text_3;
|
||||
}
|
||||
else if( cert_rev && n == 4 ) {
|
||||
code = 0x20; /* uid is no longer valid */
|
||||
code_text = text_4;
|
||||
}
|
||||
else
|
||||
tty_printf(_("Invalid selection.\n"));
|
||||
}
|
||||
|
||||
tty_printf(_("Enter an optional description; "
|
||||
"end it with an empty line:\n") );
|
||||
for(;;) {
|
||||
char *answer = cpr_get("ask_revocation_reason.text", "> " );
|
||||
trim_trailing_ws( answer, strlen(answer) );
|
||||
cpr_kill_prompt();
|
||||
if( !*answer ) {
|
||||
m_free(answer);
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
char *p = make_printable_string( answer, strlen(answer), 0 );
|
||||
m_free(answer);
|
||||
answer = p;
|
||||
}
|
||||
|
||||
if( !description )
|
||||
description = m_strdup(answer);
|
||||
else {
|
||||
char *p = m_alloc( strlen(description) + strlen(answer) + 2 );
|
||||
strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
|
||||
m_free(description);
|
||||
description = p;
|
||||
}
|
||||
m_free(answer);
|
||||
}
|
||||
|
||||
tty_printf(_("Reason for revocation: %s\n"), code_text );
|
||||
if( !description )
|
||||
tty_printf(_("(No description given)\n") );
|
||||
else
|
||||
tty_printf("%s\n", description );
|
||||
|
||||
} while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
|
||||
_("Is this okay? ")) );
|
||||
|
||||
reason = m_alloc( sizeof *reason );
|
||||
reason->code = code;
|
||||
reason->desc = description;
|
||||
return reason;
|
||||
}
|
||||
|
||||
void
|
||||
release_revocation_reason_info( struct revocation_reason_info *reason )
|
||||
{
|
||||
if( reason ) {
|
||||
m_free( reason->desc );
|
||||
m_free( reason );
|
||||
}
|
||||
}
|
400
g10/seckey-cert.c
Normal file
400
g10/seckey-cert.c
Normal file
|
@ -0,0 +1,400 @@
|
|||
/* seckey-cert.c - secret key certificate packet handling
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "packet.h"
|
||||
#include "mpi.h"
|
||||
#include "keydb.h"
|
||||
#include "cipher.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "i18n.h"
|
||||
#include "status.h"
|
||||
|
||||
|
||||
static int
|
||||
do_check( PKT_secret_key *sk, const char *tryagain_text, int mode,
|
||||
int *canceled )
|
||||
{
|
||||
byte *buffer;
|
||||
u16 csum=0;
|
||||
int i, res;
|
||||
unsigned nbytes;
|
||||
|
||||
if( sk->is_protected ) { /* remove the protection */
|
||||
DEK *dek = NULL;
|
||||
u32 keyid[4]; /* 4! because we need two of them */
|
||||
CIPHER_HANDLE cipher_hd=NULL;
|
||||
PKT_secret_key *save_sk;
|
||||
|
||||
if( sk->protect.s2k.mode == 1001 ) {
|
||||
log_info(_("secret key parts are not available\n"));
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
if( sk->protect.algo == CIPHER_ALGO_NONE )
|
||||
BUG();
|
||||
if( check_cipher_algo( sk->protect.algo ) ) {
|
||||
log_info(_("protection algorithm %d%s is not supported\n"),
|
||||
sk->protect.algo,sk->protect.algo==1?" (IDEA)":"" );
|
||||
if (sk->protect.algo==CIPHER_ALGO_IDEA)
|
||||
{
|
||||
write_status (STATUS_RSA_OR_IDEA);
|
||||
idea_cipher_warn (0);
|
||||
}
|
||||
return G10ERR_CIPHER_ALGO;
|
||||
}
|
||||
keyid_from_sk( sk, keyid );
|
||||
keyid[2] = keyid[3] = 0;
|
||||
if( !sk->is_primary ) {
|
||||
keyid[2] = sk->main_keyid[0];
|
||||
keyid[3] = sk->main_keyid[1];
|
||||
}
|
||||
dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
|
||||
&sk->protect.s2k, mode,
|
||||
tryagain_text, canceled );
|
||||
if (!dek && canceled && *canceled)
|
||||
return G10ERR_GENERAL;
|
||||
|
||||
cipher_hd = cipher_open( sk->protect.algo,
|
||||
CIPHER_MODE_AUTO_CFB, 1);
|
||||
cipher_setkey( cipher_hd, dek->key, dek->keylen );
|
||||
m_free(dek);
|
||||
save_sk = copy_secret_key( NULL, sk );
|
||||
cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
|
||||
csum = 0;
|
||||
if( sk->version >= 4 ) {
|
||||
int ndata;
|
||||
byte *p, *data;
|
||||
u16 csumc = 0;
|
||||
|
||||
i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
assert( mpi_is_opaque( sk->skey[i] ) );
|
||||
p = mpi_get_opaque( sk->skey[i], &ndata );
|
||||
if ( ndata > 1 )
|
||||
csumc = p[ndata-2] << 8 | p[ndata-1];
|
||||
data = m_alloc_secure( ndata );
|
||||
cipher_decrypt( cipher_hd, data, p, ndata );
|
||||
mpi_free( sk->skey[i] ); sk->skey[i] = NULL ;
|
||||
p = data;
|
||||
if (sk->protect.sha1chk) {
|
||||
/* This is the new SHA1 checksum method to detect
|
||||
tampering with the key as used by the Klima/Rosa
|
||||
attack */
|
||||
sk->csum = 0;
|
||||
csum = 1;
|
||||
if( ndata < 20 )
|
||||
log_error("not enough bytes for SHA-1 checksum\n");
|
||||
else {
|
||||
MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
|
||||
if (!h)
|
||||
BUG(); /* algo not available */
|
||||
md_write (h, data, ndata - 20);
|
||||
md_final (h);
|
||||
if (!memcmp (md_read (h, DIGEST_ALGO_SHA1),
|
||||
data + ndata - 20, 20) ) {
|
||||
/* digest does match. We have to keep the old
|
||||
style checksum in sk->csum, so that the
|
||||
test used for unprotected keys does work.
|
||||
This test gets used when we are adding new
|
||||
keys. */
|
||||
sk->csum = csum = checksum (data, ndata-20);
|
||||
}
|
||||
md_close (h);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if( ndata < 2 ) {
|
||||
log_error("not enough bytes for checksum\n");
|
||||
sk->csum = 0;
|
||||
csum = 1;
|
||||
}
|
||||
else {
|
||||
csum = checksum( data, ndata-2);
|
||||
sk->csum = data[ndata-2] << 8 | data[ndata-1];
|
||||
if ( sk->csum != csum ) {
|
||||
/* This is a PGP 7.0.0 workaround */
|
||||
sk->csum = csumc; /* take the encrypted one */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* must check it here otherwise the mpi_read_xx would fail
|
||||
because the length may have an arbitrary value */
|
||||
if( sk->csum == csum ) {
|
||||
for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
nbytes = ndata;
|
||||
sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
|
||||
ndata -= nbytes;
|
||||
p += nbytes;
|
||||
}
|
||||
/* Note: at this point ndata should be 2 for a simple
|
||||
checksum or 20 for the sha1 digest */
|
||||
}
|
||||
m_free(data);
|
||||
}
|
||||
else {
|
||||
for(i=pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
byte *p;
|
||||
int ndata;
|
||||
unsigned int dummy;
|
||||
|
||||
assert (mpi_is_opaque (sk->skey[i]));
|
||||
p = mpi_get_opaque (sk->skey[i], &ndata);
|
||||
assert (ndata >= 2);
|
||||
assert (ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2);
|
||||
buffer = m_alloc_secure (ndata);
|
||||
cipher_sync (cipher_hd);
|
||||
buffer[0] = p[0];
|
||||
buffer[1] = p[1];
|
||||
cipher_decrypt (cipher_hd, buffer+2, p+2, ndata-2);
|
||||
csum += checksum (buffer, ndata);
|
||||
mpi_free (sk->skey[i]);
|
||||
dummy = ndata;
|
||||
sk->skey[i] = mpi_read_from_buffer (buffer, &dummy, 1);
|
||||
assert (sk->skey[i]);
|
||||
m_free (buffer);
|
||||
/* csum += checksum_mpi (sk->skey[i]); */
|
||||
}
|
||||
}
|
||||
cipher_close( cipher_hd );
|
||||
/* now let's see whether we have used the right passphrase */
|
||||
if( csum != sk->csum ) {
|
||||
copy_secret_key( sk, save_sk );
|
||||
passphrase_clear_cache ( keyid, sk->pubkey_algo );
|
||||
free_secret_key( save_sk );
|
||||
return G10ERR_BAD_PASS;
|
||||
}
|
||||
/* the checksum may fail, so we also check the key itself */
|
||||
res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey );
|
||||
if( res ) {
|
||||
copy_secret_key( sk, save_sk );
|
||||
passphrase_clear_cache ( keyid, sk->pubkey_algo );
|
||||
free_secret_key( save_sk );
|
||||
return G10ERR_BAD_PASS;
|
||||
}
|
||||
free_secret_key( save_sk );
|
||||
sk->is_protected = 0;
|
||||
}
|
||||
else { /* not protected, assume it is okay if the checksum is okay */
|
||||
csum = 0;
|
||||
for(i=pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
csum += checksum_mpi( sk->skey[i] );
|
||||
}
|
||||
if( csum != sk->csum )
|
||||
return G10ERR_CHECKSUM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Check the secret key
|
||||
* Ask up to 3 (or n) times for a correct passphrase
|
||||
* If n is negative, disable the key info prompt and make n=abs(n)
|
||||
*/
|
||||
int
|
||||
check_secret_key( PKT_secret_key *sk, int n )
|
||||
{
|
||||
int rc = G10ERR_BAD_PASS;
|
||||
int i,mode;
|
||||
|
||||
if(n<0)
|
||||
{
|
||||
n=abs(n);
|
||||
mode=1;
|
||||
}
|
||||
else
|
||||
mode=0;
|
||||
|
||||
if( n < 1 )
|
||||
n = (opt.batch && !opt.use_agent)? 1 : 3; /* use the default value */
|
||||
|
||||
for(i=0; i < n && rc == G10ERR_BAD_PASS; i++ ) {
|
||||
int canceled = 0;
|
||||
const char *tryagain = NULL;
|
||||
if (i) {
|
||||
tryagain = N_("Invalid passphrase; please try again");
|
||||
log_info (_("%s ...\n"), _(tryagain));
|
||||
}
|
||||
rc = do_check( sk, tryagain, mode, &canceled );
|
||||
if( rc == G10ERR_BAD_PASS && is_status_enabled() ) {
|
||||
u32 kid[2];
|
||||
char buf[50];
|
||||
|
||||
keyid_from_sk( sk, kid );
|
||||
sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]);
|
||||
write_status_text( STATUS_BAD_PASSPHRASE, buf );
|
||||
}
|
||||
if( have_static_passphrase() || canceled)
|
||||
break;
|
||||
}
|
||||
|
||||
if( !rc )
|
||||
write_status( STATUS_GOOD_PASSPHRASE );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* check whether the secret key is protected.
|
||||
* Returns: 0 not protected, -1 on error or the protection algorithm
|
||||
*/
|
||||
int
|
||||
is_secret_key_protected( PKT_secret_key *sk )
|
||||
{
|
||||
return sk->is_protected? sk->protect.algo : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Protect the secret key with the passphrase from DEK
|
||||
*/
|
||||
int
|
||||
protect_secret_key( PKT_secret_key *sk, DEK *dek )
|
||||
{
|
||||
int i,j, rc = 0;
|
||||
byte *buffer;
|
||||
unsigned nbytes;
|
||||
u16 csum;
|
||||
|
||||
if( !dek )
|
||||
return 0;
|
||||
|
||||
if( !sk->is_protected ) { /* okay, apply the protection */
|
||||
CIPHER_HANDLE cipher_hd=NULL;
|
||||
|
||||
if( check_cipher_algo( sk->protect.algo ) )
|
||||
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
|
||||
else {
|
||||
print_cipher_algo_note( sk->protect.algo );
|
||||
cipher_hd = cipher_open( sk->protect.algo,
|
||||
CIPHER_MODE_AUTO_CFB, 1 );
|
||||
if( cipher_setkey( cipher_hd, dek->key, dek->keylen ) )
|
||||
log_info(_("WARNING: Weak key detected"
|
||||
" - please change passphrase again.\n"));
|
||||
sk->protect.ivlen = cipher_get_blocksize( sk->protect.algo );
|
||||
assert( sk->protect.ivlen <= DIM(sk->protect.iv) );
|
||||
if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 )
|
||||
BUG(); /* yes, we are very careful */
|
||||
randomize_buffer(sk->protect.iv, sk->protect.ivlen, 1);
|
||||
cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
|
||||
if( sk->version >= 4 ) {
|
||||
byte *bufarr[PUBKEY_MAX_NSKEY];
|
||||
unsigned narr[PUBKEY_MAX_NSKEY];
|
||||
unsigned nbits[PUBKEY_MAX_NSKEY];
|
||||
int ndata=0;
|
||||
byte *p, *data;
|
||||
|
||||
for(j=0, i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) {
|
||||
assert( !mpi_is_opaque( sk->skey[i] ) );
|
||||
bufarr[j] = mpi_get_buffer( sk->skey[i], &narr[j], NULL );
|
||||
nbits[j] = mpi_get_nbits( sk->skey[i] );
|
||||
ndata += narr[j] + 2;
|
||||
}
|
||||
for( ; j < PUBKEY_MAX_NSKEY; j++ )
|
||||
bufarr[j] = NULL;
|
||||
ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */
|
||||
|
||||
data = m_alloc_secure( ndata );
|
||||
p = data;
|
||||
for(j=0; j < PUBKEY_MAX_NSKEY && bufarr[j]; j++ ) {
|
||||
p[0] = nbits[j] >> 8 ;
|
||||
p[1] = nbits[j];
|
||||
p += 2;
|
||||
memcpy(p, bufarr[j], narr[j] );
|
||||
p += narr[j];
|
||||
m_free(bufarr[j]);
|
||||
}
|
||||
|
||||
if (opt.simple_sk_checksum) {
|
||||
log_info (_("generating the deprecated 16-bit checksum"
|
||||
" for secret key protection\n"));
|
||||
csum = checksum( data, ndata-2);
|
||||
sk->csum = csum;
|
||||
*p++ = csum >> 8;
|
||||
*p++ = csum;
|
||||
sk->protect.sha1chk = 0;
|
||||
}
|
||||
else {
|
||||
MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
|
||||
if (!h)
|
||||
BUG(); /* algo not available */
|
||||
md_write (h, data, ndata - 20);
|
||||
md_final (h);
|
||||
memcpy (p, md_read (h, DIGEST_ALGO_SHA1), 20);
|
||||
p += 20;
|
||||
md_close (h);
|
||||
sk->csum = csum = 0;
|
||||
sk->protect.sha1chk = 1;
|
||||
}
|
||||
assert( p == data+ndata );
|
||||
|
||||
cipher_encrypt( cipher_hd, data, data, ndata );
|
||||
for(i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
mpi_free( sk->skey[i] );
|
||||
sk->skey[i] = NULL;
|
||||
}
|
||||
i = pubkey_get_npkey(sk->pubkey_algo);
|
||||
sk->skey[i] = mpi_set_opaque(NULL, data, ndata );
|
||||
}
|
||||
else {
|
||||
csum = 0;
|
||||
for(i=pubkey_get_npkey(sk->pubkey_algo);
|
||||
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
|
||||
byte *data;
|
||||
unsigned int nbits;
|
||||
|
||||
csum += checksum_mpi (sk->skey[i]);
|
||||
buffer = mpi_get_buffer( sk->skey[i], &nbytes, NULL );
|
||||
cipher_sync (cipher_hd);
|
||||
assert ( !mpi_is_opaque (sk->skey[i]) );
|
||||
data = m_alloc (nbytes+2);
|
||||
nbits = mpi_get_nbits (sk->skey[i]);
|
||||
assert (nbytes == (nbits + 7)/8);
|
||||
data[0] = nbits >> 8;
|
||||
data[1] = nbits;
|
||||
cipher_encrypt (cipher_hd, data+2, buffer, nbytes);
|
||||
m_free( buffer );
|
||||
|
||||
mpi_free (sk->skey[i]);
|
||||
sk->skey[i] = mpi_set_opaque (NULL, data, nbytes+2);
|
||||
}
|
||||
sk->csum = csum;
|
||||
}
|
||||
sk->is_protected = 1;
|
||||
cipher_close( cipher_hd );
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
625
g10/sig-check.c
Normal file
625
g10/sig-check.c
Normal file
|
@ -0,0 +1,625 @@
|
|||
/* sig-check.c - Check a signature
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "util.h"
|
||||
#include "packet.h"
|
||||
#include "memory.h"
|
||||
#include "mpi.h"
|
||||
#include "keydb.h"
|
||||
#include "cipher.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "i18n.h"
|
||||
#include "options.h"
|
||||
|
||||
struct cmp_help_context_s {
|
||||
PKT_signature *sig;
|
||||
MD_HANDLE md;
|
||||
};
|
||||
|
||||
static int do_check( PKT_public_key *pk, PKT_signature *sig,
|
||||
MD_HANDLE digest, int *r_expired );
|
||||
|
||||
/****************
|
||||
* Check the signature which is contained in SIG.
|
||||
* The MD_HANDLE should be currently open, so that this function
|
||||
* is able to append some data, before finalizing the digest.
|
||||
*/
|
||||
int
|
||||
signature_check( PKT_signature *sig, MD_HANDLE digest )
|
||||
{
|
||||
u32 dummy;
|
||||
int dum2;
|
||||
return signature_check2( sig, digest, &dummy, &dum2 );
|
||||
}
|
||||
|
||||
int
|
||||
signature_check2( PKT_signature *sig, MD_HANDLE digest,
|
||||
u32 *r_expiredate, int *r_expired )
|
||||
{
|
||||
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
|
||||
int rc=0;
|
||||
|
||||
*r_expiredate = 0;
|
||||
|
||||
/* Sanity check that the md has a context for the hash that the
|
||||
sig is expecting. This can happen if a onepass sig header does
|
||||
not match the actual sig, and also if the clearsign "Hash:"
|
||||
header is missing or does not match the actual sig. */
|
||||
|
||||
if(!md_algo_present(digest,sig->digest_algo)) {
|
||||
log_info(_("WARNING: signature digest conflict in message\n"));
|
||||
rc=G10ERR_GENERAL;
|
||||
}
|
||||
else if( get_pubkey( pk, sig->keyid ) )
|
||||
rc = G10ERR_NO_PUBKEY;
|
||||
else if(!pk->is_valid && !pk->is_primary)
|
||||
rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
|
||||
invalid subkey */
|
||||
else {
|
||||
*r_expiredate = pk->expiredate;
|
||||
rc = do_check( pk, sig, digest, r_expired );
|
||||
}
|
||||
|
||||
free_public_key( pk );
|
||||
|
||||
if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
|
||||
/* This signature id works best with DLP algorithms because
|
||||
* they use a random parameter for every signature. Instead of
|
||||
* this sig-id we could have also used the hash of the document
|
||||
* and the timestamp, but the drawback of this is, that it is
|
||||
* not possible to sign more than one identical document within
|
||||
* one second. Some remote batch processing applications might
|
||||
* like this feature here */
|
||||
MD_HANDLE md;
|
||||
u32 a = sig->timestamp;
|
||||
int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
|
||||
byte *p, *buffer;
|
||||
|
||||
md = md_open( DIGEST_ALGO_RMD160, 0);
|
||||
md_putc( digest, sig->pubkey_algo );
|
||||
md_putc( digest, sig->digest_algo );
|
||||
md_putc( digest, (a >> 24) & 0xff );
|
||||
md_putc( digest, (a >> 16) & 0xff );
|
||||
md_putc( digest, (a >> 8) & 0xff );
|
||||
md_putc( digest, a & 0xff );
|
||||
for(i=0; i < nsig; i++ ) {
|
||||
unsigned n = mpi_get_nbits( sig->data[i]);
|
||||
|
||||
md_putc( md, n>>8);
|
||||
md_putc( md, n );
|
||||
p = mpi_get_buffer( sig->data[i], &n, NULL );
|
||||
md_write( md, p, n );
|
||||
m_free(p);
|
||||
}
|
||||
md_final( md );
|
||||
p = make_radix64_string( md_read( md, 0 ), 20 );
|
||||
buffer = m_alloc( strlen(p) + 60 );
|
||||
sprintf( buffer, "%s %s %lu",
|
||||
p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
|
||||
write_status_text( STATUS_SIG_ID, buffer );
|
||||
m_free(buffer);
|
||||
m_free(p);
|
||||
md_close(md);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* This function gets called by pubkey_verify() if the algorithm needs it.
|
||||
*/
|
||||
static int
|
||||
cmp_help( void *opaque, MPI result )
|
||||
{
|
||||
#if 0 /* we do not use this anymore */
|
||||
int rc=0, i, j, c, old_enc;
|
||||
byte *dp;
|
||||
const byte *asn;
|
||||
size_t mdlen, asnlen;
|
||||
struct cmp_help_context_s *ctx = opaque;
|
||||
PKT_signature *sig = ctx->sig;
|
||||
MD_HANDLE digest = ctx->md;
|
||||
|
||||
old_enc = 0;
|
||||
for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
|
||||
if( !j ) {
|
||||
if( !i && c != 1 )
|
||||
break;
|
||||
else if( i && c == 0xff )
|
||||
; /* skip the padding */
|
||||
else if( i && !c )
|
||||
j++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if( ++j == 18 && c != 1 )
|
||||
break;
|
||||
else if( j == 19 && c == 0 ) {
|
||||
old_enc++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( old_enc ) {
|
||||
log_error("old encoding scheme is not supported\n");
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
|
||||
if( (rc=check_digest_algo(sig->digest_algo)) )
|
||||
return rc; /* unsupported algo */
|
||||
asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen );
|
||||
|
||||
for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0;
|
||||
i++, j-- )
|
||||
if( asn[j] != c )
|
||||
break;
|
||||
if( j != -1 || mpi_getbyte(result, i) )
|
||||
return G10ERR_BAD_PUBKEY; /* ASN is wrong */
|
||||
for(i++; (c=mpi_getbyte(result, i)) != -1; i++ )
|
||||
if( c != 0xff )
|
||||
break;
|
||||
i++;
|
||||
if( c != sig->digest_algo || mpi_getbyte(result, i) ) {
|
||||
/* Padding or leading bytes in signature is wrong */
|
||||
return G10ERR_BAD_PUBKEY;
|
||||
}
|
||||
if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0]
|
||||
|| mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) {
|
||||
/* Wrong key used to check the signature */
|
||||
return G10ERR_BAD_PUBKEY;
|
||||
}
|
||||
|
||||
dp = md_read( digest, sig->digest_algo );
|
||||
for(i=mdlen-1; i >= 0; i--, dp++ ) {
|
||||
if( mpi_getbyte( result, i ) != *dp )
|
||||
return G10ERR_BAD_SIGN;
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
do_check_messages( PKT_public_key *pk, PKT_signature *sig, int *r_expired )
|
||||
{
|
||||
u32 cur_time;
|
||||
|
||||
*r_expired = 0;
|
||||
if( pk->version == 4 && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
|
||||
log_info(_("key %08lX: this is a PGP generated "
|
||||
"ElGamal key which is NOT secure for signatures!\n"),
|
||||
(ulong)keyid_from_pk(pk,NULL));
|
||||
return G10ERR_PUBKEY_ALGO;
|
||||
}
|
||||
|
||||
if( pk->timestamp > sig->timestamp ) {
|
||||
ulong d = pk->timestamp - sig->timestamp;
|
||||
log_info( d==1
|
||||
? _("public key %08lX is %lu second newer than the signature\n")
|
||||
: _("public key %08lX is %lu seconds newer than the signature\n"),
|
||||
(ulong)keyid_from_pk(pk,NULL),d );
|
||||
if( !opt.ignore_time_conflict )
|
||||
return G10ERR_TIME_CONFLICT; /* pubkey newer than signature */
|
||||
}
|
||||
|
||||
cur_time = make_timestamp();
|
||||
if( pk->timestamp > cur_time ) {
|
||||
ulong d = pk->timestamp - cur_time;
|
||||
log_info( d==1 ? _("key %08lX has been created %lu second "
|
||||
"in future (time warp or clock problem)\n")
|
||||
: _("key %08lX has been created %lu seconds "
|
||||
"in future (time warp or clock problem)\n"),
|
||||
(ulong)keyid_from_pk(pk,NULL),d );
|
||||
if( !opt.ignore_time_conflict )
|
||||
return G10ERR_TIME_CONFLICT;
|
||||
}
|
||||
|
||||
if( pk->expiredate && pk->expiredate < cur_time ) {
|
||||
char buf[11];
|
||||
if (opt.verbose) {
|
||||
u32 tmp_kid[2];
|
||||
|
||||
keyid_from_pk( pk, tmp_kid );
|
||||
log_info(_("NOTE: signature key %08lX expired %s\n"),
|
||||
(ulong)tmp_kid[1], asctimestamp( pk->expiredate ) );
|
||||
}
|
||||
/* SIGEXPIRED is deprecated. Use KEYEXPIRED. */
|
||||
sprintf(buf,"%lu",(ulong)pk->expiredate);
|
||||
write_status_text(STATUS_KEYEXPIRED,buf);
|
||||
write_status(STATUS_SIGEXPIRED);
|
||||
*r_expired = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest,
|
||||
int *r_expired )
|
||||
{
|
||||
MPI result = NULL;
|
||||
int rc=0;
|
||||
struct cmp_help_context_s ctx;
|
||||
|
||||
if( (rc=do_check_messages(pk,sig,r_expired)) )
|
||||
return rc;
|
||||
if( (rc=check_digest_algo(sig->digest_algo)) )
|
||||
return rc;
|
||||
if( (rc=check_pubkey_algo(sig->pubkey_algo)) )
|
||||
return rc;
|
||||
|
||||
/* make sure the digest algo is enabled (in case of a detached signature)*/
|
||||
md_enable( digest, sig->digest_algo );
|
||||
|
||||
/* complete the digest */
|
||||
if( sig->version >= 4 )
|
||||
md_putc( digest, sig->version );
|
||||
md_putc( digest, sig->sig_class );
|
||||
if( sig->version < 4 ) {
|
||||
u32 a = sig->timestamp;
|
||||
md_putc( digest, (a >> 24) & 0xff );
|
||||
md_putc( digest, (a >> 16) & 0xff );
|
||||
md_putc( digest, (a >> 8) & 0xff );
|
||||
md_putc( digest, a & 0xff );
|
||||
}
|
||||
else {
|
||||
byte buf[6];
|
||||
size_t n;
|
||||
md_putc( digest, sig->pubkey_algo );
|
||||
md_putc( digest, sig->digest_algo );
|
||||
if( sig->hashed ) {
|
||||
n = sig->hashed->len;
|
||||
md_putc (digest, (n >> 8) );
|
||||
md_putc (digest, n );
|
||||
md_write (digest, sig->hashed->data, n);
|
||||
n += 6;
|
||||
}
|
||||
else {
|
||||
/* Two octets for the (empty) length of the hashed
|
||||
section. */
|
||||
md_putc (digest, 0);
|
||||
md_putc (digest, 0);
|
||||
n = 6;
|
||||
}
|
||||
/* add some magic */
|
||||
buf[0] = sig->version;
|
||||
buf[1] = 0xff;
|
||||
buf[2] = n >> 24;
|
||||
buf[3] = n >> 16;
|
||||
buf[4] = n >> 8;
|
||||
buf[5] = n;
|
||||
md_write( digest, buf, 6 );
|
||||
}
|
||||
md_final( digest );
|
||||
|
||||
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
|
||||
mpi_get_nbits(pk->pkey[0]), 0 );
|
||||
if (!result)
|
||||
return G10ERR_GENERAL;
|
||||
ctx.sig = sig;
|
||||
ctx.md = digest;
|
||||
rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
|
||||
cmp_help, &ctx );
|
||||
mpi_free( result );
|
||||
if( (opt.emulate_bugs & EMUBUG_MDENCODE)
|
||||
&& rc == G10ERR_BAD_SIGN && is_ELGAMAL(pk->pubkey_algo) ) {
|
||||
/* In this case we try again because old GnuPG versions didn't encode
|
||||
* the hash right. There is no problem with DSA however */
|
||||
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
|
||||
mpi_get_nbits(pk->pkey[0]), (sig->version < 5) );
|
||||
if (!result)
|
||||
rc = G10ERR_GENERAL;
|
||||
else {
|
||||
ctx.sig = sig;
|
||||
ctx.md = digest;
|
||||
rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
|
||||
cmp_help, &ctx );
|
||||
}
|
||||
}
|
||||
|
||||
if( !rc && sig->flags.unknown_critical ) {
|
||||
log_info(_("assuming bad signature from key %08lX due to an unknown critical bit\n"),(ulong)keyid_from_pk(pk,NULL));
|
||||
rc = G10ERR_BAD_SIGN;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
hash_uid_node( KBNODE unode, MD_HANDLE md, PKT_signature *sig )
|
||||
{
|
||||
PKT_user_id *uid = unode->pkt->pkt.user_id;
|
||||
|
||||
assert( unode->pkt->pkttype == PKT_USER_ID );
|
||||
if( uid->attrib_data ) {
|
||||
if( sig->version >=4 ) {
|
||||
byte buf[5];
|
||||
buf[0] = 0xd1; /* packet of type 17 */
|
||||
buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
|
||||
buf[2] = uid->attrib_len >> 16;
|
||||
buf[3] = uid->attrib_len >> 8;
|
||||
buf[4] = uid->attrib_len;
|
||||
md_write( md, buf, 5 );
|
||||
}
|
||||
md_write( md, uid->attrib_data, uid->attrib_len );
|
||||
}
|
||||
else {
|
||||
if( sig->version >=4 ) {
|
||||
byte buf[5];
|
||||
buf[0] = 0xb4; /* indicates a userid packet */
|
||||
buf[1] = uid->len >> 24; /* always use 4 length bytes */
|
||||
buf[2] = uid->len >> 16;
|
||||
buf[3] = uid->len >> 8;
|
||||
buf[4] = uid->len;
|
||||
md_write( md, buf, 5 );
|
||||
}
|
||||
md_write( md, uid->name, uid->len );
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cache_sig_result ( PKT_signature *sig, int result )
|
||||
{
|
||||
if ( !result ) {
|
||||
sig->flags.checked = 1;
|
||||
sig->flags.valid = 1;
|
||||
}
|
||||
else if ( result == G10ERR_BAD_SIGN ) {
|
||||
sig->flags.checked = 1;
|
||||
sig->flags.valid = 0;
|
||||
}
|
||||
else {
|
||||
sig->flags.checked = 0;
|
||||
sig->flags.valid = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check the revocation keys to see if any of them have revoked our
|
||||
pk. sig is the revocation sig. pk is the key it is on. This code
|
||||
will need to be modified if gpg ever becomes multi-threaded. Note
|
||||
that this guarantees that a designated revocation sig will never be
|
||||
considered valid unless it is actually valid, as well as being
|
||||
issued by a revocation key in a valid direct signature. Note that
|
||||
this is written so that a revoked revoker can still issue
|
||||
revocations: i.e. If A revokes B, but A is revoked, B is still
|
||||
revoked. I'm not completely convinced this is the proper behavior,
|
||||
but it matches how PGP does it. -dms */
|
||||
|
||||
/* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
|
||||
revoked */
|
||||
int
|
||||
check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
|
||||
{
|
||||
static int busy=0;
|
||||
int i,rc=G10ERR_GENERAL;
|
||||
|
||||
assert(IS_KEY_REV(sig));
|
||||
assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
|
||||
|
||||
if(busy)
|
||||
{
|
||||
/* return -1 (i.e. not revoked), but mark the pk as uncacheable
|
||||
as we don't really know its revocation status until it is
|
||||
checked directly. */
|
||||
|
||||
pk->dont_cache=1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
busy=1;
|
||||
|
||||
/* printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
|
||||
(ulong)sig->keyid[1]); */
|
||||
|
||||
/* is the issuer of the sig one of our revokers? */
|
||||
if( !pk->revkey && pk->numrevkeys )
|
||||
BUG();
|
||||
else
|
||||
for(i=0;i<pk->numrevkeys;i++)
|
||||
{
|
||||
u32 keyid[2];
|
||||
|
||||
keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
|
||||
|
||||
if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
|
||||
{
|
||||
MD_HANDLE md;
|
||||
|
||||
md=md_open(sig->digest_algo,0);
|
||||
hash_public_key(md,pk);
|
||||
rc=signature_check(sig,md);
|
||||
cache_sig_result(sig,rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
busy=0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* check the signature pointed to by NODE. This is a key signature.
|
||||
* If the function detects a self-signature, it uses the PK from
|
||||
* ROOT and does not read any public key.
|
||||
*/
|
||||
int
|
||||
check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
|
||||
{
|
||||
u32 dummy;
|
||||
int dum2;
|
||||
return check_key_signature2(root, node, NULL, is_selfsig, &dummy, &dum2 );
|
||||
}
|
||||
|
||||
/* If check_pk is set, then use it to check the signature in node
|
||||
rather than getting it from root or the keydb. */
|
||||
int
|
||||
check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
|
||||
int *is_selfsig, u32 *r_expiredate, int *r_expired )
|
||||
{
|
||||
MD_HANDLE md;
|
||||
PKT_public_key *pk;
|
||||
PKT_signature *sig;
|
||||
int algo;
|
||||
int rc;
|
||||
|
||||
if( is_selfsig )
|
||||
*is_selfsig = 0;
|
||||
*r_expiredate = 0;
|
||||
*r_expired = 0;
|
||||
assert( node->pkt->pkttype == PKT_SIGNATURE );
|
||||
assert( root->pkt->pkttype == PKT_PUBLIC_KEY );
|
||||
|
||||
pk = root->pkt->pkt.public_key;
|
||||
sig = node->pkt->pkt.signature;
|
||||
algo = sig->digest_algo;
|
||||
|
||||
/* check whether we have cached the result of a previous signature check.*/
|
||||
if ( !opt.no_sig_cache ) {
|
||||
if (sig->flags.checked) { /*cached status available*/
|
||||
if( is_selfsig ) {
|
||||
u32 keyid[2];
|
||||
|
||||
keyid_from_pk( pk, keyid );
|
||||
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
|
||||
*is_selfsig = 1;
|
||||
}
|
||||
if((rc=do_check_messages(pk,sig,r_expired)))
|
||||
return rc;
|
||||
return sig->flags.valid? 0 : G10ERR_BAD_SIGN;
|
||||
}
|
||||
}
|
||||
|
||||
if( (rc=check_digest_algo(algo)) )
|
||||
return rc;
|
||||
|
||||
if( sig->sig_class == 0x20 ) { /* key revocation */
|
||||
u32 keyid[2];
|
||||
keyid_from_pk( pk, keyid );
|
||||
|
||||
/* is it a designated revoker? */
|
||||
if(keyid[0]!=sig->keyid[0] || keyid[1]!=sig->keyid[1])
|
||||
rc=check_revocation_keys(pk,sig);
|
||||
else
|
||||
{
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
}
|
||||
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
|
||||
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
|
||||
|
||||
if( snode ) {
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
hash_public_key( md, snode->pkt->pkt.public_key );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
if (!opt.quiet)
|
||||
log_info (_("key %08lX: no subkey for subkey "
|
||||
"revocation signature\n"),
|
||||
(ulong)keyid_from_pk (pk, NULL));
|
||||
rc = G10ERR_SIG_CLASS;
|
||||
}
|
||||
}
|
||||
else if( sig->sig_class == 0x18 ) { /* key binding */
|
||||
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
|
||||
|
||||
if( snode ) {
|
||||
if( is_selfsig ) { /* does this make sense????? */
|
||||
u32 keyid[2]; /* it should always be a selfsig */
|
||||
|
||||
keyid_from_pk( pk, keyid );
|
||||
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
|
||||
*is_selfsig = 1;
|
||||
}
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
hash_public_key( md, snode->pkt->pkt.public_key );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
if (opt.verbose)
|
||||
log_info(_("key %08lX: no subkey for subkey "
|
||||
"binding signature\n"),
|
||||
(ulong)keyid_from_pk (pk, NULL));
|
||||
rc = G10ERR_SIG_CLASS;
|
||||
}
|
||||
}
|
||||
else if( sig->sig_class == 0x1f ) { /* direct key signature */
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else { /* all other classes */
|
||||
KBNODE unode = find_prev_kbnode( root, node, PKT_USER_ID );
|
||||
|
||||
if( unode ) {
|
||||
u32 keyid[2];
|
||||
|
||||
keyid_from_pk( pk, keyid );
|
||||
md = md_open( algo, 0 );
|
||||
hash_public_key( md, pk );
|
||||
hash_uid_node( unode, md, sig );
|
||||
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
|
||||
{
|
||||
if( is_selfsig )
|
||||
*is_selfsig = 1;
|
||||
rc = do_check( pk, sig, md, r_expired );
|
||||
}
|
||||
else if (check_pk)
|
||||
rc=do_check(check_pk,sig,md,r_expired);
|
||||
else
|
||||
rc = signature_check2( sig, md, r_expiredate, r_expired );
|
||||
|
||||
cache_sig_result ( sig, rc );
|
||||
md_close(md);
|
||||
}
|
||||
else {
|
||||
if (!opt.quiet)
|
||||
log_info ("key %08lX: no user ID for key signature packet "
|
||||
"of class %02x\n",
|
||||
(ulong)keyid_from_pk (pk, NULL), sig->sig_class );
|
||||
rc = G10ERR_SIG_CLASS;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
1358
g10/sign.c
Normal file
1358
g10/sign.c
Normal file
File diff suppressed because it is too large
Load diff
217
g10/signal.c
Normal file
217
g10/signal.c
Normal file
|
@ -0,0 +1,217 @@
|
|||
/* signal.c - signal handling
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "errors.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "ttyio.h"
|
||||
|
||||
|
||||
static volatile int caught_fatal_sig = 0;
|
||||
static volatile int caught_sigusr1 = 0;
|
||||
|
||||
static void
|
||||
init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction oact, nact;
|
||||
|
||||
if (check_ign) {
|
||||
/* we don't want to change an IGN handler */
|
||||
sigaction (sig, NULL, &oact );
|
||||
if (oact.sa_handler == SIG_IGN )
|
||||
return;
|
||||
}
|
||||
|
||||
nact.sa_handler = handler;
|
||||
sigemptyset (&nact.sa_mask);
|
||||
nact.sa_flags = 0;
|
||||
sigaction ( sig, &nact, NULL);
|
||||
#else
|
||||
RETSIGTYPE (*ohandler)(int);
|
||||
|
||||
ohandler = signal (sig, handler);
|
||||
if (check_ign && ohandler == SIG_IGN) {
|
||||
/* Change it back if it was already set to IGN */
|
||||
signal (sig, SIG_IGN);
|
||||
}
|
||||
#endif
|
||||
#endif /*!HAVE_DOSISH_SYSTEM*/
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_signal_name( int signum )
|
||||
{
|
||||
#if defined(SYS_SIGLIST_DECLARED) && defined(NSIG)
|
||||
return (signum >= 0 && signum < NSIG) ? sys_siglist[signum] : "?";
|
||||
#else
|
||||
return "some signal";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE
|
||||
got_fatal_signal( int sig )
|
||||
{
|
||||
const char *s;
|
||||
|
||||
if( caught_fatal_sig )
|
||||
raise( sig );
|
||||
caught_fatal_sig = 1;
|
||||
|
||||
secmem_term();
|
||||
/* better don't transtale these messages */
|
||||
write(2, "\n", 1 );
|
||||
s = log_get_name(); if( s ) write(2, s, strlen(s) );
|
||||
write(2, ": ", 2 );
|
||||
s = get_signal_name(sig); write(2, s, strlen(s) );
|
||||
write(2, " caught ... exiting\n", 20 );
|
||||
|
||||
/* reset action to default action and raise signal again */
|
||||
init_one_signal (sig, SIG_DFL, 0);
|
||||
remove_lockfiles ();
|
||||
#ifdef __riscos__
|
||||
riscos_close_fds ();
|
||||
#endif /* __riscos__ */
|
||||
raise( sig );
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE
|
||||
got_usr_signal( int sig )
|
||||
{
|
||||
caught_sigusr1 = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
init_signals()
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
init_one_signal (SIGINT, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGHUP, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGTERM, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGQUIT, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGSEGV, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGUSR1, got_usr_signal, 0 );
|
||||
init_one_signal (SIGPIPE, SIG_IGN, 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pause_on_sigusr( int which )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t mask, oldmask;
|
||||
|
||||
assert( which == 1 );
|
||||
sigemptyset( &mask );
|
||||
sigaddset( &mask, SIGUSR1 );
|
||||
|
||||
sigprocmask( SIG_BLOCK, &mask, &oldmask );
|
||||
while( !caught_sigusr1 )
|
||||
sigsuspend( &oldmask );
|
||||
caught_sigusr1 = 0;
|
||||
sigprocmask( SIG_UNBLOCK, &mask, NULL );
|
||||
#else
|
||||
assert (which == 1);
|
||||
sighold (SIGUSR1);
|
||||
while (!caught_sigusr1)
|
||||
sigpause(SIGUSR1);
|
||||
caught_sigusr1 = 0;
|
||||
sigrelse(SIGUSR1); ????
|
||||
#endif /*!HAVE_SIGPROCMASK*/
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_block( int block )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
static int is_blocked;
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
static sigset_t oldmask;
|
||||
|
||||
if( block ) {
|
||||
sigset_t newmask;
|
||||
|
||||
if( is_blocked )
|
||||
log_bug("signals are already blocked\n");
|
||||
sigfillset( &newmask );
|
||||
sigprocmask( SIG_BLOCK, &newmask, &oldmask );
|
||||
is_blocked = 1;
|
||||
}
|
||||
else {
|
||||
if( !is_blocked )
|
||||
log_bug("signals are not blocked\n");
|
||||
sigprocmask( SIG_SETMASK, &oldmask, NULL );
|
||||
is_blocked = 0;
|
||||
}
|
||||
#else /*!HAVE_SIGPROCMASK*/
|
||||
static void (*disposition[MAXSIG])();
|
||||
int sig;
|
||||
|
||||
if( block ) {
|
||||
if( is_blocked )
|
||||
log_bug("signals are already blocked\n");
|
||||
for (sig=1; sig < MAXSIG; sig++) {
|
||||
disposition[sig] = sigset (sig, SIG_HOLD);
|
||||
}
|
||||
is_blocked = 1;
|
||||
}
|
||||
else {
|
||||
if( !is_blocked )
|
||||
log_bug("signals are not blocked\n");
|
||||
for (sig=1; sig < MAXSIG; sig++) {
|
||||
sigset (sig, disposition[sig]);
|
||||
}
|
||||
is_blocked = 0;
|
||||
}
|
||||
#endif /*!HAVE_SIGPROCMASK*/
|
||||
#endif /*HAVE_DOSISH_SYSTEM*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
block_all_signals()
|
||||
{
|
||||
do_block(1);
|
||||
}
|
||||
|
||||
void
|
||||
unblock_all_signals()
|
||||
{
|
||||
do_block(0);
|
||||
}
|
693
g10/status.c
Normal file
693
g10/status.c
Normal file
|
@ -0,0 +1,693 @@
|
|||
/* status.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
#ifdef USE_CAPABILITIES
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IPC_H
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SHM_H
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#if defined(HAVE_MLOCK)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "status.h"
|
||||
#include "ttyio.h"
|
||||
#include "options.h"
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
#include "cipher.h" /* for progress functions */
|
||||
|
||||
#define CONTROL_D ('D' - 'A' + 1)
|
||||
|
||||
|
||||
|
||||
static FILE *statusfp;
|
||||
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
static int shm_id = -1;
|
||||
static volatile char *shm_area;
|
||||
static size_t shm_size;
|
||||
static int shm_is_locked;
|
||||
#endif /*USE_SHM_COPROCESSING*/
|
||||
|
||||
|
||||
static void
|
||||
progress_cb ( void *ctx, int c )
|
||||
{
|
||||
char buf[50];
|
||||
|
||||
if ( c == '\n' )
|
||||
sprintf ( buf, "%.20s X 100 100", (char*)ctx );
|
||||
else
|
||||
sprintf ( buf, "%.20s %c 0 0", (char*)ctx, c );
|
||||
write_status_text ( STATUS_PROGRESS, buf );
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_status_string ( int no )
|
||||
{
|
||||
const char *s;
|
||||
|
||||
switch( no ) {
|
||||
case STATUS_ENTER : s = "ENTER"; break;
|
||||
case STATUS_LEAVE : s = "LEAVE"; break;
|
||||
case STATUS_ABORT : s = "ABORT"; break;
|
||||
case STATUS_GOODSIG: s = "GOODSIG"; break;
|
||||
case STATUS_KEYEXPIRED: s = "KEYEXPIRED"; break;
|
||||
case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
|
||||
case STATUS_BADSIG : s = "BADSIG"; break;
|
||||
case STATUS_ERRSIG : s = "ERRSIG"; break;
|
||||
case STATUS_BADARMOR : s = "BADARMOR"; break;
|
||||
case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
|
||||
case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
|
||||
case STATUS_TRUST_NEVER : s = "TRUST_NEVER"; break;
|
||||
case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
|
||||
case STATUS_TRUST_FULLY : s = "TRUST_FULLY"; break;
|
||||
case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
|
||||
case STATUS_GET_BOOL : s = "GET_BOOL"; break;
|
||||
case STATUS_GET_LINE : s = "GET_LINE"; break;
|
||||
case STATUS_GET_HIDDEN : s = "GET_HIDDEN"; break;
|
||||
case STATUS_GOT_IT : s = "GOT_IT"; break;
|
||||
case STATUS_SHM_INFO : s = "SHM_INFO"; break;
|
||||
case STATUS_SHM_GET : s = "SHM_GET"; break;
|
||||
case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL"; break;
|
||||
case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
|
||||
case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
|
||||
case STATUS_VALIDSIG : s = "VALIDSIG"; break;
|
||||
case STATUS_SIG_ID : s = "SIG_ID"; break;
|
||||
case STATUS_ENC_TO : s = "ENC_TO"; break;
|
||||
case STATUS_NODATA : s = "NODATA"; break;
|
||||
case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
|
||||
case STATUS_NO_PUBKEY : s = "NO_PUBKEY"; break;
|
||||
case STATUS_NO_SECKEY : s = "NO_SECKEY"; break;
|
||||
case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
|
||||
case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
|
||||
case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
|
||||
case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
|
||||
case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
|
||||
case STATUS_GOODMDC : s = "GOODMDC"; break;
|
||||
case STATUS_BADMDC : s = "BADMDC"; break;
|
||||
case STATUS_ERRMDC : s = "ERRMDC"; break;
|
||||
case STATUS_IMPORTED : s = "IMPORTED"; break;
|
||||
case STATUS_IMPORT_OK : s = "IMPORT_OK"; break;
|
||||
case STATUS_IMPORT_CHECK : s = "IMPORT_CHECK"; break;
|
||||
case STATUS_IMPORT_RES : s = "IMPORT_RES"; break;
|
||||
case STATUS_FILE_START : s = "FILE_START"; break;
|
||||
case STATUS_FILE_DONE : s = "FILE_DONE"; break;
|
||||
case STATUS_FILE_ERROR : s = "FILE_ERROR"; break;
|
||||
case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
|
||||
case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
|
||||
case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
|
||||
case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
|
||||
case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
|
||||
case STATUS_PROGRESS : s = "PROGRESS"; break;
|
||||
case STATUS_SIG_CREATED : s = "SIG_CREATED"; break;
|
||||
case STATUS_SESSION_KEY : s = "SESSION_KEY"; break;
|
||||
case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
|
||||
case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
|
||||
case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
|
||||
case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
|
||||
case STATUS_END_STREAM : s = "END_STREAM"; break;
|
||||
case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
|
||||
case STATUS_USERID_HINT : s = "USERID_HINT"; break;
|
||||
case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
|
||||
case STATUS_INV_RECP : s = "INV_RECP"; break;
|
||||
case STATUS_NO_RECP : s = "NO_RECP"; break;
|
||||
case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
|
||||
case STATUS_SIGEXPIRED : s = "SIGEXPIRED deprecated-use-keyexpired-instead"; break;
|
||||
case STATUS_EXPSIG : s = "EXPSIG"; break;
|
||||
case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break;
|
||||
case STATUS_ATTRIBUTE : s = "ATTRIBUTE"; break;
|
||||
default: s = "?"; break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
set_status_fd ( int fd )
|
||||
{
|
||||
static int last_fd = -1;
|
||||
|
||||
if ( fd != -1 && last_fd == fd )
|
||||
return;
|
||||
|
||||
if ( statusfp && statusfp != stdout && statusfp != stderr )
|
||||
fclose (statusfp);
|
||||
statusfp = NULL;
|
||||
if ( fd == -1 )
|
||||
return;
|
||||
|
||||
if( fd == 1 )
|
||||
statusfp = stdout;
|
||||
else if( fd == 2 )
|
||||
statusfp = stderr;
|
||||
else
|
||||
statusfp = fdopen( fd, "w" );
|
||||
if( !statusfp ) {
|
||||
log_fatal("can't open fd %d for status output: %s\n",
|
||||
fd, strerror(errno));
|
||||
}
|
||||
last_fd = fd;
|
||||
register_primegen_progress ( progress_cb, "primegen" );
|
||||
register_pk_dsa_progress ( progress_cb, "pk_dsa" );
|
||||
register_pk_elg_progress ( progress_cb, "pk_elg" );
|
||||
}
|
||||
|
||||
int
|
||||
is_status_enabled()
|
||||
{
|
||||
return !!statusfp;
|
||||
}
|
||||
|
||||
void
|
||||
write_status ( int no )
|
||||
{
|
||||
write_status_text( no, NULL );
|
||||
}
|
||||
|
||||
void
|
||||
write_status_text ( int no, const char *text)
|
||||
{
|
||||
if( !statusfp )
|
||||
return; /* not enabled */
|
||||
|
||||
fputs ( "[GNUPG:] ", statusfp );
|
||||
fputs ( get_status_string (no), statusfp );
|
||||
if( text ) {
|
||||
putc ( ' ', statusfp );
|
||||
for (; *text; text++) {
|
||||
if (*text == '\n')
|
||||
fputs ( "\\n", statusfp );
|
||||
else if (*text == '\r')
|
||||
fputs ( "\\r", statusfp );
|
||||
else
|
||||
putc ( *(const byte *)text, statusfp );
|
||||
}
|
||||
}
|
||||
putc ('\n',statusfp);
|
||||
fflush (statusfp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write a status line with a buffer using %XX escapes. If WRAP is >
|
||||
* 0 wrap the line after this length. If STRING is not NULL it will
|
||||
* be prepended to the buffer, no escaping is done for string.
|
||||
* A wrap of -1 forces spaces not to be encoded as %20.
|
||||
*/
|
||||
void
|
||||
write_status_text_and_buffer ( int no, const char *string,
|
||||
const char *buffer, size_t len, int wrap )
|
||||
{
|
||||
const char *s, *text;
|
||||
int esc, first;
|
||||
int lower_limit = ' ';
|
||||
size_t n, count, dowrap;
|
||||
|
||||
if( !statusfp )
|
||||
return; /* not enabled */
|
||||
|
||||
if (wrap == -1) {
|
||||
lower_limit--;
|
||||
wrap = 0;
|
||||
}
|
||||
|
||||
text = get_status_string (no);
|
||||
count = dowrap = first = 1;
|
||||
do {
|
||||
if (dowrap) {
|
||||
fprintf (statusfp, "[GNUPG:] %s ", text );
|
||||
count = dowrap = 0;
|
||||
if (first && string) {
|
||||
fputs (string, statusfp);
|
||||
count += strlen (string);
|
||||
}
|
||||
first = 0;
|
||||
}
|
||||
for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
|
||||
if ( *s == '%' || *(const byte*)s <= lower_limit
|
||||
|| *(const byte*)s == 127 )
|
||||
esc = 1;
|
||||
if ( wrap && ++count > wrap ) {
|
||||
dowrap=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (esc) {
|
||||
s--; n++;
|
||||
}
|
||||
if (s != buffer)
|
||||
fwrite (buffer, s-buffer, 1, statusfp );
|
||||
if ( esc ) {
|
||||
fprintf (statusfp, "%%%02X", *(const byte*)s );
|
||||
s++; n--;
|
||||
}
|
||||
buffer = s;
|
||||
len = n;
|
||||
if ( dowrap && len )
|
||||
putc ( '\n', statusfp );
|
||||
} while ( len );
|
||||
|
||||
putc ('\n',statusfp);
|
||||
fflush (statusfp);
|
||||
}
|
||||
|
||||
void
|
||||
write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
|
||||
{
|
||||
write_status_text_and_buffer (no, NULL, buffer, len, wrap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
|
||||
#ifndef IPC_RMID_DEFERRED_RELEASE
|
||||
static void
|
||||
remove_shmid( void )
|
||||
{
|
||||
if( shm_id != -1 ) {
|
||||
shmctl ( shm_id, IPC_RMID, 0);
|
||||
shm_id = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
init_shm_coprocessing ( ulong requested_shm_size, int lock_mem )
|
||||
{
|
||||
char buf[100];
|
||||
struct shmid_ds shmds;
|
||||
|
||||
#ifndef IPC_RMID_DEFERRED_RELEASE
|
||||
atexit( remove_shmid );
|
||||
#endif
|
||||
requested_shm_size = (requested_shm_size + 4095) & ~4095;
|
||||
if ( requested_shm_size > 2 * 4096 )
|
||||
log_fatal("too much shared memory requested; only 8k are allowed\n");
|
||||
shm_size = 4096 /* one page for us */ + requested_shm_size;
|
||||
|
||||
shm_id = shmget( IPC_PRIVATE, shm_size, IPC_CREAT | 0700 );
|
||||
if ( shm_id == -1 )
|
||||
log_fatal("can't get %uk of shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
|
||||
#if !defined(IPC_HAVE_SHM_LOCK) \
|
||||
&& defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
|
||||
/* part of the old code which uses mlock */
|
||||
shm_area = shmat( shm_id, 0, 0 );
|
||||
if ( shm_area == (char*)-1 )
|
||||
log_fatal("can't attach %uk shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
log_debug("mapped %uk shared memory at %p, id=%d\n",
|
||||
(unsigned)shm_size/1024, shm_area, shm_id );
|
||||
if( lock_mem ) {
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
|
||||
#endif
|
||||
/* (need the cast for Solaris with Sun's workshop compilers) */
|
||||
if ( mlock ( (char*)shm_area, shm_size) )
|
||||
log_info("locking shared memory %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
else
|
||||
shm_is_locked = 1;
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IPC_RMID_DEFERRED_RELEASE
|
||||
if( shmctl( shm_id, IPC_RMID, 0) )
|
||||
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
#endif
|
||||
|
||||
if( shmctl( shm_id, IPC_STAT, &shmds ) )
|
||||
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
if( shmds.shm_perm.uid != getuid() ) {
|
||||
shmds.shm_perm.uid = getuid();
|
||||
if( shmctl( shm_id, IPC_SET, &shmds ) )
|
||||
log_fatal("shmctl IPC_SET of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
}
|
||||
|
||||
#else /* this is the new code which handles the changes in the SHM
|
||||
* semantics introduced with Linux 2.4. The changes is that we
|
||||
* now change the permissions and then attach to the memory.
|
||||
*/
|
||||
|
||||
if( lock_mem ) {
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
|
||||
#endif
|
||||
#ifdef IPC_HAVE_SHM_LOCK
|
||||
if ( shmctl (shm_id, SHM_LOCK, 0) )
|
||||
log_info("locking shared memory %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
else
|
||||
shm_is_locked = 1;
|
||||
#else
|
||||
log_info("Locking shared memory %d failed: No way to do it\n", shm_id );
|
||||
#endif
|
||||
#ifdef USE_CAPABILITIES
|
||||
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
|
||||
#endif
|
||||
}
|
||||
|
||||
if( shmctl( shm_id, IPC_STAT, &shmds ) )
|
||||
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
if( shmds.shm_perm.uid != getuid() ) {
|
||||
shmds.shm_perm.uid = getuid();
|
||||
if( shmctl( shm_id, IPC_SET, &shmds ) )
|
||||
log_fatal("shmctl IPC_SET of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
}
|
||||
|
||||
shm_area = shmat( shm_id, 0, 0 );
|
||||
if ( shm_area == (char*)-1 )
|
||||
log_fatal("can't attach %uk shared memory: %s\n",
|
||||
(unsigned)shm_size/1024, strerror(errno));
|
||||
log_debug("mapped %uk shared memory at %p, id=%d\n",
|
||||
(unsigned)shm_size/1024, shm_area, shm_id );
|
||||
|
||||
#ifdef IPC_RMID_DEFERRED_RELEASE
|
||||
if( shmctl( shm_id, IPC_RMID, 0) )
|
||||
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
|
||||
shm_id, strerror(errno));
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* write info; Protocol version, id, size, locked size */
|
||||
sprintf( buf, "pv=1 pid=%d shmid=%d sz=%u lz=%u", (int)getpid(),
|
||||
shm_id, (unsigned)shm_size, shm_is_locked? (unsigned)shm_size:0 );
|
||||
write_status_text( STATUS_SHM_INFO, buf );
|
||||
}
|
||||
|
||||
/****************
|
||||
* Request a string from client
|
||||
* If bool, returns static string on true (do not free) or NULL for false
|
||||
*/
|
||||
static char *
|
||||
do_shm_get( const char *keyword, int hidden, int bool )
|
||||
{
|
||||
size_t n;
|
||||
byte *p;
|
||||
char *string;
|
||||
|
||||
if( !shm_area )
|
||||
BUG();
|
||||
|
||||
shm_area[0] = 0; /* msb of length of control block */
|
||||
shm_area[1] = 32; /* and lsb */
|
||||
shm_area[2] = 1; /* indicate that we are waiting on a reply */
|
||||
shm_area[3] = 0; /* clear data available flag */
|
||||
|
||||
write_status_text( bool? STATUS_SHM_GET_BOOL :
|
||||
hidden? STATUS_SHM_GET_HIDDEN : STATUS_SHM_GET, keyword );
|
||||
|
||||
do {
|
||||
pause_on_sigusr(1);
|
||||
if( shm_area[0] || shm_area[1] != 32 || shm_area[2] != 1 )
|
||||
log_fatal("client modified shm control block - abort\n");
|
||||
} while( !shm_area[3] );
|
||||
shm_area[2] = 0; /* reset request flag */
|
||||
p = (byte*)shm_area+32;
|
||||
n = p[0] << 8 | p[1];
|
||||
p += 2;
|
||||
if( n+32+2+1 > 4095 )
|
||||
log_fatal("client returns too large data (%u bytes)\n", (unsigned)n );
|
||||
|
||||
if( bool )
|
||||
return p[0]? "" : NULL;
|
||||
|
||||
string = hidden? m_alloc_secure( n+1 ) : m_alloc( n+1 );
|
||||
memcpy(string, p, n );
|
||||
string[n] = 0; /* make sure it is a string */
|
||||
if( hidden ) /* invalidate the memory */
|
||||
memset( p, 0, n );
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
#endif /* USE_SHM_COPROCESSING */
|
||||
|
||||
static int
|
||||
myread(int fd, void *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
do {
|
||||
rc = read( fd, buf, count );
|
||||
} while ( rc == -1 && errno == EINTR );
|
||||
if ( !rc && count ) {
|
||||
static int eof_emmited=0;
|
||||
if ( eof_emmited < 3 ) {
|
||||
*(char*)buf = CONTROL_D;
|
||||
rc = 1;
|
||||
eof_emmited++;
|
||||
}
|
||||
else { /* Ctrl-D not caught - do something reasonable */
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
raise (SIGINT); /* nothing to hangup under DOS */
|
||||
#else
|
||||
raise (SIGHUP); /* no more input data */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Request a string from the client over the command-fd
|
||||
* If bool, returns static string on true (do not free) or NULL for false
|
||||
*/
|
||||
static char *
|
||||
do_get_from_fd( const char *keyword, int hidden, int bool )
|
||||
{
|
||||
int i, len;
|
||||
char *string;
|
||||
|
||||
write_status_text( bool? STATUS_GET_BOOL :
|
||||
hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword );
|
||||
|
||||
for( string = NULL, i = len = 200; ; i++ ) {
|
||||
if( i >= len-1 ) {
|
||||
char *save = string;
|
||||
len += 100;
|
||||
string = hidden? m_alloc_secure ( len ) : m_alloc ( len );
|
||||
if( save )
|
||||
memcpy(string, save, i );
|
||||
else
|
||||
i=0;
|
||||
}
|
||||
/* Hmmm: why not use our read_line function here */
|
||||
if( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
|
||||
break;
|
||||
else if ( string[i] == CONTROL_D ) {
|
||||
/* found ETX - cancel the line and return a sole ETX */
|
||||
string[0] = CONTROL_D;
|
||||
i=1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
string[i] = 0;
|
||||
|
||||
write_status( STATUS_GOT_IT );
|
||||
|
||||
if( bool ) /* Fixme: is this correct??? */
|
||||
return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
cpr_enabled()
|
||||
{
|
||||
if( opt.command_fd != -1 )
|
||||
return 1;
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
cpr_get_no_help( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 0, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 0, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
cpr_get( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 0, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 0, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
cpr_get_utf8( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
p = cpr_get( keyword, prompt );
|
||||
if( p ) {
|
||||
char *utf8 = native_to_utf8( p );
|
||||
m_free( p );
|
||||
p = utf8;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
cpr_get_hidden( const char *keyword, const char *prompt )
|
||||
{
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return do_get_from_fd ( keyword, 1, 0 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return do_shm_get( keyword, 1, 0 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get_hidden( prompt );
|
||||
if( *p == '?' && !p[1] ) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpr_kill_prompt(void)
|
||||
{
|
||||
if( opt.command_fd != -1 )
|
||||
return;
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return;
|
||||
#endif
|
||||
tty_kill_prompt();
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
cpr_get_answer_is_yes( const char *keyword, const char *prompt )
|
||||
{
|
||||
int yes;
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return !!do_get_from_fd ( keyword, 0, 1 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return !!do_shm_get( keyword, 0, 1 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
trim_spaces(p); /* it is okay to do this here */
|
||||
if( *p == '?' && !p[1] ) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else {
|
||||
tty_kill_prompt();
|
||||
yes = answer_is_yes(p);
|
||||
m_free(p);
|
||||
return yes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
|
||||
{
|
||||
int yes;
|
||||
char *p;
|
||||
|
||||
if( opt.command_fd != -1 )
|
||||
return !!do_get_from_fd ( keyword, 0, 1 );
|
||||
#ifdef USE_SHM_COPROCESSING
|
||||
if( opt.shm_coprocess )
|
||||
return !!do_shm_get( keyword, 0, 1 );
|
||||
#endif
|
||||
for(;;) {
|
||||
p = tty_get( prompt );
|
||||
trim_spaces(p); /* it is okay to do this here */
|
||||
if( *p == '?' && !p[1] ) {
|
||||
m_free(p);
|
||||
display_online_help( keyword );
|
||||
}
|
||||
else {
|
||||
tty_kill_prompt();
|
||||
yes = answer_is_yes_no_quit(p);
|
||||
m_free(p);
|
||||
return yes;
|
||||
}
|
||||
}
|
||||
}
|
1624
g10/tdbio.c
Normal file
1624
g10/tdbio.c
Normal file
File diff suppressed because it is too large
Load diff
117
g10/tdbio.h
Normal file
117
g10/tdbio.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* tdbio.h - Trust database I/O functions
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_TDBIO_H
|
||||
#define G10_TDBIO_H
|
||||
|
||||
#include "host2net.h"
|
||||
|
||||
#define TRUST_RECORD_LEN 40
|
||||
#define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5)
|
||||
#define ITEMS_PER_HTBL_RECORD ((TRUST_RECORD_LEN-2)/4)
|
||||
#define ITEMS_PER_HLST_RECORD ((TRUST_RECORD_LEN-6)/5)
|
||||
#define ITEMS_PER_PREF_RECORD (TRUST_RECORD_LEN-10)
|
||||
#if ITEMS_PER_PREF_RECORD % 2
|
||||
#error ITEMS_PER_PREF_RECORD must be even
|
||||
#endif
|
||||
#define MAX_LIST_SIGS_DEPTH 20
|
||||
|
||||
|
||||
#define RECTYPE_VER 1
|
||||
#define RECTYPE_HTBL 10
|
||||
#define RECTYPE_HLST 11
|
||||
#define RECTYPE_TRUST 12
|
||||
#define RECTYPE_VALID 13
|
||||
#define RECTYPE_FREE 254
|
||||
|
||||
|
||||
struct trust_record {
|
||||
int rectype;
|
||||
int mark;
|
||||
int dirty; /* for now only used internal by functions */
|
||||
struct trust_record *next; /* help pointer to build lists in memory */
|
||||
ulong recnum;
|
||||
union {
|
||||
struct { /* version record: */
|
||||
byte version; /* should be 3 */
|
||||
byte marginals;
|
||||
byte completes;
|
||||
byte cert_depth;
|
||||
byte trust_model;
|
||||
ulong created; /* timestamp of trustdb creation */
|
||||
ulong nextcheck; /* timestamp of next scheduled check */
|
||||
ulong reserved;
|
||||
ulong reserved2;
|
||||
ulong firstfree;
|
||||
ulong reserved3;
|
||||
ulong trusthashtbl;
|
||||
} ver;
|
||||
struct { /* free record */
|
||||
ulong next;
|
||||
} free;
|
||||
struct {
|
||||
ulong item[ITEMS_PER_HTBL_RECORD];
|
||||
} htbl;
|
||||
struct {
|
||||
ulong next;
|
||||
ulong rnum[ITEMS_PER_HLST_RECORD]; /* of another record */
|
||||
} hlst;
|
||||
struct {
|
||||
byte fingerprint[20];
|
||||
byte ownertrust;
|
||||
byte depth;
|
||||
ulong validlist;
|
||||
byte min_ownertrust;
|
||||
} trust;
|
||||
struct {
|
||||
byte namehash[20];
|
||||
ulong next;
|
||||
byte validity;
|
||||
byte full_count;
|
||||
byte marginal_count;
|
||||
} valid;
|
||||
} r;
|
||||
};
|
||||
typedef struct trust_record TRUSTREC;
|
||||
|
||||
/*-- tdbio.c --*/
|
||||
int tdbio_update_version_record(void);
|
||||
int tdbio_set_dbname( const char *new_dbname, int create );
|
||||
const char *tdbio_get_dbname(void);
|
||||
void tdbio_dump_record( TRUSTREC *rec, FILE *fp );
|
||||
int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
|
||||
int tdbio_write_record( TRUSTREC *rec );
|
||||
int tdbio_db_matches_options(void);
|
||||
byte tdbio_read_model(void);
|
||||
ulong tdbio_read_nextcheck (void);
|
||||
int tdbio_write_nextcheck (ulong stamp);
|
||||
int tdbio_is_dirty(void);
|
||||
int tdbio_sync(void);
|
||||
int tdbio_begin_transaction(void);
|
||||
int tdbio_end_transaction(void);
|
||||
int tdbio_cancel_transaction(void);
|
||||
int tdbio_delete_record( ulong recnum );
|
||||
ulong tdbio_new_recnum(void);
|
||||
int tdbio_search_trust_byfpr(const byte *fingerprint, TRUSTREC *rec );
|
||||
int tdbio_search_trust_bypk(PKT_public_key *pk, TRUSTREC *rec );
|
||||
|
||||
void tdbio_invalid(void);
|
||||
|
||||
#endif /*G10_TDBIO_H*/
|
234
g10/textfilter.c
Normal file
234
g10/textfilter.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
/* textfilter.c
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "filter.h"
|
||||
#include "i18n.h"
|
||||
#include "options.h"
|
||||
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#define LF "\r\n"
|
||||
#else
|
||||
#define LF "\n"
|
||||
#endif
|
||||
|
||||
#define MAX_LINELEN 19995 /* a little bit smaller than in armor.c */
|
||||
/* to make sure that a warning is displayed while */
|
||||
/* creating a message */
|
||||
|
||||
static unsigned
|
||||
len_without_trailing_chars( byte *line, unsigned len, const char *trimchars )
|
||||
{
|
||||
byte *p, *mark;
|
||||
unsigned n;
|
||||
|
||||
for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
|
||||
if( strchr( trimchars, *p ) ) {
|
||||
if( !mark )
|
||||
mark = p;
|
||||
}
|
||||
else
|
||||
mark = NULL;
|
||||
}
|
||||
|
||||
return mark? (mark - line) : len;
|
||||
}
|
||||
|
||||
unsigned
|
||||
len_without_trailing_ws( byte *line, unsigned len )
|
||||
{
|
||||
return len_without_trailing_chars( line, len, " \t\r\n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
standard( text_filter_context_t *tfx, IOBUF a,
|
||||
byte *buf, size_t size, size_t *ret_len)
|
||||
{
|
||||
int rc=0;
|
||||
size_t len = 0;
|
||||
unsigned maxlen;
|
||||
|
||||
assert( size > 10 );
|
||||
size -= 2; /* reserve 2 bytes to append CR,LF */
|
||||
while( !rc && len < size ) {
|
||||
int lf_seen;
|
||||
|
||||
while( len < size && tfx->buffer_pos < tfx->buffer_len )
|
||||
buf[len++] = tfx->buffer[tfx->buffer_pos++];
|
||||
if( len >= size )
|
||||
continue;
|
||||
|
||||
/* read the next line */
|
||||
maxlen = MAX_LINELEN;
|
||||
tfx->buffer_pos = 0;
|
||||
tfx->buffer_len = iobuf_read_line( a, &tfx->buffer,
|
||||
&tfx->buffer_size, &maxlen );
|
||||
if( !maxlen )
|
||||
tfx->truncated++;
|
||||
if( !tfx->buffer_len ) {
|
||||
if( !len )
|
||||
rc = -1; /* eof */
|
||||
break;
|
||||
}
|
||||
lf_seen = tfx->buffer[tfx->buffer_len-1] == '\n';
|
||||
tfx->buffer_len = trim_trailing_ws( tfx->buffer, tfx->buffer_len );
|
||||
if( lf_seen ) {
|
||||
tfx->buffer[tfx->buffer_len++] = '\r';
|
||||
tfx->buffer[tfx->buffer_len++] = '\n';
|
||||
}
|
||||
}
|
||||
*ret_len = len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* The filter is used to make canonical text: Lines are terminated by
|
||||
* CR, LF, trailing white spaces are removed.
|
||||
*/
|
||||
int
|
||||
text_filter( void *opaque, int control,
|
||||
IOBUF a, byte *buf, size_t *ret_len)
|
||||
{
|
||||
size_t size = *ret_len;
|
||||
text_filter_context_t *tfx = opaque;
|
||||
int rc=0;
|
||||
|
||||
if( control == IOBUFCTRL_UNDERFLOW ) {
|
||||
rc = standard( tfx, a, buf, size, ret_len );
|
||||
}
|
||||
else if( control == IOBUFCTRL_FREE ) {
|
||||
if( tfx->truncated )
|
||||
log_error(_("can't handle text lines longer than %d characters\n"),
|
||||
MAX_LINELEN );
|
||||
m_free( tfx->buffer );
|
||||
tfx->buffer = NULL;
|
||||
}
|
||||
else if( control == IOBUFCTRL_DESC )
|
||||
*(char**)buf = "text_filter";
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Copy data from INP to OUT and do some escaping if requested.
|
||||
* md is updated as required by rfc2440
|
||||
*/
|
||||
int
|
||||
copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
|
||||
int escape_dash, int escape_from, int pgp2mode )
|
||||
{
|
||||
unsigned maxlen;
|
||||
byte *buffer = NULL; /* malloced buffer */
|
||||
unsigned bufsize; /* and size of this buffer */
|
||||
unsigned n;
|
||||
int truncated = 0;
|
||||
int pending_lf = 0;
|
||||
|
||||
if( !opt.pgp2_workarounds )
|
||||
pgp2mode = 0;
|
||||
|
||||
if( !escape_dash )
|
||||
escape_from = 0;
|
||||
|
||||
for(;;) {
|
||||
maxlen = MAX_LINELEN;
|
||||
n = iobuf_read_line( inp, &buffer, &bufsize, &maxlen );
|
||||
if( !maxlen )
|
||||
truncated++;
|
||||
|
||||
if( !n )
|
||||
break; /* read_line has returned eof */
|
||||
|
||||
/* update the message digest */
|
||||
if( escape_dash ) {
|
||||
if( pending_lf ) {
|
||||
md_putc( md, '\r' );
|
||||
md_putc( md, '\n' );
|
||||
}
|
||||
md_write( md, buffer,
|
||||
len_without_trailing_chars( buffer, n,
|
||||
pgp2mode? " \r\n":" \t\r\n"));
|
||||
}
|
||||
else
|
||||
md_write( md, buffer, n );
|
||||
pending_lf = buffer[n-1] == '\n';
|
||||
|
||||
/* write the output */
|
||||
if( ( escape_dash && *buffer == '-')
|
||||
|| ( escape_from && n > 4 && !memcmp(buffer, "From ", 5 ) ) ) {
|
||||
iobuf_put( out, '-' );
|
||||
iobuf_put( out, ' ' );
|
||||
}
|
||||
|
||||
#if 0 /*defined(HAVE_DOSISH_SYSTEM)*/
|
||||
/* We don't use this anymore because my interpretation of rfc2440 7.1
|
||||
* is that there is no conversion needed. If one decides to
|
||||
* clearsign a unix file on a DOS box he will get a mixed line endings.
|
||||
* If at some point it turns out, that a conversion is a nice feature
|
||||
* we can make an option out of it.
|
||||
*/
|
||||
/* make sure the lines do end in CR,LF */
|
||||
if( n > 1 && ( (buffer[n-2] == '\r' && buffer[n-1] == '\n' )
|
||||
|| (buffer[n-2] == '\n' && buffer[n-1] == '\r'))) {
|
||||
iobuf_write( out, buffer, n-2 );
|
||||
iobuf_put( out, '\r');
|
||||
iobuf_put( out, '\n');
|
||||
}
|
||||
else if( n && buffer[n-1] == '\n' ) {
|
||||
iobuf_write( out, buffer, n-1 );
|
||||
iobuf_put( out, '\r');
|
||||
iobuf_put( out, '\n');
|
||||
}
|
||||
else
|
||||
iobuf_write( out, buffer, n );
|
||||
|
||||
#else
|
||||
iobuf_write( out, buffer, n );
|
||||
#endif
|
||||
}
|
||||
|
||||
/* at eof */
|
||||
if( !pending_lf ) { /* make sure that the file ends with a LF */
|
||||
iobuf_writestr( out, LF );
|
||||
if( !escape_dash )
|
||||
md_putc( md, '\n' );
|
||||
}
|
||||
|
||||
if( truncated )
|
||||
log_info(_("input line longer than %d characters\n"), MAX_LINELEN );
|
||||
|
||||
return 0; /* okay */
|
||||
}
|
2129
g10/trustdb.c
Normal file
2129
g10/trustdb.c
Normal file
File diff suppressed because it is too large
Load diff
83
g10/trustdb.h
Normal file
83
g10/trustdb.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* trustdb.h - Trust database
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
|
||||
* Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef G10_TRUSTDB_H
|
||||
#define G10_TRUSTDB_H
|
||||
|
||||
|
||||
/* Trust values must be sorted in ascending order */
|
||||
#define TRUST_MASK 15
|
||||
#define TRUST_UNKNOWN 0 /* o: not yet calculated/assigned */
|
||||
#define TRUST_EXPIRED 1 /* e: calculation may be invalid */
|
||||
#define TRUST_UNDEFINED 2 /* q: not enough information for calculation */
|
||||
#define TRUST_NEVER 3 /* n: never trust this pubkey */
|
||||
#define TRUST_MARGINAL 4 /* m: marginally trusted */
|
||||
#define TRUST_FULLY 5 /* f: fully trusted */
|
||||
#define TRUST_ULTIMATE 6 /* u: ultimately trusted */
|
||||
/* trust values not covered by the mask */
|
||||
#define TRUST_FLAG_REVOKED 32 /* r: revoked */
|
||||
#define TRUST_FLAG_SUB_REVOKED 64 /* r: revoked but for subkeys */
|
||||
#define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */
|
||||
#define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */
|
||||
|
||||
/*-- trustdb.c --*/
|
||||
void register_trusted_key( const char *string );
|
||||
void check_trustdb (void);
|
||||
void update_trustdb (void);
|
||||
int setup_trustdb( int level, const char *dbname );
|
||||
void init_trustdb( void );
|
||||
void sync_trustdb( void );
|
||||
|
||||
const char *trust_value_to_string (unsigned int value);
|
||||
int string_to_trust_value (const char *str);
|
||||
|
||||
void revalidation_mark (void);
|
||||
int trustdb_pending_check(void);
|
||||
|
||||
int cache_disabled_value(PKT_public_key *pk);
|
||||
|
||||
unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid);
|
||||
int get_validity_info (PKT_public_key *pk, PKT_user_id *uid);
|
||||
const char *get_validity_string (PKT_public_key *pk, PKT_user_id *uid);
|
||||
|
||||
void list_trust_path( const char *username );
|
||||
int enum_cert_paths( void **context, ulong *lid,
|
||||
unsigned *ownertrust, unsigned *validity );
|
||||
void enum_cert_paths_print( void **context, FILE *fp,
|
||||
int refresh, ulong selected_lid );
|
||||
|
||||
unsigned int get_ownertrust (PKT_public_key *pk);
|
||||
unsigned int get_min_ownertrust (PKT_public_key *pk);
|
||||
int get_ownertrust_info (PKT_public_key *pk);
|
||||
const char *get_ownertrust_string (PKT_public_key *pk);
|
||||
|
||||
void update_ownertrust (PKT_public_key *pk, unsigned int new_trust );
|
||||
int clear_ownertrusts (PKT_public_key *pk);
|
||||
|
||||
/*-- tdbdump.c --*/
|
||||
void list_trustdb(const char *username);
|
||||
void export_ownertrust(void);
|
||||
void import_ownertrust(const char *fname);
|
||||
|
||||
/*-- pkclist.c --*/
|
||||
int edit_ownertrust (PKT_public_key *pk, int mode );
|
||||
|
||||
#endif /*G10_TRUSTDB_H*/
|
193
g10/verify.c
Normal file
193
g10/verify.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/* verify.c - verify signed data
|
||||
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
||||
*
|
||||
* 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h> /* for isatty() */
|
||||
|
||||
#include "options.h"
|
||||
#include "packet.h"
|
||||
#include "errors.h"
|
||||
#include "iobuf.h"
|
||||
#include "keydb.h"
|
||||
#include "memory.h"
|
||||
#include "util.h"
|
||||
#include "main.h"
|
||||
#include "status.h"
|
||||
#include "filter.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* Assume that the input is a signature and verify it without
|
||||
* generating any output. With no arguments, the signature packet
|
||||
* is read from stdin (it may be a detached signature when not
|
||||
* used in batch mode). If only a sigfile is given, it may be a complete
|
||||
* signature or a detached signature in which case the signed stuff
|
||||
* is expected from stdin. With more than 1 argument, the first should
|
||||
* be a detached signature and the remaining files are the signed stuff.
|
||||
*/
|
||||
|
||||
int
|
||||
verify_signatures( int nfiles, char **files )
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
const char *sigfile;
|
||||
int i, rc;
|
||||
STRLIST sl;
|
||||
|
||||
memset( &afx, 0, sizeof afx);
|
||||
/* decide whether we should handle a detached or a normal signature,
|
||||
* which is needed so that the code later can hash the correct data and
|
||||
* not have a normal signature act as detached signature and ignoring the
|
||||
* indended signed material from the 2nd file or stdin.
|
||||
* 1. gpg <file - normal
|
||||
* 2. gpg file - normal (or detached)
|
||||
* 3. gpg file <file2 - detached
|
||||
* 4. gpg file file2 - detached
|
||||
* The question is how decide between case 2 and 3? The only way
|
||||
* we can do it is by reading one byte from stdin and the unget
|
||||
* it; the problem here is that we may be reading from the
|
||||
* terminal (which could be detected using isatty() but won't work
|
||||
* when under contol of a pty using program (e.g. expect)) and
|
||||
* might get us in trouble when stdin is used for another purpose
|
||||
* (--passphrase-fd 0). So we have to break with the behaviour
|
||||
* prior to gpg 1.0.4 by assuming that case 3 is a normal
|
||||
* signature (where file2 is ignored and require for a detached
|
||||
* signature to indicate signed material comes from stdin by using
|
||||
* case 4 with a file2 of "-".
|
||||
*
|
||||
* Actually we don't have to change anything here but can handle
|
||||
* that all quite easily in mainproc.c
|
||||
*/
|
||||
|
||||
|
||||
sigfile = nfiles? *files : NULL;
|
||||
|
||||
/* open the signature file */
|
||||
fp = iobuf_open(sigfile);
|
||||
if( !fp ) {
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(sigfile));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
handle_progress (&pfx, fp, sigfile);
|
||||
|
||||
if( !opt.no_armor && use_armor_filter( fp ) )
|
||||
iobuf_push_filter( fp, armor_filter, &afx );
|
||||
|
||||
sl = NULL;
|
||||
for(i=1 ; i < nfiles; i++ )
|
||||
add_to_strlist( &sl, files[i] );
|
||||
rc = proc_signature_packets( NULL, fp, sl, sigfile );
|
||||
free_strlist(sl);
|
||||
iobuf_close(fp);
|
||||
if( afx.no_openpgp_data && rc == -1 ) {
|
||||
log_error(_("the signature could not be verified.\n"
|
||||
"Please remember that the signature file (.sig or .asc)\n"
|
||||
"should be the first file given on the command line.\n") );
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
print_file_status( int status, const char *name, int what )
|
||||
{
|
||||
char *p = m_alloc(strlen(name)+10);
|
||||
sprintf(p, "%d %s", what, name );
|
||||
write_status_text( status, p );
|
||||
m_free(p);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
verify_one_file( const char *name )
|
||||
{
|
||||
IOBUF fp;
|
||||
armor_filter_context_t afx;
|
||||
progress_filter_context_t pfx;
|
||||
int rc;
|
||||
|
||||
print_file_status( STATUS_FILE_START, name, 1 );
|
||||
fp = iobuf_open(name);
|
||||
if( !fp ) {
|
||||
print_file_status( STATUS_FILE_ERROR, name, 1 );
|
||||
log_error(_("can't open `%s'\n"), print_fname_stdin(name));
|
||||
return G10ERR_OPEN_FILE;
|
||||
}
|
||||
handle_progress (&pfx, fp, name);
|
||||
|
||||
if( !opt.no_armor ) {
|
||||
if( use_armor_filter( fp ) ) {
|
||||
memset( &afx, 0, sizeof afx);
|
||||
iobuf_push_filter( fp, armor_filter, &afx );
|
||||
}
|
||||
}
|
||||
|
||||
rc = proc_signature_packets( NULL, fp, NULL, name );
|
||||
iobuf_close(fp);
|
||||
write_status( STATUS_FILE_DONE );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Verify each file given in the files array or read the names of the
|
||||
* files from stdin.
|
||||
* Note: This function can not handle detached signatures.
|
||||
*/
|
||||
int
|
||||
verify_files( int nfiles, char **files )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !nfiles ) { /* read the filenames from stdin */
|
||||
char line[2048];
|
||||
unsigned int lno = 0;
|
||||
|
||||
while( fgets(line, DIM(line), stdin) ) {
|
||||
lno++;
|
||||
if( !*line || line[strlen(line)-1] != '\n' ) {
|
||||
log_error(_("input line %u too long or missing LF\n"), lno );
|
||||
return G10ERR_GENERAL;
|
||||
}
|
||||
/* This code does not work on MSDOS but how cares there are
|
||||
* also no script languages available. We don't strip any
|
||||
* spaces, so that we can process nearly all filenames */
|
||||
line[strlen(line)-1] = 0;
|
||||
verify_one_file( line );
|
||||
}
|
||||
|
||||
}
|
||||
else { /* take filenames from the array */
|
||||
for(i=0; i < nfiles; i++ )
|
||||
verify_one_file( files[i] );
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue