767372a7e4e72410f9f73c02297521db1c661c2d
[libgcrypt.git] / cipher / dynload.c
1 /* dynload.c - load cipher extensions
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #ifdef HAVE_DL_DLOPEN
26   #include <dlfcn.h>
27 #endif
28 #include "util.h"
29 #include "cipher.h"
30 #include "dynload.h"
31
32 typedef struct ext_list {
33     struct ext_list *next;
34     void *handle; /* handle from dlopen() */
35     int  failed;  /* already tried but failed */
36     void * (*enumfunc)(int, int*, int*, int*);
37     char name[1];
38 } *EXTLIST;
39
40 static EXTLIST extensions;
41
42 typedef struct {
43     EXTLIST r;
44     int seq1;
45     int seq2;
46     void *sym;
47 } ENUMCONTEXT;
48
49 /****************
50  * Register an extension module.  The last registered module will
51  * be loaded first.
52  */
53 void
54 register_cipher_extension( const char *fname )
55 {
56     EXTLIST r, el;
57
58     if( *fname != '/' ) { /* do tilde expansion etc */
59         char *p ;
60
61         if( strchr(fname, '/') )
62             p = make_filename(fname, NULL);
63         else
64             p = make_filename(GNUPG_LIBDIR, fname, NULL);
65         el = m_alloc_clear( sizeof *el + strlen(p) );
66         strcpy(el->name, p );
67         m_free(p);
68     }
69     else {
70         el = m_alloc_clear( sizeof *el + strlen(fname) );
71         strcpy(el->name, fname );
72     }
73     /* check that it is not already registered */
74     for(r = extensions; r; r = r->next )
75         if( !compare_filenames(r->name, el->name) ) {
76             log_info("extension '%s' already registered\n", el->name );
77             m_free(el);
78             return;
79         }
80     if( DBG_CIPHER )
81         log_debug("extension '%s' registered\n", el->name );
82     /* and register */
83     el->next = extensions;
84     extensions = el;
85 }
86
87
88 static int
89 load_extension( EXTLIST el )
90 {
91   #ifdef USE_DYNAMIC_LINKING
92     char **name;
93     void *sym;
94     const char *err;
95     int seq = 0;
96     int class, vers;
97
98     el->handle = dlopen(el->name, RTLD_NOW);
99     if( !el->handle ) {
100         log_error("%s: error loading extension: %s\n", el->name, dlerror() );
101         goto failure;
102     }
103     name = (char**)dlsym(el->handle, "gnupgext_version");
104     if( (err=dlerror()) ) {
105         log_error("%s: not a gnupg extension: %s\n", el->name, err );
106         goto failure;
107     }
108
109     if( g10_opt_verbose )
110         log_info("%s: version '%s'\n", el->name, *name );
111
112     sym = dlsym(el->handle, "gnupgext_enum_func");
113     if( (err=dlerror()) ) {
114         log_error("%s: invalid gnupg extension: %s\n", el->name, err );
115         goto failure;
116     }
117     el->enumfunc = (void *(*)(int,int*,int*,int*))sym;
118
119     if( g10_opt_verbose > 1 ) {
120         /* list the contents of the module */
121         while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) {
122             if( vers != 1 ) {
123                 log_info("%s: ignoring func with version %d\n",el->name,vers);
124                 continue;
125             }
126             switch( class ) {
127               case 11:
128               case 21:
129               case 31:
130                 log_info("%s: provides %s algorithm %d\n", el->name,
131                                 class == 11? "md"     :
132                                 class == 21? "cipher" : "pubkey",
133                                                        *(int*)sym);
134                 break;
135               default:
136                 /*log_debug("%s: skipping class %d\n", el->name, class);*/
137                 break;
138             }
139         }
140     }
141     return 0;
142
143   failure:
144     if( el->handle ) {
145         dlclose(el->handle);
146         el->handle = NULL;
147     }
148     el->failed = 1;
149   #endif /*USE_DYNAMIC_LINKING*/
150     return -1;
151 }
152
153
154
155 int
156 enum_gnupgext_digests( void **enum_context,
157             int *algo,
158             const char *(**r_get_info)( int, size_t*,byte**, int*, int*,
159                                        void (**)(void*),
160                                        void (**)(void*,byte*,size_t),
161                                        void (**)(void*),byte *(**)(void*)) )
162 {
163     EXTLIST r;
164     ENUMCONTEXT *ctx;
165
166     if( !*enum_context ) { /* init context */
167         ctx = m_alloc_clear( sizeof( *ctx ) );
168         ctx->r = extensions;
169         *enum_context = ctx;
170     }
171     else if( !algo ) { /* release the context */
172         m_free(*enum_context);
173         *enum_context = NULL;
174         return 0;
175     }
176     else
177         ctx = *enum_context;
178
179     for( r = ctx->r; r; r = r->next )  {
180         int class, vers;
181
182         if( r->failed )
183             continue;
184         if( !r->handle && load_extension(r) )
185             continue;
186         /* get a digest info function */
187         if( ctx->sym )
188             goto inner_loop;
189         while( (ctx->sym = (*r->enumfunc)(10, &ctx->seq1, &class, &vers)) ) {
190             void *sym;
191             /* must check class because enumfunc may be wrong coded */
192             if( vers != 1 || class != 10 )
193                 continue;
194           inner_loop:
195             *r_get_info = ctx->sym;
196             while( (sym = (*r->enumfunc)(11, &ctx->seq2, &class, &vers)) ) {
197                 if( vers != 1 || class != 11 )
198                     continue;
199                 *algo = *(int*)sym;
200                 ctx->r = r;
201                 return 1;
202             }
203             ctx->seq2 = 0;
204         }
205         ctx->seq1 = 0;
206     }
207     ctx->r = r;
208     return 0;
209 }
210
211 const char *
212 enum_gnupgext_ciphers( void **enum_context, int *algo,
213                        size_t *keylen, size_t *blocksize, size_t *contextsize,
214                        void (**setkey)( void *c, byte *key, unsigned keylen ),
215                        void (**encrypt)( void *c, byte *outbuf, byte *inbuf ),
216                        void (**decrypt)( void *c, byte *outbuf, byte *inbuf )
217                      )
218 {
219     EXTLIST r;
220     ENUMCONTEXT *ctx;
221     const char * (*finfo)(int, size_t*, size_t*, size_t*,
222                           void (**)( void *, byte *, unsigned),
223                           void (**)( void *, byte *, byte *),
224                           void (**)( void *, byte *, byte *));
225
226     if( !*enum_context ) { /* init context */
227         ctx = m_alloc_clear( sizeof( *ctx ) );
228         ctx->r = extensions;
229         *enum_context = ctx;
230     }
231     else if( !algo ) { /* release the context */
232         m_free(*enum_context);
233         *enum_context = NULL;
234         return NULL;
235     }
236     else
237         ctx = *enum_context;
238
239     for( r = ctx->r; r; r = r->next )  {
240         int class, vers;
241
242         if( r->failed )
243             continue;
244         if( !r->handle && load_extension(r) )
245             continue;
246         /* get a cipher info function */
247         if( ctx->sym )
248             goto inner_loop;
249         while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) {
250             void *sym;
251             /* must check class because enumfunc may be wrong coded */
252             if( vers != 1 || class != 20 )
253                 continue;
254           inner_loop:
255             finfo = ctx->sym;
256             while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) {
257                 const char *algname;
258                 if( vers != 1 || class != 21 )
259                     continue;
260                 *algo = *(int*)sym;
261                 algname = (*finfo)( *algo, keylen, blocksize, contextsize,
262                                     setkey, encrypt, decrypt );
263                 if( algname ) {
264                     ctx->r = r;
265                     return algname;
266                 }
267             }
268             ctx->seq2 = 0;
269         }
270         ctx->seq1 = 0;
271     }
272     ctx->r = r;
273     return NULL;
274 }
275
276 const char *
277 enum_gnupgext_pubkeys( void **enum_context, int *algo,
278     int *npkey, int *nskey, int *nenc, int *nsig, int *usage,
279     int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ),
280     int (**check_secret_key)( int algo, MPI *skey ),
281     int (**encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey ),
282     int (**decrypt)( int algo, MPI *result, MPI *data, MPI *skey ),
283     int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ),
284     int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey,
285                     int (*cmp)(void *, MPI), void *opaquev ),
286     unsigned (**get_nbits)( int algo, MPI *pkey ) )
287 {
288     EXTLIST r;
289     ENUMCONTEXT *ctx;
290     const char * (*finfo)( int, int *, int *, int *, int *, int *,
291                            int (**)( int, unsigned, MPI *, MPI **),
292                            int (**)( int, MPI * ),
293                            int (**)( int, MPI *, MPI , MPI * ),
294                            int (**)( int, MPI *, MPI *, MPI * ),
295                            int (**)( int, MPI *, MPI , MPI * ),
296                            int (**)( int, MPI , MPI *, MPI *,
297                                             int (*)(void*,MPI), void *),
298                            unsigned (**)( int , MPI * ) );
299
300     if( !*enum_context ) { /* init context */
301         ctx = m_alloc_clear( sizeof( *ctx ) );
302         ctx->r = extensions;
303         *enum_context = ctx;
304     }
305     else if( !algo ) { /* release the context */
306         m_free(*enum_context);
307         *enum_context = NULL;
308         return NULL;
309     }
310     else
311         ctx = *enum_context;
312
313     for( r = ctx->r; r; r = r->next )  {
314         int class, vers;
315
316         if( r->failed )
317             continue;
318         if( !r->handle && load_extension(r) )
319             continue;
320         /* get a pubkey info function */
321         if( ctx->sym )
322             goto inner_loop;
323         while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) {
324             void *sym;
325             if( vers != 1 || class != 30 )
326                 continue;
327           inner_loop:
328             finfo = ctx->sym;
329             while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) {
330                 const char *algname;
331                 if( vers != 1 || class != 31 )
332                     continue;
333                 *algo = *(int*)sym;
334                 algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, usage,
335                                     generate, check_secret_key, encrypt,
336                                     decrypt, sign, verify, get_nbits );
337                 if( algname ) {
338                     ctx->r = r;
339                     return algname;
340                 }
341             }
342             ctx->seq2 = 0;
343         }
344         ctx->seq1 = 0;
345     }
346     ctx->r = r;
347     return NULL;
348 }
349