dyn load auth/router/transport files
authorJeremy Harris <jgh146exb@wizmail.org>
Tue, 13 Aug 2024 18:36:04 +0000 (19:36 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 14 Aug 2024 09:51:41 +0000 (10:51 +0100)
src/src/drtables.c
src/src/functions.h
src/src/readconf.c
src/src/route.c
src/src/structs.h
src/src/transport.c

index 1a3a804601e50eeeb5903afd35fc865cc4548bde..0f64728b467ed89a1d296e857961f8629795bcb1 100644 (file)
@@ -626,8 +626,8 @@ void
 init_lookup_list(void)
 {
 #ifdef LOOKUP_MODULE_DIR
 init_lookup_list(void)
 {
 #ifdef LOOKUP_MODULE_DIR
-DIR *dd;
-struct dirent *ent;
+DIR * dd;
+struct dirent * ent;
 int countmodules = 0;
 int moduleerrors = 0;
 #endif
 int countmodules = 0;
 int moduleerrors = 0;
 #endif
index dbfad63eb5b75bbac27ac3ed2f32a2afc32ec612..3253043ae29d1a8d287d42e875d926f96a26f627 100644 (file)
@@ -107,6 +107,8 @@ extern uschar *acl_standalone_setvar(const uschar *, BOOL);
 
 extern tree_node *acl_var_create(uschar *);
 extern void    acl_var_write(uschar *, uschar *, void *);
 
 extern tree_node *acl_var_create(uschar *);
 extern void    acl_var_write(uschar *, uschar *, void *);
+extern void    add_driver_info(driver_info **, const driver_info *, size_t);
+
 
 #ifdef EXPERIMENTAL_ARC
 # ifdef SUPPORT_DMARC
 
 #ifdef EXPERIMENTAL_ARC
 # ifdef SUPPORT_DMARC
@@ -423,7 +425,7 @@ extern int     rda_interpret(redirect_block *, int, const uschar *,
                uschar **, error_block **, int *, const uschar *);
 extern int     rda_is_filter(const uschar *);
 extern BOOL    readconf_depends(driver_instance *, uschar *);
                uschar **, error_block **, int *, const uschar *);
 extern int     rda_is_filter(const uschar *);
 extern BOOL    readconf_depends(driver_instance *, uschar *);
-extern void    readconf_driver_init(driver_instance **, driver_info *, int,
+extern void    readconf_driver_init(driver_instance **, driver_info **, int,
                void *, int, optionlist *, int, const uschar *);
 extern const uschar *readconf_find_option(void *);
 extern void    readconf_main(BOOL);
                void *, int, optionlist *, int, const uschar *);
 extern const uschar *readconf_find_option(void *);
 extern void    readconf_main(BOOL);
index f22ff700e6f318e6e71b2a65acbbd51f0d208d9c..da94071b506447ab940269fb3b50b2c4ed381691 100644 (file)
@@ -3699,6 +3699,18 @@ if (!nowarn && !keep_environment && environ && *environ)
 
 
 
 
 
 
+/* Add a driver info struct to a list. */
+
+void
+add_driver_info(driver_info ** drlist_p, const driver_info * newent,
+  size_t size)
+{
+driver_info * listent = store_get(size, newent);
+memcpy(listent, newent, size);
+listent->next = *drlist_p;
+*drlist_p= listent;
+}
+
 /*************************************************
 *          Initialize one driver                 *
 *************************************************/
 /*************************************************
 *          Initialize one driver                 *
 *************************************************/
@@ -3711,20 +3723,18 @@ set by another incarnation of the same driver).
 Arguments:
   d                   pointer to driver instance block, with generic
                         options filled in
 Arguments:
   d                   pointer to driver instance block, with generic
                         options filled in
-  drivers_available   vector of available drivers
+  info_anchor        list of available drivers
   size_of_info        size of each block in drivers_available
   size_of_info        size of each block in drivers_available
-  class               class of driver, for error message
+  class               class of driver
 
 Returns:              pointer to the driver info block
 */
 
 static driver_info *
 
 Returns:              pointer to the driver info block
 */
 
 static driver_info *
-init_driver(driver_instance * d, driver_info * drivers_available,
+init_driver(driver_instance * d, driver_info ** info_anchor,
   int size_of_info, const uschar * class)
 {
   int size_of_info, const uschar * class)
 {
-/*XXX if dynamic, the _info entry will be here but code may or may not
-be loaded.  How to tell?  What's the entry point?  init call?
-Currently that is IN the _info entry.
+/*XXX if dynamic, the _info entry will not be here yet.
 
 For lookups it does it by pulling the info entry out of the dlopen()d
 file (for dynamic) or direct from the lookup .o file (for static).
 
 For lookups it does it by pulling the info entry out of the dlopen()d
 file (for dynamic) or direct from the lookup .o file (for static).
@@ -3753,26 +3763,93 @@ and scan from dlopen if marked dynamic.
 
 #ifdef old
 /*XXX walk the old array */
 
 #ifdef old
 /*XXX walk the old array */
-for (driver_info * dd = drivers_available; dd->driver_name[0] != 0;
-     dd = (driver_info *)((US dd) + size_of_info))
+for (driver_info * di= *info_anchor; di->driver_name[0] != 0;
+     di= (driver_info *)((US di) + size_of_info))
 #endif
 
 #endif
 
-for (driver_info * dd = drivers_available; dd; dd = dd->next)
-  if (Ustrcmp(d->driver_name, dd->driver_name) == 0)
+driver_info * di;
+int len;
+DIR * dd;
+
+/* First scan the list of statically-built drivers. */
+
+for (di = *info_anchor; di; di = di->next)
+  if (Ustrcmp(d->driver_name, di->driver_name) == 0)
+    goto found;
+
+#ifdef LOOKUP_MODULE_DIR
+/* Potentially a loadable module. Look for a file with the right name. */
+
+if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
+  {
+  log_write(0, LOG_MAIN|LOG_PANIC,
+           "Couldn't open %s: not loading driver modules\n", LOOKUP_MODULE_DIR);
+  }
+else
+  {
+  uschar * fname = string_sprintf("%s_%s." DYNLIB_FN_EXT, d->driver_name, class), * sname;
+  const char * errormsg;
+
+  DEBUG(D_any) debug_printf("Loading %s %s driver from %s\n",
+                           d->driver_name, class, LOOKUP_MODULE_DIR);
+
+  for(struct dirent * ent; ent = readdir(dd); ) if (Ustrcmp(ent->d_name, fname) == 0)
     {
     {
-    int len = dd->options_len;
-    d->info = dd;
-    d->options_block = store_get_perm(len, GET_UNTAINTED);
-    memcpy(d->options_block, dd->options_block, len);
-    for (int i = 0; i < *dd->options_count; i++)
-      dd->options[i].type &= ~opt_set;
-    return dd;
+    void * dl = dlopen(CS string_sprintf(LOOKUP_MODULE_DIR "/%s", fname), RTLD_NOW);
+    static driver_magics dm[] = {
+      { ROUTER_MAGIC,  US"router" },
+      { TRANSPORT_MAGIC, US"transport" },
+      { AUTH_MAGIC,    US"auth" },
+    };
+
+    if (!dl)
+      {
+      errormsg = dlerror();
+      log_write(0, LOG_MAIN|LOG_PANIC, "Error loading %s %s driver: %s\n",
+               d->driver_name, class, errormsg);
+      break;
+      }
+    (void) dlerror();          /* cf. comment in init_lookup_list() */
+
+    di = (driver_info *) dlsym(dl, CS string_sprintf("_%s_info", class));
+    if ((errormsg = dlerror()))
+      {
+      log_write(0, LOG_MAIN|LOG_PANIC,
+               "%s does not appear to be a %s module (%s)\n", fname, class, errormsg);
+      dlclose(dl);
+      break;
+      }
+    for(driver_magics * dmp = dm; dmp < dm + nelem(dm); dmp++)
+      if(Ustrcmp(dmp->class, class) == 0 && dmp->magic == di->dyn_magic)
+       {
+       add_driver_info(info_anchor, di, size_of_info);
+       DEBUG(D_any) debug_printf("Loaded %s %s\n", d->driver_name, class);
+       closedir(dd);
+       goto found;
+       }
+
+    log_write(0, LOG_MAIN|LOG_PANIC,
+             "%s module %s is not compatible with this version of Exim\n",
+             class, d->driver_name);
+    dlclose(dl);
+    break;
     }
     }
+  closedir(dd);
+  }
+#endif /* LOOKUP_MODULE_DIR */
 
 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
   "%s %s: cannot find %s driver \"%s\"", class, d->name, class, d->driver_name);
 
 
 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
   "%s %s: cannot find %s driver \"%s\"", class, d->name, class, d->driver_name);
 
-return NULL;   /* never obeyed */
+found:
+
+len = di->options_len;
+d->info = di;
+d->options_block = store_get_perm(len, GET_UNTAINTED);
+memcpy(d->options_block, di->options_block, len);
+for (int i = 0; i < *di->options_count; i++)
+  di->options[i].type &= ~opt_set;
+return di;
 }
 
 
 }
 
 
