s3:libsmbconf: add transactions to the libsmbconf api
[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
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(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(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(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         pd(ctx)->cache = NULL;
165 }
166
167 static WERROR smbconf_txt_init_cache(struct smbconf_ctx *ctx)
168 {
169         if (pd(ctx)->cache != NULL) {
170                 smbconf_txt_flush_cache(ctx);
171         }
172
173         pd(ctx)->cache = talloc_zero(pd(ctx), struct txt_cache);
174
175         if (pd(ctx)->cache == NULL) {
176                 return WERR_NOMEM;
177         }
178
179         return WERR_OK;
180 }
181
182 static WERROR smbconf_txt_load_file(struct smbconf_ctx *ctx)
183 {
184         WERROR werr;
185         uint64_t new_csn;
186
187         if (!file_exist(ctx->path)) {
188                 return WERR_BADFILE;
189         }
190
191         new_csn = (uint64_t)file_modtime(ctx->path);
192         if (new_csn == pd(ctx)->csn) {
193                 return WERR_OK;
194         }
195
196         werr = smbconf_txt_init_cache(ctx);
197         if (!W_ERROR_IS_OK(werr)) {
198                 return werr;
199         }
200
201         if (!pm_process(ctx->path, smbconf_txt_do_section,
202                         smbconf_txt_do_parameter, pd(ctx)))
203         {
204                 return WERR_CAN_NOT_COMPLETE;
205         }
206
207         pd(ctx)->csn = new_csn;
208
209         return WERR_OK;
210 }
211
212
213 /**********************************************************************
214  *
215  * smbconf operations: text backend implementations
216  *
217  **********************************************************************/
218
219 /**
220  * initialize the text based smbconf backend
221  */
222 static WERROR smbconf_txt_init(struct smbconf_ctx *ctx, const char *path)
223 {
224         if (path == NULL) {
225                 return WERR_BADFILE;
226         }
227         ctx->path = talloc_strdup(ctx, path);
228         if (ctx->path == NULL) {
229                 return WERR_NOMEM;
230         }
231
232         ctx->data = talloc_zero(ctx, struct txt_private_data);
233         if (ctx->data == NULL) {
234                 return WERR_NOMEM;
235         }
236
237         pd(ctx)->verbatim = true;
238
239         return WERR_OK;
240 }
241
242 static int smbconf_txt_shutdown(struct smbconf_ctx *ctx)
243 {
244         return ctx->ops->close_conf(ctx);
245 }
246
247 static bool smbconf_txt_requires_messaging(struct smbconf_ctx *ctx)
248 {
249         return false;
250 }
251
252 static bool smbconf_txt_is_writeable(struct smbconf_ctx *ctx)
253 {
254         /* no write support in this backend yet... */
255         return false;
256 }
257
258 static WERROR smbconf_txt_open(struct smbconf_ctx *ctx)
259 {
260         return smbconf_txt_load_file(ctx);
261 }
262
263 static int smbconf_txt_close(struct smbconf_ctx *ctx)
264 {
265         smbconf_txt_flush_cache(ctx);
266         return 0;
267 }
268
269 /**
270  * Get the change sequence number of the given service/parameter.
271  * service and parameter strings may be NULL.
272  */
273 static void smbconf_txt_get_csn(struct smbconf_ctx *ctx,
274                                 struct smbconf_csn *csn,
275                                 const char *service, const char *param)
276 {
277         if (csn == NULL) {
278                 return;
279         }
280
281         csn->csn = (uint64_t)file_modtime(ctx->path);
282 }
283
284 /**
285  * Drop the whole configuration (restarting empty)
286  */
287 static WERROR smbconf_txt_drop(struct smbconf_ctx *ctx)
288 {
289         return WERR_NOT_SUPPORTED;
290 }
291
292 /**
293  * get the list of share names defined in the configuration.
294  */
295 static WERROR smbconf_txt_get_share_names(struct smbconf_ctx *ctx,
296                                           TALLOC_CTX *mem_ctx,
297                                           uint32_t *num_shares,
298                                           char ***share_names)
299 {
300         uint32_t count;
301         uint32_t added_count = 0;
302         TALLOC_CTX *tmp_ctx = NULL;
303         WERROR werr = WERR_OK;
304         char **tmp_share_names = NULL;
305
306         if ((num_shares == NULL) || (share_names == NULL)) {
307                 werr = WERR_INVALID_PARAM;
308                 goto done;
309         }
310
311         werr = smbconf_txt_load_file(ctx);
312         if (!W_ERROR_IS_OK(werr)) {
313                 return werr;
314         }
315
316         tmp_ctx = talloc_stackframe();
317
318         /* make sure "global" is always listed first,
319          * possibly after NULL section */
320
321         if (smbconf_share_exists(ctx, NULL)) {
322                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
323                                                    0, NULL);
324                 if (!W_ERROR_IS_OK(werr)) {
325                         goto done;
326                 }
327                 added_count++;
328         }
329
330         if (smbconf_share_exists(ctx, GLOBAL_NAME)) {
331                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
332                                                    added_count, GLOBAL_NAME);
333                 if (!W_ERROR_IS_OK(werr)) {
334                         goto done;
335                 }
336                 added_count++;
337         }
338
339         for (count = 0; count < pd(ctx)->cache->num_shares; count++) {
340                 if (strequal(pd(ctx)->cache->share_names[count], GLOBAL_NAME) ||
341                     (pd(ctx)->cache->share_names[count] == NULL))
342                 {
343                         continue;
344                 }
345
346                 werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
347                                         added_count,
348                                         pd(ctx)->cache->share_names[count]);
349                 if (!W_ERROR_IS_OK(werr)) {
350                         goto done;
351                 }
352                 added_count++;
353         }
354
355         *num_shares = added_count;
356         if (added_count > 0) {
357                 *share_names = talloc_move(mem_ctx, &tmp_share_names);
358         } else {
359                 *share_names = NULL;
360         }
361
362 done:
363         talloc_free(tmp_ctx);
364         return werr;
365 }
366
367 /**
368  * check if a share/service of a given name exists
369  */
370 static bool smbconf_txt_share_exists(struct smbconf_ctx *ctx,
371                                      const char *servicename)
372 {
373         WERROR werr;
374
375         werr = smbconf_txt_load_file(ctx);
376         if (!W_ERROR_IS_OK(werr)) {
377                 return false;
378         }
379
380         return smbconf_find_in_array(servicename,
381                                      pd(ctx)->cache->share_names,
382                                      pd(ctx)->cache->num_shares, NULL);
383 }
384
385 /**
386  * Add a service if it does not already exist
387  */
388 static WERROR smbconf_txt_create_share(struct smbconf_ctx *ctx,
389                                        const char *servicename)
390 {
391         return WERR_NOT_SUPPORTED;
392 }
393
394 /**
395  * get a definition of a share (service) from configuration.
396  */
397 static WERROR smbconf_txt_get_share(struct smbconf_ctx *ctx,
398                                     TALLOC_CTX *mem_ctx,
399                                     const char *servicename,
400                                     struct smbconf_service **service)
401 {
402         WERROR werr;
403         uint32_t sidx, count;
404         bool found;
405         TALLOC_CTX *tmp_ctx = NULL;
406         struct smbconf_service *tmp_service = NULL;
407
408         werr = smbconf_txt_load_file(ctx);
409         if (!W_ERROR_IS_OK(werr)) {
410                 return werr;
411         }
412
413         found = smbconf_find_in_array(servicename,
414                                       pd(ctx)->cache->share_names,
415                                       pd(ctx)->cache->num_shares,
416                                       &sidx);
417         if (!found) {
418                 return WERR_NO_SUCH_SERVICE;
419         }
420
421         tmp_ctx = talloc_stackframe();
422
423         tmp_service = talloc_zero(tmp_ctx, struct smbconf_service);
424         if (tmp_service == NULL) {
425                 werr = WERR_NOMEM;
426                 goto done;
427         }
428
429         if (servicename != NULL) {
430                 tmp_service->name = talloc_strdup(tmp_service, servicename);
431                 if (tmp_service->name == NULL) {
432                         werr = WERR_NOMEM;
433                         goto done;
434                 }
435         }
436
437         for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
438                 werr = smbconf_add_string_to_array(tmp_service,
439                                 &(tmp_service->param_names),
440                                 count,
441                                 pd(ctx)->cache->param_names[sidx][count]);
442                 if (!W_ERROR_IS_OK(werr)) {
443                         goto done;
444                 }
445                 werr = smbconf_add_string_to_array(tmp_service,
446                                 &(tmp_service->param_values),
447                                 count,
448                                 pd(ctx)->cache->param_values[sidx][count]);
449                 if (!W_ERROR_IS_OK(werr)) {
450                         goto done;
451                 }
452         }
453
454         tmp_service->num_params = count;
455         if (count > 0) {
456                 *service = talloc_move(mem_ctx, &tmp_service);
457         } else {
458                 *service = NULL;
459         }
460
461 done:
462         talloc_free(tmp_ctx);
463         return werr;
464 }
465
466 /**
467  * delete a service from configuration
468  */
469 static WERROR smbconf_txt_delete_share(struct smbconf_ctx *ctx,
470                                        const char *servicename)
471 {
472         return WERR_NOT_SUPPORTED;
473 }
474
475 /**
476  * set a configuration parameter to the value provided.
477  */
478 static WERROR smbconf_txt_set_parameter(struct smbconf_ctx *ctx,
479                                         const char *service,
480                                         const char *param,
481                                         const char *valstr)
482 {
483         return WERR_NOT_SUPPORTED;
484 }
485
486 /**
487  * get the value of a configuration parameter as a string
488  */
489 static WERROR smbconf_txt_get_parameter(struct smbconf_ctx *ctx,
490                                         TALLOC_CTX *mem_ctx,
491                                         const char *service,
492                                         const char *param,
493                                         char **valstr)
494 {
495         WERROR werr;
496         bool found;
497         uint32_t share_index, param_index;
498
499         werr = smbconf_txt_load_file(ctx);
500         if (!W_ERROR_IS_OK(werr)) {
501                 return werr;
502         }
503
504         found = smbconf_find_in_array(service,
505                                       pd(ctx)->cache->share_names,
506                                       pd(ctx)->cache->num_shares,
507                                       &share_index);
508         if (!found) {
509                 return WERR_NO_SUCH_SERVICE;
510         }
511
512         found = smbconf_reverse_find_in_array(param,
513                                 pd(ctx)->cache->param_names[share_index],
514                                 pd(ctx)->cache->num_params[share_index],
515                                 &param_index);
516         if (!found) {
517                 return WERR_INVALID_PARAM;
518         }
519
520         *valstr = talloc_strdup(mem_ctx,
521                         pd(ctx)->cache->param_values[share_index][param_index]);
522
523         if (*valstr == NULL) {
524                 return WERR_NOMEM;
525         }
526
527         return WERR_OK;
528 }
529
530 /**
531  * delete a parameter from configuration
532  */
533 static WERROR smbconf_txt_delete_parameter(struct smbconf_ctx *ctx,
534                                            const char *service,
535                                            const char *param)
536 {
537         return WERR_NOT_SUPPORTED;
538 }
539
540 static WERROR smbconf_txt_get_includes(struct smbconf_ctx *ctx,
541                                        TALLOC_CTX *mem_ctx,
542                                        const char *service,
543                                        uint32_t *num_includes,
544                                        char ***includes)
545 {
546         WERROR werr;
547         bool found;
548         uint32_t sidx, count;
549         TALLOC_CTX *tmp_ctx = NULL;
550         uint32_t tmp_num_includes = 0;
551         char **tmp_includes = NULL;
552
553         werr = smbconf_txt_load_file(ctx);
554         if (!W_ERROR_IS_OK(werr)) {
555                 return werr;
556         }
557
558         found = smbconf_find_in_array(service,
559                                       pd(ctx)->cache->share_names,
560                                       pd(ctx)->cache->num_shares,
561                                       &sidx);
562         if (!found) {
563                 return WERR_NO_SUCH_SERVICE;
564         }
565
566         tmp_ctx = talloc_stackframe();
567
568         for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
569                 if (strequal(pd(ctx)->cache->param_names[sidx][count],
570                              "include"))
571                 {
572                         werr = smbconf_add_string_to_array(tmp_ctx,
573                                 &tmp_includes,
574                                 tmp_num_includes,
575                                 pd(ctx)->cache->param_values[sidx][count]);
576                         if (!W_ERROR_IS_OK(werr)) {
577                                 goto done;
578                         }
579                         tmp_num_includes++;
580                 }
581         }
582
583         *num_includes = tmp_num_includes;
584         if (*num_includes > 0) {
585                 *includes = talloc_move(mem_ctx, &tmp_includes);
586                 if (*includes == NULL) {
587                         werr = WERR_NOMEM;
588                         goto done;
589                 }
590         } else {
591                 *includes = NULL;
592         }
593
594         werr = WERR_OK;
595
596 done:
597         talloc_free(tmp_ctx);
598         return werr;
599 }
600
601 static WERROR smbconf_txt_set_includes(struct smbconf_ctx *ctx,
602                                        const char *service,
603                                        uint32_t num_includes,
604                                        const char **includes)
605 {
606         return WERR_NOT_SUPPORTED;
607 }
608
609 static WERROR smbconf_txt_delete_includes(struct smbconf_ctx *ctx,
610                                           const char *service)
611 {
612         return WERR_NOT_SUPPORTED;
613 }
614
615 static WERROR smbconf_txt_transaction_start(struct smbconf_ctx *ctx)
616 {
617         return WERR_OK;
618 }
619
620 static WERROR smbconf_txt_transaction_commit(struct smbconf_ctx *ctx)
621 {
622         return WERR_OK;
623 }
624
625 static WERROR smbconf_txt_transaction_cancel(struct smbconf_ctx *ctx)
626 {
627         return WERR_OK;
628 }
629
630 static struct smbconf_ops smbconf_ops_txt = {
631         .init                   = smbconf_txt_init,
632         .shutdown               = smbconf_txt_shutdown,
633         .requires_messaging     = smbconf_txt_requires_messaging,
634         .is_writeable           = smbconf_txt_is_writeable,
635         .open_conf              = smbconf_txt_open,
636         .close_conf             = smbconf_txt_close,
637         .get_csn                = smbconf_txt_get_csn,
638         .drop                   = smbconf_txt_drop,
639         .get_share_names        = smbconf_txt_get_share_names,
640         .share_exists           = smbconf_txt_share_exists,
641         .create_share           = smbconf_txt_create_share,
642         .get_share              = smbconf_txt_get_share,
643         .delete_share           = smbconf_txt_delete_share,
644         .set_parameter          = smbconf_txt_set_parameter,
645         .get_parameter          = smbconf_txt_get_parameter,
646         .delete_parameter       = smbconf_txt_delete_parameter,
647         .get_includes           = smbconf_txt_get_includes,
648         .set_includes           = smbconf_txt_set_includes,
649         .delete_includes        = smbconf_txt_delete_includes,
650         .transaction_start      = smbconf_txt_transaction_start,
651         .transaction_commit     = smbconf_txt_transaction_commit,
652         .transaction_cancel     = smbconf_txt_transaction_cancel,
653 };
654
655
656 /**
657  * initialize the smbconf text backend
658  * the only function that is exported from this module
659  */
660 WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx,
661                         struct smbconf_ctx **conf_ctx,
662                         const char *path)
663 {
664         WERROR werr;
665
666         werr = smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_txt);
667         if (!W_ERROR_IS_OK(werr)) {
668                 return werr;
669         }
670
671         return smbconf_txt_load_file(*conf_ctx);
672 }