1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-23 10:29:58 +01:00

Add gpgsplit tool

This commit is contained in:
Werner Koch 2001-06-20 13:53:08 +00:00
parent ae78aed6b6
commit 906c8ca7ca
5 changed files with 479 additions and 1 deletions

3
NEWS
View File

@ -1,3 +1,6 @@
* New tool gpgsplit to split OpenPGP data formats into packets.
Noteworthy changes in version 1.0.6 (2001-05-29) Noteworthy changes in version 1.0.6 (2001-05-29)
------------------------------------------------ ------------------------------------------------

3
TODO
View File

@ -64,6 +64,9 @@
an even log so that other software can display a key history or an even log so that other software can display a key history or
alike with GnuPG results. This should be connected to the keyrings. alike with GnuPG results. This should be connected to the keyrings.
* Using --list-only to check for recipients while decrypting may
yield an error about an unknown packet.
Scheduled for 1.1 Scheduled for 1.1
----------------- -----------------

View File

@ -1,3 +1,8 @@
2001-06-20 Werner Koch <wk@gnupg.org>
* gpgsplit.c: New.
* Makefile.am (bin_PROGRAMS): Install gpgsplit.
2001-03-27 Werner Koch <wk@gnupg.org> 2001-03-27 Werner Koch <wk@gnupg.org>
* mail-signed-keys: Add option --dry-run. * mail-signed-keys: Add option --dry-run.

View File

@ -23,6 +23,7 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
needed_libs = ../cipher/libcipher.a \ needed_libs = ../cipher/libcipher.a \
../mpi/libmpi.a ../util/libutil.a @INTLLIBS@ ../mpi/libmpi.a ../util/libutil.a @INTLLIBS@
bin_PROGRAMS = gpgsplit
noinst_PROGRAMS = mpicalc bftest clean-sat mk-tdata shmtest noinst_PROGRAMS = mpicalc bftest clean-sat mk-tdata shmtest
mpicalc_SOURCES = mpicalc.c mpicalc_SOURCES = mpicalc.c
@ -33,11 +34,17 @@ clean_sat_SOURCES = clean-sat.c
mk_tdata_SOURCES = mk-tdata.c mk_tdata_SOURCES = mk-tdata.c
shmtest_SOURCES = shmtest.c shmtest_SOURCES = shmtest.c
gpgsplit_SOURCES = gpgsplit.c
mpicalc_LDADD = $(needed_libs) mpicalc_LDADD = $(needed_libs)
bftest_LDADD = $(needed_libs) bftest_LDADD = $(needed_libs)
shmtest_LDADD = $(needed_libs) shmtest_LDADD = $(needed_libs)
gpgsplit_LDADD = $(needed_libs)
mpicalc bftest shmtest gpgsplit: $(needed_libs)
mpicalc bftest shmtest: $(needed_libs)

460
tools/gpgsplit.c Normal file
View File

