Back to index

opendkim  2.6.2
opendkim-crypto.c
Go to the documentation of this file.
00001 /*
00002 **  Copyright (c) 2008, 2009 Sendmail, Inc. and its suppliers.
00003 **     All rights reserved.
00004 **
00005 **  Copyright (c) 2009, 2010 The OpenDKIM Project.  All rights reserved.
00006 **
00007 **  $Id: opendkim-crypto.c,v 1.9.22.1 2010/10/27 21:43:09 cm-msk Exp $
00008 */
00009 
00010 #ifndef lint
00011 static char opendkim_crypto_c_id[] = "@(#)$Id: opendkim-crypto.c,v 1.9.22.1 2010/10/27 21:43:09 cm-msk Exp $";
00012 #endif /* !lint */
00013 
00014 #include "build-config.h"
00015 
00016 /* system includes */
00017 #include <sys/types.h>
00018 #ifdef HAVE_STDBOOL_H
00019 # include <stdbool.h>
00020 #endif /* HAVE_STDBOOL_H */
00021 #include <pthread.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <assert.h>
00025 #include <errno.h>
00026 
00027 #ifdef USE_GNUTLS
00028 /* libgnutls includes */
00029 # include <gnutls/gnutls.h>
00030 #else /* USE_GNUTLS */
00031 /* openssl includes */
00032 # include <openssl/crypto.h>
00033 # include <openssl/evp.h>
00034 # include <openssl/err.h>
00035 # include <openssl/ssl.h>
00036 # include <openssl/conf.h>
00037 #endif /* USE_GNUTLS */
00038 
00039 /* opendkim includes */
00040 #include "opendkim-crypto.h"
00041 #include "opendkim.h"
00042 
00043 /* globals */
00044 static _Bool crypto_init_done = FALSE;
00045 
00046 #ifdef USE_GNUTLS
00047 
00048 static pthread_key_t logkey;
00049 
00050 /*
00051 **  DKIMF_CRYPTO_LOG -- log something from inside GnuTLS
00052 **
00053 **  Parameters:
00054 **     sev -- log level
00055 **     str -- string to log
00056 **
00057 **  Return value:
00058 **     None.
00059 */
00060 
00061 static void
00062 dkimf_crypto_log(int sev, const char *str)
00063 {
00064        char *buf;
00065 
00066        buf = pthread_getspecific(logkey);
00067        if (buf == NULL)
00068        {
00069               buf = malloc(BUFRSZ);
00070               pthread_setspecific(logkey, buf);
00071        }
00072 
00073        if (buf != NULL)
00074               snprintf(buf, BUFRSZ, "%s", str);
00075 }
00076 
00077 /*
00078 **  DKIMF_CRYPTO_GETERROR -- return any logged error
00079 **
00080 **  Parameters:
00081 **     None.
00082 **
00083 **  Return value:
00084 **     Pointer to the most recently logged error, or NULL if none.
00085 */
00086 
00087 const char *
00088 dkimf_crypto_geterror(void)
00089 {
00090        return (const char *) pthread_getspecific(logkey);
00091 }
00092 
00093 /*
00094 **  DKIMF_CRYPTO_INIT -- set up GnuTLS dependencies
00095 **
00096 **  Parameters:
00097 **     None.
00098 **
00099 **  Return value:
00100 **     0 -- success
00101 **     !0 -- an error code (a la errno)
00102 */
00103 
00104 int
00105 dkimf_crypto_init(void)
00106 {
00107        (void) gnutls_global_set_log_function(dkimf_crypto_log);
00108        (void) gnutls_global_init();
00109 
00110        (void) pthread_key_create(&logkey, free);
00111 
00112        return 0;
00113 }
00114 
00115 /*
00116 **  DKIMF_CRYPTO_FREE -- tear down libGnuTLS dependencies
00117 **
00118 **  Parameters:
00119 **     None.
00120 **
00121 **  Return value:
00122 **     None.
00123 */
00124 
00125 void
00126 dkimf_crypto_free(void)
00127 {
00128        (void) gnutls_global_deinit();
00129 
00130        (void) pthread_key_delete(logkey);
00131 
00132        return;
00133 }
00134 
00135 #else /* USE_GNUTLS */
00136 
00137 static pthread_mutex_t id_lock;
00138 static pthread_key_t id_key;
00139 static unsigned int nmutexes = 0;
00140 static unsigned long threadid = 0L;
00141 static pthread_mutex_t *mutexes = NULL;
00142 
00143 /*
00144 **  DKIMF_CRYPTO_LOCK_CALLBACK -- locking callback for libcrypto
00145 **
00146 **  Parameters:
00147 **     mode -- lock mode (request from libcrypto)
00148 **     idx -- lock index for this request
00149 **     file -- file making the request
00150 **     line -- line making the request
00151 **
00152 **  Return value:
00153 **     None.
00154 */
00155 
00156 static void
00157 dkimf_crypto_lock_callback(int mode, int idx,
00158                            /* UNUSED */ const char *file,
00159                            /* UNUSED */ int line)
00160 {
00161        int status;
00162 
00163        if ((mode & CRYPTO_LOCK) != 0)
00164               status = pthread_mutex_lock(&mutexes[idx]);
00165        else
00166               status = pthread_mutex_unlock(&mutexes[idx]);
00167 
00168        assert(status == 0);
00169 }
00170 
00171 /*
00172 **  DKIMF_CRYPTO_GET_ID -- generate/retrieve thread ID
00173 **
00174 **  Parameters:
00175 **
00176 **  Return value:
00177 **
00178 */
00179 
00180 static unsigned long
00181 dkimf_crypto_get_id(void)
00182 {
00183        unsigned long *id;
00184 
00185        id = pthread_getspecific(id_key);
00186        if (id == NULL)
00187        {
00188               id = (unsigned long *) malloc(sizeof *id);
00189               assert(pthread_mutex_lock(&id_lock) == 0);
00190               threadid++;
00191               *id = threadid;
00192               assert(pthread_mutex_unlock(&id_lock) == 0);
00193               assert(pthread_setspecific(id_key, id) == 0);
00194        }
00195 
00196        return *id;
00197 }
00198 
00199 /*
00200 **  DKIMF_CRYPTO_FREE_ID -- destroy thread ID
00201 **
00202 **  Parameters:
00203 **     ptr -- pointer to be destroyed
00204 **
00205 **  Return value:
00206 **     None.
00207 */
00208 
00209 static void
00210 dkimf_crypto_free_id(void *ptr)
00211 {
00212        /*
00213        **  Trick dkimf_crypto_get_id(); the thread-specific pointer has
00214        **  already been cleared at this point, but dkimf_crypto_get_id()
00215        **  may be called by ERR_remove_state() which will then allocate a
00216        **  new thread pointer if the thread-specific pointer is NULL.  This
00217        **  means a memory leak of thread IDs and, on Solaris, an infinite loop
00218        **  because the destructor (indirectly) re-sets the thread-specific
00219        **  pointer to something not NULL.  See pthread_key_create(3).
00220        */
00221 
00222        if (ptr != NULL)
00223        {
00224               assert(pthread_setspecific(id_key, ptr) == 0);
00225 
00226               ERR_remove_state(0);
00227 
00228               free(ptr);
00229 
00230               /* now we can actually clear it for real */
00231               assert(pthread_setspecific(id_key, NULL) == 0);
00232        }
00233 }
00234 
00235 /*
00236 **  DKIMF_CRYPTO_DYN_CREATE -- dynamically create a mutex
00237 **
00238 **  Parameters:
00239 **     file -- file making the request
00240 **     line -- line making the request
00241 **
00242 **  Return value:
00243 **     Pointer to the new mutex.
00244 */
00245 
00246 static struct CRYPTO_dynlock_value *
00247 dkimf_crypto_dyn_create(/* UNUSED */ const char *file,
00248                         /* UNUSED */ int line)
00249 {
00250        int err;
00251        pthread_mutex_t *new;
00252 
00253        new = (pthread_mutex_t *) malloc(sizeof(pthread_mutex_t));
00254        if (new == NULL)
00255               return NULL;
00256 
00257        err = pthread_mutex_init(new, NULL);
00258        if (err != 0)
00259        {
00260               free(new);
00261               return NULL;
00262        }
00263 
00264        return (void *) new;
00265 }
00266 
00267 /*
00268 **  DKIMF_CRYPTO_DYN_DESTROY -- destroy a dynamic mutex
00269 **
00270 **  Parameters:
00271 **     mutex -- pointer to the mutex to destroy
00272 **     file -- file making the request
00273 **     line -- line making the request
00274 **
00275 **  Return value:
00276 **     None.
00277 */
00278 
00279 static void
00280 dkimf_crypto_dyn_destroy(struct CRYPTO_dynlock_value *lock,
00281                          /* UNUSED */ const char *file,
00282                          /* UNUSED */ int line)
00283 {
00284        assert(lock != NULL);
00285 
00286        pthread_mutex_destroy((pthread_mutex_t *) lock);
00287 
00288        free(lock);
00289 }
00290 
00291 /*
00292 **  DKIMF_CRYPTO_DYN_LOCK -- lock/unlock a dynamic mutex
00293 **
00294 **  Parameters:
00295 **     mode -- lock mode (request from libcrypto)
00296 **     mutex -- pointer to the mutex to lock/unlock
00297 **     file -- file making the request
00298 **     line -- line making the request
00299 **
00300 **  Return value:
00301 **     None.
00302 */
00303 
00304 static void
00305 dkimf_crypto_dyn_lock(int mode, struct CRYPTO_dynlock_value *lock,
00306                       /* UNUSED */ const char *file,
00307                       /* UNUSED */ int line)
00308 {
00309        int status;
00310 
00311        assert(lock != NULL);
00312 
00313        if ((mode & CRYPTO_LOCK) != 0)
00314               status = pthread_mutex_lock((pthread_mutex_t *) lock);
00315        else
00316               status = pthread_mutex_unlock((pthread_mutex_t *) lock);
00317 
00318        assert(status == 0);
00319 }
00320 
00321 /*
00322 **  DKIMF_CRYPTO_INIT -- set up openssl dependencies
00323 **
00324 **  Parameters:
00325 **     None.
00326 **
00327 **  Return value:
00328 **     0 -- success
00329 **     !0 -- an error code (a la errno)
00330 */
00331 
00332 int
00333 dkimf_crypto_init(void)
00334 {
00335        int c;
00336        int n;
00337        int status;
00338 
00339        n = CRYPTO_num_locks();
00340        mutexes = (pthread_mutex_t *) malloc(n * sizeof(pthread_mutex_t));
00341        if (mutexes == NULL)
00342               return errno;
00343 
00344        for (c = 0; c < n; c++)
00345        {
00346               status = pthread_mutex_init(&mutexes[c], NULL);
00347               if (status != 0)
00348                      return status;
00349        }
00350 
00351        status = pthread_mutex_init(&id_lock, NULL);
00352        if (status != 0)
00353               return status;
00354 
00355        nmutexes = n;
00356 
00357        status = pthread_key_create(&id_key, &dkimf_crypto_free_id);
00358        if (status != 0)
00359               return status;
00360 
00361        SSL_load_error_strings();
00362        SSL_library_init();
00363        ERR_load_crypto_strings();
00364 
00365        CRYPTO_set_id_callback(&dkimf_crypto_get_id);
00366        CRYPTO_set_locking_callback(&dkimf_crypto_lock_callback);
00367        CRYPTO_set_dynlock_create_callback(&dkimf_crypto_dyn_create);
00368        CRYPTO_set_dynlock_lock_callback(&dkimf_crypto_dyn_lock);
00369        CRYPTO_set_dynlock_destroy_callback(&dkimf_crypto_dyn_destroy);
00370 
00371 #ifdef USE_OPENSSL_ENGINE
00372        if (!SSL_set_engine(NULL))
00373               return EINVAL;
00374 #endif /* USE_OPENSSL_ENGINE */
00375 
00376        crypto_init_done = TRUE;
00377 
00378        return 0;
00379 }
00380 
00381 /*
00382 **  DKIMF_CRYPTO_FREE -- tear down openssl dependencies
00383 **
00384 **  Parameters:
00385 **     None.
00386 **
00387 **  Return value:
00388 **     None.
00389 */
00390 
00391 void
00392 dkimf_crypto_free(void)
00393 {
00394        if (crypto_init_done)
00395        {
00396               CRYPTO_cleanup_all_ex_data();
00397               CONF_modules_free();
00398               EVP_cleanup();
00399               ERR_free_strings();
00400               ERR_remove_state(0);
00401 
00402               if (nmutexes > 0)
00403               {
00404                      unsigned int c;
00405 
00406                      for (c = 0; c < nmutexes; c++)
00407                             pthread_mutex_destroy(&mutexes[c]);
00408 
00409                      free(mutexes);
00410                      mutexes = NULL;
00411                      nmutexes = 0;
00412               }
00413 
00414               crypto_init_done = FALSE;
00415        }
00416 }
00417 
00418 #endif /* USE_GNUTLS */