param: fix copy service to copy over cmdlist
[mat/samba.git] / lib / param / loadparm.c
index 809793d3ca144305698347d8b88bdfb5cab77e8c..bf2002264a61971187bb714b16f11be2cb5ea51c 100644 (file)
@@ -75,58 +75,7 @@ static bool defaults_saved = false;
 
 #include "lib/param/param_global.h"
 
-#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
-
-/* we don't need a special handler for "dos charset" and "unix charset" */
-#define handle_dos_charset NULL
-#define handle_charset NULL
-
-/* these are parameter handlers which are not needed in the
- * non-source3 code
- */
-#define handle_netbios_aliases NULL
-#define handle_printing NULL
-#define handle_ldap_debug_level NULL
-#define handle_idmap_backend NULL
-#define handle_idmap_uid NULL
-#define handle_idmap_gid NULL
-
-#ifndef N_
-#define N_(x) x
-#endif
-
-/* prototypes for the special type handlers */
-static bool handle_include(struct loadparm_context *lp_ctx, int unused,
-                          const char *pszParmValue, char **ptr);
-static bool handle_copy(struct loadparm_context *lp_ctx, int unused,
-                       const char *pszParmValue, char **ptr);
-
-#include "lib/param/param_table.c"
-
-/* local variables */
-struct loadparm_context {
-       const char *szConfigFile;
-       struct loadparm_global *globals;
-       struct loadparm_service **services;
-       struct loadparm_service *sDefault;
-       struct smb_iconv_handle *iconv_handle;
-       int iNumServices;
-       struct loadparm_service *currentService;
-       bool bInGlobalSection;
-       struct file_lists {
-               struct file_lists *next;
-               char *name;
-               char *subfname;
-               time_t modtime;
-       } *file_lists;
-       unsigned int flags[NUMPARAMETERS];
-       bool loaded;
-       bool refuse_free;
-       bool global; /* Is this the global context, which may set
-                     * global variables such as debug level etc? */
-       const struct loadparm_s3_helpers *s3_fns;
-};
-
+#define NUMPARAMETERS (num_parameters())
 
 struct loadparm_service *lpcfg_default_service(struct loadparm_context *lp_ctx)
 {
@@ -283,14 +232,10 @@ FN_LOCAL_BOOL(autoloaded, autoloaded)
 FN_GLOBAL_CONST_STRING(dnsdomain, dnsdomain)
 
 /* local prototypes */
-static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx,
+static struct loadparm_service *lpcfg_getservicebyname(struct loadparm_context *lp_ctx,
                                        const char *pszServiceName);
-static void copy_service(struct loadparm_service *pserviceDest,
-                        const struct loadparm_service *pserviceSource,
-                        struct bitmap *pcopymapDest);
 static bool lpcfg_service_ok(struct loadparm_service *service);
 static bool do_section(const char *pszSectionName, void *);
-static void init_copymap(struct loadparm_service *pservice);
 
 /* This is a helper function for parametrical options support. */
 /* It returns a pointer to parametrical option value if it exists or NULL otherwise */
@@ -307,7 +252,7 @@ const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
                return NULL;
 
        if (lp_ctx->s3_fns) {
-               return lp_ctx->s3_fns->get_parametric(service, type, option);
+               return lp_ctx->s3_fns->get_parametric(service, type, option, NULL);
        }
 
        data = (service == NULL ? lp_ctx->globals->param_opt : service->param_opt);
@@ -346,10 +291,10 @@ const char *lpcfg_get_parametric(struct loadparm_context *lp_ctx,
 /**
  * convenience routine to return int parameters.
  */
-static int lp_int(const char *s)
+int lp_int(const char *s)
 {
 
-       if (!s) {
+       if (!s || !*s) {
                DEBUG(0,("lp_int(%s): is called with NULL!\n",s));
                return -1;
        }
@@ -360,10 +305,10 @@ static int lp_int(const char *s)
 /**
  * convenience routine to return unsigned long parameters.
  */
-static unsigned long lp_ulong(const char *s)
+unsigned long lp_ulong(const char *s)
 {
 
-       if (!s) {
+       if (!s || !*s) {
                DEBUG(0,("lp_ulong(%s): is called with NULL!\n",s));
                return -1;
        }
@@ -402,11 +347,11 @@ static double lp_double(const char *s)
 /**
  * convenience routine to return boolean parameters.
  */
-static bool lp_bool(const char *s)
+bool lp_bool(const char *s)
 {
        bool ret = false;
 
-       if (!s) {
+       if (!s || !*s) {
                DEBUG(0,("lp_bool(%s): is called with NULL!\n",s));
                return false;
        }
@@ -419,7 +364,6 @@ static bool lp_bool(const char *s)
        return ret;
 }
 
-
 /**
  * Return parametric option from a given service. Type is a part of option before ':'
  * Parametric option has following syntax: 'Type: option = value'
@@ -581,7 +525,7 @@ bool lpcfg_string_set(TALLOC_CTX *mem_ctx, char **dest, const char *src)
  * Set a string value, deallocating any existing space, and allocing the space
  * for the string
  */
-bool lpcfg_string_set_upper(TALLOC_CTX *mem_ctx, char **dest, const char *src)
+static bool lpcfg_string_set_upper(TALLOC_CTX *mem_ctx, char **dest, const char *src)
 {
        talloc_free(*dest);
 
@@ -618,7 +562,7 @@ struct loadparm_service *lpcfg_add_service(struct loadparm_context *lp_ctx,
 
        /* it might already exist */
        if (name) {
-               struct loadparm_service *service = getservicebyname(lp_ctx,
+               struct loadparm_service *service = lpcfg_getservicebyname(lp_ctx,
                                                                    name);
                if (service != NULL) {
                        /* Clean all parametric options for service */
@@ -822,7 +766,7 @@ bool lpcfg_parm_is_cmdline(struct loadparm_context *lp_ctx, const char *name)
  * Find a service by name. Otherwise works like get_service.
  */
 
-static struct loadparm_service *getservicebyname(struct loadparm_context *lp_ctx,
+static struct loadparm_service *lpcfg_getservicebyname(struct loadparm_context *lp_ctx,
                                        const char *pszServiceName)
 {
        int iService;
@@ -902,9 +846,9 @@ void set_param_opt(TALLOC_CTX *mem_ctx,
  * If pcopymapDest is NULL then copy all fields
  */
 
-static void copy_service(struct loadparm_service *pserviceDest,
-                        const struct loadparm_service *pserviceSource,
-                        struct bitmap *pcopymapDest)
+void copy_service(struct loadparm_service *pserviceDest,
+                 const struct loadparm_service *pserviceSource,
+                 struct bitmap *pcopymapDest)
 {
        int i;
        bool bcopyall = (pcopymapDest == NULL);
@@ -946,6 +890,7 @@ static void copy_service(struct loadparm_service *pserviceDest,
                                                         (char **)dest_ptr,
                                                         *(const char * const *)src_ptr);
                                        break;
+                               case P_CMDLIST:
                                case P_LIST:
                                        TALLOC_FREE(*((char ***)dest_ptr));
                                        *(const char * const **)dest_ptr = (const char * const *)str_list_copy(pserviceDest,
@@ -1011,10 +956,10 @@ static bool lpcfg_service_ok(struct loadparm_service *service)
  it's date and needs to be reloaded.
 ********************************************************************/
 
-static void add_to_file_list(struct loadparm_context *lp_ctx,
+void add_to_file_list(TALLOC_CTX *mem_ctx, struct file_lists **list,
                             const char *fname, const char *subfname)
 {
-       struct file_lists *f = lp_ctx->file_lists;
+       struct file_lists *f = *list;
 
        while (f) {
                if (f->name && !strcmp(f->name, fname))
@@ -1023,27 +968,32 @@ static void add_to_file_list(struct loadparm_context *lp_ctx,
        }
 
        if (!f) {
-               f = talloc(lp_ctx, struct file_lists);
+               f = talloc(mem_ctx, struct file_lists);
                if (!f)
-                       return;
-               f->next = lp_ctx->file_lists;
+                       goto fail;
+               f->next = *list;
                f->name = talloc_strdup(f, fname);
                if (!f->name) {
-                       talloc_free(f);
-                       return;
+                       TALLOC_FREE(f);
+                       goto fail;
                }
                f->subfname = talloc_strdup(f, subfname);
                if (!f->subfname) {
-                       talloc_free(f);
-                       return;
+                       TALLOC_FREE(f);
+                       goto fail;
                }
-               lp_ctx->file_lists = f;
+               *list = f;
                f->modtime = file_modtime(subfname);
        } else {
                time_t t = file_modtime(subfname);
                if (t)
                        f->modtime = t;
        }
+       return;
+
+fail:
+       DEBUG(0, ("Unable to add file to file list: %s\n", fname));
+
 }
 
 /*******************************************************************
@@ -1077,6 +1027,26 @@ bool lpcfg_file_list_changed(struct loadparm_context *lp_ctx)
        return false;
 }
 
+/*
+ * set the value for a P_ENUM
+ */
+bool lp_set_enum_parm( struct parm_struct *parm, const char *pszParmValue,
+                              int *ptr )
+{
+       int i;
+
+       for (i = 0; parm->enum_list[i].name; i++) {
+               if ( strequal(pszParmValue, parm->enum_list[i].name)) {
+                       *ptr = parm->enum_list[i].value;
+                       return true;
+               }
+       }
+       DEBUG(0, ("WARNING: Ignoring invalid value '%s' for parameter '%s'\n",
+                 pszParmValue, parm->label));
+       return false;
+}
+
+
 /***************************************************************************
  Handle the "realm" parameter
 ***************************************************************************/
@@ -1115,12 +1085,18 @@ bool handle_realm(struct loadparm_context *lp_ctx, int unused,
  Handle the include operation.
 ***************************************************************************/
 
-static bool handle_include(struct loadparm_context *lp_ctx, int unused,
+bool handle_include(struct loadparm_context *lp_ctx, int unused,
                           const char *pszParmValue, char **ptr)
 {
-       char *fname = standard_sub_basic(lp_ctx, pszParmValue);
+       char *fname;
+
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_include(lp_ctx, unused, pszParmValue, ptr);
+       }
 
-       add_to_file_list(lp_ctx, pszParmValue, fname);
+       fname = standard_sub_basic(lp_ctx, pszParmValue);
+
+       add_to_file_list(lp_ctx, &lp_ctx->file_lists, pszParmValue, fname);
 
        lpcfg_string_set(lp_ctx, ptr, fname);
 
@@ -1136,25 +1112,38 @@ static bool handle_include(struct loadparm_context *lp_ctx, int unused,
  Handle the interpretation of the copy parameter.
 ***************************************************************************/
 
-static bool handle_copy(struct loadparm_context *lp_ctx, int unused,
+bool handle_copy(struct loadparm_context *lp_ctx, int snum,
                        const char *pszParmValue, char **ptr)
 {
        bool bRetval;
-       struct loadparm_service *serviceTemp;
-
-       lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+       struct loadparm_service *serviceTemp = NULL;
+       struct loadparm_service *current = NULL;
 
        bRetval = false;
 
        DEBUG(3, ("Copying service from service %s\n", pszParmValue));
 
-       if ((serviceTemp = getservicebyname(lp_ctx, pszParmValue)) != NULL) {
-               if (serviceTemp == lp_ctx->currentService) {
+       serviceTemp = lpcfg_getservicebyname(lp_ctx, pszParmValue);
+       if (lp_ctx->s3_fns != NULL) {
+               current = lp_ctx->s3_fns->get_servicebynum(snum);
+       } else {
+               current = lp_ctx->currentService;
+       }
+
+       if (current == NULL) {
+               DEBUG(0, ("Unable to copy service - invalid service destination"));
+               return false;
+       }
+
+       if (serviceTemp != NULL) {
+               if (serviceTemp == current) {
                        DEBUG(0, ("Can't copy service %s - unable to copy self!\n", pszParmValue));
                } else {
-                       copy_service(lp_ctx->currentService,
+                       copy_service(current,
                                     serviceTemp,
-                                    lp_ctx->currentService->copymap);
+                                    current->copymap);
+                       lpcfg_string_set(current, ptr, pszParmValue);
+
                        bRetval = true;
                }
        } else {
@@ -1191,11 +1180,158 @@ bool handle_logfile(struct loadparm_context *lp_ctx, int unused,
        return true;
 }
 
+/*
+ * These special charset handling methods only run in the source3 code.
+ */
+
+bool handle_charset(struct loadparm_context *lp_ctx, int snum,
+                       const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns) {
+               if (*ptr == NULL || strcmp(*ptr, pszParmValue) != 0) {
+                       lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
+                       global_iconv_handle = smb_iconv_handle_reinit(NULL,
+                                                       lpcfg_dos_charset(lp_ctx),
+                                                       lpcfg_unix_charset(lp_ctx),
+                                                       true, global_iconv_handle);
+               }
+
+               return true;
+       }
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+
+}
+
+bool handle_dos_charset(struct loadparm_context *lp_ctx, int snum,
+                       const char *pszParmValue, char **ptr)
+{
+       bool is_utf8 = false;
+       size_t len = strlen(pszParmValue);
+
+       if (lp_ctx->s3_fns) {
+               if (len == 4 || len == 5) {
+                       /* Don't use StrCaseCmp here as we don't want to
+                          initialize iconv. */
+                       if ((toupper_m(pszParmValue[0]) == 'U') &&
+                           (toupper_m(pszParmValue[1]) == 'T') &&
+                           (toupper_m(pszParmValue[2]) == 'F')) {
+                               if (len == 4) {
+                                       if (pszParmValue[3] == '8') {
+                                               is_utf8 = true;
+                                       }
+                               } else {
+                                       if (pszParmValue[3] == '-' &&
+                                           pszParmValue[4] == '8') {
+                                               is_utf8 = true;
+                                       }
+                               }
+                       }
+               }
+
+               if (*ptr == NULL || strcmp(*ptr, pszParmValue) != 0) {
+                       if (is_utf8) {
+                               DEBUG(0,("ERROR: invalid DOS charset: 'dos charset' must not "
+                                       "be UTF8, using (default value) %s instead.\n",
+                                       DEFAULT_DOS_CHARSET));
+                               pszParmValue = DEFAULT_DOS_CHARSET;
+                       }
+                       lp_ctx->s3_fns->lp_string_set(ptr, pszParmValue);
+                       global_iconv_handle = smb_iconv_handle_reinit(NULL,
+                                                       lpcfg_dos_charset(lp_ctx),
+                                                       lpcfg_unix_charset(lp_ctx),
+                                                       true, global_iconv_handle);
+               }
+               return true;
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
+bool handle_printing(struct loadparm_context *lp_ctx, int snum,
+                           const char *pszParmValue, char **ptr)
+{
+       static int parm_num = -1;
+       struct loadparm_service *s;
+
+       if (parm_num == -1) {
+               parm_num = lpcfg_map_parameter("printing");
+       }
+
+       if (!lp_set_enum_parm(&parm_table[parm_num], pszParmValue, (int*)ptr)) {
+               return false;
+       }
+
+       if (lp_ctx->s3_fns) {
+               if ( snum < 0 ) {
+                       s = lp_ctx->sDefault;
+                       lp_ctx->s3_fns->init_printer_values(lp_ctx->globals->ctx, s);
+               } else {
+                       s = lp_ctx->services[snum];
+                       lp_ctx->s3_fns->init_printer_values(s, s);
+               }
+       }
+
+       return true;
+}
+
+bool handle_ldap_debug_level(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       lp_ctx->globals->ldap_debug_level = lp_int(pszParmValue);
+
+       if (lp_ctx->s3_fns) {
+               lp_ctx->s3_fns->init_ldap_debugging();
+       }
+       return true;
+}
+
+bool handle_netbios_aliases(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       TALLOC_FREE(lp_ctx->globals->netbios_aliases);
+       lp_ctx->globals->netbios_aliases = (const char **)str_list_make_v3(lp_ctx->globals->ctx,
+                                                                          pszParmValue, NULL);
+
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->set_netbios_aliases(lp_ctx->globals->netbios_aliases);
+       }
+       return true;
+}
+
+/*
+ * idmap related parameters
+ */
+
+bool handle_idmap_backend(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : backend", pszParmValue);
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
+bool handle_idmap_uid(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : range", pszParmValue);
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
+bool handle_idmap_gid(struct loadparm_context *lp_ctx, int snum, const char *pszParmValue, char **ptr)
+{
+       if (lp_ctx->s3_fns) {
+               return lp_ctx->s3_fns->lp_do_parameter(snum, "idmap config * : range", pszParmValue);
+       }
+
+       return lpcfg_string_set(lp_ctx, ptr, pszParmValue);
+}
+
 /***************************************************************************
  Initialise a copymap.
 ***************************************************************************/
 
-static void init_copymap(struct loadparm_service *pservice)
+void init_copymap(struct loadparm_service *pservice)
 {
        int i;
 
@@ -1219,7 +1355,7 @@ static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
                                       const char *pszParmName,
                                       const char *pszParmValue, int flags)
 {
-       struct parmlist_entry *paramo, *data;
+       struct parmlist_entry **data;
        char *name;
        TALLOC_CTX *mem_ctx;
 
@@ -1231,43 +1367,14 @@ static bool lp_do_parameter_parametric(struct loadparm_context *lp_ctx,
        if (!name) return false;
 
        if (service == NULL) {
-               data = lp_ctx->globals->param_opt;
+               data = &lp_ctx->globals->param_opt;
                mem_ctx = lp_ctx->globals;
        } else {
-               data = service->param_opt;
+               data = &service->param_opt;
                mem_ctx = service;
        }
 
-       /* Traverse destination */
-       for (paramo=data; paramo; paramo=paramo->next) {
-               /* If we already have the option set, override it unless
-                  it was a command line option and the new one isn't */
-               if (strcmp(paramo->key, name) == 0) {
-                       if ((paramo->priority & FLAG_CMDLINE) &&
-                           !(flags & FLAG_CMDLINE)) {
-                               talloc_free(name);
-                               return true;
-                       }
-
-                       talloc_free(paramo->value);
-                       paramo->value = talloc_strdup(paramo, pszParmValue);
-                       paramo->priority = flags;
-                       talloc_free(name);
-                       return true;
-               }
-       }
-
-       paramo = talloc_zero(mem_ctx, struct parmlist_entry);
-       if (!paramo)
-               smb_panic("OOM");
-       paramo->key = talloc_strdup(paramo, name);
-       paramo->value = talloc_strdup(paramo, pszParmValue);
-       paramo->priority = flags;
-       if (service == NULL) {
-               DLIST_ADD(lp_ctx->globals->param_opt, paramo);
-       } else {
-               DLIST_ADD(service->param_opt, paramo);
-       }
+       set_param_opt(mem_ctx, data, name, pszParmValue, flags);
 
        talloc_free(name);
 
@@ -1388,19 +1495,7 @@ static bool set_variable(TALLOC_CTX *mem_ctx, int parmnum, void *parm_ptr,
                        break;
 
                case P_ENUM:
-                       for (i = 0; parm_table[parmnum].enum_list[i].name; i++) {
-                               if (strequal
-                                   (pszParmValue,
-                                    parm_table[parmnum].enum_list[i].name)) {
-                                       *(int *)parm_ptr =
-                                               parm_table[parmnum].
-                                               enum_list[i].value;
-                                       break;
-                               }
-                       }
-                       if (!parm_table[parmnum].enum_list[i].name) {
-                               DEBUG(0,("Unknown enumerated value '%s' for '%s'\n", 
-                                        pszParmValue, pszParmName));
+                       if (!lp_set_enum_parm(&parm_table[parmnum], pszParmValue, (int*)parm_ptr)) {
                                return false;
                        }
                        break;
@@ -1542,15 +1637,14 @@ bool lpcfg_set_cmdline(struct loadparm_context *lp_ctx, const char *pszParmName,
        int parmnum;
        int i;
 
+       while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
+
        if (lp_ctx->s3_fns) {
                return lp_ctx->s3_fns->set_cmdline(pszParmName, pszParmValue);
        }
 
        parmnum = lpcfg_map_parameter(pszParmName);
 
-       while (isspace((unsigned char)*pszParmValue)) pszParmValue++;
-
-
        if (parmnum < 0 && strchr(pszParmName, ':')) {
                /* set a parametric option */
                return lp_do_parameter_parametric(lp_ctx, NULL, pszParmName,
@@ -2000,7 +2094,10 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
        talloc_set_destructor(lp_ctx, lpcfg_destructor);
        lp_ctx->bInGlobalSection = true;
        lp_ctx->globals = talloc_zero(lp_ctx, struct loadparm_global);
+       /* This appears odd, but globals in s3 isn't a pointer */
+       lp_ctx->globals->ctx = lp_ctx->globals;
        lp_ctx->sDefault = talloc_zero(lp_ctx, struct loadparm_service);
+       lp_ctx->flags = talloc_zero_array(lp_ctx, unsigned int, NUMPARAMETERS);
 
        lp_ctx->sDefault->iMaxPrintJobs = 1000;
        lp_ctx->sDefault->bAvailable = true;
@@ -2531,7 +2628,7 @@ bool lpcfg_load(struct loadparm_context *lp_ctx, const char *filename)
        n2 = standard_sub_basic(lp_ctx, lp_ctx->szConfigFile);
        DEBUG(2, ("lpcfg_load: refreshing parameters from %s\n", n2));
 
-       add_to_file_list(lp_ctx, lp_ctx->szConfigFile, n2);
+       add_to_file_list(lp_ctx, &lp_ctx->file_lists, lp_ctx->szConfigFile, n2);
 
        /* We get sections first, so have to start 'behind' to make up */
        lp_ctx->currentService = NULL;