s3:net conf: reduce memory usage of "net conf import".
[ira/wip.git] / source3 / utils / net_conf.c
index 63d5477c9d94930149dafb826ae072e0d718f95a..38a2553e53a1280e51aeec563f95937e42c9886b 100644 (file)
  */
 
 /*
- * This is an interface to the configuration stored inside the
- * samba registry. In the future there might be support for other
- * configuration backends as well.
+ * This is an interface to Samba's configuration as made available
+ * by the libsmbconf interface (source/lib/smbconf/smbconf.c).
+ *
+ * This currently supports local interaction with the configuration
+ * stored in the registry. But other backends and remote access via
+ * rpc might get implemented in the future.
  */
 
 #include "includes.h"
 #include "utils/net.h"
-#include "libnet/libnet.h"
 
-/*
+/**********************************************************************
+ *
  * usage functions
- */
+ *
+ **********************************************************************/
 
-static int net_conf_list_usage(int argc, const char **argv)
+static int net_conf_list_usage(struct net_context *c, int argc,
+                              const char **argv)
 {
        d_printf("USAGE: net conf list\n");
        return -1;
 }
 
-static int net_conf_import_usage(int argc, const char**argv)
+static int net_conf_import_usage(struct net_context *c, int argc,
+                                const char**argv)
 {
        d_printf("USAGE: net conf import [--test|-T] <filename> "
                 "[<servicename>]\n"
                 "\t[--test|-T]    testmode - do not act, just print "
-                                  "what would be done\n"
+                       "what would be done\n"
                 "\t<servicename>  only import service <servicename>, "
-                                  "ignore the rest\n");
+                       "ignore the rest\n");
        return -1;
 }
 
-static int net_conf_listshares_usage(int argc, const char **argv)
+static int net_conf_listshares_usage(struct net_context *c, int argc,
+                                    const char **argv)
 {
        d_printf("USAGE: net conf listshares\n");
        return -1;
 }
 
-static int net_conf_drop_usage(int argc, const char **argv)
+static int net_conf_drop_usage(struct net_context *c, int argc,
+                              const char **argv)
 {
        d_printf("USAGE: net conf drop\n");
        return -1;
 }
 
-static int net_conf_showshare_usage(int argc, const char **argv)
+static int net_conf_showshare_usage(struct net_context *c, int argc,
+                                   const char **argv)
 {
        d_printf("USAGE: net conf showshare <sharename>\n");
        return -1;
 }
 
