[s3]loadparm: refactor setting parametric options in list out
[kai/samba.git] / source3 / param / loadparm.c
index ad0605d70b2793bf92828ea807fe7bc4fb98d716..fda086cacff0783ca7675226e602193ab9b9b844 100644 (file)
@@ -52,6 +52,7 @@
  */
 
 #include "includes.h"
+#include "printing.h"
 
 bool bLoaded = False;
 
@@ -97,9 +98,8 @@ extern int extra_time_offset;
 
 static bool defaults_saved = False;
 
-typedef struct _param_opt_struct param_opt_struct;
-struct _param_opt_struct {
-       param_opt_struct *prev, *next;
+struct param_opt_struct {
+       struct param_opt_struct *prev, *next;
        char *key;
        char *value;
        char **list;
@@ -195,8 +195,7 @@ struct global {
        bool bWinbindOfflineLogon;
        bool bWinbindNormalizeNames;
        bool bWinbindRpcOnly;
-       char **szIdmapDomains;
-       char **szIdmapBackend; /* deprecated */
+       char *szIdmapBackend;
        char *szIdmapAllocBackend;
        char *szAddShareCommand;
        char *szChangeShareCommand;
@@ -242,6 +241,7 @@ struct global {
        int map_to_guest;
        int oplock_break_wait_time;
        int winbind_cache_time;
+       int winbind_reconnect_delay;
        int winbind_max_idle_children;
        char **szWinbindNssInfo;
        int iLockSpinTime;
@@ -274,6 +274,8 @@ struct global {
        int  iPreferredMaster;
        int iDomainMaster;
        bool bDomainLogons;
+       char **szInitLogonDelayedHosts;
+       int InitLogonDelay;
        bool bEncryptPasswords;
        bool bUpdateEncrypt;
        int  clientSchannel;
@@ -338,7 +340,8 @@ struct global {
        bool bResetOnZeroVC;
        int iKeepalive;
        int iminreceivefile;
-       param_opt_struct *param_opt;
+       struct param_opt_struct *param_opt;
+       int cups_connection_timeout;
 };
 
 static struct global Globals;
@@ -482,7 +485,7 @@ struct service {
        int iMap_readonly;
        int iDirectoryNameCacheSize;
        int ismb_encrypt;
-       param_opt_struct *param_opt;
+       struct param_opt_struct *param_opt;
 
        char dummy[3];          /* for alignment */
 };
@@ -1507,7 +1510,7 @@ static struct parm_struct parm_table[] = {
                .ptr            = &sDefault.bAclGroupControl,
                .special        = NULL,
                .enum_list      = NULL,
-               .flags          = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE | FLAG_DEPRECATED,
+               .flags          = FLAG_ADVANCED | FLAG_GLOBAL | FLAG_SHARE,
        },
        {
                .label          = "acl map full control",
@@ -2593,6 +2596,15 @@ static struct parm_struct parm_table[] = {
                .enum_list      = NULL,
                .flags          = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
        },
+       {
+               .label          = "cups connection timeout",
+               .type           = P_INTEGER,
+               .p_class        = P_GLOBAL,
+               .ptr            = &Globals.cups_connection_timeout,
+               .special        = NULL,
+               .enum_list      = NULL,
+               .flags          = FLAG_ADVANCED,
+       },
        {
                .label          = "iprint server",
                .type           = P_STRING,
@@ -3191,6 +3203,23 @@ static struct parm_struct parm_table[] = {
                .flags          = FLAG_ADVANCED,
        },
 
+       {
+               .label          = "init logon delayed hosts",
+               .type           = P_LIST,
+               .p_class        = P_GLOBAL,
+               .ptr            = &Globals.szInitLogonDelayedHosts,
+               .flags          = FLAG_ADVANCED,
+       },
+
+       {
+               .label          = "init logon delay",
+               .type           = P_INTEGER,
+               .p_class        = P_GLOBAL,
+               .ptr            = &Globals.InitLogonDelay,
+               .flags          = FLAG_ADVANCED,
+
+       },
+
        {N_("Browse Options"), P_SEP, P_SEPARATOR},
 
        {
@@ -4237,18 +4266,9 @@ static struct parm_struct parm_table[] = {
                .enum_list      = NULL,
                .flags          = FLAG_ADVANCED,
        },
-       {
-               .label          = "idmap domains",
-               .type           = P_LIST,
-               .p_class        = P_GLOBAL,
-               .ptr            = &Globals.szIdmapDomains,
-               .special        = NULL,
-               .enum_list      = NULL,
-               .flags          = FLAG_ADVANCED,
-       },
        {
                .label          = "idmap backend",
-               .type           = P_LIST,
+               .type           = P_STRING,
                .p_class        = P_GLOBAL,
                .ptr            = &Globals.szIdmapBackend,
                .special        = NULL,
@@ -4354,6 +4374,15 @@ static struct parm_struct parm_table[] = {
                .enum_list      = NULL,
                .flags          = FLAG_ADVANCED,
        },
+       {
+               .label          = "winbind reconnect delay",
+               .type           = P_INTEGER,
+               .p_class        = P_GLOBAL,
+               .ptr            = &Globals.winbind_reconnect_delay,
+               .special        = NULL,
+               .enum_list      = NULL,
+               .flags          = FLAG_ADVANCED,
+       },
        {
                .label          = "winbind enum users",
                .type           = P_BOOL,
@@ -4776,6 +4805,7 @@ static void init_globals(bool first_time_only)
         * to never expire, though, when this runs out the afs client will 
         * forget the token. Set to 0 to get NEVERDATE.*/
        Globals.iAfsTokenLifetime = 604800;
+       Globals.cups_connection_timeout = CUPS_DEFAULT_CONNECTION_TIMEOUT;
 
 /* these parameters are set to defaults that are more appropriate
    for the increasing samba install base:
@@ -4798,12 +4828,16 @@ static void init_globals(bool first_time_only)
        Globals.bWINSsupport = False;
        Globals.bWINSproxy = False;
 
+       TALLOC_FREE(Globals.szInitLogonDelayedHosts);
+       Globals.InitLogonDelay = 100; /* 100 ms default delay */
+
        Globals.bDNSproxy = True;
 
        /* this just means to use them if they exist */
        Globals.bKernelOplocks = True;
 
        Globals.bAllowTrustedDomains = True;
+       string_set(&Globals.szIdmapBackend, "tdb");
 
        string_set(&Globals.szTemplateShell, "/bin/false");
        string_set(&Globals.szTemplateHomedir, "/home/%D/%U");
@@ -4817,6 +4851,7 @@ static void init_globals(bool first_time_only)
        Globals.clustering = False;
 
        Globals.winbind_cache_time = 300;       /* 5 minutes */
+       Globals.winbind_reconnect_delay = 30;   /* 30 seconds */
        Globals.bWinbindEnumUsers = False;
        Globals.bWinbindEnumGroups = False;
        Globals.bWinbindUseDefaultDomain = False;
@@ -4827,7 +4862,7 @@ static void init_globals(bool first_time_only)
        Globals.bWinbindRefreshTickets = False;
        Globals.bWinbindOfflineLogon = False;
 
-       Globals.iIdmapCacheTime = 900; /* 15 minutes by default */
+       Globals.iIdmapCacheTime = 86400 * 7; /* a week by default */
        Globals.iIdmapNegativeCacheTime = 120; /* 2 minutes by default */
 
        Globals.bPassdbExpandExplicit = False;
@@ -5070,8 +5105,7 @@ FN_GLOBAL_BOOL(lp_winbind_offline_logon, &Globals.bWinbindOfflineLogon)
 FN_GLOBAL_BOOL(lp_winbind_normalize_names, &Globals.bWinbindNormalizeNames)
 FN_GLOBAL_BOOL(lp_winbind_rpc_only, &Globals.bWinbindRpcOnly)
 
-FN_GLOBAL_LIST(lp_idmap_domains, &Globals.szIdmapDomains)
-FN_GLOBAL_LIST(lp_idmap_backend, &Globals.szIdmapBackend) /* deprecated */
+FN_GLOBAL_CONST_STRING(lp_idmap_backend, &Globals.szIdmapBackend)
 FN_GLOBAL_STRING(lp_idmap_alloc_backend, &Globals.szIdmapAllocBackend)
 FN_GLOBAL_INTEGER(lp_idmap_cache_time, &Globals.iIdmapCacheTime)
 FN_GLOBAL_INTEGER(lp_idmap_negative_cache_time, &Globals.iIdmapNegativeCacheTime)
@@ -5110,6 +5144,8 @@ FN_GLOBAL_BOOL(lp_we_are_a_wins_server, &Globals.bWINSsupport)
 FN_GLOBAL_BOOL(lp_wins_proxy, &Globals.bWINSproxy)
 FN_GLOBAL_BOOL(lp_local_master, &Globals.bLocalMaster)
 FN_GLOBAL_BOOL(lp_domain_logons, &Globals.bDomainLogons)
+FN_GLOBAL_LIST(lp_init_logon_delayed_hosts, &Globals.szInitLogonDelayedHosts)
+FN_GLOBAL_INTEGER(lp_init_logon_delay, &Globals.InitLogonDelay)
 FN_GLOBAL_BOOL(lp_load_printers, &Globals.bLoadPrinters)
 FN_GLOBAL_BOOL(lp_readraw, &Globals.bReadRaw)
 FN_GLOBAL_BOOL(lp_large_readwrite, &Globals.bLargeReadwrite)
@@ -5211,6 +5247,7 @@ FN_GLOBAL_LIST(lp_svcctl_list, &Globals.szServicesList)
 FN_LOCAL_STRING(lp_cups_options, szCupsOptions)
 FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer)
 FN_GLOBAL_STRING(lp_iprint_server, &Globals.szIPrintServer)
+FN_GLOBAL_INTEGER(lp_cups_connection_timeout, &Globals.cups_connection_timeout)
 FN_GLOBAL_CONST_STRING(lp_ctdbd_socket, &Globals.ctdbdSocket)
 FN_GLOBAL_LIST(lp_cluster_addresses, &Globals.szClusterAddresses)
 FN_GLOBAL_BOOL(lp_clustering, &Globals.clustering)
@@ -5328,6 +5365,7 @@ FN_LOCAL_INTEGER(lp_directory_name_cache_size, iDirectoryNameCacheSize)
 FN_LOCAL_INTEGER(lp_smb_encrypt, ismb_encrypt)
 FN_LOCAL_CHAR(lp_magicchar, magic_char)
 FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time)
+FN_GLOBAL_INTEGER(lp_winbind_reconnect_delay, &Globals.winbind_reconnect_delay)
 FN_GLOBAL_LIST(lp_winbind_nss_info, &Globals.szWinbindNssInfo)
 FN_GLOBAL_INTEGER(lp_algorithmic_rid_base, &Globals.AlgorithmicRidBase)
 FN_GLOBAL_INTEGER(lp_name_cache_timeout, &Globals.name_cache_timeout)
@@ -5352,18 +5390,22 @@ static bool do_section(const char *pszSectionName, void *userdata);
 static void init_copymap(struct service *pservice);
 static bool hash_a_service(const char *name, int number);
 static void free_service_byindex(int iService);
+static void free_param_opts(struct param_opt_struct **popts);
 static char * canonicalize_servicename(const char *name);
 static void show_parameter(int parmIndex);
 static bool is_synonym_of(int parm1, int parm2, bool *inverse);
 
-/* This is a helper function for parametrical options support. */
-/* It returns a pointer to parametrical option value if it exists or NULL otherwise */
-/* Actual parametrical functions are quite simple */
-static param_opt_struct *get_parametrics(int snum, const char *type, const char *option)
+/*
+ * This is a helper function for parametrical options support.  It returns a
+ * pointer to parametrical option value if it exists or NULL otherwise. Actual
+ * parametrical functions are quite simple
+ */
+static struct param_opt_struct *get_parametrics(int snum, const char *type,
+                                               const char *option)
 {
        bool global_section = False;
        char* param_key;
-        param_opt_struct *data;
+        struct param_opt_struct *data;
        
        if (snum >= iNumServices) return NULL;
        
@@ -5380,7 +5422,7 @@ static param_opt_struct *get_parametrics(int snum, const char *type, const char
        }
 
        while (data) {
-               if (strcmp(data->key, param_key) == 0) {
+               if (strwicmp(data->key, param_key) == 0) {
                        string_free(&param_key);
                        return data;
                }
@@ -5392,7 +5434,7 @@ static param_opt_struct *get_parametrics(int snum, const char *type, const char
                /* but only if we are not already working with Globals */
                data = Globals.param_opt;
                while (data) {
-                       if (strcmp(data->key, param_key) == 0) {
+                       if (strwicmp(data->key, param_key) == 0) {
                                string_free(&param_key);
                                return data;
                        }
@@ -5497,7 +5539,7 @@ static int lp_enum(const char *s,const struct enum_list *_enum)
 /* the returned value is talloced on the talloc_tos() */
 char *lp_parm_talloc_string(int snum, const char *type, const char *option, const char *def)
 {
-       param_opt_struct *data = get_parametrics(snum, type, option);
+       struct param_opt_struct *data = get_parametrics(snum, type, option);
        
        if (data == NULL||data->value==NULL) {
                if (def) {
@@ -5514,7 +5556,7 @@ char *lp_parm_talloc_string(int snum, const char *type, const char *option, cons
 /* Parametric option has following syntax: 'Type: option = value' */
 const char *lp_parm_const_string(int snum, const char *type, const char *option, const char *def)
 {
-       param_opt_struct *data = get_parametrics(snum, type, option);
+       struct param_opt_struct *data = get_parametrics(snum, type, option);
        
        if (data == NULL||data->value==NULL)
                return def;
@@ -5527,7 +5569,7 @@ const char *lp_parm_const_string(int snum, const char *type, const char *option,
 
 const char **lp_parm_string_list(int snum, const char *type, const char *option, const char **def)
 {
-       param_opt_struct *data = get_parametrics(snum, type, option);
+       struct param_opt_struct *data = get_parametrics(snum, type, option);
 
        if (data == NULL||data->value==NULL)
                return (const char **)def;
@@ -5544,7 +5586,7 @@ const char **lp_parm_string_list(int snum, const char *type, const char *option,
 
 int lp_parm_int(int snum, const char *type, const char *option, int def)
 {
-       param_opt_struct *data = get_parametrics(snum, type, option);
+       struct param_opt_struct *data = get_parametrics(snum, type, option);
        
        if (data && data->value && *data->value)
                return lp_int(data->value);
@@ -5557,7 +5599,7 @@ int lp_parm_int(int snum, const char *type, const char *option, int def)
 
 unsigned long lp_parm_ulong(int snum, const char *type, const char *option, unsigned long def)
 {
-       param_opt_struct *data = get_parametrics(snum, type, option);
+       struct param_opt_struct *data = get_parametrics(snum, type, option);
        
        if (data && data->value && *data->value)
                return lp_ulong(data->value);
@@ -5570,7 +5612,7 @@ unsigned long lp_parm_ulong(int snum, const char *type, const char *option, unsi
 
 bool lp_parm_bool(int snum, const char *type, const char *option, bool def)
 {
-       param_opt_struct *data = get_parametrics(snum, type, option);
+       struct param_opt_struct *data = get_parametrics(snum, type, option);
        
        if (data && data->value && *data->value)
                return lp_bool(data->value);
@@ -5584,7 +5626,7 @@ bool lp_parm_bool(int snum, const char *type, const char *option, bool def)
 int lp_parm_enum(int snum, const char *type, const char *option,
                 const struct enum_list *_enum, int def)
 {
-       param_opt_struct *data = get_parametrics(snum, type, option);
+       struct param_opt_struct *data = get_parametrics(snum, type, option);
        
        if (data && data->value && *data->value && _enum)
                return lp_enum(data->value, _enum);
@@ -5603,6 +5645,35 @@ static void init_service(struct service *pservice)
        copy_service(pservice, &sDefault, NULL);
 }
 
+/**
+ * free a param_opts structure.
+ * param_opts handling should be moved to talloc;
+ * then this whole functions reduces to a TALLOC_FREE().
+ */
+
+static void free_param_opts(struct param_opt_struct **popts)
+{
+       struct param_opt_struct *opt, *next_opt;
+
+       if (popts == NULL) {
+               return;
+       }
+
+       if (*popts != NULL) {
+               DEBUG(5, ("Freeing parametrics:\n"));
+       }
+       opt = *popts;
+       while (opt != NULL) {
+               string_free(&opt->key);
+               string_free(&opt->value);
+               TALLOC_FREE(opt->list);
+               next_opt = opt->next;
+               SAFE_FREE(opt);
+               opt = next_opt;
+       }
+       *popts = NULL;
+}
+
 /***************************************************************************
  Free the dynamically allocated parts of a service struct.
 ***************************************************************************/
@@ -5610,7 +5681,6 @@ static void init_service(struct service *pservice)
 static void free_service(struct service *pservice)
 {
        int i;
-        param_opt_struct *data, *pdata;
        if (!pservice)
                return;
 
@@ -5636,18 +5706,7 @@ static void free_service(struct service *pservice)
                                                     &sDefault))));
        }
 
-       data = pservice->param_opt;
-       if (data)
-               DEBUG(5,("Freeing parametrics:\n"));
-       while (data) {
-               DEBUG(5,("[%s = %s]\n", data->key, data->value));
-               string_free(&data->key);
-               string_free(&data->value);
-               TALLOC_FREE(data->list);
-               pdata = data->next;
-               SAFE_FREE(data);
-               data = pdata;
-       }
+       free_param_opts(&pservice->param_opt);
 
        ZERO_STRUCTP(pservice);
 }
@@ -5689,7 +5748,6 @@ static int add_a_service(const struct service *pservice, const char *name)
        int i;
        struct service tservice;
        int num_to_alloc = iNumServices + 1;
-       param_opt_struct *data, *pdata;
 
        tservice = *pservice;
 
@@ -5699,16 +5757,7 @@ static int add_a_service(const struct service *pservice, const char *name)
                if (i >= 0) {
                        /* Clean all parametric options for service */
                        /* They will be added during parsing again */
-                       data = ServicePtrs[i]->param_opt;
-                       while (data) {
-                               string_free(&data->key);
-                               string_free(&data->value);
-                               TALLOC_FREE(data->list);
-                               pdata = data->next;
-                               SAFE_FREE(data);
-                               data = pdata;
-                       }
-                       ServicePtrs[i]->param_opt = NULL;
+                       free_param_opts(&ServicePtrs[i]->param_opt);
                        return (i);
                }
        }
@@ -6074,7 +6123,7 @@ static int map_parameter(const char *pszParmName)
 {
        int iIndex;
 
-       if (*pszParmName == '-')
+       if (*pszParmName == '-' && !strequal(pszParmName, "-valid"))
                return (-1);
 
        for (iIndex = 0; parm_table[iIndex].label; iIndex++)
@@ -6367,13 +6416,51 @@ static int getservicebyname(const char *pszServiceName, struct service *pservice
  If pcopymapDest is NULL then copy all fields
 ***************************************************************************/
 
+/**
+ * Add a parametric option to a param_opt_struct,
+ * replacing old value, if already present.
+ */
+static void set_param_opt(struct param_opt_struct **opt_list,
+                         const char *opt_name,
+                         const char *opt_value)
+{
+       struct param_opt_struct *new_opt, *opt;
+       bool not_added;
+
+       if (opt_list == NULL) {
+               return;
+       }
+
+       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) {
+                       string_free(&opt->value);
+                       TALLOC_FREE(opt->list);
+                       opt->value = SMB_STRDUP(opt_value);
+                       not_added = false;
+                       break;
+               }
+               opt = opt->next;
+       }
+       if (not_added) {
+           new_opt = SMB_XMALLOC_P(struct param_opt_struct);
+           new_opt->key = SMB_STRDUP(opt_name);
+           new_opt->value = SMB_STRDUP(opt_value);
+           new_opt->list = NULL;
+           DLIST_ADD(*opt_list, new_opt);
+       }
+}
+
 static void copy_service(struct service *pserviceDest, struct service *pserviceSource,
                         struct bitmap *pcopymapDest)
 {
        int i;
        bool bcopyall = (pcopymapDest == NULL);
-       param_opt_struct *data, *pdata, *paramo;
-       bool not_added;
+       struct param_opt_struct *data;
 
        for (i = 0; parm_table[i].label; i++)
                if (parm_table[i].ptr && parm_table[i].p_class == P_LOCAL &&
@@ -6431,27 +6518,7 @@ static void copy_service(struct service *pserviceDest, struct service *pserviceS
        
        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) {
-                               string_free(&pdata->value);
-                               TALLOC_FREE(data->list);
-                               pdata->value = SMB_STRDUP(data->value);
-                               not_added = False;
-                               break;
-                       }
-                       pdata = pdata->next;
-               }
-               if (not_added) {
-                   paramo = SMB_XMALLOC_P(param_opt_struct);
-                   paramo->key = SMB_STRDUP(data->key);
-                   paramo->value = SMB_STRDUP(data->value);
-                   paramo->list = NULL;
-                   DLIST_ADD(pserviceDest->param_opt, paramo);
-               }
+               set_param_opt(&pserviceDest->param_opt, data->key, data->value);
                data = data->next;
        }
 }
@@ -6519,7 +6586,7 @@ static struct smbconf_ctx *lp_smbconf_ctx(void)
        return conf_ctx;
 }
 
-static bool process_registry_service(struct smbconf_service *service)
+static bool process_smbconf_service(struct smbconf_service *service)
 {
        uint32_t count;
        bool ret;
@@ -6575,7 +6642,7 @@ static bool process_registry_globals(void)
                goto done;
        }
 
-       ret = process_registry_service(service);
+       ret = process_smbconf_service(service);
        if (!ret) {
                goto done;
        }
@@ -6613,7 +6680,7 @@ static bool process_registry_shares(void)
                if (strequal(service[count]->name, GLOBAL_NAME)) {
                        continue;
                }
-               ret = process_registry_service(service[count]);
+               ret = process_smbconf_service(service[count]);
                if (!ret) {
                        goto done;
                }
@@ -7045,9 +7112,11 @@ static void lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue
        for (i = 0; parm->enum_list[i].name; i++) {
                if ( strequal(pszParmValue, parm->enum_list[i].name)) {
                        *ptr = parm->enum_list[i].value;
-                       break;
+                       return;
                }
        }
+       DEBUG(0, ("WARNING: Ignoring invalid value '%s' for parameter '%s'\n",
+                 pszParmValue, parm->label));
 }
 
 /***************************************************************************
@@ -7111,65 +7180,33 @@ void *lp_local_ptr(int snum, void *ptr)
 
 bool lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue)
 {
-       int parmnum, i, slen;
+       int parmnum, i;
        void *parm_ptr = NULL;  /* where we are going to store the result */
        void *def_ptr = NULL;
-       char *param_key = NULL;
-       char *sep;
-       param_opt_struct *paramo, *data;
-       bool not_added;
+       struct param_opt_struct **opt_list;
 
        parmnum = map_parameter(pszParmName);
 
        if (parmnum < 0) {
-               if ((sep=strchr(pszParmName, ':')) != NULL) {
-                       TALLOC_CTX *frame = talloc_stackframe();
-
-                       *sep = '\0';
-                       param_key = talloc_asprintf(frame, "%s:", pszParmName);
-                       if (!param_key) {
-                               TALLOC_FREE(frame);
-                               return false;
-                       }
-                       slen = strlen(param_key);
-                       param_key = talloc_asprintf_append(param_key, sep+1);
-                       if (!param_key) {
-                               TALLOC_FREE(frame);
-                               return false;
-                       }
-                       trim_char(param_key+slen, ' ', ' ');
-                       not_added = True;
-                       data = (snum < 0) ? Globals.param_opt :
-                               ServicePtrs[snum]->param_opt;
-                       /* Traverse destination */
-                       while (data) {
-                               /* If we already have same option, override it */
-                               if (strcmp(data->key, param_key) == 0) {
-                                       string_free(&data->value);
-                                       TALLOC_FREE(data->list);
-                                       data->value = SMB_STRDUP(pszParmValue);
-                                       not_added = False;
-                                       break;
-                               }
-                               data = data->next;
-                       }
-                       if (not_added) {
-                               paramo = SMB_XMALLOC_P(param_opt_struct);
-                               paramo->key = SMB_STRDUP(param_key);
-                               paramo->value = SMB_STRDUP(pszParmValue);
-                               paramo->list = NULL;
-                               if (snum < 0) {
-                                       DLIST_ADD(Globals.param_opt, paramo);
-                               } else {
-                                       DLIST_ADD(ServicePtrs[snum]->param_opt, paramo);
-                               }
-                       }
+               TALLOC_CTX *frame;
 
-                       *sep = ':';
-                       TALLOC_FREE(frame);
+               if (strchr(pszParmName, ':') == NULL) {
+                       DEBUG(0, ("Ignoring unknown parameter \"%s\"\n",
+                                 pszParmName));
                        return (True);
                }
-               DEBUG(0, ("Ignoring unknown parameter \"%s\"\n", pszParmName));
+
+               /*
+                * We've got a parametric option
+                */
+
+               frame = talloc_stackframe();
+
+               opt_list = (snum < 0)
+                       ? &Globals.param_opt : &ServicePtrs[snum]->param_opt;
+               set_param_opt(opt_list, pszParmName, pszParmValue);
+
+               TALLOC_FREE(frame);
                return (True);
        }
 
@@ -7208,8 +7245,8 @@ bool lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue
 
        /* if it is a special case then go ahead */
        if (parm_table[parmnum].special) {
-               parm_table[parmnum].special(snum, pszParmValue, (char **)parm_ptr);
-               return (True);
+               return parm_table[parmnum].special(snum, pszParmValue,
+                                                  (char **)parm_ptr);
        }
 
        /* now switch on the type of variable it is */
@@ -7485,7 +7522,7 @@ Display the contents of the global structure.
 static void dump_globals(FILE *f)
 {
        int i;
-       param_opt_struct *data;
+       struct param_opt_struct *data;
        
        fprintf(f, "[global]\n");
 
@@ -7529,7 +7566,7 @@ bool lp_is_default(int snum, struct parm_struct *parm)
 static void dump_a_service(struct service *pService, FILE * f)
 {
        int i;
-       param_opt_struct *data;
+       struct param_opt_struct *data;
        
        if (pService != &sDefault)
                fprintf(f, "[%s]\n", pService->szService);
@@ -8682,6 +8719,7 @@ void gfree_loadparm(void)
                SAFE_FREE( f );
                f = next;
        }
+       file_lists = NULL;
 
        /* Free resources allocated to services */
 
@@ -8728,9 +8766,6 @@ bool lp_is_in_client(void)
     return in_client;
 }
 
-
-
-
 /***************************************************************************
  Load the services array from the services file. Return True on success, 
  False on failure.
@@ -8746,7 +8781,6 @@ bool lp_load_ex(const char *pszFname,
 {
        char *n2 = NULL;
        bool bRetval;
-       param_opt_struct *data, *pdata;
 
        bRetval = False;
 
@@ -8764,22 +8798,11 @@ bool lp_load_ex(const char *pszFname,
                lp_save_defaults();
        }
 
+       free_param_opts(&Globals.param_opt);
+
        /* We get sections first, so have to start 'behind' to make up */
        iServiceIndex = -1;
 
-       if (Globals.param_opt != NULL) {
-               data = Globals.param_opt;
-               while (data) {
-                       string_free(&data->key);
-                       string_free(&data->value);
-                       TALLOC_FREE(data->list);
-                       pdata = data->next;
-                       SAFE_FREE(data);
-                       data = pdata;
-               }
-               Globals.param_opt = NULL;
-       }
-
        if (lp_config_backend_is_file()) {
                n2 = alloc_sub_basic(get_current_username(),
                                        current_user_info.domain,
@@ -8902,15 +8925,6 @@ bool lp_load_with_registry_shares(const char *pszFname,
                          true);
 }
 
-/***************************************************************************
- Reset the max number of services.
-***************************************************************************/
-
-void lp_resetnumservices(void)
-{
-       iNumServices = 0;
-}
-
 /***************************************************************************
  Return the max number of services.
 ***************************************************************************/