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