param: Remove winbindd privileged socket directory option
[sfrench/samba-autobuild/.git] / lib / param / loadparm.c
index b452f9c9531ac629bb96ecc08486d6541c6c1f0c..a05610130e8d2c81803ef4eb8c9cce2825d6a6b4 100644 (file)
 #include "lib/util/bitmap.h"
 #include "libcli/smb/smb_constants.h"
 #include "tdb.h"
+#include "librpc/gen_ndr/nbt.h"
+#include "libds/common/roles.h"
 
-#define standard_sub_basic talloc_strdup
+#ifdef HAVE_HTTPCONNECTENCRYPT
+#include <cups/http.h>
+#endif
 
-static bool do_parameter(const char *, const char *, void *);
+#define standard_sub_basic talloc_strdup
 
 #include "lib/param/param_global.h"
 
 struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx)
 {
-       if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->get_default_loadparm_service();
-       }
        return lp_ctx->sDefault;
 }
 
@@ -144,9 +145,6 @@ static const char *lpcfg_string(const char *s)
 /* this global context supports the lp_*() function varients */
 static struct loadparm_context *global_loadparm_context;
 
-#define lpcfg_default_service global_loadparm_context->sDefault
-#define lpcfg_global_service(i) global_loadparm_context->services[i]
-
 #define FN_GLOBAL_STRING(fn_name,var_name) \
  _PUBLIC_ char *lpcfg_ ## fn_name(struct loadparm_context *lp_ctx, TALLOC_CTX *ctx) {\
         if (lp_ctx == NULL) return NULL;                               \
@@ -216,12 +214,14 @@ static struct loadparm_context *global_loadparm_context;
 
 #define FN_LOCAL_PARM_INTEGER(fn_name, val) FN_LOCAL_INTEGER(fn_name, val)
 
-#define FN_LOCAL_PARM_CHAR(fn_name,val) \
+#define FN_LOCAL_CHAR(fn_name,val) \
  _PUBLIC_ char lpcfg_ ## fn_name(struct loadparm_service *service, \
                                struct loadparm_service *sDefault) {    \
         return((service != NULL)? service->val : sDefault->val); \
  }
 
+#define FN_LOCAL_PARM_CHAR(fn_name,val) FN_LOCAL_CHAR(fn_name, val)
+
 #include "lib/param/param_functions.c"
 
 /* These functions cannot be auto-generated */
@@ -231,10 +231,13 @@ FN_GLOBAL_CONST_STRING(dnsdomain, dnsdomain)
 /* local prototypes */
 static struct loadparm_service *lpcfg_getservicebyname(struct loadparm_context *lp_ctx,
                                        const char *pszServiceName);
-static bool lpcfg_service_ok(struct loadparm_service *service);
 static bool do_section(const char *pszSectionName, void *);
 static bool set_variable_helper(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
                                const char *pszParmName, const char *pszParmValue);
+static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
+                                      struct loadparm_service *service,
+                                      const char *pszParmName,
+                                      const char *pszParmValue, int flags);
 
 /* The following are helper functions for parametrical options support. */
 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
