Page MenuHome GnuPG

global.c
No OneTemporary

global.c

/* global.c - global control functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 2004, 2005, 2006 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
* Libgcrypt 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.
*
* Libgcrypt 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include "g10lib.h"
#include "cipher.h"
#include "stdmem.h" /* our own memory allocator */
#include "secmem.h" /* our own secmem allocator */
#include "ath.h"
/****************
* flag bits: 0 : general cipher debug
* 1 : general MPI debug
*/
static unsigned int debug_flags;
/* Controlled by global_init(). */
static int any_init_done;
/* Memory management. */
static gcry_handler_alloc_t alloc_func;
static gcry_handler_alloc_t alloc_secure_func;
static gcry_handler_secure_check_t is_secure_func;
static gcry_handler_realloc_t realloc_func;
static gcry_handler_free_t free_func;
static gcry_handler_no_mem_t outofcore_handler;
static void *outofcore_handler_value;
static int no_secure_memory;
/* This is our handmade constructor. It gets called by any function
likely to be called at startup. The suggested way for an
application to make sure that this has been called is by using
gcry_check_version. */
static void
global_init (void)
{
gcry_error_t err = 0;
if (any_init_done)
return;
any_init_done = 1;
err = ath_init ();
if (err)
goto fail;
err = _gcry_cipher_init ();
if (err)
goto fail;
err = _gcry_md_init ();
if (err)
goto fail;
err = _gcry_pk_init ();
if (err)
goto fail;
#if 0
/* FIXME? */
err = _gcry_ac_init ();
if (err)
goto fail;
#endif
return;
fail:
/* FIXME: use `err'? */
BUG ();
}
/* Version number parsing. */
/* This function parses the first portion of the version number S and
stores it in *NUMBER. On sucess, this function returns a pointer
into S starting with the first character, which is not part of the
initial number portion; on failure, NULL is returned. */
static const char*
parse_version_number( const char *s, int *number )
{
int val = 0;
if( *s == '0' && isdigit(s[1]) )
return NULL; /* leading zeros are not allowed */
for ( ; isdigit(*s); s++ ) {
val *= 10;
val += *s - '0';
}
*number = val;
return val < 0? NULL : s;
}
/* This function breaks up the complete string-representation of the
version number S, which is of the following struture: <major
number>.<minor number>.<micro number><patch level>. The major,
minor and micro number components will be stored in *MAJOR, *MINOR
and *MICRO.
On success, the last component, the patch level, will be returned;
in failure, NULL will be returned. */
static const char *
parse_version_string( const char *s, int *major, int *minor, int *micro )
{
s = parse_version_number( s, major );
if( !s || *s != '.' )
return NULL;
s++;
s = parse_version_number( s, minor );
if( !s || *s != '.' )
return NULL;
s++;
s = parse_version_number( s, micro );
if( !s )
return NULL;
return s; /* patchlevel */
}
/* If REQ_VERSION is non-NULL, check that the version of the library
is at minimum the requested one. Returns the string representation
of the library version if the condition is satisfied; return NULL
if the requested version is newer than that of the library.
If a NULL is passed to this function, no check is done, but the
string representation of the library is simply returned. */
const char *
gcry_check_version( const char *req_version )
{
const char *ver = VERSION;
int my_major, my_minor, my_micro;
int rq_major, rq_minor, rq_micro;
const char *my_plvl, *rq_plvl;
/* Initialize library. */
global_init ();
if ( !req_version )
/* Caller wants our version number. */
return ver;
/* Parse own version number. */
my_plvl = parse_version_string( ver, &my_major, &my_minor, &my_micro );
if ( !my_plvl )
/* very strange our own version is bogus. Shouldn't we use
assert() here and bail out in case this happens? -mo. */
return NULL;
/* Parse requested version number. */
rq_plvl = parse_version_string( req_version, &rq_major, &rq_minor,
&rq_micro );
if ( !rq_plvl )
/* req version string is invalid, this can happen. */
return NULL;
/* Compare version numbers. */
if ( my_major > rq_major
|| (my_major == rq_major && my_minor > rq_minor)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro > rq_micro)
|| (my_major == rq_major && my_minor == rq_minor
&& my_micro == rq_micro
&& strcmp( my_plvl, rq_plvl ) >= 0) ) {
return ver;
}
return NULL;
}
/* Command dispatcher function, acting as general control
function. */
gcry_error_t
gcry_control (enum gcry_ctl_cmds cmd, ...)
{
gcry_err_code_t err = GPG_ERR_NO_ERROR;
static int init_finished = 0;
va_list arg_ptr;
va_start (arg_ptr, cmd);
switch (cmd)
{
case GCRYCTL_ENABLE_M_GUARD:
_gcry_private_enable_m_guard ();
break;
case GCRYCTL_ENABLE_QUICK_RANDOM:
_gcry_enable_quick_random_gen ();
break;
case GCRYCTL_FAKED_RANDOM_P:
/* Return an error if the RNG is faked one (i.e. enabled by
ENABLE_QUICK_RANDOM. */
if (_gcry_random_is_faked ())
err = GPG_ERR_GENERAL;
break;
case GCRYCTL_DUMP_RANDOM_STATS:
_gcry_random_dump_stats ();
break;
case GCRYCTL_DUMP_MEMORY_STATS:
/*m_print_stats("[fixme: prefix]");*/
break;
case GCRYCTL_DUMP_SECMEM_STATS:
_gcry_secmem_dump_stats ();
break;
case GCRYCTL_DROP_PRIVS:
global_init ();
_gcry_secmem_init (0);
break;
case GCRYCTL_DISABLE_SECMEM:
global_init ();
no_secure_memory = 1;
break;
case GCRYCTL_INIT_SECMEM:
global_init ();
_gcry_secmem_init (va_arg (arg_ptr, unsigned int));
if ((_gcry_secmem_get_flags () & GCRY_SECMEM_FLAG_NOT_LOCKED))
err = GPG_ERR_GENERAL;
break;
case GCRYCTL_TERM_SECMEM:
global_init ();
_gcry_secmem_term ();
break;
case GCRYCTL_DISABLE_SECMEM_WARN:
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
| GCRY_SECMEM_FLAG_NO_WARNING));
break;
case GCRYCTL_SUSPEND_SECMEM_WARN:
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
| GCRY_SECMEM_FLAG_SUSPEND_WARNING));
break;
case GCRYCTL_RESUME_SECMEM_WARN:
_gcry_secmem_set_flags ((_gcry_secmem_get_flags ()
& ~GCRY_SECMEM_FLAG_SUSPEND_WARNING));
break;
case GCRYCTL_USE_SECURE_RNDPOOL:
global_init ();
_gcry_secure_random_alloc (); /* put random number into secure memory */
break;
case GCRYCTL_SET_RANDOM_SEED_FILE:
_gcry_set_random_seed_file (va_arg (arg_ptr, const char *));
break;
case GCRYCTL_UPDATE_RANDOM_SEED_FILE:
_gcry_update_random_seed_file ();
break;
case GCRYCTL_SET_VERBOSITY:
_gcry_set_log_verbosity (va_arg (arg_ptr, int));
break;
case GCRYCTL_SET_DEBUG_FLAGS:
debug_flags |= va_arg (arg_ptr, unsigned int);
break;
case GCRYCTL_CLEAR_DEBUG_FLAGS:
debug_flags &= ~va_arg (arg_ptr, unsigned int);
break;
case GCRYCTL_DISABLE_INTERNAL_LOCKING:
global_init ();
break;
case GCRYCTL_ANY_INITIALIZATION_P:
if (any_init_done)
err = GPG_ERR_GENERAL;
break;
case GCRYCTL_INITIALIZATION_FINISHED_P:
if (init_finished)
err = GPG_ERR_GENERAL;
break;
case GCRYCTL_INITIALIZATION_FINISHED:
/* This is a hook which should be used by an application after
all initialization has been done and right before any threads
are started. It is not really needed but the only way to be
really sure that all initialization for thread-safety has
been done. */
if (! init_finished)
{
global_init ();
/* Do only a basic random initialization, i.e. init the
mutexes. */
_gcry_random_initialize (0);
init_finished = 1;
}
break;
case GCRYCTL_SET_THREAD_CBS:
err = ath_install (va_arg (arg_ptr, void *), any_init_done);
if (! err)
global_init ();
break;
case GCRYCTL_FAST_POLL:
/* We need to do make sure that the random pool is really
initialized so that the poll function is not a NOP. */
_gcry_random_initialize (1);
_gcry_fast_random_poll ();
break;
case GCRYCTL_SET_RANDOM_DAEMON_SOCKET:
_gcry_set_random_daemon_socket (va_arg (arg_ptr, const char *));
break;
case GCRYCTL_USE_RANDOM_DAEMON:
/* We need to do make sure that the random pool is really
initialized so that the poll function is not a NOP. */
_gcry_random_initialize (1);
_gcry_use_random_daemon (!! va_arg (arg_ptr, int));
break;
/* This command dumps information pertaining to the
configuration of libgcrypt to the logging stream. It may be
used before the intialization has been finished but not
before a gcry_version_check. */
case GCRYCTL_DUMP_CONFIG:
log_info ("version=%s\n", VERSION);
log_info ("mpi-asm=%s\n", _gcry_mpi_get_hw_config ());
break;
default:
err = GPG_ERR_INV_OP;
}
va_end(arg_ptr);
return gcry_error (err);
}
/* Return a pointer to a string containing a description of the error
code in the error value ERR. */
const char *
gcry_strerror (gcry_error_t err)
{
return gpg_strerror (err);
}
/* Return a pointer to a string containing a description of the error
source in the error value ERR. */
const char *
gcry_strsource (gcry_error_t err)
{
return gpg_strsource (err);
}
/* Retrieve the error code for the system error ERR. This returns
GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped (report
this). */
gcry_err_code_t
gcry_err_code_from_errno (int err)
{
return gpg_err_code_from_errno (err);
}
/* Retrieve the system error for the error code CODE. This returns 0
if CODE is not a system error code. */
int
gcry_err_code_to_errno (gcry_err_code_t code)
{
return gpg_err_code_from_errno (code);
}
/* Return an error value with the error source SOURCE and the system
error ERR. */
gcry_error_t
gcry_err_make_from_errno (gpg_err_source_t source, int err)
{
return gpg_err_make_from_errno (source, err);
}
/* Return an error value with the system error ERR. */
gcry_err_code_t
gcry_error_from_errno (int err)
{
return gcry_error (gpg_err_code_from_errno (err));
}
/****************
* NOTE: All 5 functions should be set. */
void
gcry_set_allocation_handler (gcry_handler_alloc_t new_alloc_func,
gcry_handler_alloc_t new_alloc_secure_func,
gcry_handler_secure_check_t new_is_secure_func,
gcry_handler_realloc_t new_realloc_func,
gcry_handler_free_t new_free_func)
{
global_init ();
alloc_func = new_alloc_func;
alloc_secure_func = new_alloc_secure_func;
is_secure_func = new_is_secure_func;
realloc_func = new_realloc_func;
free_func = new_free_func;
}
/****************
* Set an optional handler which is called in case the xmalloc functions
* ran out of memory. This handler may do one of these things:
* o free some memory and return true, so that the xmalloc function
* tries again.
* o Do whatever it like and return false, so that the xmalloc functions
* use the default fatal error handler.
* o Terminate the program and don't return.
*
* The handler function is called with 3 arguments: The opaque value set with
* this function, the requested memory size, and a flag with these bits
* currently defined:
* bit 0 set = secure memory has been requested.
*/
void
gcry_set_outofcore_handler( int (*f)( void*, size_t, unsigned int ),
void *value )
{
global_init ();
outofcore_handler = f;
outofcore_handler_value = value;
}
gcry_err_code_t
_gcry_malloc (size_t n, unsigned int flags, void **mem)
{
gcry_err_code_t err = 0;
void *m;
if ((flags & GCRY_ALLOC_FLAG_SECURE) && !no_secure_memory)
{
if (alloc_secure_func)
m = (*alloc_secure_func) (n);
else
m = _gcry_private_malloc_secure (n);
}
else
{
if (alloc_func)
m = (*alloc_func) (n);
else
m = _gcry_private_malloc (n);
}
if (!m)
{
/* Make sure that ERRNO has been set in case a user supplied
memory handler didn't it correctly. */
if (!errno)
errno = ENOMEM;
err = gpg_err_code_from_errno (errno);
}
else
*mem = m;
return err;
}
void *
gcry_malloc (size_t n)
{
void *mem = NULL;
_gcry_malloc (n, 0, &mem);
return mem;
}
void *
gcry_malloc_secure (size_t n)
{
void *mem = NULL;
_gcry_malloc (n, GCRY_ALLOC_FLAG_SECURE, &mem);
return mem;
}
int
gcry_is_secure (const void *a)
{
if (no_secure_memory)
return 0;
if (is_secure_func)
return is_secure_func (a) ;
return _gcry_private_is_secure (a);
}
void
_gcry_check_heap( const void *a )
{
(void)a;
/* FIXME: implement this*/
#if 0
if( some_handler )
some_handler(a)
else
_gcry_private_check_heap(a)
#endif
}
void *
gcry_realloc (void *a, size_t n)
{
void *p;
if (realloc_func)
p = realloc_func (a, n);
else
p = _gcry_private_realloc (a, n);
if (!p && !errno)
errno = ENOMEM;
return p;
}
void
gcry_free( void *p )
{
if( !p )
return;
if (free_func)
free_func (p);
else
_gcry_private_free (p);
}
void *
gcry_calloc (size_t n, size_t m)
{
size_t bytes;
void *p;
bytes = n * m; /* size_t is unsigned so the behavior on overflow is
defined. */
if (m && bytes / m != n)
{
errno = ENOMEM;
return NULL;
}
p = gcry_malloc (bytes);
if (p)
memset (p, 0, bytes);
return p;
}
void *
gcry_calloc_secure (size_t n, size_t m)
{
size_t bytes;
void *p;
bytes = n * m; /* size_t is unsigned so the behavior on overflow is
defined. */
if (m && bytes / m != n)
{
errno = ENOMEM;
return NULL;
}
p = gcry_malloc_secure (bytes);
if (p)
memset (p, 0, bytes);
return p;
}
/* Create and return a copy of the null-terminated string STRING. If
it is contained in secure memory, the copy will be contained in
secure memory as well. In an out-of-memory condition, NULL is
returned. */
char *
gcry_strdup (const char *string)
{
char *string_cp = NULL;
size_t string_n = 0;
string_n = strlen (string);
if (gcry_is_secure (string))
string_cp = gcry_malloc_secure (string_n + 1);
else
string_cp = gcry_malloc (string_n + 1);
if (string_cp)
strcpy (string_cp, string);
return string_cp;
}
void *
gcry_xmalloc( size_t n )
{
void *p;
while ( !(p = gcry_malloc( n )) ) {
if( !outofcore_handler
|| !outofcore_handler( outofcore_handler_value, n, 0 ) ) {
_gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
}
}
return p;
}
void *
gcry_xrealloc( void *a, size_t n )
{
void *p;
while ( !(p = gcry_realloc( a, n )) ) {
if( !outofcore_handler
|| !outofcore_handler( outofcore_handler_value, n,
gcry_is_secure(a)? 3:2 ) ) {
_gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
}
}
return p;
}
void *
gcry_xmalloc_secure( size_t n )
{
void *p;
while ( !(p = gcry_malloc_secure( n )) ) {
if( !outofcore_handler
|| !outofcore_handler( outofcore_handler_value, n, 1 ) ) {
_gcry_fatal_error(gpg_err_code_from_errno (errno),
_("out of core in secure memory"));
}
}
return p;
}
void *
gcry_xcalloc( size_t n, size_t m )
{
size_t nbytes;
void *p;
nbytes = n * m;
if (m && nbytes / m != n)
{
errno = ENOMEM;
_gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
}
p = gcry_xmalloc ( nbytes );
memset ( p, 0, nbytes );
return p;
}
void *
gcry_xcalloc_secure( size_t n, size_t m )
{
size_t nbytes;
void *p;
nbytes = n * m;
if (m && nbytes / m != n)
{
errno = ENOMEM;
_gcry_fatal_error(gpg_err_code_from_errno (errno), NULL );
}
p = gcry_xmalloc_secure ( nbytes );
memset ( p, 0, nbytes );
return p;
}
char *
gcry_xstrdup (const char *string)
{
char *p;
while ( !(p = gcry_strdup (string)) )
{
size_t n = strlen (string);
int is_sec = !!gcry_is_secure (string);
if (!outofcore_handler
|| !outofcore_handler (outofcore_handler_value, n, is_sec) )
{
_gcry_fatal_error (gpg_err_code_from_errno (errno),
is_sec? _("out of core in secure memory"):NULL);
}
}
return p;
}
int
_gcry_get_debug_flag( unsigned int mask )
{
return debug_flags & mask;
}
/* It is often useful to get some feedback of long running operations.
This function may be used to register a handler for this.
The callback function CB is used as:
void cb (void *opaque, const char *what, int printchar,
int current, int total);
Where WHAT is a string identifying the the type of the progress
output, PRINTCHAR the character usually printed, CURRENT the amount
of progress currently done and TOTAL the expected amount of
progress. A value of 0 for TOTAL indicates that there is no
estimation available.
Defined values for WHAT:
"need_entropy" X 0 number-of-bytes-required
When running low on entropy
"primegen" '\n' 0 0
Prime generated
'!'
Need to refresh the prime pool
'<','>'
Number of bits adjusted
'^'
Looking for a generator
'.'
Fermat tests on 10 candidates failed
':'
Restart with a new random value
'+'
Rabin Miller test passed
"pk_elg" '+','-','.','\n' 0 0
Only used in debugging mode.
"pk_dsa"
Only used in debugging mode.
*/
void
gcry_set_progress_handler (void (*cb)(void *,const char*,int, int, int),
void *cb_data)
{
#if USE_DSA
_gcry_register_pk_dsa_progress (cb, cb_data);
#endif
#if USE_ELGAMAL
_gcry_register_pk_elg_progress (cb, cb_data);
#endif
_gcry_register_primegen_progress (cb, cb_data);
_gcry_register_random_progress (cb, cb_data);
}

File Metadata

Mime Type
text/x-c
Expires
Mon, Dec 23, 5:20 PM (2 h, 18 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
0a/20/78e7c888657912b8616389a4c8b6

Event Timeline