]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/openssl.c
Move more bnet functions into the BSOCK class.
[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 plus additions
11    that are listed 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 void openssl_post_errors(int code, const char *errstring)
62 {
63    openssl_post_errors(NULL, code, errstring);
64 }
65
66
67 /*
68  * Post all per-thread openssl errors
69  */
70 void openssl_post_errors(JCR *jcr, int code, const char *errstring)
71 {
72    char buf[512];
73    unsigned long sslerr;
74
75    /* Pop errors off of the per-thread queue */
76    while((sslerr = ERR_get_error()) != 0) {
77       /* Acquire the human readable string */
78       ERR_error_string_n(sslerr, (char *) &buf, sizeof(buf));
79       Dmsg3(100, "jcr=%p %s: ERR=%s\n", jcr, errstring, buf);
80       Jmsg2(jcr, M_ERROR, 0, "%s: ERR=%s\n", errstring, buf);
81    }
82 }
83
84 /*
85  * Return an OpenSSL thread ID
86  *  Returns: thread ID
87  *
88  */
89 static unsigned long get_openssl_thread_id (void)
90 {
91    /* Comparison without use of pthread_equal() is mandated by the OpenSSL API */
92    return ((unsigned long) pthread_self());
93 }
94
95 /*
96  * Allocate a dynamic OpenSSL mutex
97  */
98 static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line)
99 {
100    struct CRYPTO_dynlock_value *dynlock;
101    int stat;
102
103    dynlock = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value));
104
105    if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) {
106       berrno be;
107       Emsg1(M_ABORT, 0, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(stat));
108    }
109
110    return dynlock;
111 }
112
113 static void openssl_update_dynamic_mutex (int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
114 {
115    if (mode & CRYPTO_LOCK) {
116       P(dynlock->mutex);
117    } else {
118       V(dynlock->mutex);
119    }
120 }
121
122 static void openssl_destroy_dynamic_mutex (struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
123 {
124    int stat;
125
126    if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
127       berrno be;
128       Emsg1(M_ABORT, 0, _("Unable to destroy mutex: ERR=%s\n"), be.bstrerror(stat));
129    }
130
131    free(dynlock);
132 }
133
134 /*
135  * (Un)Lock a static OpenSSL mutex
136  */
137 static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
138 {
139    if (mode & CRYPTO_LOCK) {
140       P(mutexes[i]);
141    } else {
142       V(mutexes[i]);
143    }
144 }
145
146 /*
147  * Initialize OpenSSL thread support
148  *  Returns: 0 on success
149  *           errno on failure
150  */
151 int openssl_init_threads (void)
152 {
153    int i, numlocks;
154    int stat;
155
156
157    /* Set thread ID callback */
158    CRYPTO_set_id_callback(get_openssl_thread_id);
159
160    /* Initialize static locking */
161    numlocks = CRYPTO_num_locks();
162    mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
163    for (i = 0; i < numlocks; i++) {
164       if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
165          berrno be;
166          Emsg1(M_ERROR, 0, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(stat));
167          return stat;
168       }
169    }
170
171    /* Set static locking callback */
172    CRYPTO_set_locking_callback(openssl_update_static_mutex);
173
174    /* Initialize dyanmic locking */
175    CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
176    CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
177    CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
178
179    return 0;
180 }
181
182 /*
183  * Clean up OpenSSL threading support
184  */
185 void openssl_cleanup_threads(void)
186 {
187    int i, numlocks;
188    int stat;
189
190    /* Unset thread ID callback */
191    CRYPTO_set_id_callback(NULL);
192   
193    /* Deallocate static lock mutexes */
194    numlocks = CRYPTO_num_locks();
195    for (i = 0; i < numlocks; i++) {
196       if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
197          berrno be;
198          /* We don't halt execution, reporting the error should be sufficient */
199          Emsg1(M_ERROR, 0, _("Unable to destroy mutex: ERR=%s\n"), be.bstrerror(stat));
200       }
201    }
202
203    /* Unset static locking callback */
204    CRYPTO_set_locking_callback(NULL);
205
206    /* Free static lock array */
207    free(mutexes);
208
209    /* Unset dynamic locking callbacks */
210    CRYPTO_set_dynlock_create_callback(NULL);
211    CRYPTO_set_dynlock_lock_callback(NULL);
212    CRYPTO_set_dynlock_destroy_callback(NULL);
213 }
214
215
216 /*
217  * Seed OpenSSL PRNG
218  *  Returns: 1 on success
219  *           0 on failure
220  */
221 int openssl_seed_prng (void)
222 {
223    const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
224    int i;
225
226    // ***FIXME***
227    // Win32 Support
228    // Read saved entropy?
229
230    for (i = 0; names[i]; i++) {
231       if (RAND_load_file(names[i], 1024) != -1) {
232          /* Success */
233          return 1;
234       }
235    }
236
237    /* Fail */
238    return 0;
239 }
240
241 /*
242  * Save OpenSSL Entropy
243  *  Returns: 1 on success
244  *           0 on failure
245  */
246 int openssl_save_prng (void)
247 {
248    // ***FIXME***
249    // Implement PRNG state save
250    return 1;
251 }
252
253 #endif /* HAVE_OPENSSL */