param: fix copy service to copy over cmdlist
[mat/samba.git] / lib / param / loadparm.c
index f9092c6b8e442dd66188db236aef73c104071515..bf2002264a61971187bb714b16f11be2cb5ea51c 100644 (file)
 #include "lib/param/s3_param.h"
 #include "lib/util/bitmap.h"
 #include "libcli/smb/smb_constants.h"
+#include "tdb.h"
 
 #define standard_sub_basic talloc_strdup
 
 static bool do_parameter(const char *, const char *, void *);
 static bool defaults_saved = false;
 
-#define LOADPARM_EXTRA_GLOBALS \
-       struct parmlist_entry *param_opt;                               \
-       char *realm_original;                                           \
-       int iminreceivefile;                                            \
-       char *szPrintcapname;                                           \
-       int CupsEncrypt;                                                \
-       int  iPreferredMaster;                                          \
-       char *szLdapMachineSuffix;                                      \
-       char *szLdapUserSuffix;                                         \
-       char *szLdapIdmapSuffix;                                        \
-       char *szLdapGroupSuffix;                                        \
-       char *szIdmapUID;                                               \
-       char *szIdmapGID;                                               \
-       char *szIdmapBackend;                                           \
-       int winbindMaxDomainConnections;                                \
-       int ismb2_max_credits;                                          \
-       char *tls_keyfile;                                              \
-       char *tls_certfile;                                             \
-       char *tls_cafile;                                               \
-       char *tls_crlfile;                                              \
-       char *tls_dhpfile;
-
 #include "lib/param/param_global.h"
 
-#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
-
-/* we don't need a special handler for "dos charset" and "unix charset" */
-#define handle_dos_charset NULL
-#define handle_charset NULL
-
-/* these are parameter handlers which are not needed in the
- * non-source3 code
- */
-#define handle_netbios_aliases NULL
-#define handle_printing NULL
-#define handle_ldap_debug_level NULL
-#define handle_idmap_backend NULL
-#define handle_idmap_uid NULL
-#define handle_idmap_gid NULL
-
-#ifndef N_
-#define N_(x) x
-#endif
-
-/* prototypes for the special type handlers */
-static bool handle_include(struct loadparm_context *lp_ctx, int unused,
-                          const char *pszParmValue, char **ptr);
-static bool handle_realm(struct loadparm_context *lp_ctx, int unused,
-                        const char *pszParmValue, char **ptr);
-static bool handle_copy(struct loadparm_context *lp_ctx, int unused,
-                       const char *pszParmValue, char **ptr);
-static bool handle_debug_list(struct loadparm_context *lp_ctx, int unused,
-                             const char *pszParmValue, char **ptr);
-static bool handle_logfile(struct loadparm_context *lp_ctx, int unused,
-                          const char *pszParmValue, char **ptr);
-
-#include "lib/param/param_table.c"
-
-/* local variables */
-struct loadparm_context {
-       const char *szConfigFile;
-       struct loadparm_global *globals;
-       struct loadparm_service **services;
-       struct loadparm_service *sDefault;
-       struct smb_iconv_handle *iconv_handle;
-       int iNumServices;
-       struct loadparm_service *currentService;
-       bool bInGlobalSection;
-       struct file_lists {
-               struct file_lists *next;
-               char *name;
-               char *subfname;
-               time_t modtime;
-       } *file_lists;
-       unsigned int flags[NUMPARAMETERS];
-       bool loaded;
-       bool refuse_free;
-       bool global; /* Is this the global context, which may set
-                     * global variables such as debug level etc? */
-       const struct loadparm_s3_helpers *s3_fns;
-};
-
+#define NUMPARAMETERS (num_parameters())
 
 struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx)
 {
@@ -171,7 +93,7 @@ struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx)
  * callers without affecting the source string.
  */
 
-static const char *lp_string(const char *s)
+static const char *lpcfg_string(const char *s)
 {
 #if 0  /* until REWRITE done to make thread-safe */
        size_t len = s ? strlen(s) : 0;
@@ -184,7 +106,7 @@ static const char *lp_string(const char *s)
           present all the time? */
 
 #if 0
-       DEBUG(10, ("lp_string(%s)\n", s));
+       DEBUG(10, ("lpcfg_string(%s)\n", s));
 #endif
 
 #if 0  /* until REWRITE done to make thread-safe */
@@ -229,50 +151,34 @@ static struct loadparm_context *global_loadparm_context;
 #define lpcfg_global_service(i) global_loadparm_context->services[i]
 
 #define FN_GLOBAL_STRING(fn_name,var_name) \
- _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) {\
+ _PUBLIC_ char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx, TALLOC_CTX *ctx) {\
         if (lp_ctx == NULL) return NULL;                               \
         if (lp_ctx->s3_fns) {                                          \
-                smb_panic( __location__ ": " #fn_name " not implemented because it is an allocated and substiuted string"); \
+                return lp_ctx->globals->var_name ? lp_ctx->s3_fns->lp_string(ctx, lp_ctx->globals->var_name) : talloc_strdup(ctx, ""); \
         }                                                              \
-        return lp_ctx->globals->var_name ? lp_string(lp_ctx->globals->var_name) : ""; \
+        return lp_ctx->globals->var_name ? talloc_strdup(ctx, lpcfg_string(lp_ctx->globals->var_name)) : talloc_strdup(ctx, ""); \
 }
 
 #define FN_GLOBAL_CONST_STRING(fn_name,var_name)                               \
  _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
        if (lp_ctx == NULL) return NULL;                                \
-       if (lp_ctx->s3_fns) {                                           \
-               SMB_ASSERT(lp_ctx->s3_fns->fn_name);                    \
-               return lp_ctx->s3_fns->fn_name();                       \
-       }                                                               \
-       return lp_ctx->globals->var_name ? lp_string(lp_ctx->globals->var_name) : ""; \
+       return lp_ctx->globals->var_name ? lpcfg_string(lp_ctx->globals->var_name) : ""; \
 }
 
 #define FN_GLOBAL_LIST(fn_name,var_name)                               \
  _PUBLIC_ const char **lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
         if (lp_ctx == NULL) return NULL;                               \
