mirror of
https://github.com/vdukhovni/postfix
synced 2025-09-03 07:35:20 +00:00
snapshot-19991115
This commit is contained in:
@@ -3170,8 +3170,56 @@ Apologies for any names omitted.
|
|||||||
Bugfix: LDAP lookup timeout settings were ignored. Patch
|
Bugfix: LDAP lookup timeout settings were ignored. Patch
|
||||||
by John Hensley. File: util/dict_ldap.c.
|
by John Hensley. File: util/dict_ldap.c.
|
||||||
|
|
||||||
19991110
|
19991108
|
||||||
|
|
||||||
|
Bugfix: when doing a fresh install, INSTALL.sh didn't set
|
||||||
|
main.cf:mail_owner properly (Simon J. Mudd).
|
||||||
|
|
||||||
|
19991109
|
||||||
|
|
||||||
|
Bugfix: when doing a fresh install, INSTALL.sh no longer
|
||||||
|
worked (missing main.cf file). Fix: add "-c" argument to
|
||||||
|
the postmap commands (Lars Hecking @ nmrc.ucc.ie).
|
||||||
|
|
||||||
|
Documentation: removed spurious "do not edit" comments from
|
||||||
|
the sample pcre and regexp configuration files.
|
||||||
|
|
||||||
|
19991110-13
|
||||||
|
|
||||||
Code cleanup: greatly simplified the SMTPD command parser
|
Code cleanup: greatly simplified the SMTPD command parser
|
||||||
and somewhat simplified the code that groks RFC 822-style
|
and somewhat simplified the code that groks RFC 822-style
|
||||||
address syntax in MAIL FROM and RCPT TO commands.
|
address syntax in MAIL FROM and RCPT TO commands.
|
||||||
|
|
||||||
|
New parameter: strict_rfc821_envelopes (default: no) to
|
||||||
|
reject RFC 822 address forms (with comments etc.) in SMTP
|
||||||
|
envelopes. By default, the Postfix SMTP server only logs
|
||||||
|
a warning.
|
||||||
|
|
||||||
|
19991113
|
||||||
|
|
||||||
|
Oops, also updated the SMTP VRFY code in the light of
|
||||||
|
changes to the SMTPD command parser.
|
||||||
|
|
||||||
|
Cleanup: the local delivery agent now explicitly rejects
|
||||||
|
recipients with an empty username.
|
||||||
|
|
||||||
|
19991114
|
||||||
|
|
||||||
|
Workaround: with some gawk versions, postconf/extract.awk
|
||||||
|
reportedly returns a non-zero exit status upon success.
|
||||||
|
Added an explicit exit(0) statement.
|
||||||
|
|
||||||
|
19991115
|
||||||
|
|
||||||
|
Feature: DNS TXT record lookup support, based on initial
|
||||||
|
code by Simon J Mudd. File: dns/dns_lookup.c.
|
||||||
|
|
||||||
|
Feature: RBL TXT record lookups, based on initial code by
|
||||||
|
Simon J Mudd. File: smtpd/smtpd_check.c.
|
||||||
|
|
||||||
|
Feature: permit_auth_destination restriction based on code
|
||||||
|
by Jesper Skriver @ skriver.dk.
|
||||||
|
|
||||||
|
Code cleanup: the transport table now can override local
|
||||||
|
deliveries. Postfix no longer uses the "empty next-hop
|
||||||
|
hostname hack" to remember that a destination is local.
|
||||||
|
@@ -6,6 +6,9 @@
|
|||||||
PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc
|
PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc
|
||||||
umask 022
|
umask 022
|
||||||
|
|
||||||
|
# Workaround, should edit main.cf in place.
|
||||||
|
trap 'rm -f ./main.cf; exit' 0 1 2 3 15
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
Warning: this script replaces existing sendmail or Postfix programs.
|
Warning: this script replaces existing sendmail or Postfix programs.
|
||||||
@@ -138,7 +141,14 @@ do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
bin/postmap -c ./conf -q "$owner" unix:passwd.byname >/dev/null || {
|
# Workaround, should edit main.cf in place.
|
||||||
|
test -f $config_directory/main.cf || {
|
||||||
|
echo "mail_owner = $owner" >./main.cf
|
||||||
|
echo "myhostname = xx.yy" >>./main.cf
|
||||||
|
alt_main="-c ."
|
||||||
|
}
|
||||||
|
|
||||||
|
bin/postmap $alt_main -q "$owner" unix:passwd.byname >/dev/null || {
|
||||||
echo "$owner needs an entry in the passwd file" 1>&2
|
echo "$owner needs an entry in the passwd file" 1>&2
|
||||||
echo "Remember, $owner must have a dedicated user id and group id." 1>&2
|
echo "Remember, $owner must have a dedicated user id and group id." 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -146,7 +156,7 @@ bin/postmap -c ./conf -q "$owner" unix:passwd.byname >/dev/null || {
|
|||||||
|
|
||||||
case $setgid in
|
case $setgid in
|
||||||
no) ;;
|
no) ;;
|
||||||
*) bin/postmap -c ./conf -q "$setgid" unix:group.byname >/dev/null || {
|
*) bin/postmap $alt_main -q "$setgid" unix:group.byname >/dev/null || {
|
||||||
echo "$setgid needs an entry in the group file" 1>&2
|
echo "$setgid needs an entry in the group file" 1>&2
|
||||||
echo "Remember, $setgid must have a dedicated group id." 1>&2
|
echo "Remember, $setgid must have a dedicated group id." 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
@@ -239,6 +249,16 @@ compare_or_replace a+x,go-w $postfix_script $config_directory/postfix-script ||
|
|||||||
|
|
||||||
case $manpages in
|
case $manpages in
|
||||||
no) ;;
|
no) ;;
|
||||||
*) test -d $manpages || mkdir -p $manpages || exit 1
|
*) (
|
||||||
(cd man && tar cf - man?) | (cd $manpages && tar xf -)
|
cd man || exit 1
|
||||||
|
for dir in man?
|
||||||
|
do mkdir -p $manpages/$dir || exit 1
|
||||||
|
done
|
||||||
|
for file in man?/*
|
||||||
|
do
|
||||||
|
rm -f $manpages/$file
|
||||||
|
cp $file $manpages/$file || exit 1
|
||||||
|
chmod 644 $manpages/$file || exit 1
|
||||||
|
done
|
||||||
|
)
|
||||||
esac
|
esac
|
||||||
|
@@ -22,6 +22,9 @@ update printfck:
|
|||||||
|
|
||||||
printfck: update
|
printfck: update
|
||||||
|
|
||||||
|
install: update
|
||||||
|
sh INSTALL.sh
|
||||||
|
|
||||||
depend clean:
|
depend clean:
|
||||||
set -e; for i in $(DIRS); do \
|
set -e; for i in $(DIRS); do \
|
||||||
(set -e; echo "[$$i]"; cd $$i; $(MAKE) $@) || exit 1; \
|
(set -e; echo "[$$i]"; cd $$i; $(MAKE) $@) || exit 1; \
|
||||||
|
@@ -191,8 +191,10 @@ smtpd_sender_restrictions =
|
|||||||
# reject_invalid_hostname: reject HELO hostname with bad syntax.
|
# reject_invalid_hostname: reject HELO hostname with bad syntax.
|
||||||
# reject_unknown_hostname: reject HELO hostname without DNS A or MX record.
|
# reject_unknown_hostname: reject HELO hostname without DNS A or MX record.
|
||||||
# reject_unknown_sender_domain: reject sender domain without A or MX record.
|
# reject_unknown_sender_domain: reject sender domain without A or MX record.
|
||||||
# check_relay_domains: permit only mail from/to domains in $relay_domains.
|
# check_relay_domains: permit only mail from/to domains in $relay_domains
|
||||||
# reject_unauth_destination: reject mail not to domains in $relay_domains.
|
or to the local machine.
|
||||||
|
# permit_auth_destination: permit mail to self or to $relay_domains.
|
||||||
|
# reject_unauth_destination: reject mail not to self or to $relay_domains.
|
||||||
# reject_unauth_pipelining: reject mail from improperly pipelining spamware
|
# reject_unauth_pipelining: reject mail from improperly pipelining spamware
|
||||||
# permit_mx_backup: accept mail for sites that list me as MX host.
|
# permit_mx_backup: accept mail for sites that list me as MX host.
|
||||||
# reject_unknown_recipient_domain: reject domains without A or MX record.
|
# reject_unknown_recipient_domain: reject domains without A or MX record.
|
||||||
|
@@ -100,6 +100,7 @@
|
|||||||
#include <stdlib.h> /* BSDI stdarg.h uses abort() */
|
#include <stdlib.h> /* BSDI stdarg.h uses abort() */
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/* Utility library. */
|
/* Utility library. */
|
||||||
|
|
||||||
@@ -107,6 +108,7 @@
|
|||||||
#include <vstring.h>
|
#include <vstring.h>
|
||||||
#include <msg.h>
|
#include <msg.h>
|
||||||
#include <valid_hostname.h>
|
#include <valid_hostname.h>
|
||||||
|
#include <stringops.h>
|
||||||
|
|
||||||
/* DNS library. */
|
/* DNS library. */
|
||||||
|
|
||||||
@@ -246,8 +248,13 @@ static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
|
|||||||
char *rr_name, DNS_FIXED *fixed)
|
char *rr_name, DNS_FIXED *fixed)
|
||||||
{
|
{
|
||||||
char temp[DNS_NAME_LEN];
|
char temp[DNS_NAME_LEN];
|
||||||
int data_len = fixed->length;
|
int data_len;
|
||||||
unsigned pref = 0;
|
unsigned pref = 0;
|
||||||
|
unsigned char *src;
|
||||||
|
unsigned char *dst;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
#define MIN2(a, b) ((unsigned)(a) < (unsigned)(b) ? (a) : (b))
|
||||||
|
|
||||||
if (pos + fixed->length > reply->end)
|
if (pos + fixed->length > reply->end)
|
||||||
return (0);
|
return (0);
|
||||||
@@ -287,6 +294,14 @@ static DNS_RR *dns_get_rr(DNS_REPLY *reply, unsigned char *pos,
|
|||||||
memcpy(temp, pos, fixed->length);
|
memcpy(temp, pos, fixed->length);
|
||||||
data_len = fixed->length;
|
data_len = fixed->length;
|
||||||
break;
|
break;
|
||||||
|
case T_TXT:
|
||||||
|
data_len = MIN2(fixed->length + 1, sizeof(temp));
|
||||||
|
for (src = pos, dst = temp; dst < temp + data_len - 1; /* void */ ) {
|
||||||
|
ch = *src++;
|
||||||
|
*dst++ = (ISPRINT(ch) ? ch : ' ');
|
||||||
|
}
|
||||||
|
*dst = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return (dns_rr_create(rr_name, fixed, pref, temp, data_len));
|
return (dns_rr_create(rr_name, fixed, pref, temp, data_len));
|
||||||
}
|
}
|
||||||
|
@@ -55,6 +55,7 @@ static void print_rr(DNS_RR *rr)
|
|||||||
case T_MR:
|
case T_MR:
|
||||||
case T_NS:
|
case T_NS:
|
||||||
case T_PTR:
|
case T_PTR:
|
||||||
|
case T_TXT:
|
||||||
printf("%s: %s\n", dns_strtype(rr->type), rr->data);
|
printf("%s: %s\n", dns_strtype(rr->type), rr->data);
|
||||||
break;
|
break;
|
||||||
case T_MX:
|
case T_MX:
|
||||||
|
@@ -208,11 +208,11 @@ extern char *var_db_type;
|
|||||||
extern char *var_always_bcc;
|
extern char *var_always_bcc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Standards violation: permit RFC 822-style addresses in SMTP commands.
|
* Standards violation: allow/permit RFC 822-style addresses in SMTP commands.
|
||||||
*/
|
*/
|
||||||
#define VAR_ALLOW_RFC822_ENV "allow_rfc822_envelopes"
|
#define VAR_STRICT_RFC821_ENV "strict_rfc821_envelopes"
|
||||||
#define DEF_ALLOW_RFC822_ENV 1
|
#define DEF_STRICT_RFC821_ENV 0
|
||||||
extern bool var_allow_rfc822_envelopes;
|
extern bool var_strict_rfc821_env;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* trivial rewrite/resolve service: mapping tables.
|
* trivial rewrite/resolve service: mapping tables.
|
||||||
@@ -773,6 +773,7 @@ extern int var_non_fqdn_code;
|
|||||||
#define DEF_UNK_ADDR_CODE 450
|
#define DEF_UNK_ADDR_CODE 450
|
||||||
extern int var_unk_addr_code;
|
extern int var_unk_addr_code;
|
||||||
|
|
||||||
|
#define PERMIT_AUTH_DEST "permit_auth_destination"
|
||||||
#define REJECT_UNAUTH_DEST "reject_unauth_destination"
|
#define REJECT_UNAUTH_DEST "reject_unauth_destination"
|
||||||
#define CHECK_RELAY_DOMAINS "check_relay_domains"
|
#define CHECK_RELAY_DOMAINS "check_relay_domains"
|
||||||
#define VAR_RELAY_CODE "relay_domains_reject_code"
|
#define VAR_RELAY_CODE "relay_domains_reject_code"
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* Version of this program.
|
* Version of this program.
|
||||||
*/
|
*/
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "Snapshot-19991110"
|
#define DEF_MAIL_VERSION "Snapshot-19991115"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
@@ -537,20 +537,30 @@ reject_unauth_destination</b>
|
|||||||
|
|
||||||
<dt> <b>check_relay_domains</b> <dd> Permit the request when the
|
<dt> <b>check_relay_domains</b> <dd> Permit the request when the
|
||||||
client hostname matches <a href="#relay_domains">$relay_domains</a>,
|
client hostname matches <a href="#relay_domains">$relay_domains</a>,
|
||||||
or when the resolved destination address matches <a href="#relay_domains">
|
or when the resolved destination address matches the the local
|
||||||
$relay_domains</a>, otherwise reject. The <b>relay_domains_reject_code</b>
|
machine or <a href="#relay_domains"> $relay_domains</a>, otherwise
|
||||||
parameter specifies the response code for rejected requests (default:
|
reject the request. The <b>relay_domains_reject_code</b> parameter
|
||||||
|
specifies the response code for rejected requests (default:
|
||||||
<b>554</b>).
|
<b>554</b>).
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
|
<a name="permit_auth_destination">
|
||||||
|
|
||||||
|
<dt> <b>permit_auth_destination</b> <dd> Ignore the client hostname.
|
||||||
|
Permit the request when the resolved destination address matches
|
||||||
|
the local machine or <a href="#relay_domains"> $relay_domains</a>.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
<a name="reject_unauth_destination">
|
<a name="reject_unauth_destination">
|
||||||
|
|
||||||
<dt> <b>reject_unauth_destination</b> <dd> Ignore the client
|
<dt> <b>reject_unauth_destination</b> <dd> Ignore the client
|
||||||
hostname. Reject the request when the resolved destination address
|
hostname. Reject the request when the resolved destination address
|
||||||
does not match <a href="#relay_domains"> $relay_domains</a>. The
|
does not match the local machine or <a href="#relay_domains">
|
||||||
<b>relay_domains_reject_code</b> parameter specifies the response
|
$relay_domains</a>. The <b>relay_domains_reject_code</b> parameter
|
||||||
code for rejected requests (default: <b>554</b>).
|
specifies the response code for rejected requests (default:
|
||||||
|
<b>554</b>).
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
|
@@ -221,6 +221,13 @@ int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr)
|
|||||||
state.msg_attr.extension = 0;
|
state.msg_attr.extension = 0;
|
||||||
state.msg_attr.unmatched = state.msg_attr.extension;
|
state.msg_attr.unmatched = state.msg_attr.extension;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not allow null usernames.
|
||||||
|
*/
|
||||||
|
if (state.msg_attr.user[0] == 0)
|
||||||
|
return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
|
||||||
|
"null username in %s", state.msg_attr.recipient));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run the recipient through the delivery switch.
|
* Run the recipient through the delivery switch.
|
||||||
*/
|
*/
|
||||||
|
@@ -62,6 +62,7 @@
|
|||||||
#include <rewrite_clnt.h>
|
#include <rewrite_clnt.h>
|
||||||
#include <tok822.h>
|
#include <tok822.h>
|
||||||
#include <mail_params.h>
|
#include <mail_params.h>
|
||||||
|
#include <resolve_local.h>
|
||||||
|
|
||||||
/* Application-specific. */
|
/* Application-specific. */
|
||||||
|
|
||||||
@@ -138,7 +139,7 @@ int deliver_resolve_tree(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr
|
|||||||
* ugly code to force local recursive alias expansions on a host with no
|
* ugly code to force local recursive alias expansions on a host with no
|
||||||
* authority over the local domain, but that code was just too unclean.
|
* authority over the local domain, but that code was just too unclean.
|
||||||
*/
|
*/
|
||||||
if (VSTRING_LEN(reply.nexthop) == 0) {
|
if (resolve_local(STR(reply.nexthop))) {
|
||||||
status = deliver_recipient(state, usr_attr);
|
status = deliver_recipient(state, usr_attr);
|
||||||
} else {
|
} else {
|
||||||
status = deliver_indirect(state);
|
status = deliver_indirect(state);
|
||||||
|
@@ -18,3 +18,7 @@
|
|||||||
print | "sort -u >bool_table.h"
|
print | "sort -u >bool_table.h"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Workaround for broken gawk versions.
|
||||||
|
|
||||||
|
END { exit(0); }
|
||||||
|
@@ -110,6 +110,7 @@
|
|||||||
#include <deliver_completed.h>
|
#include <deliver_completed.h>
|
||||||
#include <mail_addr_find.h>
|
#include <mail_addr_find.h>
|
||||||
#include <opened.h>
|
#include <opened.h>
|
||||||
|
#include <resolve_local.h>
|
||||||
|
|
||||||
/* Client stubs. */
|
/* Client stubs. */
|
||||||
|
|
||||||
@@ -476,7 +477,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
/*
|
/*
|
||||||
* Bounce mail to non-existent users in virtual domains.
|
* Bounce mail to non-existent users in virtual domains.
|
||||||
*/
|
*/
|
||||||
if (VSTRING_LEN(reply.nexthop) > 0
|
if (!resolve_local(STR(reply.nexthop))
|
||||||
&& qmgr_virtual != 0
|
&& qmgr_virtual != 0
|
||||||
&& (at = strrchr(recipient->address, '@')) != 0) {
|
&& (at = strrchr(recipient->address, '@')) != 0) {
|
||||||
domain = lowercase(mystrdup(at + 1));
|
domain = lowercase(mystrdup(at + 1));
|
||||||
@@ -515,7 +516,7 @@ static void qmgr_message_resolve(QMGR_MESSAGE *message)
|
|||||||
* job requires knowledge of local aliases. Yuck! I don't want to
|
* job requires knowledge of local aliases. Yuck! I don't want to
|
||||||
* duplicate delivery-agent specific knowledge in the queue manager.
|
* duplicate delivery-agent specific knowledge in the queue manager.
|
||||||
*/
|
*/
|
||||||
if (VSTRING_LEN(reply.nexthop) == 0) {
|
if (resolve_local(STR(reply.nexthop))) {
|
||||||
vstring_strcpy(reply.nexthop, STR(reply.recipient));
|
vstring_strcpy(reply.nexthop, STR(reply.recipient));
|
||||||
(void) split_at_right(STR(reply.nexthop), '@');
|
(void) split_at_right(STR(reply.nexthop), '@');
|
||||||
#if 0
|
#if 0
|
||||||
|
@@ -52,6 +52,12 @@
|
|||||||
/* this program. See the Postfix \fBmain.cf\fR file for syntax details
|
/* this program. See the Postfix \fBmain.cf\fR file for syntax details
|
||||||
/* and for default values. Use the \fBpostfix reload\fR command after
|
/* and for default values. Use the \fBpostfix reload\fR command after
|
||||||
/* a configuration change.
|
/* a configuration change.
|
||||||
|
/* .SH "Compatibility controls"
|
||||||
|
/* .ad
|
||||||
|
/* .fi
|
||||||
|
/* .IP \fBstrict_rfc821_envelopes\fR
|
||||||
|
/* Disallow non-RFC 821 style addresses in envelopes. For example,
|
||||||
|
/* allow RFC822-style address forms with comments, like Sendmail does.
|
||||||
/* .SH Miscellaneous
|
/* .SH Miscellaneous
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@@ -284,6 +290,7 @@ char *var_always_bcc;
|
|||||||
char *var_error_rcpt;
|
char *var_error_rcpt;
|
||||||
int var_smtpd_delay_reject;
|
int var_smtpd_delay_reject;
|
||||||
char *var_rest_classes;
|
char *var_rest_classes;
|
||||||
|
int var_strict_rfc821_env;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global state, for stand-alone mode queue file cleanup. When this is
|
* Global state, for stand-alone mode queue file cleanup. When this is
|
||||||
@@ -291,17 +298,23 @@ char *var_rest_classes;
|
|||||||
*/
|
*/
|
||||||
char *smtpd_path;
|
char *smtpd_path;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Silly little macros.
|
||||||
|
*/
|
||||||
|
#define STR(x) vstring_str(x)
|
||||||
|
#define LEN(x) VSTRING_LEN(x)
|
||||||
|
|
||||||
/* collapse_args - put arguments together again */
|
/* collapse_args - put arguments together again */
|
||||||
|
|
||||||
static void collapse_args(int argc, SMTPD_TOKEN *argv)
|
static void collapse_args(int argc, SMTPD_TOKEN *argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 2; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
||||||
vstring_strcat(argv[1].vstrval, " ");
|
vstring_strcat(argv[0].vstrval, " ");
|
||||||
vstring_strcat(argv[1].vstrval, argv[i].strval);
|
vstring_strcat(argv[0].vstrval, argv[i].strval);
|
||||||
}
|
}
|
||||||
argv[1].strval = vstring_str(argv[1].vstrval);
|
argv[0].strval = STR(argv[0].vstrval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* helo_cmd - process HELO command */
|
/* helo_cmd - process HELO command */
|
||||||
@@ -320,7 +333,8 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
smtpd_chat_reply(state, "503 Duplicate HELO/EHLO");
|
smtpd_chat_reply(state, "503 Duplicate HELO/EHLO");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
collapse_args(argc, argv);
|
if (argc > 2)
|
||||||
|
collapse_args(argc - 1, argv + 1);
|
||||||
if (SMTPD_STAND_ALONE(state) == 0
|
if (SMTPD_STAND_ALONE(state) == 0
|
||||||
&& var_smtpd_delay_reject == 0
|
&& var_smtpd_delay_reject == 0
|
||||||
&& (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
|
&& (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
|
||||||
@@ -349,7 +363,8 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
smtpd_chat_reply(state, "503 Error: duplicate HELO/EHLO");
|
smtpd_chat_reply(state, "503 Error: duplicate HELO/EHLO");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
collapse_args(argc, argv);
|
if (argc > 2)
|
||||||
|
collapse_args(argc - 1, argv + 1);
|
||||||
if (SMTPD_STAND_ALONE(state) == 0
|
if (SMTPD_STAND_ALONE(state) == 0
|
||||||
&& var_smtpd_delay_reject == 0
|
&& var_smtpd_delay_reject == 0
|
||||||
&& (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
|
&& (err = smtpd_check_helo(state, argv[1].strval)) != 0) {
|
||||||
@@ -427,46 +442,94 @@ static void mail_open_stream(SMTPD_STATE *state)
|
|||||||
|
|
||||||
/* extract_addr - extract address from rubble */
|
/* extract_addr - extract address from rubble */
|
||||||
|
|
||||||
static VSTRING *extract_addr(SMTPD_STATE *state, VSTRING *buf)
|
static char *extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg,
|
||||||
|
int allow_empty_addr)
|
||||||
{
|
{
|
||||||
char *myname = "extract_addr";
|
char *myname = "extract_addr";
|
||||||
TOK822 *tree;
|
TOK822 *tree;
|
||||||
TOK822 *tp;
|
TOK822 *tp;
|
||||||
|
TOK822 *addr = 0;
|
||||||
int naddr;
|
int naddr;
|
||||||
int non_addr;
|
int non_addr;
|
||||||
|
char *err = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special case.
|
||||||
|
*/
|
||||||
|
#define PERMIT_EMPTY_ADDR 1
|
||||||
|
#define REJECT_EMPTY_ADDR 0
|
||||||
|
|
||||||
|
if (allow_empty_addr && strcmp(STR(arg->vstrval), "<>") == 0) {
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: empty address", myname);
|
||||||
|
VSTRING_RESET(arg->vstrval);
|
||||||
|
VSTRING_TERMINATE(arg->vstrval);
|
||||||
|
arg->strval = STR(arg->vstrval);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some mailers send RFC822-style address forms (with comments and such)
|
* Some mailers send RFC822-style address forms (with comments and such)
|
||||||
* in SMTP envelopes. We cannot blame users for this: the blame is with
|
* in SMTP envelopes. We cannot blame users for this: the blame is with
|
||||||
* programmers violating the RFC, and with sendmail for being permissive.
|
* programmers violating the RFC, and with sendmail for being permissive.
|
||||||
*
|
*
|
||||||
* Extract the address from any surrounding junk. XXX Because of this, the
|
* XXX The SMTP command tokenizer must leave the address in externalized
|
||||||
* SMTP command tokenizer must leave the address in externalized (quoted)
|
* (quoted) form, so that the address parser can correctly extract the
|
||||||
* form.
|
* address from surrounding junk.
|
||||||
|
*
|
||||||
|
* XXX We have only one address parser, written according to the rules of
|
||||||
|
* RFC 822. That standard differs subtly from RFC 821.
|
||||||
*/
|
*/
|
||||||
#define STR(x) vstring_str(x)
|
|
||||||
#define LEN(x) VSTRING_LEN(x)
|
|
||||||
|
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: input: %s", myname, STR(buf));
|
msg_info("%s: input: %s", myname, STR(arg->vstrval));
|
||||||
tree = tok822_parse(STR(buf));
|
tree = tok822_parse(STR(arg->vstrval));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find trouble.
|
||||||
|
*/
|
||||||
for (naddr = non_addr = 0, tp = tree; tp != 0; tp = tp->next) {
|
for (naddr = non_addr = 0, tp = tree; tp != 0; tp = tp->next) {
|
||||||
if (tp->type == TOK822_ADDR) {
|
if (tp->type == TOK822_ADDR) {
|
||||||
if (++naddr == 1)
|
addr = tp;
|
||||||
tok822_internalize(buf, tp->head, TOK822_STR_DEFL);
|
naddr += 1; /* count address forms */
|
||||||
else if (naddr == 2)
|
} else if (tp->type == '<' || tp->type == '>') {
|
||||||
msg_warn("Multiple addresses from %s in %s command: %s",
|
/* void */ ; /* ignore brackets */
|
||||||
state->namaddr, state->where, STR(buf));
|
} else {
|
||||||
} else if (tp->type != '<' && tp->type != '>') {
|
non_addr += 1; /* count non-address forms */
|
||||||
if (++non_addr == 1)
|
|
||||||
msg_warn("Non-RFC 821 syntax from %s in %s command: %s",
|
|
||||||
state->namaddr, state->where, STR(buf));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Report trouble.
|
||||||
|
*/
|
||||||
|
if (naddr != 1) { /* sorry, no can do */
|
||||||
|
msg_warn("Illegal address syntax from %s in %s command: %s",
|
||||||
|
state->namaddr, state->where, STR(arg->vstrval));
|
||||||
|
err = "501 Bad address syntax";
|
||||||
|
} else if (non_addr > 0) { /* it works with Sendmail... */
|
||||||
|
msg_warn("Illegal address syntax from %s in %s command: %s",
|
||||||
|
state->namaddr, state->where, STR(arg->vstrval));
|
||||||
|
err = (var_strict_rfc821_env ? "501 Bad address syntax" : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Overwrite the input with the extracted address. This seems bad design,
|
||||||
|
* but we really are not going to use the original data anymore. What we
|
||||||
|
* start with is quoted (external) form, and what we need is unquoted
|
||||||
|
* (internal form).
|
||||||
|
*/
|
||||||
|
if (addr)
|
||||||
|
tok822_internalize(arg->vstrval, addr->head, TOK822_STR_DEFL);
|
||||||
|
else
|
||||||
|
vstring_strcat(arg->vstrval, "");
|
||||||
|
arg->strval = STR(arg->vstrval);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup.
|
||||||
|
*/
|
||||||
tok822_free_tree(tree);
|
tok822_free_tree(tree);
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: result: %s", myname, STR(buf));
|
msg_info("%s: result: %s", myname, STR(arg->vstrval));
|
||||||
return (buf);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mail_cmd - process MAIL command */
|
/* mail_cmd - process MAIL command */
|
||||||
@@ -498,7 +561,16 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
smtpd_chat_reply(state, "501 Syntax: MAIL FROM: <address>");
|
smtpd_chat_reply(state, "501 Syntax: MAIL FROM: <address>");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
argv[2].strval = STR(extract_addr(state, argv[2].vstrval));
|
if (argv[2].tokval == SMTPD_TOK_ERROR) {
|
||||||
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
|
smtpd_chat_reply(state, "501 Bad address syntax");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if ((err = extract_addr(state, argv + 2, PERMIT_EMPTY_ADDR)) != 0) {
|
||||||
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
|
smtpd_chat_reply(state, "%s", err);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
for (narg = 3; narg < argc; narg++) {
|
for (narg = 3; narg < argc; narg++) {
|
||||||
arg = argv[narg].strval;
|
arg = argv[narg].strval;
|
||||||
if (strcasecmp(arg, "BODY=8BITMIME") == 0
|
if (strcasecmp(arg, "BODY=8BITMIME") == 0
|
||||||
@@ -596,7 +668,16 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
smtpd_chat_reply(state, "501 Syntax: RCPT TO: <address>");
|
smtpd_chat_reply(state, "501 Syntax: RCPT TO: <address>");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
argv[2].strval = STR(extract_addr(state, argv[2].vstrval));
|
if (argv[2].tokval == SMTPD_TOK_ERROR) {
|
||||||
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
|
smtpd_chat_reply(state, "501 Bad address syntax");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
if ((err = extract_addr(state, argv + 2, REJECT_EMPTY_ADDR)) != 0) {
|
||||||
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
|
smtpd_chat_reply(state, "%s", err);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
if (var_smtpd_rcpt_limit && state->rcpt_count >= var_smtpd_rcpt_limit) {
|
if (var_smtpd_rcpt_limit && state->rcpt_count >= var_smtpd_rcpt_limit) {
|
||||||
state->error_mask |= MAIL_ERROR_POLICY;
|
state->error_mask |= MAIL_ERROR_POLICY;
|
||||||
smtpd_chat_reply(state, "452 Error: too many recipients");
|
smtpd_chat_reply(state, "452 Error: too many recipients");
|
||||||
@@ -845,13 +926,25 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
|
|||||||
* The SMTP standard (RFC 821) disallows unquoted special characters in
|
* The SMTP standard (RFC 821) disallows unquoted special characters in
|
||||||
* the VRFY argument. Common practice violates the standard, however.
|
* the VRFY argument. Common practice violates the standard, however.
|
||||||
* Postfix accomodates common practice where it violates the standard.
|
* Postfix accomodates common practice where it violates the standard.
|
||||||
|
*
|
||||||
|
* XXX Impedance mismatch! The SMTP command tokenizer preserves quoting,
|
||||||
|
* whereas the recipient restrictions checks expect unquoted (internal)
|
||||||
|
* address forms. Therefore we must parse out the address, or we must
|
||||||
|
* stop doing recipient restriction checks and lose the opportunity to
|
||||||
|
* say "user unknown" at the SMTP port.
|
||||||
*/
|
*/
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
smtpd_chat_reply(state, "501 Syntax: VRFY address");
|
smtpd_chat_reply(state, "501 Syntax: VRFY address");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
collapse_args(argc, argv);
|
if (argc > 2)
|
||||||
|
collapse_args(argc - 1, argv + 1);
|
||||||
|
if ((err = extract_addr(state, argv + 1, REJECT_EMPTY_ADDR)) != 0) {
|
||||||
|
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||||
|
smtpd_chat_reply(state, "%s", err);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
if (SMTPD_STAND_ALONE(state) == 0)
|
if (SMTPD_STAND_ALONE(state) == 0)
|
||||||
err = smtpd_check_rcpt(state, argv[1].strval);
|
err = smtpd_check_rcpt(state, argv[1].strval);
|
||||||
|
|
||||||
@@ -1216,6 +1309,7 @@ int main(int argc, char **argv)
|
|||||||
static CONFIG_BOOL_TABLE bool_table[] = {
|
static CONFIG_BOOL_TABLE bool_table[] = {
|
||||||
VAR_HELO_REQUIRED, DEF_HELO_REQUIRED, &var_helo_required,
|
VAR_HELO_REQUIRED, DEF_HELO_REQUIRED, &var_helo_required,
|
||||||
VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
|
VAR_SMTPD_DELAY_REJECT, DEF_SMTPD_DELAY_REJECT, &var_smtpd_delay_reject,
|
||||||
|
VAR_STRICT_RFC821_ENV, DEF_STRICT_RFC821_ENV, &var_strict_rfc821_env,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
static CONFIG_STR_TABLE str_table[] = {
|
static CONFIG_STR_TABLE str_table[] = {
|
||||||
|
@@ -124,10 +124,13 @@
|
|||||||
/* parameter. Reject the request otherwise.
|
/* parameter. Reject the request otherwise.
|
||||||
/* The \fIrelay_domains_reject_code\fR configuration parameter specifies
|
/* The \fIrelay_domains_reject_code\fR configuration parameter specifies
|
||||||
/* the reject status code (default: 554).
|
/* the reject status code (default: 554).
|
||||||
|
/* .IP permit_auth_destination
|
||||||
|
/* Permit the request when the resolved recipient domain matches
|
||||||
|
/* the local machine or the \fIrelay_domains\fR configuration parameter.
|
||||||
/* .IP reject_unauth_destination
|
/* .IP reject_unauth_destination
|
||||||
/* Reject the request when the resolved recipient domain does not match
|
/* Reject the request when the resolved recipient domain does not match
|
||||||
/* the \fIrelay_domains\fR configuration parameter. Same error code as
|
/* the local machine or the \fIrelay_domains\fR configuration parameter.
|
||||||
/* check_relay_domains.
|
/* Same error code as check_relay_domains.
|
||||||
/* .IP reject_unauth_pipelining
|
/* .IP reject_unauth_pipelining
|
||||||
/* Reject the request when the client has already sent the next request
|
/* Reject the request when the client has already sent the next request
|
||||||
/* without being told that the server implements SMTP command pipelining.
|
/* without being told that the server implements SMTP command pipelining.
|
||||||
@@ -709,7 +712,7 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient,
|
|||||||
* Permit if destination is local. XXX This must be generalized for
|
* Permit if destination is local. XXX This must be generalized for
|
||||||
* per-domain user tables and for non-UNIX local delivery agents.
|
* per-domain user tables and for non-UNIX local delivery agents.
|
||||||
*/
|
*/
|
||||||
if (STR(reply.nexthop)[0] == 0
|
if (resolve_local(STR(reply.nexthop))
|
||||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||||
return (SMTPD_CHECK_OK);
|
return (SMTPD_CHECK_OK);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
@@ -728,6 +731,43 @@ static int check_relay_domains(SMTPD_STATE *state, char *recipient,
|
|||||||
var_relay_code, reply_name, reply_class));
|
var_relay_code, reply_name, reply_class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* permit_auth_destination - OK for message relaying */
|
||||||
|
|
||||||
|
static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
|
||||||
|
{
|
||||||
|
char *myname = "permit_auth_destination";
|
||||||
|
char *domain;
|
||||||
|
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("%s: %s", myname, recipient);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve the address.
|
||||||
|
*/
|
||||||
|
canon_addr_internal(query, recipient);
|
||||||
|
resolve_clnt_query(STR(query), &reply);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Permit if destination is local. XXX This must be generalized for
|
||||||
|
* per-domain user tables and for non-UNIX local delivery agents.
|
||||||
|
*/
|
||||||
|
if (resolve_local(STR(reply.nexthop))
|
||||||
|
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||||
|
return (SMTPD_CHECK_OK);
|
||||||
|
domain += 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Permit if the destination matches the relay_domains list.
|
||||||
|
*/
|
||||||
|
if (domain_list_match(relay_domains, domain))
|
||||||
|
return (SMTPD_CHECK_OK);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip when not matched
|
||||||
|
*/
|
||||||
|
return (SMTPD_CHECK_DUNNO);
|
||||||
|
}
|
||||||
|
|
||||||
/* reject_unauth_destination - FAIL for message relaying */
|
/* reject_unauth_destination - FAIL for message relaying */
|
||||||
|
|
||||||
static int reject_unauth_destination(SMTPD_STATE *state, char *recipient)
|
static int reject_unauth_destination(SMTPD_STATE *state, char *recipient)
|
||||||
@@ -748,7 +788,7 @@ static int reject_unauth_destination(SMTPD_STATE *state, char *recipient)
|
|||||||
* Pass if destination is local. XXX This must be generalized for
|
* Pass if destination is local. XXX This must be generalized for
|
||||||
* per-domain user tables and for non-UNIX local delivery agents.
|
* per-domain user tables and for non-UNIX local delivery agents.
|
||||||
*/
|
*/
|
||||||
if (STR(reply.nexthop)[0] == 0
|
if (resolve_local(STR(reply.nexthop))
|
||||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
@@ -850,7 +890,7 @@ static int permit_mx_backup(SMTPD_STATE *unused_state, const char *recipient)
|
|||||||
* If the destination is local, it is acceptable, because we are
|
* If the destination is local, it is acceptable, because we are
|
||||||
* supposedly MX for our own address.
|
* supposedly MX for our own address.
|
||||||
*/
|
*/
|
||||||
if (STR(reply.nexthop)[0] == 0
|
if (resolve_local(STR(reply.nexthop))
|
||||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||||
return (SMTPD_CHECK_OK);
|
return (SMTPD_CHECK_OK);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
@@ -984,7 +1024,7 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
|
|||||||
/*
|
/*
|
||||||
* Skip local destinations and non-DNS forms.
|
* Skip local destinations and non-DNS forms.
|
||||||
*/
|
*/
|
||||||
if (STR(reply.nexthop)[0] == 0
|
if (resolve_local(STR(reply.nexthop))
|
||||||
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
|| (domain = strrchr(STR(reply.recipient), '@')) == 0)
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
@@ -1024,7 +1064,7 @@ static int permit_rcpt_map(char *table, char *reply_name)
|
|||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
domain += 1;
|
domain += 1;
|
||||||
if (domain[0] == '#' || domain[0] == '[')
|
if (domain[0] == '#' || domain[0] == '[')
|
||||||
if (STR(reply.nexthop)[0] != 0)
|
if (!resolve_local(STR(reply.nexthop)))
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1338,6 +1378,9 @@ static int reject_maps_rbl(SMTPD_STATE *state)
|
|||||||
char *saved_domains = mystrdup(var_maps_rbl_domains);
|
char *saved_domains = mystrdup(var_maps_rbl_domains);
|
||||||
char *bp = saved_domains;
|
char *bp = saved_domains;
|
||||||
char *rbl_domain;
|
char *rbl_domain;
|
||||||
|
char *rbl_reason;
|
||||||
|
char *rbl_fodder;
|
||||||
|
DNS_RR *txt_list;
|
||||||
int reverse_len;
|
int reverse_len;
|
||||||
int dns_status = DNS_FAIL;
|
int dns_status = DNS_FAIL;
|
||||||
int i;
|
int i;
|
||||||
@@ -1371,11 +1414,22 @@ static int reject_maps_rbl(SMTPD_STATE *state)
|
|||||||
/*
|
/*
|
||||||
* Report the result.
|
* Report the result.
|
||||||
*/
|
*/
|
||||||
if (dns_status == DNS_OK)
|
if (dns_status == DNS_OK) {
|
||||||
|
if (dns_lookup(STR(query), T_TXT, 0, &txt_list,
|
||||||
|
(VSTRING *) 0, (VSTRING *) 0) == DNS_OK) {
|
||||||
|
rbl_fodder = ", reason: ";
|
||||||
|
rbl_reason = (char *) txt_list->data;
|
||||||
|
} else {
|
||||||
|
txt_list = 0;
|
||||||
|
rbl_fodder = rbl_reason = "";
|
||||||
|
}
|
||||||
result = smtpd_check_reject(state, MAIL_ERROR_POLICY,
|
result = smtpd_check_reject(state, MAIL_ERROR_POLICY,
|
||||||
"%d Service unavailable; [%s] blocked using %s",
|
"%d Service unavailable; [%s] blocked using %s%s%s",
|
||||||
var_maps_rbl_code, state->addr, rbl_domain);
|
var_maps_rbl_code, state->addr, rbl_domain,
|
||||||
else
|
rbl_fodder, rbl_reason);
|
||||||
|
if (txt_list)
|
||||||
|
dns_rr_free(txt_list);
|
||||||
|
} else
|
||||||
result = SMTPD_CHECK_DUNNO;
|
result = SMTPD_CHECK_DUNNO;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1549,6 +1603,9 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
|
|||||||
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
|
} else if (strcasecmp(name, PERMIT_MX_BACKUP) == 0) {
|
||||||
if (state->recipient)
|
if (state->recipient)
|
||||||
status = permit_mx_backup(state, state->recipient);
|
status = permit_mx_backup(state, state->recipient);
|
||||||
|
} else if (strcasecmp(name, PERMIT_AUTH_DEST) == 0) {
|
||||||
|
if (state->recipient)
|
||||||
|
status = permit_auth_destination(state, state->recipient);
|
||||||
} else if (strcasecmp(name, REJECT_UNAUTH_DEST) == 0) {
|
} else if (strcasecmp(name, REJECT_UNAUTH_DEST) == 0) {
|
||||||
if (state->recipient)
|
if (state->recipient)
|
||||||
status = reject_unauth_destination(state, state->recipient);
|
status = reject_unauth_destination(state, state->recipient);
|
||||||
|
@@ -94,3 +94,14 @@ rcpt wietse@porcupine.org
|
|||||||
rcpt wietse@no.recipient.domain
|
rcpt wietse@no.recipient.domain
|
||||||
mail wietse@no.sender.domain
|
mail wietse@no.sender.domain
|
||||||
rcpt wietse@porcupine.org
|
rcpt wietse@porcupine.org
|
||||||
|
#
|
||||||
|
# {permit_auth,reject_unauth}_destination
|
||||||
|
#
|
||||||
|
relay_domains foo.com,bar.com
|
||||||
|
mail user@some.where
|
||||||
|
recipient_restrictions permit_auth_destination,reject
|
||||||
|
rcpt user@foo.org
|
||||||
|
rcpt user@foo.com
|
||||||
|
recipient_restrictions reject_unauth_destination,permit
|
||||||
|
rcpt user@foo.org
|
||||||
|
rcpt user@foo.com
|
||||||
|
@@ -182,8 +182,8 @@ OK
|
|||||||
>>> client spike.porcupine.org 168.100.189.2
|
>>> client spike.porcupine.org 168.100.189.2
|
||||||
OK
|
OK
|
||||||
>>> client foo 127.0.0.2
|
>>> client foo 127.0.0.2
|
||||||
./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com; from=<foo@friend.bad.domain>
|
./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<foo@friend.bad.domain>
|
||||||
554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
|
554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
|
||||||
>>> #
|
>>> #
|
||||||
>>> # Hybrids
|
>>> # Hybrids
|
||||||
>>> #
|
>>> #
|
||||||
|
@@ -172,8 +172,8 @@ OK
|
|||||||
>>> client spike.porcupine.org 168.100.189.2
|
>>> client spike.porcupine.org 168.100.189.2
|
||||||
OK
|
OK
|
||||||
>>> client foo 127.0.0.2
|
>>> client foo 127.0.0.2
|
||||||
./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com; from=<foo@friend.bad.domain>
|
./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>; from=<foo@friend.bad.domain>
|
||||||
554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com
|
554 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com, reason: EBlackholed - see <URL:http://mail-abuse.org/cgi-bin/lookup?127.0.0.2>
|
||||||
>>> #
|
>>> #
|
||||||
>>> # unknown sender/recipient domain
|
>>> # unknown sender/recipient domain
|
||||||
>>> #
|
>>> #
|
||||||
@@ -193,3 +193,24 @@ OK
|
|||||||
>>> rcpt wietse@porcupine.org
|
>>> rcpt wietse@porcupine.org
|
||||||
./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 <wietse@no.sender.domain>: Sender address rejected: Domain not found; from=<wietse@no.sender.domain> to=<wietse@porcupine.org>
|
./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 <wietse@no.sender.domain>: Sender address rejected: Domain not found; from=<wietse@no.sender.domain> to=<wietse@porcupine.org>
|
||||||
554 <wietse@no.sender.domain>: Sender address rejected: Domain not found
|
554 <wietse@no.sender.domain>: Sender address rejected: Domain not found
|
||||||
|
>>> #
|
||||||
|
>>> # {permit_auth,reject_unauth}_destination
|
||||||
|
>>> #
|
||||||
|
>>> relay_domains foo.com,bar.com
|
||||||
|
OK
|
||||||
|
>>> mail user@some.where
|
||||||
|
OK
|
||||||
|
>>> recipient_restrictions permit_auth_destination,reject
|
||||||
|
OK
|
||||||
|
>>> rcpt user@foo.org
|
||||||
|
./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 <user@foo.org>: Recipient address rejected: Access denied; from=<user@some.where> to=<user@foo.org>
|
||||||
|
554 <user@foo.org>: Recipient address rejected: Access denied
|
||||||
|
>>> rcpt user@foo.com
|
||||||
|
OK
|
||||||
|
>>> recipient_restrictions reject_unauth_destination,permit
|
||||||
|
OK
|
||||||
|
>>> rcpt user@foo.org
|
||||||
|
./smtpd_check: reject: RCPT from foo[127.0.0.2]: 554 <user@foo.org>: Relay access denied; from=<user@some.where> to=<user@foo.org>
|
||||||
|
554 <user@foo.org>: Relay access denied
|
||||||
|
>>> rcpt user@foo.com
|
||||||
|
OK
|
||||||
|
@@ -31,7 +31,7 @@
|
|||||||
/* It understands backslash escapes, white space, quoted strings,
|
/* It understands backslash escapes, white space, quoted strings,
|
||||||
/* and addresses (including quoted text) enclosed by < and >.
|
/* and addresses (including quoted text) enclosed by < and >.
|
||||||
/* The input is broken up into tokens by whitespace, except for
|
/* The input is broken up into tokens by whitespace, except for
|
||||||
/* whitespace that is protected by quites etc.
|
/* whitespace that is protected by quotes etc.
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@@ -64,12 +64,22 @@
|
|||||||
static char *smtp_quoted(char *cp, SMTPD_TOKEN *arg, int start, int last)
|
static char *smtp_quoted(char *cp, SMTPD_TOKEN *arg, int start, int last)
|
||||||
{
|
{
|
||||||
static VSTRING *stack;
|
static VSTRING *stack;
|
||||||
|
int wanted;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parser stack. `ch' is always the most-recently entered character.
|
||||||
|
*/
|
||||||
|
#define ENTER_CHAR(buf, ch) VSTRING_ADDCH(buf, ch);
|
||||||
|
#define LEAVE_CHAR(buf, ch) { \
|
||||||
|
vstring_truncate(buf, VSTRING_LEN(buf) - 1); \
|
||||||
|
ch = vstring_end(buf)[-1]; \
|
||||||
|
}
|
||||||
|
|
||||||
if (stack == 0)
|
if (stack == 0)
|
||||||
stack = vstring_alloc(1);
|
stack = vstring_alloc(1);
|
||||||
VSTRING_RESET(stack);
|
VSTRING_RESET(stack);
|
||||||
VSTRING_ADDCH(stack, last);
|
ENTER_CHAR(stack, wanted = last);
|
||||||
|
|
||||||
VSTRING_ADDCH(arg->vstrval, start);
|
VSTRING_ADDCH(arg->vstrval, start);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -77,25 +87,22 @@ static char *smtp_quoted(char *cp, SMTPD_TOKEN *arg, int start, int last)
|
|||||||
break;
|
break;
|
||||||
cp++;
|
cp++;
|
||||||
VSTRING_ADDCH(arg->vstrval, c);
|
VSTRING_ADDCH(arg->vstrval, c);
|
||||||
if (c == vstring_end(stack)[-1]) { /* closing quote etc. */
|
if (c == '\\') { /* parse escape sequence */
|
||||||
vstring_truncate(stack, VSTRING_LEN(stack) - 1);
|
if ((c = *cp) == 0)
|
||||||
if (VSTRING_LEN(stack) == 0)
|
|
||||||
break;
|
break;
|
||||||
} else {
|
cp++;
|
||||||
if (c == '\\') { /* parse escape sequence */
|
VSTRING_ADDCH(arg->vstrval, c);
|
||||||
if ((c = *cp) == 0)
|
} else if (c == wanted) { /* closing quote etc. */
|
||||||
break;
|
if (VSTRING_LEN(stack) == 1)
|
||||||
cp++;
|
return (cp);
|
||||||
VSTRING_ADDCH(arg->vstrval, c);
|
LEAVE_CHAR(stack, wanted);
|
||||||
} else if (c == '"') {
|
} else if (c == '"') {
|
||||||
VSTRING_ADDCH(stack, '"'); /* highest precedence */
|
ENTER_CHAR(stack, wanted = '"'); /* highest precedence */
|
||||||
} else if (c == '(' && vstring_end(stack)[-1] != '"') {
|
} else if (c == '<' && wanted == '>') {
|
||||||
VSTRING_ADDCH(stack, ')'); /* medium precedence */
|
ENTER_CHAR(stack, wanted = '>'); /* lowest precedence */
|
||||||
} else if (c == '<' && vstring_end(stack)[-1] == '>') {
|
|
||||||
VSTRING_ADDCH(stack, '>'); /* lowest precedence */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
arg->tokval = SMTPD_TOK_ERROR; /* missing end */
|
||||||
return (cp);
|
return (cp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,12 +113,15 @@ static char *smtp_next_token(char *cp, SMTPD_TOKEN *arg)
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
VSTRING_RESET(arg->vstrval);
|
VSTRING_RESET(arg->vstrval);
|
||||||
|
arg->tokval = SMTPD_TOK_OTHER;
|
||||||
|
|
||||||
#define STR(x) vstring_str(x)
|
#define STR(x) vstring_str(x)
|
||||||
#define LEN(x) VSTRING_LEN(x)
|
#define LEN(x) VSTRING_LEN(x)
|
||||||
#define STREQ(x,y,l) ((x)[0] == (x)[0] && strncasecmp((x), (y), (l)) == 0)
|
#define STREQ(x,y,l) (strncasecmp((x), (y), (l)) == 0)
|
||||||
|
|
||||||
while ((c = *cp) != 0) {
|
for (;;) {
|
||||||
|
if ((c = *cp) == 0) /* end of input */
|
||||||
|
break;
|
||||||
cp++;
|
cp++;
|
||||||
if (ISSPACE(c)) { /* whitespace, skip */
|
if (ISSPACE(c)) { /* whitespace, skip */
|
||||||
while (*cp && ISSPACE(*cp))
|
while (*cp && ISSPACE(*cp))
|
||||||
@@ -120,8 +130,6 @@ static char *smtp_next_token(char *cp, SMTPD_TOKEN *arg)
|
|||||||
break;
|
break;
|
||||||
} else if (c == '<') { /* <stuff> */
|
} else if (c == '<') { /* <stuff> */
|
||||||
cp = smtp_quoted(cp, arg, c, '>');
|
cp = smtp_quoted(cp, arg, c, '>');
|
||||||
} else if (c == '[') { /* [stuff] */
|
|
||||||
cp = smtp_quoted(cp, arg, c, ']');
|
|
||||||
} else if (c == '"') { /* "stuff" */
|
} else if (c == '"') { /* "stuff" */
|
||||||
cp = smtp_quoted(cp, arg, c, c);
|
cp = smtp_quoted(cp, arg, c, c);
|
||||||
} else if (c == ':') { /* this is gross, but... */
|
} else if (c == ':') { /* this is gross, but... */
|
||||||
@@ -138,7 +146,7 @@ static char *smtp_next_token(char *cp, SMTPD_TOKEN *arg)
|
|||||||
VSTRING_ADDCH(arg->vstrval, c);
|
VSTRING_ADDCH(arg->vstrval, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (LEN(arg->vstrval) == 0) /* no token found */
|
if (LEN(arg->vstrval) <= 0) /* no token found */
|
||||||
return (0);
|
return (0);
|
||||||
VSTRING_TERMINATE(arg->vstrval);
|
VSTRING_TERMINATE(arg->vstrval);
|
||||||
arg->strval = vstring_str(arg->vstrval);
|
arg->strval = vstring_str(arg->vstrval);
|
||||||
@@ -197,15 +205,20 @@ main(int unused_argc, char **unused_argv)
|
|||||||
if (isatty(STDIN_FILENO))
|
if (isatty(STDIN_FILENO))
|
||||||
vstream_printf("enter SMTPD command: ");
|
vstream_printf("enter SMTPD command: ");
|
||||||
vstream_fflush(VSTREAM_OUT);
|
vstream_fflush(VSTREAM_OUT);
|
||||||
if (vstring_fgets(vp, VSTREAM_IN) == 0)
|
if (vstring_get_nonl(vp, VSTREAM_IN) == VSTREAM_EOF)
|
||||||
break;
|
break;
|
||||||
if (*vstring_str(vp) == '#')
|
if (*vstring_str(vp) == '#')
|
||||||
continue;
|
continue;
|
||||||
if (!isatty(STDIN_FILENO))
|
if (!isatty(STDIN_FILENO))
|
||||||
vstream_fputs(vstring_str(vp), VSTREAM_OUT);
|
vstream_printf("%s\n", vstring_str(vp));
|
||||||
tok_argc = smtpd_token(vstring_str(vp), &tok_argv);
|
tok_argc = smtpd_token(vstring_str(vp), &tok_argv);
|
||||||
for (i = 0; i < tok_argc; i++)
|
for (i = 0; i < tok_argc; i++) {
|
||||||
|
vstream_printf("Token type: %s\n",
|
||||||
|
tok_argv[i].tokval == SMTPD_TOK_OTHER ? "other" :
|
||||||
|
tok_argv[i].tokval == SMTPD_TOK_ERROR ? "error" :
|
||||||
|
"unknown");
|
||||||
vstream_printf("Token value: %s\n", tok_argv[i].strval);
|
vstream_printf("Token value: %s\n", tok_argv[i].strval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
* External interface.
|
* External interface.
|
||||||
*/
|
*/
|
||||||
typedef struct SMTPD_TOKEN {
|
typedef struct SMTPD_TOKEN {
|
||||||
|
int tokval;
|
||||||
char *strval;
|
char *strval;
|
||||||
VSTRING *vstrval;
|
VSTRING *vstrval;
|
||||||
} SMTPD_TOKEN;
|
} SMTPD_TOKEN;
|
||||||
|
@@ -7,3 +7,6 @@ mail from:<"wietse venema" <wietse@porcupine.org>>
|
|||||||
mail from:<"wietse venema"@porcupine.org ( ("wietse ) venema") )>
|
mail from:<"wietse venema"@porcupine.org ( ("wietse ) venema") )>
|
||||||
mail from:"wietse venema"@porcupine.org
|
mail from:"wietse venema"@porcupine.org
|
||||||
mail from:wietse\ venema@porcupine.org
|
mail from:wietse\ venema@porcupine.org
|
||||||
|
mail to:<"wietse venema>
|
||||||
|
mail to:<wietse@[stuff>
|
||||||
|
mail to:<wietse@["stuff]>
|
||||||
|
@@ -1,36 +1,84 @@
|
|||||||
mail from:<wietse@porcupine.org>
|
mail from:<wietse@porcupine.org>
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: <wietse@porcupine.org>
|
Token value: <wietse@porcupine.org>
|
||||||
mail from:<"wietse venema"@porcupine.org>
|
mail from:<"wietse venema"@porcupine.org>
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: <"wietse venema"@porcupine.org>
|
Token value: <"wietse venema"@porcupine.org>
|
||||||
mail from:wietse@porcupine.org
|
mail from:wietse@porcupine.org
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: wietse@porcupine.org
|
Token value: wietse@porcupine.org
|
||||||
mail from:<wietse @ porcupine.org>
|
mail from:<wietse @ porcupine.org>
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: <wietse @ porcupine.org>
|
Token value: <wietse @ porcupine.org>
|
||||||
mail from:<"wietse venema"@porcupine.org ("wietse ) venema")>
|
mail from:<"wietse venema"@porcupine.org ("wietse ) venema")>
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: <"wietse venema"@porcupine.org ("wietse ) venema")>
|
Token value: <"wietse venema"@porcupine.org ("wietse ) venema")>
|
||||||
mail from:<"wietse venema" <wietse@porcupine.org>>
|
mail from:<"wietse venema" <wietse@porcupine.org>>
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: <"wietse venema" <wietse@porcupine.org>>
|
Token value: <"wietse venema" <wietse@porcupine.org>>
|
||||||
mail from:<"wietse venema"@porcupine.org ( ("wietse ) venema") )>
|
mail from:<"wietse venema"@porcupine.org ( ("wietse ) venema") )>
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: <"wietse venema"@porcupine.org ( ("wietse ) venema") )>
|
Token value: <"wietse venema"@porcupine.org ( ("wietse ) venema") )>
|
||||||
mail from:"wietse venema"@porcupine.org
|
mail from:"wietse venema"@porcupine.org
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: "wietse venema"@porcupine.org
|
Token value: "wietse venema"@porcupine.org
|
||||||
mail from:wietse\ venema@porcupine.org
|
mail from:wietse\ venema@porcupine.org
|
||||||
|
Token type: other
|
||||||
Token value: mail
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
Token value: from:
|
Token value: from:
|
||||||
|
Token type: other
|
||||||
Token value: wietse venema@porcupine.org
|
Token value: wietse venema@porcupine.org
|
||||||
|
mail to:<"wietse venema>
|
||||||
|
Token type: other
|
||||||
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
|
Token value: to:
|
||||||
|
Token type: error
|
||||||
|
Token value: <"wietse venema>
|
||||||
|
mail to:<wietse@[stuff>
|
||||||
|
Token type: other
|
||||||
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
|
Token value: to:
|
||||||
|
Token type: other
|
||||||
|
Token value: <wietse@[stuff>
|
||||||
|
mail to:<wietse@["stuff]>
|
||||||
|
Token type: other
|
||||||
|
Token value: mail
|
||||||
|
Token type: other
|
||||||
|
Token value: to:
|
||||||
|
Token type: error
|
||||||
|
Token value: <wietse@["stuff]>
|
||||||
|
@@ -151,39 +151,43 @@ void resolve_addr(char *addr, VSTRING *channel, VSTRING *nexthop,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Non-local delivery: if no transport is specified, assume the transport
|
* The transport map, if specified, overrides default routing.
|
||||||
* specified in var_def_transport. If no mail relay is specified in
|
|
||||||
* var_relayhost, forward to the domain's mail exchanger.
|
|
||||||
*/
|
*/
|
||||||
if (domain != 0) {
|
if (*var_transport_maps == 0
|
||||||
if (*var_transport_maps == 0
|
|| (tok822_internalize(addr_buf, domain->next, TOK822_STR_DEFL),
|
||||||
|| (tok822_internalize(addr_buf, domain->next, TOK822_STR_DEFL),
|
transport_lookup(STR(addr_buf), channel, nexthop)) == 0) {
|
||||||
transport_lookup(STR(addr_buf), channel, nexthop) == 0)) {
|
|
||||||
|
/*
|
||||||
|
* Non-local delivery. Use the default transport specified in
|
||||||
|
* var_def_transport. If no default mail relay is specified in
|
||||||
|
* var_relayhost, forward to the domain's mail exchanger.
|
||||||
|
*/
|
||||||
|
if (domain != 0) {
|
||||||
vstring_strcpy(channel, var_def_transport);
|
vstring_strcpy(channel, var_def_transport);
|
||||||
if (*var_relayhost)
|
if (*var_relayhost)
|
||||||
vstring_strcpy(nexthop, var_relayhost);
|
vstring_strcpy(nexthop, var_relayhost);
|
||||||
else
|
else
|
||||||
tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL);
|
tok822_internalize(nexthop, domain->next, TOK822_STR_DEFL);
|
||||||
}
|
}
|
||||||
tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local delivery: if no domain was specified, assume the local machine.
|
* Local delivery. Use the default transport and next-hop hostname.
|
||||||
* See above for what happens with an empty localpart.
|
* If no domain was specified, assume the local machine. See above
|
||||||
*/
|
* for what happens with an empty localpart.
|
||||||
else {
|
*/
|
||||||
vstring_strcpy(channel, MAIL_SERVICE_LOCAL);
|
else {
|
||||||
vstring_strcpy(nexthop, "");
|
vstring_strcpy(channel, MAIL_SERVICE_LOCAL);
|
||||||
if (saved_domain) {
|
vstring_strcpy(nexthop, var_myhostname);
|
||||||
tok822_sub_append(tree, saved_domain);
|
if (saved_domain) {
|
||||||
saved_domain = 0;
|
tok822_sub_append(tree, saved_domain);
|
||||||
} else {
|
saved_domain = 0;
|
||||||
tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
|
} else {
|
||||||
tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
|
tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
|
||||||
|
tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
|
|
||||||
}
|
}
|
||||||
|
tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clean up.
|
* Clean up.
|
||||||
|
Reference in New Issue
Block a user