param: setup more variables in for the temporary loadparm context for the special...
[kai/samba-autobuild/.git] / lib / param / loadparm.c
index a95c3f6126946e026129c4f0afae51e827830051..2b8ea237a0624f094ce18b69e1a3ea24ad47bc69 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;                                           \
-       char *szConfigFile;                                             \
-       int iminreceivefile;                                            \
-       char *szPrintcapname;                                           \
-       int CupsEncrypt;                                                \
-       int  iPreferredMaster;                                          \
-       char *szLdapMachineSuffix;                                      \
-       char *szLdapUserSuffix;                                         \
-       char *szLdapIdmapSuffix;                                        \
-       char *szLdapGroupSuffix;                                        \
-       char *szUsershareTemplateShare;                                 \
-       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;                                              \
-       char *loglevel;
-
 #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
  */
@@ -119,45 +91,8 @@ static bool defaults_saved = false;
 #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;
-};
-
-
 struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx)
 {
        if (lp_ctx->s3_fns) {
@@ -174,7 +109,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;
@@ -187,7 +122,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 */
@@ -232,50 +167,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;                              \
  }
 
@@ -283,13 +202,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) {\
@@ -320,22 +243,15 @@ static struct loadparm_context *global_loadparm_context;
 
 #include "lib/param/param_functions.c"
 
-/* These functions remain only in lib/param for now */
-FN_GLOBAL_BOOL(readraw, bReadRaw)
-FN_GLOBAL_BOOL(writeraw, bWriteRaw)
-FN_GLOBAL_CONST_STRING(cachedir, szCacheDir)
-FN_GLOBAL_CONST_STRING(statedir, szStateDir)
+/* These functions cannot be auto-generated */
+FN_LOCAL_BOOL(autoloaded, autoloaded)
+FN_GLOBAL_CONST_STRING(dnsdomain, dnsdomain)
 
 /* local prototypes */
-static int map_parameter(const char *pszParmName);
-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 */
@@ -352,7 +268,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);
@@ -391,10 +307,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;
        }
@@ -405,10 +321,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;
        }
@@ -447,11 +363,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;
        }
@@ -464,7 +380,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'
@@ -478,7 +393,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;
 }
@@ -602,23 +517,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);
 
@@ -666,7 +569,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;
 
@@ -674,11 +576,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 */
@@ -716,12 +616,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];
@@ -744,11 +644,11 @@ bool lpcfg_add_home(struct loadparm_context *lp_ctx,
        if (service == NULL)
                return false;
 
-       if (!(*(default_service->pathname))
-           || strequal(default_service->pathname, lp_ctx->sDefault->pathname)) {
-               service->pathname = talloc_strdup(service, pszHomedir);
+       if (!(*(default_service->path))
+           || strequal(default_service->path, lp_ctx->sDefault->path)) {
+               service->path = talloc_strdup(service, pszHomedir);
        } else {
-               service->pathname = string_sub_talloc(service, lpcfg_pathname(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))) {
@@ -758,7 +658,7 @@ bool lpcfg_add_home(struct loadparm_context *lp_ctx,
        service->browseable = default_service->browseable;
 
        DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n",
-                 pszHomename, user, service->pathname));
+                 pszHomename, user, service->path));
 
        return true;
 }
