libsmbconf: implement get_includes() and set_includes() for registry backend.
[samba.git] / source3 / lib / smbconf / smbconf_reg.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libsmbconf - Samba configuration library, registry backend
4  *  Copyright (C) Michael Adam 2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "smbconf_private.h"
22
23 #define INCLUDES_VALNAME "includes"
24
25 struct reg_private_data {
26         NT_USER_TOKEN *token;
27         bool open;              /* did _we_ open the registry? */
28 };
29
30 /**********************************************************************
31  *
32  * helper functions
33  *
34  **********************************************************************/
35
36 /**
37  * a convenience helper to cast the private data structure
38  */
39 static struct reg_private_data *rpd(struct smbconf_ctx *ctx)
40 {
41         return (struct reg_private_data *)(ctx->data);
42 }
43
44 /**
45  * Open a registry key specified by "path"
46  */
47 static WERROR smbconf_reg_open_path(TALLOC_CTX *mem_ctx,
48                                     struct smbconf_ctx *ctx,
49                                     const char *path,
50                                     uint32 desired_access,
51                                     struct registry_key **key)
52 {
53         WERROR werr = WERR_OK;
54
55         if (ctx == NULL) {
56                 DEBUG(1, ("Error: configuration is not open!\n"));
57                 werr = WERR_INVALID_PARAM;
58                 goto done;
59         }
60
61         if (rpd(ctx)->token == NULL) {
62                 DEBUG(1, ("Error: token missing from smbconf_ctx. "
63                           "was smbconf_init() called?\n"));
64                 werr = WERR_INVALID_PARAM;
65                 goto done;
66         }
67
68         werr = ctx->ops->open_conf(ctx);
69         if (!W_ERROR_IS_OK(werr)) {
70                 DEBUG(1, ("Error opening the registry.\n"));
71                 goto done;
72         }
73
74         if (path == NULL) {
75                 DEBUG(1, ("Error: NULL path string given\n"));
76                 werr = WERR_INVALID_PARAM;
77                 goto done;
78         }
79
80         werr = reg_open_path(mem_ctx, path, desired_access, rpd(ctx)->token,
81                              key);
82
83         if (!W_ERROR_IS_OK(werr)) {
84                 DEBUG(1, ("Error opening registry path '%s': %s\n",
85                           path, dos_errstr(werr)));
86         }
87
88 done:
89         return werr;
90 }
91
92 /**
93  * Open a subkey of the base key (i.e a service)
94  */
95 static WERROR smbconf_reg_open_service_key(TALLOC_CTX *mem_ctx,
96                                            struct smbconf_ctx *ctx,
97                                            const char *servicename,
98                                            uint32 desired_access,
99                                            struct registry_key **key)
100 {
101         WERROR werr = WERR_OK;
102         char *path = NULL;
103
104         if (servicename == NULL) {
105                 DEBUG(3, ("Error: NULL servicename given.\n"));
106                 werr = WERR_INVALID_PARAM;
107                 goto done;
108         }
109
110         path = talloc_asprintf(mem_ctx, "%s\\%s", ctx->path, servicename);
111         if (path == NULL) {
112                 werr = WERR_NOMEM;
113                 goto done;
114         }
115
116         werr = smbconf_reg_open_path(mem_ctx, ctx, path, desired_access, key);
117
118 done:
119         TALLOC_FREE(path);
120         return werr;
121 }
122
123 /**
124  * open the base key
125  */
126 static WERROR smbconf_reg_open_base_key(TALLOC_CTX *mem_ctx,
127                                         struct smbconf_ctx *ctx,
128                                         uint32 desired_access,
129                                         struct registry_key **key)
130 {
131         return smbconf_reg_open_path(mem_ctx, ctx, ctx->path, desired_access,
132                                      key);
133 }
134
135 /**
136  * check if a value exists in a given registry key
137  */
138 static bool smbconf_value_exists(struct registry_key *key, const char *param)
139 {
140         bool ret = false;
141         WERROR werr = WERR_OK;
142         TALLOC_CTX *ctx = talloc_stackframe();
143         struct registry_value *value = NULL;
144
145         werr = reg_queryvalue(ctx, key, param, &value);
146         if (W_ERROR_IS_OK(werr)) {
147                 ret = true;
148         }
149
150         TALLOC_FREE(ctx);
151         return ret;
152 }
153
154 /**
155  * create a subkey of the base key (i.e. a service...)
156  */
157 static WERROR smbconf_reg_create_service_key(TALLOC_CTX *mem_ctx,
158                                              struct smbconf_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_stackframe())) {
171                 werr = WERR_NOMEM;
172                 goto done;
173         }
174
175         werr = smbconf_reg_open_base_key(create_ctx, ctx, REG_KEY_WRITE,
176                                          &create_parent);
177         if (!W_ERROR_IS_OK(werr)) {
178                 goto done;
179         }
180
181         werr = reg_createkey(mem_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 smbconf_reg_set_value(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         if (registry_smbconf_valname_forbidden(canon_valname)) {
226                 DEBUG(5, ("Parameter '%s' not allowed in registry.\n",
227                           canon_valname));
228                 werr = WERR_INVALID_PARAM;
229                 goto done;
230         }
231
232         subkeyname = strrchr_m(key->key->name, '\\');
233         if ((subkeyname == NULL) || (*(subkeyname +1) == '\0')) {
234                 DEBUG(5, ("Invalid registry key '%s' given as "
235                           "smbconf section.\n", key->key->name));
236                 werr = WERR_INVALID_PARAM;
237                 goto done;
238         }
239         subkeyname++;
240         if (!strequal(subkeyname, GLOBAL_NAME) &&
241             lp_parameter_is_global(valname))
242         {
243                 DEBUG(5, ("Global paramter '%s' not allowed in "
244                           "service definition ('%s').\n", canon_valname,
245                           subkeyname));
246                 werr = WERR_INVALID_PARAM;
247                 goto done;
248         }
249
250         ZERO_STRUCT(val);
251
252         val.type = REG_SZ;
253         val.v.sz.str = CONST_DISCARD(char *, canon_valstr);
254         val.v.sz.len = strlen(canon_valstr) + 1;
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 static WERROR smbconf_reg_set_multi_sz_value(struct registry_key *key,
268                                              const char *valname,
269                                              const uint32_t num_strings,
270                                              const char **strings)
271 {
272         WERROR werr;
273         struct registry_value *value;
274         uint32_t count;
275         TALLOC_CTX *tmp_ctx = talloc_stackframe();
276
277         if (strings == NULL) {
278                 werr = WERR_INVALID_PARAM;
279                 goto done;
280         }
281
282         value = TALLOC_ZERO_P(tmp_ctx, struct registry_value);
283
284         value->type = REG_MULTI_SZ;
285         value->v.multi_sz.num_strings = num_strings;
286         value->v.multi_sz.strings = TALLOC_ARRAY(tmp_ctx, char *, num_strings);
287         if (value->v.multi_sz.strings == NULL) {
288                 werr = WERR_NOMEM;
289                 goto done;
290         }
291         for (count = 0; count < num_strings; count++) {
292                 value->v.multi_sz.strings[count] =
293                         talloc_strdup(value->v.multi_sz.strings,
294                                       strings[count]);
295                 if (value->v.multi_sz.strings[count] == NULL) {
296                         werr = WERR_NOMEM;
297                         goto done;
298                 }
299         }
300
301         werr = reg_setvalue(key, valname, value);
302         if (!W_ERROR_IS_OK(werr)) {
303                 DEBUG(5, ("Error adding value '%s' to key '%s': %s\n",
304                           valname, key->key->name, dos_errstr(werr)));
305         }
306
307 done:
308         TALLOC_FREE(tmp_ctx);
309         return werr;
310 }
311
312 /**
313  * format a registry_value into a string.
314  *
315  * This is intended to be used for smbconf registry values,
316  * which are ar stored as REG_SZ values, so the incomplete
317  * handling should be ok.
318  */
319 static char *smbconf_format_registry_value(TALLOC_CTX *mem_ctx,
320                                            struct registry_value *value)
321 {
322         char *result = NULL;
323
324         /* alternatively, create a new talloc context? */
325         if (mem_ctx == NULL) {
326                 return result;
327         }
328
329         switch (value->type) {
330         case REG_DWORD:
331                 result = talloc_asprintf(mem_ctx, "%d", value->v.dword);
332                 break;
333         case REG_SZ:
334         case REG_EXPAND_SZ:
335                 result = talloc_asprintf(mem_ctx, "%s", value->v.sz.str);
336                 break;
337         case REG_MULTI_SZ: {
338                 uint32 j;
339                 for (j = 0; j < value->v.multi_sz.num_strings; j++) {
340                         result = talloc_asprintf(mem_ctx, "%s \"%s\" ",
341                                                  result,
342                                                  value->v.multi_sz.strings[j]);
343                         if (result == NULL) {
344                                 break;
345                         }
346                 }
347                 break;
348         }
349         case REG_BINARY:
350                 result = talloc_asprintf(mem_ctx, "binary (%d bytes)",
351                                          (int)value->v.binary.length);
352                 break;
353         default:
354                 result = talloc_asprintf(mem_ctx, "<unprintable>");
355                 break;
356         }
357         return result;
358 }
359
360 /**
361  * Get the values of a key as a list of value names
362  * and a list of value strings (ordered)
363  */
364 static WERROR smbconf_reg_get_values(TALLOC_CTX *mem_ctx,
365                                      struct registry_key *key,
366                                      uint32_t *num_values,
367                                      char ***value_names,
368                                      char ***value_strings)
369 {
370         TALLOC_CTX *tmp_ctx = NULL;
371         WERROR werr = WERR_OK;
372         uint32_t count;
373         struct registry_value *valvalue = NULL;
374         char *valname = NULL;
375         char **tmp_valnames = NULL;
376         char **tmp_valstrings = NULL;
377
378         if ((num_values == NULL) || (value_names == NULL) ||
379             (value_strings == NULL))
380         {
381                 werr = WERR_INVALID_PARAM;
382                 goto done;
383         }
384
385         tmp_ctx = talloc_stackframe();
386         if (tmp_ctx == NULL) {
387                 werr = WERR_NOMEM;
388                 goto done;
389         }
390
391         for (count = 0;
392              werr = reg_enumvalue(tmp_ctx, key, count, &valname, &valvalue),
393              W_ERROR_IS_OK(werr);
394              count++)
395         {
396                 char *valstring;
397
398                 werr = smbconf_add_string_to_array(tmp_ctx,
399                                                    &tmp_valnames,
400                                                    count, valname);
401                 if (!W_ERROR_IS_OK(werr)) {
402                         goto done;
403                 }
404
405                 valstring = smbconf_format_registry_value(tmp_ctx, valvalue);
406                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_valstrings,
407                                                    count, valstring);
408                 if (!W_ERROR_IS_OK(werr)) {
409                         goto done;
410                 }
411         }
412         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
413                 goto done;
414         }
415
416         werr = WERR_OK;
417
418         *num_values = count;
419         if (count > 0) {
420                 *value_names = talloc_move(mem_ctx, &tmp_valnames);
421                 *value_strings = talloc_move(mem_ctx, &tmp_valstrings);
422         } else {
423                 *value_names = NULL;
424                 *value_strings = NULL;
425         }
426
427 done:
428         TALLOC_FREE(tmp_ctx);
429         return werr;
430 }
431
432 /**********************************************************************
433  *
434  * smbconf operations: registry implementations
435  *
436  **********************************************************************/
437
438 /**
439  * initialize the registry smbconf backend
440  */
441 static WERROR smbconf_reg_init(struct smbconf_ctx *ctx, const char *path)
442 {
443         WERROR werr = WERR_OK;
444
445         if (path == NULL) {
446                 path = KEY_SMBCONF;
447         }
448         ctx->path = talloc_strdup(ctx, path);
449         if (ctx->path == NULL) {
450                 werr = WERR_NOMEM;
451                 goto done;
452         }
453
454         ctx->data = TALLOC_ZERO_P(ctx, struct reg_private_data);
455
456         werr = ntstatus_to_werror(registry_create_admin_token(ctx,
457                                                         &(rpd(ctx)->token)));
458         if (!W_ERROR_IS_OK(werr)) {
459                 DEBUG(1, ("Error creating admin token\n"));
460                 goto done;
461         }
462         rpd(ctx)->open = false;
463
464         if (!registry_init_smbconf()) {
465                 werr = WERR_REG_IO_FAILURE;
466                 goto done;
467         }
468
469 done:
470         return werr;
471 }
472
473 static int smbconf_reg_shutdown(struct smbconf_ctx *ctx)
474 {
475         return ctx->ops->close_conf(ctx);
476 }
477
478 static WERROR smbconf_reg_open(struct smbconf_ctx *ctx)
479 {
480         WERROR werr;
481
482         if (rpd(ctx)->open) {
483                 return WERR_OK;
484         }
485
486         werr = regdb_open();
487         if (W_ERROR_IS_OK(werr)) {
488                 rpd(ctx)->open = true;
489         }
490         return werr;
491 }
492
493 static int smbconf_reg_close(struct smbconf_ctx *ctx)
494 {
495         int ret;
496
497         if (!rpd(ctx)->open) {
498                 return 0;
499         }
500
501         ret = regdb_close();
502         if (ret == 0) {
503                 rpd(ctx)->open = false;
504         }
505         return ret;
506 }
507
508 /**
509  * Get the change sequence number of the given service/parameter.
510  * service and parameter strings may be NULL.
511  */
512 static void smbconf_reg_get_csn(struct smbconf_ctx *ctx,
513                                 struct smbconf_csn *csn,
514                                 const char *service, const char *param)
515 {
516         if (csn == NULL) {
517                 return;
518         }
519
520         if (!W_ERROR_IS_OK(ctx->ops->open_conf(ctx))) {
521                 return;
522         }
523
524         csn->csn = (uint64_t)regdb_get_seqnum();
525 }
526
527 /**
528  * Drop the whole configuration (restarting empty) - registry version
529  */
530 static WERROR smbconf_reg_drop(struct smbconf_ctx *ctx)
531 {
532         char *path, *p;
533         WERROR werr = WERR_OK;
534         struct registry_key *parent_key = NULL;
535         struct registry_key *new_key = NULL;
536         TALLOC_CTX* mem_ctx = talloc_stackframe();
537         enum winreg_CreateAction action;
538
539         path = talloc_strdup(mem_ctx, ctx->path);
540         if (path == NULL) {
541                 werr = WERR_NOMEM;
542                 goto done;
543         }
544         p = strrchr(path, '\\');
545         *p = '\0';
546         werr = smbconf_reg_open_path(mem_ctx, ctx, path, REG_KEY_WRITE,
547                                      &parent_key);
548
549         if (!W_ERROR_IS_OK(werr)) {
550                 goto done;
551         }
552
553         werr = reg_deletekey_recursive(mem_ctx, parent_key, p+1);
554
555         if (!W_ERROR_IS_OK(werr)) {
556                 goto done;
557         }
558
559         werr = reg_createkey(mem_ctx, parent_key, p+1, REG_KEY_WRITE,
560                              &new_key, &action);
561
562 done:
563         TALLOC_FREE(mem_ctx);
564         return werr;
565 }
566
567 /**
568  * get the list of share names defined in the configuration.
569  * registry version.
570  */
571 static WERROR smbconf_reg_get_share_names(struct smbconf_ctx *ctx,
572                                           TALLOC_CTX *mem_ctx,
573                                           uint32_t *num_shares,
574                                           char ***share_names)
575 {
576         uint32_t count;
577         uint32_t added_count = 0;
578         TALLOC_CTX *tmp_ctx = NULL;
579         WERROR werr = WERR_OK;
580         struct registry_key *key = NULL;
581         char *subkey_name = NULL;
582         char **tmp_share_names = NULL;
583
584         if ((num_shares == NULL) || (share_names == NULL)) {
585                 werr = WERR_INVALID_PARAM;
586                 goto done;
587         }
588
589         tmp_ctx = talloc_stackframe();
590         if (tmp_ctx == NULL) {
591                 werr = WERR_NOMEM;
592                 goto done;
593         }
594
595         /* make sure "global" is always listed first */
596         if (smbconf_share_exists(ctx, GLOBAL_NAME)) {
597                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
598                                                    0, GLOBAL_NAME);
599                 if (!W_ERROR_IS_OK(werr)) {
600                         goto done;
601                 }
602                 added_count++;
603         }
604
605         werr = smbconf_reg_open_base_key(tmp_ctx, ctx,
606                                          SEC_RIGHTS_ENUM_SUBKEYS, &key);
607         if (!W_ERROR_IS_OK(werr)) {
608                 goto done;
609         }
610
611         for (count = 0;
612              werr = reg_enumkey(tmp_ctx, key, count, &subkey_name, NULL),
613              W_ERROR_IS_OK(werr);
614              count++)
615         {
616                 if (strequal(subkey_name, GLOBAL_NAME)) {
617                         continue;
618                 }
619
620                 werr = smbconf_add_string_to_array(tmp_ctx,
621                                                    &tmp_share_names,
622                                                    added_count,
623                                                    subkey_name);
624                 if (!W_ERROR_IS_OK(werr)) {
625                         goto done;
626                 }
627                 added_count++;
628         }
629         if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
630                 goto done;
631         }
632         werr = WERR_OK;
633
634         *num_shares = added_count;
635         if (added_count > 0) {
636                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
637         } else {
638                 *share_names = NULL;
639         }
640
641 done:
642         TALLOC_FREE(tmp_ctx);
643         return werr;
644 }
645
646 /**
647  * check if a share/service of a given name exists - registry version
648  */
649 static bool smbconf_reg_share_exists(struct smbconf_ctx *ctx,
650                                      const char *servicename)
651 {
652         bool ret = false;
653         WERROR werr = WERR_OK;
654         TALLOC_CTX *mem_ctx = talloc_stackframe();
655         struct registry_key *key = NULL;
656
657         werr = smbconf_reg_open_service_key(mem_ctx, ctx, servicename,
658                                             REG_KEY_READ, &key);
659         if (W_ERROR_IS_OK(werr)) {
660                 ret = true;
661         }
662
663         TALLOC_FREE(mem_ctx);
664         return ret;
665 }
666
667 /**
668  * Add a service if it does not already exist - registry version
669  */
670 static WERROR smbconf_reg_create_share(struct smbconf_ctx *ctx,
671                                        const char *servicename)
672 {
673         WERROR werr;
674         TALLOC_CTX *mem_ctx = talloc_stackframe();
675         struct registry_key *key = NULL;
676
677         werr = smbconf_reg_create_service_key(mem_ctx, ctx, servicename, &key);
678
679         TALLOC_FREE(mem_ctx);
680         return werr;
681 }
682
683 /**
684  * get a definition of a share (service) from configuration.
685  */
686 static WERROR smbconf_reg_get_share(struct smbconf_ctx *ctx,
687                                     TALLOC_CTX *mem_ctx,
688                                     const char *servicename,
689                                     uint32_t *num_params,
690                                     char ***param_names, char ***param_values)
691 {
692         WERROR werr = WERR_OK;
693         struct registry_key *key = NULL;
694
695         werr = smbconf_reg_open_service_key(mem_ctx, ctx, servicename,
696                                             REG_KEY_READ, &key);
697         if (!W_ERROR_IS_OK(werr)) {
698                 goto done;
699         }
700
701         werr = smbconf_reg_get_values(mem_ctx, key, num_params,
702                                       param_names, param_values);
703
704 done:
705         TALLOC_FREE(key);
706         return werr;
707 }
708
709 /**
710  * delete a service from configuration
711  */
712 static WERROR smbconf_reg_delete_share(struct smbconf_ctx *ctx,
713                                        const char *servicename)
714 {
715         WERROR werr = WERR_OK;
716         struct registry_key *key = NULL;
717         TALLOC_CTX *mem_ctx = talloc_stackframe();
718
719         werr = smbconf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE, &key);
720         if (!W_ERROR_IS_OK(werr)) {
721                 goto done;
722         }
723
724         werr = reg_deletekey_recursive(key, key, servicename);
725
726 done:
727         TALLOC_FREE(mem_ctx);
728         return werr;
729 }
730
731 /**
732  * set a configuration parameter to the value provided.
733  */
734 static WERROR smbconf_reg_set_parameter(struct smbconf_ctx *ctx,
735                                         const char *service,
736                                         const char *param,
737                                         const char *valstr)
738 {
739         WERROR werr;
740         struct registry_key *key = NULL;
741         TALLOC_CTX *mem_ctx = talloc_stackframe();
742
743         werr = smbconf_reg_open_service_key(mem_ctx, ctx, service,
744                                             REG_KEY_WRITE, &key);
745         if (!W_ERROR_IS_OK(werr)) {
746                 goto done;
747         }
748
749         werr = smbconf_reg_set_value(key, param, valstr);
750
751 done:
752         TALLOC_FREE(mem_ctx);
753         return werr;
754 }
755
756 /**
757  * get the value of a configuration parameter as a string
758  */
759 static WERROR smbconf_reg_get_parameter(struct smbconf_ctx *ctx,
760                                         TALLOC_CTX *mem_ctx,
761                                         const char *service,
762                                         const char *param,
763                                         char **valstr)
764 {
765         WERROR werr = WERR_OK;
766         struct registry_key *key = NULL;
767         struct registry_value *value = NULL;
768
769         werr = smbconf_reg_open_service_key(mem_ctx, ctx, service,
770                                             REG_KEY_READ, &key);
771         if (!W_ERROR_IS_OK(werr)) {
772                 goto done;
773         }
774
775         if (!smbconf_value_exists(key, param)) {
776                 werr = WERR_INVALID_PARAM;
777                 goto done;
778         }
779
780         werr = reg_queryvalue(mem_ctx, key, param, &value);
781         if (!W_ERROR_IS_OK(werr)) {
782                 goto done;
783         }
784
785         *valstr = smbconf_format_registry_value(mem_ctx, value);
786
787         if (*valstr == NULL) {
788                 werr = WERR_NOMEM;
789         }
790
791 done:
792         TALLOC_FREE(key);
793         TALLOC_FREE(value);
794         return werr;
795 }
796
797 /**
798  * delete a parameter from configuration
799  */
800 static WERROR smbconf_reg_delete_parameter(struct smbconf_ctx *ctx,
801                                            const char *service,
802                                            const char *param)
803 {
804         struct registry_key *key = NULL;
805         WERROR werr = WERR_OK;
806         TALLOC_CTX *mem_ctx = talloc_stackframe();
807
808         werr = smbconf_reg_open_service_key(mem_ctx, ctx, service,
809                                             REG_KEY_ALL, &key);
810         if (!W_ERROR_IS_OK(werr)) {
811                 goto done;
812         }
813
814         if (!smbconf_value_exists(key, param)) {
815                 werr = WERR_INVALID_PARAM;
816                 goto done;
817         }
818
819         werr = reg_deletevalue(key, param);
820
821 done:
822         TALLOC_FREE(mem_ctx);
823         return werr;
824 }
825
826 static WERROR smbconf_reg_get_includes(struct smbconf_ctx *ctx,
827                                        TALLOC_CTX *mem_ctx,
828                                        const char *service,
829                                        uint32_t *num_includes,
830                                        char ***includes)
831 {
832         WERROR werr;
833         uint32_t count;
834         struct registry_key *key = NULL;
835         struct registry_value *value = NULL;
836         char **tmp_includes = NULL;
837         TALLOC_CTX *tmp_ctx = talloc_stackframe();
838
839         werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service,
840                                             REG_KEY_READ, &key);
841         if (!W_ERROR_IS_OK(werr)) {
842                 goto done;
843         }
844
845         if (!smbconf_value_exists(key, INCLUDES_VALNAME)) {
846                 /* no includes */
847                 goto done;
848         }
849
850         werr = reg_queryvalue(tmp_ctx, key, INCLUDES_VALNAME, &value);
851         if (!W_ERROR_IS_OK(werr)) {
852                 goto done;
853         }
854
855         if (value->type != REG_MULTI_SZ) {
856                 /* wront type -- ignore */
857                 goto done;
858         }
859
860         for (count = 0; count < value->v.multi_sz.num_strings; count++)
861         {
862                 werr = smbconf_add_string_to_array(tmp_ctx,
863                                         &tmp_includes,
864                                         count,
865                                         value->v.multi_sz.strings[count]);
866                 if (!W_ERROR_IS_OK(werr)) {
867                         goto done;
868                 }
869         }
870
871         if (count > 0) {
872                 *includes = talloc_move(mem_ctx, &tmp_includes);
873                 if (*includes == NULL) {
874                         werr = WERR_NOMEM;
875                         goto done;
876                 }
877                 *num_includes = count;
878         } else {
879                 *num_includes = 0;
880                 *includes = NULL;
881         }
882
883 done:
884         TALLOC_FREE(tmp_ctx);
885         return werr;
886 }
887
888 static WERROR smbconf_reg_set_includes(struct smbconf_ctx *ctx,
889                                        const char *service,
890                                        uint32_t num_includes,
891                                        const char **includes)
892 {
893         WERROR werr = WERR_OK;
894         struct registry_key *key = NULL;
895         TALLOC_CTX *tmp_ctx = talloc_stackframe();
896
897         werr = smbconf_reg_open_service_key(tmp_ctx, ctx, service,
898                                             REG_KEY_ALL, &key);
899         if (!W_ERROR_IS_OK(werr)) {
900                 goto done;
901         }
902
903         werr = smbconf_reg_set_multi_sz_value(key, INCLUDES_VALNAME,
904                                               num_includes, includes);
905
906 done:
907         TALLOC_FREE(tmp_ctx);
908         return werr;
909 }
910
911
912 struct smbconf_ops smbconf_ops_reg = {
913         .init                   = smbconf_reg_init,
914         .shutdown               = smbconf_reg_shutdown,
915         .open_conf              = smbconf_reg_open,
916         .close_conf             = smbconf_reg_close,
917         .get_csn                = smbconf_reg_get_csn,
918         .drop                   = smbconf_reg_drop,
919         .get_share_names        = smbconf_reg_get_share_names,
920         .share_exists           = smbconf_reg_share_exists,
921         .create_share           = smbconf_reg_create_share,
922         .get_share              = smbconf_reg_get_share,
923         .delete_share           = smbconf_reg_delete_share,
924         .set_parameter          = smbconf_reg_set_parameter,
925         .get_parameter          = smbconf_reg_get_parameter,
926         .delete_parameter       = smbconf_reg_delete_parameter,
927         .get_includes           = smbconf_reg_get_includes,
928         .set_includes           = smbconf_reg_set_includes,
929 };
930
931
932 /**
933  * initialize the smbconf registry backend
934  * the only function that is exported from this module
935  */
936 WERROR smbconf_init_reg(TALLOC_CTX *mem_ctx, struct smbconf_ctx **conf_ctx,
937                         const char *path)
938 {
939         return smbconf_init(mem_ctx, conf_ctx, path, &smbconf_ops_reg);
940 }