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