libsmbconf: parse an empty share as empty share, not as NULL.
[obnox/samba-ctdb.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         *service = talloc_move(mem_ctx, &tmp_service);
456
457 done:
458         talloc_free(tmp_ctx);
459         return werr;
460 }
461
462 /**
463  * delete a service from configuration
464  */
465 static WERROR smbconf_txt_delete_share(struct smbconf_ctx *ctx,
466                                        const char *servicename)
467 {
468         return WERR_NOT_SUPPORTED;
469 }
470
471 /**
472  * set a configuration parameter to the value provided.
473  */
474 static WERROR smbconf_txt_set_parameter(struct smbconf_ctx *ctx,
475                                         const char *service,
476                                         const char *param,
477                                         const char *valstr)
478 {
479         return WERR_NOT_SUPPORTED;
480 }
481
482 /**
483  * get the value of a configuration parameter as a string
484  */
485 static WERROR smbconf_txt_get_parameter(struct smbconf_ctx *ctx,
486                                         TALLOC_CTX *mem_ctx,
487                                         const char *service,
488                                         const char *param,
489                                         char **valstr)
490 {
491         WERROR werr;
492         bool found;
493         uint32_t share_index, param_index;
494
495         werr = smbconf_txt_load_file(ctx);
496         if (!W_ERROR_IS_OK(werr)) {
497                 return werr;
498         }
499
500         found = smbconf_find_in_array(service,
501                                       pd(ctx)->cache->share_names,
502                                       pd(ctx)->cache->num_shares,
503                                       &share_index);
504         if (!found) {
505                 return WERR_NO_SUCH_SERVICE;
506         }
507
508         found = smbconf_reverse_find_in_array(param,
509                                 pd(ctx)->cache->param_names[share_index],
510                                 pd(ctx)->cache->num_params[share_index],
511                                 &param_index);
512         if (!found) {
513                 return WERR_INVALID_PARAM;
514         }
515
516         *valstr = talloc_strdup(mem_ctx,
517                         pd(ctx)->cache->param_values[share_index][param_index]);
518
519         if (*valstr == NULL) {
520                 return WERR_NOMEM;
521         }
522
523         return WERR_OK;
524 }
525
526 /**
527  * delete a parameter from configuration
528  */
529 static WERROR smbconf_txt_delete_parameter(struct smbconf_ctx *ctx,
530                                            const char *service,
531                                            const char *param)
532 {
533         return WERR_NOT_SUPPORTED;
534 }
535
536 static WERROR smbconf_txt_get_includes(struct smbconf_ctx *ctx,
537                                        TALLOC_CTX *mem_ctx,
538                                        const char *service,
539                                        uint32_t *num_includes,
540                                        char ***includes)
541 {
542         WERROR werr;
543         bool found;
544         uint32_t sidx, count;
545         TALLOC_CTX *tmp_ctx = NULL;
546         uint32_t tmp_num_includes = 0;
547         char **tmp_includes = NULL;
548
549         werr = smbconf_txt_load_file(ctx);
550         if (!W_ERROR_IS_OK(werr)) {
551                 return werr;
552         }
553
554         found = smbconf_find_in_array(service,
555                                       pd(ctx)->cache->share_names,
556                                       pd(ctx)->cache->num_shares,
557                                       &sidx);
558         if (!found) {
559                 return WERR_NO_SUCH_SERVICE;
560         }
561
562         tmp_ctx = talloc_stackframe();
563
564         for (count = 0; count < pd(ctx)->cache->num_params[sidx]; count++) {
565                 if (strequal(pd(ctx)->cache->param_names[sidx][count],
566                              "include"))
567                 {
568                         werr = smbconf_add_string_to_array(tmp_ctx,
569                                 &tmp_includes,
570                                 tmp_num_includes,
571                                 pd(ctx)->cache->param_values[sidx][count]);
572                         if (!W_ERROR_IS_OK(werr)) {
573                                 goto done;
574                         }
575                         tmp_num_includes++;
576                 }
577         }
578
579         *num_includes = tmp_num_includes;
580         if (*num_includes > 0) {
581                 *includes = talloc_move(mem_ctx, &tmp_includes);
582                 if (*includes == NULL) {
583                         werr = WERR_NOMEM;
584                         goto done;
585                 }
586         } else {
587                 *includes = NULL;
588         }
589
590         werr = WERR_OK;
591
592 done:
593         talloc_free(tmp_ctx);
594         return werr;
595 }
596
597 static WERROR smbconf_txt_set_includes(struct smbconf_ctx *ctx,
598                                        const char *service,
599                                        uint32_t num_includes,
600                                        const char **includes)
601 {
602         return WERR_NOT_SUPPORTED;
603 }
604
605 static WERROR smbconf_txt_delete_includes(struct smbconf_ctx *ctx,
606                                           const char *service)
607 {
608         return WERR_NOT_SUPPORTED;
609 }
610
611 static WERROR smbconf_txt_transaction_start(struct smbconf_ctx *ctx)
612 {
613         return WERR_OK;
614 }
615
616 static WERROR smbconf_txt_transaction_commit(struct smbconf_ctx *ctx)
617 {
618         return WERR_OK;
619 }
620
621 static WERROR smbconf_txt_transaction_cancel(struct smbconf_ctx *ctx)
622 {
623         return WERR_OK;
624 }
625
626 static struct smbconf_ops smbconf_ops_txt = {
627         .init                   = smbconf_txt_init,
628         .shutdown               = smbconf_txt_shutdown,
629         .requires_messaging     = smbconf_txt_requires_messaging,
630         .is_writeable           = smbconf_txt_is_writeable,
631         .open_conf              = smbconf_txt_open,
632         .close_conf             = smbconf_txt_close,
633         .get_csn                = smbconf_txt_get_csn,
634         .drop                   = smbconf_txt_drop,
635         .get_share_names        = smbconf_txt_get_share_names,
636         .share_exists           = smbconf_txt_share_exists,
637         .create_share           = smbconf_txt_create_share,
638         .get_share              = smbconf_txt_get_share,
639         .delete_share           = smbconf_txt_delete_share,
640         .set_parameter          = smbconf_txt_set_parameter,
641         .get_parameter          = smbconf_txt_get_parameter,
642         .delete_parameter       = smbconf_txt_delete_parameter,
643         .get_includes           = smbconf_txt_get_includes,
644         .set_includes           = smbconf_txt_set_includes,
645         .delete_includes        = smbconf_txt_delete_includes,
646         .transaction_start      = smbconf_txt_transaction_start,
647         .transaction_commit     = smbconf_txt_transaction_commit,
648         .transaction_cancel     = smbconf_txt_transaction_cancel,
649 };
650
651
652 /**
653  * initialize the smbconf text backend
654  * the only function that is exported from this module
655  */
656 WERROR smbconf_init_txt(TALLOC_CTX *mem_ctx,
657                         struct smbconf_ctx **conf_ctx,
658                         const char *path)
659 {
660         WERROR werr;
661
662         werr = smbconf_init_internal(mem_ctx, conf_ctx, path, &smbconf_ops_txt);
663         if (!W_ERROR_IS_OK(werr)) {
664                 return werr;
665         }
666
667         return smbconf_txt_load_file(*conf_ctx);
668 }