-static int net_conf_addshare_usage(int argc, const char **argv)
+static int net_conf_addshare_usage(struct net_context *c, int argc,
+                                  const char **argv)
 {
        d_printf("USAGE: net conf addshare <sharename> <path> "
                 "[writeable={y|N} [guest_ok={y|N} [<comment>]]\n"
@@ -81,233 +91,182 @@ static int net_conf_addshare_usage(int argc, const char **argv)
        return -1;
 }
 
-static int net_conf_delshare_usage(int argc, const char **argv)
+static int net_conf_delshare_usage(struct net_context *c, int argc,
+                                  const char **argv)
 {
        d_printf("USAGE: net conf delshare <sharename>\n");
        return -1;
 }
 
-static int net_conf_setparm_usage(int argc, const char **argv)
+static int net_conf_setparm_usage(struct net_context *c, int argc,
+                                 const char **argv)
 {
        d_printf("USAGE: net conf setparm <section> <param> <value>\n");
        return -1;
 }
 
-static int net_conf_getparm_usage(int argc, const char **argv)
+static int net_conf_getparm_usage(struct net_context *c, int argc,
+                                 const char **argv)
 {
        d_printf("USAGE: net conf getparm <section> <param>\n");
        return -1;
 }
 
-static int net_conf_delparm_usage(int argc, const char **argv)
+static int net_conf_delparm_usage(struct net_context *c, int argc,
+                                 const char **argv)
 {
        d_printf("USAGE: net conf delparm <section> <param>\n");
        return -1;
 }
 
+static int net_conf_getincludes_usage(struct net_context *c, int argc,
+                                     const char **argv)
+{
+       d_printf("USAGE: net conf getincludes <section>\n");
+       return -1;
+}
 
-/*
- * Helper functions
- */
-
-static char *parm_valstr(TALLOC_CTX *ctx, struct parm_struct *parm,
-                        struct share_params *share)
+static int net_conf_setincludes_usage(struct net_context *c, int argc,
+                                     const char **argv)
 {
-       char *valstr = NULL;
-       int i = 0;
-       void *ptr = parm->ptr;
-
-       if (parm->p_class == P_LOCAL && share->service >= 0) {
-               ptr = lp_local_ptr(share->service, ptr);
-       }
-
-       switch (parm->type) {
-       case P_CHAR:
-               valstr = talloc_asprintf(ctx, "%c", *(char *)ptr);
-               break;
-       case P_STRING:
-       case P_USTRING:
-               valstr = talloc_asprintf(ctx, "%s", *(char **)ptr);
-               break;
-       case P_BOOL:
-               valstr = talloc_asprintf(ctx, "%s", BOOLSTR(*(bool *)ptr));
-               break;
-       case P_BOOLREV:
-               valstr = talloc_asprintf(ctx, "%s", BOOLSTR(!*(bool *)ptr));
-               break;
-       case P_ENUM:
-               for (i = 0; parm->enum_list[i].name; i++) {
-                       if (*(int *)ptr == parm->enum_list[i].value)
-                       {
-                               valstr = talloc_asprintf(ctx, "%s",
-                                        parm->enum_list[i].name);
-                               break;
-                       }
-               }
-               break;
-       case P_OCTAL: {
-               char *o = octal_string(*(int *)ptr);
-               valstr = talloc_move(ctx, &o);
-               break;
-       }
-       case P_LIST:
-               valstr = talloc_strdup(ctx, "");
-               if ((char ***)ptr && *(char ***)ptr) {
-                       char **list = *(char ***)ptr;
-                       for (; *list; list++) {
-                               /* surround strings with whitespace
-                                * in double quotes */
-                               if (strchr_m(*list, ' '))
-                               {
-                                       valstr = talloc_asprintf_append(
-                                               valstr, "\"%s\"%s",
-                                               *list,
-                                                ((*(list+1))?", ":""));
-                               } else {
-                                       valstr = talloc_asprintf_append(
-                                               valstr, "%s%s", *list,
-                                                ((*(list+1))?", ":""));
-                               }
-                       }
-               }
-               break;
-       case P_INTEGER:
-               valstr = talloc_asprintf(ctx, "%d", *(int *)ptr);
-               break;
-       case P_SEP:
-               break;
-       default:
-               valstr = talloc_asprintf(ctx, "<type unimplemented>\n");
-               break;
-       }
-
-       return valstr;
+       d_printf("USAGE: net conf setincludes <section> [<filename>]*\n");
+       return -1;
 }
 
-static int import_process_service(TALLOC_CTX *ctx,
-                                 struct share_params *share)
+static int net_conf_delincludes_usage(struct net_context *c, int argc,
+                                     const char **argv)
 {
-       int ret = -1;
-       struct parm_struct *parm;
-       int pnum = 0;
-       const char *servicename;
-       WERROR werr;
-       char *valstr = NULL;
-       TALLOC_CTX *tmp_ctx = NULL;
+       d_printf("USAGE: net conf delincludes <section>\n");
+       return -1;
+}
 
-       tmp_ctx = talloc_new(ctx);
-       if (tmp_ctx == NULL) {
-               werr = WERR_NOMEM;
-               goto done;
-       }
 
-       servicename = (share->service == GLOBAL_SECTION_SNUM)?
-               GLOBAL_NAME : lp_servicename(share->service);
+/**********************************************************************
+ *
+ * Helper functions
+ *
+ **********************************************************************/
 
-       if (opt_testmode) {
-               d_printf("[%s]\n", servicename);
-       } else {
-               if (libnet_conf_share_exists(servicename)) {
-                       werr = libnet_conf_delete_share(servicename);
-                       if (!W_ERROR_IS_OK(werr)) {
-                               goto done;
-                       }
+/**
+ * This functions process a service previously loaded with libsmbconf.
+ */
+static WERROR import_process_service(struct net_context *c,
+                                    struct smbconf_ctx *conf_ctx,
+                                    struct smbconf_service *service)
+{
+       uint32_t idx;
+       WERROR werr = WERR_OK;
+       uint32_t num_includes = 0;
+       char **includes = NULL;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+       if (c->opt_testmode) {
+               const char *indent = "";
+               if (service->name != NULL) {
+                       d_printf("[%s]\n", service->name);
+                       indent = "\t";
+               }
+               for (idx = 0; idx < service->num_params; idx++) {
+                       d_printf("%s%s = %s\n", indent,
+                                service->param_names[idx],
+                                service->param_values[idx]);
                }
+               d_printf("\n");
+               goto done;
        }
 
-       while ((parm = lp_next_parameter(share->service, &pnum, 0)))
-       {
-               if ((share->service < 0) && (parm->p_class == P_LOCAL)
-                   && !(parm->flags & FLAG_GLOBAL))
-               {
-                       continue;
+       if (smbconf_share_exists(conf_ctx, service->name)) {
+               werr = smbconf_delete_share(conf_ctx, service->name);
+               if (!W_ERROR_IS_OK(werr)) {
+                       goto done;
                }
+       }
+       werr = smbconf_create_share(conf_ctx, service->name);
+       if (!W_ERROR_IS_OK(werr)) {
+               goto done;
+       }
 
-               valstr = parm_valstr(tmp_ctx, parm, share);
-
-               if (parm->type != P_SEP) {
-                       if (opt_testmode) {
-                               d_printf("\t%s = %s\n", parm->label, valstr);
-                       } else {
-                               werr = libnet_conf_set_parameter(servicename,
-                                                                parm->label,
-                                                                valstr);
-                               if (!W_ERROR_IS_OK(werr)) {
-                                       d_fprintf(stderr,
-                                                 "Error setting parameter '%s'"
-                                                 ": %s\n", parm->label,
-                                                  dos_errstr(werr));
-                                       goto done;
-                               }
+       for (idx = 0; idx < service->num_params; idx ++) {
+               if (strequal(service->param_names[idx], "include")) {
+                       includes = TALLOC_REALLOC_ARRAY(mem_ctx,
+                                                       includes,
+                                                       char *,
+                                                       num_includes+1);
+                       if (includes == NULL) {
+                               werr = WERR_NOMEM;
+                               goto done;
+                       }
+                       includes[num_includes] = talloc_strdup(includes,
+                                               service->param_values[idx]);
+                       if (includes[num_includes] == NULL) {
+                               werr = WERR_NOMEM;
+                               goto done;
+                       }
+                       num_includes++;
+               } else {
+                       werr = smbconf_set_parameter(conf_ctx,
+                                                    service->name,
+                                                    service->param_names[idx],
+                                                    service->param_values[idx]);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               goto done;
                        }
                }
        }
 
-       if (opt_testmode) {
-               d_printf("\n");
-       }
-
-       ret = 0;
+       werr = smbconf_set_includes(conf_ctx, service->name, num_includes,
+                                   (const char **)includes);
 
 done:
-       TALLOC_FREE(tmp_ctx);
-       return ret;
+       TALLOC_FREE(mem_ctx);
+       return werr;
 }
 
-/* return true iff there are nondefault globals */
-static bool globals_exist(void)
-{
-       int i = 0;
-       struct parm_struct *parm;
-
-       while ((parm = lp_next_parameter(GLOBAL_SECTION_SNUM, &i, 0)) != NULL) {
-               if (parm->type != P_SEP) {
-                       return true;
-               }
-       }
-       return false;
-}
 
-/*
- * the conf functions
- */
+/**********************************************************************
+ *
+ * the main conf functions
+ *
+ **********************************************************************/
 
-static int net_conf_list(int argc, const char **argv)
+static int net_conf_list(struct net_context *c, struct smbconf_ctx *conf_ctx,
+                        int argc, const char **argv)
 {
        WERROR werr = WERR_OK;
        int ret = -1;
-       TALLOC_CTX *ctx;
+       TALLOC_CTX *mem_ctx;
        uint32_t num_shares;
-       char **share_names;
-       uint32_t *num_params;
-       char ***param_names;
-       char ***param_values;
        uint32_t share_count, param_count;
+       struct smbconf_service **shares = NULL;
 
-       ctx = talloc_init("list");
+       mem_ctx = talloc_stackframe();
 
-       if (argc != 0) {
-               net_conf_list_usage(argc, argv);
+       if (argc != 0 || c->display_usage) {
+               net_conf_list_usage(c, argc, argv);
                goto done;
        }
 
-       werr = libnet_conf_get_config(ctx, &num_shares, &share_names,
-                                     &num_params, &param_names,
-                                     &param_values);
+       werr = smbconf_get_config(conf_ctx, mem_ctx, &num_shares, &shares);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error getting config: %s\n",
-                         dos_errstr(werr));
+                         win_errstr(werr));
                goto done;
        }
 
        for (share_count = 0; share_count < num_shares; share_count++) {
-               d_printf("[%s]\n", share_names[share_count]);
-               for (param_count = 0; param_count < num_params[share_count];
+               const char *indent = "";
+               if (shares[share_count]->name != NULL) {
+                       d_printf("[%s]\n", shares[share_count]->name);
+                       indent = "\t";
+               }
+               for (param_count = 0;
+                    param_count < shares[share_count]->num_params;
                     param_count++)
                {
-                       d_printf("\t%s = %s\n",
-                                param_names[share_count][param_count],
-                                param_values[share_count][param_count]);
+                       d_printf("%s%s = %s\n",
+                                indent,
+                                shares[share_count]->param_names[param_count],
+                                shares[share_count]->param_values[param_count]);
                }
                d_printf("\n");
        }
@@ -315,30 +274,37 @@ static int net_conf_list(int argc, const char **argv)
        ret = 0;
 
 done:
-       TALLOC_FREE(ctx);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
-static int net_conf_import(int argc, const char **argv)
+static int net_conf_import(struct net_context *c, struct smbconf_ctx *conf_ctx,
+                          int argc, const char **argv)
 {
        int ret = -1;
        const char *filename = NULL;
        const char *servicename = NULL;
-       bool service_found = false;
-       TALLOC_CTX *ctx;
-       struct share_iterator *shares;
-       struct share_params *share;
-       struct share_params global_share = { GLOBAL_SECTION_SNUM };
+       char *conf_source = NULL;
+       TALLOC_CTX *mem_ctx;
+       struct smbconf_ctx *txt_ctx;
+       WERROR werr;
 
-       ctx = talloc_init("net_conf_import");
+       if (c->display_usage)
+               return net_conf_import_usage(c, argc, argv);
+
+       mem_ctx = talloc_stackframe();
 
        switch (argc) {
                case 0:
                default:
-                       net_conf_import_usage(argc, argv);
+                       net_conf_import_usage(c, argc, argv);
                        goto done;
                case 2:
-                       servicename = argv[1];
+                       servicename = talloc_strdup_lower(mem_ctx, argv[1]);
+                       if (servicename == NULL) {
+                               d_printf("error: out of memory!\n");
+                               goto done;
+                       }
                case 1:
                        filename = argv[0];
                        break;
@@ -347,80 +313,136 @@ static int net_conf_import(int argc, const char **argv)
        DEBUG(3,("net_conf_import: reading configuration from file %s.\n",
                filename));
 
-       if (!lp_load(filename,
-                    false,     /* global_only */
-                    true,      /* save_defaults */
-                    false,     /* add_ipc */
-                    true))     /* initialize_globals */
-       {
-               d_fprintf(stderr, "Error parsing configuration file.\n");
+       conf_source = talloc_asprintf(mem_ctx, "file:%s", filename);
+       if (conf_source == NULL) {
+               d_printf("error: out of memory!\n");
                goto done;
        }
 
-       if (opt_testmode) {
+       werr = smbconf_init(mem_ctx, &txt_ctx, conf_source);
+       if (!W_ERROR_IS_OK(werr)) {
+               d_printf("error loading file '%s': %s\n", filename,
+                        win_errstr(werr));
+               goto done;
+       }
+
+       if (c->opt_testmode) {
                d_printf("\nTEST MODE - "
                         "would import the following configuration:\n\n");
        }
 
-       if (((servicename == NULL) && globals_exist()) ||
-           strequal(servicename, GLOBAL_NAME))
-       {
-               service_found = true;
-               if (import_process_service(ctx, &global_share) != 0) {
+       if (servicename != NULL) {
+               struct smbconf_service *service = NULL;
+
+               werr = smbconf_get_share(txt_ctx, mem_ctx,
+                                        servicename,
+                                        &service);
+               if (!W_ERROR_IS_OK(werr)) {
+                       goto cancel;
+               }
+               werr = import_process_service(c, conf_ctx, service);
+               if (!W_ERROR_IS_OK(werr)) {
+                       goto cancel;
+               }
+       } else {
+               struct smbconf_service **services = NULL;
+               uint32_t num_shares, sidx;
+
+               werr = smbconf_get_config(txt_ctx, mem_ctx,
+                                         &num_shares,
+                                         &services);
+               if (!W_ERROR_IS_OK(werr)) {
+                       goto cancel;
+               }
+               if (!c->opt_testmode) {
+                       werr = smbconf_drop(conf_ctx);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               goto cancel;
+                       }
+               }
+
+               /*
+                * Wrap the importing of shares into a transaction,
+                * but only 100 at a time, in order to serve memory.
+                * The allocated memory accumulates across the actions
+                * within the transaction, and for me, some 1500
+                * imported shares, the MAX_TALLOC_SIZE of 256 MB
+                * was exceeded.
+                */
+               werr = smbconf_transaction_start(conf_ctx);
+               if (!W_ERROR_IS_OK(werr)) {
+                       d_printf("error starting transaction: %s\n",
+                                win_errstr(werr));
                        goto done;
                }
-       }
 
-       if (service_found && (servicename != NULL)) {
-               ret = 0;
-               goto done;
-       }
+               for (sidx = 0; sidx < num_shares; sidx++) {
+                       werr = import_process_service(c, conf_ctx,
+                                                     services[sidx]);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               goto cancel;
+                       }
 
-       if (!(shares = share_list_all(ctx))) {
-               d_fprintf(stderr, "Could not list shares...\n");
-               goto done;
-       }
-       while ((share = next_share(shares)) != NULL) {
-               if ((servicename == NULL)
-                   || strequal(servicename, lp_servicename(share->service)))
-               {
-                       service_found = true;
-                       if (import_process_service(ctx, share)!= 0) {
+                       if (sidx % 100) {
+                               continue;
+                       }
+
+                       werr = smbconf_transaction_commit(conf_ctx);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               d_printf("error committing transaction: %s\n",
+                                        win_errstr(werr));
+                               goto done;
+                       }
+                       werr = smbconf_transaction_start(conf_ctx);
+                       if (!W_ERROR_IS_OK(werr)) {
+                               d_printf("error starting transaction: %s\n",
+                                        win_errstr(werr));
                                goto done;
                        }
                }
        }
 
-       if ((servicename != NULL) && !service_found) {
-               d_printf("Share %s not found in file %s\n",
-                        servicename, filename);
-               goto done;
-
+       werr = smbconf_transaction_commit(conf_ctx);
+       if (!W_ERROR_IS_OK(werr)) {
+               d_printf("error committing transaction: %s\n",
+                        win_errstr(werr));
+       } else {
+               ret = 0;
        }
 
-       ret = 0;
+       goto done;
+
+cancel:
+       werr = smbconf_transaction_cancel(conf_ctx);
+       if (!W_ERROR_IS_OK(werr)) {
+               d_printf("error cancelling transaction: %s\n",
+                        win_errstr(werr));
+       }
 
 done:
-       TALLOC_FREE(ctx);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
-static int net_conf_listshares(int argc, const char **argv)
+static int net_conf_listshares(struct net_context *c,
+                              struct smbconf_ctx *conf_ctx, int argc,
+                              const char **argv)
 {
        WERROR werr = WERR_OK;
        int ret = -1;
        uint32_t count, num_shares = 0;
        char **share_names = NULL;
-       TALLOC_CTX *ctx;
+       TALLOC_CTX *mem_ctx;
 
-       ctx = talloc_init("listshares");
+       mem_ctx = talloc_stackframe();
 
-       if (argc != 0) {
-               net_conf_listshares_usage(argc, argv);
+       if (argc != 0 || c->display_usage) {
+               net_conf_listshares_usage(c, argc, argv);
                goto done;
        }
 
-       werr = libnet_conf_get_share_names(ctx, &num_shares, &share_names);
+       werr = smbconf_get_share_names(conf_ctx, mem_ctx, &num_shares,
+                                      &share_names);
        if (!W_ERROR_IS_OK(werr)) {
                goto done;
        }
@@ -433,24 +455,25 @@ static int net_conf_listshares(int argc, const char **argv)
        ret = 0;
 
 done:
-       TALLOC_FREE(ctx);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
-static int net_conf_drop(int argc, const char **argv)
+static int net_conf_drop(struct net_context *c, struct smbconf_ctx *conf_ctx,
+                        int argc, const char **argv)
 {
        int ret = -1;
        WERROR werr;
 
-       if (argc != 0) {
-               net_conf_drop_usage(argc, argv);
+       if (argc != 0 || c->display_usage) {
+               net_conf_drop_usage(c, argc, argv);
                goto done;
        }
 
-       werr = libnet_conf_drop();
+       werr = smbconf_drop(conf_ctx);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error deleting configuration: %s\n",
-                         dos_errstr(werr));
+                         win_errstr(werr));
                goto done;
        }
 
@@ -460,45 +483,48 @@ done:
        return ret;
 }
 
-static int net_conf_showshare(int argc, const char **argv)
+static int net_conf_showshare(struct net_context *c,
+                             struct smbconf_ctx *conf_ctx, int argc,
+                             const char **argv)
 {
        int ret = -1;
        WERROR werr = WERR_OK;
        const char *sharename = NULL;
-       TALLOC_CTX *ctx;
-       uint32_t num_params;
+       TALLOC_CTX *mem_ctx;
        uint32_t count;
-       char **param_names;
-       char **param_values;
+       struct smbconf_service *service = NULL;
 
-       ctx = talloc_init("showshare");
+       mem_ctx = talloc_stackframe();
 
-       if (argc != 1) {
-               net_conf_showshare_usage(argc, argv);
+       if (argc != 1 || c->display_usage) {
+               net_conf_showshare_usage(c, argc, argv);
                goto done;
        }
 
-       sharename = argv[0];
+       sharename = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (sharename == NULL) {
+               d_printf("error: out of memory!\n");
+               goto done;
+       }
 
-       werr = libnet_conf_get_share(ctx, sharename, &num_params,
-                                    &param_names, &param_values);
+       werr = smbconf_get_share(conf_ctx, mem_ctx, sharename, &service);
        if (!W_ERROR_IS_OK(werr)) {
                d_printf("error getting share parameters: %s\n",
-                        dos_errstr(werr));
+                        win_errstr(werr));
                goto done;
        }
 
        d_printf("[%s]\n", sharename);
 
-       for (count = 0; count < num_params; count++) {
-               d_printf("\t%s = %s\n", param_names[count],
-                        param_values[count]);
+       for (count = 0; count < service->num_params; count++) {
+               d_printf("\t%s = %s\n", service->param_names[count],
+                        service->param_values[count]);
        }
 
        ret = 0;
 
 done:
-       TALLOC_FREE(ctx);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
@@ -506,9 +532,11 @@ done:
  * Add a share, with a couple of standard parameters, partly optional.
  *
  * This is a high level utility function of the net conf utility,
- * not a direct frontend to the libnet_conf API.
+ * not a direct frontend to the smbconf API.
  */
-static int net_conf_addshare(int argc, const char **argv)
+static int net_conf_addshare(struct net_context *c,
+                            struct smbconf_ctx *conf_ctx, int argc,
+                            const char **argv)
 {
        int ret = -1;
        WERROR werr = WERR_OK;
@@ -518,18 +546,25 @@ static int net_conf_addshare(int argc, const char **argv)
        const char *guest_ok = "no";
        const char *writeable = "no";
        SMB_STRUCT_STAT sbuf;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+       if (c->display_usage) {
+               net_conf_addshare_usage(c, argc, argv);
+               ret = 0;
+               goto done;
+       }
 
        switch (argc) {
                case 0:
                case 1:
                default:
-                       net_conf_addshare_usage(argc, argv);
+                       net_conf_addshare_usage(c, argc, argv);
                        goto done;
                case 5:
                        comment = argv[4];
                case 4:
                        if (!strnequal(argv[3], "guest_ok=", 9)) {
-                               net_conf_addshare_usage(argc, argv);
+                               net_conf_addshare_usage(c, argc, argv);
                                goto done;
                        }
                        switch (argv[3][9]) {
@@ -542,12 +577,12 @@ static int net_conf_addshare(int argc, const char **argv)
                                        guest_ok = "no";
                                        break;
                                default:
-                                       net_conf_addshare_usage(argc, argv);
+                                       net_conf_addshare_usage(c, argc, argv);
                                        goto done;
                        }
                case 3:
                        if (!strnequal(argv[2], "writeable=", 10)) {
-                               net_conf_addshare_usage(argc, argv);
+                               net_conf_addshare_usage(c, argc, argv);
                                goto done;
                        }
                        switch (argv[2][10]) {
@@ -560,12 +595,17 @@ static int net_conf_addshare(int argc, const char **argv)
                                        writeable = "no";
                                        break;
                                default:
-                                       net_conf_addshare_usage(argc, argv);
+                                       net_conf_addshare_usage(c, argc, argv);
                                        goto done;
                        }
                case 2:
                        path = argv[1];
-                       sharename = strdup_lower(argv[0]);
+                       sharename = talloc_strdup_lower(mem_ctx, argv[0]);
+                       if (sharename == NULL) {
+                               d_printf("error: out of memory!\n");
+                               goto done;
+                       }
+
                        break;
        }
 
@@ -584,19 +624,13 @@ static int net_conf_addshare(int argc, const char **argv)
                goto done;
        }
 
-       if (getpwnam(sharename)) {
-               d_fprintf(stderr, "ERROR: share name %s is already a valid "
-                         "system user name.\n", sharename);
-               goto done;
-       }
-
        if (strequal(sharename, GLOBAL_NAME)) {
                d_fprintf(stderr,
                          "ERROR: 'global' is not a valid share name.\n");
                goto done;
        }
 
-       if (libnet_conf_share_exists(sharename)) {
+       if (smbconf_share_exists(conf_ctx, sharename)) {
                d_fprintf(stderr, "ERROR: share %s already exists.\n",
                          sharename);
                goto done;
@@ -631,10 +665,10 @@ static int net_conf_addshare(int argc, const char **argv)
         * create the share
         */
 
-       werr = libnet_conf_create_share(sharename);
+       werr = smbconf_create_share(conf_ctx, sharename);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error creating share %s: %s\n",
-                         sharename, dos_errstr(werr));
+                         sharename, win_errstr(werr));
                goto done;
        }
 
@@ -642,118 +676,155 @@ static int net_conf_addshare(int argc, const char **argv)
         * fill the share with parameters
         */
 
-       werr = libnet_conf_set_parameter(sharename, "path", path);
+       werr = smbconf_set_parameter(conf_ctx, sharename, "path", path);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error setting parameter %s: %s\n",
-                         "path", dos_errstr(werr));
+                         "path", win_errstr(werr));
                goto done;
        }
 
        if (comment != NULL) {
-               werr = libnet_conf_set_parameter(sharename, "comment", comment);
+               werr = smbconf_set_parameter(conf_ctx, sharename, "comment",
+                                            comment);
                if (!W_ERROR_IS_OK(werr)) {
                        d_fprintf(stderr, "Error setting parameter %s: %s\n",
-                                 "comment", dos_errstr(werr));
+                                 "comment", win_errstr(werr));
                        goto done;
                }
        }
 
-       werr = libnet_conf_set_parameter(sharename, "guest ok", guest_ok);
+       werr = smbconf_set_parameter(conf_ctx, sharename, "guest ok", guest_ok);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error setting parameter %s: %s\n",
-                         "'guest ok'", dos_errstr(werr));
+                         "'guest ok'", win_errstr(werr));
                goto done;
        }
 
-       werr = libnet_conf_set_parameter(sharename, "writeable", writeable);
+       werr = smbconf_set_parameter(conf_ctx, sharename, "writeable",
+                                    writeable);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error setting parameter %s: %s\n",
-                         "writeable", dos_errstr(werr));
+                         "writeable", win_errstr(werr));
                goto done;
        }
 
        ret = 0;
 
 done:
-       SAFE_FREE(sharename);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
-static int net_conf_delshare(int argc, const char **argv)
+static int net_conf_delshare(struct net_context *c,
+                            struct smbconf_ctx *conf_ctx, int argc,
+                            const char **argv)
 {
        int ret = -1;
        const char *sharename = NULL;
        WERROR werr = WERR_OK;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
 
-       if (argc != 1) {
-               net_conf_delshare_usage(argc, argv);
+       if (argc != 1 || c->display_usage) {
+               net_conf_delshare_usage(c, argc, argv);
+               goto done;
+       }
+       sharename = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (sharename == NULL) {
+               d_printf("error: out of memory!\n");
                goto done;
        }
-       sharename = argv[0];
 
-       werr = libnet_conf_delete_share(sharename);
+       werr = smbconf_delete_share(conf_ctx, sharename);
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error deleting share %s: %s\n",
-                         sharename, dos_errstr(werr));
+                         sharename, win_errstr(werr));
                goto done;
        }
 
        ret = 0;
 done:
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
-static int net_conf_setparm(int argc, const char **argv)
+static int net_conf_setparm(struct net_context *c, struct smbconf_ctx *conf_ctx,
+                           int argc, const char **argv)
 {
        int ret = -1;
        WERROR werr = WERR_OK;
        char *service = NULL;
        char *param = NULL;
        const char *value_str = NULL;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
 
-       if (argc != 3) {
-               net_conf_setparm_usage(argc, argv);
+       if (argc != 3 || c->display_usage) {
+               net_conf_setparm_usage(c, argc, argv);
+               goto done;
+       }
+       service = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (service == NULL) {
+               d_printf("error: out of memory!\n");
+               goto done;
+       }
+       param = talloc_strdup_lower(mem_ctx, argv[1]);
+       if (param == NULL) {
+               d_printf("error: out of memory!\n");
                goto done;
        }
-       service = strdup_lower(argv[0]);
-       param = strdup_lower(argv[1]);
        value_str = argv[2];
 
-       werr = libnet_conf_set_parameter(service, param, value_str);
+       if (!smbconf_share_exists(conf_ctx, service)) {
+               werr = smbconf_create_share(conf_ctx, service);
+               if (!W_ERROR_IS_OK(werr)) {
+                       d_fprintf(stderr, "Error creating share '%s': %s\n",
+                                 service, win_errstr(werr));
+                       goto done;
+               }
+       }
+
+       werr = smbconf_set_parameter(conf_ctx, service, param, value_str);
 
        if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error setting value '%s': %s\n",
-                         param, dos_errstr(werr));
+                         param, win_errstr(werr));
                goto done;
        }
 
        ret = 0;
 
 done:
-       SAFE_FREE(service);
-       SAFE_FREE(param);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
-static int net_conf_getparm(int argc, const char **argv)
+static int net_conf_getparm(struct net_context *c, struct smbconf_ctx *conf_ctx,
+                           int argc, const char **argv)
 {
        int ret = -1;
        WERROR werr = WERR_OK;
        char *service = NULL;
        char *param = NULL;
        char *valstr = NULL;
-       TALLOC_CTX *ctx;
+       TALLOC_CTX *mem_ctx;
 
-       ctx = talloc_init("getparm");
+       mem_ctx = talloc_stackframe();
 
-       if (argc != 2) {
-               net_conf_getparm_usage(argc, argv);
+       if (argc != 2 || c->display_usage) {
+               net_conf_getparm_usage(c, argc, argv);
+               goto done;
+       }
+       service = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (service == NULL) {
+               d_printf("error: out of memory!\n");
+               goto done;
+       }
+       param = talloc_strdup_lower(mem_ctx, argv[1]);
+       if (param == NULL) {
+               d_printf("error: out of memory!\n");
                goto done;
        }
-       service = strdup_lower(argv[0]);
-       param = strdup_lower(argv[1]);
 
-       werr = libnet_conf_get_parameter(ctx, service, param, &valstr);
+       werr = smbconf_get_parameter(conf_ctx, mem_ctx, service, param, &valstr);
 
        if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
                d_fprintf(stderr,
@@ -767,7 +838,7 @@ static int net_conf_getparm(int argc, const char **argv)
                goto done;
        } else if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error getting value '%s': %s.\n",
-                         param, dos_errstr(werr));
+                         param, win_errstr(werr));
                goto done;
        }
 
