* ttyio.c (tty_enable_completion, tty_disable_completion): Add checks
[gnupg.git] / cipher / dynload.c
index b40eb40..05d82f6 100644 (file)
 /* dynload.c - load cipher extensions
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <dlfcn.h>
+#include <unistd.h>
 #include "util.h"
 #include "cipher.h"
-#include "dynload.h"
+#include "algorithms.h"
+
 
 typedef struct ext_list {
     struct ext_list *next;
-    void *handle; /* handle from dlopen() */
-    int  failed;  /* already tried but failed */
-    void * (*enumfunc)(int, int*, int*, int*);
     char name[1];
 } *EXTLIST;
 
 static EXTLIST extensions;
 
-typedef struct {
-    EXTLIST r;
-    int seq1;
-    int seq2;
-    void *sym;
-} ENUMCONTEXT;
-
-/****************
+/* This is actually not used anymore but we keep a list of already 
+ * set extensions modules here.   
+ *
+ * Here is the ancient comment:
  * Register an extension module.  The last registered module will
- * be loaded first.
+ * be loaded first.  A name may have a list of classes
+ * appended; e.g:
+ *     mymodule.so(1:17,3:20,3:109)
+ * means that this module provides digest algorithm 17 and public key
+ * algorithms 20 and 109.  This is only a hint but if it is there the
+ * loader may decide to only load a module which claims to have a
+ * requested algorithm.
+ *
+ * mainpgm is the path to the program which wants to load a module
+ * it is only used in some environments.
  */
 void
