b4ed77177da4c5946acf48c87d8e7615d1594571
[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     /* fixme: have a look at the hint string */
339     for( r = ctx->r; r; r = r->next )  {
340         int class, vers;
341
342         if( r->failed )
343             continue;
344         if( !r->handle && load_extension(r) )
345             continue;
346         /* get a digest info function */
347         if( ctx->sym )
348             goto inner_loop;
349         while( (ctx->sym = (*r->enumfunc)(10, &ctx->seq1, &class, &vers)) ) {
350             void *sym;
351             /* must check class because enumfunc may be wrong coded */
352             if( vers != 1 || class != 10 )
353                 continue;
354           inner_loop:
355             *r_get_info = ctx->sym;
356             while( (sym = (*r->enumfunc)(11, &ctx->seq2, &class, &vers)) ) {
357                 if( vers != 1 || class != 11 )
358                     continue;
359                 *algo = *(int*)sym;
360                 ctx->r = r;
361                 return 1;
362             }
363             ctx->seq2 = 0;
364         }
365         ctx->seq1 = 0;
366     }
367     ctx->r = r;
368     return 0;
369 }
370
371 const char *
372 enum_gnupgext_ciphers( void **enum_context, int *algo,
373                        size_t *keylen, size_t *blocksize, size_t *contextsize,
374                        int  (**setkeyf)( void *c, byte *key, unsigned keylen ),
375                        void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
376                        void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
377                      )
378 {
379     EXTLIST r;
380     ENUMCONTEXT *ctx;
381     const char * (*finfo)(int, size_t*, size_t*, size_t*,
382                           int  (**)( void *, byte *, unsigned),
383                           void (**)( void *, byte *, byte *),
384                           void (**)( void *, byte *, byte *));
385
386     if( !*enum_context ) { /* init context */
387         ctx = m_alloc_clear( sizeof( *ctx ) );
388         ctx->r = extensions;
389         *enum_context = ctx;
390     }
391     else if( !algo ) { /* release the context */
392         m_free(*enum_context);
393         *enum_context = NULL;
394         return NULL;
395     }
396     else
397         ctx = *enum_context;
398
399     for( r = ctx->r; r; r = r->next )  {
400         int class, vers;
401
402         if( r->failed )
403             continue;
404         if( !r->handle && load_extension(r) )
405             continue;
406         /* get a cipher info function */
407         if( ctx->sym )
408             goto inner_loop;
409         while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) {
410             void *sym;
411             /* must check class because enumfunc may be wrong coded */
412             if( vers != 1 || class != 20 )
413                 continue;
414           inner_loop:
415             finfo = ctx->sym;
416             while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) {
417                 const char *algname;
418                 if( vers != 1 || class != 21 )
419                     continue;
420                 *algo = *(int*)sym;
421                 algname = (*finfo)( *algo, keylen, blocksize, contextsize,
422                                     setkeyf, encryptf, decryptf );
423                 if( algname ) {
424                     ctx->r = r;
425                     return algname;
426                 }
427             }
428             ctx->seq2 = 0;
429         }
430         ctx->seq1 = 0;
431     }
432     ctx->r = r;
433     return NULL;
434 }
435
436 const char *
437 enum_gnupgext_pubkeys( void **enum_context, int *algo,
438     int *npkey, int *nskey, int *nenc, int *nsig, int *use,
439     int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ),
440     int (**check_secret_key)( int algo, MPI *skey ),
441     int (**encryptf)( int algo, MPI *resarr, MPI data, MPI *pkey ),
442     int (**decryptf)( int algo, MPI *result, MPI *data, MPI *skey ),
443     int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ),
444     int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey,
445                     int (*cmp)(void *, MPI), void *opaquev ),
446     unsigned (**get_nbits)( int algo, MPI *pkey ) )
447 {
448     EXTLIST r;
449     ENUMCONTEXT *ctx;
450     const char * (*finfo)( int, int *, int *, int *, int *, int *,
451                            int (**)( int, unsigned, MPI *, MPI **),
452                            int (**)( int, MPI * ),
453                            int (**)( int, MPI *, MPI , MPI * ),
454                            int (**)( int, MPI *, MPI *, MPI * ),
455                            int (**)( int, MPI *, MPI , MPI * ),
456                            int (**)( int, MPI , MPI *, MPI *,
457                                             int (*)(void*,MPI), void *),
458                            unsigned (**)( int , MPI * ) );
459
460     if( !*enum_context ) { /* init context */
461         ctx = m_alloc_clear( sizeof( *ctx ) );
462         ctx->r = extensions;
463         *enum_context = ctx;
464     }
465     else if( !algo ) { /* release the context */
466         m_free(*enum_context);
467         *enum_context = NULL;
468         return NULL;
469     }
470     else
471         ctx = *enum_context;
472
473     for( r = ctx->r; r; r = r->next )  {
474         int class, vers;
475
476         if( r->failed )
477             continue;
478         if( !r->handle && load_extension(r) )
479             continue;
480         /* get a pubkey info function */
481         if( ctx->sym )
482             goto inner_loop;
483         while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) {
484             void *sym;
485             if( vers != 1 || class != 30 )
486                 continue;
487           inner_loop:
488             finfo = ctx->sym;
489             while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) {
490                 const char *algname;
491                 if( vers != 1 || class != 31 )
492                     continue;
493                 *algo = *(int*)sym;
494                 algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, use,
495                                     generate, check_secret_key, encryptf,
496                                     decryptf, sign, verify, get_nbits );
497                 if( algname ) {
498                     ctx->r = r;
499                     return algname;
500                 }
501             }
502             ctx->seq2 = 0;
503         }
504         ctx->seq1 = 0;
505     }
506     ctx->r = r;
507     return NULL;
508 }
509
510
511 int (*
512 dynload_getfnc_gather_random())(void (*)(const void*, size_t, int), int,
513                                                             size_t, int)
514 {
515     EXTLIST r;
516     void *sym;
517
518     for( r = extensions; r; r = r->next )  {
519         int seq, class, vers;
520
521         if( r->failed )
522             continue;
523         if( !r->handle && load_extension(r) )
524             continue;
525         seq = 0;
526         while( (sym = (*r->enumfunc)(40, &seq, &class, &vers)) ) {
527             if( vers != 1 || class != 40 )
528                 continue;
529             return (int (*)(void (*)(const void*, size_t, int), int,
530                                                         size_t, int))sym;
531         }
532     }
533     return NULL;
534 }
535
536
537 void (*
538 dynload_getfnc_fast_random_poll())( void (*)(const void*, size_t, int), int)
539 {
540     EXTLIST r;
541     void *sym;
542
543     for( r = extensions; r; r = r->next )  {
544         int seq, class, vers;
545
546         if( r->failed )
547             continue;
548         if( !r->handle && load_extension(r) )
549             continue;
550         seq = 0;
551         while( (sym = (*r->enumfunc)(41, &seq, &class, &vers)) ) {
552             if( vers != 1 || class != 41 )
553                 continue;
554             return (void (*)( void (*)(const void*, size_t, int), int))sym;
555         }
556     }
557     return NULL;
558 }
559