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