@@ -243,16 +246,12 @@ struct parmlist_entry *get_parametric_helper(struct loadparm_service *service,
                                             const char *type, const char *option,
                                             struct parmlist_entry *global_opts)
 {
-       char* param_key;
+       size_t type_len = strlen(type);
+       size_t option_len = strlen(option);
+       char param_key[type_len + option_len + 2];
        struct parmlist_entry *data = NULL;
-       TALLOC_CTX *mem_ctx = talloc_stackframe();
 
-       param_key = talloc_asprintf(mem_ctx, "%s:%s", type, option);
-       if (param_key == NULL) {
-               DEBUG(0,("asprintf failed!\n"));
-               TALLOC_FREE(mem_ctx);
-               return NULL;
-       }
+       snprintf(param_key, sizeof(param_key), "%s:%s", type, option);
 
        /*
         * Try to fetch the option from the data.
@@ -261,7 +260,6 @@ struct parmlist_entry *get_parametric_helper(struct loadparm_service *service,
                data = service->param_opt;
                while (data != NULL) {
                        if (strwicmp(data->key, param_key) == 0) {
-                               TALLOC_FREE(mem_ctx);
                                return data;
                        }
                        data = data->next;
@@ -274,18 +272,12 @@ struct parmlist_entry *get_parametric_helper(struct loadparm_service *service,
        data = global_opts;
        while (data != NULL) {
                if (strwicmp(data->key, param_key) == 0) {
-                       TALLOC_FREE(mem_ctx);
                        return data;
                }
                data = data->next;
        }
 
-
-       TALLOC_FREE(mem_ctx);
-
        return NULL;
-
-
 }
 
 const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
@@ -336,6 +328,20 @@ unsigned long lp_ulong(const char *s)
        return strtoul(s, NULL, 0);
 }
 
+/**
+ * convenience routine to return unsigned long long parameters.
+ */
+unsigned long long lp_ulonglong(const char *s)
+{
+
+       if (!s || !*s) {
+               DEBUG(0, ("lp_ulonglong(%s): is called with NULL!\n", s));
+               return -1;
+       }
+
+       return strtoull(s, NULL, 0);
+}
+
 /**
  * convenience routine to return unsigned long parameters.
  */
@@ -416,8 +422,10 @@ const char **lpcfg_parm_string_list(TALLOC_CTX *mem_ctx,
 {
        const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
 
-       if (value != NULL)
-               return (const char **)str_list_make(mem_ctx, value, separator);
+       if (value != NULL) {
+               char **l = str_list_make(mem_ctx, value, separator);
+               return discard_const_p(const char *, l);
+       }
 
        return NULL;
 }
@@ -479,6 +487,25 @@ unsigned long lpcfg_parm_ulong(struct loadparm_context *lp_ctx,
        return default_v;
 }
 
+/**
+ * Return parametric option from a given service.
+ * Type is a part of option before ':'
+ * Parametric option has following syntax: 'Type: option = value'
+ */
+unsigned long long lpcfg_parm_ulonglong(struct loadparm_context *lp_ctx,
+                                       struct loadparm_service *service,
+                                       const char *type, const char *option,
+                                       unsigned long long default_v)
+{
+       const char *value = lpcfg_get_parametric(lp_ctx, service, type, option);
+
+       if (value) {
+               return lp_ulonglong(value);
+       }
+
+       return default_v;
+}
+
 long lpcfg_parm_long(struct loadparm_context *lp_ctx,
                     struct loadparm_service *service, const char *type,
                     const char *option, long default_v)
@@ -521,16 +548,36 @@ bool lpcfg_parm_bool(struct loadparm_context *lp_ctx,
 }
 
 
+/* this is used to prevent lots of mallocs of size 1 */
+static const char lpcfg_string_empty[] = "";
+
+/**
+ Free a string value.
+**/
+void lpcfg_string_free(char **s)
+{
+       if (s == NULL) {
+               return;
+       }
+       if (*s == lpcfg_string_empty) {
+               *s = NULL;
+               return;
+       }
+       TALLOC_FREE(*s);
+}
+
 /**
  * Set a string value, deallocating any existing space, and allocing the space
  * for the string
  */
 bool lpcfg_string_set(TALLOC_CTX *mem_ctx, char **dest, const char *src)
 {
-       talloc_free(*dest);
+       lpcfg_string_free(dest);
 
-       if (src == NULL)
-               src = "";
+       if ((src == NULL) || (*src == '\0')) {
+               *dest = discard_const_p(char, lpcfg_string_empty);
+               return true;
+       }
 
        *dest = talloc_strdup(mem_ctx, src);
        if ((*dest) == NULL) {
@@ -547,10 +594,12 @@ bool lpcfg_string_set(TALLOC_CTX *mem_ctx, char **dest, const char *src)
  */
 bool lpcfg_string_set_upper(TALLOC_CTX *mem_ctx, char **dest, const char *src)
 {
-       talloc_free(*dest);
+       lpcfg_string_free(dest);
 
-       if (src == NULL)
-               src = "";
+       if ((src == NULL) || (*src == '\0')) {
+               *dest = discard_const_p(char, lpcfg_string_empty);
+               return true;
+       }
 
        *dest = strupper_talloc(mem_ctx, src);
        if ((*dest) == NULL) {
@@ -576,6 +625,10 @@ struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
        int num_to_alloc = lp_ctx->iNumServices + 1;
        struct parmlist_entry *data, *pdata;
 
+       if (lp_ctx->s3_fns != NULL) {
+               smb_panic("Add a service should not be called on an s3 loadparm ctx");
+       }
+
        if (pservice == NULL) {
                pservice = lp_ctx->sDefault;
        }
@@ -658,7 +711,7 @@ bool lpcfg_add_home(struct loadparm_context *lp_ctx,
        if (!(*(service->comment))) {
                service->comment = talloc_asprintf(service, "Home directory of %s", user);
        }
-       service->bAvailable = default_service->bAvailable;
+       service->available = default_service->available;
        service->browseable = default_service->browseable;
 
        DEBUG(3, ("adding home's share [%s] for user '%s' at '%s'\n",
@@ -729,15 +782,13 @@ int lpcfg_map_parameter(const char *pszParmName)
 */
 struct parm_struct *lpcfg_parm_struct(struct loadparm_context *lp_ctx, const char *name)
 {
-       int parmnum;
+       int num = lpcfg_map_parameter(name);
 
-       if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->get_parm_struct(name);
+       if (num < 0) {
+               return NULL;
        }
 
-       parmnum = lpcfg_map_parameter(name);
-       if (parmnum == -1) return NULL;
-       return &parm_table[parmnum];
+       return &parm_table[num];
 }
 
 /**
@@ -768,14 +819,6 @@ bool lpcfg_parm_is_cmdline(struct loadparm_context *lp_ctx, const char *name)
 {
        int parmnum;
 
-       if (lp_ctx->s3_fns) {
-               struct parm_struct *parm = lp_ctx->s3_fns->get_parm_struct(name);
-               if (parm) {
-                       return parm->flags & FLAG_CMDLINE;
-               }
-               return false;
-       }
-
        parmnum = lpcfg_map_parameter(name);
        if (parmnum == -1) return false;
 
@@ -815,10 +858,8 @@ void set_param_opt(TALLOC_CTX *mem_ctx,
                   unsigned priority)
 {
        struct parmlist_entry *new_opt, *opt;
-       bool not_added;
 
        opt = *opt_list;
-       not_added = true;
 
        /* Traverse destination */
        while (opt) {
@@ -830,35 +871,28 @@ void set_param_opt(TALLOC_CTX *mem_ctx,
                                   overridden */
                                return;
                        }
-                       TALLOC_FREE(opt->value);
                        TALLOC_FREE(opt->list);
-                       opt->value = talloc_strdup(opt, opt_value);
+                       lpcfg_string_set(opt, &opt->value, opt_value);
                        opt->priority = priority;
-                       not_added = false;
-                       break;
+                       return;
                }
                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);
+       new_opt = talloc_pooled_object(
+               mem_ctx, struct parmlist_entry,
+               2, strlen(opt_name) + 1 + strlen(opt_value) + 1);
+       if (new_opt == NULL) {
+               smb_panic("OOM");
        }
+       new_opt->key = NULL;
+       lpcfg_string_set(new_opt, &new_opt->key, opt_name);
+       new_opt->value = NULL;
+       lpcfg_string_set(new_opt, &new_opt->value, opt_value);
+
+       new_opt->list = NULL;
+       new_opt->priority = priority;
+       DLIST_ADD(*opt_list, new_opt);
 }
 
 /**
@@ -913,8 +947,8 @@ void copy_service(struct loadparm_service *pserviceDest,
                                case P_CMDLIST:
                                case P_LIST:
                                        TALLOC_FREE(*((char ***)dest_ptr));
-                                       *(const char * const **)dest_ptr = (const char * const *)str_list_copy(pserviceDest,
-                                                                                 *(const char * * const *)src_ptr);
+                                       *(char ***)dest_ptr = str_list_copy(pserviceDest,
+                                                                           *discard_const_p(const char **, src_ptr));
                                        break;
                                default:
                                        break;
@@ -938,7 +972,7 @@ void copy_service(struct loadparm_service *pserviceDest,
  * Check a service for consistency. Return False if the service is in any way
  * incomplete or faulty, else True.
  */
-static bool lpcfg_service_ok(struct loadparm_service *service)
+bool lpcfg_service_ok(struct loadparm_service *service)
 {
        bool bRetval;
 
@@ -962,8 +996,16 @@ static bool lpcfg_service_ok(struct loadparm_service *service)
                        service->browseable = false;
        }
 
-       /* If a service is flagged unavailable, log the fact at level 0. */
-       if (!service->bAvailable)
+       if (service->path[0] == '\0' &&
+           strwicmp(service->szService, HOMES_NAME) != 0 &&
+           service->msdfs_proxy[0] == '\0')
+       {
+               DEBUG(0, ("WARNING: No path in service %s - making it unavailable!\n",
+                       service->szService));
+               service->available = false;
+       }
+
+       if (!service->available)
                DEBUG(1, ("NOTE: Service %s is flagged unavailable.\n",
                          service->szService));
 
@@ -1041,8 +1083,10 @@ bool lpcfg_file_list_changed(struct loadparm_context *lp_ctx)
                        f->modtime = mod_time;
                        talloc_free(f->subfname);
                        f->subfname = talloc_strdup(f, n2);
+                       TALLOC_FREE(n2);
                        return true;
                }
+               TALLOC_FREE(n2);
        }
        return false;
 }
@@ -1056,7 +1100,7 @@ bool lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue,
        int i;
 
        for (i = 0; parm->enum_list[i].name; i++) {
-               if ( strequal(pszParmValue, parm->enum_list[i].name)) {
+               if (strwicmp(pszParmValue, parm->enum_list[i].name) == 0) {
                        *ptr = parm->enum_list[i].value;
                        return true;
                }
@@ -1071,7 +1115,7 @@ bool lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue,
  Handle the "realm" parameter
 ***************************************************************************/
 
-bool handle_realm(struct loadparm_context *lp_ctx, int unused,
+bool handle_realm(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                  const char *pszParmValue, char **ptr)
 {
        char *upper;
@@ -1088,15 +1132,9 @@ bool handle_realm(struct loadparm_context *lp_ctx, int unused,
                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);
-       }
+       lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->realm_original, pszParmValue);
+       lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->realm, upper);
+       lpcfg_string_set(lp_ctx->globals->ctx, &lp_ctx->globals->dnsdomain, lower);
 
        return true;
 }
@@ -1105,13 +1143,15 @@ bool handle_realm(struct loadparm_context *lp_ctx, int unused,
  Handle the include operation.
 ***************************************************************************/
 
-bool handle_include(struct loadparm_context *lp_ctx, int unused,
+bool handle_include(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                           const char *pszParmValue, char **ptr)
 {
        char *fname;
+       const char *substitution_variable_substring;
+       char next_char;
 
        if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->lp_include(lp_ctx, unused, pszParmValue, ptr);
+               return lp_ctx->s3_fns->lp_include(lp_ctx, service, pszParmValue, ptr);
        }
 
        fname = standard_sub_basic(lp_ctx, pszParmValue);
@@ -1121,7 +1161,23 @@ bool handle_include(struct loadparm_context *lp_ctx, int unused,
        lpcfg_string_set(lp_ctx, ptr, fname);
 
        if (file_exist(fname))
-               return pm_process(fname, do_section, do_parameter, lp_ctx);
+               return pm_process(fname, do_section, lpcfg_do_parameter, lp_ctx);
+
+       /*
+        * If the file doesn't exist, we check that it isn't due to variable
+        * substitution
+        */
+       substitution_variable_substring = strchr(fname, '%');
+
+       if (substitution_variable_substring != NULL) {
+               next_char = substitution_variable_substring[1];
+               if ((next_char >= 'a' && next_char <= 'z')
+                   || (next_char >= 'A' && next_char <= 'Z')) {
+                       DEBUG(2, ("Tried to load %s but variable substitution in "
+                                "filename, ignoring file.\n", fname));
+                       return true;
+               }
+       }
 
        DEBUG(2, ("Can't find include file %s\n", fname));
 
@@ -1132,37 +1188,31 @@ bool handle_include(struct loadparm_context *lp_ctx, int unused,
  Handle the interpretation of the copy parameter.
 ***************************************************************************/
 
-bool handle_copy(struct loadparm_context *lp_ctx, int snum,
+bool handle_copy(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                        const char *pszParmValue, char **ptr)
 {
        bool bRetval;
        struct loadparm_service *serviceTemp = NULL;
-       struct loadparm_service *current = NULL;
 
        bRetval = false;
 
        DEBUG(3, ("Copying service from service %s\n", pszParmValue));
 
        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"));
+       if (service == NULL) {
+               DEBUG(0, ("Unable to copy service - invalid service destination.\n"));
                return false;
        }
 
        if (serviceTemp != NULL) {
-               if (serviceTemp == current) {
+               if (serviceTemp == service) {
                        DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
                } else {
-                       copy_service(current,
+                       copy_service(service,
                                     serviceTemp,
-                                    current->copymap);
-                       lpcfg_string_set(current, ptr, pszParmValue);
+                                    service->copymap);
+                       lpcfg_string_set(service, ptr, pszParmValue);
 
                        bRetval = true;
                }
@@ -1175,28 +1225,23 @@ bool handle_copy(struct loadparm_context *lp_ctx, int snum,
        return bRetval;
 }
 
-bool handle_debug_list(struct loadparm_context *lp_ctx, int unused,
+bool handle_debug_list(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                        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->globals->ctx, ptr, pszParmValue);
 
        return debug_parse_levels(pszParmValue);
 }
 
-bool handle_logfile(struct loadparm_context *lp_ctx, int unused,
+bool handle_logfile(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                    const char *pszParmValue, char **ptr)
 {
-       if (lp_ctx->s3_fns != NULL) {
-               lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
-       } else {
+       if (lp_ctx->s3_fns == NULL) {
                debug_set_logfile(pszParmValue);
-               lpcfg_string_set(lp_ctx, ptr, pszParmValue);
        }
 
+       lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
+
        return true;
 }
 
@@ -1204,25 +1249,23 @@ 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,
+bool handle_charset(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                        const char *pszParmValue, char **ptr)
 {
        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);
+       return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
 
 }
 
-bool handle_dos_charset(struct loadparm_context *lp_ctx, int snum,
+bool handle_dos_charset(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                        const char *pszParmValue, char **ptr)
 {
        bool is_utf8 = false;
@@ -1255,23 +1298,20 @@ bool handle_dos_charset(struct loadparm_context *lp_ctx, int snum,
                                        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);
+       return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
 }
 
-bool handle_printing(struct loadparm_context *lp_ctx, int snum,
+bool handle_printing(struct loadparm_context *lp_ctx, struct loadparm_service *service,
                            const char *pszParmValue, char **ptr)
 {
        static int parm_num = -1;
-       struct loadparm_service *s;
 
        if (parm_num == -1) {
                parm_num = lpcfg_map_parameter("printing");
@@ -1282,19 +1322,18 @@ bool handle_printing(struct loadparm_context *lp_ctx, int snum,
        }
 
        if (lp_ctx->s3_fns) {
-               if ( snum < 0 ) {
-                       s = lp_ctx->sDefault;
-                       lp_ctx->s3_fns->init_printer_values(lp_ctx->globals->ctx, s);
+               if (service == NULL) {
+                       init_printer_values(lp_ctx, lp_ctx->globals->ctx, lp_ctx->sDefault);
                } else {
-                       s = lp_ctx->services[snum];
-                       lp_ctx->s3_fns->init_printer_values(s, s);
+                       init_printer_values(lp_ctx, service, service);
                }
        }
 
        return true;
 }
 
-bool handle_ldap_debug_level(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+bool handle_ldap_debug_level(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+                            const char *pszParmValue, char **ptr)
 {
        lp_ctx->globals->ldap_debug_level = lp_int(pszParmValue);
 
@@ -1304,11 +1343,12 @@ bool handle_ldap_debug_level(struct loadparm_context *lp_ctx, int snum, const ch
        return true;
 }
 
-bool handle_netbios_aliases(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+bool handle_netbios_aliases(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+                           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);
+       lp_ctx->globals->netbios_aliases = str_list_make_v3_const(lp_ctx->globals->ctx,
+                                                                 pszParmValue, NULL);
 
        if (lp_ctx->s3_fns) {
                return lp_ctx->s3_fns->set_netbios_aliases(lp_ctx->globals->netbios_aliases);
@@ -1320,34 +1360,41 @@ bool handle_netbios_aliases(struct loadparm_context *lp_ctx, int snum, const cha
  * idmap related parameters
  */
 
-bool handle_idmap_backend(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+bool handle_idmap_backend(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+                         const char *pszParmValue, char **ptr)
 {
        if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : backend", pszParmValue);
+               lp_do_parameter_parametric(lp_ctx, service, "idmap config * : backend",
+                                          pszParmValue, 0);
        }
 
-       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
 }
 
-bool handle_idmap_uid(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+bool handle_idmap_uid(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+                     const char *pszParmValue, char **ptr)
 {
        if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : range", pszParmValue);
+               lp_do_parameter_parametric(lp_ctx, service, "idmap config * : range",
+                                          pszParmValue, 0);
        }
 
-       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
 }
 
-bool handle_idmap_gid(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+bool handle_idmap_gid(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+                     const char *pszParmValue, char **ptr)
 {
        if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : range", pszParmValue);
+               lp_do_parameter_parametric(lp_ctx, service, "idmap config * : range",
+                                          pszParmValue, 0);
        }
 
-       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       return lpcfg_string_set(lp_ctx->globals->ctx, ptr, pszParmValue);
 }
 
-bool handle_smb_ports(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+bool handle_smb_ports(struct loadparm_context *lp_ctx, struct loadparm_service *service,
+                     const char *pszParmValue, char **ptr)
 {
        static int parm_num = -1;
        int i;
@@ -1359,6 +1406,9 @@ bool handle_smb_ports(struct loadparm_context *lp_ctx, int snum, const char *psz
 
        if (parm_num == -1) {
                parm_num = lpcfg_map_parameter("smb ports");
+               if (parm_num == -1) {
+                       return false;
+               }
        }
 
        if(!set_variable_helper(lp_ctx->globals->ctx, parm_num, ptr, "smb ports",
@@ -1385,24 +1435,73 @@ bool handle_smb_ports(struct loadparm_context *lp_ctx, int snum, const char *psz
        return true;
 }
 
+bool handle_smb2_max_credits(struct loadparm_context *lp_ctx,
+                            struct loadparm_service *service,
+                            const char *pszParmValue, char **ptr)
+{
+       int value = lp_int(pszParmValue);
+
+       if (value <= 0) {
+               value = DEFAULT_SMB2_MAX_CREDITS;
+       }
+
+       *(int *)ptr = value;
+
+       return true;
+}
+
+bool handle_cups_encrypt(struct loadparm_context *lp_ctx,
+                        struct loadparm_service *service,
+                        const char *pszParmValue, char **ptr)
+{
+       int result = 0;
+#ifdef HAVE_HTTPCONNECTENCRYPT
+       int value = lp_int(pszParmValue);
+
+       switch (value) {
+               case Auto:
+                       result = HTTP_ENCRYPT_REQUIRED;
+                       break;
+               case true:
+                       result = HTTP_ENCRYPT_ALWAYS;
+                       break;
+               case false:
+                       result = HTTP_ENCRYPT_NEVER;
+                       break;
+               default:
+                       result = 0;
+                       break;
+       }
+#endif
+       *(int *)ptr = result;
+
+       return true;
+}
+
 /***************************************************************************
  Initialise a copymap.
 ***************************************************************************/
 
+/**
+ * Initializes service copymap
+ * Note: pservice *must* be valid TALLOC_CTX
+ */
 void init_copymap(struct loadparm_service *pservice)
 {
        int i;
 
        TALLOC_FREE(pservice->copymap);
 
-       pservice->copymap = bitmap_talloc(NULL, num_parameters());
-       if (!pservice->copymap)
+       pservice->copymap = bitmap_talloc(pservice, num_parameters());
+       if (!pservice->copymap) {
                DEBUG(0,
                      ("Couldn't allocate copymap!! (size %d)\n",
                       (int)num_parameters()));
-       else
-               for (i = 0; i < num_parameters(); i++)
+       } else {
+               for (i = 0; i < num_parameters(); i++) {
                        bitmap_set(pservice->copymap, i);
+               }
+       }
 }
 
 /**
@@ -1509,9 +1608,8 @@ static bool set_variable_helper(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr
 
                case P_CMDLIST:
                        TALLOC_FREE(*(char ***)parm_ptr);
-                       *(const char * const **)parm_ptr
-                               = (const char * const *)str_list_make_v3(mem_ctx,
-                                                                        pszParmValue, NULL);
+                       *(char ***)parm_ptr = str_list_make_v3(mem_ctx,
+                                                       pszParmValue, NULL);
                        break;
 
                case P_LIST:
@@ -1544,7 +1642,7 @@ static bool set_variable_helper(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr
                                                          pszParmName, pszParmValue));
                                                return false;
                                        }
-                                       *(const char * const **)parm_ptr = (const char * const *) new_list;
+                                       *(char ***)parm_ptr = new_list;
                                        break;
                                }
                        }
@@ -1565,15 +1663,14 @@ static bool set_variable_helper(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr
                        }
                        break;
 
-               case P_SEP:
-                       break;
        }
 
        return true;
 
 }
 
-bool set_variable(TALLOC_CTX *mem_ctx, int snum, int parmnum, void *parm_ptr,
+static bool set_variable(TALLOC_CTX *mem_ctx, struct loadparm_service *service,
+                        int parmnum, void *parm_ptr,
                         const char *pszParmName, const char *pszParmValue,
                         struct loadparm_context *lp_ctx, bool on_globals)
 {
@@ -1582,21 +1679,17 @@ bool set_variable(TALLOC_CTX *mem_ctx, int snum, int parmnum, void *parm_ptr,
 
        /* if it is a special case then go ahead */
        if (parm_table[parmnum].special) {
-               ok = parm_table[parmnum].special(lp_ctx, snum, pszParmValue,
+               ok = parm_table[parmnum].special(lp_ctx, service, pszParmValue,
                                                  (char **)parm_ptr);
-               if (!ok) {
-                       return false;
-               }
-               goto mark_non_default;
+       } else {
+               ok = set_variable_helper(mem_ctx, parmnum, parm_ptr,
+                                        pszParmName, pszParmValue);
        }
 
-       ok = set_variable_helper(mem_ctx, parmnum, parm_ptr, pszParmName, pszParmValue);
-
        if (!ok) {
                return false;
        }
 
-mark_non_default:
        if (on_globals && (lp_ctx->flags[parmnum] & FLAG_DEFAULT)) {
                lp_ctx->flags[parmnum] &= ~FLAG_DEFAULT;
                /* we have to also unset FLAG_DEFAULT on aliases */
@@ -1638,7 +1731,7 @@ bool lpcfg_do_global_parameter(struct loadparm_context *lp_ctx,
 
        parm_ptr = lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[parmnum]);
 
-       return set_variable(lp_ctx->globals->ctx, -1, parmnum, parm_ptr,
+       return set_variable(lp_ctx->globals->ctx, NULL, parmnum, parm_ptr,
                            pszParmName, pszParmValue, lp_ctx, true);
 }
 
@@ -1687,7 +1780,7 @@ bool lpcfg_do_service_parameter(struct loadparm_context *lp_ctx,
                    parm_table[i].p_class == parm_table[parmnum].p_class)
                        bitmap_clear(service->copymap, i);
 
-       return set_variable(service, -1, parmnum, parm_ptr, pszParmName,
+       return set_variable(service, service, parmnum, parm_ptr, pszParmName,
                            pszParmValue, lp_ctx, false);
 }
 
@@ -1695,7 +1788,7 @@ bool lpcfg_do_service_parameter(struct loadparm_context *lp_ctx,
  * Process a parameter.
  */
 
-static bool do_parameter(const char *pszParmName, const char *pszParmValue,
+bool lpcfg_do_parameter(const char *pszParmName, const char *pszParmValue,
                         void *userdata)
 {
        struct loadparm_context *lp_ctx = (struct loadparm_context *)userdata;
@@ -1764,14 +1857,8 @@ bool lpcfg_set_cmdline(struct loadparm_context *lp_ctx, const char *pszParmName,
        /* reset the CMDLINE flag in case this has been called before */
        lp_ctx->flags[parmnum] &= ~FLAG_CMDLINE;
 
-       if (lp_ctx->s3_fns != NULL) {
-               if (!lp_ctx->s3_fns->lp_do_parameter(-1, pszParmName, pszParmValue)) {
-                       return false;
-               }
-       } else {
-               if (!lpcfg_do_global_parameter(lp_ctx, pszParmName, pszParmValue)) {
-                       return false;
-               }
+       if (!lpcfg_do_global_parameter(lp_ctx, pszParmName, pszParmValue)) {
+               return false;
        }
 
        lp_ctx->flags[parmnum] |= FLAG_CMDLINE;
@@ -1902,8 +1989,6 @@ void lpcfg_print_parameter(struct parm_struct *p, void *ptr, FILE * f)
                                fprintf(f, "%s", *(char **)ptr);
                        }
                        break;
-               case P_SEP:
-                       break;
        }
 }
 
@@ -1941,8 +2026,6 @@ static bool lpcfg_equal_parameter(parm_type type, void *ptr1, void *ptr2)
                                p2 = NULL;
                        return (p1 == p2 || strequal(p1, p2));
                }
-               case P_SEP:
-                       break;
        }
        return false;
 }
@@ -2007,14 +2090,14 @@ static bool do_section(const char *pszSectionName, void *userdata)
  * Determine if a particular base parameter is currently set to the default value.
  */
 
-static bool is_default(struct loadparm_service *sDefault, int i)
+static bool is_default(void *base_structure, int i)
 {
-       void *def_ptr = ((char *)sDefault) + parm_table[i].offset;
+       void *def_ptr = ((char *)base_structure) + parm_table[i].offset;
        switch (parm_table[i].type) {
                case P_CMDLIST:
                case P_LIST:
                        return str_list_equal((const char * const *)parm_table[i].def.lvalue,
-                                             *(const char ***)def_ptr);
+                                             *(const char * const **)def_ptr);
                case P_STRING:
                case P_USTRING:
                        return strequal(parm_table[i].def.svalue,
@@ -2030,8 +2113,6 @@ static bool is_default(struct loadparm_service *sDefault, int i)
                case P_ENUM:
                        return parm_table[i].def.ivalue ==
                                *(int *)def_ptr;
-               case P_SEP:
-                       break;
        }
        return false;
 }
@@ -2040,7 +2121,7 @@ static bool is_default(struct loadparm_service *sDefault, int i)
  *Display the contents of the global structure.
  */
 
-static void dump_globals(struct loadparm_context *lp_ctx, FILE *f,
+void lpcfg_dump_globals(struct loadparm_context *lp_ctx, FILE *f,
                         bool show_defaults)
 {
        int i;
@@ -2048,14 +2129,28 @@ static void dump_globals(struct loadparm_context *lp_ctx, FILE *f,
 
        fprintf(f, "# Global parameters\n[global]\n");
 
-       for (i = 0; parm_table[i].label; i++)
-               if (parm_table[i].p_class == P_GLOBAL &&
-                   (i == 0 || (parm_table[i].offset != parm_table[i - 1].offset))) {
-                       if (!show_defaults && (lp_ctx->flags[i] & FLAG_DEFAULT))
+       for (i = 0; parm_table[i].label; i++) {
+               if (parm_table[i].p_class != P_GLOBAL) {
+                       continue;
+               }
+
+               if (parm_table[i].flags & FLAG_SYNONYM) {
+                       continue;
+               }
+
+               if (!show_defaults) {
+                       if (lp_ctx->flags && (lp_ctx->flags[i] & FLAG_DEFAULT)) {
                                continue;
-                       fprintf(f, "\t%s = ", parm_table[i].label);
-                       lpcfg_print_parameter(&parm_table[i], lpcfg_parm_ptr(lp_ctx, NULL, &parm_table[i]), f);
-                       fprintf(f, "\n");
+                       }
+
+                       if (is_default(lp_ctx->globals, i)) {
+                               continue;
+                       }
+               }
+
+               fprintf(f, "\t%s = ", parm_table[i].label);
+               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) {
                for (data = lp_ctx->globals->param_opt; data;
@@ -2083,33 +2178,45 @@ void lpcfg_dump_a_service(struct loadparm_service * pService, struct loadparm_se
                fprintf(f, "\n[%s]\n", pService->szService);
 
        for (i = 0; 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 (pService == sDefault) {
+               if (parm_table[i].p_class != P_LOCAL) {
+                       continue;
+               }
+
+               if (parm_table[i].flags & FLAG_SYNONYM) {
+                       continue;
+               }
+
+               if (*parm_table[i].label == '-') {
+                       continue;
+               }
+
+               if (pService == sDefault) {
+                       if (!show_defaults) {
                                if (flags && (flags[i] & FLAG_DEFAULT)) {
                                        continue;
                                }
-                               if (!show_defaults) {
-                                       if (is_default(sDefault, i)) {
-                                               continue;
-                                       }
-                               }
-                       } else {
-                               if (lpcfg_equal_parameter(parm_table[i].type,
-                                                         ((char *)pService) +
-                                                         parm_table[i].offset,
-                                                         ((char *)sDefault) +
-                                                         parm_table[i].offset))
+
+                               if (is_default(sDefault, i)) {
                                        continue;
+                               }
+                       }
+               } else {
+                       bool equal;
+
+                       equal = lpcfg_equal_parameter(parm_table[i].type,
+                                                     ((char *)pService) +
+                                                     parm_table[i].offset,
+                                                     ((char *)sDefault) +
+                                                     parm_table[i].offset);
+                       if (equal) {
+                               continue;
                        }
-
-                       fprintf(f, "\t%s = ", parm_table[i].label);
-                       lpcfg_print_parameter(&parm_table[i],
-                                       ((char *)pService) + parm_table[i].offset, f);
-                       fprintf(f, "\n");
                }
+
+               fprintf(f, "\t%s = ", parm_table[i].label);
+               lpcfg_print_parameter(&parm_table[i],
+                               ((char *)pService) + parm_table[i].offset, f);
+               fprintf(f, "\n");
        }
        if (pService->param_opt != NULL) {
                for (data = pService->param_opt; data; data = data->next) {
@@ -2179,6 +2286,127 @@ static void lpcfg_add_auto_services(struct loadparm_context *lp_ctx,
        return;
 }
 
+/***************************************************************************
+ Initialise the sDefault parameter structure for the printer values.
+***************************************************************************/
+
+void init_printer_values(struct loadparm_context *lp_ctx, TALLOC_CTX *ctx,
+                        struct loadparm_service *pService)
+{
+       /* choose defaults depending on the type of printing */
+       switch (pService->printing) {
+               case PRINT_BSD:
+               case PRINT_AIX:
+               case PRINT_LPRNT:
+               case PRINT_LPROS2:
+                       lpcfg_string_set(ctx, &pService->lpq_command, "lpq -P'%p'");
+                       lpcfg_string_set(ctx, &pService->lprm_command, "lprm -P'%p' %j");
+                       lpcfg_string_set(ctx, &pService->print_command, "lpr -r -P'%p' %s");
+                       break;
+
+               case PRINT_LPRNG:
+               case PRINT_PLP:
+                       lpcfg_string_set(ctx, &pService->lpq_command, "lpq -P'%p'");
+                       lpcfg_string_set(ctx, &pService->lprm_command, "lprm -P'%p' %j");
+                       lpcfg_string_set(ctx, &pService->print_command, "lpr -r -P'%p' %s");
+                       lpcfg_string_set(ctx, &pService->queuepause_command, "lpc stop '%p'");
+                       lpcfg_string_set(ctx, &pService->queueresume_command, "lpc start '%p'");
+                       lpcfg_string_set(ctx, &pService->lppause_command, "lpc hold '%p' %j");
+                       lpcfg_string_set(ctx, &pService->lpresume_command, "lpc release '%p' %j");
+                       break;
+
+               case PRINT_CUPS:
+               case PRINT_IPRINT:
+                       /* set the lpq command to contain the destination printer
+                          name only.  This is used by cups_queue_get() */
+                       lpcfg_string_set(ctx, &pService->lpq_command, "%p");
+                       lpcfg_string_set(ctx, &pService->lprm_command, "");
+                       lpcfg_string_set(ctx, &pService->print_command, "");
+                       lpcfg_string_set(ctx, &pService->lppause_command, "");
+                       lpcfg_string_set(ctx, &pService->lpresume_command, "");
+                       lpcfg_string_set(ctx, &pService->queuepause_command, "");
+                       lpcfg_string_set(ctx, &pService->queueresume_command, "");
+                       break;
+
+               case PRINT_SYSV:
+               case PRINT_HPUX:
+                       lpcfg_string_set(ctx, &pService->lpq_command, "lpstat -o%p");
+                       lpcfg_string_set(ctx, &pService->lprm_command, "cancel %p-%j");
+                       lpcfg_string_set(ctx, &pService->print_command, "lp -c -d%p %s; rm %s");
+                       lpcfg_string_set(ctx, &pService->queuepause_command, "disable %p");
+                       lpcfg_string_set(ctx, &pService->queueresume_command, "enable %p");
+#ifndef HPUX
+                       lpcfg_string_set(ctx, &pService->lppause_command, "lp -i %p-%j -H hold");
+                       lpcfg_string_set(ctx, &pService->lpresume_command, "lp -i %p-%j -H resume");
+#endif /* HPUX */
+                       break;
+
+               case PRINT_QNX:
+                       lpcfg_string_set(ctx, &pService->lpq_command, "lpq -P%p");
+                       lpcfg_string_set(ctx, &pService->lprm_command, "lprm -P%p %j");
+                       lpcfg_string_set(ctx, &pService->print_command, "lp -r -P%p %s");
+                       break;
+
+#if defined(DEVELOPER) || defined(ENABLE_SELFTEST)
+
+       case PRINT_TEST:
+       case PRINT_VLP: {
+               const char *tdbfile;
+               TALLOC_CTX *tmp_ctx = talloc_new(ctx);
+               const char *tmp;
+
+               tmp = lpcfg_parm_string(lp_ctx, NULL, "vlp", "tdbfile");
+               if (tmp == NULL) {
+                       tmp = "/tmp/vlp.tdb";
+               }
+
+               tdbfile = talloc_asprintf(tmp_ctx, "tdbfile=%s", tmp);
+               if (tdbfile == NULL) {
+                       tdbfile="tdbfile=/tmp/vlp.tdb";
+               }
+
+               tmp = talloc_asprintf(tmp_ctx, "vlp %s print %%p %%s",
+                                     tdbfile);
+               lpcfg_string_set(ctx, &pService->print_command,
+                          tmp ? tmp : "vlp print %p %s");
+
+               tmp = talloc_asprintf(tmp_ctx, "vlp %s lpq %%p",
+                                     tdbfile);
+               lpcfg_string_set(ctx, &pService->lpq_command,
+                          tmp ? tmp : "vlp lpq %p");
+
+               tmp = talloc_asprintf(tmp_ctx, "vlp %s lprm %%p %%j",
+                                     tdbfile);
+               lpcfg_string_set(ctx, &pService->lprm_command,
+                          tmp ? tmp : "vlp lprm %p %j");
+
+               tmp = talloc_asprintf(tmp_ctx, "vlp %s lppause %%p %%j",
+                                     tdbfile);
+               lpcfg_string_set(ctx, &pService->lppause_command,
+                          tmp ? tmp : "vlp lppause %p %j");
+
+               tmp = talloc_asprintf(tmp_ctx, "vlp %s lpresume %%p %%j",
+                                     tdbfile);
+               lpcfg_string_set(ctx, &pService->lpresume_command,
+                          tmp ? tmp : "vlp lpresume %p %j");
+
+               tmp = talloc_asprintf(tmp_ctx, "vlp %s queuepause %%p",
+                                     tdbfile);
+               lpcfg_string_set(ctx, &pService->queuepause_command,
+                          tmp ? tmp : "vlp queuepause %p");
+
+               tmp = talloc_asprintf(tmp_ctx, "vlp %s queueresume %%p",
+                                     tdbfile);
+               lpcfg_string_set(ctx, &pService->queueresume_command,
+                          tmp ? tmp : "vlp queueresume %p");
+               TALLOC_FREE(tmp_ctx);
+
+               break;
+       }
+#endif /* DEVELOPER */
+
+       }
+}
 
 /**
  * Unload unused services.
@@ -2189,6 +2417,11 @@ void lpcfg_killunused(struct loadparm_context *lp_ctx,
                   bool (*snumused) (struct smbsrv_connection *, int))
 {
        int i;
+
+       if (lp_ctx->s3_fns != NULL) {
+               smb_panic("Cannot be used from an s3 loadparm ctx");
+       }
+
        for (i = 0; i < lp_ctx->iNumServices; i++) {
                if (lp_ctx->services[i] == NULL)
                        continue;
@@ -2225,6 +2458,23 @@ static int lpcfg_destructor(struct loadparm_context *lp_ctx)
        return 0;
 }
 
+struct defaults_hook_data {
+       const char *name;
+       lpcfg_defaults_hook hook;
+       struct defaults_hook_data *prev, *next;
+} *defaults_hooks = NULL;
+
+
+bool lpcfg_register_defaults_hook(const char *name, lpcfg_defaults_hook hook)
+{
+       struct defaults_hook_data *hook_data = talloc(talloc_autofree_context(),
+                                                                                                 struct defaults_hook_data);
+       hook_data->name = talloc_strdup(hook_data, name);
+       hook_data->hook = hook;
+       DLIST_ADD(defaults_hooks, hook_data);
+       return false;
+}
+
 /**
  * Initialise the global parameter structure.
  *
@@ -2237,6 +2487,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        struct loadparm_context *lp_ctx;
        struct parmlist_entry *parm;
        char *logfile;
+       struct defaults_hook_data *defaults_hook;
 
        lp_ctx = talloc_zero(mem_ctx, struct loadparm_context);
        if (lp_ctx == NULL)
@@ -2250,8 +2501,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lp_ctx->sDefault = talloc_zero(lp_ctx, struct loadparm_service);
        lp_ctx->flags = talloc_zero_array(lp_ctx, unsigned int, num_parameters());
 
-       lp_ctx->sDefault->iMaxPrintJobs = 1000;
-       lp_ctx->sDefault->bAvailable = true;
+       lp_ctx->sDefault->max_print_jobs = 1000;
+       lp_ctx->sDefault->available = true;
        lp_ctx->sDefault->browseable = true;
        lp_ctx->sDefault->read_only = true;
        lp_ctx->sDefault->map_archive = true;
@@ -2268,13 +2519,16 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
                if ((parm_table[i].type == P_STRING ||
                     parm_table[i].type == P_USTRING) &&
                    !(lp_ctx->flags[i] & FLAG_CMDLINE)) {
+                       TALLOC_CTX *parent_mem;
                        char **r;
                        if (parm_table[i].p_class == P_LOCAL) {
+                               parent_mem = lp_ctx->sDefault;
                                r = (char **)(((char *)lp_ctx->sDefault) + parm_table[i].offset);
                        } else {
+                               parent_mem = lp_ctx->globals;
                                r = (char **)(((char *)lp_ctx->globals) + parm_table[i].offset);
                        }
-                       *r = talloc_strdup(lp_ctx, "");
+                       lpcfg_string_set(parent_mem, r, "");
                }
        }
 
@@ -2315,7 +2569,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "ntvfs handler", "unixuid default");
        lpcfg_do_global_parameter(lp_ctx, "max connections", "0");
 
-       lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper wkssvc rpcecho samr netlogon lsarpc spoolss drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver");
+       lpcfg_do_global_parameter(lp_ctx, "dcerpc endpoint servers", "epmapper wkssvc rpcecho samr netlogon lsarpc drsuapi dssetup unixinfo browser eventlog6 backupkey dnsserver");
        lpcfg_do_global_parameter(lp_ctx, "server services", "s3fs rpc nbt wrepl ldap cldap kdc drepl winbindd ntp_signd kcc dnsupdate dns");
        lpcfg_do_global_parameter(lp_ctx, "kccsrv:samba_kcc", "true");
        /* the winbind method for domain controllers is for both RODC
@@ -2359,7 +2613,9 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        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, "client max protocol", "default");
+       lpcfg_do_global_parameter(lp_ctx, "client ipc min protocol", "default");
+       lpcfg_do_global_parameter(lp_ctx, "client ipc max protocol", "default");
        lpcfg_do_global_parameter(lp_ctx, "security", "AUTO");
        lpcfg_do_global_parameter(lp_ctx, "EncryptPasswords", "True");
        lpcfg_do_global_parameter(lp_ctx, "ReadRaw", "True");
@@ -2374,9 +2630,12 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "ClientLanManAuth", "False");
        lpcfg_do_global_parameter(lp_ctx, "ClientNTLMv2Auth", "True");
        lpcfg_do_global_parameter(lp_ctx, "LanmanAuth", "False");
-       lpcfg_do_global_parameter(lp_ctx, "NTLMAuth", "True");
+       lpcfg_do_global_parameter(lp_ctx, "NTLMAuth", "False");
+       lpcfg_do_global_parameter(lp_ctx, "RawNTLMv2Auth", "False");
        lpcfg_do_global_parameter(lp_ctx, "client use spnego principal", "False");
 
+       lpcfg_do_global_parameter(lp_ctx, "allow dcerpc auth level connect", "False");
+
        lpcfg_do_global_parameter(lp_ctx, "UnixExtensions", "True");
 
        lpcfg_do_global_parameter(lp_ctx, "PreferredMaster", "Auto");
@@ -2389,7 +2648,6 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "winbind sealed pipes", "True");
        lpcfg_do_global_parameter(lp_ctx, "require strong key", "True");
        lpcfg_do_global_parameter(lp_ctx, "winbindd socket directory", dyn_WINBINDD_SOCKET_DIR);
-       lpcfg_do_global_parameter(lp_ctx, "winbindd privileged socket directory", dyn_WINBINDD_PRIVILEGED_SOCKET_DIR);
        lpcfg_do_global_parameter(lp_ctx, "ntp signd socket directory", dyn_NTP_SIGND_SOCKET_DIR);
        lpcfg_do_global_parameter_var(lp_ctx, "dns update command", "%s/samba_dnsupdate", dyn_SCRIPTSBINDIR);
        lpcfg_do_global_parameter_var(lp_ctx, "spn update command", "%s/samba_spnupdate", dyn_SCRIPTSBINDIR);
@@ -2399,6 +2657,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "template homedir", "/home/%D/%U");
 
        lpcfg_do_global_parameter(lp_ctx, "client signing", "default");
+       lpcfg_do_global_parameter(lp_ctx, "client ipc signing", "default");
        lpcfg_do_global_parameter(lp_ctx, "server signing", "default");
 
        lpcfg_do_global_parameter(lp_ctx, "use spnego", "True");
@@ -2406,8 +2665,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        lpcfg_do_global_parameter(lp_ctx, "use mmap", "True");
 
        lpcfg_do_global_parameter(lp_ctx, "smb ports", "445 139");
-       lpcfg_do_global_parameter(lp_ctx, "nbt port", "137");
-       lpcfg_do_global_parameter(lp_ctx, "dgram port", "138");
+       lpcfg_do_global_parameter_var(lp_ctx, "nbt port", "%d", NBT_NAME_SERVICE_PORT);
+       lpcfg_do_global_parameter_var(lp_ctx, "dgram port", "%d", NBT_DGRAM_SERVICE_PORT);
        lpcfg_do_global_parameter(lp_ctx, "cldap port", "389");
        lpcfg_do_global_parameter(lp_ctx, "krb5 port", "88");
        lpcfg_do_global_parameter(lp_ctx, "kpasswd port", "464");
@@ -2419,9 +2678,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        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 verify peer", "as_strict_as_possible");
        lpcfg_do_global_parameter(lp_ctx, "tls keyfile", "tls/key.pem");
        lpcfg_do_global_parameter(lp_ctx, "tls certfile", "tls/cert.pem");
        lpcfg_do_global_parameter(lp_ctx, "tls cafile", "tls/ca.pem");
+       lpcfg_do_global_parameter(lp_ctx, "tls priority", "NORMAL:-VERS-SSL3.0");
        lpcfg_do_global_parameter(lp_ctx, "prefork children:smb", "4");
 
        lpcfg_do_global_parameter(lp_ctx, "rndc command", "/usr/sbin/rndc");
@@ -2504,12 +2765,16 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        lpcfg_do_global_parameter(lp_ctx, "winbind reconnect delay", "30");
 
+       lpcfg_do_global_parameter(lp_ctx, "winbind request timeout", "60");
+
        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, "smbd profiling level", "off");
+
        lpcfg_do_global_parameter(lp_ctx, "winbind cache time", "300");
 
        lpcfg_do_global_parameter(lp_ctx, "level2 oplocks", "yes");
@@ -2518,7 +2783,7 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        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, "ldap page size", "1000");
 
        lpcfg_do_global_parameter(lp_ctx, "kernel share modes", "yes");
 
@@ -2548,13 +2813,17 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        lpcfg_do_global_parameter(lp_ctx, "ldap debug threshold", "10");
 
+       lpcfg_do_global_parameter(lp_ctx, "client ldap sasl wrapping", "sign");
+
+       lpcfg_do_global_parameter(lp_ctx, "ldap server require strong auth", "yes");
+
        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, "winbind expand groups", "0");
 
        lpcfg_do_global_parameter(lp_ctx, "stat cache", "yes");
 
@@ -2626,6 +2895,26 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
 
        lpcfg_do_global_parameter(lp_ctx, "printjob username", "%U");
 
+       lpcfg_do_global_parameter(lp_ctx, "aio max threads", "100");
+
+       lpcfg_do_global_parameter(lp_ctx, "smb2 leases", "yes");
+
+       lpcfg_do_global_parameter(lp_ctx, "kerberos encryption types", "all");
+
+       /* Allow modules to adjust defaults */
+       for (defaults_hook = defaults_hooks; defaults_hook;
+                defaults_hook = defaults_hook->next) {
+               bool ret;
+
+               ret = defaults_hook->hook(lp_ctx);
+               if (!ret) {
+                       DEBUG(1, ("Defaults hook %s failed to run.",
+                                         defaults_hook->name));
+                       talloc_free(lp_ctx);
+                       return NULL;
+               }
+       }
+
        for (i = 0; parm_table[i].label; i++) {
                if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
                        lp_ctx->flags[i] |= FLAG_DEFAULT;
@@ -2644,7 +2933,6 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
                }
        }
 
-
        return lp_ctx;
 }
 
@@ -2729,15 +3017,15 @@ static bool lpcfg_update(struct loadparm_context *lp_ctx)
        ZERO_STRUCT(settings);
        /* Add any more debug-related smb.conf parameters created in
         * future here */
-       settings.syslog = lp_ctx->globals->syslog;
-       settings.syslog_only = lp_ctx->globals->syslog_only;
        settings.timestamp_logs = lp_ctx->globals->timestamp_logs;
        settings.debug_prefix_timestamp = lp_ctx->globals->debug_prefix_timestamp;
        settings.debug_hires_timestamp = lp_ctx->globals->debug_hires_timestamp;
        settings.debug_pid = lp_ctx->globals->debug_pid;
        settings.debug_uid = lp_ctx->globals->debug_uid;
        settings.debug_class = lp_ctx->globals->debug_class;
-       debug_set_settings(&settings);
+       debug_set_settings(&settings, lp_ctx->globals->logging,
+                          lp_ctx->globals->syslog,
+                          lp_ctx->globals->syslog_only);
 
        /* FIXME: This is a bit of a hack, but we can't use a global, since 
         * not everything that uses lp also uses the socket library */
@@ -2792,7 +3080,7 @@ bool lpcfg_load(struct loadparm_context *lp_ctx, const char *filename)
 
        /* We get sections first, so have to start 'behind' to make up */
        lp_ctx->currentService = NULL;
-       bRetval = pm_process(n2, do_section, do_parameter, lp_ctx);
+       bRetval = pm_process(n2, do_section, lpcfg_do_parameter, lp_ctx);
 
        /* finish up the last section */
        DEBUG(4, ("pm_process() returned %s\n", BOOLSTR(bRetval)));
@@ -2847,7 +3135,7 @@ void lpcfg_dump(struct loadparm_context *lp_ctx, FILE *f, bool show_defaults,
                return;
        }
 
-       dump_globals(lp_ctx, f, show_defaults);
+       lpcfg_dump_globals(lp_ctx, f, show_defaults);
 
        lpcfg_dump_a_service(lp_ctx->sDefault, lp_ctx->sDefault, f, lp_ctx->flags, show_defaults);
 
@@ -2947,7 +3235,8 @@ const char *lpcfg_printername(struct loadparm_service *service, struct loadparm_
  */
 int lpcfg_maxprintjobs(struct loadparm_service *service, struct loadparm_service *sDefault)
 {
-       int maxjobs = (service != NULL) ? service->iMaxPrintJobs : sDefault->iMaxPrintJobs;
+       int maxjobs = lpcfg_max_print_jobs(service, sDefault);
+
        if (maxjobs <= 0 || maxjobs >= PRINT_MAX_JOBID)
                maxjobs = PRINT_MAX_JOBID - 1;
 
@@ -3029,6 +3318,48 @@ int lpcfg_security(struct loadparm_context *lp_ctx)
                                lpcfg__security(lp_ctx));
 }
 
+int lpcfg_client_max_protocol(struct loadparm_context *lp_ctx)
+{
+       int client_max_protocol = lpcfg__client_max_protocol(lp_ctx);
+       if (client_max_protocol == PROTOCOL_DEFAULT) {
+               return PROTOCOL_NT1;
+       }
+       return client_max_protocol;
+}
+
+int lpcfg_client_ipc_min_protocol(struct loadparm_context *lp_ctx)
+{
+       int client_ipc_min_protocol = lpcfg__client_ipc_min_protocol(lp_ctx);
+       if (client_ipc_min_protocol == PROTOCOL_DEFAULT) {
+               client_ipc_min_protocol = lpcfg_client_min_protocol(lp_ctx);
+       }
+       if (client_ipc_min_protocol < PROTOCOL_NT1) {
+               return PROTOCOL_NT1;
+       }
+       return client_ipc_min_protocol;
+}
+
+int lpcfg_client_ipc_max_protocol(struct loadparm_context *lp_ctx)
+{
+       int client_ipc_max_protocol = lpcfg__client_ipc_max_protocol(lp_ctx);
+       if (client_ipc_max_protocol == PROTOCOL_DEFAULT) {
+               return PROTOCOL_LATEST;
+       }
+       if (client_ipc_max_protocol < PROTOCOL_NT1) {
+               return PROTOCOL_NT1;
+       }
+       return client_ipc_max_protocol;
+}
+
+int lpcfg_client_ipc_signing(struct loadparm_context *lp_ctx)
+{
+       int client_ipc_signing = lpcfg__client_ipc_signing(lp_ctx);
+       if (client_ipc_signing == SMB_SIGNING_DEFAULT) {
+               return SMB_SIGNING_REQUIRED;
+       }
+       return client_ipc_signing;
+}
+
 bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandatory)
 {
        bool allowed = true;
@@ -3060,12 +3391,16 @@ bool lpcfg_server_signing_allowed(struct loadparm_context *lp_ctx, bool *mandato
        case SMB_SIGNING_REQUIRED:
                *mandatory = true;
                break;
+       case SMB_SIGNING_DESIRED:
        case SMB_SIGNING_IF_REQUIRED:
                break;
-       case SMB_SIGNING_DEFAULT:
        case SMB_SIGNING_OFF:
                allowed = false;
                break;
+       case SMB_SIGNING_DEFAULT:
+       case SMB_SIGNING_IPC_DEFAULT:
+               smb_panic(__location__);
+               break;
        }
 
        return allowed;