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