-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
Miscellaneous:
+ auxiliary/ Auxiliary software etc.
bin/ Postfix command executables
conf/ Sample configuration files
include/ Installed include files
19990908
Portability: Unixware has <sysexits.h> only after sendmail
- is installed. Changed postlock.c to use global/sys_exists.h.
+ is installed. Changed postlock.c to use global/sys_exits.h.
19990909
File: smtpd/smtpd_access.c.
Cleanup: removed spurious sender address checks for <>.
+ File: smtpd/smtpd_check.c.
Cleanup: the smtp client now consistently logs host[address]
for all connection attempts.
+
+19990919
+
+ Feature: in an SMTPD access map, an all-numeric right-hand
+ side now means OK, for better cooperation with out-of-band
+ authentication mechanisms.
+
+19990922
+
+ Security: recipient addresses must not start with '-', in
+ order to protect external commands. The old behavior is
+ re-instated when main.cf specifies: "allow_min_user =
+ yes". Credits to Mads Kiilerich @ Kiilerich.com. File:
+ qmgr/qmgr_message.c.
+
+ Bugfix: after 19990831, the queue manager would throw away
+ defer logs after deferring mail to known-to-be-dead hosts
+ or message transports. This means that in some cases, mailq
+ would not show why mail is delayed, and that delayed mail
+ could be sent back with recipients missing from the error
+ report. Reported by Giulio Orsero @ tiscalinet.it.
+
+19990923
+
+ Bugfix: the above bugfix broke bounces of mail with bad
+ address syntax and relocated users. Problem diagnosed by
+ Dick Porter @ acm.org.
+
+ Documentation: added DO NOT EDIT THIS FILE. EDIT MAIN.CF
+ INSTEAD notices to the sample-xxx.cf files.
+
+19991007
+
+ Compatibility: ignore the sendmail -U (initial user
+ submission) option. Thomas Quinot @ cuivre.fr.eu.org.
+
+19991103
+
+ Code cleanup: don't send postmaster notifications when an
+ SMTP client sends a DATA command while no recipients were
+ accepted. This can happen when a pipelined client runs
+ into an UCE block. File: smtpd/smtpd.c.
+
+19991104
+
+ Robustness: do not apply UCE header checks to mail that is
+ generated by Postfix (bounces, forwarded mail etc.). Files:
+ smtpd/smtpd.c, pickup/pickup.c, cleanup/cleanup_message.c.
+
+ Robustness: new generic watchdog module that can deal with
+ clocks that jump occasionally. Files: util/watchdog.c,
+ master/master.c, master/{single,multi,trigger}_server.c.
+ This hopefully ends the false watchdog alarms that happen
+ when clocks are set or when laptops are resumed.
+
+ Code cleanup: BSMTP requires dot quoting as per RFC 821.
+ Based on code by Florian Lohoff @ rfc822.org. Files:
+ global/mail_copy.[hc], pipe/pipe.c.
+
+19991105
+
+ Bugfix: the crufty code in inet_addr_local() did not find
+ IP aliases. File: util/inet_addr_local.c.
+
+ Portability: the INSTALL.sh utility did not find users or
+ groups in NIS or Netinfo tables. The script no longer
+ searches the /etc/passwd and /etc/group files. Instead it
+ now queries the unix:passwd.byname and unix:group.byname
+ maps. For this, a -q (query) option was added to postmap
+ (and to postalias, for symmetry). Files: util/dict_unix.c,
+ postalias/postalias.c, postmap/postmap.c, INSTALL.sh.
+
+ Bugfix: LDAP lookup timeout settings were ignored. Patch
+ by John Hensley. File: util/dict_ldap.c.
+
+19991110
+
+ Code cleanup: greatly simplified the SMTPD command parser
+ and somewhat simplified the code that groks RFC 822-style
+ address syntax in MAIL FROM and RCPT TO commands.
command_directory - directory with Postfix administrative commands.
queue_directory - directory with Postfix queues.
- sendmail_path - full pathname of the sendmail command.
- newaliases_path - full pathname of the newaliases command.
- mailq_path - full pathname of the mailq command.
+ sendmail_path - full pathname of the Postfix sendmail command.
+ newaliases_path - full pathname of the Postfix newaliases command.
+ mailq_path - full pathname of the Postfix mailq command.
owner - owner of Postfix queue files.
esac
done
-grep "^$owner:" /etc/passwd >/dev/null || {
+bin/postmap -c ./conf -q "$owner" unix:passwd.byname >/dev/null || {
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
exit 1
case $setgid in
no) ;;
- *) grep "^$setgid:" /etc/group >/dev/null || {
+ *) bin/postmap -c ./conf -q "$setgid" unix:group.byname >/dev/null || {
echo "$setgid needs an entry in the group file" 1>&2
echo "Remember, $setgid must have a dedicated group id." 1>&2
exit 1
# Install files. Be careful to not copy over running programs.
-for file in `ls libexec | grep '^[a-z]'`
+for file in `ls libexec`
do
compare_or_replace a+x,go-w libexec/$file $daemon_directory/$file || exit 1
done
s;^daemon_directory .*;daemon_directory = $daemon_directory;
s;^command_directory .*;command_directory = $command_directory;
s;^queue_directory .*;queue_directory = $queue_directory;
- s;^mail_owner .*;mail_owner = $mail_owner;
+ s;^mail_owner .*;mail_owner = $owner;
" conf/main.cf >$config_directory/main.cf || exit 1
echo "Warning: you still need to edit myorigin/mydestination in" 1>&2
-Incompatible changes with snapshot 19990911
+Incompatible changes with snapshot XXXXXXXX
===========================================
+- Recipient addresses may no longer begin with `-'. In order to
+reinstate the old behavior, specify "allow_min_user = yes" in
+main.cf.
+
- You can not longer use virtual, canonical or aliases tables as
SMTPD access control tables. Use the permit_recipient_map feature
instead. The loss is compensated for.
-Major changes with snapshot 19990911
+Major changes with snapshot XXXXXXXX
====================================
- Per-client/helo/sender/recipient UCE restrictions: you can now
restrictive = reject_unknown_sender reject_unknown_client ...
permissive = permit
-Then use "restrictive" or "restrictive" on the right-hand side of
+Then use "restrictive" or "permissive" on the right-hand side of
your per-client/helo/sender/recipient SMTPD access tables.
- Reject mail for non-existent local accounts. You can now use
non-existent local recipients.
Unfortunately, permit_recipient_map does not combine well with
-check_relay_domains, because check_relay_domains permits either
-rejects mail, or accepts mail for non-existent local recipients.
+check_relay_domains, because check_relay_domains either rejects
+mail, or accepts mail regardless of whether a recipient exists.
Incompatible changes with postfix-19990906
==========================================
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
if (msg_verbose)
msg_info("%s: '%s'", myname, vstring_str(cleanup_header_buf));
- if (cleanup_header_checks) {
+ if ((cleanup_flags & CLEANUP_FLAG_FILTER) && cleanup_header_checks) {
char *header = vstring_str(cleanup_header_buf);
const char *value;
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control alias database lookups.
#
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control canonical address map lookups.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control debugging features.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control LDAP lookups. Source code for LDAP
# lookup is available separately from http://www.postfix.org/
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control local delivery.
#
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings for miscellaneous Postfix
# configuration parameters.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix parameters that
# control delivery rates.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control relocated database lookups.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of general Postfix resource
# control parameters.
#
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control address rewriting.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control the SMTP client program.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration parameters
# that control the SMTP server program.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control the optional transport table lookups.
+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
+# HERE JUST SERVES AS AN EXAMPLE.
+#
# This file contains example settings of Postfix configuration
# parameters that control virtual database lookups.
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
* only if the name server told us so.
*/
len = res_search((char *) name, C_IN, type, reply->buf, sizeof(reply->buf));
+ reply_header = (HEADER *) reply->buf;
if (len < 0) {
+ if (reply_header->rcode == SERVFAIL)
+ h_errno = NO_RECOVERY;
if (why)
vstring_sprintf(why, "Name service error for domain %s: %s",
name, dns_strerror(h_errno));
*/
if ((reply->end = reply->buf + len) > reply->buf + sizeof(reply->buf))
reply->end = reply->buf + sizeof(reply->buf);
- reply_header = (HEADER *) reply->buf;
reply->query_start = reply->buf + sizeof(HEADER);
reply->answer_start = 0;
reply->query_count = ntohs(reply_header->qdcount);
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
#define BOUNCE_FLAG_NONE 0 /* no flags up */
#define BOUNCE_FLAG_CLEAN (1<<0) /* remove log on error */
#define BOUNCE_FLAG_COPY (1<<1) /* postmaster notice */
+#define BOUNCE_FLAG_VERP (1<<2) /* personalized bounce */
/*
* Backwards compatibility.
/* The binary OR of zero or more of the following:
/* .RS
/* .IP MAIL_COPY_QUOTE
-/* prepend a `>' character to lines beginning with `From '.
+/* Prepend a `>' character to lines beginning with `From '.
+/* .IP MAIL_COPY_DOT
+/* Prepend a `.' character to lines beginning with `.'.
/* .IP MAIL_COPY_TOFILE
/* On systems that support this, use fsync() to flush the
/* data to stable storage, and truncate the destination
bp = vstring_str(buf);
if ((flags & MAIL_COPY_QUOTE) && *bp == 'F' && !strncmp(bp, "From ", 5))
VSTREAM_PUTC('>', dst);
+ if ((flags & MAIL_COPY_DOT) && *bp == '.')
+ VSTREAM_PUTC('.', dst);
if (VSTRING_LEN(buf) && VSTREAM_FWRITE_BUF(dst, buf) != VSTRING_LEN(buf))
break;
if (type == REC_TYPE_NORM && VSTREAM_PUTC('\n', dst) == VSTREAM_EOF)
#define MAIL_COPY_FROM (1<<2) /* prepend From_ */
#define MAIL_COPY_DELIVERED (1<<3) /* prepend Delivered-To: */
#define MAIL_COPY_RETURN_PATH (1<<4) /* prepend Return-Path: */
-#define MAIL_COPY_MBOX (~0) /* all turned on */
+#define MAIL_COPY_DOT (1<<5) /* escape dots - needed for bsmtp */
+#define MAIL_COPY_MBOX (MAIL_COPY_FROM | MAIL_COPY_QUOTE | \
+ MAIL_COPY_TOFILE | MAIL_COPY_DELIVERED | \
+ MAIL_COPY_RETURN_PATH)
#define MAIL_COPY_NONE 0 /* all turned off */
/* LICENSE
#define DEF_ALWAYS_BCC ""
extern char *var_always_bcc;
+ /*
+ * Standards violation: permit RFC 822-style addresses in SMTP commands.
+ */
+#define VAR_ALLOW_RFC822_ENV "allow_rfc822_envelopes"
+#define DEF_ALLOW_RFC822_ENV 1
+extern bool var_allow_rfc822_envelopes;
+
/*
* trivial rewrite/resolve service: mapping tables.
*/
#define DEF_OWNREQ_SPECIAL 1
extern bool var_ownreq_special;
+ /*
+ * Allow/disallow recipient addresses starting with `-'.
+ */
+#define VAR_ALLOW_MIN_USER "allow_min_user"
+#define DEF_ALLOW_MIN_USER 0
+extern bool var_allow_min_user;
+
extern void mail_params_init(void);
/* LICENSE
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-19990912"
+#define DEF_MAIL_VERSION "Snapshot-19991110"
extern char *var_mail_version;
/* LICENSE
*/
CLNT_STREAM *rewrite_clnt_stream = 0;
-VSTRING *last_addr;
-VSTRING *last_result;
+static VSTRING *last_addr;
+static VSTRING *last_result;
/* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
<li><a href="#timeouts">Mail fails with timeout or lost connection</a>
+<p>
+
<li><a href="#bind">Undefined symbols: ___dn_expand, ___res_init etc.</a>
+<li><a href="#dbm">Undefined symbols: dbm_pagfno, dbm_dirfno etc.</a>
+
<li><a href="#db">Using DB libraries on Solaris etc.</a>
</ul>
<hr>
+<a name="dbm"><h2>Undefined symbols: dbm_pagfno, dbm_dirfno etc.</h2></a>
+
+Question: When I build Postfix I get the following errors:
+
+<p>
+
+<pre>
+ Undefined first referenced
+ symbol in file
+ dbm_pagfno ../lib/libutil.a(dict_dbm.o)
+ dbm_dirfno ../lib/libutil.a(dict_dbm.o)
+</pre>
+
+<p>
+
+Answer: instead of using /usr/include/ndbm.h, you're building
+Postfix with some incompatible third-party ndbm.h include file,
+typically something in /usr/local/include.
+
+<p>
+
+Fix: get rid of the third-party ndbm.h include file.
+
+<hr>
+
<a name="db"><h2>Using DB libraries on Solaris etc.</h2> </a>
The old <b>dbm</b> UNIX database has severe limitations when you
<p>
-One problem: older DB versions install a file <b>/usr/include/ndbm.h</b>
-that is incompatible with the one in <b>/usr/include</b>. Be sure
+One problem: older DB versions install a file <b>/usr/local/include/ndbm.h</b>
+that is incompatible with <b>/usr/include/ndbm.h</b>. Be sure
to get rid of the bogus file, or the linker will fail to find
<b>dbm_dirfno</b>.
<p>
-What is Postfix? It is Wietse Venema's attempt to provide an
-alternative to the widely-used <a
-href="http://www.sendmail.org/">Sendmail</a> program. Sendmail is
-responsible for an estimated 70% of all e-mail delivered on the
+What is Postfix? It is <a href="http://www.porcupine.org/wietse/">Wietse
+Venema's</a> attempt to provide an alternative to the widely-used
+<a href="http://www.sendmail.org/">Sendmail</a> program. Sendmail
+is responsible for an estimated 70% of all e-mail delivered on the
Internet. With an estimated 100 million users, that's billions of
messages daily. A stunning number.
file at the end of a service definition. The syntax is as
follows:
- <b>flags=FR</b>> (optional)
+ <b>flags=FR.</b>> (optional)
Optional message processing flags. By default, a
message is copied unchanged.
<b>R</b> Prepend a <b>Return-Path:</b> message header with
the envelope sender address.
- > Prepend > to lines starting with "<b>From</b> ".
+ <b>.</b> Prepend <b>.</b> to lines starting with "<b>.</b>". This
+ is needed by, for example, <b>BSMTP</b> software.
+
+ > Prepend > to lines starting with "<b>From</b> ".
This is expected by, for example, <b>UUCP</b> soft-
ware.
<b>user</b>=<i>username</i>:<i>groupname</i>
The external command is executed with the rights of
- the specified <i>username</i>. The software refuses to
- execute commands with root privileges, or with the
- privileges of the mail system owner. If <i>groupname</i>
- is specified, the corresponding group ID is used
+ the specified <i>username</i>. The software refuses to
+ execute commands with root privileges, or with the
+ privileges of the mail system owner. If <i>groupname</i>
+ is specified, the corresponding group ID is used
instead of the group ID of of <i>username</i>.
- <b>argv</b>=<i>command</i>... (required)
- The command to be executed. This must be specified
-
1
PIPE(8) PIPE(8)
+ <b>argv</b>=<i>command</i>... (required)
+ The command to be executed. This must be specified
as the last command attribute. The command is exe-
cuted directly, i.e. without interpretation of
- shell meta characters by a shell command inter-
+ shell meta characters by a shell command inter-
preter.
In the command argument vector, the following
macros are recognized and replaced with correspond-
- ing information from the Postfix queue manager
+ ing information from the Postfix queue manager
delivery request:
<b>${extension</b>}
- This macro expands to the extension part of
- a recipient address. For example, with an
+ This macro expands to the extension part of
+ a recipient address. For example, with an
address <i>user+foo@domain</i> the extension is
- <i>foo</i>. A command-line argument that contains
- <b>${extension</b>} expands into as many command-
+ <i>foo</i>. A command-line argument that contains
+ <b>${extension</b>} expands into as many command-
line arguments as there are recipients.
<b>${mailbox</b>}
- This macro expands to the complete local
- part of a recipient address. For example,
- with an address <i>user+foo@domain</i> the mailbox
- is <i>user+foo</i>. A command-line argument that
- contains <b>${mailbox</b>} expands into as many
- command-line arguments as there are recipi-
+ This macro expands to the complete local
+ part of a recipient address. For example,
+ with an address <i>user+foo@domain</i> the mailbox
+ is <i>user+foo</i>. A command-line argument that
+ contains <b>${mailbox</b>} expands into as many
+ command-line arguments as there are recipi-
ents.
<b>${nexthop</b>}
<b>${recipient</b>}
This macro expands to the complete recipient
- address. A command-line argument that con-
+ address. A command-line argument that con-
tains <b>${recipient</b>} expands into as many com-
mand-line arguments as there are recipients.
<b>${sender</b>}
- This macro expands to the envelope sender
+ This macro expands to the envelope sender
address.
<b>${user</b>}
This macro expands to the username part of a
- recipient address. For example, with an
+ recipient address. For example, with an
address <i>user+foo@domain</i> the username part is
<i>user</i>. A command-line argument that contains
- <b>${user</b>} expands into as many command-line
+ <b>${user</b>} expands into as many command-line
arguments as there are recipients.
- In addition to the form ${<i>name</i>}, the forms $<i>name</i> and
- $(<i>name</i>) are also recognized. Specify <b>$$</b> where a single <b>$</b>
+ In addition to the form ${<i>name</i>}, the forms $<i>name</i> and
+ $(<i>name</i>) are also recognized. Specify <b>$$</b> where a single <b>$</b>
is wanted.
-<b>DIAGNOSTICS</b>
- Command exit status codes are expected to follow the
PIPE(8) PIPE(8)
- conventions defined in <<b>sysexits.h</b>>.
+<b>DIAGNOSTICS</b>
+ Command exit status codes are expected to follow the con-
+ ventions defined in <<b>sysexits.h</b>>.
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the <b>corrupt</b> queue for further inspection.
<b>SECURITY</b>
- This program needs a dual personality 1) to access the
- private Postfix queue and IPC mechanisms, and 2) to exe-
+ This program needs a dual personality 1) to access the
+ private Postfix queue and IPC mechanisms, and 2) to exe-
cute external commands as the specified user. It is there-
fore security sensitive.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
- details and for default values. Use the <b>postfix</b> <b>reload</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
<b>Miscellaneous</b>
<b>mail</b><i>_</i><b>owner</b>
- The process privileges used while not running an
+ The process privileges used while not running an
external command.
<b>Resource</b> <b>controls</b>
- In the text below, <i>transport</i> is the first field in a <b>mas-</b>
+ In the text below, <i>transport</i> is the first field in a <b>mas-</b>
<b>ter.cf</b> entry.
<i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
Limit the number of parallel deliveries to the same
- destination, for delivery via the named <i>transport</i>.
- The default limit is taken from the <b>default</b><i>_</i><b>desti-</b>
- <b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. The limit is
+ destination, for delivery via the named <i>transport</i>.
+ The default limit is taken from the <b>default</b><i>_</i><b>desti-</b>
+ <b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. The limit is
enforced by the Postfix queue manager.
<i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
- Limit the number of recipients per message deliv-
- ery, for delivery via the named <i>transport</i>. The
- default limit is taken from the <b>default</b><i>_</i><b>destina-</b>
- <b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is
+ Limit the number of recipients per message deliv-
+ ery, for delivery via the named <i>transport</i>. The
+ default limit is taken from the <b>default</b><i>_</i><b>destina-</b>
+ <b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is
enforced by the Postfix queue manager.
<i>transport_</i><b>time</b><i>_</i><b>limit</b>
- Limit the time for delivery to external command,
- for delivery via the named <b>transport</b>. The default
- limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame-
- ter. The limit is enforced by the Postfix queue
+ Limit the time for delivery to external command,
+ for delivery via the named <b>transport</b>. The default
+ limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame-
+ ter. The limit is enforced by the Postfix queue
manager.
<b>SEE</b> <b>ALSO</b>
<a href="bounce.8.html">bounce(8)</a> non-delivery status reports
<a href="master.8.html">master(8)</a> process manager
<a href="qmgr.8.html">qmgr(8)</a> queue manager
- syslogd(8) system logging
-
PIPE(8) PIPE(8)
+ syslogd(8) system logging
+
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
-
-
postalias - Postfix alias database maintenance
<b>SYNOPSIS</b>
- <b>postalias</b> [<b>-c</b> <i>config_dir</i>] [<b>-i</b>] [<b>-v</b>] [<b>-w</b>]
+ <b>postalias</b> [<b>-ivw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
[<i>file_type</i>:]<i>file_name</i> ...
<b>DESCRIPTION</b>
- The <b>postalias</b> command creates a new Postfix alias
- database, or updates an existing one. The input and output
- file formats are expected to be compatible with Sendmail
- version 8, and are expected to be suitable for the use as
- NIS alias maps.
+ The <b>postalias</b> command creates or queries one or more Post-
+ fix alias databases, or updates an existing one. The input
+ and output file formats are expected to be compatible with
+ Sendmail version 8, and are expected to be suitable for
+ the use as NIS alias maps.
While a database update is in progress, signal delivery is
postponed, and an exclusive, advisory, lock is placed on
default, <b>postalias</b> creates a new database from the
entries in <b>file</b><i>_</i><b>name</b>.
+ <b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
+ first value found on the standard output stream.
+ The exit status is non-zero if the requested infor-
+ mation was not found.
+
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>-w</b> Do not warn about duplicate entries; silently
<i>file_type</i>
The type of database to be produced.
- <b>btree</b> The output is a btree file, named
- <i>file_name</i><b>.db</b>. This is available only on
- systems with support for <b>db</b> databases.
-
- <b>dbm</b> The output consists of two files, named
- <i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
- available only on systems with support for
- <b>dbm</b> databases.
-
- <b>hash</b> The output is a hashed file, named
+ <b>btree</b> The output is a btree file, named
<i>file_name</i><b>.db</b>. This is available only on
systems with support for <b>db</b> databases.
+ <b>dbm</b> The output consists of two files, named
+ <i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
+ available only on systems with support for
+
1
POSTALIAS(1) POSTALIAS(1)
- When no <i>file_type</i> is specified, the software uses
- the database type specified via the <b>database</b><i>_</i><b>type</b>
- configuration parameter. The default value for
+ <b>dbm</b> databases.
+
+ <b>hash</b> The output is a hashed file, named
+ <i>file_name</i><b>.db</b>. This is available only on
+ systems with support for <b>db</b> databases.
+
+ When no <i>file_type</i> is specified, the software uses
+ the database type specified via the <b>database</b><i>_</i><b>type</b>
+ configuration parameter. The default value for
this parameter depends on the host environment.
<i>file_name</i>
- The name of the alias database source file when
+ The name of the alias database source file when
rebuilding a database.
<b>DIAGNOSTICS</b>
- Problems are logged to the standard error stream. No out-
+ Problems are logged to the standard error stream. No out-
put means no problems were detected. Duplicate entries are
skipped and are flagged with a warning.
Enable verbose logging for debugging purposes.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
details and for default values.
<b>database</b><i>_</i><b>type</b>
- Default alias database type. On many UNIX systems,
+ Default alias database type. On many UNIX systems,
the default type is either <b>dbm</b> or <b>hash</b>.
<b>STANDARDS</b>
<a href="sendmail.1.html">sendmail(1)</a> mail posting and compatibility interface.
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
-
-
-
-
-
-
2
postmap - Postfix lookup table management
<b>SYNOPSIS</b>
- <b>postmap</b> [<b>-c</b> <i>config_dir</i>] [<b>-i</b>] [<b>-v</b>] [<b>-w</b>]
- [<i>file_type</i>:]<i>file_name</i>
+ <b>postmap</b> [<b>-ivw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
+ [<i>file_type</i>:]<i>file_name</i> ...
<b>DESCRIPTION</b>
- The <b>postmap</b> command creates a new Postfix lookup table, or
- updates an existing one. The input and output formats are
- expected to be compatible with:
+ The <b>postmap</b> command creates or queries one or more Postfix
+ lookup tables, or updates an existing one. The input and
+ output file formats are expected to be compatible with:
<b>makemap</b> <i>file_type</i> <i>file_name</i> < <i>file_name</i>
default, <b>postmap</b> creates a new database from the
entries in <b>file</b><i>_</i><b>name</b>.
- <b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
- verbose.
+ <b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
+ first value found on the standard output stream.
+ The exit status is non-zero if the requested infor-
+ mation was not found.
- B-w Do not warn about duplicate entries; silently
POSTMAP(1) POSTMAP(1)
+ <b>-v</b> Enable verbose logging for debugging purposes. Mul-
+ tiple <b>-v</b> options make the software increasingly
+ verbose.
+
+ <b>-w</b> Do not warn about duplicate entries; silently
ignore them.
Arguments:
<i>file_type</i>
The type of database to be produced.
- <b>btree</b> The output file is a btree file, named
- <i>file_name</i><b>.db</b>. This is available only on
+ <b>btree</b> The output file is a btree file, named
+ <i>file_name</i><b>.db</b>. This is available only on
systems with support for <b>db</b> databases.
- <b>dbm</b> The output consists of two files, named
- <i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
- available only on systems with support for
+ <b>dbm</b> The output consists of two files, named
+ <i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
+ available only on systems with support for
<b>dbm</b> databases.
- <b>hash</b> The output file is a hashed file, named
- <i>file_name</i><b>.db</b>. This is available only on
+ <b>hash</b> The output file is a hashed file, named
+ <i>file_name</i><b>.db</b>. This is available only on
systems with support for <b>db</b> databases.
- When no <i>file_type</i> is specified, the software uses
- the database type specified via the <b>database</b><i>_</i><b>type</b>
+ When no <i>file_type</i> is specified, the software uses
+ the database type specified via the <b>database</b><i>_</i><b>type</b>
configuration parameter.
<i>file_name</i>
- The name of the lookup table source file when
+ The name of the lookup table source file when
rebuilding a database.
<b>DIAGNOSTICS</b>
<b>CONFIGURATION</b> <b>PARAMETERS</b>
<b>database</b><i>_</i><b>type</b>
- Default output database type. On many UNIX sys-
- tems, the default database type is either <b>hash</b> or
+ Default output database type. On many UNIX sys-
+ tems, the default database type is either <b>hash</b> or
<b>dbm</b>.
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
-<b>AUTHOR(S)</b>
- Wietse Venema
- IBM T.J. Watson Research
- P.O. Box 704
-
2
POSTMAP(1) POSTMAP(1)
+<b>AUTHOR(S)</b>
+ Wietse Venema
+ IBM T.J. Watson Research
+ P.O. Box 704
Yorktown Heights, NY 10598, USA
-
-
-
-
Log mailer traffic. Use the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> and
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> configuration parameters instead.
+ <b>-U</b> (ignored)
+ Initial user submission.
+
<b>-bd</b> Go into daemon mode. This mode of operation is
implemented by executing the <b>postfix</b> <b>start</b> command.
address where delivery problems are sent to, unless
the message contains an <b>Errors-To:</b> message header.
- <b>-h</b> <i>hop_count</i> (ignored)
- Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
- tion parameter instead.
SENDMAIL(1) SENDMAIL(1)
+ <b>-h</b> <i>hop_count</i> (ignored)
+ Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura-
+ tion parameter instead.
+
<b>-i</b> (ignored)
Lines beginning with "." get special treatment only
with <b>-bs</b>.
<b>SECURITY</b>
By design, this program is not set-user (or group) id.
- However, it must handle data from untrusted users or
- untrusted machines. Thus, the usual precautions need to
- be taken against malicious inputs.
-
SENDMAIL(1) SENDMAIL(1)
+ However, it must handle data from untrusted users or
+ untrusted machines. Thus, the usual precautions need to
+ be taken against malicious inputs.
+
<b>DIAGNOSTICS</b>
Problems are logged to <b>syslogd</b>(8) and to the standard
error stream.
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
List of domain or network patterns. When a remote
- host matches a pattern, increase the verbose log-
- ging level by the amount specified in the
- <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
-
-
+ host matches a pattern, increase the verbose
SENDMAIL(1) SENDMAIL(1)
+ logging level by the amount specified in the
+ <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter.
+
<b>fork</b><i>_</i><b>attempts</b>
Number of attempts to <b>fork</b>() a process before giv-
ing up.
Wietse Venema
IBM T.J. Watson Research
P.O. Box 704
+
+
+
+ 5
+
+
+
+
+
+SENDMAIL(1) SENDMAIL(1)
+
+
Yorktown Heights, NY 10598, USA
- 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 6
</pre> </body> </html>
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
#define COPY_ATTR(attr) attr.sender, attr.delivered, attr.fp
#define MSG_LOG_STATE(m, p) \
- msg_info("%s[%d]: local %s recip %s exten %s deliver %s", m, \
+ msg_info("%s[%d]: local %s recip %s exten %s deliver %s exp_from %s", \
+ m, \
p.level, \
p.msg_attr.local ? p.msg_attr.local : "" , \
p.msg_attr.recipient ? p.msg_attr.recipient : "", \
p.msg_attr.extension ? p.msg_attr.extension : "", \
- p.msg_attr.delivered ? p.msg_attr.delivered : "")
+ p.msg_attr.delivered ? p.msg_attr.delivered : "", \
+ p.msg_attr.exp_from ? p.msg_attr.exp_from : "")
/*
* "inner" nodes of the delivery graph.
.na
.nf
.fi
-\fBpostalias\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-[\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
+\fBpostalias\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
+[\fIfile_type\fR:]\fIfile_name\fR ...
.SH DESCRIPTION
.ad
.fi
-The \fBpostalias\fR command creates a new Postfix alias database,
-or updates an existing one. The input and output file formats
-are expected to be compatible with Sendmail version 8, and are
-expected to be suitable for the use as NIS alias maps.
+The \fBpostalias\fR command creates or queries one or more Postfix
+alias databases, or updates an existing one. The input and output
+file formats are expected to be compatible with Sendmail version 8,
+and are expected to be suitable for the use as NIS alias maps.
While a database update is in progress, signal delivery is
postponed, and an exclusive, advisory, lock is placed on the
Incremental mode. Read entries from standard input and do not
truncate an existing database. By default, \fBpostalias\fR creates
a new database from the entries in \fBfile_name\fR.
+.IP "\fB-q \fIkey\fR"
+Search the specified maps for \fIkey\fR and print the first value
+found on the standard output stream. The exit status is non-zero
+if the requested information was not found.
.IP \fB-v\fR
Enable verbose logging for debugging purposes. Multiple \fB-v\fR
options make the software increasingly verbose.
.na
.nf
.fi
-\fBpostmap\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-[\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR
+\fBpostmap\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
+[\fIfile_type\fR:]\fIfile_name\fR ...
.SH DESCRIPTION
.ad
.fi
-The \fBpostmap\fR command creates a new Postfix lookup table,
-or updates an existing one. The input and output formats are
-expected to be compatible with:
+The \fBpostmap\fR command creates or queries one or more Postfix
+lookup tables, or updates an existing one. The input and output
+file formats are expected to be compatible with:
.ti +4
\fBmakemap \fIfile_type\fR \fIfile_name\fR < \fIfile_name\fR
Incremental mode. Read entries from standard input and do not
truncate an existing database. By default, \fBpostmap\fR creates
a new database from the entries in \fBfile_name\fR.
+.IP "\fB-q \fIkey\fR"
+Search the specified maps for \fIkey\fR and print the first value
+found on the standard output stream. The exit status is non-zero
+if the requested information was not found.
.IP \fB-v\fR
Enable verbose logging for debugging purposes. Multiple \fB-v\fR
options make the software increasingly verbose.
-.IP \f\B-w\fR
+.IP \fB-w\fR
Do not warn about duplicate entries; silently ignore them.
.PP
Arguments:
.IP "\fB-X \fIlog_file\fR (ignored)"
Log mailer traffic. Use the \fBdebug_peer_list\fR and
\fBdebug_peer_level\fR configuration parameters instead.
+.IP "\fB-U\fR (ignored)"
+Initial user submission.
.IP \fB-bd\fR
Go into daemon mode. This mode of operation is implemented by
executing the \fBpostfix start\fR command.
.fi
The external command attributes are given in the \fBmaster.cf\fR
file at the end of a service definition. The syntax is as follows:
-.IP "\fBflags=FR>\fR (optional)"
+.IP "\fBflags=FR.>\fR (optional)"
Optional message processing flags. By default, a message is
copied unchanged.
.RS
.IP \fBR\fR
Prepend a \fBReturn-Path:\fR message header with the envelope sender
address.
+.IP \fB.\fR
+Prepend \fB.\fR to lines starting with "\fB.\fR". This is needed
+by, for example, \fBBSMTP\fR software.
.IP \fB>\fR
Prepend \fB>\fR to lines starting with "\fBFrom \fR". This is expected
by, for example, \fBUUCP\fR software.
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
master.o: ../include/vstream.h
master.o: ../include/stringops.h
master.o: ../include/myflock.h
+master.o: ../include/watchdog.h
master.o: ../include/mail_params.h
master.o: ../include/debug_process.h
master.o: ../include/mail_task.h
multi_server.o: ../include/sane_accept.h
multi_server.o: ../include/myflock.h
multi_server.o: ../include/safe_open.h
+multi_server.o: ../include/watchdog.h
multi_server.o: ../include/mail_task.h
multi_server.o: ../include/debug_process.h
multi_server.o: ../include/mail_params.h
single_server.o: ../include/myflock.h
single_server.o: ../include/safe_open.h
single_server.o: ../include/listen.h
+single_server.o: ../include/watchdog.h
single_server.o: ../include/mail_params.h
single_server.o: ../include/mail_task.h
single_server.o: ../include/debug_process.h
trigger_server.o: ../include/myflock.h
trigger_server.o: ../include/safe_open.h
trigger_server.o: ../include/listen.h
+trigger_server.o: ../include/watchdog.h
trigger_server.o: ../include/mail_params.h
trigger_server.o: ../include/mail_task.h
trigger_server.o: ../include/debug_process.h
#include <vstream.h>
#include <stringops.h>
#include <myflock.h>
+#include <watchdog.h>
/* Global library. */
#include "master.h"
-/* master_watchdog - something got stuck */
-
-static NORETURN master_watchdog(int unused_sig)
-{
-
- /*
- * This runs as a signal handler. We should not do anything that could
- * involve memory managent, but exiting without explanation would be
- * worse.
- */
- msg_fatal("watchdog timer");
-}
-
int main(int argc, char **argv)
{
static VSTREAM *lock_fp;
int test_lock = 0;
int fd_limit = open_limit(0);
VSTRING *why;
+ WATCHDOG *watchdog;
/*
* Initialize.
* multiple things at the same time, it really is all a single thread, so
* that there are no concurrency conflicts within the master process.
*/
- signal(SIGALRM, master_watchdog);
+ watchdog = watchdog_create(1000, (WATCHDOG_FN) 0, (char *) 0);
for (;;) {
#ifdef HAS_VOLATILE_LOCKS
if (myflock(vstream_fileno(lock_fp), MYFLOCK_EXCLUSIVE) < 0)
msg_fatal("refresh exclusive lock: %m");
#endif
- alarm(1000); /* same as trigger servers */
+ watchdog_start(watchdog); /* same as trigger servers */
event_loop(-1);
if (master_gotsighup) {
msg_info("reload configuration");
#include <myflock.h>
#include <safe_open.h>
#include <listen.h>
+#include <watchdog.h>
/* Global library. */
exit(0);
}
-/* multi_server_watchdog - something got stuck */
-
-static NORETURN multi_server_watchdog(int unused_sig)
-{
-
- /*
- * This runs as a signal handler. We should not do anything that could
- * involve memory managent, but exiting without explanation would be
- * worse.
- */
- msg_fatal("watchdog timer");
-}
-
/* multi_server_abort - terminate after abnormal master exit */
static void multi_server_abort(int unused_event, char *unused_context)
int time_left = -1;
int fd;
- /*
- * Some buggy systems cause Postfix to lock up.
- */
- signal(SIGALRM, multi_server_watchdog);
- alarm(var_daemon_timeout);
-
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
int time_left = -1;
int fd;
- /*
- * Some buggy systems cause Postfix to lock up.
- */
- signal(SIGALRM, multi_server_watchdog);
- alarm(var_daemon_timeout);
-
/*
* Be prepared for accept() to fail because some other process already
* got the connection (the number of processes competing for clients is
char *lock_path;
VSTRING *why;
int alone = 0;
+ WATCHDOG *watchdog;
/*
* Process environment options as early as we can.
}
event_enable_read(MASTER_STATUS_FD, multi_server_abort, (char *) 0);
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
+ watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0);
+
+ /*
+ * The event loop, at last.
+ */
while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) {
+ if (multi_server_lock != 0) {
+ watchdog_stop(watchdog);
+ if (myflock(vstream_fileno(multi_server_lock), MYFLOCK_EXCLUSIVE) < 0)
+ msg_fatal("select lock: %m");
+ }
+ watchdog_start(watchdog);
delay = loop ? loop(multi_server_name, multi_server_argv) : -1;
- if (multi_server_lock != 0
- && myflock(vstream_fileno(multi_server_lock), MYFLOCK_EXCLUSIVE) < 0)
- msg_fatal("select lock: %m");
event_loop(delay);
}
multi_server_exit();
#include <myflock.h>
#include <safe_open.h>
#include <listen.h>
+#include <watchdog.h>
/* Global library. */
exit(0);
}
-/* single_server_watchdog - something got stuck */
-
-static NORETURN single_server_watchdog(int unused_sig)
-{
-
- /*
- * This runs as a signal handler. We should not do anything that could
- * involve memory managent, but exiting without explanation would be
- * worse.
- */
- msg_fatal("watchdog timer");
-}
-
/* single_server_abort - terminate after abnormal master exit */
static void single_server_abort(int unused_event, char *unused_context)
int time_left = -1;
int fd;
- /*
- * Some buggy systems cause Postfix to lock up.
- */
- signal(SIGALRM, single_server_watchdog);
- alarm(var_daemon_timeout);
-
/*
* Be prepared for accept() to fail because some other process already
* got the connection. We use select() + accept(), instead of simply
int time_left = -1;
int fd;
- /*
- * Some buggy systems cause Postfix to lock up.
- */
- signal(SIGALRM, single_server_watchdog);
- alarm(var_daemon_timeout);
-
/*
* Be prepared for accept() to fail because some other process already
* got the connection. We use select() + accept(), instead of simply
char *lock_path;
VSTRING *why;
int alone = 0;
+ WATCHDOG *watchdog;
/*
* Process environment options as early as we can.
}
event_enable_read(MASTER_STATUS_FD, single_server_abort, (char *) 0);
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
+ watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0);
+
+ /*
+ * The event loop, at last.
+ */
while (var_use_limit == 0 || use_count < var_use_limit) {
+ if (single_server_lock != 0) {
+ watchdog_stop(watchdog);
+ if (myflock(vstream_fileno(single_server_lock), MYFLOCK_EXCLUSIVE) < 0)
+ msg_fatal("select lock: %m");
+ }
+ watchdog_start(watchdog);
delay = loop ? loop(single_server_name, single_server_argv) : -1;
- if (single_server_lock != 0
- && myflock(vstream_fileno(single_server_lock), MYFLOCK_EXCLUSIVE) < 0)
- msg_fatal("select lock: %m");
event_loop(delay);
}
single_server_exit();
#include <myflock.h>
#include <safe_open.h>
#include <listen.h>
+#include <watchdog.h>
/* Global library. */
exit(0);
}
-/* trigger_server_watchdog - something got stuck */
-
-static NORETURN trigger_server_watchdog(int unused_sig)
-{
-
- /*
- * This runs as a signal handler. We should not do anything that could
- * involve memory managent, but exiting without explanation would be
- * worse.
- */
- msg_fatal("watchdog timer");
-}
-
/* trigger_server_abort - terminate after abnormal master exit */
static void trigger_server_abort(int unused_event, char *unused_context)
if (msg_verbose)
msg_info("%s: trigger arrived", myname);
- /*
- * Some buggy systems cause Postfix to lock up.
- */
- signal(SIGALRM, trigger_server_watchdog);
- alarm(1000);
-
/*
* Read whatever the other side wrote into the FIFO. The FIFO read end is
* non-blocking so we won't get stuck when multiple processes wake up.
if (msg_verbose)
msg_info("%s: trigger arrived", myname);
- /*
- * Some buggy systems cause Postfix to lock up.
- */
- signal(SIGALRM, trigger_server_watchdog);
- alarm(1000);
-
/*
* Read a message from a socket. Be prepared for accept() to fail because
* some other process already got the connection. The socket is
char *lock_path;
VSTRING *why;
int alone = 0;
+ WATCHDOG *watchdog;
/*
* Process environment options as early as we can.
}
event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (char *) 0);
close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC);
+ watchdog = watchdog_create(1000, (WATCHDOG_FN) 0, (char *) 0);
+
+ /*
+ * The event loop, at last.
+ */
while (var_use_limit == 0 || use_count < var_use_limit) {
+ if (trigger_server_lock != 0) {
+ watchdog_stop(watchdog);
+ if (myflock(vstream_fileno(trigger_server_lock), MYFLOCK_EXCLUSIVE) < 0)
+ msg_fatal("select lock: %m");
+ }
+ watchdog_start(watchdog);
delay = loop ? loop(trigger_server_name, trigger_server_argv) : -1;
- if (trigger_server_lock != 0
- && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_EXCLUSIVE) < 0)
- msg_fatal("select lock: %m");
event_loop(delay);
}
trigger_server_exit();
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
static int cleanup_service_error(PICKUP_INFO *info, int status)
{
msg_warn("%s: %s", info->path, cleanup_strerror(status));
- return (status == CLEANUP_STAT_BAD ?
+ return ((status & CLEANUP_STAT_BAD) ?
REMOVE_MESSAGE_FILE : KEEP_MESSAGE_FILE);
}
* easier to implement the many possible error exits without forgetting
* to close files, or to release memory.
*/
+#define PICKUP_CLEANUP_FLAGS (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_FILTER)
+
buf = vstring_alloc(100);
cleanup = mail_connect_wait(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP);
if (mail_scan(cleanup, "%s", buf) != 1
- || mail_print(cleanup, "%d", CLEANUP_FLAG_BOUNCE) != 0) {
+ || mail_print(cleanup, "%d", PICKUP_CLEANUP_FLAGS) != 0) {
status = KEEP_MESSAGE_FILE;
} else {
info->id = mystrdup(vstring_str(buf));
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
/* .fi
/* The external command attributes are given in the \fBmaster.cf\fR
/* file at the end of a service definition. The syntax is as follows:
-/* .IP "\fBflags=FR>\fR (optional)"
+/* .IP "\fBflags=FR.>\fR (optional)"
/* Optional message processing flags. By default, a message is
/* copied unchanged.
/* .RS
/* .IP \fBR\fR
/* Prepend a \fBReturn-Path:\fR message header with the envelope sender
/* address.
+/* .IP \fB.\fR
+/* Prepend \fB.\fR to lines starting with "\fB.\fR". This is needed
+/* by, for example, \fBBSMTP\fR software.
/* .IP \fB>\fR
/* Prepend \fB>\fR to lines starting with "\fBFrom \fR". This is expected
/* by, for example, \fBUUCP\fR software.
case 'F':
attr->flags |= MAIL_COPY_FROM;
break;
+ case '.':
+ attr->flags |= MAIL_COPY_DOT;
+ break;
case '>':
attr->flags |= MAIL_COPY_QUOTE;
break;
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
/* Postfix alias database maintenance
/* SYNOPSIS
/* .fi
-/* \fBpostalias\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-/* [\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
+/* \fBpostalias\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
+/* [\fIfile_type\fR:]\fIfile_name\fR ...
/* DESCRIPTION
-/* The \fBpostalias\fR command creates a new Postfix alias database,
-/* or updates an existing one. The input and output file formats
-/* are expected to be compatible with Sendmail version 8, and are
-/* expected to be suitable for the use as NIS alias maps.
+/* The \fBpostalias\fR command creates or queries one or more Postfix
+/* alias databases, or updates an existing one. The input and output
+/* file formats are expected to be compatible with Sendmail version 8,
+/* and are expected to be suitable for the use as NIS alias maps.
/*
/* While a database update is in progress, signal delivery is
/* postponed, and an exclusive, advisory, lock is placed on the
/* Incremental mode. Read entries from standard input and do not
/* truncate an existing database. By default, \fBpostalias\fR creates
/* a new database from the entries in \fBfile_name\fR.
+/* .IP "\fB-q \fIkey\fR"
+/* Search the specified maps for \fIkey\fR and print the first value
+/* found on the standard output stream. The exit status is non-zero
+/* if the requested information was not found.
/* .IP \fB-v\fR
/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
/* options make the software increasingly verbose.
vstream_fclose(source_fp);
}
+/* postalias_query - query a map and print the result to stdout */
+
+static int postalias_query(const char *map_type, const char *map_name,
+ const char *key)
+{
+ DICT *dict;
+ const char *value;
+
+ dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+ if ((value = dict_get(dict, key)) != 0) {
+ vstream_printf("%s\n", value);
+ vstream_fflush(VSTREAM_OUT);
+ }
+ dict_close(dict);
+ return (value != 0);
+}
+
/* usage - explain */
static NORETURN usage(char *myname)
{
- msg_fatal("usage: %s [-c config_dir] [-i] [-v] [-w] [output_type:]file...",
+ msg_fatal("usage: %s [-ivw] [-c config_dir] [-q key] [map_type:]file...",
myname);
}
struct stat st;
int open_flags = O_RDWR | O_CREAT | O_TRUNC;
int dict_flags = DICT_FLAG_DUP_WARN;
+ char *query = 0;
+ int found;
/*
* Be consistent with file permissions.
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "c:ivw")) > 0) {
+ while ((ch = GETOPT(argc, argv, "c:iq:vw")) > 0) {
switch (ch) {
default:
usage(argv[0]);
case 'i':
open_flags &= ~O_TRUNC;
break;
+ case 'q':
+ query = optarg;
+ break;
case 'v':
msg_verbose++;
break;
* Use the map type specified by the user, or fall back to a default
* database type.
*/
- if (optind + 1 > argc)
- usage(argv[0]);
- while (optind < argc) {
- if ((path_name = split_at(argv[optind], ':')) != 0) {
- postalias(argv[optind], path_name, open_flags, dict_flags);
- } else {
- postalias(var_db_type, argv[optind], open_flags, dict_flags);
+ if (query == 0) { /* create/update map(s) */
+ if (optind + 1 > argc)
+ usage(argv[0]);
+ while (optind < argc) {
+ if ((path_name = split_at(argv[optind], ':')) != 0) {
+ postalias(argv[optind], path_name, open_flags, dict_flags);
+ } else {
+ postalias(var_db_type, argv[optind], open_flags, dict_flags);
+ }
+ optind++;
+ }
+ exit(0);
+ } else { /* query map(s) */
+ if (optind + 1 > argc)
+ usage(argv[0]);
+ while (optind < argc) {
+ if ((path_name = split_at(argv[optind], ':')) != 0) {
+ found = postalias_query(argv[optind], path_name, query);
+ } else {
+ found = postalias_query(var_db_type, argv[optind], query);
+ }
+ if (found)
+ exit(0);
+ optind++;
}
- optind++;
+ exit(1);
}
- exit(0);
}
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
postlock.o: ../include/dot_lockfile.h
postlock.o: ../include/deliver_flock.h
postlock.o: ../include/mail_conf.h
+postlock.o: ../include/sys_exits.h
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
/* Postfix lookup table management
/* SYNOPSIS
/* .fi
-/* \fBpostmap\fR [\fB-c \fIconfig_dir\fR] [\fB-i\fR] [\fB-v\fR]
-/* [\fB-w\fR] [\fIfile_type\fR:]\fIfile_name\fR
+/* \fBpostmap\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
+/* [\fIfile_type\fR:]\fIfile_name\fR ...
/* DESCRIPTION
-/* The \fBpostmap\fR command creates a new Postfix lookup table,
-/* or updates an existing one. The input and output formats are
-/* expected to be compatible with:
+/* The \fBpostmap\fR command creates or queries one or more Postfix
+/* lookup tables, or updates an existing one. The input and output
+/* file formats are expected to be compatible with:
/*
/* .ti +4
/* \fBmakemap \fIfile_type\fR \fIfile_name\fR < \fIfile_name\fR
/* Incremental mode. Read entries from standard input and do not
/* truncate an existing database. By default, \fBpostmap\fR creates
/* a new database from the entries in \fBfile_name\fR.
+/* .IP "\fB-q \fIkey\fR"
+/* Search the specified maps for \fIkey\fR and print the first value
+/* found on the standard output stream. The exit status is non-zero
+/* if the requested information was not found.
/* .IP \fB-v\fR
/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR
/* options make the software increasingly verbose.
-/* .IP \f\B-w\fR
+/* .IP \fB-w\fR
/* Do not warn about duplicate entries; silently ignore them.
/* .PP
/* Arguments:
vstream_fclose(source_fp);
}
+/* postmap_query - query a map and print the result to stdout */
+
+static int postmap_query(const char *map_type, const char *map_name,
+ const char *key)
+{
+ DICT *dict;
+ const char *value;
+
+ dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+ if ((value = dict_get(dict, key)) != 0) {
+ vstream_printf("%s\n", value);
+ vstream_fflush(VSTREAM_OUT);
+ }
+ dict_close(dict);
+ return (value != 0);
+}
+
/* usage - explain */
static NORETURN usage(char *myname)
{
- msg_fatal("usage: %s [-c config_dir] [-i] [-v] [-w] [output_type:]file...",
+ msg_fatal("usage: %s [-ivw] [-c config_dir] [-q key] [map_type:]file...",
myname);
}
struct stat st;
int open_flags = O_RDWR | O_CREAT | O_TRUNC;
int dict_flags = DICT_FLAG_DUP_WARN;
+ char *query = 0;
+ int found;
/*
* Be consistent with file permissions.
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "c:ivw")) > 0) {
+ while ((ch = GETOPT(argc, argv, "c:iq:vw")) > 0) {
switch (ch) {
default:
usage(argv[0]);
case 'i':
open_flags &= ~O_TRUNC;
break;
+ case 'q':
+ query = optarg;
+ break;
case 'v':
msg_verbose++;
break;
* Use the map type specified by the user, or fall back to a default
* database type.
*/
- if (optind + 1 > argc)
- usage(argv[0]);
- while (optind < argc) {
- if ((path_name = split_at(argv[optind], ':')) != 0) {
- postmap(argv[optind], path_name, open_flags, dict_flags);
- } else {
- postmap(var_db_type, argv[optind], open_flags, dict_flags);
+ if (query == 0) { /* create/update map(s) */
+ if (optind + 1 > argc)
+ usage(argv[0]);
+ while (optind < argc) {
+ if ((path_name = split_at(argv[optind], ':')) != 0) {
+ postmap(argv[optind], path_name, open_flags, dict_flags);
+ } else {
+ postmap(var_db_type, argv[optind], open_flags, dict_flags);
+ }
+ optind++;
+ }
+ exit(0);
+ } else { /* query map(s) */
+ if (optind + 1 > argc)
+ usage(argv[0]);
+ while (optind < argc) {
+ if ((path_name = split_at(argv[optind], ':')) != 0) {
+ found = postmap_query(argv[optind], path_name, query);
+ } else {
+ found = postmap_query(var_db_type, argv[optind], query);
+ }
+ if (found)
+ exit(0);
+ optind++;
}
- optind++;
+ exit(1);
}
- exit(0);
}
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
char *var_relocated_maps;
char *var_virtual_maps;
char *var_defer_xports;
+bool var_allow_min_user;
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
VAR_DEST_RCPT_LIMIT, DEF_DEST_RCPT_LIMIT, &var_dest_rcpt_limit, 0, 0,
0,
};
+ static CONFIG_BOOL_TABLE bool_table[] = {
+ VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user,
+ 0,
+ };
/*
* Use the trigger service skeleton, because no-one else should be
qmgr_active_defer(MAIL_QUEUE_ACTIVE, queue_id, var_min_backoff_time);
} else {
- /*
- * Reset the defer log. Leave the bounce log alone; if it is still
- * around, something did not send it previously.
- */
- if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
- msg_fatal("%s: %s: remove %s %s: %m", myname,
- queue_id, MAIL_QUEUE_DEFER, queue_id);
-
/*
* Special case if all recipients were already delivered. Send any
* bounces and clean up.
}
}
+ /*
+ * Bounce recipient addresses that start with `-'. External commands
+ * may misinterpret such addresses as command-line options.
+ *
+ * In theory I could say people should always carefully set up their
+ * master.cf pipe mailer entries with `--' before the first
+ * non-option argument, but mistakes will happen regardless.
+ *
+ * Therefore the protection is put in place here, in the queue manager,
+ * where it cannot be bypassed.
+ */
+ if (var_allow_min_user == 0 && recipient->address[0] == '-') {
+ qmgr_bounce_recipient(message, recipient,
+ "invalid recipient syntax: \"%s\"",
+ recipient->address);
+ continue;
+ }
+
/*
* Queues are identified by the transport name and by the next-hop
* hostname. When the destination is local (no next hop), derive the
qmgr_message_free(message);
return (0);
} else {
+
+ /*
+ * Reset the defer log. This code should not be here, but we must
+ * reset the defer log *after* acquiring the exclusive lock on the
+ * queue file and *before* resolving new recipients. Since all those
+ * operations are encapsulated so nicely by this routine, the defer
+ * log reset has to be done here as well.
+ */
+ if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
+ msg_fatal("%s: %s: remove %s %s: %m", myname,
+ queue_id, MAIL_QUEUE_DEFER, queue_id);
qmgr_message_sort(message);
qmgr_message_resolve(message);
qmgr_message_sort(message);
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
/* .IP "\fB-X \fIlog_file\fR (ignored)"
/* Log mailer traffic. Use the \fBdebug_peer_list\fR and
/* \fBdebug_peer_level\fR configuration parameters instead.
+/* .IP "\fB-U\fR (ignored)"
+/* Initial user submission.
/* .IP \fB-bd\fR
/* Go into daemon mode. This mode of operation is implemented by
/* executing the \fBpostfix start\fR command.
optind++;
continue;
}
- if ((c = GETOPT(argc, argv, "B:C:F:IN:R:X:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
+ if ((c = GETOPT(argc, argv, "B:C:F:IN:R:UX:b:ce:f:h:imno:p:r:q:tvx")) <= 0)
break;
switch (c) {
default:
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
tidy: clean
-smtpd_token_test: smtpd_token_test.c smtpd_token.o $(LIBS)
- $(CC) $(CFLAGS) -DTEST -o $@ $@.c smtpd_token.o $(LIBS) $(SYSLIBS)
-
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
@make -f Makefile.in Makefile
-tests: smtpd_check_test smtpd_check_test2
+tests: smtpd_check_test smtpd_check_test2 smtpd_token_test
smtpd_check_test: smtpd_check smtpd_check.in smtpd_check.ref
../postmap/postmap smtpd_check_access
diff smtpd_check.ref2 smtpd_check.tmp
rm -f smtpd_check.tmp smtpd_check_access.*
+smtpd_token_test: smtpd_token smtpd_token.in smtpd_token.ref
+ ./smtpd_token <smtpd_token.in >smtpd_token.tmp 2>&1
+ diff smtpd_token.ref smtpd_token.tmp
+ rm -f smtpd_token.tmp
+
# do not edit below this line - it is generated by 'make depend'
smtpd.o: smtpd.c
smtpd.o: ../include/sys_defs.h
smtpd.o: ../include/mail_flush.h
smtpd.o: ../include/mail_stream.h
smtpd.o: ../include/mail_queue.h
+smtpd.o: ../include/tok822.h
+smtpd.o: ../include/resolve_clnt.h
smtpd.o: ../include/mail_server.h
smtpd.o: smtpd_token.h
smtpd.o: smtpd.h
smtpd_check.o: ../include/mymalloc.h
smtpd_check.o: ../include/dict.h
smtpd_check.o: ../include/vstream.h
+smtpd_check.o: ../include/htable.h
smtpd_check.o: ../include/dns.h
smtpd_check.o: ../include/namadr_list.h
smtpd_check.o: ../include/domain_list.h
smtpd_check.o: ../include/name_mask.h
smtpd_check.o: ../include/resolve_local.h
smtpd_check.o: ../include/own_inet_addr.h
+smtpd_check.o: ../include/mail_conf.h
+smtpd_check.o: ../include/maps.h
+smtpd_check.o: ../include/mail_addr_find.h
smtpd_check.o: smtpd.h
smtpd_check.o: ../include/mail_stream.h
smtpd_check.o: smtpd_check.h
#include <mail_flush.h>
#include <mail_stream.h>
#include <mail_queue.h>
+#include <tok822.h>
/* Single-threaded server skeleton. */
state->dest = mail_stream_service(MAIL_CLASS_PRIVATE,
MAIL_SERVICE_CLEANUP);
if (state->dest == 0
- || mail_print(state->dest->stream, "%d", CLEANUP_FLAG_NONE) != 0)
+ || mail_print(state->dest->stream, "%d", CLEANUP_FLAG_FILTER) != 0)
msg_fatal("unable to connect to the %s %s service",
MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP);
}
state->queue_id = mystrdup(state->dest->id);
}
+/* extract_addr - extract address from rubble */
+
+static VSTRING *extract_addr(SMTPD_STATE *state, VSTRING *buf)
+{
+ char *myname = "extract_addr";
+ TOK822 *tree;
+ TOK822 *tp;
+ int naddr;
+ int non_addr;
+
+ /*
+ * Some mailers send RFC822-style address forms (with comments and such)
+ * in SMTP envelopes. We cannot blame users for this: the blame is with
+ * programmers violating the RFC, and with sendmail for being permissive.
+ *
+ * Extract the address from any surrounding junk. XXX Because of this, the
+ * SMTP command tokenizer must leave the address in externalized (quoted)
+ * form.
+ */
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+ if (msg_verbose)
+ msg_info("%s: input: %s", myname, STR(buf));
+ tree = tok822_parse(STR(buf));
+ for (naddr = non_addr = 0, tp = tree; tp != 0; tp = tp->next) {
+ if (tp->type == TOK822_ADDR) {
+ if (++naddr == 1)
+ tok822_internalize(buf, tp->head, TOK822_STR_DEFL);
+ else if (naddr == 2)
+ msg_warn("Multiple addresses from %s in %s command: %s",
+ state->namaddr, state->where, STR(buf));
+ } else if (tp->type != '<' && tp->type != '>') {
+ if (++non_addr == 1)
+ msg_warn("Non-RFC 821 syntax from %s in %s command: %s",
+ state->namaddr, state->where, STR(buf));
+ }
+ }
+ tok822_free_tree(tree);
+ if (msg_verbose)
+ msg_info("%s: result: %s", myname, STR(buf));
+ return (buf);
+}
+
/* mail_cmd - process MAIL command */
static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
smtpd_chat_reply(state, "503 Error: nested MAIL command");
return (-1);
}
- if (argc < 4
- || strcasecmp(argv[1].strval, "from") != 0
- || strcmp(argv[2].strval, ":") != 0) {
+ if (argc < 3
+ || strcasecmp(argv[1].strval, "from:") != 0) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Syntax: MAIL FROM: <address>");
return (-1);
}
- for (narg = 4; narg < argc; narg++) {
+ argv[2].strval = STR(extract_addr(state, argv[2].vstrval));
+ for (narg = 3; narg < argc; narg++) {
arg = argv[narg].strval;
if (strcasecmp(arg, "BODY=8BITMIME") == 0
|| strcasecmp(arg, "BODY=7BIT") == 0) {
state->time = time((time_t *) 0);
if (SMTPD_STAND_ALONE(state) == 0
&& var_smtpd_delay_reject == 0
- && (err = smtpd_check_mail(state, argv[3].strval)) != 0) {
+ && (err = smtpd_check_mail(state, argv[2].strval)) != 0) {
smtpd_chat_reply(state, "%s", err);
return (-1);
}
*/
rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld",
(long) time((time_t *) 0));
- rec_fputs(state->cleanup, REC_TYPE_FROM, argv[3].strval);
- state->sender = mystrdup(argv[3].strval);
+ rec_fputs(state->cleanup, REC_TYPE_FROM, argv[2].strval);
+ state->sender = mystrdup(argv[2].strval);
smtpd_chat_reply(state, "250 Ok");
return (0);
}
smtpd_chat_reply(state, "503 Error: need MAIL command");
return (-1);
}
- if (argc != 4
- || strcasecmp(argv[1].strval, "to") != 0
- || strcmp(argv[2].strval, ":") != 0) {
+ if (argc != 3
+ || strcasecmp(argv[1].strval, "to:") != 0) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "501 Syntax: RCPT TO: <address>");
return (-1);
}
+ argv[2].strval = STR(extract_addr(state, argv[2].vstrval));
if (var_smtpd_rcpt_limit && state->rcpt_count >= var_smtpd_rcpt_limit) {
state->error_mask |= MAIL_ERROR_POLICY;
smtpd_chat_reply(state, "452 Error: too many recipients");
return (-1);
}
if (SMTPD_STAND_ALONE(state) == 0
- && (err = smtpd_check_rcpt(state, argv[3].strval)) != 0) {
+ && (err = smtpd_check_rcpt(state, argv[2].strval)) != 0) {
smtpd_chat_reply(state, "%s", err);
return (-1);
}
*/
state->rcpt_count++;
if (state->recipient == 0)
- state->recipient = mystrdup(argv[3].strval);
- rec_fputs(state->cleanup, REC_TYPE_RCPT, argv[3].strval);
+ state->recipient = mystrdup(argv[2].strval);
+ rec_fputs(state->cleanup, REC_TYPE_RCPT, argv[2].strval);
smtpd_chat_reply(state, "250 Ok");
return (0);
}
int first = 1;
/*
- * Sanity checks.
+ * Sanity checks. With ESMTP command pipelining the client can send DATA
+ * before all recipients are rejected, so don't report that as a protocol
+ * error.
*/
if (state->rcpt_count == 0) {
- state->error_mask |= MAIL_ERROR_PROTOCOL;
+ if (state->cleanup == 0)
+ state->error_mask |= MAIL_ERROR_PROTOCOL;
smtpd_chat_reply(state, "503 Error: need RCPT command");
return (-1);
}
"%d <%s>: %s rejected: Access denied",
var_access_map_code, reply_name, reply_class));
+ /*
+ * All-numeric result probably means OK - some out-of-band authentication
+ * mechanism uses this as time stamp.
+ */
+ if (value[strcspn(value, "0123456789")] == 0)
+ return (SMTPD_CHECK_OK);
+
/*
* 4xx or 5xx means NO as well. smtpd_check_reject() will validate the
* response status code.
/* #include <smtpd_token.h>
/*
/* typedef struct {
- int tokval;
- char *strval;
+/* .in +4
+/* char *strval;
+/* /* other stuff... */
+/* .in -4
/* } SMTPD_TOKEN;
/*
/* int smtpd_token(str, argvp)
/* via the function return value.
/*
/* Token types:
-/* .IP SMTPD_TOK_ADDR
-/* The token is of the form <text>, not including the angle brackets.
/* .IP SMTPD_TOK_OTHER
/* The token is something else.
/* .IP SMTPD_TOK_ERROR
/* BUGS
/* This tokenizer understands just enough to tokenize SMTPD commands.
/* It understands backslash escapes, white space, quoted strings,
-/* and addresses (including quoted text) enclosed by < and >. Any
-/* other sequence of characters is lumped together as one token.
+/* and addresses (including quoted text) enclosed by < and >.
+/* The input is broken up into tokens by whitespace, except for
+/* whitespace that is protected by quites etc.
/* LICENSE
/* .ad
/* .fi
#include <sys_defs.h>
#include <ctype.h>
#include <string.h>
+#include <unistd.h>
/* Utility library. */
#include "smtpd_token.h"
- /*
- * Macros to make complex code more readable.
- */
-#define COLLECT(cp,vp,c,cond) { \
- while ((c = *cp) != 0) { \
- if (c == '\\') { \
- cp++; \
- if ((c = *cp) == 0) \
- break; \
- } else if (!(cond)) { \
- break; \
- } \
- cp++; \
- VSTRING_ADDCH(vp, c); \
- } \
- }
-
/* smtp_quoted - read until closing quote */
-static char *smtp_quoted(char *cp, SMTPD_TOKEN *arg, int last)
+static char *smtp_quoted(char *cp, SMTPD_TOKEN *arg, int start, int last)
{
+ static VSTRING *stack;
int c;
- while ((c = *cp) != 0) {
+ if (stack == 0)
+ stack = vstring_alloc(1);
+ VSTRING_RESET(stack);
+ VSTRING_ADDCH(stack, last);
+
+ VSTRING_ADDCH(arg->vstrval, start);
+ for (;;) {
+ if ((c = *cp) == 0)
+ break;
cp++;
- if (c == '\\') { /* parse escape sequence */
- if ((c = *cp) == 0)
- break; /* end of input, punt */
- cp++;
- VSTRING_ADDCH(arg->vstrval, c); /* store escaped character */
- } else if (c == last) {
- return (cp); /* closing quote */
- } else if (c == '"') {
- cp = smtp_quoted(cp, arg, c); /* recurse */
+ VSTRING_ADDCH(arg->vstrval, c);
+ if (c == vstring_end(stack)[-1]) { /* closing quote etc. */
+ vstring_truncate(stack, VSTRING_LEN(stack) - 1);
+ if (VSTRING_LEN(stack) == 0)
+ break;
} else {
- VSTRING_ADDCH(arg->vstrval, c); /* store character */
+ if (c == '\\') { /* parse escape sequence */
+ if ((c = *cp) == 0)
+ break;
+ cp++;
+ VSTRING_ADDCH(arg->vstrval, c);
+ } else if (c == '"') {
+ VSTRING_ADDCH(stack, '"'); /* highest precedence */
+ } else if (c == '(' && vstring_end(stack)[-1] != '"') {
+ VSTRING_ADDCH(stack, ')'); /* medium precedence */
+ } else if (c == '<' && vstring_end(stack)[-1] == '>') {
+ VSTRING_ADDCH(stack, '>'); /* lowest precedence */
+ }
}
}
- arg->tokval = SMTPD_TOK_ERROR; /* missing end */
return (cp);
}
static char *smtp_next_token(char *cp, SMTPD_TOKEN *arg)
{
- char *special = "<[\">]:";
int c;
VSTRING_RESET(arg->vstrval);
- arg->tokval = SMTPD_TOK_OTHER;
- for (;;) {
- if ((c = *cp++) == 0) {
- return (0);
- } else if (ISSPACE(c)) { /* whitespace, skip */
- while (ISSPACE(*cp))
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+#define STREQ(x,y,l) ((x)[0] == (x)[0] && strncasecmp((x), (y), (l)) == 0)
+
+ while ((c = *cp) != 0) {
+ cp++;
+ if (ISSPACE(c)) { /* whitespace, skip */
+ while (*cp && ISSPACE(*cp))
cp++;
- continue;
+ if (LEN(arg->vstrval) > 0) /* end of token */
+ break;
} else if (c == '<') { /* <stuff> */
- arg->tokval = SMTPD_TOK_ADDR;
- cp = smtp_quoted(cp, arg, '>');
- break;
- } else if (c == '[') { /* [stuff], keep [] */
- VSTRING_ADDCH(arg->vstrval, c);
- cp = smtp_quoted(cp, arg, ']');
- if (cp[-1] == ']')
- VSTRING_ADDCH(arg->vstrval, ']');
- break;
- } else if (c == '"') { /* string */
- cp = smtp_quoted(cp, arg, c);
- break;
- } else if (ISCNTRL(c) || strchr(special, c)) {
+ cp = smtp_quoted(cp, arg, c, '>');
+ } else if (c == '[') { /* [stuff] */
+ cp = smtp_quoted(cp, arg, c, ']');
+ } else if (c == '"') { /* "stuff" */
+ cp = smtp_quoted(cp, arg, c, c);
+ } else if (c == ':') { /* this is gross, but... */
VSTRING_ADDCH(arg->vstrval, c);
- break;
+ if (STREQ(STR(arg->vstrval), "to:", LEN(arg->vstrval))
+ || STREQ(STR(arg->vstrval), "from:", LEN(arg->vstrval)))
+ break;
} else { /* other */
- if (c == '\\')
+ if (c == '\\') {
if ((c = *cp) == 0)
break;
+ cp++;
+ }
VSTRING_ADDCH(arg->vstrval, c);
- COLLECT(cp, arg->vstrval, c,
- !ISSPACE(c) && !ISCNTRL(c) && !strchr(special, c));
- break;
}
}
+ if (LEN(arg->vstrval) == 0) /* no token found */
+ return (0);
VSTRING_TERMINATE(arg->vstrval);
arg->strval = vstring_str(arg->vstrval);
return (cp);
if (smtp_argv == 0)
smtp_argv = (SMTPD_TOKEN *) mvect_alloc(&mvect, sizeof(*smtp_argv), 1,
- smtpd_token_init, (MVECT_FN) 0);
+ smtpd_token_init, (MVECT_FN) 0);
for (n = 0; /* void */ ; n++) {
smtp_argv = (SMTPD_TOKEN *) mvect_realloc(&mvect, n + 1);
if ((cp = smtp_next_token(cp, smtp_argv + n)) == 0)
int i;
for (;;) {
- vstream_printf("enter SMTPD command: ");
+ if (isatty(STDIN_FILENO))
+ vstream_printf("enter SMTPD command: ");
vstream_fflush(VSTREAM_OUT);
if (vstring_fgets(vp, VSTREAM_IN) == 0)
break;
+ if (*vstring_str(vp) == '#')
+ continue;
+ if (!isatty(STDIN_FILENO))
+ vstream_fputs(vstring_str(vp), VSTREAM_OUT);
tok_argc = smtpd_token(vstring_str(vp), &tok_argv);
- for (i = 0; i < tok_argc; i++) {
- vstream_printf("Token type: %s\n",
- tok_argv[i].tokval == SMTPD_TOK_ADDR ?
- "address" : "other");
+ for (i = 0; i < tok_argc; i++)
vstream_printf("Token value: %s\n", tok_argv[i].strval);
- }
}
exit(0);
}
* External interface.
*/
typedef struct SMTPD_TOKEN {
- int tokval;
char *strval;
VSTRING *vstrval;
} SMTPD_TOKEN;
--- /dev/null
+mail from:<wietse@porcupine.org>
+mail from:<"wietse venema"@porcupine.org>
+mail from:wietse@porcupine.org
+mail from:<wietse @ porcupine.org>
+mail from:<"wietse venema"@porcupine.org ("wietse ) venema")>
+mail from:<"wietse venema" <wietse@porcupine.org>>
+mail from:<"wietse venema"@porcupine.org ( ("wietse ) venema") )>
+mail from:"wietse venema"@porcupine.org
+mail from:wietse\ venema@porcupine.org
--- /dev/null
+mail from:<wietse@porcupine.org>
+Token value: mail
+Token value: from:
+Token value: <wietse@porcupine.org>
+mail from:<"wietse venema"@porcupine.org>
+Token value: mail
+Token value: from:
+Token value: <"wietse venema"@porcupine.org>
+mail from:wietse@porcupine.org
+Token value: mail
+Token value: from:
+Token value: wietse@porcupine.org
+mail from:<wietse @ porcupine.org>
+Token value: mail
+Token value: from:
+Token value: <wietse @ porcupine.org>
+mail from:<"wietse venema"@porcupine.org ("wietse ) venema")>
+Token value: mail
+Token value: from:
+Token value: <"wietse venema"@porcupine.org ("wietse ) venema")>
+mail from:<"wietse venema" <wietse@porcupine.org>>
+Token value: mail
+Token value: from:
+Token value: <"wietse venema" <wietse@porcupine.org>>
+mail from:<"wietse venema"@porcupine.org ( ("wietse ) venema") )>
+Token value: mail
+Token value: from:
+Token value: <"wietse venema"@porcupine.org ( ("wietse ) venema") )>
+mail from:"wietse venema"@porcupine.org
+Token value: mail
+Token value: from:
+Token value: "wietse venema"@porcupine.org
+mail from:wietse\ venema@porcupine.org
+Token value: mail
+Token value: from:
+Token value: wietse venema@porcupine.org
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
-TSINGLE_SERVER
-TSINK_COMMAND
-TSINK_STATE
--TSMTPD_REST_TABLE
-TSMTPD_STATE
-TSMTPD_TOKEN
-TSMTP_ADDR
-TVSTREAM_POPEN_ARGS
-TVSTRING
-TWAIT_STATUS_T
+-TWATCHDOG
-TWATCH_FD
vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \
write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \
stream_connect.c stream_trigger.c dict_regexp.c mac_expand.c \
- clean_env.c
+ clean_env.c watchdog.c
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \
write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \
stream_connect.o stream_trigger.o dict_regexp.o mac_expand.o \
- clean_env.o
+ clean_env.o watchdog.o
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
sigdelay.h split_at.h stat_as.h stringops.h sys_defs.h \
timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \
vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
- dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h
+ dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
+ watchdog.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
fifo_rdonly_bug fifo_rdwr_bug fifo_trigger fsspace fullname \
inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \
mystrtok peer_name sigdelay translit valid_hostname vstream_popen \
- vstring vstring_vstream doze select_bug stream_test mac_expand
+ vstring vstring_vstream doze select_bug stream_test mac_expand \
+ watchdog
LIB_DIR = ../lib
INC_DIR = ../include
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+watchdog: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
vstring_vstream.o: vbuf.h
vstring_vstream.o: vstream.h
vstring_vstream.o: vstring_vstream.h
+watchdog.o: watchdog.c
+watchdog.o: sys_defs.h
+watchdog.o: msg.h
+watchdog.o: mymalloc.h
+watchdog.o: watchdog.h
writable.o: writable.c
writable.o: sys_defs.h
writable.o: msg.h
/* get configured value of "ldapsource_timeout"; default to 10 */
vstring_sprintf(config_param, "%s_timeout", ldapsource);
- dict_ldap->timeout = get_mail_conf_int(config_param, 10, 0, 0);
+ dict_ldap->timeout = get_mail_conf_int(vstring_str(config_param), 10, 0, 0);
if (msg_verbose)
msg_info("%s: %s is %d", myname, vstring_str(config_param),
dict_ldap->timeout);
/* .IP passwd.byname
/* The table is the UNIX password database. The key is a login name.
/* The result is a password file entry in passwd(5) format.
+/* .IP group.byname
+/* The table is the UNIX group database. The key is a group name.
+/* The result is a group file entry in group(5) format.
/* SEE ALSO
/* dict(3) generic dictionary manager
/* DIAGNOSTICS
/* System library. */
#include "sys_defs.h"
+#include <unistd.h>
#include <string.h>
#include <pwd.h>
+#include <grp.h>
/* Utility library. */
}
}
+/* dict_unix_getgrnam - find group table entry */
+
+static const char *dict_unix_getgrnam(DICT *unused_dict, const char *key)
+{
+ struct group *grp;
+ static VSTRING *buf;
+ char **cpp;
+
+ dict_errno = 0;
+
+ if ((grp = getgrnam(key)) == 0) {
+ return (0);
+ } else {
+ if (buf == 0)
+ buf = vstring_alloc(10);
+ vstring_sprintf(buf, "%s:%s:%d:",
+ grp->gr_name, grp->gr_passwd, grp->gr_gid);
+ for (cpp = grp->gr_mem; *cpp; cpp++) {
+ vstring_strcat(buf, *cpp);
+ if (cpp[1])
+ VSTRING_ADDCH(buf, ',');
+ }
+ VSTRING_TERMINATE(buf);
+ return (vstring_str(buf));
+ }
+}
+
/* dict_unix_update - add or update table entry */
static void dict_unix_update(DICT *dict, const char *unused_name, const char *unused_value)
};
static struct dict_unix_lookup dict_unix_lookup[] = {
"passwd.byname", dict_unix_getpwnam,
+ "group.byname", dict_unix_getgrnam,
0,
};
struct dict_unix_lookup *lp;
{
char *myname = "inet_addr_local";
struct ifconf ifc;
- struct ifreq ifreq;
struct ifreq *ifr;
struct ifreq *the_end;
int sock;
VSTRING *buf = vstring_alloc(1024);
int initial_count = addr_list->used;
+ struct in_addr addr;
if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
msg_fatal("%s: socket: %m", myname);
}
/*
- * Get the IP address of each active IP network interface.
+ * Get the address of each IP network interface. According to BIND we
+ * must include interfaces that are down because the machine may still
+ * receive packets for that address (yes, via some other interface).
+ * Having no way to verify this claim on every machine, I will give them
+ * the benefit of the doubt.
*/
the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
for (ifr = ifc.ifc_req; ifr < the_end;) {
if (ifr->ifr_addr.sa_family == AF_INET) { /* IP interface */
- ifreq = *ifr;
- if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0)
- msg_fatal("%s: ioctl SIOCGIFFLAGS: %m", myname);
- if (ifreq.ifr_flags & IFF_UP) { /* active interface */
- if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0)
- msg_fatal("%s: ioctl SIOCGIFADDR: %m", myname);
- inet_addr_list_append(addr_list,
- &(((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr));
- }
+ addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr;
+ if (addr.s_addr != INADDR_ANY) /* has IP address */
+ inet_addr_list_append(addr_list, &addr);
}
ifr = NEXT_INTERFACE(ifr);
}
char *myname = "timed_waitpid";
struct sigaction action;
struct sigaction old_action;
+ int time_left;
int wpid;
/*
if (sigaction(SIGALRM, &action, &old_action) < 0)
msg_fatal("%s: sigaction(SIGALRM): %m", myname);
timed_wait_expired = 0;
- alarm(time_limit);
+ time_left = alarm(time_limit);
/*
* Wait for only a limited amount of time.
alarm(0);
if (sigaction(SIGALRM, &old_action, (struct sigaction *) 0) < 0)
msg_fatal("%s: sigaction(SIGALRM): %m", myname);
+ if (time_left)
+ alarm(time_left);
return (wpid);
}
--- /dev/null
+/*++
+/* NAME
+/* watchdog 3
+/* SUMMARY
+/* watchdog timer
+/* SYNOPSIS
+/* #include <watchdog.h>
+/*
+/* WATCHDOG *watchdog_create(timeout, action, context)
+/* unsigned timeout;
+/* void (*action)(WATCHDOG *watchdog, char *context);
+/* char *context;
+/*
+/* void watchdog_start(watchdog)
+/* WATCHDOG *watchdog;
+/*
+/* void watchdog_stop(watchdog)
+/* WATCHDOG *watchdog;
+/*
+/* void watchdog_destroy(watchdog)
+/* WATCHDOG *watchdog;
+/* DESCRIPTION
+/* This module implements watchdog timers that are based on ugly
+/* UNIX alarm timers. The module is designed to survive systems
+/* with clocks that jump occasionally.
+/*
+/* Watchdog timers can be stacked. Only one watchdog timer can be
+/* active at a time. Only the last created watchdog timer can be
+/* manipulated. Watchdog timers must be destroyed in reverse order
+/* of creation.
+/*
+/* watchdog_create() suspends the current watchdog timer, if any,
+/* and instantiates a new watchdog timer.
+/*
+/* watchdog_start() starts or restarts the watchdog timer.
+/*
+/* watchdog_stop() stops the watchdog timer.
+/*
+/* watchdog_destroy() stops the watchdog timer, and resumes the
+/* watchdog timer instance that was suspended by watchdog_create().
+/*
+/* Arguments:
+/* .IP timeout
+/* The watchdog time limit. When the watchdog timer runs, the
+/* process must invoke watchdog_start(), watchdog_stop() or
+/* watchdog_destroy() before the time limit is reached.
+/* .IP action
+/* A null pointer, or pointer to function that is called when the
+/* watchdog alarm goes off. The default action is to terminate
+/* the process with a fatal error.
+/* .IP context
+/* Application context that is passed to the action routine.
+/* .IP watchdog
+/* Must be a pointer to the most recently created watchdog instance.
+/* This argument is checked upon each call.
+/* BUGS
+/* UNIX alarm timers are not stackable, so there can be at most one
+/* watchdog instance active at any given time.
+/* SEE ALSO
+/* msg(3) diagnostics interface
+/* DIAGNOSTICS
+/* Fatal errors: memory allocation problem, system call failure.
+/* Panics: interface violations.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <unistd.h>
+#include <signal.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <watchdog.h>
+
+/* Application-specific. */
+
+ /*
+ * Rather than having one timer that goes off when it is too late, we break
+ * up the time limit into smaller intervals so that we can deal with clocks
+ * that jump occasionally.
+ */
+#define WATCHDOG_STEPS 3
+
+ /*
+ * UNIX alarms are not stackable, but we can save and restore state, so that
+ * watchdogs can at least be nested, sort of.
+ */
+struct WATCHDOG {
+ unsigned timeout; /* our time resolution */
+ WATCHDOG_FN action; /* application routine */
+ char *context; /* application context */
+ int trip_run; /* number of successive timeouts */
+ WATCHDOG *saved_watchdog; /* saved state */
+ struct sigaction saved_action; /* saved state */
+ unsigned saved_time; /* saved state */
+};
+
+ /*
+ * However, only one watchdog instance can be current, and the caller has to
+ * restore state before a prior watchdog instance can be manipulated.
+ */
+static WATCHDOG *watchdog_curr;
+
+/* watchdog_event - handle timeout event */
+
+static void watchdog_event(int unused_sig)
+{
+ char *myname = "watchdog_event";
+ WATCHDOG *wp;
+
+ /*
+ * This routine runs as a signal handler. We should not do anything that
+ * could involve memory allocation/deallocation, but exiting without
+ * proper explanation would be unacceptable.
+ */
+ if ((wp = watchdog_curr) == 0)
+ msg_panic("%s: no instance", myname);
+ if (msg_verbose)
+ msg_info("%s: %p %d", myname, (char *) wp, wp->trip_run);
+ if (++(wp->trip_run) < WATCHDOG_STEPS) {
+ alarm(wp->timeout);
+ } else {
+ if (wp->action)
+ wp->action(wp, wp->context);
+ else
+ msg_fatal("watchdog timeout");
+ }
+}
+
+/* watchdog_create - create watchdog instance */
+
+WATCHDOG *watchdog_create(unsigned timeout, WATCHDOG_FN action, char *context)
+{
+ char *myname = "watchdog_create";
+ struct sigaction sig_action;
+ WATCHDOG *wp;
+
+ wp = (WATCHDOG *) mymalloc(sizeof(*wp));
+ if ((wp->timeout = timeout / WATCHDOG_STEPS) == 0)
+ msg_panic("%s: timeout %d is too small", myname, timeout);
+ wp->action = action;
+ wp->context = context;
+ wp->saved_watchdog = watchdog_curr;
+ wp->saved_time = alarm(0);
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_flags = SA_RESTART;
+ sig_action.sa_handler = watchdog_event;
+ if (sigaction(SIGALRM, &sig_action, &wp->saved_action) < 0)
+ msg_fatal("%s: sigaction(SIGALRM): %m", myname);
+ if (msg_verbose)
+ msg_info("%s: %p %d", myname, (char *) wp, timeout);
+ return (watchdog_curr = wp);
+}
+
+/* watchdog_destroy - destroy watchdog instance, restore state */
+
+void watchdog_destroy(WATCHDOG *wp)
+{
+ char *myname = "watchdog_destroy";
+
+ watchdog_stop(wp);
+ watchdog_curr = wp->saved_watchdog;
+ if (sigaction(SIGALRM, &wp->saved_action, (struct sigaction *) 0) < 0)
+ msg_fatal("%s: sigaction(SIGALRM): %m", myname);
+ if (wp->saved_time)
+ alarm(wp->saved_time);
+ myfree((char *) wp);
+ if (msg_verbose)
+ msg_info("%s: %p", myname, (char *) wp);
+}
+
+/* watchdog_start - enable watchdog timer */
+
+void watchdog_start(WATCHDOG *wp)
+{
+ char *myname = "watchdog_start";
+
+ if (wp != watchdog_curr)
+ msg_panic("%s: wrong watchdog instance", myname);
+ wp->trip_run = 0;
+ alarm(wp->timeout);
+ if (msg_verbose)
+ msg_info("%s: %p", myname, (char *) wp);
+}
+
+/* watchdog_stop - disable watchdog timer */
+
+void watchdog_stop(WATCHDOG *wp)
+{
+ char *myname = "watchdog_stop";
+
+ if (wp != watchdog_curr)
+ msg_panic("%s: wrong watchdog instance", myname);
+ alarm(0);
+ if (msg_verbose)
+ msg_info("%s: %p", myname, (char *) wp);
+}
+
+#ifdef TEST
+
+#include <vstream.h>
+
+main(int unused_argc, char **unused_argv)
+{
+ WATCHDOG *wp;
+
+ msg_verbose = 1;
+
+ wp = watchdog_create(10, (WATCHDOG_FN) 0, (char *) 0);
+ do {
+ watchdog_start(wp);
+ } while (VSTREAM_GETCHAR() != VSTREAM_EOF);
+ watchdog_destroy(wp);
+}
+
+#endif
--- /dev/null
+#ifndef _WATCHDOG_H_INCLUDED_
+#define _WATCHDOG_H_INCLUDED_
+
+/*++
+/* NAME
+/* watchdog 3h
+/* SUMMARY
+/* watchdog timer
+/* SYNOPSIS
+/* #include "watchdog.h"
+ DESCRIPTION
+ .nf
+
+ /*
+ * External interface.
+ */
+typedef struct WATCHDOG WATCHDOG;
+typedef void (*WATCHDOG_FN) (WATCHDOG *, char *);
+extern WATCHDOG *watchdog_create(unsigned, WATCHDOG_FN, char *);
+extern void watchdog_start(WATCHDOG *);
+extern void watchdog_stop(WATCHDOG *);
+extern void watchdog_destroy(WATCHDOG *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif