libsmbconf: Convert smbconf_init() to sbcErr.
[samba.git] / lib / smbconf / smbconf_txt.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  libsmbconf - Samba configuration library, text 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 /*
21  * This is a sample implementation of a libsmbconf text backend
22  * using the params.c parser.
23  *
24  * It is read only.
25  * Don't expect brilliant performance, since it is not hashing the lists.
26  */
27
28 #include "includes.h"
29 #include "smbconf_private.h"
30 #include "lib/smbconf/smbconf_txt.h"
31
32 struct txt_cache {
33         uint32_t current_share;
34         uint32_t num_shares;
35         char **share_names;
36         uint32_t *num_params;
37         char ***param_names;
38         char ***param_values;
39 };
40
41 struct txt_private_data {
42         struct txt_cache *cache;
43         uint64_t csn;
44         bool verbatim;
45 };
46
47 /**********************************************************************
48  *
49  * helper functions
50  *
51  **********************************************************************/
52
53 /**
54  * a convenience helper to cast the private data structure
55  */
56 static struct txt_private_data *pd(struct smbconf_ctx *ctx)
57 {
58         return (struct txt_private_data *)(ctx->data);
59 }
60
61 static bool smbconf_txt_do_section(const char *section, void *private_data)
62 {
63         WERROR werr;
64         uint32_t idx;
65         struct txt_private_data *tpd = (struct txt_private_data *)private_data;
66         struct txt_cache *cache = tpd->cache;
67
68         if (smbconf_find_in_array(section, cache->share_names,
69                                   cache->num_shares, &idx))
70         {
71                 cache->current_share = idx;
72                 return true;
73         }
74
75         werr = smbconf_add_string_to_array(cache, &(cache->share_names),
76                                            cache->num_shares, section);
77         if (!W_ERROR_IS_OK(werr)) {
78                 return false;
79         }
80         cache->current_share = cache->num_shares;
81         cache->num_shares++;
82
83         cache->param_names = talloc_realloc(cache,
84                                                   cache->param_names,
85                                                   char **,
86                                                   cache->num_shares);
87         if (cache->param_names == NULL) {
88                 return false;
89         }
90         cache->param_names[cache->current_share] = NULL;
91
92         cache->param_values = talloc_realloc(cache,
93                                                    cache->param_values,
94                                                    char **,
95                                                    cache->num_shares);
96         if (cache->param_values == NULL) {
97                 return false;
98         }
99         cache->param_values[cache->current_share] = NULL;
100
101         cache->num_params = talloc_realloc(cache,
102                                                  cache->num_params,
103                                                  uint32_t,
104                                                  cache->num_shares);
105         if (cache->num_params == NULL) {
106                 return false;
107         }
108         cache->num_params[cache->current_share] = 0;
109
110         return true;
111 }
112
113 static bool smbconf_txt_do_parameter(const char *param_name,
114                                      const char *param_value,
115                                      void *private_data)
116 {
117         WERROR werr;
118         char **param_names, **param_values;
119         uint32_t num_params;
120         uint32_t idx;
121         struct txt_private_data *tpd = (struct txt_private_data *)private_data;
122         struct txt_cache *cache = tpd->cache;
123
124         if (cache->num_shares == 0) {
125                 /*
126                  * not in any share yet,
127                  * initialize the "empty" section (NULL):
128                  * parameters without a previous [section] are stored here.
129                  */
130                 if (!smbconf_txt_do_section(NULL, private_data)) {
131                         return false;
132                 }
133         }
134
135         param_names  = cache->param_names[cache->current_share];
136         param_values = cache->param_values[cache->current_share];
137         num_params   = cache->num_params[cache->current_share];
138
139         if (!(tpd->verbatim) &&
140             smbconf_find_in_array(param_name, param_names, num_params, &idx))
141         {
142                 talloc_free(param_values[idx]);
143                 param_values[idx] = talloc_strdup(cache, param_value);
144                 if (param_values[idx] == NULL) {
145                         return false;
146                 }
147                 return true;
148         }
149         werr = smbconf_add_string_to_array(cache,
150                                 &(cache->param_names[cache->current_share]),
151                                 num_params, param_name);
152         if (!W_ERROR_IS_OK(werr)) {
153                 return false;
154         }
155         werr = smbconf_add_string_to_array(cache,
156                                 &(cache->param_values[cache->current_share]),
157                                 num_params, param_value);
158         cache->num_params[cache->current_share]++;
159         return W_ERROR_IS_OK(werr);
160 }
161
162 static void smbconf_txt_flush_cache(struct smbconf_ctx *ctx)
163 {
164         talloc_free(pd(ctx)->cache);
165         pd(ctx)->cache = NULL;
166 }
167
168 static sbcErr smbconf_txt_init_cache(struct smbconf_ctx *ctx)
169 {
170         if (pd(ctx)->cache != NULL) {
171                 smbconf_txt_flush_cache(ctx);
172         }
173
174         pd(ctx)->cache = talloc_zero(pd(ctx), struct txt_cache);
175
176         if (pd(ctx)->cache == NULL) {
177                 return SBC_ERR_NOMEM;
178         }
179
180         return SBC_ERR_OK;
181 }
182
183 static sbcErr smbconf_txt_load_file(struct smbconf_ctx *ctx)
184 {
185         sbcErr err;
186         uint64_t new_csn;
187
188         if (!file_exist(ctx->path)) {
189                 return SBC_ERR_BADFILE;
190         }
191
192         new_csn = (uint64_t)file_modtime(ctx->path);
193         if (new_csn == pd(ctx)->csn) {
194                 return SBC_ERR_OK;
195         }
196
197         err = smbconf_txt_init_cache(ctx);
198         if (!SBC_ERROR_IS_OK(err)) {
199                 return err;
200         }
201
202         if (!pm_process(ctx->path, smbconf_txt_do_section,
203                         smbconf_txt_do_parameter, pd(ctx)))
204         {
205                 return SBC_ERR_CAN_NOT_COMPLETE;
206         }
207
208         pd(ctx)->csn = new_csn;
209
210         return SBC_ERR_OK;
211 }
212
213
214 /**********************************************************************
215  *
216  * smbconf operations: text backend implementations
217  *
218  **********************************************************************/
219
220 /**
221  * initialize the text based smbconf backend
222  */
223 static sbcErr smbconf_txt_init(struct smbconf_ctx *ctx, const char *path)
224 {
225         if (path == NULL) {
226                 return SBC_ERR_BADFILE;
227         }
228         ctx->path = talloc_strdup(ctx, path);
229         if (ctx->path == NULL) {
230                 return SBC_ERR_NOMEM;
231         }
232
233         ctx->data = talloc_zero(ctx, struct txt_private_data);
234         if (ctx->data == NULL) {
235                 return SBC_ERR_NOMEM;
236         }
237
238         pd(ctx)->verbatim = true;
239
240         return SBC_ERR_OK;
241 }
242
243 static int smbconf_txt_shutdown(struct smbconf_ctx *ctx)
244 {
245         return ctx->ops->close_conf(ctx);
246 }
247
248 static bool smbconf_txt_requires_messaging(struct smbconf_ctx *ctx)
249 {
250         return false;
251 }
252
253 static bool smbconf_txt_is_writeable(struct smbconf_ctx *ctx)
254 {
255         /* no write support in this backend yet... */
256         return false;
257 }
258
259 static WERROR smbconf_txt_open(struct smbconf_ctx *ctx)
260 {
261         sbcErr err;
262
263         err = smbconf_txt_load_file(ctx);
264         if (!SBC_ERROR_IS_OK(err)) {
265                 return WERR_GENERAL_FAILURE;
266         }
267
268         return WERR_OK;
269 }
270
271 static int smbconf_txt_close(struct smbconf_ctx *ctx)
272 {
273         smbconf_txt_flush_cache(ctx);
274         return 0;
275 }
276
277 /**
278  * Get the change sequence number of the given service/parameter.
279  * service and parameter strings may be NULL.
280  */
281 static void smbconf_txt_get_csn(struct smbconf_ctx *ctx,
282                                 struct smbconf_csn *csn,
283                                 const char *service, const char *param)
284 {
285         if (csn == NULL) {
286                 return;
287         }
288
289         csn->csn = (uint64_t)file_modtime(ctx->path);
290 }
291
292 /**
293  * Drop the whole configuration (restarting empty)
294  */
295 static WERROR smbconf_txt_drop(struct smbconf_ctx *ctx)
296 {
297         return WERR_NOT_SUPPORTED;
298 }
299
300 /**
301  * get the list of share names defined in the configuration.
302  */
303 static WERROR smbconf_txt_get_share_names(struct smbconf_ctx *ctx,
304                                           TALLOC_CTX *mem_ctx,
305                                           uint32_t *num_shares,
306                                           char ***share_names)
307 {
308         uint32_t count;
309         uint32_t added_count = 0;
310         TALLOC_CTX *tmp_ctx = NULL;
311         WERROR werr = WERR_OK;
312         sbcErr err = SBC_ERR_OK;
313         char **tmp_share_names = NULL;
314
315         if ((num_shares == NULL) || (share_names == NULL)) {
316                 werr = WERR_INVALID_PARAM;
317                 goto done;
318         }
319
320         err = smbconf_txt_load_file(ctx);
321         if (!SBC_ERROR_IS_OK(err)) {
322                 return WERR_GENERAL_FAILURE;
323         }
324
325         tmp_ctx = talloc_stackframe();
326
327         /* make sure "global" is always listed first,
328          * possibly after NULL section */
329
330         if (smbconf_share_exists(ctx, NULL)) {
331                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
332                                                    0, NULL);
333                 if (!W_ERROR_IS_OK(werr)) {
334                         goto done;
335                 }
336                 added_count++;
337         }
338
339         if (smbconf_share_exists(ctx, GLOBAL_NAME)) {
340                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
341                                                    added_count, GLOBAL_NAME);
342                 if (!W_ERROR_IS_OK(werr)) {
343                         goto done;
344                 }
345                 added_count++;
346         }
347
348         for (count = 0; count < pd(ctx)->cache->num_shares; count++) {
349                 if (strequal(pd(ctx)->cache->share_names[count], GLOBAL_NAME) ||
350                     (pd(ctx)->cache->share_names[count] == NULL))
351                 {
352                         continue;
353                 }
354
355                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
356                                         added_count,
357                                         pd(ctx)->cache->share_names[count]);
358                 if (!W_ERROR_IS_OK(werr)) {
359                         goto done;
360                 }
361                 added_count++;
362         }
363
364         *num_shares = added_count;
365         if (added_count > 0) {
366                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
367         } else {
368                 *share_names = NULL;
369         }
370
371 done:
372         talloc_free(tmp_ctx);
373         return werr;
374 }
375
376 /**
377  * check if a share/service of a given name exists
378  */
379 static bool smbconf_txt_share_exists(struct smbconf_ctx *ctx,
380                                      const char *servicename)
381 {
382         sbcErr err;
383
384         err = smbconf_txt_load_file(ctx);
385         if (!SBC_ERROR_IS_OK(err)) {
386                 return false;
387         }
388
389         return smbconf_find_in_array(servicename,
390                                      pd(ctx)->cache->share_names,
391                                      pd(ctx)->cache->num_shares, NULL);
392 }
393
394 /**
395  * Add a service if it does not already exist
396  */
397 static WERROR smbconf_txt_create_share(struct smbconf_ctx *ctx,
398                                        const char *servicename)
399 {
400         return WERR_NOT_SUPPORTED;
401 }
402
403 /**
404  * get a definition of a share (service) from configuration.
405  */
406 static WERROR smbconf_txt_get_share(struct smbconf_ctx *ctx,
407                                     TALLOC_CTX *mem_ctx,
408                                     const char *servicename,
409                                     struct smbconf_service **service)
410 {
411         WERROR werr;
412         sbcErr err;
413         uint32_t sidx, count;
414         bool found;
415         TALLOC_CTX *tmp_ctx = NULL;
416         struct smbconf_service *tmp_service = NULL;
417
418         err = smbconf_txt_load_file(ctx);
419         if (!SBC_ERROR_IS_OK(err)) {
420                 return WERR_GENERAL_FAILURE;
421         }
422
423         found = smbconf_find_in_array(servicename,
424                                       pd(ctx)->cache->share_names,
425                                       pd(ctx)->cache->num_shares,
426                                       &sidx);
427         if (!found) {
428                 return WERR_NO_SUCH_SERVICE;
429         }
430
431         tmp_ctx = talloc_stackframe();
432
433         tmp_service = talloc_zero(tmp_ctx, struct smbconf_service);
434         if (tmp_service == NULL) {
435                 werr = WERR_NOMEM;
436                 goto done;
437         }
438
439         if (servicename != NULL) {
440                 tmp_service->name = talloc_strdup(tmp_service, servicename);
441                 if (tmp_service->name == NULL) {
442                         werr = WERR_NOMEM;
443                         goto done;
444                 }
445         }
446
447         for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
448                 werr = smbconf_add_string_to_array(tmp_service,
449                                 &(tmp_service->param_names),
450                                 count,
451                                 pd(ctx)->cache->param_names[sidx][count]);
452                 if (!W_ERROR_IS_OK(werr)) {
453                         goto done;
454                 }
455                 werr = smbconf_add_string_to_array(tmp_service,
456                                 &(tmp_service->param_values),
457                                 count,
458                                 pd(ctx)->cache->param_values[sidx][count]);
459                 if (!W_ERROR_IS_OK(werr)) {
460                         goto done;
461                 }
462         }
463
464         tmp_service->num_params = count;
465         *service = talloc_move(mem_ctx, &tmp_service);
466
467 done:
468         talloc_free(tmp_ctx);
469         return werr;
470 }
471
472 /**
473  * delete a service from configuration
474  */
475 static WERROR smbconf_txt_delete_share(struct smbconf_ctx *ctx,
476                                        const char *servicename)
477 {
478         return WERR_NOT_SUPPORTED;
479 }
480
481 /**
482  * set a configuration parameter to the value provided.
483  */
484 static WERROR smbconf_txt_set_parameter(struct smbconf_ctx *ctx,
485                                         const char *service,
486                                         const char *param,
487                                         const char *valstr)
488 {
489         return WERR_NOT_SUPPORTED;
490 }
491
492 /**
493  * get the value of a configuration parameter as a string
494  */
495 static WERROR smbconf_txt_get_parameter(struct smbconf_ctx *ctx,
496                                         TALLOC_CTX *mem_ctx,
497                                         const char *service,
498                                         const char *param,
499                                         char **valstr)
500 {
501         sbcErr err;
502         bool found;
503         uint32_t share_index, param_index;
504
505         err = smbconf_txt_load_file(ctx);
506         if (!SBC_ERROR_IS_OK(err)) {
507                 return WERR_GENERAL_FAILURE;
508         }
509
510         found = smbconf_find_in_array(service,
511                                       pd(ctx)->cache->share_names,
512                                       pd(ctx)->cache->num_shares,
513                                       &share_index);
514         if (!found) {
515                 return WERR_NO_SUCH_SERVICE;
516         }
517
518         found = smbconf_reverse_find_in_array(param,
519                                 pd(ctx)->cache->param_names[share_index],
520                                 pd(ctx)->cache->num_params[share_index],
521                                 &param_index);
522         if (!found) {
523                 return WERR_INVALID_PARAM;
524         }
525
526         *valstr = talloc_strdup(mem_ctx,
527                         pd(ctx)->cache->param_values[share_index][param_index]);
528
529         if (*valstr == NULL) {
530                 return WERR_NOMEM;
531         }
532
533         return WERR_OK;
534 }
535
536 /**
537  * delete a parameter from configuration
538  */
539 static WERROR smbconf_txt_delete_parameter(struct smbconf_ctx *ctx,
540                                            const char *service,
541                                            const char *param)
542 {
543         return WERR_NOT_SUPPORTED;
544 }
545
546 static WERROR smbconf_txt_get_includes(struct smbconf_ctx *ctx,
547                                        TALLOC_CTX *mem_ctx,
548                                        const char *service,
549                                        uint32_t *num_includes,
550                                        char ***includes)
551 {
552         WERROR werr;
553         sbcErr err;
554         bool found;
555         uint32_t sidx, count;
556         TALLOC_CTX *tmp_ctx = NULL;
557         uint32_t tmp_num_includes = 0;
558         char **tmp_includes = NULL;
559
560         err = smbconf_txt_load_file(ctx);
561         if (!SBC_ERROR_IS_OK(err)) {
562                 return WERR_GENERAL_FAILURE;
563         }
564
565         found = smbconf_find_in_array(service,
566                                       pd(ctx)->cache->share_names,
567                                       pd(ctx)->cache->num_shares,
568                                       &sidx);
569         if (!found) {
570                 return WERR_NO_SUCH_SERVICE;
571         }
572
573         tmp_ctx = talloc_stackframe();
574
575         for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
576                 if (strequal(pd(ctx)->cache->param_names[sidx][count],
577                              "include"))
578                 {
579                         werr = smbconf_add_string_to_array(tmp_ctx,
580                                 &tmp_includes,
581                                 tmp_num_includes,
582                                 pd(ctx)->cache->param_values[sidx][count]);
583                         if (!W_ERROR_IS_OK(werr)) {
584                                 goto done;
585                         }
586                         tmp_num_includes++;
587                 }
588         }
589
590         *num_includes = tmp_num_includes;
591         if (*num_includes > 0) {
592                 *includes = talloc_move(mem_ctx, &tmp_includes);
593                 if (*includes == NULL) {
594                         werr = WERR_NOMEM;
595                         goto done;
596                 }
597         } else {
598                 *includes = NULL;
599         }
600
601         werr = WERR_OK;
602
603 done:
604         talloc_free(tmp_ctx);
605         return werr;
606 }
607
608 static WERROR smbconf_txt_set_includes(struct smbconf_ctx *ctx,
609                                        const char *service,
610                                        uint32_t num_includes,
611                                        const char **includes)
612 {
613         return WERR_NOT_SUPPORTED;
614 }
615
616 static WERROR smbconf_txt_delete_includes(struct smbconf_ctx *ctx,
617                                           const char *service)
618 {
619         return WERR_NOT_SUPPORTED;
620 }
621
622 static WERROR smbconf_txt_transaction_start(struct smbconf_ctx *ctx)
623 {
624         return WERR_OK;
625 }
626
627 static WERROR smbconf_txt_transaction_commit(struct smbconf_ctx *ctx)
628 {
629         return WERR_OK;
630 }
631
632 static WERROR smbconf_txt_transaction_cancel(struct smbconf_ctx *ctx)
633 {
634         return WERR_OK;
635 }
636
637 static struct smbconf_ops smbconf_ops_txt = {
638         .init                   = smbconf_txt_init,
639         .shutdown               = smbconf_txt_shutdown,
640         .requires_messaging     = smbconf_txt_requires_messaging,
641         .is_writeable           = smbconf_txt_is_writeable,
642         .open_conf              = smbconf_txt_open,
643         .close_conf             = smbconf_txt_close,
644         .get_csn                = smbconf_txt_get_csn,
645         .drop                   = smbconf_txt_drop,
646         .get_share_names        = smbconf_txt_get_share_names,
647         .share_exists           = smbconf_txt_share_exists,
648         .create_share           = smbconf_txt_create_share,
649         .get_share              = smbconf_txt_get_share,
650         .delete_share           = smbconf_txt_delete_share,
651         .set_parameter          = smbconf_txt_set_parameter,
652         .get_parameter          = smbconf_txt_get_parameter,
653         .delete_parameter       = smbconf_txt_delete_parameter,
654         .get_includes           = smbconf_txt_get_includes,
655         .set_includes           = smbconf_txt_set_includes,
656         .delete_includes        = smbconf_txt_delete_includes,
657         .transaction_start      = smbconf_txt_transaction_start,
658         .transaction_commit     = smbconf_txt_transaction_commit,
659         .transaction_cancel     = smbconf_txt_transaction_cancel,
660 };
661
662
663 /**
664  * initialize the smbconf text backend
665  * the only function that is exported from this module
666  */
667 sbcErr smbconf_init_txt(TALLOC_CTX *mem_ctx,
668                         struct smbconf_ctx **conf_ctx,
669                         const char *path)
670 {
671         sbcErr err;
672
673         err = smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_txt);
674         if (!SBC_ERROR_IS_OK(err)) {
675                 return err;
676         }
677
678         return smbconf_txt_load_file(*conf_ctx);
679 }