-        if (lp_ctx->s3_fns) {                                          \
-                SMB_ASSERT(lp_ctx->s3_fns->fn_name);                   \
-                return lp_ctx->s3_fns->fn_name();                      \
-        }                                                              \
         return lp_ctx->globals->var_name;                              \
  }
 
 #define FN_GLOBAL_BOOL(fn_name,var_name) \
  _PUBLIC_ bool lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) {\
         if (lp_ctx == NULL) return false;                              \
-        if (lp_ctx->s3_fns) {                                          \
-                SMB_ASSERT(lp_ctx->s3_fns->fn_name);                   \
-                return lp_ctx->s3_fns->fn_name();                      \
-        }                                                              \
         return lp_ctx->globals->var_name;                              \
 }
 
 #define FN_GLOBAL_INTEGER(fn_name,var_name) \
  _PUBLIC_ int lpcfg_ ## fn_name(struct loadparm_context *lp_ctx) { \
-        if (lp_ctx->s3_fns) {                                          \
-                SMB_ASSERT(lp_ctx->s3_fns->fn_name);                   \
-                return lp_ctx->s3_fns->fn_name();                      \
-        }                                                              \
         return lp_ctx->globals->var_name;                              \
  }
 
@@ -280,13 +186,17 @@ static struct loadparm_context *global_loadparm_context;
  * loadparm_service is shared and lpcfg_service() checks the ->s3_fns
  * hook */
 #define FN_LOCAL_STRING(fn_name,val) \
+ _PUBLIC_ char *lpcfg_ ## fn_name(struct loadparm_service *service, \
+                                       struct loadparm_service *sDefault, TALLOC_CTX *ctx) { \
+        return(talloc_strdup(ctx, lpcfg_string((const char *)((service != NULL && service->val != NULL) ? service->val : sDefault->val)))); \
+ }
+
+#define FN_LOCAL_CONST_STRING(fn_name,val) \
  _PUBLIC_ const char *lpcfg_ ## fn_name(struct loadparm_service *service, \
                                        struct loadparm_service *sDefault) { \
-        return(lp_string((const char *)((service != NULL && service->val != NULL) ? service->val : sDefault->val))); \
+        return((const char *)((service != NULL && service->val != NULL) ? service->val : sDefault->val)); \
  }
 
-#define FN_LOCAL_CONST_STRING(fn_name,val) FN_LOCAL_STRING(fn_name, val)
-
 #define FN_LOCAL_LIST(fn_name,val) \
  _PUBLIC_ const char **lpcfg_ ## fn_name(struct loadparm_service *service, \
                                         struct loadparm_service *sDefault) {\
@@ -322,14 +232,10 @@ FN_LOCAL_BOOL(autoloaded, autoloaded)
 FN_GLOBAL_CONST_STRING(dnsdomain, dnsdomain)
 
 /* local prototypes */
-static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx,
+static struct loadparm_service *lpcfg_getservicebyname(struct loadparm_context *lp_ctx,
                                        const char *pszServiceName);
-static void copy_service(struct loadparm_service *pserviceDest,
-                        struct loadparm_service *pserviceSource,
-                        struct bitmap *pcopymapDest);
 static bool lpcfg_service_ok(struct loadparm_service *service);
 static bool do_section(const char *pszSectionName, void *);
-static void init_copymap(struct loadparm_service *pservice);
 
 /* This is a helper function for parametrical options support. */
 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
@@ -346,7 +252,7 @@ const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
                return NULL;
 
        if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->get_parametric(service, type, option);
+               return lp_ctx->s3_fns->get_parametric(service, type, option, NULL);
        }
 
        data = (service == NULL ? lp_ctx->globals->param_opt : service->param_opt);
@@ -385,10 +291,10 @@ const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
 /**
  * convenience routine to return int parameters.
  */
