r22135: Check in most of Michael Adam's net conf utility. A good share of this patch
[amitay/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
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 2 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, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
20  */
21
22 /*
23  * This currently only an interface to the configuration
24  * stored inside the samba registry. In the future there
25  * might be support for other configuration backends as well.
26  */
27
28 /*
29  * TODO:
30  *
31  *  - check uid 0 for write operations
32  *  - check for valid parameter names and types (loadparm...) ???
33  *  - check for correctness of shares (service_ok) ?
34  *  - refactor to use _internal functions for pieces of code
35  *
36  */
37
38 #include "includes.h"
39 #include "utils/net.h"
40
41 extern REGISTRY_OPS smbconf_reg_ops;
42
43 /* 
44  * usage functions
45  */
46
47 static int net_conf_list_usage(int argc, const char **argv)
48 {
49         d_printf("USAGE: net conf list\n");
50         return -1;
51 }
52
53 static int net_conf_import_usage(int argc, const char**argv)
54 {
55         d_printf("USAGE: net conf import [--test|-T] <filename> [<servicename>]\n"
56                  "\t[--test|-T]    testmode - do not act, just print "
57                                    "what would be done\n"
58                  "\t<servicename>  only import service <servicename>, "
59                                    "ignore the rest\n");
60         return -1;
61 }
62
63 static int net_conf_listshares_usage(int argc, const char **argv)
64 {
65         d_printf("USAGE: net conf listshares\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> <type> <value>\n"
98                  "\t(Supported types are 'dword' and 'sz' by now.)\n");
99         return -1;
100 }
101
102 static int net_conf_getparm_usage(int argc, const char **argv)
103 {
104         d_printf("USAGE: net conf getparm <section> <param>\n");
105         return -1;
106 }
107
108 static int net_conf_delparm_usage(int argc, const char **argv)
109 {
110         d_printf("USAGE: net conf delparm <section> <param>\n");
111         return -1;
112 }
113
114
115 /*
116  * Helper functions
117  */
118
119 static char *format_value(TALLOC_CTX *mem_ctx, struct registry_value *value)
120 {
121         char *result = NULL;
122
123         /* what if mem_ctx = NULL? */
124
125         switch (value->type) {
126         case REG_DWORD:
127                 result = talloc_asprintf(mem_ctx, "%d", value->v.dword);
128                 break;
129         case REG_SZ:
130         case REG_EXPAND_SZ:
131                 result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str);
132                 break;
133         case REG_MULTI_SZ: {
134                 uint32 j;
135                 for (j = 0; j < value->v.multi_sz.num_strings; j++) {
136                         result = talloc_asprintf(mem_ctx, "\"%s\" ", 
137                                                  value->v.multi_sz.strings[j]);
138                 }
139                 break;
140         }
141          case REG_BINARY:
142                 result = talloc_asprintf(mem_ctx, "binary (%d bytes)",
143                                          (int)value->v.binary.length);
144                 break;
145         default:
146                 result = talloc_asprintf(mem_ctx, "<unprintable>");
147                 break;
148         }
149         return result;
150 }
151
152 /*
153  * add a value to a key. 
154  */
155 static WERROR reg_setvalue_internal(struct registry_key *key, 
156                                     const char *valname,
157                                     const char *valtype,
158                                     const char *valstr)
159 {
160         struct registry_value val;
161         WERROR werr = WERR_OK;
162
163         ZERO_STRUCT(val);
164
165         if (strequal(valtype, "dword")) {
166                 val.type = REG_DWORD;
167                 val.v.dword = strtoul(valstr, NULL, 10);
168         }
169         else if (strequal(valtype, "sz")) {
170                 val.type = REG_SZ;
171                 val.v.sz.str = CONST_DISCARD(char *, valstr);
172                 val.v.sz.len = strlen(valstr) + 1;
173         }
174         else {
175                 d_fprintf(stderr, "Sorry, only value types DWORD and SZ implementd currently for setting values.\n");
176                 goto done;
177         }
178
179         werr = reg_setvalue(key, valname, &val);
180         if (!W_ERROR_IS_OK(werr)) {
181                 d_fprintf(stderr,
182                           "Error adding value '%s' to "
183                           "key '%s': %s\n",
184                           valname, key->key->name, dos_errstr(werr));
185         }
186
187 done:
188         return werr;
189 }
190
191 /* 
192  * Open a subkey of KEY_SMBCONF (i.e a service)
193  * - variant without error output (q = quiet)-
194  */
195 static WERROR smbconf_open_path_q(TALLOC_CTX *ctx, const char *subkeyname,
196                                   uint32 desired_access, 
197                                   struct registry_key **key)
198 {
199         WERROR werr = WERR_OK;
200         char *path = NULL;
201
202         if (subkeyname == NULL) {
203                 path = talloc_strdup(ctx, KEY_SMBCONF);
204         }
205         else {
206                 path = talloc_asprintf(ctx, "%s\\%s", KEY_SMBCONF, subkeyname);
207         }
208
209         werr = reg_open_path(ctx, path, desired_access,
210                              get_root_nt_token(), key);
211
212         TALLOC_FREE(path);
213         return werr;
214 }
215
216 /* 
217  * Open a subkey of KEY_SMBCONF (i.e a service)
218  * - variant with error output -
219  */
220 static WERROR smbconf_open_path(TALLOC_CTX *ctx, const char *subkeyname,
221                                 uint32 desired_access, 
222                                 struct registry_key **key)
223 {
224         WERROR werr = WERR_OK;
225
226         werr = smbconf_open_path_q(ctx, subkeyname, desired_access, key);
227         if (!W_ERROR_IS_OK(werr)) {
228                 d_fprintf(stderr, "Error opening registry path '%s\\%s': %s\n",
229                           KEY_SMBCONF, 
230                           (subkeyname == NULL) ? "" : subkeyname, 
231                           dos_errstr(werr));
232         }
233
234         return werr;
235 }
236
237 /*
238  * open the base key KEY_SMBCONF
239  */
240 static WERROR smbconf_open_basepath(TALLOC_CTX *ctx, uint32 desired_access,
241                                     struct registry_key **key)
242 {
243         return smbconf_open_path(ctx, NULL, desired_access, key);
244 }
245
246 /*
247  * delete a subkey of KEY_SMBCONF
248  */
249 static WERROR reg_delkey_internal(TALLOC_CTX *ctx, const char *keyname)
250 {
251         WERROR werr = WERR_OK;
252         struct registry_key *key = NULL;
253
254         werr = smbconf_open_basepath(ctx, REG_KEY_WRITE, &key);
255         if (!W_ERROR_IS_OK(werr)) {
256                 goto done;
257         }
258
259         werr = reg_deletekey(key, keyname);
260         if (!W_ERROR_IS_OK(werr)) {
261                 d_fprintf(stderr, "Error deleting registry key %s\\%s: %s\n",
262                           KEY_SMBCONF, keyname, dos_errstr(werr));
263         }
264
265 done:
266         TALLOC_FREE(key);
267         return werr;
268 }
269
270 /*
271  * create a subkey of KEY_SMBCONF
272  */
273 static WERROR reg_createkey_internal(TALLOC_CTX *ctx,
274                                      const char * subkeyname,
275                                      struct registry_key **newkey)
276 {
277         WERROR werr = WERR_OK;
278         struct registry_key *create_parent = NULL;
279         TALLOC_CTX *create_ctx;
280         enum winreg_CreateAction action = REG_ACTION_NONE;
281
282         /* create a new talloc ctx for creation. it will hold
283          * the intermediate parent key (SMBCONF) for creation
284          * and will be destroyed when leaving this function... */
285         if (!(create_ctx = talloc_new(ctx))) {
286                 werr = WERR_NOMEM;
287                 goto done;
288         }
289
290         werr = smbconf_open_basepath(create_ctx, REG_KEY_WRITE, &create_parent);
291         if (!W_ERROR_IS_OK(werr)) {
292                 goto done;
293         }
294
295         werr = reg_createkey(ctx, create_parent, subkeyname, 
296                              REG_KEY_WRITE, newkey, &action);
297         if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
298                 d_fprintf(stderr, "Key '%s' already exists.\n", subkeyname);
299                 werr = WERR_ALREADY_EXISTS;
300         }
301         if (!W_ERROR_IS_OK(werr)) {
302                 d_fprintf(stderr, "Error creating key %s: %s\n",
303                          subkeyname, dos_errstr(werr));
304         }
305
306 done:
307         TALLOC_FREE(create_ctx);
308         return werr;
309 }
310
311 /*
312  * check if a subkey of KEY_SMBCONF of a given name exists
313  */
314 static BOOL smbconf_key_exists(TALLOC_CTX *ctx, const char *subkeyname)
315 {
316         BOOL ret = False;
317         WERROR werr = WERR_OK;
318         TALLOC_CTX *mem_ctx;
319         struct registry_key *key;
320
321         if (!(mem_ctx = talloc_new(ctx))) {
322                 d_fprintf(stderr, "ERROR: Out of memory...!\n");
323                 goto done;
324         }
325
326         werr = smbconf_open_path_q(mem_ctx, subkeyname, REG_KEY_READ, &key);
327         if (W_ERROR_IS_OK(werr)) {
328                 ret = True;
329         }
330
331 done:
332         TALLOC_FREE(mem_ctx);
333         return ret;
334 }
335
336 static BOOL smbconf_value_exists(TALLOC_CTX *ctx, struct registry_key *key,
337                                  const char *param)
338 {
339         BOOL ret = False;
340         WERROR werr = WERR_OK;
341         struct registry_value *value = NULL;
342
343         werr = reg_queryvalue(ctx, key, param, &value); 
344         if (W_ERROR_IS_OK(werr)) {
345                 ret = True;
346         }
347
348         TALLOC_FREE(value);
349         return ret;
350 }
351
352 static WERROR list_values(TALLOC_CTX *ctx, struct registry_key *key)
353 {
354         WERROR werr = WERR_OK;
355         uint32 idx = 0;
356         struct registry_value *valvalue = NULL;
357         char *valname = NULL;
358
359         for (idx = 0;
360              W_ERROR_IS_OK(werr = reg_enumvalue(ctx, key, idx, &valname,
361                                                 &valvalue));
362              idx++)
363         {
364                 d_printf("\t%s = %s\n", valname, format_value(ctx, valvalue));
365         }
366         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
367                 d_fprintf(stderr, "Error enumerating values: %s\n",
368                           dos_errstr(werr));
369                 goto done;
370         }
371         werr = WERR_OK;
372
373 done:
374         return werr; 
375 }
376
377 static int import_process_service(TALLOC_CTX *ctx, 
378                                   struct share_params *share)
379 {
380         int ret = -1;
381         struct parm_struct *parm;
382         int pnum = 0;
383         const char *servicename;
384         struct registry_key *key;
385         WERROR werr;
386         const char *valtype = NULL;
387         char *valstr = NULL;
388
389         servicename = (share->service == GLOBAL_SECTION_SNUM)?
390                 GLOBAL_NAME : lp_servicename(share->service);
391
392         if (opt_testmode) {
393                 d_printf("[%s]\n", servicename);
394         }
395         else {
396                 if (smbconf_key_exists(ctx, servicename)) {
397                         werr = reg_delkey_internal(ctx, servicename);
398                         if (!W_ERROR_IS_OK(werr)) {
399                                 goto done;
400                         }
401                 }
402                 werr = reg_createkey_internal(ctx, servicename, &key);
403                 if (!W_ERROR_IS_OK(werr)) {
404                         goto done;
405                 }
406         }
407
408         while ((parm = lp_next_parameter(share->service, &pnum, 0)))
409         {
410                 void *ptr = parm->ptr;
411                 int i = 0;
412
413                 if ((share->service < 0 && parm->p_class == P_LOCAL) 
414                     && !(parm->flags & FLAG_GLOBAL))
415                         continue;
416
417                 if (parm->p_class == P_LOCAL && share->service >= 0) {
418                         ptr = lp_local_ptr(share->service, ptr);
419                 }
420
421                 valtype = "sz";
422
423                 switch (parm->type) {
424                 case P_CHAR:
425                         valstr = talloc_asprintf(ctx, "%c", *(char *)ptr);
426                         break;
427                 case P_STRING:
428                 case P_USTRING:
429                         valstr = talloc_asprintf(ctx, "%s", *(char **)ptr);
430                         break;
431                 case P_GSTRING:
432                 case P_UGSTRING:
433                         valstr = talloc_asprintf(ctx, "%s", (char *)ptr);
434                         break;
435                 case P_BOOL:
436                         valstr = talloc_asprintf(ctx, "%s", 
437                                                 BOOLSTR(*(BOOL *)ptr));
438                         break;
439                 case P_BOOLREV:
440                         valstr = talloc_asprintf(ctx, "%s", 
441                                                 BOOLSTR(!*(BOOL *)ptr));
442                         break;
443                 case P_ENUM:
444                         for (i = 0; parm->enum_list[i].name; i++) {
445                                 if (*(int *)ptr == 
446                                     parm->enum_list[i].value) 
447                                 {
448                                         valstr = talloc_asprintf(ctx, "%s",
449                                                  parm->enum_list[i].name);
450                                         break;
451                                 }
452                         }
453                         break;
454                 case P_OCTAL:
455                         talloc_asprintf(ctx, "%s", octal_string(*(int *)ptr));
456                         break;
457                 case P_LIST:
458                         valstr = talloc_strdup(ctx, "");
459                         if ((char ***)ptr && *(char ***)ptr) {
460                                 char **list = *(char ***)ptr;
461                                 for (; *list; list++) {
462                                         /* surround strings with whitespace 
463                                          * in double quotes */
464                                         if (strchr_m(*list, ' '))
465                                         {
466                                                 valstr = talloc_asprintf_append(
467                                                         valstr, "\"%s\"%s", 
468                                                         *list, 
469                                                          ((*(list+1))?", ":""));
470                                         }
471                                         else {
472                                                 valstr = talloc_asprintf_append(
473                                                         valstr, "%s%s", *list, 
474                                                          ((*(list+1))?", ":""));
475                                         }
476                                 }
477                         }
478                         break;
479                 case P_INTEGER:
480                         valtype = "dword";
481                         talloc_asprintf(ctx, "%d", *(int *)ptr);
482                         break;
483                 case P_SEP:
484                         break;
485                 default:
486                         valstr = talloc_asprintf(ctx, "<type unimplemented>\n");
487                         break;
488                 }
489
490                 if (parm->type != P_SEP) {
491                         if (opt_testmode) {
492                                 d_printf("\t%s = %s\n", parm->label, valstr);
493                         }
494                         else {
495                                 werr = reg_setvalue_internal(key, parm->label, 
496                                                              valtype, valstr);
497                                 if (!W_ERROR_IS_OK(werr)) {
498                                         goto done;
499                                 }
500                         }
501                 }
502         }
503
504         if (opt_testmode) {
505                 d_printf("\n");
506         }
507
508         ret = 0;
509 done:
510         return ret;
511 }
512
513
514 /*
515  * the conf functions 
516  */
517
518 int net_conf_list(int argc, const char **argv)
519 {
520         WERROR werr = WERR_OK;
521         int ret = -1;
522         TALLOC_CTX *ctx;
523         struct registry_key *base_key = NULL;
524         struct registry_key *sub_key = NULL;
525         uint32 idx_key = 0;
526         char *subkey_name = NULL;
527
528         ctx = talloc_init("list");
529
530         if (argc != 0) {
531                 net_conf_list_usage(argc, argv);
532                 goto done;
533         }
534
535         werr = smbconf_open_basepath(ctx, REG_KEY_READ, &base_key);
536         if (!W_ERROR_IS_OK(werr)) {
537                 goto done;
538         }
539
540         if (smbconf_key_exists(ctx, GLOBAL_NAME))  {
541                 werr = reg_openkey(ctx, base_key, GLOBAL_NAME, 
542                                    REG_KEY_READ, &sub_key);
543                 if (!W_ERROR_IS_OK(werr)) {
544                         d_fprintf(stderr, "Error opening subkey '%s' : %s\n",
545                                   subkey_name, dos_errstr(werr));
546                         goto done;
547                 }
548                 d_printf("[%s]\n", GLOBAL_NAME);
549                 if (!W_ERROR_IS_OK(list_values(ctx, sub_key))) {
550                         goto done;
551                 }
552                 d_printf("\n");
553         }
554
555         for (idx_key = 0;
556              W_ERROR_IS_OK(werr = reg_enumkey(ctx, base_key, idx_key,
557                                               &subkey_name, NULL));
558              idx_key++) 
559         {
560                 if (strequal(subkey_name, GLOBAL_NAME)) {
561                         continue;
562                 }
563                 d_printf("[%s]\n", subkey_name);
564
565                 werr = reg_openkey(ctx, base_key, subkey_name, 
566                                    REG_KEY_READ, &sub_key);
567                 if (!W_ERROR_IS_OK(werr)) {
568                         d_fprintf(stderr, 
569                                   "Error opening subkey '%s': %s\n",
570                                   subkey_name, dos_errstr(werr));
571                         goto done;
572                 }
573                 if (!W_ERROR_IS_OK(list_values(ctx, sub_key))) {
574                         goto done;
575                 }
576                 d_printf("\n");
577         }
578         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
579                 d_fprintf(stderr, "Error enumerating subkeys: %s\n", 
580                           dos_errstr(werr));
581                 goto done;
582         }
583
584         ret = 0;
585
586 done:
587         TALLOC_FREE(ctx);
588         return ret;
589 }
590
591 int net_conf_import(int argc, const char **argv)
592 {
593         int ret = -1;
594         const char *filename = NULL;
595         const char *servicename = NULL;
596         BOOL service_found = False;
597         TALLOC_CTX *ctx;
598         struct share_iterator *shares;
599         struct share_params *share;
600         struct share_params global_share = { GLOBAL_SECTION_SNUM };
601
602         ctx = talloc_init("net_conf_import");
603
604         switch (argc) {
605                 case 0:
606                 default:
607                         net_conf_import_usage(argc, argv);
608                         goto done;
609                 case 2:
610                         servicename = argv[1];
611                 case 1:
612                         filename = argv[0];
613                         break;
614         }
615
616         DEBUG(3,("net_conf_import: reading configuration from file %s.\n",
617                 filename));
618
619         /* TODO: check for existence and readability */
620
621         if (!lp_load(filename, 
622                      False,     /* global_only */
623                      True,      /* save_defaults */
624                      False,     /* add_ipc */
625                      True))     /* initialize_globals */
626         {
627                 d_fprintf(stderr, "Error parsing configuration file.\n");
628                 goto done;
629         }
630
631         if (opt_testmode) {
632                 d_printf("\nTEST MODE - would import the following configuration:\n\n");
633         }
634
635         if ((servicename == NULL) || strequal(servicename, GLOBAL_NAME)) {
636                 service_found = True;
637                 if (import_process_service(ctx, &global_share) != 0) {
638                         goto done;
639                 }
640         }
641
642         if (service_found && (servicename != NULL)) {
643                 ret = 0;
644                 goto done;
645         }
646
647         if (!(shares = share_list_all(ctx))) {
648                 d_fprintf(stderr, "Could not list shares...\n");
649                 goto done;
650         }
651         while ((share = next_share(shares)) != NULL) {
652                 if ((servicename == NULL) 
653                     || strequal(servicename, lp_servicename(share->service))) 
654                 {
655                         service_found = True;
656                         if (import_process_service(ctx, share)!= 0) {
657                                 goto done;
658                         }
659                 }
660         }
661         
662         if ((servicename != NULL) && !service_found) {
663                 d_printf("Share %s not found in file %s\n", 
664                          servicename, filename);
665                 goto done;
666
667         }
668
669         ret = 0;
670         
671 done:
672         TALLOC_FREE(ctx);
673         return ret;
674 }
675
676 int net_conf_listshares(int argc, const char **argv)
677 {
678         WERROR werr = WERR_OK;
679         int ret = -1;
680         struct registry_key *key;
681         uint32 idx = 0;
682         char *subkey_name = NULL;
683         TALLOC_CTX *ctx;
684
685         ctx = talloc_init("listshares");
686
687         if (argc != 0) {
688                 net_conf_listshares_usage(argc, argv);
689                 goto done;
690         }
691
692         werr = smbconf_open_basepath(ctx, SEC_RIGHTS_ENUM_SUBKEYS, &key);
693         if (!W_ERROR_IS_OK(werr)) {
694                 goto done;
695         }
696
697         for (idx = 0;
698              W_ERROR_IS_OK(werr = reg_enumkey(ctx, key, idx,
699                                               &subkey_name, NULL));
700              idx++) 
701         {
702                 d_printf("%s\n", subkey_name);
703         }
704         if (! W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
705                 d_fprintf(stderr, "Error enumerating subkeys: %s\n", 
706                           dos_errstr(werr));
707                 goto done;
708         }
709
710         ret = 0;
711
712 done:
713         TALLOC_FREE(ctx);
714         return ret;
715 }
716
717 int net_conf_showshare(int argc, const char **argv)
718 {
719         int ret = -1;
720         WERROR werr = WERR_OK;
721         struct registry_key *key = NULL;
722         TALLOC_CTX *ctx;
723
724         ctx = talloc_init("showshare");
725
726         if (argc != 1) {
727                 net_conf_showshare_usage(argc, argv);
728                 goto done;
729         }
730
731         werr = smbconf_open_path(ctx, argv[0], REG_KEY_READ, &key);
732         if (!W_ERROR_IS_OK(werr)) {
733                 goto done;
734         }
735
736         d_printf("[%s]\n", argv[0]);
737
738         if (!W_ERROR_IS_OK(list_values(ctx, key))) {
739                 goto done;
740         }
741
742         ret = 0;
743
744 done:
745         TALLOC_FREE(ctx);
746         return ret;
747 }
748
749 int net_conf_addshare(int argc, const char **argv)
750 {
751         int ret = -1;
752         WERROR werr = WERR_OK;
753         struct registry_key *newkey = NULL;
754         char *sharename = NULL;
755         const char *path = NULL;
756         const char *comment = NULL;
757         const char *guest_ok = "no";
758         const char *writeable = "no";
759         SMB_STRUCT_STAT sbuf;
760
761         switch (argc) {
762                 case 0:
763                 case 1:
764                 default: 
765                         net_conf_addshare_usage(argc, argv);
766                         goto done;
767                 case 5:
768                         comment = argv[4];
769                 case 4:
770                         if (!strnequal(argv[3], "guest_ok=", 9)) {
771                                 net_conf_addshare_usage(argc, argv);
772                                 goto done;
773                         }
774                         switch (argv[3][9]) {
775                                 case 'y':
776                                 case 'Y':
777                                         guest_ok = "yes";
778                                         break;
779                                 case 'n':
780                                 case 'N':
781                                         guest_ok = "no";
782                                         break;
783                                 default: 
784                                         net_conf_addshare_usage(argc, argv);
785                                         goto done;
786                         }
787                 case 3:
788                         if (!strnequal(argv[2], "writeable=", 10)) {
789                                 net_conf_addshare_usage(argc, argv);
790                                 goto done;
791                         }
792                         switch (argv[2][10]) {
793                                 case 'y':
794                                 case 'Y':
795                                         writeable = "yes";
796                                         break;
797                                 case 'n':
798                                 case 'N':
799                                         writeable = "no";
800                                         break;
801                                 default:
802                                         net_conf_addshare_usage(argc, argv);
803                                         goto done;
804                         }
805
806                 case 2:
807                         path = argv[1];
808                         sharename = strdup_lower(argv[0]);
809                         break;
810         }
811
812         /* 
813          * validate arguments 
814          */
815
816         /* validate share name */
817
818         if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, 
819                                strlen(sharename))) 
820         {
821                 d_fprintf(stderr, "ERROR: share name %s contains "
822                         "invalid characters (any of %s)\n",
823                         sharename, INVALID_SHARENAME_CHARS);
824                 goto done;
825         }
826
827         if (getpwnam(sharename)) {
828                 d_fprintf(stderr, "ERROR: share name %s is already a valid "
829                           "system user name.\n", sharename);
830                 goto done;
831         }
832
833         if (strequal(sharename, GLOBAL_NAME)) {
834                 d_fprintf(stderr, 
835                           "ERROR: 'global' is not a valid share name.\n");
836                 goto done;
837         }
838
839         /* validate path */
840
841         if (path[0] != '/') {
842                 d_fprintf(stderr, 
843                           "Error: path '%s' is not an absolute path.\n",
844                           path);
845                 goto done;
846         }
847
848         if (sys_stat(path, &sbuf) != 0) {
849                 d_fprintf(stderr,
850                           "ERROR: cannot stat path '%s' to ensure "
851                           "this is a directory.\n"
852                           "Error was '%s'.\n", 
853                           path, strerror(errno));
854                 goto done;
855         }
856
857         if (!S_ISDIR(sbuf.st_mode)) {
858                 d_fprintf(stderr,
859                           "ERROR: path '%s' is not a directory.\n",
860                           path);
861                 goto done;
862         }
863
864         /* 
865          * create the share 
866          */
867
868         werr = reg_createkey_internal(NULL, argv[0], &newkey);
869         if (!W_ERROR_IS_OK(werr)) {
870                 goto done;
871         }
872
873         /* add config params as values */
874
875         werr = reg_setvalue_internal(newkey, "path", "sz", path);
876         if (!W_ERROR_IS_OK(werr))
877                 goto done;
878
879         if (comment != NULL) {
880                 werr = reg_setvalue_internal(newkey, "comment", "sz", comment);
881                 if (!W_ERROR_IS_OK(werr))
882                         goto done;
883         }
884
885         werr = reg_setvalue_internal(newkey, "guest ok", "sz", guest_ok);
886         if (!W_ERROR_IS_OK(werr))
887                 goto done;
888         
889         werr = reg_setvalue_internal(newkey, "writeable", "sz", writeable);
890         if (!W_ERROR_IS_OK(werr))
891                 goto done;
892
893         ret = 0;
894
895 done:
896         TALLOC_FREE(newkey);
897         SAFE_FREE(sharename);
898         return ret;
899 }
900
901 int net_conf_delshare(int argc, const char **argv)
902 {
903         int ret = -1;
904         const char *sharename = NULL;
905
906         if (argc != 1) {
907                 net_conf_delshare_usage(argc, argv);
908                 goto done;
909         }
910         sharename = argv[0];
911         
912         if (W_ERROR_IS_OK(reg_delkey_internal(NULL, sharename))) {
913                 ret = 0;
914         }
915 done:
916         return ret;
917 }
918
919 static int net_conf_setparm(int argc, const char **argv)
920 {
921         int ret = -1;
922         WERROR werr = WERR_OK;
923         struct registry_key *key = NULL;
924         char *service = NULL;
925         char *param = NULL;
926         char *type = NULL;
927         const char *value_str = NULL;
928         TALLOC_CTX *ctx;
929
930         ctx = talloc_init("setparm");
931
932         if (argc != 4) {
933                 net_conf_setparm_usage(argc, argv);
934                 goto done;
935         }
936         service = strdup_lower(argv[0]);
937         param = strdup_lower(argv[1]);
938         type = strdup_lower(argv[2]);
939         value_str = argv[3];
940
941         if (!smbconf_key_exists(ctx, service)) {
942                 werr = reg_createkey_internal(ctx, service, &key);
943         }
944         else {
945                 werr = smbconf_open_path(ctx, service, REG_KEY_READ, &key);
946         }
947         if (!W_ERROR_IS_OK(werr)) {
948                 goto done;
949         }
950
951         werr = reg_setvalue_internal(key, param, type, value_str);
952         if (!W_ERROR_IS_OK(werr)) {
953                 d_fprintf(stderr, "Error setting value '%s': %s\n",
954                           param, dos_errstr(werr));
955                 goto done;
956         }
957
958
959         ret = 0;
960
961 done:
962         SAFE_FREE(service);
963         TALLOC_FREE(ctx);
964         return ret;
965 }
966
967 static int net_conf_getparm(int argc, const char **argv)
968 {
969         int ret = -1;
970         WERROR werr = WERR_OK;
971         struct registry_key *key = NULL;
972         char *service = NULL;
973         char *param = NULL;
974         struct registry_value *value = NULL;
975         TALLOC_CTX *ctx;
976
977         ctx = talloc_init("getparm");
978
979         if (argc != 2) {
980                 net_conf_getparm_usage(argc, argv);
981                 goto done;
982         }
983         service = strdup_lower(argv[0]);
984         param = strdup_lower(argv[1]);
985
986         if (!smbconf_key_exists(ctx, service)) {
987                 d_fprintf(stderr, 
988                           "ERROR: given service '%s' does not exist.\n",
989                           service);
990                 goto done;
991         }
992
993         werr = smbconf_open_path(ctx, service, REG_KEY_READ, &key);
994         if (!W_ERROR_IS_OK(werr)) {
995                 goto done;
996         }
997
998         werr = reg_queryvalue(ctx, key, param, &value);
999         if (!W_ERROR_IS_OK(werr)) {
1000                 d_fprintf(stderr, "Error querying value '%s': %s.\n",
1001                           param, dos_errstr(werr));
1002                 goto done;
1003         }
1004         
1005         d_printf("%s\n", format_value(ctx, value));
1006         
1007         ret = 0;
1008 done:
1009         SAFE_FREE(service);
1010         SAFE_FREE(param);
1011         TALLOC_FREE(ctx);
1012         return ret;
1013 }
1014
1015 static int net_conf_delparm(int argc, const char **argv)
1016 {
1017         int ret = -1;
1018         WERROR werr = WERR_OK;
1019         struct registry_key *key = NULL;
1020         char *service = NULL;
1021         char *param = NULL;
1022         TALLOC_CTX *ctx;
1023
1024         ctx = talloc_init("delparm");
1025
1026         if (argc != 2) {
1027                 net_conf_delparm_usage(argc, argv);
1028                 goto done;
1029         }
1030         service = strdup_lower(argv[0]);
1031         param = strdup_lower(argv[1]);
1032
1033         if (!smbconf_key_exists(ctx, service)) {
1034                 d_fprintf(stderr, 
1035                           "Error: given service '%s' does not exist.\n",
1036                           service);
1037                 goto done;
1038         }
1039
1040         werr = smbconf_open_path(ctx, service, REG_KEY_READ, &key);
1041         if (!W_ERROR_IS_OK(werr)) {
1042                 goto done;
1043         }
1044
1045         if (!smbconf_value_exists(ctx, key, param)) {
1046                 d_fprintf(stderr, 
1047                           "Error: given parameter '%s' is not set.\n",
1048                           param);
1049                 goto done;
1050         }
1051         werr = reg_deletevalue(key, param);
1052         if (!W_ERROR_IS_OK(werr)) {
1053                 d_fprintf(stderr, "Error deleting value '%s': %s.\n",
1054                           param, dos_errstr(werr));
1055                 goto done;
1056         }
1057
1058         ret = 0;
1059
1060 done:
1061         return ret;
1062 }
1063
1064 /*
1065  * Entry-point for all the CONF functions.
1066  */
1067
1068 int net_conf(int argc, const char **argv)
1069 {
1070         int ret = -1;
1071         int saved_errno = 0;
1072         struct functable2 func[] = {
1073                 {"list", net_conf_list, 
1074                  "Dump the complete configuration in smb.conf like format."},
1075                 {"import", net_conf_import,
1076                  "Import configuration from file in smb.conf format."},
1077                 {"listshares", net_conf_listshares, 
1078                  "List the registry shares."},
1079                 {"showshare", net_conf_showshare, 
1080                  "Show the definition of a registry share."},
1081                 {"addshare", net_conf_addshare, 
1082                  "Create a new registry share."},
1083                 {"delshare", net_conf_delshare, 
1084                  "Delete a registry share."},
1085                 {"setparm", net_conf_setparm, 
1086                  "Store a parameter."},
1087                 {"getparm", net_conf_getparm, 
1088                  "Retrieve the value of a parameter."},
1089                 {"delparm", net_conf_delparm, 
1090                  "Delete a parameter."},
1091                 {NULL, NULL, NULL}
1092         };
1093
1094         REGISTRY_HOOK smbconf_reg_hook = {KEY_SMBCONF, &smbconf_reg_ops};
1095         
1096         if (!regdb_init()) {
1097                 saved_errno = errno;
1098                 d_fprintf(stderr, "Can't open the registry");
1099                 if (saved_errno) {
1100                         d_fprintf(stderr, ": %s\n", strerror(saved_errno));
1101                 }
1102                 else {
1103                         d_fprintf(stderr, "!\n");
1104                 }
1105                 goto done;
1106         }
1107         reghook_cache_init();
1108         reghook_cache_add(&smbconf_reg_hook);
1109
1110         ret = net_run_function2(argc, argv, "net conf", func);
1111
1112         regdb_close();
1113
1114 done:
1115         return ret;
1116 }
1117
1118 /* END */