]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/openssl.c
57fea7cacf09ac33d051f3fe7b7262e504738c51
[bacula/bacula] / bacula / src / lib / openssl.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2005-2011 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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(50, "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 #ifdef HAVE_WIN32
98    return (unsigned long)getpid();
99 #else
100    /*
101     * Comparison without use of pthread_equal() is mandated by the OpenSSL API 
102     *
103     * Note: this creates problems with the new Win32 pthreads
104     *   emulation code, which defines pthread_t as a structure.
105     */
106    return ((unsigned long)pthread_self());
107 #endif
108 }
109
110 /*
111  * Allocate a dynamic OpenSSL mutex
112  */
113 static struct CRYPTO_dynlock_value *openssl_create_dynamic_mutex (const char *file, int line)
114 {
115    struct CRYPTO_dynlock_value *dynlock;
116    int stat;
117
118    dynlock = (struct CRYPTO_dynlock_value *)malloc(sizeof(struct CRYPTO_dynlock_value));
119
120    if ((stat = pthread_mutex_init(&dynlock->mutex, NULL)) != 0) {
121       berrno be;
122       Jmsg1(NULL, M_ABORT, 0, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(stat));
123    }
124
125    return dynlock;
126 }
127
128 static void openssl_update_dynamic_mutex(int mode, struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
129 {
130    if (mode & CRYPTO_LOCK) {
131       P(dynlock->mutex);
132    } else {
133       V(dynlock->mutex);
134    }
135 }
136
137 static void openssl_destroy_dynamic_mutex(struct CRYPTO_dynlock_value *dynlock, const char *file, int line)
138 {
139    int stat;
140
141    if ((stat = pthread_mutex_destroy(&dynlock->mutex)) != 0) {
142       berrno be;
143       Jmsg1(NULL, M_ABORT, 0, _("Unable to destroy mutex: ERR=%s\n"), be.bstrerror(stat));
144    }
145
146    free(dynlock);
147 }
148
149 /*
150  * (Un)Lock a static OpenSSL mutex
151  */
152 static void openssl_update_static_mutex (int mode, int i, const char *file, int line)
153 {
154    if (mode & CRYPTO_LOCK) {
155       P(mutexes[i]);
156    } else {
157       V(mutexes[i]);
158    }
159 }
160
161 /*
162  * Initialize OpenSSL thread support
163  *  Returns: 0 on success
164  *           errno on failure
165  */
166 int openssl_init_threads (void)
167 {
168    int i, numlocks;
169    int stat;
170
171
172    /* Set thread ID callback */
173    CRYPTO_set_id_callback(get_openssl_thread_id);
174
175    /* Initialize static locking */
176    numlocks = CRYPTO_num_locks();
177    mutexes = (pthread_mutex_t *) malloc(numlocks * sizeof(pthread_mutex_t));
178    for (i = 0; i < numlocks; i++) {
179       if ((stat = pthread_mutex_init(&mutexes[i], NULL)) != 0) {
180          berrno be;
181          Jmsg1(NULL, M_FATAL, 0, _("Unable to init mutex: ERR=%s\n"), be.bstrerror(stat));
182          return stat;
183       }
184    }
185
186    /* Set static locking callback */
187    CRYPTO_set_locking_callback(openssl_update_static_mutex);
188
189    /* Initialize dyanmic locking */
190    CRYPTO_set_dynlock_create_callback(openssl_create_dynamic_mutex);
191    CRYPTO_set_dynlock_lock_callback(openssl_update_dynamic_mutex);
192    CRYPTO_set_dynlock_destroy_callback(openssl_destroy_dynamic_mutex);
193
194    return 0;
195 }
196
197 /*
198  * Clean up OpenSSL threading support
199  */
200 void openssl_cleanup_threads(void)
201 {
202    int i, numlocks;
203    int stat;
204
205    /* Unset thread ID callback */
206    CRYPTO_set_id_callback(NULL);
207   
208    /* Deallocate static lock mutexes */
209    numlocks = CRYPTO_num_locks();
210    for (i = 0; i < numlocks; i++) {
211       if ((stat = pthread_mutex_destroy(&mutexes[i])) != 0) {
212          berrno be;
213          /* We don't halt execution, reporting the error should be sufficient */
214          Jmsg1(NULL, M_ERROR, 0, _("Unable to destroy mutex: ERR=%s\n"), 
215                be.bstrerror(stat));
216       }
217    }
218
219    /* Unset static locking callback */
220    CRYPTO_set_locking_callback(NULL);
221
222    /* Free static lock array */
223    free(mutexes);
224
225    /* Unset dynamic locking callbacks */
226    CRYPTO_set_dynlock_create_callback(NULL);
227    CRYPTO_set_dynlock_lock_callback(NULL);
228    CRYPTO_set_dynlock_destroy_callback(NULL);
229 }
230
231
232 /*
233  * Seed OpenSSL PRNG
234  *  Returns: 1 on success
235  *           0 on failure
236  */
237 int openssl_seed_prng (void)
238 {
239    const char *names[]  = { "/dev/urandom", "/dev/random", NULL };
240    int i;
241
242    // ***FIXME***
243    // Win32 Support
244    // Read saved entropy?
245
246    for (i = 0; names[i]; i++) {
247       if (RAND_load_file(names[i], 1024) != -1) {
248          /* Success */
249          return 1;
250       }
251    }
252
253    /* Fail */
254    return 0;
255 }
256
257 /*
258  * Save OpenSSL Entropy
259  *  Returns: 1 on success
260  *           0 on failure
261  */
262 int openssl_save_prng (void)
263 {
264    // ***FIXME***
265    // Implement PRNG state save
266    return 1;
267 }
268
269 #endif /* HAVE_OPENSSL */