]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/openssl.c
kes Save jcr in thread specific data (tsd) for each thread.
[bacula/bacula] / bacula / src / lib / openssl.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2005-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * openssl.c OpenSSL support functions
30  *
31  * Author: Landon Fuller <landonf@opendarwin.org>
32  *
33  * Version $Id$
34  *
35  * This file was contributed to the Bacula project by Landon Fuller.
36  *
37  * Landon Fuller has been granted a perpetual, worldwide, non-exclusive,
38  * no-charge, royalty-free, irrevocable copyright license to reproduce,
39  * prepare derivative works of, publicly display, publicly perform,
40  * sublicense, and distribute the original work contributed by Landon Fuller
41  * to the Bacula project in source or object form.
42  *
43  * If you wish to license these contributions under an alternate open source
44  * license please contact Landon Fuller <landonf@opendarwin.org>.
45  */
46
47
48 #include "bacula.h"
49 #include <assert.h>
50
51 #ifdef HAVE_OPENSSL
52
53 /* Array of mutexes for use with OpenSSL static locking */
54 static pthread_mutex_t *mutexes;
55
56 /* OpenSSL dynamic locking structure */
57 struct CRYPTO_dynlock_value {
58    pthread_mutex_t mutex;
59 };
60
61 /*
62  * ***FIXME*** this is a sort of dummy to avoid having to
63  *   change all the existing code to pass either a jcr or
64  *   a NULL.  Passing a NULL causes the messages to be
65  *   printed by the daemon -- not very good :-(
66  */
67 void openssl_post_errors(int code, const char *errstring)
68 {
69    openssl_post_errors(NULL, code, errstring);
70 }
71
72
73 /*
74  * Post all per-thread openssl errors
75  */
76 void openssl_post_errors(JCR *jcr, int code, const char *errstring)
77 {
78    char buf[512];
79    unsigned long sslerr;
80
81    /* Pop errors off of the per-thread queue */
82    while((sslerr = ERR_get_error()) != 0) {
83       /* Acquire the human readable string */
84       ERR_error_string_n(sslerr, buf, sizeof(buf));
85       Dmsg3(100, "jcr=%p %s: ERR=%s\n", jcr, errstring, buf);
86       Qmsg2(jcr, M_ERROR, 0, "%s: ERR=%s\n", errstring, buf);
87    }
88 }
89
90 /*
91  * Return an OpenSSL thread ID
92  *  Returns: thread ID
93  *
94  */
95 static unsigned long get_openssl_thread_id(void)
96 {
97    /* Comparison without use of pthread_equal() is mandated by the OpenSSL API */
98    /*
99     * Note that this creates problems with the new Win32 pthreads
100     *   emulation code, which defines pthread_t as a structure. For
101     *   this reason, we continue to use a very old implementation.
102     */
103    return ((unsigned long)pthread_self());
104 }
105
106 /*
107  * Allocate a dynamic OpenSSL mutex
108  */
109 static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line)
110 {
111    struct CRYPTO_dynlock_value *dynlock;
112    int stat;
113
114    dynlock = (struct CRYPTO_dynlock_value *)malloc(sizeof(struct CRYPTO_dynlock_value));
115
116    if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) {
117       berrno be;
118       Jmsg1(NULL, M_ABORT, 0, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(stat));
119    }
120
121    return dynlock;
122 }
123
124 static void openssl_update_dynamic_mutex(int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
125 {
126    if (mode & CRYPTO_LOCK) {
127       P(dynlock->mutex);
128    } else {
129       V(dynlock->mutex);
130    }
131 }
132
133 static void openssl_destroy_dynamic_mutex(struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
134 {
135    int stat;
136
137    if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
138       berrno be;
139       Jmsg1(NULL, M_ABORT, 0, _("Unable to destroy mutex: ERR=%s\n"), be.bstrerror(stat));
140    }
141
142    free(dynlock);
143 }
144
145 /*
146  * (Un)Lock a static OpenSSL mutex
147  */
148 static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
149 {
150    if (mode & CRYPTO_LOCK) {
151       P(mutexes[i]);
152    } else {
153       V(mutexes[i]);
154    }
155 }
156
157 /*
158  * Initialize OpenSSL thread support
159  *  Returns: 0 on success
160  *           errno on failure
161  */
162 int openssl_init_threads (void)
163 {
164    int i, numlocks;
165    int stat;
166
167
168    /* Set thread ID callback */
169    CRYPTO_set_id_callback(get_openssl_thread_id);
170
171    /* Initialize static locking */
172    numlocks = CRYPTO_num_locks();
173    mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
174    for (i = 0; i < numlocks; i++) {
175       if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
176          berrno be;
177          Jmsg1(NULL, M_FATAL, 0, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(stat));
178          return stat;
179       }
180    }
181
182    /* Set static locking callback */
183    CRYPTO_set_locking_callback(openssl_update_static_mutex);
184
185    /* Initialize dyanmic locking */
186    CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
187    CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
188    CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
189
190    return 0;
191 }
192
193 /*
194  * Clean up OpenSSL threading support
195  */
196 void openssl_cleanup_threads(void)
197 {
198    int i, numlocks;
199    int stat;
200
201    /* Unset thread ID callback */
202    CRYPTO_set_id_callback(NULL);
203   
204    /* Deallocate static lock mutexes */
205    numlocks = CRYPTO_num_locks();
206    for (i = 0; i < numlocks; i++) {
207       if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
208          berrno be;
209          /* We don't halt execution, reporting the error should be sufficient */
210          Jmsg1(NULL, M_ERROR, 0, _("Unable to destroy mutex: ERR=%s\n"), 
211                be.bstrerror(stat));
212       }
213    }
214
215    /* Unset static locking callback */
216    CRYPTO_set_locking_callback(NULL);
217
218    /* Free static lock array */
219    free(mutexes);
220
221    /* Unset dynamic locking callbacks */
222    CRYPTO_set_dynlock_create_callback(NULL);
223    CRYPTO_set_dynlock_lock_callback(NULL);
224    CRYPTO_set_dynlock_destroy_callback(NULL);
225 }
226
227
228 /*
229  * Seed OpenSSL PRNG
230  *  Returns: 1 on success
231  *           0 on failure
232  */
233 int openssl_seed_prng (void)
234 {
235    const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
236    int i;
237
238    // ***FIXME***
239    // Win32 Support
240    // Read saved entropy?
241
242    for (i = 0; names[i]; i++) {
243       if (RAND_load_file(names[i], 1024) != -1) {
244          /* Success */
245          return 1;
246       }
247    }
248
249    /* Fail */
250    return 0;
251 }
252
253 /*
254  * Save OpenSSL Entropy
255  *  Returns: 1 on success
256  *           0 on failure
257  */
258 int openssl_save_prng (void)
259 {
260    // ***FIXME***
261    // Implement PRNG state save
262    return 1;
263 }
264
265 #endif /* HAVE_OPENSSL */