|
Packit |
3c2767 |
/* assuan.c - Global interface (not specific to context).
|
|
Packit |
3c2767 |
* Copyright (C) 2009 Free Software Foundation, Inc.
|
|
Packit |
3c2767 |
* Copyright (C) 2001, 2002, 2012, 2013 g10 Code GmbH
|
|
Packit |
3c2767 |
*
|
|
Packit |
3c2767 |
* This file is part of Assuan.
|
|
Packit |
3c2767 |
*
|
|
Packit |
3c2767 |
* Assuan is free software; you can redistribute it and/or modify it
|
|
Packit |
3c2767 |
* under the terms of the GNU Lesser General Public License as
|
|
Packit |
3c2767 |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
3c2767 |
* the License, or (at your option) any later version.
|
|
Packit |
3c2767 |
*
|
|
Packit |
3c2767 |
* Assuan is distributed in the hope that it will be useful, but
|
|
Packit |
3c2767 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
3c2767 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
3c2767 |
* Lesser General Public License for more details.
|
|
Packit |
3c2767 |
*
|
|
Packit |
3c2767 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
3c2767 |
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
3c2767 |
* SPDX-License-Identifier: LGPL-2.1+
|
|
Packit |
3c2767 |
*/
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
3c2767 |
#include <config.h>
|
|
Packit |
3c2767 |
#endif
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
#include <stdlib.h>
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
#include "assuan-defs.h"
|
|
Packit |
3c2767 |
#include "debug.h"
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
#define digitp(a) ((a) >= '0' && (a) <= '9')
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Global default state. */
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* The default error source gor generated error codes. */
|
|
Packit |
3c2767 |
static gpg_err_source_t _assuan_default_err_source = GPG_ERR_SOURCE_USER_1;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* The default memory management functions. */
|
|
Packit |
3c2767 |
static struct assuan_malloc_hooks _assuan_default_malloc_hooks =
|
|
Packit |
3c2767 |
{ malloc, realloc, free };
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* The default logging handler. */
|
|
Packit |
3c2767 |
static assuan_log_cb_t _assuan_default_log_cb = _assuan_log_handler;
|
|
Packit |
3c2767 |
static void *_assuan_default_log_cb_data = NULL;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Set the default gpg error source. */
|
|
Packit |
3c2767 |
void
|
|
Packit |
3c2767 |
assuan_set_gpg_err_source (gpg_err_source_t errsource)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
_assuan_default_err_source = errsource;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Get the default gpg error source. */
|
|
Packit |
3c2767 |
gpg_err_source_t
|
|
Packit |
3c2767 |
assuan_get_gpg_err_source (void)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
return _assuan_default_err_source;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Set the default malloc hooks. */
|
|
Packit |
3c2767 |
void
|
|
Packit |
3c2767 |
assuan_set_malloc_hooks (assuan_malloc_hooks_t malloc_hooks)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
_assuan_default_malloc_hooks = *malloc_hooks;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Get the default malloc hooks. */
|
|
Packit |
3c2767 |
assuan_malloc_hooks_t
|
|
Packit |
3c2767 |
assuan_get_malloc_hooks (void)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
return &_assuan_default_malloc_hooks;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Set the default log callback handler. */
|
|
Packit |
3c2767 |
void
|
|
Packit |
3c2767 |
assuan_set_log_cb (assuan_log_cb_t log_cb, void *log_cb_data)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
_assuan_default_log_cb = log_cb;
|
|
Packit |
3c2767 |
_assuan_default_log_cb_data = log_cb_data;
|
|
Packit |
3c2767 |
_assuan_init_log_envvars ();
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Get the default log callback handler. */
|
|
Packit |
3c2767 |
void
|
|
Packit |
3c2767 |
assuan_get_log_cb (assuan_log_cb_t *log_cb, void **log_cb_data)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
*log_cb = _assuan_default_log_cb;
|
|
Packit |
3c2767 |
*log_cb_data = _assuan_default_log_cb_data;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
void
|
|
Packit |
3c2767 |
assuan_set_system_hooks (assuan_system_hooks_t system_hooks)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
_assuan_system_hooks_copy (&_assuan_system_hooks, system_hooks);
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Create a new Assuan context. The initial parameters are all needed
|
|
Packit |
3c2767 |
in the creation of the context. */
|
|
Packit |
3c2767 |
gpg_error_t
|
|
Packit |
3c2767 |
assuan_new_ext (assuan_context_t *r_ctx, gpg_err_source_t err_source,
|
|
Packit |
3c2767 |
assuan_malloc_hooks_t malloc_hooks, assuan_log_cb_t log_cb,
|
|
Packit |
3c2767 |
void *log_cb_data)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
struct assuan_context_s wctx;
|
|
Packit |
3c2767 |
assuan_context_t ctx;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Set up a working context so we can use standard functions. */
|
|
Packit |
3c2767 |
memset (&wctx, 0, sizeof (wctx));
|
|
Packit |
3c2767 |
wctx.err_source = err_source;
|
|
Packit |
3c2767 |
wctx.malloc_hooks = *malloc_hooks;
|
|
Packit |
3c2767 |
wctx.log_cb = log_cb;
|
|
Packit |
3c2767 |
wctx.log_cb_data = log_cb_data;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Need a new block for the trace macros to work. */
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
TRACE_BEG8 (&wctx, ASSUAN_LOG_CTX, "assuan_new_ext", r_ctx,
|
|
Packit |
3c2767 |
"err_source = %i (%s), malloc_hooks = %p (%p, %p, %p), "
|
|
Packit |
3c2767 |
"log_cb = %p, log_cb_data = %p", err_source,
|
|
Packit |
3c2767 |
gpg_strsource (err_source), malloc_hooks, malloc_hooks->malloc,
|
|
Packit |
3c2767 |
malloc_hooks->realloc, malloc_hooks->free, log_cb, log_cb_data);
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
*r_ctx = NULL;
|
|
Packit |
3c2767 |
ctx = _assuan_malloc (&wctx, sizeof (*ctx));
|
|
Packit |
3c2767 |
if (!ctx)
|
|
Packit |
3c2767 |
return TRACE_ERR (gpg_err_code_from_syserror ());
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
memcpy (ctx, &wctx, sizeof (*ctx));
|
|
Packit |
3c2767 |
ctx->system = _assuan_system_hooks;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* FIXME: Delegate to subsystems/engines, as the FDs are not our
|
|
Packit |
3c2767 |
responsibility (we don't deallocate them, for example). */
|
|
Packit |
3c2767 |
ctx->input_fd = ASSUAN_INVALID_FD;
|
|
Packit |
3c2767 |
ctx->output_fd = ASSUAN_INVALID_FD;
|
|
Packit |
3c2767 |
ctx->inbound.fd = ASSUAN_INVALID_FD;
|
|
Packit |
3c2767 |
ctx->outbound.fd = ASSUAN_INVALID_FD;
|
|
Packit |
3c2767 |
ctx->listen_fd = ASSUAN_INVALID_FD;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
*r_ctx = ctx;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
return TRACE_SUC1 ("ctx=%p", ctx);
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Create a new context with default arguments. */
|
|
Packit |
3c2767 |
gpg_error_t
|
|
Packit |
3c2767 |
assuan_new (assuan_context_t *r_ctx)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
return assuan_new_ext (r_ctx, _assuan_default_err_source,
|
|
Packit |
3c2767 |
&_assuan_default_malloc_hooks,
|
|
Packit |
3c2767 |
_assuan_default_log_cb,
|
|
Packit |
3c2767 |
_assuan_default_log_cb_data);
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Release all resources associated with an engine operation. */
|
|
Packit |
3c2767 |
void
|
|
Packit |
3c2767 |
_assuan_reset (assuan_context_t ctx)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
if (ctx->engine.release)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
(*ctx->engine.release) (ctx);
|
|
Packit |
3c2767 |
ctx->engine.release = NULL;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* FIXME: Clean standard commands */
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/* Release all resources associated with the given context. */
|
|
Packit |
3c2767 |
void
|
|
Packit |
3c2767 |
assuan_release (assuan_context_t ctx)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
if (! ctx)
|
|
Packit |
3c2767 |
return;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
TRACE (ctx, ASSUAN_LOG_CTX, "assuan_release", ctx);
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
_assuan_reset (ctx);
|
|
Packit |
3c2767 |
/* None of the members that are our responsibility requires
|
|
Packit |
3c2767 |
deallocation. To avoid sensitive data in the line buffers we
|
|
Packit |
3c2767 |
wipe them out, though. Note that we can't wipe the entire
|
|
Packit |
3c2767 |
context because it also has a pointer to the actual free(). */
|
|
Packit |
3c2767 |
wipememory (&ctx->inbound, sizeof ctx->inbound);
|
|
Packit |
3c2767 |
wipememory (&ctx->outbound, sizeof ctx->outbound);
|
|
Packit |
3c2767 |
_assuan_free (ctx, ctx);
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/*
|
|
Packit |
3c2767 |
Version number stuff.
|
|
Packit |
3c2767 |
*/
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
static const char*
|
|
Packit |
3c2767 |
parse_version_number (const char *s, int *number)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
int val = 0;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
if (*s == '0' && digitp (s[1]))
|
|
Packit |
3c2767 |
return NULL; /* Leading zeros are not allowed. */
|
|
Packit |
3c2767 |
for (; digitp (*s); s++)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
val *= 10;
|
|
Packit |
3c2767 |
val += *s - '0';
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
*number = val;
|
|
Packit |
3c2767 |
return val < 0 ? NULL : s;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
static const char *
|
|
Packit |
3c2767 |
parse_version_string (const char *s, int *major, int *minor, int *micro)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
s = parse_version_number (s, major);
|
|
Packit |
3c2767 |
if (!s || *s != '.')
|
|
Packit |
3c2767 |
return NULL;
|
|
Packit |
3c2767 |
s++;
|
|
Packit |
3c2767 |
s = parse_version_number (s, minor);
|
|
Packit |
3c2767 |
if (!s || *s != '.')
|
|
Packit |
3c2767 |
return NULL;
|
|
Packit |
3c2767 |
s++;
|
|
Packit |
3c2767 |
s = parse_version_number (s, micro);
|
|
Packit |
3c2767 |
if (!s)
|
|
Packit |
3c2767 |
return NULL;
|
|
Packit |
3c2767 |
return s; /* Patchlevel. */
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
static const char *
|
|
Packit |
3c2767 |
compare_versions (const char *my_version, const char *req_version)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
int my_major, my_minor, my_micro;
|
|
Packit |
3c2767 |
int rq_major, rq_minor, rq_micro;
|
|
Packit |
3c2767 |
const char *my_plvl, *rq_plvl;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
if (!req_version)
|
|
Packit |
3c2767 |
return my_version;
|
|
Packit |
3c2767 |
if (!my_version)
|
|
Packit |
3c2767 |
return NULL;
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
my_plvl = parse_version_string (my_version, &my_major, &my_minor, &my_micro);
|
|
Packit |
3c2767 |
if (!my_plvl)
|
|
Packit |
3c2767 |
return NULL; /* Very strange: our own version is bogus. */
|
|
Packit |
3c2767 |
rq_plvl = parse_version_string(req_version,
|
|
Packit |
3c2767 |
&rq_major, &rq_minor, &rq_micro);
|
|
Packit |
3c2767 |
if (!rq_plvl)
|
|
Packit |
3c2767 |
return NULL; /* Requested version string is invalid. */
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
if (my_major > rq_major
|
|
Packit |
3c2767 |
|| (my_major == rq_major && my_minor > rq_minor)
|
|
Packit |
3c2767 |
|| (my_major == rq_major && my_minor == rq_minor
|
|
Packit |
3c2767 |
&& my_micro > rq_micro)
|
|
Packit |
3c2767 |
|| (my_major == rq_major && my_minor == rq_minor
|
|
Packit |
3c2767 |
&& my_micro == rq_micro))
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
return my_version;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
return NULL;
|
|
Packit |
3c2767 |
}
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
|
|
Packit |
3c2767 |
/*
|
|
Packit |
3c2767 |
* Check that the the version of the library is at minimum REQ_VERSION
|
|
Packit |
3c2767 |
* and return the actual version string; return NULL if the condition
|
|
Packit |
3c2767 |
* is not met. If NULL is passed to this function, no check is done
|
|
Packit |
3c2767 |
* and the version string is simply returned.
|
|
Packit |
3c2767 |
*/
|
|
Packit |
3c2767 |
const char *
|
|
Packit |
3c2767 |
assuan_check_version (const char *req_version)
|
|
Packit |
3c2767 |
{
|
|
Packit |
3c2767 |
if (req_version && req_version[0] == 1 && req_version[1] == 1)
|
|
Packit |
3c2767 |
return _assuan_sysutils_blurb ();
|
|
Packit |
3c2767 |
return compare_versions (PACKAGE_VERSION, req_version);
|
|
Packit |
3c2767 |
}
|