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