diff options
Diffstat (limited to 'source3/lib/smbconf')
-rw-r--r-- | source3/lib/smbconf/smbconf.c | 388 | ||||
-rw-r--r-- | source3/lib/smbconf/smbconf.h | 114 | ||||
-rw-r--r-- | source3/lib/smbconf/smbconf_init.c | 95 | ||||
-rw-r--r-- | source3/lib/smbconf/smbconf_private.h | 85 | ||||
-rw-r--r-- | source3/lib/smbconf/smbconf_reg.c | 1148 | ||||
-rw-r--r-- | source3/lib/smbconf/smbconf_txt.c | 641 | ||||
-rw-r--r-- | source3/lib/smbconf/smbconf_util.c | 151 | ||||
-rw-r--r-- | source3/lib/smbconf/testsuite.c | 283 |
8 files changed, 2905 insertions, 0 deletions
diff --git a/source3/lib/smbconf/smbconf.c b/source3/lib/smbconf/smbconf.c new file mode 100644 index 0000000000..1a9b4e07f9 --- /dev/null +++ b/source3/lib/smbconf/smbconf.c @@ -0,0 +1,388 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library + * Copyright (C) Michael Adam 2007-2008 + * Copyright (C) Guenther Deschner 2007 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "smbconf_private.h" + +/********************************************************************** + * + * internal helper functions + * + **********************************************************************/ + +static WERROR smbconf_global_check(struct smbconf_ctx *ctx) +{ + if (!smbconf_share_exists(ctx, GLOBAL_NAME)) { + return smbconf_create_share(ctx, GLOBAL_NAME); + } + return WERR_OK; +} + + +/********************************************************************** + * + * The actual libsmbconf API functions that are exported. + * + **********************************************************************/ + +/** + * Close the configuration. + */ +void smbconf_shutdown(struct smbconf_ctx *ctx) +{ + TALLOC_FREE(ctx); +} + +/** + * Detect changes in the configuration. + * The given csn struct is filled with the current csn. + * smbconf_changed() can also be used for initial retrieval + * of the csn. + */ +bool smbconf_changed(struct smbconf_ctx *ctx, struct smbconf_csn *csn, + const char *service, const char *param) +{ + struct smbconf_csn old_csn; + + if (csn == NULL) { + return false; + } + + old_csn = *csn; + + ctx->ops->get_csn(ctx, csn, service, param); + return (csn->csn != old_csn.csn); +} + +/** + * Drop the whole configuration (restarting empty). + */ +WERROR smbconf_drop(struct smbconf_ctx *ctx) +{ + return ctx->ops->drop(ctx); +} + +/** + * Get the whole configuration as lists of strings with counts: + * + * num_shares : number of shares + * share_names : list of length num_shares of share names + * num_params : list of length num_shares of parameter counts for each share + * param_names : list of lists of parameter names for each share + * param_values : list of lists of parameter values for each share + */ +WERROR smbconf_get_config(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + struct smbconf_service ***services) +{ + WERROR werr = WERR_OK; + TALLOC_CTX *tmp_ctx = NULL; + uint32_t tmp_num_shares; + char **tmp_share_names; + struct smbconf_service **tmp_services; + uint32_t count; + + if ((num_shares == NULL) || (services == NULL)) { + werr = WERR_INVALID_PARAM; + goto done; + } + + tmp_ctx = talloc_stackframe(); + + werr = smbconf_get_share_names(ctx, tmp_ctx, &tmp_num_shares, + &tmp_share_names); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + tmp_services = TALLOC_ARRAY(tmp_ctx, struct smbconf_service *, + tmp_num_shares); + + if (tmp_services == NULL) { + werr = WERR_NOMEM; + goto done; + } + + for (count = 0; count < tmp_num_shares; count++) { + werr = smbconf_get_share(ctx, tmp_services, + tmp_share_names[count], + &tmp_services[count]); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + } + + werr = WERR_OK; + + *num_shares = tmp_num_shares; + if (tmp_num_shares > 0) { + *services = talloc_move(mem_ctx, &tmp_services); + } else { + *services = NULL; + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +/** + * get the list of share names defined in the configuration. + */ +WERROR smbconf_get_share_names(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + char ***share_names) +{ + return ctx->ops->get_share_names(ctx, mem_ctx, num_shares, + share_names); +} + +/** + * check if a share/service of a given name exists + */ +bool smbconf_share_exists(struct smbconf_ctx *ctx, + const char *servicename) +{ + return ctx->ops->share_exists(ctx, servicename); +} + +/** + * Add a service if it does not already exist. + */ +WERROR smbconf_create_share(struct smbconf_ctx *ctx, + const char *servicename) +{ + if ((servicename != NULL) && smbconf_share_exists(ctx, servicename)) { + return WERR_ALREADY_EXISTS; + } + + return ctx->ops->create_share(ctx, servicename); +} + +/** + * get a definition of a share (service) from configuration. + */ +WERROR smbconf_get_share(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *servicename, + struct smbconf_service **service) +{ + if (!smbconf_share_exists(ctx, servicename)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->get_share(ctx, mem_ctx, servicename, service); +} + +/** + * delete a service from configuration + */ +WERROR smbconf_delete_share(struct smbconf_ctx *ctx, const char *servicename) +{ + if (!smbconf_share_exists(ctx, servicename)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->delete_share(ctx, servicename); +} + +/** + * set a configuration parameter to the value provided. + */ +WERROR smbconf_set_parameter(struct smbconf_ctx *ctx, + const char *service, + const char *param, + const char *valstr) +{ + if (!smbconf_share_exists(ctx, service)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->set_parameter(ctx, service, param, valstr); +} + +/** + * Set a global parameter + * (i.e. a parameter in the [global] service). + * + * This also creates [global] when it does not exist. + */ +WERROR smbconf_set_global_parameter(struct smbconf_ctx *ctx, + const char *param, const char *val) +{ + WERROR werr; + + werr = smbconf_global_check(ctx); + if (W_ERROR_IS_OK(werr)) { + werr = smbconf_set_parameter(ctx, GLOBAL_NAME, param, val); + } + + return werr; +} + +/** + * get the value of a configuration parameter as a string + */ +WERROR smbconf_get_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + const char *param, + char **valstr) +{ + if (valstr == NULL) { + return WERR_INVALID_PARAM; + } + + if (!smbconf_share_exists(ctx, service)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->get_parameter(ctx, mem_ctx, service, param, valstr); +} + +/** + * Get the value of a global parameter. + * + * Create [global] if it does not exist. + */ +WERROR smbconf_get_global_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *param, + char **valstr) +{ + WERROR werr; + + werr = smbconf_global_check(ctx); + if (W_ERROR_IS_OK(werr)) { + werr = smbconf_get_parameter(ctx, mem_ctx, GLOBAL_NAME, param, + valstr); + } + + return werr; +} + +/** + * delete a parameter from configuration + */ +WERROR smbconf_delete_parameter(struct smbconf_ctx *ctx, + const char *service, const char *param) +{ + if (!smbconf_share_exists(ctx, service)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->delete_parameter(ctx, service, param); +} + +/** + * Delete a global parameter. + * + * Create [global] if it does not exist. + */ +WERROR smbconf_delete_global_parameter(struct smbconf_ctx *ctx, + const char *param) +{ + WERROR werr; + + werr = smbconf_global_check(ctx); + if (W_ERROR_IS_OK(werr)) { + werr = smbconf_delete_parameter(ctx, GLOBAL_NAME, param); + } + + return werr; +} + +WERROR smbconf_get_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + uint32_t *num_includes, char ***includes) +{ + if (!smbconf_share_exists(ctx, service)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->get_includes(ctx, mem_ctx, service, num_includes, + includes); +} + +WERROR smbconf_get_global_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_includes, char ***includes) +{ + WERROR werr; + + werr = smbconf_global_check(ctx); + if (W_ERROR_IS_OK(werr)) { + werr = smbconf_get_includes(ctx, mem_ctx, GLOBAL_NAME, + num_includes, includes); + } + + return werr; +} + +WERROR smbconf_set_includes(struct smbconf_ctx *ctx, + const char *service, + uint32_t num_includes, const char **includes) +{ + if (!smbconf_share_exists(ctx, service)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->set_includes(ctx, service, num_includes, includes); +} + +WERROR smbconf_set_global_includes(struct smbconf_ctx *ctx, + uint32_t num_includes, + const char **includes) +{ + WERROR werr; + + werr = smbconf_global_check(ctx); + if (W_ERROR_IS_OK(werr)) { + werr = smbconf_set_includes(ctx, GLOBAL_NAME, + num_includes, includes); + } + + return werr; +} + + +WERROR smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service) +{ + if (!smbconf_share_exists(ctx, service)) { + return WERR_NO_SUCH_SERVICE; + } + + return ctx->ops->delete_includes(ctx, service); +} + +WERROR smbconf_delete_global_includes(struct smbconf_ctx *ctx) +{ + WERROR werr; + + werr = smbconf_global_check(ctx); + if (W_ERROR_IS_OK(werr)) { + werr = smbconf_delete_includes(ctx, GLOBAL_NAME); + } + + return werr; +} diff --git a/source3/lib/smbconf/smbconf.h b/source3/lib/smbconf/smbconf.h new file mode 100644 index 0000000000..e337476665 --- /dev/null +++ b/source3/lib/smbconf/smbconf.h @@ -0,0 +1,114 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library + * Copyright (C) Michael Adam 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __LIBSMBCONF_H__ +#define __LIBSMBCONF_H__ + +struct smbconf_ctx; + +/* the change sequence number */ +struct smbconf_csn { + uint64_t csn; +}; + +struct smbconf_service { + char *name; + uint32_t num_params; + char **param_names; + char **param_values; +}; + + +/** + * intialization dispatcher function. + * takes source string in the form of "backend:path" + */ +WERROR smbconf_init(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx, + const char *source); + +/** + * initialization functions for the available modules + */ + +WERROR smbconf_init_reg(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx, + const char *path); + +WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx, + struct smbconf_ctx **conf_ctx, + const char *path); + +/* + * the smbconf API functions + */ +void smbconf_shutdown(struct smbconf_ctx *ctx); +bool smbconf_changed(struct smbconf_ctx *ctx, struct smbconf_csn *csn, + const char *service, const char *param); +WERROR smbconf_drop(struct smbconf_ctx *ctx); +WERROR smbconf_get_config(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + struct smbconf_service ***services); +WERROR smbconf_get_share_names(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + char ***share_names); +bool smbconf_share_exists(struct smbconf_ctx *ctx, const char *servicename); +WERROR smbconf_create_share(struct smbconf_ctx *ctx, const char *servicename); +WERROR smbconf_get_share(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *servicename, + struct smbconf_service **service); +WERROR smbconf_delete_share(struct smbconf_ctx *ctx, + const char *servicename); +WERROR smbconf_set_parameter(struct smbconf_ctx *ctx, + const char *service, + const char *param, + const char *valstr); +WERROR smbconf_set_global_parameter(struct smbconf_ctx *ctx, + const char *param, const char *val); +WERROR smbconf_get_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + const char *param, + char **valstr); +WERROR smbconf_get_global_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *param, + char **valstr); +WERROR smbconf_delete_parameter(struct smbconf_ctx *ctx, + const char *service, const char *param); +WERROR smbconf_delete_global_parameter(struct smbconf_ctx *ctx, + const char *param); +WERROR smbconf_get_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + uint32_t *num_includes, char ***includes); +WERROR smbconf_get_global_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_includes, char ***includes); +WERROR smbconf_set_includes(struct smbconf_ctx *ctx, + const char *service, + uint32_t num_includes, const char **includes); +WERROR smbconf_set_global_includes(struct smbconf_ctx *ctx, + uint32_t num_includes, + const char **includes); +WERROR smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service); +WERROR smbconf_delete_global_includes(struct smbconf_ctx *ctx); + +#endif /* _LIBSMBCONF_H_ */ diff --git a/source3/lib/smbconf/smbconf_init.c b/source3/lib/smbconf/smbconf_init.c new file mode 100644 index 0000000000..4efc440819 --- /dev/null +++ b/source3/lib/smbconf/smbconf_init.c @@ -0,0 +1,95 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library, init dispatcher + * Copyright (C) Michael Adam 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "smbconf_private.h" + +#define INCLUDES_VALNAME "includes" + + +/** + * smbconf initialization dispatcher + * + * this takes a configuration source in the form of + * backend:path and calles the appropriate backend + * init function with the path argument + * + * known backends: + * - "registry" or "reg" + * - "txt" or "file" + */ +WERROR smbconf_init(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx, + const char *source) +{ + WERROR werr; + char *backend = NULL; + char *path = NULL; + char *sep; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + if (conf_ctx == NULL) { + werr = WERR_INVALID_PARAM; + goto done; + } + + if ((source == NULL) || (*source == '\0')) { + werr = WERR_INVALID_PARAM; + goto done; + } + + backend = talloc_strdup(tmp_ctx, source); + if (backend == NULL) { + werr = WERR_NOMEM; + goto done; + } + + sep = strchr(backend, ':'); + if (sep != NULL) { + *sep = '\0'; + path = sep + 1; + if (strlen(path) == 0) { + path = NULL; + } + } + + if (strequal(backend, "registry") || strequal(backend, "reg")) { + werr = smbconf_init_reg(mem_ctx, conf_ctx, path); + } else if (strequal(backend, "file") || strequal(backend, "txt")) { + werr = smbconf_init_txt(mem_ctx, conf_ctx, path); + } else if (sep == NULL) { + /* + * If no separator was given in the source, and the string is + * not a know backend, assume file backend and use the source + * string as a path argument. + */ + werr = smbconf_init_txt(mem_ctx, conf_ctx, backend); + } else { + /* + * Separator was specified but this is not a known backend. + * Can't handle this. + */ + DEBUG(1, ("smbconf_init: ERROR - unknown backend '%s' given\n", + backend)); + werr = WERR_INVALID_PARAM; + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} diff --git a/source3/lib/smbconf/smbconf_private.h b/source3/lib/smbconf/smbconf_private.h new file mode 100644 index 0000000000..8e7d6a9983 --- /dev/null +++ b/source3/lib/smbconf/smbconf_private.h @@ -0,0 +1,85 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library + * Copyright (C) Michael Adam 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __LIBSMBCONF_PRIVATE_H__ +#define __LIBSMBCONF_PRIVATE_H__ + +struct smbconf_ops { + WERROR (*init)(struct smbconf_ctx *ctx, const char *path); + int (*shutdown)(struct smbconf_ctx *ctx); + WERROR (*open_conf)(struct smbconf_ctx *ctx); + int (*close_conf)(struct smbconf_ctx *ctx); + void (*get_csn)(struct smbconf_ctx *ctx, struct smbconf_csn *csn, + const char *service, const char *param); + WERROR (*drop)(struct smbconf_ctx *ctx); + WERROR (*get_share_names)(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + char ***share_names); + bool (*share_exists)(struct smbconf_ctx *ctx, const char *service); + WERROR (*create_share)(struct smbconf_ctx *ctx, const char *service); + WERROR (*get_share)(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *servicename, + struct smbconf_service **service); + WERROR (*delete_share)(struct smbconf_ctx *ctx, + const char *servicename); + WERROR (*set_parameter)(struct smbconf_ctx *ctx, + const char *service, + const char *param, + const char *valstr); + WERROR (*get_parameter)(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + const char *param, + char **valstr); + WERROR (*delete_parameter)(struct smbconf_ctx *ctx, + const char *service, const char *param); + WERROR (*get_includes)(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + uint32_t *num_includes, char ***includes); + WERROR (*set_includes)(struct smbconf_ctx *ctx, + const char *service, + uint32_t num_includes, const char **includes); + WERROR (*delete_includes)(struct smbconf_ctx *ctx, + const char *service); +}; + +struct smbconf_ctx { + const char *path; + struct smbconf_ops *ops; + void *data; /* private data for use in backends */ +}; + +WERROR smbconf_init_internal(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx, + const char *path, struct smbconf_ops *ops); + +WERROR smbconf_add_string_to_array(TALLOC_CTX *mem_ctx, + char ***array, + uint32_t count, + const char *string); + +bool smbconf_find_in_array(const char *string, char **list, + uint32_t num_entries, uint32_t *entry); + +bool smbconf_reverse_find_in_array(const char *string, char **list, + uint32_t num_entries, uint32_t *entry); + +#endif diff --git a/source3/lib/smbconf/smbconf_reg.c b/source3/lib/smbconf/smbconf_reg.c new file mode 100644 index 0000000000..033f800e2a --- /dev/null +++ b/source3/lib/smbconf/smbconf_reg.c @@ -0,0 +1,1148 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library, registry backend + * Copyright (C) Michael Adam 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "smbconf_private.h" + +#define INCLUDES_VALNAME "includes" + +struct reg_private_data { + NT_USER_TOKEN *token; + bool open; /* did _we_ open the registry? */ +}; + +/********************************************************************** + * + * helper functions + * + **********************************************************************/ + +/** + * a convenience helper to cast the private data structure + */ +static struct reg_private_data *rpd(struct smbconf_ctx *ctx) +{ + return (struct reg_private_data *)(ctx->data); +} + +/* + * check whether a given value name is forbidden in registry (smbconf) + */ +static bool smbconf_reg_valname_forbidden(const char *valname) +{ + /* hard code the list of forbidden names here for now */ + const char *forbidden_valnames[] = { + "lock directory", + "lock dir", + "config backend", + "include", + "includes", /* this has a special meaning internally */ + NULL + }; + const char **forbidden = NULL; + + for (forbidden = forbidden_valnames; *forbidden != NULL; forbidden++) { + if (strwicmp(valname, *forbidden) == 0) { + return true; + } + } + return false; +} + +static bool smbconf_reg_valname_valid(const char *valname) +{ + return (!smbconf_reg_valname_forbidden(valname) && + lp_parameter_is_valid(valname)); +} + +/** + * Open a registry key specified by "path" + */ +static WERROR smbconf_reg_open_path(TALLOC_CTX *mem_ctx, + struct smbconf_ctx *ctx, + const char *path, + uint32 desired_access, + struct registry_key **key) +{ + WERROR werr = WERR_OK; + + if (ctx == NULL) { + DEBUG(1, ("Error: configuration is not open!\n")); + werr = WERR_INVALID_PARAM; + goto done; + } + + if (rpd(ctx)->token == NULL) { + DEBUG(1, ("Error: token missing from smbconf_ctx. " + "was smbconf_init() called?\n")); + werr = WERR_INVALID_PARAM; + goto done; + } + + werr = ctx->ops->open_conf(ctx); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(1, ("Error opening the registry.\n")); + goto done; + } + + if (path == NULL) { + DEBUG(1, ("Error: NULL path string given\n")); + werr = WERR_INVALID_PARAM; + goto done; + } + + werr = reg_open_path(mem_ctx, path, desired_access, rpd(ctx)->token, + key); + + if (!W_ERROR_IS_OK(werr)) { + DEBUG(5, ("Error opening registry path '%s': %s\n", + path, dos_errstr(werr))); + } + +done: + return werr; +} + +/** + * Open a subkey of the base key (i.e a service) + */ +static WERROR smbconf_reg_open_service_key(TALLOC_CTX *mem_ctx, + struct smbconf_ctx *ctx, + const char *servicename, + uint32 desired_access, + struct registry_key **key) +{ + WERROR werr = WERR_OK; + char *path = NULL; + + if (servicename == NULL) { + path = talloc_strdup(mem_ctx, ctx->path); + } else { + path = talloc_asprintf(mem_ctx, "%s\\%s", ctx->path, + servicename); + } + if (path == NULL) { + werr = WERR_NOMEM; + goto done; + } + + werr = smbconf_reg_open_path(mem_ctx, ctx, path, desired_access, key); + +done: + TALLOC_FREE(path); + return werr; +} + +/** + * open the base key + */ +static WERROR smbconf_reg_open_base_key(TALLOC_CTX *mem_ctx, + struct smbconf_ctx *ctx, + uint32 desired_access, + struct registry_key **key) +{ + return smbconf_reg_open_path(mem_ctx, ctx, ctx->path, desired_access, + key); +} + +/** + * check if a value exists in a given registry key + */ +static bool smbconf_value_exists(struct registry_key *key, const char *param) +{ + bool ret = false; + WERROR werr = WERR_OK; + TALLOC_CTX *ctx = talloc_stackframe(); + struct registry_value *value = NULL; + + werr = reg_queryvalue(ctx, key, param, &value); + if (W_ERROR_IS_OK(werr)) { + ret = true; + } + + TALLOC_FREE(ctx); + return ret; +} + +/** + * create a subkey of the base key (i.e. a service...) + */ +static WERROR smbconf_reg_create_service_key(TALLOC_CTX *mem_ctx, + struct smbconf_ctx *ctx, + const char * subkeyname, + struct registry_key **newkey) +{ + WERROR werr = WERR_OK; + struct registry_key *create_parent = NULL; + TALLOC_CTX *create_ctx; + enum winreg_CreateAction action = REG_ACTION_NONE; + + /* create a new talloc ctx for creation. it will hold + * the intermediate parent key (SMBCONF) for creation + * and will be destroyed when leaving this function... */ + create_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_base_key(create_ctx, ctx, REG_KEY_WRITE, + &create_parent); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = reg_createkey(mem_ctx, create_parent, subkeyname, + REG_KEY_WRITE, newkey, &action); + if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) { + DEBUG(10, ("Key '%s' already exists.\n", subkeyname)); + werr = WERR_ALREADY_EXISTS; + } + if (!W_ERROR_IS_OK(werr)) { + DEBUG(5, ("Error creating key %s: %s\n", + subkeyname, dos_errstr(werr))); + } + +done: + TALLOC_FREE(create_ctx); + return werr; +} + +/** + * add a value to a key. + */ +static WERROR smbconf_reg_set_value(struct registry_key *key, + const char *valname, + const char *valstr) +{ + struct registry_value val; + WERROR werr = WERR_OK; + char *subkeyname; + const char *canon_valname; + const char *canon_valstr; + + if (!lp_canonicalize_parameter_with_value(valname, valstr, + &canon_valname, + &canon_valstr)) + { + if (canon_valname == NULL) { + DEBUG(5, ("invalid parameter '%s' given\n", + valname)); + } else { + DEBUG(5, ("invalid value '%s' given for " + "parameter '%s'\n", valstr, valname)); + } + werr = WERR_INVALID_PARAM; + goto done; + } + + if (smbconf_reg_valname_forbidden(canon_valname)) { + DEBUG(5, ("Parameter '%s' not allowed in registry.\n", + canon_valname)); + werr = WERR_INVALID_PARAM; + goto done; + } + + subkeyname = strrchr_m(key->key->name, '\\'); + if ((subkeyname == NULL) || (*(subkeyname +1) == '\0')) { + DEBUG(5, ("Invalid registry key '%s' given as " + "smbconf section.\n", key->key->name)); + werr = WERR_INVALID_PARAM; + goto done; + } + subkeyname++; + if (!strequal(subkeyname, GLOBAL_NAME) && + lp_parameter_is_global(valname)) + { + DEBUG(5, ("Global paramter '%s' not allowed in " + "service definition ('%s').\n", canon_valname, + subkeyname)); + werr = WERR_INVALID_PARAM; + goto done; + } + + ZERO_STRUCT(val); + + val.type = REG_SZ; + val.v.sz.str = CONST_DISCARD(char *, canon_valstr); + val.v.sz.len = strlen(canon_valstr) + 1; + + werr = reg_setvalue(key, canon_valname, &val); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(5, ("Error adding value '%s' to " + "key '%s': %s\n", + canon_valname, key->key->name, dos_errstr(werr))); + } + +done: + return werr; +} + +static WERROR smbconf_reg_set_multi_sz_value(struct registry_key *key, + const char *valname, + const uint32_t num_strings, + const char **strings) +{ + WERROR werr; + struct registry_value *value; + uint32_t count; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + if (strings == NULL) { + werr = WERR_INVALID_PARAM; + goto done; + } + + value = TALLOC_ZERO_P(tmp_ctx, struct registry_value); + + value->type = REG_MULTI_SZ; + value->v.multi_sz.num_strings = num_strings; + value->v.multi_sz.strings = TALLOC_ARRAY(tmp_ctx, char *, num_strings); + if (value->v.multi_sz.strings == NULL) { + werr = WERR_NOMEM; + goto done; + } + for (count = 0; count < num_strings; count++) { + value->v.multi_sz.strings[count] = + talloc_strdup(value->v.multi_sz.strings, + strings[count]); + if (value->v.multi_sz.strings[count] == NULL) { + werr = WERR_NOMEM; + goto done; + } + } + + werr = reg_setvalue(key, valname, value); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(5, ("Error adding value '%s' to key '%s': %s\n", + valname, key->key->name, dos_errstr(werr))); + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +/** + * format a registry_value into a string. + * + * This is intended to be used for smbconf registry values, + * which are ar stored as REG_SZ values, so the incomplete + * handling should be ok. + */ +static char *smbconf_format_registry_value(TALLOC_CTX *mem_ctx, + struct registry_value *value) +{ + char *result = NULL; + + /* alternatively, create a new talloc context? */ + if (mem_ctx == NULL) { + return result; + } + + switch (value->type) { + case REG_DWORD: + result = talloc_asprintf(mem_ctx, "%d", value->v.dword); + break; + case REG_SZ: + case REG_EXPAND_SZ: + result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str); + break; + case REG_MULTI_SZ: { + uint32 j; + for (j = 0; j < value->v.multi_sz.num_strings; j++) { + result = talloc_asprintf(mem_ctx, "%s\"%s\" ", + result ? result : "" , + value->v.multi_sz.strings[j]); + if (result == NULL) { + break; + } + } + break; + } + case REG_BINARY: + result = talloc_asprintf(mem_ctx, "binary (%d bytes)", + (int)value->v.binary.length); + break; + default: + result = talloc_asprintf(mem_ctx, "<unprintable>"); + break; + } + return result; +} + +static WERROR smbconf_reg_get_includes_internal(TALLOC_CTX *mem_ctx, + struct registry_key *key, + uint32_t *num_includes, + char ***includes) +{ + WERROR werr; + uint32_t count; + struct registry_value *value = NULL; + char **tmp_includes = NULL; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + if (!smbconf_value_exists(key, INCLUDES_VALNAME)) { + /* no includes */ + *num_includes = 0; + *includes = NULL; + werr = WERR_OK; + goto done; + } + + werr = reg_queryvalue(tmp_ctx, key, INCLUDES_VALNAME, &value); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (value->type != REG_MULTI_SZ) { + /* wront type -- ignore */ + goto done; + } + + for (count = 0; count < value->v.multi_sz.num_strings; count++) + { + werr = smbconf_add_string_to_array(tmp_ctx, + &tmp_includes, + count, + value->v.multi_sz.strings[count]); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + } + + if (count > 0) { + *includes = talloc_move(mem_ctx, &tmp_includes); + if (*includes == NULL) { + werr = WERR_NOMEM; + goto done; + } + *num_includes = count; + } else { + *num_includes = 0; + *includes = NULL; + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +/** + * Get the values of a key as a list of value names + * and a list of value strings (ordered) + */ +static WERROR smbconf_reg_get_values(TALLOC_CTX *mem_ctx, + struct registry_key *key, + uint32_t *num_values, + char ***value_names, + char ***value_strings) +{ + TALLOC_CTX *tmp_ctx = NULL; + WERROR werr = WERR_OK; + uint32_t count; + struct registry_value *valvalue = NULL; + char *valname = NULL; + uint32_t tmp_num_values = 0; + char **tmp_valnames = NULL; + char **tmp_valstrings = NULL; + uint32_t num_includes = 0; + char **includes = NULL; + + if ((num_values == NULL) || (value_names == NULL) || + (value_strings == NULL)) + { + werr = WERR_INVALID_PARAM; + goto done; + } + + tmp_ctx = talloc_stackframe(); + + for (count = 0; + werr = reg_enumvalue(tmp_ctx, key, count, &valname, &valvalue), + W_ERROR_IS_OK(werr); + count++) + { + char *valstring; + + if (!smbconf_reg_valname_valid(valname)) { + continue; + } + + werr = smbconf_add_string_to_array(tmp_ctx, + &tmp_valnames, + tmp_num_values, valname); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + valstring = smbconf_format_registry_value(tmp_ctx, valvalue); + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_valstrings, + tmp_num_values, valstring); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + tmp_num_values++; + } + if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) { + goto done; + } + + /* now add the includes at the end */ + werr = smbconf_reg_get_includes_internal(tmp_ctx, key, &num_includes, + &includes); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + for (count = 0; count < num_includes; count++) { + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_valnames, + tmp_num_values, "include"); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_valstrings, + tmp_num_values, + includes[count]); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + tmp_num_values++; + } + + *num_values = tmp_num_values; + if (tmp_num_values > 0) { + *value_names = talloc_move(mem_ctx, &tmp_valnames); + *value_strings = talloc_move(mem_ctx, &tmp_valstrings); + } else { + *value_names = NULL; + *value_strings = NULL; + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +static bool smbconf_reg_key_has_values(struct registry_key *key) +{ + WERROR werr; + uint32_t num_subkeys; + uint32_t max_subkeylen; + uint32_t max_subkeysize; + uint32_t num_values; + uint32_t max_valnamelen; + uint32_t max_valbufsize; + uint32_t secdescsize; + NTTIME last_changed_time; + + werr = reg_queryinfokey(key, &num_subkeys, &max_subkeylen, + &max_subkeysize, &num_values, &max_valnamelen, + &max_valbufsize, &secdescsize, + &last_changed_time); + if (!W_ERROR_IS_OK(werr)) { + return false; + } + + return (num_values != 0); +} + +/** + * delete all values from a key + */ +static WERROR smbconf_reg_delete_values(struct registry_key *key) +{ + WERROR werr; + char *valname; + struct registry_value *valvalue; + uint32_t count; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + for (count = 0; + werr = reg_enumvalue(mem_ctx, key, count, &valname, &valvalue), + W_ERROR_IS_OK(werr); + count++) + { + werr = reg_deletevalue(key, valname); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + } + if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) { + DEBUG(1, ("smbconf_reg_delete_values: " + "Error enumerating values of %s: %s\n", + key->key->name, + dos_errstr(werr))); + goto done; + } + + werr = WERR_OK; + +done: + TALLOC_FREE(mem_ctx); + return werr; +} + +/********************************************************************** + * + * smbconf operations: registry implementations + * + **********************************************************************/ + +/** + * initialize the registry smbconf backend + */ +static WERROR smbconf_reg_init(struct smbconf_ctx *ctx, const char *path) +{ + WERROR werr = WERR_OK; + + if (path == NULL) { + path = KEY_SMBCONF; + } + ctx->path = talloc_strdup(ctx, path); + if (ctx->path == NULL) { + werr = WERR_NOMEM; + goto done; + } + + ctx->data = TALLOC_ZERO_P(ctx, struct reg_private_data); + + werr = ntstatus_to_werror(registry_create_admin_token(ctx, + &(rpd(ctx)->token))); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(1, ("Error creating admin token\n")); + goto done; + } + rpd(ctx)->open = false; + + werr = registry_init_smbconf(path); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + +done: + return werr; +} + +static int smbconf_reg_shutdown(struct smbconf_ctx *ctx) +{ + return ctx->ops->close_conf(ctx); +} + +static WERROR smbconf_reg_open(struct smbconf_ctx *ctx) +{ + WERROR werr; + + if (rpd(ctx)->open) { + return WERR_OK; + } + + werr = regdb_open(); + if (W_ERROR_IS_OK(werr)) { + rpd(ctx)->open = true; + } + return werr; +} + +static int smbconf_reg_close(struct smbconf_ctx *ctx) +{ + int ret; + + if (!rpd(ctx)->open) { + return 0; + } + + ret = regdb_close(); + if (ret == 0) { + rpd(ctx)->open = false; + } + return ret; +} + +/** + * Get the change sequence number of the given service/parameter. + * service and parameter strings may be NULL. + */ +static void smbconf_reg_get_csn(struct smbconf_ctx *ctx, + struct smbconf_csn *csn, + const char *service, const char *param) +{ + if (csn == NULL) { + return; + } + + if (!W_ERROR_IS_OK(ctx->ops->open_conf(ctx))) { + return; + } + + csn->csn = (uint64_t)regdb_get_seqnum(); +} + +/** + * Drop the whole configuration (restarting empty) - registry version + */ +static WERROR smbconf_reg_drop(struct smbconf_ctx *ctx) +{ + char *path, *p; + WERROR werr = WERR_OK; + struct registry_key *parent_key = NULL; + struct registry_key *new_key = NULL; + TALLOC_CTX* mem_ctx = talloc_stackframe(); + enum winreg_CreateAction action; + + path = talloc_strdup(mem_ctx, ctx->path); + if (path == NULL) { + werr = WERR_NOMEM; + goto done; + } + p = strrchr(path, '\\'); + *p = '\0'; + werr = smbconf_reg_open_path(mem_ctx, ctx, path, REG_KEY_WRITE, + &parent_key); + + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = reg_deletekey_recursive(mem_ctx, parent_key, p+1); + + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = reg_createkey(mem_ctx, parent_key, p+1, REG_KEY_WRITE, + &new_key, &action); + +done: + TALLOC_FREE(mem_ctx); + return werr; +} + +/** + * get the list of share names defined in the configuration. + * registry version. + */ +static WERROR smbconf_reg_get_share_names(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + char ***share_names) +{ + uint32_t count; + uint32_t added_count = 0; + TALLOC_CTX *tmp_ctx = NULL; + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + char *subkey_name = NULL; + char **tmp_share_names = NULL; + + if ((num_shares == NULL) || (share_names == NULL)) { + werr = WERR_INVALID_PARAM; + goto done; + } + + tmp_ctx = talloc_stackframe(); + + /* if there are values in the base key, return NULL as share name */ + werr = smbconf_reg_open_base_key(tmp_ctx, ctx, + SEC_RIGHTS_ENUM_SUBKEYS, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (smbconf_reg_key_has_values(key)) { + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names, + 0, NULL); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + added_count++; + } + + /* make sure "global" is always listed first */ + if (smbconf_share_exists(ctx, GLOBAL_NAME)) { + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names, + added_count, GLOBAL_NAME); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + added_count++; + } + + for (count = 0; + werr = reg_enumkey(tmp_ctx, key, count, &subkey_name, NULL), + W_ERROR_IS_OK(werr); + count++) + { + if (strequal(subkey_name, GLOBAL_NAME)) { + continue; + } + + werr = smbconf_add_string_to_array(tmp_ctx, + &tmp_share_names, + added_count, + subkey_name); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + added_count++; + } + if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) { + goto done; + } + werr = WERR_OK; + + *num_shares = added_count; + if (added_count > 0) { + *share_names = talloc_move(mem_ctx, &tmp_share_names); + } else { + *share_names = NULL; + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +/** + * check if a share/service of a given name exists - registry version + */ +static bool smbconf_reg_share_exists(struct smbconf_ctx *ctx, + const char *servicename) +{ + bool ret = false; + WERROR werr = WERR_OK; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + struct registry_key *key = NULL; + + werr = smbconf_reg_open_service_key(mem_ctx, ctx, servicename, + REG_KEY_READ, &key); + if (W_ERROR_IS_OK(werr)) { + ret = true; + } + + TALLOC_FREE(mem_ctx); + return ret; +} + +/** + * Add a service if it does not already exist - registry version + */ +static WERROR smbconf_reg_create_share(struct smbconf_ctx *ctx, + const char *servicename) +{ + WERROR werr; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + struct registry_key *key = NULL; + + if (servicename == NULL) { + werr = smbconf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE, + &key); + } else { + werr = smbconf_reg_create_service_key(mem_ctx, ctx, + servicename, &key); + } + + TALLOC_FREE(mem_ctx); + return werr; +} + +/** + * get a definition of a share (service) from configuration. + */ +static WERROR smbconf_reg_get_share(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *servicename, + struct smbconf_service **service) +{ + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + struct smbconf_service *tmp_service = NULL; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_service_key(tmp_ctx, ctx, servicename, + REG_KEY_READ, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + tmp_service = TALLOC_ZERO_P(tmp_ctx, struct smbconf_service); + if (tmp_service == NULL) { + werr = WERR_NOMEM; + goto done; + } + + if (servicename != NULL) { + tmp_service->name = talloc_strdup(tmp_service, servicename); + if (tmp_service->name == NULL) { + werr = WERR_NOMEM; + goto done; + } + } + + werr = smbconf_reg_get_values(tmp_service, key, + &(tmp_service->num_params), + &(tmp_service->param_names), + &(tmp_service->param_values)); + + if (W_ERROR_IS_OK(werr)) { + *service = talloc_move(mem_ctx, &tmp_service); + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +/** + * delete a service from configuration + */ +static WERROR smbconf_reg_delete_share(struct smbconf_ctx *ctx, + const char *servicename) +{ + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (servicename != NULL) { + werr = reg_deletekey_recursive(key, key, servicename); + } else { + werr = smbconf_reg_delete_values(key); + } + +done: + TALLOC_FREE(mem_ctx); + return werr; +} + +/** + * set a configuration parameter to the value provided. + */ +static WERROR smbconf_reg_set_parameter(struct smbconf_ctx *ctx, + const char *service, + const char *param, + const char *valstr) +{ + WERROR werr; + struct registry_key *key = NULL; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_service_key(mem_ctx, ctx, service, + REG_KEY_WRITE, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = smbconf_reg_set_value(key, param, valstr); + +done: + TALLOC_FREE(mem_ctx); + return werr; +} + +/** + * get the value of a configuration parameter as a string + */ +static WERROR smbconf_reg_get_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + const char *param, + char **valstr) +{ + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + struct registry_value *value = NULL; + + werr = smbconf_reg_open_service_key(mem_ctx, ctx, service, + REG_KEY_READ, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (!smbconf_reg_valname_valid(param)) { + werr = WERR_INVALID_PARAM; + goto done; + } + + if (!smbconf_value_exists(key, param)) { + werr = WERR_INVALID_PARAM; + goto done; + } + + werr = reg_queryvalue(mem_ctx, key, param, &value); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + *valstr = smbconf_format_registry_value(mem_ctx, value); + + if (*valstr == NULL) { + werr = WERR_NOMEM; + } + +done: + TALLOC_FREE(key); + TALLOC_FREE(value); + return werr; +} + +/** + * delete a parameter from configuration + */ +static WERROR smbconf_reg_delete_parameter(struct smbconf_ctx *ctx, + const char *service, + const char *param) +{ + struct registry_key *key = NULL; + WERROR werr = WERR_OK; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_service_key(mem_ctx, ctx, service, + REG_KEY_ALL, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (!smbconf_reg_valname_valid(param)) { + werr = WERR_INVALID_PARAM; + goto done; + } + + if (!smbconf_value_exists(key, param)) { + werr = WERR_INVALID_PARAM; + goto done; + } + + werr = reg_deletevalue(key, param); + +done: + TALLOC_FREE(mem_ctx); + return werr; +} + +static WERROR smbconf_reg_get_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + uint32_t *num_includes, + char ***includes) +{ + WERROR werr; + struct registry_key *key = NULL; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service, + REG_KEY_READ, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + werr = smbconf_reg_get_includes_internal(mem_ctx, key, num_includes, + includes); + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +static WERROR smbconf_reg_set_includes(struct smbconf_ctx *ctx, + const char *service, + uint32_t num_includes, + const char **includes) +{ + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service, + REG_KEY_ALL, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (num_includes == 0) { + if (!smbconf_value_exists(key, INCLUDES_VALNAME)) { + goto done; + } + werr = reg_deletevalue(key, INCLUDES_VALNAME); + } else { + werr = smbconf_reg_set_multi_sz_value(key, INCLUDES_VALNAME, + num_includes, includes); + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +static WERROR smbconf_reg_delete_includes(struct smbconf_ctx *ctx, + const char *service) +{ + WERROR werr = WERR_OK; + struct registry_key *key = NULL; + TALLOC_CTX *tmp_ctx = talloc_stackframe(); + + werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service, + REG_KEY_ALL, &key); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + + if (!smbconf_value_exists(key, INCLUDES_VALNAME)) { + goto done; + } + + werr = reg_deletevalue(key, INCLUDES_VALNAME); + + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +struct smbconf_ops smbconf_ops_reg = { + .init = smbconf_reg_init, + .shutdown = smbconf_reg_shutdown, + .open_conf = smbconf_reg_open, + .close_conf = smbconf_reg_close, + .get_csn = smbconf_reg_get_csn, + .drop = smbconf_reg_drop, + .get_share_names = smbconf_reg_get_share_names, + .share_exists = smbconf_reg_share_exists, + .create_share = smbconf_reg_create_share, + .get_share = smbconf_reg_get_share, + .delete_share = smbconf_reg_delete_share, + .set_parameter = smbconf_reg_set_parameter, + .get_parameter = smbconf_reg_get_parameter, + .delete_parameter = smbconf_reg_delete_parameter, + .get_includes = smbconf_reg_get_includes, + .set_includes = smbconf_reg_set_includes, + .delete_includes = smbconf_reg_delete_includes, +}; + + +/** + * initialize the smbconf registry backend + * the only function that is exported from this module + */ +WERROR smbconf_init_reg(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx, + const char *path) +{ + return smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_reg); +} diff --git a/source3/lib/smbconf/smbconf_txt.c b/source3/lib/smbconf/smbconf_txt.c new file mode 100644 index 0000000000..1a29f40164 --- /dev/null +++ b/source3/lib/smbconf/smbconf_txt.c @@ -0,0 +1,641 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library, text backend + * Copyright (C) Michael Adam 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This is a sample implementation of a libsmbconf text backend + * using the params.c parser. + * + * It is read only. + * Don't expect brilliant performance, since it is not hashing the lists. + */ + +#include "includes.h" +#include "smbconf_private.h" + +struct txt_cache { + uint32_t current_share; + uint32_t num_shares; + char **share_names; + uint32_t *num_params; + char ***param_names; + char ***param_values; +}; + +struct txt_private_data { + struct txt_cache *cache; + uint64_t csn; + bool verbatim; +}; + +/********************************************************************** + * + * helper functions + * + **********************************************************************/ + +/** + * a convenience helper to cast the private data structure + */ +static struct txt_private_data *pd(struct smbconf_ctx *ctx) +{ + return (struct txt_private_data *)(ctx->data); +} + +static bool smbconf_txt_do_section(const char *section, void *private_data) +{ + WERROR werr; + uint32_t idx; + struct txt_private_data *tpd = (struct txt_private_data *)private_data; + struct txt_cache *cache = tpd->cache; + + if (smbconf_find_in_array(section, cache->share_names, + cache->num_shares, &idx)) + { + cache->current_share = idx; + return true; + } + + werr = smbconf_add_string_to_array(cache, &(cache->share_names), + cache->num_shares, section); + if (!W_ERROR_IS_OK(werr)) { + return false; + } + cache->current_share = cache->num_shares; + cache->num_shares++; + + cache->param_names = TALLOC_REALLOC_ARRAY(cache, + cache->param_names, + char **, + cache->num_shares); + if (cache->param_names == NULL) { + return false; + } + cache->param_names[cache->current_share] = NULL; + + cache->param_values = TALLOC_REALLOC_ARRAY(cache, + cache->param_values, + char **, + cache->num_shares); + if (cache->param_values == NULL) { + return false; + } + cache->param_values[cache->current_share] = NULL; + + cache->num_params = TALLOC_REALLOC_ARRAY(cache, + cache->num_params, + uint32_t, + cache->num_shares); + if (cache->num_params == NULL) { + return false; + } + cache->num_params[cache->current_share] = 0; + + return true; +} + +static bool smbconf_txt_do_parameter(const char *param_name, + const char *param_value, + void *private_data) +{ + WERROR werr; + char **param_names, **param_values; + uint32_t num_params; + uint32_t idx; + struct txt_private_data *tpd = (struct txt_private_data *)private_data; + struct txt_cache *cache = tpd->cache; + + if (cache->num_shares == 0) { + /* + * not in any share yet, + * initialize the "empty" section (NULL): + * parameters without a previous [section] are stored here. + */ + if (!smbconf_txt_do_section(NULL, private_data)) { + return false; + } + } + + param_names = cache->param_names[cache->current_share]; + param_values = cache->param_values[cache->current_share]; + num_params = cache->num_params[cache->current_share]; + + if (!(tpd->verbatim) && + smbconf_find_in_array(param_name, param_names, num_params, &idx)) + { + TALLOC_FREE(param_values[idx]); + param_values[idx] = talloc_strdup(cache, param_value); + if (param_values[idx] == NULL) { + return false; + } + return true; + } + werr = smbconf_add_string_to_array(cache, + &(cache->param_names[cache->current_share]), + num_params, param_name); + if (!W_ERROR_IS_OK(werr)) { + return false; + } + werr = smbconf_add_string_to_array(cache, + &(cache->param_values[cache->current_share]), + num_params, param_value); + cache->num_params[cache->current_share]++; + return W_ERROR_IS_OK(werr); +} + +static void smbconf_txt_flush_cache(struct smbconf_ctx *ctx) +{ + TALLOC_FREE(pd(ctx)->cache); +} + +static WERROR smbconf_txt_init_cache(struct smbconf_ctx *ctx) +{ + if (pd(ctx)->cache != NULL) { + smbconf_txt_flush_cache(ctx); + } + + pd(ctx)->cache = TALLOC_ZERO_P(pd(ctx), struct txt_cache); + + if (pd(ctx)->cache == NULL) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +static WERROR smbconf_txt_load_file(struct smbconf_ctx *ctx) +{ + WERROR werr; + uint64_t new_csn; + + if (!file_exist(ctx->path, NULL)) { + return WERR_BADFILE; + } + + new_csn = (uint64_t)file_modtime(ctx->path); + if (new_csn == pd(ctx)->csn) { + return WERR_OK; + } + + werr = smbconf_txt_init_cache(ctx); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + if (!pm_process(ctx->path, smbconf_txt_do_section, + smbconf_txt_do_parameter, pd(ctx))) + { + return WERR_CAN_NOT_COMPLETE; + } + + pd(ctx)->csn = new_csn; + + return WERR_OK; +} + + +/********************************************************************** + * + * smbconf operations: text backend implementations + * + **********************************************************************/ + +/** + * initialize the text based smbconf backend + */ +static WERROR smbconf_txt_init(struct smbconf_ctx *ctx, const char *path) +{ + if (path == NULL) { + path = get_dyn_CONFIGFILE(); + } + ctx->path = talloc_strdup(ctx, path); + if (ctx->path == NULL) { + return WERR_NOMEM; + } + + ctx->data = TALLOC_ZERO_P(ctx, struct txt_private_data); + if (ctx->data == NULL) { + return WERR_NOMEM; + } + + pd(ctx)->verbatim = true; + + return WERR_OK; +} + +static int smbconf_txt_shutdown(struct smbconf_ctx *ctx) +{ + return ctx->ops->close_conf(ctx); +} + +static WERROR smbconf_txt_open(struct smbconf_ctx *ctx) +{ + return smbconf_txt_load_file(ctx); +} + +static int smbconf_txt_close(struct smbconf_ctx *ctx) +{ + smbconf_txt_flush_cache(ctx); + return 0; +} + +/** + * Get the change sequence number of the given service/parameter. + * service and parameter strings may be NULL. + */ +static void smbconf_txt_get_csn(struct smbconf_ctx *ctx, + struct smbconf_csn *csn, + const char *service, const char *param) +{ + if (csn == NULL) { + return; + } + + csn->csn = (uint64_t)file_modtime(ctx->path); +} + +/** + * Drop the whole configuration (restarting empty) + */ +static WERROR smbconf_txt_drop(struct smbconf_ctx *ctx) +{ + return WERR_NOT_SUPPORTED; +} + +/** + * get the list of share names defined in the configuration. + */ +static WERROR smbconf_txt_get_share_names(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + char ***share_names) +{ + uint32_t count; + uint32_t added_count = 0; + TALLOC_CTX *tmp_ctx = NULL; + WERROR werr = WERR_OK; + char **tmp_share_names = NULL; + + if ((num_shares == NULL) || (share_names == NULL)) { + werr = WERR_INVALID_PARAM; + goto done; + } + + werr = smbconf_txt_load_file(ctx); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + tmp_ctx = talloc_stackframe(); + + /* make sure "global" is always listed first, + * possibly after NULL section */ + + if (smbconf_share_exists(ctx, NULL)) { + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names, + 0, NULL); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + added_count++; + } + + if (smbconf_share_exists(ctx, GLOBAL_NAME)) { + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names, + added_count, GLOBAL_NAME); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + added_count++; + } + + for (count = 0; count < pd(ctx)->cache->num_shares; count++) { + if (strequal(pd(ctx)->cache->share_names[count], GLOBAL_NAME) || + (pd(ctx)->cache->share_names[count] == NULL)) + { + continue; + } + + werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names, + added_count, + pd(ctx)->cache->share_names[count]); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + added_count++; + } + + *num_shares = added_count; + if (added_count > 0) { + *share_names = talloc_move(mem_ctx, &tmp_share_names); + } else { + *share_names = NULL; + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +/** + * check if a share/service of a given name exists + */ +static bool smbconf_txt_share_exists(struct smbconf_ctx *ctx, + const char *servicename) +{ + WERROR werr; + + werr = smbconf_txt_load_file(ctx); + if (!W_ERROR_IS_OK(werr)) { + return false; + } + + return smbconf_find_in_array(servicename, + pd(ctx)->cache->share_names, + pd(ctx)->cache->num_shares, NULL); +} + +/** + * Add a service if it does not already exist + */ +static WERROR smbconf_txt_create_share(struct smbconf_ctx *ctx, + const char *servicename) +{ + return WERR_NOT_SUPPORTED; +} + +/** + * get a definition of a share (service) from configuration. + */ +static WERROR smbconf_txt_get_share(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *servicename, + struct smbconf_service **service) +{ + WERROR werr; + uint32_t sidx, count; + bool found; + TALLOC_CTX *tmp_ctx = NULL; + struct smbconf_service *tmp_service = NULL; + + werr = smbconf_txt_load_file(ctx); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + found = smbconf_find_in_array(servicename, + pd(ctx)->cache->share_names, + pd(ctx)->cache->num_shares, + &sidx); + if (!found) { + return WERR_NO_SUCH_SERVICE; + } + + tmp_ctx = talloc_stackframe(); + + tmp_service = TALLOC_ZERO_P(tmp_ctx, struct smbconf_service); + if (tmp_service == NULL) { + werr = WERR_NOMEM; + goto done; + } + + if (servicename != NULL) { + tmp_service->name = talloc_strdup(tmp_service, servicename); + if (tmp_service->name == NULL) { + werr = WERR_NOMEM; + goto done; + } + } + + for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) { + werr = smbconf_add_string_to_array(tmp_service, + &(tmp_service->param_names), + count, + pd(ctx)->cache->param_names[sidx][count]); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + werr = smbconf_add_string_to_array(tmp_service, + &(tmp_service->param_values), + count, + pd(ctx)->cache->param_values[sidx][count]); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + } + + tmp_service->num_params = count; + if (count > 0) { + *service = talloc_move(mem_ctx, &tmp_service); + } else { + *service = NULL; + } + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +/** + * delete a service from configuration + */ +static WERROR smbconf_txt_delete_share(struct smbconf_ctx *ctx, + const char *servicename) +{ + return WERR_NOT_SUPPORTED; +} + +/** + * set a configuration parameter to the value provided. + */ +static WERROR smbconf_txt_set_parameter(struct smbconf_ctx *ctx, + const char *service, + const char *param, + const char *valstr) +{ + return WERR_NOT_SUPPORTED; +} + +/** + * get the value of a configuration parameter as a string + */ +static WERROR smbconf_txt_get_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + const char *param, + char **valstr) +{ + WERROR werr; + bool found; + uint32_t share_index, param_index; + + werr = smbconf_txt_load_file(ctx); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + found = smbconf_find_in_array(service, + pd(ctx)->cache->share_names, + pd(ctx)->cache->num_shares, + &share_index); + if (!found) { + return WERR_NO_SUCH_SERVICE; + } + + found = smbconf_reverse_find_in_array(param, + pd(ctx)->cache->param_names[share_index], + pd(ctx)->cache->num_params[share_index], + ¶m_index); + if (!found) { + return WERR_INVALID_PARAM; + } + + *valstr = talloc_strdup(mem_ctx, + pd(ctx)->cache->param_values[share_index][param_index]); + + if (*valstr == NULL) { + return WERR_NOMEM; + } + + return WERR_OK; +} + +/** + * delete a parameter from configuration + */ +static WERROR smbconf_txt_delete_parameter(struct smbconf_ctx *ctx, + const char *service, + const char *param) +{ + return WERR_NOT_SUPPORTED; +} + +static WERROR smbconf_txt_get_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + uint32_t *num_includes, + char ***includes) +{ + WERROR werr; + bool found; + uint32_t sidx, count; + TALLOC_CTX *tmp_ctx = NULL; + uint32_t tmp_num_includes = 0; + char **tmp_includes = NULL; + + werr = smbconf_txt_load_file(ctx); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + found = smbconf_find_in_array(service, + pd(ctx)->cache->share_names, + pd(ctx)->cache->num_shares, + &sidx); + if (!found) { + return WERR_NO_SUCH_SERVICE; + } + + tmp_ctx = talloc_stackframe(); + + for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) { + if (strequal(pd(ctx)->cache->param_names[sidx][count], + "include")) + { + werr = smbconf_add_string_to_array(tmp_ctx, + &tmp_includes, + tmp_num_includes, + pd(ctx)->cache->param_values[sidx][count]); + if (!W_ERROR_IS_OK(werr)) { + goto done; + } + tmp_num_includes++; + } + } + + *num_includes = tmp_num_includes; + if (*num_includes > 0) { + *includes = talloc_move(mem_ctx, &tmp_includes); + if (*includes == NULL) { + werr = WERR_NOMEM; + goto done; + } + } else { + *includes = NULL; + } + + werr = WERR_OK; + +done: + TALLOC_FREE(tmp_ctx); + return werr; +} + +static WERROR smbconf_txt_set_includes(struct smbconf_ctx *ctx, + const char *service, + uint32_t num_includes, + const char **includes) +{ + return WERR_NOT_SUPPORTED; +} + +static WERROR smbconf_txt_delete_includes(struct smbconf_ctx *ctx, + const char *service) +{ + return WERR_NOT_SUPPORTED; +} + + +static struct smbconf_ops smbconf_ops_txt = { + .init = smbconf_txt_init, + .shutdown = smbconf_txt_shutdown, + .open_conf = smbconf_txt_open, + .close_conf = smbconf_txt_close, + .get_csn = smbconf_txt_get_csn, + .drop = smbconf_txt_drop, + .get_share_names = smbconf_txt_get_share_names, + .share_exists = smbconf_txt_share_exists, + .create_share = smbconf_txt_create_share, + .get_share = smbconf_txt_get_share, + .delete_share = smbconf_txt_delete_share, + .set_parameter = smbconf_txt_set_parameter, + .get_parameter = smbconf_txt_get_parameter, + .delete_parameter = smbconf_txt_delete_parameter, + .get_includes = smbconf_txt_get_includes, + .set_includes = smbconf_txt_set_includes, + .delete_includes = smbconf_txt_delete_includes, +}; + + +/** + * initialize the smbconf text backend + * the only function that is exported from this module + */ +WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx, + struct smbconf_ctx **conf_ctx, + const char *path) +{ + WERROR werr; + + werr = smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_txt); + if (!W_ERROR_IS_OK(werr)) { + return werr; + } + + return smbconf_txt_load_file(*conf_ctx); +} diff --git a/source3/lib/smbconf/smbconf_util.c b/source3/lib/smbconf/smbconf_util.c new file mode 100644 index 0000000000..271fc47dd4 --- /dev/null +++ b/source3/lib/smbconf/smbconf_util.c @@ -0,0 +1,151 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library, utility functions + * Copyright (C) Michael Adam 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "smbconf_private.h" + + +static int smbconf_destroy_ctx(struct smbconf_ctx *ctx) +{ + return ctx->ops->shutdown(ctx); +} + +/** + * Initialize the configuration. + * + * This should be the first function in a sequence of calls to smbconf + * functions: + * + * Upon success, this creates and returns the conf context + * that should be passed around in subsequent calls to the other + * smbconf functions. + * + * After the work with the configuration is completed, smbconf_shutdown() + * should be called. + */ +WERROR smbconf_init_internal(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx, + const char *path, struct smbconf_ops *ops) +{ + WERROR werr = WERR_OK; + struct smbconf_ctx *ctx; + + if (conf_ctx == NULL) { + return WERR_INVALID_PARAM; + } + + ctx = TALLOC_ZERO_P(mem_ctx, struct smbconf_ctx); + if (ctx == NULL) { + return WERR_NOMEM; + } + + ctx->ops = ops; + + werr = ctx->ops->init(ctx, path); + if (!W_ERROR_IS_OK(werr)) { + goto fail; + } + + talloc_set_destructor(ctx, smbconf_destroy_ctx); + + *conf_ctx = ctx; + return werr; + +fail: + TALLOC_FREE(ctx); + return werr; +} + + +/** + * add a string to a talloced array of strings. + */ +WERROR smbconf_add_string_to_array(TALLOC_CTX *mem_ctx, + char ***array, + uint32_t count, + const char *string) +{ + char **new_array = NULL; + + if (array == NULL) { + return WERR_INVALID_PARAM; + } + + new_array = TALLOC_REALLOC_ARRAY(mem_ctx, *array, char *, count + 1); + if (new_array == NULL) { + return WERR_NOMEM; + } + + if (string == NULL) { + new_array[count] = NULL; + } else { + new_array[count] = talloc_strdup(new_array, string); + if (new_array[count] == NULL) { + TALLOC_FREE(new_array); + return WERR_NOMEM; + } + } + + *array = new_array; + + return WERR_OK; +} + +bool smbconf_find_in_array(const char *string, char **list, + uint32_t num_entries, uint32_t *entry) +{ + uint32_t i; + + if (list == NULL) { + return false; + } + + for (i = 0; i < num_entries; i++) { + if (((string == NULL) && (list[i] == NULL)) || + strequal(string, list[i])) + { + if (entry != NULL) { + *entry = i; + } + return true; + } + } + + return false; +} + +bool smbconf_reverse_find_in_array(const char *string, char **list, + uint32_t num_entries, uint32_t *entry) +{ + int32_t i; + + if ((string == NULL) || (list == NULL) || (num_entries == 0)) { + return false; + } + + for (i = num_entries - 1; i >= 0; i--) { + if (strequal(string, list[i])) { + if (entry != NULL) { + *entry = i; + } + return true; + } + } + + return false; +} diff --git a/source3/lib/smbconf/testsuite.c b/source3/lib/smbconf/testsuite.c new file mode 100644 index 0000000000..cffd239df6 --- /dev/null +++ b/source3/lib/smbconf/testsuite.c @@ -0,0 +1,283 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library: testsuite + * Copyright (C) Michael Adam 2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" + +static void print_strings(const char *prefix, + uint32_t num_strings, const char **strings) +{ + uint32_t count; + + if (prefix == NULL) { + prefix = ""; + } + + for (count = 0; count < num_strings; count++) { + printf("%s%s\n", prefix, strings[count]); + } +} + +static bool test_get_includes(struct smbconf_ctx *ctx) +{ + WERROR werr; + bool ret = false; + uint32_t num_includes = 0; + char **includes = NULL; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + printf("test: get_includes\n"); + werr = smbconf_get_global_includes(ctx, mem_ctx, + &num_includes, &includes); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: get_includes - %s\n", dos_errstr(werr)); + goto done; + } + + printf("got %u includes%s\n", num_includes, + (num_includes > 0) ? ":" : "."); + print_strings("", num_includes, (const char **)includes); + + printf("success: get_includes\n"); + ret = true; + +done: + TALLOC_FREE(mem_ctx); + return ret; +} + +static bool test_set_get_includes(struct smbconf_ctx *ctx) +{ + WERROR werr; + uint32_t count; + bool ret = false; + const char *set_includes[] = { + "/path/to/include1", + "/path/to/include2" + }; + uint32_t set_num_includes = 2; + char **get_includes = NULL; + uint32_t get_num_includes = 0; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + printf("test: set_get_includes\n"); + + werr = smbconf_set_global_includes(ctx, set_num_includes, set_includes); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: get_set_includes (setting includes) - %s\n", + dos_errstr(werr)); + goto done; + } + + werr = smbconf_get_global_includes(ctx, mem_ctx, &get_num_includes, + &get_includes); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: get_set_includes (getting includes) - %s\n", + dos_errstr(werr)); + goto done; + } + + if (get_num_includes != set_num_includes) { + printf("failure: get_set_includes - set %d includes, got %d\n", + set_num_includes, get_num_includes); + goto done; + } + + for (count = 0; count < get_num_includes; count++) { + if (!strequal(set_includes[count], get_includes[count])) { + printf("expected: \n"); + print_strings("* ", set_num_includes, set_includes); + printf("got: \n"); + print_strings("* ", get_num_includes, + (const char **)get_includes); + printf("failure: get_set_includes - data mismatch:\n"); + goto done; + } + } + + printf("success: set_includes\n"); + ret = true; + +done: + TALLOC_FREE(mem_ctx); + return ret; +} + +static bool test_delete_includes(struct smbconf_ctx *ctx) +{ + WERROR werr; + bool ret = false; + const char *set_includes[] = { + "/path/to/include", + }; + uint32_t set_num_includes = 1; + char **get_includes = NULL; + uint32_t get_num_includes = 0; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + printf("test: delete_includes\n"); + + werr = smbconf_set_global_includes(ctx, set_num_includes, set_includes); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: delete_includes (setting includes) - %s\n", + dos_errstr(werr)); + goto done; + } + + werr = smbconf_delete_global_includes(ctx); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: delete_includes (deleting includes) - %s\n", + dos_errstr(werr)); + goto done; + } + + werr = smbconf_get_global_includes(ctx, mem_ctx, &get_num_includes, + &get_includes); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: delete_includes (getting includes) - %s\n", + dos_errstr(werr)); + goto done; + } + + if (get_num_includes != 0) { + printf("failure: delete_includes (not empty after delete)\n"); + goto done; + } + + werr = smbconf_delete_global_includes(ctx); + if (!W_ERROR_IS_OK(werr)) { + printf("failuer: delete_includes (delete empty includes) - " + "%s\n", dos_errstr(werr)); + goto done; + } + + printf("success: delete_includes\n"); + ret = true; + +done: + return ret; +} + +static bool torture_smbconf_txt(void) +{ + WERROR werr; + bool ret = true; + struct smbconf_ctx *conf_ctx = NULL; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + printf("test: text backend\n"); + + printf("test: init\n"); + werr = smbconf_init_txt(mem_ctx, &conf_ctx, NULL); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: init failed: %s\n", dos_errstr(werr)); + ret = false; + goto done; + } + printf("success: init\n"); + + ret &= test_get_includes(conf_ctx); + + smbconf_shutdown(conf_ctx); + + printf("%s: text backend\n", ret ? "success" : "failure"); + +done: + TALLOC_FREE(mem_ctx); + return ret; +} + +static bool torture_smbconf_reg(void) +{ + WERROR werr; + bool ret = true; + struct smbconf_ctx *conf_ctx = NULL; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + printf("test: registry backend\n"); + + printf("test: init\n"); + werr = smbconf_init_reg(mem_ctx, &conf_ctx, NULL); + if (!W_ERROR_IS_OK(werr)) { + printf("failure: init failed: %s\n", dos_errstr(werr)); + ret = false; + goto done; + } + printf("success: init\n"); + + ret &= test_get_includes(conf_ctx); + ret &= test_set_get_includes(conf_ctx); + ret &= test_delete_includes(conf_ctx); + + smbconf_shutdown(conf_ctx); + + printf("%s: registry backend\n", ret ? "success" : "failure"); + +done: + TALLOC_FREE(mem_ctx); + return ret; +} + +static bool torture_smbconf(void) +{ + bool ret = true; + ret &= torture_smbconf_txt(); + printf("\n"); + ret &= torture_smbconf_reg(); + return ret; +} + +int main(int argc, const char **argv) +{ + bool ret; + poptContext pc; + TALLOC_CTX *mem_ctx = talloc_stackframe(); + + struct poptOption long_options[] = { + POPT_COMMON_SAMBA + {0, 0, 0, 0} + }; + + load_case_tables(); + dbf = x_stderr; + + /* parse options */ + pc = poptGetContext("smbconftort", argc, (const char **)argv, + long_options, 0); + + while(poptGetNextOpt(pc) != -1) { } + + poptFreeContext(pc); + + ret = lp_load(get_dyn_CONFIGFILE(), + true, /* globals_only */ + false, /* save_defaults */ + false, /* add_ipc */ + true /* initialize globals */); + + if (!ret) { + printf("failure: error loading the configuration\n"); + goto done; + } + + ret = torture_smbconf(); + +done: + TALLOC_FREE(mem_ctx); + return ret ? 0 : -1; +} |