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