-register_cipher_extension( const char *fname )
+register_cipher_extension( const char *mainpgm, const char *fname )
 {
-    EXTLIST r, el;
+    EXTLIST r, el, intex;
+    char *p, *pe;
 
-    if( *fname != '/' ) { /* do tilde expansion etc */
-       char *;
+    if( *fname != DIRSEP_C ) { /* do tilde expansion etc */
+       char *tmp;
 
-       if( strchr(fname, '/') )
-           p = make_filename(fname, NULL);
+       if( strchr(fname, DIRSEP_C) )
+           tmp = make_filename(fname, NULL);
        else
-           p = make_filename(GNUPG_LIBDIR, fname, NULL);
-       el = m_alloc_clear( sizeof *el + strlen(p) );
-       strcpy(el->name, p );
-       m_free(p);
+           tmp = make_filename(GNUPG_LIBDIR, fname, NULL);
+       el = xmalloc_clear( sizeof *el + strlen(tmp) );
+       strcpy(el->name, tmp );
+       xfree(tmp);
     }
     else {
-       el = m_alloc_clear( sizeof *el + strlen(fname) );
+       el = xmalloc_clear( sizeof *el + strlen(fname) );
        strcpy(el->name, fname );
     }
+    /* check whether we have a class hint */
+    if( (p=strchr(el->name,'(')) && (pe=strchr(p+1,')')) && !pe[1] )
+       *p = *pe = 0;
+
     /* check that it is not already registered */
-    for(r = extensions; r; r = r->next )
+    intex = NULL;
+    for(r = extensions; r; r = r->next ) {
        if( !compare_filenames(r->name, el->name) ) {
-           log_debug("extension '%s' already registered\n", el->name );
-           m_free(el);
+           log_info("extension `%s' already registered\n", el->name );
+           xfree(el);
            return;
        }
-    log_debug("extension '%s' registered\n", el->name );
+    }
     /* and register */
     el->next = extensions;
     extensions = el;
 }
 
-
-static int
-load_extension( EXTLIST el )
-{
-    char **name;
-    void *sym;
-    const char *err;
-    int seq = 0;
-    int class, vers;
-
-    el->handle = dlopen(el->name, RTLD_LAZY);
-    if( !el->handle ) {
-       log_error("%s: error loading extension: %s\n", el->name, dlerror() );
-       goto failure;
-    }
-    name = (char**)dlsym(el->handle, "gnupgext_version");
-    if( (err=dlerror()) ) {
-       log_error("%s: not a gnupg extension: %s\n", el->name, err );
-       goto failure;
-    }
-
-    log_info("%s: version '%s'\n", el->name, *name );
-
-    sym = dlsym(el->handle, "gnupgext_enum_func");
-    if( (err=dlerror()) ) {
-       log_error("%s: invalid gnupg extension: %s\n", el->name, err );
-       goto failure;
-    }
-    el->enumfunc = (void *(*)(int,int*,int*,int*))sym;
-
-    /* list the contents of the module */
-    while( (sym = (*el->enumfunc)(0, &seq, &class, &vers)) ) {
-       if( vers != 1 ) {
-           log_error("%s: ignoring func with version %d\n", el->name, vers);
-           continue;
-       }
-       switch( class ) {
-         case 11:
-         case 21:
-         case 31:
-           log_info("%s: provides %s algorithm %d\n", el->name,
-                           class == 11? "md"     :
-                           class == 21? "cipher" : "pubkey",
-                                                  *(int*)sym);
-           break;
-         default:
-           log_debug("%s: skipping class %d\n", el->name, class);
-       }
-    }
-    return 0;
-
-  failure:
-    if( el->handle ) {
-       dlclose(el->handle);
-       el->handle = NULL;
-    }
-    el->failed = 1;
-    return -1;
-}
-
-
-
+/* Return the module name with index SEQ, return NULL as as indication
+   for end of list. */
 const char *
-enum_gnupgext_ciphers( void **enum_context, int *algo,
-                      size_t *keylen, size_t *blocksize, size_t *contextsize,
-                      void (**setkey)( void *c, byte *key, unsigned keylen ),
-                      void (**encrypt)( void *c, byte *outbuf, byte *inbuf ),
-                      void (**decrypt)( void *c, byte *outbuf, byte *inbuf )
-                    )
+dynload_enum_module_names (int seq)
 {
-    EXTLIST r;
-    ENUMCONTEXT *ctx;
-    const char * (*finfo)(int, size_t*, size_t*, size_t*,
-                         void (**)( void *, byte *, unsigned),
-                         void (**)( void *, byte *, byte *),
-                         void (**)( void *, byte *, byte *));
+  EXTLIST el = extensions;
 
-    if( !*enum_context ) { /* init context */
-       ctx = m_alloc_clear( sizeof( *ctx ) );
-       ctx->r = extensions;
-       *enum_context = ctx;
-    }
-    else if( !algo ) { /* release the context */
-       m_free(*enum_context);
-       *enum_context = NULL;
-       return NULL;
-    }
-    else
-       ctx = *enum_context;
-
-    for( r = ctx->r; r; r = r->next )  {
-       int class, vers;
-
-       if( r->failed )
-           continue;
-       if( !r->handle && load_extension(r) )
-           continue;
-       /* get a cipher info function */
-       if( ctx->sym )
-           goto inner_loop;
-       while( (ctx->sym = (*r->enumfunc)(20, &ctx->seq1, &class, &vers)) ) {
-           void *sym;
-           /* must check class because enumfunc may be wrong coded */
-           if( vers != 1 || class != 20 )
-               continue;
-         inner_loop:
-           finfo = ctx->sym;
-           while( (sym = (*r->enumfunc)(21, &ctx->seq2, &class, &vers)) ) {
-               const char *algname;
-               if( vers != 1 || class != 21 )
-                   continue;
-               *algo = *(int*)sym;
-               algname = (*finfo)( *algo, keylen, blocksize, contextsize,
-                                   setkey, encrypt, decrypt );
-               log_debug("found algo %d (%s)\n", *algo, algname );
-               if( algname ) {
-                   ctx->r = r;
-                   return algname;
-               }
-           }
-           ctx->seq2 = 0;
-       }
-       ctx->seq1 = 0;
-    }
-    ctx->r = r;
-    return NULL;
+  for (; el && el->name && seq; el = el->next, seq--)
+    ;
+  return el? el->name:NULL;
 }
-