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