@@ -775,27 +846,35 @@ static int net_conf_getparm(int argc, const char **argv)
 
        ret = 0;
 done:
-       SAFE_FREE(service);
-       SAFE_FREE(param);
-       TALLOC_FREE(ctx);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
-static int net_conf_delparm(int argc, const char **argv)
+static int net_conf_delparm(struct net_context *c, struct smbconf_ctx *conf_ctx,
+                           int argc, const char **argv)
 {
        int ret = -1;
        WERROR werr = WERR_OK;
        char *service = NULL;
        char *param = NULL;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
 
-       if (argc != 2) {
-               net_conf_delparm_usage(argc, argv);
+       if (argc != 2 || c->display_usage) {
+               net_conf_delparm_usage(c, argc, argv);
+               goto done;
+       }
+       service = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (service == NULL) {
+               d_printf("error: out of memory!\n");
+               goto done;
+       }
+       param = talloc_strdup_lower(mem_ctx, argv[1]);
+       if (param == NULL) {
+               d_printf("error: out of memory!\n");
                goto done;
        }
-       service = strdup_lower(argv[0]);
-       param = strdup_lower(argv[1]);
 
-       werr = libnet_conf_delete_parameter(service, param);
+       werr = smbconf_delete_parameter(conf_ctx, service, param);
 
        if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
                d_fprintf(stderr,
@@ -809,52 +888,333 @@ static int net_conf_delparm(int argc, const char **argv)
                goto done;
        } else if (!W_ERROR_IS_OK(werr)) {
                d_fprintf(stderr, "Error deleting value '%s': %s.\n",
-                         param, dos_errstr(werr));
+                         param, win_errstr(werr));
+               goto done;
+       }
+
+       ret = 0;
+
+done:
+       TALLOC_FREE(mem_ctx);
+       return ret;
+}
+
+static int net_conf_getincludes(struct net_context *c,
+                               struct smbconf_ctx *conf_ctx,
+                               int argc, const char **argv)
+{
+       WERROR werr;
+       uint32_t num_includes;
+       uint32_t count;
+       char *service;
+       char **includes = NULL;
+       int ret = -1;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+       if (argc != 1 || c->display_usage) {
+               net_conf_getincludes_usage(c, argc, argv);
+               goto done;
+       }
+
+       service = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (service == NULL) {
+               d_printf("error: out of memory!\n");
+               goto done;
+       }
+
+       werr = smbconf_get_includes(conf_ctx, mem_ctx, service,
+                                   &num_includes, &includes);
+       if (!W_ERROR_IS_OK(werr)) {
+               d_printf("error getting includes: %s\n", win_errstr(werr));
                goto done;
        }
 
+       for (count = 0; count < num_includes; count++) {
+               d_printf("include = %s\n", includes[count]);
+       }
+
        ret = 0;
 
 done:
-       SAFE_FREE(service);
-       SAFE_FREE(param);
+       TALLOC_FREE(mem_ctx);
        return ret;
 }
 
