146 #ifdef STRCASECMP_IN_STRINGS_H
181 #define PSC_SMTPD_HAVE_PUSH_BACK(state) (0)
182 #define PSC_SMTPD_PUSH_BACK_CHAR(state, ch) \
183 vstream_ungetc((state)->smtp_client_stream, (ch))
184 #define PSC_SMTPD_NEXT_CHAR(state) \
185 VSTREAM_GETC((state)->smtp_client_stream)
187 #define PSC_SMTPD_BUFFER_EMPTY(state) \
188 (!PSC_SMTPD_HAVE_PUSH_BACK(state) \
189 && vstream_peek((state)->smtp_client_stream) <= 0)
191 #define PSC_SMTPD_PEEK_DATA(state) \
192 vstream_peek_data((state)->smtp_client_stream)
193 #define PSC_SMTPD_PEEK_LEN(state) \
194 vstream_peek((state)->smtp_client_stream)
199 static char *psc_smtpd_greeting;
200 static char *psc_smtpd_helo_reply;
201 static char *psc_smtpd_ehlo_reply_plain;
202 static char *psc_smtpd_ehlo_reply_tls;
203 static char *psc_smtpd_timeout_reply;
204 static char *psc_smtpd_421_reply;
209 static void psc_smtpd_time_event(
int,
void *);
210 static void psc_smtpd_read_event(
int,
void *);
220 #define PSC_RESUME_SMTP_CMD_EVENTS(state) do { \
221 PSC_READ_EVENT_REQUEST2(vstream_fileno((state)->smtp_client_stream), \
222 psc_smtpd_read_event, psc_smtpd_time_event, \
223 (void *) (state), PSC_EFF_CMD_TIME_LIMIT); \
224 if (!PSC_SMTPD_BUFFER_EMPTY(state)) \
225 psc_smtpd_read_event(EVENT_READ, (void *) state); \
228 #define PSC_SUSPEND_SMTP_CMD_EVENTS(state) \
229 PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
230 psc_smtpd_time_event, (void *) (state));
235 #define PSC_SMTPD_ESCAPE_TEXT(dest, src, src_len, max_len) do { \
236 ssize_t _s_len = (src_len); \
237 ssize_t _m_len = (max_len); \
238 (void) escape((dest), (src), _s_len < _m_len ? _s_len : _m_len); \
244 #define PSC_SMTPD_NEXT_TOKEN(ptr) mystrtok(&(ptr), " ")
249 static MAPS *psc_ehlo_discard_maps;
250 static int psc_ehlo_discard_mask;
255 static DICT *psc_cmd_filter;
266 #define PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, event, reply) do { \
267 PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
268 (event), (void *) (state)); \
269 PSC_DROP_SESSION_STATE((state), (reply)); \
272 #define PSC_CLEAR_EVENT_HANGUP(state, event) do { \
273 PSC_CLEAR_EVENT_REQUEST(vstream_fileno((state)->smtp_client_stream), \
274 (event), (void *) (state)); \
275 psc_hangup_event(state); \
280 static int psc_helo_cmd(
PSC_STATE *state,
char *args)
298 static void psc_smtpd_format_ehlo_reply(
VSTRING *buf,
int discard_mask
301 const char *myname =
"psc_smtpd_format_ehlo_reply";
307 #define PSC_EHLO_APPEND(save, buf, fmt) do { \
309 vstring_sprintf_append((buf), (fmt)); \
312 #define PSC_EHLO_APPEND1(save, buf, fmt, arg1) do { \
314 vstring_sprintf_append((buf), (fmt), (arg1)); \
331 #ifdef TODO_SASL_AUTH
333 && (!var_psc_tls_auth_only || (discard_mask & EHLO_MASK_STARTTLS))) {
353 static int psc_ehlo_cmd(
PSC_STATE *state,
char *args)
356 const char *ehlo_words;
373 if (psc_ehlo_discard_maps != 0
376 && (discard_mask =
ehlo_mask(ehlo_words)) != psc_ehlo_discard_mask) {
378 msg_info(
"[%s]%s: discarding EHLO keywords: %s",
382 psc_smtpd_format_ehlo_reply(
psc_temp, discard_mask);
385 }
else if (psc_ehlo_discard_maps && psc_ehlo_discard_maps->
error) {
389 reply = psc_smtpd_ehlo_reply_tls;
392 reply = psc_smtpd_ehlo_reply_plain;
400 static void psc_starttls_resume(
int unused_event,
void *context)
402 const char *myname =
"psc_starttls_resume";
412 #ifdef TODO_SASL_AUTH
426 static int psc_starttls_cmd(
PSC_STATE *state,
char *args)
428 const char *myname =
"psc_starttls_cmd";
438 "554 5.5.1 Error: TLS already active\r\n"));
441 "502 5.5.1 Error: command not implemented\r\n"));
453 static char *psc_extract_addr(
VSTRING *result,
const char *
string)
455 const unsigned char *cp = (
const unsigned char *)
string;
470 while (*cp && *cp ==
' ')
484 if (!inquote && *cp == stop_at)
489 if (*cp ==
'\\' && *++cp == 0)
501 if (*addr ==
'@' && (colon = strchr(addr,
':')) != 0)
508 static int psc_mail_cmd(
PSC_STATE *state,
char *args)
519 "503 5.5.1 Error: send HELO/EHLO first\r\n"));
522 "503 5.5.1 Error: nested MAIL command\r\n"));
523 if (args == 0 || (colon = strchr(args,
':')) == 0)
525 "501 5.5.4 Syntax: MAIL FROM:<address>\r\n"));
526 if ((addr = psc_extract_addr(
psc_temp, colon + 1)) == 0)
528 "501 5.1.7 Bad sender address syntax\r\n"));
535 static char *psc_soften_reply(
const char *reply)
551 static int psc_rcpt_cmd(
PSC_STATE *state,
char *args)
562 "503 5.5.1 Error: need MAIL command\r\n"));
563 if (args == 0 || (colon = strchr(args,
':')) == 0)
565 "501 5.5.4 Syntax: RCPT TO:<address>\r\n"));
566 if ((addr = psc_extract_addr(
psc_temp, colon + 1)) == 0)
568 "501 5.1.3 Bad recipient address syntax\r\n"));
569 msg_info(
"NOQUEUE: reject: RCPT from [%s]:%s: %.*s; "
570 "from=<%s>, to=<%s>, proto=%s, helo=<%s>",
582 static int psc_data_cmd(
PSC_STATE *state,
char *args)
590 "501 5.5.4 Syntax: DATA\r\n"));
593 "503 5.5.1 Error: need RCPT command\r\n"));
604 "554 5.5.1 Error: no valid recipients\r\n"));
609 static int psc_rset_cmd(
PSC_STATE *state,
char *unused_args)
617 static int psc_noop_cmd(
PSC_STATE *state,
char *unused_args)
624 static int psc_vrfy_cmd(
PSC_STATE *state,
char *args)
633 "501 5.5.4 Syntax: VRFY address\r\n"));
636 "502 5.5.1 VRFY command is disabled\r\n"));
642 static int psc_etrn_cmd(
PSC_STATE *state,
char *args)
651 "503 5.5.1 Error: send HELO/EHLO first\r\n"));
654 "500 Syntax: ETRN domain\r\n"));
655 return (
PSC_SEND_REPLY(state,
"458 Unable to queue messages\r\n"));
660 static int psc_quit_cmd(
PSC_STATE *state,
char *unused_args)
662 const char *myname =
"psc_quit_cmd";
665 "221 2.0.0 Bye\r\n");
672 static void psc_smtpd_time_event(
int event,
void *context)
674 const char *myname =
"psc_smtpd_time_event";
678 msg_info(
"%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
684 msg_info(
"COMMAND TIME LIMIT from [%s]:%s after %s",
687 psc_smtpd_timeout_reply);
699 #define PSC_SMTPD_CMD_FLAG_NONE (0)
700 #define PSC_SMTPD_CMD_FLAG_ENABLE (1<<0)
701 #define PSC_SMTPD_CMD_FLAG_DESTROY (1<<1)
702 #define PSC_SMTPD_CMD_FLAG_PRE_TLS (1<<2)
703 #define PSC_SMTPD_CMD_FLAG_SUSPEND (1<<3)
726 static void psc_smtpd_read_event(
int event,
void *context)
728 const char *myname =
"psc_smtpd_read_event";
737 const char *saved_where;
739 #define PSC_SMTPD_CMD_ST_ANY 0
740 #define PSC_SMTPD_CMD_ST_CR 1
741 #define PSC_SMTPD_CMD_ST_CR_LF 2
743 static const struct cmd_trans cmd_trans[] = {
748 const struct cmd_trans *transp;
749 char *cmd_buffer_ptr;
755 msg_info(
"%s: sq=%d cq=%d event %d on smtp socket %d from [%s]:%s flags=%s",
801 msg_info(
"COMMAND LENGTH LIMIT from [%s]:%s after %s",
804 psc_smtpd_421_reply);
816 for (transp = cmd_trans; transp->state != state->
read_state; transp++)
817 if (transp->want == 0)
818 msg_panic(
"%s: command_read: unknown state: %d",
820 if (ch == transp->want)
822 else if (ch == cmd_trans[0].want)
840 msg_info(
"BARE NEWLINE from [%s]:%s after %s",
851 psc_smtpd_time_event,
852 "521 5.5.1 Protocol error\r\n");
856 "550 5.5.1 Protocol error\r\n");
867 msg_panic(
"%s: unknown bare_newline action value %d",
892 if (psc_cmd_filter != 0) {
898 msg_info(
"[%s]:%s: replacing command \"%.100s\" with \"%.100s\"",
902 }
else if (psc_cmd_filter->
error != 0) {
903 msg_fatal(
"%s:%s lookup error for \"%.100s\"",
904 psc_cmd_filter->
type, psc_cmd_filter->
name, cp);
939 saved_where = state->
where;
941 for (cmdp = command_table; cmdp->
name != 0; cmdp++) {
949 && cmdp->
action != psc_quit_cmd) {
963 strlen(cmd_buffer_ptr), 100);
964 msg_info(
"NON-SMTP COMMAND from [%s]:%s after %s: %.100s %s",
976 psc_smtpd_time_event,
977 "521 5.7.0 Error: I can break rules, too. Goodbye.\r\n");
981 "550 5.5.1 Protocol error\r\n");
992 msg_panic(
"%s: unknown non_smtp_command action value %d",
1002 msg_info(
"COMMAND PIPELINING from [%s]:%s after %.100s: %s",
1013 psc_smtpd_time_event,
1014 "521 5.5.1 Protocol error\r\n");
1018 "550 5.5.1 Protocol error\r\n");
1029 msg_panic(
"%s: unknown pipelining action value %d",
1039 if (cmdp->
action == psc_rcpt_cmd) {
1064 && cmdp->
action != psc_quit_cmd) {
1065 msg_info(
"COMMAND COUNT LIMIT from [%s]:%s after %s",
1068 psc_smtpd_421_reply);
1074 "502 5.5.2 Error: command not recognized\r\n");
1079 "530 5.7.0 Must issue a STARTTLS command first\r\n");
1081 write_stat = cmdp->
action(state, cmd_buffer_ptr);
1089 if (write_stat < 0) {
1120 static char *myname =
"psc_smtpd_tests";
1161 psc_smtpd_read_event, psc_smtpd_time_event,
1201 msg_warn(
"%s: unsupported TLS level \"%s\", using \"encrypt\"",
1217 #ifdef TODO_SASL_AUTH
1225 psc_smtpd_format_ehlo_reply(
psc_temp, psc_ehlo_discard_mask);
1228 psc_smtpd_format_ehlo_reply(
psc_temp,
1229 psc_ehlo_discard_mask | EHLO_MASK_STARTTLS);
PSC_CLIENT_INFO * client_info
#define PSC_SMTPD_CMD_UNIMPL
#define PSC_RESUME_SMTP_CMD_EVENTS(state)
#define PSC_EHLO_APPEND1(save, buf, fmt, arg1)
#define PSC_SMTPD_CMD_ST_CR
#define PSC_STATE_FLAG_NSMTP_TODO
char * mystrdup(const char *str)
#define EHLO_MASK_STARTTLS
time_t expire_time[PSC_TINDX_COUNT]
#define EHLO_MASK_SMTPUTF8
#define PSC_FAIL_SESSION_STATE(state, bits)
NORETURN msg_panic(const char *fmt,...)
bool var_disable_vrfy_cmd
bool var_psc_helo_required
#define PSC_STATE_FLAG_PIPEL_SKIP
#define PSC_STATE_MASK_BARLF_TODO_PASS_FAIL
STRING_LIST * psc_forbid_cmds
#define PSC_SUSPEND_SMTP_CMD_EVENTS(state)
#define PSC_STATE_FLAG_PIPEL_PASS
#define PSC_STATE_MASK_NSMTP_TODO_SKIP
#define EHLO_MASK_8BITMIME
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
#define PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL
DICT * dict_open(const char *, int, int)
#define PSC_TIME_STAMP_DISABLED
void psc_starttls_open(PSC_STATE *, EVENT_NOTIFY_FN)
void psc_expand_init(void)
int psc_check_queue_length
void psc_smtpd_init(void)
#define PSC_UNFAIL_SESSION_STATE(state, bits)
#define PSC_SMTPD_CMD_FLAG_DESTROY
#define DICT_FLAG_FOLD_FIX
#define PSC_UNPASS_SESSION_STATE(state, bits)
char * var_psc_cmd_filter
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
#define VSTRING_TERMINATE(vp)
#define PSC_SMTPD_CMD_FLAG_ENABLE
const char * str_ehlo_mask(int mask_bits)
#define PSC_EFF_CMD_TIME_LIMIT
#define PSC_STATE_FLAG_SMTPD_X21
#define string_list_match
#define VSTRING_ADDCH(vp, ch)
#define PSC_BEGIN_TESTS(state, name)
#define PSC_STRING_UPDATE(str, text)
void psc_smtpd_tests(PSC_STATE *state)
bool var_broken_auth_clients
#define PSC_CLIENT_ADDR_PORT(state)
#define PSC_STATE_MASK_SMTPD_TODO
const char * psc_maps_find(MAPS *, const char *, int)
MAPS * maps_create(const char *title, const char *map_names, int dict_flags)
#define PSC_ENFORCE_SESSION_STATE(state, reply)
#define PSC_SMTPD_BUFFER_EMPTY(state)
#define PSC_CLEAR_EVENT_HANGUP(state, event)
#define VSTRING_RESET(vp)
#define PSC_STATE_FLAG_NSMTP_PASS
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
void psc_hangup_event(PSC_STATE *)
#define PSC_SKIP_SESSION_STATE(state, what, bits)
#define PSC_STATE_FLAG_BARLF_SKIP
#define PSC_SMTPD_CMD_FLAG_SUSPEND
#define PSC_SMTPD_PEEK_DATA(state)
#define PSC_SMTPD_CMD_ST_CR_LF
void psc_smtpd_pre_jail_init(void)
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
char * var_psc_ehlo_dis_maps
#define PSC_SMTPD_NEXT_TOKEN(ptr)
#define PSC_SMTPD_NEXT_CHAR(state)
NORETURN msg_fatal(const char *fmt,...)
#define PSC_STATE_MASK_PIPEL_TODO_SKIP
int(* action)(PSC_STATE *, char *)
char * var_psc_ehlo_dis_words
#define PSC_STATE_FLAG_BARLF_FAIL
int tls_level_lookup(const char *)
#define PSC_STATE_MASK_BARLF_TODO_SKIP
#define PSC_CLEAR_EVENT_DROP_SESSION_STATE(state, event, reply)
char * var_psc_rej_footer
#define VAR_PSC_TLS_LEVEL
#define PSC_SMTPD_CMD_FLAG_NONE
char * var_psc_forbid_cmds
int strcasecmp(const char *s1, const char *s2)
#define PSC_STATE_FLAG_USING_TLS
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
#define VAR_PSC_EHLO_DIS_MAPS
#define PSC_STATE_FLAG_PREGR_FAIL
#define PSC_SMTPD_ESCAPE_TEXT(dest, src, src_len, max_len)
#define PSC_PASS_SESSION_STATE(state, what, bits)
#define vstream_fileno(vp)
#define PSC_STRING_RESET(str)
#define PSC_STATE_FLAG_BARLF_PASS
#define PSC_SMTPD_PEEK_LEN(state)
#define EHLO_MASK_ENHANCEDSTATUSCODES
#define PSC_READ_EVENT_REQUEST2(fd, read_act, time_act, context, timeout)
#define PSC_STATE_FLAG_PIPEL_TODO
#define PSC_STATE_FLAG_PIPEL_FAIL
char * printable(char *string, int replacement)
#define PSC_STATE_FLAG_NSMTP_SKIP
int psc_post_queue_length
#define PSC_EHLO_APPEND(save, buf, fmt)
bool var_psc_disable_vrfy
const char * psc_dict_get(DICT *, const char *)
#define PSC_STATE_FLAG_BARLF_TODO
#define PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL
const char * psc_print_state_flags(int, const char *)
#define PSC_SMTPD_CMD_ST_ANY
VSTREAM * smtp_client_stream
#define PSC_SMTPD_CMD_FLAG_PRE_TLS
#define PSC_STATE_FLAG_NSMTP_FAIL
int ehlo_mask(const char *mask_str)
void msg_info(const char *fmt,...)