/* * Copyright (c) 2004-2006 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-0.c,v 1.19 2006/12/24 00:20:24 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/sm-conf.h" #include #endif /* SM_LIBCONF_ALONE */ /* ** Just a test program to play around with libconf. ** However, this is used in t-conf-0.sh, so don't break it. */ #define SM_SSPEC_MAGIC SM_MAGIC('S', 'S', 'P', 'E') #define SM_SUB_MAGIC SM_MAGIC('S', 'S', 'U', 'B') #define SM_SS_MAGIC SM_MAGIC('S', 'S', '_', '_') #define SM_S_MAGIC SM_MAGIC('S', '_', '_', '_') typedef struct { sm_magic_T sm_magic; int sspec_type; short sspec_port; ipv4_T sspec_addr; char *sspec_host; } sockspec; typedef struct { sm_magic_T sm_magic; unsigned int sub_int_u32; unsigned short sub_limit; /* between 2 and 12 */ unsigned long sub_duration; sockspec *sub_bind; unsigned int sub_sockets_n; } sub; typedef struct { sm_magic_T sm_magic; unsigned short ss_port; char *ss_name; } ss; typedef struct { sm_magic_T sm_magic; char const *s_socket; ipv4_T s_ipv4; uint32_t s_flags; uint32_t s_int; sub s_sub; ss s_ss; } structure; sm_conf_definition_T const flag_names[] = { { SM_CONF_DEF_MAGIC, "Flag1", sm_conf_type_choice_value, 0x01 }, { SM_CONF_DEF_MAGIC, "Flag2", sm_conf_type_choice_value, 0x02 }, /* 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 }, { SM_CONF_DEF_MAGIC, "m", sm_conf_type_u32_suffix, 60 }, { SM_CONF_DEF_MAGIC, "h", sm_conf_type_u32_suffix, 60 * 60 }, { SM_CONF_DEF_MAGIC, "d", sm_conf_type_u32_suffix, 60 * 60 * 24 }, { SM_CONF_DEF_MAGIC, "w", sm_conf_type_u32_suffix, 60 * 60 * 24 * 7 }, { SM_CONF_DEF_MAGIC, "y", sm_conf_type_u32_suffix, 60 * 60 * 24 * 365 }, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; #define SM_SOCK_INET 1 #define SM_SOCK_UNIX 2 #define SM_SOCK_INET6 4 sm_conf_definition_T const sock_types[] = { { SM_CONF_DEF_MAGIC, "inet", sm_conf_type_choice_value, SM_SOCK_INET}, { SM_CONF_DEF_MAGIC, "unix", sm_conf_type_choice_value, SM_SOCK_UNIX}, { SM_CONF_DEF_MAGIC, "inet6", sm_conf_type_choice_value, SM_SOCK_INET6}, /* Sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T sock_spec_defs[] = { { SM_CONF_DEF_MAGIC, "type", sm_conf_type_choice, offsetof(sockspec, sspec_type), sizeof(int), "inet", SM_CONF_FLAG_KEEP_DEFAULT, sock_types }, { SM_CONF_DEF_MAGIC, "port", sm_conf_type_u32, offsetof(sockspec, sspec_port), sizeof(short), "1234", SM_CONF_FLAG_KEEP_DEFAULT }, { SM_CONF_DEF_MAGIC, "address", sm_conf_type_ipv4, offsetof(sockspec, sspec_addr), sizeof(ipv4_T), "127.0.0.1", SM_CONF_FLAG_KEEP_DEFAULT }, { SM_CONF_DEF_MAGIC, "host", sm_conf_type_string, offsetof(sockspec, sspec_host), 0, NULL, 0 }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T sockets_defs[] = { { SM_CONF_DEF_MAGIC, "listen", sm_conf_type_section, offsetof(sub, sub_bind), sizeof(sockspec), NULL, SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT, sock_spec_defs }, /* counter: unsigned int */ { SM_CONF_DEF_MAGIC, "", sm_conf_type_array_n, offsetof(sub, sub_sockets_n), sizeof(unsigned int) }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T subdefinitions[] = { { SM_CONF_DEF_MAGIC, "value", sm_conf_type_u32, offsetof(sub, sub_int_u32), sizeof(unsigned int), NULL, 0, NULL, NULL, NULL, "value" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_SUB_MAGIC #endif }, { SM_CONF_DEF_MAGIC, "limit", sm_conf_type_u32, offsetof(sub, sub_limit), sizeof(unsigned short), NULL, 0, limit_constraints }, /* A number with suffix multipliers. */ { SM_CONF_DEF_MAGIC, "duration", sm_conf_type_u32, offsetof(sub, sub_duration), sizeof(unsigned long), "0", 0, duration_suffixes }, { SM_CONF_DEF_MAGIC, "listen", sm_conf_type_array, 0, /* offset (n/a; see contents) */ 10, /* size: maximum number of elements */ NULL, SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT, sockets_defs, NULL, NULL, "listen socket(s)" }, #if 0 { SM_CONF_DEF_MAGIC, "listen", sm_conf_type_section, offsetof(sub, sub_bind), sizeof(sockspec), NULL, SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_KEEP_DEFAULT, sock_spec_defs }, #endif /* 0 */ /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static sm_conf_definition_T smtps_defs[] = { { SM_CONF_DEF_MAGIC, "port", sm_conf_type_u32, offsetof(ss, ss_port), sizeof(unsigned short), "25", 0, NULL, NULL, NULL, "port" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_SS_MAGIC #endif }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; sm_conf_definition_T definitions[] = { { SM_CONF_DEF_MAGIC, "socket", sm_conf_type_string, offsetof(structure, s_socket), 0, "path/to/socket", 0, NULL, NULL, NULL, "socket" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_S_MAGIC #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" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_S_MAGIC #endif }, { SM_CONF_DEF_MAGIC, "flags", sm_conf_type_choice, offsetof(structure, s_flags), sizeof(uint32_t), NULL, SM_CONF_FLAG_MULTIPLE, flag_names, NULL, NULL, "flags" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_S_MAGIC #endif }, { SM_CONF_DEF_MAGIC, "int", sm_conf_type_u32, offsetof(structure, s_int), sizeof(unsigned int), NULL, 0, NULL, NULL, NULL, "int" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_S_MAGIC #endif }, { SM_CONF_DEF_MAGIC, "qmgr", sm_conf_type_section, offsetof(structure, s_sub), sizeof(sub), NULL, SM_CONF_FLAG_KEEP_DEFAULT, subdefinitions, NULL, NULL, "qmgr" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_S_MAGIC #endif }, { SM_CONF_DEF_MAGIC, "smtps", sm_conf_type_section, offsetof(structure, s_ss), sizeof(ss), NULL, SM_CONF_FLAG_MULTIPLE|SM_CONF_FLAG_PARSE_ONLY, smtps_defs, NULL, NULL, "smtp server" #if SM_LIBCONF_ISSET , 0 #endif #if SM_LIBCONF_MAGIC , SM_S_MAGIC #endif }, /* sentinel */ { SM_CONF_DEF_MAGIC, NULL } }; static structure st; static void print_ipv4(ipv4_T ipv4, const char *name) { sm_ret_T ret; sm_str_P ipv4s; ipv4s = sm_str_new(NULL, 20, 32); if (ipv4s == NULL) { printf("out of memory\n"); return; } ret = sm_inet_ipv4str(ipv4, ipv4s); if (ret != SM_SUCCESS) { printf("sm_inet_ipv4str=0x%x\n", ret); return; } printf("%s= %s\n", name, sm_str_getdata(ipv4s)); } static void print_sock_spec(sockspec *ss, char *sockspecname, const char *name, int l) { printf("\nsockspec= %s\n", sockspecname); printf("name= %s\n", name == NULL ? "(none)" : name); printf("type= %u\n", ss->sspec_type); if (ss->sspec_type == SM_SOCK_INET) { printf("port= %hu\n", ss->sspec_port); printf("host= \"%s\"\n", (ss->sspec_host == NULL) ? "(NULL)" : ss->sspec_host); print_ipv4(ss->sspec_addr, "address"); } else if (ss->sspec_type == SM_SOCK_UNIX) { printf("path= \"%s\"\n", (ss->sspec_host == NULL) ? "(NULL)" : ss->sspec_host); } else { printf("type=unknown\n"); } printf("\n"); } static void print_structure(structure *strct) { unsigned int u; char *name; printf("value= %u\n", strct->s_sub.sub_int_u32); printf("limit= %hu\n", strct->s_sub.sub_limit); printf("duration= %lu\n", strct->s_sub.sub_duration); printf("socket= \"%s\"\n", strct->s_socket); printf("flags= %X\n", strct->s_flags); print_ipv4(strct->s_ipv4, "nameserver"); for (u = 0; u < strct->s_sub.sub_sockets_n; u++) print_sock_spec(&(strct->s_sub.sub_bind[u]), "struct", NULL, 0); name = strct->s_ss.ss_name; #if 0 printf("smtps= %s\n", name == NULL ? "(NoName)" : name); printf("smtps.port= %d\n", strct->s_ss.ss_port); #endif /* 0 */ } static int process(char const *name, FILE *fp, int show, const char *opt, const char *ssname, int flags) { sm_conf_T *stream; int err; unsigned int v; char const *service_name; size_t service_name_n; sm_conf_iterator_T service_iter; sockspec sock_spec; char buf[SM_CONF_ERROR_BUFFER_SIZE]; char const *e = NULL; if (((stream = sm_conf_new(name ? name : "*stdin*"))) == NULL) { fprintf(stderr, "error -- sm_conf_new() returns NULL!\n"); return 1; } if ((err = sm_conf_read_FILE(stream, name, fp)) != 0) { fprintf(stderr, "%s: %s\n", name ? name : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(stream, e)) != NULL) fprintf(stderr, "%s\n", e); sm_conf_destroy(stream); return 2; } st.sm_magic = SM_S_MAGIC; st.s_sub.sm_magic = SM_SUB_MAGIC; st.s_ss.sm_magic = SM_SS_MAGIC; st.s_flags = flags; if ((err = sm_conf_scan(stream, definitions, 0, &st)) != 0) { fprintf(stderr, "(while scanning) %s: %s\n", name ? name : "*stdin*", sm_conf_strerror(err, buf, sizeof buf)); while ((e = sm_conf_syntax_error(stream, e)) != NULL) fprintf(stderr, "%s\n", e); sm_conf_destroy(stream); return 3; } if (show) print_structure(&st); if (opt != NULL && *opt != '\0') { err = sm_conf_get(stream, opt, sm_conf_type_u32, NULL, 0, (void *) &v, sizeof(v)); fprintf(stdout, "opt=%s, conf_get=%d, text=%s\n", opt != NULL ? opt : "(null)", err, err == 0 ? "OK" : sm_conf_strerror(err, buf, sizeof buf)); } service_iter = NULL; while ((err = sm_conf_scan_next(stream, "qmgr.listen", sock_spec_defs, 0, &service_name, &service_name_n, &sock_spec, &service_iter)) == 0) { print_sock_spec(&sock_spec, "loop" , service_name, service_name_n); } service_iter = NULL; while ((err = sm_conf_scan_next(stream, "smtps", smtps_defs, 0, &service_name, &service_name_n, &(st.s_ss), &service_iter)) == 0) { if (ssname == NULL || ( strlen(ssname) == service_name_n && strncmp(ssname, service_name, service_name_n) == 0)) { const char *n; #if 0 print_structure(&st); #endif /* 0 */ n = service_name; printf("smtps= %s\n", n == NULL ? "(NoName)" : n); printf("smtps.port= %hu\n", st.s_ss.ss_port); } } if (ssname != NULL) { service_iter = NULL; snprintf(buf, sizeof(buf), "smtps{%s}", ssname); while ((err = sm_conf_scan_next(stream, buf, smtps_defs, 0, &service_name, &service_name_n, &(st.s_ss), &service_iter)) == 0) { { const char *n; n = service_name; printf("smtps{%s}= %s\n", ssname, n == NULL ? "(NoName)" : n); printf("smtps.port= %hu\n", st.s_ss.ss_port); } } } #if 0 sm_conf_destroy(stream); #endif /* 0 */ return 0; } int main(int ac, char **av) { int ai, c, ret, done, flags; char *opt, *ssname; done = 0; opt = "qmgr.limit"; ssname = NULL; flags = 0; while ((c = getopt(ac, av, "F:f:l:N:o:v:")) != -1) { switch (c) { case 'F': flags = strtol(optarg, NULL, 0); break; case 'f': ret = process(optarg, NULL, 0, opt, ssname, flags); if (ret != 0) return ret; done = 1; break; case 'l': st.s_sub.sub_limit = atoi(optarg); break; case 'N': ssname = strdup(optarg); if (ssname == NULL) return ENOMEM; break; case 'o': opt = strdup(optarg); if (opt == NULL) return ENOMEM; break; case 'v': st.s_sub.sub_int_u32 = atoi(optarg); break; } } ac -= optind; av += optind; if (done) { print_structure(&st); return 0; } if (ac == 0) return process("*stdin*", stdin, 1, opt, ssname, flags); for (ai = 0; ai < ac; ai++) { int ret = process(av[ai], NULL, 1, opt, ssname, flags); if (ret != 0) return ret; } return 0; }