1 /*
2 Copyright (C) 2012-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5
6 /*
7 WARNING: This file was generated by the dkct program (see
8 http://dktools.sourceforge.net/ for details).
9 Changes you make here will be lost if dkct is run again!
10 You should modify the original source and run dkct on it.
11 Original source: itaconf.ctr
12 */
13
14 /** @file itaconf.c The itaconf module.
15 */
16
17
18 #include <libdk3c/dk3all.h>
19 #include <itadmin/itadmin.h>
20
21
22
23
24
25
26
27 /** Key names in configuration file.
28 */
29 static dkChar const * const itadmin_config_keys[] = {
30 /* 0 */
31 dkT("database-host"),
32
33 /* 1 */
34 dkT("database-name"),
35
36 /* 2 */
37 dkT("database-credentials-file"),
38
39 /* 3 */
40 dkT("dhcpd.conf-vlan"),
41
42 /* 4 */
43 dkT("organization"),
44
45 /* 5 */
46 dkT("organizational-unit"),
47
48 /* 6 */
49 dkT("administrator-name"),
50
51 /* 7 */
52 dkT("create-dhcpd.conf"),
53
54 /* 8 */
55 dkT("database-type"),
56
57 /* 9 */
58 dkT("ldap-base"),
59
60 /* 10 */
61 dkT("use-koma-script"),
62
63 /* 11 */
64 dkT("msft-release-lease-on-shutdown"),
65
66 /* 12 */
67 dkT("marker-point"),
68
69 /* 13 */
70 dkT("marker-vlan"),
71
72 /* 14 */
73 dkT("marker-subnet"),
74
75 /* 15 */
76 dkT("marker-group"),
77
78 /* 16 */
79 dkT("marker-pool"),
80
81 /* 17 */
82 dkT("marker-host"),
83
84 NULL
85
86 };
87
88
89
90 /** Items for "msft release lease on shutdown".
91 */
92 static const char * const msft_release_keys[] = {
93 "none", "pool", "all", NULL
94 };
95
96
97 /** Names of SQL database types.
98 */
99 static dkChar const * const itadmin_config_database_types[] = {
100 /* 0 */
101 dkT("MySQL"),
102
103 NULL
104
105 };
106
107
108
109 /** Keywords to watch out for when processing a credential file.
110 Typically this is a .my.cnf file.
111 */
112 static dkChar const * const itadmin_config_credential_keys[] = {
113 /* 0 */
114 dkT("client"),
115
116 /* 1 */
117 dkT("user"),
118
119 /* 2 */
120 dkT("password"),
121
122 NULL
123
124 };
125
126
127
128 /** Set one string entry in job structure.
129 @param job Job structure to modify.
130 @param resptr Pointer to result pointer.
131 @param srcptr Source string.
132 @return 1 on success, 0 on error.
133 */
134 static
135 int
itadmin_config_set_string(itadmin_job * job,dkChar const ** resptr,dkChar const * srcptr)136 itadmin_config_set_string(
137 itadmin_job *job,
138 dkChar const **resptr,
139 dkChar const *srcptr
140 )
141 {
142 dkChar const *np; /* New string duplicate. */
143 int back = 0;
144
145 np = dk3str_dup_app(srcptr,job->app);
146 if(np) {
147 dk3_release(*resptr);
148 *resptr = np;
149 back = 1;
150 } else {
151 /* ERROR: Memory allocation failed! */
152 }
153 return back;
154 }
155
156
157
158 /** Configure a boolean value setting.
159 @param job Job structure.
160 @param bp Pointer to result variable.
161 @param defv Default value, used for empty or non-boolean strings.
162 @param txt Configuration text.
163 @return 1 on success, 0 on error.
164 */
165 static
166 int
itadmin_config_set_bool(itadmin_job * job,int * bp,int defv,dkChar const * txt)167 itadmin_config_set_bool(itadmin_job *job, int *bp, int defv, dkChar const *txt)
168 {
169 dkChar lb[ITADMIN_CONFIG_LINE_SIZE]; /* Copy of value. */
170 dkChar *p1; /* Start of text in copy. */
171 int back = 1;
172
173 if(txt) {
174 p1 = dk3str_start(txt, NULL);
175 if(p1) {
176 if(dk3str_len(p1) < DK3_SIZEOF(lb,dkChar)) {
177 dk3str_cpy_not_overlapped(lb, p1);
178 dk3str_normalize(lb,NULL,dkT(' '));
179 if(dk3str_is_bool(lb)) {
180 *bp = ((dk3str_is_on(lb)) ? 1 : 0);
181 } else {
182 back = 0;
183 *bp = defv;
184 /* ERROR: Not a boolean! */
185 dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 106, 107, lb);
186 }
187 } else {
188 back = 0;
189 *bp = defv;
190 /* ERROR: Text too long! */
191 dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 108, 109, p1);
192 }
193 } else {
194 *bp = defv;
195 }
196 } else {
197 *bp = defv;
198 }
199 return back;
200 }
201
202
203
204 /** Set database type.
205 @param job Job structure.
206 @param txt Text for database type (at this time only "MySQL"
207 can be used).
208 @return 1 on success, 0 on error.
209 */
210 static
211 int
itadmin_config_set_dbtype(itadmin_job * job,dkChar const * txt)212 itadmin_config_set_dbtype(itadmin_job *job, dkChar const *txt)
213 {
214 int back = 0;
215 int i; /* Index of type in array of known types. */
216 if(txt) {
217 i = dk3str_array_index(itadmin_config_database_types, txt, 0);
218 if(i >= 0) {
219 job->dbt = i;
220 back = 1;
221 } else {
222 /* ERROR: No such database type! */
223 dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 110, 111, txt);
224 }
225 } else {
226 /* ERROR: Empty text. */
227 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 112);
228 }
229 return back;
230 }
231
232
233
234
235 /** Handler function for one configuration file line.
236 @param obj Reader object.
237 @param il Input line to process (constant text).
238 @return 1 for OK, 0 for recoverable error, -1 for abort.
239 */
240 static
241 int
itadmin_config_const_line_handler(void * obj,dkChar const * il)242 itadmin_config_const_line_handler(void *obj, dkChar const *il)
243 {
244 dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Private copy of line.*/
245 itadmin_job *job;
246 dkChar *p1; /* Start of line. */
247 dkChar *p2; /* Start of value in line. */
248 int back = 0;
249
250 if((obj) && (il)) {
251 job = (itadmin_job *)obj;
252 if(dk3str_len(il) < DK3_SIZEOF(line,dkChar)) {
253 dk3str_cpy_not_overlapped(line, il);
254 dk3str_delnl(line);
255 p1 = dk3str_start(line, NULL);
256 if(p1) {
257 if(*p1 == dkT('#')) {
258 back = 1; /* Comment line. */
259 } else {
260 p2 = dk3str_chr(p1, dkT('='));
261 if(p2) {
262 *(p2++) = dkT('\0');
263 p2 = dk3str_start(p2, NULL);
264 if(p2) {
265 dk3str_normalize(p1, NULL, dkT('-'));
266 switch(dk3str_array_index(itadmin_config_keys, p1, 0)) {
267 case 0: { /* database host */
268 back = itadmin_config_set_string(job, &(job->dbhn), p2);
269 } break;
270 case 1: { /* database name */
271 back = itadmin_config_set_string(job, &(job->dbn), p2);
272 } break;
273 case 2: { /* credentials file */
274 back = itadmin_config_set_string(job, &(job->dbcf), p2);
275 } break;
276 case 3: { /* VLAN name */
277 back = itadmin_config_set_string(job, &(job->vlan), p2);
278 if(back) {
279 job->f_dh = 1;
280 }
281 } break;
282 case 4: { /* organization */
283 back = itadmin_config_set_string(job, &(job->org), p2);
284 } break;
285 case 5: { /* organizational unit */
286 back = itadmin_config_set_string(job, &(job->ou), p2);
287 } break;
288 case 6: { /* administrator name */
289 back = itadmin_config_set_string(job, &(job->admn), p2);
290 } break;
291 case 7: {
292 back = itadmin_config_set_bool(job, &(job->f_dh), 1, p2);
293 } break;
294 case 8: {
295 back = itadmin_config_set_dbtype(job, p2);
296 } break;
297 case 9: {
298 dk3str_normalize(p2, NULL, ' ');
299 back = itadmin_config_set_string(job, &(job->ldapb), p2);
300 } break;
301 case 10: {
302 back = itadmin_config_set_bool(job, &(job->ukoma), 0, p2);
303 } break;
304 case 11: {
305 switch(dk3str_array_index(msft_release_keys, p2, 0)) {
306 case 0: {
307 job->rel = 0; back = 1;
308 } break;
309 case 1: {
310 job->rel = 1; back = 1;
311 } break;
312 case 2: {
313 job->rel = 2; back = 1;
314 } break;
315 default: {
316 /* ##### ERROR: Illegal keyword */
317 } break;
318 }
319 } break;
320 case 12: {
321 back = itadmin_config_set_bool(job, &(job->m_p), 1, p2);
322 } break;
323 case 13: {
324 back = itadmin_config_set_bool(job, &(job->m_vl), 1, p2);
325 } break;
326 case 14: {
327 back = itadmin_config_set_bool(job, &(job->m_sn), 1, p2);
328 } break;
329 case 15: {
330 back = itadmin_config_set_bool(job, &(job->m_gr), 1, p2);
331 } break;
332 case 16: {
333 back = itadmin_config_set_bool(job, &(job->m_po), 1, p2);
334 } break;
335 case 17: {
336 back = itadmin_config_set_bool(job, &(job->m_ho), 0, p2);
337 } break;
338 default: {
339 /* ERROR: Unknown option ... */
340 dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 113, 114, p1);
341 } break;
342 }
343 } else {
344 /* ERROR: No value! */
345 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 115);
346 }
347 } else {
348 /* ERROR: Missing '=' */
349 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 115);
350 }
351 }
352 } else {
353 back = 1; /* Empty line. */
354 }
355 } else {
356 /* ERROR: Input line too long! */
357 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 116);
358 }
359 }
360 return back;
361 }
362
363
364
365 /** Handler function for one configuration file line.
366 @param obj Reader object.
367 @param il Input line to process.
368 @return 1 for OK, 0 for recoverable error, -1 for abort.
369 */
370 static
371 int
itadmin_cred_file_const_line_handler(void * obj,dkChar const * il)372 itadmin_cred_file_const_line_handler(void *obj, dkChar const *il)
373 {
374 dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Copy of line. */
375 dkChar *p1; /* Start of key. */
376 dkChar *p2; /* Start of value. */
377 itadmin_cred_reader *reader; /* Help structure to read creds. */
378 int back = 0;
379
380 if((obj) && (il)) {
381 reader = (itadmin_cred_reader *)obj;
382 if(dk3str_len(il) < DK3_SIZEOF(line,dkChar)) {
383 dk3str_cpy_not_overlapped(line, il);
384 dk3str_delnl(line);
385 p1 = dk3str_start(line, NULL);
386 if(p1) {
387 if(*p1 == dkT('#')) {
388 back = 1; /* Ignore comment. */
389 } else {
390 if(*p1 == dkT('[')) {
391 reader->f_clnt = 0;
392 p1++;
393 p2 = dk3str_chr(p1, dkT(']'));
394 if(p2) {
395 back = 1;
396 *p2 = dkT('\0');
397 if(dk3str_cmp(p1, itadmin_config_credential_keys[0]) == 0) {
398 reader->f_clnt = 1;
399 }
400 } else {
401 /* ERROR: Syntax! */
402 dk3app_log_1(
403 (reader->job)->app, DK3_LL_ERROR, (reader->job)->msg, 117
404 );
405 }
406 } else {
407 back = 1;
408 p2 = dk3str_chr(p1, dkT('='));
409 if(p2) {
410 *(p2++) = dkT('\0');
411 p2 = dk3str_start(p2, NULL);
412 if(p2) {
413 dk3str_normalize(p1,NULL,dkT(' '));
414 switch(dk3str_array_index(itadmin_config_credential_keys,p1,0))
415 {
416 case 1: { /* user */
417 back = itadmin_config_set_string(
418 reader->job, &((reader->job)->dbus), p2
419 );
420 } break;
421 case 2: { /* password */
422 back = itadmin_config_set_string(
423 reader->job, &((reader->job)->dbpw), p2
424 );
425 } break;
426 }
427 } else {
428 /* Empty key. */
429 }
430 } else {
431 /* Not a key=value line. */
432 }
433 }
434 }
435 } else {
436 back = 1; /* Ignore empty line. */
437 }
438 } else {
439 /* ERROR: Line too long! */
440 dk3app_log_1(
441 (reader->job)->app, DK3_LL_ERROR, (reader->job)->msg, 116
442 );
443 }
444 } else {
445 }
446 return back;
447 }
448
449
450
451 /** Handler function for one configuration file line.
452 @param obj Reader object.
453 @param il Input line to process.
454 @return 1 for OK, 0 for recoverable error, -1 for abort.
455 */
456 static
457 int
itadmin_cred_file_line_handler(void * obj,dkChar * il)458 itadmin_cred_file_line_handler(void *obj, dkChar *il)
459 {
460 int back;
461 back = itadmin_cred_file_const_line_handler(obj, il);
462 return back;
463 }
464
465
466
467 /** Handler function for one configuration file line.
468 @param obj Reader object.
469 @param il Input line to process.
470 @return 1 for OK, 0 for recoverable error, -1 for abort.
471 */
472 static
473 int
itadmin_config_line_handler(void * obj,dkChar * il)474 itadmin_config_line_handler(void *obj, dkChar *il)
475 {
476 int back;
477 back = itadmin_config_const_line_handler(obj, il);
478 return back;
479 }
480
481
482
483 /** Process one configuration file.
484 @param job Job structure.
485 @param fn File name to process.
486 @return 1 on success, 0 on error.
487 */
488 static
489 int
itadmin_config_process_one_file(itadmin_job * job,dkChar const * fn)490 itadmin_config_process_one_file(itadmin_job *job, dkChar const *fn)
491 {
492 dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Copy of line. */
493 int back = 0;
494
495 back = dk3stream_process_filename_lines_app(
496 (void *)job,
497 itadmin_config_line_handler,
498 fn,
499 line,
500 DK3_SIZEOF(line,dkChar),
501 dk3app_get_encoding(job->app),
502 dk3app_get_input_file_encoding(job->app),
503 job->app
504 );
505 if(back < 1) {
506 back = 0;
507 }
508 return back;
509 }
510
511
512
513 /** Read credentials file to obtain database user name and password.
514 @param job Job structure.
515 @return 1 on success, 0 on error.
516 */
517 static
518 int
itadmin_config_read_credentials(itadmin_job * job)519 itadmin_config_read_credentials(itadmin_job *job)
520 {
521 dkChar fnb[DK3_MAX_PATH]; /* File name buffer. */
522 dkChar line[ITADMIN_CONFIG_LINE_SIZE]; /* Input line buffer. */
523 itadmin_cred_reader reader; /* Helper structure to read creds. */
524 int back = 0;
525
526 if(dk3str_len(job->dbcf) < DK3_SIZEOF(fnb,dkChar)) {
527 dk3str_cpy_not_overlapped(fnb, job->dbcf);
528 dk3str_correct_filename(fnb);
529 if(dk3sf_must_expand(fnb)) {
530 /* ERROR: File name must not contain wildcards! */
531 dk3app_log_3(job->app, DK3_LL_ERROR, job->msg, 118, 119, fnb);
532 } else {
533 if(!dk3str_is_abs_path(fnb)) {
534 /* WARNING: File name should be specified as absolute path! */
535 dk3app_log_3(job->app, DK3_LL_WARNING, job->msg, 120, 121, fnb);
536 }
537 reader.job = job;
538 reader.f_clnt = 1;
539 back = dk3stream_process_filename_sanitized_lines_app(
540 (void *)(&reader),
541 itadmin_cred_file_line_handler,
542 fnb,
543 line,
544 DK3_SIZEOF(line,dkChar),
545 dk3app_get_encoding(job->app),
546 dk3app_get_input_file_encoding(job->app),
547 job->app
548 );
549 }
550 } else {
551 /* ERROR: File name too long! */
552 dk3app_log_i3(job->app, DK3_LL_ERROR, 65, 66, job->dbcf);
553 }
554 if(job->ec) {
555 back = 0;
556 }
557 return back;
558 }
559
560
561
562 int
itadmin_config_read(itadmin_job * job)563 itadmin_config_read(itadmin_job *job)
564 {
565 dkChar fnb[DK3_MAX_PATH]; /* Copy of file name. */
566 dk3_search_t *res; /* Search result, config. */
567 dk3_dir_t *fne; /* File name expander. */
568 dk3_stat_t const *es; /* Expandend file status. */
569 dkChar const *fn; /* File name. */
570 dkChar const *en; /* Expanded file name. */
571 dkChar const *fnorig; /* Original file name. */
572 int back = 0;
573 int have_file = 0; /* Flag: File found. */
574 int have_error = 0; /* Flag: Error occured. */
575 int argc; /* Number of file names. */
576 int i; /* Current file name index. */
577
578 /*
579 Process default configuration files.
580 */
581 res = dk3app_find_config_file(job->app, (job->noloc)[4], 0);
582 if(res) {
583 dk3search_reset(res);
584 while((fn = dk3search_next(res)) != NULL) {
585 have_file = 1;
586 if(!itadmin_config_process_one_file(job, fn)) {
587 have_error = 1;
588 }
589 }
590 dk3search_close(res);
591 }
592 /*
593 Process configuration file(s) specified on command line.
594 */
595 argc = dk3opt_get_num_args(job->opt);
596 for(i = 0; i < argc; i++) {
597 fnorig = dk3opt_get_arg(job->opt, i);
598 if(fnorig) {
599 if(dk3str_len(fnorig) < DK3_SIZEOF(fnb,dkChar)) {
600 dk3str_cpy_not_overlapped(fnb, fnorig);
601 dk3str_correct_filename(fnb);
602 if(dk3sf_must_expand(fnb)) {
603 fne = dk3dir_fne_open_app(fnb, job->app);
604 if(fne) {
605 while(dk3dir_get_next_file(fne)) {
606 en = dk3dir_get_fullname(fne);
607 es = dk3dir_get_stat(fne);
608 if((en) && (es)) {
609 switch((es->ft) & (~(DK3_FT_SYMLINK))) {
610 case DK3_FT_REGULAR: {
611 have_file = 1;
612 if(!itadmin_config_process_one_file(job, fnb)) {
613 have_error = 1;
614 }
615 } break;
616 default: {
617 have_error = 1;
618 /* ERROR: Wrong file type! */
619 dk3app_log_i3(job->app, DK3_LL_ERROR, 255, 256, en);
620 } break;
621 }
622 } else {
623 /* BUG: No complete information available! */
624 }
625 }
626 dk3dir_close(fne);
627 } else {
628 /* ERROR: Failed to expand file name! */
629 }
630 } else {
631 have_file = 1;
632 if(!itadmin_config_process_one_file(job, fnb)) {
633 have_error = 1;
634 }
635 }
636 } else {
637 /* ERROR: File name fnorig too long! */
638 dk3app_log_i3(job->app, DK3_LL_ERROR, 65, 66, fnorig);
639 }
640 } else {
641 /* BUG: No pointer returned! */
642 }
643 }
644 /*
645 Final tests and error messages.
646 */
647 if(have_file) {
648 if(!(have_error)) {
649 back = 1;
650 if(!(job->dbhn)) {
651 /* ERROR: Missing database host name! */
652 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 122);
653 back = 0;
654 }
655 if(!(job->dbn)) {
656 /* ERROR: Missing database name! */
657 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 123);
658 back = 0;
659 }
660 if(!(job->vlan)) {
661 /* Warning: Missing VLAN name! */
662 dk3app_log_1(job->app, DK3_LL_WARNING, job->msg, 124);
663 }
664 if(!(job->org)) {
665 /* ERROR: Missing organization name! */
666 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 125);
667 back = 0;
668 }
669 if(!(job->ou)) {
670 /* ERROR: Missing organizational unit name! */
671 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 126);
672 back = 0;
673 }
674 if(!(job->admn)) {
675 /* ERROR: Missing administrator name! */
676 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 127);
677 back = 0;
678 }
679 if(!(job->dbcf)) {
680 /* ERROR: Missing database credentials file name! */
681 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 128);
682 back = 0;
683 } else {
684 if(back) {
685 back = itadmin_config_read_credentials(job);
686 if(back) {
687 if(!(job->dbus)) {
688 /* ERROR: Missing database user name! */
689 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 129);
690 back = 0;
691 }
692 if(!(job->dbpw)) {
693 /* ERROR: Missing database user password! */
694 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 130);
695 back = 0;
696 }
697 }
698 }
699 }
700 if(back) {
701 if(!(job->ukoma)) {
702 if(dk3str_casecmp(dkT("de"), dk3app_get_language(job->app)) == 0) {
703 dk3app_log_1(job->app, DK3_LL_INFO, job->msg, 302);
704 }
705 }
706 }
707 if(!(back)) {
708 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 132);
709 }
710 } else {
711 }
712 } else {
713 /* ERROR: No configuration file found for processing! */
714 dk3app_log_1(job->app, DK3_LL_ERROR, job->msg, 131);
715 }
716 return back;
717 }
718
719