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