diff --git a/src/common_indep.c b/src/common_indep.c
index 7f4415f..046def8 100644
--- a/src/common_indep.c
+++ b/src/common_indep.c
@@ -1,770 +1,752 @@
/* common_indep.c - Common, platform indepentent routines used by GpgOL
* Copyright (C) 2005, 2007, 2008 g10 Code GmbH
* Copyright (C) 2016 by Bundesamt für Sicherheit in der Informationstechnik
* Software engineering by Intevation GmbH
*
* This file is part of GpgOL.
*
* GpgOL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* GpgOL 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 Lesser General Public License
* along with this program; if not, see .
*/
#include "common_indep.h"
#ifdef HAVE_W32_SYSTEM
#include
#endif
#include
#include
/* The base-64 list used for base64 encoding. */
static unsigned char bintoasc[64+1] = ("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/");
/* The reverse base-64 list used for base-64 decoding. */
static unsigned char const asctobin[256] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff
};
void
out_of_core (void)
{
#ifdef HAVE_W32_SYSTEM
MessageBox (NULL, "Out of core!", "Fatal Error", MB_OK);
#endif
abort ();
}
void*
xmalloc (size_t n)
{
void *p = malloc (n);
if (!p)
out_of_core ();
return p;
}
void*
xcalloc (size_t m, size_t n)
{
void *p = calloc (m, n);
if (!p)
out_of_core ();
return p;
}
void *
xrealloc (void *a, size_t n)
{
void *p = realloc (a, n);
if (!p)
out_of_core ();
return p;
}
char*
xstrdup (const char *s)
{
char *p = xmalloc (strlen (s)+1);
strcpy (p, s);
return p;
}
void
xfree (void *p)
{
if (p)
free (p);
}
/* Strip off leading and trailing white spaces from STRING. Returns
STRING. */
char *
trim_spaces (char *arg_string)
{
char *string = arg_string;
char *p, *mark;
/* Find first non space character. */
for (p = string; *p && isascii (*p) && isspace (*p) ; p++ )
;
/* Move characters. */
for (mark = NULL; (*string = *p); string++, p++ )
{
if (isascii (*p) && isspace (*p))
{
if (!mark)
mark = string;
}
else
mark = NULL ;
}
if (mark)
*mark = 0;
return arg_string;
}
/* Assume STRING is a Latin-1 encoded and convert it to utf-8.
Returns a newly malloced UTF-8 string. */
char *
latin1_to_utf8 (const char *string)
{
const char *s;
char *buffer, *p;
size_t n;
for (s=string, n=0; *s; s++)
{
n++;
if (*s & 0x80)
n++;
}
buffer = xmalloc (n + 1);
for (s=string, p=buffer; *s; s++)
{
if (*s & 0x80)
{
*p++ = 0xc0 | ((*s >> 6) & 3);
*p++ = 0x80 | (*s & 0x3f);
}
else
*p++ = *s;
}
*p = 0;
return buffer;
}
/* This function is similar to strncpy(). However it won't copy more
than N - 1 characters and makes sure that a Nul is appended. With N
given as 0, nothing will happen. With DEST given as NULL, memory
will be allocated using xmalloc (i.e. if it runs out of core the
function terminates). Returns DEST or a pointer to the allocated
memory. */
char *
mem2str (char *dest, const void *src, size_t n)
{
char *d;
const char *s;
if (n)
{
if (!dest)
dest = xmalloc (n);
d = dest;
s = src ;
for (n--; n && *s; n--)
*d++ = *s++;
*d = 0;
}
else if (!dest)
{
dest = xmalloc (1);
*dest = 0;
}
return dest;
}
/* Strip off trailing white spaces from STRING. Returns STRING. */
char *
trim_trailing_spaces (char *string)
{
char *p, *mark;
for (mark=NULL, p=string; *p; p++)
{
if (strchr (" \t\r\n", *p ))
{
if (!mark)
mark = p;
}
else
mark = NULL;
}
if (mark)
*mark = 0;
return string;
}
/* Do in-place decoding of quoted-printable data of LENGTH in BUFFER.
Returns the new length of the buffer and stores true at R_SLBRK if
the line ended with a soft line break; false is stored if not.
This fucntion asssumes that a complete line is passed in
buffer. */
size_t
qp_decode (char *buffer, size_t length, int *r_slbrk)
{
char *d, *s;
if (r_slbrk)
*r_slbrk = 0;
/* Fixme: We should remove trailing white space first. */
for (s=d=buffer; length; length--)
if (*s == '=')
{
if (length > 2 && hexdigitp (s+1) && hexdigitp (s+2))
{
s++;
*(unsigned char*)d++ = xtoi_2 (s);
s += 2;
length -= 2;
}
else if (length > 2 && s[1] == '\r' && s[2] == '\n')
{
/* Soft line break. */
s += 3;
length -= 2;
if (r_slbrk && length == 1)
*r_slbrk = 1;
}
else if (length > 1 && s[1] == '\n')
{
/* Soft line break with only a Unix line terminator. */
s += 2;
length -= 1;
if (r_slbrk && length == 1)
*r_slbrk = 1;
}
else if (length == 1)
{
/* Soft line break at the end of the line. */
s += 1;
if (r_slbrk)
*r_slbrk = 1;
}
else
*d++ = *s++;
}
else
*d++ = *s++;
return d - buffer;
}
/* Return the a quoted printable encoded version of the
input string. If outlen is not null the size of the
quoted printable string is returned. String will be
malloced and zero terminated. Aborts if the output
is more then three times the size of the input.
This is only basic and does not handle mutliline data. */
char *
qp_encode (const char *input, size_t inlen, size_t *r_outlen)
{
size_t max_len = inlen * 3 +1;
char *outbuf = xmalloc (max_len);
size_t outlen = 0;
const unsigned char *p;
memset (outbuf, 0, max_len);
for (p = input; inlen; p++, inlen--)
{
if (*p >= '!' && *p <= '~' && *p != '=')
{
outbuf[outlen++] = *p;
}
else if (*p == ' ')
{
/* Outlook does it this way */
outbuf[outlen++] = '_';
}
else
{
outbuf[outlen++] = '=';
outbuf[outlen++] = tohex ((*p>>4)&15);
outbuf[outlen++] = tohex (*p&15);
}
if (outlen == max_len -1)
{
log_error ("Quoted printable too long. Bug.");
r_outlen = NULL;
xfree (outbuf);
return NULL;
}
}
if (r_outlen)
*r_outlen = outlen;
return outbuf;
}
/* Initialize the Base 64 decoder state. */
void b64_init (b64_state_t *state)
{
state->idx = 0;
state->val = 0;
state->stop_seen = 0;
state->invalid_encoding = 0;
}
/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Returns
the new length of the buffer. STATE is required to return errors and
to maintain the state of the decoder. */
size_t
b64_decode (b64_state_t *state, char *buffer, size_t length)
{
int idx = state->idx;
unsigned char val = state->val;
int c;
char *d, *s;
if (state->stop_seen)
return 0;
for (s=d=buffer; length; length--, s++)
{
if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
continue;
if (*s == '=')
{
/* Pad character: stop */
if (idx == 1)
*d++ = val;
state->stop_seen = 1;
break;
}
if ((c = asctobin[*(unsigned char *)s]) == 255)
{
if (!state->invalid_encoding)
log_debug ("%s: invalid base64 character %02X at pos %d skipped\n",
__func__, *(unsigned char*)s, (int)(s-buffer));
state->invalid_encoding = 1;
continue;
}
switch (idx)
{
case 0:
val = c << 2;
break;
case 1:
val |= (c>>4)&3;
*d++ = val;
val = (c<<4)&0xf0;
break;
case 2:
val |= (c>>2)&15;
*d++ = val;
val = (c<<6)&0xc0;
break;
case 3:
val |= c&0x3f;
*d++ = val;
break;
}
idx = (idx+1) % 4;
}
state->idx = idx;
state->val = val;
return d - buffer;
}
/* Base 64 encode the input. If input is null returns NULL otherwise
a pointer to the malloced encoded string. */
char *
b64_encode (const char *input, size_t length)
{
size_t out_len = 4 * ((length + 2) / 3);
char *ret;
int i, j;
if (!length || !input)
{
return NULL;
}
ret = xmalloc (out_len);
memset (ret, 0, out_len);
for (i = 0, j = 0; i < length;)
{
unsigned int a = i < length ? (unsigned char)input[i++] : 0;
unsigned int b = i < length ? (unsigned char)input[i++] : 0;
unsigned int c = i < length ? (unsigned char)input[i++] : 0;
unsigned int triple = (a << 0x10) + (b << 0x08) + c;
ret[j++] = bintoasc[(triple >> 3 * 6) & 0x3F];
ret[j++] = bintoasc[(triple >> 2 * 6) & 0x3F];
ret[j++] = bintoasc[(triple >> 1 * 6) & 0x3F];
ret[j++] = bintoasc[(triple >> 0 * 6) & 0x3F];
}
if (length % 3)
{
ret [j - 1] = '=';
}
if (length % 3 == 1)
{
ret [j - 2] = '=';
}
return ret;
}
/* Create a boundary. Note that mimemaker.c knows about the structure
of the boundary (i.e. that it starts with "=-=") so that it can
protect against accidently used boundaries within the content. */
char *
generate_boundary (char *buffer)
{
char *p = buffer;
int i;
#if RAND_MAX < (64*2*BOUNDARYSIZE)
#error RAND_MAX is way too small
#endif
*p++ = '=';
*p++ = '-';
*p++ = '=';
for (i=0; i < BOUNDARYSIZE-6; i++)
*p++ = bintoasc[rand () % 64];
*p++ = '=';
*p++ = '-';
*p++ = '=';
*p = 0;
return buffer;
}
/* The malloced name of the logfile and the logging stream. If
LOGFILE is NULL, no logging is done. */
static char *logfile;
static FILE *logfp;
#ifdef HAVE_W32_SYSTEM
/* Acquire the mutex for logging. Returns 0 on success. */
static int
lock_log (void)
{
int code = WaitForSingleObject (log_mutex, INFINITE);
return code != WAIT_OBJECT_0;
}
/* Release the mutex for logging. No error return is done because this
is a fatal error anyway and we have no means for proper
notification. */
static void
unlock_log (void)
{
ReleaseMutex (log_mutex);
}
#endif
const char *
get_log_file (void)
{
return logfile? logfile : "";
}
void
set_log_file (const char *name)
{
#ifdef HAVE_W32_SYSTEM
if (!lock_log ())
{
#endif
if (logfp)
{
fclose (logfp);
logfp = NULL;
}
xfree (logfile);
if (!name || *name == '\"' || !*name)
logfile = NULL;
else
logfile = xstrdup (name);
#ifdef HAVE_W32_SYSTEM
unlock_log ();
}
#endif
}
static void
do_log (const char *fmt, va_list a, int w32err, int err,
const void *buf, size_t buflen)
{
if (!logfile)
return;
#ifdef HAVE_W32_SYSTEM
if (!opt.enable_debug)
return;
if (lock_log ())
return;
#endif
if (!strcmp (logfile, "stdout"))
{
logfp = stdout;
}
else if (!strcmp (logfile, "stderr"))
{
logfp = stderr;
}
if (!logfp)
logfp = fopen (logfile, "a+");
#ifdef HAVE_W32_SYSTEM
if (!logfp)
{
unlock_log ();
return;
}
char time_str[9];
SYSTEMTIME utc_time;
GetSystemTime (&utc_time);
if (GetTimeFormatA (LOCALE_INVARIANT,
TIME_FORCE24HOURFORMAT | LOCALE_USE_CP_ACP,
&utc_time,
"HH:mm:ss",
time_str,
9))
{
fprintf (logfp, "%s/%lu/",
time_str,
(unsigned long)GetCurrentThreadId ());
}
else
{
fprintf (logfp, "unknown/%lu/",
(unsigned long)GetCurrentThreadId ());
}
#endif
if (err == 1)
fputs ("ERROR/", logfp);
vfprintf (logfp, fmt, a);
#ifdef HAVE_W32_SYSTEM
if (w32err)
{
char tmpbuf[256];
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, w32err,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
tmpbuf, sizeof (tmpbuf)-1, NULL);
fputs (": ", logfp);
if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\n')
tmpbuf[strlen (tmpbuf)-1] = 0;
if (*tmpbuf && tmpbuf[strlen (tmpbuf)-1] == '\r')
tmpbuf[strlen (tmpbuf)-1] = 0;
fprintf (logfp, "%s (%d)", tmpbuf, w32err);
}
#endif
if (buf)
{
const unsigned char *p = (const unsigned char*)buf;
for ( ; buflen; buflen--, p++)
fprintf (logfp, "%02X", *p);
putc ('\n', logfp);
}
else if ( *fmt && fmt[strlen (fmt) - 1] != '\n')
putc ('\n', logfp);
fflush (logfp);
#ifdef HAVE_W32_SYSTEM
unlock_log ();
#endif
}
const char *
log_srcname (const char *file)
{
const char *s = strrchr (file, '/');
return s? s+1:file;
}
void
log_debug (const char *fmt, ...)
{
va_list a;
va_start (a, fmt);
do_log (fmt, a, 0, 0, NULL, 0);
va_end (a);
}
void
log_error (const char *fmt, ...)
{
va_list a;
va_start (a, fmt);
do_log (fmt, a, 0, 1, NULL, 0);
va_end (a);
}
void
log_vdebug (const char *fmt, va_list a)
{
do_log (fmt, a, 0, 0, NULL, 0);
}
void
log_hexdump (const void *buf, size_t buflen, const char *fmt, ...)
{
va_list a;
va_start (a, fmt);
do_log (fmt, a, 0, 2, buf, buflen);
va_end (a);
}
#ifdef HAVE_W32_SYSTEM
void
log_debug_w32 (int w32err, const char *fmt, ...)
{
va_list a;
if (w32err == -1)
w32err = GetLastError ();
va_start (a, fmt);
do_log (fmt, a, w32err, 0, NULL, 0);
va_end (a);
}
void
log_error_w32 (int w32err, const char *fmt, ...)
{
va_list a;
if (w32err == -1)
w32err = GetLastError ();
va_start (a, fmt);
do_log (fmt, a, w32err, 1, NULL, 0);
va_end (a);
}
static void
do_log_window_info (HWND window, int level)
{
char buf[1024+1];
char name[200];
int nname;
char *pname;
DWORD pid;
if (!window)
return;
GetWindowThreadProcessId (window, &pid);
if (pid != GetCurrentProcessId ())
return;
memset (buf, 0, sizeof (buf));
GetWindowText (window, buf, sizeof (buf)-1);
nname = GetClassName (window, name, sizeof (name)-1);
if (nname)
pname = name;
else
pname = NULL;
if (level == -1)
log_debug (" parent=%p/%lu (%s) `%s'", window, (unsigned long)pid,
pname? pname:"", buf);
else
log_debug (" %*shwnd=%p/%lu (%s) `%s'", level*2, "", window,
(unsigned long)pid, pname? pname:"", buf);
}
/* Helper to log_window_hierarchy. */
static HWND
do_log_window_hierarchy (HWND parent, int level)
{
HWND child;
child = GetWindow (parent, GW_CHILD);
while (child)
{
do_log_window_info (child, level);
do_log_window_hierarchy (child, level+1);
child = GetNextWindow (child, GW_HWNDNEXT);
}
return NULL;
}
/* Print a debug message using the format string FMT followed by the
window hierarchy of WINDOW. */
void
log_window_hierarchy (HWND window, const char *fmt, ...)
{
va_list a;
va_start (a, fmt);
do_log (fmt, a, 0, 0, NULL, 0);
va_end (a);
if (window)
{
do_log_window_info (window, -1);
do_log_window_hierarchy (window, 0);
}
}
-void
-set_default_key (const char *name)
-{
- if (!lock_log ())
- {
- if (!name || *name == '\"' || !*name)
- {
- xfree (opt.default_key);
- opt.default_key = NULL;
- }
- else
- {
- xfree (opt.default_key);
- opt.default_key = xstrdup (name);;
- }
- unlock_log ();
- }
-}
#endif
diff --git a/src/common_indep.h b/src/common_indep.h
index 285ab42..00921e6 100644
--- a/src/common_indep.h
+++ b/src/common_indep.h
@@ -1,402 +1,381 @@
#ifndef COMMON_INDEP_H
#define COMMON_INDEP_H
/* common_indep.h - Common, platform indepentent routines used by GpgOL
* Copyright (C) 2005, 2007, 2008 g10 Code GmbH
* Copyright (C) 2016 by Bundesamt für Sicherheit in der Informationstechnik
* Software engineering by Intevation GmbH
*
* This file is part of GpgOL.
*
* GpgOL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* GpgOL 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 Lesser General Public License
* along with this program; if not, see .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include "xmalloc.h"
#ifdef HAVE_W32_SYSTEM
/* Not so independenent ;-) need this for logging HANDLE */
# include
#endif
/* The Registry key used by Gpg4win. */
#ifdef _WIN64
# define GPG4WIN_REGKEY_2 "Software\\Wow6432Node\\GNU\\GnuPG"
#else
# define GPG4WIN_REGKEY_2 "Software\\GNU\\GnuPG"
#endif
#ifdef _WIN64
# define GPG4WIN_REGKEY_3 "Software\\Wow6432Node\\Gpg4win"
#else
# define GPG4WIN_REGKEY_3 "Software\\Gpg4win"
#endif
/* Identifiers for the protocol. We use different one than those use
by gpgme. FIXME: We might want to define an unknown protocol to
non-null and define such a value also in gpgme. */
typedef enum
{
PROTOCOL_UNKNOWN = 0,
PROTOCOL_OPENPGP = 1000,
PROTOCOL_SMIME = 1001
}
protocol_t;
/* Possible options for the recipient dialog. */
enum
{
OPT_FLAG_TEXT = 2,
OPT_FLAG_FORCE = 4,
OPT_FLAG_CANCEL = 8
};
typedef enum
{
GPG_FMT_NONE = 0, /* do not encrypt attachments */
GPG_FMT_CLASSIC = 1, /* encrypt attachments without any encoding */
GPG_FMT_PGP_PEF = 2 /* use the PGP partioned encoding format (PEF) */
}
gpgol_format_t;
/* Type of a message. */
typedef enum
{
OPENPGP_NONE = 0,
OPENPGP_MSG,
OPENPGP_SIG,
OPENPGP_CLEARSIG,
OPENPGP_PUBKEY, /* Note, that this type is only partly supported */
OPENPGP_SECKEY /* Note, that this type is only partly supported */
}
openpgp_t;
/* The list of message types we support in GpgOL. */
typedef enum
{
MSGTYPE_UNKNOWN = 0,
MSGTYPE_SMIME, /* Original SMIME class. */
MSGTYPE_GPGOL,
MSGTYPE_GPGOL_MULTIPART_SIGNED,
MSGTYPE_GPGOL_MULTIPART_ENCRYPTED,
MSGTYPE_GPGOL_OPAQUE_SIGNED,
MSGTYPE_GPGOL_OPAQUE_ENCRYPTED,
MSGTYPE_GPGOL_CLEAR_SIGNED,
MSGTYPE_GPGOL_PGP_MESSAGE,
MSGTYPE_GPGOL_WKS_CONFIRMATION
}
msgtype_t;
typedef enum
{
ATTACHTYPE_UNKNOWN = 0,
ATTACHTYPE_MOSS = 1, /* The original MOSS message (ie. a
S/MIME or PGP/MIME message. */
ATTACHTYPE_FROMMOSS = 2, /* Attachment created from MOSS. */
ATTACHTYPE_MOSSTEMPL = 3, /* Attachment has been created in the
course of sending a message */
ATTACHTYPE_PGPBODY = 4, /* Attachment contains the original
PGP message body of PGP inline
encrypted messages. */
ATTACHTYPE_FROMMOSS_DEC = 5 /* A FROMMOSS attachment that has been
temporarily decrypted and needs to be
encrypted before it is written back
into storage. */
}
attachtype_t;
/* An object to collect information about one MAPI attachment. */
struct mapi_attach_item_s
{
int end_of_table; /* True if this is the last plus one entry of
the table. */
void *private_mapitable; /* Only for use by mapi_release_attach_table. */
int mapipos; /* The position which needs to be passed to
MAPI to open the attachment. -1 means that
there is no valid attachment. */
int method; /* MAPI attachment method. */
char *filename; /* Malloced filename of this attachment or NULL. */
/* Malloced string with the MIME attrib or NULL. Parameters are
stripped off thus a compare against "type/subtype" is
sufficient. */
char *content_type;
/* If not NULL the parameters of the content_type. */
const char *content_type_parms;
/* If not NULL the content_id */
char *content_id;
/* The attachment type from Property GpgOL Attach Type. */
attachtype_t attach_type;
};
typedef struct mapi_attach_item_s mapi_attach_item_t;
/* Passphrase callback structure. */
struct passphrase_cb_s
{
gpgme_key_t signer;
gpgme_ctx_t ctx;
char keyid[16+1];
char *user_id;
char *pass;
int opts;
int ttl; /* TTL of the passphrase. */
unsigned int decrypt_cmd:1; /* 1 = show decrypt dialog, otherwise secret key
selection. */
unsigned int hide_pwd:1;
unsigned int last_was_bad:1;
};
/* Global options - initialized to default by main.c. */
#ifdef __cplusplus
extern "C" {
#if 0
}
#endif
#endif
#ifdef __cplusplus
extern
#endif
struct
{
int enable_debug; /* Enable extra debug options. Values
larger than 1 increases the debug log
verbosity. */
int enable_smime; /* Enable S/MIME support. */
int encrypt_default; /* Encrypt by default. */
int sign_default; /* Sign by default. */
- char *default_key; /* The key we want to always encrypt to. */
int prefer_html; /* Prefer html in html/text alternatives. */
int inline_pgp; /* Only for Addin. Use Inline PGP by default. */
int autoresolve; /* Autresolve keys with --locate-keys. */
int autosecure; /* Autmatically encrypt if locate returns enough validity. */
int reply_crypt; /* Only for Addin. Encrypt / Sign based on cryptostatus. */
+ int automation; /* General automation */
+ int autotrust; /* TOFU configured for GpgOL */
+ int prefer_smime; /* S/MIME prefered when autoresolving */
int smime_html_warn_shown; /* Flag to save if unsigned smime warning was shown */
- /* The compatibility flags. */
- struct
- {
- unsigned int no_msgcache:1;
- unsigned int no_pgpmime:1;
- unsigned int no_oom_write:1; /* Don't write using Outlooks object model. */
- unsigned int no_preview_info:1; /* No preview info about PGP/MIME. */
- unsigned int old_reply_hack: 1; /* See gpgmsg.cpp:decrypt. */
- unsigned int auto_decrypt: 1; /* Try to decrypt when clicked. */
- unsigned int no_attestation: 1; /* Don't create an attestation. */
- unsigned int use_mwfmo: 1; /* Use MsgWaitForMultipleObjects. */
- } compat;
-
- /* The current git commit id. */
- unsigned int git_commit;
-
/* The forms revision number of the binary. */
int forms_revision;
- /* The stored number of the binary which showed the last announcement. */
- int announce_number;
-
- /* Disable message processing until restart. This is required to
- implement message reverting as a perparation to remove GpgOL. */
- int disable_gpgol;
-
} opt;
/* The state object used by b64_decode. */
struct b64_state_s
{
int idx;
unsigned char val;
int stop_seen;
int invalid_encoding;
};
typedef struct b64_state_s b64_state_t;
/* Bit values used for extra log file verbosity. Value 1 is reserved
to enable debug menu options. */
#define DBG_IOWORKER (1<<1)
#define DBG_IOWORKER_EXTRA (1<<2)
#define DBG_FILTER (1<<3)
#define DBG_FILTER_EXTRA (1<<4)
#define DBG_MEMORY (1<<5)
#define DBG_COMMANDS (1<<6)
#define DBG_MIME_PARSER (1<<7)
#define DBG_MIME_DATA (1<<8)
#define DBG_OOM (1<<9)
#define DBG_OOM_EXTRA (1<<10)
/* Macros to used in conditionals to enable debug output. */
#define debug_commands (opt.enable_debug & DBG_COMMANDS)
size_t qp_decode (char *buffer, size_t length, int *r_slbrk);
char *qp_encode (const char *input, size_t length, size_t* outlen);
void b64_init (b64_state_t *state);
size_t b64_decode (b64_state_t *state, char *buffer, size_t length);
char * b64_encode (const char *input, size_t length);
char *latin1_to_utf8 (const char *string);
char *mem2str (char *dest, const void *src, size_t n);
char *trim_spaces (char *string);
char *trim_trailing_spaces (char *string);
/* To avoid that a compiler optimizes certain memset calls away, these
macros may be used instead. */
#define wipememory2(_ptr,_set,_len) do { \
volatile char *_vptr=(volatile char *)(_ptr); \
size_t _vlen=(_len); \
while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
} while(0)
#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
#define wipestring(_ptr) do { \
volatile char *_vptr=(volatile char *)(_ptr); \
while(*_vptr) { *_vptr=0; _vptr++; } \
} while(0)
#define debug_oom (opt.enable_debug & DBG_OOM)
#define debug_oom_extra (opt.enable_debug & DBG_OOM_EXTRA)
void log_debug (const char *fmt, ...) __attribute__ ((format (printf,1,2)));
void log_error (const char *fmt, ...) __attribute__ ((format (printf,1,2)));
void log_vdebug (const char *fmt, va_list a);
void log_debug_w32 (int w32err, const char *fmt,
...) __attribute__ ((format (printf,2,3)));
void log_error_w32 (int w32err, const char *fmt,
...) __attribute__ ((format (printf,2,3)));
void log_hexdump (const void *buf, size_t buflen, const char *fmt,
...) __attribute__ ((format (printf,3,4)));
#define log_oom if (opt.enable_debug & DBG_OOM) log_debug
#define log_oom_extra if (opt.enable_debug & DBG_OOM_EXTRA) log_debug
#define log_mime_parser if (opt.enable_debug & DBG_MIME_PARSER) log_debug
#define log_mime_data if (opt.enable_debug & DBG_MIME_DATA) log_debug
#define gpgol_release(X) \
{ \
if (X && opt.enable_debug & DBG_OOM_EXTRA) \
{ \
log_debug ("%s:%s: Object: %p released ref: %lu \n", \
SRCNAME, __func__, X, X->Release()); \
} \
else if (X) \
{ \
X->Release(); \
} \
}
const char *log_srcname (const char *s);
#define SRCNAME log_srcname (__FILE__)
#define TRACEPOINT log_debug ("%s:%s:%d: tracepoint\n", \
SRCNAME, __func__, __LINE__);
const char *get_log_file (void);
void set_log_file (const char *name);
void set_default_key (const char *name);
/*-- Convenience macros. -- */
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#define DIMof(type,member) DIM(((type *)0)->member)
/*-- Macros to replace ctype ones to avoid locale problems. --*/
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
#define hexdigitp(a) (digitp (a) \
|| (*(a) >= 'A' && *(a) <= 'F') \
|| (*(a) >= 'a' && *(a) <= 'f'))
/* Note this isn't identical to a C locale isspace() without \f and
\v, but works for the purposes used here. */
#define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
/* The atoi macros assume that the buffer has only valid digits. */
#define atoi_1(p) (*(p) - '0' )
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
#define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2))
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
#define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
/***** Inline functions. ****/
/* Return true if LINE consists only of white space (up to and
including the LF). */
static inline int
trailing_ws_p (const char *line)
{
for ( ; *line && *line != '\n'; line++)
if (*line != ' ' && *line != '\t' && *line != '\r')
return 0;
return 1;
}
/* An strcmp variant with the compare ending at the end of B. */
static inline int
tagcmp (const char *a, const char *b)
{
return strncmp (a, b, strlen (b));
}
#ifdef HAVE_W32_SYSTEM
extern HANDLE log_mutex;
#endif
/***** Missing functions. ****/
#ifndef HAVE_STPCPY
static inline char *
_gpgol_stpcpy (char *a, const char *b)
{
while (*b)
*a++ = *b++;
*a = 0;
return a;
}
#define stpcpy(a,b) _gpgol_stpcpy ((a), (b))
#endif /*!HAVE_STPCPY*/
#ifdef _WIN64
#define SIZE_T_FORMAT "%I64u"
#else
# ifdef HAVE_W32_SYSTEM
# define SIZE_T_FORMAT "%u"
# else
# define SIZE_T_FORMAT "%lu"
# endif
#endif
/* The length of the boundary - the buffer needs to be allocated one
byte larger. */
#define BOUNDARYSIZE 20
char *generate_boundary (char *buffer);
#ifdef __cplusplus
}
#endif
#endif // COMMON_INDEP_H
diff --git a/src/main.c b/src/main.c
index e0d553d..12754fb 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,418 +1,395 @@
/* main.c - DLL entry point
* Copyright (C) 2005, 2007, 2008 g10 Code GmbH
*
* This file is part of GpgOL.
*
* GpgOL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* GpgOL 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 Lesser General Public License
* along with this program; if not, see .
*/
#include
#include
#include
#include
#include
#include
#include "mymapi.h"
#include "mymapitags.h"
#include "common.h"
#include "mymapi.h"
/* Local function prototypes. */
static char *get_locale_dir (void);
static void drop_locale_dir (char *locale_dir);
/* The major version of Outlook we are attached to */
int g_ol_version_major;
/* For certain operations we need to acquire a log on the logging
functions. This lock is controlled by this Mutex. */
HANDLE log_mutex;
/* Early initialization of this module. This is done right at startup
with only one thread running. Should be called only once. Returns
0 on success. */
static int
initialize_main (void)
{
SECURITY_ATTRIBUTES sa;
memset (&sa, 0, sizeof sa);
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof sa;
log_mutex = CreateMutex (&sa, FALSE, NULL);
return log_mutex? 0 : -1;
}
/* Return nbytes of cryptographic strong random. Caller needs to free
the returned buffer. */
static char *
get_crypt_random (size_t nbytes)
{
HCRYPTPROV prov;
char *buffer;
if (!CryptAcquireContext (&prov, NULL, NULL, PROV_RSA_FULL,
(CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) )
return NULL;
buffer = xmalloc (nbytes);
if (!CryptGenRandom (prov, nbytes, buffer))
{
xfree (buffer);
buffer = NULL;
}
CryptReleaseContext (prov, 0);
return buffer;
}
void
i18n_init (void)
{
char *locale_dir;
#ifdef ENABLE_NLS
# ifdef HAVE_LC_MESSAGES
setlocale (LC_TIME, "");
setlocale (LC_MESSAGES, "");
# else
setlocale (LC_ALL, "" );
# endif
#endif
locale_dir = get_locale_dir ();
if (locale_dir)
{
bindtextdomain (PACKAGE_GT, locale_dir);
drop_locale_dir (locale_dir);
}
textdomain (PACKAGE_GT);
}
static char *
get_gpgme_w32_inst_dir (void)
{
char *gpg4win_dir = get_gpg4win_dir ();
char *tmp;
gpgrt_asprintf (&tmp, "%s\\bin\\gpgme-w32spawn.exe", gpg4win_dir);
if (!access(tmp, R_OK))
{
xfree (tmp);
gpgrt_asprintf (&tmp, "%s\\bin", gpg4win_dir);
xfree (gpg4win_dir);
return tmp;
}
xfree (tmp);
gpgrt_asprintf (&tmp, "%s\\gpgme-w32spawn.exe", gpg4win_dir);
if (!access(tmp, R_OK))
{
xfree (tmp);
return gpg4win_dir;
}
OutputDebugString("Failed to find gpgme-w32spawn.exe!");
return NULL;
}
/* Entry point called by DLL loader. */
int WINAPI
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
(void)reserved;
if (reason == DLL_PROCESS_ATTACH)
{
set_global_hinstance (hinst);
gpg_err_init ();
/* Set the installation directory for GpgME so that
it can find tools like gpgme-w32-spawn correctly. */
char *instdir = get_gpgme_w32_inst_dir();
gpgme_set_global_flag ("w32-inst-dir", instdir);
xfree (instdir);
/* The next call initializes subsystems of gpgme and should be
done as early as possible. The actual return value (the
version string) is not used here. It may be called at any
time later for this. */
gpgme_check_version (NULL);
/* Early initializations of our subsystems. */
if (initialize_main ())
return FALSE;
}
else if (reason == DLL_PROCESS_DETACH)
{
gpg_err_deinit (0);
}
return TRUE;
}
/* Return a new allocated IV of size NBYTES. Caller must free it. On
error NULL is returned. */
void *
create_initialization_vector (size_t nbytes)
{
return get_crypt_random (nbytes);
}
static char *
get_locale_dir (void)
{
char *instdir;
char *p;
char *dname;
instdir = get_gpg4win_dir();
if (!instdir)
return NULL;
/* Build the key: "/share/locale". */
#define SLDIR "\\share\\locale"
dname = malloc (strlen (instdir) + strlen (SLDIR) + 1);
if (!dname)
{
free (instdir);
return NULL;
}
p = dname;
strcpy (p, instdir);
p += strlen (instdir);
strcpy (p, SLDIR);
free (instdir);
return dname;
}
static void
drop_locale_dir (char *locale_dir)
{
free (locale_dir);
}
+static int
+get_conf_bool (const char *name, int defaultVal)
+{
+ char *val = NULL;
+ int ret;
+ load_extension_value (name, &val);
+ ret = val == NULL ? defaultVal : *val != '1' ? 0 : 1;
+ xfree (val);
+ return ret;
+}
+
/* Read option settings from the Registry. */
void
read_options (void)
{
char *val = NULL;
/* Set the log file first so that output from this function is
logged too. */
load_extension_value ("logFile", &val);
set_log_file (val);
xfree (val); val = NULL;
/* Parse the debug flags. */
load_extension_value ("enableDebug", &val);
opt.enable_debug = 0;
if (val)
{
char *p, *pend;
trim_spaces (val);
for (p = val; p; p = pend)
{
pend = strpbrk (p, ", \t\n\r\f");
if (pend)
{
*pend++ = 0;
pend += strspn (pend, ", \t\n\r\f");
}
if (isascii (*p) && isdigit (*p))
opt.enable_debug |= strtoul (p, NULL, 0);
else if (!strcmp (p, "ioworker"))
opt.enable_debug |= DBG_IOWORKER;
else if (!strcmp (p, "ioworker-extra"))
opt.enable_debug |= DBG_IOWORKER_EXTRA;
else if (!strcmp (p, "filter"))
opt.enable_debug |= DBG_FILTER;
else if (!strcmp (p, "filter-extra"))
opt.enable_debug |= DBG_FILTER_EXTRA;
else if (!strcmp (p, "memory"))
opt.enable_debug |= DBG_MEMORY;
else if (!strcmp (p, "commands"))
opt.enable_debug |= DBG_COMMANDS;
else if (!strcmp (p, "mime-parser"))
opt.enable_debug |= DBG_MIME_PARSER;
else if (!strcmp (p, "mime-data"))
opt.enable_debug |= DBG_MIME_DATA;
else if (!strcmp (p, "oom"))
opt.enable_debug |= DBG_OOM;
else if (!strcmp (p, "oom-extra"))
opt.enable_debug |= DBG_OOM_EXTRA;
else
log_debug ("invalid debug flag `%s' ignored", p);
}
}
else
{
/* To help the user enable debugging make sure that the registry
key exists. Note that the other registry keys are stored
after using the configuration dialog. */
store_extension_value ("enableDebug", "0");
}
xfree (val); val = NULL;
if (opt.enable_debug)
log_debug ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s\n",
(opt.enable_debug & DBG_IOWORKER)? " ioworker":"",
(opt.enable_debug & DBG_IOWORKER_EXTRA)? " ioworker-extra":"",
(opt.enable_debug & DBG_FILTER)? " filter":"",
(opt.enable_debug & DBG_FILTER_EXTRA)? " filter-extra":"",
(opt.enable_debug & DBG_MEMORY)? " memory":"",
(opt.enable_debug & DBG_COMMANDS)? " commands":"",
(opt.enable_debug & DBG_MIME_PARSER)? " mime-parser":"",
(opt.enable_debug & DBG_MIME_DATA)? " mime-data":"",
(opt.enable_debug & DBG_OOM)? " oom":"",
(opt.enable_debug & DBG_OOM_EXTRA)? " oom-extra":""
);
-
- load_extension_value ("enableSmime", &val);
- opt.enable_smime = !val ? 0 : atoi (val);
- xfree (val); val = NULL;
-
- load_extension_value ("encryptDefault", &val);
- opt.encrypt_default = val == NULL || *val != '1'? 0 : 1;
- xfree (val); val = NULL;
-
- load_extension_value ("signDefault", &val);
- opt.sign_default = val == NULL || *val != '1'? 0 : 1;
- xfree (val); val = NULL;
-
- load_extension_value ("defaultKey", &val);
- set_default_key (val);
- xfree (val); val = NULL;
-
- load_extension_value ("gitCommit", &val);
- opt.git_commit = val? strtoul (val, NULL, 16) : 0;
- xfree (val); val = NULL;
-
- load_extension_value ("formsRevision", &val);
- opt.forms_revision = val? atol (val) : 0;
- xfree (val); val = NULL;
-
- load_extension_value ("announceNumber", &val);
- opt.announce_number = val? atol (val) : 0;
- xfree (val); val = NULL;
-
- load_extension_value ("inlinePGP", &val);
- opt.inline_pgp = val == NULL || *val != '1'? 0 : 1;
- xfree (val); val = NULL;
- load_extension_value ("autoresolve", &val);
- opt.autoresolve = val == NULL ? 1 : *val != '1' ? 0 : 1;
- xfree (val); val = NULL;
- load_extension_value ("replyCrypt", &val);
- opt.reply_crypt = val == NULL ? 1 : *val != '1' ? 0 : 1;
- xfree (val); val = NULL;
- load_extension_value ("smimeHtmlWarnShown", &val);
- opt.smime_html_warn_shown = val == NULL || *val != '1'? 0 : 1;
- xfree (val); val = NULL;
- load_extension_value ("autosecure", &val);
- opt.autosecure = val == NULL ? 1 : *val != '1' ? 0 : 1;
- xfree (val); val = NULL;
+ opt.enable_smime = get_conf_bool ("enableSmime", 0);
+ opt.encrypt_default = get_conf_bool ("encryptDefault", 0);
+ opt.sign_default = get_conf_bool ("signDefault", 0);
+ opt.inline_pgp = get_conf_bool ("inlinePGP", 0);
+ opt.reply_crypt = get_conf_bool ("replyCrypt", 1);
+ opt.prefer_smime = get_conf_bool ("preferSmime", 0);
+ opt.autoresolve = get_conf_bool ("autoresolve", 1);
+ opt.automation = get_conf_bool ("automation", 1);
+ opt.autosecure = get_conf_bool ("autosecure", 1);
+ opt.autotrust = get_conf_bool ("autotrust", 0);
+ opt.smime_html_warn_shown = get_conf_bool ("smimeHtmlWarnShown", 0);
+
+ if (!opt.automation)
+ {
+ // Disabling automation is a shorthand to disable the
+ // others, too.
+ opt.autosecure = 0;
+ opt.autoresolve = 0;
+ opt.autotrust = 0;
+ }
}
/* Write current options back to the Registry. */
int
write_options (void)
{
struct
{
const char *name;
int mode;
int value;
char *s_val;
} table[] = {
- {"enableSmime", 0, opt.enable_smime, NULL},
- {"encryptDefault", 0, opt.encrypt_default, NULL},
- {"signDefault", 0, opt.sign_default, NULL},
- {"logFile", 2, 0, (char*) get_log_file ()},
- {"gitCommit", 4, opt.git_commit, NULL},
- {"formsRevision", 1, opt.forms_revision, NULL},
- {"announceNumber", 1, opt.announce_number, NULL},
- {"inlinePGP", 0, opt.inline_pgp, NULL},
- {"autoresolve", 0, opt.autoresolve, NULL},
- {"replyCrypt", 0, opt.reply_crypt, NULL},
{"smimeHtmlWarnShown", 0, opt.smime_html_warn_shown, NULL},
{NULL, 0, 0, NULL}
};
char buf[32];
int rc, i;
const char *string;
for (i=0; table[i].name; i++)
{
switch (table[i].mode)
{
case 0:
string = table[i].value? "1": "0";
log_debug ("storing option `%s' value=`%s'\n",
table[i].name, string);
rc = store_extension_value (table[i].name, string);
break;
case 1:
sprintf (buf, "%d", table[i].value);
log_debug ("storing option `%s' value=`%s'\n",
table[i].name, buf);
rc = store_extension_value (table[i].name, buf);
break;
case 2:
string = table[i].s_val? table[i].s_val : "";
log_debug ("storing option `%s' value=`%s'\n",
table[i].name, string);
rc = store_extension_value (table[i].name, string);
break;
/* case 3: */
/* buf[0] = '0'; */
/* buf[1] = 0; */
/* switch (opt.default_protocol) */
/* { */
/* case PROTOCOL_UNKNOWN: buf[0] = '0'; /\* auto *\/ break; */
/* case PROTOCOL_OPENPGP: buf[0] = '1'; break; */
/* case PROTOCOL_SMIME: buf[0] = '2'; break; */
/* } */
/* log_debug ("storing option `%s' value=`%s'\n", */
/* table[i].name, buf); */
/* rc = store_extension_value (table[i].name, buf); */
/* break; */
case 4:
sprintf (buf, "0x%x", table[i].value);
log_debug ("storing option `%s' value=`%s'\n",
table[i].name, buf);
rc = store_extension_value (table[i].name, buf);
break;
default:
rc = -1;
break;
}
if (rc)
log_error ("error storing option `%s': rc = %d\n", table[i].name, rc);
}
return 0;
}