]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/openssl.c
More tweaks to crypto and bsock
[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(get_jcr_from_tid(), 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(get_jcr_from_tid(), M_ABORT, 0, _("Unable to init mutex: ERR=%s\n"), 
119             be.bstrerror(stat));
120    }
121
122    return dynlock;
123 }
124
125 static void openssl_update_dynamic_mutex(int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
126 {
127    if (mode & CRYPTO_LOCK) {
128       P(dynlock->mutex);
129    } else {
130       V(dynlock->mutex);
131    }
132 }
133
134 static void openssl_destroy_dynamic_mutex(struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
135 {
136    int stat;
137
138    if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
139       berrno be;
140       Jmsg1(get_jcr_from_tid(), M_ABORT, 0, _("Unable to destroy mutex: ERR=%s\n"), 
141             be.bstrerror(stat));
142    }
143
144    free(dynlock);
145 }
146
147 /*
148  * (Un)Lock a static OpenSSL mutex
149  */
150 static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
151 {
152    if (mode & CRYPTO_LOCK) {
153       P(mutexes[i]);
154    } else {
155       V(mutexes[i]);
156    }
157 }
158
159 /*
160  * Initialize OpenSSL thread support
161  *  Returns: 0 on success
162  *           errno on failure
163  */
164 int openssl_init_threads (void)
165 {
166    int i, numlocks;
167    int stat;
168
169
170    /* Set thread ID callback */
171    CRYPTO_set_id_callback(get_openssl_thread_id);
172
173    /* Initialize static locking */
174    numlocks = CRYPTO_num_locks();
175    mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
176    for (i = 0; i < numlocks; i++) {
177       if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
178          berrno be;
179          Jmsg1(get_jcr_from_tid(), M_ERROR, 0, _("Unable to init mutex: ERR=%s\n"), 
180                be.bstrerror(stat));
181          return stat;
182       }
183    }
184
185    /* Set static locking callback */
186    CRYPTO_set_locking_callback(openssl_update_static_mutex);
187
188    /* Initialize dyanmic locking */
189    CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
190    CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
191    CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
192
193    return 0;
194 }
195
196 /*
197  * Clean up OpenSSL threading support
198  */
199 void openssl_cleanup_threads(void)
200 {
201    int i, numlocks;
202    int stat;
203
204    /* Unset thread ID callback */
205    CRYPTO_set_id_callback(NULL);
206   
207    /* Deallocate static lock mutexes */
208    numlocks = CRYPTO_num_locks();
209    for (i = 0; i < numlocks; i++) {
210       if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
211          berrno be;
212          /* We don't halt execution, reporting the error should be sufficient */
213          Jmsg1(get_jcr_from_tid(), M_ERROR, 0, _("Unable to destroy mutex: ERR=%s\n"), 
214                be.bstrerror(stat));
215       }
216    }
217
218    /* Unset static locking callback */
219    CRYPTO_set_locking_callback(NULL);
220
221    /* Free static lock array */
222    free(mutexes);
223
224    /* Unset dynamic locking callbacks */
225    CRYPTO_set_dynlock_create_callback(NULL);
226    CRYPTO_set_dynlock_lock_callback(NULL);
227    CRYPTO_set_dynlock_destroy_callback(NULL);
228 }
229
230
231 /*
232  * Seed OpenSSL PRNG
233  *  Returns: 1 on success
234  *           0 on failure
235  */
236 int openssl_seed_prng (void)
237 {
238    const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
239    int i;
240
241    // ***FIXME***
242    // Win32 Support
243    // Read saved entropy?
244
245    for (i = 0; names[i]; i++) {
246       if (RAND_load_file(names[i], 1024) != -1) {
247          /* Success */
248          return 1;
249       }
250    }
251
252    /* Fail */
253    return 0;
254 }
255
256 /*
257  * Save OpenSSL Entropy
258  *  Returns: 1 on success
259  *           0 on failure
260  */
261 int openssl_save_prng (void)
262 {
263    // ***FIXME***
264    // Implement PRNG state save
265    return 1;
266 }
267
268 #endif /* HAVE_OPENSSL */