#include <sys_defs.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>
#include <htable.h>
#include <stringops.h>
#include <dict.h>
#include <mail_conf.h>
#include <mail_params.h>
#include <mail_proto.h>
#include <dict_proxy.h>
#include <mail_server.h>
char *var_local_rcpt_maps;
char *var_virt_alias_maps;
char *var_virt_alias_doms;
char *var_virt_mailbox_maps;
char *var_virt_mailbox_doms;
char *var_relay_rcpt_maps;
char *var_relay_domains;
char *var_canonical_maps;
char *var_send_canon_maps;
char *var_rcpt_canon_maps;
char *var_relocated_maps;
char *var_transport_maps;
char *var_proxy_read_maps;
static HTABLE *proxy_read_maps;
static VSTRING *request;
static VSTRING *request_map;
static VSTRING *request_key;
static VSTRING *map_type_name_flags;
#define STR(x) vstring_str(x)
#define VSTREQ(x,y) (strcmp(STR(x),y) == 0)
static DICT *proxy_map_find(const char *map_type_name, int request_flags,
int *statp)
{
DICT *dict;
#define PROXY_COLON DICT_TYPE_PROXY ":"
#define PROXY_COLON_LEN (sizeof(PROXY_COLON) - 1)
#define READ_OPEN_FLAGS O_RDONLY
#define PROXY_MAP_FIND_ERROR_RETURN(x) { *statp = (x); return (0); }
while (strncmp(map_type_name, PROXY_COLON, PROXY_COLON_LEN) == 0)
map_type_name += PROXY_COLON_LEN;
if (strchr(map_type_name, ':') == 0)
PROXY_MAP_FIND_ERROR_RETURN(PROXY_STAT_BAD);
if (htable_locate(proxy_read_maps, map_type_name) == 0) {
msg_warn("request for unapproved table: \"%s\"", map_type_name);
msg_warn("to approve this table for %s access, list %s:%s in %s:%s",
MAIL_SERVICE_PROXYMAP, DICT_TYPE_PROXY, map_type_name,
MAIN_CONF_FILE, VAR_PROXY_READ_MAPS);
PROXY_MAP_FIND_ERROR_RETURN(PROXY_STAT_DENY);
}
vstring_sprintf(map_type_name_flags, "%s:%o",
map_type_name, request_flags);
if ((dict = dict_handle(STR(map_type_name_flags))) == 0)
dict = dict_open(map_type_name, READ_OPEN_FLAGS, request_flags);
if (dict == 0)
msg_panic("proxy_map_find: dict_open null result");
dict_register(STR(map_type_name_flags), dict);
return (dict);
}
static void proxymap_lookup_service(VSTREAM *client_stream)
{
int request_flags;
DICT *dict;
const char *reply_value;
int reply_status;
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request_flags,
ATTR_TYPE_STR, MAIL_ATTR_KEY, request_key,
ATTR_TYPE_END) != 3) {
reply_status = PROXY_STAT_BAD;
reply_value = "";
} else if ((dict = proxy_map_find(STR(request_map), request_flags,
&reply_status)) == 0) {
reply_value = "";
} else if ((reply_value = dict_get(dict, STR(request_key))) != 0) {
reply_status = PROXY_STAT_OK;
} else if (dict_errno == 0) {
reply_status = PROXY_STAT_NOKEY;
reply_value = "";
} else {
reply_status = PROXY_STAT_RETRY;
reply_value = "";
}
attr_print(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, reply_status,
ATTR_TYPE_STR, MAIL_ATTR_VALUE, reply_value,
ATTR_TYPE_END);
}
static void proxymap_open_service(VSTREAM *client_stream)
{
int request_flags;
DICT *dict;
int reply_status;
int reply_flags;
if (attr_scan(client_stream, ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_TABLE, request_map,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request_flags,
ATTR_TYPE_END) != 2) {
reply_status = PROXY_STAT_BAD;
reply_flags = 0;
} else if ((dict = proxy_map_find(STR(request_map), request_flags,
&reply_status)) == 0) {
reply_flags = 0;
} else {
reply_status = PROXY_STAT_OK;
reply_flags = dict->flags;
}
attr_print(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, reply_status,
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, reply_flags,
ATTR_TYPE_END);
}
static void proxymap_service(VSTREAM *client_stream, char *unused_service,
char **argv)
{
if (argv[0])
msg_fatal("unexpected command-line argument: %s", argv[0]);
if (attr_scan(client_stream,
ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
ATTR_TYPE_STR, MAIL_ATTR_REQ, request,
ATTR_TYPE_END) == 1) {
if (VSTREQ(request, PROXY_REQ_LOOKUP)) {
proxymap_lookup_service(client_stream);
} else if (VSTREQ(request, PROXY_REQ_OPEN)) {
proxymap_open_service(client_stream);
} else {
msg_warn("unrecognized request: \"%s\", ignored", STR(request));
attr_print(client_stream, ATTR_FLAG_NONE,
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, PROXY_STAT_BAD,
ATTR_TYPE_END);
}
}
vstream_fflush(client_stream);
}
DICT *dict_proxy_open(const char *map, int open_flags, int dict_flags)
{
if (msg_verbose)
msg_info("dict_proxy_open(%s, 0%o, 0%o) called from internal routine",
map, open_flags, dict_flags);
while (strncmp(map, PROXY_COLON, PROXY_COLON_LEN) == 0)
map += PROXY_COLON_LEN;
return (dict_open(map, open_flags, dict_flags));
}
static void post_jail_init(char *unused_name, char **unused_argv)
{
const char *sep = ", \t\r\n";
char *saved_filter;
char *bp;
char *type_name;
request = vstring_alloc(10);
request_map = vstring_alloc(10);
request_key = vstring_alloc(10);
map_type_name_flags = vstring_alloc(10);
saved_filter = bp = mystrdup(var_proxy_read_maps);
proxy_read_maps = htable_create(13);
while ((type_name = mystrtok(&bp, sep)) != 0) {
if (strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN))
continue;
do {
type_name += PROXY_COLON_LEN;
} while (!strncmp(type_name, PROXY_COLON, PROXY_COLON_LEN));
if (strchr(type_name, ':') != 0
&& htable_locate(proxy_read_maps, type_name) == 0)
(void) htable_enter(proxy_read_maps, type_name, (char *) 0);
}
myfree(saved_filter);
}
static void pre_accept(char *unused_name, char **unused_argv)
{
const char *table;
if ((table = dict_changed_name()) != 0) {
msg_info("table %s has changed -- restarting", table);
exit(0);
}
}
int main(int argc, char **argv)
{
static CONFIG_STR_TABLE str_table[] = {
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mailbox_doms, 0, 0,
VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0,
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0,
0,
};
multi_server_main(argc, argv, proxymap_service,
MAIL_SERVER_STR_TABLE, str_table,
MAIL_SERVER_POST_INIT, post_jail_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
0);
}