Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into ctdb-merge
[ira/wip.git] / source3 / libnet / libnet_conf.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libnet smbconf registry Support
4  *  Copyright (C) Michael Adam 2007-2008
5  *  Copyright (C) Guenther Deschner 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 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 #include "includes.h"
22 #include "libnet/libnet.h"
23
24 /**********************************************************************
25  *
26  * Helper functions (mostly registry related)
27  * TODO: These should be eventually static.
28
29  **********************************************************************/
30
31 /**
32  * add a string to a talloced array of strings.
33  */
34 static WERROR libnet_conf_add_string_to_array(TALLOC_CTX *mem_ctx,
35                                               char ***array,
36                                               uint32_t count,
37                                               const char *string)
38 {
39         char **new_array = NULL;
40
41         if ((array == NULL) || (string == NULL)) {
42                 return WERR_INVALID_PARAM;
43         }
44
45         new_array = TALLOC_REALLOC_ARRAY(mem_ctx, *array, char *, count + 1);
46         if (new_array == NULL) {
47                 return WERR_NOMEM;
48         }
49
50         new_array[count] = talloc_strdup(new_array, string);
51         if (new_array[count] == NULL) {
52                 TALLOC_FREE(new_array);
53                 return WERR_NOMEM;
54         }
55
56         *array = new_array;
57
58         return WERR_OK;
59 }
60
61 static WERROR libnet_conf_reg_initialize(struct libnet_conf_ctx *ctx)
62 {
63         WERROR werr = WERR_OK;
64
65         if (!registry_init_regdb()) {
66                 werr = WERR_REG_IO_FAILURE;
67                 goto done;
68         }
69
70         werr = ntstatus_to_werror(registry_create_admin_token(ctx,
71                                                               &(ctx->token)));
72         if (!W_ERROR_IS_OK(werr)) {
73                 DEBUG(1, ("Error creating admin token\n"));
74                 goto done;
75         }
76
77 done:
78         return werr;
79 }
80
81 /**
82  * Open a registry key specified by "path"
83  */
84 static WERROR libnet_conf_reg_open_path(TALLOC_CTX *mem_ctx,
85                                         struct libnet_conf_ctx *ctx,
86                                         const char *path,
87                                         uint32 desired_access,
88                                         struct registry_key **key)
89 {
90         WERROR werr = WERR_OK;
91
92         if (ctx == NULL) {
93                 DEBUG(1, ("Error: configuration is not open!\n"));
94                 werr = WERR_INVALID_PARAM;
95                 goto done;
96         }
97
98         if (ctx->token == NULL) {
99                 DEBUG(1, ("Error: token missing from libnet_conf_ctx. "
100                           "was libnet_conf_open() called?\n"));
101                 werr = WERR_INVALID_PARAM;
102                 goto done;
103         }
104
105         if (path == NULL) {
106                 DEBUG(1, ("Error: NULL path string given\n"));
107                 werr = WERR_INVALID_PARAM;
108                 goto done;
109         }
110
111         werr = reg_open_path(mem_ctx, path, desired_access, ctx->token, key);
112
113         if (!W_ERROR_IS_OK(werr)) {
114                 DEBUG(1, ("Error opening registry path '%s': %s\n",
115                           path, dos_errstr(werr)));
116         }
117
118 done:
119         return werr;
120 }
121
122 /**
123  * Open a subkey of KEY_SMBCONF (i.e a service)
124  */
125 static WERROR libnet_conf_reg_open_service_key(TALLOC_CTX *mem_ctx,
126                                                struct libnet_conf_ctx *ctx,
127                                                const char *servicename,
128                                                uint32 desired_access,
129                                                struct registry_key **key)
130 {
131         WERROR werr = WERR_OK;
132         char *path = NULL;
133
134         if (servicename == NULL) {
135                 DEBUG(3, ("Error: NULL servicename given.\n"));
136                 werr = WERR_INVALID_PARAM;
137                 goto done;
138         }
139
140         path = talloc_asprintf(mem_ctx, "%s\\%s", KEY_SMBCONF, servicename);
141         if (path == NULL) {
142                 werr = WERR_NOMEM;
143                 goto done;
144         }
145
146         werr = libnet_conf_reg_open_path(mem_ctx, ctx, path, desired_access,
147                                          key);
148
149 done:
150         TALLOC_FREE(path);
151         return werr;
152 }
153
154 /**
155  * open the base key KEY_SMBCONF
156  */
157 static WERROR libnet_conf_reg_open_base_key(TALLOC_CTX *mem_ctx,
158                                             struct libnet_conf_ctx *ctx,
159                                             uint32 desired_access,
160                                             struct registry_key **key)
161 {
162         return libnet_conf_reg_open_path(mem_ctx, ctx, KEY_SMBCONF,
163                                          desired_access, key);
164 }
165
166 /**
167  * check if a value exists in a given registry key
168  */
169 static bool libnet_conf_value_exists(struct registry_key *key,
170                                      const char *param)
171 {
172         bool ret = false;
173         WERROR werr = WERR_OK;
174         TALLOC_CTX *ctx = talloc_stackframe();
175         struct registry_value *value = NULL;
176
177         werr = reg_queryvalue(ctx, key, param, &value);
178         if (W_ERROR_IS_OK(werr)) {
179                 ret = true;
180         }
181
182         TALLOC_FREE(ctx);
183         return ret;
184 }
185
186 /**
187  * create a subkey of KEY_SMBCONF
188  */
189 static WERROR libnet_conf_reg_create_service_key(TALLOC_CTX *mem_ctx,
190                                                  struct libnet_conf_ctx *ctx,
191                                                  const char * subkeyname,
192                                                  struct registry_key **newkey)
193 {
194         WERROR werr = WERR_OK;
195         struct registry_key *create_parent = NULL;
196         TALLOC_CTX *create_ctx;
197         enum winreg_CreateAction action = REG_ACTION_NONE;
198
199         /* create a new talloc ctx for creation. it will hold
200          * the intermediate parent key (SMBCONF) for creation
201          * and will be destroyed when leaving this function... */
202         if (!(create_ctx = talloc_stackframe())) {
203                 werr = WERR_NOMEM;
204                 goto done;
205         }
206
207         werr = libnet_conf_reg_open_base_key(create_ctx, ctx, REG_KEY_WRITE,
208                                              &create_parent);
209         if (!W_ERROR_IS_OK(werr)) {
210                 goto done;
211         }
212
213         werr = reg_createkey(mem_ctx, create_parent, subkeyname,
214                              REG_KEY_WRITE, newkey, &action);
215         if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
216                 DEBUG(10, ("Key '%s' already exists.\n", subkeyname));
217                 werr = WERR_ALREADY_EXISTS;
218         }
219         if (!W_ERROR_IS_OK(werr)) {
220                 DEBUG(5, ("Error creating key %s: %s\n",
221                          subkeyname, dos_errstr(werr)));
222         }
223
224 done:
225         TALLOC_FREE(create_ctx);
226         return werr;
227 }
228
229 /**
230  * add a value to a key.
231  */
232 static WERROR libnet_conf_reg_set_value(struct registry_key *key,
233                                         const char *valname,
234                                         const char *valstr)
235 {
236         struct registry_value val;
237         WERROR werr = WERR_OK;
238         char *subkeyname;
239         const char *canon_valname;
240         const char *canon_valstr;
241
242         if (!lp_canonicalize_parameter_with_value(valname, valstr,
243                                                   &canon_valname,
244                                                   &canon_valstr))
245         {
246                 if (canon_valname == NULL) {
247                         DEBUG(5, ("invalid parameter '%s' given\n",
248                                   valname));
249                 } else {
250                         DEBUG(5, ("invalid value '%s' given for "
251                                   "parameter '%s'\n", valstr, valname));
252                 }
253                 werr = WERR_INVALID_PARAM;
254                 goto done;
255         }
256
257         ZERO_STRUCT(val);
258
259         val.type = REG_SZ;
260         val.v.sz.str = CONST_DISCARD(char *, canon_valstr);
261         val.v.sz.len = strlen(canon_valstr) + 1;
262
263         if (registry_smbconf_valname_forbidden(canon_valname)) {
264                 DEBUG(5, ("Parameter '%s' not allowed in registry.\n",
265                           canon_valname));
266                 werr = WERR_INVALID_PARAM;
267                 goto done;
268         }
269
270         subkeyname = strrchr_m(key->key->name, '\\');
271         if ((subkeyname == NULL) || (*(subkeyname +1) == '\0')) {
272                 DEBUG(5, ("Invalid registry key '%s' given as "
273                           "smbconf section.\n", key->key->name));
274                 werr = WERR_INVALID_PARAM;
275                 goto done;
276         }
277         subkeyname++;
278         if (!strequal(subkeyname, GLOBAL_NAME) &&
279             lp_parameter_is_global(valname))
280         {
281                 DEBUG(5, ("Global paramter '%s' not allowed in "
282                           "service definition ('%s').\n", canon_valname,
283                           subkeyname));
284                 werr = WERR_INVALID_PARAM;
285                 goto done;
286         }
287
288         werr = reg_setvalue(key, canon_valname, &val);
289         if (!W_ERROR_IS_OK(werr)) {
290                 DEBUG(5, ("Error adding value '%s' to "
291                           "key '%s': %s\n",
292                           canon_valname, key->key->name, dos_errstr(werr)));
293         }
294
295 done:
296         return werr;
297 }
298
299 /**
300  * format a registry_value into a string.
301  *
302  * This is intended to be used for smbconf registry values,
303  * which are ar stored as REG_SZ values, so the incomplete
304  * handling should be ok.
305  */
306 static char *libnet_conf_format_registry_value(TALLOC_CTX *mem_ctx,
307                                                struct registry_value *value)
308 {
309         char *result = NULL;
310
311         /* alternatively, create a new talloc context? */
312         if (mem_ctx == NULL) {
313                 return result;
314         }
315
316         switch (value->type) {
317         case REG_DWORD:
318                 result = talloc_asprintf(mem_ctx, "%d", value->v.dword);
319                 break;
320         case REG_SZ:
321         case REG_EXPAND_SZ:
322                 result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str);
323                 break;
324         case REG_MULTI_SZ: {
325                 uint32 j;
326                 for (j = 0; j < value->v.multi_sz.num_strings; j++) {
327                         result = talloc_asprintf(mem_ctx, "%s \"%s\" ",
328                                                  result,
329                                                  value->v.multi_sz.strings[j]);
330                         if (result == NULL) {
331                                 break;
332                         }
333                 }
334                 break;
335         }
336         case REG_BINARY:
337                 result = talloc_asprintf(mem_ctx, "binary (%d bytes)",
338                                          (int)value->v.binary.length);
339                 break;
340         default:
341                 result = talloc_asprintf(mem_ctx, "<unprintable>");
342                 break;
343         }
344         return result;
345 }
346
347 /**
348  * Get the values of a key as a list of value names
349  * and a list of value strings (ordered)
350  */
351 static WERROR libnet_conf_reg_get_values(TALLOC_CTX *mem_ctx,
352                                          struct registry_key *key,
353                                          uint32_t *num_values,
354                                          char ***value_names,
355                                          char ***value_strings)
356 {
357         TALLOC_CTX *tmp_ctx = NULL;
358         WERROR werr = WERR_OK;
359         uint32_t count;
360         struct registry_value *valvalue = NULL;
361         char *valname = NULL;
362         char **tmp_valnames = NULL;
363         char **tmp_valstrings = NULL;
364
365         if ((num_values == NULL) || (value_names == NULL) ||
366             (value_strings == NULL))
367         {
368                 werr = WERR_INVALID_PARAM;
369                 goto done;
370         }
371
372         tmp_ctx = talloc_stackframe();
373         if (tmp_ctx == NULL) {
374                 werr = WERR_NOMEM;
375                 goto done;
376         }
377
378         for (count = 0;
379              W_ERROR_IS_OK(werr = reg_enumvalue(tmp_ctx, key, count, &valname,
380                                                 &valvalue));
381              count++)
382         {
383                 char *valstring;
384
385                 werr = libnet_conf_add_string_to_array(tmp_ctx,
386                                                        &tmp_valnames,
387                                                        count, valname);
388                 if (!W_ERROR_IS_OK(werr)) {
389                         goto done;
390                 }
391
392                 valstring = libnet_conf_format_registry_value(tmp_ctx,
393                                                               valvalue);
394                 werr = libnet_conf_add_string_to_array(tmp_ctx,
395                                                        &tmp_valstrings,
396                                                        count,
397                                                        valstring);
398                 if (!W_ERROR_IS_OK(werr)) {
399                         goto done;
400                 }
401         }
402         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
403                 goto done;
404         }
405
406         werr = WERR_OK;
407
408         *num_values = count;
409         if (count > 0) {
410                 *value_names = talloc_move(mem_ctx, &tmp_valnames);
411                 *value_strings = talloc_move(mem_ctx, &tmp_valstrings);
412         } else {
413                 *value_names = NULL;
414                 *value_strings = NULL;
415         }
416
417 done:
418         TALLOC_FREE(tmp_ctx);
419         return werr;
420 }
421
422 static int libnet_conf_destroy_ctx(struct libnet_conf_ctx *ctx)
423 {
424         return regdb_close();
425 }
426
427 /**********************************************************************
428  *
429  * The actual net conf api functions, that are exported.
430  *
431  **********************************************************************/
432
433 /**
434  * Open the configuration.
435  *
436  * This should be the first function in a sequence of calls to libnet_conf
437  * functions:
438  *
439  * Upon success, this creates and returns the conf context
440  * that should be passed around in subsequent calls to the other
441  * libnet_conf functions.
442  *
443  * After the work with the configuration is completed, libnet_conf_close()
444  * should be called.
445  */
446 WERROR libnet_conf_open(TALLOC_CTX *mem_ctx, struct libnet_conf_ctx **conf_ctx)
447 {
448         WERROR werr = WERR_OK;
449         struct libnet_conf_ctx *ctx;
450
451         if (conf_ctx == NULL) {
452                 return WERR_INVALID_PARAM;
453         }
454
455         ctx = TALLOC_ZERO_P(mem_ctx, struct libnet_conf_ctx);
456         if (ctx == NULL) {
457                 return WERR_NOMEM;
458         }
459
460         werr = libnet_conf_reg_initialize(ctx);
461         if (!W_ERROR_IS_OK(werr)) {
462                 goto fail;
463         }
464
465         talloc_set_destructor(ctx, libnet_conf_destroy_ctx);
466
467         *conf_ctx = ctx;
468         return werr;
469
470 fail:
471         TALLOC_FREE(ctx);
472         return werr;
473 }
474
475 /**
476  * Close the configuration.
477  */
478 void libnet_conf_close(struct libnet_conf_ctx *ctx)
479 {
480         /* this also closes the registry (by destructor): */
481         TALLOC_FREE(ctx);
482 }
483
484 /**
485  * Drop the whole configuration (restarting empty).
486  */
487 WERROR libnet_conf_drop(struct libnet_conf_ctx *ctx)
488 {
489         char *path, *p;
490         WERROR werr = WERR_OK;
491         struct registry_key *parent_key = NULL;
492         struct registry_key *new_key = NULL;
493         TALLOC_CTX* mem_ctx = talloc_stackframe();
494         enum winreg_CreateAction action;
495
496         path = talloc_strdup(mem_ctx, KEY_SMBCONF);
497         if (path == NULL) {
498                 werr = WERR_NOMEM;
499                 goto done;
500         }
501         p = strrchr(path, '\\');
502         *p = '\0';
503         werr = libnet_conf_reg_open_path(mem_ctx, ctx, path, REG_KEY_WRITE,
504                                          &parent_key);
505
506         if (!W_ERROR_IS_OK(werr)) {
507                 goto done;
508         }
509
510         werr = reg_deletekey_recursive(mem_ctx, parent_key, p+1);
511
512         if (!W_ERROR_IS_OK(werr)) {
513                 goto done;
514         }
515
516         werr = reg_createkey(mem_ctx, parent_key, p+1, REG_KEY_WRITE,
517                              &new_key, &action);
518
519 done:
520         TALLOC_FREE(mem_ctx);
521         return werr;
522 }
523
524 /**
525  * Get the whole configuration as lists of strings with counts:
526  *
527  *  num_shares   : number of shares
528  *  share_names  : list of length num_shares of share names
529  *  num_params   : list of length num_shares of parameter counts for each share
530  *  param_names  : list of lists of parameter names for each share
531  *  param_values : list of lists of parameter values for each share
532  */
533 WERROR libnet_conf_get_config(TALLOC_CTX *mem_ctx,
534                               struct libnet_conf_ctx *ctx, uint32_t *num_shares,
535                               char ***share_names, uint32_t **num_params,
536                               char ****param_names, char ****param_values)
537 {
538         WERROR werr = WERR_OK;
539         TALLOC_CTX *tmp_ctx = NULL;
540         uint32_t tmp_num_shares;
541         char **tmp_share_names;
542         uint32_t *tmp_num_params;
543         char ***tmp_param_names;
544         char ***tmp_param_values;
545         uint32_t count;
546
547         if ((num_shares == NULL) || (share_names == NULL) ||
548             (num_params == NULL) || (param_names == NULL) ||
549             (param_values == NULL))
550         {
551                 werr = WERR_INVALID_PARAM;
552                 goto done;
553         }
554
555         tmp_ctx = talloc_stackframe();
556         if (tmp_ctx == NULL) {
557                 werr = WERR_NOMEM;
558                 goto done;
559         }
560
561         werr = libnet_conf_get_share_names(tmp_ctx, ctx, &tmp_num_shares,
562                                            &tmp_share_names);
563         if (!W_ERROR_IS_OK(werr)) {
564                 goto done;
565         }
566
567         tmp_num_params   = TALLOC_ARRAY(tmp_ctx, uint32_t, tmp_num_shares);
568         tmp_param_names  = TALLOC_ARRAY(tmp_ctx, char **, tmp_num_shares);
569         tmp_param_values = TALLOC_ARRAY(tmp_ctx, char **, tmp_num_shares);
570
571         if ((tmp_num_params == NULL) || (tmp_param_names == NULL) ||
572             (tmp_param_values == NULL))
573         {
574                 werr = WERR_NOMEM;
575                 goto done;
576         }
577
578         for (count = 0; count < tmp_num_shares; count++) {
579                 werr = libnet_conf_get_share(mem_ctx, ctx,
580                                              tmp_share_names[count],
581                                              &tmp_num_params[count],
582                                              &tmp_param_names[count],
583                                              &tmp_param_values[count]);
584                 if (!W_ERROR_IS_OK(werr)) {
585                         goto done;
586                 }
587         }
588
589         werr = WERR_OK;
590
591         *num_shares = tmp_num_shares;
592         if (tmp_num_shares > 0) {
593                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
594                 *num_params = talloc_move(mem_ctx, &tmp_num_params);
595                 *param_names = talloc_move(mem_ctx, &tmp_param_names);
596                 *param_values = talloc_move(mem_ctx, &tmp_param_values);
597         } else {
598                 *share_names = NULL;
599                 *num_params = NULL;
600                 *param_names = NULL;
601                 *param_values = NULL;
602         }
603
604 done:
605         TALLOC_FREE(tmp_ctx);
606         return werr;
607 }
608
609 /**
610  * get the list of share names defined in the configuration.
611  */
612 WERROR libnet_conf_get_share_names(TALLOC_CTX *mem_ctx,
613                                    struct libnet_conf_ctx *ctx,
614                                    uint32_t *num_shares,
615                                    char ***share_names)
616 {
617         uint32_t count;
618         uint32_t added_count = 0;
619         TALLOC_CTX *tmp_ctx = NULL;
620         WERROR werr = WERR_OK;
621         struct registry_key *key = NULL;
622         char *subkey_name = NULL;
623         char **tmp_share_names = NULL;
624
625         if ((num_shares == NULL) || (share_names == NULL)) {
626                 werr = WERR_INVALID_PARAM;
627                 goto done;
628         }
629
630         tmp_ctx = talloc_stackframe();
631         if (tmp_ctx == NULL) {
632                 werr = WERR_NOMEM;
633                 goto done;
634         }
635
636         /* make sure "global" is always listed first */
637         if (libnet_conf_share_exists(ctx, GLOBAL_NAME)) {
638                 werr = libnet_conf_add_string_to_array(tmp_ctx,
639                                                        &tmp_share_names,
640                                                        0, GLOBAL_NAME);
641                 if (!W_ERROR_IS_OK(werr)) {
642                         goto done;
643                 }
644                 added_count++;
645         }
646
647         werr = libnet_conf_reg_open_base_key(tmp_ctx, ctx,
648                                              SEC_RIGHTS_ENUM_SUBKEYS, &key);
649         if (!W_ERROR_IS_OK(werr)) {
650                 goto done;
651         }
652
653         for (count = 0;
654              W_ERROR_IS_OK(werr = reg_enumkey(tmp_ctx, key, count,
655                                               &subkey_name, NULL));
656              count++)
657         {
658                 if (strequal(subkey_name, GLOBAL_NAME)) {
659                         continue;
660                 }
661
662                 werr = libnet_conf_add_string_to_array(tmp_ctx,
663                                                        &tmp_share_names,
664                                                        added_count,
665                                                        subkey_name);
666                 if (!W_ERROR_IS_OK(werr)) {
667                         goto done;
668                 }
669                 added_count++;
670         }
671         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
672                 goto done;
673         }
674         werr = WERR_OK;
675
676         *num_shares = added_count;
677         if (added_count > 0) {
678                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
679         } else {
680                 *share_names = NULL;
681         }
682
683 done:
684         TALLOC_FREE(tmp_ctx);
685         return werr;
686 }
687
688 /**
689  * check if a share/service of a given name exists
690  */
691 bool libnet_conf_share_exists(struct libnet_conf_ctx *ctx,
692                               const char *servicename)
693 {
694         bool ret = false;
695         WERROR werr = WERR_OK;
696         TALLOC_CTX *mem_ctx = talloc_stackframe();
697         struct registry_key *key = NULL;
698
699         werr = libnet_conf_reg_open_service_key(mem_ctx, ctx, servicename,
700                                                 REG_KEY_READ, &key);
701         if (W_ERROR_IS_OK(werr)) {
702                 ret = true;
703         }
704
705         TALLOC_FREE(mem_ctx);
706         return ret;
707 }
708
709 /**
710  * Add a service if it does not already exist.
711  */
712 WERROR libnet_conf_create_share(struct libnet_conf_ctx *ctx,
713                                 const char *servicename)
714 {
715         WERROR werr;
716         TALLOC_CTX *mem_ctx = talloc_stackframe();
717         struct registry_key *key = NULL;
718
719         if (libnet_conf_share_exists(ctx, servicename)) {
720                 werr = WERR_ALREADY_EXISTS;
721                 goto done;
722         }
723
724         werr = libnet_conf_reg_create_service_key(mem_ctx, ctx, servicename,
725                                                   &key);
726
727 done:
728         TALLOC_FREE(mem_ctx);
729         return werr;
730 }
731
732 /**
733  * get a definition of a share (service) from configuration.
734  */
735 WERROR libnet_conf_get_share(TALLOC_CTX *mem_ctx, struct libnet_conf_ctx *ctx,
736                              const char *servicename, uint32_t *num_params,
737                              char ***param_names, char ***param_values)
738 {
739         WERROR werr = WERR_OK;
740         struct registry_key *key = NULL;
741
742         werr = libnet_conf_reg_open_service_key(mem_ctx, ctx, servicename,
743                                                 REG_KEY_READ, &key);
744         if (!W_ERROR_IS_OK(werr)) {
745                 goto done;
746         }
747
748         werr = libnet_conf_reg_get_values(mem_ctx, key, num_params,
749                                           param_names, param_values);
750
751 done:
752         TALLOC_FREE(key);
753         return werr;
754 }
755
756 /**
757  * delete a service from configuration
758  */
759 WERROR libnet_conf_delete_share(struct libnet_conf_ctx *ctx,
760                                 const char *servicename)
761 {
762         WERROR werr = WERR_OK;
763         struct registry_key *key = NULL;
764         TALLOC_CTX *mem_ctx = talloc_stackframe();
765
766         werr = libnet_conf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE, &key);
767         if (!W_ERROR_IS_OK(werr)) {
768                 goto done;
769         }
770
771         werr = reg_deletekey_recursive(key, key, servicename);
772
773 done:
774         TALLOC_FREE(mem_ctx);
775         return werr;
776 }
777
778 /**
779  * set a configuration parameter to the value provided.
780  */
781 WERROR libnet_conf_set_parameter(struct libnet_conf_ctx *ctx,
782                                  const char *service,
783                                  const char *param,
784                                  const char *valstr)
785 {
786         WERROR werr;
787         struct registry_key *key = NULL;
788         TALLOC_CTX *mem_ctx = talloc_stackframe();
789
790         if (!libnet_conf_share_exists(ctx, service)) {
791                 werr = WERR_NO_SUCH_SERVICE;
792                 goto done;
793         }
794
795         werr = libnet_conf_reg_open_service_key(mem_ctx, ctx, service,
796                                                 REG_KEY_WRITE, &key);
797         if (!W_ERROR_IS_OK(werr)) {
798                 goto done;
799         }
800
801         werr = libnet_conf_reg_set_value(key, param, valstr);
802
803 done:
804         TALLOC_FREE(mem_ctx);
805         return werr;
806 }
807
808 /**
809  * Set a global parameter
810  * (i.e. a parameter in the [global] service).
811  *
812  * This also creates [global] when it does not exist.
813  */
814 WERROR libnet_conf_set_global_parameter(struct libnet_conf_ctx *ctx,
815                                         const char *param, const char *val)
816 {
817         WERROR werr;
818
819         if (!libnet_conf_share_exists(ctx, GLOBAL_NAME)) {
820                 werr = libnet_conf_create_share(ctx, GLOBAL_NAME);
821                 if (!W_ERROR_IS_OK(werr)) {
822                         goto done;
823                 }
824         }
825         werr = libnet_conf_set_parameter(ctx, GLOBAL_NAME, param, val);
826
827 done:
828         return werr;
829 }
830
831 /**
832  * get the value of a configuration parameter as a string
833  */
834 WERROR libnet_conf_get_parameter(TALLOC_CTX *mem_ctx,
835                                  struct libnet_conf_ctx *ctx,
836                                  const char *service,
837                                  const char *param,
838                                  char **valstr)
839 {
840         WERROR werr = WERR_OK;
841         struct registry_key *key = NULL;
842         struct registry_value *value = NULL;
843
844         if (valstr == NULL) {
845                 werr = WERR_INVALID_PARAM;
846                 goto done;
847         }
848
849         if (!libnet_conf_share_exists(ctx, service)) {
850                 werr = WERR_NO_SUCH_SERVICE;
851                 goto done;
852         }
853
854         werr = libnet_conf_reg_open_service_key(mem_ctx, ctx, service,
855                                                 REG_KEY_READ, &key);
856         if (!W_ERROR_IS_OK(werr)) {
857                 goto done;
858         }
859
860         if (!libnet_conf_value_exists(key, param)) {
861                 werr = WERR_INVALID_PARAM;
862                 goto done;
863         }
864
865         werr = reg_queryvalue(mem_ctx, key, param, &value);
866         if (!W_ERROR_IS_OK(werr)) {
867                 goto done;
868         }
869
870         *valstr = libnet_conf_format_registry_value(mem_ctx, value);
871
872         if (*valstr == NULL) {
873                 werr = WERR_NOMEM;
874         }
875
876 done:
877         TALLOC_FREE(key);
878         TALLOC_FREE(value);
879         return werr;
880 }
881
882 /**
883  * Get the value of a global parameter.
884  *
885  * Create [global] if it does not exist.
886  */
887 WERROR libnet_conf_get_global_parameter(TALLOC_CTX *mem_ctx,
888                                         struct libnet_conf_ctx *ctx,
889                                         const char *param,
890                                         char **valstr)
891 {
892         WERROR werr;
893
894         if (!libnet_conf_share_exists(ctx, GLOBAL_NAME)) {
895                 werr = libnet_conf_create_share(ctx, GLOBAL_NAME);
896                 if (!W_ERROR_IS_OK(werr)) {
897                         goto done;
898                 }
899         }
900         werr = libnet_conf_get_parameter(mem_ctx, ctx, GLOBAL_NAME, param,
901                                          valstr);
902
903 done:
904         return werr;
905 }
906
907 /**
908  * delete a parameter from configuration
909  */
910 WERROR libnet_conf_delete_parameter(struct libnet_conf_ctx *ctx,
911                                     const char *service, const char *param)
912 {
913         struct registry_key *key = NULL;
914         WERROR werr = WERR_OK;
915         TALLOC_CTX *mem_ctx = talloc_stackframe();
916
917         if (!libnet_conf_share_exists(ctx, service)) {
918                 return WERR_NO_SUCH_SERVICE;
919         }
920
921         werr = libnet_conf_reg_open_service_key(mem_ctx, ctx, service,
922                                                 REG_KEY_ALL,
923                                                 &key);
924         if (!W_ERROR_IS_OK(werr)) {
925                 goto done;
926         }
927
928         if (!libnet_conf_value_exists(key, param)) {
929                 werr = WERR_INVALID_PARAM;
930                 goto done;
931         }
932
933         werr = reg_deletevalue(key, param);
934
935 done:
936         TALLOC_FREE(mem_ctx);
937         return werr;
938 }
939
940 /**
941  * Delete a global parameter.
942  *
943  * Create [global] if it does not exist.
944  */
945 WERROR libnet_conf_delete_global_parameter(struct libnet_conf_ctx *ctx,
946                                            const char *param)
947 {
948         WERROR werr;
949
950         if (!libnet_conf_share_exists(ctx, GLOBAL_NAME)) {
951                 werr = libnet_conf_create_share(ctx, GLOBAL_NAME);
952                 if (!W_ERROR_IS_OK(werr)) {
953                         goto done;
954                 }
955         }
956         werr = libnet_conf_delete_parameter(ctx, GLOBAL_NAME, param);
957
958 done:
959         return werr;
960 }