heimdal: import heimdal's trunk svn rev 23697 + lorikeet-heimdal patches
[amitay/samba.git] / source4 / heimdal / lib / hcrypto / engine.c
1 /*
2  * Copyright (c) 2006 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 RCSID("$Id$");
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include <engine.h>
45
46 #ifdef HAVE_DLFCN_H
47 #include <dlfcn.h>
48 #ifndef RTLD_NOW
49 #define RTLD_NOW 0
50 #endif
51 #endif
52
53 struct hc_engine {
54     int references;
55     char *name;
56     char *id;
57     void (*destroy)(ENGINE *);
58     const RSA_METHOD *rsa;
59     const DH_METHOD *dh;
60     const RAND_METHOD *rand;
61 };
62
63 int
64 ENGINE_finish(ENGINE *engine)
65 {
66     if (engine->references-- <= 0)
67         abort();
68     if (engine->references > 0)
69         return 1;
70
71     if (engine->name)
72         free(engine->name);
73     if (engine->id)
74         free(engine->id);
75     if(engine->destroy)
76         (*engine->destroy)(engine);
77
78     memset(engine, 0, sizeof(engine));
79     engine->references = -1;
80
81
82     free(engine);
83     return 1;
84 }
85
86 int
87 ENGINE_up_ref(ENGINE *engine)
88 {
89     if (engine->references < 0)
90         abort();
91     engine->references++;
92     return 1;
93 }
94
95 int
96 ENGINE_set_id(ENGINE *engine, const char *id)
97 {
98     engine->id = strdup(id);
99     return (engine->id == NULL) ? 0 : 1;
100 }
101
102 int
103 ENGINE_set_name(ENGINE *engine, const char *name)
104 {
105     engine->name = strdup(name);
106     return (engine->name == NULL) ? 0 : 1;
107 }
108
109 int
110 ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method)
111 {
112     engine->rsa = method;
113     return 1;
114 }
115
116 int
117 ENGINE_set_DH(ENGINE *engine, const DH_METHOD *method)
118 {
119     engine->dh = method;
120     return 1;
121 }
122
123 int
124 ENGINE_set_destroy_function(ENGINE *e, void (*destroy)(ENGINE *))
125 {
126     e->destroy = destroy;
127     return 1;
128 }
129
130 const char *
131 ENGINE_get_id(const ENGINE *engine)
132 {
133     return engine->id;
134 }
135
136 const char *
137 ENGINE_get_name(const ENGINE *engine)
138 {
139     return engine->name;
140 }
141
142 const RSA_METHOD *
143 ENGINE_get_RSA(const ENGINE *engine)
144 {
145     return engine->rsa;
146 }
147
148 const DH_METHOD *
149 ENGINE_get_DH(const ENGINE *engine)
150 {
151     return engine->dh;
152 }
153
154 const RAND_METHOD *
155 ENGINE_get_RAND(const ENGINE *engine)
156 {
157     return engine->rand;
158 }
159
160 /*
161  *
162  */
163
164 #define SG_default_engine(type)                 \
165 static ENGINE *type##_engine;                   \
166 int                                             \
167 ENGINE_set_default_##type(ENGINE *engine)       \
168 {                                               \
169     if (type##_engine)                          \
170         ENGINE_finish(type##_engine);           \
171     type##_engine = engine;                     \
172     if (type##_engine)                          \
173         ENGINE_up_ref(type##_engine);           \
174     return 1;                                   \
175 }                                               \
176 ENGINE *                                        \
177 ENGINE_get_default_##type(void)                 \
178 {                                               \
179     if (type##_engine)                          \
180         ENGINE_up_ref(type##_engine);           \
181     return type##_engine;                       \
182 }
183
184 SG_default_engine(RSA)
185 SG_default_engine(DH)
186
187 #undef SG_default_engine
188
189 /*
190  *
191  */
192
193 static ENGINE **engines;
194 static unsigned int num_engines;
195
196 static int
197 add_engine(ENGINE *engine)
198 {
199     ENGINE **d, *dup;
200
201     dup = ENGINE_by_id(engine->id);
202     if (dup) {
203         ENGINE_finish(dup);
204         return 0;
205     }
206
207     d = realloc(engines, (num_engines + 1) * sizeof(*engines));
208     if (d == NULL)
209         return 1;
210     engines = d;
211     engines[num_engines++] = engine;
212     
213     return 1;
214 }
215
216 void
217 ENGINE_load_builtin_engines(void)
218 {
219     ENGINE *engine;
220     int ret;
221
222     engine = calloc(1, sizeof(*engine));
223     if (engine == NULL)
224         return;
225
226     ENGINE_set_id(engine, "builtin");
227     ENGINE_set_name(engine, 
228                     "Heimdal crypto builtin engine version " PACKAGE_VERSION);
229     ENGINE_set_RSA(engine, RSA_imath_method());
230     ENGINE_set_DH(engine, DH_imath_method());
231
232     ret = add_engine(engine);
233     if (ret != 1)
234         ENGINE_finish(engine);
235 }
236
237 ENGINE *
238 ENGINE_by_dso(const char *path, const char *id)
239 {
240 #ifdef HAVE_DLOPEN
241     ENGINE *engine;
242     void *handle;
243     int ret;
244
245     engine = calloc(1, sizeof(*engine));
246     if (engine == NULL)
247         return NULL;
248
249     handle = dlopen(path, RTLD_NOW);
250     if (handle == NULL) {
251         /* printf("error: %s\n", dlerror()); */
252         free(engine);
253         return NULL;
254     }
255
256     {
257         unsigned long version;
258         openssl_v_check v_check;
259
260         v_check = (openssl_v_check)dlsym(handle, "v_check");
261         if (v_check == NULL) {
262             dlclose(handle);
263             free(engine);
264             return NULL;
265         }
266
267         version = (*v_check)(OPENSSL_DYNAMIC_VERSION);
268         if (version == 0) {
269             dlclose(handle);
270             free(engine);
271             return NULL;
272         }           
273     }
274
275     {
276         openssl_bind_engine bind_engine;
277
278         bind_engine = (openssl_bind_engine)dlsym(handle, "bind_engine");
279         if (bind_engine == NULL) {
280             dlclose(handle);
281             free(engine);
282             return NULL;
283         }
284
285         ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */
286         if (ret != 1) {
287             dlclose(handle);
288             free(engine);
289             return NULL;
290         }           
291     }
292
293     ENGINE_up_ref(engine);
294
295     ret = add_engine(engine);
296     if (ret != 1) {
297         dlclose(handle);
298         ENGINE_finish(engine);
299         return NULL;
300     }
301
302     return engine;
303 #else
304     return NULL;
305 #endif
306 }
307
308 ENGINE *
309 ENGINE_by_id(const char *id)
310 {
311     int i;
312
313     for (i = 0; i < num_engines; i++) {
314         if (strcmp(id, engines[i]->id) == 0) {
315             ENGINE_up_ref(engines[i]);
316             return engines[i];
317         }
318     }
319     return NULL;
320 }
321
322 void
323 ENGINE_add_conf_module(void)
324 {
325 }