diff options
Diffstat (limited to '')
-rw-r--r-- | lib/smbconf/smbconf.c | 511 |
1 files changed, 511 insertions, 0 deletions
diff --git a/lib/smbconf/smbconf.c b/lib/smbconf/smbconf.c new file mode 100644 index 0000000..4129ea5 --- /dev/null +++ b/lib/smbconf/smbconf.c @@ -0,0 +1,511 @@ +/* + * 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 sbcErr smbconf_global_check(struct smbconf_ctx *ctx) +{ + if (!smbconf_share_exists(ctx, GLOBAL_NAME)) { + return smbconf_create_share(ctx, GLOBAL_NAME); + } + + return SBC_ERR_OK; +} + + +/********************************************************************** + * + * The actual libsmbconf API functions that are exported. + * + **********************************************************************/ + +const char *sbcErrorString(sbcErr error) +{ + switch (error) { + case SBC_ERR_OK: + return "SBC_ERR_OK"; + case SBC_ERR_NOT_IMPLEMENTED: + return "SBC_ERR_NOT_IMPLEMENTED"; + case SBC_ERR_NOT_SUPPORTED: + return "SBC_ERR_NOT_SUPPORTED"; + case SBC_ERR_UNKNOWN_FAILURE: + return "SBC_ERR_UNKNOWN_FAILURE"; + case SBC_ERR_NOMEM: + return "SBC_ERR_NOMEM"; + case SBC_ERR_INVALID_PARAM: + return "SBC_ERR_INVALID_PARAM"; + case SBC_ERR_BADFILE: + return "SBC_ERR_BADFILE"; + case SBC_ERR_NO_SUCH_SERVICE: + return "SBC_ERR_NO_SUCH_SERVICE"; + case SBC_ERR_IO_FAILURE: + return "SBC_ERR_IO_FAILURE"; + case SBC_ERR_CAN_NOT_COMPLETE: + return "SBC_ERR_CAN_NOT_COMPLETE"; + case SBC_ERR_NO_MORE_ITEMS: + return "SBC_ERR_NO_MORE_ITEMS"; + case SBC_ERR_FILE_EXISTS: + return "SBC_ERR_FILE_EXISTS"; + case SBC_ERR_ACCESS_DENIED: + return "SBC_ERR_ACCESS_DENIED"; + } + + return "unknown sbcErr value"; +} + + +/** + * 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). + */ +sbcErr 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 + */ +sbcErr smbconf_get_config(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_shares, + struct smbconf_service ***services) +{ + sbcErr err; + 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)) { + err = SBC_ERR_INVALID_PARAM; + goto done; + } + + tmp_ctx = talloc_stackframe(); + + err = smbconf_get_share_names(ctx, tmp_ctx, &tmp_num_shares, + &tmp_share_names); + if (!SBC_ERROR_IS_OK(err)) { + goto done; + } + + tmp_services = talloc_array(tmp_ctx, struct smbconf_service *, + tmp_num_shares); + if (tmp_services == NULL) { + err = SBC_ERR_NOMEM; + goto done; + } + + for (count = 0; count < tmp_num_shares; count++) { + err = smbconf_get_share(ctx, tmp_services, + tmp_share_names[count], + &tmp_services[count]); + if (!SBC_ERROR_IS_OK(err)) { + goto done; + } + } + + err = SBC_ERR_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 err; +} + +/** + * get the list of share names defined in the configuration. + */ +sbcErr 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. + */ +sbcErr smbconf_create_share(struct smbconf_ctx *ctx, + const char *servicename) +{ + if ((servicename != NULL) && smbconf_share_exists(ctx, servicename)) { + return SBC_ERR_FILE_EXISTS; + } + + return ctx->ops->create_share(ctx, servicename); +} + +/** + * create and set the definition for a new share (service). + */ +sbcErr smbconf_create_set_share(struct smbconf_ctx *ctx, + struct smbconf_service *service) +{ + sbcErr err, err2; + int i; + uint32_t num_includes = 0; + char **includes = NULL; + TALLOC_CTX *tmp_ctx = NULL; + + if ((service->name != NULL) && smbconf_share_exists(ctx, service->name)) + { + return SBC_ERR_FILE_EXISTS; + } + + err = smbconf_transaction_start(ctx); + if (!SBC_ERROR_IS_OK(err)) { + return err; + } + + tmp_ctx = talloc_stackframe(); + + err = smbconf_create_share(ctx, service->name); + if (!SBC_ERROR_IS_OK(err)) { + goto cancel; + } + + for (i = 0; i < service->num_params; i++) { + if (strequal(service->param_names[i], "include")) { + includes = talloc_realloc(tmp_ctx, includes, char *, + num_includes+1); + if (includes == NULL) { + err = SBC_ERR_NOMEM; + goto cancel; + } + includes[num_includes] = talloc_strdup(includes, + service->param_values[i]); + if (includes[num_includes] == NULL) { + err = SBC_ERR_NOMEM; + goto cancel; + } + num_includes++; + } else { + err = smbconf_set_parameter(ctx, + service->name, + service->param_names[i], + service->param_values[i]); + if (!SBC_ERROR_IS_OK(err)) { + goto cancel; + } + } + } + + err = smbconf_set_includes(ctx, service->name, num_includes, + discard_const_p(const char *, includes)); + if (!SBC_ERROR_IS_OK(err)) { + goto cancel; + } + + err = smbconf_transaction_commit(ctx); + + goto done; + +cancel: + err2 = smbconf_transaction_cancel(ctx); + if (!SBC_ERROR_IS_OK(err2)) { + DEBUG(5, (__location__ ": Error cancelling transaction: %s\n", + sbcErrorString(err2))); + } + +done: + talloc_free(tmp_ctx); + return err; +} + +/** + * get a definition of a share (service) from configuration. + */ +sbcErr smbconf_get_share(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *servicename, + struct smbconf_service **service) +{ + return ctx->ops->get_share(ctx, mem_ctx, servicename, service); +} + +/** + * delete a service from configuration + */ +sbcErr smbconf_delete_share(struct smbconf_ctx *ctx, const char *servicename) +{ + if (!smbconf_share_exists(ctx, servicename)) { + return SBC_ERR_NO_SUCH_SERVICE; + } + + return ctx->ops->delete_share(ctx, servicename); +} + +/** + * set a configuration parameter to the value provided. + */ +sbcErr smbconf_set_parameter(struct smbconf_ctx *ctx, + const char *service, + const char *param, + const char *valstr) +{ + 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. + */ +sbcErr smbconf_set_global_parameter(struct smbconf_ctx *ctx, + const char *param, const char *val) +{ + sbcErr err; + + err = smbconf_global_check(ctx); + if (!SBC_ERROR_IS_OK(err)) { + return err; + } + err = smbconf_set_parameter(ctx, GLOBAL_NAME, param, val); + + return err; +} + +/** + * get the value of a configuration parameter as a string + */ +sbcErr smbconf_get_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + const char *param, + char **valstr) +{ + if (valstr == NULL) { + return SBC_ERR_INVALID_PARAM; + } + + 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. + */ +sbcErr smbconf_get_global_parameter(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *param, + char **valstr) +{ + sbcErr err; + + err = smbconf_global_check(ctx); + if (!SBC_ERROR_IS_OK(err)) { + return err; + } + + err = smbconf_get_parameter(ctx, mem_ctx, GLOBAL_NAME, param, + valstr); + + return err; +} + +/** + * delete a parameter from configuration + */ +sbcErr smbconf_delete_parameter(struct smbconf_ctx *ctx, + const char *service, const char *param) +{ + return ctx->ops->delete_parameter(ctx, service, param); +} + +/** + * Delete a global parameter. + * + * Create [global] if it does not exist. + */ +sbcErr smbconf_delete_global_parameter(struct smbconf_ctx *ctx, + const char *param) +{ + sbcErr err; + + err = smbconf_global_check(ctx); + if (!SBC_ERROR_IS_OK(err)) { + return err; + } + err = smbconf_delete_parameter(ctx, GLOBAL_NAME, param); + + return err; +} + +sbcErr smbconf_get_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + const char *service, + uint32_t *num_includes, char ***includes) +{ + return ctx->ops->get_includes(ctx, mem_ctx, service, num_includes, + includes); +} + +sbcErr smbconf_get_global_includes(struct smbconf_ctx *ctx, + TALLOC_CTX *mem_ctx, + uint32_t *num_includes, char ***includes) +{ + sbcErr err; + + err = smbconf_global_check(ctx); + if (!SBC_ERROR_IS_OK(err)) { + return err; + } + err = smbconf_get_includes(ctx, mem_ctx, GLOBAL_NAME, + num_includes, includes); + + return err; +} + +sbcErr smbconf_set_includes(struct smbconf_ctx *ctx, + const char *service, + uint32_t num_includes, const char **includes) +{ + return ctx->ops->set_includes(ctx, service, num_includes, includes); +} + +sbcErr smbconf_set_global_includes(struct smbconf_ctx *ctx, + uint32_t num_includes, + const char **includes) +{ + sbcErr err; + + err = smbconf_global_check(ctx); + if (!SBC_ERROR_IS_OK(err)) { + return err; + } + err = smbconf_set_includes(ctx, GLOBAL_NAME, + num_includes, includes); + + return err; +} + + +sbcErr smbconf_delete_includes(struct smbconf_ctx *ctx, const char *service) +{ + return ctx->ops->delete_includes(ctx, service); +} + +sbcErr smbconf_delete_global_includes(struct smbconf_ctx *ctx) +{ + sbcErr err; + + err = smbconf_global_check(ctx); + if (!SBC_ERROR_IS_OK(err)) { + return err; + } + err = smbconf_delete_includes(ctx, GLOBAL_NAME); + + return err; +} + +sbcErr smbconf_transaction_start(struct smbconf_ctx *ctx) +{ + return ctx->ops->transaction_start(ctx); +} + +sbcErr smbconf_transaction_commit(struct smbconf_ctx *ctx) +{ + return ctx->ops->transaction_commit(ctx); +} + +sbcErr smbconf_transaction_cancel(struct smbconf_ctx *ctx) +{ + return ctx->ops->transaction_cancel(ctx); +} |