#ifndef OPT_SERV_H #define OPT_SERV_H #include "opt.h" #include "conf.h" #include "evnt.h" #define OPT_SERV_CONF_BUF_SZ (128 - sizeof(Vstr_node_buf)) #define OPT_SERV_CONF_VSTR_PREALLOC_MAX 8 /* ~4 connections */ #define OPT_SERV_CONF_MEM_PREALLOC_MAX (128 * 1024) #define OPT_SERV_CONF_USE_DAEMON FALSE #define OPT_SERV_CONF_USE_DROP_PRIVS FALSE #define OPT_SERV_CONF_USE_PDEATHSIG FALSE #define OPT_SERV_CONF_DEF_RLIM_AS_CALL FALSE #define OPT_SERV_CONF_DEF_RLIM_CORE_CALL FALSE #define OPT_SERV_CONF_DEF_RLIM_FILE_CALL FALSE #define OPT_SERV_CONF_DEF_TCP_DEFER_ACCEPT 8 /* HC usage txt */ #define OPT_SERV_CONF_DEF_PRIV_UID 60001 #define OPT_SERV_CONF_DEF_PRIV_GID 60001 #define OPT_SERV_CONF_DEF_NUM_PROCS 1 #define OPT_SERV_CONF_DEF_IDLE_TIMEOUT (2 * 60) #define OPT_SERV_CONF_DEF_MAX_TIMEOUT 0 /* never */ #define OPT_SERV_CONF_USE_INSTA_CLOSE FALSE #define OPT_SERV_CONF_DEF_Q_LISTEN_LEN 128 #define OPT_SERV_CONF_DEF_MAX_CONNECTIONS 0 #define OPT_SERV_CONF_DEF_RLIM_AS_NUM 0 #define OPT_SERV_CONF_DEF_RLIM_CORE_NUM 0 #define OPT_SERV_CONF_DEF_RLIM_FILE_NUM 0 #define OPT_SERV_CONF_USE_CAP_FOWNER FALSE #define OPT_SERV_CONF_USE_DUMPABLE FALSE #define OPT_SERV_CONF_VLG_DATE_FMT_TYPE VLG_DATE_FMT_SYSLOG_TRAD #define OPT_SERV_CONF_VLG_SYSLOG_NATIVE FALSE #define OPT_SERV_CONF_VLG_TWEAKED_SIZE FALSE #define OPT_SERV_CONF_VLG_SIZE_DEF 0 /* syslog has 1024 limit as of FC5 */ #define OPT_SERV_CONF_VLG_SIZE_UNTWEAKED_CONSOLE 0 #define OPT_SERV_CONF_VLG_SIZE_UNTWEAKED_DAEMON 1024 typedef struct Opt_serv_policy_opts { Vstr_ref *ref; struct Opt_serv_policy_opts *next; struct Opt_serv_opts *beg; Vstr_base *policy_name; struct Evnt_limit io_limit; Vstr_ref *ref_io_limit; struct Evnt_limit io_nslimit; unsigned int idle_timeout; unsigned int max_timeout; unsigned int max_connections; unsigned int use_insta_close : 1; } Opt_serv_policy_opts; /* NOTE: remember to copy changes to * opt_policy.c:opt_policy_init * opt_policy.h:opt_policy_copy */ typedef struct Opt_serv_addr_opts { struct Opt_serv_addr_opts *next; Vstr_base *acpt_filter_file; Vstr_base *acpt_address; Vstr_base *acpt_cong; Vstr_base *def_policy; unsigned short tcp_port; unsigned int defer_accept; unsigned int q_listen_len; unsigned int max_connections; } Opt_serv_addr_opts; typedef struct Opt_serv_opts { Opt_serv_policy_opts *def_policy; Opt_serv_policy_opts *(*make_policy)(struct Opt_serv_opts *); int (*copy_policy)(struct Opt_serv_policy_opts *, const struct Opt_serv_policy_opts *); const char *vers_cstr; const size_t vers_len; const char *name_cstr; size_t name_len; unsigned int become_daemon : 1; unsigned int drop_privs : 1; unsigned int use_pdeathsig : 1; unsigned int no_conf_listen : 1; unsigned int rlim_as_call : 1; unsigned int rlim_core_call : 1; unsigned int rlim_file_call : 1; unsigned int keep_cap_fowner : 1; /* 8 */ unsigned int make_dumpable : 1; unsigned int vlg_date_fmt_type : 2; unsigned int vlg_syslog_native : 1; unsigned int vlg_tweaked_size : 1; /* not user settable */ size_t vlg_size; Vstr_base *pid_file; Vstr_base *cntl_file; Vstr_base *chroot_dir; Vstr_base *vpriv_uid; uid_t priv_uid; Vstr_base *vpriv_gid; gid_t priv_gid; unsigned int num_procs; unsigned int syslog_facility; unsigned int rlim_as_num; unsigned int rlim_core_num; unsigned int rlim_file_num; struct Evnt_limit io_limit; Vstr_ref *ref_io_limit; struct Evnt_limit io_nslimit; unsigned int max_spare_bases; unsigned int max_spare_buf_nodes; unsigned int max_spare_ptr_nodes; unsigned int max_spare_ref_nodes; Opt_serv_addr_opts *addr_beg; } Opt_serv_opts; /* uid/gid default to NFS nobody */ #define OPT_SERV_CONF_INIT_OPTS(x, y) \ NULL, \ opt_policy_make, \ opt_policy_copy, \ x, \ sizeof(x) - 1, \ y, \ sizeof(y) - 1, \ OPT_SERV_CONF_USE_DAEMON, \ OPT_SERV_CONF_USE_DROP_PRIVS, \ OPT_SERV_CONF_USE_PDEATHSIG, \ FALSE, \ OPT_SERV_CONF_DEF_RLIM_AS_CALL, \ OPT_SERV_CONF_DEF_RLIM_CORE_CALL, \ OPT_SERV_CONF_DEF_RLIM_FILE_CALL, \ OPT_SERV_CONF_USE_CAP_FOWNER, \ OPT_SERV_CONF_USE_DUMPABLE, \ OPT_SERV_CONF_VLG_DATE_FMT_TYPE, \ OPT_SERV_CONF_VLG_SYSLOG_NATIVE, \ OPT_SERV_CONF_VLG_TWEAKED_SIZE, \ OPT_SERV_CONF_VLG_SIZE_DEF, \ NULL, NULL, NULL, \ NULL, OPT_SERV_CONF_DEF_PRIV_UID, \ NULL, OPT_SERV_CONF_DEF_PRIV_GID, \ OPT_SERV_CONF_DEF_NUM_PROCS, \ LOG_DAEMON, \ OPT_SERV_CONF_DEF_RLIM_AS_NUM, \ OPT_SERV_CONF_DEF_RLIM_CORE_NUM, \ OPT_SERV_CONF_DEF_RLIM_FILE_NUM, \ {0, 0, {0,0}, 0, 0, {0,0}}, NULL, \ {0, 0, {0,0}, 0, 0, {0,0}}, \ OPT_SERV_CONF_VSTR_PREALLOC_MAX, \ (OPT_SERV_CONF_MEM_PREALLOC_MAX / OPT_SERV_CONF_BUF_SZ), \ (OPT_SERV_CONF_MEM_PREALLOC_MAX / OPT_SERV_CONF_BUF_SZ), \ (OPT_SERV_CONF_MEM_PREALLOC_MAX / OPT_SERV_CONF_BUF_SZ), \ NULL #define OPT_SERV_CONF_DECL_OPTS(N, x, y) \ Opt_serv_opts N[1] = {{OPT_SERV_CONF_INIT_OPTS(x, y)}} extern void opt_serv_conf_free_beg(Opt_serv_opts *); extern void opt_serv_conf_free_end(Opt_serv_opts *); extern int opt_serv_conf_init(Opt_serv_opts *); extern int opt_serv_conf(Opt_serv_opts *, Conf_parse *, Conf_token *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_conf_parse_cstr(Vstr_base *, Opt_serv_opts *, const char *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_conf_parse_file(Vstr_base *, Opt_serv_opts *, const char *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern void opt_serv_logger(Vlg *) COMPILE_ATTR_NONNULL_A(); extern int opt_serv_sc_tst(Conf_parse *, Conf_token *, int *, int, int (*tst_func)(Conf_parse *, Conf_token *, int *, int, void *), void *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_match_init(struct Opt_serv_opts *, Conf_parse *, Conf_token *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern void opt_serv_sc_drop_privs(Opt_serv_opts *) COMPILE_ATTR_NONNULL_A(); extern void opt_serv_sc_rlim_as_num(unsigned int); extern void opt_serv_sc_rlim_core_num(unsigned int); extern void opt_serv_sc_rlim_file_num(unsigned int); extern int opt_serv_sc_acpt_end(const Opt_serv_policy_opts *, struct Evnt *, struct Evnt *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern void opt_serv_sc_free_beg(struct Evnt *, const char *) COMPILE_ATTR_NONNULL_A(); extern void opt_serv_sc_signals(void); extern void opt_serv_sc_check_children(void); extern void opt_serv_sc_cntl_resources(const Opt_serv_opts *) COMPILE_ATTR_NONNULL_A(); extern int opt_serv_sc_append_hostname(Vstr_base *, size_t) COMPILE_ATTR_NONNULL_A(); extern int opt_serv_sc_append_cwd(Vstr_base *, size_t) COMPILE_ATTR_NONNULL_A(); extern int opt_serv_build_single_str(struct Opt_serv_opts *, const Conf_parse *, Conf_token *, int, int) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_sc_make_str(struct Opt_serv_opts *, Conf_parse *, Conf_token *, Vstr_base *, size_t, size_t) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_sc_make_static_path(struct Opt_serv_opts *, Conf_parse *, Conf_token *, Vstr_base *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_sc_make_uint(Conf_parse *, Conf_token *, unsigned int *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_sc_make_ulong(Conf_parse *, Conf_token *, unsigned long *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); extern int opt_serv_sc_make_uintmax(Conf_parse *, Conf_token *, uintmax_t *) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); #ifndef CONF_FULL_STATIC extern void opt_serv_sc_resolve_uid(struct Opt_serv_opts *, const char *, void (*)(const char *, int, const char *)) COMPILE_ATTR_NONNULL_A(); extern void opt_serv_sc_resolve_gid(struct Opt_serv_opts *, const char *, void (*)(const char *, int, const char *)) COMPILE_ATTR_NONNULL_A(); #endif extern int opt_serv_sc_config_dir(Vstr_base *, void *, const char *, int (*)(Vstr_base *, void *, const char *)) COMPILE_ATTR_NONNULL_A() COMPILE_ATTR_WARN_UNUSED_RET(); #define OPT_SERV_DECL_GETOPTS() \ {"help", no_argument, NULL, 'h'}, \ {"daemon", optional_argument, NULL, 1}, \ {"chroot", required_argument, NULL, 2}, \ {"drop-privs", optional_argument, NULL, 3}, \ {"priv-uid", required_argument, NULL, 4}, \ {"priv-gid", required_argument, NULL, 5}, \ {"pid-file", required_argument, NULL, 6}, \ {"cntl-file", required_argument, NULL, 7}, \ {"acpt-filter-file", required_argument, NULL, 8}, \ {"accept-filter-file", required_argument, NULL, 8}, \ {"processes", required_argument, NULL, 9}, \ {"procs", required_argument, NULL, 9}, \ {"debug", no_argument, NULL, 'd'}, \ {"host", required_argument, NULL, 'H'}, \ {"port", required_argument, NULL, 'P'}, \ {"nagle", optional_argument, NULL, 'n'}, \ {"max-connections", required_argument, NULL, 'M'}, \ {"idle-timeout", required_argument, NULL, 't'}, \ {"defer-accept", required_argument, NULL, 10}, \ {"io-r-limit-process", required_argument, NULL, 11}, \ {"io-w-limit-process", required_argument, NULL, 12}, \ {"io-r-limit-connection", required_argument, NULL, 13}, \ {"io-w-limit-connection", required_argument, NULL, 14}, \ {"version", no_argument, NULL, 'V'} #define OPT_SERV_GETOPTS(opts) \ case 't': opts->def_policy->idle_timeout = atoi(optarg); break; \ case 'H': OPT_VSTR_ARG(opts->addr_beg->acpt_address); break; \ case 'M': OPT_NUM_NR_ARG(opts->addr_beg->max_connections, \ "max connections"); \ opts->def_policy->max_connections = opts->addr_beg->max_connections; \ break; \ case 'P': OPT_NUM_ARG(opts->addr_beg->tcp_port, "tcp port", \ 0, 65535, ""); \ opts->no_conf_listen = FALSE; break; \ case 'd': vlg_debug(vlg); break; \ \ case 'n': OPT_TOGGLE_ARG(evnt_opt_nagle); break; \ \ case 1: OPT_TOGGLE_ARG(opts->become_daemon); break; \ case 2: OPT_VSTR_ARG(opts->chroot_dir); break; \ case 3: OPT_TOGGLE_ARG(opts->drop_privs); break; \ case 4: OPT_VSTR_ARG(opts->vpriv_uid); break; \ case 5: OPT_VSTR_ARG(opts->vpriv_gid); break; \ case 6: OPT_VSTR_ARG(opts->pid_file); break; \ case 7: OPT_VSTR_ARG(opts->cntl_file); break; \ case 8: OPT_VSTR_ARG(opts->addr_beg->acpt_filter_file); break; \ case 9: OPT_NUM_ARG(opts->num_procs, "number of processes", \ 1, 255, ""); break; \ case 10: OPT_NUM_ARG(opts->addr_beg->defer_accept, \ "seconds to defer connections", \ 0, 4906, " (1 hour 8 minutes)"); break; \ case 11: OPT_NUM_NR_ARG(opts->io_limit.io_w_max, \ "process read limit"); break; \ case 12: OPT_NUM_NR_ARG(opts->io_limit.io_w_max, \ "process write limit"); break; \ case 13: OPT_NUM_NR_ARG(opts->io_nslimit.io_w_max, \ "connection read limit"); break; \ case 14: OPT_NUM_NR_ARG(opts->io_nslimit.io_w_max, \ "connection write limit"); break /* simple typer for EQ */ #define OPT_SERV_SYM_EQ(x) \ conf_token_cmp_sym_cstr_eq(conf, token, x) /* eXport data from configuration file to structs... */ #define OPT_SERV_X_TOGGLE(x) do { \ int opt__val = (x); \ \ if (conf_sc_token_parse_toggle(conf, token, &opt__val)) \ return (FALSE); \ (x) = opt__val; \ } while (FALSE) #define OPT_SERV_X_NEG_TOGGLE(x) do { \ int opt__val = !(x); \ \ if (conf_sc_token_parse_toggle(conf, token, &opt__val)) \ return (FALSE); \ (x) = !opt__val; \ } while (FALSE) #define OPT_SERV_X_SINGLE_UINT(x) do { \ unsigned int opt__val = 0; \ \ if (conf_sc_token_parse_uint(conf, token, &opt__val)) \ return (FALSE); \ (x) = opt__val; \ } while (FALSE) #define OPT_SERV_X_UINT(x) do { \ unsigned int opt__val = 0; \ \ if (!opt_serv_sc_make_uint(conf, token, &opt__val)) \ return (FALSE); \ (x) = opt__val; \ } while (FALSE) #define OPT_SERV_X_SINGLE_ULONG(x) do { \ unsigned long opt__val = 0; \ \ if (conf_sc_token_parse_uint(conf, token, &opt__val)) \ return (FALSE); \ (x) = opt__val; \ } while (FALSE) #define OPT_SERV_X_ULONG(x) do { \ unsigned long opt__val = 0; \ \ if (!opt_serv_sc_make_ulong(conf, token, &opt__val)) \ return (FALSE); \ (x) = opt__val; \ } while (FALSE) #define OPT_SERV_X_SINGLE_UINTMAX(x) do { \ uintmax_t opt__val = 0; \ \ if (conf_sc_token_parse_uintmax(conf, token, &opt__val)) \ return (FALSE); \ (x) = opt__val; \ } while (FALSE) #define OPT_SERV_X_UINTMAX(x) do { \ uintmax_t opt__val = 0; \ \ if (!opt_serv_sc_make_uintmax(conf, token, &opt__val)) \ return (FALSE); \ (x) = opt__val; \ } while (FALSE) /* take either a number or one of a few symbols, allow clist around symbols */ #define OPT_SERV_X_SYM__NUM_BEG(x) \ if (!ern) \ (x) = val; \ else \ { \ const Vstr_sect_node *pv = NULL; \ int clist_num = FALSE; \ \ if ((ern == CONF_SC_TYPE_RET_ERR_PARSE) && \ !(pv = conf_token_value(token))) \ CONF_SC_TOGGLE_CLIST_VAR(clist_num); \ if (ern && !(pv = conf_token_value(token))) \ return (FALSE); \ \ if (0) do { } while (FALSE) #define OPT_SERV_X_SYM_SINGLE_UINT_BEG(x) do { \ unsigned int val = 0; \ int ern = 0; \ \ ern = conf_sc_token_parse_uint(conf, token, &val); \ OPT_SERV_X_SYM__NUM_BEG(x) #define OPT_SERV_X_SYM_UINT_BEG(x) do { \ unsigned int val = (x); \ int ern = CONF_SC_TYPE_RET_OK; \ Conf_token save; \ \ save = *token; \ if (!opt_serv_sc_make_uint(conf, token, &val)) \ { \ ern = CONF_SC_TYPE_RET_ERR_PARSE; \ *token = save; \ conf_parse_token(conf, token); \ } \ OPT_SERV_X_SYM__NUM_BEG(x) #define OPT_SERV_X_SYM_SINGLE_ULONG_BEG(x) do { \ unsigned long val = 0; \ int ern = 0; \ \ ern = conf_sc_token_parse_ulong(conf, token, &val); \ OPT_SERV_X_SYM__NUM_BEG(x) #define OPT_SERV_X_SYM_ULONG_BEG(x) do { \ unsigned long val = (x); \ int ern = CONF_SC_TYPE_RET_OK; \ Conf_token save; \ \ save = *token; \ if (!opt_serv_sc_make_ulong(conf, token, &val)) \ { \ ern = CONF_SC_TYPE_RET_ERR_PARSE; \ *token = save; \ conf_parse_token(conf, token); \ } \ OPT_SERV_X_SYM__NUM_BEG(x) #define OPT_SERV_X_SYM_SINGLE_UINTMAX_BEG(x) do { \ uintmax_t val = 0; \ int ern = 0; \ \ ern = conf_sc_token_parse_uintmax(conf, token, &val); \ OPT_SERV_X_SYM__NUM_BEG(x) #define OPT_SERV_X_SYM_UINTMAX_BEG(x) do { \ uintmax_t val = (x); \ int ern = CONF_SC_TYPE_RET_OK; \ Conf_token save; \ \ save = *token; \ if (!opt_serv_sc_make_uintmax(conf, token, &val)) \ { \ ern = CONF_SC_TYPE_RET_ERR_PARSE; \ *token = save; \ conf_parse_token(conf, token); \ } \ OPT_SERV_X_SYM__NUM_BEG(x) #define OPT_SERV_X_SYM_NUM_END() \ else return (FALSE); \ } \ } while (FALSE) #define OPT_SERV_X__ESC_VSTR(x, p, l) do { \ if ((token->type == CONF_TOKEN_TYPE_QUOTE_ESC_D) || \ (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_DDD) || \ (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_S) || \ (token->type == CONF_TOKEN_TYPE_QUOTE_ESC_SSS) || \ FALSE) \ if (!conf_sc_conv_unesc((x), p, l, NULL)) \ return (FALSE); \ } while (FALSE) #define OPT_SERV_X__SINGLE_VSTR(x, p, l) do { \ if (conf_sc_token_sub_vstr(conf, token, x, p, l)) \ return (FALSE); \ \ if ((x)->conf->malloc_bad) \ return (FALSE); \ OPT_SERV_X__ESC_VSTR(x, p, token->u.node->len); \ } while (FALSE) #define OPT_SERV_X_SINGLE_VSTR(x) OPT_SERV_X__SINGLE_VSTR(x, 1, (x)->len) #define OPT_SERV_X__VSTR(o, x, p, l) do { \ if (!opt_serv_sc_make_str(o, conf, token, x, p, l)) \ return (FALSE); \ } while (FALSE) #define OPT_SERV_X_VSTR(o, x) OPT_SERV_X__VSTR(o, x, 1, (x)->len) #define OPT_SERV_X_EQ(x) do { \ if (conf_sc_token_parse_eq(conf, token, (x), 1, (x)->len, matches)) \ return (FALSE); \ } while (FALSE) #define OPT_SERV_X_CSTR_EQ(x) do { \ if (conf_sc_token_parse_cstr_eq(conf, token, (x), matches)) \ return (FALSE); \ } while (FALSE) #define OPT_SERV_SC_MATCH_INIT(x, y) do { \ unsigned int match_init__depth = token->depth_num; \ \ if (!opt_serv_match_init(x, conf, token)) \ return (FALSE); \ \ while (conf_token_list_num(token, match_init__depth)) \ { \ CONF_SC_PARSE_DEPTH_TOKEN_RET(conf, token, match_init__depth, FALSE); \ CONF_SC_TOGGLE_CLIST_VAR(clist); \ if (y) continue; \ \ return (FALSE); \ } \ } while (FALSE) #ifndef CONF_FULL_STATIC # define OPT_SERV_SC_RESOLVE_UID(opts) \ opt_serv_sc_resolve_uid(opts, program_name, usage) # define OPT_SERV_SC_RESOLVE_GID(opts) \ opt_serv_sc_resolve_gid(opts, program_name, usage) #else # define OPT_SERV_SC_RESOLVE_UID(opts) # define OPT_SERV_SC_RESOLVE_GID(opts) #endif #endif