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