diff --git a/configure.ac b/configure.ac
index 9b5cbad..3699875 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,302 +1,292 @@
# configure.ac - for GpgOL
# Copyright (C) 2005, 2006, 2007, 2008, 2011 g10 Code GmbH
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
min_automake_version="1.14"
# To build a release you need to create a tag with the version number
# (git tag -s gpgol-k.n.m) and run "./autogen.sh --force". Please
# bump the version number immediately *after* the release and do
# another commit and push so that the git magic is able to work.
m4_define([mym4_version], [1.4.1])
# Below is m4 magic to extract and compute the git revision number,
# the decimalized short revision number, a beta version string and a
# flag indicating a development version (mym4_isgit). Note that the
# m4 processing is done by autoconf and not during the configure run.
m4_define([mym4_revision],
m4_esyscmd([git rev-parse --short HEAD | tr -d '\n\r']))
m4_define([mym4_revision_dec],
m4_esyscmd_s([echo $((0x$(echo ]mym4_revision[|head -c 4)))]))
m4_define([mym4_betastring],
m4_esyscmd_s([git describe --match 'gpgol-[0-9].[0-9].*[0-9]' \
--long | awk -F- '$3!=0{print"-beta"$3}']))
m4_define([mym4_isgit],m4_if(mym4_betastring,[],[no],[yes]))
m4_define([mym4_full_version],[mym4_version[]mym4_betastring])
AC_INIT([gpgol],[mym4_full_version], [http://bugs.gnupg.org])
# Bump up this value if you changed any form.
GPGOL_FORMS_REVISION=335
NEED_GPG_ERROR_VERSION=1.9
NEED_GPGME_API=1
NEED_GPGME_VERSION=1.1.0
NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.0.0
GIT_COMMIT=0x[]mym4_revision
GIT_COMMIT_DECIMAL=0x[]mym4_revision_dec
PACKAGE=$PACKAGE_NAME
PACKAGE_GT=${PACKAGE_NAME}
VERSION=$PACKAGE_VERSION
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_SRCDIR(src/gpgol.def)
AM_CONFIG_HEADER(config.h)
AC_CANONICAL_TARGET()
AM_INIT_AUTOMAKE
AC_GNU_SOURCE
have_gpg_error=no
have_libassuan=no
AC_SUBST(PACKAGE)
AC_SUBST(PACKAGE_GT)
AC_SUBST(VERSION)
AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of this package])
AC_DEFINE_UNQUOTED(PACKAGE_GT, "$PACKAGE_GT",
[Name of this package for gettext])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version of this package])
AC_DEFINE_UNQUOTED(PACKAGE_BUGREPORT, "$PACKAGE_BUGREPORT",
[Bug report address])
AC_DEFINE_UNQUOTED(NEED_GPGME_VERSION, "$NEED_GPGME_VERSION",
[Required version of GPGME])
AC_DEFINE_UNQUOTED(GIT_COMMIT, ${GIT_COMMIT}, [Current GIT commit])
AC_DEFINE_UNQUOTED(GPGOL_FORMS_REVISION, ${GPGOL_FORMS_REVISION},
[Current Forms revision])
BUILD_TIMESTAMP=`date --iso-8601=minutes`
AC_SUBST(BUILD_TIMESTAMP)
changequote(,)dnl
BUILD_FILEVERSION=`echo "$VERSION" | sed 's/\([0-9.]*\).*/\1./;s/\./,/g'`
changequote([,])dnl
BUILD_FILEVERSION="${BUILD_FILEVERSION}${GIT_COMMIT_DECIMAL}"
AC_SUBST(BUILD_FILEVERSION)
AH_BOTTOM([
/* Some global constants. */
/* Force using of NLS for W32 even if no libintl has been found. This is
okay because we have our own gettext implementation for W32. */
#if defined(HAVE_W32_SYSTEM) && !defined(ENABLE_NLS)
#define ENABLE_NLS 1
#endif
])
AM_MAINTAINER_MODE
# Checks for programs.
AC_PROG_MAKE_SET
AM_SANITY_CHECK
missing_dir=`cd $ac_aux_dir && pwd`
AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir)
AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir)
AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir)
AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir)
AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir)
AC_PROG_AWK
AC_PROG_CC
AC_PROG_CPP
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_PROG_RANLIB
AC_CHECK_TOOL(AR, ar, :)
AC_CHECK_TOOL(DLLTOOL, dlltool, :)
AC_CHECK_TOOL(WINDRES, windres, :)
have_dosish_system=no
have_w32_system=no
case "${host}" in
*-mingw32*)
# special stuff for Windoze NT
ac_cv_have_dev_random=no
AC_DEFINE(USE_ONLY_8DOT3,1,
[set this to limit filenames to the 8.3 format])
AC_DEFINE(HAVE_DRIVE_LETTERS,1,
[defined if we must run on a stupid file system])
have_dosish_system=yes
have_w32_system=yes
;;
*)
AC_MSG_ERROR([[
***
*** This software my only be build for W32 systems. Use
*** ./autogen.sh --build-w32
*** to prepare it for such a build.
***]])
;;
esac
if test "$have_dosish_system" = yes; then
AC_DEFINE(HAVE_DOSISH_SYSTEM,1,
[Defined if we run on some of the PCDOS like systems
(DOS, Windoze. OS/2) with special properties like
no file modes])
fi
AM_CONDITIONAL(HAVE_DOSISH_SYSTEM, test "$have_dosish_system" = yes)
if test "$have_w32_system" = yes; then
AC_DEFINE(HAVE_W32_SYSTEM,1, [Defined if we run on a W32 API based system])
fi
AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes)
AM_CONDITIONAL(BUILD_W64, test "$host" = "x86_64-w64-mingw32")
#
# Checks for libraries.
#
AM_PATH_GPGME("$NEED_GPGME_API:$NEED_GPGME_VERSION",
have_gpgme=yes,have_gpgme=no)
AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION",
have_gpg_error=yes,have_gpg_error=no)
AC_DEFINE(GPG_ERR_SOURCE_DEFAULT, GPG_ERR_SOURCE_USER_2,
[The default error source for GpgOL.])
AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_API:$NEED_LIBASSUAN_VERSION",
have_libassuan=yes,have_libassuan=no)
# Note, that autogen.sh greps for the next line.
AM_GNU_GETTEXT_VERSION([0.12.1])
AM_GNU_GETTEXT([external])
# We always want NLs, despite what the above macro figures out.
USE_NLS=yes
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(string.h unistd.h langinfo.h termio.h locale.h)
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
AC_TYPE_SIGNAL
AM_CONDITIONAL(CROSS_COMPILING, test x$cross_compiling = xyes)
# Add some extra libs here so that previous tests don't fail for
# mysterious reasons - the final link step should bail out.
if test "$have_w32_system" = yes; then
W32LIBS="-lwsock32"
fi
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -mms-bitfields -fno-strict-aliasing"
CXXFLAGS="$CXXFLAGS -Wall -mms-bitfields -fno-strict-aliasing"
if test "$USE_MAINTAINER_MODE" = "yes"; then
CFLAGS="$CFLAGS -Werror -Wcast-align -Wshadow -Wstrict-prototypes"
- CFLAGS="$CFLAGS -Wno-format-y2k -Wformat-security"
+ CFLAGS="$CFLAGS -Wformat-security"
CFLAGS="$CFLAGS -W -Wno-sign-compare"
CXXFLAGS="$CXXFLAGS -Werror -Wcast-align -Wshadow"
- CXXFLAGS="$CXXFLAGS -Wno-format-y2k -Wformat-security"
+ CXXFLAGS="$CXXFLAGS -Wformat-security"
CXXFLAGS="$CXXFLAGS -W -Wno-sign-compare"
- AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers])
- _gcc_cflags_save=$CFLAGS
- CFLAGS="-Wno-missing-field-initializers"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_mfi=yes,_gcc_mfi=no)
- AC_MSG_RESULT($_gcc_mfi)
- CFLAGS=$_gcc_cflags_save;
- if test x"$_gcc_mfi" = xyes ; then
- CFLAGS="$CFLAGS -Wno-missing-field-initializers"
- CXXFLAGS="$CXXFLAGS -Wno-missing-field-initializers"
- fi
fi
AC_MSG_CHECKING([if gcc supports -Wno-pointer-sign])
_gcc_cflags_save=$CFLAGS
CFLAGS="-Wno-pointer-sign"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_psign=yes,_gcc_psign=no)
AC_MSG_RESULT($_gcc_psign)
CFLAGS=$_gcc_cflags_save;
if test x"$_gcc_psign" = xyes ; then
CFLAGS="$CFLAGS -Wno-pointer-sign"
fi
fi
AC_SUBST(W32LIBS)
#
# This should be a temporary option that will eventually become the
# default.
#
AC_ARG_ENABLE(mime-send,
AC_HELP_STRING([--enable-mime-send], [Enable experimental send support for mime messages]),
mime_send=$enableval, mime_send=no)
if test "$mime_send" != "no"; then
AC_DEFINE(MIME_SEND, 1,
[Sending Mime messages will be supported.])
fi
#
# Print errors here so that they are visible all
# together and the user can acquire them all together.
#
die=no
if test "$have_gpg_error" = "no"; then
die=yes
AC_MSG_NOTICE([[
***
*** You need libgpg-error to build this program.
** This library is for example available at
*** ftp://ftp.gnupg.org/pub/gcrypt/libgpg-error
*** (at least version $NEED_GPG_ERROR_VERSION is required.)
***]])
fi
if test "$have_gpgme" = "no"; then
die=yes
AC_MSG_NOTICE([[
***
*** You need gpgme to build this program.
** This library is for example available at
*** ftp://ftp.gnupg.org/gcrypt/gpgme/
*** (at least version $NEED_GPGME_VERSION is required.)
***]])
fi
if test "$have_libassuan" = "no"; then
die=yes
AC_MSG_NOTICE([[
***
*** You need libassuan to build this program.
*** This library is for example available at
*** ftp://ftp.gnupg.org/pub/gcrypt/libassuan/
*** (at least version $NEED_LIBASSUAN_VERSION is required).
***]])
fi
if test "$die" = "yes"; then
AC_MSG_ERROR([[
***
*** Required libraries not found. Please consult the above messages
*** and install them before running configure again.
***]])
fi
AC_CONFIG_FILES([ Makefile
src/Makefile
src/versioninfo.rc
forms/Makefile
doc/Makefile
po/Makefile.in
m4/Makefile
])
AC_OUTPUT
diff --git a/src/attachment.cpp b/src/attachment.cpp
index c93a3a4..87071dc 100644
--- a/src/attachment.cpp
+++ b/src/attachment.cpp
@@ -1,340 +1,340 @@
/* attachment.cpp - Functions for attachment handling
* Copyright (C) 2005, 2007 g10 Code GmbH
* Copyright (C) 2015 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 Lesser 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 "config.h"
#include "common.h"
#include "attachment.h"
#include "serpent.h"
#include "oomhelp.h"
#include "mymapitags.h"
#include "mapihelp.h"
#include
#define COPYBUFFERSIZE 4096
#define IV_DEFAULT_LEN 16
/** Decrypt the first 16 bytes of stream and check that it contains
our header. Return 0 on success. */
static int
check_header (LPSTREAM stream, symenc_t symenc)
{
HRESULT hr;
char tmpbuf[16];
ULONG nread;
hr = stream->Read (tmpbuf, 16, &nread);
if (hr || nread != 16)
{
log_error ("%s:%s: Read failed: hr=%#lx", SRCNAME, __func__, hr);
return -1;
}
symenc_cfb_decrypt (symenc, tmpbuf, tmpbuf, 16);
if (memcmp (tmpbuf, "GpgOL attachment", 16))
{
log_error ("%s:%s: Invalid header.",
SRCNAME, __func__);
char buf2 [17];
snprintf (buf2, 17, "%s", tmpbuf);
log_error("Buf2: %s", buf2);
return -1;
}
return 0;
}
/** Encrypts or decrypts a stream in place using the symenc context.
Returns 0 on success. */
static int
do_crypt_stream (LPSTREAM stream, symenc_t symenc, bool encrypt)
{
char *buf = NULL;
HRESULT hr;
ULONG nread;
bool fixed_str_written = false;
int rc = -1;
ULONG written = 0;
/* The original intention was to use IStream::Clone to have
an independent read / write stream. But the MAPI attachment
stream returns E_NOT_IMPLMENTED for that :-)
So we manually track the read and writepos. Read is offset
at 16 because of the GpgOL message. */
- LARGE_INTEGER readpos = {0},
- writepos = {0};
- ULARGE_INTEGER new_size = {0};
+ LARGE_INTEGER readpos = {0, 0},
+ writepos = {0, 0};
+ ULARGE_INTEGER new_size = {0, 0};
if (!encrypt)
{
readpos.QuadPart = 16;
}
buf = (char*)xmalloc (COPYBUFFERSIZE);
do
{
hr = stream->Read (buf, COPYBUFFERSIZE, &nread);
if (hr)
{
log_error ("%s:%s: Read failed: hr=%#lx", SRCNAME, __func__, hr);
goto done;
}
if (!nread)
{
break;
}
readpos.QuadPart += nread;
stream->Seek(writepos, STREAM_SEEK_SET, NULL);
if (nread && encrypt && !fixed_str_written)
{
char tmpbuf[16];
/* Write an encrypted fixed 16 byte string which we need to
check at decryption time to see whether we have actually
encrypted it using this session key. */
symenc_cfb_encrypt (symenc, tmpbuf, "GpgOL attachment", 16);
stream->Write (tmpbuf, 16, NULL);
fixed_str_written = true;
writepos.QuadPart = 16;
}
if (encrypt)
{
symenc_cfb_encrypt (symenc, buf, buf, nread);
}
else
{
symenc_cfb_decrypt (symenc, buf, buf, nread);
}
hr = stream->Write (buf, nread, &written);
if (FAILED (hr) || written != nread)
{
log_error ("%s:%s: Write failed: %i", SRCNAME, __func__, __LINE__);
goto done;
}
writepos.QuadPart += written;
stream->Seek(readpos, STREAM_SEEK_SET, NULL);
}
while (nread == COPYBUFFERSIZE);
new_size.QuadPart = writepos.QuadPart;
hr = stream->SetSize (new_size);
if (FAILED (hr))
{
log_error ("%s:%s: Failed to update size", SRCNAME, __func__);
goto done;
}
rc = 0;
done:
xfree (buf);
if (rc)
{
stream->Revert ();
}
else
{
stream->Commit (0);
}
return rc;
}
/** If encrypt is set to true this will encrypt the attachment
data with serpent otherwiese it will decrypt.
This function handles the mapi side of things.
*/
static int
do_crypt_mapi (LPATTACH att, bool encrypt)
{
char *iv;
ULONG tag;
size_t ivlen = IV_DEFAULT_LEN;
symenc_t symenc = NULL;
HRESULT hr;
LPSTREAM stream = NULL;
int rc = -1;
if (!att)
{
log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
return -1;
}
/* Get or create a new IV */
if (get_gpgolprotectiv_tag ((LPMESSAGE)att, &tag) )
{
log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
return -1;
}
if (encrypt)
{
iv = (char*)create_initialization_vector (IV_DEFAULT_LEN);
}
else
{
iv = mapi_get_binary_prop ((LPMESSAGE)att, tag, &ivlen);
}
if (!iv)
{
log_error ("%s:%s: Error creating / getting IV: %i", SRCNAME,
__func__, __LINE__);
goto done;
}
symenc = symenc_open (get_128bit_session_key (), 16, iv, ivlen);
xfree (iv);
if (!symenc)
{
log_error ("%s:%s: can't open encryption context", SRCNAME, __func__);
goto done;
}
hr = att->OpenProperty (PR_ATTACH_DATA_BIN, &IID_IStream,
0, MAPI_MODIFY, (LPUNKNOWN*) &stream);
if (FAILED (hr))
{
log_error ("%s:%s: can't open data stream of attachment: hr=%#lx",
SRCNAME, __func__, hr);
goto done;
}
/* When decrypting check the first 16 bytes for the header */
if (!encrypt && check_header (stream, symenc))
{
goto done;
}
if (FAILED (hr))
{
log_error ("%s:%s: can't create temp file: hr=%#lx",
SRCNAME, __func__, hr);
goto done;
}
if (do_crypt_stream (stream, symenc, encrypt))
{
log_error ("%s:%s: stream handling failed",
SRCNAME, __func__);
goto done;
}
rc = 0;
done:
if (symenc)
symenc_close (symenc);
RELDISP (stream);
return rc;
}
/** Protect or unprotect attachments.*/
static int
do_crypt (LPDISPATCH mailitem, bool protect)
{
LPDISPATCH attachments = get_oom_object (mailitem, "Attachments");
LPMESSAGE message = get_oom_base_message (mailitem);
int count = 0;
int err = -1;
char *item_str;
int i;
ULONG tag_id;
if (!attachments || !message)
{
log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
return -1;
}
count = get_oom_int (attachments, "Count");
if (get_gpgolattachtype_tag (message, &tag_id))
{
log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
goto done;
}
if (count < 1)
{
log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
goto done;
}
/* Yes the items start at 1! */
for (i = 1; i <= count; i++)
{
LPDISPATCH attachment;
LPATTACH mapi_attachment;
attachtype_t att_type;
if (gpgrt_asprintf (&item_str, "Item(%i)", i) == -1)
{
log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
goto done;
}
attachment = get_oom_object (attachments, item_str);
xfree (item_str);
if (!attachment)
{
log_error ("%s:%s: Error: %i", SRCNAME, __func__, __LINE__);
}
mapi_attachment = (LPATTACH) get_oom_iunknown (attachment,
"MapiObject");
if (!mapi_attachment)
{
log_debug ("%s:%s: Failed to get MapiObject of attachment: %p",
SRCNAME, __func__, attachment);
attachment->Release ();
continue;
}
att_type = get_gpgolattachtype (mapi_attachment, tag_id);
if ((protect && att_type == ATTACHTYPE_FROMMOSS_DEC) ||
(!protect && att_type == ATTACHTYPE_FROMMOSS))
{
if (do_crypt_mapi (mapi_attachment, protect))
{
log_error ("%s:%s: Error: Session crypto failed.",
SRCNAME, __func__);
mapi_attachment->Release ();
attachment->Release ();
goto done;
}
}
mapi_attachment->Release ();
attachment->Release ();
}
err = 0;
done:
RELDISP (message);
RELDISP (attachments);
return err;
}
int
protect_attachments (LPDISPATCH mailitem)
{
return do_crypt (mailitem, true);
}
int
unprotect_attachments (LPDISPATCH mailitem)
{
return do_crypt (mailitem, false);
}
diff --git a/src/main.c b/src/main.c
index d30f74b..12321f3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,812 +1,812 @@
/* 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 "mymapi.h"
#include "mymapitags.h"
#include "common.h"
#include "msgcache.h"
#include "mymapi.h"
/* The malloced name of the logfile and the logging stream. If
LOGFILE is NULL, no logging is done. */
static char *logfile;
static FILE *logfp;
/* For certain operations we need to acquire a log on the logging
functions. This lock is controlled by this Mutex. */
static HANDLE log_mutex;
/* The session key used to temporary encrypt attachments. It is
initialized at startup. */
static char *the_session_key;
/* The session marker to identify this session. Its value is not
confidential. It is initialized at startup. */
static char *the_session_marker;
/* 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;
/* Initialization of gloabl options. These are merely the defaults
and will get updated later from the Registry. That is done later
at the time Outlook calls its entry point the first time. */
static void
init_options (void)
{
opt.enc_format = GPG_FMT_CLASSIC;
}
/* 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;
}
/* Initialize the session key and the session marker. */
static int
initialize_session_key (void)
{
the_session_key = get_crypt_random (16+sizeof (unsigned int)+8);
if (the_session_key)
{
/* We use rand() in generate_boundary so we need to seed it. */
unsigned int tmp;
memcpy (&tmp, the_session_key+16, sizeof (unsigned int));
srand (tmp);
/* And save the session marker. */
the_session_marker = the_session_key + 16 + sizeof (unsigned int);
}
return !the_session_key;
}
static 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);
}
/* 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 ();
/* 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;
i18n_init ();
if (initialize_session_key ())
return FALSE;
if (initialize_msgcache ())
return FALSE;
if (initialize_inspectors ())
return FALSE;
init_options ();
}
else if (reason == DLL_PROCESS_DETACH)
{
gpg_err_deinit (0);
}
return TRUE;
}
/* Return the static session key we are using for temporary encrypting
attachments. The session key is guaranteed to be available. */
const void *
get_128bit_session_key (void)
{
return the_session_key;
}
const void *
get_64bit_session_marker (void)
{
return the_session_marker;
}
/* 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);
}
/* 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);
}
static void
do_log (const char *fmt, va_list a, int w32err, int err,
const void *buf, size_t buflen)
{
if (!logfile)
return;
if (lock_log ())
return;
if (!logfp)
logfp = fopen (logfile, "a+");
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 ());
}
if (err == 1)
fputs ("ERROR/", logfp);
vfprintf (logfp, fmt, a);
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);
}
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);
unlock_log ();
}
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_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);
}
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);
}
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);
}
}
const char *
log_srcname (const char *file)
{
const char *s = strrchr (file, '/');
return s? s+1:file;
}
const char *
get_log_file (void)
{
return logfile? logfile : "";
}
void
set_log_file (const char *name)
{
if (!lock_log ())
{
if (logfp)
{
fclose (logfp);
logfp = NULL;
}
xfree (logfile);
if (!name || *name == '\"' || !*name)
logfile = NULL;
else
logfile = xstrdup (name);
unlock_log ();
}
}
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 ();
}
}
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);
}
/* Read option settings from the Registry. */
void
read_options (void)
{
static int warnings_shown;
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 ("defaultProtocol", &val); */
/* switch ((!val || *val == '0')? 0 : atol (val)) */
/* { */
/* case 1: opt.default_protocol = PROTOCOL_OPENPGP; break; */
/* case 2: opt.default_protocol = PROTOCOL_SMIME; break; */
/* case 0: */
/* default: opt.default_protocol = PROTOCOL_UNKNOWN /\*(auto*)*\/; break; */
/* } */
/* xfree (val); val = NULL; */
opt.default_protocol = PROTOCOL_UNKNOWN; /* (auto)*/
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 ("previewDecrypt", &val);
opt.preview_decrypt = val == NULL || *val != '1'? 0 : 1;
xfree (val); val = NULL;
load_extension_value ("enableDefaultKey", &val);
opt.enable_default_key = val == NULL || *val != '1' ? 0 : 1;
xfree (val); val = NULL;
load_extension_value ("encodingFormat", &val);
opt.enc_format = val == NULL? GPG_FMT_CLASSIC : atol (val);
xfree (val); val = NULL;
load_extension_value ("defaultKey", &val);
set_default_key (val);
xfree (val); val = NULL;
load_extension_value ("preferHtml", &val);
opt.prefer_html = val == NULL || *val != '1'? 0 : 1;
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 ("bodyAsAttachment", &val);
opt.body_as_attachment = val == NULL || *val != '1'? 0 : 1;
xfree (val); val = NULL;
#ifdef MIME_SEND
opt.mime_ui = 1;
#else
load_extension_value ("mimeUI", &val);
opt.mime_ui = val == NULL || *val != '1'? 0 : 1;
xfree (val); val = NULL;
#endif
/* Note, that on purpose these flags are only Registry changeable.
The format of the entry is a string of of "0" and "1" digits; see
the switch below for a description. */
memset (&opt.compat, 0, sizeof opt.compat);
load_extension_value ("compatFlags", &val);
if (val)
{
const char *s = val;
int i, x;
for (s=val, i=0; *s; s++, i++)
{
x = *s == '1';
switch (i)
{
case 0: opt.compat.no_msgcache = x; break;
case 1: opt.compat.no_pgpmime = x; break;
case 2: opt.compat.no_oom_write = x; break;
case 3: opt.compat.no_preview_info = x; break;
case 4: opt.compat.old_reply_hack = x; break;
case 5: opt.compat.auto_decrypt = x; break;
case 6: opt.compat.no_attestation = x; break;
case 7: opt.compat.use_mwfmo = x; break;
}
}
log_debug ("Note: using compatibility flags: %s", val);
}
if (!warnings_shown)
{
char tmpbuf[512];
warnings_shown = 1;
if (val && *val)
{
snprintf (tmpbuf, sizeof tmpbuf,
_("Note: Using compatibility flags: %s"), val);
MessageBox (NULL, tmpbuf, _("GpgOL"), MB_ICONWARNING|MB_OK);
}
if (logfile && !opt.enable_debug)
{
snprintf (tmpbuf, sizeof tmpbuf,
_("Note: Writing debug logs to\n\n\"%s\""), logfile);
MessageBox (NULL, tmpbuf, _("GpgOL"), MB_ICONWARNING|MB_OK);
}
}
xfree (val); val = NULL;
}
/* 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},
+ {"enableSmime", 0, opt.enable_smime, NULL},
/* {"defaultProtocol", 3, opt.default_protocol}, */
- {"encryptDefault", 0, opt.encrypt_default},
- {"signDefault", 0, opt.sign_default},
- {"previewDecrypt", 0, opt.preview_decrypt},
- {"encodingFormat", 1, opt.enc_format},
+ {"encryptDefault", 0, opt.encrypt_default, NULL},
+ {"signDefault", 0, opt.sign_default, NULL},
+ {"previewDecrypt", 0, opt.preview_decrypt, NULL},
+ {"encodingFormat", 1, opt.enc_format, NULL},
{"logFile", 2, 0, logfile},
{"defaultKey", 2, 0, opt.default_key},
- {"enableDefaultKey", 0, opt.enable_default_key},
- {"preferHtml", 0, opt.prefer_html},
- {"gitCommit", 4, opt.git_commit},
- {"formsRevision", 1, opt.forms_revision},
- {"announceNumber", 1, opt.announce_number},
- {"bodyAsAttachment", 0, opt.body_as_attachment},
- {"mimeUI", MIME_UI_DEFAULT, opt.mime_ui},
- {NULL, 0}
+ {"enableDefaultKey", 0, opt.enable_default_key, NULL},
+ {"preferHtml", 0, opt.prefer_html, NULL},
+ {"gitCommit", 4, opt.git_commit, NULL},
+ {"formsRevision", 1, opt.forms_revision, NULL},
+ {"announceNumber", 1, opt.announce_number, NULL},
+ {"bodyAsAttachment", 0, opt.body_as_attachment, NULL},
+ {"mimeUI", MIME_UI_DEFAULT, opt.mime_ui, 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;
}
diff --git a/src/windowmessages.cpp b/src/windowmessages.cpp
index ce1afa5..e0c95cd 100644
--- a/src/windowmessages.cpp
+++ b/src/windowmessages.cpp
@@ -1,110 +1,110 @@
#include "windowmessages.h"
#include "util.h"
#include "oomhelp.h"
#include
#define RESPONDER_CLASS_NAME "GpgOLResponder"
/* Singleton window */
static HWND g_responder_window = NULL;
static int
request_send_mail (LPDISPATCH mailitem)
{
if (invoke_oom_method (mailitem, "Send", NULL))
{
log_debug ("%s:%s: Failed to resend message.",
SRCNAME, __func__);
return -1;
}
log_debug ("%s:%s: Message %p sent.",
SRCNAME, __func__, mailitem);
return 0;
}
LONG_PTR WINAPI
gpgol_window_proc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_USER + 1)
{
wm_ctx_t *ctx = (wm_ctx_t *) lParam;
log_debug ("%s:%s: Recieved user msg: %i",
SRCNAME, __func__, ctx->wmsg_type);
switch (ctx->wmsg_type)
{
case (REQUEST_SEND_MAIL):
{
ctx->err = request_send_mail ((LPDISPATCH) ctx->data);
break;
}
default:
log_debug ("Unknown msg");
}
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
HWND
create_responder_window ()
{
size_t cls_name_len = strlen(RESPONDER_CLASS_NAME) + 1;
char cls_name[cls_name_len];
if (g_responder_window)
{
return g_responder_window;
}
/* Create Window wants a mutable string as the first parameter */
snprintf (cls_name, cls_name_len, "%s", RESPONDER_CLASS_NAME);
WNDCLASS windowClass;
windowClass.style = CS_GLOBALCLASS | CS_DBLCLKS;
windowClass.lpfnWndProc = gpgol_window_proc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = (HINSTANCE) GetModuleHandle(NULL);
windowClass.hIcon = 0;
windowClass.hCursor = 0;
windowClass.hbrBackground = 0;
windowClass.lpszMenuName = 0;
windowClass.lpszClassName = cls_name;
RegisterClass(&windowClass);
g_responder_window = CreateWindow (cls_name, RESPONDER_CLASS_NAME, 0, 0, 0,
0, 0, 0, (HMENU) 0,
(HINSTANCE) GetModuleHandle(NULL), 0);
return g_responder_window;
}
int
send_msg_to_ui_thread (wm_ctx_t *ctx)
{
size_t cls_name_len = strlen(RESPONDER_CLASS_NAME) + 1;
char cls_name[cls_name_len];
snprintf (cls_name, cls_name_len, "%s", RESPONDER_CLASS_NAME);
HWND responder = FindWindow (cls_name, RESPONDER_CLASS_NAME);
if (!responder)
{
log_error ("%s:%s: Failed to find responder window.",
SRCNAME, __func__);
return -1;
}
SendMessage (responder, WM_USER + 1, 0, (LPARAM) ctx);
return 0;
}
int
do_in_ui_thread (gpgol_wmsg_type type, void *data)
{
- wm_ctx_t ctx = {0};
+ wm_ctx_t ctx = {NULL, UNKNOWN, 0};
ctx.wmsg_type = type;
ctx.data = data;
if (send_msg_to_ui_thread (&ctx))
{
return -1;
}
return ctx.err;
}