Line data Source code
1 : /*
2 : SSSD
3 :
4 : sss_ini.c
5 :
6 : Authors:
7 : Ondrej Kos <okos@redhat.com>
8 :
9 : Copyright (C) 2013 Red Hat
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include <stdio.h>
26 : #include <errno.h>
27 : #include <talloc.h>
28 :
29 : #include "config.h"
30 : #include "util/util.h"
31 : #include "util/sss_ini.h"
32 : #include "confdb/confdb_setup.h"
33 : #include "confdb/confdb_private.h"
34 :
35 : #ifdef HAVE_LIBINI_CONFIG_V1
36 : #include "ini_configobj.h"
37 : #else
38 : #include "collection.h"
39 : #include "collection_tools.h"
40 : #endif
41 :
42 : #include "ini_config.h"
43 :
44 :
45 : #ifdef HAVE_LIBINI_CONFIG_V1
46 :
47 : struct sss_ini_initdata {
48 : char **error_list;
49 : struct ref_array *ra_success_list;
50 : struct ref_array *ra_error_list;
51 : struct ini_cfgobj *sssd_config;
52 : struct value_obj *obj;
53 : const struct stat *cstat;
54 : struct ini_cfgfile *file;
55 : };
56 :
57 : #define sss_ini_get_sec_list ini_get_section_list
58 : #define sss_ini_get_attr_list ini_get_attribute_list
59 : #define sss_ini_get_const_string_config_value ini_get_const_string_config_value
60 : #define sss_ini_get_config_obj ini_get_config_valueobj
61 :
62 : #else
63 :
64 : struct sss_ini_initdata {
65 : struct collection_item *error_list;
66 : struct collection_item *sssd_config;
67 : struct collection_item *obj;
68 : struct stat cstat;
69 : int file;
70 : };
71 :
72 : #define sss_ini_get_sec_list get_section_list
73 : #define sss_ini_get_attr_list get_attribute_list
74 : #define sss_ini_get_const_string_config_value get_const_string_config_value
75 : #define sss_ini_get_config_obj(secs,attrs,cfg,flag,attr) \
76 : get_config_item(secs,attrs,cfg,attr)
77 :
78 : #endif
79 :
80 :
81 : /* Initialize data structure */
82 :
83 0 : struct sss_ini_initdata* sss_ini_initdata_init(TALLOC_CTX *mem_ctx)
84 : {
85 0 : return talloc_zero(mem_ctx, struct sss_ini_initdata);
86 : }
87 :
88 :
89 :
90 : /* Close file descriptor */
91 :
92 0 : void sss_ini_close_file(struct sss_ini_initdata *init_data)
93 : {
94 0 : if (init_data == NULL) return;
95 : #ifdef HAVE_LIBINI_CONFIG_V1
96 0 : if (init_data->file != NULL) {
97 0 : ini_config_file_destroy(init_data->file);
98 0 : init_data->file = NULL;
99 : }
100 : #else
101 : if (init_data->file != -1) {
102 : close(init_data->file);
103 : init_data->file = -1;
104 : }
105 : #endif
106 : }
107 :
108 :
109 :
110 : /* Open configuration file */
111 :
112 0 : int sss_ini_config_file_open(struct sss_ini_initdata *init_data,
113 : const char *config_file)
114 : {
115 : #ifdef HAVE_LIBINI_CONFIG_V1
116 0 : return ini_config_file_open(config_file,
117 : INI_META_STATS,
118 : &init_data->file);
119 : #else
120 : return check_and_open_readonly(config_file, &init_data->file, 0, 0,
121 : S_IFREG|S_IRUSR, /* f r**------ */
122 : S_IFMT|(ALLPERMS & ~(S_IWUSR|S_IXUSR)));
123 : #endif
124 : }
125 :
126 :
127 :
128 : /* Check configuration file permissions */
129 :
130 0 : int sss_ini_config_access_check(struct sss_ini_initdata *init_data)
131 : {
132 : #ifdef HAVE_LIBINI_CONFIG_V1
133 0 : return ini_config_access_check(init_data->file,
134 : INI_ACCESS_CHECK_MODE |
135 : INI_ACCESS_CHECK_UID |
136 : INI_ACCESS_CHECK_GID,
137 : 0, /* owned by root */
138 : 0, /* owned by root */
139 : S_IRUSR, /* r**------ */
140 : ALLPERMS & ~(S_IWUSR|S_IXUSR));
141 : #else
142 : return EOK;
143 : #endif
144 : }
145 :
146 :
147 :
148 : /* Get cstat */
149 :
150 0 : int sss_ini_get_stat(struct sss_ini_initdata *init_data)
151 : {
152 : #ifdef HAVE_LIBINI_CONFIG_V1
153 0 : init_data->cstat = ini_config_get_stat(init_data->file);
154 :
155 0 : if (!init_data->cstat) return EIO;
156 :
157 0 : return EOK;
158 : #else
159 :
160 : return fstat(init_data->file, &init_data->cstat);
161 : #endif
162 : }
163 :
164 :
165 :
166 : /* Get mtime */
167 :
168 0 : int sss_ini_get_mtime(struct sss_ini_initdata *init_data,
169 : size_t timestr_len,
170 : char *timestr)
171 : {
172 : #ifdef HAVE_LIBINI_CONFIG_V1
173 0 : return snprintf(timestr, timestr_len, "%llu",
174 0 : (long long unsigned)init_data->cstat->st_mtime);
175 : #else
176 : return snprintf(timestr, timestr_len, "%llu",
177 : (long long unsigned)init_data->cstat.st_mtime);
178 : #endif
179 : }
180 :
181 :
182 :
183 : /* Print ini_config errors */
184 :
185 0 : void sss_ini_config_print_errors(char **error_list)
186 : {
187 : #ifdef HAVE_LIBINI_CONFIG_V1
188 0 : unsigned count = 0;
189 :
190 0 : if (!error_list) {
191 0 : return;
192 : }
193 :
194 0 : while (error_list[count]) {
195 0 : DEBUG(SSSDBG_CRIT_FAILURE, "%s\n", error_list[count]);
196 0 : count++;
197 : }
198 : #endif
199 :
200 0 : return;
201 : }
202 :
203 :
204 :
205 : /* Load configuration */
206 :
207 0 : int sss_ini_get_config(struct sss_ini_initdata *init_data,
208 : const char *config_file,
209 : const char *config_dir)
210 : {
211 : int ret;
212 : #ifdef HAVE_LIBINI_CONFIG_V1
213 : #ifdef HAVE_LIBINI_CONFIG_V1_3
214 : const char *patterns[] = { "^[^\\.].*\\.conf", NULL };
215 : const char *sections[] = { ".*", NULL };
216 : uint32_t i = 0;
217 : char *msg = NULL;
218 : struct access_check snip_check;
219 : struct ini_cfgobj *modified_sssd_config = NULL;
220 : #endif /* HAVE_LIBINI_CONFIG_V1_3 */
221 :
222 : /* Create config object */
223 0 : ret = ini_config_create(&(init_data->sssd_config));
224 0 : if (ret != EOK) {
225 0 : DEBUG(SSSDBG_FATAL_FAILURE,
226 : "Failed to create config object. Error %d.\n", ret);
227 0 : return ret;
228 : }
229 :
230 : /* Parse file */
231 0 : ret = ini_config_parse(init_data->file,
232 : INI_STOP_ON_ANY,
233 : INI_MV1S_OVERWRITE,
234 : INI_PARSE_NOWRAP,
235 : init_data->sssd_config);
236 :
237 0 : if (ret != EOK) {
238 0 : DEBUG(SSSDBG_FATAL_FAILURE,
239 : "Failed to parse configuration. Error %d.\n", ret);
240 :
241 0 : if (ini_config_error_count(init_data->sssd_config)) {
242 0 : DEBUG(SSSDBG_FATAL_FAILURE,
243 : "Errors detected while parsing: %s\n",
244 : ini_config_get_filename(init_data->file));
245 :
246 0 : ini_config_get_errors(init_data->sssd_config,
247 : &init_data->error_list);
248 0 : sss_ini_config_print_errors(init_data->error_list);
249 0 : ini_config_free_errors(init_data->error_list);
250 : }
251 0 : ini_config_destroy(init_data->sssd_config);
252 0 : init_data->sssd_config = NULL;
253 0 : return ret;
254 : }
255 :
256 : #ifdef HAVE_LIBINI_CONFIG_V1_3
257 : snip_check.flags = INI_ACCESS_CHECK_MODE | INI_ACCESS_CHECK_UID
258 : | INI_ACCESS_CHECK_GID;
259 : snip_check.uid = 0; /* owned by root */
260 : snip_check.gid = 0; /* owned by root */
261 : snip_check.mode = S_IRUSR; /* r**------ */
262 : snip_check.mask = ALLPERMS & ~(S_IWUSR | S_IXUSR);
263 :
264 : ret = ini_config_augment(init_data->sssd_config,
265 : config_dir,
266 : patterns,
267 : sections,
268 : &snip_check,
269 : INI_STOP_ON_ANY,
270 : INI_MV1S_OVERWRITE,
271 : INI_PARSE_NOWRAP,
272 : INI_MV2S_OVERWRITE,
273 : &modified_sssd_config,
274 : &init_data->ra_error_list,
275 : &init_data->ra_success_list);
276 : if (ret != EOK) {
277 : DEBUG(SSSDBG_CRIT_FAILURE,
278 : "Failed to augment configuration [%d]: %s",
279 : ret, sss_strerror(ret));
280 : }
281 :
282 : while (ref_array_get(init_data->ra_success_list, i, &msg) != NULL) {
283 : DEBUG(SSSDBG_TRACE_FUNC,
284 : "Config merge success: %s\n", msg);
285 : i++;
286 : }
287 :
288 : i = 0;
289 : while (ref_array_get(init_data->ra_error_list, i, &msg) != NULL) {
290 : DEBUG(SSSDBG_CRIT_FAILURE,
291 : "Config merge error: %s\n", msg);
292 : i++;
293 : }
294 :
295 : /* switch config objects if there are no errors */
296 : if (modified_sssd_config != NULL) {
297 : ini_config_destroy(init_data->sssd_config);
298 : init_data->sssd_config = modified_sssd_config;
299 : } else {
300 : DEBUG(SSSDBG_TRACE_FUNC,
301 : "Using only main configuration file due to errors in merging\n");
302 : }
303 : #endif
304 :
305 0 : return ret;
306 :
307 : #else
308 :
309 : /* Read the configuration into a collection */
310 : ret = config_from_fd("sssd",
311 : init_data->file,
312 : config_file,
313 : &init_data->sssd_config,
314 : INI_STOP_ON_ANY,
315 : &init_data->error_list);
316 :
317 : if (ret != EOK) {
318 : DEBUG(SSSDBG_FATAL_FAILURE,
319 : "Parse error reading configuration file [%s]\n",
320 : config_file);
321 :
322 : print_file_parsing_errors(stderr, init_data->error_list);
323 :
324 : free_ini_config_errors(init_data->error_list);
325 : free_ini_config(init_data->sssd_config);
326 :
327 : return ret;
328 : }
329 :
330 : return EOK;
331 :
332 : #endif
333 : }
334 :
335 :
336 :
337 : /* Get configuration object */
338 :
339 0 : int sss_ini_get_cfgobj(struct sss_ini_initdata *init_data,
340 : const char *section, const char *name)
341 : {
342 0 : return sss_ini_get_config_obj(section,name, init_data->sssd_config,
343 : INI_GET_FIRST_VALUE, &init_data->obj);
344 : }
345 :
346 :
347 :
348 : /* Check configuration object */
349 :
350 0 : int sss_ini_check_config_obj(struct sss_ini_initdata *init_data)
351 : {
352 0 : if (init_data->obj == NULL) {
353 0 : return ENOENT;
354 : }
355 :
356 0 : return EOK;
357 : }
358 :
359 :
360 :
361 : /* Get integer value */
362 :
363 0 : int sss_ini_get_int_config_value(struct sss_ini_initdata *init_data,
364 : int strict, int def, int *error)
365 : {
366 : #ifdef HAVE_LIBINI_CONFIG_V1
367 0 : return ini_get_int_config_value(init_data->obj, strict, def, error);
368 : #else
369 : return get_int_config_value(init_data->obj, strict, def, error);
370 : #endif
371 : }
372 :
373 :
374 :
375 : /* Destroy ini config (v1) */
376 :
377 0 : void sss_ini_config_destroy(struct sss_ini_initdata *init_data)
378 : {
379 0 : if (init_data == NULL) return;
380 : #ifdef HAVE_LIBINI_CONFIG_V1
381 0 : if (init_data->sssd_config != NULL) {
382 0 : ini_config_destroy(init_data->sssd_config);
383 0 : init_data->sssd_config = NULL;
384 : }
385 : #else
386 : free_ini_config(init_data->sssd_config);
387 : #endif
388 : }
389 :
390 :
391 :
392 : /* Create LDIF */
393 :
394 0 : int sss_confdb_create_ldif(TALLOC_CTX *mem_ctx,
395 : struct sss_ini_initdata *init_data,
396 : const char **config_ldif)
397 : {
398 : int ret, i, j;
399 : char *ldif;
400 : char *tmp_ldif;
401 : char **sections;
402 : int section_count;
403 : char *dn;
404 : char *tmp_dn;
405 : char *sec_dn;
406 : char **attrs;
407 : int attr_count;
408 : char *ldif_attr;
409 : TALLOC_CTX *tmp_ctx;
410 : size_t dn_size;
411 : size_t ldif_len;
412 : size_t attr_len;
413 : #ifdef HAVE_LIBINI_CONFIG_V1
414 0 : struct value_obj *obj = NULL;
415 : #else
416 : struct collection_item *obj = NULL;
417 : #endif
418 :
419 0 : ldif_len = strlen(CONFDB_INTERNAL_LDIF);
420 0 : ldif = talloc_array(mem_ctx, char, ldif_len+1);
421 0 : if (!ldif) return ENOMEM;
422 :
423 0 : tmp_ctx = talloc_new(ldif);
424 0 : if (!tmp_ctx) {
425 0 : ret = ENOMEM;
426 0 : goto error;
427 : }
428 :
429 0 : memcpy(ldif, CONFDB_INTERNAL_LDIF, ldif_len);
430 :
431 : /* Read in the collection and convert it to an LDIF */
432 : /* Get the list of sections */
433 0 : sections = sss_ini_get_sec_list(init_data->sssd_config,
434 : §ion_count, &ret);
435 0 : if (ret != EOK) {
436 0 : goto error;
437 : }
438 :
439 0 : for (i = 0; i < section_count; i++) {
440 0 : const char *rdn = NULL;
441 0 : DEBUG(SSSDBG_TRACE_FUNC,
442 : "Processing config section [%s]\n", sections[i]);
443 0 : ret = parse_section(tmp_ctx, sections[i], &sec_dn, &rdn);
444 0 : if (ret != EOK) {
445 0 : goto error;
446 : }
447 :
448 0 : dn = talloc_asprintf(tmp_ctx,
449 : "dn: %s,cn=config\n"
450 : "cn: %s\n",
451 : sec_dn, rdn);
452 0 : if (!dn) {
453 0 : ret = ENOMEM;
454 0 : free_section_list(sections);
455 0 : goto error;
456 : }
457 0 : dn_size = strlen(dn);
458 :
459 : /* Get all of the attributes and their values as LDIF */
460 0 : attrs = sss_ini_get_attr_list(init_data->sssd_config, sections[i],
461 : &attr_count, &ret);
462 0 : if (ret != EOK) {
463 0 : free_section_list(sections);
464 0 : goto error;
465 : }
466 :
467 0 : for (j = 0; j < attr_count; j++) {
468 0 : DEBUG(SSSDBG_TRACE_FUNC,
469 : "Processing attribute [%s]\n", attrs[j]);
470 0 : ret = sss_ini_get_config_obj(sections[i], attrs[j],
471 : init_data->sssd_config,
472 : INI_GET_FIRST_VALUE, &obj);
473 0 : if (ret != EOK) goto error;
474 :
475 0 : const char *value = sss_ini_get_const_string_config_value(obj, &ret);
476 0 : if (ret != EOK) goto error;
477 0 : if (value && value[0] == '\0') {
478 0 : DEBUG(SSSDBG_CRIT_FAILURE,
479 : "Attribute '%s' has empty value, ignoring\n",
480 : attrs[j]);
481 0 : continue;
482 : }
483 :
484 0 : ldif_attr = talloc_asprintf(tmp_ctx,
485 0 : "%s: %s\n", attrs[j], value);
486 0 : DEBUG(SSSDBG_TRACE_ALL, "%s\n", ldif_attr);
487 :
488 0 : attr_len = strlen(ldif_attr);
489 :
490 0 : tmp_dn = talloc_realloc(tmp_ctx, dn, char,
491 : dn_size+attr_len+1);
492 0 : if (!tmp_dn) {
493 0 : ret = ENOMEM;
494 0 : free_attribute_list(attrs);
495 0 : free_section_list(sections);
496 0 : goto error;
497 : }
498 0 : dn = tmp_dn;
499 0 : memcpy(dn+dn_size, ldif_attr, attr_len+1);
500 0 : dn_size += attr_len;
501 : }
502 :
503 0 : dn_size ++;
504 0 : tmp_dn = talloc_realloc(tmp_ctx, dn, char,
505 : dn_size+1);
506 0 : if (!tmp_dn) {
507 0 : ret = ENOMEM;
508 0 : free_attribute_list(attrs);
509 0 : free_section_list(sections);
510 0 : goto error;
511 : }
512 0 : dn = tmp_dn;
513 0 : dn[dn_size-1] = '\n';
514 0 : dn[dn_size] = '\0';
515 :
516 0 : DEBUG(SSSDBG_TRACE_ALL, "Section dn\n%s\n", dn);
517 :
518 0 : tmp_ldif = talloc_realloc(mem_ctx, ldif, char,
519 : ldif_len+dn_size+1);
520 0 : if (!tmp_ldif) {
521 0 : ret = ENOMEM;
522 0 : free_attribute_list(attrs);
523 0 : free_section_list(sections);
524 0 : goto error;
525 : }
526 0 : ldif = tmp_ldif;
527 0 : memcpy(ldif+ldif_len, dn, dn_size);
528 0 : ldif_len += dn_size;
529 :
530 0 : free_attribute_list(attrs);
531 0 : talloc_free(dn);
532 : }
533 :
534 0 : ldif[ldif_len] = '\0';
535 :
536 0 : free_section_list(sections);
537 :
538 0 : *config_ldif = (const char *)ldif;
539 0 : talloc_free(tmp_ctx);
540 0 : return EOK;
541 :
542 : error:
543 0 : talloc_free(ldif);
544 0 : return ret;
545 : }
546 :
547 0 : int sss_ini_call_validators(struct sss_ini_initdata *data,
548 : const char *rules_path)
549 : {
550 : #ifdef HAVE_LIBINI_CONFIG_V1_3
551 : int ret;
552 : struct ini_cfgobj *rules_cfgobj = NULL;
553 : struct ini_errobj *errobj = NULL;
554 :
555 : ret = ini_errobj_create(&errobj);
556 : if (ret != EOK) {
557 : DEBUG(SSSDBG_FATAL_FAILURE, "Failed to create error list\n");
558 : goto done;
559 : }
560 :
561 : ret = ini_rules_read_from_file(rules_path, &rules_cfgobj);
562 : if (ret != EOK) {
563 : DEBUG(SSSDBG_FATAL_FAILURE,
564 : "Failed to read sssd.conf schema %d [%s]\n", ret, strerror(ret));
565 : goto done;
566 : }
567 :
568 : ret = ini_rules_check(rules_cfgobj, data->sssd_config, NULL, errobj);
569 : if (ret != EOK) {
570 : DEBUG(SSSDBG_FATAL_FAILURE,
571 : "ini_rules_check failed %d [%s]\n", ret, strerror(ret));
572 : goto done;
573 : }
574 :
575 : /* Do not error out when validators find some issue */
576 : while (!ini_errobj_no_more_msgs(errobj)) {
577 : DEBUG(SSSDBG_CRIT_FAILURE,
578 : "%s\n", ini_errobj_get_msg(errobj));
579 : ini_errobj_next(errobj);
580 : }
581 :
582 : done:
583 : if (rules_cfgobj) ini_config_destroy(rules_cfgobj);
584 : ini_errobj_destroy(&errobj);
585 :
586 : return ret;
587 : #else
588 0 : DEBUG(SSSDBG_TRACE_FUNC,
589 : "libini_config does not support configuration file validataion\n");
590 0 : return EOK;
591 : #endif /* HAVE_LIBINI_CONFIG_V1_3 */
592 : }
|