|
Packit |
d7e8d0 |
/* conversion.c - String conversion helper functions.
|
|
Packit Service |
30b792 |
* Copyright (C) 2000 Werner Koch (dd9jn)
|
|
Packit Service |
30b792 |
* Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
|
|
Packit Service |
30b792 |
*
|
|
Packit Service |
30b792 |
* This file is part of GPGME.
|
|
Packit Service |
30b792 |
*
|
|
Packit Service |
30b792 |
* GPGME is free software; you can redistribute it and/or modify it
|
|
Packit Service |
30b792 |
* under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
30b792 |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
30b792 |
* the License, or (at your option) any later version.
|
|
Packit Service |
30b792 |
*
|
|
Packit Service |
30b792 |
* GPGME is distributed in the hope that it will be useful, but
|
|
Packit Service |
30b792 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
30b792 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
30b792 |
* Lesser General Public License for more details.
|
|
Packit Service |
30b792 |
*
|
|
Packit Service |
30b792 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
30b792 |
* License along with this program; if not, see <https://gnu.org/licenses/>.
|
|
Packit Service |
30b792 |
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
Packit Service |
30b792 |
*/
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
#if HAVE_CONFIG_H
|
|
Packit |
d7e8d0 |
#include <config.h>
|
|
Packit |
d7e8d0 |
#endif
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
#include <stdlib.h>
|
|
Packit |
d7e8d0 |
#include <string.h>
|
|
Packit |
d7e8d0 |
#ifdef HAVE_SYS_TYPES_H
|
|
Packit |
d7e8d0 |
/* Solaris 8 needs sys/types.h before time.h. */
|
|
Packit |
d7e8d0 |
# include <sys/types.h>
|
|
Packit |
d7e8d0 |
#endif
|
|
Packit |
d7e8d0 |
#include <time.h>
|
|
Packit |
d7e8d0 |
#include <errno.h>
|
|
Packit |
d7e8d0 |
#include <stdarg.h>
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
#include "gpgme.h"
|
|
Packit |
d7e8d0 |
#include "util.h"
|
|
Packit |
d7e8d0 |
#include "debug.h"
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
#define atoi_1(p) (*(p) - '0' )
|
|
Packit |
d7e8d0 |
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
|
|
Packit |
d7e8d0 |
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
static char *
|
|
Packit |
d7e8d0 |
do_strconcat (const char *s1, va_list arg_ptr)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
const char *argv[16];
|
|
Packit |
d7e8d0 |
size_t argc;
|
|
Packit |
d7e8d0 |
size_t needed;
|
|
Packit |
d7e8d0 |
char *buffer, *p;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
argc = 0;
|
|
Packit |
d7e8d0 |
argv[argc++] = s1;
|
|
Packit |
d7e8d0 |
needed = strlen (s1);
|
|
Packit |
d7e8d0 |
while (((argv[argc] = va_arg (arg_ptr, const char *))))
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
needed += strlen (argv[argc]);
|
|
Packit |
d7e8d0 |
if (argc >= DIM (argv)-1)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
gpg_err_set_errno (EINVAL);
|
|
Packit |
d7e8d0 |
return NULL;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
argc++;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
needed++;
|
|
Packit |
d7e8d0 |
buffer = malloc (needed);
|
|
Packit |
d7e8d0 |
if (buffer)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
for (p = buffer, argc=0; argv[argc]; argc++)
|
|
Packit |
d7e8d0 |
p = stpcpy (p, argv[argc]);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
return buffer;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Concatenate the string S1 with all the following strings up to a
|
|
Packit |
d7e8d0 |
* NULL. Returns a malloced buffer with the new string or NULL on a
|
|
Packit |
d7e8d0 |
malloc error or if too many arguments are given. */
|
|
Packit |
d7e8d0 |
char *
|
|
Packit |
d7e8d0 |
_gpgme_strconcat (const char *s1, ...)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
va_list arg_ptr;
|
|
Packit |
d7e8d0 |
char *result;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
if (!s1)
|
|
Packit |
d7e8d0 |
result = strdup ("");
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
va_start (arg_ptr, s1);
|
|
Packit |
d7e8d0 |
result = do_strconcat (s1, arg_ptr);
|
|
Packit |
d7e8d0 |
va_end (arg_ptr);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
return result;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Convert two hexadecimal digits from STR to the value they
|
|
Packit |
d7e8d0 |
represent. Returns -1 if one of the characters is not a
|
|
Packit |
d7e8d0 |
hexadecimal digit. */
|
|
Packit |
d7e8d0 |
int
|
|
Packit |
d7e8d0 |
_gpgme_hextobyte (const char *str)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
int val = 0;
|
|
Packit |
d7e8d0 |
int i;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
#define NROFHEXDIGITS 2
|
|
Packit |
d7e8d0 |
for (i = 0; i < NROFHEXDIGITS; i++)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (*str >= '0' && *str <= '9')
|
|
Packit |
d7e8d0 |
val += *str - '0';
|
|
Packit |
d7e8d0 |
else if (*str >= 'A' && *str <= 'F')
|
|
Packit |
d7e8d0 |
val += 10 + *str - 'A';
|
|
Packit |
d7e8d0 |
else if (*str >= 'a' && *str <= 'f')
|
|
Packit |
d7e8d0 |
val += 10 + *str - 'a';
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
return -1;
|
|
Packit |
d7e8d0 |
if (i < NROFHEXDIGITS - 1)
|
|
Packit |
d7e8d0 |
val *= 16;
|
|
Packit |
d7e8d0 |
str++;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
return val;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Decode the C formatted string SRC and store the result in the
|
|
Packit |
d7e8d0 |
buffer *DESTP which is LEN bytes long. If LEN is zero, then a
|
|
Packit |
d7e8d0 |
large enough buffer is allocated with malloc and *DESTP is set to
|
|
Packit |
d7e8d0 |
the result. Currently, LEN is only used to specify if allocation
|
|
Packit |
d7e8d0 |
is desired or not, the caller is expected to make sure that *DESTP
|
|
Packit |
d7e8d0 |
is large enough if LEN is not zero. */
|
|
Packit |
d7e8d0 |
gpgme_error_t
|
|
Packit |
d7e8d0 |
_gpgme_decode_c_string (const char *src, char **destp, size_t len)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
char *dest;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Set up the destination buffer. */
|
|
Packit |
d7e8d0 |
if (len)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (len < strlen (src) + 1)
|
|
Packit |
d7e8d0 |
return gpg_error (GPG_ERR_INTERNAL);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
dest = *destp;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* The converted string will never be larger than the original
|
|
Packit |
d7e8d0 |
string. */
|
|
Packit |
d7e8d0 |
dest = malloc (strlen (src) + 1);
|
|
Packit |
d7e8d0 |
if (!dest)
|
|
Packit |
d7e8d0 |
return gpg_error_from_syserror ();
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
*destp = dest;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Convert the string. */
|
|
Packit |
d7e8d0 |
while (*src)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (*src != '\\')
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
continue;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
switch (src[1])
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
#define DECODE_ONE(match,result) \
|
|
Packit |
d7e8d0 |
case match: \
|
|
Packit |
d7e8d0 |
src += 2; \
|
|
Packit |
d7e8d0 |
*(dest++) = result; \
|
|
Packit |
d7e8d0 |
break;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
DECODE_ONE ('\'', '\'');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('\"', '\"');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('\?', '\?');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('\\', '\\');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('a', '\a');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('b', '\b');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('f', '\f');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('n', '\n');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('r', '\r');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('t', '\t');
|
|
Packit |
d7e8d0 |
DECODE_ONE ('v', '\v');
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
case 'x':
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
int val = _gpgme_hextobyte (&src[2]);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
if (val == -1)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* Should not happen. */
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
if (*src)
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
if (*src)
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (!val)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* A binary zero is not representable in a C
|
|
Packit |
d7e8d0 |
string. */
|
|
Packit |
d7e8d0 |
*(dest++) = '\\';
|
|
Packit |
d7e8d0 |
*(dest++) = '0';
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
*((unsigned char *) dest++) = val;
|
|
Packit |
d7e8d0 |
src += 4;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
break;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
default:
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* Should not happen. */
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
*(dest++) = 0;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
return 0;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Decode the percent escaped string SRC and store the result in the
|
|
Packit |
d7e8d0 |
buffer *DESTP which is LEN bytes long. If LEN is zero, then a
|
|
Packit |
d7e8d0 |
large enough buffer is allocated with malloc and *DESTP is set to
|
|
Packit |
d7e8d0 |
the result. Currently, LEN is only used to specify if allocation
|
|
Packit |
d7e8d0 |
is desired or not, the caller is expected to make sure that *DESTP
|
|
Packit |
d7e8d0 |
is large enough if LEN is not zero. If BINARY is 1, then '\0'
|
|
Packit |
d7e8d0 |
characters are allowed in the output. */
|
|
Packit |
d7e8d0 |
gpgme_error_t
|
|
Packit |
d7e8d0 |
_gpgme_decode_percent_string (const char *src, char **destp, size_t len,
|
|
Packit |
d7e8d0 |
int binary)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
char *dest;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Set up the destination buffer. */
|
|
Packit |
d7e8d0 |
if (len)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (len < strlen (src) + 1)
|
|
Packit |
d7e8d0 |
return gpg_error (GPG_ERR_INTERNAL);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
dest = *destp;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* The converted string will never be larger than the original
|
|
Packit |
d7e8d0 |
string. */
|
|
Packit |
d7e8d0 |
dest = malloc (strlen (src) + 1);
|
|
Packit |
d7e8d0 |
if (!dest)
|
|
Packit |
d7e8d0 |
return gpg_error_from_syserror ();
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
*destp = dest;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Convert the string. */
|
|
Packit |
d7e8d0 |
while (*src)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (*src != '%')
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
continue;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
int val = _gpgme_hextobyte (&src[1]);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
if (val == -1)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* Should not happen. */
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
if (*src)
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
if (*src)
|
|
Packit |
d7e8d0 |
*(dest++) = *(src++);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (!val && !binary)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* A binary zero is not representable in a C
|
|
Packit |
d7e8d0 |
string. */
|
|
Packit |
d7e8d0 |
*(dest++) = '\\';
|
|
Packit |
d7e8d0 |
*(dest++) = '0';
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
*((unsigned char *) dest++) = val;
|
|
Packit |
d7e8d0 |
src += 3;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
*(dest++) = 0;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
return 0;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Encode the string SRC with percent escaping and store the result in
|
|
Packit |
d7e8d0 |
the buffer *DESTP which is LEN bytes long. If LEN is zero, then a
|
|
Packit |
d7e8d0 |
large enough buffer is allocated with malloc and *DESTP is set to
|
|
Packit |
d7e8d0 |
the result. Currently, LEN is only used to specify if allocation
|
|
Packit |
d7e8d0 |
is desired or not, the caller is expected to make sure that *DESTP
|
|
Packit |
d7e8d0 |
is large enough if LEN is not zero. If BINARY is 1, then '\0'
|
|
Packit |
d7e8d0 |
characters are allowed in the output. */
|
|
Packit |
d7e8d0 |
gpgme_error_t
|
|
Packit |
d7e8d0 |
_gpgme_encode_percent_string (const char *src, char **destp, size_t len)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
size_t destlen;
|
|
Packit |
d7e8d0 |
char *dest;
|
|
Packit |
d7e8d0 |
const char *str;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
destlen = 0;
|
|
Packit |
d7e8d0 |
str = src;
|
|
Packit |
d7e8d0 |
/* We percent-escape the + character because the user might need a
|
|
Packit |
d7e8d0 |
"percent plus" escaped string (special gpg format). But we
|
|
Packit |
d7e8d0 |
percent-escape the space character, which works with and without
|
|
Packit |
d7e8d0 |
the special plus format. */
|
|
Packit |
d7e8d0 |
while (*str)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (*str == '+' || *str == '\"' || *str == '%'
|
|
Packit |
d7e8d0 |
|| *(const unsigned char *)str <= 0x20)
|
|
Packit |
d7e8d0 |
destlen += 3;
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
destlen++;
|
|
Packit |
d7e8d0 |
str++;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
/* Terminating nul byte. */
|
|
Packit |
d7e8d0 |
destlen++;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Set up the destination buffer. */
|
|
Packit |
d7e8d0 |
if (len)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (len < destlen)
|
|
Packit |
d7e8d0 |
return gpg_error (GPG_ERR_INTERNAL);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
dest = *destp;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* The converted string will never be larger than the original
|
|
Packit |
d7e8d0 |
string. */
|
|
Packit |
d7e8d0 |
dest = malloc (destlen);
|
|
Packit |
d7e8d0 |
if (!dest)
|
|
Packit |
d7e8d0 |
return gpg_error_from_syserror ();
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
*destp = dest;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Convert the string. */
|
|
Packit |
d7e8d0 |
while (*src)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (*src == '+' || *src == '\"' || *src == '%'
|
|
Packit |
d7e8d0 |
|| *(const unsigned char *)src <= 0x20)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
snprintf (dest, 4, "%%%02X", *(unsigned char *)src);
|
|
Packit |
d7e8d0 |
dest += 3;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
*(dest++) = *src;
|
|
Packit |
d7e8d0 |
src++;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
*(dest++) = 0;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
return 0;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Split a string into space delimited fields and remove leading and
|
|
Packit |
d7e8d0 |
* trailing spaces from each field. A pointer to each field is
|
|
Packit |
d7e8d0 |
* stored in ARRAY. Stop splitting at ARRAYSIZE fields. The function
|
|
Packit |
d7e8d0 |
* modifies STRING. The number of parsed fields is returned.
|
|
Packit |
d7e8d0 |
*/
|
|
Packit |
d7e8d0 |
int
|
|
Packit |
d7e8d0 |
_gpgme_split_fields (char *string, char **array, int arraysize)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
int n = 0;
|
|
Packit |
d7e8d0 |
char *p, *pend;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
for (p = string; *p == ' '; p++)
|
|
Packit |
d7e8d0 |
;
|
|
Packit |
d7e8d0 |
do
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (n == arraysize)
|
|
Packit |
d7e8d0 |
break;
|
|
Packit |
d7e8d0 |
array[n++] = p;
|
|
Packit |
d7e8d0 |
pend = strchr (p, ' ');
|
|
Packit |
d7e8d0 |
if (!pend)
|
|
Packit |
d7e8d0 |
break;
|
|
Packit |
d7e8d0 |
*pend++ = 0;
|
|
Packit |
d7e8d0 |
for (p = pend; *p == ' '; p++)
|
|
Packit |
d7e8d0 |
;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
while (*p);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
return n;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Convert the field STRING into an unsigned long value. Check for
|
|
Packit |
d7e8d0 |
* trailing garbage. */
|
|
Packit |
d7e8d0 |
gpgme_error_t
|
|
Packit |
d7e8d0 |
_gpgme_strtoul_field (const char *string, unsigned long *result)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
char *endp;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
gpg_err_set_errno (0);
|
|
Packit |
d7e8d0 |
*result = strtoul (string, &endp, 0);
|
|
Packit |
d7e8d0 |
if (errno)
|
|
Packit |
d7e8d0 |
return gpg_error_from_syserror ();
|
|
Packit |
d7e8d0 |
if (endp == string || *endp)
|
|
Packit |
d7e8d0 |
return gpg_error (GPG_ERR_INV_VALUE);
|
|
Packit |
d7e8d0 |
return 0;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Convert STRING into an offset value. Note that this functions only
|
|
Packit |
d7e8d0 |
* allows for a base-10 length. This function is similar to atoi()
|
|
Packit |
d7e8d0 |
* and thus there is no error checking. */
|
|
Packit |
d7e8d0 |
gpgme_off_t
|
|
Packit |
d7e8d0 |
_gpgme_string_to_off (const char *string)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
gpgme_off_t value = 0;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
while (*string == ' ' || *string == '\t')
|
|
Packit |
d7e8d0 |
string++;
|
|
Packit |
d7e8d0 |
for (; *string >= '0' && *string <= '9'; string++)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
value *= 10;
|
|
Packit |
d7e8d0 |
value += atoi_1 (string);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
return value;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
#ifdef HAVE_W32_SYSTEM
|
|
Packit |
d7e8d0 |
static time_t
|
|
Packit |
d7e8d0 |
_gpgme_timegm (struct tm *tm)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* This one is thread safe. */
|
|
Packit |
d7e8d0 |
SYSTEMTIME st;
|
|
Packit |
d7e8d0 |
FILETIME ft;
|
|
Packit |
d7e8d0 |
unsigned long long cnsecs;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
st.wYear = tm->tm_year + 1900;
|
|
Packit |
d7e8d0 |
st.wMonth = tm->tm_mon + 1;
|
|
Packit |
d7e8d0 |
st.wDay = tm->tm_mday;
|
|
Packit |
d7e8d0 |
st.wHour = tm->tm_hour;
|
|
Packit |
d7e8d0 |
st.wMinute = tm->tm_min;
|
|
Packit |
d7e8d0 |
st.wSecond = tm->tm_sec;
|
|
Packit |
d7e8d0 |
st.wMilliseconds = 0; /* Not available. */
|
|
Packit |
d7e8d0 |
st.wDayOfWeek = 0; /* Ignored. */
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* System time is UTC thus the conversion is pretty easy. */
|
|
Packit |
d7e8d0 |
if (!SystemTimeToFileTime (&st, &ft))
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
gpg_err_set_errno (EINVAL);
|
|
Packit |
d7e8d0 |
return (time_t)(-1);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
|
Packit |
d7e8d0 |
| ft.dwLowDateTime);
|
|
Packit |
d7e8d0 |
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
|
Packit |
d7e8d0 |
return (time_t)(cnsecs / 10000000ULL);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
#endif
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Parse the string TIMESTAMP into a time_t. The string may either be
|
|
Packit |
d7e8d0 |
seconds since Epoch or in the ISO 8601 format like
|
|
Packit |
d7e8d0 |
"20390815T143012". Returns 0 for an empty string or seconds since
|
|
Packit |
d7e8d0 |
Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
|
|
Packit |
d7e8d0 |
point to the next non-parsed character in TIMESTRING. */
|
|
Packit |
d7e8d0 |
time_t
|
|
Packit |
d7e8d0 |
_gpgme_parse_timestamp (const char *timestamp, char **endp)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
/* Need to skip leading spaces, because that is what strtoul does
|
|
Packit |
d7e8d0 |
but not our ISO 8601 checking code. */
|
|
Packit |
d7e8d0 |
while (*timestamp && *timestamp== ' ')
|
|
Packit |
d7e8d0 |
timestamp++;
|
|
Packit |
d7e8d0 |
if (!*timestamp)
|
|
Packit |
d7e8d0 |
return 0;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
struct tm buf;
|
|
Packit |
d7e8d0 |
int year;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
year = atoi_4 (timestamp);
|
|
Packit |
d7e8d0 |
if (year < 1900)
|
|
Packit |
d7e8d0 |
return (time_t)(-1);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
if (endp)
|
|
Packit |
d7e8d0 |
*endp = (char*)(timestamp + 15);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* Fixme: We would better use a configure test to see whether
|
|
Packit |
d7e8d0 |
mktime can handle dates beyond 2038. */
|
|
Packit |
d7e8d0 |
if (sizeof (time_t) <= 4 && year >= 2038)
|
|
Packit |
d7e8d0 |
return (time_t)2145914603; /* 2037-12-31 23:23:23 */
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
memset (&buf, 0, sizeof buf);
|
|
Packit |
d7e8d0 |
buf.tm_year = year - 1900;
|
|
Packit |
d7e8d0 |
buf.tm_mon = atoi_2 (timestamp+4) - 1;
|
|
Packit |
d7e8d0 |
buf.tm_mday = atoi_2 (timestamp+6);
|
|
Packit |
d7e8d0 |
buf.tm_hour = atoi_2 (timestamp+9);
|
|
Packit |
d7e8d0 |
buf.tm_min = atoi_2 (timestamp+11);
|
|
Packit |
d7e8d0 |
buf.tm_sec = atoi_2 (timestamp+13);
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
#ifdef HAVE_W32_SYSTEM
|
|
Packit |
d7e8d0 |
return _gpgme_timegm (&buf;;
|
|
Packit |
d7e8d0 |
#else
|
|
Packit |
d7e8d0 |
#ifdef HAVE_TIMEGM
|
|
Packit |
d7e8d0 |
return timegm (&buf;;
|
|
Packit |
d7e8d0 |
#else
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
time_t tim;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
putenv ("TZ=UTC");
|
|
Packit |
d7e8d0 |
tim = mktime (&buf;;
|
|
Packit |
d7e8d0 |
#ifdef __GNUC__
|
|
Packit |
d7e8d0 |
#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
|
|
Packit |
d7e8d0 |
#endif
|
|
Packit |
d7e8d0 |
return tim;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
#endif /* !HAVE_TIMEGM */
|
|
Packit |
d7e8d0 |
#endif /* !HAVE_W32_SYSTEM */
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
else
|
|
Packit |
d7e8d0 |
return (time_t)strtoul (timestamp, endp, 10);
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* This function is similar to _gpgme_parse_timestamp but returns an
|
|
Packit |
d7e8d0 |
* unsigned long and 0 on error. */
|
|
Packit |
d7e8d0 |
unsigned long
|
|
Packit |
d7e8d0 |
_gpgme_parse_timestamp_ul (const char *timestamp)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
time_t tim;
|
|
Packit |
d7e8d0 |
char *tail;
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
if (!*timestamp)
|
|
Packit |
d7e8d0 |
return 0; /* Shortcut empty strings. */
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
tim = _gpgme_parse_timestamp (timestamp, &tail);
|
|
Packit |
d7e8d0 |
if (tim == -1 || timestamp == tail || (*tail && *tail != ' '))
|
|
Packit |
d7e8d0 |
tim = 0; /* No time given or invalid engine. */
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
return (unsigned long)tim;
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
/* The GPG backend uses OpenPGP algorithm numbers which we need to map
|
|
Packit |
d7e8d0 |
to our algorithm numbers. This function MUST not change ERRNO. */
|
|
Packit |
d7e8d0 |
int
|
|
Packit |
d7e8d0 |
_gpgme_map_pk_algo (int algo, gpgme_protocol_t protocol)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
if (protocol == GPGME_PROTOCOL_OPENPGP)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
switch (algo)
|
|
Packit |
d7e8d0 |
{
|
|
Packit |
d7e8d0 |
case 1: case 2: case 3: case 16: case 17: break;
|
|
Packit |
d7e8d0 |
case 18: algo = GPGME_PK_ECDH; break;
|
|
Packit |
d7e8d0 |
case 19: algo = GPGME_PK_ECDSA; break;
|
|
Packit |
d7e8d0 |
case 20: break;
|
|
Packit |
d7e8d0 |
case 22: algo = GPGME_PK_EDDSA; break;
|
|
Packit |
d7e8d0 |
default: algo = 0; break; /* Unknown. */
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
}
|
|
Packit |
d7e8d0 |
|
|
Packit |
d7e8d0 |
return algo;
|
|
Packit |
d7e8d0 |
}
|
|
Packit Service |
30b792 |
|
|
Packit Service |
30b792 |
|
|
Packit Service |
30b792 |
/* Return a string with a cipher algorithm. */
|
|
Packit Service |
30b792 |
const char *
|
|
Packit Service |
30b792 |
_gpgme_cipher_algo_name (int algo, gpgme_protocol_t protocol)
|
|
Packit Service |
30b792 |
{
|
|
Packit Service |
30b792 |
if (protocol == GPGME_PROTOCOL_OPENPGP)
|
|
Packit Service |
30b792 |
{
|
|
Packit Service |
30b792 |
/* The algo is given according to OpenPGP specs. */
|
|
Packit Service |
30b792 |
switch (algo)
|
|
Packit Service |
30b792 |
{
|
|
Packit Service |
30b792 |
case 1: return "IDEA";
|
|
Packit Service |
30b792 |
case 2: return "3DES";
|
|
Packit Service |
30b792 |
case 3: return "CAST5";
|
|
Packit Service |
30b792 |
case 4: return "BLOWFISH";
|
|
Packit Service |
30b792 |
case 7: return "AES";
|
|
Packit Service |
30b792 |
case 8: return "AES192";
|
|
Packit Service |
30b792 |
case 9: return "AES256";
|
|
Packit Service |
30b792 |
case 10: return "TWOFISH";
|
|
Packit Service |
30b792 |
case 11: return "CAMELLIA128";
|
|
Packit Service |
30b792 |
case 12: return "CAMELLIA192";
|
|
Packit Service |
30b792 |
case 13: return "CAMELLIA256";
|
|
Packit Service |
30b792 |
}
|
|
Packit Service |
30b792 |
}
|
|
Packit Service |
30b792 |
|
|
Packit Service |
30b792 |
return "Unknown";
|
|
Packit Service |
30b792 |
}
|
|
Packit Service |
30b792 |
|
|
Packit Service |
30b792 |
|
|
Packit Service |
30b792 |
/* Return a string with the cipher mode. */
|
|
Packit Service |
30b792 |
const char *
|
|
Packit Service |
30b792 |
_gpgme_cipher_mode_name (int algo, gpgme_protocol_t protocol)
|
|
Packit Service |
30b792 |
{
|
|
Packit Service |
30b792 |
if (protocol == GPGME_PROTOCOL_OPENPGP)
|
|
Packit Service |
30b792 |
{
|
|
Packit Service |
30b792 |
/* The algo is given according to OpenPGP specs. */
|
|
Packit Service |
30b792 |
switch (algo)
|
|
Packit Service |
30b792 |
{
|
|
Packit Service |
30b792 |
case 0: return "CFB";
|
|
Packit Service |
30b792 |
case 1: return "EAX";
|
|
Packit Service |
30b792 |
case 2: return "OCB";
|
|
Packit Service |
30b792 |
}
|
|
Packit Service |
30b792 |
}
|
|
Packit Service |
30b792 |
|
|
Packit Service |
30b792 |
return "Unknown";
|
|
Packit Service |
30b792 |
}
|