+static int net_conf_setincludes(struct net_context *c,
+                               struct smbconf_ctx *conf_ctx,
+                               int argc, const char **argv)
+{
+       WERROR werr;
+       char *service;
+       uint32_t num_includes;
+       const char **includes;
+       int ret = -1;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+       if (argc < 1 || c->display_usage) {
+               net_conf_setincludes_usage(c, argc, argv);
+               goto done;
+       }
+
+       service = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (service == NULL) {
+               d_printf("error: out of memory!\n");
+               goto done;
+       }
+
+       num_includes = argc - 1;
+       if (num_includes == 0) {
+               includes = NULL;
+       } else {
+               includes = argv + 1;
+       }
+
+       werr = smbconf_set_includes(conf_ctx, service, num_includes, includes);
+       if (!W_ERROR_IS_OK(werr)) {
+               d_printf("error setting includes: %s\n", win_errstr(werr));
+               goto done;
+       }
+
+       ret = 0;
+
+done:
+       TALLOC_FREE(mem_ctx);
+       return ret;
+}
+
+static int net_conf_delincludes(struct net_context *c,
+                               struct smbconf_ctx *conf_ctx,
+                               int argc, const char **argv)
+{
+       WERROR werr;
+       char *service;
+       int ret = -1;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+
+       if (argc != 1 || c->display_usage) {
+               net_conf_delincludes_usage(c, argc, argv);
+               goto done;
+       }
+
+       service = talloc_strdup_lower(mem_ctx, argv[0]);
+       if (service == NULL) {
+               d_printf("error: out of memory!\n");
+               goto done;
+       }
+
+       werr = smbconf_delete_includes(conf_ctx, service);
+       if (!W_ERROR_IS_OK(werr)) {
+               d_printf("error deleting includes: %s\n", win_errstr(werr));
+               goto done;
+       }
+
+       ret = 0;
+
+done:
+       TALLOC_FREE(mem_ctx);
+       return ret;
+}
+
+
+/**********************************************************************
+ *
+ * Wrapper and net_conf_run_function mechanism.
+ *
+ **********************************************************************/
+
+/**
+ * Wrapper function to call the main conf functions.
+ * The wrapper calls handles opening and closing of the
+ * configuration.
+ */
+static int net_conf_wrap_function(struct net_context *c,
+                                 int (*fn)(struct net_context *,
+                                           struct smbconf_ctx *,
+                                           int, const char **),
+                                 int argc, const char **argv)
+{
+       WERROR werr;
+       TALLOC_CTX *mem_ctx = talloc_stackframe();
+       struct smbconf_ctx *conf_ctx;
+       int ret = -1;
+
+       werr = smbconf_init(mem_ctx, &conf_ctx, "registry:");
+
+       if (!W_ERROR_IS_OK(werr)) {
+               return -1;
+       }
+
+       ret = fn(c, conf_ctx, argc, argv);
+
+       smbconf_shutdown(conf_ctx);
+
+       return ret;
+}
+
+/*
+ * We need a functable struct of our own, because the
+ * functions are called through a wrapper that handles
+ * the opening and closing of the configuration, and so on.
+ */
+struct conf_functable {
+       const char *funcname;
+       int (*fn)(struct net_context *c, struct smbconf_ctx *ctx, int argc,
+                 const char **argv);
+       int valid_transports;
+       const char *description;
+       const char *usage;
+};
+
+/**
+ * This imitates net_run_function but calls the main functions
+ * through the wrapper net_conf_wrap_function().
+ */
+static int net_conf_run_function(struct net_context *c, int argc,
+                                const char **argv, const char *whoami,
+                                struct conf_functable *table)
+{
+       int i;
+
+       if (argc != 0) {
+               for (i=0; table[i].funcname; i++) {
+                       if (StrCaseCmp(argv[0], table[i].funcname) == 0)
+                               return net_conf_wrap_function(c, table[i].fn,
+                                                             argc-1,
+                                                             argv+1);
+               }
+       }
+
+       d_printf("Usage:\n");
+       for (i=0; table[i].funcname; i++) {
+               if (c->display_usage == false)
+                       d_printf("%s %-15s %s\n", whoami, table[i].funcname,
+                                table[i].description);
+               else
+                       d_printf("%s\n", table[i].usage);
+       }
+
+       return c->display_usage?0:-1;
+}
+
 /*
  * Entry-point for all the CONF functions.
  */
 
