See ChangeLog: Sat May 22 22:47:26 CEST 1999 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 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   #ifdef HAVE_DL_DLOPEN
174     el->handle = (void*)1;
175   #else
176     el->handle = 1;
177   #endif
178     el->next = extensions;
179     extensions = el;
180 }
181
182
183 static int
184 load_extension( EXTLIST el )
185 {
186   #ifdef USE_DYNAMIC_LINKING
187     char **name;
188   #ifdef HAVE_DL_DLOPEN
189     const char *err;
190     int seq = 0;
191     int class, vers;
192     void *sym;
193   #else
194     unsigned long addr;
195     int rc;
196   #endif
197
198     /* make sure we are not setuid */
199     if( getuid() != geteuid() )
200         log_bug("trying to load an extension while still setuid\n");
201
202     /* now that we are not setuid anymore, we can safely load modules */
203   #ifdef HAVE_DL_DLOPEN
204     el->handle = dlopen(el->name, RTLD_NOW);
205     if( !el->handle ) {
206         log_error("%s: error loading extension: %s\n", el->name, dlerror() );
207         goto failure;
208     }
209     name = (char**)dlsym(el->handle, SYMBOL_VERSION);
210     if( (err=dlerror()) ) {
211         log_error("%s: not a gnupg extension: %s\n", el->name, err );
212         goto failure;
213     }
214   #else /* have dld */
215     if( !did_dld_init ) {
216         did_dld_init = 1;
217         if( !mainpgm_path )
218             log_error("DLD is not correctly initialized\n");
219         else {
220             rc = dld_init( dld_find_executable(mainpgm_path) );
221             if( rc )
222                 log_error("DLD init failed: %s\n", dld_strerror(rc) );
223             else
224                 dld_available = 1;
225         }
226     }
227     if( !dld_available ) {
228         log_error("%s: DLD not available\n", el->name );
229         goto failure;
230     }
231
232     rc = dld_link( el->name );
233     if( rc ) {
234         log_error("%s: error loading extension: %s\n",
235                                     el->name, dld_strerror(rc) );
236         goto failure;
237     }
238     addr = dld_get_symbol(SYMBOL_VERSION);
239     if( !addr ) {
240         log_error("%s: not a gnupg extension: %s\n",
241                                 el->name, dld_strerror(dld_errno) );
242         goto failure;
243     }
244     name = (char**)addr;
245   #endif
246
247     if( g10_opt_verbose > 1 )
248         log_info("%s: %s%s%s%s\n", el->name, *name,
249                   el->hintstr? " (":"",
250                   el->hintstr? el->hintstr:"",
251                   el->hintstr? ")":"");
252
253   #ifdef HAVE_DL_DLOPEN
254     sym = dlsym(el->handle, SYMBOL_ENUM);
255     if( (err=dlerror()) ) {
256         log_error("%s: invalid gnupg extension: %s\n", el->name, err );
257         goto failure;
258     }
259     el->enumfunc = (void *(*)(int,int*,int*,int*))sym;
260   #else /* dld */
261     addr = dld_get_func(SYMBOL_ENUM);
262     if( !addr ) {
263         log_error("%s: invalid gnupg extension: %s\n",
264                                 el->name, dld_strerror(dld_errno) );
265         goto failure;
266     }
267     rc = dld_function_executable_p(SYMBOL_ENUM);
268     if( rc ) {
269         log_error("%s: extension function is not executable: %s\n",
270                                         el->name, dld_strerror(rc) );
271         goto failure;
272     }
273     el->enumfunc = (void *(*)(int,int*,int*,int*))addr;
274     el->handle = 1; /* mark as usable */
275   #endif
276
277   #ifdef HAVE_DL_DLOPEN
278     if( g10_opt_verbose > 2 ) {
279         /* list the contents of the module */
280         while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) {
281             if( vers != 1 ) {
282                 log_info("%s: ignoring func with version %d\n",el->name,vers);
283                 continue;
284             }
285             switch( class ) {
286               case 11:
287               case 21:
288               case 31:
289                 log_info("%s: provides %s algorithm %d\n", el->name,
290                                 class == 11? "md"     :
291                                 class == 21? "cipher" : "pubkey",
292                                                        *(int*)sym);
293                 break;
294               default:
295                 /*log_debug("%s: skipping class %d\n", el->name, class);*/
296                 break;
297             }
298         }
299     }
300   #endif
301     return 0;
302
303   failure:
304   #ifdef HAVE_DL_DLOPEN
305     if( el->handle ) {
306         dlclose(el->handle);
307         el->handle = NULL;
308     }
309   #endif
310     el->failed = 1;
311   #endif /*USE_DYNAMIC_LINKING*/
312     return -1;
313 }
314
315
316
317 int
318 enum_gnupgext_digests( void **enum_context,
319             int *algo,
320             const char *(**r_get_info)( int, size_t*,byte**, int*, int*,
321                                        void (**)(void*),
322                                        void (**)(void*,byte*,size_t),
323                                        void (**)(void*),byte *(**)(void*)) )
324 {
325     EXTLIST r;
326     ENUMCONTEXT *ctx;
327
328     if( !*enum_context ) { /* init context */
329         ctx = m_alloc_clear( sizeof( *ctx ) );
330         ctx->r = extensions;
331         ctx->reqalgo = *algo;
332         *enum_context = ctx;
333     }
334     else if( !algo ) { /* release the context */
335         m_free(*enum_context);
336         *enum_context = NULL;
337         return 0;
338     }
339     else
340         ctx = *enum_context;
341
342     for( r = ctx->r; r; r = r->next )  {
343         int class, vers;
344
345         if( r->failed )
346             continue;
347         if( !r->handle && load_extension(r) )
348             continue;
349         /* get a digest info function */
350         if( ctx->sym )
351             goto inner_loop;
352         while( (ctx->sym = (*r->enumfunc)(10, &ctx->seq1, &class, &vers)) ) {
353             void *sym;
354             /* must check class because enumfunc may be wrong coded */
355             if( vers != 1 || class != 10 )
356                 continue;
357           inner_loop:
358             *r_get_info = ctx->sym;
359             while( (sym = (*r->enumfunc)(11, &ctx->seq2, &class, &vers)) ) {
360                 if( vers != 1 || class != 11 )
361                     continue;
362                 *algo = *(int*)sym;
363                 ctx->r = r;
364                 return 1;
365             }
366             ctx->seq2 = 0;
367         }
368         ctx->seq1 = 0;
369     }
370     ctx->r = r;
371     return 0;
372 }
373
374 const char *
375 enum_gnupgext_ciphers( void **enum_context, int *algo,
376                        size_t *keylen, size_t *blocksize, size_t *contextsize,
377                        int  (**setkeyf)( void *c, byte *key, unsigned keylen ),
378                        void (**encryptf)( void *c, byte *outbuf, byte *inbuf ),
379                        void (**decryptf)( void *c, byte *outbuf, byte *inbuf )
380                      )
381 {
382     EXTLIST r;
383     ENUMCONTEXT *ctx;
384     const char * (*finfo)(int, size_t*, size_t*, size_t*,
385                           int  (**)( void *, byte *, unsigned),
386                           void (**)( void *, byte *, byte *),
387                           void (**)( void *, byte *, byte *));
388
389     if( !*enum_context ) { /* init context */
390         ctx = m_alloc_clear( sizeof( *ctx ) );
391         ctx->r = extensions;
392         *enum_context = ctx;
393     }
394     else if( !algo ) { /* release the context */
395         m_free(*enum_context);
396         *enum_context = NULL;
397         return NULL;
398     }
399     else
400         ctx = *enum_context;
401
402     for( r = ctx->r; r; r = r->next )  {
403         int class, vers;
404
405         if( r->failed )
406             continue;
407         if( !r->handle && load_extension(r) )
408             continue;
409         /* get a cipher info function */
410         if( ctx->sym )
411             goto inner_loop;
412         while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) {
413             void *sym;
414             /* must check class because enumfunc may be wrong coded */
415             if( vers != 1 || class != 20 )
416                 continue;
417           inner_loop:
418             finfo = ctx->sym;
419             while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) {
420                 const char *algname;
421                 if( vers != 1 || class != 21 )
422                     continue;
423                 *algo = *(int*)sym;
424                 algname = (*finfo)( *algo, keylen, blocksize, contextsize,
425                                     setkeyf, encryptf, decryptf );
426                 if( algname ) {
427                     ctx->r = r;
428                     return algname;
429                 }
430             }
431             ctx->seq2 = 0;
432         }
433         ctx->seq1 = 0;
434     }
435     ctx->r = r;
436     return NULL;
437 }
438
439 const char *
440 enum_gnupgext_pubkeys( void **enum_context, int *algo,
441     int *npkey, int *nskey, int *nenc, int *nsig, int *use,
442     int (**generate)( int algo, unsigned nbits, MPI *skey, MPI **retfactors ),
443     int (**check_secret_key)( int algo, MPI *skey ),
444     int (**encryptf)( int algo, MPI *resarr, MPI data, MPI *pkey ),
445     int (**decryptf)( int algo, MPI *result, MPI *data, MPI *skey ),
446     int (**sign)( int algo, MPI *resarr, MPI data, MPI *skey ),
447     int (**verify)( int algo, MPI hash, MPI *data, MPI *pkey,
448                     int (*cmp)(void *, MPI), void *opaquev ),
449     unsigned (**get_nbits)( int algo, MPI *pkey ) )
450 {
451     EXTLIST r;
452     ENUMCONTEXT *ctx;
453     const char * (*finfo)( int, int *, int *, int *, int *, int *,
454                            int (**)( int, unsigned, MPI *, MPI **),
455                            int (**)( int, MPI * ),
456                            int (**)( int, MPI *, MPI , MPI * ),
457                            int (**)( int, MPI *, MPI *, MPI * ),
458                            int (**)( int, MPI *, MPI , MPI * ),
459                            int (**)( int, MPI , MPI *, MPI *,
460                                             int (*)(void*,MPI), void *),
461                            unsigned (**)( int , MPI * ) );
462
463     if( !*enum_context ) { /* init context */
464         ctx = m_alloc_clear( sizeof( *ctx ) );
465         ctx->r = extensions;
466         *enum_context = ctx;
467     }
468     else if( !algo ) { /* release the context */
469         m_free(*enum_context);
470         *enum_context = NULL;
471         return NULL;
472     }
473     else
474         ctx = *enum_context;
475
476     for( r = ctx->r; r; r = r->next )  {
477         int class, vers;
478
479         if( r->failed )
480             continue;
481         if( !r->handle && load_extension(r) )
482             continue;
483         /* get a pubkey info function */
484         if( ctx->sym )
485             goto inner_loop;
486         while( (ctx->sym = (*r->enumfunc)(30, &ctx->seq1, &class, &vers)) ) {
487             void *sym;
488             if( vers != 1 || class != 30 )
489                 continue;
490           inner_loop:
491             finfo = ctx->sym;
492             while( (sym = (*r->enumfunc)(31, &ctx->seq2, &class, &vers)) ) {
493                 const char *algname;
494                 if( vers != 1 || class != 31 )
495                     continue;
496                 *algo = *(int*)sym;
497                 algname = (*finfo)( *algo, npkey, nskey, nenc, nsig, use,
498                                     generate, check_secret_key, encryptf,
499                                     decryptf, sign, verify, get_nbits );
500                 if( algname ) {
501                     ctx->r = r;
502                     return algname;
503                 }
504             }
505             ctx->seq2 = 0;
506         }
507         ctx->seq1 = 0;
508     }
509     ctx->r = r;
510     return NULL;
511 }
512
513
514 int (*
515 dynload_getfnc_gather_random())(void (*)(const void*, size_t, int), int,
516                                                             size_t, int)
517 {
518     EXTLIST r;
519     void *sym;
520
521     for( r = extensions; r; r = r->next )  {
522         int seq, class, vers;
523
524         if( r->failed )
525             continue;
526         if( !r->handle && load_extension(r) )
527             continue;
528         seq = 0;
529         while( (sym = (*r->enumfunc)(40, &seq, &class, &vers)) ) {
530             if( vers != 1 || class != 40 )
531                 continue;
532             return (int (*)(void (*)(const void*, size_t, int), int,
533                                                         size_t, int))sym;
534         }
535     }
536     return NULL;
537 }
538
539
540 void (*
541 dynload_getfnc_fast_random_poll())( void (*)(const void*, size_t, int), int)
542 {
543     EXTLIST r;
544     void *sym;
545
546     for( r = extensions; r; r = r->next )  {
547         int seq, class, vers;
548
549         if( r->failed )
550             continue;
551         if( !r->handle && load_extension(r) )
552             continue;
553         seq = 0;
554         while( (sym = (*r->enumfunc)(41, &seq, &class, &vers)) ) {
555             if( vers != 1 || class != 41 )
556                 continue;
557             return (void (*)( void (*)(const void*, size_t, int), int))sym;
558         }
559     }
560     return NULL;
561 }
562