@@ -784,13 +684,13 @@ bool lpcfg_add_printer(struct loadparm_context *lp_ctx,
        /* entry (if/when the 'available' keyword is implemented!).    */
 
        /* the printer name is set to the service name. */
-       lpcfg_string_set(service, &service->szPrintername, pszPrintername);
+       lpcfg_string_set(service, &service->_printername, pszPrintername);
        lpcfg_string_set(service, &service->comment, comment);
        service->browseable = default_service->browseable;
        /* Printers cannot be read_only. */
-       service->readonly = false;
+       service->read_only = false;
        /* Printer services must be printable. */
-       service->print_ok = true;
+       service->printable = true;
 
        DEBUG(3, ("adding printer service %s\n", pszPrintername));
 
@@ -802,13 +702,10 @@ bool lpcfg_add_printer(struct loadparm_context *lp_ctx,
  * Returns False if the parameter string is not recognised, else TRUE.
  */
 
-static int map_parameter(const char *pszParmName)
+int lpcfg_map_parameter(const char *pszParmName)
 {
        int iIndex;
 
-       if (*pszParmName == '-')
-               return -1;
-
        for (iIndex = 0; parm_table[iIndex].label; iIndex++)
                if (strwicmp(parm_table[iIndex].label, pszParmName) == 0)
                        return iIndex;
@@ -834,7 +731,7 @@ struct parm_struct *lpcfg_parm_struct(struct loadparm_context *lp_ctx, const cha
                return lp_ctx->s3_fns->get_parm_struct(name);
        }
 
-       parmnum = map_parameter(name);
+       parmnum = lpcfg_map_parameter(name);
        if (parmnum == -1) return NULL;
        return &parm_table[parmnum];
 }
@@ -875,7 +772,7 @@ bool lpcfg_parm_is_cmdline(struct loadparm_context *lp_ctx, const char *name)
                return false;
        }
 
-       parmnum = map_parameter(name);
+       parmnum = lpcfg_map_parameter(name);
        if (parmnum == -1) return false;
 
        return lp_ctx->flags[parmnum] & FLAG_CMDLINE;
@@ -885,7 +782,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;
@@ -903,54 +800,116 @@ 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:
-                                       *(bool *)dest_ptr = *(bool *)src_ptr;
+                               case P_BOOLREV:
+                                       *(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 = *(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_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;
@@ -964,31 +923,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);
        }
 }
 
@@ -1010,10 +947,10 @@ static bool lpcfg_service_ok(struct loadparm_service *service)
        /* The [printers] entry MUST be printable. I'm all for flexibility, but */
        /* I can't see why you'd want a non-printable printer service...        */
        if (strwicmp(service->szService, PRINTERS_NAME) == 0) {
-               if (!service->print_ok) {
+               if (!service->printable) {
                        DEBUG(0, ("WARNING: [%s] service MUST be printable!\n",
                               service->szService));
-                       service->print_ok = true;
+                       service->printable = true;
                }
                /* [printers] service must also be non-browsable. */
                if (service->browseable)
@@ -1034,10 +971,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))
@@ -1046,27 +983,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));
+
 }
 
 /*******************************************************************
@@ -1100,20 +1042,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;
 }
@@ -1122,12 +1100,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;
+
+       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, pszParmValue, fname);
+       add_to_file_list(lp_ctx, &lp_ctx->file_lists, pszParmValue, fname);
 
        lpcfg_string_set(lp_ctx, ptr, fname);
 
@@ -1143,25 +1127,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 {
@@ -1173,32 +1170,103 @@ 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);
+       }
 
-       lpcfg_string_set(lp_ctx, ptr, pszParmValue);
-       if (lp_ctx->global) {
-               return debug_parse_levels(pszParmValue);
+       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 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);
 }
 
 /***************************************************************************
  Initialise a copymap.
 ***************************************************************************/
 
-static void init_copymap(struct loadparm_service *pservice)
+void init_copymap(struct loadparm_service *pservice)
 {
        int i;
 
@@ -1346,8 +1414,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:
                {
@@ -1375,7 +1444,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;
                                }
                        }
