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