int main(int argc, char **argv) { INET_PROTO_INFO *proto_info; INET_ADDR_LIST *list; if (argc != 3) msg_fatal("usage: %s protocols interface_list (e.g. \"all all\")", argv[0]); msg_verbose = 10; proto_info = inet_proto_init(argv[0], argv[1]); var_inet_interfaces = argv[2]; list = own_inet_addr_list(); inet_addr_list_print(list); return (0); }
static DNS_RR *smtp_find_self(DNS_RR *addr_list) { const char *myname = "smtp_find_self"; INET_ADDR_LIST *self; INET_ADDR_LIST *proxy; DNS_RR *addr; int i; self = own_inet_addr_list(); proxy = proxy_inet_addr_list(); for (addr = addr_list; addr; addr = addr->next) { /* * Find out if this mail system is listening on this address. */ for (i = 0; i < self->used; i++) if (DNS_RR_EQ_SA(addr, (struct sockaddr *) (self->addrs + i))) { if (msg_verbose) msg_info("%s: found self at pref %d", myname, addr->pref); return (addr); } /* * Find out if this mail system has a proxy listening on this * address. */ for (i = 0; i < proxy->used; i++) if (DNS_RR_EQ_SA(addr, (struct sockaddr *) (proxy->addrs + i))) { if (msg_verbose) msg_info("%s: found proxy at pref %d", myname, addr->pref); return (addr); } } /* * Didn't find myself, or my proxy. */ if (msg_verbose) msg_info("%s: not found", myname); return (0); }
static SMTP_SESSION *smtp_connect_addr(SMTP_ITERATOR *iter, DSN_BUF *why, int sess_flags) { const char *myname = "smtp_connect_addr"; struct sockaddr_storage ss; /* remote */ struct sockaddr *sa = (struct sockaddr *) &ss; SOCKADDR_SIZE salen = sizeof(ss); MAI_HOSTADDR_STR hostaddr; DNS_RR *addr = iter->rr; unsigned port = iter->port; int sock; char *bind_addr; char *bind_var; dsb_reset(why); /* Paranoia */ /* * Sanity checks. */ if (dns_rr_to_sa(addr, port, sa, &salen) != 0) { msg_warn("%s: skip address type %s: %m", myname, dns_strtype(addr->type)); dsb_simple(why, "4.4.0", "network address conversion failed: %m"); return (0); } /* * Initialize. */ if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) msg_fatal("%s: socket: %m", myname); if (inet_windowsize > 0) set_inet_windowsize(sock, inet_windowsize); /* * Allow the sysadmin to specify the source address, for example, as "-o * smtp_bind_address=x.x.x.x" in the master.cf file. */ #ifdef HAS_IPV6 if (sa->sa_family == AF_INET6) { bind_addr = var_smtp_bind_addr6; bind_var = VAR_LMTP_SMTP(BIND_ADDR6); } else #endif if (sa->sa_family == AF_INET) { bind_addr = var_smtp_bind_addr; bind_var = VAR_LMTP_SMTP(BIND_ADDR); } else bind_var = bind_addr = ""; if (*bind_addr) { int aierr; struct addrinfo *res0; if ((aierr = hostaddr_to_sockaddr(bind_addr, (char *) 0, 0, &res0)) != 0) msg_fatal("%s: bad %s parameter: %s: %s", myname, bind_var, bind_addr, MAI_STRERROR(aierr)); if (bind(sock, res0->ai_addr, res0->ai_addrlen) < 0) msg_warn("%s: bind %s: %m", myname, bind_addr); else if (msg_verbose) msg_info("%s: bind %s", myname, bind_addr); freeaddrinfo(res0); } /* * When running as a virtual host, bind to the virtual interface so that * the mail appears to come from the "right" machine address. * * XXX The IPv6 patch expands the null host (as client endpoint) and uses * the result as the loopback address list. */ else { int count = 0; struct sockaddr *own_addr = 0; INET_ADDR_LIST *addr_list = own_inet_addr_list(); struct sockaddr_storage *s; for (s = addr_list->addrs; s < addr_list->addrs + addr_list->used; s++) { if (SOCK_ADDR_FAMILY(s) == sa->sa_family) { if (count++ > 0) break; own_addr = SOCK_ADDR_PTR(s); } } if (count == 1 && !sock_addr_in_loopback(own_addr)) { if (bind(sock, own_addr, SOCK_ADDR_LEN(own_addr)) < 0) { SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr), &hostaddr, (MAI_SERVPORT_STR *) 0, 0); msg_warn("%s: bind %s: %m", myname, hostaddr.buf); } else if (msg_verbose) { SOCKADDR_TO_HOSTADDR(own_addr, SOCK_ADDR_LEN(own_addr), &hostaddr, (MAI_SERVPORT_STR *) 0, 0); msg_info("%s: bind %s", myname, hostaddr.buf); } } } /* * Connect to the server. */ if (msg_verbose) msg_info("%s: trying: %s[%s] port %d...", myname, STR(iter->host), STR(iter->addr), ntohs(port)); return (smtp_connect_sock(sock, sa, salen, iter, why, sess_flags)); }
const char *mynetworks(void) { static VSTRING *result; if (result == 0) { char *myname = "mynetworks"; INET_ADDR_LIST *my_addr_list; INET_ADDR_LIST *my_mask_list; unsigned long addr; unsigned long mask; struct in_addr net; int shift; int junk; int i; int mask_style; mask_style = name_mask("mynetworks mask style", mask_styles, var_mynetworks_style); /* * XXX Workaround: name_mask() needs a flags argument so that we can * require exactly one value, or we need to provide an API that is * dedicated for single-valued flags. */ for (i = 0, junk = mask_style; junk != 0; junk >>= 1) i += (junk & 1); if (i != 1) msg_fatal("bad %s value: %s; specify exactly one value", VAR_MYNETWORKS_STYLE, var_mynetworks_style); result = vstring_alloc(20); my_addr_list = own_inet_addr_list(); my_mask_list = own_inet_mask_list(); for (i = 0; i < my_addr_list->used; i++) { addr = ntohl(my_addr_list->addrs[i].s_addr); mask = ntohl(my_mask_list->addrs[i].s_addr); switch (mask_style) { /* * Natural mask. This is dangerous if you're customer of an * ISP who gave you a small portion of their network. */ case MASK_STYLE_CLASS: if (IN_CLASSA(addr)) { mask = IN_CLASSA_NET; shift = IN_CLASSA_NSHIFT; } else if (IN_CLASSB(addr)) { mask = IN_CLASSB_NET; shift = IN_CLASSB_NSHIFT; } else if (IN_CLASSC(addr)) { mask = IN_CLASSC_NET; shift = IN_CLASSC_NSHIFT; } else if (IN_CLASSD(addr)) { mask = IN_CLASSD_NET; shift = IN_CLASSD_NSHIFT; } else { msg_fatal("%s: bad address class: %s", myname, inet_ntoa(my_addr_list->addrs[i])); } break; /* * Subnet mask. This is safe, but breaks backwards * compatibility when used as default setting. */ case MASK_STYLE_SUBNET: for (junk = mask, shift = BITS_PER_ADDR; junk != 0; shift--, (junk <<= 1)) /* void */ ; break; /* * Host only. Do not relay authorize other hosts. */ case MASK_STYLE_HOST: mask = ~0; shift = 0; break; default: msg_panic("unknown mynetworks mask style: %s", var_mynetworks_style); } net.s_addr = htonl(addr & mask); vstring_sprintf_append(result, "%s/%d ", inet_ntoa(net), BITS_PER_ADDR - shift); } if (msg_verbose) msg_info("%s: %s", myname, vstring_str(result)); }
void mail_params_init() { static const CONFIG_STR_TABLE first_str_defaults[] = { VAR_SYSLOG_FACILITY, DEF_SYSLOG_FACILITY, &var_syslog_facility, 1, 0, VAR_INET_PROTOCOLS, DEF_INET_PROTOCOLS, &var_inet_protocols, 0, 0, VAR_MULTI_CONF_DIRS, DEF_MULTI_CONF_DIRS, &var_multi_conf_dirs, 0, 0, /* multi_instance_wrapper may have dependencies but not dependents. */ VAR_MULTI_GROUP, DEF_MULTI_GROUP, &var_multi_group, 0, 0, VAR_MULTI_NAME, DEF_MULTI_NAME, &var_multi_name, 0, 0, 0, }; static const CONFIG_BOOL_TABLE first_bool_defaults[] = { /* read and process the following before opening tables. */ VAR_DAEMON_OPEN_FATAL, DEF_DAEMON_OPEN_FATAL, &var_daemon_open_fatal, 0, }; static const CONFIG_STR_FN_TABLE function_str_defaults[] = { VAR_MYHOSTNAME, check_myhostname, &var_myhostname, 1, 0, VAR_MYDOMAIN, check_mydomainname, &var_mydomain, 1, 0, 0, }; static const CONFIG_STR_TABLE other_str_defaults[] = { VAR_MAIL_NAME, DEF_MAIL_NAME, &var_mail_name, 1, 0, VAR_SYSLOG_NAME, DEF_SYSLOG_NAME, &var_syslog_name, 1, 0, VAR_MAIL_OWNER, DEF_MAIL_OWNER, &var_mail_owner, 1, 0, VAR_SGID_GROUP, DEF_SGID_GROUP, &var_sgid_group, 1, 0, VAR_MYDEST, DEF_MYDEST, &var_mydest, 0, 0, VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin, 1, 0, VAR_RELAYHOST, DEF_RELAYHOST, &var_relayhost, 0, 0, VAR_DAEMON_DIR, DEF_DAEMON_DIR, &var_daemon_dir, 1, 0, VAR_DATA_DIR, DEF_DATA_DIR, &var_data_dir, 1, 0, VAR_COMMAND_DIR, DEF_COMMAND_DIR, &var_command_dir, 1, 0, VAR_QUEUE_DIR, DEF_QUEUE_DIR, &var_queue_dir, 1, 0, VAR_PID_DIR, DEF_PID_DIR, &var_pid_dir, 1, 0, VAR_INET_INTERFACES, DEF_INET_INTERFACES, &var_inet_interfaces, 0, 0, VAR_PROXY_INTERFACES, DEF_PROXY_INTERFACES, &var_proxy_interfaces, 0, 0, VAR_DOUBLE_BOUNCE, DEF_DOUBLE_BOUNCE, &var_double_bounce_sender, 1, 0, VAR_DEFAULT_PRIVS, DEF_DEFAULT_PRIVS, &var_default_privs, 1, 0, VAR_ALIAS_DB_MAP, DEF_ALIAS_DB_MAP, &var_alias_db_map, 0, 0, VAR_MAIL_RELEASE, DEF_MAIL_RELEASE, &var_mail_release, 1, 0, VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0, VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0, VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0, VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 0, VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0, VAR_FFLUSH_DOMAINS, DEF_FFLUSH_DOMAINS, &var_fflush_domains, 0, 0, VAR_EXPORT_ENVIRON, DEF_EXPORT_ENVIRON, &var_export_environ, 0, 0, VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0, VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0, VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0, VAR_VERP_DELIMS, DEF_VERP_DELIMS, &var_verp_delims, 2, 2, VAR_VERP_FILTER, DEF_VERP_FILTER, &var_verp_filter, 1, 0, VAR_PAR_DOM_MATCH, DEF_PAR_DOM_MATCH, &var_par_dom_match, 0, 0, VAR_CONFIG_DIRS, DEF_CONFIG_DIRS, &var_config_dirs, 0, 0, VAR_BOUNCE_SERVICE, DEF_BOUNCE_SERVICE, &var_bounce_service, 1, 0, VAR_CLEANUP_SERVICE, DEF_CLEANUP_SERVICE, &var_cleanup_service, 1, 0, VAR_DEFER_SERVICE, DEF_DEFER_SERVICE, &var_defer_service, 1, 0, VAR_PICKUP_SERVICE, DEF_PICKUP_SERVICE, &var_pickup_service, 1, 0, VAR_QUEUE_SERVICE, DEF_QUEUE_SERVICE, &var_queue_service, 1, 0, VAR_REWRITE_SERVICE, DEF_REWRITE_SERVICE, &var_rewrite_service, 1, 0, VAR_SHOWQ_SERVICE, DEF_SHOWQ_SERVICE, &var_showq_service, 1, 0, VAR_ERROR_SERVICE, DEF_ERROR_SERVICE, &var_error_service, 1, 0, VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0, VAR_VERIFY_SERVICE, DEF_VERIFY_SERVICE, &var_verify_service, 1, 0, VAR_TRACE_SERVICE, DEF_TRACE_SERVICE, &var_trace_service, 1, 0, VAR_PROXYMAP_SERVICE, DEF_PROXYMAP_SERVICE, &var_proxymap_service, 1, 0, VAR_PROXYWRITE_SERVICE, DEF_PROXYWRITE_SERVICE, &var_proxywrite_service, 1, 0, VAR_INT_FILT_CLASSES, DEF_INT_FILT_CLASSES, &var_int_filt_classes, 0, 0, /* multi_instance_wrapper may have dependencies but not dependents. */ VAR_MULTI_WRAPPER, DEF_MULTI_WRAPPER, &var_multi_wrapper, 0, 0, 0, }; static const CONFIG_STR_FN_TABLE function_str_defaults_2[] = { VAR_MYNETWORKS, mynetworks, &var_mynetworks, 0, 0, 0, }; static const CONFIG_INT_TABLE other_int_defaults[] = { VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0, VAR_MAX_USE, DEF_MAX_USE, &var_use_limit, 1, 0, VAR_DONT_REMOVE, DEF_DONT_REMOVE, &var_dont_remove, 0, 0, VAR_LINE_LIMIT, DEF_LINE_LIMIT, &var_line_limit, 512, 0, VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0, VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0, VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0, VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0, VAR_FAULT_INJ_CODE, DEF_FAULT_INJ_CODE, &var_fault_inj_code, 0, 0, VAR_DB_CREATE_BUF, DEF_DB_CREATE_BUF, &var_db_create_buf, 1, 0, VAR_DB_READ_BUF, DEF_DB_READ_BUF, &var_db_read_buf, 1, 0, VAR_HEADER_LIMIT, DEF_HEADER_LIMIT, &var_header_limit, 1, 0, VAR_TOKEN_LIMIT, DEF_TOKEN_LIMIT, &var_token_limit, 1, 0, VAR_MIME_MAXDEPTH, DEF_MIME_MAXDEPTH, &var_mime_maxdepth, 1, 0, VAR_MIME_BOUND_LEN, DEF_MIME_BOUND_LEN, &var_mime_bound_len, 1, 0, VAR_DELAY_MAX_RES, DEF_DELAY_MAX_RES, &var_delay_max_res, MIN_DELAY_MAX_RES, MAX_DELAY_MAX_RES, VAR_INET_WINDOW, DEF_INET_WINDOW, &var_inet_windowsize, 0, 0, 0, }; static const CONFIG_LONG_TABLE long_defaults[] = { VAR_MESSAGE_LIMIT, DEF_MESSAGE_LIMIT, &var_message_limit, 0, 0, VAR_LMDB_MAP_SIZE, DEF_LMDB_MAP_SIZE, &var_lmdb_map_size, 1, 0, 0, }; static const CONFIG_TIME_TABLE time_defaults[] = { VAR_EVENT_DRAIN, DEF_EVENT_DRAIN, &var_event_drain, 1, 0, VAR_MAX_IDLE, DEF_MAX_IDLE, &var_idle_limit, 1, 0, VAR_IPC_TIMEOUT, DEF_IPC_TIMEOUT, &var_ipc_timeout, 1, 0, VAR_IPC_IDLE, DEF_IPC_IDLE, &var_ipc_idle_limit, 1, 0, VAR_IPC_TTL, DEF_IPC_TTL, &var_ipc_ttl_limit, 1, 0, VAR_TRIGGER_TIMEOUT, DEF_TRIGGER_TIMEOUT, &var_trigger_timeout, 1, 0, VAR_FORK_DELAY, DEF_FORK_DELAY, &var_fork_delay, 1, 0, VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0, VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0, VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0, VAR_IN_FLOW_DELAY, DEF_IN_FLOW_DELAY, &var_in_flow_delay, 0, 10, 0, }; static const CONFIG_BOOL_TABLE bool_defaults[] = { VAR_DISABLE_DNS, DEF_DISABLE_DNS, &var_disable_dns, VAR_SOFT_BOUNCE, DEF_SOFT_BOUNCE, &var_soft_bounce, VAR_OWNREQ_SPECIAL, DEF_OWNREQ_SPECIAL, &var_ownreq_special, VAR_STRICT_8BITMIME, DEF_STRICT_8BITMIME, &var_strict_8bitmime, VAR_STRICT_7BIT_HDRS, DEF_STRICT_7BIT_HDRS, &var_strict_7bit_hdrs, VAR_STRICT_8BIT_BODY, DEF_STRICT_8BIT_BODY, &var_strict_8bit_body, VAR_STRICT_ENCODING, DEF_STRICT_ENCODING, &var_strict_encoding, VAR_DISABLE_MIME_INPUT, DEF_DISABLE_MIME_INPUT, &var_disable_mime_input, VAR_DISABLE_MIME_OCONV, DEF_DISABLE_MIME_OCONV, &var_disable_mime_oconv, VAR_VERIFY_NEG_CACHE, DEF_VERIFY_NEG_CACHE, &var_verify_neg_cache, VAR_OLDLOG_COMPAT, DEF_OLDLOG_COMPAT, &var_oldlog_compat, VAR_HELPFUL_WARNINGS, DEF_HELPFUL_WARNINGS, &var_helpful_warnings, VAR_CYRUS_SASL_AUTHZID, DEF_CYRUS_SASL_AUTHZID, &var_cyrus_sasl_authzid, VAR_MULTI_ENABLE, DEF_MULTI_ENABLE, &var_multi_enable, VAR_LONG_QUEUE_IDS, DEF_LONG_QUEUE_IDS, &var_long_queue_ids, 0, }; const char *cp; INET_PROTO_INFO *proto_info; /* * Extract syslog_facility early, so that from here on all errors are * logged with the proper facility. */ get_mail_conf_str_table(first_str_defaults); if (!msg_syslog_facility(var_syslog_facility)) msg_fatal("file %s/%s: parameter %s: unrecognized value: %s", var_config_dir, MAIN_CONF_FILE, VAR_SYSLOG_FACILITY, var_syslog_facility); /* * Should daemons terminate after table open error, or should they * continue execution with reduced functionality? */ get_mail_conf_bool_table(first_bool_defaults); if (var_daemon_open_fatal) dict_allow_surrogate = 0; /* * What protocols should we attempt to support? The result is stored in * the global inet_proto_table variable. */ proto_info = inet_proto_init(VAR_INET_PROTOCOLS, var_inet_protocols); /* * Variables whose defaults are determined at runtime. Some sites use * short hostnames in the host table; some sites name their system after * the domain. */ get_mail_conf_str_fn_table(function_str_defaults); if (!valid_hostname(var_myhostname, DO_GRIPE)) msg_fatal("file %s/%s: parameter %s: bad parameter value: %s", var_config_dir, MAIN_CONF_FILE, VAR_MYHOSTNAME, var_myhostname); if (!valid_hostname(var_mydomain, DO_GRIPE)) msg_fatal("file %s/%s: parameter %s: bad parameter value: %s", var_config_dir, MAIN_CONF_FILE, VAR_MYDOMAIN, var_mydomain); /* * Variables that are needed by almost every program. * * XXX Reading the myorigin value from file is originally a Debian Linux * feature. This code is not enabled by default because of problems: 1) * it re-implements its own parameter syntax checks, and 2) it does not * implement $name expansions. */ get_mail_conf_str_table(other_str_defaults); #ifdef MYORIGIN_FROM_FILE if (*var_myorigin == '/') { char *origin = read_param_from_file(var_myorigin); if (*origin == 0) msg_fatal("%s file %s is empty", VAR_MYORIGIN, var_myorigin); myfree(var_myorigin); /* FIX 20070501 */ var_myorigin = origin; } #endif get_mail_conf_int_table(other_int_defaults); get_mail_conf_long_table(long_defaults); get_mail_conf_bool_table(bool_defaults); get_mail_conf_time_table(time_defaults); check_default_privs(); check_mail_owner(); check_sgid_group(); check_overlap(); #ifdef HAS_DB dict_db_cache_size = var_db_read_buf; #endif #ifdef HAS_LMDB dict_lmdb_map_size = var_lmdb_map_size; #endif inet_windowsize = var_inet_windowsize; /* * Variables whose defaults are determined at runtime, after other * variables have been set. This dependency is admittedly a bit tricky. * XXX Perhaps we should just register variables, and let the evaluator * figure out in what order to evaluate things. */ get_mail_conf_str_fn_table(function_str_defaults_2); /* * FIX 200412 The IPv6 patch did not call own_inet_addr_list() before * entering the chroot jail on Linux IPv6 systems. Linux has the IPv6 * interface list in /proc, which is not available after chrooting. */ (void) own_inet_addr_list(); /* * The PID variable cannot be set from the configuration file!! */ set_mail_conf_int(VAR_PID, var_pid = getpid()); /* * Neither can the start time variable. It isn't even visible. */ time(&var_starttime); /* * Export the syslog name so children can inherit and use it before they * have initialized. */ if ((cp = safe_getenv(CONF_ENV_LOGTAG)) == 0 || strcmp(cp, var_syslog_name) != 0) if (setenv(CONF_ENV_LOGTAG, var_syslog_name, 1) < 0) msg_fatal("setenv %s %s: %m", CONF_ENV_LOGTAG, var_syslog_name); /* * I have seen this happen just too often. */ if (strcasecmp(var_myhostname, var_relayhost) == 0) msg_fatal("%s and %s parameter settings must not be identical: %s", VAR_MYHOSTNAME, VAR_RELAYHOST, var_myhostname); /* * XXX These should be caught by a proper parameter parsing algorithm. */ if (var_myorigin[strcspn(var_myorigin, ", \t\r\n")]) msg_fatal("%s parameter setting must not contain multiple values: %s", VAR_MYORIGIN, var_myorigin); if (var_relayhost[strcspn(var_relayhost, ", \t\r\n")]) msg_fatal("%s parameter setting must not contain multiple values: %s", VAR_RELAYHOST, var_relayhost); /* * One more sanity check. */ if ((cp = verp_delims_verify(var_verp_delims)) != 0) msg_fatal("file %s/%s: parameters %s and %s: %s", var_config_dir, MAIN_CONF_FILE, VAR_VERP_DELIMS, VAR_VERP_FILTER, cp); }
MASTER_SERV *get_master_ent() { VSTRING *buf = vstring_alloc(100); VSTRING *junk = vstring_alloc(100); MASTER_SERV *serv; char *cp; char *name; char *host = 0; char *port = 0; char *transport; int private; int unprivileged; /* passed on to child */ int chroot; /* passed on to child */ char *command; int n; char *bufp; char *atmp; const char *parse_err; static char *saved_interfaces = 0; char *err; if (master_fp == 0) msg_panic("get_master_ent: config file not open"); if (master_disable == 0) msg_panic("get_master_ent: no service disable list"); /* * XXX We cannot change the inet_interfaces setting for a running master * process. Listening sockets are inherited by child processes so that * closing and reopening those sockets in the master does not work. * * Another problem is that library routines still cache results that are * based on the old inet_interfaces setting. It is too much trouble to * recompute everything. * * In order to keep our data structures consistent we ignore changes in * inet_interfaces settings, and issue a warning instead. */ if (saved_interfaces == 0) saved_interfaces = mystrdup(var_inet_interfaces); /* * Skip blank lines and comment lines. */ for (;;) { if (readllines(buf, master_fp, &master_line_last, &master_line) == 0) { vstring_free(buf); vstring_free(junk); return (0); } bufp = vstring_str(buf); if ((cp = mystrtok(&bufp, master_blanks)) == 0) continue; name = cp; transport = get_str_ent(&bufp, "transport type", (char *) 0); vstring_sprintf(junk, "%s/%s", name, transport); if (match_service_match(master_disable, vstring_str(junk)) == 0) break; } /* * Parse one logical line from the configuration file. Initialize service * structure members in order. */ serv = (MASTER_SERV *) mymalloc(sizeof(MASTER_SERV)); serv->next = 0; /* * Flags member. */ serv->flags = 0; /* * All servers busy warning timer. */ serv->busy_warn_time = 0; /* * Service name. Syntax is transport-specific. */ serv->ext_name = mystrdup(name); /* * Transport type: inet (wild-card listen or virtual) or unix. */ #define STR_SAME !strcmp if (STR_SAME(transport, MASTER_XPORT_NAME_INET)) { if (!STR_SAME(saved_interfaces, var_inet_interfaces)) { msg_warn("service %s: ignoring %s change", serv->ext_name, VAR_INET_INTERFACES); msg_warn("to change %s, stop and start Postfix", VAR_INET_INTERFACES); } serv->type = MASTER_SERV_TYPE_INET; atmp = mystrdup(name); if ((parse_err = host_port(atmp, &host, "", &port, (char *) 0)) != 0) fatal_with_context("%s in \"%s\"", parse_err, name); if (*host) { serv->flags |= MASTER_FLAG_INETHOST;/* host:port */ MASTER_INET_ADDRLIST(serv) = (INET_ADDR_LIST *) mymalloc(sizeof(*MASTER_INET_ADDRLIST(serv))); inet_addr_list_init(MASTER_INET_ADDRLIST(serv)); if (inet_addr_host(MASTER_INET_ADDRLIST(serv), host) == 0) fatal_with_context("bad hostname or network address: %s", name); inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; } else { MASTER_INET_ADDRLIST(serv) = strcasecmp(saved_interfaces, INET_INTERFACES_ALL) ? own_inet_addr_list() : /* virtual */ wildcard_inet_addr_list(); /* wild-card */ inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; } MASTER_INET_PORT(serv) = mystrdup(port); for (n = 0; /* see below */ ; n++) { if (n >= MASTER_INET_ADDRLIST(serv)->used) { serv->flags |= MASTER_FLAG_LOCAL_ONLY; break; } if (!sock_addr_in_loopback(SOCK_ADDR_PTR(MASTER_INET_ADDRLIST(serv)->addrs + n))) break; } } else if (STR_SAME(transport, MASTER_XPORT_NAME_UNIX)) { serv->type = MASTER_SERV_TYPE_UNIX; serv->listen_fd_count = 1; serv->flags |= MASTER_FLAG_LOCAL_ONLY; } else if (STR_SAME(transport, MASTER_XPORT_NAME_UXDG)) { serv->type = MASTER_SERV_TYPE_UXDG; serv->listen_fd_count = 1; serv->flags |= MASTER_FLAG_LOCAL_ONLY; } else if (STR_SAME(transport, MASTER_XPORT_NAME_FIFO)) { serv->type = MASTER_SERV_TYPE_FIFO; serv->listen_fd_count = 1; serv->flags |= MASTER_FLAG_LOCAL_ONLY; #ifdef MASTER_SERV_TYPE_PASS } else if (STR_SAME(transport, MASTER_XPORT_NAME_PASS)) { serv->type = MASTER_SERV_TYPE_PASS; serv->listen_fd_count = 1; /* If this is a connection screener, remote clients are likely. */ #endif } else { fatal_with_context("bad transport type: %s", transport); } /* * Service class: public or private. */ private = get_bool_ent(&bufp, "private", "y");