diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-05-07 15:17:34 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-05-07 15:17:34 +0300 |
commit | 05a8bb0ca988f41f016420ffc7dde427e423c187 (patch) | |
tree | fff58297f073bec8148c2d5468a45d592eab0379 | |
parent | 9f8f65324491b4186f4fd3c2580a8e0b14a248d9 (diff) | |
download | mailfromd-05a8bb0ca988f41f016420ffc7dde427e423c187.tar.gz mailfromd-05a8bb0ca988f41f016420ffc7dde427e423c187.tar.bz2 |
Implement v6 negotiation on the server side.
* gacopyz/stagenames.c: New file.
* gacopyz/Makefile.am (libgacopyz_a_SOURCES): Add stagenames.c.
* gacopyz/gacopyz.c (gacopyz_context_loop): Free req_macros.
(gacopyz_addrcpt_par): rename to gacopyz_add_rcpt_par.
* gacopyz/gacopyz.h (SM_LM_VRS_MAJOR, SM_LM_VRS_MAJOR)
(SM_LM_VRS_PLVL, GACOPYZ_SM_MKVER): New macros.
(macro_index): Rename to gacopyz_stage. All uses updated.
(smfi_version): New proto.
(gacopyz_addrcpt_par): rename to gacopyz_add_rcpt_par.
(gacopyz_stage_name): New declaration.
(gacopyz_srv_get_required_macros): New proto.
(gacopyz_srv_set_version, gacopyz_srv_set_protocol)
(gacopyz_srv_set_actions): 2nd argument is unsigned long.
* gacopyz/server.c (struct gacopyz_srv): New member req_macros.
(gacopyz_srv_get_required_macros): New function.
(gacopyz_srv_destroy): Free req_macros.
(gacopyz_srv_negotiate): Read macros.
* mfd/gram.y (milter_state_name): Removed. Use gacopyz_stage_name instead.
* mtasim/mtasim.c: New options: --gacopyz-log, --milter-proto, --milter-acts.
* doc/mtasim.texi, doc/mailfromd.texi: Update.
-rw-r--r-- | doc/mailfromd.texi | 8 | ||||
-rw-r--r-- | doc/mtasim.texi | 33 | ||||
-rw-r--r-- | gacopyz/Makefile.am | 1 | ||||
-rw-r--r-- | gacopyz/context.c | 4 | ||||
-rw-r--r-- | gacopyz/gacopyz.c | 71 | ||||
-rw-r--r-- | gacopyz/gacopyz.h | 58 | ||||
-rw-r--r-- | gacopyz/gacopyz_priv.h | 4 | ||||
-rw-r--r-- | gacopyz/server.c | 121 | ||||
-rw-r--r-- | gacopyz/smfi.c | 17 | ||||
-rw-r--r-- | gacopyz/stagenames.c | 27 | ||||
-rw-r--r-- | mfd/engine.c | 4 | ||||
-rw-r--r-- | mfd/gram.y | 44 | ||||
-rw-r--r-- | mfd/mailfromd.h | 2 | ||||
-rw-r--r-- | mtasim/mtasim.c | 111 |
14 files changed, 383 insertions, 122 deletions
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi index 3f8f893b..fd270c1a 100644 --- a/doc/mailfromd.texi +++ b/doc/mailfromd.texi @@ -12295,6 +12295,7 @@ Overrides @code{#pragma option stack-trace}, which you are advised to use instead (@pxref{pragma stack-trace}). @xref{tracing runtime errors}, for more information on this feature. +@anchor{gacopyz-log option} @opsummary{gacopyz-log} @item --gacopyz-log=@var{level} Set desired logging level for @command{gacopyz} library @@ -12326,7 +12327,10 @@ Apr 28 09:00:11 host mailfromd[9411]: finishing This level can be useful for debugging your scripts. @item debug -Log debugging information. This level prints huge amounts of +Log debugging information. + +@item proto +Log Milter protocol interactions. This level prints huge amounts of information, in particular it displays dumps of each Milter packet sent and received. @@ -12339,7 +12343,7 @@ other, it is seldom practical. Therefore, the option log levels @samp{warn}, @samp{err} and @samp{fatal}. It is the default. If you need to trace each subprocess startup and shutdown, set @option{--gacopyz-log=info}. Setting the logging level to -@samp{debug} can be needed only for @command{Gacopyz} developers, to +@samp{proto} can be needed only for @command{Gacopyz} developers, to debug the protocol. @xref{Testing Filter Scripts}. diff --git a/doc/mtasim.texi b/doc/mtasim.texi index a8849fea..513d045d 100644 --- a/doc/mtasim.texi +++ b/doc/mtasim.texi @@ -454,6 +454,14 @@ cases. Define Sendmail macro @var{macro} to the given @var{value}. It is similar to the @code{\D} administrative command (@pxref{D command}) +@mtasimopt{gacopyz-log, summary} +@item --gacopyz-log=@var{level} +Set desired logging level for @command{gacopyz} library +(@pxref{Gacopyz}). @xref{gacopyz-log option}, for a detailed +description of @var{level}. Notice, that unless this option is used, +the @option{--verbose} (@option{-v}) command line option implies +@option{--gacopyz-log=debug}. + @mtasimopt{group, summary} @mtindex g, -g, @command{mtasim} option, summary @item --group=@var{name} @@ -476,11 +484,29 @@ privileges. Display a short help summary @mtasimopt{milter-version, summary} -@item --milter-version=@var{number} - Force using the given Milter protocol version number. This option +@item --milter-version=@var{version} + Force using the given Milter protocol version number. The +@var{version} argument is either a numeric version (e.g. @samp{2}), or +a version string in form @samp{@var{major}.@var{minor}[.@var{patch}]}, +where square brackets indicate optional part. The default is +@samp{1.0.0}. If @var{version} is any of @samp{2}, @samp{3} or +@samp{1.0.0}, the default protocol capabilities and actions for that +version are set automatically. This option is intended for development and testing of the Gacopyz library (@pxref{Gacopyz}). +@mtasimopt{milter-proto, summary} +@item --milter-proto=@var{bitmask} +Set Milter protocol capabilities. See @file{gacopyz/gacopyz.h} for +the meaning of various bits in the @var{bitmask}. Look for the C +macros with the prefix @samp{SMFIP_}. + +@mtasimopt{milter-actions, summary} +@item --milter-actions=@var{bitmask} +Set Milter actions. See @file{gacopyz/gacopyz.h} for +the meaning of various bits in the @var{bitmask}. Look for the C +macros with the prefix @samp{SMFIF_}. + @mtasimopt{no-interactive, summary} @item --no-interactive Not-interactive mode (disable readline). @xref{Command Line Editing, , @@ -520,7 +546,8 @@ is the default mode for @command{mtasim}. @xref{interactive mode}. @mtindex v, -v, @command{mtasim} option, summary @item --verbose @itemx -v - Increase verbosity level. + Increase verbosity level. Implies @option{--gacopyz-log=debug}, +unless that option is used explicitly. @item --version @itemx -V diff --git a/gacopyz/Makefile.am b/gacopyz/Makefile.am index 7d8c012b..d658b3e7 100644 --- a/gacopyz/Makefile.am +++ b/gacopyz/Makefile.am @@ -27,6 +27,7 @@ libgacopyz_a_SOURCES = \ mfapi.h\ proc.c\ server.c\ + stagenames.c\ trans.h EXTRA_DIST=trans.tab trans.awk diff --git a/gacopyz/context.c b/gacopyz/context.c index 41d64c44..12094fdf 100644 --- a/gacopyz/context.c +++ b/gacopyz/context.c @@ -1,5 +1,5 @@ /* This file is part of gacopyz. - Copyright (C) 2006, 2007 Sergey Poznyakoff + Copyright (C) 2006, 2007, 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 @@ -50,7 +50,7 @@ gacopyz_getsymval(SMFICTX *ctx, const char *name) if (name[len-1] == '}') len--; - for (i = maci_max - 1; i >= 0; i--) { + for (i = gacopyz_stage_max - 1; i >= 0; i--) { if (ctx->macros[i].argv) { char **p; diff --git a/gacopyz/gacopyz.c b/gacopyz/gacopyz.c index f29681be..e26f7e2e 100644 --- a/gacopyz/gacopyz.c +++ b/gacopyz/gacopyz.c @@ -764,7 +764,7 @@ make_optneg_buf(SMFICTX *ctx, gacopyz_uint32_t *vbuf, size_t bufsize = 0; int i; - for (i = 0; i < maci_max; i++) { + for (i = 0; i < gacopyz_stage_max; i++) { if (ctx->req_macros[i]) bufsize += strlen(ctx->req_macros[i]) + 1 + sizeof(gacopyz_uint32_t); @@ -789,7 +789,7 @@ make_optneg_buf(SMFICTX *ctx, gacopyz_uint32_t *vbuf, *pbuf = buf; buf += OPTLEN; - for (i = 0; i < maci_max; i++) { + for (i = 0; i < gacopyz_stage_max; i++) { if (ctx->req_macros[i]) { gacopyz_uint32_t v; size_t len; @@ -901,7 +901,7 @@ macro_assoc_free(macro_assoc_t *p) static void clear_macros(SMFICTX *ctx, int i) { - for (; i < maci_max; i++) + for (; i < gacopyz_stage_max; i++) macro_assoc_free(&ctx->macros[i]); } @@ -962,7 +962,7 @@ shan_abort(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd) static state_ret_type shan_macro(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd) { - enum macro_index ind; + enum gacopyz_stage ind; char **p; if (!arg->argv.v) @@ -970,31 +970,31 @@ shan_macro(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd) switch (arg->argv.cmd) { case SMFIC_CONNECT: - ind = maci_conn; + ind = gacopyz_stage_conn; break; case SMFIC_HELO: - ind = maci_helo; + ind = gacopyz_stage_helo; break; case SMFIC_MAIL: - ind = maci_mail; + ind = gacopyz_stage_mail; break; case SMFIC_RCPT: - ind = maci_rcpt; + ind = gacopyz_stage_rcpt; break; case SMFIC_DATA: - ind = maci_data; + ind = gacopyz_stage_data; break; case SMFIC_BODYEOB: - ind = maci_eom; + ind = gacopyz_stage_eom; break; case SMFIC_EOH: - ind = maci_eoh; + ind = gacopyz_stage_eoh; break; default: @@ -1346,33 +1346,33 @@ shan_unkn(SMFICTX *ctx, union state_arg *arg, unsigned char *cmd) static struct state_disp disp[] = { { SMFIC_ABORT, "abort", - arg_no_args, shan_abort, st_abrt, CT_CNT, maci_none }, + arg_no_args, shan_abort, st_abrt, CT_CNT, gacopyz_stage_none }, { SMFIC_MACRO, "macro", - arg_argvc, shan_macro, st_none, CT_CNT, maci_none }, + arg_argvc, shan_macro, st_none, CT_CNT, gacopyz_stage_none }, { SMFIC_BODY, "body", - arg_one_string, shan_body, st_body, CT_CNT, maci_none }, + arg_one_string, shan_body, st_body, CT_CNT, gacopyz_stage_none }, { SMFIC_CONNECT, "connect", - arg_two_strings, shan_connect, st_conn, CT_CLR, maci_conn }, + arg_two_strings, shan_connect, st_conn, CT_CLR, gacopyz_stage_conn }, { SMFIC_BODYEOB, "endm", - arg_one_string, shan_endm, st_endm, CT_CNT, maci_eom }, + arg_one_string, shan_endm, st_endm, CT_CNT, gacopyz_stage_eom }, { SMFIC_HELO, "helo", - arg_one_string, shan_helo, st_helo, CT_CLR, maci_helo }, + arg_one_string, shan_helo, st_helo, CT_CLR, gacopyz_stage_helo }, { SMFIC_HEADER, "header", - arg_two_strings, shan_header, st_hdrs, CT_CNT, maci_none }, + arg_two_strings, shan_header, st_hdrs, CT_CNT, gacopyz_stage_none }, { SMFIC_MAIL, "mail", - arg_argv, shan_mail, st_mail, CT_CLR, maci_mail }, + arg_argv, shan_mail, st_mail, CT_CLR, gacopyz_stage_mail }, { SMFIC_OPTNEG, "optneg", - arg_ints, shan_optneg, st_opts, CT_CNT, maci_none }, + arg_ints, shan_optneg, st_opts, CT_CNT, gacopyz_stage_none }, { SMFIC_EOH, "eoh", - arg_no_args, shan_eoh, st_eohs, CT_CNT, maci_none }, + arg_no_args, shan_eoh, st_eohs, CT_CNT, gacopyz_stage_none }, { SMFIC_QUIT, "quit", - arg_no_args, shan_quit, st_quit, CT_END, maci_none }, + arg_no_args, shan_quit, st_quit, CT_END, gacopyz_stage_none }, { SMFIC_DATA, "data", - arg_no_args, shan_data, st_data, CT_CNT, maci_none }, + arg_no_args, shan_data, st_data, CT_CNT, gacopyz_stage_none }, { SMFIC_RCPT, "rcpt", - arg_argv, shan_rcpt, st_rcpt, CT_IGN|CT_CLR, maci_rcpt }, + arg_argv, shan_rcpt, st_rcpt, CT_IGN|CT_CLR, gacopyz_stage_rcpt }, { SMFIC_UNKNOWN, "unknown", - arg_one_string, shan_unkn, st_unkn, CT_IGN|CT_CLR, maci_none } + arg_one_string, shan_unkn, st_unkn, CT_IGN|CT_CLR, gacopyz_stage_none } }; struct state_disp * @@ -1488,6 +1488,17 @@ report_command(enum state state, enum state next_state, gacopyz_logdump(SMI_LOG_WARN, _("buffer"), buffer, size); } +static int +ctx_free(SMFICTX *ctx) +{ + int i; + + free(ctx->reply); + clear_macros(&ctx, 0); + for (i = 0; i < gacopyz_stage_max; i++) + free(ctx->req_macros[i]); +} + int gacopyz_context_loop(int fd, struct smfiDesc *desc) { @@ -1648,9 +1659,9 @@ gacopyz_context_loop(int fd, struct smfiDesc *desc) free(buffer); if (desc->xxfi_close) desc->xxfi_close(&ctx); - free(ctx.reply); - clear_macros(&ctx, 0); + ctx_free(&ctx); + if (desc->xxfi_finish) desc->xxfi_finish(); @@ -2026,7 +2037,7 @@ gacopyz_quarantine(SMFICTX *ctx, const char *reason) } int -gacopyz_addrcpt_par(SMFICTX *ctx, const char *rcpt, const char *args) +gacopyz_add_rcpt_par(SMFICTX *ctx, const char *rcpt, const char *args) { if (!rcpt || !*rcpt) return MI_FAILURE; @@ -2046,9 +2057,9 @@ gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args) } int -gacopyz_setsymlist(SMFICTX *ctx, enum macro_index ind, const char *macros) +gacopyz_setsymlist(SMFICTX *ctx, enum gacopyz_stage ind, const char *macros) { - if (ind < 0 || ind >= maci_max) + if (ind < 0 || ind >= gacopyz_stage_max) return MI_FAILURE; if (ctx->req_macros[ind]) free(ctx->req_macros[ind]); diff --git a/gacopyz/gacopyz.h b/gacopyz/gacopyz.h index f0b5bff2..f7d547a7 100644 --- a/gacopyz/gacopyz.h +++ b/gacopyz/gacopyz.h @@ -48,6 +48,13 @@ extern "C" { /* Implementation version number */ #define SMFI_VERSION 0x01000000 +#define SM_LM_VRS_MAJOR(v) (((v) & 0x7f000000) >> 24) +#define SM_LM_VRS_MINOR(v) (((v) & 0x007fff00) >> 8) +#define SM_LM_VRS_PLVL(v) ((v) & 0x0000007f) + +#define GACOPYZ_SM_MKVER(maj,min,pat) \ + ((((maj) & 0x7f)<<24) | (((min) & 0x7ffff) << 8) | ((pat) & 0x7f)) + /* Milter protocol version */ #define SMFI_PROT_VERSION 6 @@ -199,26 +206,26 @@ typedef union { struct sockaddr_un sunix; } milter_sockaddr_t; -enum macro_index { - maci_conn, - maci_helo, - maci_mail, - maci_rcpt, - maci_data, - maci_eom, - maci_eoh, +enum gacopyz_stage { + gacopyz_stage_conn, + gacopyz_stage_helo, + gacopyz_stage_mail, + gacopyz_stage_rcpt, + gacopyz_stage_data, + gacopyz_stage_eom, + gacopyz_stage_eoh, - maci_max, - maci_none = maci_max + gacopyz_stage_max, + gacopyz_stage_none = gacopyz_stage_max }; -#define SMFIM_CONNECT maci_conn -#define SMFIM_HELO maci_helo -#define SMFIM_ENVFROM maci_mail -#define SMFIM_ENVRCPT maci_rcpt -#define SMFIM_DATA maci_data -#define SMFIM_EOM maci_eom -#define SMFIM_EOH maci_eoh +#define SMFIM_CONNECT gacopyz_stage_conn +#define SMFIM_HELO gacopyz_stage_helo +#define SMFIM_ENVFROM gacopyz_stage_mail +#define SMFIM_ENVRCPT gacopyz_stage_rcpt +#define SMFIM_DATA gacopyz_stage_data +#define SMFIM_EOM gacopyz_stage_eom +#define SMFIM_EOH gacopyz_stage_eoh #define _SOCK_ADDR milter_sockaddr_t #define smfiDesc gacopyz_milter_descr @@ -275,6 +282,7 @@ struct gacopyz_milter_descr }; /* Standard API calls */ +extern int smfi_version (unsigned int *, unsigned int *, unsigned int *); extern int smfi_opensocket (int); extern int smfi_register (struct smfiDesc); extern int smfi_main (void); @@ -365,15 +373,17 @@ int gacopyz_replace_body(SMFICTX *ctx, const unsigned char *bodyp, size_t bodylen); int gacopyz_progress(SMFICTX *ctx); int gacopyz_quarantine(SMFICTX *ctx, const char *reason); -int gacopyz_addrcpt_par(SMFICTX *ctx, const char *rcpt, const char *args); +int gacopyz_add_rcpt_par(SMFICTX *ctx, const char *rcpt, const char *args); int gacopyz_chgfrom(SMFICTX *ctx, const char *from, const char *args); -int gacopyz_setsymlist(SMFICTX *ctx, enum macro_index ind, const char *macros); +int gacopyz_setsymlist(SMFICTX *ctx, enum gacopyz_stage ind, const char *macros); int gacopyz_setpriv (SMFICTX *ctx, void *data); void *gacopyz_getpriv (SMFICTX *ctx); /* Logging (extensions) */ +extern const char *gacopyz_stage_name[gacopyz_stage_max]; + #define GACOPYZ_VBUFSIZE 69 size_t gacopyz_format_vbuf(char vbuf[GACOPYZ_VBUFSIZE], const char *buf, size_t size); @@ -411,6 +421,10 @@ void gacopyz_srv_iterate_macros (gacopyz_srv_t srv, void *data), void *data); void gacopyz_srv_count_macros (gacopyz_srv_t srv, size_t *count); + +const char **gacopyz_srv_get_required_macros(gacopyz_srv_t srv, + enum gacopyz_stage stage); + int gacopyz_srv_connect (gacopyz_srv_t srv); int gacopyz_srv_init(gacopyz_srv_t srv); int gacopyz_srv_negotiate(gacopyz_srv_t srv); @@ -440,9 +454,9 @@ void gacopyz_srv_set_callback(gacopyz_srv_t srv, void gacopyz_srv_set_callback_data(gacopyz_srv_t, void *); int gacopyz_srv_set_source(gacopyz_srv_t srv, unsigned long addr); -int gacopyz_srv_set_version(gacopyz_srv_t srv, int version); -int gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto); -int gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts); +int gacopyz_srv_set_version(gacopyz_srv_t srv, unsigned long version); +int gacopyz_srv_set_protocol(gacopyz_srv_t srv, unsigned long proto); +int gacopyz_srv_set_actions(gacopyz_srv_t srv, unsigned long acts); #define GACOPYZ_WRITE_TIMEOUT 10 #define GACOPYZ_READ_TIMEOUT 10 diff --git a/gacopyz/gacopyz_priv.h b/gacopyz/gacopyz_priv.h index 76be1611..d7e1ffe9 100644 --- a/gacopyz/gacopyz_priv.h +++ b/gacopyz/gacopyz_priv.h @@ -34,8 +34,8 @@ struct smfi_str { unsigned long mta_pflags; /* pflags supported by MTA */ unsigned long aflags; /* milter action flags (from xxfi_flags) */ int nmacros; /* Number of entries in macros */ - macro_assoc_t macros[maci_max]; /* Macro tables */ - char *req_macros[maci_max]; /* Required macros */ + macro_assoc_t macros[gacopyz_stage_max]; /* Macro tables */ + char *req_macros[gacopyz_stage_max]; /* Required macros */ char *reply; /* reply code */ void *privdata; /* private data */ }; diff --git a/gacopyz/server.c b/gacopyz/server.c index a61836e8..e7cfa643 100644 --- a/gacopyz/server.c +++ b/gacopyz/server.c @@ -1,5 +1,5 @@ /* This file is part of gacopyz. - Copyright (C) 2007, 2008 Sergey Poznyakoff + Copyright (C) 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 @@ -49,6 +49,7 @@ struct gacopyz_srv { unsigned long version; unsigned long acts; unsigned long proto; + char **req_macros[gacopyz_stage_max]; /* Required macros */ int (*cb_reply) (gacopyz_srv_t srv, int cmd, int rcmd, void *data); void *cb_data; @@ -279,6 +280,13 @@ gacopyz_srv_count_macros(gacopyz_srv_t srv, size_t *count) } +const char ** +gacopyz_srv_get_required_macros(gacopyz_srv_t srv, enum gacopyz_stage stage) +{ + return (const char **) srv->req_macros[stage]; +} + + struct timeval default_gacopyz_timeout[GACOPYZ_TO_COUNT] = { { GACOPYZ_WRITE_TIMEOUT, 0 }, @@ -612,7 +620,7 @@ gacopyz_srv_set_source(gacopyz_srv_t srv, unsigned long addr) } int -gacopyz_srv_set_version(gacopyz_srv_t srv, int version) +gacopyz_srv_set_version(gacopyz_srv_t srv, unsigned long version) { GACOPYZ_ASSERT(srv); @@ -621,7 +629,7 @@ gacopyz_srv_set_version(gacopyz_srv_t srv, int version) } int -gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto) +gacopyz_srv_set_protocol(gacopyz_srv_t srv, unsigned long proto) { GACOPYZ_ASSERT(srv); @@ -630,7 +638,7 @@ gacopyz_srv_set_protocol(gacopyz_srv_t srv, int proto) } int -gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts) +gacopyz_srv_set_actions(gacopyz_srv_t srv, unsigned long acts) { GACOPYZ_ASSERT(srv); @@ -638,15 +646,24 @@ gacopyz_srv_set_actions(gacopyz_srv_t srv, int acts) return MI_SUCCESS; } - void gacopyz_srv_destroy(gacopyz_srv_t *p) { + int i; + gacopyz_srv_t srv = *p; gacopyz_srv_clear_macros(srv); free(srv->portspec); free(srv->id); free(srv->def); + for (i = 0; i < gacopyz_stage_max; i++) + if (srv->req_macros[i]) { + int j; + + for (j = 0; srv->req_macros[i][j]; j++) + free(srv->req_macros[i][j]); + free(srv->req_macros[i]); + } free(srv->buf); free(srv); *p = 0; @@ -860,6 +877,94 @@ gacopyz_srv_connect(gacopyz_srv_t srv) return MI_SUCCESS; } +#define ISWS(c) ((c) == ' ' || (c) == '\t') + +static void +parse_macros(gacopyz_srv_t srv, enum gacopyz_stage stage, char *buf) +{ + char *p; + char **argv; + size_t count; + + count = 0; + for (p = buf; *p;) { + while (*p && ISWS(*p)) + p++; + if (*p) { + count++; + while (*p && !ISWS(*p)) + p++; + } + } + if (count == 0) + return; + GACOPYZ_ALLOC(srv, argv = calloc(count + 1, sizeof(argv[0]))); + count = 0; + for (p = buf; *p;) { + while (*p && ISWS(*p)) + p++; + if (*p) { + size_t i; + char *str = p; + + for (i = 0; *p && !ISWS(*p); p++, i++) + ; + if (i > 0) { + char *newstr; + + if (*str == '{' && str[i-1] == '}') { + str++; + i -= 2; + } + GACOPYZ_ALLOC(srv, newstr = malloc(i + 1)); + memcpy(newstr, str, i); + newstr[i] = 0; + argv[count++] = newstr; + } + } + } + argv[count] = NULL; + srv->req_macros[stage] = argv; +} + + +static void +read_macros(gacopyz_srv_t srv) +{ + char *buf = srv->buf + 3 * sizeof(gacopyz_uint32_t); + size_t size = srv->bufsize - 3 * sizeof(gacopyz_uint32_t); + + while (size > sizeof(gacopyz_uint32_t)) { + gacopyz_uint32_t v; + unsigned n; + size_t len; + + memcpy (&v, buf, sizeof(gacopyz_uint32_t)); + n = ntohl(v); + if (n >= gacopyz_stage_max) { + gacopyz_io_log(&srv->iod, SMI_LOG_ERR, + _("received invalid stage number")); + break; + } + buf += sizeof(gacopyz_uint32_t); + size -= sizeof(gacopyz_uint32_t); + if (size == 0) + break; + len = strlen(buf) + 1; + if (len > size) { + gacopyz_io_log(&srv->iod, SMI_LOG_ERR, + _("invalid macro list")); + break; + } + gacopyz_io_log(&srv->iod, SMI_LOG_DEBUG, + _("macros for stage \"%s\" (%d): %s"), + gacopyz_stage_name[n], n, buf); + parse_macros(srv, n, buf); + buf += len; + size -= len; + } +} + int gacopyz_srv_negotiate(gacopyz_srv_t srv) { @@ -927,6 +1032,10 @@ gacopyz_srv_negotiate(gacopyz_srv_t srv) return MI_FAILURE; } + if (milter_version > 3 + && srv->bufsize > 3 * sizeof(gacopyz_uint32_t)) + read_macros(srv); + srv->version = milter_version; srv->acts = milter_acts; srv->proto = milter_proto; @@ -1209,8 +1318,6 @@ gacopyz_srv_conn(gacopyz_srv_t srv, const char *hostname, struct sockaddr *sa) int gacopyz_srv_helo(gacopyz_srv_t srv, const char *domain) { - int rc; - GACOPYZ_ASSERT(srv); if (srv->state == srv_msgproc) gacopyz_srv_abort(srv); diff --git a/gacopyz/smfi.c b/gacopyz/smfi.c index 721b3460..4f8628d4 100644 --- a/gacopyz/smfi.c +++ b/gacopyz/smfi.c @@ -197,7 +197,7 @@ smfi_quarantine(SMFICTX *ctx, char *reason) int smfi_addrcpt_par(SMFICTX *ctx, char *rcpt, char *args) { - return gacopyz_addrcpt_par(ctx, rcpt, args); + return gacopyz_add_rcpt_par(ctx, rcpt, args); } int @@ -209,12 +209,23 @@ smfi_chgfrom(SMFICTX *ctx, char *from, char *args) int smfi_setsymlist(SMFICTX *ctx, int n, char *macros) { - if (n < 0 || n >= maci_max) + if (n < 0 || n >= gacopyz_stage_max) return MI_FAILURE; if (!macros || !*macros || ctx->req_macros[n]) return MI_FAILURE; return gacopyz_setsymlist(ctx, n, macros); } - +int +smfi_version(unsigned int *maj, unsigned int *min, unsigned int *pat) +{ + if (maj) + *maj = SM_LM_VRS_MAJOR(SMFI_VERSION); + if (min) + *min = SM_LM_VRS_MINOR(SMFI_VERSION); + if (pat) + *pat = SM_LM_VRS_MINOR(SMFI_VERSION); + return MI_SUCCESS; +} + diff --git a/gacopyz/stagenames.c b/gacopyz/stagenames.c new file mode 100644 index 00000000..0be67617 --- /dev/null +++ b/gacopyz/stagenames.c @@ -0,0 +1,27 @@ +/* This file is part of gacopyz. + Copyright (C) 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/>. */ + +#include <gacopyz_priv.h> + +const char *gacopyz_stage_name[gacopyz_stage_max] = { + "connect", + "helo", + "envfrom", + "envrcpt", + "data", + "eom", + "eoh" +}; diff --git a/mfd/engine.c b/mfd/engine.c index 2ddfd5f9..a9b42b29 100644 --- a/mfd/engine.c +++ b/mfd/engine.c @@ -1358,13 +1358,13 @@ mlfi_negotiate(SMFICTX *ctx, unsigned long *unused4, unsigned long *unused5) { - enum macro_index i; + enum gacopyz_stage i; debug4(70, "Negotiate: mta_actions=%#lx, mta_capa=%#lx, " "filter_actions=%#lx, filter_capa=%#lx", mta_actions, mta_capa, *filter_actions, *filter_capa); - for (i = 0; i < maci_max; i++) { + for (i = 0; i < gacopyz_stage_max; i++) { char *str = get_stage_macro_string(i); gacopyz_setsymlist(ctx, i, str); free(str); @@ -2412,49 +2412,39 @@ print_xref() } -static mu_list_t smtp_macro_list[maci_max]; +static mu_list_t smtp_macro_list[gacopyz_stage_max]; -static enum macro_index -smtp_to_milter_state(enum smtp_state tag) +static enum gacopyz_stage +smtp_to_gacopyz_stage(enum smtp_state tag) { switch (tag) { case smtp_state_connect: - return maci_conn; + return gacopyz_stage_conn; case smtp_state_helo: - return maci_helo; + return gacopyz_stage_helo; case smtp_state_envfrom: - return maci_mail; + return gacopyz_stage_mail; case smtp_state_envrcpt: - return maci_rcpt; + return gacopyz_stage_rcpt; case smtp_state_data: case smtp_state_header: case smtp_state_body: - return maci_data; + return gacopyz_stage_data; case smtp_state_eoh: - return maci_eoh; + return gacopyz_stage_eoh; case smtp_state_eom: - return maci_eom; + return gacopyz_stage_eom; default: break; } - return maci_none; + return gacopyz_stage_none; } -static const char *milter_state_name[maci_max] = { - "connect", - "helo", - "envfrom", - "envrcpt", - "data", - "eom", - "eoh" -}; - void register_macro(enum smtp_state state, const char *macro) { - enum macro_index ind = smtp_to_milter_state(state); - if (ind == maci_none) + enum gacopyz_stage ind = smtp_to_gacopyz_stage(state); + if (ind == gacopyz_stage_none) return; if (!smtp_macro_list[ind]) { mu_list_create(&smtp_macro_list[ind]); @@ -2481,12 +2471,12 @@ print_macro(void *item, void *data) void print_used_macros() { - enum macro_index i; + enum gacopyz_stage i; - for (i = 0; i < maci_max; i++) { + for (i = 0; i < gacopyz_stage_max; i++) { if (smtp_macro_list[i]) { int n = 1; - printf("%s", milter_state_name[i]); + printf("%s", gacopyz_stage_name[i]); mu_list_do(smtp_macro_list[i], print_macro, &n); printf("\n"); } @@ -2521,7 +2511,7 @@ concat_macro(void *item, void *data) } char * -get_stage_macro_string(enum macro_index i) +get_stage_macro_string(enum gacopyz_stage i) { struct macro_acc acc; size_t size; diff --git a/mfd/mailfromd.h b/mfd/mailfromd.h index 47360b8d..a45bf346 100644 --- a/mfd/mailfromd.h +++ b/mfd/mailfromd.h @@ -732,7 +732,7 @@ char *mf_strdup(const char *str); void regex_push(void); void regex_pop(void); -char *get_stage_macro_string(enum macro_index i); +char *get_stage_macro_string(enum gacopyz_stage i); /* Data types and declarations for handling compiled configuration code */ diff --git a/mtasim/mtasim.c b/mtasim/mtasim.c index 5c79ff7f..f9a85f53 100644 --- a/mtasim/mtasim.c +++ b/mtasim/mtasim.c @@ -102,7 +102,10 @@ int define_macro (char *arg); /* Milter-related options */ char *milter_port; size_t max_body_chunk = 65535; -int milter_version_option = 0; +unsigned long milter_version_option = 0; +unsigned long milter_proto_option = 0; +unsigned long milter_acts_option = 0; +int gacopyz_log_mask; struct timeval milter_timeouts[GACOPYZ_TO_COUNT] = { { GACOPYZ_WRITE_TIMEOUT, 0 }, { GACOPYZ_READ_TIMEOUT, 0 }, @@ -268,6 +271,7 @@ static char doc[] = N_("mtasim -- MTA simulator for mailfromd"); enum { OPTION_STDIO = 128, + OPTION_GACOPYZ_LOG, OPTION_DAEMON, OPTION_TLS_CERT, OPTION_TLS_CA, @@ -275,6 +279,8 @@ enum { OPTION_TRACE_FILE, OPTION_BODY_CHUNK, OPTION_MILTER_VERSION, + OPTION_MILTER_PROTO, + OPTION_MILTER_ACTS, OPTION_NO_INTERACTIVE, OPTION_PROMPT, OPTION_STATEDIR @@ -322,8 +328,12 @@ static struct argp_option options[] = { { "body-chunk", OPTION_BODY_CHUNK, N_("NUMBER"), 0, N_("Set the body chunk for xxfi_body calls"), GRP+1 }, - { "milter-version", OPTION_MILTER_VERSION, N_("NUMBER"), 0, + { "milter-version", OPTION_MILTER_VERSION, N_("VER"), 0, N_("Force using the given Milter protocol version number"), GRP+1 }, + { "milter-actions", OPTION_MILTER_ACTS, N_("BITMASK"), 0, + N_("Force the given Milter actions"), GRP+1 }, + { "milter-proto", OPTION_MILTER_PROTO, N_("BITMASK"), 0, + N_("Set Milter protocol capabilities"), GRP+1 }, #undef GRP #define GRP 20 @@ -343,6 +353,8 @@ static struct argp_option options[] = { { "verbose", 'v', NULL, 0, N_("Increase verbosity level"), GRP+1 }, + { "gacopyz-log", OPTION_GACOPYZ_LOG, N_("LEVEL"), 0, + N_("Set Gacopyz log level"), GRP+1 }, #undef GRP #define GRP 40 @@ -369,6 +381,31 @@ char *trace_name = NULL; int append; int statedir_option; +static unsigned long +parse_version (char *arg, struct argp_state *state) +{ + char *p; + unsigned long maj, min, pat; + + maj = strtoul (arg, &p, 0); + if (*p == 0) + return maj; + else if (*p == '.') + { + min = strtoul (p + 1, &p, 0); + if (*p == '.') + { + pat = strtoul (p + 1, &p, 0); + if (*p == 0) + return GACOPYZ_SM_MKVER (maj, min, pat); + } + else if (*p == 0) + return GACOPYZ_SM_MKVER (maj, min, 0); + } + argp_error (state, _("invalid version syntax (near %s)"), p); + return 0; +} + static error_t parse_opt (int key, char *arg, struct argp_state *state) { @@ -392,11 +429,19 @@ parse_opt (int key, char *arg, struct argp_state *state) break; default: - mu_error (_("unsupported mode")); - exit (EX_USAGE); |