-static int lp_int(const char *s)
+int lp_int(const char *s)
 {
 
-       if (!s) {
+       if (!s || !*s) {
                DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
                return -1;
        }
@@ -399,10 +305,10 @@ static int lp_int(const char *s)
 /**
  * convenience routine to return unsigned long parameters.
  */
-static unsigned long lp_ulong(const char *s)
+unsigned long lp_ulong(const char *s)
 {
 
-       if (!s) {
+       if (!s || !*s) {
                DEBUG(0,("lp_ulong(%s): is called with NULL!\n",s));
                return -1;
        }
@@ -441,11 +347,11 @@ static double lp_double(const char *s)
 /**
  * convenience routine to return boolean parameters.
  */
-static bool lp_bool(const char *s)
+bool lp_bool(const char *s)
 {
        bool ret = false;
 
-       if (!s) {
+       if (!s || !*s) {
                DEBUG(0,("lp_bool(%s): is called with NULL!\n",s));
                return false;
        }
@@ -458,7 +364,6 @@ static bool lp_bool(const char *s)
        return ret;
 }
 
-
 /**
  * Return parametric option from a given service. Type is a part of option before ':'
  * Parametric option has following syntax: 'Type: option = value'
@@ -472,7 +377,7 @@ const char *lpcfg_parm_string(struct loadparm_context *lp_ctx,
        const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
 
        if (value)
-               return lp_string(value);
+               return lpcfg_string(value);
 
        return NULL;
 }
@@ -596,23 +501,11 @@ bool lpcfg_parm_bool(struct loadparm_context *lp_ctx,
 }
 
 
-/**
- * Initialise a service to the defaults.
- */
-
-static struct loadparm_service *init_service(TALLOC_CTX *mem_ctx, struct loadparm_service *sDefault)
-{
-       struct loadparm_service *pservice =
-               talloc_zero(mem_ctx, struct loadparm_service);
-       copy_service(pservice, sDefault, NULL);
-       return pservice;
-}
-
 /**
  * Set a string value, deallocating any existing space, and allocing the space
  * for the string
  */
-static bool lpcfg_string_set(TALLOC_CTX *mem_ctx, char **dest, const char *src)
+bool lpcfg_string_set(TALLOC_CTX *mem_ctx, char **dest, const char *src)
 {
        talloc_free(*dest);
 
@@ -660,7 +553,6 @@ struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
                                           const char *name)
 {
        int i;
-       struct loadparm_service tservice;
        int num_to_alloc = lp_ctx->iNumServices + 1;
        struct parmlist_entry *data, *pdata;
 
@@ -668,11 +560,9 @@ struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
                pservice = lp_ctx->sDefault;
        }
 
-       tservice = *pservice;
-
        /* it might already exist */
        if (name) {
-               struct loadparm_service *service = getservicebyname(lp_ctx,
+               struct loadparm_service *service = lpcfg_getservicebyname(lp_ctx,
                                                                    name);
                if (service != NULL) {
                        /* Clean all parametric options for service */
@@ -710,12 +600,12 @@ struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
                lp_ctx->iNumServices++;
        }
 
-       lp_ctx->services[i] = init_service(lp_ctx->services, lp_ctx->sDefault);
+       lp_ctx->services[i] = talloc_zero(lp_ctx->services, struct loadparm_service);
        if (lp_ctx->services[i] == NULL) {
                DEBUG(0,("lpcfg_add_service: out of memory!\n"));
                return NULL;
        }
-       copy_service(lp_ctx->services[i], &tservice, NULL);
+       copy_service(lp_ctx->services[i], pservice, NULL);
        if (name != NULL)
                lpcfg_string_set(lp_ctx->services[i], &lp_ctx->services[i]->szService, name);
        return lp_ctx->services[i];
@@ -742,7 +632,7 @@ bool lpcfg_add_home(struct loadparm_context *lp_ctx,
            || strequal(default_service->path, lp_ctx->sDefault->path)) {
                service->path = talloc_strdup(service, pszHomedir);
        } else {
-               service->path = string_sub_talloc(service, lpcfg_path(default_service, lp_ctx->sDefault), "%H", pszHomedir);
+               service->path = string_sub_talloc(service, lpcfg_path(default_service, lp_ctx->sDefault, service), "%H", pszHomedir);
        }
 
        if (!(*(service->comment))) {
@@ -876,7 +766,7 @@ bool lpcfg_parm_is_cmdline(struct loadparm_context *lp_ctx, const char *name)
  * Find a service by name. Otherwise works like get_service.
  */
 
-static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx,
+static struct loadparm_service *lpcfg_getservicebyname(struct loadparm_context *lp_ctx,
                                        const char *pszServiceName)
 {
        int iService;
@@ -894,59 +784,117 @@ static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx
        return NULL;
 }
 
+/**
+ * Add a parametric option to a parmlist_entry,
+ * replacing old value, if already present.
+ */
+void set_param_opt(TALLOC_CTX *mem_ctx,
+                  struct parmlist_entry **opt_list,
+                  const char *opt_name,
+                  const char *opt_value,
+                  unsigned priority)
+{
+       struct parmlist_entry *new_opt, *opt;
+       bool not_added;
+
+       opt = *opt_list;
+       not_added = true;
+
+       /* Traverse destination */
+       while (opt) {
+               /* If we already have same option, override it */
+               if (strwicmp(opt->key, opt_name) == 0) {
+                       if ((opt->priority & FLAG_CMDLINE) &&
+                           !(priority & FLAG_CMDLINE)) {
+                               /* it's been marked as not to be
+                                  overridden */
+                               return;
+                       }
+                       TALLOC_FREE(opt->value);
+                       TALLOC_FREE(opt->list);
+                       opt->value = talloc_strdup(opt, opt_value);
+                       opt->priority = priority;
+                       not_added = false;
+                       break;
+               }
+               opt = opt->next;
+       }
+       if (not_added) {
+               new_opt = talloc(mem_ctx, struct parmlist_entry);
+               if (new_opt == NULL) {
+                       smb_panic("OOM");
+               }
+
+               new_opt->key = talloc_strdup(new_opt, opt_name);
+               if (new_opt->key == NULL) {
+                       smb_panic("talloc_strdup failed");
+               }
+
+               new_opt->value = talloc_strdup(new_opt, opt_value);
+               if (new_opt->value == NULL) {
+                       smb_panic("talloc_strdup failed");
+               }
+
+               new_opt->list = NULL;
+               new_opt->priority = priority;
+               DLIST_ADD(*opt_list, new_opt);
+       }
+}
+
 /**
  * Copy a service structure to another.
  * If pcopymapDest is NULL then copy all fields
  */
 
-static void copy_service(struct loadparm_service *pserviceDest,
-                        struct loadparm_service *pserviceSource,
-                        struct bitmap *pcopymapDest)
+void copy_service(struct loadparm_service *pserviceDest,
+                 const struct loadparm_service *pserviceSource,
+                 struct bitmap *pcopymapDest)
 {
        int i;
        bool bcopyall = (pcopymapDest == NULL);
-       struct parmlist_entry *data, *pdata, *paramo;
-       bool not_added;
+       struct parmlist_entry *data;
 
        for (i = 0; parm_table[i].label; i++)
                if (parm_table[i].p_class == P_LOCAL &&
                    (bcopyall || bitmap_query(pcopymapDest, i))) {
-                       void *src_ptr =
-                               ((char *)pserviceSource) + parm_table[i].offset;
+                       const void *src_ptr =
+                               ((const char *)pserviceSource) + parm_table[i].offset;
                        void *dest_ptr =
                                ((char *)pserviceDest) + parm_table[i].offset;
 
                        switch (parm_table[i].type) {
                                case P_BOOL:
                                case P_BOOLREV:
-                                       *(bool *)dest_ptr = *(bool *)src_ptr;
+                                       *(bool *)dest_ptr = *(const bool *)src_ptr;
                                        break;
 
                                case P_INTEGER:
                                case P_BYTES:
                                case P_OCTAL:
                                case P_ENUM:
-                                       *(int *)dest_ptr = *(int *)src_ptr;
+                                       *(int *)dest_ptr = *(const int *)src_ptr;
                                        break;
 
                                case P_CHAR:
-                                       *(char *)dest_ptr = *(char *)src_ptr;
+                                       *(char *)dest_ptr = *(const char *)src_ptr;
                                        break;
 
                                case P_STRING:
                                        lpcfg_string_set(pserviceDest,
                                                   (char **)dest_ptr,
-                                                  *(char **)src_ptr);
+                                                  *(const char * const *)src_ptr);
                                        break;
 
                                case P_USTRING:
                                        lpcfg_string_set_upper(pserviceDest,
                                                         (char **)dest_ptr,
-                                                        *(char **)src_ptr);
+                                                        *(const char * const *)src_ptr);
                                        break;
+                               case P_CMDLIST:
                                case P_LIST:
-                                       *(const char ***)dest_ptr = (const char **)str_list_copy(pserviceDest, 
-                                                                                 *(const char ***)src_ptr);
+                                       TALLOC_FREE(*((char ***)dest_ptr));
+                                       *(const char * const **)dest_ptr = (const char * const *)str_list_copy(pserviceDest,
+                                                                                 *(const char * * const *)src_ptr);
                                        break;
                                default:
                                        break;
@@ -960,31 +908,9 @@ static void copy_service(struct loadparm_service *pserviceDest,
                                    pserviceSource->copymap);
        }
 
-       data = pserviceSource->param_opt;
-       while (data) {
-               not_added = true;
-               pdata = pserviceDest->param_opt;
-               /* Traverse destination */
-               while (pdata) {
-                       /* If we already have same option, override it */
-                       if (strcmp(pdata->key, data->key) == 0) {
-                               talloc_free(pdata->value);
-                               pdata->value = talloc_strdup(pdata,
-                                                            data->value);
-                               not_added = false;
-                               break;
-                       }
-                       pdata = pdata->next;
-               }
-               if (not_added) {
-                       paramo = talloc_zero(pserviceDest, struct parmlist_entry);
-                       if (paramo == NULL)
-                               smb_panic("OOM");
-                       paramo->key = talloc_strdup(paramo, data->key);
-                       paramo->value = talloc_strdup(paramo, data->value);
-                       DLIST_ADD(pserviceDest->param_opt, paramo);
-               }
-               data = data->next;
+       for (data = pserviceSource->param_opt; data != NULL; data = data->next) {
+               set_param_opt(pserviceDest, &pserviceDest->param_opt,
+                             data->key, data->value, data->priority);
        }
 }
 
@@ -1030,10 +956,10 @@ static bool lpcfg_service_ok(struct loadparm_service *service)
  it's date and needs to be reloaded.
 ********************************************************************/
 
-static void add_to_file_list(struct loadparm_context *lp_ctx,
+void add_to_file_list(TALLOC_CTX *mem_ctx, struct file_lists **list,
                             const char *fname, const char *subfname)
 {
-       struct file_lists *f = lp_ctx->file_lists;
+       struct file_lists *f = *list;
 
        while (f) {
                if (f->name && !strcmp(f->name, fname))
@@ -1042,27 +968,32 @@ static void add_to_file_list(struct loadparm_context *lp_ctx,
        }
 
        if (!f) {
-               f = talloc(lp_ctx, struct file_lists);
+               f = talloc(mem_ctx, struct file_lists);
                if (!f)
-                       return;
-               f->next = lp_ctx->file_lists;
+                       goto fail;
+               f->next = *list;
                f->name = talloc_strdup(f, fname);
                if (!f->name) {
-                       talloc_free(f);
-                       return;
+                       TALLOC_FREE(f);
+                       goto fail;
                }
                f->subfname = talloc_strdup(f, subfname);
                if (!f->subfname) {
-                       talloc_free(f);
-                       return;
+                       TALLOC_FREE(f);
+                       goto fail;
                }
-               lp_ctx->file_lists = f;
+               *list = f;
                f->modtime = file_modtime(subfname);
        } else {
                time_t t = file_modtime(subfname);
                if (t)
                        f->modtime = t;
        }
+       return;
+
+fail:
+       DEBUG(0, ("Unable to add file to file list: %s\n", fname));
+
 }
 
 /*******************************************************************
@@ -1096,20 +1027,56 @@ bool lpcfg_file_list_changed(struct loadparm_context *lp_ctx)
        return false;
 }
 
+/*
+ * set the value for a P_ENUM
+ */
+bool lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue,
+                              int *ptr )
+{
+       int i;
+
+       for (i = 0; parm->enum_list[i].name; i++) {
+               if ( strequal(pszParmValue, parm->enum_list[i].name)) {
+                       *ptr = parm->enum_list[i].value;
+                       return true;
+               }
+       }
+       DEBUG(0, ("WARNING: Ignoring invalid value '%s' for parameter '%s'\n",
+                 pszParmValue, parm->label));
+       return false;
+}
+
+
 /***************************************************************************
  Handle the "realm" parameter
 ***************************************************************************/
 
-static bool handle_realm(struct loadparm_context *lp_ctx, int unused,
-                        const char *pszParmValue, char **ptr)
+bool handle_realm(struct loadparm_context *lp_ctx, int unused,
+                 const char *pszParmValue, char **ptr)
 {
-       lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       char *upper;
+       char *lower;
 
-       talloc_free(lp_ctx->globals->realm);
-       talloc_free(lp_ctx->globals->dnsdomain);
+       upper = strupper_talloc(lp_ctx, pszParmValue);
+       if (upper == NULL) {
+               return false;
+       }
 
-       lp_ctx->globals->realm = strupper_talloc(lp_ctx, pszParmValue);
-       lp_ctx->globals->dnsdomain = strlower_talloc(lp_ctx, pszParmValue);
+       lower = strlower_talloc(lp_ctx, pszParmValue);
+       if (lower == NULL) {
+               TALLOC_FREE(upper);
+               return false;
+       }
+
+       if (lp_ctx->s3_fns != NULL) {
+               lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
+               lp_ctx->s3_fns->lp_string_set(&lp_ctx->globals->realm, upper);
+               lp_ctx->s3_fns->lp_string_set(&lp_ctx->globals->dnsdomain, lower);
+       } else {
+               lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+               lpcfg_string_set(lp_ctx, &lp_ctx->globals->realm, upper);
+               lpcfg_string_set(lp_ctx, &lp_ctx->globals->dnsdomain, lower);
+       }
 
        return true;
 }
@@ -1118,12 +1085,18 @@ static bool handle_realm(struct loadparm_context *lp_ctx, int unused,
  Handle the include operation.
 ***************************************************************************/
 
-static bool handle_include(struct loadparm_context *lp_ctx, int unused,
+bool handle_include(struct loadparm_context *lp_ctx, int unused,
                           const char *pszParmValue, char **ptr)
 {
-       char *fname = standard_sub_basic(lp_ctx, pszParmValue);
+       char *fname;
 
-       add_to_file_list(lp_ctx, pszParmValue, fname);
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_include(lp_ctx, unused, pszParmValue, ptr);
+       }
+
+       fname = standard_sub_basic(lp_ctx, pszParmValue);
+
+       add_to_file_list(lp_ctx, &lp_ctx->file_lists, pszParmValue, fname);
 
        lpcfg_string_set(lp_ctx, ptr, fname);
 
@@ -1139,25 +1112,38 @@ static bool handle_include(struct loadparm_context *lp_ctx, int unused,
  Handle the interpretation of the copy parameter.
 ***************************************************************************/
 
-static bool handle_copy(struct loadparm_context *lp_ctx, int unused,
+bool handle_copy(struct loadparm_context *lp_ctx, int snum,
                        const char *pszParmValue, char **ptr)
 {
        bool bRetval;
-       struct loadparm_service *serviceTemp;
-
-       lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       struct loadparm_service *serviceTemp = NULL;
+       struct loadparm_service *current = NULL;
 
        bRetval = false;
 
        DEBUG(3, ("Copying service from service %s\n", pszParmValue));
 
-       if ((serviceTemp = getservicebyname(lp_ctx, pszParmValue)) != NULL) {
-               if (serviceTemp == lp_ctx->currentService) {
+       serviceTemp = lpcfg_getservicebyname(lp_ctx, pszParmValue);
+       if (lp_ctx->s3_fns != NULL) {
+               current = lp_ctx->s3_fns->get_servicebynum(snum);
+       } else {
+               current = lp_ctx->currentService;
+       }
+
+       if (current == NULL) {
+               DEBUG(0, ("Unable to copy service - invalid service destination"));
+               return false;
+       }
+
+       if (serviceTemp != NULL) {
+               if (serviceTemp == current) {
                        DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
                } else {
-                       copy_service(lp_ctx->currentService,
+                       copy_service(current,
                                     serviceTemp,
-                                    lp_ctx->currentService->copymap);
+                                    current->copymap);
+                       lpcfg_string_set(current, ptr, pszParmValue);
+
                        bRetval = true;
                }
        } else {
@@ -1169,32 +1155,183 @@ static bool handle_copy(struct loadparm_context *lp_ctx, int unused,
        return bRetval;
 }
 
-static bool handle_debug_list(struct loadparm_context *lp_ctx, int unused,
+bool handle_debug_list(struct loadparm_context *lp_ctx, int unused,
                        const char *pszParmValue, char **ptr)
 {
+       if (lp_ctx->s3_fns != NULL) {
+               lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
+       } else {
+               lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       }
+
+       return debug_parse_levels(pszParmValue);
+}
 
-       lpcfg_string_set(lp_ctx, ptr, pszParmValue);
-       if (lp_ctx->global) {
-               return debug_parse_levels(pszParmValue);
+bool handle_logfile(struct loadparm_context *lp_ctx, int unused,
+                   const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns != NULL) {
+               lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
+       } else {
+               debug_set_logfile(pszParmValue);
+               lpcfg_string_set(lp_ctx, ptr, pszParmValue);
        }
+
        return true;
 }
 
-static bool handle_logfile(struct loadparm_context *lp_ctx, int unused,
+/*
+ * These special charset handling methods only run in the source3 code.
+ */
+
+bool handle_charset(struct loadparm_context *lp_ctx, int snum,
                        const char *pszParmValue, char **ptr)
 {
-       debug_set_logfile(pszParmValue);
-       if (lp_ctx->global) {
-               lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       if (lp_ctx->s3_fns) {
+               if (*ptr == NULL || strcmp(*ptr, pszParmValue) != 0) {
+                       lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
+                       global_iconv_handle = smb_iconv_handle_reinit(NULL,
+                                                       lpcfg_dos_charset(lp_ctx),
+                                                       lpcfg_unix_charset(lp_ctx),
+                                                       true, global_iconv_handle);
+               }
+
+               return true;
+       }
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+
+}
+
+bool handle_dos_charset(struct loadparm_context *lp_ctx, int snum,
+                       const char *pszParmValue, char **ptr)
+{
+       bool is_utf8 = false;
+       size_t len = strlen(pszParmValue);
+
+       if (lp_ctx->s3_fns) {
+               if (len == 4 || len == 5) {
+                       /* Don't use StrCaseCmp here as we don't want to
+                          initialize iconv. */
+                       if ((toupper_m(pszParmValue[0]) == 'U') &&
+                           (toupper_m(pszParmValue[1]) == 'T') &&
+                           (toupper_m(pszParmValue[2]) == 'F')) {
+                               if (len == 4) {
+                                       if (pszParmValue[3] == '8') {
+                                               is_utf8 = true;
+                                       }
+                               } else {
+                                       if (pszParmValue[3] == '-' &&
+                                           pszParmValue[4] == '8') {
+                                               is_utf8 = true;
+                                       }
+                               }
+                       }
+               }
+
+               if (*ptr == NULL || strcmp(*ptr, pszParmValue) != 0) {
+                       if (is_utf8) {
+                               DEBUG(0,("ERROR: invalid DOS charset: 'dos charset' must not "
+                                       "be UTF8, using (default value) %s instead.\n",
+                                       DEFAULT_DOS_CHARSET));
+                               pszParmValue = DEFAULT_DOS_CHARSET;
+                       }
+                       lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
+                       global_iconv_handle = smb_iconv_handle_reinit(NULL,
+                                                       lpcfg_dos_charset(lp_ctx),
+                                                       lpcfg_unix_charset(lp_ctx),
+                                                       true, global_iconv_handle);
+               }
+               return true;
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
+bool handle_printing(struct loadparm_context *lp_ctx, int snum,
+                           const char *pszParmValue, char **ptr)
+{
+       static int parm_num = -1;
+       struct loadparm_service *s;
+
+       if (parm_num == -1) {
+               parm_num = lpcfg_map_parameter("printing");
+       }
+
+       if (!lp_set_enum_parm(&parm_table[parm_num], pszParmValue, (int*)ptr)) {
+               return false;
+       }
+
+       if (lp_ctx->s3_fns) {
+               if ( snum < 0 ) {
+                       s = lp_ctx->sDefault;
+                       lp_ctx->s3_fns->init_printer_values(lp_ctx->globals->ctx, s);
+               } else {
+                       s = lp_ctx->services[snum];
+                       lp_ctx->s3_fns->init_printer_values(s, s);
+               }
+       }
+
+       return true;
+}
+
+bool handle_ldap_debug_level(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       lp_ctx->globals->ldap_debug_level = lp_int(pszParmValue);
+
+       if (lp_ctx->s3_fns) {
+               lp_ctx->s3_fns->init_ldap_debugging();
        }
        return true;
 }
 
+bool handle_netbios_aliases(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       TALLOC_FREE(lp_ctx->globals->netbios_aliases);
+       lp_ctx->globals->netbios_aliases = (const char **)str_list_make_v3(lp_ctx->globals->ctx,
+                                                                          pszParmValue, NULL);
+
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->set_netbios_aliases(lp_ctx->globals->netbios_aliases);
+       }
+       return true;
+}
+
+/*
+ * idmap related parameters
+ */
+
+bool handle_idmap_backend(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : backend", pszParmValue);
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
+bool handle_idmap_uid(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : range", pszParmValue);
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
+bool handle_idmap_gid(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : range", pszParmValue);
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
 /***************************************************************************
  Initialise a copymap.
 ***************************************************************************/
 
-static void init_copymap(struct loadparm_service *pservice)
+void init_copymap(struct loadparm_service *pservice)
 {
        int i;
 
@@ -1218,7 +1355,7 @@ static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
                                       const char *pszParmName,
                                       const char *pszParmValue, int flags)
 {
-       struct parmlist_entry *paramo, *data;
+       struct parmlist_entry **data;
        char *name;
        TALLOC_CTX *mem_ctx;
 
@@ -1230,43 +1367,14 @@ static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
        if (!name) return false;
 
        if (service == NULL) {
-               data = lp_ctx->globals->param_opt;
+               data = &lp_ctx->globals->param_opt;
                mem_ctx = lp_ctx->globals;
        } else {
-               data = service->param_opt;
+               data = &service->param_opt;
                mem_ctx = service;
        }
 
-       /* Traverse destination */
-       for (paramo=data; paramo; paramo=paramo->next) {
-               /* If we already have the option set, override it unless
-                  it was a command line option and the new one isn't */
-               if (strcmp(paramo->key, name) == 0) {
-                       if ((paramo->priority & FLAG_CMDLINE) &&
-                           !(flags & FLAG_CMDLINE)) {
-                               talloc_free(name);
-                               return true;
-                       }
-
-                       talloc_free(paramo->value);
-                       paramo->value = talloc_strdup(paramo, pszParmValue);
-                       paramo->priority = flags;
-                       talloc_free(name);
-                       return true;
-               }
-       }
-
-       paramo = talloc_zero(mem_ctx, struct parmlist_entry);
-       if (!paramo)
-               smb_panic("OOM");
-       paramo->key = talloc_strdup(paramo, name);
-       paramo->value = talloc_strdup(paramo, pszParmValue);
-       paramo->priority = flags;
-       if (service == NULL) {
-               DLIST_ADD(lp_ctx->globals->param_opt, paramo);
-       } else {
-               DLIST_ADD(service->param_opt, paramo);
-       }
+       set_param_opt(mem_ctx, data, name, pszParmValue, flags);
 
        talloc_free(name);
 
@@ -1342,8 +1450,9 @@ static bool set_variable(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
                }
 
                case P_CMDLIST:
-                       *(const char ***)parm_ptr = (const char **)str_list_make(mem_ctx,
-                                                                 pszParmValue, NULL);
+                       *(const char * const **)parm_ptr
+                               = (const char * const *)str_list_make(mem_ctx,
+                                                                     pszParmValue, NULL);
                        break;
                case P_LIST:
                {
@@ -1371,7 +1480,7 @@ static bool set_variable(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
                                                          pszParmName, pszParmValue));
                                                return false;
                                        }
-                                       *(const char ***)parm_ptr = (const char **) new_list;
+                                       *(const char * const **)parm_ptr = (const char * const *) new_list;
                                        break;
                                }
                        }
@@ -1386,19 +1495,7 @@ static bool set_variable(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
                        break;
 
                case P_ENUM:
-                       for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
-                               if (strequal
-                                   (pszParmValue,
-                                    parm_table[parmnum].enum_list[i].name)) {
-                                       *(int *)parm_ptr =
-                                               parm_table[parmnum].
-                                               enum_list[i].value;
-                                       break;
-                               }
-                       }
-                       if (!parm_table[parmnum].enum_list[i].name) {
-                               DEBUG(0,("Unknown enumerated value '%s' for '%s'\n", 
-                                        pszParmValue, pszParmName));
+                       if (!lp_set_enum_parm(&parm_table[parmnum], pszParmValue, (int*)parm_ptr)) {
                                return false;
                        }
                        break;
@@ -1540,15 +1637,14 @@ bool lpcfg_set_cmdline(struct loadparm_context *lp_ctx, const char *pszParmName,
        int parmnum;
        int i;
 
+       while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
+
        if (lp_ctx->s3_fns) {
                return lp_ctx->s3_fns->set_cmdline(pszParmName, pszParmValue);
        }
 
        parmnum = lpcfg_map_parameter(pszParmName);
 
-       while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
-
-
        if (parmnum < 0 && strchr(pszParmName, ':')) {
                /* set a parametric option */
                return lp_do_parameter_parametric(lp_ctx, NULL, pszParmName,
@@ -1795,7 +1891,7 @@ static bool is_default(struct loadparm_service *sDefault, int i)
        switch (parm_table[i].type) {
                case P_CMDLIST:
                case P_LIST:
-                       return str_list_equal((const char **)parm_table[i].def.lvalue, 
+                       return str_list_equal((const char * const *)parm_table[i].def.lvalue,
                                              (const char **)def_ptr);
                case P_STRING:
                case P_USTRING:
@@ -1998,7 +2094,10 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        talloc_set_destructor(lp_ctx, lpcfg_destructor);
        lp_ctx->bInGlobalSection = true;
        lp_ctx->globals = talloc_zero(lp_ctx, struct loadparm_global);
+       /* This appears odd, but globals in s3 isn't a pointer */
+       lp_ctx->globals->ctx = lp_ctx->globals;
        lp_ctx->sDefault = talloc_zero(lp_ctx, struct loadparm_service);
+       lp_ctx->flags = talloc_zero_array(lp_ctx, unsigned int, NUMPARAMETERS);
 
        lp_ctx->sDefault->iMaxPrintJobs = 1000;
        lp_ctx->sDefault->bAvailable = true;
@@ -2115,6 +2214,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "ReadRaw", "True");
        lpcfg_do_global_parameter(lp_ctx, "WriteRaw", "True");
        lpcfg_do_global_parameter(lp_ctx, "NullPasswords", "False");
+       lpcfg_do_global_parameter(lp_ctx, "old password allowed period", "60");
        lpcfg_do_global_parameter(lp_ctx, "ObeyPamRestrictions", "False");
 
        lpcfg_do_global_parameter(lp_ctx, "TimeServer", "False");
@@ -2211,7 +2311,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        lpcfg_do_global_parameter(lp_ctx, "enable privileges", "True");
 
-       lpcfg_do_global_parameter(lp_ctx, "smb2 max write", "1048576");
+       lpcfg_do_global_parameter_var(lp_ctx, "smb2 max write", "%u", DEFAULT_SMB2_MAX_WRITE);
 
        lpcfg_do_global_parameter(lp_ctx, "passdb backend", "tdbsam");
 
@@ -2221,7 +2321,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        lpcfg_do_global_parameter(lp_ctx, "mangled names", "True");
 
-       lpcfg_do_global_parameter(lp_ctx, "smb2 max credits", "8192");
+       lpcfg_do_global_parameter_var(lp_ctx, "smb2 max credits", "%u", DEFAULT_SMB2_MAX_CREDITS);
 
        lpcfg_do_global_parameter(lp_ctx, "ldap ssl", "start tls");
 
@@ -2309,9 +2409,9 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        lpcfg_do_global_parameter(lp_ctx, "lpq cache time", "30");
 
-       lpcfg_do_global_parameter(lp_ctx, "smb2 max trans", "1048576");
+       lpcfg_do_global_parameter_var(lp_ctx, "smb2 max trans", "%u", DEFAULT_SMB2_MAX_TRANSACT);
 
-       lpcfg_do_global_parameter(lp_ctx, "smb2 max read", "1048576");
+       lpcfg_do_global_parameter_var(lp_ctx, "smb2 max read", "%u", DEFAULT_SMB2_MAX_READ);
 
        lpcfg_do_global_parameter(lp_ctx, "durable handles", "yes");
 
@@ -2420,6 +2520,7 @@ struct loadparm_context *loadparm_init_s3(TALLOC_CTX *mem_ctx,
                return NULL;
        }
        loadparm_context->s3_fns = s3_fns;
+       loadparm_context->globals = s3_fns->globals;
        return loadparm_context;
 }
 
@@ -2443,13 +2544,21 @@ const char *lp_default_path(void)
 static bool lpcfg_update(struct loadparm_context *lp_ctx)
 {
        struct debug_settings settings;
-       lpcfg_add_auto_services(lp_ctx, lpcfg_auto_services(lp_ctx));
+       TALLOC_CTX *tmp_ctx;
+
+       tmp_ctx = talloc_new(lp_ctx);
+       if (tmp_ctx == NULL) {
+               return false;
+       }
+
+       lpcfg_add_auto_services(lp_ctx, lpcfg_auto_services(lp_ctx, tmp_ctx));
 
        if (!lp_ctx->globals->wins_server_list && lp_ctx->globals->we_are_a_wins_server) {
                lpcfg_do_global_parameter(lp_ctx, "wins server", "127.0.0.1");
        }
 
        if (!lp_ctx->global) {
+               TALLOC_FREE(tmp_ctx);
                return true;
        }
 
@@ -2478,6 +2587,7 @@ static bool lpcfg_update(struct loadparm_context *lp_ctx)
                unsetenv("SOCKET_TESTNONBLOCK");
        }
 
+       TALLOC_FREE(tmp_ctx);
        return true;
 }
 
@@ -2518,7 +2628,7 @@ bool lpcfg_load(struct loadparm_context *lp_ctx, const char *filename)
        n2 = standard_sub_basic(lp_ctx, lp_ctx->szConfigFile);
        DEBUG(2, ("lpcfg_load: refreshing parameters from %s\n", n2));
 
-       add_to_file_list(lp_ctx, lp_ctx->szConfigFile, n2);
+       add_to_file_list(lp_ctx, &lp_ctx->file_lists, lp_ctx->szConfigFile, n2);
 
        /* We get sections first, so have to start 'behind' to make up */
        lp_ctx->currentService = NULL;
@@ -2643,7 +2753,7 @@ struct loadparm_service *lpcfg_service(struct loadparm_context *lp_ctx,
 
 const char *lpcfg_servicename(const struct loadparm_service *service)
 {
-       return lp_string((const char *)service->szService);
+       return lpcfg_string((const char *)service->szService);
 }
 
 /**
@@ -2652,7 +2762,7 @@ const char *lpcfg_servicename(const struct loadparm_service *service)
 const char *lpcfg_volume_label(struct loadparm_service *service, struct loadparm_service *sDefault)
 {
        const char *ret;
-       ret = lp_string((const char *)((service != NULL && service->volume != NULL) ?
+       ret = lpcfg_string((const char *)((service != NULL && service->volume != NULL) ?
                                       service->volume : sDefault->volume));
        if (!*ret)
                return lpcfg_servicename(service);
@@ -2665,7 +2775,7 @@ const char *lpcfg_volume_label(struct loadparm_service *service, struct loadparm
 const char *lpcfg_printername(struct loadparm_service *service, struct loadparm_service *sDefault)
 {
        const char *ret;
-       ret = lp_string((const char *)((service != NULL && service->_printername != NULL) ?
+       ret = lpcfg_string((const char *)((service != NULL && service->_printername != NULL) ?
                                       service->_printername : sDefault->_printername));
        if (ret == NULL || (ret != NULL && *ret == '\0'))
                ret = lpcfg_servicename(service);
@@ -2710,27 +2820,27 @@ _PUBLIC_ void reload_charcnv(struct loadparm_context *lp_ctx)
 
 _PUBLIC_ char *lpcfg_tls_keyfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
 {
-       return lpcfg_private_path(mem_ctx, lp_ctx, lp_ctx->globals->tls_keyfile);
+       return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_keyfile(lp_ctx));
 }
 
 _PUBLIC_ char *lpcfg_tls_certfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
 {
-       return lpcfg_private_path(mem_ctx, lp_ctx, lp_ctx->globals->tls_certfile);
+       return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_certfile(lp_ctx));
 }
 
 _PUBLIC_ char *lpcfg_tls_cafile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
 {
-       return lpcfg_private_path(mem_ctx, lp_ctx, lp_ctx->globals->tls_cafile);
+       return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_cafile(lp_ctx));
 }
 
 _PUBLIC_ char *lpcfg_tls_crlfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
 {
-       return lpcfg_private_path(mem_ctx, lp_ctx, lp_ctx->globals->tls_crlfile);
+       return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_crlfile(lp_ctx));
 }
 
 _PUBLIC_ char *lpcfg_tls_dhpfile(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
 {
-       return lpcfg_private_path(mem_ctx, lp_ctx, lp_ctx->globals->tls_dhpfile);
+       return lpcfg_private_path(mem_ctx, lp_ctx, lpcfg__tls_dhpfile(lp_ctx));
 }
 
 struct gensec_settings *lpcfg_gensec_settings(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx)
@@ -2802,3 +2912,29 @@ bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandato
 
        return allowed;
 }
+
+int lpcfg_tdb_hash_size(struct loadparm_context *lp_ctx, const char *name)
+{
+       const char *base;
+
+       if (name == NULL) {
+               return 0;
+       }
+
+       base = strrchr_m(name, '/');
+       if (base != NULL) {
+               base += 1;
+       } else {
+               base = name;
+       }
+       return lpcfg_parm_int(lp_ctx, NULL, "tdb_hashsize", base, 0);
+
+}
+
+int lpcfg_tdb_flags(struct loadparm_context *lp_ctx, int tdb_flags)
+{
+       if (!lpcfg_use_mmap(lp_ctx)) {
+               tdb_flags |= TDB_NOMMAP;
+       }
+       return tdb_flags;
+}