/* * Copyright (c) 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: t-conf-1.c,v 1.23 2007/06/10 16:05:07 ca Exp $") #if SM_LIBCONF_ALONE #include #include #include #include "sm-conf.h" #else /* SM_LIBCONF_ALONE */ #include "sm/string.h" #include "sm/net.h" #include "sm/io.h" #include "sm/sm-conf.h" #include "sm/sm-conf-prt.h" #define SM_CONF_LOG_DEF 1 #include "sm/logcnfdef.h" #include #endif /* SM_LIBCONF_ALONE */ /* ** Just a test program to play around with libconf. */ typedef struct { char const *s_socket; uchar s_socket_isset; ipv4_T s_ipv4; uchar s_ipv4_isset; uint32_t s_flags; uchar s_flags_isset; uint32_t s_cflags; uchar s_cflags_isset; unsigned int s_int_u32; uchar s_int_u32_isset; unsigned int s_type; uchar s_type_isset; unsigned short s_limit; /* between 2 and 12 */ uchar s_limit_isset; unsigned long s_duration; uchar s_duration_isset; uchar s_char; uchar s_char_isset; sm_logspec_T s_log; uchar s_log_isset; char s_pi[13]; unsigned int s_pi_n; char s_seq[5]; unsigned int s_seq_n; } structure; sm_conf_definition_T const flag_names[] = { { SM_CONF_DEF_MAGIC, "Flag1", sm_conf_type_choice_value, 0x01, 0, NULL, 0, NULL, NULL, NULL, "first flag" }, { SM_CONF_DEF_MAGIC, "Flag2", sm_conf_type_choice_value, 0x02, 0, NULL, 0, NULL, NULL, NULL, "second flag" }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; sm_conf_definition_T const cflag_names[] = { { SM_CONF_DEF_MAGIC, "cflag1", sm_conf_type_choice_value, 0x01, 0, "cflag2", 0, NULL, NULL, NULL, "first cflag" }, { SM_CONF_DEF_MAGIC, "cflag2", sm_conf_type_choice_value, 0x02, 0, "cflag2", 0, NULL, NULL, NULL, "second cflag" }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; sm_conf_definition_T const alias_options[] = { { SM_CONF_DEF_MAGIC, "none", sm_conf_type_choice_value, 0x00, 0, NULL, 0, NULL, NULL, NULL, "no flag" }, { SM_CONF_DEF_MAGIC, "localpart", sm_conf_type_choice_value, 0x04, 0, NULL, 0, NULL, NULL, NULL, "apply aliases to local part" }, { SM_CONF_DEF_MAGIC, "localdomains", sm_conf_type_choice_value, 0x08, 0, NULL, 0, NULL, NULL, NULL, "apply aliases to local domains" }, { SM_CONF_DEF_MAGIC, "all", sm_conf_type_choice_value, 0x10, 0, NULL, 0, NULL, NULL, NULL, "apply aliases to all domains" }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; sm_conf_definition_T const limit_constraints[] = { { SM_CONF_DEF_MAGIC, "", sm_conf_type_u32_minimum, 2 }, { SM_CONF_DEF_MAGIC, "", sm_conf_type_u32_maximum, 12 }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; sm_conf_definition_T const duration_suffixes[] = { { SM_CONF_DEF_MAGIC, "s", sm_conf_type_u32_suffix, 1, 60 }, { SM_CONF_DEF_MAGIC, "m", sm_conf_type_u32_suffix, 60, 60 }, { SM_CONF_DEF_MAGIC, "h", sm_conf_type_u32_suffix, 60 * 60, 24 }, { SM_CONF_DEF_MAGIC, "d", sm_conf_type_u32_suffix, 60 * 60 * 24, 7 }, { SM_CONF_DEF_MAGIC, "w", sm_conf_type_u32_suffix, 60 * 60 * 24 * 7, 365 }, { SM_CONF_DEF_MAGIC, "y", sm_conf_type_u32_suffix, 60 * 60 * 24 * 365 }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T qmgr_definitions[] = { { SM_CONF_DEF_MAGIC, "type", sm_conf_type_u32, offsetof(structure, s_type), sizeof(unsigned int), NULL, SM_CONF_FLAG_STRICTLY_REQUIRED }, { SM_CONF_DEF_MAGIC, "value", sm_conf_type_u32, offsetof(structure, s_int_u32), sizeof(unsigned int), NULL }, { SM_CONF_DEF_MAGIC, "limit", sm_conf_type_u32, offsetof(structure, s_limit), sizeof(unsigned short), NULL, 0, limit_constraints }, /* A number with suffix multipliers. */ { SM_CONF_DEF_MAGIC, "duration", sm_conf_type_u32, offsetof(structure, s_duration), sizeof(unsigned long), "0", 0, duration_suffixes }, { SM_CONF_DEF_MAGIC, "log", sm_conf_type_section, offsetof(structure, s_log), 0, NULL, SM_CONF_FLAG_KEEP_DEFAULT, sm_log_spec_defs, NULL, NULL, "Specify syslog configuration instead of logging to files" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; #define SS_PR_CNF "protected_recipients" #define SS_PR_A_SENDER "sender" #define SS_PR_A_CLTADDR "client_ip" #define SS_PR_USE_LOOKUP "use_lookup" #define SS_PR_MATCH_DET "implicitly_match_detail" sm_conf_definition_T const ss_protrcpt_allow_names[] = { { SM_CONF_DEF_MAGIC, SS_PR_A_SENDER, sm_conf_type_choice_value, 0x0100, 0, NULL, 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, SS_PR_A_CLTADDR, sm_conf_type_choice_value, 0x0200, 0, NULL, 0, NULL, NULL, NULL, NULL }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL } }; sm_conf_definition_T const ss_protrcpt_match_names[] = { { SM_CONF_DEF_MAGIC, "exact", sm_conf_type_choice_value, 0x0000, 0, NULL, 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, SS_PR_USE_LOOKUP, sm_conf_type_choice_value, 0x0400, 0, NULL, 0, NULL, NULL, NULL, NULL }, { SM_CONF_DEF_MAGIC, SS_PR_MATCH_DET, sm_conf_type_choice_value, 0x0800, 0, NULL, 0, NULL, NULL, NULL, NULL }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL } }; static sm_conf_definition_T ss_protrcpt_defs[] = { { SM_CONF_DEF_MAGIC, "allow_by", sm_conf_type_choice, offsetof(structure, s_flags), sizeof(uint32_t), NULL, SM_CONF_FLAG_STRICTLY_REQUIRED|SM_CONF_FLAG_MULTIPLE, ss_protrcpt_allow_names, NULL, NULL, "allow by" }, { SM_CONF_DEF_MAGIC, "match_type", sm_conf_type_choice, offsetof(structure, s_flags), sizeof(uint32_t), NULL, SM_CONF_FLAG_OR, ss_protrcpt_match_names, NULL, NULL, "match type" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T pi_definitions[] = { /* numbers: char */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_u32, offsetof(structure, s_pi), sizeof(char), NULL, 0, NULL }, /* counter: unsigned int */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(structure, s_pi_n), sizeof(unsigned int), NULL, 0, NULL }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; sm_conf_definition_T const seq_names[] = { { SM_CONF_DEF_MAGIC, "dnsbl", sm_conf_type_choice_value, 0x01 }, { SM_CONF_DEF_MAGIC, "grey", sm_conf_type_choice_value, 0x02 }, { SM_CONF_DEF_MAGIC, "access", sm_conf_type_choice_value, 0x04 }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T seq_defs[] = { /* values: choise */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_choice, offsetof(structure, s_seq), sizeof(char), NULL, 0, seq_names }, /* counter: unsigned int */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(structure, s_seq_n), sizeof(unsigned int), NULL, 0, NULL }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; sm_conf_definition_T definitions[] = { { SM_CONF_DEF_MAGIC, "qmgr", sm_conf_type_section, 0, sizeof(structure), NULL, SM_CONF_FLAG_ALLOW_ANY, qmgr_definitions }, { SM_CONF_DEF_MAGIC, "socket", sm_conf_type_string, offsetof(structure, s_socket), 0, "path/to/socket", 0, NULL, NULL, NULL, "socket path" #if SM_LIBCONF_ISSET , offsetof(structure, s_socket_isset) #endif }, { SM_CONF_DEF_MAGIC, "delim", sm_conf_type_char, offsetof(structure, s_char), 0, "+", 0, NULL, NULL, NULL, "delimiter" #if SM_LIBCONF_ISSET , offsetof(structure, s_char_isset) #endif }, { SM_CONF_DEF_MAGIC, "nameserver", sm_conf_type_ipv4, offsetof(structure, s_ipv4), sizeof(ipv4_T), "127.0.0.1", 0, NULL, NULL, NULL, "nameserver IPv4" #if SM_LIBCONF_ISSET , offsetof(structure, s_ipv4_isset) #endif }, { SM_CONF_DEF_MAGIC, "flags", sm_conf_type_choice, offsetof(structure, s_flags), sizeof(uint32_t), NULL, SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT, flag_names, NULL, NULL, "flags what else" #if SM_LIBCONF_ISSET , offsetof(structure, s_flags_isset) #endif }, { SM_CONF_DEF_MAGIC, "cflags", sm_conf_type_choice, offsetof(structure, s_cflags), sizeof(uint32_t), "cflag2", SM_CONF_FLAG_MULTIPLE, cflag_names }, { SM_CONF_DEF_MAGIC, "sequence", sm_conf_type_array, 0, 4, NULL, SM_CONF_FLAG_FLAT, seq_defs }, { SM_CONF_DEF_MAGIC, "pi", sm_conf_type_array, 0, /* offset (n/a; see contents) */ 12, /* size: maximum number of elements */ NULL, SM_CONF_FLAG_FLAT, pi_definitions, NULL, NULL, "digits of pi" }, { SM_CONF_DEF_MAGIC, "aliases", sm_conf_type_choice, offsetof(structure, s_flags), sizeof(uint32_t), NULL, SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT, alias_options }, { SM_CONF_DEF_MAGIC, SS_PR_CNF, sm_conf_type_section, 0, sizeof(uint32_t), NULL, SM_CONF_FLAG_KEEP_DEFAULT, ss_protrcpt_defs, NULL, NULL, "how to protect recipient addresses" }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static structure s; static void print_structure(structure *st) { sm_ret_T ret; sm_str_P ipv4s; unsigned int i; ipv4s = sm_str_new(NULL, 20, 32); if (ipv4s == NULL) { printf("out of memory\n"); return; } printf("int_u32: %u\n", st->s_int_u32); printf("limit: %hu\n", st->s_limit); printf("duration: %lu\n", st->s_duration); printf("socket: \"%s\"\n", st->s_socket); printf("flags: %X\n", st->s_flags); printf("cflags: %X\n", st->s_cflags); printf("char: %c\n", st->s_char); ret = sm_inet_ipv4str(st->s_ipv4, ipv4s); if (ret != SM_SUCCESS) { printf("sm_inet_ipv4str=0x%x\n", ret); return; } printf("nameserver: %s\n", sm_str_getdata(ipv4s)); printf("pi: [%lu]", (unsigned long)st->s_pi_n); for (i = 0; i < st->s_pi_n; i++) printf(" %d", (int)st->s_pi[i]); putchar('\n'); printf("seq: [%lu]", (unsigned long)st->s_seq_n); for (i = 0; i < st->s_seq_n; i++) printf(" %d", (int)st->s_seq[i]); putchar('\n'); printf("int_u32: %c\n", st->s_int_u32_isset + '0'); printf("limit: %c\n", st->s_limit_isset + '0'); printf("duration: %c\n", st->s_duration_isset + '0'); printf("socket: %c\n", st->s_socket_isset + '0'); printf("flags: %c\n", st->s_flags_isset + '0'); printf("cflags: %c\n", st->s_cflags_isset + '0'); printf("char: %c\n", st->s_char_isset + '0'); printf("ns: %c\n", st->s_ipv4_isset + '0'); } static int process(char const *confname, FILE *fp, bool show, bool prt, const char *option, const char *opt) { sm_conf_T *smc; int err; char const *name, *kw; size_t name_n, kw_n; #if 0 sm_conf_iterator_T service_iter; #endif /* 0 */ sm_conf_node_T *node, *root; char buf[SM_CONF_ERROR_BUFFER_SIZE]; char const *e = NULL; if (((smc = sm_conf_new(confname ? confname : "*stdin*"))) == NULL) { fprintf(stderr, "error -- sm_conf_new() returns NULL!\n"); return 1; } if ((err = sm_conf_read_FILE(smc, confname, fp)) != 0) { fprintf(stderr, "%s: %s\n", confname ? confname : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(smc, e)) != NULL) fprintf(stderr, "%s\n", e); sm_conf_destroy(smc); return 2; } /* s.s_flags = 0x7; */ s.s_cflags = 0x3; err = sm_conf_scan(smc, definitions, SM_CONF_FLAG_ALLOW_ANY|SM_CONF_FLAG_KEEP_DEFAULT, &s); if (err != 0) { #if 0 fprintf(stderr, "%s: %d\n", confname ? confname : "*stdin*", err); #endif /* 0 */ fprintf(stderr, "(while scanning) %s: %s\n", confname ? confname : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(smc, e)) != NULL) fprintf(stderr, "%s\n", e); sm_conf_destroy(smc); return 3; } if (show) print_structure(&s); if (prt) { sm_str_P text; text = sm_str_new(NULL, 256, 8192); sm_io_fprintf(smioout, "prt_conf1:\n"); (void) sm_conf_prt_cnfs(definitions, &s, 0, smioout, 0, NULL, text); sm_io_flush(smioout); } #if 0 service_iter = NULL; while ((err = sm_conf_scan_next(smc, "", definitions, 0, &service_name, &service_name_n, &s, &service_iter)) == 0) { node = (sm_conf_node_T *) service_iter; err = sm_conf_section_keyword(smc, node, &kw, &kw_n); if (kw == NULL) printf("kw=(none)\n"); else printf("kw=%*s\n", (int) kw_n, kw); if (service_name == NULL) printf("name=(none)\n"); else printf("name=%*s\n", (int) service_name_n, service_name); } #endif /* 0 */ root = sm_conf_root(smc); node = NULL; while ((node = sm_conf_section_next_subsection(smc, root, NULL, 0, NULL, 0, node)) != NULL) { err = sm_conf_section_keyword(smc, node, &kw, &kw_n); if (kw == NULL) printf("kw=(none)\n"); else printf("kw=%*s\n", (int) kw_n, kw); err = sm_conf_section_name(smc, node, &name, &name_n); if (name == NULL) printf("name=(none)\n"); else printf("name=%*s\n", (int) name_n, name); printf("type=%d\n", sm_conf_node_type(smc, node)); err = sm_conf_get_relative(smc, node, NULL, sm_conf_type_section, qmgr_definitions, SM_CONF_FLAG_ALLOW_ANY, &s, sizeof(s)); if (err != 0) { fprintf(stderr, "%s: %#x\n", confname ? confname : "*stdin*", err); #if 0 fprintf(stderr, "%s: %s\n", confname ? confname : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(smc, e)) != NULL) fprintf(stderr, "%s\n", e); #endif /* 0 */ } } if (option != NULL && *option != '\0') { uint v; err = sm_conf_get(smc, option, sm_conf_type_u32, NULL, 0, (void *) &v, sizeof(v)); fprintf(stdout, "option=%s, conf_get=%d, text=%s, val=%u\n", option != NULL ? option : "(null)", err, err == 0 ? "OK" : sm_conf_strerror(err, buf, sizeof buf), v); } if (opt != NULL && *opt != '\0') { char *v; err = sm_conf_get(smc, opt, sm_conf_type_string, NULL, 0, (void *) &v, 0); fprintf(stdout, "opt=%s, conf_get=%d, text=%s, val=\"%s\"\n", opt != NULL ? opt : "(null)", err, err == 0 ? "OK" : sm_conf_strerror(err, buf, sizeof buf), err == 0 ? v : "(some error)"); } #if 0 sm_conf_destroy(smc); #endif /* 0 */ return 0; } int main(int ac, char **av) { int ai, c, ret; bool prt, done; char *option, *opt; done = false; prt = false; option = NULL; opt = NULL; while ((c = getopt(ac, av, "df:l:O:o:sv:")) != -1) { switch (c) { case 'd': sm_conf_prt_dflt(definitions, SMC_FLD_FLAGS, smioout); sm_io_flush(smioout); return 0; case 'f': ret = process(optarg, NULL, 0, prt, option, opt); if (ret != 0) return ret; done = true; break; case 'l': s.s_limit = atoi(optarg); break; case 'O': opt = strdup(optarg); break; case 'o': option = strdup(optarg); break; case 's': prt = true; break; case 'v': s.s_int_u32 = atoi(optarg); break; } } ac -= optind; av += optind; if (done) { print_structure(&s); if (prt) { sm_io_fprintf(smioout, "prt_conf:\n"); (void) sm_conf_prt_cnfs(definitions, &s, 0, smioout, 0, NULL, NULL); sm_io_flush(smioout); } return 0; } if (ac == 0) return process("*stdin*", stdin, 1, prt, option, opt); for (ai = 0; ai < ac; ai++) { int ret; ret = process(av[ai], NULL, 1, prt, option, opt); if (ret != 0) return ret; } return 0; }