From a868d2f3d5281dea923718486e4e42b20cf8fe74 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 21 Jan 2009 18:10:23 +0100 Subject: libsmbconf: move the non-registry parts of libsmbconf to top level Michael --- lib/smbconf/smbconf.c | 405 ++++++++++++++++++++++++++ lib/smbconf/smbconf.h | 97 +++++++ lib/smbconf/smbconf_private.h | 87 ++++++ lib/smbconf/smbconf_txt.c | 655 ++++++++++++++++++++++++++++++++++++++++++ lib/smbconf/smbconf_txt.h | 33 +++ lib/smbconf/smbconf_util.c | 151 ++++++++++ 6 files changed, 1428 insertions(+) create mode 100644 lib/smbconf/smbconf.c create mode 100644 lib/smbconf/smbconf.h create mode 100644 lib/smbconf/smbconf_private.h create mode 100644 lib/smbconf/smbconf_txt.c create mode 100644 lib/smbconf/smbconf_txt.h create mode 100644 lib/smbconf/smbconf_util.c (limited to 'lib/smbconf') diff --git a/lib/smbconf/smbconf.c b/lib/smbconf/smbconf.c new file mode 100644 index 0000000000..d723f0b140 --- /dev/null +++ b/lib/smbconf/smbconf.c @@ -0,0 +1,405 @@ +/* + * 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 . + */ + +#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. + * + **********************************************************************/ + +/** + * Tell whether the backend requires messaging to be set up + * for the backend to work correctly. + */ +bool smbconf_backend_requires_messaging(struct smbconf_ctx *ctx) +{ + return ctx->ops->requires_messaging(ctx); +} + +/** + * Tell whether the source is writeable. + */ +bool smbconf_is_writeable(struct smbconf_ctx *ctx) +{ + return ctx->ops->is_writeable(ctx); +} + +/** + * 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_FILE_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/lib/smbconf/smbconf.h b/lib/smbconf/smbconf.h new file mode 100644 index 0000000000..106fae6431 --- /dev/null +++ b/lib/smbconf/smbconf.h @@ -0,0 +1,97 @@ +/* + * 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 . + */ + +#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; +}; + +/* + * the smbconf API functions + */ +bool smbconf_backend_requires_messaging(struct smbconf_ctx *ctx); +bool smbconf_is_writeable(struct smbconf_ctx *ctx); +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/lib/smbconf/smbconf_private.h b/lib/smbconf/smbconf_private.h new file mode 100644 index 0000000000..b0333e981a --- /dev/null +++ b/lib/smbconf/smbconf_private.h @@ -0,0 +1,87 @@ +/* + * 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 . + */ + +#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); + bool (*requires_messaging)(struct smbconf_ctx *ctx); + bool (*is_writeable)(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/lib/smbconf/smbconf_txt.c b/lib/smbconf/smbconf_txt.c new file mode 100644 index 0000000000..c4d2d2b1af --- /dev/null +++ b/lib/smbconf/smbconf_txt.c @@ -0,0 +1,655 @@ +/* + * 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 . + */ + +/* + * 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); + pd(ctx)->cache = NULL; +} + +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)) { + 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) { + return WERR_BADFILE; + } + 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 bool smbconf_txt_requires_messaging(struct smbconf_ctx *ctx) +{ + return false; +} + +static bool smbconf_txt_is_writeable(struct smbconf_ctx *ctx) +{ + /* no write support in this backend yet... */ + return false; +} + +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, + .requires_messaging = smbconf_txt_requires_messaging, + .is_writeable = smbconf_txt_is_writeable, + .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/lib/smbconf/smbconf_txt.h b/lib/smbconf/smbconf_txt.h new file mode 100644 index 0000000000..688bbc9d48 --- /dev/null +++ b/lib/smbconf/smbconf_txt.h @@ -0,0 +1,33 @@ +/* + * Unix SMB/CIFS implementation. + * libsmbconf - Samba configuration library + * Copyright (C) Michael Adam 2009 + * + * 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 . + */ + +#ifndef __LIBSMBCONF_TXT_H__ +#define __LIBSMBCONF_TXT_H__ + +struct smbconf_ctx; + +/** + * initialization functions for the text/file backend modules + */ + +WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx, + struct smbconf_ctx **conf_ctx, + const char *path); + +#endif /* _LIBSMBCONF_TXT_H_ */ diff --git a/lib/smbconf/smbconf_util.c b/lib/smbconf/smbconf_util.c new file mode 100644 index 0000000000..5eb5e963ed --- /dev/null +++ b/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 . + */ + +#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; +} -- cgit