[s3]libsmbconf: add backend_requires_messaging() method to libsmbconf.
[samba.git] / source3 / 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)) {
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 WERROR smbconf_txt_open(struct smbconf_ctx *ctx)
252 {
253         return smbconf_txt_load_file(ctx);
254 }
255
256 static int smbconf_txt_close(struct smbconf_ctx *ctx)
257 {
258         smbconf_txt_flush_cache(ctx);
259         return 0;
260 }
261
262 /**
263  * Get the change sequence number of the given service/parameter.
264  * service and parameter strings may be NULL.
265  */
266 static void smbconf_txt_get_csn(struct smbconf_ctx *ctx,
267                                 struct smbconf_csn *csn,
268                                 const char *service, const char *param)
269 {
270         if (csn == NULL) {
271                 return;
272         }
273
274         csn->csn = (uint64_t)file_modtime(ctx->path);
275 }
276
277 /**
278  * Drop the whole configuration (restarting empty)
279  */
280 static WERROR smbconf_txt_drop(struct smbconf_ctx *ctx)
281 {
282         return WERR_NOT_SUPPORTED;
283 }
284
285 /**
286  * get the list of share names defined in the configuration.
287  */
288 static WERROR smbconf_txt_get_share_names(struct smbconf_ctx *ctx,
289                                           TALLOC_CTX *mem_ctx,
290                                           uint32_t *num_shares,
291                                           char ***share_names)
292 {
293         uint32_t count;
294         uint32_t added_count = 0;
295         TALLOC_CTX *tmp_ctx = NULL;
296         WERROR werr = WERR_OK;
297         char **tmp_share_names = NULL;
298
299         if ((num_shares == NULL) || (share_names == NULL)) {
300                 werr = WERR_INVALID_PARAM;
301                 goto done;
302         }
303
304         werr = smbconf_txt_load_file(ctx);
305         if (!W_ERROR_IS_OK(werr)) {
306                 return werr;
307         }
308
309         tmp_ctx = talloc_stackframe();
310
311         /* make sure "global" is always listed first,
312          * possibly after NULL section */
313
314         if (smbconf_share_exists(ctx, NULL)) {
315                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
316                                                    0, NULL);
317                 if (!W_ERROR_IS_OK(werr)) {
318                         goto done;
319                 }
320                 added_count++;
321         }
322
323         if (smbconf_share_exists(ctx, GLOBAL_NAME)) {
324                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
325                                                    added_count, GLOBAL_NAME);
326                 if (!W_ERROR_IS_OK(werr)) {
327                         goto done;
328                 }
329                 added_count++;
330         }
331
332         for (count = 0; count < pd(ctx)->cache->num_shares; count++) {
333                 if (strequal(pd(ctx)->cache->share_names[count], GLOBAL_NAME) ||
334                     (pd(ctx)->cache->share_names[count] == NULL))
335                 {
336                         continue;
337                 }
338
339                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
340                                         added_count,
341                                         pd(ctx)->cache->share_names[count]);
342                 if (!W_ERROR_IS_OK(werr)) {
343                         goto done;
344                 }
345                 added_count++;
346         }
347
348         *num_shares = added_count;
349         if (added_count > 0) {
350                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
351         } else {
352                 *share_names = NULL;
353         }
354
355 done:
356         TALLOC_FREE(tmp_ctx);
357         return werr;
358 }
359
360 /**
361  * check if a share/service of a given name exists
362  */
363 static bool smbconf_txt_share_exists(struct smbconf_ctx *ctx,
364                                      const char *servicename)
365 {
366         WERROR werr;
367
368         werr = smbconf_txt_load_file(ctx);
369         if (!W_ERROR_IS_OK(werr)) {
370                 return false;
371         }
372
373         return smbconf_find_in_array(servicename,
374                                      pd(ctx)->cache->share_names,
375                                      pd(ctx)->cache->num_shares, NULL);
376 }
377
378 /**
379  * Add a service if it does not already exist
380  */
381 static WERROR smbconf_txt_create_share(struct smbconf_ctx *ctx,
382                                        const char *servicename)
383 {
384         return WERR_NOT_SUPPORTED;
385 }
386
387 /**
388  * get a definition of a share (service) from configuration.
389  */
390 static WERROR smbconf_txt_get_share(struct smbconf_ctx *ctx,
391                                     TALLOC_CTX *mem_ctx,
392                                     const char *servicename,
393                                     struct smbconf_service **service)
394 {
395         WERROR werr;
396         uint32_t sidx, count;
397         bool found;
398         TALLOC_CTX *tmp_ctx = NULL;
399         struct smbconf_service *tmp_service = NULL;
400
401         werr = smbconf_txt_load_file(ctx);
402         if (!W_ERROR_IS_OK(werr)) {
403                 return werr;
404         }
405
406         found = smbconf_find_in_array(servicename,
407                                       pd(ctx)->cache->share_names,
408                                       pd(ctx)->cache->num_shares,
409                                       &sidx);
410         if (!found) {
411                 return WERR_NO_SUCH_SERVICE;
412         }
413
414         tmp_ctx = talloc_stackframe();
415
416         tmp_service = TALLOC_ZERO_P(tmp_ctx, struct smbconf_service);
417         if (tmp_service == NULL) {
418                 werr = WERR_NOMEM;
419                 goto done;
420         }
421
422         if (servicename != NULL) {
423                 tmp_service->name = talloc_strdup(tmp_service, servicename);
424                 if (tmp_service->name == NULL) {
425                         werr = WERR_NOMEM;
426                         goto done;
427                 }
428         }
429
430         for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
431                 werr = smbconf_add_string_to_array(tmp_service,
432                                 &(tmp_service->param_names),
433                                 count,
434                                 pd(ctx)->cache->param_names[sidx][count]);
435                 if (!W_ERROR_IS_OK(werr)) {
436                         goto done;
437                 }
438                 werr = smbconf_add_string_to_array(tmp_service,
439                                 &(tmp_service->param_values),
440                                 count,
441                                 pd(ctx)->cache->param_values[sidx][count]);
442                 if (!W_ERROR_IS_OK(werr)) {
443                         goto done;
444                 }
445         }
446
447         tmp_service->num_params = count;
448         if (count > 0) {
449                 *service = talloc_move(mem_ctx, &tmp_service);
450         } else {
451                 *service = NULL;
452         }
453
454 done:
455         TALLOC_FREE(tmp_ctx);
456         return werr;
457 }
458
459 /**
460  * delete a service from configuration
461  */
462 static WERROR smbconf_txt_delete_share(struct smbconf_ctx *ctx,
463                                        const char *servicename)
464 {
465         return WERR_NOT_SUPPORTED;
466 }
467
468 /**
469  * set a configuration parameter to the value provided.
470  */
471 static WERROR smbconf_txt_set_parameter(struct smbconf_ctx *ctx,
472                                         const char *service,
473                                         const char *param,
474                                         const char *valstr)
475 {
476         return WERR_NOT_SUPPORTED;
477 }
478
479 /**
480  * get the value of a configuration parameter as a string
481  */
482 static WERROR smbconf_txt_get_parameter(struct smbconf_ctx *ctx,
483                                         TALLOC_CTX *mem_ctx,
484                                         const char *service,
485                                         const char *param,
486                                         char **valstr)
487 {
488         WERROR werr;
489         bool found;
490         uint32_t share_index, param_index;
491
492         werr = smbconf_txt_load_file(ctx);
493         if (!W_ERROR_IS_OK(werr)) {
494                 return werr;
495         }
496
497         found = smbconf_find_in_array(service,
498                                       pd(ctx)->cache->share_names,
499                                       pd(ctx)->cache->num_shares,
500                                       &share_index);
501         if (!found) {
502                 return WERR_NO_SUCH_SERVICE;
503         }
504
505         found = smbconf_reverse_find_in_array(param,
506                                 pd(ctx)->cache->param_names[share_index],
507                                 pd(ctx)->cache->num_params[share_index],
508                                 &param_index);
509         if (!found) {
510                 return WERR_INVALID_PARAM;
511         }
512
513         *valstr = talloc_strdup(mem_ctx,
514                         pd(ctx)->cache->param_values[share_index][param_index]);
515
516         if (*valstr == NULL) {
517                 return WERR_NOMEM;
518         }
519
520         return WERR_OK;
521 }
522
523 /**
524  * delete a parameter from configuration
525  */
526 static WERROR smbconf_txt_delete_parameter(struct smbconf_ctx *ctx,
527                                            const char *service,
528                                            const char *param)
529 {
530         return WERR_NOT_SUPPORTED;
531 }
532
533 static WERROR smbconf_txt_get_includes(struct smbconf_ctx *ctx,
534                                        TALLOC_CTX *mem_ctx,
535                                        const char *service,
536                                        uint32_t *num_includes,
537                                        char ***includes)
538 {
539         WERROR werr;
540         bool found;
541         uint32_t sidx, count;
542         TALLOC_CTX *tmp_ctx = NULL;
543         uint32_t tmp_num_includes = 0;
544         char **tmp_includes = NULL;
545
546         werr = smbconf_txt_load_file(ctx);
547         if (!W_ERROR_IS_OK(werr)) {
548                 return werr;
549         }
550
551         found = smbconf_find_in_array(service,
552                                       pd(ctx)->cache->share_names,
553                                       pd(ctx)->cache->num_shares,
554                                       &sidx);
555         if (!found) {
556                 return WERR_NO_SUCH_SERVICE;
557         }
558
559         tmp_ctx = talloc_stackframe();
560
561         for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
562                 if (strequal(pd(ctx)->cache->param_names[sidx][count],
563                              "include"))
564                 {
565                         werr = smbconf_add_string_to_array(tmp_ctx,
566                                 &tmp_includes,
567                                 tmp_num_includes,
568                                 pd(ctx)->cache->param_values[sidx][count]);
569                         if (!W_ERROR_IS_OK(werr)) {
570                                 goto done;
571                         }
572                         tmp_num_includes++;
573                 }
574         }
575
576         *num_includes = tmp_num_includes;
577         if (*num_includes > 0) {
578                 *includes = talloc_move(mem_ctx, &tmp_includes);
579                 if (*includes == NULL) {
580                         werr = WERR_NOMEM;
581                         goto done;
582                 }
583         } else {
584                 *includes = NULL;
585         }
586
587         werr = WERR_OK;
588
589 done:
590         TALLOC_FREE(tmp_ctx);
591         return werr;
592 }
593
594 static WERROR smbconf_txt_set_includes(struct smbconf_ctx *ctx,
595                                        const char *service,
596                                        uint32_t num_includes,
597                                        const char **includes)
598 {
599         return WERR_NOT_SUPPORTED;
600 }
601
602 static WERROR smbconf_txt_delete_includes(struct smbconf_ctx *ctx,
603                                           const char *service)
604 {
605         return WERR_NOT_SUPPORTED;
606 }
607
608
609 static struct smbconf_ops smbconf_ops_txt = {
610         .init                   = smbconf_txt_init,
611         .shutdown               = smbconf_txt_shutdown,
612         .requires_messaging     = smbconf_txt_requires_messaging,
613         .open_conf              = smbconf_txt_open,
614         .close_conf             = smbconf_txt_close,
615         .get_csn                = smbconf_txt_get_csn,
616         .drop                   = smbconf_txt_drop,
617         .get_share_names        = smbconf_txt_get_share_names,
618         .share_exists           = smbconf_txt_share_exists,
619         .create_share           = smbconf_txt_create_share,
620         .get_share              = smbconf_txt_get_share,
621         .delete_share           = smbconf_txt_delete_share,
622         .set_parameter          = smbconf_txt_set_parameter,
623         .get_parameter          = smbconf_txt_get_parameter,
624         .delete_parameter       = smbconf_txt_delete_parameter,
625         .get_includes           = smbconf_txt_get_includes,
626         .set_includes           = smbconf_txt_set_includes,
627         .delete_includes        = smbconf_txt_delete_includes,
628 };
629
630
631 /**
632  * initialize the smbconf text backend
633  * the only function that is exported from this module
634  */
635 WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx,
636                         struct smbconf_ctx **conf_ctx,
637                         const char *path)
638 {
639         WERROR werr;
640
641         werr = smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_txt);
642         if (!W_ERROR_IS_OK(werr)) {
643                 return werr;
644         }
645
646         return smbconf_txt_load_file(*conf_ctx);
647 }