[exim-cvs] dyn load auth/router/transport files

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] dyn load auth/router/transport files
Gitweb: https://git.exim.org/exim.git/commitdiff/cbe845f056c7a15d97056435a9e112a87f2ad312
Commit:     cbe845f056c7a15d97056435a9e112a87f2ad312
Parent:     51d2588be64b116d4b4318b182e0ab2bad14570c
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Tue Aug 13 19:36:04 2024 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Wed Aug 14 10:51:41 2024 +0100


    dyn load auth/router/transport files
---
 src/src/drtables.c  |   4 +-
 src/src/functions.h |   4 +-
 src/src/readconf.c  | 121 ++++++++++++++++++++++++++++++++++++++++++----------
 src/src/route.c     |  29 ++++---------
 src/src/structs.h   |   5 +++
 src/src/transport.c |   2 +-
 6 files changed, 119 insertions(+), 46 deletions(-)


diff --git a/src/src/drtables.c b/src/src/drtables.c
index 1a3a80460..0f64728b4 100644
--- a/src/src/drtables.c
+++ b/src/src/drtables.c
@@ -626,8 +626,8 @@ void
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
diff --git a/src/src/functions.h b/src/src/functions.h
index dbfad63eb..3253043ae 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -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 void    add_driver_info(driver_info **, const driver_info *, size_t);
+


 #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 *);
-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);
diff --git a/src/src/readconf.c b/src/src/readconf.c
index f22ff700e..da94071b5 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -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                 *
 *************************************************/
@@ -3711,20 +3723,18 @@ set by another incarnation of the same driver).
 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
-  class               class of driver, for error message
+  class               class of driver


 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)
{
-/*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).
@@ -3753,26 +3763,93 @@ and scan from dlopen if marked dynamic.

 #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


-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);

-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
-  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
@@ -3821,7 +3898,7 @@ Returns:                     nothing
 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,
@@ -3914,7 +3991,7 @@ while ((buffer = get_config_line()))
         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
@@ -4296,7 +4373,7 @@ for (auth_info * tblent = auths_available_oldarray;


 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 */
diff --git a/src/src/route.c b/src/src/route.c
index cce120967..b733d1a52 100644
--- a/src/src/route.c
+++ b/src/src/route.c
@@ -220,17 +220,6 @@ if (after && !afterthis)
 *             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
@@ -273,30 +262,30 @@ store_pool = POOL_PERM;
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
- 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
- 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
- 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
- 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
- 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
- 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
- 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;
@@ -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 */
-  (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 */
diff --git a/src/src/structs.h b/src/src/structs.h
index 3446664cd..ffcd8a5df 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -158,6 +158,11 @@ typedef struct driver_info {
 #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
diff --git a/src/src/transport.c b/src/src/transport.c
index e92541bbf..7e47cf1da 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -159,7 +159,7 @@ for (transport_info * tblent = transports_available_oldarray;
}

 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 */


--
## subscription configuration (requires account):
## https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/