@ -0,0 +1,460 @@
/* gpgsplit.c - An OpenPGP packet splitting tool
* 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
*/
/*
* TODO: Add an option to uncompress packets. This should come wuite handy.
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <assert.h>
#ifdef HAVE_DOSISH_SYSTEM
#include <fcntl.h> /* for setmode() */
#endif
#include "../g10/packet.h"
#include "util.h"
static int opt_verbose;
static const char *opt_prefix = "";
static void g10_exit( int rc );
static void split_packets (const char *fname);
enum cmd_and_opt_values { aNull = 0,
oVerbose = 'v',
oPrefix = 'p',
aTest };
static ARGPARSE_OPTS opts[] = {
{ 301, NULL, 0, "@\nOptions:\n " },
{ oVerbose, "verbose", 0, "verbose" },
{ oPrefix, "prefix", 2, "|STRING| Prepend filenames with STRING" },
{0} };
const char *
strusage( int level )
{
const char *p;
switch( level ) {
case 11: p = "gpgsplit (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p =
"Please report bugs to <bug-gnupg@gnu.org>.\n";
break;
case 1:
case 40: p =
"Usage: gpgsplit [options] [files] (-h for help)";
break;
case 41: p =
"Syntax: gpgsplit [options] [files]\n"
"Split an OpenPGP message into packets\n";
break;
default: p = default_strusage(level);
}
return p;
}
int
main( int argc, char **argv )
{
ARGPARSE_ARGS pargs;
#ifdef HAVE_DOSISH_SYSTEM
setmode( fileno(stdin), O_BINARY );
setmode( fileno(stdout), O_BINARY );
#endif
log_set_name("gpgsplit");
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
while( optfile_parse( NULL, NULL, NULL, &pargs, opts) ) {
switch( pargs.r_opt ) {
case oVerbose: opt_verbose = 1; break;
case oPrefix: opt_prefix = pargs.r.ret_str; break;
default : pargs.err = 2; break;
}
}
if( log_get_errorcount(0) )
g10_exit(2);
if (!argc)
split_packets (NULL);
else {
for ( ;argc; argc--, argv++)
split_packets (*argv);
}
g10_exit (0);
return 0;
}
static void
g10_exit( int rc )
{
rc = rc? rc : log_get_errorcount(0)? 2 : 0;
exit(rc );
}
static const char *
pkttype_to_string (int pkttype)
{
const char *s;
switch (pkttype) {
case PKT_PUBKEY_ENC : s = "pk_enc"; break;
case PKT_SIGNATURE : s = "sig"; break;
case PKT_SYMKEY_ENC : s = "sym_enc"; break;
case PKT_ONEPASS_SIG : s = "onepass_sig"; break;
case PKT_SECRET_KEY : s = "secret_key"; break;
case PKT_PUBLIC_KEY : s = "public_key"; break;
case PKT_SECRET_SUBKEY : s = "secret_subkey"; break;
case PKT_COMPRESSED : s = "compressed"; break;
case PKT_ENCRYPTED : s = "encrypted"; break;
case PKT_MARKER : s = "marker"; break;
case PKT_PLAINTEXT : s = "plaintext"; break;
case PKT_RING_TRUST : s = "ring_trust"; break;
case PKT_USER_ID : s = "user_id"; break;
case PKT_PUBLIC_SUBKEY : s = "public_subkey"; break;
case PKT_OLD_COMMENT : s = "old_comment"; break;
case PKT_PHOTO_ID : s = "photo_id"; break;
case PKT_ENCRYPTED_MDC : s = "encrypted_mdc"; break;
case PKT_MDC : s = "mdc"; break;
case PKT_COMMENT : s = "comment"; break;
case PKT_GPG_CONTROL : s = "gpg_control"; break;
default: s = "unknown"; break;
}
return s;
}
/*
* Create a new filename and a return a pointer to a statically
* allocated buffer
*/
static char *
create_filename (int pkttype)
{
static unsigned int partno = 0;
static char *name;
if (!name)
name = m_alloc (strlen (opt_prefix) + 100 );
assert (pkttype < 1000 && pkttype >= 0 );
partno++;
sprintf (name, "%s%06u-%03d.%.40s",
opt_prefix, partno, pkttype, pkttype_to_string (pkttype));
return name;
}
static int
read_u16 (FILE *fp, size_t *rn)
{
int c;
if ( (c = getc (fp)) == EOF )
return -1;
*rn = c << 8;
if ( (c = getc (fp)) == EOF )
return -1;
*rn |= c;
return 0;
}
static int
read_u32 (FILE *fp, unsigned long *rn)
{
size_t tmp;
if (read_u16 (fp, &tmp))
return -1;
*rn = tmp << 16;
if (read_u16 (fp, &tmp))
return -1;
*rn |= tmp;
return 0;
}
/* hdr must pint to a buffer large enough to hold all header bytes */
static int
write_part ( const char *fname, FILE *fpin, unsigned long pktlen,
int pkttype, int partial, unsigned char *hdr, size_t hdrlen)
{
FILE *fpout;
int c, first;
unsigned char *p;
const char *outname = create_filename (pkttype);
/* fixme: should we check that this file does not yet exist? */
if (opt_verbose)
log_info ("writing `%s'\n", outname);
fpout = fopen (outname, "wb");
if (!fpout) {
log_error ("error creating `%s': %s\n", outname, strerror(errno));
/* stop right now, otherwise we would mess up the sequence of
* the part numbers */
g10_exit (1);
}
for (p=hdr; hdrlen; p++, hdrlen--) {
if ( putc (*p, fpout) == EOF )
goto write_error;
}
first = 1;
while (partial) {
size_t partlen;
if (partial == 1) { /* openpgp */
if( first ) {
c = pktlen;
assert( c >= 224 && c < 255 );
first = 0;
}
else if( (c = getc (fpin)) == EOF ) {
goto read_error;
}
else
hdr[hdrlen++] = c;
if( c < 192 ) {
pktlen = c;
partial = 0; /* (last segment may follow) */
}
else if( c < 224 ) {
pktlen = (c - 192) * 256;
if( (c = getc (fpin)) == EOF )
goto read_error;
hdr[hdrlen++] = c;
pktlen += c + 192;
partial = 0;
}
else if( c == 255 ) {
if (read_u32 (fpin, &pktlen))
goto read_error;
hdr[hdrlen++] = pktlen >> 24;
hdr[hdrlen++] = pktlen >> 16;
hdr[hdrlen++] = pktlen >> 8;
hdr[hdrlen++] = pktlen;
partial = 0;
}
else { /* next partial body length */
for (p=hdr; hdrlen; p++, hdrlen--) {
if ( putc (*p, fpout) == EOF )
goto write_error;
}
partlen = 1 << (c & 0x1f);
for (; partlen; partlen--) {
if ((c = getc (fpin)) == EOF)
goto read_error;
if ( putc (c, fpout) == EOF )
goto write_error;
}
}
}
else if (partial == 2) { /* old gnupg */
assert (!pktlen);
if ( read_u16 (fpin, &partlen) )
goto read_error;
hdr[hdrlen++] = partlen >> 8;
hdr[hdrlen++] = partlen;
for (p=hdr; hdrlen; p++, hdrlen--) {
if ( putc (*p, fpout) == EOF )
goto write_error;
}
if (!partlen)
partial = 0; /* end of packet */
for (; partlen; partlen--) {
c = getc (fpin);
if (c == EOF)
goto read_error;
if ( putc (c, fpout) == EOF )
goto write_error;
}
}
else { /* compressed: read to end */
pktlen = 0;
partial = 0;
while ( (c=getc (fpin)) != EOF ) {
if ( putc (c, fpout) == EOF )
goto write_error;
}
if (!feof (fpin))
goto read_error;
}
}
for (p=hdr; hdrlen; p++, hdrlen--) {
if ( putc (*p, fpout) == EOF )
goto write_error;
}
/* standard packet or last segment of partial length encoded packet */
for (; pktlen; pktlen--) {
c = getc (fpin);
if (c == EOF)
goto read_error;
if ( putc (c, fpout) == EOF )
goto write_error;
}
if ( fclose (fpout) )
log_error ("error closing `%s': %s\n", outname, strerror (errno));
return 0;
write_error:
log_error ("error writing `%s': %s\n", outname, strerror (errno));
fclose (fpout);
return 2;
read_error: {
int save = errno;
fclose (fpout);
errno = save;
}
return -1;
}
static int
do_split (const char *fname, FILE *fp)
{
int c, ctb, pkttype;
unsigned long pktlen = 0;
int partial = 0;
unsigned char header[20];
int header_idx = 0;
ctb = getc (fp);
if (ctb == EOF)
return 3; /* ready */
header[header_idx++] = ctb;
if( !(ctb & 0x80) ) {
log_error("invalid CTB %02x\n", ctb );
return 1;
}
if ( (ctb & 0x40) ) { /* new CTB */
pkttype = (ctb & 0x3f);
if( (c = getc (fp)) == EOF )
return -1;
header[header_idx++] = c;
if( c < 192 )
pktlen = c;
else if( c < 224 ) {
pktlen = (c - 192) * 256;
if( (c = getc (fp)) == EOF )
return -1;
header[header_idx++] = c;
pktlen += c + 192;
}
else if( c == 255 ) {
if (read_u32 (fp, &pktlen))
return -1;
header[header_idx++] = pktlen >> 24;
header[header_idx++] = pktlen >> 16;
header[header_idx++] = pktlen >> 8;
header[header_idx++] = pktlen;
}
else { /* partial body length */
pktlen = c;
partial = 1;
}
}
else {
int lenbytes;
pkttype = (ctb>>2)&0xf;
lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
if( !lenbytes ) {
pktlen = 0; /* don't know the value */
if( pkttype == PKT_COMPRESSED )
partial = 3;
else
partial = 2; /* the old GnuPG partial length encoding */
}
else {
for( ; lenbytes; lenbytes-- ) {
pktlen <<= 8;
if( (c = getc (fp)) == EOF )
return -1;
header[header_idx++] = c;
pktlen |= c;
}
}
}
return write_part (fname, fp, pktlen, pkttype, partial,
header, header_idx);
}
static void
split_packets (const char *fname)
{
FILE *fp;
int rc;
if (!fname || !strcmp (fname, "-")) {
fp = stdin;
fname = "-";
}
else if ( !(fp = fopen (fname,"rb")) ) {
log_error ("can't open `%s': %s\n", fname, strerror (errno));
return;
}
while ( !(rc = do_split (fname, fp)) )
;
if ( rc > 0 )
; /* error already handled */
else if ( ferror (fp) )
log_error ("error reading `%s': %s\n", fname, strerror (errno));
else
log_error ("premature EOF while reading `%s'\n", fname );
if ( fp != stdin )
fclose (fp);
}