Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
[samba.git] / source3 / utils / net_conf.c
1 /*
2  *  Samba Unix/Linux SMB client library
3  *  Distributed SMB/CIFS Server Management Utility
4  *  Local configuration interface
5  *  Copyright (C) Michael Adam 2007-2008
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 /*
22  * This is an interface to Samba's configuration as made available
23  * by the libnet_conf interface (source/libnet/libnet_conf.c).
24  *
25  * This currently supports local interaction with the configuration
26  * stored in the registry. But other backends and remote access via
27  * rpc might get implemented in the future.
28  */
29
30 #include "includes.h"
31 #include "utils/net.h"
32 #include "libnet/libnet.h"
33
34 /**********************************************************************
35  *
36  * usage functions
37  *
38  **********************************************************************/
39
40 static int net_conf_list_usage(int argc, const char **argv)
41 {
42         d_printf("USAGE: net conf list\n");
43         return -1;
44 }
45
46 static int net_conf_import_usage(int argc, const char**argv)
47 {
48         d_printf("USAGE: net conf import [--test|-T] <filename> "
49                  "[<servicename>]\n"
50                  "\t[--test|-T]    testmode - do not act, just print "
51                         "what would be done\n"
52                  "\t<servicename>  only import service <servicename>, "
53                         "ignore the rest\n");
54         return -1;
55 }
56
57 static int net_conf_listshares_usage(int argc, const char **argv)
58 {
59         d_printf("USAGE: net conf listshares\n");
60         return -1;
61 }
62
63 static int net_conf_drop_usage(int argc, const char **argv)
64 {
65         d_printf("USAGE: net conf drop\n");
66         return -1;
67 }
68
69 static int net_conf_showshare_usage(int argc, const char **argv)
70 {
71         d_printf("USAGE: net conf showshare <sharename>\n");
72         return -1;
73 }
74
75 static int net_conf_addshare_usage(int argc, const char **argv)
76 {
77         d_printf("USAGE: net conf addshare <sharename> <path> "
78                  "[writeable={y|N} [guest_ok={y|N} [<comment>]]\n"
79                  "\t<sharename>      the new share name.\n"
80                  "\t<path>           the path on the filesystem to export.\n"
81                  "\twriteable={y|N}  set \"writeable to \"yes\" or "
82                  "\"no\" (default) on this share.\n"
83                  "\tguest_ok={y|N}   set \"guest ok\" to \"yes\" or "
84                  "\"no\" (default)   on this share.\n"
85                  "\t<comment>        optional comment for the new share.\n");
86         return -1;
87 }
88
89 static int net_conf_delshare_usage(int argc, const char **argv)
90 {
91         d_printf("USAGE: net conf delshare <sharename>\n");
92         return -1;
93 }
94
95 static int net_conf_setparm_usage(int argc, const char **argv)
96 {
97         d_printf("USAGE: net conf setparm <section> <param> <value>\n");
98         return -1;
99 }
100
101 static int net_conf_getparm_usage(int argc, const char **argv)
102 {
103         d_printf("USAGE: net conf getparm <section> <param>\n");
104         return -1;
105 }
106
107 static int net_conf_delparm_usage(int argc, const char **argv)
108 {
109         d_printf("USAGE: net conf delparm <section> <param>\n");
110         return -1;
111 }
112
113
114 /**********************************************************************
115  *
116  * Helper functions
117  *
118  **********************************************************************/
119
120 /**
121  * This formats an in-memory smbconf parameter to a string.
122  * The result string is allocated with talloc.
123  */
124 static char *parm_valstr(TALLOC_CTX *ctx, struct parm_struct *parm,
125                          struct share_params *share)
126 {
127         char *valstr = NULL;
128         int i = 0;
129         void *ptr = parm->ptr;
130
131         if (parm->p_class == P_LOCAL && share->service >= 0) {
132                 ptr = lp_local_ptr(share->service, ptr);
133         }
134
135         switch (parm->type) {
136         case P_CHAR:
137                 valstr = talloc_asprintf(ctx, "%c", *(char *)ptr);
138                 break;
139         case P_STRING:
140         case P_USTRING:
141                 valstr = talloc_asprintf(ctx, "%s", *(char **)ptr);
142                 break;
143         case P_BOOL:
144                 valstr = talloc_asprintf(ctx, "%s", BOOLSTR(*(bool *)ptr));
145                 break;
146         case P_BOOLREV:
147                 valstr = talloc_asprintf(ctx, "%s", BOOLSTR(!*(bool *)ptr));
148                 break;
149         case P_ENUM:
150                 for (i = 0; parm->enum_list[i].name; i++) {
151                         if (*(int *)ptr == parm->enum_list[i].value)
152                         {
153                                 valstr = talloc_asprintf(ctx, "%s",
154                                         parm->enum_list[i].name);
155                                 break;
156                         }
157                 }
158                 break;
159         case P_OCTAL: {
160                 char *o = octal_string(*(int *)ptr);
161                 valstr = talloc_move(ctx, &o);
162                 break;
163         }
164         case P_LIST:
165                 valstr = talloc_strdup(ctx, "");
166                 if ((char ***)ptr && *(char ***)ptr) {
167                         char **list = *(char ***)ptr;
168                         for (; *list; list++) {
169                                 /* surround strings with whitespace
170                                  * in double quotes */
171                                 if (strchr_m(*list, ' '))
172                                 {
173                                         valstr = talloc_asprintf_append(
174                                                 valstr, "\"%s\"%s",
175                                                 *list,
176                                                  ((*(list+1))?", ":""));
177                                 } else {
178                                         valstr = talloc_asprintf_append(
179                                                 valstr, "%s%s", *list,
180                                                  ((*(list+1))?", ":""));
181                                 }
182                         }
183                 }
184                 break;
185         case P_INTEGER:
186                 valstr = talloc_asprintf(ctx, "%d", *(int *)ptr);
187                 break;
188         case P_SEP:
189                 break;
190         default:
191                 valstr = talloc_asprintf(ctx, "<type unimplemented>\n");
192                 break;
193         }
194
195         return valstr;
196 }
197
198 /**
199  * This functions imports a configuration that has previously
200  * been loaded with lp_load() to registry.
201  */
202 static int import_process_service(TALLOC_CTX *ctx,
203                                   struct libnet_conf_ctx *conf_ctx,
204                                   struct share_params *share)
205 {
206         int ret = -1;
207         struct parm_struct *parm;
208         int pnum = 0;
209         const char *servicename;
210         WERROR werr;
211         char *valstr = NULL;
212         TALLOC_CTX *tmp_ctx = NULL;
213
214         tmp_ctx = talloc_new(ctx);
215         if (tmp_ctx == NULL) {
216                 werr = WERR_NOMEM;
217                 goto done;
218         }
219
220         servicename = (share->service == GLOBAL_SECTION_SNUM)?
221                 GLOBAL_NAME : lp_servicename(share->service);
222
223         if (opt_testmode) {
224                 d_printf("[%s]\n", servicename);
225         } else {
226                 if (libnet_conf_share_exists(conf_ctx, servicename)) {
227                         werr = libnet_conf_delete_share(conf_ctx, servicename);
228                         if (!W_ERROR_IS_OK(werr)) {
229                                 goto done;
230                         }
231                 }
232                 werr = libnet_conf_create_share(conf_ctx, servicename);
233                 if (!W_ERROR_IS_OK(werr)) {
234                         goto done;
235                 }
236         }
237
238         while ((parm = lp_next_parameter(share->service, &pnum, 0)))
239         {
240                 if ((share->service < 0) && (parm->p_class == P_LOCAL)
241                     && !(parm->flags & FLAG_GLOBAL))
242                 {
243                         continue;
244                 }
245
246                 valstr = parm_valstr(tmp_ctx, parm, share);
247
248                 if (parm->type != P_SEP) {
249                         if (opt_testmode) {
250                                 d_printf("\t%s = %s\n", parm->label, valstr);
251                         } else {
252                                 werr = libnet_conf_set_parameter(conf_ctx,
253                                                                  servicename,
254                                                                  parm->label,
255                                                                  valstr);
256                                 if (!W_ERROR_IS_OK(werr)) {
257                                         d_fprintf(stderr,
258                                                   "Error setting parameter '%s'"
259                                                   ": %s\n", parm->label,
260                                                    dos_errstr(werr));
261                                         goto done;
262                                 }
263                         }
264                 }
265         }
266
267         if (opt_testmode) {
268                 d_printf("\n");
269         }
270
271         ret = 0;
272
273 done:
274         TALLOC_FREE(tmp_ctx);
275         return ret;
276 }
277
278 /**
279  * Return true iff there are nondefault globals in the
280  * currently loaded configuration.
281  */
282 static bool globals_exist(void)
283 {
284         int i = 0;
285         struct parm_struct *parm;
286
287         while ((parm = lp_next_parameter(GLOBAL_SECTION_SNUM, &i, 0)) != NULL) {
288                 if (parm->type != P_SEP) {
289                         return true;
290                 }
291         }
292         return false;
293 }
294
295
296 /**********************************************************************
297  *
298  * the main conf functions
299  *
300  **********************************************************************/
301
302 static int net_conf_list(struct libnet_conf_ctx *conf_ctx,
303                          int argc, const char **argv)
304 {
305         WERROR werr = WERR_OK;
306         int ret = -1;
307         TALLOC_CTX *ctx;
308         uint32_t num_shares;
309         char **share_names;
310         uint32_t *num_params;
311         char ***param_names;
312         char ***param_values;
313         uint32_t share_count, param_count;
314
315         ctx = talloc_init("list");
316
317         if (argc != 0) {
318                 net_conf_list_usage(argc, argv);
319                 goto done;
320         }
321
322         werr = libnet_conf_get_config(ctx, conf_ctx, &num_shares, &share_names,
323                                       &num_params, &param_names, &param_values);
324         if (!W_ERROR_IS_OK(werr)) {
325                 d_fprintf(stderr, "Error getting config: %s\n",
326                           dos_errstr(werr));
327                 goto done;
328         }
329
330         for (share_count = 0; share_count < num_shares; share_count++) {
331                 d_printf("[%s]\n", share_names[share_count]);
332                 for (param_count = 0; param_count < num_params[share_count];
333                      param_count++)
334                 {
335                         d_printf("\t%s = %s\n",
336                                  param_names[share_count][param_count],
337                                  param_values[share_count][param_count]);
338                 }
339                 d_printf("\n");
340         }
341
342         ret = 0;
343
344 done:
345         TALLOC_FREE(ctx);
346         return ret;
347 }
348
349 static int net_conf_import(struct libnet_conf_ctx *conf_ctx,
350                            int argc, const char **argv)
351 {
352         int ret = -1;
353         const char *filename = NULL;
354         const char *servicename = NULL;
355         bool service_found = false;
356         TALLOC_CTX *ctx;
357         struct share_iterator *shares;
358         struct share_params *share;
359         struct share_params global_share = { GLOBAL_SECTION_SNUM };
360
361         ctx = talloc_init("net_conf_import");
362
363         switch (argc) {
364                 case 0:
365                 default:
366                         net_conf_import_usage(argc, argv);
367                         goto done;
368                 case 2:
369                         servicename = argv[1];
370                 case 1:
371                         filename = argv[0];
372                         break;
373         }
374
375         DEBUG(3,("net_conf_import: reading configuration from file %s.\n",
376                 filename));
377
378         if (!lp_load(filename,
379                      false,     /* global_only */
380                      true,      /* save_defaults */
381                      false,     /* add_ipc */
382                      true))     /* initialize_globals */
383         {
384                 d_fprintf(stderr, "Error parsing configuration file.\n");
385                 goto done;
386         }
387
388         if (opt_testmode) {
389                 d_printf("\nTEST MODE - "
390                          "would import the following configuration:\n\n");
391         }
392
393         if (((servicename == NULL) && globals_exist()) ||
394             strequal(servicename, GLOBAL_NAME))
395         {
396                 service_found = true;
397                 if (import_process_service(ctx, conf_ctx, &global_share) != 0) {
398                         goto done;
399                 }
400         }
401
402         if (service_found && (servicename != NULL)) {
403                 ret = 0;
404                 goto done;
405         }
406
407         if (!(shares = share_list_all(ctx))) {
408                 d_fprintf(stderr, "Could not list shares...\n");
409                 goto done;
410         }
411         while ((share = next_share(shares)) != NULL) {
412                 if ((servicename == NULL)
413                     || strequal(servicename, lp_servicename(share->service)))
414                 {
415                         service_found = true;
416                         if (import_process_service(ctx, conf_ctx, share)!= 0) {
417                                 goto done;
418                         }
419                 }
420         }
421
422         if ((servicename != NULL) && !service_found) {
423                 d_printf("Share %s not found in file %s\n",
424                          servicename, filename);
425                 goto done;
426
427         }
428
429         ret = 0;
430
431 done:
432         TALLOC_FREE(ctx);
433         return ret;
434 }
435
436 static int net_conf_listshares(struct libnet_conf_ctx *conf_ctx,
437                                int argc, const char **argv)
438 {
439         WERROR werr = WERR_OK;
440         int ret = -1;
441         uint32_t count, num_shares = 0;
442         char **share_names = NULL;
443         TALLOC_CTX *ctx;
444
445         ctx = talloc_init("listshares");
446
447         if (argc != 0) {
448                 net_conf_listshares_usage(argc, argv);
449                 goto done;
450         }
451
452         werr = libnet_conf_get_share_names(ctx, conf_ctx, &num_shares,
453                                            &share_names);
454         if (!W_ERROR_IS_OK(werr)) {
455                 goto done;
456         }
457
458         for (count = 0; count < num_shares; count++)
459         {
460                 d_printf("%s\n", share_names[count]);
461         }
462
463         ret = 0;
464
465 done:
466         TALLOC_FREE(ctx);
467         return ret;
468 }
469
470 static int net_conf_drop(struct libnet_conf_ctx *conf_ctx,
471                          int argc, const char **argv)
472 {
473         int ret = -1;
474         WERROR werr;
475
476         if (argc != 0) {
477                 net_conf_drop_usage(argc, argv);
478                 goto done;
479         }
480
481         werr = libnet_conf_drop(conf_ctx);
482         if (!W_ERROR_IS_OK(werr)) {
483                 d_fprintf(stderr, "Error deleting configuration: %s\n",
484                           dos_errstr(werr));
485                 goto done;
486         }
487
488         ret = 0;
489
490 done:
491         return ret;
492 }
493
494 static int net_conf_showshare(struct libnet_conf_ctx *conf_ctx,
495                               int argc, const char **argv)
496 {
497         int ret = -1;
498         WERROR werr = WERR_OK;
499         const char *sharename = NULL;
500         TALLOC_CTX *ctx;
501         uint32_t num_params;
502         uint32_t count;
503         char **param_names;
504         char **param_values;
505
506         ctx = talloc_init("showshare");
507
508         if (argc != 1) {
509                 net_conf_showshare_usage(argc, argv);
510                 goto done;
511         }
512
513         sharename = argv[0];
514
515         werr = libnet_conf_get_share(ctx, conf_ctx, sharename, &num_params,
516                                      &param_names, &param_values);
517         if (!W_ERROR_IS_OK(werr)) {
518                 d_printf("error getting share parameters: %s\n",
519                          dos_errstr(werr));
520                 goto done;
521         }
522
523         d_printf("[%s]\n", sharename);
524
525         for (count = 0; count < num_params; count++) {
526                 d_printf("\t%s = %s\n", param_names[count],
527                          param_values[count]);
528         }
529
530         ret = 0;
531
532 done:
533         TALLOC_FREE(ctx);
534         return ret;
535 }
536
537 /**
538  * Add a share, with a couple of standard parameters, partly optional.
539  *
540  * This is a high level utility function of the net conf utility,
541  * not a direct frontend to the libnet_conf API.
542  */
543 static int net_conf_addshare(struct libnet_conf_ctx *conf_ctx,
544                              int argc, const char **argv)
545 {
546         int ret = -1;
547         WERROR werr = WERR_OK;
548         char *sharename = NULL;
549         const char *path = NULL;
550         const char *comment = NULL;
551         const char *guest_ok = "no";
552         const char *writeable = "no";
553         SMB_STRUCT_STAT sbuf;
554
555         switch (argc) {
556                 case 0:
557                 case 1:
558                 default:
559                         net_conf_addshare_usage(argc, argv);
560                         goto done;
561                 case 5:
562                         comment = argv[4];
563                 case 4:
564                         if (!strnequal(argv[3], "guest_ok=", 9)) {
565                                 net_conf_addshare_usage(argc, argv);
566                                 goto done;
567                         }
568                         switch (argv[3][9]) {
569                                 case 'y':
570                                 case 'Y':
571                                         guest_ok = "yes";
572                                         break;
573                                 case 'n':
574                                 case 'N':
575                                         guest_ok = "no";
576                                         break;
577                                 default:
578                                         net_conf_addshare_usage(argc, argv);
579                                         goto done;
580                         }
581                 case 3:
582                         if (!strnequal(argv[2], "writeable=", 10)) {
583                                 net_conf_addshare_usage(argc, argv);
584                                 goto done;
585                         }
586                         switch (argv[2][10]) {
587                                 case 'y':
588                                 case 'Y':
589                                         writeable = "yes";
590                                         break;
591                                 case 'n':
592                                 case 'N':
593                                         writeable = "no";
594                                         break;
595                                 default:
596                                         net_conf_addshare_usage(argc, argv);
597                                         goto done;
598                         }
599                 case 2:
600                         path = argv[1];
601                         sharename = strdup_lower(argv[0]);
602                         break;
603         }
604
605         /*
606          * validate arguments
607          */
608
609         /* validate share name */
610
611         if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS,
612                                strlen(sharename)))
613         {
614                 d_fprintf(stderr, "ERROR: share name %s contains "
615                         "invalid characters (any of %s)\n",
616                         sharename, INVALID_SHARENAME_CHARS);
617                 goto done;
618         }
619
620         if (getpwnam(sharename)) {
621                 d_fprintf(stderr, "ERROR: share name %s is already a valid "
622                           "system user name.\n", sharename);
623                 goto done;
624         }
625
626         if (strequal(sharename, GLOBAL_NAME)) {
627                 d_fprintf(stderr,
628                           "ERROR: 'global' is not a valid share name.\n");
629                 goto done;
630         }
631
632         if (libnet_conf_share_exists(conf_ctx, sharename)) {
633                 d_fprintf(stderr, "ERROR: share %s already exists.\n",
634                           sharename);
635                 goto done;
636         }
637
638         /* validate path */
639
640         if (path[0] != '/') {
641                 d_fprintf(stderr,
642                           "Error: path '%s' is not an absolute path.\n",
643                           path);
644                 goto done;
645         }
646
647         if (sys_stat(path, &sbuf) != 0) {
648                 d_fprintf(stderr,
649                           "ERROR: cannot stat path '%s' to ensure "
650                           "this is a directory.\n"
651                           "Error was '%s'.\n",
652                           path, strerror(errno));
653                 goto done;
654         }
655
656         if (!S_ISDIR(sbuf.st_mode)) {
657                 d_fprintf(stderr,
658                           "ERROR: path '%s' is not a directory.\n",
659                           path);
660                 goto done;
661         }
662
663         /*
664          * create the share
665          */
666
667         werr = libnet_conf_create_share(conf_ctx, sharename);
668         if (!W_ERROR_IS_OK(werr)) {
669                 d_fprintf(stderr, "Error creating share %s: %s\n",
670                           sharename, dos_errstr(werr));
671                 goto done;
672         }
673
674         /*
675          * fill the share with parameters
676          */
677
678         werr = libnet_conf_set_parameter(conf_ctx, sharename, "path", path);
679         if (!W_ERROR_IS_OK(werr)) {
680                 d_fprintf(stderr, "Error setting parameter %s: %s\n",
681                           "path", dos_errstr(werr));
682                 goto done;
683         }
684
685         if (comment != NULL) {
686                 werr = libnet_conf_set_parameter(conf_ctx, sharename, "comment",
687                                                  comment);
688                 if (!W_ERROR_IS_OK(werr)) {
689                         d_fprintf(stderr, "Error setting parameter %s: %s\n",
690                                   "comment", dos_errstr(werr));
691                         goto done;
692                 }
693         }
694
695         werr = libnet_conf_set_parameter(conf_ctx, sharename, "guest ok",
696                                          guest_ok);
697         if (!W_ERROR_IS_OK(werr)) {
698                 d_fprintf(stderr, "Error setting parameter %s: %s\n",
699                           "'guest ok'", dos_errstr(werr));
700                 goto done;
701         }
702
703         werr = libnet_conf_set_parameter(conf_ctx, sharename, "writeable",
704                                          writeable);
705         if (!W_ERROR_IS_OK(werr)) {
706                 d_fprintf(stderr, "Error setting parameter %s: %s\n",
707                           "writeable", dos_errstr(werr));
708                 goto done;
709         }
710
711         ret = 0;
712
713 done:
714         SAFE_FREE(sharename);
715         return ret;
716 }
717
718 static int net_conf_delshare(struct libnet_conf_ctx *conf_ctx,
719                              int argc, const char **argv)
720 {
721         int ret = -1;
722         const char *sharename = NULL;
723         WERROR werr = WERR_OK;
724
725         if (argc != 1) {
726                 net_conf_delshare_usage(argc, argv);
727                 goto done;
728         }
729         sharename = argv[0];
730
731         werr = libnet_conf_delete_share(conf_ctx, sharename);
732         if (!W_ERROR_IS_OK(werr)) {
733                 d_fprintf(stderr, "Error deleting share %s: %s\n",
734                           sharename, dos_errstr(werr));
735                 goto done;
736         }
737
738         ret = 0;
739 done:
740         return ret;
741 }
742
743 static int net_conf_setparm(struct libnet_conf_ctx *conf_ctx,
744                             int argc, const char **argv)
745 {
746         int ret = -1;
747         WERROR werr = WERR_OK;
748         char *service = NULL;
749         char *param = NULL;
750         const char *value_str = NULL;
751
752         if (argc != 3) {
753                 net_conf_setparm_usage(argc, argv);
754                 goto done;
755         }
756         service = strdup_lower(argv[0]);
757         param = strdup_lower(argv[1]);
758         value_str = argv[2];
759
760         if (!libnet_conf_share_exists(conf_ctx, service)) {
761                 werr = libnet_conf_create_share(conf_ctx, service);
762                 if (!W_ERROR_IS_OK(werr)) {
763                         d_fprintf(stderr, "Error creating share '%s': %s\n",
764                                   service, dos_errstr(werr));
765                         goto done;
766                 }
767         }
768
769         werr = libnet_conf_set_parameter(conf_ctx, service, param, value_str);
770
771         if (!W_ERROR_IS_OK(werr)) {
772                 d_fprintf(stderr, "Error setting value '%s': %s\n",
773                           param, dos_errstr(werr));
774                 goto done;
775         }
776
777         ret = 0;
778
779 done:
780         SAFE_FREE(service);
781         SAFE_FREE(param);
782         return ret;
783 }
784
785 static int net_conf_getparm(struct libnet_conf_ctx *conf_ctx,
786                             int argc, const char **argv)
787 {
788         int ret = -1;
789         WERROR werr = WERR_OK;
790         char *service = NULL;
791         char *param = NULL;
792         char *valstr = NULL;
793         TALLOC_CTX *ctx;
794
795         ctx = talloc_init("getparm");
796
797         if (argc != 2) {
798                 net_conf_getparm_usage(argc, argv);
799                 goto done;
800         }
801         service = strdup_lower(argv[0]);
802         param = strdup_lower(argv[1]);
803
804         werr = libnet_conf_get_parameter(ctx, conf_ctx, service, param, &valstr);
805
806         if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
807                 d_fprintf(stderr,
808                           "Error: given service '%s' does not exist.\n",
809                           service);
810                 goto done;
811         } else if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) {
812                 d_fprintf(stderr,
813                           "Error: given parameter '%s' is not set.\n",
814                           param);
815                 goto done;
816         } else if (!W_ERROR_IS_OK(werr)) {
817                 d_fprintf(stderr, "Error getting value '%s': %s.\n",
818                           param, dos_errstr(werr));
819                 goto done;
820         }
821
822         d_printf("%s\n", valstr);
823
824         ret = 0;
825 done:
826         SAFE_FREE(service);
827         SAFE_FREE(param);
828         TALLOC_FREE(ctx);
829         return ret;
830 }
831
832 static int net_conf_delparm(struct libnet_conf_ctx *conf_ctx,
833                             int argc, const char **argv)
834 {
835         int ret = -1;
836         WERROR werr = WERR_OK;
837         char *service = NULL;
838         char *param = NULL;
839
840         if (argc != 2) {
841                 net_conf_delparm_usage(argc, argv);
842                 goto done;
843         }
844         service = strdup_lower(argv[0]);
845         param = strdup_lower(argv[1]);
846
847         werr = libnet_conf_delete_parameter(conf_ctx, service, param);
848
849         if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
850                 d_fprintf(stderr,
851                           "Error: given service '%s' does not exist.\n",
852                           service);
853                 goto done;
854         } else if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) {
855                 d_fprintf(stderr,
856                           "Error: given parameter '%s' is not set.\n",
857                           param);
858                 goto done;
859         } else if (!W_ERROR_IS_OK(werr)) {
860                 d_fprintf(stderr, "Error deleting value '%s': %s.\n",
861                           param, dos_errstr(werr));
862                 goto done;
863         }
864
865         ret = 0;
866
867 done:
868         SAFE_FREE(service);
869         SAFE_FREE(param);
870         return ret;
871 }
872
873
874 /**********************************************************************
875  *
876  * Wrapper and net_conf_run_function mechanism.
877  *
878  **********************************************************************/
879
880 /**
881  * Wrapper function to call the main conf functions.
882  * The wrapper calls handles opening and closing of the
883  * configuration.
884  */
885 static int net_conf_wrap_function(int (*fn)(struct libnet_conf_ctx *,
886                                             int, const char **),
887                                   int argc, const char **argv)
888 {
889         WERROR werr;
890         TALLOC_CTX *mem_ctx = talloc_stackframe();
891         struct libnet_conf_ctx *conf_ctx;
892         int ret = -1;
893
894         werr = libnet_conf_open(mem_ctx, &conf_ctx);
895
896         if (!W_ERROR_IS_OK(werr)) {
897                 return -1;
898         }
899
900         ret = fn(conf_ctx, argc, argv);
901
902         libnet_conf_close(conf_ctx);
903
904         return ret;
905 }
906
907 /*
908  * We need a functable struct of our own, because the
909  * functions are called through a wrapper that handles
910  * the opening and closing of the configuration, and so on.
911  */
912 struct conf_functable {
913         const char *funcname;
914         int (*fn)(struct libnet_conf_ctx *ctx, int argc, const char **argv);
915         const char *helptext;
916 };
917
918 /**
919  * This imitates net_run_function2 but calls the main functions
920  * through the wrapper net_conf_wrap_function().
921  */
922 static int net_conf_run_function(int argc, const char **argv,
923                                  const char *whoami,
924                                  struct conf_functable *table)
925 {
926         int i;
927
928         if (argc != 0) {
929                 for (i=0; table[i].funcname; i++) {
930                         if (StrCaseCmp(argv[0], table[i].funcname) == 0)
931                                 return net_conf_wrap_function(table[i].fn,
932                                                               argc-1,
933                                                               argv+1);
934                 }
935         }
936
937         for (i=0; table[i].funcname; i++) {
938                 d_printf("%s %-15s %s\n", whoami, table[i].funcname,
939                          table[i].helptext);
940         }
941
942         return -1;
943 }
944
945 /*
946  * Entry-point for all the CONF functions.
947  */
948
949 int net_conf(int argc, const char **argv)
950 {
951         int ret = -1;
952         struct conf_functable func_table[] = {
953                 {"list", net_conf_list,
954                  "Dump the complete configuration in smb.conf like format."},
955                 {"import", net_conf_import,
956                  "Import configuration from file in smb.conf format."},
957                 {"listshares", net_conf_listshares,
958                  "List the share names."},
959                 {"drop", net_conf_drop,
960                  "Delete the complete configuration."},
961                 {"showshare", net_conf_showshare,
962                  "Show the definition of a share."},
963                 {"addshare", net_conf_addshare,
964                  "Create a new share."},
965                 {"delshare", net_conf_delshare,
966                  "Delete a share."},
967                 {"setparm", net_conf_setparm,
968                  "Store a parameter."},
969                 {"getparm", net_conf_getparm,
970                  "Retrieve the value of a parameter."},
971                 {"delparm", net_conf_delparm,
972                  "Delete a parameter."},
973                 {NULL, NULL, NULL}
974         };
975
976         ret = net_conf_run_function(argc, argv, "net conf", func_table);
977
978         return ret;
979 }
980