See ChangeLog: Sat Dec 12 18:40:32 CET 1998 Werner Koch
[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 #include <unistd.h>
26 #ifdef HAVE_DL_DLOPEN
27   #include <dlfcn.h>
28 #elif defined(HAVE_DLD_DLD_LINK)
29   #include <dld.h>
30 #endif
31 #include "util.h"
32 #include "cipher.h"
33 #include "dynload.h"
34
35 #ifdef DLSYM_NEEDS_UNDERSCORE
36   #define SYMBOL_VERSION "_gnupgext_version"
37   #define SYMBOL_ENUM    "_gnupgext_enum_func"
38 #else
39   #define SYMBOL_VERSION "gnupgext_version"
40   #define SYMBOL_ENUM    "gnupgext_enum_func"
41 #endif
42
43
44 #ifndef RTLD_NOW
45   #define RTLD_NOW  1
46 #endif
47
48 typedef struct ext_list {
49     struct ext_list *next;
50     int internal;
51   #ifdef HAVE_DL_DLOPEN
52     void *handle; /* handle from dlopen() */
53   #else
54     int handle;   /* if the function has been loaded, this is true */
55   #endif
56     int  failed;  /* already tried but failed */
57     void * (*enumfunc)(int, int*, int*, int*);
58     char *hintstr; /* pointer into name */
59     char name[1];
60 } *EXTLIST;
61
62 static EXTLIST extensions;
63
64 typedef struct {
65     EXTLIST r;
66     int seq1;
67     int seq2;
68     void *sym;
69 } ENUMCONTEXT;
70
71
72 #ifdef HAVE_DLD_DLD_LINK
73 static char *mainpgm_path;
74 static int did_dld_init;
75 static int dld_available;
76 #endif
77
78
79 /****************
80  * Register an extension module.  The last registered module will
81  * be loaded first.  A name may have a list of classes
82  * appended; e.g:
83  *      mymodule.so(1:17,3:20,3:109)
84  * means that this module provides digest algorithm 17 and public key
85  * algorithms 20 and 109.  This is only a hint but if it is there the
86  * loader may decide to only load a module which claims to have a
87  * requested algorithm.
88  *
89  * mainpgm is the path to the program which wants to load a module
90  * it is only used in some environments.
91  */
92 void
93 register_cipher_extension( const char *mainpgm, const char *fname )
94 {
95     EXTLIST r, el, intex;
96     char *p, *pe;
97
98   #ifdef HAVE_DLD_DLD_LINK
99     if( !mainpgm_path && mainpgm && *mainpgm )
100         mainpgm_path = m_strdup(mainpgm);
101   #endif
102     if( *fname != '/' ) { /* do tilde expansion etc */
103         char *p ;
104
105         if( strchr(fname, '/') )
106             p = make_filename(fname, NULL);
107         else
108             p = make_filename(GNUPG_LIBDIR, fname, NULL);
109         el = m_alloc_clear( sizeof *el + strlen(p) );
110         strcpy(el->name, p );
111         m_free(p);
112     }
113     else {
114         el = m_alloc_clear( sizeof *el + strlen(fname) );
115         strcpy(el->name, fname );
116     }
117     /* check whether we have a class hint */
118     if( (p=strchr(el->name,'(')) && (pe=strchr(p+1,')')) && !pe[1] ) {
119         *p = *pe = 0;
120         el->hintstr = p+1;
121     }
122     else
123         el->hintstr = NULL;
124
125     /* check that it is not already registered */
126     intex = NULL;
127     for(r = extensions; r; r = r->next ) {
128         if( !compare_filenames(r->name, el->name) ) {
129             log_info("extension '%s' already registered\n", el->name );
130             m_free(el);
131             return;
132         }
133         else if( r->internal )
134             intex = r;
135     }
136     /* and register */
137     /* we put them after the internal extension modules */
138     /* this is so that the external modules do not get loaded */
139     /* as soon as the internal modules are requested */
140     if( intex ) {
141         el->next = intex->next;
142         intex->next = el;
143     }
144     else {
145         el->next = extensions;
146         extensions = el;
147     }
148 }
149
150 void
151 register_internal_cipher_extension(
152                         const char *module_id,
153                         void * (*enumfunc)(int, int*, int*, int*)
154                                   )
155 {
156     EXTLIST r, el;
157
158     el = m_alloc_clear( sizeof *el + strlen(module_id) );
159     strcpy(el->name, module_id );
160     el->internal = 1;
161
162     /* check that it is not already registered */
163     for(r = extensions; r; r = r->next ) {
164         if( !compare_filenames(r->name, el->name) ) {
165             log_info("extension '%s' already registered\n", el->name );
166             m_free(el);
167             return;
168         }
169     }
170     /* and register */
171     el->enumfunc = enumfunc;
172     el->handle = (void*)1;
173     el->next = extensions;
174     extensions = el;
175 }
176
177
178 static int
179 load_extension( EXTLIST el )
180 {
181   #ifdef USE_DYNAMIC_LINKING
182     char **name;
183   #ifdef HAVE_DL_DLOPEN
184     const char *err;
185     int seq = 0;
186     int class, vers;
187     void *sym;
188   #else
189     unsigned long addr;
190     int rc;
191   #endif
192
193     /* make sure we are not setuid */
194     if( getuid() != geteuid() )
195         log_bug("trying to load an extension while still setuid\n");
196
197     /* now that we are not setuid anymore, we can safely load modules */
198   #ifdef HAVE_DL_DLOPEN
199     el->handle = dlopen(el->name, RTLD_NOW);
200     if( !el->handle ) {
201         log_error("%s: error loading extension: %s\n", el->name, dlerror() );
202         goto failure;
203     }
204     name = (char**)dlsym(el->handle, SYMBOL_VERSION);
205     if( (err=dlerror()) ) {
206         log_error("%s: not a gnupg extension: %s\n", el->name, err );
207         goto failure;
208     }
209   #else /* have dld */
210     if( !did_dld_init ) {
211         did_dld_init = 1;
212         if( !mainpgm_path )
213             log_error("DLD is not correctly initialized\n");
214         else {
215             rc = dld_init( dld_find_executable(mainpgm_path) );
216             if( rc )
217                 log_error("DLD init failed: %s\n", dld_strerror(rc) );
218             else
219                 dld_available = 1;
220         }
221     }
222     if( !dld_available ) {
223         log_error("%s: DLD not available\n", el->name );
224         goto failure;
225     }
226
227     rc = dld_link( el->name );
228     if( rc ) {
229         log_error("%s: error loading extension: %s\n",
230                                     el->name, dld_strerror(rc) );
231         goto failure;
232     }
233     addr = dld_get_symbol(SYMBOL_VERSION);
234     if( !addr ) {
235         log_error("%s: not a gnupg extension: %s\n",
236                                 el->name, dld_strerror(dld_errno) );
237         goto failure;
238     }
239     name = (char**)addr;
240   #endif
241
242     if( g10_opt_verbose > 1 )
243         log_info("%s: %s%s%s%s\n", el->name, *name,
244                   el->hintstr? " (":"",
245                   el->hintstr? el->hintstr:"",
246                   el->hintstr? ")":"");
247
248   #ifdef HAVE_DL_DLOPEN
249     sym = dlsym(el->handle, SYMBOL_ENUM);
250     if( (err=dlerror()) ) {
251         log_error("%s: invalid gnupg extension: %s\n", el->name, err );
252         goto failure;
253     }
254     el->enumfunc = (void *(*)(int,int*,int*,int*))sym;
255   #else /* dld */
256     addr = dld_get_func(SYMBOL_ENUM);
257     if( !addr ) {
258         log_error("%s: invalid gnupg extension: %s\n",
259                                 el->name, dld_strerror(dld_errno) );
260         goto failure;
261     }
262     rc = dld_function_executable_p(SYMBOL_ENUM);
263     if( rc ) {
264         log_error("%s: extension function is not executable: %s\n",
265                                         el->name, dld_strerror(rc) );
266         goto failure;
267     }
268     el->enumfunc = (void *(*)(int,int*,int*,int*))addr;
269     el->handle = 1; /* mark as usable */
270   #endif
271
272   #ifdef HAVE_DL_DLOPEN
273     if( g10_opt_verbose > 2 ) {
274         /* list the contents of the module */
275         while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) {
276             if( vers != 1 ) {
277                 log_info("%s: ignoring func with version %d\n",el->name,vers);
278                 continue;
279             }
280             switch( class ) {
281               case 11:
282               case 21:
283               case 31:
284                 log_info("%s: provides %s algorithm %d\n", el->name,
285                                 class == 11? "md"     :
286                                 class == 21? "cipher" : "pubkey",
287                                                        *(int*)sym);
288                 break;
289               default:
290                 /*log_debug("%s: skipping class %d\n", el->name, class);*/
291                 break;
292             }
293         }
294     }
295   #endif
296     return 0;
297
298   failure:
299   #ifdef HAVE_DL_DLOPEN
300     if( el->handle ) {
301         dlclose(el->handle);
302         el->handle = NULL;
303     }
304   #endif
305     el->failed = 1;
306   #endif /*USE_DYNAMIC_LINKING*/
307     return -1;
308 }
309
310
311
312 int
313 enum_gnupgext_digests( void **enum_context,
314             int *algo,
315             const char *(**r_get_info)( int, size_t*,byte**, int*, int*,
316                                        void (**)(void*),
317                                        void (**)(void*,byte*,size_t),
318                                        void (**)(void*),byte *(**)(void*)) )
319 {
320     EXTLIST r;
321     ENUMCONTEXT *ctx;
322
323     if( !*enum_context ) { /* init context */
324         ctx = m_alloc_clear( sizeof( *ctx ) );
325         ctx->r = extensions;
326         *enum_context = ctx;
327     }
328     else if( !algo ) { /* release the context */
329         m_free(*enum_context);
330         *enum_context = NULL;
331         return 0;
332     }
333     else
334         ctx = *enum_context;
335
336     for( r = ctx->r; r; r = r->next )  {
337         int class, vers;
338
339         if( r->failed )
340             continue;
341         if( !r->handle && load_extension(r) )
342             continue;
343         /* get a digest info function */
344         if( ctx->sym )
345             goto inner_loop;
346         while( (ctx->sym = (*r->enumfunc)(10, &ctx->seq1, &class, &vers)) ) {
347             void *sym;
348             /* must check class because enumfunc may be wrong coded */
349             if( vers != 1 || class != 10 )
350                 continue;
351           inner_loop:
352             *r_get_info = ctx->sym;
353             while( (sym = (*r->enumfunc)(11, &ctx->seq2, &class, &vers)) ) {
354                 if( vers != 1 || class != 11 )
355                     continue;
356                 *algo = *(int*)sym;
357                 ctx->r = r;
358                 return 1;
359             }
360             ctx->seq2 = 0;
361         }
362         ctx->seq1 = 0;
363     }
364     ctx->r = r;
365     return 0;
366 }
367
368 const char *
369 enum_gnupgext_ciphers( void **enum_context, int *algo,
370                        size_t *keylen, size_t *blocksize, size_t *contextsize,
371                        int  (**setkey)( void *c, byte *key, unsigned keylen ),
372                        void (**encrypt)( void *c, byte *outbuf, byte *inbuf ),
373                        void (**decrypt)( void *c, byte *outbuf, byte *inbuf )
374                      )
375 {
376     EXTLIST r;
377     ENUMCONTEXT *ctx;
378     const char * (*finfo)(int, size_t*, size_t*, size_t*,
379                           int  (**)( void *, byte *, unsigned),
380                           void (**)( void *, byte *, byte *),
381                           void (**)( void *, byte *, byte *));
382
383     if( !*enum_context ) { /* init context */
384         ctx = m_alloc_clear( sizeof( *ctx ) );
385         ctx->r = extensions;
386         *enum_context = ctx;
387     }
388     else if( !algo ) { /* release the context */
389         m_free(*enum_context);
390         *enum_context = NULL;
391         return NULL;
392     }
393     else
394         ctx = *enum_context;
395
396     for( r = ctx->r; r; r = r->next )  {
397         int class, vers;
398
399         if( r->failed )
400             continue;
401         if( !r->handle && load_extension(r) )
402             continue;
403         /* get a cipher info function */
404         if( ctx->sym )
405             goto inner_loop;
406         while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) {
407             void *sym;
408             /* must check class because enumfunc may be wrong coded */
409             if( vers != 1 || class != 20 )
410                 continue;
411           inner_loop:
412             finfo = ctx->sym;
413             while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) {
414                 const char *algname;
415                 if( vers != 1 || class != 21 )
416                     continue;
417                 *algo = *(int*)sym;
418                 algname = (*finfo)( *algo, keylen, blocksize, contextsize,
419                                     setkey, encrypt, decrypt );
420                 if( algname ) {
421                     ctx->r = r;
422                     return algname;
423                 }
424             }
425             ctx->seq2 = 0;
426         }
427         ctx->seq1 = 0;
428     }
429     ctx->r = r;
430     return NULL;
431 }
432
433 const char *
434 enum_gnupgext_pubkeys( void **enum_context, int *algo,
435     int *npkey, int *nskey, int *nenc, int *nsig, int *usage,
436     int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ),
437     int (**check_secret_key)( int algo, MPI *skey ),
438     int (**encrypt)( int algo, MPI *resarr, MPI data, MPI *pkey ),
439     int (**decrypt)( int algo, MPI *result, MPI *data, MPI *skey ),
440     int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ),
441     int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey,
442                     int (*cmp)(void *, MPI), void *opaquev ),
443     unsigned (**get_nbits)( int algo, MPI *pkey ) )
444 {
445     EXTLIST r;
446     ENUMCONTEXT *ctx;
447     const char * (*finfo)( int, int *, int *, int *, int *, int *,
448                            int (**)( int, unsigned, MPI *, MPI **),
449                            int (**)( int, MPI * ),
450                            int (**)( int, MPI *, MPI , MPI * ),
451                            int (**)( int, MPI *, MPI *, MPI * ),
452                            int (**)( int, MPI *, MPI , MPI * ),
453                            int (**)( int, MPI , MPI *, MPI *,
454                                             int (*)(void*,MPI), void *),
455                            unsigned (**)( int , MPI * ) );
456
457     if( !*enum_context ) { /* init context */
458         ctx = m_alloc_clear( sizeof( *ctx ) );
459         ctx->r = extensions;
460         *enum_context = ctx;
461     }
462     else if( !algo ) { /* release the context */
463         m_free(*enum_context);
464         *enum_context = NULL;
465         return NULL;
466     }
467     else
468         ctx = *enum_context;
469
470     for( r = ctx->r; r; r = r->next )  {
471         int class, vers;
472
473         if( r->failed )
474             continue;
475         if( !r->handle && load_extension(r) )
476             continue;
477         /* get a pubkey info function */
478         if( ctx->sym )
479             goto inner_loop;
480         while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) {
481             void *sym;
482             if( vers != 1 || class != 30 )
483                 continue;
484           inner_loop:
485             finfo = ctx->sym;
486             while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) {
487                 const char *algname;
488                 if( vers != 1 || class != 31 )
489                     continue;
490                 *algo = *(int*)sym;
491                 algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, usage,
492                                     generate, check_secret_key, encrypt,
493                                     decrypt, sign, verify, get_nbits );
494                 if( algname ) {
495                     ctx->r = r;
496                     return algname;
497                 }
498             }
499             ctx->seq2 = 0;
500         }
501         ctx->seq1 = 0;
502     }
503     ctx->r = r;
504     return NULL;
505 }
506
507
508 int (*
509 dynload_getfnc_gather_random())(byte*, size_t*, int)
510 {
511     EXTLIST r;
512     void *sym;
513
514     for( r = extensions; r; r = r->next )  {
515         int seq, class, vers;
516
517         if( r->failed )
518             continue;
519         if( !r->handle && load_extension(r) )
520             continue;
521         seq = 0;
522         while( (sym = (*r->enumfunc)(40, &seq, &class, &vers)) ) {
523             if( vers != 1 || class != 40 )
524                 continue;
525             return (int (*)(byte*, size_t*, int))sym;
526         }
527     }
528     return NULL;
529 }
530
531
532 void (*
533 dynload_getfnc_fast_random_poll())( void (*)(const void*, size_t, int))
534 {
535     EXTLIST r;
536     void *sym;
537
538     for( r = extensions; r; r = r->next )  {
539         int seq, class, vers;
540
541         if( r->failed )
542             continue;
543         if( !r->handle && load_extension(r) )
544             continue;
545         seq = 0;
546         while( (sym = (*r->enumfunc)(41, &seq, &class, &vers)) ) {
547             if( vers != 1 || class != 41 )
548                 continue;
549             return (void (*)( void (*)(const void*, size_t, int)))sym;
550         }
551     }
552     return NULL;
553 }
554