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