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