@@ -3806,7 +3883,7 @@ blocks for this shared code to work.
 
 Arguments:
   anchor                     &routers, &transports, &auths
 
 Arguments:
   anchor                     &routers, &transports, &auths
-  drivers_available          available drivers
+  info_anchor               available drivers
   size_of_info               size of each info block
   instance_default           points to default data for an instance
   instance_size              size of instance block
   size_of_info               size of each info block
   instance_default           points to default data for an instance
   instance_size              size of instance block
@@ -3821,7 +3898,7 @@ Returns:                     nothing
 void
 readconf_driver_init(
   driver_instance ** anchor,
 void
 readconf_driver_init(
   driver_instance ** anchor,
-  driver_info * drivers_available,     /*XXX now list not array */
+  driver_info ** info_anchor,  /*XXX now list not array, static only so far */
   int size_of_info,
   void * instance_default,
   int  instance_size,
   int size_of_info,
   void * instance_default,
   int  instance_size,
@@ -3914,7 +3991,7 @@ while ((buffer = get_config_line()))
         driver_optionlist_count, d, NULL))
     {
     if (!d->info && d->driver_name)
         driver_optionlist_count, d, NULL))
     {
     if (!d->info && d->driver_name)
-      init_driver(d, drivers_available, size_of_info, class);
+      init_driver(d, info_anchor, size_of_info, class);
     }
 
   /* Handle private options - pass the generic block because some may
     }
 
   /* Handle private options - pass the generic block because some may
@@ -4296,7 +4373,7 @@ for (auth_info * tblent = auths_available_oldarray;
 
 
 readconf_driver_init((driver_instance **)&auths,      /* chain anchor */
 
 
 readconf_driver_init((driver_instance **)&auths,      /* chain anchor */
-  (driver_info *)auths_available_newlist,    /* available drivers */
+  (driver_info **)&auths_available_newlist,    /* available drivers */
   sizeof(auth_info),                 /* size of info block */
   &auth_defaults,                    /* default values for generic options */
   sizeof(auth_instance),             /* size of instance block */
   sizeof(auth_info),                 /* size of info block */
   &auth_defaults,                    /* default values for generic options */
   sizeof(auth_instance),             /* size of instance block */
index cce1209671e7c8a5f2aa54de27e7dcd7ce8efecd..b733d1a522445fa7cdd4156d518ae3ceccbde16a 100644 (file)
@@ -220,17 +220,6 @@ if (after && !afterthis)
 *             Initialize router list             *
 *************************************************/
 
 *             Initialize router list             *
 *************************************************/
 
-/*XXX will likely want to rename to generic */
-
-static void
-add_router(driver_info ** drlist_p, const driver_info * newent, size_t size)
-{
-driver_info * listent = store_get(size, newent);
-memcpy(listent, newent, size);
-listent->next = *drlist_p;
-*drlist_p= listent;
-}
-
 /* Read the routers section of the configuration file, and set up a chain of
 router instances according to its contents. Each router has generic options and
 may also have its own private options. This function is only ever called when
 /* Read the routers section of the configuration file, and set up a chain of
 router instances according to its contents. Each router has generic options and
 may also have its own private options. This function is only ever called when
@@ -273,30 +262,30 @@ store_pool = POOL_PERM;
   extern router_info redirect_router_info;
   extern router_info queryprogram_router_info;
 
   extern router_info redirect_router_info;
   extern router_info queryprogram_router_info;
 
-  /*XXX this addsonly the statics.  We can't get the dynamics as they
+  /*XXX this adds only the statics.  We can't get the dynamics as they
   are not linked.  Until dlopen(), when we can use dlsym().  So the discovery
   is by the file exitence, via the filename pattern. */
   /*XXX TODO: move the info structs to individual driver files */
 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
   are not linked.  Until dlopen(), when we can use dlsym().  So the discovery
   is by the file exitence, via the filename pattern. */
   /*XXX TODO: move the info structs to individual driver files */
 #if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
-  add_router(anchor, &accept_router_info.drinfo, sizeof(router_info));
+  add_driver_info(anchor, &accept_router_info.drinfo, sizeof(router_info));
 #endif
 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
 #endif
 #if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
-  add_router(anchor, &dnslookup_router_info.drinfo, sizeof(router_info));
+  add_driver_info(anchor, &dnslookup_router_info.drinfo, sizeof(router_info));
 #endif
 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
 #endif
 # if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
-  add_router(anchor, &ipliteral_router_info.drinfo, sizeof(router_info));
+  add_driver_info(anchor, &ipliteral_router_info.drinfo, sizeof(router_info));
 #endif
 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
 #endif
 #if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
-  add_router(anchor, &iplookup_router_info.drinfo, sizeof(router_info));
+  add_driver_info(anchor, &iplookup_router_info.drinfo, sizeof(router_info));
 #endif
 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
 #endif
 #if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
-  add_router(anchor, &manualroute_router_info.drinfo, sizeof(router_info));
+  add_driver_info(anchor, &manualroute_router_info.drinfo, sizeof(router_info));
 #endif
 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
 #endif
 #if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
-  add_router(anchor, &redirect_router_info.drinfo, sizeof(router_info));
+  add_driver_info(anchor, &redirect_router_info.drinfo, sizeof(router_info));
 #endif
 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
 #endif
 #if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
-  add_router(anchor, &queryprogram_router_info.drinfo, sizeof(router_info));
+  add_driver_info(anchor, &queryprogram_router_info.drinfo, sizeof(router_info));
 #endif
   }
 store_pool = old_pool;
 #endif
   }
 store_pool = old_pool;
