2003-08-05 17:11:04 +00:00
|
|
|
|
/* miscellaneous.c - Stuff not fitting elsewhere
|
2006-05-23 16:19:43 +00:00
|
|
|
|
* Copyright (C) 2003, 2006 Free Software Foundation, Inc.
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*
|
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
|
*
|
Change license for some files in common to LGPLv3+/GPLv2+.
Having the LGPL on the common GnuPG code helps to share code
between GnuPG and related projects (like GPGME and Libassuan). This
is good for interoperability and to reduces bugs.
* common/asshelp.c, common/asshelp.h, common/asshelp2.c, common/b64dec.c
* common/b64enc.c, common/convert.c, common/dns-cert.c
* common/dns-cert.h common/exechelp-posix.c, common/exechelp-w32.c
* common/exechelp-w32ce.c, common/exechelp.h, common/get-passphrase.c
* common/get-passphrase.h, common/gettime.c, common/gpgrlhelp.c
* common/helpfile.c, common/homedir.c, common/http.c, common/http.h
* common/i18n.c, common/init.c, common/init.h, common/iobuf.c
* common/iobuf.h, common/localename.c, common/membuf.c, common/membuf.h
* common/miscellaneous.c, common/openpgp-oid.c, common/openpgpdefs.h
* common/percent.c, common/pka.c, common/pka.h, common/session-env.c
* common/session-env.h, common/sexp-parse.h, common/sexputil.c
* common/signal.c, common/srv.c, common/srv.h, common/ssh-utils.c
* common/ssh-utils.h, common/sysutils.c, common/sysutils.h
* common/tlv.c, common/tlv.h, common/ttyio.c, common/ttyio.h
* common/userids.c, common/userids.h, common/xasprintf.c: Change
license to LGPLv3+/GPLv2+/
2012-04-20 15:43:06 +02:00
|
|
|
|
* This file is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of either
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*
|
Change license for some files in common to LGPLv3+/GPLv2+.
Having the LGPL on the common GnuPG code helps to share code
between GnuPG and related projects (like GPGME and Libassuan). This
is good for interoperability and to reduces bugs.
* common/asshelp.c, common/asshelp.h, common/asshelp2.c, common/b64dec.c
* common/b64enc.c, common/convert.c, common/dns-cert.c
* common/dns-cert.h common/exechelp-posix.c, common/exechelp-w32.c
* common/exechelp-w32ce.c, common/exechelp.h, common/get-passphrase.c
* common/get-passphrase.h, common/gettime.c, common/gpgrlhelp.c
* common/helpfile.c, common/homedir.c, common/http.c, common/http.h
* common/i18n.c, common/init.c, common/init.h, common/iobuf.c
* common/iobuf.h, common/localename.c, common/membuf.c, common/membuf.h
* common/miscellaneous.c, common/openpgp-oid.c, common/openpgpdefs.h
* common/percent.c, common/pka.c, common/pka.h, common/session-env.c
* common/session-env.h, common/sexp-parse.h, common/sexputil.c
* common/signal.c, common/srv.c, common/srv.h, common/ssh-utils.c
* common/ssh-utils.h, common/sysutils.c, common/sysutils.h
* common/tlv.c, common/tlv.h, common/ttyio.c, common/ttyio.h
* common/userids.c, common/userids.h, common/xasprintf.c: Change
license to LGPLv3+/GPLv2+/
2012-04-20 15:43:06 +02:00
|
|
|
|
* - the GNU Lesser General Public License as published by the Free
|
|
|
|
|
* Software Foundation; either version 3 of the License, or (at
|
|
|
|
|
* your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* or
|
|
|
|
|
*
|
|
|
|
|
* - the GNU General Public License as published by the Free
|
|
|
|
|
* Software Foundation; either version 2 of the License, or (at
|
|
|
|
|
* your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* or both in parallel, as here.
|
|
|
|
|
*
|
|
|
|
|
* This file is distributed in the hope that it will be useful,
|
2003-08-05 17:11:04 +00:00
|
|
|
|
* 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
|
2016-11-05 12:02:19 +01:00
|
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdlib.h>
|
2015-06-22 20:54:23 +02:00
|
|
|
|
#include <limits.h>
|
2003-08-05 17:11:04 +00:00
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "iobuf.h"
|
2007-04-20 16:59:37 +00:00
|
|
|
|
#include "i18n.h"
|
|
|
|
|
|
|
|
|
|
/* Used by libgcrypt for logging. */
|
|
|
|
|
static void
|
|
|
|
|
my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
|
|
|
|
|
{
|
2008-10-17 19:18:46 +00:00
|
|
|
|
(void)dummy;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2007-04-20 16:59:37 +00:00
|
|
|
|
/* Map the log levels. */
|
|
|
|
|
switch (level)
|
|
|
|
|
{
|
2017-12-11 10:37:30 +01:00
|
|
|
|
case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break;
|
|
|
|
|
case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break;
|
|
|
|
|
case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break;
|
|
|
|
|
case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break;
|
|
|
|
|
case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break;
|
|
|
|
|
case GCRY_LOG_BUG: level = GPGRT_LOGLVL_BUG; break;
|
|
|
|
|
case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break;
|
|
|
|
|
default: level = GPGRT_LOGLVL_ERROR; break;
|
2007-04-20 16:59:37 +00:00
|
|
|
|
}
|
|
|
|
|
log_logv (level, fmt, arg_ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function is called by libgcrypt on a fatal error. */
|
|
|
|
|
static void
|
|
|
|
|
my_gcry_fatalerror_handler (void *opaque, int rc, const char *text)
|
|
|
|
|
{
|
2008-10-17 19:18:46 +00:00
|
|
|
|
(void)opaque;
|
|
|
|
|
|
2007-04-20 16:59:37 +00:00
|
|
|
|
log_fatal ("libgcrypt problem: %s\n", text ? text : gpg_strerror (rc));
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function is called by libgcrypt if it ran out of core and
|
|
|
|
|
there is no way to return that error to the caller. We do our own
|
|
|
|
|
function here to make use of our logging functions. */
|
|
|
|
|
static int
|
|
|
|
|
my_gcry_outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
|
|
|
|
|
{
|
|
|
|
|
static int been_here; /* Used to protect against recursive calls. */
|
|
|
|
|
|
2008-10-17 19:18:46 +00:00
|
|
|
|
(void)opaque;
|
|
|
|
|
|
2007-04-20 16:59:37 +00:00
|
|
|
|
if (!been_here)
|
|
|
|
|
{
|
|
|
|
|
been_here = 1;
|
|
|
|
|
if ( (flags & 1) )
|
|
|
|
|
log_fatal (_("out of core in secure memory "
|
|
|
|
|
"while allocating %lu bytes"), (unsigned long)req_n);
|
|
|
|
|
else
|
|
|
|
|
log_fatal (_("out of core while allocating %lu bytes"),
|
|
|
|
|
(unsigned long)req_n);
|
|
|
|
|
}
|
|
|
|
|
return 0; /* Let libgcrypt call its own fatal error handler.
|
|
|
|
|
Actually this will turn out to be
|
|
|
|
|
my_gcry_fatalerror_handler. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Setup libgcrypt to use our own logging functions. Should be used
|
|
|
|
|
early at startup. */
|
|
|
|
|
void
|
|
|
|
|
setup_libgcrypt_logging (void)
|
|
|
|
|
{
|
|
|
|
|
gcry_set_log_handler (my_gcry_logger, NULL);
|
|
|
|
|
gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
|
|
|
|
|
gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-17 12:59:29 +02:00
|
|
|
|
|
2016-04-25 17:26:57 +02:00
|
|
|
|
/* Print an out of core message and let the process die. The printed
|
|
|
|
|
* error is taken from ERRNO. */
|
|
|
|
|
void
|
|
|
|
|
xoutofcore (void)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = gpg_error_from_syserror ();
|
|
|
|
|
log_fatal (_("error allocating enough memory: %s\n"), gpg_strerror (err));
|
|
|
|
|
abort (); /* Never called; just to make the compiler happy. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-03-04 13:55:53 +01:00
|
|
|
|
/* Wrapper around gpgrt_reallocarray. */
|
|
|
|
|
void *
|
|
|
|
|
xreallocarray (void *a, size_t oldnmemb, size_t nmemb, size_t size)
|
|
|
|
|
{
|
|
|
|
|
void *p = gpgrt_reallocarray (a, oldnmemb, nmemb, size);
|
|
|
|
|
if (!p)
|
|
|
|
|
xoutofcore ();
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-12-02 15:49:02 +00:00
|
|
|
|
/* A wrapper around gcry_cipher_algo_name to return the string
|
|
|
|
|
"AES-128" instead of "AES". Given that we have an alias in
|
|
|
|
|
libgcrypt for it, it does not harm to too much to return this other
|
|
|
|
|
string. Some users complained that we print "AES" but "AES192"
|
|
|
|
|
and "AES256". We can't fix that in libgcrypt but it is pretty
|
|
|
|
|
safe to do it in an application. */
|
|
|
|
|
const char *
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gnupg_cipher_algo_name (int algo)
|
2010-12-02 15:49:02 +00:00
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
s = gcry_cipher_algo_name (algo);
|
|
|
|
|
if (!strcmp (s, "AES"))
|
|
|
|
|
s = "AES128";
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2015-06-17 12:59:29 +02:00
|
|
|
|
void
|
|
|
|
|
obsolete_option (const char *configname, unsigned int configlineno,
|
|
|
|
|
const char *name)
|
|
|
|
|
{
|
|
|
|
|
if (configname)
|
|
|
|
|
log_info (_("%s:%u: obsolete option \"%s\" - it has no effect\n"),
|
|
|
|
|
configname, configlineno, name);
|
|
|
|
|
else
|
|
|
|
|
log_info (_("WARNING: \"%s%s\" is an obsolete option - it has no effect\n"),
|
|
|
|
|
"--", name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
/* Decide whether the filename is stdout or a real filename and return
|
|
|
|
|
* an appropriate string. */
|
|
|
|
|
const char *
|
|
|
|
|
print_fname_stdout (const char *s)
|
|
|
|
|
{
|
|
|
|
|
if( !s || (*s == '-' && !s[1]) )
|
|
|
|
|
return "[stdout]";
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Decide whether the filename is stdin or a real filename and return
|
|
|
|
|
* an appropriate string. */
|
|
|
|
|
const char *
|
|
|
|
|
print_fname_stdin (const char *s)
|
|
|
|
|
{
|
|
|
|
|
if( !s || (*s == '-' && !s[1]) )
|
|
|
|
|
return "[stdin]";
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-08-26 17:47:22 +02:00
|
|
|
|
static int
|
|
|
|
|
do_print_utf8_buffer (estream_t stream,
|
|
|
|
|
const void *buffer, size_t length,
|
|
|
|
|
const char *delimiters, size_t *bytes_written)
|
|
|
|
|
{
|
|
|
|
|
const char *p = buffer;
|
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
|
|
/* We can handle plain ascii simpler, so check for it first. */
|
|
|
|
|
for (i=0; i < length; i++ )
|
|
|
|
|
{
|
|
|
|
|
if ( (p[i] & 0x80) )
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (i < length)
|
|
|
|
|
{
|
|
|
|
|
int delim = delimiters? *delimiters : 0;
|
|
|
|
|
char *buf;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/*(utf8 conversion already does the control character quoting). */
|
|
|
|
|
buf = utf8_to_native (p, length, delim);
|
|
|
|
|
if (bytes_written)
|
|
|
|
|
*bytes_written = strlen (buf);
|
|
|
|
|
ret = es_fputs (buf, stream);
|
|
|
|
|
xfree (buf);
|
|
|
|
|
return ret == EOF? ret : (int)i;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return es_write_sanitized (stream, p, length, delimiters, bytes_written);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
print_utf8_buffer3 (estream_t stream, const void *p, size_t n,
|
|
|
|
|
const char *delim)
|
|
|
|
|
{
|
|
|
|
|
do_print_utf8_buffer (stream, p, n, delim, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void
|
2010-03-15 11:15:45 +00:00
|
|
|
|
print_utf8_buffer2 (estream_t stream, const void *p, size_t n, int delim)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2010-03-15 11:15:45 +00:00
|
|
|
|
char tmp[2];
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-03-15 11:15:45 +00:00
|
|
|
|
tmp[0] = delim;
|
|
|
|
|
tmp[1] = 0;
|
2014-08-26 17:47:22 +02:00
|
|
|
|
do_print_utf8_buffer (stream, p, n, tmp, NULL);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-03-15 11:15:45 +00:00
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void
|
2010-03-15 11:15:45 +00:00
|
|
|
|
print_utf8_buffer (estream_t stream, const void *p, size_t n)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2014-08-26 17:47:22 +02:00
|
|
|
|
do_print_utf8_buffer (stream, p, n, NULL, NULL);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-20 17:20:17 +02:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
print_utf8_string (estream_t stream, const char *p)
|
|
|
|
|
{
|
|
|
|
|
if (!p)
|
|
|
|
|
p = "";
|
|
|
|
|
do_print_utf8_buffer (stream, p, strlen (p), NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2007-03-19 15:44:59 +00:00
|
|
|
|
/* Write LENGTH bytes of BUFFER to FP as a hex encoded string.
|
|
|
|
|
RESERVED must be 0. */
|
|
|
|
|
void
|
|
|
|
|
print_hexstring (FILE *fp, const void *buffer, size_t length, int reserved)
|
|
|
|
|
{
|
|
|
|
|
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
|
|
|
|
|
const unsigned char *s;
|
|
|
|
|
|
2008-10-17 19:18:46 +00:00
|
|
|
|
(void)reserved;
|
|
|
|
|
|
2007-03-19 15:44:59 +00:00
|
|
|
|
for (s = buffer; length; s++, length--)
|
|
|
|
|
{
|
|
|
|
|
putc ( tohex ((*s>>4)&15), fp);
|
|
|
|
|
putc ( tohex (*s&15), fp);
|
|
|
|
|
}
|
|
|
|
|
#undef tohex
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 19:04:43 +02:00
|
|
|
|
|
|
|
|
|
/* Create a string from the buffer P_ARG of length N which is suitable
|
|
|
|
|
* for printing. Caller must release the created string using xfree.
|
|
|
|
|
* On error ERRNO is set and NULL returned. Errors are only possible
|
|
|
|
|
* due to malloc failure. */
|
2003-08-05 17:11:04 +00:00
|
|
|
|
char *
|
2016-08-10 19:04:43 +02:00
|
|
|
|
try_make_printable_string (const void *p_arg, size_t n, int delim)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2016-08-10 19:04:43 +02:00
|
|
|
|
const unsigned char *p = p_arg;
|
|
|
|
|
size_t save_n, buflen;
|
|
|
|
|
const unsigned char *save_p;
|
|
|
|
|
char *buffer, *d;
|
|
|
|
|
|
|
|
|
|
/* First count length. */
|
|
|
|
|
for (save_n = n, save_p = p, buflen=1 ; n; n--, p++ )
|
|
|
|
|
{
|
|
|
|
|
if ( *p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\'))
|
|
|
|
|
{
|
|
|
|
|
if ( *p=='\n' || *p=='\r' || *p=='\f'
|
|
|
|
|
|| *p=='\v' || *p=='\b' || !*p )
|
|
|
|
|
buflen += 2;
|
|
|
|
|
else
|
|
|
|
|
buflen += 5;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
buflen++;
|
|
|
|
|
}
|
|
|
|
|
p = save_p;
|
|
|
|
|
n = save_n;
|
|
|
|
|
/* And now make the string */
|
|
|
|
|
d = buffer = xtrymalloc (buflen);
|
|
|
|
|
for ( ; n; n--, p++ )
|
|
|
|
|
{
|
|
|
|
|
if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
|
|
|
|
|
*d++ = '\\';
|
|
|
|
|
if( *p == '\n' )
|
|
|
|
|
*d++ = 'n';
|
|
|
|
|
else if( *p == '\r' )
|
|
|
|
|
*d++ = 'r';
|
|
|
|
|
else if( *p == '\f' )
|
|
|
|
|
*d++ = 'f';
|
|
|
|
|
else if( *p == '\v' )
|
|
|
|
|
*d++ = 'v';
|
|
|
|
|
else if( *p == '\b' )
|
|
|
|
|
*d++ = 'b';
|
|
|
|
|
else if( !*p )
|
|
|
|
|
*d++ = '0';
|
|
|
|
|
else {
|
|
|
|
|
sprintf(d, "x%02x", *p );
|
|
|
|
|
d += 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*d++ = *p;
|
|
|
|
|
}
|
|
|
|
|
*d = 0;
|
|
|
|
|
return buffer;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-08-10 19:04:43 +02:00
|
|
|
|
/* Same as try_make_printable_string but terminates the process on
|
|
|
|
|
* memory shortage. */
|
|
|
|
|
char *
|
|
|
|
|
make_printable_string (const void *p, size_t n, int delim )
|
|
|
|
|
{
|
|
|
|
|
char *string = try_make_printable_string (p, n, delim);
|
|
|
|
|
if (!string)
|
|
|
|
|
xoutofcore ();
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-19 14:35:04 +00:00
|
|
|
|
|
2019-01-30 08:28:56 +01:00
|
|
|
|
/* Decode the C formatted string SRC and return the result in a newly
|
|
|
|
|
* allocated buffer. In error returns NULL and sets ERRNO. */
|
|
|
|
|
char *
|
|
|
|
|
decode_c_string (const char *src)
|
|
|
|
|
{
|
|
|
|
|
char *buffer, *dst;
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
/* The converted string will never be larger than the original
|
|
|
|
|
string. */
|
|
|
|
|
buffer = dst = xtrymalloc (strlen (src) + 1);
|
|
|
|
|
if (!buffer)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
while (*src)
|
|
|
|
|
{
|
|
|
|
|
if (*src != '\\')
|
|
|
|
|
{
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define DECODE_ONE(_m,_r) case _m: src += 2; *dst++ = _r; break;
|
|
|
|
|
|
|
|
|
|
switch (src[1])
|
|
|
|
|
{
|
|
|
|
|
DECODE_ONE ('n', '\n');
|
|
|
|
|
DECODE_ONE ('r', '\r');
|
|
|
|
|
DECODE_ONE ('f', '\f');
|
|
|
|
|
DECODE_ONE ('v', '\v');
|
|
|
|
|
DECODE_ONE ('b', '\b');
|
|
|
|
|
DECODE_ONE ('t', '\t');
|
|
|
|
|
DECODE_ONE ('\\', '\\');
|
|
|
|
|
DECODE_ONE ('\'', '\'');
|
|
|
|
|
DECODE_ONE ('\"', '\"');
|
|
|
|
|
|
|
|
|
|
case 'x':
|
|
|
|
|
val = hextobyte (src+2);
|
|
|
|
|
if (val == -1) /* Bad coding, keep as is. */
|
|
|
|
|
{
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
if (*src)
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
if (*src)
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
}
|
|
|
|
|
else if (!val)
|
|
|
|
|
{
|
|
|
|
|
/* A binary zero is not representable in a C string thus
|
|
|
|
|
* we keep the C-escaping. Note that this will also
|
|
|
|
|
* never be larger than the source string. */
|
|
|
|
|
*dst++ = '\\';
|
|
|
|
|
*dst++ = '0';
|
|
|
|
|
src += 4;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*(unsigned char *)dst++ = val;
|
|
|
|
|
src += 4;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default: /* Bad coding; keep as is.. */
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
*dst++ = *src++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#undef DECODE_ONE
|
|
|
|
|
}
|
|
|
|
|
*dst++ = 0;
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-03-24 11:51:44 +01:00
|
|
|
|
/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
|
|
|
|
|
* packet. LEN should be at least 6. */
|
|
|
|
|
static int
|
|
|
|
|
is_openpgp_compressed_packet (unsigned char *buf, size_t len)
|
|
|
|
|
{
|
|
|
|
|
int c, ctb, pkttype;
|
|
|
|
|
int lenbytes;
|
|
|
|
|
|
|
|
|
|
ctb = *buf++; len--;
|
|
|
|
|
if (!(ctb & 0x80))
|
|
|
|
|
return 0; /* Invalid packet. */
|
|
|
|
|
|
|
|
|
|
if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
|
|
|
|
|
{
|
|
|
|
|
pkttype = (ctb & 0x3f);
|
|
|
|
|
if (!len)
|
|
|
|
|
return 0; /* Expected first length octet missing. */
|
|
|
|
|
c = *buf++; len--;
|
|
|
|
|
if (c < 192)
|
|
|
|
|
;
|
|
|
|
|
else if (c < 224)
|
|
|
|
|
{
|
|
|
|
|
if (!len)
|
|
|
|
|
return 0; /* Expected second length octet missing. */
|
|
|
|
|
}
|
|
|
|
|
else if (c == 255)
|
|
|
|
|
{
|
|
|
|
|
if (len < 4)
|
|
|
|
|
return 0; /* Expected length octets missing */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else /* Old style CTB. */
|
|
|
|
|
{
|
|
|
|
|
pkttype = (ctb>>2)&0xf;
|
|
|
|
|
lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
|
|
|
|
|
if (len < lenbytes)
|
|
|
|
|
return 0; /* Not enough length bytes. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (pkttype == 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
/*
|
|
|
|
|
* Check if the file is compressed.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
is_file_compressed (const char *s, int *ret_rc)
|
|
|
|
|
{
|
|
|
|
|
iobuf_t a;
|
2017-03-24 11:51:44 +01:00
|
|
|
|
byte buf[6];
|
|
|
|
|
int i;
|
|
|
|
|
int rc = 0;
|
2006-04-21 12:56:40 +00:00
|
|
|
|
int overflow;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
|
|
|
|
struct magic_compress_s {
|
|
|
|
|
size_t len;
|
|
|
|
|
byte magic[4];
|
|
|
|
|
} magic[] = {
|
|
|
|
|
{ 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
|
|
|
|
|
{ 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
|
|
|
|
|
{ 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
|
|
|
|
|
};
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2006-04-21 12:56:40 +00:00
|
|
|
|
if ( iobuf_is_pipe_filename (s) || !ret_rc )
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return 0; /* We can't check stdin or no file was given */
|
|
|
|
|
|
|
|
|
|
a = iobuf_open( s );
|
|
|
|
|
if ( a == NULL ) {
|
2006-09-14 16:50:33 +00:00
|
|
|
|
*ret_rc = gpg_error_from_syserror ();
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2018-05-02 19:03:07 +02:00
|
|
|
|
iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2017-03-24 11:51:44 +01:00
|
|
|
|
if ( iobuf_get_filelength( a, &overflow ) < 6 && !overflow) {
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*ret_rc = 0;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 11:51:44 +01:00
|
|
|
|
if ( iobuf_read( a, buf, 6 ) == -1 ) {
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*ret_rc = a->error;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( i = 0; i < DIM( magic ); i++ ) {
|
|
|
|
|
if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) {
|
|
|
|
|
*ret_rc = 0;
|
|
|
|
|
rc = 1;
|
2017-03-24 11:51:44 +01:00
|
|
|
|
goto leave;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 11:51:44 +01:00
|
|
|
|
if (is_openpgp_compressed_packet (buf, 6))
|
|
|
|
|
{
|
|
|
|
|
*ret_rc = 0;
|
|
|
|
|
rc = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
leave:
|
2003-08-05 17:11:04 +00:00
|
|
|
|
iobuf_close( a );
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-05-23 16:19:43 +00:00
|
|
|
|
/* Try match against each substring of multistr, delimited by | */
|
|
|
|
|
int
|
|
|
|
|
match_multistr (const char *multistr,const char *match)
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
size_t seglen = strcspn (multistr,"|");
|
|
|
|
|
if (!seglen)
|
|
|
|
|
break;
|
|
|
|
|
/* Using the localized strncasecmp! */
|
|
|
|
|
if (strncasecmp(multistr,match,seglen)==0)
|
|
|
|
|
return 1;
|
|
|
|
|
multistr += seglen;
|
|
|
|
|
if (*multistr == '|')
|
|
|
|
|
multistr++;
|
|
|
|
|
}
|
|
|
|
|
while (*multistr);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2010-10-13 15:57:08 +00:00
|
|
|
|
|
|
|
|
|
/* Parse the first portion of the version number S and store it at
|
|
|
|
|
NUMBER. On success, the function returns a pointer into S starting
|
|
|
|
|
with the first character, which is not part of the initial number
|
|
|
|
|
portion; on failure, NULL is returned. */
|
|
|
|
|
static const char*
|
|
|
|
|
parse_version_number (const char *s, int *number)
|
|
|
|
|
{
|
|
|
|
|
int val = 0;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2010-10-13 15:57:08 +00:00
|
|
|
|
if (*s == '0' && digitp (s+1))
|
|
|
|
|
return NULL; /* Leading zeros are not allowed. */
|
|
|
|
|
for (; digitp (s); s++ )
|
|
|
|
|
{
|
|
|
|
|
val *= 10;
|
|
|
|
|
val += *s - '0';
|
|
|
|
|
}
|
|
|
|
|
*number = val;
|
|
|
|
|
return val < 0? NULL : s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Break up the complete string representation of the version number S,
|
|
|
|
|
which is expected to have this format:
|
|
|
|
|
|
|
|
|
|
<major number>.<minor number>.<micro number><patch level>.
|
|
|
|
|
|
|
|
|
|
The major, minor and micro number components will be stored at
|
|
|
|
|
MAJOR, MINOR and MICRO. On success, a pointer to the last
|
|
|
|
|
component, the patch level, will be returned; on failure, NULL will
|
|
|
|
|
be returned. */
|
|
|
|
|
static const char *
|
|
|
|
|
parse_version_string (const char *s, int *major, int *minor, int *micro)
|
|
|
|
|
{
|
|
|
|
|
s = parse_version_number (s, major);
|
|
|
|
|
if (!s || *s != '.')
|
|
|
|
|
return NULL;
|
|
|
|
|
s++;
|
|
|
|
|
s = parse_version_number (s, minor);
|
|
|
|
|
if (!s || *s != '.')
|
|
|
|
|
return NULL;
|
|
|
|
|
s++;
|
|
|
|
|
s = parse_version_number (s, micro);
|
|
|
|
|
if (!s)
|
|
|
|
|
return NULL;
|
|
|
|
|
return s; /* Patchlevel. */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return true if version string is at least version B. */
|
|
|
|
|
int
|
|
|
|
|
gnupg_compare_version (const char *a, const char *b)
|
|
|
|
|
{
|
|
|
|
|
int a_major, a_minor, a_micro;
|
|
|
|
|
int b_major, b_minor, b_micro;
|
|
|
|
|
const char *a_plvl, *b_plvl;
|
|
|
|
|
|
|
|
|
|
if (!a || !b)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Parse version A. */
|
|
|
|
|
a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
|
|
|
|
|
if (!a_plvl )
|
|
|
|
|
return 0; /* Invalid version number. */
|
|
|
|
|
|
|
|
|
|
/* Parse version B. */
|
|
|
|
|
b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
|
|
|
|
|
if (!b_plvl )
|
|
|
|
|
return 0; /* Invalid version number. */
|
|
|
|
|
|
|
|
|
|
/* Compare version numbers. */
|
|
|
|
|
return (a_major > b_major
|
|
|
|
|
|| (a_major == b_major && a_minor > b_minor)
|
|
|
|
|
|| (a_major == b_major && a_minor == b_minor
|
|
|
|
|
&& a_micro > b_micro)
|
|
|
|
|
|| (a_major == b_major && a_minor == b_minor
|
|
|
|
|
&& a_micro == b_micro
|
|
|
|
|
&& strcmp (a_plvl, b_plvl) >= 0));
|
|
|
|
|
}
|
2015-06-22 20:54:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Parse an --debug style argument. We allow the use of number values
|
|
|
|
|
* in the usual C notation or a string with comma separated keywords.
|
|
|
|
|
*
|
|
|
|
|
* Returns: 0 on success or -1 and ERRNO set on error. On success the
|
|
|
|
|
* supplied variable is updated by the parsed flags.
|
|
|
|
|
*
|
|
|
|
|
* If STRING is NULL the enabled debug flags are printed.
|
2016-12-19 09:41:15 +01:00
|
|
|
|
*
|
|
|
|
|
* See doc/DETAILS for a summary of used debug options.
|
2015-06-22 20:54:23 +02:00
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
parse_debug_flag (const char *string, unsigned int *debugvar,
|
|
|
|
|
const struct debug_flags_s *flags)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
unsigned long result = 0;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
if (!string)
|
|
|
|
|
{
|
|
|
|
|
if (debugvar)
|
|
|
|
|
{
|
|
|
|
|
log_info ("enabled debug flags:");
|
|
|
|
|
for (i=0; flags[i].name; i++)
|
|
|
|
|
if ((*debugvar & flags[i].flag))
|
|
|
|
|
log_printf (" %s", flags[i].name);
|
|
|
|
|
log_printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (spacep (string))
|
|
|
|
|
string++;
|
|
|
|
|
if (*string == '-')
|
|
|
|
|
{
|
|
|
|
|
errno = EINVAL;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!strcmp (string, "?") || !strcmp (string, "help"))
|
|
|
|
|
{
|
|
|
|
|
log_info ("available debug flags:\n");
|
|
|
|
|
for (i=0; flags[i].name; i++)
|
|
|
|
|
log_info (" %5u %s\n", flags[i].flag, flags[i].name);
|
2015-06-23 09:10:56 +02:00
|
|
|
|
if (flags[i].flag != 77)
|
|
|
|
|
exit (0);
|
2015-06-22 20:54:23 +02:00
|
|
|
|
}
|
|
|
|
|
else if (digitp (string))
|
|
|
|
|
{
|
|
|
|
|
errno = 0;
|
|
|
|
|
result = strtoul (string, NULL, 0);
|
|
|
|
|
if (result == ULONG_MAX && errno == ERANGE)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char **words;
|
|
|
|
|
words = strtokenize (string, ",");
|
|
|
|
|
if (!words)
|
|
|
|
|
return -1;
|
|
|
|
|
for (i=0; words[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (*words[i])
|
|
|
|
|
{
|
|
|
|
|
for (j=0; flags[j].name; j++)
|
|
|
|
|
if (!strcmp (words[i], flags[j].name))
|
|
|
|
|
{
|
|
|
|
|
result |= flags[j].flag;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!flags[j].name)
|
2015-06-23 09:10:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (!strcmp (words[i], "none"))
|
|
|
|
|
{
|
|
|
|
|
*debugvar = 0;
|
|
|
|
|
result = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (words[i], "all"))
|
|
|
|
|
result = ~0;
|
|
|
|
|
else
|
|
|
|
|
log_info (_("unknown debug flag '%s' ignored\n"), words[i]);
|
|
|
|
|
}
|
2015-06-22 20:54:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
xfree (words);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*debugvar |= result;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-06-13 17:35:05 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Parse an --comaptibility_flags style argument consisting of comma
|
|
|
|
|
* separated strings.
|
|
|
|
|
*
|
|
|
|
|
* Returns: 0 on success or -1 and ERRNO set on error. On success the
|
|
|
|
|
* supplied variable is updated by the parsed flags.
|
|
|
|
|
*
|
|
|
|
|
* If STRING is NULL the enabled flags are printed.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
parse_compatibility_flags (const char *string, unsigned int *flagvar,
|
|
|
|
|
const struct compatibility_flags_s *flags)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
unsigned long result = 0;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
if (!string)
|
|
|
|
|
{
|
|
|
|
|
if (flagvar)
|
|
|
|
|
{
|
|
|
|
|
log_info ("enabled compatibility flags:");
|
|
|
|
|
for (i=0; flags[i].name; i++)
|
|
|
|
|
if ((*flagvar & flags[i].flag))
|
|
|
|
|
log_printf (" %s", flags[i].name);
|
|
|
|
|
log_printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (spacep (string))
|
|
|
|
|
string++;
|
|
|
|
|
|
|
|
|
|
if (!strcmp (string, "?") || !strcmp (string, "help"))
|
|
|
|
|
{
|
|
|
|
|
log_info ("available compatibility flags:\n");
|
|
|
|
|
for (i=0; flags[i].name; i++)
|
|
|
|
|
log_info (" %s\n", flags[i].name);
|
|
|
|
|
if (flags[i].flag != 77)
|
|
|
|
|
exit (0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char **words;
|
|
|
|
|
words = strtokenize (string, ",");
|
|
|
|
|
if (!words)
|
|
|
|
|
return -1;
|
|
|
|
|
for (i=0; words[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
if (*words[i])
|
|
|
|
|
{
|
|
|
|
|
for (j=0; flags[j].name; j++)
|
|
|
|
|
if (!strcmp (words[i], flags[j].name))
|
|
|
|
|
{
|
|
|
|
|
result |= flags[j].flag;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!flags[j].name)
|
|
|
|
|
{
|
|
|
|
|
if (!strcmp (words[i], "none"))
|
|
|
|
|
{
|
|
|
|
|
*flagvar = 0;
|
|
|
|
|
result = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (words[i], "all"))
|
|
|
|
|
result = ~0;
|
|
|
|
|
else
|
|
|
|
|
log_info ("unknown compatibility flag '%s' ignored\n",
|
|
|
|
|
words[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
xfree (words);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*flagvar |= result;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|