Blame src/assuan.c

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
}