@@ -305,7 +294,7 @@ store_pool = old_pool;
 
 /*XXX this does the config file "routers" section reading */
 readconf_driver_init((driver_instance **)&routers,     /* chain anchor */
 
 /*XXX this does the config file "routers" section reading */
 readconf_driver_init((driver_instance **)&routers,     /* chain anchor */
-  (driver_info *)routers_available_newlist,   /* available drivers */
+  (driver_info **)&routers_available_newlist,   /* available drivers */
   sizeof(router_info),                /* size of info blocks */
   &router_defaults,                   /* default values for generic options */
   sizeof(router_instance),            /* size of instance block */
   sizeof(router_info),                /* size of info blocks */
   &router_defaults,                   /* default values for generic options */
   sizeof(router_instance),            /* size of instance block */
index 3446664cd8b1631999023dbc03b78f845eee0fea..ffcd8a5dfe9b1ce597f87e6962d38f55b7ea8882 100644 (file)
@@ -158,6 +158,11 @@ typedef struct driver_info {
 #define TRANSPORT_MAGIC        0x54504d31      /* TPM1 */
 #define AUTH_MAGIC     0x65554d31      /* AUM1 */
 
 #define TRANSPORT_MAGIC        0x54504d31      /* TPM1 */
 #define AUTH_MAGIC     0x65554d31      /* AUM1 */
 
+typedef struct {
+  uint         magic;
+  uschar *     class;
+} driver_magics;
+
 
 /* Structure for holding information about the configured transports. Some
 of the generally accessible options are set from the configuration file; others
 
 /* Structure for holding information about the configured transports. Some
 of the generally accessible options are set from the configuration file; others
index e92541bbf1018d51b797dfe36cd03af032f362c3..7e47cf1da56697e380d7c7363186e63ae3bd2209 100644 (file)
@@ -159,7 +159,7 @@ for (transport_info * tblent = transports_available_oldarray;
   }
 
 readconf_driver_init((driver_instance **)&transports,     /* chain anchor */
   }
 
 readconf_driver_init((driver_instance **)&transports,     /* chain anchor */
-  (driver_info *)transports_available_newlist,   /* available drivers */
+  (driver_info **)&transports_available_newlist,   /* available drivers */
   sizeof(transport_info),                /* size of info block */
   &transport_defaults,                   /* default values for generic options */
   sizeof(transport_instance),            /* size of instance block */
   sizeof(transport_info),                /* size of info block */
   &transport_defaults,                   /* default values for generic options */
   sizeof(transport_instance),            /* size of instance block */