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