@@ -1390,19 +1459,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;
@@ -1429,7 +1486,7 @@ mark_non_default:
 bool lpcfg_do_global_parameter(struct loadparm_context *lp_ctx,
                               const char *pszParmName, const char *pszParmValue)
 {
-       int parmnum = map_parameter(pszParmName);
+       int parmnum = lpcfg_map_parameter(pszParmName);
        void *parm_ptr;
 
        if (parmnum < 0) {
@@ -1458,7 +1515,7 @@ bool lpcfg_do_service_parameter(struct loadparm_context *lp_ctx,
 {
        void *parm_ptr;
        int i;
-       int parmnum = map_parameter(pszParmName);
+       int parmnum = lpcfg_map_parameter(pszParmName);
 
        if (parmnum < 0) {
                if (strchr(pszParmName, ':')) {
@@ -1544,14 +1601,13 @@ 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 = map_parameter(pszParmName);
-
-       while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
-
+       parmnum = lpcfg_map_parameter(pszParmName);
 
        if (parmnum < 0 && strchr(pszParmName, ':')) {
                /* set a parametric option */
@@ -1574,10 +1630,17 @@ bool lpcfg_set_cmdline(struct loadparm_context *lp_ctx, const char *pszParmName,
        lp_ctx->flags[parmnum] |= FLAG_CMDLINE;
 
        /* we have to also set FLAG_CMDLINE on aliases */
-       for (i=parmnum-1;i>=0 && parm_table[i].offset == parm_table[parmnum].offset;i--) {
+       for (i=parmnum-1;
+            i>=0 && parm_table[i].p_class == parm_table[parmnum].p_class &&
+            parm_table[i].offset == parm_table[parmnum].offset;
+            i--) {
                lp_ctx->flags[i] |= FLAG_CMDLINE;
        }
-       for (i=parmnum+1;i<NUMPARAMETERS && parm_table[i].offset == parm_table[parmnum].offset;i++) {
+       for (i=parmnum+1;
+            i<NUMPARAMETERS &&
+            parm_table[i].p_class == parm_table[parmnum].p_class &&
+            parm_table[i].offset == parm_table[parmnum].offset;
+            i++) {
                lp_ctx->flags[i] |= FLAG_CMDLINE;
        }
 
@@ -1617,7 +1680,7 @@ bool lpcfg_set_option(struct loadparm_context *lp_ctx, const char *option)
  * Print a parameter of the specified type.
  */
 
-static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
+void lpcfg_print_parameter(struct parm_struct *p, void *ptr, FILE * f)
 {
        /* For the seperation of lists values that we print below */
        const char *list_sep = ", ";
@@ -1656,7 +1719,7 @@ static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
                        if (val == -1) {
                                fprintf(f, "-1");
                        } else {
-                               fprintf(f, "0%o", val);
+                               fprintf(f, "0%03o", val);
                        }
                        break;
                }
@@ -1697,7 +1760,7 @@ static void print_parameter(struct parm_struct *p, void *ptr, FILE * f)
  * Check if two parameters are equal.
  */
 
-static bool equal_parameter(parm_type type, void *ptr1, void *ptr2)
+ bool lpcfg_equal_parameter(parm_type type, void *ptr1, void *ptr2)
 {
        switch (type) {
                case P_BOOL:
@@ -1789,12 +1852,10 @@ static bool do_section(const char *pszSectionName, void *userdata)
 static bool is_default(struct loadparm_service *sDefault, int i)
 {
        void *def_ptr = ((char *)sDefault) + parm_table[i].offset;
-       if (!defaults_saved)
-               return false;
        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:
@@ -1835,7 +1896,7 @@ static void dump_globals(struct loadparm_context *lp_ctx, FILE *f,
                        if (!show_defaults && (lp_ctx->flags[i] & FLAG_DEFAULT))
                                continue;
                        fprintf(f, "\t%s = ", parm_table[i].label);
-                       print_parameter(&parm_table[i], lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[i]), f);
+                       lpcfg_print_parameter(&parm_table[i], lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[i]), f);
                        fprintf(f, "\n");
        }
        if (lp_ctx->globals->param_opt != NULL) {
@@ -1878,16 +1939,16 @@ static void dump_a_service(struct loadparm_service * pService, struct loadparm_s
                                        }
                                }
                        } else {
-                               if (equal_parameter(parm_table[i].type,
-                                                   ((char *)pService) +
-                                                   parm_table[i].offset,
-                                                   ((char *)sDefault) +
-                                                   parm_table[i].offset))
+                               if (lpcfg_equal_parameter(parm_table[i].type,
+                                                         ((char *)pService) +
+                                                         parm_table[i].offset,
+                                                         ((char *)sDefault) +
+                                                         parm_table[i].offset))
                                        continue;
                        }
 
                        fprintf(f, "\t%s = ", parm_table[i].label);
-                       print_parameter(&parm_table[i],
+                       lpcfg_print_parameter(&parm_table[i],
                                        ((char *)pService) + parm_table[i].offset, f);
                        fprintf(f, "\n");
                }
@@ -1917,63 +1978,11 @@ bool lpcfg_dump_a_parameter(struct loadparm_context *lp_ctx,
 
        ptr = lpcfg_parm_ptr(lp_ctx, service,parm);
 
-       print_parameter(parm, ptr, f);
+       lpcfg_print_parameter(parm, ptr, f);
        fprintf(f, "\n");
        return true;
 }
 
-/**
- * Return info about the next parameter in a service.
- * snum==-1 gives the globals.
- * Return NULL when out of parameters.
- */
-
-
-struct parm_struct *lpcfg_next_parameter(struct loadparm_context *lp_ctx, int snum, int *i,
-                                        int allparameters)
-{
-       if (snum == -1) {
-               /* do the globals */
-               for (; parm_table[*i].label; (*i)++) {
-                       if ((*parm_table[*i].label == '-'))
-                               continue;
-
-                       if ((*i) > 0
-                           && (parm_table[*i].offset ==
-                               parm_table[(*i) - 1].offset)
-                           && (parm_table[*i].p_class ==
-                               parm_table[(*i) - 1].p_class))
-                               continue;
-
-                       return &parm_table[(*i)++];
-               }
-       } else {
-               struct loadparm_service *pService = lp_ctx->services[snum];
-
-               for (; parm_table[*i].label; (*i)++) {
-                       if (parm_table[*i].p_class == P_LOCAL &&
-                           (*parm_table[*i].label != '-') &&
-                           ((*i) == 0 ||
-                            (parm_table[*i].offset !=
-                             parm_table[(*i) - 1].offset)))
-                       {
-                               if (allparameters ||
-                                   !equal_parameter(parm_table[*i].type,
-                                                    ((char *)pService) +
-                                                    parm_table[*i].offset,
-                                                    ((char *)lp_ctx->sDefault) +
-                                                    parm_table[*i].offset))
-                               {
-                                       return &parm_table[(*i)++];
-                               }
-                       }
-               }
-       }
-
-       return NULL;
-}
-
-
 /**
  * Auto-load some home services.
  */
@@ -2050,18 +2059,19 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lp_ctx->bInGlobalSection = true;
        lp_ctx->globals = talloc_zero(lp_ctx, struct loadparm_global);
        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;
        lp_ctx->sDefault->browseable = true;
-       lp_ctx->sDefault->readonly = true;
+       lp_ctx->sDefault->read_only = true;
        lp_ctx->sDefault->map_archive = true;
        lp_ctx->sDefault->strict_locking = true;
        lp_ctx->sDefault->oplocks = true;
        lp_ctx->sDefault->create_mask = 0744;
        lp_ctx->sDefault->force_create_mode = 0000;
-       lp_ctx->sDefault->dir_mask = 0755;
-       lp_ctx->sDefault->force_dir_mode = 0000;
+       lp_ctx->sDefault->directory_mask = 0755;
+       lp_ctx->sDefault->force_directory_mode = 0000;
 
        DEBUG(3, ("Initialising global parameters\n"));
 
@@ -2109,7 +2119,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        myname = get_myname(lp_ctx);
        lpcfg_do_global_parameter(lp_ctx, "netbios name", myname);
        talloc_free(myname);
-       lpcfg_do_global_parameter(lp_ctx, "name resolve order", "wins host bcast");
+       lpcfg_do_global_parameter(lp_ctx, "name resolve order", "lmhosts wins host bcast");
 
        lpcfg_do_global_parameter(lp_ctx, "fstype", "NTFS");
 
@@ -2146,7 +2156,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "cache directory", dyn_CACHEDIR);
        lpcfg_do_global_parameter(lp_ctx, "ncalrpc dir", dyn_NCALRPCDIR);
 
-       lpcfg_do_global_parameter(lp_ctx, "nbt client socket address", "");
+       lpcfg_do_global_parameter(lp_ctx, "nbt client socket address", "0.0.0.0");
        lpcfg_do_global_parameter_var(lp_ctx, "server string",
                                   "Samba %s", SAMBA_VERSION_STRING);
 
@@ -2157,8 +2167,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "host msdfs", "true");
 
        lpcfg_do_global_parameter(lp_ctx, "LargeReadwrite", "True");
-       lpcfg_do_global_parameter(lp_ctx, "server min protocol", "CORE");
-       lpcfg_do_global_parameter(lp_ctx, "server max protocol", "NT1");
+       lpcfg_do_global_parameter(lp_ctx, "server min protocol", "LANMAN1");
+       lpcfg_do_global_parameter(lp_ctx, "server max protocol", "SMB3");
        lpcfg_do_global_parameter(lp_ctx, "client min protocol", "CORE");
        lpcfg_do_global_parameter(lp_ctx, "client max protocol", "NT1");
        lpcfg_do_global_parameter(lp_ctx, "security", "AUTO");
@@ -2166,6 +2176,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");
@@ -2216,7 +2227,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "nt status support", "True");
 
        lpcfg_do_global_parameter(lp_ctx, "max wins ttl", "518400"); /* 6 days */
-       lpcfg_do_global_parameter(lp_ctx, "min wins ttl", "10");
+       lpcfg_do_global_parameter(lp_ctx, "min wins ttl", "21600");
 
        lpcfg_do_global_parameter(lp_ctx, "tls enabled", "True");
        lpcfg_do_global_parameter(lp_ctx, "tls keyfile", "tls/key.pem");
@@ -2246,6 +2257,186 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        lpcfg_do_global_parameter(lp_ctx, "locking", "True");
 
+       lpcfg_do_global_parameter(lp_ctx, "block size", "1024");
+
+       lpcfg_do_global_parameter(lp_ctx, "client use spnego", "True");
+
+       lpcfg_do_global_parameter(lp_ctx, "change notify", "True");
+
+       lpcfg_do_global_parameter(lp_ctx, "name cache timeout", "660");
+
+       lpcfg_do_global_parameter(lp_ctx, "defer sharing violations", "True");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap replication sleep", "1000");
+
+       lpcfg_do_global_parameter(lp_ctx, "idmap backend", "tdb");
+
+       lpcfg_do_global_parameter(lp_ctx, "enable privileges", "True");
+
+       lpcfg_do_global_parameter_var(lp_ctx, "smb2 max write", "%u", DEFAULT_SMB2_MAX_WRITE);
+
+       lpcfg_do_global_parameter(lp_ctx, "passdb backend", "tdbsam");
+
+       lpcfg_do_global_parameter(lp_ctx, "getwd cache", "True");
+
+       lpcfg_do_global_parameter(lp_ctx, "winbind nested groups", "True");
+
+       lpcfg_do_global_parameter(lp_ctx, "mangled names", "True");
+
+       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");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap deref", "auto");
+
+       lpcfg_do_global_parameter(lp_ctx, "lm interval", "60");
+
+       lpcfg_do_global_parameter(lp_ctx, "mangling method", "hash2");
+
+       lpcfg_do_global_parameter(lp_ctx, "hide dot files", "True");
+
+       lpcfg_do_global_parameter(lp_ctx, "browse list", "True");
+
+       lpcfg_do_global_parameter(lp_ctx, "passwd chat timeout", "2");
+
+       lpcfg_do_global_parameter(lp_ctx, "guest account", GUEST_ACCOUNT);
+
+       lpcfg_do_global_parameter(lp_ctx, "client schannel", "auto");
+
+       lpcfg_do_global_parameter(lp_ctx, "smb encrypt", "default");
+
+       lpcfg_do_global_parameter(lp_ctx, "max log size", "5000");
+
+       lpcfg_do_global_parameter(lp_ctx, "idmap negative cache time", "120");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap follow referral", "auto");
+
+       lpcfg_do_global_parameter(lp_ctx, "multicast dns register", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "winbind reconnect delay", "30");
+
+       lpcfg_do_global_parameter(lp_ctx, "nt acl support", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "acl check permissions", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "keepalive", "300");
+
+       lpcfg_do_global_parameter(lp_ctx, "winbind cache time", "300");
+
+       lpcfg_do_global_parameter(lp_ctx, "level2 oplocks", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "show add printer wizard", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "allocation roundup size", "1048576");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap page size", "1024");
+
+       lpcfg_do_global_parameter(lp_ctx, "kernel share modes", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "strict locking", "Auto");
+
+       lpcfg_do_global_parameter(lp_ctx, "map readonly", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "allow trusted domains", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "default devmode", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "os level", "20");
+
+       lpcfg_do_global_parameter(lp_ctx, "dos filetimes", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "mangling char", "~");
+
+       lpcfg_do_global_parameter(lp_ctx, "printcap cache time", "750");
+
+       lpcfg_do_global_parameter(lp_ctx, "create krb5 conf", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "winbind max clients", "200");
+
+       lpcfg_do_global_parameter(lp_ctx, "acl map full control", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "nt pipe support", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap debug threshold", "10");
+
+       lpcfg_do_global_parameter(lp_ctx, "follow symlinks", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "machine password timeout", "604800");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap connection timeout", "2");
+
+       lpcfg_do_global_parameter(lp_ctx, "winbind expand groups", "1");
+
+       lpcfg_do_global_parameter(lp_ctx, "stat cache", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "lpq cache time", "30");
+
+       lpcfg_do_global_parameter_var(lp_ctx, "smb2 max trans", "%u", DEFAULT_SMB2_MAX_TRANSACT);
+
+       lpcfg_do_global_parameter_var(lp_ctx, "smb2 max read", "%u", DEFAULT_SMB2_MAX_READ);
+
+       lpcfg_do_global_parameter(lp_ctx, "durable handles", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "max stat cache size", "256");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap passwd sync", "no");
+
+       lpcfg_do_global_parameter(lp_ctx, "kernel change notify", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "max ttl", "259200");
+
+       lpcfg_do_global_parameter(lp_ctx, "blocking locks", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "oplock contention limit", "2");
+
+       lpcfg_do_global_parameter(lp_ctx, "load printers", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "idmap cache time", "604800");
+
+       lpcfg_do_global_parameter(lp_ctx, "preserve case", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "lm announce", "auto");
+
+       lpcfg_do_global_parameter(lp_ctx, "afs token lifetime", "604800");
+
+       lpcfg_do_global_parameter(lp_ctx, "enable core files", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "winbind max domain connections", "1");
+
+       lpcfg_do_global_parameter(lp_ctx, "case sensitive", "auto");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap timeout", "15");
+
+       lpcfg_do_global_parameter(lp_ctx, "mangle prefix", "1");
+
+       lpcfg_do_global_parameter(lp_ctx, "posix locking", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "lock spin time", "200");
+
+       lpcfg_do_global_parameter(lp_ctx, "directory name cache size", "100");
+
+       lpcfg_do_global_parameter(lp_ctx, "nmbd bind explicit broadcast", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "init logon delay", "100");
+
+       lpcfg_do_global_parameter(lp_ctx, "usershare owner only", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "-valid", "yes");
+
+       lpcfg_do_global_parameter_var(lp_ctx, "usershare path", "%s/usershares", get_dyn_STATEDIR());
+
+#ifdef DEVELOPER
+       lpcfg_do_global_parameter_var(lp_ctx, "panic action", "/bin/sleep 999999999");
+#endif
+
+       lpcfg_do_global_parameter(lp_ctx, "smb passwd file", get_dyn_SMB_PASSWD_FILE());
+
+       lpcfg_do_global_parameter(lp_ctx, "logon home", "\\\\%N\\%U");
+
+       lpcfg_do_global_parameter(lp_ctx, "logon path", "\\\\%N\\%U\\profile");
+
+       lpcfg_do_global_parameter(lp_ctx, "printjob username", "%U");
+
        for (i = 0; parm_table[i].label; i++) {
                if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
                        lp_ctx->flags[i] |= FLAG_DEFAULT;
@@ -2291,6 +2482,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;
 }
 
@@ -2314,13 +2506,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;
        }
 
@@ -2349,6 +2549,7 @@ static bool lpcfg_update(struct loadparm_context *lp_ctx)
                unsetenv("SOCKET_TESTNONBLOCK");
        }
 
+       TALLOC_FREE(tmp_ctx);
        return true;
 }
 
@@ -2389,7 +2590,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;
@@ -2514,7 +2715,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);
 }
 
 /**
@@ -2523,7 +2724,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);
@@ -2531,13 +2732,13 @@ const char *lpcfg_volume_label(struct loadparm_service *service, struct loadparm
 }
 
 /**
- * If we are PDC then prefer us as DMB
+ * Return the correct printer name.
  */
 const char *lpcfg_printername(struct loadparm_service *service, struct loadparm_service *sDefault)
 {
        const char *ret;
-       ret = lp_string((const char *)((service != NULL && service->szPrintername != NULL) ?
-                                      service->szPrintername : sDefault->szPrintername));
+       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);
 
@@ -2581,27 +2782,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)
@@ -2673,3 +2874,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;
+}