diff --git a/src/common.cpp b/src/common.cpp
index a4e9c7d..2b7857d 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -1,868 +1,871 @@
/* common.c - Common routines used by GpgOL
* Copyright (C) 2005, 2007, 2008 g10 Code GmbH
* 2015, 2016, 2017 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
#define OEMRESOURCE /* Required for OBM_CHECKBOXES. */
#include
#include
#ifndef CSIDL_APPDATA
#define CSIDL_APPDATA 0x001a
#endif
#ifndef CSIDL_LOCAL_APPDATA
#define CSIDL_LOCAL_APPDATA 0x001c
#endif
#ifndef CSIDL_FLAG_CREATE
#define CSIDL_FLAG_CREATE 0x8000
#endif
#include
#include
#include
#include "common.h"
#include "dialogs.h"
#include
HINSTANCE glob_hinst = NULL;
void
set_global_hinstance (HINSTANCE hinst)
{
glob_hinst = hinst;
}
void
bring_to_front (HWND wid)
{
if (wid)
{
if (!SetForegroundWindow (wid))
{
log_debug ("%s:%s: SetForegroundWindow failed", SRCNAME, __func__);
/* Yet another fallback which will not work on some
* versions and is not recommended by msdn */
if (!ShowWindow (wid, SW_SHOWNORMAL))
{
log_debug ("%s:%s: ShowWindow failed.", SRCNAME, __func__);
}
}
}
log_debug ("%s:%s: done", SRCNAME, __func__);
}
void
fatal_error (const char *format, ...)
{
va_list arg_ptr;
char buf[512];
va_start (arg_ptr, format);
vsnprintf (buf, sizeof buf -1, format, arg_ptr);
buf[sizeof buf - 1] = 0;
va_end (arg_ptr);
MessageBox (NULL, buf, "Fatal Error", MB_OK);
abort ();
}
/* Helper for read_w32_registry_string(). */
static HKEY
get_root_key(const char *root)
{
HKEY root_key;
if( !root )
root_key = HKEY_CURRENT_USER;
else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
root_key = HKEY_CLASSES_ROOT;
else if( !strcmp( root, "HKEY_CURRENT_USER" ) )
root_key = HKEY_CURRENT_USER;
else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
root_key = HKEY_LOCAL_MACHINE;
else if( !strcmp( root, "HKEY_USERS" ) )
root_key = HKEY_USERS;
else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
root_key = HKEY_PERFORMANCE_DATA;
else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
root_key = HKEY_CURRENT_CONFIG;
else
return NULL;
return root_key;
}
#if defined(_WIN64)
#define CROSS_ACCESS KEY_WOW64_32KEY
#else
#define CROSS_ACCESS KEY_WOW64_64KEY
#endif
std::string
_readRegStr (HKEY root_key, const char *dir,
const char *name, bool alternate)
{
#ifndef _WIN32
(void) root_key; (void)alternate; (void)dir; (void)name;
return std::string();
#else
HKEY key_handle;
DWORD n1, nbytes, type;
std::string ret;
DWORD flags = KEY_READ;
if (alternate) {
flags |= CROSS_ACCESS;
}
if (RegOpenKeyExA(root_key, dir, 0, flags, &key_handle)) {
return ret;
}
nbytes = 1;
if (RegQueryValueExA(key_handle, name, 0, nullptr, nullptr, &nbytes)) {
RegCloseKey (key_handle);
return ret;
}
n1 = nbytes+1;
char result[n1];
if (RegQueryValueExA(key_handle, name, 0, &type, (LPBYTE)result, &n1)) {
RegCloseKey(key_handle);
return ret;
}
RegCloseKey(key_handle);
result[nbytes] = 0; /* make sure it is really a string */
ret = result;
if (type == REG_EXPAND_SZ && strchr (result, '%')) {
n1 += 1000;
char tmp[n1 +1];
nbytes = ExpandEnvironmentStringsA(ret.c_str(), tmp, n1);
if (nbytes && nbytes > n1) {
n1 = nbytes;
char tmp2[n1 +1];
nbytes = ExpandEnvironmentStringsA(result, tmp2, n1);
if (nbytes && nbytes > n1) {
/* oops - truncated, better don't expand at all */
return ret;
}
tmp2[nbytes] = 0;
ret = tmp2;
} else if (nbytes) { /* okay, reduce the length */
tmp[nbytes] = 0;
ret = tmp;
}
}
return ret;
#endif
}
std::string
readRegStr (const char *root, const char *dir, const char *name)
{
#ifndef _WIN32
(void)root; (void)dir; (void)name;
return std::string();
#else
HKEY root_key;
std::string ret;
if (!(root_key = get_root_key(root))) {
return ret;
}
ret = _readRegStr (root_key, dir, name, false);
-
+ if (ret.empty()) {
+ // Try alternate as fallback
+ ret = _readRegStr (root_key, dir, name, true);
+ }
if (ret.empty()) {
// Try local machine as fallback.
ret = _readRegStr (HKEY_LOCAL_MACHINE, dir, name, false);
if (ret.empty()) {
// Try alternative registry view as fallback
ret = _readRegStr (HKEY_LOCAL_MACHINE, dir, name, true);
}
}
return ret;
#endif
}
/* Return a string from the Win32 Registry or NULL in case of error.
Caller must release the return value. A NULL for root is an alias
for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. NOTE: The value
is allocated with a plain xmalloc () - use xfree () and not the usual
xfree(). */
char *
read_w32_registry_string (const char *root, const char *dir, const char *name)
{
const auto ret = readRegStr (root, dir, name);
if (ret.empty())
{
return nullptr;
}
return xstrdup (ret.c_str ());
}
/* Return the data dir used for forms etc. Returns NULL on error. */
char *
get_data_dir (void)
{
char *instdir;
char *p;
char *dname;
instdir = get_gpg4win_dir();
if (!instdir)
return NULL;
/* Build the key: "/share/gpgol". */
#define SDDIR "\\share\\gpgol"
dname = (char*) xmalloc (strlen (instdir) + strlen (SDDIR) + 1);
if (!dname)
{
xfree (instdir);
return NULL;
}
p = dname;
strcpy (p, instdir);
p += strlen (instdir);
strcpy (p, SDDIR);
xfree (instdir);
#undef SDDIR
return dname;
}
/* Percent-escape the string STR by replacing colons with '%3a'. If
EXTRA is not NULL all characters in it are also escaped. */
char *
percent_escape (const char *str, const char *extra)
{
int i, j;
char *ptr;
if (!str)
return NULL;
for (i=j=0; str[i]; i++)
if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
j++;
ptr = (char *) xmalloc (i + 2 * j + 1);
i = 0;
while (*str)
{
/* FIXME: Work around a bug in Kleo. */
if (*str == ':')
{
ptr[i++] = '%';
ptr[i++] = '3';
ptr[i++] = 'a';
}
else
{
if (*str == '%')
{
ptr[i++] = '%';
ptr[i++] = '2';
ptr[i++] = '5';
}
else if (extra && strchr (extra, *str))
{
ptr[i++] = '%';
ptr[i++] = tohex_lower ((*str >> 4) & 15);
ptr[i++] = tohex_lower (*str & 15);
}
else
ptr[i++] = *str;
}
str++;
}
ptr[i] = '\0';
return ptr;
}
/* Fix linebreaks.
This replaces all consecutive \r or \n characters
by a single \n.
There can be extremly weird combinations of linebreaks
like \r\r\n\r\r\n at the end of each line when
getting the body of a mail message.
*/
void
fix_linebreaks (char *str, int *len)
{
char *src;
char *dst;
src = str;
dst = str;
while (*src)
{
if (*src == '\r' || *src == '\n')
{
do
src++;
while (*src == '\r' || *src == '\n');
*(dst++) = '\n';
}
else
{
*(dst++) = *(src++);
}
}
*dst = '\0';
*len = dst - str;
}
/* Get a pretty name for the file at path path. File extension
will be set to work for the protocol as provided in protocol and
depends on the signature setting. Set signature to 0 if the
extension should not be a signature extension.
Returns NULL on success.
Caller must free result. */
wchar_t *
get_pretty_attachment_name (wchar_t *path, protocol_t protocol,
int signature)
{
wchar_t* pretty;
wchar_t* buf;
if (!path || !wcslen (path))
{
log_error("%s:%s: No path given", SRCNAME, __func__);
return NULL;
}
pretty = (wchar_t*) xmalloc ((MAX_PATH + 1) * sizeof (wchar_t));
memset (pretty, 0, (MAX_PATH + 1) * sizeof (wchar_t));
buf = wcsrchr (path, '\\') + 1;
if (!buf || !*buf)
{
log_error("%s:%s: No filename found in path", SRCNAME, __func__);
xfree (pretty);
return NULL;
}
wcscpy (pretty, buf);
buf = pretty + wcslen(pretty);
if (signature)
{
if (protocol == PROTOCOL_SMIME)
{
*(buf++) = '.';
*(buf++) = 'p';
*(buf++) = '7';
*(buf++) = 's';
}
else
{
*(buf++) = '.';
*(buf++) = 's';
*(buf++) = 'i';
*(buf++) = 'g';
}
}
else
{
if (protocol == PROTOCOL_SMIME)
{
*(buf++) = '.';
*(buf++) = 'p';
*(buf++) = '7';
*(buf++) = 'm';
}
else
{
*(buf++) = '.';
*(buf++) = 'g';
*(buf++) = 'p';
*(buf++) = 'g';
}
}
return pretty;
}
static HANDLE
CreateFileUtf8 (const char *utf8Name)
{
if (!utf8Name)
{
return INVALID_HANDLE_VALUE;
}
wchar_t *wname = utf8_to_wchar (utf8Name);
if (!wname)
{
TRACEPOINT;
return INVALID_HANDLE_VALUE;
}
auto ret = CreateFileW (wname,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_TEMPORARY,
NULL);
xfree (wname);
return ret;
}
static std::string
getTmpPathUtf8 ()
{
static std::string ret;
if (!ret.empty())
{
return ret;
}
wchar_t tmpPath[MAX_PATH + 2];
if (!GetTempPathW (MAX_PATH, tmpPath))
{
log_error ("%s:%s: Could not get tmp path.",
SRCNAME, __func__);
return ret;
}
char *utf8Name = wchar_to_utf8 (tmpPath);
if (!utf8Name)
{
TRACEPOINT;
return ret;
}
ret = utf8Name;
xfree (utf8Name);
return ret;
}
/* Open a file in a temporary directory, take name as a
suggestion and put the open Handle in outHandle.
Returns the actually used file name in case there
were other files with that name. */
wchar_t*
get_tmp_outfile (wchar_t *name, HANDLE *outHandle)
{
const auto utf8Name = wchar_to_utf8_string (name);
const auto tmpPath = getTmpPathUtf8 ();
if (utf8Name.empty() || tmpPath.empty())
{
TRACEPOINT;
return nullptr;
}
auto outName = tmpPath + utf8Name;
log_data("%s:%s: Attachment candidate is %s",
SRCNAME, __func__, outName.c_str ());
int tries = 1;
while ((*outHandle = CreateFileUtf8 (outName.c_str ())) == INVALID_HANDLE_VALUE)
{
log_debug_w32 (-1, "%s:%s: Failed to open candidate '%s'",
SRCNAME, __func__, anonstr (outName.c_str()));
char *outNameC = xstrdup (outName.c_str());
const auto lastBackslash = strrchr (outNameC, '\\');
if (!lastBackslash)
{
/* This is an error because tmp name by definition contains one */
log_error ("%s:%s: No backslash in origname '%s'",
SRCNAME, __func__, outNameC);
xfree (outNameC);
return NULL;
}
auto fileExt = strchr (lastBackslash, '.');
if (fileExt)
{
*fileExt = '\0';
++fileExt;
}
// OutNameC is now without an extension and if
// there is a file ext it now points to the extension.
outName = outNameC + std::string("_") + std::to_string(tries++);
if (fileExt)
{
outName += std::string(".") + fileExt;
}
xfree (outNameC);
if (tries == 50)
{
/* Mmh fishy, maybe the name cannot be created on the file
system. Let's switch to a generic name. */
log_dbg ("Can't find an attachment name. "
"Switching over to a generic attachment name.");
outName = tmpPath + "attachment";
if (fileExt)
{
outName += ".";
outName += fileExt;
}
}
if (tries > 100)
{
/* You have to know when to give up,.. */
log_error ("%s:%s: Could not get a name out of 100 tries",
SRCNAME, __func__);
return NULL;
}
}
return utf8_to_wchar (outName.c_str ());
}
/** Get the Gpg4win Install directory.
*
* Looks first for the Gpg4win 3.x registry key. Then for the Gpg4win
* 2.x registry key. And checks that the directory can be read.
*
* @returns NULL if no dir could be found. Otherwise a malloced string.
*/
char *
get_gpg4win_dir()
{
const char *g4win_keys[] = {GPG4WIN_REGKEY_3,
GPG4WIN_REGKEY_2,
NULL};
const char **key;
for (key = g4win_keys; *key; key++)
{
char *tmp = read_w32_registry_string (NULL, *key, "Install Directory");
if (!tmp)
{
continue;
}
if (!access(tmp, R_OK))
{
return tmp;
}
else
{
log_debug ("Failed to access: %s\n", tmp);
xfree (tmp);
}
}
return NULL;
}
static void
epoch_to_file_time (unsigned long time, LPFILETIME pft)
{
LONGLONG ll;
ll = Int32x32To64(time, 10000000) + 116444736000000000;
pft->dwLowDateTime = (DWORD)ll;
pft->dwHighDateTime = ll >> 32;
}
char *
format_date_from_gpgme (unsigned long time)
{
wchar_t buf[256];
FILETIME ft;
SYSTEMTIME st;
epoch_to_file_time (time, &ft);
FileTimeToSystemTime(&ft, &st);
int ret = GetDateFormatEx (NULL,
DATE_SHORTDATE,
&st,
NULL,
buf,
256,
NULL);
if (ret == 0)
{
return NULL;
}
return wchar_to_utf8 (buf);
}
/* Return the name of the default UI server. This name is used to
auto start an UI server if an initial connect failed. */
char *
get_uiserver_name (void)
{
char *name = NULL;
char *dir, *uiserver, *p;
int extra_arglen = 9;
const char * server_names[] = {"kleopatra.exe",
"bin\\kleopatra.exe",
"gpa.exe",
"bin\\gpa.exe",
NULL};
const char **tmp = NULL;
dir = get_gpg4win_dir ();
if (!dir)
{
log_error ("Failed to find gpg4win dir");
return NULL;
}
uiserver = read_w32_registry_string (NULL, GPG4WIN_REGKEY_3,
"UI Server");
if (!uiserver)
{
uiserver = read_w32_registry_string (NULL, GPG4WIN_REGKEY_2,
"UI Server");
}
if (uiserver)
{
name = (char*) xmalloc (strlen (dir) + strlen (uiserver) + extra_arglen + 2);
strcpy (stpcpy (stpcpy (name, dir), "\\"), uiserver);
for (p = name; *p; p++)
if (*p == '/')
*p = '\\';
xfree (uiserver);
}
if (name && !access (name, F_OK))
{
/* Set through registry and is accessible */
xfree(dir);
return name;
}
/* Fallbacks */
for (tmp = server_names; *tmp; tmp++)
{
if (name)
{
xfree (name);
}
name = (char *) xmalloc (strlen (dir) + strlen (*tmp) + extra_arglen + 2);
strcpy (stpcpy (stpcpy (name, dir), "\\"), *tmp);
for (p = name; *p; p++)
if (*p == '/')
*p = '\\';
if (!access (name, F_OK))
{
/* Found a viable candidate */
if (strstr (name, "kleopatra.exe"))
{
strcat (name, " --daemon");
}
xfree (dir);
return name;
}
}
xfree (dir);
log_error ("Failed to find a viable UIServer");
return NULL;
}
int
has_high_integrity(HANDLE hToken)
{
PTOKEN_MANDATORY_LABEL integrity_label = NULL;
DWORD integrity_level = 0,
size = 0;
if (hToken == NULL || hToken == INVALID_HANDLE_VALUE)
{
log_debug ("Invalid parameters.");
return 0;
}
/* Get the required size */
if (!GetTokenInformation (hToken, TokenIntegrityLevel,
NULL, 0, &size))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
log_debug ("Failed to get required size.\n");
return 0;
}
}
integrity_label = (PTOKEN_MANDATORY_LABEL) LocalAlloc(0, size);
if (integrity_label == NULL)
{
log_debug ("Failed to allocate label. \n");
return 0;
}
if (!GetTokenInformation (hToken, TokenIntegrityLevel,
integrity_label, size, &size))
{
log_debug ("Failed to get integrity level.\n");
LocalFree(integrity_label);
return 0;
}
/* Get the last integrity level */
integrity_level = *GetSidSubAuthority(integrity_label->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(
integrity_label->Label.Sid) - 1));
LocalFree (integrity_label);
return integrity_level >= SECURITY_MANDATORY_HIGH_RID;
}
int
is_elevated()
{
int ret = 0;
HANDLE hToken = NULL;
if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
DWORD elevation;
DWORD cbSize = sizeof (DWORD);
if (GetTokenInformation (hToken, TokenElevation, &elevation,
sizeof (TokenElevation), &cbSize))
{
ret = elevation;
}
}
/* Elevation will be true and ElevationType TokenElevationTypeFull even
if the token is a user token created by SAFER so we additionally
check the integrity level of the token which will only be high in
the real elevated process and medium otherwise. */
ret = ret && has_high_integrity (hToken);
if (hToken)
CloseHandle (hToken);
return ret;
}
int
gpgol_message_box (HWND parent, const char *utf8_text,
const char *utf8_caption, UINT type)
{
wchar_t *w_text = utf8_to_wchar (utf8_text);
wchar_t *w_caption = utf8_to_wchar (utf8_caption);
int ret = 0;
MSGBOXPARAMSW mbp;
mbp.cbSize = sizeof (MSGBOXPARAMS);
mbp.hwndOwner = parent;
mbp.hInstance = glob_hinst;
mbp.lpszText = w_text;
mbp.lpszCaption = w_caption;
mbp.dwStyle = type | MB_USERICON;
mbp.dwLanguageId = MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT);
mbp.lpfnMsgBoxCallback = NULL;
mbp.dwContextHelpId = 0;
mbp.lpszIcon = (LPCWSTR) MAKEINTRESOURCE (IDI_GPGOL_LOCK_ICON);
ret = MessageBoxIndirectW (&mbp);
xfree (w_text);
xfree (w_caption);
return ret;
}
void
gpgol_bug (HWND parent, int code)
{
const char *bugmsg = utf8_gettext ("Operation failed.\n\n"
"This is usually caused by a bug in GpgOL or an error in your setup.\n"
"Please see https://www.gpg4win.org/reporting-bugs.html "
"or ask your Administrator for support.");
char *with_code;
gpgrt_asprintf (&with_code, "%s\nCode: %i", bugmsg, code);
memdbg_alloc (with_code);
gpgol_message_box (parent,
with_code,
_("GpgOL Error"), MB_OK);
xfree (with_code);
return;
}
static int
store_config_value (HKEY hk, const char *path, const char *key, const char *val)
{
HKEY h;
int type;
int ec;
if (hk == NULL)
{
hk = HKEY_CURRENT_USER;
}
ec = RegCreateKeyEx (hk, path, 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &h, NULL);
if (ec != ERROR_SUCCESS)
{
log_debug_w32 (ec, "creating/opening registry key `%s' failed", path);
return -1;
}
type = strchr (val, '%')? REG_EXPAND_SZ : REG_SZ;
ec = RegSetValueEx (h, key, 0, type, (const BYTE*)val, strlen (val));
if (ec != ERROR_SUCCESS)
{
log_debug_w32 (ec, "saving registry key `%s'->`%s' failed", path, key);
RegCloseKey(h);
return -1;
}
RegCloseKey(h);
return 0;
}
/* Store a key in the registry with the key given by @key and the
value @value. */
int
store_extension_value (const char *key, const char *val)
{
return store_config_value (HKEY_CURRENT_USER, GPGOL_REGPATH, key, val);
}
/* Load a key from the registry with the key given by @key. The value is
returned in @val and needs to freed by the caller. */
int
load_extension_value (const char *key, char **val)
{
if (!val)
{
STRANGEPOINT;
return -1;
}
*val = read_w32_registry_string (nullptr, GPGOL_REGPATH, key);
log_debug ("%s:%s: LoadReg '%s' val '%s'",
SRCNAME, __func__, key ? key : "null",
*val ? *val : "null");
return 0;
}
int
store_extension_subkey_value (const char *subkey,
const char *key,
const char *val)
{
int ret;
char *path;
gpgrt_asprintf (&path, "%s\\%s", GPGOL_REGPATH, subkey);
memdbg_alloc (path);
ret = store_config_value (HKEY_CURRENT_USER, path, key, val);
xfree (path);
return ret;
}
diff --git a/src/common_indep.h b/src/common_indep.h
index 4c43b10..aad03a8 100644
--- a/src/common_indep.h
+++ b/src/common_indep.h
@@ -1,351 +1,343 @@
#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"
#include "debug.h"
#include "memdbg.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
+#define GPG4WIN_REGKEY_2 "Software\\GNU\\GnuPG"
+#define GPG4WIN_REGKEY_3 "Software\\Gpg4win"
/* 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. */
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 sync_enc; /* Disabed async encryption */
int sync_dec; /* Disabed async decryption */
int prefer_smime; /* S/MIME prefered when autoresolving */
int smime_html_warn_shown; /* Flag to save if unsigned smime warning was shown */
int autoretrieve; /* Use --auto-key-retrieve. */
int search_smime_servers; /* Search for S/MIME keys on all configured S/MIME keyservers
for each new unknown mail */
int auto_unstrusted; /* Automatically encrypt even to untrusted keys. */
int autoimport; /* Automatically import keys from headers or attachments. */
char *draft_key; /* Encrypt drafts with this key (fingerprint) */
int alwaysShowApproval; /* Always show the certificate approval dialog. */
int combinedOpsEnabled; /* Enable S/MIME and OpenPGP combined operations. */
int splitBCCMails; /* Split BCC recipients in their own mails. */
int encryptSubject; /* Encrypt the subject with protected headers. */
/* The forms revision number of the binary. */
int forms_revision;
} 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;
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)
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*/
/* The length of the boundary - the buffer needs to be allocated one
byte larger. */
#define BOUNDARYSIZE 20
char *generate_boundary (char *buffer);
#ifdef __cplusplus
}
#include
#include
struct autocrypt_s
{
bool exists;
std::string pref;
std::string addr;
GpgME::Data data;
};
/* A general way to transfer some header infos around
without having to parse them multiple times. */
struct header_info_s
{
std::string boundary;
autocrypt_s acInfo;
};
#endif
#endif // COMMON_INDEP_H