diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-21 18:48:35 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-21 18:48:35 +0200 |
commit | d20b648b02aa1f8caf9975a116c54e05d67d1c39 (patch) | |
tree | a060073bdc2da690dca5817220538e2410cd914e | |
parent | 118f9d898f8e0208aa01275cf37752b888c39d20 (diff) | |
download | mailfromd-d20b648b02aa1f8caf9975a116c54e05d67d1c39.tar.gz mailfromd-d20b648b02aa1f8caf9975a116c54e05d67d1c39.tar.bz2 |
Implement the callout server.
* mfd/savsrv.c: New file.
* mfd/Makefile.am (mailfromd_SOURCES): Add savsrv.c.
* mfd/callout.c (struct smtp_io_data): Add new fields:
email, ehlo and mailfrom.
(smtp_io_create): trim trailing ': ' from the id.
(smtp_io_init, smtp_io_setup_callout): New functions.
(smtp_io_free): Free new members.
(smtp_io_email): New function.
(callout_io): Change signature.
(smtp_io_open): 2nd arg is const char *.
(callout): Remove.
(callout_host, callout_mx)
(callout_strict, callout_standard): New functions.
* mfd/engine.c (mfl_smtp_io_callback): Now extern.
(check_on_host, check_mx_records): Remove.
(method_strict, method_standard): Rewrite using new callout
support.
* mfd/mailfromd.h: Fix protos.
(callout_host, callout_mx)
(callout_strict, callout_standard): New functions.
* mfd/main.c (cb_url)
(callout_resolver, callout_resolver_section_param)
(callout_resolver_cfg_init): Remove.
(milter_config_stmt): Rename to server_config_stmt. Add new
field `server'.
(cb_milter_stmt_listen): Rename to cb_server_stmt_listen.
(milter_section_param): Rename to server_section_param.
(milter_section_parser): Rename to server_section_parser.
The label of the statement determines the server type.
(milter_cfg_init): Rename to server_cfg_init.
(mf_cfg_param): Rename `milter' and `callout-resolver'
statements. Add new statement `server'.
(main): Call server_cfg_init.
* mfd/bi_poll.m4 (_pollhost, _pollmx): Use callout_host
and callout_mx, correspondingly.
* mfd/cache.c (cache_get, cache_insert)
(cache_get2, cache_insert2): String args are const.
* mfd/dns.c (getmx): Likewise.
* mfd/srvman.c: Add debugging statements.
-rw-r--r-- | mfd/Makefile.am | 1 | ||||
-rw-r--r-- | mfd/bi_poll.m4 | 22 | ||||
-rw-r--r-- | mfd/cache.c | 12 | ||||
-rw-r--r-- | mfd/callout.c | 210 | ||||
-rw-r--r-- | mfd/dns.c | 2 | ||||
-rw-r--r-- | mfd/engine.c | 124 | ||||
-rw-r--r-- | mfd/mailfromd.h | 31 | ||||
-rw-r--r-- | mfd/main.c | 133 | ||||
-rw-r--r-- | mfd/savsrv.c | 225 | ||||
-rw-r--r-- | mfd/srvman.c | 32 |
10 files changed, 545 insertions, 247 deletions
diff --git a/mfd/Makefile.am b/mfd/Makefile.am index d1288a9a..962c22a0 100644 --- a/mfd/Makefile.am +++ b/mfd/Makefile.am @@ -72,6 +72,7 @@ mailfromd_SOURCES = \ pragma.c\ prog.c\ prog.h\ + savsrv.c\ srvman.c\ srvman.h\ spf.c\ diff --git a/mfd/bi_poll.m4 b/mfd/bi_poll.m4 index dc730200..efec3935 100644 --- a/mfd/bi_poll.m4 +++ b/mfd/bi_poll.m4 @@ -99,6 +99,8 @@ MF_DEFUN(_pollhost, NUMBER, STRING host, STRING email, STRING ehlo, STRING mailfrom) { mf_status rc; + smtp_io_t io; + const char *id = mailfromd_msgid(env_get_context(env)); const struct locus *locus = env_get_locus(env); trace("%s%s:%lu: POLLHOST %s FOR %s FROM %s AS %s", @@ -107,8 +109,14 @@ MF_DEFUN(_pollhost, NUMBER, STRING host, STRING email, STRING ehlo, email, host, ehlo, mailfrom); - rc = check_on_host(env, email, host, ehlo, mailfrom); - + io = smtp_io_create(id ? id : "(none): ", + smtp_timeout_soft, + mfl_smtp_io_callback, + env); + smtp_io_setup_callout(io, email, ehlo, mailfrom); + rc = callout_host(io, host); + smtp_io_free(io); + MF_ASSERT(mf_resolved(rc), mf_status_to_exception(rc), _("unhandled exception %s"), mf_exception_str(rc)); @@ -120,6 +128,8 @@ MF_DEFUN(_pollmx, NUMBER, STRING domain, STRING email, STRING ehlo, STRING mailfrom) { mf_status rc; + smtp_io_t io; + const char *id = mailfromd_msgid(env_get_context(env)); const struct locus *locus = env_get_locus(env); trace("%s%s:%lu: POLLMX %s FOR %s FROM %s AS %s", @@ -127,7 +137,13 @@ MF_DEFUN(_pollmx, NUMBER, STRING domain, STRING email, STRING ehlo, locus->file, locus->line, domain, email, ehlo, mailfrom); - rc = check_mx_records(env, email, domain, ehlo, mailfrom, NULL); + io = smtp_io_create(id ? id : "(none): ", + smtp_timeout_soft, + mfl_smtp_io_callback, + env); + smtp_io_setup_callout(io, email, ehlo, mailfrom); + rc = callout_mx(io, domain, NULL); + smtp_io_free(io); MF_ASSERT(mf_resolved(rc), mf_status_to_exception(rc), _("unhandled exception %s"), mf_exception_str(rc)); diff --git a/mfd/cache.c b/mfd/cache.c index 99150a13..89318137 100644 --- a/mfd/cache.c +++ b/mfd/cache.c @@ -32,7 +32,7 @@ struct cache_result { ((s) == mf_success ? cache_format->expire_interval : negative_expire_interval) mf_status -cache_get(char *email) +cache_get(const char *email) { mf_status rc; DBM_FILE db; @@ -57,7 +57,7 @@ cache_get(char *email) memset (&key, 0, sizeof key); memset (&contents, 0, sizeof contents); - MU_DATUM_PTR (key) = email; + MU_DATUM_PTR (key) = (void*) email; MU_DATUM_SIZE (key) = strlen (email) + 1; if ((res = mu_dbm_fetch(&db, key, &contents)) == 0) { char timebuf[80]; @@ -94,7 +94,7 @@ cache_get(char *email) } void -cache_insert(char *email, mf_status rc) +cache_insert(const char *email, mf_status rc) { DBM_FILE db; DBM_DATUM key; @@ -119,7 +119,7 @@ cache_insert(char *email, mf_status rc) memset(&key, 0, sizeof key); memset(&contents, 0, sizeof contents); - MU_DATUM_PTR(key) = email; + MU_DATUM_PTR(key) = (void*) email; MU_DATUM_SIZE(key) = strlen (email) + 1; MU_DATUM_PTR(contents) = (void*)&res; MU_DATUM_SIZE(contents) = sizeof(res); @@ -150,7 +150,7 @@ cache_expire_item(const void *content) } mf_status -cache_get2(char *email, char *client_addr) +cache_get2(const char *email, const char *client_addr) { mf_status rc = mf_failure; size_t size; @@ -169,7 +169,7 @@ cache_get2(char *email, char *client_addr) } void -cache_insert2(char *email, char *client_addr, mf_status rc) +cache_insert2(const char *email, const char *client_addr, mf_status rc) { if (!cache_format->enabled) return; diff --git a/mfd/callout.c b/mfd/callout.c index c6a75b5f..c028838e 100644 --- a/mfd/callout.c +++ b/mfd/callout.c @@ -38,11 +38,14 @@ #include "mailfromd.h" - #define SMTP_MAJOR(c) ((c)/100) struct smtp_io_data { char *id; /* I/O id */ + char *email; + char *ehlo; + char *mailfrom; + time_t timeout[SMTP_NUM_TIMEOUT]; smtp_io_callback_t callback; void *callback_closure; @@ -63,7 +66,16 @@ smtp_io_create(const char *id, time_t timeout[], smtp_io_callback_t callback, void *closure) { struct smtp_io_data *iop = xzalloc(sizeof(*iop)); - iop->id = xstrdup(id); + + if (!id) + iop->id = xstrdup("null"); + else { + size_t len; + iop->id = xstrdup(id); + len = strlen(iop->id); + if (len > 2 && strcmp(iop->id + len - 2, ": ") == 0) + iop->id[len - 2] = 0; + } memcpy(&iop->timeout, timeout, sizeof(iop->timeout)); iop->callback = callback; iop->callback_closure = closure; @@ -74,6 +86,33 @@ smtp_io_create(const char *id, time_t timeout[], smtp_io_callback_t callback, return iop; } +static void +replstr(char **pdst, const char *str) +{ + if (*pdst) + free(*pdst); + *pdst = xstrdup(str); +} + +void +smtp_io_init(struct smtp_io_data *iop) +{ + iop->send_off = iop->recv_off = 0; + iop->start = iop->command = iop->reply = NULL; + iop->level = 0; +} + +void +smtp_io_setup_callout(struct smtp_io_data *iop, + const char *email, + const char *ehlo, + const char *mailfrom) +{ + replstr(&iop->email, email); + replstr(&iop->ehlo, ehlo); + replstr(&iop->mailfrom, mailfrom); +} + void smtp_io_free(struct smtp_io_data *iop) { @@ -84,6 +123,9 @@ smtp_io_free(struct smtp_io_data *iop) } obstack_free(&iop->stk, NULL); free(iop->id); + free(iop->email); + free(iop->ehlo); + free(iop->mailfrom); free(iop); } @@ -98,7 +140,7 @@ transcript(struct smtp_io_data *io, char *prefix, const char *msg) --len; } if (len) - logmsg(LOG_INFO, "%s%s %*.*s", + logmsg(LOG_INFO, "%s: %s %*.*s", io->id, prefix, len, len, msg); } @@ -343,6 +385,12 @@ smtp_last_received(struct smtp_io_data *iop) return "nothing"; } +const char * +smtp_io_email(struct smtp_io_data *iop) +{ + return iop->email; +} + /* Milter-specific functions */ @@ -359,38 +407,43 @@ reset(struct smtp_io_data *io) } static mf_status -callout_io(struct smtp_io_data *io, char *email, char *ehlo, - mu_address_t addr) +callout_io(struct smtp_io_data *io, const char *hostname, mu_address_t addr) { size_t i; size_t mailcount; mf_status status; + if (io->callback) + io->callback(io->callback_closure, "INIT", + smtp_last_received(io)); + mu_address_get_count(addr, &mailcount); if (smtp_recv(io, smtp_timeout_initial)) return mf_temp_failure; - io->callback(io->callback_closure, "INIT", - smtp_last_received(io)); + if (io->callback) + io->callback(io->callback_closure, "GRTNG", + smtp_last_received(io)); if (SMTP_MAJOR(io->code) != 2) return SMTP_MAJOR(io->code) == 4 ? mf_temp_failure : mf_not_found; - smtp_send2(io, "HELO ", ehlo); + smtp_send2(io, "HELO ", io->ehlo); if (smtp_recv(io, smtp_timeout_helo)) return mf_temp_failure; if (SMTP_MAJOR(io->code) == 5) { /* Let's try EHLO, then */ - smtp_send2(io, "EHLO ", ehlo); + smtp_send2(io, "EHLO ", io->ehlo); if (smtp_recv(io, smtp_timeout_helo)) return mf_not_found; } - - io->callback(io->callback_closure, - "HELO", smtp_last_received(io)); + + if (io->callback) + io->callback(io->callback_closure, + "HELO", smtp_last_received(io)); if (SMTP_MAJOR(io->code) != 2) return SMTP_MAJOR(io->code) == 4 ? @@ -426,7 +479,7 @@ callout_io(struct smtp_io_data *io, char *email, char *ehlo, if (status != mf_success) return status; - smtp_send3(io, "RCPT TO:<", email, ">"); + smtp_send3(io, "RCPT TO:<", io->email, ">"); if (smtp_recv(io, smtp_timeout_rcpt)) return mf_temp_failure; else if (SMTP_MAJOR(io->code) != 2) @@ -437,18 +490,18 @@ callout_io(struct smtp_io_data *io, char *email, char *ehlo, mf_status -smtp_io_open(struct smtp_io_data *io, char *client_addr) +smtp_io_open(struct smtp_io_data *io, const char *hostname) { int rc; mu_stream_t stream; struct timeout_ctl tctl; - rc = mu_tcp_stream_create_with_source_ip (&stream, client_addr, 25, + rc = mu_tcp_stream_create_with_source_ip (&stream, hostname, 25, source_address, MU_STREAM_NONBLOCK); if (rc) { - mu_error(_("%scannot connect to `%s': %s"), - io->id, client_addr, + mu_error(_("%s: cannot connect to `%s': %s"), + io->id, hostname, mu_strerror(rc)); return mf_temp_failure; } @@ -464,7 +517,7 @@ smtp_io_open(struct smtp_io_data *io, char *client_addr) continue; } } - mu_error("%sstream_open: %s", + mu_error("%s: stream_open: %s", io->id, mu_strerror(rc)); mu_stream_destroy(&stream, mu_stream_get_owner(stream)); return mf_temp_failure; @@ -479,28 +532,28 @@ smtp_io_close(struct smtp_io_data *io) { if (io->stream) { mu_stream_close(io->stream); - mu_stream_destroy(&io->stream, mu_stream_get_owner(io->stream)); + mu_stream_destroy(&io->stream, + mu_stream_get_owner(io->stream)); } } mf_status -callout(struct smtp_io_data *io, - char *client_addr, - char *email, char *ehlo, char *mailfrom) +callout_host(struct smtp_io_data *io, const char *hostname) { int rc; mf_status status = mf_success; mu_address_t addr; + const char *mailfrom; - debug2(10, "email = %s, client_addr = %s", email, client_addr); + debug2(10, "email = %s, hostname = %s", io->email, hostname); - status = smtp_io_open(io, client_addr); + smtp_io_init(io); + status = smtp_io_open(io, hostname); if (status != mf_success) return status; /* FIXME-MU: compensate for mailutils deficiency */ - if (mailfrom[0] == 0) - mailfrom = "<>"; + mailfrom = (io->mailfrom[0] == 0) ? "<>" : io->mailfrom; rc = mu_address_create(&addr, mailfrom); if (rc) { mu_error(_("cannot create address `%s': %s"), @@ -508,17 +561,19 @@ callout(struct smtp_io_data *io, return mf_temp_failure; } - status = callout_io(io, email, ehlo, addr); + status = callout_io(io, hostname, addr); mu_address_destroy(&addr); - io->callback(io->callback_closure, - "SENT", smtp_last_sent(io)); - io->callback(io->callback_closure, - "RECV", smtp_last_received(io)); + if (io->callback) { + io->callback(io->callback_closure, + "SENT", smtp_last_sent(io)); + io->callback(io->callback_closure, + "RECV", smtp_last_received(io)); + } debug4(1, - "%spoll exited with status: %s; sent \"%s\", got \"%s\"", + "%s: poll exited with status: %s; sent \"%s\", got \"%s\"", io->id, mf_status_str(status), smtp_last_sent(io), @@ -533,7 +588,90 @@ callout(struct smtp_io_data *io, } mf_status -listens_on (const char *client_addr, int port, time_t timeout) +callout_mx(struct smtp_io_data *iop, const char *hostname, int *pcount) +{ + int i; + mxbuf_t mxbuf; + mf_status rc, mxstat = getmx(hostname, mxbuf); + + if (pcount) + *pcount = 0; + switch (mxstat) { + case mf_temp_failure: + case mf_failure: + case mf_not_found: + rc = mxstat; + break; + + case mf_success: + debug1(2,"Checking MX servers for %s", iop->email); + rc = mf_not_found; + for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { + rc = callout_host(iop, mxbuf[i]); + if (mf_resolved(rc)) + break; + } + if (pcount) { + for (; i < MAXMXCOUNT && mxbuf[i]; i++) + ; + *pcount = i; + } + dns_freemx(mxbuf); + break; + + default: + abort(); + } + return rc; +} + +/* Method "strict". Verifies whether EMAIL is understood either by + host CLIENT_ADDR or one of MX servers of its domain */ +mf_status +callout_strict(struct smtp_io_data *iop, const char *hostname) +{ + mf_status rc; + + rc = callout_host(iop, hostname); + if (!mf_resolved(rc)) { + int mxcount; + mf_status mx_stat; + mx_stat = callout_mx(iop, hostname, &mxcount); + if (!(mx_stat == mf_not_found && mxcount == 0) + && (mf_resolved(mx_stat) + || mx_stat == mf_temp_failure)) + rc = mx_stat; + } + return rc; +} + +mf_status +callout_standard(struct smtp_io_data *iop) +{ + int rc; + + char *p = strchr(iop->email, '@'); + if (p == NULL) { + mu_error(_("invalid address: %s"), iop->email); + rc = mf_not_found; + } else { + int mxcount; + p++; + rc = callout_mx(iop, p, &mxcount); + if (rc != mf_success && mxcount == 0) { + mf_status host_stat; + host_stat = callout_host(iop, p); + if (mf_resolved(host_stat) + || host_stat == mf_temp_failure) + rc = host_stat; + } + } + return rc; +} + + +mf_status +listens_on (const char *hostname, int port, time_t timeout) { unsigned count = 0; mu_stream_t stream; @@ -543,8 +681,8 @@ listens_on (const char *client_addr, int port, time_t timeout) if (port == 0) port = 25; - debug2(10, "client_addr = %s, port = %d", client_addr, port); - rc = mu_tcp_stream_create_with_source_ip (&stream, client_addr, port, + debug2(10, "hostname = %s, port = %d", hostname, port); + rc = mu_tcp_stream_create_with_source_ip (&stream, hostname, port, source_address, MU_STREAM_NONBLOCK); if (rc) { @@ -567,7 +705,7 @@ listens_on (const char *client_addr, int port, time_t timeout) } mu_stream_destroy(&stream, mu_stream_get_owner(stream)); - debug3 (10, "mu_stream_open(%s): %s, %u", client_addr, mu_strerror(rc), + debug3 (10, "mu_stream_open(%s): %s, %u", hostname, mu_strerror(rc), count); return rc == 0 ? mf_success : @@ -37,7 +37,7 @@ dns_to_mf_status(dns_status stat) } mf_status -getmx(char *host, mxbuf_t mxbuf) +getmx(const char *host, mxbuf_t mxbuf) { mf_status rc = dns_cache_get(T_MX, host, mxbuf, MAXMXCOUNT); if (!mf_resolved(rc)) { diff --git a/mfd/engine.c b/mfd/engine.c index 6c9b1cc6..e1f2de06 100644 --- a/mfd/engine.c +++ b/mfd/engine.c @@ -251,12 +251,17 @@ capture_eom(eval_environ_t env) -static void +void mfl_smtp_io_callback(void *data, const char *key, const char *value) { eval_environ_t env = data; - if (strcmp (key, "INIT") == 0) + if (strcmp (key, "INIT") == 0) { + set_last_poll_helo(env, ""); + set_last_poll_greeting(env, ""); + set_last_poll_sent(env, ""); + set_last_poll_recv(env, ""); + } else if (strcmp (key, "GRTNG") == 0) set_last_poll_greeting(env, value); else if (strcmp (key, "HELO") == 0) set_last_poll_helo(env, ""); @@ -266,71 +271,6 @@ mfl_smtp_io_callback(void *data, const char *key, const char *value) set_last_poll_recv(env, value); } -/* Verify whether EMAIL address is served by host CLIENT_ADDR. */ -mf_status -check_on_host(eval_environ_t env, char *email, char *client_addr, - char *ehlo, char *mailfrom) -{ - mf_status status; - smtp_io_t io; - const char *id = mailfromd_msgid(env_get_context(env)); - - io = smtp_io_create(id ? id : "(none)", - smtp_timeout_soft, - mfl_smtp_io_callback, - env); - - set_last_poll_helo(env, ""); - set_last_poll_greeting(env, ""); - set_last_poll_sent(env, ""); - set_last_poll_recv(env, ""); - - status = callout(io, client_addr, email, ehlo, mailfrom); - smtp_io_free(io); - - return status; -} - -mf_status -check_mx_records(eval_environ_t env, char *email, char *client_addr, - char *ehlo, char *mailfrom, int *pcount) -{ - int i; - mxbuf_t mxbuf; - mf_status rc, mxstat = getmx(client_addr, mxbuf); - - if (pcount) - *pcount = 0; - switch (mxstat) { - case mf_temp_failure: - case mf_failure: - case mf_not_found: - rc = mxstat; - break; - - case mf_success: - debug1(2,"Checking MX servers for %s", email); - rc = mf_not_found; - for (i = 0; i < MAXMXCOUNT && mxbuf[i]; i++) { - rc = check_on_host(env, email, mxbuf[i], - ehlo, mailfrom); - if (mf_resolved(rc)) - break; - } - if (pcount) { - for (; i < MAXMXCOUNT && mxbuf[i]; i++) - ; - *pcount = i; - } - dns_freemx(mxbuf); - break; - - default: - abort(); - } - return rc; -} - /* Method "strict". Verifies whether EMAIL is understood either by host CLIENT_ADDR or one of MX servers of its domain */ mf_status @@ -344,18 +284,19 @@ method_strict(eval_environ_t env, char *email, char *client_addr, rc = cache_get2(email, client_addr); if (!mf_resolved(rc)) { + smtp_io_t io; + const char *id = mailfromd_msgid(env_get_context(env)); + set_cache_used(env, 0); - rc = check_on_host(env, email, client_addr, ehlo, mailfrom); - if (!mf_resolved(rc)) { - int mxcount; - mf_status mx_stat; - mx_stat = check_mx_records(env, email, client_addr, - ehlo, mailfrom, &mxcount); - if (!(mx_stat == mf_not_found && mxcount == 0) - && (mf_resolved(mx_stat) - || mx_stat == mf_temp_failure)) - rc = mx_stat; - } + + io = smtp_io_create(id, + smtp_timeout_soft, + mfl_smtp_io_callback, + env); + smtp_io_setup_callout(io, email, ehlo, mailfrom); + rc = callout_strict(io, client_addr); + smtp_io_free(io); + if (mf_resolved(rc)) cache_insert2(email, client_addr, rc); } else { @@ -380,24 +321,17 @@ method_standard(eval_environ_t env, char *email, char *ehlo, char *mailfrom) rc = cache_get(email); if (!mf_resolved(rc)) { - char *p = strchr(email, '@'); + smtp_io_t io; + const char *id = mailfromd_msgid(env_get_context(env)); + set_cache_used(env, 0); - if (p == NULL) { - mu_error(_("invalid address: %s"), email); - rc = mf_not_found; - } else { - int mxcount; - rc = check_mx_records(env, email, p+1, ehlo, mailfrom, - &mxcount); - if (rc != mf_success && mxcount == 0) { - mf_status host_stat; - host_stat = check_on_host(env, email, p+1, - ehlo, mailfrom); - if (mf_resolved(host_stat) - || host_stat == mf_temp_failure) - rc = host_stat; - } - } + + io = smtp_io_create(id, + smtp_timeout_soft, + mfl_smtp_io_callback, + env); + rc = callout_standard(io); + smtp_io_free(io); if (mf_resolved(rc)) cache_insert(email, rc); } else { diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h index 4ea27ff1..5df54636 100644 --- a/mfd/mailfromd.h +++ b/mfd/mailfromd.h @@ -151,7 +151,7 @@ mf_status resolve_ipstr_domain(const char *ipstr, const char *domain, char **phbuf); mf_status resolve_hostname(const char *host, char **pipbuf); -mf_status getmx(char *ipstr, mxbuf_t mxbuf); +mf_status getmx(const char *ipstr, mxbuf_t mxbuf); mf_status getmxip(char *host, GACOPYZ_UINT32_T ipbuf[MAXMXCOUNT], size_t *pcount); @@ -955,6 +955,8 @@ void env_msgmod(eval_environ_t env, enum msgmod_opcode opcode, void capture_on(void); const char *env_get_macro(eval_environ_t env, const char *symbol); +void mfl_smtp_io_callback(void *data, const char *key, const char *value); + /* Runtime functions */ const char *mailfromd_msgid(SMFICTX *ctx); @@ -1037,10 +1039,10 @@ struct db_format *db_format_install(struct db_format *fmt); struct db_format *db_format_lookup(const char *name); void db_format_enumerate(dbfmt_enumerator_t fp, void *data); -mf_status cache_get(char *email); -void cache_insert(char *email, mf_status rc); -mf_status cache_get2(char *email, char *client_addr); -void cache_insert2(char *email, char *client_addr, mf_status rc); +mf_status cache_get(const char *email); +void cache_insert(const char *email, mf_status rc); +mf_status cache_get2(const char *email, const char *client_addr); +void cache_insert2(const char *email, const char *client_addr, mf_status rc); mf_status dns_cache_get(int type, const char *keystr, char **rbuf, size_t rcnt); @@ -1132,9 +1134,22 @@ typedef struct smtp_io_data *smtp_io_t; smtp_io_t smtp_io_create(const char *id, time_t timeout[], smtp_io_callback_t callback, void *closure); +void smtp_io_setup_callout(struct smtp_io_data *iop, + const char *email, + const char *ehlo, + const char *mailfrom); + void smtp_io_free(struct smtp_io_data *iop); -mf_status callout(smtp_io_t io, - char *client_addr, - char *email, char *ehlo, char *mailfrom); +const char *smtp_io_email(struct smtp_io_data *iop); + +mf_status callout_host(struct smtp_io_data *, const char *); +mf_status callout_mx(struct smtp_io_data *, const char *, int *); +mf_status callout_strict(struct smtp_io_data *, const char *); +mf_status callout_standard(struct smtp_io_data *); +/* savsrv.c */ +int callout_session_server(const char *id, int fd, + struct sockaddr const *sa, socklen_t len, + void *server_data, void *srvman_data); + @@ -2092,80 +2092,19 @@ smtp_timeout_cfg_init() } - -static int -cb_url(mu_debug_t err, void *data, mu_config_value_t *arg) -{ - mu_url_t url; - int rc; - - if (mu_cfg_assert_value_type(arg, MU_CFG_STRING, err)) - return 0; - rc = mu_url_create(&url, arg->v.string); - if (rc) { - mf_error_on_locus(err, - _("cannot create URL from `%s': %s"), - arg->v.string, mu_strerror(rc)); - return 0; - } - rc = mu_url_parse(url); - if (rc) { - mu_url_destroy(&url); - mf_error_on_locus(err, - _("%s: error parsing URL: %s"), - arg->v.string, mu_strerror(rc)); - return 0; - } - *(mu_url_t*) data = url; - return 0; -} - - - -struct callout_resolver_server { - mu_url_t url; - mu_acl_t acl; -}; - -struct callout_resolver_server callout_resolver; - -struct mu_cfg_param callout_resolver_section_param[] = { - { "listen", mu_cfg_callback, - NULL, offsetof(struct callout_resolver_server, url), cb_url, - N_("Listen on this URL."), - N_("url") }, - { "acl", mu_cfg_section, - NULL, offsetof(struct callout_resolver_server, acl) }, - { NULL } -}; - -void -callout_resolver_cfg_init() -{ - struct mu_cfg_section *section; - - if (mu_create_canned_section ("callout-resolver", §ion) == 0) { - section->parser = NULL; - section->docstring = N_("Set-up callout resolver server."); - section->label = NULL; - mu_cfg_section_add_params(section, - callout_resolver_section_param); - } -} - - /* Milter configuration */ -struct milter_config_stmt { +struct server_config_stmt { const char *id; mu_url_t url; mu_acl_t acl; size_t max_children; + mfd_server_func_t server; }; -static struct milter_config_stmt milter_config_stmt; +static struct server_config_stmt server_config_stmt; static int -cb_milter_stmt_listen(mu_debug_t err, void *data, mu_config_value_t *arg) +cb_server_stmt_listen(mu_debug_t err, void *data, mu_config_value_t *arg) { if (mu_cfg_assert_value_type(arg, MU_CFG_STRING, err)) return 1; @@ -2173,27 +2112,27 @@ cb_milter_stmt_listen(mu_debug_t err, void *data, mu_config_value_t *arg) return 0; } -struct mu_cfg_param milter_section_param[] = { +struct mu_cfg_param server_section_param[] = { { "id", mu_cfg_string, - &milter_config_stmt.id, 0, + &server_config_stmt.id, 0, NULL, N_("Server ID.") }, { "listen", mu_cfg_callback, - &milter_config_stmt.url, 0, - cb_milter_stmt_listen, + &server_config_stmt.url, 0, + cb_server_stmt_listen, N_("Listen on this URL."), N_("url") }, { "max-instances", mu_cfg_size, - &milter_config_stmt.max_children, 0, + &server_config_stmt.max_children, 0, NULL, N_("Maximum number of instances allowed for this server.") }, { "acl", mu_cfg_section, - &milter_config_stmt.acl }, + &server_config_stmt.acl }, { NULL } }; static int -milter_section_parser(enum mu_cfg_section_stage stage, +server_section_parser(enum mu_cfg_section_stage stage, const mu_cfg_node_t *node, const char *section_label, void **section_data, void *call_data, @@ -2201,22 +2140,35 @@ milter_section_parser(enum mu_cfg_section_stage stage, { switch (stage) { case mu_cfg_section_start: - memset(&milter_config_stmt, 0, sizeof(milter_config_stmt)); + memset(&server_config_stmt, 0, sizeof(server_config_stmt)); + if (mu_cfg_assert_value_type (node->label, MU_CFG_STRING, + tree->debug)) + return 1; + if (strcmp(node->label->v.string, "milter") == 0) + server_config_stmt.server = milter_session_server; + else if (strcmp(node->label->v.string, "callout") == 0) + server_config_stmt.server = callout_session_server; + else { + mu_cfg_format_error (tree->debug, + MU_DEBUG_ERROR, + _("unknown server type")); + return 1; + } break; case mu_cfg_section_end: - if (!milter_config_stmt.id) - milter_config_stmt.id = next_server_id(); - if (milter_config_stmt.url) { + if (!server_config_stmt.id) + server_config_stmt.id = next_server_id(); + if (server_config_stmt.url && server_config_stmt.server) { mfd_server_t srv = - mfd_server_new(milter_config_stmt.id, - milter_config_stmt.url, - milter_session_server); + mfd_server_new(server_config_stmt.id, + server_config_stmt.url, + server_config_stmt.server); if (srv) { mfd_server_set_max_children(srv, - milter_config_stmt.max_children); + server_config_stmt.max_children); mfd_server_set_acl(srv, - milter_config_stmt.acl); + server_config_stmt.acl); mfd_srvman_attach_server(srv); } } @@ -2226,15 +2178,15 @@ milter_section_parser(enum mu_cfg_section_stage stage, } void -milter_cfg_init() +server_cfg_init() { struct mu_cfg_section *section; - if (mu_create_canned_section ("milter", §ion) == 0) { - section->parser = milter_section_parser; - section->docstring = N_("Configure milter server."); - section->label = NULL; - mu_cfg_section_add_params(section, milter_section_param); + if (mu_create_canned_section ("server", §ion) == 0) { + section->parser = server_section_parser; + section->docstring = N_("Configure milter or callout server."); + section->label = "milter | callout"; + mu_cfg_section_add_params(section, server_section_param); } } @@ -2317,7 +2269,7 @@ struct mu_cfg_param mf_cfg_param[] = { { "listen", mu_cfg_callback, NULL, 0, cb_milter_listen, N_("Listen for milter requests on the given URL."), N_("url") }, - { "milter", mu_cfg_section }, + { "server", mu_cfg_section }, { "acl", mu_cfg_section, &srvman_param.acl }, #ifdef USE_SYSLOG_ASYNC { "syslog-async", mu_cfg_bool, &use_syslog_async, 0, NULL, @@ -2341,8 +2293,6 @@ struct mu_cfg_param mf_cfg_param[] = { { "database", mu_cfg_section, NULL }, - { "callout-resolver", mu_cfg_section, &callout_resolver }, - { NULL } }; @@ -2668,8 +2618,7 @@ main(int argc, char **argv) mu_acl_cfg_init(); database_cfg_init(); smtp_timeout_cfg_init(); - milter_cfg_init(); - callout_resolver_cfg_init(); + server_cfg_init(); mu_argp_init(program_version, "<" PACKAGE_BUGREPORT ">"); mu_app_rcfile = SYSCONFDIR "/mailfromd.conf"; diff --git a/mfd/savsrv.c b/mfd/savsrv.c new file mode 100644 index 00000000..4e90d364 --- /dev/null +++ b/mfd/savsrv.c @@ -0,0 +1,225 @@ +/* This file is part of Mailfromd. + Copyright (C) 2005, 2006, 2007, 2008, 2009 Sergey Poznyakoff + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define MF_SOURCE_NAME MF_SOURCE_CALLOUT +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <syslog.h> +#include <signal.h> +#include <pwd.h> +#include <grp.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <mailutils/mailutils.h> +#include <mailutils/daemon.h> + +#include "mailfromd.h" + +struct callout_command { + const char *command; + int argc; + int (*handler) (FILE *, int, char **); +}; + +struct vrfy_queue { + struct vrfy_queue *next; + |