]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/openssl.c
Tweak Win32 build
[bacula/bacula] / bacula / src / lib / openssl.c
1 /*
2  * openssl.c OpenSSL support functions
3  *
4  * Author: Landon Fuller <landonf@opendarwin.org>
5  *
6  * Version $Id$
7  *
8  * Copyright (C) 2005 Kern Sibbald
9  *
10  * This file was contributed to the Bacula project by Landon Fuller.
11  *
12  * Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
13  * no-charge, royalty-free, irrevocable copyright license to reproduce,
14  * prepare derivative works of, publicly display, publicly perform,
15  * sublicense, and distribute the original work contributed by Landon Fuller
16  * to the Bacula project in source or object form.
17  *
18  * If you wish to license these contributions under an alternate open source
19  * license please contact Landon Fuller <landonf@opendarwin.org>.
20  */
21 /*
22    Copyright (C) 2005-2006 Kern Sibbald
23
24    This program is free software; you can redistribute it and/or
25    modify it under the terms of the GNU General Public License
26    version 2 as amended with additional clauses defined in the
27    file LICENSE in the main source directory.
28
29    This program is distributed in the hope that it will be useful,
30    but WITHOUT ANY WARRANTY; without even the implied warranty of
31    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
32    the file LICENSE for additional details.
33
34  */
35
36
37 #include "bacula.h"
38 #include <assert.h>
39
40 #ifdef HAVE_OPENSSL
41
42 /* Array of mutexes for use with OpenSSL static locking */
43 static pthread_mutex_t *mutexes;
44
45 /* OpenSSL dynamic locking structure */
46 struct CRYPTO_dynlock_value {
47    pthread_mutex_t mutex;
48 };
49
50
51 /*
52  * Post all per-thread openssl errors
53  */
54 void openssl_post_errors(int code, const char *errstring)
55 {
56    char buf[512];
57    unsigned long sslerr;
58
59    /* Pop errors off of the per-thread queue */
60    while((sslerr = ERR_get_error()) != 0) {
61       /* Acquire the human readable string */
62       ERR_error_string_n(sslerr, (char *) &buf, sizeof(buf));
63       Emsg2(M_ERROR, 0, "%s: ERR=%s\n", errstring, buf);
64    }
65 }
66
67 /*
68  * Return an OpenSSL thread ID
69  *  Returns: thread ID
70  *
71  */
72 static unsigned long get_openssl_thread_id (void)
73 {
74    /* Comparison without use of pthread_equal() is mandated by the OpenSSL API */
75    return ((unsigned long) pthread_self());
76 }
77
78 /*
79  * Allocate a dynamic OpenSSL mutex
80  */
81 static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line)
82 {
83    struct CRYPTO_dynlock_value *dynlock;
84    int stat;
85
86    dynlock = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value));
87
88    if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) {
89       Emsg1(M_ABORT, 0, _("Unable to init mutex: ERR=%s\n"), strerror(stat));
90    }
91
92    return dynlock;
93 }
94
95 static void openssl_update_dynamic_mutex (int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
96 {
97    if (mode & CRYPTO_LOCK) {
98       P(dynlock->mutex);
99    } else {
100       V(dynlock->mutex);
101    }
102 }
103
104 static void openssl_destroy_dynamic_mutex (struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
105 {
106    int stat;
107
108    if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
109       Emsg1(M_ABORT, 0, _("Unable to destroy mutex: ERR=%s\n"), strerror(stat));
110    }
111
112    free(dynlock);
113 }
114
115 /*
116  * (Un)Lock a static OpenSSL mutex
117  */
118 static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
119 {
120    if (mode & CRYPTO_LOCK) {
121       P(mutexes[i]);
122    } else {
123       V(mutexes[i]);
124    }
125 }
126
127 /*
128  * Initialize OpenSSL thread support
129  *  Returns: 0 on success
130  *           errno on failure
131  */
132 int openssl_init_threads (void)
133 {
134    int i, numlocks;
135    int stat;
136
137
138    /* Set thread ID callback */
139    CRYPTO_set_id_callback(get_openssl_thread_id);
140
141    /* Initialize static locking */
142    numlocks = CRYPTO_num_locks();
143    mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
144    for (i = 0; i < numlocks; i++) {
145       if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
146          Emsg1(M_ERROR, 0, _("Unable to init mutex: ERR=%s\n"), strerror(stat));
147          return stat;
148       }
149    }
150
151    /* Set static locking callback */
152    CRYPTO_set_locking_callback(openssl_update_static_mutex);
153
154    /* Initialize dyanmic locking */
155    CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
156    CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
157    CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
158
159    return 0;
160 }
161
162 /*
163  * Clean up OpenSSL threading support
164  */
165 void openssl_cleanup_threads (void)
166 {
167    int i, numlocks;
168    int stat;
169
170    /* Unset thread ID callback */
171    CRYPTO_set_id_callback(NULL);
172   
173    /* Deallocate static lock mutexes */
174    numlocks = CRYPTO_num_locks();
175    for (i = 0; i < numlocks; i++) {
176       if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
177          /* We don't halt execution, reporting the error should be sufficient */
178          Emsg1(M_ERROR, 0, _("Unable to destroy mutex: ERR=%s\n"), strerror(stat));
179       }
180    }
181
182    /* Unset static locking callback */
183    CRYPTO_set_locking_callback(NULL);
184
185    /* Free static lock array */
186    free(mutexes);
187
188    /* Unset dynamic locking callbacks */
189    CRYPTO_set_dynlock_create_callback(NULL);
190    CRYPTO_set_dynlock_lock_callback(NULL);
191    CRYPTO_set_dynlock_destroy_callback(NULL);
192 }
193
194
195 /*
196  * Seed OpenSSL PRNG
197  *  Returns: 1 on success
198  *           0 on failure
199  */
200 int openssl_seed_prng (void)
201 {
202    const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
203    int i;
204
205    // ***FIXME***
206    // Win32 Support
207    // Read saved entropy?
208
209    for (i = 0; names[i]; i++) {
210       if (RAND_load_file(names[i], 1024) != -1) {
211          /* Success */
212          return 1;
213       }
214    }
215
216    /* Fail */
217    return 0;
218 }
219
220 /*
221  * Save OpenSSL Entropy
222  *  Returns: 1 on success
223  *           0 on failure
224  */
225 int openssl_save_prng (void)
226 {
227    // ***FIXME***
228    // Implement PRNG state save
229    return 1;
230 }
231
232 #endif /* HAVE_OPENSSL */