Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
[ira/wip.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  * 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 share_params *share)
192 {
193         int ret = -1;
194         struct parm_struct *parm;
195         int pnum = 0;
196         const char *servicename;
197         WERROR werr;
198         char *valstr = NULL;
199         TALLOC_CTX *tmp_ctx = NULL;
200
201         tmp_ctx = talloc_new(ctx);
202         if (tmp_ctx == NULL) {
203                 werr = WERR_NOMEM;
204                 goto done;
205         }
206
207         servicename = (share->service == GLOBAL_SECTION_SNUM)?
208                 GLOBAL_NAME : lp_servicename(share->service);
209
210         if (opt_testmode) {
211                 d_printf("[%s]\n", servicename);
212         } else {
213                 if (libnet_conf_share_exists(servicename)) {
214                         werr = libnet_conf_delete_share(servicename);
215                         if (!W_ERROR_IS_OK(werr)) {
216                                 goto done;
217                         }
218                 }
219         }
220
221         while ((parm = lp_next_parameter(share->service, &pnum, 0)))
222         {
223                 if ((share->service < 0) && (parm->p_class == P_LOCAL)
224                     && !(parm->flags & FLAG_GLOBAL))
225                 {
226                         continue;
227                 }
228
229                 valstr = parm_valstr(tmp_ctx, parm, share);
230
231                 if (parm->type != P_SEP) {
232                         if (opt_testmode) {
233                                 d_printf("\t%s = %s\n", parm->label, valstr);
234                         } else {
235                                 werr = libnet_conf_set_parameter(servicename,
236                                                                  parm->label,
237                                                                  valstr);
238                                 if (!W_ERROR_IS_OK(werr)) {
239                                         d_fprintf(stderr,
240                                                   "Error setting parameter '%s'"
241                                                   ": %s\n", parm->label,
242                                                    dos_errstr(werr));
243                                         goto done;
244                                 }
245                         }
246                 }
247         }
248
249         if (opt_testmode) {
250                 d_printf("\n");
251         }
252
253         ret = 0;
254
255 done:
256         TALLOC_FREE(tmp_ctx);
257         return ret;
258 }
259
260 /* return true iff there are nondefault globals */
261 static bool globals_exist(void)
262 {
263         int i = 0;
264         struct parm_struct *parm;
265
266         while ((parm = lp_next_parameter(GLOBAL_SECTION_SNUM, &i, 0)) != NULL) {
267                 if (parm->type != P_SEP) {
268                         return true;
269                 }
270         }
271         return false;
272 }
273
274 /*
275  * the conf functions
276  */
277
278 static int net_conf_list(int argc, const char **argv)
279 {
280         WERROR werr = WERR_OK;
281         int ret = -1;
282         TALLOC_CTX *ctx;
283         uint32_t num_shares;
284         char **share_names;
285         uint32_t *num_params;
286         char ***param_names;
287         char ***param_values;
288         uint32_t share_count, param_count;
289
290         ctx = talloc_init("list");
291
292         if (argc != 0) {
293                 net_conf_list_usage(argc, argv);
294                 goto done;
295         }
296
297         werr = libnet_conf_get_config(ctx, &num_shares, &share_names,
298                                       &num_params, &param_names,
299                                       &param_values);
300         if (!W_ERROR_IS_OK(werr)) {
301                 d_fprintf(stderr, "Error getting config: %s\n",
302                           dos_errstr(werr));
303                 goto done;
304         }
305
306         for (share_count = 0; share_count < num_shares; share_count++) {
307                 d_printf("[%s]\n", share_names[share_count]);
308                 for (param_count = 0; param_count < num_params[share_count];
309                      param_count++)
310                 {
311                         d_printf("\t%s = %s\n",
312                                  param_names[share_count][param_count],
313                                  param_values[share_count][param_count]);
314                 }
315                 d_printf("\n");
316         }
317
318         ret = 0;
319
320 done:
321         TALLOC_FREE(ctx);
322         return ret;
323 }
324
325 static int net_conf_import(int argc, const char **argv)
326 {
327         int ret = -1;
328         const char *filename = NULL;
329         const char *servicename = NULL;
330         bool service_found = false;
331         TALLOC_CTX *ctx;
332         struct share_iterator *shares;
333         struct share_params *share;
334         struct share_params global_share = { GLOBAL_SECTION_SNUM };
335
336         ctx = talloc_init("net_conf_import");
337
338         switch (argc) {
339                 case 0:
340                 default:
341                         net_conf_import_usage(argc, argv);
342                         goto done;
343                 case 2:
344                         servicename = argv[1];
345                 case 1:
346                         filename = argv[0];
347                         break;
348         }
349
350         DEBUG(3,("net_conf_import: reading configuration from file %s.\n",
351                 filename));
352
353         if (!lp_load(filename,
354                      false,     /* global_only */
355                      true,      /* save_defaults */
356                      false,     /* add_ipc */
357                      true))     /* initialize_globals */
358         {
359                 d_fprintf(stderr, "Error parsing configuration file.\n");
360                 goto done;
361         }
362
363         if (opt_testmode) {
364                 d_printf("\nTEST MODE - "
365                          "would import the following configuration:\n\n");
366         }
367
368         if (((servicename == NULL) && globals_exist()) ||
369             strequal(servicename, GLOBAL_NAME))
370         {
371                 service_found = true;
372                 if (import_process_service(ctx, &global_share) != 0) {
373                         goto done;
374                 }
375         }
376
377         if (service_found && (servicename != NULL)) {
378                 ret = 0;
379                 goto done;
380         }
381
382         if (!(shares = share_list_all(ctx))) {
383                 d_fprintf(stderr, "Could not list shares...\n");
384                 goto done;
385         }
386         while ((share = next_share(shares)) != NULL) {
387                 if ((servicename == NULL)
388                     || strequal(servicename, lp_servicename(share->service)))
389                 {
390                         service_found = true;
391                         if (import_process_service(ctx, share)!= 0) {
392                                 goto done;
393                         }
394                 }
395         }
396
397         if ((servicename != NULL) && !service_found) {
398                 d_printf("Share %s not found in file %s\n",
399                          servicename, filename);
400                 goto done;
401
402         }
403
404         ret = 0;
405
406 done:
407         TALLOC_FREE(ctx);
408         return ret;
409 }
410
411 static int net_conf_listshares(int argc, const char **argv)
412 {
413         WERROR werr = WERR_OK;
414         int ret = -1;
415         uint32_t count, num_shares = 0;
416         char **share_names = NULL;
417         TALLOC_CTX *ctx;
418
419         ctx = talloc_init("listshares");
420
421         if (argc != 0) {
422                 net_conf_listshares_usage(argc, argv);
423                 goto done;
424         }
425
426         werr = libnet_conf_get_share_names(ctx, &num_shares, &share_names);
427         if (!W_ERROR_IS_OK(werr)) {
428                 goto done;
429         }
430
431         for (count = 0; count < num_shares; count++)
432         {
433                 d_printf("%s\n", share_names[count]);
434         }
435
436         ret = 0;
437
438 done:
439         TALLOC_FREE(ctx);
440         return ret;
441 }
442
443 static int net_conf_drop(int argc, const char **argv)
444 {
445         int ret = -1;
446         WERROR werr;
447
448         if (argc != 0) {
449                 net_conf_drop_usage(argc, argv);
450                 goto done;
451         }
452
453         werr = libnet_conf_drop();
454         if (!W_ERROR_IS_OK(werr)) {
455                 d_fprintf(stderr, "Error deleting configuration: %s\n",
456                           dos_errstr(werr));
457                 goto done;
458         }
459
460         ret = 0;
461
462 done:
463         return ret;
464 }
465
466 static int net_conf_showshare(int argc, const char **argv)
467 {
468         int ret = -1;
469         WERROR werr = WERR_OK;
470         const char *sharename = NULL;
471         TALLOC_CTX *ctx;
472         uint32_t num_params;
473         uint32_t count;
474         char **param_names;
475         char **param_values;
476
477         ctx = talloc_init("showshare");
478
479         if (argc != 1) {
480                 net_conf_showshare_usage(argc, argv);
481                 goto done;
482         }
483
484         sharename = argv[0];
485
486         werr = libnet_conf_get_share(ctx, sharename, &num_params,
487                                      &param_names, &param_values);
488         if (!W_ERROR_IS_OK(werr)) {
489                 d_printf("error getting share parameters: %s\n",
490                          dos_errstr(werr));
491                 goto done;
492         }
493
494         d_printf("[%s]\n", sharename);
495
496         for (count = 0; count < num_params; count++) {
497                 d_printf("\t%s = %s\n", param_names[count],
498                          param_values[count]);
499         }
500
501         ret = 0;
502
503 done:
504         TALLOC_FREE(ctx);
505         return ret;
506 }
507
508 /**
509  * Add a share, with a couple of standard parameters, partly optional.
510  *
511  * This is a high level utility function of the net conf utility,
512  * not a direct frontend to the libnet_conf API.
513  */
514 static int net_conf_addshare(int argc, const char **argv)
515 {
516         int ret = -1;
517         WERROR werr = WERR_OK;
518         char *sharename = NULL;
519         const char *path = NULL;
520         const char *comment = NULL;
521         const char *guest_ok = "no";
522         const char *writeable = "no";
523         SMB_STRUCT_STAT sbuf;
524
525         switch (argc) {
526                 case 0:
527                 case 1:
528                 default:
529                         net_conf_addshare_usage(argc, argv);
530                         goto done;
531                 case 5:
532                         comment = argv[4];
533                 case 4:
534                         if (!strnequal(argv[3], "guest_ok=", 9)) {
535                                 net_conf_addshare_usage(argc, argv);
536                                 goto done;
537                         }
538                         switch (argv[3][9]) {
539                                 case 'y':
540                                 case 'Y':
541                                         guest_ok = "yes";
542                                         break;
543                                 case 'n':
544                                 case 'N':
545                                         guest_ok = "no";
546                                         break;
547                                 default:
548                                         net_conf_addshare_usage(argc, argv);
549                                         goto done;
550                         }
551                 case 3:
552                         if (!strnequal(argv[2], "writeable=", 10)) {
553                                 net_conf_addshare_usage(argc, argv);
554                                 goto done;
555                         }
556                         switch (argv[2][10]) {
557                                 case 'y':
558                                 case 'Y':
559                                         writeable = "yes";
560                                         break;
561                                 case 'n':
562                                 case 'N':
563                                         writeable = "no";
564                                         break;
565                                 default:
566                                         net_conf_addshare_usage(argc, argv);
567                                         goto done;
568                         }
569                 case 2:
570                         path = argv[1];
571                         sharename = strdup_lower(argv[0]);
572                         break;
573         }
574
575         /*
576          * validate arguments
577          */
578
579         /* validate share name */
580
581         if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS,
582                                strlen(sharename)))
583         {
584                 d_fprintf(stderr, "ERROR: share name %s contains "
585                         "invalid characters (any of %s)\n",
586                         sharename, INVALID_SHARENAME_CHARS);
587                 goto done;
588         }
589
590         if (getpwnam(sharename)) {
591                 d_fprintf(stderr, "ERROR: share name %s is already a valid "
592                           "system user name.\n", sharename);
593                 goto done;
594         }
595
596         if (strequal(sharename, GLOBAL_NAME)) {
597                 d_fprintf(stderr,
598                           "ERROR: 'global' is not a valid share name.\n");
599                 goto done;
600         }
601
602         if (libnet_conf_share_exists(sharename)) {
603                 d_fprintf(stderr, "ERROR: share %s already exists.\n",
604                           sharename);
605                 goto done;
606         }
607
608         /* validate path */
609
610         if (path[0] != '/') {
611                 d_fprintf(stderr,
612                           "Error: path '%s' is not an absolute path.\n",
613                           path);
614                 goto done;
615         }
616
617         if (sys_stat(path, &sbuf) != 0) {
618                 d_fprintf(stderr,
619                           "ERROR: cannot stat path '%s' to ensure "
620                           "this is a directory.\n"
621                           "Error was '%s'.\n",
622                           path, strerror(errno));
623                 goto done;
624         }
625
626         if (!S_ISDIR(sbuf.st_mode)) {
627                 d_fprintf(stderr,
628                           "ERROR: path '%s' is not a directory.\n",
629                           path);
630                 goto done;
631         }
632
633         /*
634          * create the share
635          */
636
637         werr = libnet_conf_create_share(sharename);
638         if (!W_ERROR_IS_OK(werr)) {
639                 d_fprintf(stderr, "Error creating share %s: %s\n",
640                           sharename, dos_errstr(werr));
641                 goto done;
642         }
643
644         /*
645          * fill the share with parameters
646          */
647
648         werr = libnet_conf_set_parameter(sharename, "path", path);
649         if (!W_ERROR_IS_OK(werr)) {
650                 d_fprintf(stderr, "Error setting parameter %s: %s\n",
651                           "path", dos_errstr(werr));
652                 goto done;
653         }
654
655         if (comment != NULL) {
656                 werr = libnet_conf_set_parameter(sharename, "comment", comment);
657                 if (!W_ERROR_IS_OK(werr)) {
658                         d_fprintf(stderr, "Error setting parameter %s: %s\n",
659                                   "comment", dos_errstr(werr));
660                         goto done;
661                 }
662         }
663
664         werr = libnet_conf_set_parameter(sharename, "guest ok", guest_ok);
665         if (!W_ERROR_IS_OK(werr)) {
666                 d_fprintf(stderr, "Error setting parameter %s: %s\n",
667                           "'guest ok'", dos_errstr(werr));
668                 goto done;
669         }
670
671         werr = libnet_conf_set_parameter(sharename, "writeable", writeable);
672         if (!W_ERROR_IS_OK(werr)) {
673                 d_fprintf(stderr, "Error setting parameter %s: %s\n",
674                           "writeable", dos_errstr(werr));
675                 goto done;
676         }
677
678         ret = 0;
679
680 done:
681         SAFE_FREE(sharename);
682         return ret;
683 }
684
685 static int net_conf_delshare(int argc, const char **argv)
686 {
687         int ret = -1;
688         const char *sharename = NULL;
689         WERROR werr = WERR_OK;
690
691         if (argc != 1) {
692                 net_conf_delshare_usage(argc, argv);
693                 goto done;
694         }
695         sharename = argv[0];
696
697         werr = libnet_conf_delete_share(sharename);
698         if (!W_ERROR_IS_OK(werr)) {
699                 d_fprintf(stderr, "Error deleting share %s: %s\n",
700                           sharename, dos_errstr(werr));
701                 goto done;
702         }
703
704         ret = 0;
705 done:
706         return ret;
707 }
708
709 static int net_conf_setparm(int argc, const char **argv)
710 {
711         int ret = -1;
712         WERROR werr = WERR_OK;
713         char *service = NULL;
714         char *param = NULL;
715         const char *value_str = NULL;
716
717         if (argc != 3) {
718                 net_conf_setparm_usage(argc, argv);
719                 goto done;
720         }
721         service = strdup_lower(argv[0]);
722         param = strdup_lower(argv[1]);
723         value_str = argv[2];
724
725         if (!libnet_conf_share_exists(service)) {
726                 werr = libnet_conf_create_share(service);
727                 if (!W_ERROR_IS_OK(werr)) {
728                         d_fprintf(stderr, "Error creating share '%s': %s\n",
729                                   service, dos_errstr(werr));
730                         goto done;
731                 }
732         }
733
734         werr = libnet_conf_set_parameter(service, param, value_str);
735
736         if (!W_ERROR_IS_OK(werr)) {
737                 d_fprintf(stderr, "Error setting value '%s': %s\n",
738                           param, dos_errstr(werr));
739                 goto done;
740         }
741
742         ret = 0;
743
744 done:
745         SAFE_FREE(service);
746         SAFE_FREE(param);
747         return ret;
748 }
749
750 static int net_conf_getparm(int argc, const char **argv)
751 {
752         int ret = -1;
753         WERROR werr = WERR_OK;
754         char *service = NULL;
755         char *param = NULL;
756         char *valstr = NULL;
757         TALLOC_CTX *ctx;
758
759         ctx = talloc_init("getparm");
760
761         if (argc != 2) {
762                 net_conf_getparm_usage(argc, argv);
763                 goto done;
764         }
765         service = strdup_lower(argv[0]);
766         param = strdup_lower(argv[1]);
767
768         werr = libnet_conf_get_parameter(ctx, service, param, &valstr);
769
770         if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
771                 d_fprintf(stderr,
772                           "Error: given service '%s' does not exist.\n",
773                           service);
774                 goto done;
775         } else if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) {
776                 d_fprintf(stderr,
777                           "Error: given parameter '%s' is not set.\n",
778                           param);
779                 goto done;
780         } else if (!W_ERROR_IS_OK(werr)) {
781                 d_fprintf(stderr, "Error getting value '%s': %s.\n",
782                           param, dos_errstr(werr));
783                 goto done;
784         }
785
786         d_printf("%s\n", valstr);
787
788         ret = 0;
789 done:
790         SAFE_FREE(service);
791         SAFE_FREE(param);
792         TALLOC_FREE(ctx);
793         return ret;
794 }
795
796 static int net_conf_delparm(int argc, const char **argv)
797 {
798         int ret = -1;
799         WERROR werr = WERR_OK;
800         char *service = NULL;
801         char *param = NULL;
802
803         if (argc != 2) {
804                 net_conf_delparm_usage(argc, argv);
805                 goto done;
806         }
807         service = strdup_lower(argv[0]);
808         param = strdup_lower(argv[1]);
809
810         werr = libnet_conf_delete_parameter(service, param);
811
812         if (W_ERROR_EQUAL(werr, WERR_NO_SUCH_SERVICE)) {
813                 d_fprintf(stderr,
814                           "Error: given service '%s' does not exist.\n",
815                           service);
816                 goto done;
817         } else if (W_ERROR_EQUAL(werr, WERR_INVALID_PARAM)) {
818                 d_fprintf(stderr,
819                           "Error: given parameter '%s' is not set.\n",
820                           param);
821                 goto done;
822         } else if (!W_ERROR_IS_OK(werr)) {
823                 d_fprintf(stderr, "Error deleting value '%s': %s.\n",
824                           param, dos_errstr(werr));
825                 goto done;
826         }
827
828         ret = 0;
829
830 done:
831         SAFE_FREE(service);
832         SAFE_FREE(param);
833         return ret;
834 }
835
836 /*
837  * Entry-point for all the CONF functions.
838  */
839
840 int net_conf(int argc, const char **argv)
841 {
842         int ret = -1;
843         struct functable2 func[] = {
844                 {"list", net_conf_list,
845                  "Dump the complete configuration in smb.conf like format."},
846                 {"import", net_conf_import,
847                  "Import configuration from file in smb.conf format."},
848                 {"listshares", net_conf_listshares,
849                  "List the share names."},
850                 {"drop", net_conf_drop,
851                  "Delete the complete configuration."},
852                 {"showshare", net_conf_showshare,
853                  "Show the definition of a share."},
854                 {"addshare", net_conf_addshare,
855                  "Create a new share."},
856                 {"delshare", net_conf_delshare,
857                  "Delete a share."},
858                 {"setparm", net_conf_setparm,
859                  "Store a parameter."},
860                 {"getparm", net_conf_getparm,
861                  "Retrieve the value of a parameter."},
862                 {"delparm", net_conf_delparm,
863                  "Delete a parameter."},
864                 {NULL, NULL, NULL}
865         };
866
867         ret = net_run_function2(argc, argv, "net conf", func);
868
869         return ret;
870 }
871