nearly ready for 0.3.0
[gnupg.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 *hintstr; /* pointer into name */
38     char name[1];
39 } *EXTLIST;
40
41 static EXTLIST extensions;
42
43 typedef struct {
44     EXTLIST r;
45     int seq1;
46     int seq2;
47     void *sym;
48 } ENUMCONTEXT;
49
50 /****************
51  * Register an extension module.  The last registered module will
52  * be loaded first.  A name may have a list of classes
53  * appended; e.g:
54  *      mymodule.so(1:17,3:20,3:109)
55  * means that this module provides digest algorithm 17 and public key
56  * algorithms 20 and 109.  This is only a hint but if it is there the
57  * loader may decide to only load a module which claims to have a
58  * requested algorithm.
59  */
60 void
61 register_cipher_extension( const char *fname )
62 {
63     EXTLIST r, el;
64     char *p, *pe;
65
66     if( *fname != '/' ) { /* do tilde expansion etc */
67         char *p ;
68
69         if( strchr(fname, '/') )
70             p = make_filename(fname, NULL);
71         else
72             p = make_filename(GNUPG_LIBDIR, fname, NULL);
73         el = m_alloc_clear( sizeof *el + strlen(p) );
74         strcpy(el->name, p );
75         m_free(p);
76     }
77     else {
78         el = m_alloc_clear( sizeof *el + strlen(fname) );
79         strcpy(el->name, fname );
80     }
81     /* check whether we have a class hint */
82     if( (p=strchr(el->name,'(')) && (pe=strchr(p+1,')')) && !pe[1] ) {
83         *p = *pe = 0;
84         el->hintstr = p+1;
85     }
86     else
87         el->hintstr = NULL;
88
89     /* check that it is not already registered */
90     for(r = extensions; r; r = r->next )
91         if( !compare_filenames(r->name, el->name) ) {
92             log_info("extension '%s' already registered\n", el->name );
93             m_free(el);
94             return;
95         }
96     /* and register */
97     el->next = extensions;
98     extensions = el;
99 }
100
101
102 static int
103 load_extension( EXTLIST el )
104 {
105   #ifdef USE_DYNAMIC_LINKING
106     char **name;
107     void *sym;
108     const char *err;
109     int seq = 0;
110     int class, vers;
111
112
113     el->handle = dlopen(el->name, RTLD_NOW);
114     if( !el->handle ) {
115         log_error("%s: error loading extension: %s\n", el->name, dlerror() );
116         goto failure;
117     }
118     name = (char**)dlsym(el->handle, "gnupgext_version");
119     if( (err=dlerror()) ) {
120         log_error("%s: not a gnupg extension: %s\n", el->name, err );
121         goto failure;
122     }
123
124     if( g10_opt_verbose )
125         log_info("%s: %s%s%s%s\n", el->name, *name,
126                   el->hintstr? " (":"",
127                   el->hintstr? el->hintstr:"",
128                   el->hintstr? ")":"");
129
130     sym = dlsym(el->handle, "gnupgext_enum_func");
131     if( (err=dlerror()) ) {
132         log_error("%s: invalid gnupg extension: %s\n", el->name, err );
133         goto failure;
134     }
135     el->enumfunc = (void *(*)(int,int*,int*,int*))sym;
136
137     if( g10_opt_verbose > 1 ) {
138         /* list the contents of the module */
139         while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) {
140             if( vers != 1 ) {
141                 log_info("%s: ignoring func with version %d\n",el->name,vers);
142                 continue;
143             }
144             switch( class ) {
145               case 11:
146               case 21:
147               case 31:
148                 log_info("%s: provides %s algorithm %d\n", el->name,
149                                 class == 11? "md"     :
150                                 class == 21? "cipher" : "pubkey",
151                                                        *(int*)sym);
152                 break;
153               default:
154                 /*log_debug("%s: skipping class %d\n", el->name, class);*/
155                 break;
156             }
157         }
158     }
159     return 0;
160
161   failure:
162     if( el->handle ) {
163         dlclose(el->handle);
164         el->handle = NULL;
165     }
166     el->failed = 1;
167   #endif /*USE_DYNAMIC_LINKING*/
168     return -1;
169 }
170
171
172
173 int
174 enum_gnupgext_digests( void **enum_context,
175             int *algo,
176             const char *(**r_get_info)( int, size_t*,byte**, int*, int*,
177                                        void (**)(void*),
178                                        void (**)(void*,byte*,size_t),
179                                        void (**)(void*),byte *(**)(void*)) )
180 {
181     EXTLIST r;
182     ENUMCONTEXT *ctx;
183
184     if( !*enum_context ) { /* init context */
185         ctx = m_alloc_clear( sizeof( *ctx ) );
186         ctx->r = extensions;
187         *enum_context = ctx;
188     }
189     else if( !algo ) { /* release the context */
190         m_free(*enum_context);
191         *enum_context = NULL;
192         return 0;
193     }
194     else
195         ctx = *enum_context;
196
197     for( r = ctx->r; r; r = r->next )  {
198         int class, vers;
199
200         if( r->failed )
201             continue;
202         if( !r->handle && load_extension(r) )
203             continue;
204         /* get a digest info function */
205         if( ctx->sym )
206             goto inner_loop;
207         while( (ctx->sym = (*r->enumfunc)(10, &ctx->seq1, &class, &vers)) ) {
208             void *sym;
209             /* must check class because enumfunc may be wrong coded */
210             if( vers != 1 || class != 10 )
211                 continue;
212           inner_loop:
213             *r_get_info = ctx->sym;
214             while( (sym = (*r->enumfunc)(11, &ctx->seq2, &class, &vers)) ) {
215                 if( vers != 1 || class != 11 )
216                     continue;
217                 *algo = *(int*)sym;
218                 ctx->r = r;
219                 return 1;
220             }
221             ctx->seq2 = 0;
222         }
223         ctx->seq1 = 0;
224     }
225     ctx->r = r;
226     return 0;
227 }
228
229 const char *
230 enum_gnupgext_ciphers( void **enum_context, int *algo,
231                        size_t *keylen, size_t *blocksize, size_t *contextsize,
232                        void (**setkey)( void *c, byte *key, unsigned keylen ),
233                        void (**encrypt)( void *c, byte *outbuf, byte *inbuf ),
234                        void (**decrypt)( void *c, byte *outbuf, byte *inbuf )
235                      )
236 {
237     EXTLIST r;
238     ENUMCONTEXT *ctx;
239     const char * (*finfo)(int, size_t*, size_t*, size_t*,
240                           void (**)( void *, byte *, unsigned),
241                           void (**)( void *, byte *, byte *),
242                           void (**)( void *, byte *, byte *));
243
244     if( !*enum_context ) { /* init context */
245         ctx = m_alloc_clear( sizeof( *ctx ) );
246         ctx->r = extensions;
247         *enum_context = ctx;
248     }
249     else if( !algo ) { /* release the context */
250         m_free(*enum_context);
251         *enum_context = NULL;
252         return NULL;
253     }
254     else
255         ctx = *enum_context;
256
257     for( r = ctx->r; r; r = r->next )  {
258         int class, vers;
259
260         if( r->failed )
261             continue;
262         if( !r->handle && load_extension(r) )
263             continue;
264         /* get a cipher info function */
265         if( ctx->sym )
266             goto inner_loop;
267         while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) {
268             void *sym;
269             /* must check class because enumfunc may be wrong coded */
270             if( vers != 1 || class != 20 )
271                 continue;
272           inner_loop:
273             finfo = ctx->sym;
274             while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) {
275                 const char *algname;
276                 if( vers != 1 || class != 21 )
277                     continue;
278                 *algo = *(int*)sym;
279                 algname = (*finfo)( *algo, keylen, blocksize, contextsize,
280                                     setkey, encrypt, decrypt );
281                 if( algname ) {
282                     ctx->r = r;
283                     return algname;
284                 }
285             }
286             ctx->seq2 = 0;
287         }
288         ctx->seq1 = 0;
289     }
290     ctx->r = r;
291     return NULL;
292 }
293
294 const char *
295 enum_gnupgext_pubkeys( void **enum_context, int *algo,
296     int *npkey, int *nskey, int *nenc, int *nsig, int *usage,
297     int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ),
298     int (**check_secret_key)( int algo, MPI *skey ),
299     int (**encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey ),
300     int (**decrypt)( int algo, MPI *result, MPI *data, MPI *skey ),
301     int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ),
302     int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey,
303                     int (*cmp)(void *, MPI), void *opaquev ),
304     unsigned (**get_nbits)( int algo, MPI *pkey ) )
305 {
306     EXTLIST r;
307     ENUMCONTEXT *ctx;
308     const char * (*finfo)( int, int *, int *, int *, int *, int *,
309                            int (**)( int, unsigned, MPI *, MPI **),
310                            int (**)( int, MPI * ),
311                            int (**)( int, MPI *, MPI , MPI * ),
312                            int (**)( int, MPI *, MPI *, MPI * ),
313                            int (**)( int, MPI *, MPI , MPI * ),
314                            int (**)( int, MPI , MPI *, MPI *,
315                                             int (*)(void*,MPI), void *),
316                            unsigned (**)( int , MPI * ) );
317
318     if( !*enum_context ) { /* init context */
319         ctx = m_alloc_clear( sizeof( *ctx ) );
320         ctx->r = extensions;
321         *enum_context = ctx;
322     }
323     else if( !algo ) { /* release the context */
324         m_free(*enum_context);
325         *enum_context = NULL;
326         return NULL;
327     }
328     else
329         ctx = *enum_context;
330
331     for( r = ctx->r; r; r = r->next )  {
332         int class, vers;
333
334         if( r->failed )
335             continue;
336         if( !r->handle && load_extension(r) )
337             continue;
338         /* get a pubkey info function */
339         if( ctx->sym )
340             goto inner_loop;
341         while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) {
342             void *sym;
343             if( vers != 1 || class != 30 )
344                 continue;
345           inner_loop:
346             finfo = ctx->sym;
347             while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) {
348                 const char *algname;
349                 if( vers != 1 || class != 31 )
350                     continue;
351                 *algo = *(int*)sym;
352                 algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, usage,
353                                     generate, check_secret_key, encrypt,
354                                     decrypt, sign, verify, get_nbits );
355                 if( algname ) {
356                     ctx->r = r;
357                     return algname;
358                 }
359             }
360             ctx->seq2 = 0;
361         }
362         ctx->seq1 = 0;
363     }
364     ctx->r = r;
365     return NULL;
366 }
367