-int net_conf(int argc, const char **argv)
+int net_conf(struct net_context *c, int argc, const char **argv)
 {
        int ret = -1;
-       struct functable2 func[] = {
-               {"list", net_conf_list,
-                "Dump the complete configuration in smb.conf like format."},
-               {"import", net_conf_import,
-                "Import configuration from file in smb.conf format."},
-               {"listshares", net_conf_listshares,
-                "List the registry shares."},
-               {"drop", net_conf_drop,
-                "Delete the complete configuration from registry."},
-               {"showshare", net_conf_showshare,
-                "Show the definition of a registry share."},
-               {"addshare", net_conf_addshare,
-                "Create a new registry share."},
-               {"delshare", net_conf_delshare,
-                "Delete a registry share."},
-               {"setparm", net_conf_setparm,
-                "Store a parameter."},
-               {"getparm", net_conf_getparm,
-                "Retrieve the value of a parameter."},
-               {"delparm", net_conf_delparm,
-                "Delete a parameter."},
-               {NULL, NULL, NULL}
+       struct conf_functable func_table[] = {
+               {
+                       "list",
+                       net_conf_list,
+                       NET_TRANSPORT_LOCAL,
+                       "Dump the complete configuration in smb.conf like "
+                       "format.",
+                       "net conf list\n"
+                       "    Dump the complete configuration in smb.conf like "
+                       "format."
+
+               },
+               {
+                       "import",
+                       net_conf_import,
+                       NET_TRANSPORT_LOCAL,
+                       "Import configuration from file in smb.conf format.",
+                       "net conf import\n"
+                       "    Import configuration from file in smb.conf format."
+               },
+               {
+                       "listshares",
+                       net_conf_listshares,
+                       NET_TRANSPORT_LOCAL,
+                       "List the share names.",
+                       "net conf listshares\n"
+                       "    List the share names."
+               },
+               {
+                       "drop",
+                       net_conf_drop,
+                       NET_TRANSPORT_LOCAL,
+                       "Delete the complete configuration.",
+                       "net conf drop\n"
+                       "    Delete the complete configuration."
+               },
+               {
+                       "showshare",
+                       net_conf_showshare,
+                       NET_TRANSPORT_LOCAL,
+                       "Show the definition of a share.",
+                       "net conf showshare\n"
+                       "    Show the definition of a share."
+               },
+               {
+                       "addshare",
+                       net_conf_addshare,
+                       NET_TRANSPORT_LOCAL,
+                       "Create a new share.",
+                       "net conf addshare\n"
+                       "    Create a new share."
+               },
+               {
+                       "delshare",
+                       net_conf_delshare,
+                       NET_TRANSPORT_LOCAL,
+                       "Delete a share.",
+                       "net conf delshare\n"
+                       "    Delete a share."
+               },
+               {
+                       "setparm",
+                       net_conf_setparm,
+                       NET_TRANSPORT_LOCAL,
+                       "Store a parameter.",
+                       "net conf setparm\n"
+                       "    Store a parameter."
+               },
+               {
+                       "getparm",
+                       net_conf_getparm,
+                       NET_TRANSPORT_LOCAL,
+                       "Retrieve the value of a parameter.",
+                       "net conf getparm\n"
+                       "    Retrieve the value of a parameter."
+               },
+               {
+                       "delparm",
+                       net_conf_delparm,
+                       NET_TRANSPORT_LOCAL,
+                       "Delete a parameter.",
+                       "net conf delparm\n"
+                       "    Delete a parameter."
+               },
+               {
+                       "getincludes",
+                       net_conf_getincludes,
+                       NET_TRANSPORT_LOCAL,
+                       "Show the includes of a share definition.",
+                       "net conf getincludes\n"
+                       "    Show the includes of a share definition."
+               },
+               {
+                       "setincludes",
+                       net_conf_setincludes,
+                       NET_TRANSPORT_LOCAL,
+                       "Set includes for a share.",
+                       "net conf setincludes\n"
+                       "    Set includes for a share."
+               },
+               {
+                       "delincludes",
+                       net_conf_delincludes,
+                       NET_TRANSPORT_LOCAL,
+                       "Delete includes from a share definition.",
+                       "net conf setincludes\n"
+                       "    Delete includes from a share definition."
+               },
+               {NULL, NULL, 0, NULL, NULL}
        };
 
-       ret = net_run_function2(argc, argv, "net conf", func);
-
-       regdb_close();
+       ret = net_conf_run_function(c, argc, argv, "net conf", func_table);
 
        return ret;
 }