mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-31 14:17:41 +00:00
snapshot-20010707
This commit is contained in:
committed by
Viktor Dukhovni
parent
14829b5994
commit
7e8044da83
3
postfix/.indent.pro
vendored
3
postfix/.indent.pro
vendored
@@ -24,10 +24,10 @@
|
|||||||
-TDICT
|
-TDICT
|
||||||
-TDICT_DB
|
-TDICT_DB
|
||||||
-TDICT_DBM
|
-TDICT_DBM
|
||||||
|
-TDICT_DEBUG
|
||||||
-TDICT_ENV
|
-TDICT_ENV
|
||||||
-TDICT_HT
|
-TDICT_HT
|
||||||
-TDICT_LDAP
|
-TDICT_LDAP
|
||||||
-TDICT_DEBUG
|
|
||||||
-TDICT_MYSQL
|
-TDICT_MYSQL
|
||||||
-TDICT_NI
|
-TDICT_NI
|
||||||
-TDICT_NIS
|
-TDICT_NIS
|
||||||
@@ -93,6 +93,7 @@
|
|||||||
-TQMGR_RECIPIENT
|
-TQMGR_RECIPIENT
|
||||||
-TQMGR_SCAN
|
-TQMGR_SCAN
|
||||||
-TQMGR_TRANSPORT
|
-TQMGR_TRANSPORT
|
||||||
|
-TQMQPD_STATE
|
||||||
-TRECIPIENT
|
-TRECIPIENT
|
||||||
-TRECIPIENT_LIST
|
-TRECIPIENT_LIST
|
||||||
-TREC_TYPE_NAME
|
-TREC_TYPE_NAME
|
||||||
|
@@ -5261,3 +5261,51 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
Feature: address quoting and case folding flags for the
|
Feature: address quoting and case folding flags for the
|
||||||
pipe(8) mailer.
|
pipe(8) mailer.
|
||||||
|
|
||||||
|
20010611
|
||||||
|
|
||||||
|
Workaround: some MTAs fall on their face when they receive
|
||||||
|
unexpectedly long lines. From now on, Postfix defaults to
|
||||||
|
breaking long lines at 2048 (like Sendmail so it has got to
|
||||||
|
be right). To get the old, content preserving, behavior
|
||||||
|
specify "smtp_truncate_lines = no". File: smtp/smtp_proto.c.
|
||||||
|
|
||||||
|
20010614
|
||||||
|
|
||||||
|
Bugfix: did not really undo 2821 552->452 mapping.
|
||||||
|
|
||||||
|
20010628
|
||||||
|
|
||||||
|
Bugfix: postfix-script used a hard-coded maildrop group
|
||||||
|
owner instead of using the install-time specified name
|
||||||
|
stored in /etc/postfix/install.cf. Problem reported by
|
||||||
|
David Terrell @ meat.net.
|
||||||
|
|
||||||
|
20010701
|
||||||
|
|
||||||
|
Feature: mail_spool_directory ending in / causes maildir
|
||||||
|
style delivery.
|
||||||
|
|
||||||
|
Bugfix: the FreeBSD kernel parameters kern.ipc.nmbclusters
|
||||||
|
and kern.ipc.maxsockets cannot be set with sysctl commands.
|
||||||
|
File: html/faq.html. Len Conrad @ Go2France.com.
|
||||||
|
|
||||||
|
Cleanup: the virtual delivery agent was poorly integrated
|
||||||
|
so that the SMTP server and queue manager did not reject
|
||||||
|
mail for unknown users. Files: smtpd/smtpd_check.c,
|
||||||
|
*qmgr/qmgr_message.c.
|
||||||
|
|
||||||
|
20010705
|
||||||
|
|
||||||
|
Feature: QMQP server for compatibility with the ezmlm list
|
||||||
|
manager. Files: util/netstring.[hc], qmqpd/qmqpd*.c.
|
||||||
|
|
||||||
|
20010706
|
||||||
|
|
||||||
|
Feature: QMQP stress test message generator program. Files:
|
||||||
|
smtpstone/qmqp-source.c, smtpstone/qmqp-sink.c.
|
||||||
|
|
||||||
|
20010708
|
||||||
|
|
||||||
|
Bugfix: with disable_dns=yes, the SMTP client treated all
|
||||||
|
host lookup errors as permanent. File: smtp/smtp_addr.c.
|
||||||
|
@@ -6,7 +6,7 @@ DIRS = src/util src/global src/dns src/master src/postfix src/smtpstone \
|
|||||||
src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \
|
src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \
|
||||||
src/showq src/postalias src/postcat src/postconf src/postdrop \
|
src/showq src/postalias src/postcat src/postconf src/postdrop \
|
||||||
src/postkick src/postlock src/postlog src/postmap src/postsuper \
|
src/postkick src/postlock src/postlog src/postmap src/postsuper \
|
||||||
src/nqmgr src/spawn src/flush src/virtual # proto man html
|
src/nqmgr src/qmqpd src/spawn src/flush src/virtual # proto man html
|
||||||
|
|
||||||
default: update
|
default: update
|
||||||
|
|
||||||
|
39
postfix/README_QMQP
Normal file
39
postfix/README_QMQP
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
Postfix QMQP server support
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Postfix has preliminary server support for the QMQP protocol, so
|
||||||
|
that Postfix can be used as a backend for the Ezmlm-idx mailing
|
||||||
|
list manager. This support includes qmqp-source and qmqp-sink
|
||||||
|
programs for protocol stress testing.
|
||||||
|
|
||||||
|
Turning on the QMQP service
|
||||||
|
===========================
|
||||||
|
|
||||||
|
To enable QMQP server support on an existing Postfix system you
|
||||||
|
have to add the following line to /etc/postfix/master.cf:
|
||||||
|
|
||||||
|
628 inet n - n - - qmqpd
|
||||||
|
|
||||||
|
|
||||||
|
QMQP server access control
|
||||||
|
==========================
|
||||||
|
|
||||||
|
By default, the QMQP server does not accept mail from any client.
|
||||||
|
This is because the QMQP server relays mail to any destination
|
||||||
|
(the "protocol" has no provision to reject specific recipients).
|
||||||
|
|
||||||
|
To authorize QMQP clients, edit /etc/postfix/main.cf and specify
|
||||||
|
a list of client patterns.
|
||||||
|
|
||||||
|
qmqp_authorized_clients = client, client, ...
|
||||||
|
|
||||||
|
A list pattern specifies a host name, a domain name, an internet
|
||||||
|
address, or a network/mask pattern, where the mask specifies the
|
||||||
|
number of bits in the network part. When a pattern specifies a
|
||||||
|
file name, its contents are substituted for the file name; when a
|
||||||
|
pattern is a type:name table specification, table lookup is used
|
||||||
|
instead.
|
||||||
|
|
||||||
|
Patterns are separated by whitespace and/or commas. In order to
|
||||||
|
reverse the result, precede a non-file name pattern with an
|
||||||
|
exclamation point (!).
|
@@ -1,3 +1,28 @@
|
|||||||
|
Incompatible changes with snapshot-20010707
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
The SMTP client by default breaks lines > 2048 characters, in order
|
||||||
|
to avoid problems with mail delivery to fragile SMTP server software.
|
||||||
|
To get the old behavior, specify "smtp_break_lines = no" in the
|
||||||
|
Postfix main.cf file.
|
||||||
|
|
||||||
|
Major changes with snapshot-20010707
|
||||||
|
====================================
|
||||||
|
|
||||||
|
QMQP server support, so that Postfix can be used as a backend mailer
|
||||||
|
for the Ezmlm-idx mailing list manager. The service is disabled by
|
||||||
|
default. To enable, follow instructions in the README_QMQP file.
|
||||||
|
|
||||||
|
You can now reject unknown virtual(8) recipients at the SMTP port
|
||||||
|
by specifying a "domain.name whatever" entry in the tables specified
|
||||||
|
with virtual_mailbox_maps, similar to Postfix virtual(5) domains.
|
||||||
|
[virtual(8) is the Postfix virtual delivery agent, virtual(5) is
|
||||||
|
the Postfix virtual map. The two implement virtual domains in a
|
||||||
|
very different manner.]
|
||||||
|
|
||||||
|
Specify "mail_spool_directory = /var/mail/" (note the trailing "/"
|
||||||
|
character) to enable maildir format for /var/mail/username.
|
||||||
|
|
||||||
Incompatible changes with snapshot-20010610
|
Incompatible changes with snapshot-20010610
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
|
@@ -69,6 +69,7 @@
|
|||||||
# (yes) (yes) (yes) (never) (50)
|
# (yes) (yes) (yes) (never) (50)
|
||||||
# ==========================================================================
|
# ==========================================================================
|
||||||
smtp inet n - n - - smtpd
|
smtp inet n - n - - smtpd
|
||||||
|
#628 inet n - n - - qmqpd
|
||||||
pickup fifo n n n 60 1 pickup
|
pickup fifo n n n 60 1 pickup
|
||||||
cleanup unix - - n - 0 cleanup
|
cleanup unix - - n - 0 cleanup
|
||||||
qmgr fifo n - n 300 1 qmgr
|
qmgr fifo n - n 300 1 qmgr
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
*** postfix-script-nosgid Wed Mar 24 11:20:49 1999
|
*** postfix-script-nosgid Thu May 24 17:13:59 2001
|
||||||
--- postfix-script-sgid Wed Mar 24 11:20:53 1999
|
--- postfix-script-sgid Fri Jun 29 10:28:19 2001
|
||||||
***************
|
***************
|
||||||
*** 174,181 ****
|
*** 177,184 ****
|
||||||
test -d maildrop || {
|
test -d maildrop || {
|
||||||
$WARN creating missing Postfix maildrop directory
|
$WARN creating missing Postfix maildrop directory
|
||||||
mkdir maildrop || exit 1
|
mkdir maildrop || exit 1
|
||||||
@@ -10,13 +10,13 @@
|
|||||||
}
|
}
|
||||||
test -d pid || {
|
test -d pid || {
|
||||||
$WARN creating missing Postfix pid directory
|
$WARN creating missing Postfix pid directory
|
||||||
--- 174,182 ----
|
--- 177,185 ----
|
||||||
test -d maildrop || {
|
test -d maildrop || {
|
||||||
$WARN creating missing Postfix maildrop directory
|
$WARN creating missing Postfix maildrop directory
|
||||||
mkdir maildrop || exit 1
|
mkdir maildrop || exit 1
|
||||||
! chmod 1730 maildrop
|
! chmod 1730 maildrop
|
||||||
chown $mail_owner maildrop
|
chown $mail_owner maildrop
|
||||||
+ chgrp maildrop maildrop
|
+ (. $config_directory/install.cf; chgrp $setgid maildrop)
|
||||||
}
|
}
|
||||||
test -d pid || {
|
test -d pid || {
|
||||||
$WARN creating missing Postfix pid directory
|
$WARN creating missing Postfix pid directory
|
||||||
|
2
postfix/conf/postfix-script-sgid
Executable file → Normal file
2
postfix/conf/postfix-script-sgid
Executable file → Normal file
@@ -179,7 +179,7 @@ check)
|
|||||||
mkdir maildrop || exit 1
|
mkdir maildrop || exit 1
|
||||||
chmod 1730 maildrop
|
chmod 1730 maildrop
|
||||||
chown $mail_owner maildrop
|
chown $mail_owner maildrop
|
||||||
chgrp maildrop maildrop
|
(. $config_directory/install.cf; chgrp $setgid maildrop)
|
||||||
}
|
}
|
||||||
test -d pid || {
|
test -d pid || {
|
||||||
$WARN creating missing Postfix pid directory
|
$WARN creating missing Postfix pid directory
|
||||||
|
40
postfix/conf/sample-qmqpd.cf
Normal file
40
postfix/conf/sample-qmqpd.cf
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
# 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 QMQP server program.
|
||||||
|
|
||||||
|
# The qmqpd_authorized_clients parameter specifies what clients are
|
||||||
|
# allowed to connect to the QMQP server port.
|
||||||
|
#
|
||||||
|
# By default, no client is allowed to use the service. This is
|
||||||
|
# because the QMQP server will relay mail to any destination.
|
||||||
|
#
|
||||||
|
# Specify a list of client patterns. A list pattern specifies a host
|
||||||
|
# name, a domain name, an internet address, or a network/mask pattern,
|
||||||
|
# where the mask specifies the number of bits in the network part.
|
||||||
|
# When a pattern specifies a file name, its contents are substituted
|
||||||
|
# for the file name; when a pattern is a type:name table specification,
|
||||||
|
# table lookup is used instead.
|
||||||
|
#
|
||||||
|
# Patterns are separated by whitespace and/or commas. In order to
|
||||||
|
# reverse the result, precede a non-file name pattern with an
|
||||||
|
# exclamation point (!).
|
||||||
|
#
|
||||||
|
#qmqpd_authorized_clients =
|
||||||
|
|
||||||
|
# The qmqpd_error_delay parameter specifies how long the QMQP server
|
||||||
|
# will pause before sending a negative reply to the client. The
|
||||||
|
# purpose is to slow down confused or malicious clients.
|
||||||
|
#
|
||||||
|
# By default, the QMQP server pauses for 5 seconds.
|
||||||
|
#
|
||||||
|
#qmqpd_error_delay = 5s
|
||||||
|
|
||||||
|
# The qmqpd_timeout parameter specifies a time limit for network I/O
|
||||||
|
# operations. If a read or write operation blocks for more than
|
||||||
|
# $qmqpd_timeout seconds the QMQP server gives up and disconnects.
|
||||||
|
#
|
||||||
|
# By default, the QMQP server runs out of patience after 300 seconds.
|
||||||
|
#
|
||||||
|
#qmqpd_timeout = 300s
|
@@ -65,6 +65,14 @@ smtp_never_send_ehlo = no
|
|||||||
#
|
#
|
||||||
#smtp_bind_address=111.222.333.444
|
#smtp_bind_address=111.222.333.444
|
||||||
|
|
||||||
|
# The smtp_break_lines parameter controls whether the SMTP client
|
||||||
|
# will break lines longer than $line_length_limit characters.
|
||||||
|
#
|
||||||
|
# By default, line breaking is turned on, because some fragile SMTP
|
||||||
|
# server implementations cannot receive mail with long lines.
|
||||||
|
#
|
||||||
|
#smtp_break_lines = yes
|
||||||
|
|
||||||
# The smtp_skip_4xx_greeting parameter controls what happens when
|
# The smtp_skip_4xx_greeting parameter controls what happens when
|
||||||
# an SMTP server greets us with a 4XX status code (go away, try
|
# an SMTP server greets us with a 4XX status code (go away, try
|
||||||
# again later).
|
# again later).
|
||||||
|
@@ -5,7 +5,7 @@ SHELL = /bin/sh
|
|||||||
DAEMONS = bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
|
DAEMONS = bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \
|
||||||
lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
|
lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \
|
||||||
showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
|
showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \
|
||||||
nqmgr.8.html spawn.8.html flush.8.html virtual.8.html
|
nqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html
|
||||||
COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
|
COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \
|
||||||
postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
|
postconf.1.html postfix.1.html postkick.1.html postlock.1.html \
|
||||||
postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
|
postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \
|
||||||
@@ -68,6 +68,9 @@ pipe.8.html: ../src/pipe/pipe.c
|
|||||||
qmgr.8.html: ../src/qmgr/qmgr.c
|
qmgr.8.html: ../src/qmgr/qmgr.c
|
||||||
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
|
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
|
||||||
|
|
||||||
|
qmqpd.8.html: ../src/qmqpd/qmqpd.c
|
||||||
|
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
|
||||||
|
|
||||||
showq.8.html: ../src/showq/showq.c
|
showq.8.html: ../src/showq/showq.c
|
||||||
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
|
srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@
|
||||||
|
|
||||||
|
@@ -94,6 +94,12 @@ domains with "relay access denied"</a>
|
|||||||
<li><a href="#broken_transport">Mail delivery fails with: "unknown
|
<li><a href="#broken_transport">Mail delivery fails with: "unknown
|
||||||
mail transport error"</a>
|
mail transport error"</a>
|
||||||
|
|
||||||
|
<li><a href="#msql_limit">Too many connections</a>
|
||||||
|
|
||||||
|
<li><a href="#reiser_bugs">write queue file: No such file or directory</a>
|
||||||
|
|
||||||
|
<li><a href="#reiser_bugs">write queue file: Unknown error 4294967289</a>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -1033,7 +1039,7 @@ Berkeley DB library version.
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<a name="nosuid"><h1>sendmail has set-uid root file permissions, or is run from a
|
<a name="nosuid"><h3>sendmail has set-uid root file permissions, or is run from a
|
||||||
set-uid root process</h3></a>
|
set-uid root process</h3></a>
|
||||||
|
|
||||||
Traditionally, the UNIX <b>sendmail</b> command is installed with
|
Traditionally, the UNIX <b>sendmail</b> command is installed with
|
||||||
@@ -1126,36 +1132,49 @@ run out of file handles; after that, it will run out of sockets.
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
To set kernel parameters at boot time, add the following lines to
|
To set the following kernel parameters at boot time, add the
|
||||||
the <b>/boot/loader.conf</b> file (this is specific to FreeBSD 4.x):
|
following lines to the <b>/boot/loader.conf</b> file (this is
|
||||||
|
specific to FreeBSD 4.x):
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre>
|
<pre>
|
||||||
kern.ipc.maxsockets="5000"
|
kern.ipc.maxsockets="5000"
|
||||||
kern.maxfiles="16384"
|
|
||||||
kern.maxfilesperproc="16384"
|
|
||||||
kern.ipc.nmbclusters="65536"
|
kern.ipc.nmbclusters="65536"
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
To set kernel parameters at run time execute the following commands
|
These parameters cannot be set at run time (verified with FreeBSD
|
||||||
as root (this is specific to FreeBSD 4.x):
|
4.2).
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
To set the following kernel parameters at run time execute the
|
||||||
|
following commands as root (this is specific to FreeBSD 4.x):
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<pre>
|
<pre>
|
||||||
# sysctl -w kern.ipc.maxsockets=5000
|
|
||||||
# sysctl -w kern.maxfiles=16384
|
# sysctl -w kern.maxfiles=16384
|
||||||
# sysctl -w kern.maxfilesperproc=16384
|
# sysctl -w kern.maxfilesperproc=16384
|
||||||
# sysctl -w kern.ipc.nmbclusters=65536
|
|
||||||
</pre>
|
</pre>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
These parameters cannot be set from <b>/boot/loader.conf</b>
|
||||||
|
(verified with FreeBSD 4.2).
|
||||||
|
|
||||||
|
<p>
|
||||||
|
|
||||||
|
Other kernel parameters such as <b>kern.maxproc</b> can be increased
|
||||||
|
only by recompiling the kernel with a different <b>maxusers</b>
|
||||||
|
setting in the kernel configuration file (verified with FreeBSD 4.2).
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<a name="moby-linux"><h3>Running hundreds of Postfix processes on Linux</h3></a>
|
<a name="moby-linux"><h3>Running hundreds of Postfix processes on Linux</h3></a>
|
||||||
@@ -3367,6 +3386,27 @@ files, and to mount the Postfix queue file system with the
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
<a name="msql_limit"><h3>Too many connections</h3></a>
|
||||||
|
|
||||||
|
This message is produced by the MYQSL server. You need to increase
|
||||||
|
the number of connections that it can handle. Things to bear in
|
||||||
|
mind: the <b>virtual</b> and <b>canonical</b> maps are accessed by
|
||||||
|
every <b>smtpd</b> and <b>cleanup</b> process.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<a name="reiser_bugs"><h3>write queue file: No such file or directory</h3></a>
|
||||||
|
|
||||||
|
<h3>write queue file: Unknown error 4294967289</h3>
|
||||||
|
|
||||||
|
Reiserfs reports the wrong error code when a message exceeds the
|
||||||
|
<b>message_size_limit</b> setting. As a result, the Postfix SMTP
|
||||||
|
server reports a "queue file write error" to the SMTP client, rather
|
||||||
|
than reporting a "file too large" condition. The client will keep
|
||||||
|
sending the same email again and again until the mail is too old.
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
<a href="index.html">Up one level</a> | Postfix FAQ
|
<a href="index.html">Up one level</a> | Postfix FAQ
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@@ -108,7 +108,7 @@ LMTP(8) LMTP(8)
|
|||||||
found in <b>services</b>(4).
|
found in <b>services</b>(4).
|
||||||
|
|
||||||
<b>Authentication</b> <b>controls</b>
|
<b>Authentication</b> <b>controls</b>
|
||||||
<b>lmtp</b><i>_</i><b>enable</b><i>_</i><b>sasl</b><i>_</i><b>auth</b>
|
<b>lmtp</b><i>_</i><b>sasl</b><i>_</i><b>auth</b><i>_</i><b>enable</b>
|
||||||
Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
|
Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a>
|
||||||
(SASL). By default, Postfix is built without SASL
|
(SASL). By default, Postfix is built without SASL
|
||||||
support.
|
support.
|
||||||
|
@@ -78,7 +78,7 @@ PIPE(8) PIPE(8)
|
|||||||
|
|
||||||
The <b>q</b> flag affects only entire addresses,
|
The <b>q</b> flag affects only entire addresses,
|
||||||
not the partial address information from the
|
not the partial address information from the
|
||||||
<b>$user</b>, <b>extension</b> or <b>mailbox</b> command-line
|
<b>$user</b>, <b>$extension</b> or <b>$mailbox</b> command-line
|
||||||
macros.
|
macros.
|
||||||
|
|
||||||
<b>u</b> Fold the command-line <b>$recipient</b> address
|
<b>u</b> Fold the command-line <b>$recipient</b> address
|
||||||
|
122
postfix/html/qmqpd.8.html
Normal file
122
postfix/html/qmqpd.8.html
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
<html> <head> </head> <body> <pre>
|
||||||
|
|
||||||
|
QMQPD(8) QMQPD(8)
|
||||||
|
|
||||||
|
<b>NAME</b>
|
||||||
|
qmqpd - Postfix QMQP server
|
||||||
|
|
||||||
|
<b>SYNOPSIS</b>
|
||||||
|
<b>qmqpd</b> [generic Postfix daemon options]
|
||||||
|
|
||||||
|
<b>DESCRIPTION</b>
|
||||||
|
The Postfix QMQP server receives one message per connec-
|
||||||
|
tion. Each message is piped through the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> dae-
|
||||||
|
mon, and is placed into the <b>incoming</b> queue as one single
|
||||||
|
queue file. The program expects to be run from the <a href="master.8.html"><b>mas-</b></a>
|
||||||
|
<a href="master.8.html"><b>ter</b>(8)</a> process manager.
|
||||||
|
|
||||||
|
The QMQP server implements one access policy: only explic-
|
||||||
|
itly authorized client hosts are allowed to use the ser-
|
||||||
|
vice.
|
||||||
|
|
||||||
|
<b>SECURITY</b>
|
||||||
|
The QMQP server is moderately security-sensitive. It talks
|
||||||
|
to QMQP clients and to DNS servers on the network. The
|
||||||
|
QMQP server can be run chrooted at fixed low privilege.
|
||||||
|
|
||||||
|
<b>DIAGNOSTICS</b>
|
||||||
|
Problems and transactions are logged to <b>syslogd</b>(8).
|
||||||
|
|
||||||
|
<b>BUGS</b>
|
||||||
|
The QMQP protocol provides only one server reply per mes-
|
||||||
|
sage delivery. It is therefore not possible to reject
|
||||||
|
individual recipients.
|
||||||
|
|
||||||
|
The QMQP protocol requires the server to receive the
|
||||||
|
entire message before replying. If a message is malformed,
|
||||||
|
or if any netstring component is longer than acceptable,
|
||||||
|
Postfix replies immediately and closes the connection. It
|
||||||
|
is left up to the client to handle the situation.
|
||||||
|
|
||||||
|
<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>
|
||||||
|
command after a configuration change.
|
||||||
|
|
||||||
|
<b>Miscellaneous</b>
|
||||||
|
<b>always</b><i>_</i><b>bcc</b>
|
||||||
|
Address to send a copy of each message that enters
|
||||||
|
the system.
|
||||||
|
|
||||||
|
<b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b>
|
||||||
|
Increment in verbose logging level when a remote
|
||||||
|
host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b>
|
||||||
|
parameter.
|
||||||
|
|
||||||
|
<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.
|
||||||
|
|
||||||
|
<b>hopcount</b><i>_</i><b>limit</b>
|
||||||
|
Limit the number of <b>Received:</b> message headers.
|
||||||
|
|
||||||
|
<b>qmqpd</b><i>_</i><b>authorized</b><i>_</i><b>clients</b>
|
||||||
|
A list of domain or network patterns that specifies
|
||||||
|
what clients are allowed to use the service.
|
||||||
|
|
||||||
|
<b>qmqpd</b><i>_</i><b>timeout</b>
|
||||||
|
Limit the time to send a server response and to
|
||||||
|
receive a client request.
|
||||||
|
|
||||||
|
<b>soft</b><i>_</i><b>bounce</b>
|
||||||
|
Change hard (D) reject responses into soft (Z)
|
||||||
|
reject responses. This can be useful for testing
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
<b>Content</b> <b>inspection</b> <b>controls</b>
|
||||||
|
<b>content</b><i>_</i><b>filter</b>
|
||||||
|
The name of a mail delivery transport that filters
|
||||||
|
mail and that either bounces mail or re-injects the
|
||||||
|
result back into Postfix. This parameter uses the
|
||||||
|
same syntax as the right-hand side of a Postfix
|
||||||
|
transport table.
|
||||||
|
|
||||||
|
<b>Resource</b> <b>controls</b>
|
||||||
|
<b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b>
|
||||||
|
Limit the amount of memory in bytes used for the
|
||||||
|
handling of partial input lines, and the length of
|
||||||
|
sender and recipient addresses that are received
|
||||||
|
from client.
|
||||||
|
|
||||||
|
<b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b>
|
||||||
|
Limit the total size in bytes of a message, includ-
|
||||||
|
ing on-disk storage for sender and recipient
|
||||||
|
address information.
|
||||||
|
|
||||||
|
<b>Tarpitting</b>
|
||||||
|
<b>qmqpd</b><i>_</i><b>error</b><i>_</i><b>sleep</b><i>_</i><b>time</b>
|
||||||
|
Time to wait in seconds before informing the client
|
||||||
|
of a problem. This slows down run-away errors.
|
||||||
|
|
||||||
|
<b>SEE</b> <b>ALSO</b>
|
||||||
|
http://cr.yp.to/proto/qmqp.html, QMQP protocol
|
||||||
|
<a href="cleanup.8.html">cleanup(8)</a> message canonicalization
|
||||||
|
<a href="master.8.html">master(8)</a> process manager
|
||||||
|
syslogd(8) system logging
|
||||||
|
|
||||||
|
<b>LICENSE</b>
|
||||||
|
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
|
||||||
|
Yorktown Heights, NY 10598, USA
|
||||||
|
|
||||||
|
1
|
||||||
|
|
||||||
|
</pre> </body> </html>
|
@@ -117,6 +117,11 @@ SMTP(8) SMTP(8)
|
|||||||
<b>smtp</b><i>_</i><b>never</b><i>_</i><b>send</b><i>_</i><b>ehlo</b>
|
<b>smtp</b><i>_</i><b>never</b><i>_</i><b>send</b><i>_</i><b>ehlo</b>
|
||||||
Never send EHLO at the start of a connection.
|
Never send EHLO at the start of a connection.
|
||||||
|
|
||||||
|
<b>smtp</b><i>_</i><b>break</b><i>_</i><b>lines</b>
|
||||||
|
Break lines > <b>$line</b><i>_</i><b>length</b><i>_</i><b>limit</b> into multiple
|
||||||
|
shorter lines. Some SMTP servers misbehave on long
|
||||||
|
lines.
|
||||||
|
|
||||||
<b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
|
<b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b>
|
||||||
Skip servers that greet us with a 4xx status code.
|
Skip servers that greet us with a 4xx status code.
|
||||||
|
|
||||||
|
@@ -5,7 +5,7 @@ SHELL = /bin/sh
|
|||||||
DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
|
DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
|
||||||
man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
|
man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \
|
||||||
man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
|
man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \
|
||||||
man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8
|
man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8
|
||||||
COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
|
COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
|
||||||
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
|
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
|
||||||
man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
|
man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
|
||||||
@@ -65,6 +65,9 @@ man8/pipe.8: ../src/pipe/pipe.c
|
|||||||
man8/qmgr.8: ../src/qmgr/qmgr.c
|
man8/qmgr.8: ../src/qmgr/qmgr.c
|
||||||
../mantools/srctoman $? >$@
|
../mantools/srctoman $? >$@
|
||||||
|
|
||||||
|
man8/qmqpd.8: ../src/qmqpd/qmqpd.c
|
||||||
|
../mantools/srctoman $? >$@
|
||||||
|
|
||||||
man8/showq.8: ../src/showq/showq.c
|
man8/showq.8: ../src/showq/showq.c
|
||||||
../mantools/srctoman $? >$@
|
../mantools/srctoman $? >$@
|
||||||
|
|
||||||
|
@@ -104,7 +104,7 @@ Do not wait for the server response after sending QUIT.
|
|||||||
The TCP port to be used when connecting to a LMTP server. Used as
|
The TCP port to be used when connecting to a LMTP server. Used as
|
||||||
backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
||||||
.SH "Authentication controls"
|
.SH "Authentication controls"
|
||||||
.IP \fBlmtp_enable_sasl_auth\fR
|
.IP \fBlmtp_sasl_auth_enable\fR
|
||||||
Enable per-session authentication as per RFC 2554 (SASL).
|
Enable per-session authentication as per RFC 2554 (SASL).
|
||||||
By default, Postfix is built without SASL support.
|
By default, Postfix is built without SASL support.
|
||||||
.IP \fBlmtp_sasl_password_maps\fR
|
.IP \fBlmtp_sasl_password_maps\fR
|
||||||
|
@@ -80,8 +80,8 @@ The result is compatible with the address parsing of command-line
|
|||||||
recipients by the Postfix \fBsendmail\fR mail submission command.
|
recipients by the Postfix \fBsendmail\fR mail submission command.
|
||||||
.sp
|
.sp
|
||||||
The \fBq\fR flag affects only entire addresses, not the partial
|
The \fBq\fR flag affects only entire addresses, not the partial
|
||||||
address information from the \fB$user\fR, \fBextension\fR or
|
address information from the \fB$user\fR, \fB$extension\fR or
|
||||||
\fBmailbox\fR command-line macros.
|
\fB$mailbox\fR command-line macros.
|
||||||
.IP \fBu\fR
|
.IP \fBu\fR
|
||||||
Fold the command-line \fB$recipient\fR address localpart (text to
|
Fold the command-line \fB$recipient\fR address localpart (text to
|
||||||
the left of the right-most \fB@\fR character) to lower case.
|
the left of the right-most \fB@\fR character) to lower case.
|
||||||
|
120
postfix/man/man8/qmqpd.8
Normal file
120
postfix/man/man8/qmqpd.8
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
.TH QMQPD 8
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
.SH NAME
|
||||||
|
qmqpd
|
||||||
|
\-
|
||||||
|
Postfix QMQP server
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.na
|
||||||
|
.nf
|
||||||
|
\fBqmqpd\fR [generic Postfix daemon options]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
The Postfix QMQP server receives one message per connection.
|
||||||
|
Each message is piped through the \fBcleanup\fR(8)
|
||||||
|
daemon, and is placed into the \fBincoming\fR queue as one
|
||||||
|
single queue file. The program expects to be run from the
|
||||||
|
\fBmaster\fR(8) process manager.
|
||||||
|
|
||||||
|
The QMQP server implements one access policy: only explicitly
|
||||||
|
authorized client hosts are allowed to use the service.
|
||||||
|
.SH SECURITY
|
||||||
|
.na
|
||||||
|
.nf
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
The QMQP server is moderately security-sensitive. It talks to QMQP
|
||||||
|
clients and to DNS servers on the network. The QMQP server can be
|
||||||
|
run chrooted at fixed low privilege.
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
Problems and transactions are logged to \fBsyslogd\fR(8).
|
||||||
|
.SH BUGS
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
The QMQP protocol provides only one server reply per message
|
||||||
|
delivery. It is therefore not possible to reject individual
|
||||||
|
recipients.
|
||||||
|
|
||||||
|
The QMQP protocol requires the server to receive the entire
|
||||||
|
message before replying. If a message is malformed, or if any
|
||||||
|
netstring component is longer than acceptable, Postfix replies
|
||||||
|
immediately and closes the connection. It is left up to the
|
||||||
|
client to handle the situation.
|
||||||
|
.SH CONFIGURATION PARAMETERS
|
||||||
|
.na
|
||||||
|
.nf
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
The following \fBmain.cf\fR parameters are especially relevant to
|
||||||
|
this program. See the Postfix \fBmain.cf\fR file for syntax details
|
||||||
|
and for default values. Use the \fBpostfix reload\fR command after
|
||||||
|
a configuration change.
|
||||||
|
.SH Miscellaneous
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
.IP \fBalways_bcc\fR
|
||||||
|
Address to send a copy of each message that enters the system.
|
||||||
|
.IP \fBdebug_peer_level\fR
|
||||||
|
Increment in verbose logging level when a remote host matches a
|
||||||
|
pattern in the \fBdebug_peer_list\fR parameter.
|
||||||
|
.IP \fBdebug_peer_list\fR
|
||||||
|
List of domain or network patterns. When a remote host matches
|
||||||
|
a pattern, increase the verbose logging level by the amount
|
||||||
|
specified in the \fBdebug_peer_level\fR parameter.
|
||||||
|
.IP \fBhopcount_limit\fR
|
||||||
|
Limit the number of \fBReceived:\fR message headers.
|
||||||
|
.IP \fBqmqpd_authorized_clients\fR
|
||||||
|
A list of domain or network patterns that specifies what
|
||||||
|
clients are allowed to use the service.
|
||||||
|
.IP \fBqmqpd_timeout\fR
|
||||||
|
Limit the time to send a server response and to receive a client
|
||||||
|
request.
|
||||||
|
.IP \fBsoft_bounce\fR
|
||||||
|
Change hard (D) reject responses into soft (Z) reject responses.
|
||||||
|
This can be useful for testing purposes.
|
||||||
|
.SH "Content inspection controls"
|
||||||
|
.IP \fBcontent_filter\fR
|
||||||
|
The name of a mail delivery transport that filters mail and that
|
||||||
|
either bounces mail or re-injects the result back into Postfix.
|
||||||
|
This parameter uses the same syntax as the right-hand side of
|
||||||
|
a Postfix transport table.
|
||||||
|
.SH "Resource controls"
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
.IP \fBline_length_limit\fR
|
||||||
|
Limit the amount of memory in bytes used for the handling of
|
||||||
|
partial input lines, and the length of sender and recipient
|
||||||
|
addresses that are received from client.
|
||||||
|
.IP \fBmessage_size_limit\fR
|
||||||
|
Limit the total size in bytes of a message, including on-disk
|
||||||
|
storage for sender and recipient address information.
|
||||||
|
.SH Tarpitting
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
.IP \fBqmqpd_error_sleep_time\fR
|
||||||
|
Time to wait in seconds before informing the client of
|
||||||
|
a problem. This slows down run-away errors.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.na
|
||||||
|
.nf
|
||||||
|
http://cr.yp.to/proto/qmqp.html, QMQP protocol
|
||||||
|
cleanup(8) message canonicalization
|
||||||
|
master(8) process manager
|
||||||
|
syslogd(8) system logging
|
||||||
|
.SH LICENSE
|
||||||
|
.na
|
||||||
|
.nf
|
||||||
|
.ad
|
||||||
|
.fi
|
||||||
|
The Secure Mailer license must be distributed with this software.
|
||||||
|
.SH AUTHOR(S)
|
||||||
|
.na
|
||||||
|
.nf
|
||||||
|
Wietse Venema
|
||||||
|
IBM T.J. Watson Research
|
||||||
|
P.O. Box 704
|
||||||
|
Yorktown Heights, NY 10598, USA
|
@@ -111,6 +111,9 @@ postmaster with transcripts of SMTP sessions with protocol errors.
|
|||||||
Always send EHLO at the start of a connection.
|
Always send EHLO at the start of a connection.
|
||||||
.IP \fBsmtp_never_send_ehlo\fR
|
.IP \fBsmtp_never_send_ehlo\fR
|
||||||
Never send EHLO at the start of a connection.
|
Never send EHLO at the start of a connection.
|
||||||
|
.IP \fBsmtp_break_lines\fR
|
||||||
|
Break lines > \fB$line_length_limit\fR into multiple shorter lines.
|
||||||
|
Some SMTP servers misbehave on long lines.
|
||||||
.IP \fBsmtp_skip_4xx_greeting\fR
|
.IP \fBsmtp_skip_4xx_greeting\fR
|
||||||
Skip servers that greet us with a 4xx status code.
|
Skip servers that greet us with a 4xx status code.
|
||||||
.IP \fBsmtp_skip_5xx_greeting\fR
|
.IP \fBsmtp_skip_5xx_greeting\fR
|
||||||
|
@@ -19,6 +19,7 @@ exec sed '
|
|||||||
s/[<bB>]*pickup[</bB>]*(8)/<a href="pickup.8.html">&<\/a>/
|
s/[<bB>]*pickup[</bB>]*(8)/<a href="pickup.8.html">&<\/a>/
|
||||||
s/[<bB>]*pipe[</bB>]*(8)/<a href="pipe.8.html">&<\/a>/
|
s/[<bB>]*pipe[</bB>]*(8)/<a href="pipe.8.html">&<\/a>/
|
||||||
s/[<bB>]*qmgr[</bB>]*(8)/<a href="qmgr.8.html">&<\/a>/
|
s/[<bB>]*qmgr[</bB>]*(8)/<a href="qmgr.8.html">&<\/a>/
|
||||||
|
s/[<bB>]*qmqpd[</bB>]*(8)/<a href="qmqpd.8.html">&<\/a>/
|
||||||
s/[<bB>]*showq[</bB>]*(8)/<a href="showq.8.html">&<\/a>/
|
s/[<bB>]*showq[</bB>]*(8)/<a href="showq.8.html">&<\/a>/
|
||||||
s/[<bB>]*smtp[</bB>]*(8)/<a href="smtp.8.html">&<\/a>/
|
s/[<bB>]*smtp[</bB>]*(8)/<a href="smtp.8.html">&<\/a>/
|
||||||
s/[<bB>]*smtpd[</bB>]*(8)/<a href="smtpd.8.html">&<\/a>/
|
s/[<bB>]*smtpd[</bB>]*(8)/<a href="smtpd.8.html">&<\/a>/
|
||||||
|
@@ -54,7 +54,7 @@ HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
|
|||||||
recipient_list.h record.h resolve_clnt.h resolve_local.h \
|
recipient_list.h record.h resolve_clnt.h resolve_local.h \
|
||||||
rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
|
rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
|
||||||
sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
|
sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
|
||||||
mbox_conf.h mbox_open.h abounce.h
|
mbox_conf.h mbox_open.h abounce.h qmqp_proto.h
|
||||||
TESTSRC = rec2stream.c stream2rec.c recdump.c
|
TESTSRC = rec2stream.c stream2rec.c recdump.c
|
||||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||||
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||||
|
@@ -714,6 +714,10 @@ extern char *var_smtp_bind_addr;
|
|||||||
#define DEF_SMTP_RAND_ADDR 1
|
#define DEF_SMTP_RAND_ADDR 1
|
||||||
extern bool var_smtp_rand_addr;
|
extern bool var_smtp_rand_addr;
|
||||||
|
|
||||||
|
#define VAR_SMTP_BREAK_LINES "smtp_break_lines"
|
||||||
|
#define DEF_SMTP_BREAK_LINES 1
|
||||||
|
extern bool var_smtp_break_lines;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SMTP server. The soft error limit determines how many errors an SMTP
|
* SMTP server. The soft error limit determines how many errors an SMTP
|
||||||
* client may make before we start to slow down; the hard error limit
|
* client may make before we start to slow down; the hard error limit
|
||||||
@@ -1252,6 +1256,21 @@ extern char *var_virt_mailbox_lock;
|
|||||||
#define DEF_SYSLOG_NAME "postfix"
|
#define DEF_SYSLOG_NAME "postfix"
|
||||||
extern char *var_syslog_name;
|
extern char *var_syslog_name;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QMQPD
|
||||||
|
*/
|
||||||
|
#define VAR_QMQPD_CLIENTS "qmqpd_authorized_clients"
|
||||||
|
#define DEF_QMQPD_CLIENTS ""
|
||||||
|
extern char *var_qmqpd_clients;
|
||||||
|
|
||||||
|
#define VAR_QMTPD_TMOUT "qmqpd_timeout"
|
||||||
|
#define DEF_QMTPD_TMOUT "300s"
|
||||||
|
extern int var_qmqpd_timeout;
|
||||||
|
|
||||||
|
#define VAR_QMTPD_ERR_SLEEP "qmqpd_error_delay"
|
||||||
|
#define DEF_QMTPD_ERR_SLEEP "5s"
|
||||||
|
extern int var_qmqpd_err_sleep;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
|
@@ -76,7 +76,7 @@
|
|||||||
/* mail_queue_rename() renames a queue file. A non-zero result
|
/* mail_queue_rename() renames a queue file. A non-zero result
|
||||||
/* means the operation failed.
|
/* means the operation failed.
|
||||||
/*
|
/*
|
||||||
/* mail_queue_remove() renames the named queue file. A non-zero result
|
/* mail_queue_remove() removes the named queue file. A non-zero result
|
||||||
/* means the operation failed.
|
/* means the operation failed.
|
||||||
/*
|
/*
|
||||||
/* mail_queue_name_ok() validates a mail queue name and returns
|
/* mail_queue_name_ok() validates a mail queue name and returns
|
||||||
|
@@ -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-20010610"
|
#define DEF_MAIL_VERSION "Snapshot-20010707"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
27
postfix/src/global/qmqp_proto.h
Normal file
27
postfix/src/global/qmqp_proto.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* qmqpd 3h
|
||||||
|
/* SUMMARY
|
||||||
|
/* QMQP protocol
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* include <qmqpd_proto.h>
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* .nf
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QMQP protocol status codes.
|
||||||
|
*/
|
||||||
|
#define QMQP_STAT_OK 'K' /* success */
|
||||||
|
#define QMQP_STAT_RETRY 'Z' /* recoverable error */
|
||||||
|
#define QMQP_STAT_HARD 'D' /* unrecoverable error */
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
/*--*/
|
@@ -88,7 +88,7 @@
|
|||||||
/* The TCP port to be used when connecting to a LMTP server. Used as
|
/* The TCP port to be used when connecting to a LMTP server. Used as
|
||||||
/* backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
/* backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
||||||
/* .SH "Authentication controls"
|
/* .SH "Authentication controls"
|
||||||
/* .IP \fBlmtp_enable_sasl_auth\fR
|
/* .IP \fBlmtp_sasl_auth_enable\fR
|
||||||
/* Enable per-session authentication as per RFC 2554 (SASL).
|
/* Enable per-session authentication as per RFC 2554 (SASL).
|
||||||
/* By default, Postfix is built without SASL support.
|
/* By default, Postfix is built without SASL support.
|
||||||
/* .IP \fBlmtp_sasl_password_maps\fR
|
/* .IP \fBlmtp_sasl_password_maps\fR
|
||||||
|
@@ -498,7 +498,7 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state)
|
|||||||
*/
|
*/
|
||||||
case LMTP_STATE_RCPT:
|
case LMTP_STATE_RCPT:
|
||||||
if (!mail_from_rejected) {
|
if (!mail_from_rejected) {
|
||||||
#ifndef notRFC821_SYNTAX
|
#ifdef notdef
|
||||||
if (resp->code == 552)
|
if (resp->code == 552)
|
||||||
resp->code = 452;
|
resp->code = 452;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -276,7 +276,7 @@ int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
|
|||||||
SET_USER_ATTR(usr_attr, mbox_pwd, state.level);
|
SET_USER_ATTR(usr_attr, mbox_pwd, state.level);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deliver to mailbox or to external command.
|
* Deliver to mailbox, maildir or to external command.
|
||||||
*/
|
*/
|
||||||
#define LAST_CHAR(s) (s[strlen(s) - 1])
|
#define LAST_CHAR(s) (s[strlen(s) - 1])
|
||||||
|
|
||||||
@@ -286,6 +286,11 @@ int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
|
|||||||
path = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0);
|
path = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0);
|
||||||
status = deliver_maildir(state, usr_attr, path);
|
status = deliver_maildir(state, usr_attr, path);
|
||||||
myfree(path);
|
myfree(path);
|
||||||
|
} else if (*var_mail_spool_dir && LAST_CHAR(var_mail_spool_dir) == '/') {
|
||||||
|
path = concatenate(var_mail_spool_dir, state.msg_attr.user,
|
||||||
|
"/", (char *) 0);
|
||||||
|
status = deliver_maildir(state, usr_attr, path);
|
||||||
|
myfree(path);
|
||||||
} else
|
} else
|
||||||
status = deliver_mailbox_file(state, usr_attr);
|
status = deliver_mailbox_file(state, usr_attr);
|
||||||
|
|
||||||
|
@@ -70,8 +70,8 @@
|
|||||||
/* recipients by the Postfix \fBsendmail\fR mail submission command.
|
/* recipients by the Postfix \fBsendmail\fR mail submission command.
|
||||||
/* .sp
|
/* .sp
|
||||||
/* The \fBq\fR flag affects only entire addresses, not the partial
|
/* The \fBq\fR flag affects only entire addresses, not the partial
|
||||||
/* address information from the \fB$user\fR, \fBextension\fR or
|
/* address information from the \fB$user\fR, \fB$extension\fR or
|
||||||
/* \fBmailbox\fR command-line macros.
|
/* \fB$mailbox\fR command-line macros.
|
||||||
/* .IP \fBu\fR
|
/* .IP \fBu\fR
|
||||||
/* Fold the command-line \fB$recipient\fR address localpart (text to
|
/* Fold the command-line \fB$recipient\fR address localpart (text to
|
||||||
/* the left of the right-most \fB@\fR character) to lower case.
|
/* the left of the right-most \fB@\fR character) to lower case.
|
||||||
|
1
postfix/src/qmqpd/.indent.pro
vendored
Symbolic link
1
postfix/src/qmqpd/.indent.pro
vendored
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../.indent.pro
|
25
postfix/src/qmqpd/.printfck
Normal file
25
postfix/src/qmqpd/.printfck
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
been_here_xt 2 0
|
||||||
|
bounce_append 5 0
|
||||||
|
cleanup_out_format 1 0
|
||||||
|
defer_append 5 0
|
||||||
|
mail_command 1 0
|
||||||
|
mail_print 1 0
|
||||||
|
msg_error 0 0
|
||||||
|
msg_fatal 0 0
|
||||||
|
msg_info 0 0
|
||||||
|
msg_panic 0 0
|
||||||
|
msg_warn 0 0
|
||||||
|
opened 4 0
|
||||||
|
post_mail_fprintf 1 0
|
||||||
|
qmgr_message_bounce 2 0
|
||||||
|
rec_fprintf 2 0
|
||||||
|
sent 4 0
|
||||||
|
smtp_cmd 1 0
|
||||||
|
smtp_mesg_fail 2 0
|
||||||
|
smtp_printf 1 0
|
||||||
|
smtp_rcpt_fail 3 0
|
||||||
|
smtp_site_fail 2 0
|
||||||
|
udp_syslog 1 0
|
||||||
|
vstream_fprintf 1 0
|
||||||
|
vstream_printf 0 0
|
||||||
|
vstring_sprintf 1 0
|
113
postfix/src/qmqpd/Makefile.in
Normal file
113
postfix/src/qmqpd/Makefile.in
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
SHELL = /bin/sh
|
||||||
|
SRCS = qmqpd.c qmqpd_state.c qmqpd_peer.c
|
||||||
|
OBJS = qmqpd.o qmqpd_state.o qmqpd_peer.o
|
||||||
|
HDRS =
|
||||||
|
TESTSRC =
|
||||||
|
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||||
|
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||||
|
-Wunused
|
||||||
|
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||||
|
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||||
|
TESTPROG= qmqpd_token qmqpd_check
|
||||||
|
PROG = qmqpd
|
||||||
|
INC_DIR = ../../include
|
||||||
|
LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libdns.a ../../lib/libutil.a
|
||||||
|
|
||||||
|
.c.o:; $(CC) $(CFLAGS) -c $*.c
|
||||||
|
|
||||||
|
$(PROG): $(OBJS) $(LIBS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
|
||||||
|
|
||||||
|
Makefile: Makefile.in
|
||||||
|
(set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
|
||||||
|
|
||||||
|
test: $(TESTPROG)
|
||||||
|
|
||||||
|
update: ../../libexec/$(PROG)
|
||||||
|
|
||||||
|
../../libexec/$(PROG): $(PROG)
|
||||||
|
cp $(PROG) ../../libexec
|
||||||
|
|
||||||
|
SMTPD_CHECK_OBJ = qmqpd_state.o qmqpd_peer.o
|
||||||
|
|
||||||
|
qmqpd_token: qmqpd_token.c $(LIBS)
|
||||||
|
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS)
|
||||||
|
|
||||||
|
qmqpd_check: qmqpd_check.c $(SMTPD_CHECK_OBJ) $(LIBS)
|
||||||
|
mv $@.o junk
|
||||||
|
$(CC) $(CFLAGS) -DTEST -o $@ qmqpd_check.c $(SMTPD_CHECK_OBJ) \
|
||||||
|
$(LIBS) $(SYSLIBS)
|
||||||
|
mv junk $@.o
|
||||||
|
|
||||||
|
printfck: $(OBJS) $(PROG)
|
||||||
|
rm -rf printfck
|
||||||
|
mkdir printfck
|
||||||
|
cp *.h printfck
|
||||||
|
sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
|
||||||
|
set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
|
||||||
|
cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
|
||||||
|
|
||||||
|
lint:
|
||||||
|
lint $(DEFS) $(SRCS) $(LINTFIX)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *core $(PROG) $(TESTPROG) junk *.db *.out *.tmp
|
||||||
|
rm -rf printfck
|
||||||
|
|
||||||
|
tidy: clean
|
||||||
|
|
||||||
|
depend: $(MAKES)
|
||||||
|
(sed '1,/^# do not edit/!d' Makefile.in; \
|
||||||
|
set -e; for i in [a-z][a-z0-9]*.c; do \
|
||||||
|
$(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
|
||||||
|
-e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
|
||||||
|
done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
|
||||||
|
@$(EXPORT) make -f Makefile.in Makefile 1>&2
|
||||||
|
|
||||||
|
tests:
|
||||||
|
|
||||||
|
# do not edit below this line - it is generated by 'make depend'
|
||||||
|
qmqpd.o: qmqpd.c
|
||||||
|
qmqpd.o: ../../include/sys_defs.h
|
||||||
|
qmqpd.o: ../../include/msg.h
|
||||||
|
qmqpd.o: ../../include/mymalloc.h
|
||||||
|
qmqpd.o: ../../include/vstring.h
|
||||||
|
qmqpd.o: ../../include/vbuf.h
|
||||||
|
qmqpd.o: ../../include/vstream.h
|
||||||
|
qmqpd.o: ../../include/netstring.h
|
||||||
|
qmqpd.o: ../../include/dict.h
|
||||||
|
qmqpd.o: ../../include/argv.h
|
||||||
|
qmqpd.o: ../../include/mail_params.h
|
||||||
|
qmqpd.o: ../../include/record.h
|
||||||
|
qmqpd.o: ../../include/rec_type.h
|
||||||
|
qmqpd.o: ../../include/mail_proto.h
|
||||||
|
qmqpd.o: ../../include/iostuff.h
|
||||||
|
qmqpd.o: ../../include/cleanup_user.h
|
||||||
|
qmqpd.o: ../../include/mail_date.h
|
||||||
|
qmqpd.o: ../../include/mail_conf.h
|
||||||
|
qmqpd.o: ../../include/debug_peer.h
|
||||||
|
qmqpd.o: ../../include/mail_stream.h
|
||||||
|
qmqpd.o: ../../include/namadr_list.h
|
||||||
|
qmqpd.o: ../../include/quote_822_local.h
|
||||||
|
qmqpd.o: ../../include/mail_server.h
|
||||||
|
qmqpd.o: qmqpd.h
|
||||||
|
qmqpd_peer.o: qmqpd_peer.c
|
||||||
|
qmqpd_peer.o: ../../include/sys_defs.h
|
||||||
|
qmqpd_peer.o: ../../include/msg.h
|
||||||
|
qmqpd_peer.o: ../../include/mymalloc.h
|
||||||
|
qmqpd_peer.o: ../../include/valid_hostname.h
|
||||||
|
qmqpd_peer.o: ../../include/stringops.h
|
||||||
|
qmqpd_peer.o: ../../include/vstring.h
|
||||||
|
qmqpd_peer.o: ../../include/vbuf.h
|
||||||
|
qmqpd_peer.o: qmqpd.h
|
||||||
|
qmqpd_peer.o: ../../include/vstream.h
|
||||||
|
qmqpd_peer.o: ../../include/mail_stream.h
|
||||||
|
qmqpd_state.o: qmqpd_state.c
|
||||||
|
qmqpd_state.o: ../../include/sys_defs.h
|
||||||
|
qmqpd_state.o: ../../include/mymalloc.h
|
||||||
|
qmqpd_state.o: ../../include/vstream.h
|
||||||
|
qmqpd_state.o: ../../include/vbuf.h
|
||||||
|
qmqpd_state.o: ../../include/vstring.h
|
||||||
|
qmqpd_state.o: ../../include/mail_stream.h
|
||||||
|
qmqpd_state.o: ../../include/cleanup_user.h
|
||||||
|
qmqpd_state.o: qmqpd.h
|
645
postfix/src/qmqpd/qmqpd.c
Normal file
645
postfix/src/qmqpd/qmqpd.c
Normal file
@@ -0,0 +1,645 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* qmqpd 8
|
||||||
|
/* SUMMARY
|
||||||
|
/* Postfix QMQP server
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* \fBqmqpd\fR [generic Postfix daemon options]
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* The Postfix QMQP server receives one message per connection.
|
||||||
|
/* Each message is piped through the \fBcleanup\fR(8)
|
||||||
|
/* daemon, and is placed into the \fBincoming\fR queue as one
|
||||||
|
/* single queue file. The program expects to be run from the
|
||||||
|
/* \fBmaster\fR(8) process manager.
|
||||||
|
/*
|
||||||
|
/* The QMQP server implements one access policy: only explicitly
|
||||||
|
/* authorized client hosts are allowed to use the service.
|
||||||
|
/* SECURITY
|
||||||
|
/* .ad
|
||||||
|
/* .fi
|
||||||
|
/* The QMQP server is moderately security-sensitive. It talks to QMQP
|
||||||
|
/* clients and to DNS servers on the network. The QMQP server can be
|
||||||
|
/* run chrooted at fixed low privilege.
|
||||||
|
/* DIAGNOSTICS
|
||||||
|
/* Problems and transactions are logged to \fBsyslogd\fR(8).
|
||||||
|
/* BUGS
|
||||||
|
/* The QMQP protocol provides only one server reply per message
|
||||||
|
/* delivery. It is therefore not possible to reject individual
|
||||||
|
/* recipients.
|
||||||
|
/*
|
||||||
|
/* The QMQP protocol requires the server to receive the entire
|
||||||
|
/* message before replying. If a message is malformed, or if any
|
||||||
|
/* netstring component is longer than acceptable, Postfix replies
|
||||||
|
/* immediately and closes the connection. It is left up to the
|
||||||
|
/* client to handle the situation.
|
||||||
|
/* CONFIGURATION PARAMETERS
|
||||||
|
/* .ad
|
||||||
|
/* .fi
|
||||||
|
/* The following \fBmain.cf\fR parameters are especially relevant to
|
||||||
|
/* this program. See the Postfix \fBmain.cf\fR file for syntax details
|
||||||
|
/* and for default values. Use the \fBpostfix reload\fR command after
|
||||||
|
/* a configuration change.
|
||||||
|
/* .SH Miscellaneous
|
||||||
|
/* .ad
|
||||||
|
/* .fi
|
||||||
|
/* .IP \fBalways_bcc\fR
|
||||||
|
/* Address to send a copy of each message that enters the system.
|
||||||
|
/* .IP \fBdebug_peer_level\fR
|
||||||
|
/* Increment in verbose logging level when a remote host matches a
|
||||||
|
/* pattern in the \fBdebug_peer_list\fR parameter.
|
||||||
|
/* .IP \fBdebug_peer_list\fR
|
||||||
|
/* List of domain or network patterns. When a remote host matches
|
||||||
|
/* a pattern, increase the verbose logging level by the amount
|
||||||
|
/* specified in the \fBdebug_peer_level\fR parameter.
|
||||||
|
/* .IP \fBhopcount_limit\fR
|
||||||
|
/* Limit the number of \fBReceived:\fR message headers.
|
||||||
|
/* .IP \fBqmqpd_authorized_clients\fR
|
||||||
|
/* A list of domain or network patterns that specifies what
|
||||||
|
/* clients are allowed to use the service.
|
||||||
|
/* .IP \fBqmqpd_timeout\fR
|
||||||
|
/* Limit the time to send a server response and to receive a client
|
||||||
|
/* request.
|
||||||
|
/* .IP \fBsoft_bounce\fR
|
||||||
|
/* Change hard (D) reject responses into soft (Z) reject responses.
|
||||||
|
/* This can be useful for testing purposes.
|
||||||
|
/* .SH "Content inspection controls"
|
||||||
|
/* .IP \fBcontent_filter\fR
|
||||||
|
/* The name of a mail delivery transport that filters mail and that
|
||||||
|
/* either bounces mail or re-injects the result back into Postfix.
|
||||||
|
/* This parameter uses the same syntax as the right-hand side of
|
||||||
|
/* a Postfix transport table.
|
||||||
|
/* .SH "Resource controls"
|
||||||
|
/* .ad
|
||||||
|
/* .fi
|
||||||
|
/* .IP \fBline_length_limit\fR
|
||||||
|
/* Limit the amount of memory in bytes used for the handling of
|
||||||
|
/* partial input lines, and the length of sender and recipient
|
||||||
|
/* addresses that are received from client.
|
||||||
|
/* .IP \fBmessage_size_limit\fR
|
||||||
|
/* Limit the total size in bytes of a message, including on-disk
|
||||||
|
/* storage for sender and recipient address information.
|
||||||
|
/* .SH Tarpitting
|
||||||
|
/* .ad
|
||||||
|
/* .fi
|
||||||
|
/* .IP \fBqmqpd_error_sleep_time\fR
|
||||||
|
/* Time to wait in seconds before informing the client of
|
||||||
|
/* a problem. This slows down run-away errors.
|
||||||
|
/* SEE ALSO
|
||||||
|
/* http://cr.yp.to/proto/qmqp.html, QMQP protocol
|
||||||
|
/* cleanup(8) message canonicalization
|
||||||
|
/* master(8) process manager
|
||||||
|
/* syslogd(8) system logging
|
||||||
|
/* 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 <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef STRCASECMP_IN_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Utility library. */
|
||||||
|
|
||||||
|
#include <msg.h>
|
||||||
|
#include <mymalloc.h>
|
||||||
|
#include <vstring.h>
|
||||||
|
#include <vstream.h>
|
||||||
|
#include <netstring.h>
|
||||||
|
#include <dict.h>
|
||||||
|
|
||||||
|
/* Global library. */
|
||||||
|
|
||||||
|
#include <mail_params.h>
|
||||||
|
#include <record.h>
|
||||||
|
#include <rec_type.h>
|
||||||
|
#include <mail_proto.h>
|
||||||
|
#include <cleanup_user.h>
|
||||||
|
#include <mail_date.h>
|
||||||
|
#include <mail_conf.h>
|
||||||
|
#include <debug_peer.h>
|
||||||
|
#include <mail_stream.h>
|
||||||
|
#include <namadr_list.h>
|
||||||
|
#include <quote_822_local.h>
|
||||||
|
|
||||||
|
/* Single-threaded server skeleton. */
|
||||||
|
|
||||||
|
#include <mail_server.h>
|
||||||
|
|
||||||
|
/* Application-specific */
|
||||||
|
|
||||||
|
#include <qmqpd.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tunable parameters. Make sure that there is some bound on the length of a
|
||||||
|
* netstring, so that the mail system stays in control even when a malicious
|
||||||
|
* client sends netstrings of unreasonable length. The recipient count limit
|
||||||
|
* is enforced by the message size limit.
|
||||||
|
*/
|
||||||
|
int var_qmqpd_timeout;
|
||||||
|
int var_qmqpd_err_sleep;
|
||||||
|
char *var_always_bcc;
|
||||||
|
char *var_filter_xport;
|
||||||
|
char *var_qmqpd_clients;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Silly little macros.
|
||||||
|
*/
|
||||||
|
#define STR(x) vstring_str(x)
|
||||||
|
#define LEN(x) VSTRING_LEN(x)
|
||||||
|
|
||||||
|
#define DO_LOG 1
|
||||||
|
#define DONT_LOG 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Access control. This service should be exposed only to explicitly
|
||||||
|
* authorized clients. There is no default authorization.
|
||||||
|
*/
|
||||||
|
static NAMADR_LIST *qmqpd_clients;
|
||||||
|
|
||||||
|
/* qmqpd_open_file - open a queue file */
|
||||||
|
|
||||||
|
static void qmqpd_open_file(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connect to the cleanup server. Log client name/address with queue ID.
|
||||||
|
*/
|
||||||
|
state->dest = mail_stream_service(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP);
|
||||||
|
if (state->dest == 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->cleanup = state->dest->stream;
|
||||||
|
state->queue_id = mystrdup(state->dest->id);
|
||||||
|
msg_info("%s: client=%s", state->queue_id, state->namaddr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record the time of arrival. Optionally, enable content filtering (not
|
||||||
|
* bloody likely, but present for the sake of consistency with all other
|
||||||
|
* Postfix points of entrance).
|
||||||
|
*/
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld", state->time);
|
||||||
|
if (*var_filter_xport)
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_read_content - receive message content */
|
||||||
|
|
||||||
|
static void qmqpd_read_content(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
state->where = "receiving message content";
|
||||||
|
netstring_get(state->client, state->message, var_message_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_copy_sender - copy envelope sender */
|
||||||
|
|
||||||
|
static void qmqpd_copy_sender(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
state->where = "receiving sender address";
|
||||||
|
netstring_get(state->client, state->buf, var_line_limit);
|
||||||
|
if (state->err == CLEANUP_STAT_OK
|
||||||
|
&& REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0)
|
||||||
|
state->err = CLEANUP_STAT_WRITE;
|
||||||
|
state->sender = mystrndup(STR(state->buf), LEN(state->buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_copy_recipients - copy message recipients */
|
||||||
|
|
||||||
|
static void qmqpd_copy_recipients(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remember the first recipient. We are done when we read the over-all
|
||||||
|
* netstring terminator.
|
||||||
|
*
|
||||||
|
* XXX This approach violates abstractions, but it is a heck of a lot more
|
||||||
|
* convenient than counting the over-all byte count down to zero, like
|
||||||
|
* qmail does.
|
||||||
|
*/
|
||||||
|
state->where = "receiving recipient address";
|
||||||
|
while ((ch = VSTREAM_GETC(state->client)) != ',') {
|
||||||
|
vstream_ungetc(state->client, ch);
|
||||||
|
netstring_get(state->client, state->buf, var_line_limit);
|
||||||
|
if (state->err == CLEANUP_STAT_OK
|
||||||
|
&& REC_PUT_BUF(state->cleanup, REC_TYPE_RCPT, state->buf) < 0)
|
||||||
|
state->err = CLEANUP_STAT_WRITE;
|
||||||
|
state->rcpt_count++;
|
||||||
|
if (state->recipient == 0)
|
||||||
|
state->recipient = mystrndup(STR(state->buf), LEN(state->buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append the optional recipient who is copied on all mail.
|
||||||
|
*/
|
||||||
|
if (*var_always_bcc)
|
||||||
|
rec_fputs(state->cleanup, REC_TYPE_RCPT, var_always_bcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_next_line - get line from buffer, return last char, newline, or -1 */
|
||||||
|
|
||||||
|
static int qmqpd_next_line(VSTRING *message, char **start, int *len,
|
||||||
|
char **next)
|
||||||
|
{
|
||||||
|
char *beyond = STR(message) + LEN(message);
|
||||||
|
char *enough = *next + var_line_limit;
|
||||||
|
char *cp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop at newline or at some limit. Don't look beyond the end of the
|
||||||
|
* buffer.
|
||||||
|
*/
|
||||||
|
#define UCHARPTR(x) ((unsigned char *) (x))
|
||||||
|
|
||||||
|
for (cp = *start = *next; /* void */ ; cp++) {
|
||||||
|
if (cp >= beyond)
|
||||||
|
return ((*len = (*next = cp) - *start) > 0 ? UCHARPTR(cp)[-1] : -1);
|
||||||
|
if (*cp == '\n')
|
||||||
|
return ((*len = cp - *start), (*next = cp + 1), '\n');
|
||||||
|
if (cp >= enough)
|
||||||
|
return ((*len = cp - *start), (*next = cp), UCHARPTR(cp)[-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_write_content - write the message content segment */
|
||||||
|
|
||||||
|
static void qmqpd_write_content(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
char *start;
|
||||||
|
char *next;
|
||||||
|
int len;
|
||||||
|
int rec_type;
|
||||||
|
int first = 1;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the message content segment. Prepend our own Received: header to
|
||||||
|
* the message content. List the recipient only when a message has one
|
||||||
|
* recipient. Otherwise, don't list the recipient to avoid revealing Bcc:
|
||||||
|
* recipients that are supposed to be invisible.
|
||||||
|
*/
|
||||||
|
rec_fputs(state->cleanup, REC_TYPE_MESG, "");
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_NORM, "Received: from %s (%s [%s])",
|
||||||
|
state->name, state->name, state->addr);
|
||||||
|
if (state->rcpt_count == 1 && state->recipient) {
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_NORM,
|
||||||
|
"\tby %s (%s) with %s id %s",
|
||||||
|
var_myhostname, var_mail_name,
|
||||||
|
state->protocol, state->queue_id);
|
||||||
|
quote_822_local(state->buf, state->recipient);
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_NORM,
|
||||||
|
"\tfor <%s>; %s", STR(state->buf), mail_date(state->time));
|
||||||
|
} else {
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_NORM,
|
||||||
|
"\tby %s (%s) with %s",
|
||||||
|
var_myhostname, var_mail_name, state->protocol);
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_NORM,
|
||||||
|
"\tid %s; %s", state->queue_id, mail_date(state->time));
|
||||||
|
}
|
||||||
|
#ifdef RECEIVED_ENVELOPE_FROM
|
||||||
|
quote_822_local(state->buf, state->sender);
|
||||||
|
rec_fprintf(state->cleanup, REC_TYPE_NORM,
|
||||||
|
"\t(envelope-from <%s>)", STR(state->buf));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the message content.
|
||||||
|
*
|
||||||
|
* XXX Force an empty record when the queue file content begins with
|
||||||
|
* whitespace, so that it won't be considered as being part of our own
|
||||||
|
* Received: header. What an ugly Kluge.
|
||||||
|
*
|
||||||
|
* XXX Deal with UNIX-style From_ lines at the start of message content just
|
||||||
|
* in case.
|
||||||
|
*/
|
||||||
|
for (next = STR(state->message); /* void */ ; /* void */ ) {
|
||||||
|
if ((ch = qmqpd_next_line(state->message, &start, &len, &next)) < 0)
|
||||||
|
break;
|
||||||
|
if (ch == '\n')
|
||||||
|
rec_type = REC_TYPE_NORM;
|
||||||
|
else
|
||||||
|
rec_type = REC_TYPE_CONT;
|
||||||
|
if (first) {
|
||||||
|
if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) {
|
||||||
|
rec_fprintf(state->cleanup, rec_type,
|
||||||
|
"Mailbox-Line: %*s", len, start);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
first = 0;
|
||||||
|
if (len > 0 && ISSPACE(start[0]))
|
||||||
|
rec_put(state->cleanup, REC_TYPE_NORM, "", 0);
|
||||||
|
}
|
||||||
|
if (rec_put(state->cleanup, rec_type, start, len) < 0) {
|
||||||
|
state->err = CLEANUP_STAT_WRITE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_close_file - close queue file */
|
||||||
|
|
||||||
|
static void qmqpd_close_file(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send the end-of-segment markers.
|
||||||
|
*/
|
||||||
|
if (state->err == CLEANUP_STAT_OK)
|
||||||
|
if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0
|
||||||
|
|| rec_fputs(state->cleanup, REC_TYPE_END, "") < 0
|
||||||
|
|| vstream_fflush(state->cleanup))
|
||||||
|
state->err = CLEANUP_STAT_WRITE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finish the queue file or finish the cleanup conversation.
|
||||||
|
*/
|
||||||
|
if (state->err == 0)
|
||||||
|
state->err = mail_stream_finish(state->dest);
|
||||||
|
else
|
||||||
|
mail_stream_cleanup(state->dest);
|
||||||
|
state->dest = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_reply - send status to client and optionally log message */
|
||||||
|
|
||||||
|
static void qmqpd_reply(QMQPD_STATE *state, int log_message,
|
||||||
|
int status_code, const char *fmt,...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Optionally change hard errors into retryable ones. Send the reply and
|
||||||
|
* optionally log it. Always insert a delay before reporting a problem.
|
||||||
|
* This slows down software run-away conditions.
|
||||||
|
*/
|
||||||
|
if (status_code == QMQPD_STAT_HARD && var_soft_bounce)
|
||||||
|
status_code = QMQPD_STAT_RETRY;
|
||||||
|
VSTRING_RESET(state->buf);
|
||||||
|
VSTRING_ADDCH(state->buf, status_code);
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vstring_vsprintf_append(state->buf, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
NETSTRING_PUT_BUF(state->client, state->buf);
|
||||||
|
if (log_message)
|
||||||
|
(status_code == QMQPD_STAT_OK ? msg_info : msg_warn) ("%s: %s: %s",
|
||||||
|
state->queue_id, state->namaddr, STR(state->buf) + 1);
|
||||||
|
if (status_code != QMQPD_STAT_OK)
|
||||||
|
sleep(var_qmqpd_err_sleep);
|
||||||
|
netstring_fflush(state->client);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_send_status - send mail transaction completion status */
|
||||||
|
|
||||||
|
static int qmqpd_send_status(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One message may suffer from multiple errors, so complain only about
|
||||||
|
* the most severe error.
|
||||||
|
*/
|
||||||
|
state->where = "sending completion status";
|
||||||
|
|
||||||
|
if (state->err == CLEANUP_STAT_OK) {
|
||||||
|
qmqpd_reply(state, DONT_LOG, QMQPD_STAT_OK,
|
||||||
|
"Ok: queued as %s", state->queue_id);
|
||||||
|
} else if ((state->err & CLEANUP_STAT_BAD) != 0) {
|
||||||
|
qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
|
||||||
|
"Error: internal error %d", state->err);
|
||||||
|
} else if ((state->err & CLEANUP_STAT_SIZE) != 0) {
|
||||||
|
qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
|
||||||
|
"Error: message too large");
|
||||||
|
} else if ((state->err & CLEANUP_STAT_HOPS) != 0) {
|
||||||
|
qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
|
||||||
|
"Error: too many hops");
|
||||||
|
} else if ((state->err & CLEANUP_STAT_CONT) != 0) {
|
||||||
|
qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
|
||||||
|
"Error: content rejected");
|
||||||
|
} else if ((state->err & CLEANUP_STAT_WRITE) != 0) {
|
||||||
|
qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY,
|
||||||
|
"Error: queue file write error");
|
||||||
|
} else if ((state->err & CLEANUP_STAT_RCPT) != 0) {
|
||||||
|
qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD,
|
||||||
|
"Error: no recipients specified");
|
||||||
|
} else {
|
||||||
|
msg_panic("qmqpd_send_status: unknown status %d", state->err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_receive - receive QMQP message+sender+recipients */
|
||||||
|
|
||||||
|
static int qmqpd_receive(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open a queue file. This must be first so that we can simplify the
|
||||||
|
* error logging and always include the queue ID information.
|
||||||
|
*/
|
||||||
|
qmqpd_open_file(state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read and ignore the over-all netstring length indicator.
|
||||||
|
*/
|
||||||
|
state->where = "receiving QMQP packet header";
|
||||||
|
(void) netstring_get_length(state->client);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Read the message content into memory, because Postfix expects to
|
||||||
|
* store the sender before storing the message content. Fixing that
|
||||||
|
* requires changes to pickup, cleanup, qmgr, and perhaps elsewhere, so
|
||||||
|
* that will have to happen later when I have more time. However, QMQP is
|
||||||
|
* used for mailing list distribution, so the bulk of the volume is
|
||||||
|
* expected to be not message content but recipients, and recipients are
|
||||||
|
* not accumulated in memory.
|
||||||
|
*/
|
||||||
|
qmqpd_read_content(state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read and write the envelope sender.
|
||||||
|
*/
|
||||||
|
qmqpd_copy_sender(state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read and write the envelope recipients, including the optional big
|
||||||
|
* brother recipient.
|
||||||
|
*/
|
||||||
|
qmqpd_copy_recipients(state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the message content segment, prepend our own Received: header,
|
||||||
|
* and write the message content.
|
||||||
|
*/
|
||||||
|
qmqpd_write_content(state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the queue file.
|
||||||
|
*/
|
||||||
|
qmqpd_close_file(state);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Report the completion status to the client.
|
||||||
|
*/
|
||||||
|
qmqpd_send_status(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_proto - speak the QMQP "protocol" */
|
||||||
|
|
||||||
|
static void qmqpd_proto(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
netstring_setup(state->client, var_qmqpd_timeout);
|
||||||
|
|
||||||
|
switch (status = vstream_setjmp(state->client)) {
|
||||||
|
|
||||||
|
default:
|
||||||
|
msg_panic("qmqpd_proto: unknown status %d", status);
|
||||||
|
|
||||||
|
case NETSTRING_ERR_EOF:
|
||||||
|
state->reason = "lost connection";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NETSTRING_ERR_TIME:
|
||||||
|
state->reason = "read/write timeout";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NETSTRING_ERR_FORMAT:
|
||||||
|
state->reason = "netstring format error";
|
||||||
|
if (vstream_setjmp(state->client) == 0)
|
||||||
|
if (state->reason && state->where)
|
||||||
|
qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
|
||||||
|
state->reason, state->where);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NETSTRING_ERR_SIZE:
|
||||||
|
state->reason = "netstring length exceeds storage limit";
|
||||||
|
if (vstream_setjmp(state->client) == 0)
|
||||||
|
if (state->reason && state->where)
|
||||||
|
qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s",
|
||||||
|
state->reason, state->where);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
qmqpd_receive(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Log abnormal session termination. Indicate the last recognized state
|
||||||
|
* before things went wrong.
|
||||||
|
*/
|
||||||
|
if (state->reason && state->where)
|
||||||
|
msg_info("%s: %s: %s while %s",
|
||||||
|
state->queue_id, state->namaddr, state->reason, state->where);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_service - service one client */
|
||||||
|
|
||||||
|
static void qmqpd_service(VSTREAM *stream, char *unused_service, char **argv)
|
||||||
|
{
|
||||||
|
QMQPD_STATE *state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check. This service takes no command-line arguments.
|
||||||
|
*/
|
||||||
|
if (argv[0])
|
||||||
|
msg_fatal("unexpected command-line argument: %s", argv[0]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This routine runs when a client has connected to our network port.
|
||||||
|
* Look up and sanitize the peer name and initialize some connection-
|
||||||
|
* specific state.
|
||||||
|
*/
|
||||||
|
state = qmqpd_state_alloc(stream);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we need to turn on verbose logging for this client.
|
||||||
|
*/
|
||||||
|
debug_peer_check(state->name, state->addr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if we want to talk to this client at all. In all cases, log the
|
||||||
|
* connection event.
|
||||||
|
*/
|
||||||
|
if (namadr_list_match(qmqpd_clients, state->name, state->addr) == 0) {
|
||||||
|
msg_info("refused connect from %s", state->namaddr);
|
||||||
|
qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD,
|
||||||
|
"Error: %s is not authorized to use this service",
|
||||||
|
state->namaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Provide the QMQP service.
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
msg_info("connect from %s", state->namaddr);
|
||||||
|
qmqpd_proto(state);
|
||||||
|
msg_info("disconnect from %s", state->namaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* After the client has gone away, clean up whatever we have set up at
|
||||||
|
* connection time.
|
||||||
|
*/
|
||||||
|
debug_peer_restore();
|
||||||
|
qmqpd_state_free(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pre_accept - see if tables have changed */
|
||||||
|
|
||||||
|
static void pre_accept(char *unused_name, char **unused_argv)
|
||||||
|
{
|
||||||
|
if (dict_changed()) {
|
||||||
|
msg_info("lookup table has changed -- exiting");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pre_jail_init - pre-jail initialization */
|
||||||
|
|
||||||
|
static void pre_jail_init(char *unused_name, char **unused_argv)
|
||||||
|
{
|
||||||
|
debug_peer_init();
|
||||||
|
qmqpd_clients = namadr_list_init(var_qmqpd_clients);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* main - the main program */
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
static CONFIG_TIME_TABLE time_table[] = {
|
||||||
|
VAR_QMTPD_TMOUT, DEF_QMTPD_TMOUT, &var_qmqpd_timeout, 1, 0,
|
||||||
|
VAR_QMTPD_ERR_SLEEP, DEF_QMTPD_ERR_SLEEP, &var_qmqpd_err_sleep, 0, 0,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
static CONFIG_STR_TABLE str_table[] = {
|
||||||
|
VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0,
|
||||||
|
VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
|
||||||
|
VAR_QMQPD_CLIENTS, DEF_QMQPD_CLIENTS, &var_qmqpd_clients, 0, 0,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pass control to the single-threaded service skeleton.
|
||||||
|
*/
|
||||||
|
single_server_main(argc, argv, qmqpd_service,
|
||||||
|
MAIL_SERVER_TIME_TABLE, time_table,
|
||||||
|
MAIL_SERVER_STR_TABLE, str_table,
|
||||||
|
MAIL_SERVER_PRE_INIT, pre_jail_init,
|
||||||
|
MAIL_SERVER_PRE_ACCEPT, pre_accept,
|
||||||
|
0);
|
||||||
|
}
|
78
postfix/src/qmqpd/qmqpd.h
Normal file
78
postfix/src/qmqpd/qmqpd.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* qmqpd 3h
|
||||||
|
/* SUMMARY
|
||||||
|
/* Postfix QMQP server
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* include "qmqpd.h"
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* .nf
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System library.
|
||||||
|
*/
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility library.
|
||||||
|
*/
|
||||||
|
#include <vstream.h>
|
||||||
|
#include <vstring.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global library.
|
||||||
|
*/
|
||||||
|
#include <mail_stream.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per-session state.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int err; /* error flags */
|
||||||
|
VSTREAM *client; /* client connection */
|
||||||
|
VSTRING *message; /* message buffer */
|
||||||
|
VSTRING *buf; /* line buffer */
|
||||||
|
time_t time; /* start of session */
|
||||||
|
char *name; /* client name */
|
||||||
|
char *addr; /* client IP address */
|
||||||
|
char *namaddr; /* name[addr] */
|
||||||
|
char *queue_id; /* queue file ID */
|
||||||
|
VSTREAM *cleanup; /* cleanup server */
|
||||||
|
MAIL_STREAM *dest; /* cleanup server */
|
||||||
|
int rcpt_count; /* recipient count */
|
||||||
|
char *reason; /* exception name */
|
||||||
|
char *sender; /* sender address */
|
||||||
|
char *recipient; /* recipient address */
|
||||||
|
char *protocol; /* protocol name */
|
||||||
|
char *where; /* protocol state */
|
||||||
|
} QMQPD_STATE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* QMQP protocol status codes.
|
||||||
|
*/
|
||||||
|
#define QMQPD_STAT_OK 'K'
|
||||||
|
#define QMQPD_STAT_RETRY 'Z'
|
||||||
|
#define QMQPD_STAT_HARD 'D'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qmqpd_state.c
|
||||||
|
*/
|
||||||
|
QMQPD_STATE *qmqpd_state_alloc(VSTREAM *);
|
||||||
|
void qmqpd_state_free(QMQPD_STATE *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qmqpd_peer.c
|
||||||
|
*/
|
||||||
|
void qmqpd_peer_init(QMQPD_STATE *);
|
||||||
|
void qmqpd_peer_reset(QMQPD_STATE *);
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
/*--*/
|
183
postfix/src/qmqpd/qmqpd_peer.c
Normal file
183
postfix/src/qmqpd/qmqpd_peer.c
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* qmqpd_peer 3
|
||||||
|
/* SUMMARY
|
||||||
|
/* look up peer name/address information
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* #include "qmqpd.h"
|
||||||
|
/*
|
||||||
|
/* void qmqpd_peer_init(state)
|
||||||
|
/* QMQPD_STATE *state;
|
||||||
|
/*
|
||||||
|
/* void qmqpd_peer_reset(state)
|
||||||
|
/* QMQPD_STATE *state;
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* The qmqpd_peer_init() routine attempts to produce a printable
|
||||||
|
/* version of the peer name and address of the specified socket.
|
||||||
|
/* Where information is unavailable, the name and/or address
|
||||||
|
/* are set to "unknown".
|
||||||
|
/*
|
||||||
|
/* qmqpd_peer_init() updates the following fields:
|
||||||
|
/* .IP name
|
||||||
|
/* The client hostname. An unknown name is represented by the
|
||||||
|
/* string "unknown".
|
||||||
|
/* .IP addr
|
||||||
|
/* Printable representation of the client address.
|
||||||
|
/* .IP namaddr
|
||||||
|
/* String of the form: "name[addr]".
|
||||||
|
/* .PP
|
||||||
|
/* qmqpd_peer_reset() releases memory allocate by qmqpd_peer_init().
|
||||||
|
/* 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 <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <stdio.h> /* strerror() */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Older systems don't have h_errno. Even modern systems don't have
|
||||||
|
* hstrerror().
|
||||||
|
*/
|
||||||
|
#ifdef NO_HERRNO
|
||||||
|
|
||||||
|
static int h_errno = TRY_AGAIN;
|
||||||
|
|
||||||
|
#define HSTRERROR(err) "Host not found"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define HSTRERROR(err) (\
|
||||||
|
err == TRY_AGAIN ? "Host not found, try again" : \
|
||||||
|
err == HOST_NOT_FOUND ? "Host not found" : \
|
||||||
|
err == NO_DATA ? "Host name has no address" : \
|
||||||
|
err == NO_RECOVERY ? "Name server failure" : \
|
||||||
|
strerror(errno) \
|
||||||
|
)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Utility library. */
|
||||||
|
|
||||||
|
#include <msg.h>
|
||||||
|
#include <mymalloc.h>
|
||||||
|
#include <valid_hostname.h>
|
||||||
|
#include <stringops.h>
|
||||||
|
|
||||||
|
/* Global library. */
|
||||||
|
|
||||||
|
|
||||||
|
/* Application-specific. */
|
||||||
|
|
||||||
|
#include "qmqpd.h"
|
||||||
|
|
||||||
|
/* qmqpd_peer_init - initialize peer information */
|
||||||
|
|
||||||
|
void qmqpd_peer_init(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
SOCKADDR_SIZE len = sizeof(sin);
|
||||||
|
struct hostent *hp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up the peer address information.
|
||||||
|
*/
|
||||||
|
if (getpeername(vstream_fileno(state->client),
|
||||||
|
(struct sockaddr *) & sin, &len) >= 0) {
|
||||||
|
errno = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If peer went away, give up.
|
||||||
|
*/
|
||||||
|
if (errno == ECONNRESET || errno == ECONNABORTED) {
|
||||||
|
state->name = mystrdup("unknown");
|
||||||
|
state->addr = mystrdup("unknown");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Look up and "verify" the client hostname.
|
||||||
|
*/
|
||||||
|
else if (errno == 0 && sin.sin_family == AF_INET) {
|
||||||
|
state->addr = mystrdup(inet_ntoa(sin.sin_addr));
|
||||||
|
hp = gethostbyaddr((char *) &(sin.sin_addr),
|
||||||
|
sizeof(sin.sin_addr), AF_INET);
|
||||||
|
if (hp == 0) {
|
||||||
|
state->name = mystrdup("unknown");
|
||||||
|
} else if (!valid_hostname(hp->h_name, DONT_GRIPE)) {
|
||||||
|
state->name = mystrdup("unknown");
|
||||||
|
} else {
|
||||||
|
state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reject the hostname if it does not list the peer address.
|
||||||
|
*/
|
||||||
|
#define REJECT_PEER_NAME(state) { \
|
||||||
|
myfree(state->name); \
|
||||||
|
state->name = mystrdup("unknown"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
hp = gethostbyname(state->name); /* clobbers hp->name!! */
|
||||||
|
if (hp == 0) {
|
||||||
|
msg_warn("%s: hostname %s verification failed: %s",
|
||||||
|
state->addr, state->name, HSTRERROR(h_errno));
|
||||||
|
REJECT_PEER_NAME(state);
|
||||||
|
} else if (hp->h_length != sizeof(sin.sin_addr)) {
|
||||||
|
msg_warn("%s: hostname %s verification failed: bad address size %d",
|
||||||
|
state->addr, state->name, hp->h_length);
|
||||||
|
REJECT_PEER_NAME(state);
|
||||||
|
} else {
|
||||||
|
for (i = 0; /* void */ ; i++) {
|
||||||
|
if (hp->h_addr_list[i] == 0) {
|
||||||
|
msg_warn("%s: address not listed for hostname %s",
|
||||||
|
state->addr, state->name);
|
||||||
|
REJECT_PEER_NAME(state);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (memcmp(hp->h_addr_list[i],
|
||||||
|
(char *) &sin.sin_addr,
|
||||||
|
sizeof(sin.sin_addr)) == 0)
|
||||||
|
break; /* keep peer name */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If it's not Internet, assume the client is local, and avoid using the
|
||||||
|
* naming service because that can hang when the machine is disconnected.
|
||||||
|
*/
|
||||||
|
else {
|
||||||
|
state->name = mystrdup("localhost");
|
||||||
|
state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do the name[addr] formatting for pretty reports.
|
||||||
|
*/
|
||||||
|
state->namaddr =
|
||||||
|
concatenate(state->name, "[", state->addr, "]", (char *) 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_peer_reset - destroy peer information */
|
||||||
|
|
||||||
|
void qmqpd_peer_reset(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
myfree(state->name);
|
||||||
|
myfree(state->addr);
|
||||||
|
myfree(state->namaddr);
|
||||||
|
}
|
96
postfix/src/qmqpd/qmqpd_state.c
Normal file
96
postfix/src/qmqpd/qmqpd_state.c
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* qmqpd_state 3
|
||||||
|
/* SUMMARY
|
||||||
|
/* Postfix QMQP server
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* #include "qmqpd.h"
|
||||||
|
/*
|
||||||
|
/* QMQPD_STATE *qmqpd_state_alloc(stream)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/*
|
||||||
|
/* void qmqpd_state_free(state)
|
||||||
|
/* QMQPD_STATE *state;
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* qmqpd_state_alloc() creates and initializes session context.
|
||||||
|
/*
|
||||||
|
/* qmqpd_state_free() destroys session context.
|
||||||
|
/*
|
||||||
|
/* Arguments:
|
||||||
|
/* .IP stream
|
||||||
|
/* Stream connected to peer. The stream is not copied.
|
||||||
|
/* DIAGNOSTICS
|
||||||
|
/* All errors are fatal.
|
||||||
|
/* 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 <time.h>
|
||||||
|
|
||||||
|
/* Utility library. */
|
||||||
|
|
||||||
|
#include <mymalloc.h>
|
||||||
|
#include <vstream.h>
|
||||||
|
#include <vstring.h>
|
||||||
|
|
||||||
|
/* Global library. */
|
||||||
|
|
||||||
|
#include <mail_stream.h>
|
||||||
|
#include <cleanup_user.h>
|
||||||
|
|
||||||
|
/* Application-specific. */
|
||||||
|
|
||||||
|
#include <qmqpd.h>
|
||||||
|
|
||||||
|
/* qmqpd_state_alloc - allocate and initialize session state */
|
||||||
|
|
||||||
|
QMQPD_STATE *qmqpd_state_alloc(VSTREAM *stream)
|
||||||
|
{
|
||||||
|
QMQPD_STATE *state;
|
||||||
|
|
||||||
|
state = (QMQPD_STATE *) mymalloc(sizeof(*state));
|
||||||
|
state->err = CLEANUP_STAT_OK;
|
||||||
|
state->client = stream;
|
||||||
|
state->message = vstring_alloc(1000);
|
||||||
|
state->buf = vstring_alloc(100);
|
||||||
|
state->time = time((time_t *) 0);
|
||||||
|
qmqpd_peer_init(state);
|
||||||
|
state->queue_id = 0;
|
||||||
|
state->cleanup = 0;
|
||||||
|
state->dest = 0;
|
||||||
|
state->rcpt_count = 0;
|
||||||
|
state->reason = 0;
|
||||||
|
state->sender = 0;
|
||||||
|
state->recipient = 0;
|
||||||
|
state->protocol = "QMQP";
|
||||||
|
state->where = "initializing client connection";
|
||||||
|
return (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* qmqpd_state_free - destroy session state */
|
||||||
|
|
||||||
|
void qmqpd_state_free(QMQPD_STATE *state)
|
||||||
|
{
|
||||||
|
vstring_free(state->message);
|
||||||
|
vstring_free(state->buf);
|
||||||
|
qmqpd_peer_reset(state);
|
||||||
|
if (state->queue_id)
|
||||||
|
myfree(state->queue_id);
|
||||||
|
if (state->dest)
|
||||||
|
mail_stream_cleanup(state->dest);
|
||||||
|
if (state->sender)
|
||||||
|
myfree(state->sender);
|
||||||
|
if (state->recipient)
|
||||||
|
myfree(state->recipient);
|
||||||
|
myfree((char *) state);
|
||||||
|
}
|
@@ -95,6 +95,9 @@
|
|||||||
/* Always send EHLO at the start of a connection.
|
/* Always send EHLO at the start of a connection.
|
||||||
/* .IP \fBsmtp_never_send_ehlo\fR
|
/* .IP \fBsmtp_never_send_ehlo\fR
|
||||||
/* Never send EHLO at the start of a connection.
|
/* Never send EHLO at the start of a connection.
|
||||||
|
/* .IP \fBsmtp_break_lines\fR
|
||||||
|
/* Break lines > \fB$line_length_limit\fR into multiple shorter lines.
|
||||||
|
/* Some SMTP servers misbehave on long lines.
|
||||||
/* .IP \fBsmtp_skip_4xx_greeting\fR
|
/* .IP \fBsmtp_skip_4xx_greeting\fR
|
||||||
/* Skip servers that greet us with a 4xx status code.
|
/* Skip servers that greet us with a 4xx status code.
|
||||||
/* .IP \fBsmtp_skip_5xx_greeting\fR
|
/* .IP \fBsmtp_skip_5xx_greeting\fR
|
||||||
@@ -250,6 +253,7 @@ char *var_smtp_sasl_passwd;
|
|||||||
bool var_smtp_sasl_enable;
|
bool var_smtp_sasl_enable;
|
||||||
char *var_smtp_bind_addr;
|
char *var_smtp_bind_addr;
|
||||||
bool var_smtp_rand_addr;
|
bool var_smtp_rand_addr;
|
||||||
|
bool var_smtp_break_lines;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global variables. smtp_errno is set by the address lookup routines and by
|
* Global variables. smtp_errno is set by the address lookup routines and by
|
||||||
@@ -426,6 +430,7 @@ int main(int argc, char **argv)
|
|||||||
VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo,
|
VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo,
|
||||||
VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
|
VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
|
||||||
VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr,
|
VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr,
|
||||||
|
VAR_SMTP_BREAK_LINES, DEF_SMTP_BREAK_LINES, &var_smtp_break_lines,
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -79,11 +79,33 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#ifndef INADDR_NONE
|
#ifndef INADDR_NONE
|
||||||
#define INADDR_NONE 0xffffffff
|
#define INADDR_NONE 0xffffffff
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Older systems don't have h_errno. Even modern systems don't have
|
||||||
|
* hstrerror().
|
||||||
|
*/
|
||||||
|
#ifdef NO_HERRNO
|
||||||
|
|
||||||
|
static int h_errno = TRY_AGAIN;
|
||||||
|
|
||||||
|
#define HSTRERROR(err) "Host not found"
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define HSTRERROR(err) (\
|
||||||
|
err == TRY_AGAIN ? "Host not found, try again" : \
|
||||||
|
err == HOST_NOT_FOUND ? "Host not found" : \
|
||||||
|
err == NO_DATA ? "Host name has no address" : \
|
||||||
|
err == NO_RECOVERY ? "Name server failure" : \
|
||||||
|
strerror(errno) \
|
||||||
|
)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Utility library. */
|
/* Utility library. */
|
||||||
|
|
||||||
#include <msg.h>
|
#include <msg.h>
|
||||||
@@ -158,8 +180,8 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRI
|
|||||||
if (var_disable_dns) {
|
if (var_disable_dns) {
|
||||||
memset((char *) &fixed, 0, sizeof(fixed));
|
memset((char *) &fixed, 0, sizeof(fixed));
|
||||||
if ((hp = gethostbyname(host)) == 0) {
|
if ((hp = gethostbyname(host)) == 0) {
|
||||||
vstring_sprintf(why, "%s: host not found", host);
|
vstring_sprintf(why, "%s: %s", host, HSTRERROR(h_errno));
|
||||||
smtp_errno = SMTP_FAIL;
|
smtp_errno = (h_errno == TRY_AGAIN ? SMTP_RETRY : SMTP_FAIL);
|
||||||
} else if (hp->h_addrtype != AF_INET) {
|
} else if (hp->h_addrtype != AF_INET) {
|
||||||
vstring_sprintf(why, "%s: host not found", host);
|
vstring_sprintf(why, "%s: host not found", host);
|
||||||
msg_warn("%s: unknown address family %d for %s",
|
msg_warn("%s: unknown address family %d for %s",
|
||||||
|
@@ -394,7 +394,7 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
|
|||||||
char *save;
|
char *save;
|
||||||
char *dest;
|
char *dest;
|
||||||
char *cp;
|
char *cp;
|
||||||
int found_myself;
|
int found_myself = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First try to deliver to the indicated destination, then try to deliver
|
* First try to deliver to the indicated destination, then try to deliver
|
||||||
|
@@ -505,7 +505,7 @@ int smtp_xfer(SMTP_STATE *state)
|
|||||||
*/
|
*/
|
||||||
case SMTP_STATE_RCPT:
|
case SMTP_STATE_RCPT:
|
||||||
if (!mail_from_rejected) {
|
if (!mail_from_rejected) {
|
||||||
#ifndef notRFC821_SYNTAX
|
#ifdef notdef
|
||||||
if (resp->code == 552)
|
if (resp->code == 552)
|
||||||
resp->code = 452;
|
resp->code = 452;
|
||||||
#endif
|
#endif
|
||||||
@@ -642,6 +642,8 @@ int smtp_xfer(SMTP_STATE *state)
|
|||||||
if (prev_type != REC_TYPE_CONT)
|
if (prev_type != REC_TYPE_CONT)
|
||||||
if (vstring_str(state->scratch)[0] == '.')
|
if (vstring_str(state->scratch)[0] == '.')
|
||||||
smtp_fputc('.', session->stream);
|
smtp_fputc('.', session->stream);
|
||||||
|
if (var_smtp_break_lines)
|
||||||
|
rec_type = REC_TYPE_NORM;
|
||||||
if (rec_type == REC_TYPE_CONT)
|
if (rec_type == REC_TYPE_CONT)
|
||||||
smtp_fwrite(vstring_str(state->scratch),
|
smtp_fwrite(vstring_str(state->scratch),
|
||||||
VSTRING_LEN(state->scratch),
|
VSTRING_LEN(state->scratch),
|
||||||
|
@@ -139,11 +139,11 @@ static int smtp_sasl_log(void *unused_context, int priority,
|
|||||||
switch (priority) {
|
switch (priority) {
|
||||||
case SASL_LOG_ERR:
|
case SASL_LOG_ERR:
|
||||||
case SASL_LOG_WARNING:
|
case SASL_LOG_WARNING:
|
||||||
msg_warn("%s", message);
|
msg_warn("SASL authentication problem: %s", message);
|
||||||
break;
|
break;
|
||||||
case SASL_LOG_INFO:
|
case SASL_LOG_INFO:
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s", message);
|
msg_info("SASL authentication info: %s", message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (SASL_OK);
|
return (SASL_OK);
|
||||||
|
@@ -339,6 +339,7 @@ bool var_disable_vrfy_cmd;
|
|||||||
char *var_canonical_maps;
|
char *var_canonical_maps;
|
||||||
char *var_rcpt_canon_maps;
|
char *var_rcpt_canon_maps;
|
||||||
char *var_virtual_maps;
|
char *var_virtual_maps;
|
||||||
|
char *var_virt_mailbox_maps;
|
||||||
char *var_relocated_maps;
|
char *var_relocated_maps;
|
||||||
char *var_alias_maps;
|
char *var_alias_maps;
|
||||||
char *var_local_rcpt_maps;
|
char *var_local_rcpt_maps;
|
||||||
@@ -1551,6 +1552,7 @@ int main(int argc, char **argv)
|
|||||||
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
|
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
|
||||||
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
|
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
|
||||||
VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, 0, 0,
|
VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, 0, 0,
|
||||||
|
VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
|
||||||
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
|
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
|
||||||
VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0,
|
VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0,
|
||||||
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
|
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
|
||||||
|
@@ -323,6 +323,7 @@ static MAPS *local_rcpt_maps;
|
|||||||
static MAPS *rcpt_canon_maps;
|
static MAPS *rcpt_canon_maps;
|
||||||
static MAPS *canonical_maps;
|
static MAPS *canonical_maps;
|
||||||
static MAPS *virtual_maps;
|
static MAPS *virtual_maps;
|
||||||
|
static MAPS *virt_mailbox_maps;
|
||||||
static MAPS *relocated_maps;
|
static MAPS *relocated_maps;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -467,6 +468,8 @@ void smtpd_check_init(void)
|
|||||||
DICT_FLAG_LOCK);
|
DICT_FLAG_LOCK);
|
||||||
virtual_maps = maps_create(VAR_VIRTUAL_MAPS, var_virtual_maps,
|
virtual_maps = maps_create(VAR_VIRTUAL_MAPS, var_virtual_maps,
|
||||||
DICT_FLAG_LOCK);
|
DICT_FLAG_LOCK);
|
||||||
|
virt_mailbox_maps = maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps,
|
||||||
|
DICT_FLAG_LOCK);
|
||||||
relocated_maps = maps_create(VAR_RELOCATED_MAPS, var_relocated_maps,
|
relocated_maps = maps_create(VAR_RELOCATED_MAPS, var_relocated_maps,
|
||||||
DICT_FLAG_LOCK);
|
DICT_FLAG_LOCK);
|
||||||
|
|
||||||
@@ -565,7 +568,7 @@ static int smtpd_check_reject(SMTPD_STATE *state, int error_class,
|
|||||||
*
|
*
|
||||||
* We could eliminate the code duplication and implement the soft_bounce
|
* We could eliminate the code duplication and implement the soft_bounce
|
||||||
* safety net only in the code below. But then the safety net would cover
|
* safety net only in the code below. But then the safety net would cover
|
||||||
* the UCE restrictions only. This would be at odds with the documentation
|
* the UCE restrictions only. This would be at odds with documentation
|
||||||
* which says soft_bounce changes all 5xx replies into 4xx ones.
|
* which says soft_bounce changes all 5xx replies into 4xx ones.
|
||||||
*/
|
*/
|
||||||
if (var_soft_bounce && STR(error_text)[0] == '5')
|
if (var_soft_bounce && STR(error_text)[0] == '5')
|
||||||
@@ -898,7 +901,9 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient)
|
|||||||
*/
|
*/
|
||||||
if (resolve_local(domain)
|
if (resolve_local(domain)
|
||||||
|| (*var_virtual_maps
|
|| (*var_virtual_maps
|
||||||
&& check_maps_find(state, recipient, virtual_maps, domain, 0)))
|
&& check_maps_find(state, recipient, virtual_maps, domain, 0))
|
||||||
|
|| (*var_virt_mailbox_maps
|
||||||
|
&& check_maps_find(state, recipient, virt_mailbox_maps, domain, 0)))
|
||||||
return (SMTPD_CHECK_OK);
|
return (SMTPD_CHECK_OK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1032,7 +1037,9 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
|
|||||||
domain += 1;
|
domain += 1;
|
||||||
if (resolve_local(domain)
|
if (resolve_local(domain)
|
||||||
|| (*var_virtual_maps
|
|| (*var_virtual_maps
|
||||||
&& check_maps_find(state, recipient, virtual_maps, domain, 0)))
|
&& check_maps_find(state, recipient, virtual_maps, domain, 0))
|
||||||
|
|| (*var_virt_mailbox_maps
|
||||||
|
&& check_maps_find(state, recipient, virt_mailbox_maps, domain, 0)))
|
||||||
return (SMTPD_CHECK_OK);
|
return (SMTPD_CHECK_OK);
|
||||||
|
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
@@ -1174,7 +1181,9 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
|
|||||||
domain += 1;
|
domain += 1;
|
||||||
if (resolve_local(domain)
|
if (resolve_local(domain)
|
||||||
|| (*var_virtual_maps
|
|| (*var_virtual_maps
|
||||||
&& check_maps_find(state, reply_name, virtual_maps, domain, 0)))
|
&& check_maps_find(state, reply_name, virtual_maps, domain, 0))
|
||||||
|
|| (*var_virt_mailbox_maps
|
||||||
|
&& check_maps_find(state, reply_name, virt_mailbox_maps, domain, 0)))
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
if (domain[0] == '#')
|
if (domain[0] == '#')
|
||||||
return (SMTPD_CHECK_DUNNO);
|
return (SMTPD_CHECK_DUNNO);
|
||||||
@@ -2066,6 +2075,23 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
|||||||
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
||||||
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
||||||
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
||||||
|
&& NOMATCH(virt_mailbox_maps, STR(reply.recipient))
|
||||||
|
&& NOMATCH(virtual_maps, STR(reply.recipient))) {
|
||||||
|
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||||
|
"%d <%s>: User unknown", 550, recipient);
|
||||||
|
SMTPD_CHECK_RCPT_RETURN(STR(error_text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reject mail to unknown addresses in Postfix-style virtual domains.
|
||||||
|
*/
|
||||||
|
if (*var_virt_mailbox_maps
|
||||||
|
&& (check_maps_find(state, recipient, virt_mailbox_maps, domain, 0))) {
|
||||||
|
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
||||||
|
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
||||||
|
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
||||||
|
&& NOMATCH(virt_mailbox_maps, STR(reply.recipient))
|
||||||
&& NOMATCH(virtual_maps, STR(reply.recipient))) {
|
&& NOMATCH(virtual_maps, STR(reply.recipient))) {
|
||||||
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||||
"%d <%s>: User unknown", 550, recipient);
|
"%d <%s>: User unknown", 550, recipient);
|
||||||
@@ -2082,6 +2108,7 @@ char *smtpd_check_rcptmap(SMTPD_STATE *state, char *recipient)
|
|||||||
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
if (NOMATCH(rcpt_canon_maps, STR(reply.recipient))
|
||||||
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
&& NOMATCH(canonical_maps, STR(reply.recipient))
|
||||||
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
&& NOMATCH(relocated_maps, STR(reply.recipient))
|
||||||
|
&& NOMATCH(virt_mailbox_maps, STR(reply.recipient))
|
||||||
&& NOMATCH(virtual_maps, STR(reply.recipient))
|
&& NOMATCH(virtual_maps, STR(reply.recipient))
|
||||||
&& NOMATCH(local_rcpt_maps, STR(reply.recipient))) {
|
&& NOMATCH(local_rcpt_maps, STR(reply.recipient))) {
|
||||||
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||||
@@ -2175,6 +2202,7 @@ char *var_alias_maps;
|
|||||||
char *var_rcpt_canon_maps;
|
char *var_rcpt_canon_maps;
|
||||||
char *var_canonical_maps;
|
char *var_canonical_maps;
|
||||||
char *var_virtual_maps;
|
char *var_virtual_maps;
|
||||||
|
char *var_virt_mailbox_maps;
|
||||||
char *var_relocated_maps;
|
char *var_relocated_maps;
|
||||||
char *var_local_rcpt_maps;
|
char *var_local_rcpt_maps;
|
||||||
|
|
||||||
@@ -2195,6 +2223,7 @@ static STRING_TABLE string_table[] = {
|
|||||||
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps,
|
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps,
|
||||||
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps,
|
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps,
|
||||||
VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps,
|
VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps,
|
||||||
|
VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps,
|
||||||
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps,
|
VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps,
|
||||||
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps,
|
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps,
|
||||||
0,
|
0,
|
||||||
@@ -2503,6 +2532,13 @@ main(int argc, char **argv)
|
|||||||
resp = 0;
|
resp = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (strcasecmp(args->argv[0], VAR_VIRT_MAILBOX_MAPS) == 0) {
|
||||||
|
UPDATE_STRING(var_virt_mailbox_maps, args->argv[1]);
|
||||||
|
UPDATE_MAPS(virt_mailbox_maps, VAR_VIRT_MAILBOX_MAPS,
|
||||||
|
var_virt_mailbox_maps, DICT_FLAG_LOCK);
|
||||||
|
resp = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (strcasecmp(args->argv[0], "local_recipient_maps") == 0) {
|
if (strcasecmp(args->argv[0], "local_recipient_maps") == 0) {
|
||||||
UPDATE_STRING(var_local_rcpt_maps, args->argv[1]);
|
UPDATE_STRING(var_local_rcpt_maps, args->argv[1]);
|
||||||
UPDATE_MAPS(local_rcpt_maps, VAR_LOCAL_RCPT_MAPS,
|
UPDATE_MAPS(local_rcpt_maps, VAR_LOCAL_RCPT_MAPS,
|
||||||
|
@@ -119,7 +119,6 @@ void smtpd_peer_init(SMTPD_STATE *state)
|
|||||||
* If peer went away, give up.
|
* If peer went away, give up.
|
||||||
*/
|
*/
|
||||||
if (errno == ECONNRESET || errno == ECONNABORTED) {
|
if (errno == ECONNRESET || errno == ECONNABORTED) {
|
||||||
msg_info("errno %d %m", errno);
|
|
||||||
state->name = mystrdup("unknown");
|
state->name = mystrdup("unknown");
|
||||||
state->addr = mystrdup("unknown");
|
state->addr = mystrdup("unknown");
|
||||||
state->peer_code = 5;
|
state->peer_code = 5;
|
||||||
|
@@ -118,11 +118,11 @@ static int smtpd_sasl_log(void *unused_context, int priority,
|
|||||||
switch (priority) {
|
switch (priority) {
|
||||||
case SASL_LOG_ERR:
|
case SASL_LOG_ERR:
|
||||||
case SASL_LOG_WARNING:
|
case SASL_LOG_WARNING:
|
||||||
msg_warn("%s", message);
|
msg_warn("SASL authentication problem: %s", message);
|
||||||
break;
|
break;
|
||||||
case SASL_LOG_INFO:
|
case SASL_LOG_INFO:
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s", message);
|
msg_info("SASL authentication info: %s", message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return SASL_OK;
|
return SASL_OK;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
SRCS = smtp-source.c smtp-sink.c
|
SRCS = smtp-source.c smtp-sink.c qmqp-source.c qmqp-sink.c
|
||||||
OBJS = smtp-source.o smtp-sink.o
|
OBJS = smtp-source.o smtp-sink.o qmqp-source.o qmqp-sink.o
|
||||||
HDRS =
|
HDRS =
|
||||||
TESTSRC =
|
TESTSRC =
|
||||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||||
@@ -10,7 +10,7 @@ DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
|||||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||||
TESTPROG=
|
TESTPROG=
|
||||||
INC_DIR = ../../include
|
INC_DIR = ../../include
|
||||||
PROG = smtp-source smtp-sink
|
PROG = smtp-source smtp-sink qmqp-source qmqp-sink
|
||||||
LIBS = ../../lib/libglobal.a ../../lib/libutil.a
|
LIBS = ../../lib/libglobal.a ../../lib/libutil.a
|
||||||
|
|
||||||
.c.o:; $(CC) $(CFLAGS) -c $*.c
|
.c.o:; $(CC) $(CFLAGS) -c $*.c
|
||||||
@@ -26,9 +26,15 @@ smtp-sink: smtp-sink.o $(LIBS)
|
|||||||
smtp-source: smtp-source.o $(LIBS)
|
smtp-source: smtp-source.o $(LIBS)
|
||||||
$(CC) $(CFLAGS) -o $@ smtp-source.o $(LIBS) $(SYSLIBS)
|
$(CC) $(CFLAGS) -o $@ smtp-source.o $(LIBS) $(SYSLIBS)
|
||||||
|
|
||||||
|
qmqp-sink: qmqp-sink.o $(LIBS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ qmqp-sink.o $(LIBS) $(SYSLIBS)
|
||||||
|
|
||||||
|
qmqp-source: qmqp-source.o $(LIBS)
|
||||||
|
$(CC) $(CFLAGS) -o $@ qmqp-source.o $(LIBS) $(SYSLIBS)
|
||||||
|
|
||||||
test: $(TESTPROG)
|
test: $(TESTPROG)
|
||||||
|
|
||||||
update: ../../bin/smtp-source ../../bin/smtp-sink
|
update: ../../bin/smtp-source ../../bin/smtp-sink ../../bin/qmqp-source
|
||||||
|
|
||||||
../../bin/smtp-source: smtp-source
|
../../bin/smtp-source: smtp-source
|
||||||
cp $? $@
|
cp $? $@
|
||||||
@@ -36,6 +42,12 @@ update: ../../bin/smtp-source ../../bin/smtp-sink
|
|||||||
../../bin/smtp-sink: smtp-sink
|
../../bin/smtp-sink: smtp-sink
|
||||||
cp $? $@
|
cp $? $@
|
||||||
|
|
||||||
|
../../bin/qmqp-source: qmqp-source
|
||||||
|
cp $? $@
|
||||||
|
|
||||||
|
../../bin/qmqp-sink: qmqp-sink
|
||||||
|
cp $? $@
|
||||||
|
|
||||||
printfck: $(OBJS) $(PROG)
|
printfck: $(OBJS) $(PROG)
|
||||||
rm -rf printfck
|
rm -rf printfck
|
||||||
mkdir printfck
|
mkdir printfck
|
||||||
@@ -61,6 +73,36 @@ depend: $(MAKES)
|
|||||||
@$(EXPORT) make -f Makefile.in Makefile 1>&2
|
@$(EXPORT) make -f Makefile.in Makefile 1>&2
|
||||||
|
|
||||||
# do not edit below this line - it is generated by 'make depend'
|
# do not edit below this line - it is generated by 'make depend'
|
||||||
|
qmqp-sink.o: qmqp-sink.c
|
||||||
|
qmqp-sink.o: ../../include/sys_defs.h
|
||||||
|
qmqp-sink.o: ../../include/msg.h
|
||||||
|
qmqp-sink.o: ../../include/vstring.h
|
||||||
|
qmqp-sink.o: ../../include/vbuf.h
|
||||||
|
qmqp-sink.o: ../../include/vstream.h
|
||||||
|
qmqp-sink.o: ../../include/listen.h
|
||||||
|
qmqp-sink.o: ../../include/iostuff.h
|
||||||
|
qmqp-sink.o: ../../include/events.h
|
||||||
|
qmqp-sink.o: ../../include/mymalloc.h
|
||||||
|
qmqp-sink.o: ../../include/msg_vstream.h
|
||||||
|
qmqp-sink.o: ../../include/netstring.h
|
||||||
|
qmqp-sink.o: ../../include/qmqp_proto.h
|
||||||
|
qmqp-source.o: qmqp-source.c
|
||||||
|
qmqp-source.o: ../../include/sys_defs.h
|
||||||
|
qmqp-source.o: ../../include/msg.h
|
||||||
|
qmqp-source.o: ../../include/msg_vstream.h
|
||||||
|
qmqp-source.o: ../../include/vstream.h
|
||||||
|
qmqp-source.o: ../../include/vbuf.h
|
||||||
|
qmqp-source.o: ../../include/vstring.h
|
||||||
|
qmqp-source.o: ../../include/get_hostname.h
|
||||||
|
qmqp-source.o: ../../include/split_at.h
|
||||||
|
qmqp-source.o: ../../include/connect.h
|
||||||
|
qmqp-source.o: ../../include/iostuff.h
|
||||||
|
qmqp-source.o: ../../include/mymalloc.h
|
||||||
|
qmqp-source.o: ../../include/events.h
|
||||||
|
qmqp-source.o: ../../include/find_inet.h
|
||||||
|
qmqp-source.o: ../../include/netstring.h
|
||||||
|
qmqp-source.o: ../../include/mail_date.h
|
||||||
|
qmqp-source.o: ../../include/qmqp_proto.h
|
||||||
smtp-sink.o: smtp-sink.c
|
smtp-sink.o: smtp-sink.c
|
||||||
smtp-sink.o: ../../include/sys_defs.h
|
smtp-sink.o: ../../include/sys_defs.h
|
||||||
smtp-sink.o: ../../include/msg.h
|
smtp-sink.o: ../../include/msg.h
|
||||||
|
287
postfix/src/smtpstone/qmqp-sink.c
Normal file
287
postfix/src/smtpstone/qmqp-sink.c
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* qmqp-sink 8
|
||||||
|
/* SUMMARY
|
||||||
|
/* multi-threaded QMQP test server
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* .fi
|
||||||
|
/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR]
|
||||||
|
/* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR
|
||||||
|
/*
|
||||||
|
/* \fBqmqp-sink\fR [\fB-cv\fR]
|
||||||
|
/* \fBunix:\fR\fIpathname\fR \fIbacklog\fR
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* \fIqmqp-sink\fR listens on the named host (or address) and port.
|
||||||
|
/* It receives messages from the network and throws them away.
|
||||||
|
/* The purpose is to measure QMQP client performance, not protocol
|
||||||
|
/* compliance.
|
||||||
|
/* Connections can be accepted on IPV4 endpoints or UNIX-domain sockets.
|
||||||
|
/* IPV4 is the default.
|
||||||
|
/* This program is the complement of the \fIqmqp-source\fR program.
|
||||||
|
/* .IP \fB-c\fR
|
||||||
|
/* Display a running counter that is updated whenever a delivery
|
||||||
|
/* is completed.
|
||||||
|
/* .IP \fB-v\fR
|
||||||
|
/* Increase verbosity. Specify \fB-v -v\fR to see some of the QMQP
|
||||||
|
/* conversation.
|
||||||
|
/* .IP "\fB-x \fItime\fR
|
||||||
|
/* Terminate after \fItime\fR seconds. This is to facilitate memory
|
||||||
|
/* leak testing.
|
||||||
|
/* SEE ALSO
|
||||||
|
/* qmqp-source, QMQP test message generator
|
||||||
|
/* 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 <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#ifdef STRCASECMP_IN_STRINGS_H
|
||||||
|
#include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Utility library. */
|
||||||
|
|
||||||
|
#include <msg.h>
|
||||||
|
#include <vstring.h>
|
||||||
|
#include <vstream.h>
|
||||||
|
#include <listen.h>
|
||||||
|
#include <events.h>
|
||||||
|
#include <mymalloc.h>
|
||||||
|
#include <iostuff.h>
|
||||||
|
#include <msg_vstream.h>
|
||||||
|
#include <netstring.h>
|
||||||
|
|
||||||
|
/* Global library. */
|
||||||
|
|
||||||
|
#include <qmqp_proto.h>
|
||||||
|
|
||||||
|
/* Application-specific. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VSTREAM *stream; /* client connection */
|
||||||
|
int count; /* bytes to go */
|
||||||
|
} SINK_STATE;
|
||||||
|
|
||||||
|
static int var_tmout;
|
||||||
|
static VSTRING *buffer;
|
||||||
|
static void disconnect(SINK_STATE *);
|
||||||
|
static int count;
|
||||||
|
static int counter;
|
||||||
|
|
||||||
|
/* send_reply - finish conversation */
|
||||||
|
|
||||||
|
static void send_reply(SINK_STATE *state)
|
||||||
|
{
|
||||||
|
vstring_sprintf(buffer, "%cOk", QMQP_STAT_OK);
|
||||||
|
NETSTRING_PUT_BUF(state->stream, buffer);
|
||||||
|
netstring_fflush(state->stream);
|
||||||
|
if (count) {
|
||||||
|
counter++;
|
||||||
|
vstream_printf("%d\r", counter);
|
||||||
|
vstream_fflush(VSTREAM_OUT);
|
||||||
|
}
|
||||||
|
disconnect(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read_data - read over-all netstring data */
|
||||||
|
|
||||||
|
static void read_data(int unused_event, char *context)
|
||||||
|
{
|
||||||
|
SINK_STATE *state = (SINK_STATE *) context;
|
||||||
|
int fd = vstream_fileno(state->stream);
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Refill the VSTREAM buffer, if necessary.
|
||||||
|
*/
|
||||||
|
if (VSTREAM_GETC(state->stream) == VSTREAM_EOF)
|
||||||
|
netstring_except(state->stream, vstream_ftimeout(state->stream) ?
|
||||||
|
NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
|
||||||
|
state->count--;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flush the VSTREAM buffer. As documented, vstream_fseek() discards
|
||||||
|
* unread input.
|
||||||
|
*/
|
||||||
|
if ((count = vstream_peek(state->stream)) > 0) {
|
||||||
|
state->count -= count;
|
||||||
|
if (state->count <= 0) {
|
||||||
|
send_reply(state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vstream_fseek(state->stream, 0L, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not block while waiting for the arrival of more data.
|
||||||
|
*/
|
||||||
|
event_disable_readwrite(fd);
|
||||||
|
event_enable_read(fd, read_data, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read_length - read over-all netstring length */
|
||||||
|
|
||||||
|
static void read_length(int event, char *context)
|
||||||
|
{
|
||||||
|
SINK_STATE *state = (SINK_STATE *) context;
|
||||||
|
|
||||||
|
switch (vstream_setjmp(state->stream)) {
|
||||||
|
|
||||||
|
default:
|
||||||
|
msg_panic("unknown error reading input");
|
||||||
|
|
||||||
|
case NETSTRING_ERR_TIME:
|
||||||
|
msg_panic("attempt to read non-readable socket");
|
||||||
|
/* NOTREACHED */
|
||||||
|
|
||||||
|
case NETSTRING_ERR_EOF:
|
||||||
|
msg_warn("lost connection");
|
||||||
|
disconnect(state);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case NETSTRING_ERR_FORMAT:
|
||||||
|
msg_warn("netstring format error");
|
||||||
|
disconnect(state);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case NETSTRING_ERR_SIZE:
|
||||||
|
msg_warn("netstring size error");
|
||||||
|
disconnect(state);
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Include the netstring terminator in the read byte count. This
|
||||||
|
* violates abstractions.
|
||||||
|
*/
|
||||||
|
case 0:
|
||||||
|
state->count = netstring_get_length(state->stream) + 1;
|
||||||
|
read_data(event, context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disconnect - handle disconnection events */
|
||||||
|
|
||||||
|
static void disconnect(SINK_STATE *state)
|
||||||
|
{
|
||||||
|
event_disable_readwrite(vstream_fileno(state->stream));
|
||||||
|
vstream_fclose(state->stream);
|
||||||
|
myfree((char *) state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* connect_event - handle connection events */
|
||||||
|
|
||||||
|
static void connect_event(int unused_event, char *context)
|
||||||
|
{
|
||||||
|
int sock = CAST_CHAR_PTR_TO_INT(context);
|
||||||
|
struct sockaddr sa;
|
||||||
|
SOCKADDR_SIZE len = sizeof(sa);
|
||||||
|
SINK_STATE *state;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if ((fd = accept(sock, &sa, &len)) >= 0) {
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("connect (%s)",
|
||||||
|
#ifdef AF_LOCAL
|
||||||
|
sa.sa_family == AF_LOCAL ? "AF_LOCAL" :
|
||||||
|
#else
|
||||||
|
sa.sa_family == AF_UNIX ? "AF_UNIX" :
|
||||||
|
#endif
|
||||||
|
sa.sa_family == AF_INET ? "AF_INET" :
|
||||||
|
#ifdef AF_INET6
|
||||||
|
sa.sa_family == AF_INET6 ? "AF_INET6" :
|
||||||
|
#endif
|
||||||
|
"unknown protocol family");
|
||||||
|
non_blocking(fd, NON_BLOCKING);
|
||||||
|
state = (SINK_STATE *) mymalloc(sizeof(*state));
|
||||||
|
state->stream = vstream_fdopen(fd, O_RDWR);
|
||||||
|
netstring_setup(state->stream, var_tmout);
|
||||||
|
event_enable_read(fd, read_length, (char *) state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* terminate - voluntary exit */
|
||||||
|
|
||||||
|
static void terminate(int unused_event, char *unused_context)
|
||||||
|
{
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* usage - explain */
|
||||||
|
|
||||||
|
static void usage(char *myname)
|
||||||
|
{
|
||||||
|
msg_fatal("usage: %s [-cv] [-x time] [host]:port backlog", myname);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
int backlog;
|
||||||
|
int ch;
|
||||||
|
int ttl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize diagnostics.
|
||||||
|
*/
|
||||||
|
msg_vstream_init(argv[0], VSTREAM_ERR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse JCL.
|
||||||
|
*/
|
||||||
|
while ((ch = GETOPT(argc, argv, "cvx:")) > 0) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'c':
|
||||||
|
count++;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
msg_verbose++;
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
if ((ttl = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
event_request_timer(terminate, (char *) 0, ttl);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argc - optind != 2)
|
||||||
|
usage(argv[0]);
|
||||||
|
if ((backlog = atoi(argv[optind + 1])) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize.
|
||||||
|
*/
|
||||||
|
buffer = vstring_alloc(1024);
|
||||||
|
if (strncmp(argv[optind], "unix:", 5) == 0) {
|
||||||
|
sock = unix_listen(argv[optind] + 5, backlog, BLOCKING);
|
||||||
|
} else {
|
||||||
|
if (strncmp(argv[optind], "inet:", 5) == 0)
|
||||||
|
argv[optind] += 5;
|
||||||
|
sock = inet_listen(argv[optind], backlog, BLOCKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the event handler.
|
||||||
|
*/
|
||||||
|
event_enable_read(sock, connect_event, CAST_INT_TO_CHAR_PTR(sock));
|
||||||
|
for (;;)
|
||||||
|
event_loop(-1);
|
||||||
|
}
|
592
postfix/src/smtpstone/qmqp-source.c
Normal file
592
postfix/src/smtpstone/qmqp-source.c
Normal file
@@ -0,0 +1,592 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* qmqp-source 8
|
||||||
|
/* SUMMARY
|
||||||
|
/* multi-threaded QMQP test generator
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* .fi
|
||||||
|
/* \fBqmqp-source\fR [\fIoptions\fR] [\fBinet:\fR]\fIhost\fR[:\fIport\fR]
|
||||||
|
/*
|
||||||
|
/* \fBqmqp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* qmqp-source connects to the named host and TCP port (default 628)
|
||||||
|
/* and sends one or more messages to it, either sequentially
|
||||||
|
/* or in parallel. The program speaks the QMQP protocol.
|
||||||
|
/* Connections can be made to UNIX-domain and IPV4 servers.
|
||||||
|
/* IPV4 is the default.
|
||||||
|
/*
|
||||||
|
/* Options:
|
||||||
|
/* .IP -c
|
||||||
|
/* Display a running counter that is incremented each time
|
||||||
|
/* a delivery completes.
|
||||||
|
/* .IP "-C count"
|
||||||
|
/* When a host sends RESET instead of SYN|ACK, try \fIcount\fR times
|
||||||
|
/* before giving up. The default count is 1. Specify a larger count in
|
||||||
|
/* order to work around a problem with TCP/IP stacks that send RESET
|
||||||
|
/* when the listen queue is full.
|
||||||
|
/* .IP "-f from"
|
||||||
|
/* Use the specified sender address (default: <foo@myhostname>).
|
||||||
|
/* .IP "-l length"
|
||||||
|
/* Send \fIlength\fR bytes as message payload. The length
|
||||||
|
/* includes the message headers.
|
||||||
|
/* .IP "-m message_count"
|
||||||
|
/* Send the specified number of messages (default: 1).
|
||||||
|
/* .IP "-r recipient_count"
|
||||||
|
/* Send the specified number of recipients per transaction (default: 1).
|
||||||
|
/* Recipient names are generated by prepending a number to the
|
||||||
|
/* recipient address.
|
||||||
|
/* .IP "-s session_count"
|
||||||
|
/* Run the specified number of QMQP sessions in parallel (default: 1).
|
||||||
|
/* .IP "-t to"
|
||||||
|
/* Use the specified recipient address (default: <foo@myhostname>).
|
||||||
|
/* .IP "-R interval"
|
||||||
|
/* Wait for a random period of time 0 <= n <= interval between messages.
|
||||||
|
/* Suspending one thread does not affect other delivery threads.
|
||||||
|
/* .IP "-w interval"
|
||||||
|
/* Wait a fixed time between messages.
|
||||||
|
/* Suspending one thread does not affect other delivery threads.
|
||||||
|
/* 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 <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Utility library. */
|
||||||
|
|
||||||
|
#include <msg.h>
|
||||||
|
#include <msg_vstream.h>
|
||||||
|
#include <vstring.h>
|
||||||
|
#include <vstream.h>
|
||||||
|
#include <get_hostname.h>
|
||||||
|
#include <split_at.h>
|
||||||
|
#include <connect.h>
|
||||||
|
#include <mymalloc.h>
|
||||||
|
#include <events.h>
|
||||||
|
#include <find_inet.h>
|
||||||
|
#include <iostuff.h>
|
||||||
|
#include <netstring.h>
|
||||||
|
|
||||||
|
/* Global library. */
|
||||||
|
|
||||||
|
#include <mail_date.h>
|
||||||
|
#include <qmqp_proto.h>
|
||||||
|
|
||||||
|
/* Application-specific. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Per-session data structure with state.
|
||||||
|
*
|
||||||
|
* This software can maintain multiple parallel connections to the same QMQP
|
||||||
|
* server. However, it makes no more than one connection request at a time
|
||||||
|
* to avoid overwhelming the server with SYN packets and having to back off.
|
||||||
|
* Back-off would screw up the benchmark. Pending connection requests are
|
||||||
|
* kept in a linear list.
|
||||||
|
*/
|
||||||
|
typedef struct SESSION {
|
||||||
|
int xfer_count; /* # of xfers in session */
|
||||||
|
int rcpt_done; /* # of recipients done */
|
||||||
|
int rcpt_count; /* # of recipients to go */
|
||||||
|
VSTREAM *stream; /* open connection */
|
||||||
|
int connect_count; /* # of connect()s to retry */
|
||||||
|
struct SESSION *next; /* connect() queue linkage */
|
||||||
|
} SESSION;
|
||||||
|
|
||||||
|
static SESSION *last_session; /* connect() queue tail */
|
||||||
|
|
||||||
|
static VSTRING *buffer;
|
||||||
|
static int var_line_limit = 10240;
|
||||||
|
static int var_timeout = 300;
|
||||||
|
static const char *var_myhostname;
|
||||||
|
static int session_count;
|
||||||
|
static int message_count = 1;
|
||||||
|
static struct sockaddr_in sin;
|
||||||
|
|
||||||
|
#undef sun
|
||||||
|
static struct sockaddr_un sun;
|
||||||
|
static struct sockaddr *sa;
|
||||||
|
static int sa_length;
|
||||||
|
static int recipients = 1;
|
||||||
|
static char *defaddr;
|
||||||
|
static char *recipient;
|
||||||
|
static char *sender;
|
||||||
|
static int message_length = 1024;
|
||||||
|
static int count = 0;
|
||||||
|
static int counter = 0;
|
||||||
|
static int connect_count = 1;
|
||||||
|
static int random_delay = 0;
|
||||||
|
static int fixed_delay = 0;
|
||||||
|
static const char *mydate;
|
||||||
|
static int mypid;
|
||||||
|
|
||||||
|
static void enqueue_connect(SESSION *);
|
||||||
|
static void start_connect(SESSION *);
|
||||||
|
static void connect_done(int, char *);
|
||||||
|
|
||||||
|
static void send_data(SESSION *);
|
||||||
|
static void receive_reply(int, char *);
|
||||||
|
|
||||||
|
static VSTRING *message_buffer;
|
||||||
|
static VSTRING *sender_buffer;
|
||||||
|
static VSTRING *recipient_buffer;
|
||||||
|
|
||||||
|
/* Silly little macros. */
|
||||||
|
|
||||||
|
#define STR(x) vstring_str(x)
|
||||||
|
#define LEN(x) VSTRING_LEN(x)
|
||||||
|
|
||||||
|
/* random_interval - generate a random value in 0 .. (small) interval */
|
||||||
|
|
||||||
|
static int random_interval(int interval)
|
||||||
|
{
|
||||||
|
return (rand() % (interval + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* socket_error - look up and reset the last socket error */
|
||||||
|
|
||||||
|
static int socket_error(int sock)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
SOCKOPT_SIZE error_len;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some Solaris 2 versions have getsockopt() itself return the error,
|
||||||
|
* instead of returning it via the parameter list.
|
||||||
|
*/
|
||||||
|
error = 0;
|
||||||
|
error_len = sizeof(error);
|
||||||
|
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &error, &error_len) < 0)
|
||||||
|
return (-1);
|
||||||
|
if (error) {
|
||||||
|
errno = error;
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No problems.
|
||||||
|
*/
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exception_text - translate exceptions from the netstring module */
|
||||||
|
|
||||||
|
static char *exception_text(int except)
|
||||||
|
{
|
||||||
|
;
|
||||||
|
|
||||||
|
switch (except) {
|
||||||
|
case NETSTRING_ERR_EOF:
|
||||||
|
return ("lost connection");
|
||||||
|
case NETSTRING_ERR_TIME:
|
||||||
|
return ("timeout");
|
||||||
|
case NETSTRING_ERR_FORMAT:
|
||||||
|
return ("netstring format error");
|
||||||
|
case NETSTRING_ERR_SIZE:
|
||||||
|
return ("netstring size exceeds limit");
|
||||||
|
default:
|
||||||
|
msg_panic("exception_text: unknown exception %d", except);
|
||||||
|
}
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* startup - connect to server but do not wait */
|
||||||
|
|
||||||
|
static void startup(SESSION *session)
|
||||||
|
{
|
||||||
|
if (message_count-- <= 0) {
|
||||||
|
myfree((char *) session);
|
||||||
|
session_count--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
enqueue_connect(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start_event - invoke startup from timer context */
|
||||||
|
|
||||||
|
static void start_event(int unused_event, char *context)
|
||||||
|
{
|
||||||
|
SESSION *session = (SESSION *) context;
|
||||||
|
|
||||||
|
startup(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start_another - start another session */
|
||||||
|
|
||||||
|
static void start_another(SESSION *session)
|
||||||
|
{
|
||||||
|
if (random_delay > 0) {
|
||||||
|
event_request_timer(start_event, (char *) session,
|
||||||
|
random_interval(random_delay));
|
||||||
|
} else if (fixed_delay > 0) {
|
||||||
|
event_request_timer(start_event, (char *) session, fixed_delay);
|
||||||
|
} else {
|
||||||
|
startup(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enqueue_connect - queue a connection request */
|
||||||
|
|
||||||
|
static void enqueue_connect(SESSION *session)
|
||||||
|
{
|
||||||
|
session->next = 0;
|
||||||
|
if (last_session == 0) {
|
||||||
|
last_session = session;
|
||||||
|
start_connect(session);
|
||||||
|
} else {
|
||||||
|
last_session->next = session;
|
||||||
|
last_session = session;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dequeue_connect - connection request completed */
|
||||||
|
|
||||||
|
static void dequeue_connect(SESSION *session)
|
||||||
|
{
|
||||||
|
if (session == last_session) {
|
||||||
|
if (session->next != 0)
|
||||||
|
msg_panic("dequeue_connect: queue ends after last");
|
||||||
|
last_session = 0;
|
||||||
|
} else {
|
||||||
|
if (session->next == 0)
|
||||||
|
msg_panic("dequeue_connect: queue ends before last");
|
||||||
|
start_connect(session->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fail_connect - handle failed startup */
|
||||||
|
|
||||||
|
static void fail_connect(SESSION *session)
|
||||||
|
{
|
||||||
|
if (session->connect_count-- == 1)
|
||||||
|
msg_fatal("connect: %m");
|
||||||
|
msg_warn("connect: %m");
|
||||||
|
event_disable_readwrite(vstream_fileno(session->stream));
|
||||||
|
vstream_fclose(session->stream);
|
||||||
|
session->stream = 0;
|
||||||
|
#ifdef MISSING_USLEEP
|
||||||
|
doze(10);
|
||||||
|
#else
|
||||||
|
usleep(10);
|
||||||
|
#endif
|
||||||
|
start_connect(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start_connect - start TCP handshake */
|
||||||
|
|
||||||
|
static void start_connect(SESSION *session)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some systems don't set the socket error when connect() fails early
|
||||||
|
* (loopback) so we must deal with the error immediately, rather than
|
||||||
|
* retrieving it later with getsockopt(). We can't use MSG_PEEK to
|
||||||
|
* distinguish between server disconnect and connection refused.
|
||||||
|
*/
|
||||||
|
if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
|
||||||
|
msg_fatal("socket: %m");
|
||||||
|
(void) non_blocking(fd, NON_BLOCKING);
|
||||||
|
session->stream = vstream_fdopen(fd, O_RDWR);
|
||||||
|
event_enable_write(fd, connect_done, (char *) session);
|
||||||
|
netstring_setup(session->stream, var_timeout);
|
||||||
|
if (connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS)
|
||||||
|
fail_connect(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* connect_done - send message sender info */
|
||||||
|
|
||||||
|
static void connect_done(int unused_event, char *context)
|
||||||
|
{
|
||||||
|
SESSION *session = (SESSION *) context;
|
||||||
|
int fd = vstream_fileno(session->stream);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try again after some delay when the connection failed, in case they
|
||||||
|
* run a Mickey Mouse protocol stack.
|
||||||
|
*/
|
||||||
|
if (socket_error(fd) < 0) {
|
||||||
|
fail_connect(session);
|
||||||
|
} else {
|
||||||
|
dequeue_connect(session);
|
||||||
|
non_blocking(fd, BLOCKING);
|
||||||
|
event_disable_readwrite(fd);
|
||||||
|
send_data(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send_data - send message+sender+recipients */
|
||||||
|
|
||||||
|
static void send_data(SESSION *session)
|
||||||
|
{
|
||||||
|
int fd = vstream_fileno(session->stream);
|
||||||
|
int except;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare for disaster.
|
||||||
|
*/
|
||||||
|
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||||
|
msg_fatal("%s while sending message", exception_text(except));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send the message content, by wrapping three netstrings into an
|
||||||
|
* over-all netstring.
|
||||||
|
*
|
||||||
|
* XXX This should be done more carefully to avoid blocking when sending
|
||||||
|
* large messages over slow networks.
|
||||||
|
*/
|
||||||
|
netstring_put_multi(session->stream,
|
||||||
|
STR(message_buffer), LEN(message_buffer),
|
||||||
|
STR(sender_buffer), LEN(sender_buffer),
|
||||||
|
STR(recipient_buffer), LEN(recipient_buffer),
|
||||||
|
0);
|
||||||
|
netstring_fflush(session->stream);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wake me up when the server replies or when something bad happens.
|
||||||
|
*/
|
||||||
|
event_enable_read(fd, receive_reply, (char *) session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receive_reply - read server reply */
|
||||||
|
|
||||||
|
static void receive_reply(int unused_event, char *context)
|
||||||
|
{
|
||||||
|
SESSION *session = (SESSION *) context;
|
||||||
|
int except;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare for disaster.
|
||||||
|
*/
|
||||||
|
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||||
|
msg_fatal("%s while receiving server reply", exception_text(except));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Receive and process the server reply.
|
||||||
|
*/
|
||||||
|
netstring_get(session->stream, buffer, var_line_limit);
|
||||||
|
if (msg_verbose)
|
||||||
|
vstream_printf("<< %.*s\n", LEN(buffer), STR(buffer));
|
||||||
|
if (STR(buffer)[0] != QMQP_STAT_OK)
|
||||||
|
msg_fatal("%s error: %.*s",
|
||||||
|
STR(buffer)[0] == QMQP_STAT_RETRY ? "recoverable" :
|
||||||
|
STR(buffer)[0] == QMQP_STAT_HARD ? "unrecoverable" :
|
||||||
|
"unknown", LEN(buffer) - 1, STR(buffer) + 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update the optional running counter.
|
||||||
|
*/
|
||||||
|
if (count) {
|
||||||
|
counter++;
|
||||||
|
vstream_printf("%d\r", counter);
|
||||||
|
vstream_fflush(VSTREAM_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finish this session. QMQP sends only one message per session.
|
||||||
|
*/
|
||||||
|
event_disable_readwrite(vstream_fileno(session->stream));
|
||||||
|
vstream_fclose(session->stream);
|
||||||
|
session->stream = 0;
|
||||||
|
start_another(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* usage - explain */
|
||||||
|
|
||||||
|
static void usage(char *myname)
|
||||||
|
{
|
||||||
|
msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -f from -t to -R delay -v -w delay host[:port]", myname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* main - parse JCL and start the machine */
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
SESSION *session;
|
||||||
|
char *host;
|
||||||
|
char *port;
|
||||||
|
char *path;
|
||||||
|
int path_len;
|
||||||
|
int sessions = 1;
|
||||||
|
int ch;
|
||||||
|
int n;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
msg_vstream_init(argv[0], VSTREAM_ERR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse JCL.
|
||||||
|
*/
|
||||||
|
while ((ch = GETOPT(argc, argv, "cC:f:l:m:r:R:s:t:vw:")) > 0) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'c':
|
||||||
|
count++;
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if ((connect_count = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
sender = optarg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
if ((message_length = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
if ((message_count = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
if ((recipients = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
if (fixed_delay > 0 || (random_delay = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if ((sessions = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
recipient = optarg;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
msg_verbose++;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (random_delay > 0 || (fixed_delay = atoi(optarg)) <= 0)
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argc - optind != 1)
|
||||||
|
usage(argv[0]);
|
||||||
|
|
||||||
|
if (random_delay > 0)
|
||||||
|
srand(getpid());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate endpoint address to internal form.
|
||||||
|
*/
|
||||||
|
if (strncmp(argv[optind], "unix:", 5) == 0) {
|
||||||
|
path = argv[optind] + 5;
|
||||||
|
path_len = strlen(path);
|
||||||
|
if (path_len >= (int) sizeof(sun.sun_path))
|
||||||
|
msg_fatal("unix-domain name too long: %s", path);
|
||||||
|
memset((char *) &sun, 0, sizeof(sun));
|
||||||
|
sun.sun_family = AF_UNIX;
|
||||||
|
#ifdef HAS_SUN_LEN
|
||||||
|
sun.sun_len = path_len + 1;
|
||||||
|
#endif
|
||||||
|
memcpy(sun.sun_path, path, path_len);
|
||||||
|
sa = (struct sockaddr *) & sun;
|
||||||
|
sa_length = sizeof(sun);
|
||||||
|
} else {
|
||||||
|
if (strncmp(argv[optind], "inet:", 5) == 0)
|
||||||
|
argv[optind] += 5;
|
||||||
|
if ((port = split_at(host = argv[optind], ':')) == 0 || *port == 0)
|
||||||
|
port = "628";
|
||||||
|
memset((char *) &sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
sin.sin_addr.s_addr = find_inet_addr(host);
|
||||||
|
sin.sin_port = find_inet_port(port, "tcp");
|
||||||
|
sa = (struct sockaddr *) & sin;
|
||||||
|
sa_length = sizeof(sin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate space for temporary buffer.
|
||||||
|
*/
|
||||||
|
buffer = vstring_alloc(100);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure we have sender and recipient addresses.
|
||||||
|
*/
|
||||||
|
var_myhostname = get_hostname();
|
||||||
|
if (sender == 0 || recipient == 0) {
|
||||||
|
vstring_sprintf(buffer, "foo@%s", var_myhostname);
|
||||||
|
defaddr = mystrdup(vstring_str(buffer));
|
||||||
|
if (sender == 0)
|
||||||
|
sender = defaddr;
|
||||||
|
if (recipient == 0)
|
||||||
|
recipient = defaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare some results that may be used multiple times: the message
|
||||||
|
* content netstring, the sender netstring, and the recipient netstrings.
|
||||||
|
*/
|
||||||
|
mydate = mail_date(time((time_t *) 0));
|
||||||
|
mypid = getpid();
|
||||||
|
|
||||||
|
message_buffer = vstring_alloc(message_length + 200);
|
||||||
|
vstring_sprintf(buffer,
|
||||||
|
"From: <%s>\nTo: <%s>\nDate: %s\nMessage-Id: <%d@%s>\n\n",
|
||||||
|
sender, recipient, mydate, mypid, var_myhostname);
|
||||||
|
for (n = 1; LEN(buffer) < message_length; n++) {
|
||||||
|
for (i = 0; i < n && i < 79; i++)
|
||||||
|
VSTRING_ADDCH(buffer, 'X');
|
||||||
|
VSTRING_ADDCH(buffer, '\n');
|
||||||
|
}
|
||||||
|
netstring_memcpy(message_buffer, STR(buffer), message_length);
|
||||||
|
|
||||||
|
n = strlen(sender);
|
||||||
|
sender_buffer = vstring_alloc(n);
|
||||||
|
netstring_memcpy(sender_buffer, sender, n);
|
||||||
|
|
||||||
|
if (recipients == 1) {
|
||||||
|
n = strlen(recipient);
|
||||||
|
recipient_buffer = vstring_alloc(n);
|
||||||
|
netstring_memcpy(recipient_buffer, recipient, n);
|
||||||
|
} else {
|
||||||
|
recipient_buffer = vstring_alloc(100);
|
||||||
|
for (n = 0; n < recipients; n++) {
|
||||||
|
vstring_sprintf(buffer, "%d%s", n, recipient);
|
||||||
|
netstring_memcat(recipient_buffer, STR(buffer), LEN(buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start sessions.
|
||||||
|
*/
|
||||||
|
while (sessions-- > 0) {
|
||||||
|
session = (SESSION *) mymalloc(sizeof(*session));
|
||||||
|
session->stream = 0;
|
||||||
|
session->xfer_count = 0;
|
||||||
|
session->connect_count = connect_count;
|
||||||
|
session->next = 0;
|
||||||
|
session_count++;
|
||||||
|
startup(session);
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
event_loop(-1);
|
||||||
|
if (session_count <= 0 && message_count <= 0) {
|
||||||
|
if (count) {
|
||||||
|
VSTREAM_PUTC('\n', VSTREAM_OUT);
|
||||||
|
vstream_fflush(VSTREAM_OUT);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -9,8 +9,8 @@
|
|||||||
/*
|
/*
|
||||||
/* \fBsmtp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR
|
/* \fBsmtp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* smtp-source connects to the named host and port (default 25)
|
/* smtp-source connects to the named host and TCP port (default port 25)
|
||||||
/* and sends one or more little messages to it, either sequentially
|
/* and sends one or more messages to it, either sequentially
|
||||||
/* or in parallel. The program speaks either SMTP (default) or
|
/* or in parallel. The program speaks either SMTP (default) or
|
||||||
/* LMTP. Connections can be made to UNIX-domain and IPV4 servers.
|
/* LMTP. Connections can be made to UNIX-domain and IPV4 servers.
|
||||||
/* IPV4 is the default.
|
/* IPV4 is the default.
|
||||||
@@ -32,7 +32,8 @@
|
|||||||
/* .IP -o
|
/* .IP -o
|
||||||
/* Old mode: don't send HELO, and don't send message headers.
|
/* Old mode: don't send HELO, and don't send message headers.
|
||||||
/* .IP "-l length"
|
/* .IP "-l length"
|
||||||
/* Send \fIlength\fR bytes as message payload.
|
/* Send \fIlength\fR bytes as message payload. The length does not
|
||||||
|
/* include message headers.
|
||||||
/* .IP -L
|
/* .IP -L
|
||||||
/* Speak LMTP rather than SMTP.
|
/* Speak LMTP rather than SMTP.
|
||||||
/* .IP "-m message_count"
|
/* .IP "-m message_count"
|
||||||
@@ -40,7 +41,7 @@
|
|||||||
/* .IP "-r recipient_count"
|
/* .IP "-r recipient_count"
|
||||||
/* Send the specified number of recipients per transaction (default: 1).
|
/* Send the specified number of recipients per transaction (default: 1).
|
||||||
/* Recipient names are generated by prepending a number to the
|
/* Recipient names are generated by prepending a number to the
|
||||||
/* recipient address. The default is one recipient per transaction.
|
/* recipient address.
|
||||||
/* .IP "-s session_count"
|
/* .IP "-s session_count"
|
||||||
/* Run the specified number of SMTP sessions in parallel (default: 1).
|
/* Run the specified number of SMTP sessions in parallel (default: 1).
|
||||||
/* .IP "-t to"
|
/* .IP "-t to"
|
||||||
@@ -781,7 +782,7 @@ int main(int argc, char **argv)
|
|||||||
message_data = mymalloc(message_length);
|
message_data = mymalloc(message_length);
|
||||||
memset(message_data, 'X', message_length);
|
memset(message_data, 'X', message_length);
|
||||||
for (i = 80; i < message_length; i += 80) {
|
for (i = 80; i < message_length; i += 80) {
|
||||||
message_data[i - 80] = "0123456789"[(i/80) % 10];
|
message_data[i - 80] = "0123456789"[(i / 80) % 10];
|
||||||
message_data[i - 2] = '\r';
|
message_data[i - 2] = '\r';
|
||||||
message_data[i - 1] = '\n';
|
message_data[i - 1] = '\n';
|
||||||
}
|
}
|
||||||
@@ -848,7 +849,7 @@ int main(int argc, char **argv)
|
|||||||
} else {
|
} else {
|
||||||
if (strncmp(argv[optind], "inet:", 5) == 0)
|
if (strncmp(argv[optind], "inet:", 5) == 0)
|
||||||
argv[optind] += 5;
|
argv[optind] += 5;
|
||||||
if ((port = split_at(host = argv[optind], ':')) == 0)
|
if ((port = split_at(host = argv[optind], ':')) == 0 || *port == 0)
|
||||||
port = "smtp";
|
port = "smtp";
|
||||||
memset((char *) &sin, 0, sizeof(sin));
|
memset((char *) &sin, 0, sizeof(sin));
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
|
@@ -23,7 +23,7 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
|
|||||||
clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
|
clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
|
||||||
sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
|
sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
|
||||||
hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
|
hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
|
||||||
sane_socketpair.c myrand.c
|
sane_socketpair.c myrand.c netstring.c
|
||||||
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
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 \
|
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 \
|
dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
|
||||||
@@ -48,7 +48,7 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
|||||||
clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
|
clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
|
||||||
sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
|
sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
|
||||||
hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
|
hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
|
||||||
sane_socketpair.o myrand.o
|
sane_socketpair.o myrand.o netstring.o
|
||||||
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
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_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 \
|
dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
|
||||||
@@ -64,12 +64,12 @@ HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
|||||||
vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.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 spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
|
watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
|
||||||
sane_time.h sane_socketpair.h myrand.h
|
sane_time.h sane_socketpair.h myrand.h netstring.h
|
||||||
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
|
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
|
||||||
stream_test.c dup2_pass_on_exec.c
|
stream_test.c dup2_pass_on_exec.c
|
||||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||||
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||||
-Wunused
|
-Wunused
|
||||||
DEFS = -I. -D$(SYSTYPE)
|
DEFS = -I. -D$(SYSTYPE)
|
||||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||||
FILES = Makefile $(SRCS) $(HDRS)
|
FILES = Makefile $(SRCS) $(HDRS)
|
||||||
@@ -770,6 +770,13 @@ name_mask.o: stringops.h
|
|||||||
name_mask.o: vstring.h
|
name_mask.o: vstring.h
|
||||||
name_mask.o: vbuf.h
|
name_mask.o: vbuf.h
|
||||||
name_mask.o: name_mask.h
|
name_mask.o: name_mask.h
|
||||||
|
netstring.o: netstring.c
|
||||||
|
netstring.o: sys_defs.h
|
||||||
|
netstring.o: msg.h
|
||||||
|
netstring.o: vstream.h
|
||||||
|
netstring.o: vbuf.h
|
||||||
|
netstring.o: vstring.h
|
||||||
|
netstring.o: netstring.h
|
||||||
non_blocking.o: non_blocking.c
|
non_blocking.o: non_blocking.c
|
||||||
non_blocking.o: sys_defs.h
|
non_blocking.o: sys_defs.h
|
||||||
non_blocking.o: msg.h
|
non_blocking.o: msg.h
|
||||||
|
@@ -274,14 +274,14 @@ static MYSQL_RES *plmysql_query(PLMYSQL *PLDB,
|
|||||||
if (res == 0 && host->stat == STATACTIVE) {
|
if (res == 0 && host->stat == STATACTIVE) {
|
||||||
if (!(mysql_query(host->db, query))) {
|
if (!(mysql_query(host->db, query))) {
|
||||||
if ((res = mysql_store_result(host->db)) == 0) {
|
if ((res = mysql_store_result(host->db)) == 0) {
|
||||||
msg_warn("%s", mysql_error(host->db));
|
msg_warn("mysql query failed: %s", mysql_error(host->db));
|
||||||
plmysql_down_host(host);
|
plmysql_down_host(host);
|
||||||
} else {
|
} else {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("dict_mysql: successful query from host %s", host->hostname);
|
msg_info("dict_mysql: successful query from host %s", host->hostname);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
msg_warn("%s", mysql_error(host->db));
|
msg_warn("mysql query failed: %s", mysql_error(host->db));
|
||||||
plmysql_down_host(host);
|
plmysql_down_host(host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,7 +323,8 @@ static void plmysql_connect_single(HOST *host, char *dbname, char *username, cha
|
|||||||
host->hostname);
|
host->hostname);
|
||||||
host->stat = STATACTIVE;
|
host->stat = STATACTIVE;
|
||||||
} else {
|
} else {
|
||||||
msg_warn("%s", mysql_error(host->db));
|
msg_warn("connect to mysql server %s: %s",
|
||||||
|
host->hostname, mysql_error(host->db));
|
||||||
plmysql_down_host(host);
|
plmysql_down_host(host);
|
||||||
}
|
}
|
||||||
if (hostname)
|
if (hostname)
|
||||||
@@ -366,7 +367,7 @@ DICT *dict_mysql_open(const char *name, int unused_open_flags, int dict_flags)
|
|||||||
if (dict_mysql->pldb == NULL)
|
if (dict_mysql->pldb == NULL)
|
||||||
msg_fatal("couldn't intialize pldb!\n");
|
msg_fatal("couldn't intialize pldb!\n");
|
||||||
dict_register(name, (DICT *) dict_mysql);
|
dict_register(name, (DICT *) dict_mysql);
|
||||||
return (DICT_DEBUG(&dict_mysql->dict));
|
return (DICT_DEBUG (&dict_mysql->dict));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* mysqlname_parse - parse mysql configuration file */
|
/* mysqlname_parse - parse mysql configuration file */
|
||||||
|
@@ -173,10 +173,10 @@ char *mystrdup(const char *str)
|
|||||||
char *mystrndup(const char *str, int len)
|
char *mystrndup(const char *str, int len)
|
||||||
{
|
{
|
||||||
char *result;
|
char *result;
|
||||||
int slen;
|
char *cp;
|
||||||
|
|
||||||
if ((slen = strlen(str)) < len)
|
if ((cp = memchr(str, 0, len)) != 0)
|
||||||
len = slen;
|
len = cp - str;
|
||||||
result = memcpy(mymalloc(len + 1), str, len);
|
result = memcpy(mymalloc(len + 1), str, len);
|
||||||
result[len] = 0;
|
result[len] = 0;
|
||||||
return (result);
|
return (result);
|
||||||
|
350
postfix/src/util/netstring.c
Normal file
350
postfix/src/util/netstring.c
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* netstring 3
|
||||||
|
/* SUMMARY
|
||||||
|
/* netstring stream I/O support
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* #include <netstring.h>
|
||||||
|
/*
|
||||||
|
/* void netstring_setup(stream, timeout)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* int timeout;
|
||||||
|
/*
|
||||||
|
/* void netstring_except(stream, exception)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* int exception;
|
||||||
|
/*
|
||||||
|
/* VSTRING *netstring_get(stream, buf, limit)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* VSTRING *buf;
|
||||||
|
/* int limit;
|
||||||
|
/*
|
||||||
|
/* void netstring_put(stream, data, len)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* const char *data;
|
||||||
|
/* int len;
|
||||||
|
/*
|
||||||
|
/* void netstring_put_multi(stream, data, len, data, len, ..., 0)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* const char *data;
|
||||||
|
/* int len;
|
||||||
|
/*
|
||||||
|
/* void NETSTRING_PUT_BUF(stream, buf)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* VSTRING *buf;
|
||||||
|
/*
|
||||||
|
/* void netstring_fflush(stream)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/*
|
||||||
|
/* VSTRING *netstring_memcpy(buf, data, len)
|
||||||
|
/* VSTRING *buf;
|
||||||
|
/* const char *data;
|
||||||
|
/* int len;
|
||||||
|
/*
|
||||||
|
/* VSTRING *netstring_memcat(buf, data, len)
|
||||||
|
/* VSTRING *buf;
|
||||||
|
/* const char *src;
|
||||||
|
/* int len;
|
||||||
|
/* AUXILIARY ROUTINES
|
||||||
|
/* int netstring_get_length(stream)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/*
|
||||||
|
/* VSTRING *netstring_get_data(stream, buf, len)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* VSTRING *buf;
|
||||||
|
/* int len;
|
||||||
|
/*
|
||||||
|
/* void netstring_get_terminator(stream)
|
||||||
|
/* VSTREAM *stream;
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* This module reads and writes netstrings with error detection:
|
||||||
|
/* timeouts, unexpected end-of-file, or format errors. Netstring
|
||||||
|
/* is a data format designed by Daniel Bernstein.
|
||||||
|
/*
|
||||||
|
/* netstring_setup() arranges for a time limit on the netstring
|
||||||
|
/* read and write operations described below.
|
||||||
|
/* This routine alters the behavior of streams as follows:
|
||||||
|
/* .IP \(bu
|
||||||
|
/* The read/write timeout is set to the specified value.
|
||||||
|
/* .IP \(bu
|
||||||
|
/* The stream is configured to enable exception handling.
|
||||||
|
/* .PP
|
||||||
|
/* netstring_except() raises the specified exception on the
|
||||||
|
/* named stream. See the DIAGNOSTICS section below.
|
||||||
|
/*
|
||||||
|
/* netstring_get() reads a netstring from the specified stream
|
||||||
|
/* and extracts its content. The limit specifies a maximal size.
|
||||||
|
/* Specify zero to disable the size limit. The result is not null
|
||||||
|
/* terminated. The result value is the buf argument.
|
||||||
|
/*
|
||||||
|
/* netstring_put() encapsulates the specified string as a netstring
|
||||||
|
/* and sends the result to the specified stream.
|
||||||
|
/* The stream output buffer is not flushed.
|
||||||
|
/*
|
||||||
|
/* netstring_put_multi() encapsulates the content of multiple strings
|
||||||
|
/* as one netstring and sends the result to the specified stream. The
|
||||||
|
/* argument list must be terminated with a null data pointer.
|
||||||
|
/* The stream output buffer is not flushed.
|
||||||
|
/*
|
||||||
|
/* NETSTRING_PUT_BUF() is a macro that provides a VSTRING-based
|
||||||
|
/* wrapper for the netstring_put() routine.
|
||||||
|
/*
|
||||||
|
/* netstring_fflush() flushes the output buffer of the specified
|
||||||
|
/* stream and handles any errors.
|
||||||
|
/*
|
||||||
|
/* netstring_memcpy() encapsulates the specified data as a netstring
|
||||||
|
/* and copies the result over the specified buffer. The result
|
||||||
|
/* value is the buffer.
|
||||||
|
/*
|
||||||
|
/* netstring_memcat() encapsulates the specified data as a netstring
|
||||||
|
/* and appends the result to the specified buffer. The result
|
||||||
|
/* value is the buffer.
|
||||||
|
/*
|
||||||
|
/* The following routines provide low-level access to a netstring
|
||||||
|
/* stream.
|
||||||
|
/*
|
||||||
|
/* netstring_get_length() reads a length field from the specified
|
||||||
|
/* stream, and absorbs the netstring length field terminator.
|
||||||
|
/*
|
||||||
|
/* netstring_get_data() reads the specified number of bytes from the
|
||||||
|
/* specified stream into the specified buffer, and absorbs the
|
||||||
|
/* netstring terminator. The result value is the buf argument.
|
||||||
|
/*
|
||||||
|
/* netstring_get_terminator() reads the netstring terminator from
|
||||||
|
/* the specified stream.
|
||||||
|
/* DIAGNOSTICS
|
||||||
|
/* .fi
|
||||||
|
/* .ad
|
||||||
|
/* In case of error, a vstream_longjmp() call is performed to the
|
||||||
|
/* context specified with vstream_setjmp().
|
||||||
|
/* Error codes passed along with vstream_longjmp() are:
|
||||||
|
/* .IP NETSTRING_ERR_EOF
|
||||||
|
/* An I/O error happened, or the peer has disconnected unexpectedly.
|
||||||
|
/* .IP NETSTRING_ERR_TIME
|
||||||
|
/* The time limit specified to netstring_setup() was exceeded.
|
||||||
|
/* .IP NETSTRING_ERR_FORMAT
|
||||||
|
/* The input contains an unexpected character value.
|
||||||
|
/* .IP NETSTRING_ERR_SIZE
|
||||||
|
/* The input is larger than acceptable.
|
||||||
|
/* BUGS
|
||||||
|
/* The timeout deadline affects all I/O on the named stream, not
|
||||||
|
/* just the I/O done on behalf of this module.
|
||||||
|
/*
|
||||||
|
/* The timeout deadline overwrites any previously set up state on
|
||||||
|
/* the named stream.
|
||||||
|
/*
|
||||||
|
/* netstrings are not null terminated, which makes printing them
|
||||||
|
/* a bit awkward.
|
||||||
|
/* LICENSE
|
||||||
|
/* .ad
|
||||||
|
/* .fi
|
||||||
|
/* The Secure Mailer license must be distributed with this software.
|
||||||
|
/* SEE ALSO
|
||||||
|
/* http://cr.yp.to/proto/netstrings.txt, netstring definition
|
||||||
|
/* 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 <stdarg.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
/* Utility library. */
|
||||||
|
|
||||||
|
#include <msg.h>
|
||||||
|
#include <vstream.h>
|
||||||
|
#include <vstring.h>
|
||||||
|
#include <netstring.h>
|
||||||
|
|
||||||
|
/* Application-specific. */
|
||||||
|
|
||||||
|
#define STR(x) vstring_str(x)
|
||||||
|
#define LEN(x) VSTRING_LEN(x)
|
||||||
|
|
||||||
|
/* netstring_setup - initialize netstring stream */
|
||||||
|
|
||||||
|
void netstring_setup(VSTREAM *stream, int timeout)
|
||||||
|
{
|
||||||
|
vstream_control(stream,
|
||||||
|
VSTREAM_CTL_TIMEOUT, timeout,
|
||||||
|
VSTREAM_CTL_EXCEPT,
|
||||||
|
VSTREAM_CTL_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_except - process netstring stream exception */
|
||||||
|
|
||||||
|
void netstring_except(VSTREAM *stream, int exception)
|
||||||
|
{
|
||||||
|
vstream_longjmp(stream, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_get_length - read netstring length + terminator */
|
||||||
|
|
||||||
|
int netstring_get_length(VSTREAM *stream)
|
||||||
|
{
|
||||||
|
char *myname = "netstring_get_length";
|
||||||
|
int len = 0;
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
switch (ch = VSTREAM_GETC(stream)) {
|
||||||
|
case VSTREAM_EOF:
|
||||||
|
netstring_except(stream, vstream_ftimeout(stream) ?
|
||||||
|
NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
|
||||||
|
case ':':
|
||||||
|
if (msg_verbose > 1)
|
||||||
|
msg_info("%s: read netstring length %d", myname, len);
|
||||||
|
return (len);
|
||||||
|
default:
|
||||||
|
if (!ISDIGIT(ch))
|
||||||
|
netstring_except(stream, NETSTRING_ERR_FORMAT);
|
||||||
|
len = len * 10 + ch - '0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_get_data - read netstring payload + terminator */
|
||||||
|
|
||||||
|
VSTRING *netstring_get_data(VSTREAM *stream, VSTRING *buf, int len)
|
||||||
|
{
|
||||||
|
char *myname = "netstring_get_data";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate buffer space.
|
||||||
|
*/
|
||||||
|
VSTRING_RESET(buf);
|
||||||
|
VSTRING_SPACE(buf, len);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the payload and absorb the terminator.
|
||||||
|
*/
|
||||||
|
if (vstream_fread(stream, STR(buf), len) != len)
|
||||||
|
netstring_except(stream, vstream_ftimeout(stream) ?
|
||||||
|
NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
|
||||||
|
if (msg_verbose > 1)
|
||||||
|
msg_info("%s: read netstring data %.*s",
|
||||||
|
myname, len < 30 ? len : 30, STR(buf));
|
||||||
|
netstring_get_terminator(stream);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Position the buffer.
|
||||||
|
*/
|
||||||
|
VSTRING_AT_OFFSET(buf, len);
|
||||||
|
return (buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_get_terminator - absorb netstring terminator */
|
||||||
|
|
||||||
|
void netstring_get_terminator(VSTREAM *stream)
|
||||||
|
{
|
||||||
|
if (VSTREAM_GETC(stream) != ',')
|
||||||
|
netstring_except(stream, NETSTRING_ERR_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_get - read string from netstring stream */
|
||||||
|
|
||||||
|
VSTRING *netstring_get(VSTREAM *stream, VSTRING *buf, int limit)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = netstring_get_length(stream);
|
||||||
|
if (limit && len > limit)
|
||||||
|
netstring_except(stream, NETSTRING_ERR_SIZE);
|
||||||
|
netstring_get_data(stream, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_put - send string as netstring */
|
||||||
|
|
||||||
|
void netstring_put(VSTREAM *stream, const char *data, int len)
|
||||||
|
{
|
||||||
|
char *myname = "netstring_put";
|
||||||
|
|
||||||
|
if (msg_verbose > 1)
|
||||||
|
msg_info("%s: write netstring len %d data %.*s",
|
||||||
|
myname, len, len < 30 ? len : 30, data);
|
||||||
|
vstream_fprintf(stream, "%d:", len);
|
||||||
|
vstream_fwrite(stream, data, len);
|
||||||
|
VSTREAM_PUTC(',', stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_put_multi - send multiple strings as one netstring */
|
||||||
|
|
||||||
|
void netstring_put_multi(VSTREAM *stream,...)
|
||||||
|
{
|
||||||
|
char *myname = "netstring_put_multi";
|
||||||
|
int total;
|
||||||
|
char *data;
|
||||||
|
int data_len;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Figure out the total result size.
|
||||||
|
*/
|
||||||
|
va_start(ap, stream);
|
||||||
|
for (total = 0; (data = va_arg(ap, char *)) != 0; total += data_len)
|
||||||
|
if ((data_len = va_arg(ap, int)) < 0)
|
||||||
|
msg_panic("netstring_put_multi: bad data length %d", data_len);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debugging support.
|
||||||
|
*/
|
||||||
|
if (msg_verbose > 1) {
|
||||||
|
va_start(ap, stream);
|
||||||
|
data = va_arg(ap, char *);
|
||||||
|
data_len = va_arg(ap, int);
|
||||||
|
msg_info("%s: write netstring len %d data %.*s",
|
||||||
|
myname, total, data_len < 30 ? data_len : 30, data);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send the length, content and terminator.
|
||||||
|
*/
|
||||||
|
vstream_fprintf(stream, "%d:", total);
|
||||||
|
va_start(ap, stream);
|
||||||
|
while ((data = va_arg(ap, char *)) != 0) {
|
||||||
|
data_len = va_arg(ap, int);
|
||||||
|
if (data_len > 0)
|
||||||
|
if (vstream_fwrite(stream, data, data_len) != data_len)
|
||||||
|
netstring_except(stream, vstream_ftimeout(stream) ?
|
||||||
|
NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
vstream_fwrite(stream, ",", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_fflush - flush netstring stream */
|
||||||
|
|
||||||
|
void netstring_fflush(VSTREAM *stream)
|
||||||
|
{
|
||||||
|
if (vstream_fflush(stream) == VSTREAM_EOF)
|
||||||
|
netstring_except(stream, vstream_ftimeout(stream) ?
|
||||||
|
NETSTRING_ERR_TIME : NETSTRING_ERR_EOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_memcpy - copy data as in-memory netstring */
|
||||||
|
|
||||||
|
VSTRING *netstring_memcpy(VSTRING *buf, const char *src, int len)
|
||||||
|
{
|
||||||
|
vstring_sprintf(buf, "%d:", len);
|
||||||
|
vstring_memcat(buf, src, len);
|
||||||
|
VSTRING_ADDCH(buf, ',');
|
||||||
|
return (buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* netstring_memcat - append data as in-memory netstring */
|
||||||
|
|
||||||
|
VSTRING *netstring_memcat(VSTRING *buf, const char *src, int len)
|
||||||
|
{
|
||||||
|
vstring_sprintf_append(buf, "%d:", len);
|
||||||
|
vstring_memcat(buf, src, len);
|
||||||
|
VSTRING_ADDCH(buf, ',');
|
||||||
|
return (buf);
|
||||||
|
}
|
54
postfix/src/util/netstring.h
Normal file
54
postfix/src/util/netstring.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#ifndef _NETSTRING_H_INCLUDED_
|
||||||
|
#define _NETSTRING_H_INCLUDED_
|
||||||
|
|
||||||
|
/*++
|
||||||
|
/* NAME
|
||||||
|
/* netstring 3h
|
||||||
|
/* SUMMARY
|
||||||
|
/* netstring stream I/O support
|
||||||
|
/* SYNOPSIS
|
||||||
|
/* #include <netstring.h>
|
||||||
|
/* DESCRIPTION
|
||||||
|
/* .nf
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility library.
|
||||||
|
*/
|
||||||
|
#include <vstring.h>
|
||||||
|
#include <vstream.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* External interface.
|
||||||
|
*/
|
||||||
|
#define NETSTRING_ERR_EOF 1 /* unexpected disconnect */
|
||||||
|
#define NETSTRING_ERR_TIME 2 /* time out */
|
||||||
|
#define NETSTRING_ERR_FORMAT 3 /* format error */
|
||||||
|
#define NETSTRING_ERR_SIZE 4 /* netstring too large */
|
||||||
|
|
||||||
|
extern void netstring_except(VSTREAM *, int);
|
||||||
|
extern void netstring_setup(VSTREAM *, int);
|
||||||
|
extern int netstring_get_length(VSTREAM *);
|
||||||
|
extern VSTRING *netstring_get_data(VSTREAM *, VSTRING *, int);
|
||||||
|
extern void netstring_get_terminator(VSTREAM *);
|
||||||
|
extern VSTRING *netstring_get(VSTREAM *, VSTRING *, int);
|
||||||
|
extern void netstring_put(VSTREAM *, const char *, int);
|
||||||
|
extern void netstring_put_multi(VSTREAM *,...);
|
||||||
|
extern void netstring_fflush(VSTREAM *);
|
||||||
|
extern VSTRING *netstring_memcpy(VSTRING *, const char *, int);
|
||||||
|
extern VSTRING *netstring_memcat(VSTRING *, const char *, int);
|
||||||
|
|
||||||
|
#define NETSTRING_PUT_BUF(str, buf) \
|
||||||
|
netstring_put((str), vstring_str(buf), VSTRING_LEN(buf))
|
||||||
|
|
||||||
|
/* 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
|
@@ -175,11 +175,11 @@
|
|||||||
/*
|
/*
|
||||||
/* VSTREAM_PUTCHAR(c) is an alias for VSTREAM_PUTC(c, VSTREAM_OUT).
|
/* VSTREAM_PUTCHAR(c) is an alias for VSTREAM_PUTC(c, VSTREAM_OUT).
|
||||||
/*
|
/*
|
||||||
/* vstream_unget() pushes back a character onto the specified stream
|
/* vstream_ungetc() pushes back a character onto the specified stream
|
||||||
/* and returns the character, or VSTREAM_EOF in case of problems.
|
/* and returns the character, or VSTREAM_EOF in case of problems.
|
||||||
/* It is an error to push back before reading (or immediately after
|
/* It is an error to push back before reading (or immediately after
|
||||||
/* changing the stream offset via vstream_fseek()). Upon successful
|
/* changing the stream offset via vstream_fseek()). Upon successful
|
||||||
/* return, vstream_unget() clears the end-of-file stream flag.
|
/* return, vstream_ungetc() clears the end-of-file stream flag.
|
||||||
/*
|
/*
|
||||||
/* vstream_fputs() appends the given null-terminated string to the
|
/* vstream_fputs() appends the given null-terminated string to the
|
||||||
/* specified buffered stream. The result is 0 in case of success,
|
/* specified buffered stream. The result is 0 in case of success,
|
||||||
|
@@ -67,6 +67,16 @@
|
|||||||
/* const char *src;
|
/* const char *src;
|
||||||
/* int len;
|
/* int len;
|
||||||
/*
|
/*
|
||||||
|
/* VSTRING *vstring_memcpy(vp, src, len)
|
||||||
|
/* VSTRING *vp;
|
||||||
|
/* const char *src;
|
||||||
|
/* int len;
|
||||||
|
/*
|
||||||
|
/* VSTRING *vstring_memcat(vp, src, len)
|
||||||
|
/* VSTRING *vp;
|
||||||
|
/* const char *src;
|
||||||
|
/* int len;
|
||||||
|
/*
|
||||||
/* VSTRING *vstring_sprintf(vp, format, ...)
|
/* VSTRING *vstring_sprintf(vp, format, ...)
|
||||||
/* VSTRING *vp;
|
/* VSTRING *vp;
|
||||||
/* const char *format;
|
/* const char *format;
|
||||||
@@ -174,6 +184,14 @@
|
|||||||
/* vstring_strncat() copies at most \fIlen\fR characters. Otherwise it is
|
/* vstring_strncat() copies at most \fIlen\fR characters. Otherwise it is
|
||||||
/* identical to vstring_strcat().
|
/* identical to vstring_strcat().
|
||||||
/*
|
/*
|
||||||
|
/* vstring_memcpy() copies \fIlen\fR bytes to a variable-length string.
|
||||||
|
/* \fIsrc\fP provides the data to be copied; \fIvp\fP is the
|
||||||
|
/* target and result value. The result is not null-terminated.
|
||||||
|
/*
|
||||||
|
/* vstring_memcat() appends \fIlen\fR bytes to a variable-length string.
|
||||||
|
/* \fIsrc\fP provides the data to be copied; \fIvp\fP is the
|
||||||
|
/* target and result value. The result is not null-terminated.
|
||||||
|
/*
|
||||||
/* vstring_sprintf() produces a formatted string according to its
|
/* vstring_sprintf() produces a formatted string according to its
|
||||||
/* \fIformat\fR argument. See vstring_vsprintf() for details.
|
/* \fIformat\fR argument. See vstring_vsprintf() for details.
|
||||||
/*
|
/*
|
||||||
@@ -392,6 +410,29 @@ VSTRING *vstring_strncat(VSTRING *vp, const char *src, int len)
|
|||||||
return (vp);
|
return (vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* vstring_memcpy - copy buffer of limited length */
|
||||||
|
|
||||||
|
VSTRING *vstring_memcpy(VSTRING *vp, const char *src, int len)
|
||||||
|
{
|
||||||
|
VSTRING_RESET(vp);
|
||||||
|
|
||||||
|
VSTRING_SPACE(vp, len);
|
||||||
|
memcpy(vstring_str(vp), src, len);
|
||||||
|
VSTRING_AT_OFFSET(vp, len);
|
||||||
|
return (vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vstring_memcat - append buffer of limited length */
|
||||||
|
|
||||||
|
VSTRING *vstring_memcat(VSTRING *vp, const char *src, int len)
|
||||||
|
{
|
||||||
|
VSTRING_SPACE(vp, len);
|
||||||
|
memcpy(vstring_end(vp), src, len);
|
||||||
|
len += VSTRING_LEN(vp);
|
||||||
|
VSTRING_AT_OFFSET(vp, len);
|
||||||
|
return (vp);
|
||||||
|
}
|
||||||
|
|
||||||
/* vstring_export - VSTRING to bare string */
|
/* vstring_export - VSTRING to bare string */
|
||||||
|
|
||||||
char *vstring_export(VSTRING *vp)
|
char *vstring_export(VSTRING *vp)
|
||||||
|
@@ -38,6 +38,8 @@ extern VSTRING *vstring_strcpy(VSTRING *, const char *);
|
|||||||
extern VSTRING *vstring_strncpy(VSTRING *, const char *, int);
|
extern VSTRING *vstring_strncpy(VSTRING *, const char *, int);
|
||||||
extern VSTRING *vstring_strcat(VSTRING *, const char *);
|
extern VSTRING *vstring_strcat(VSTRING *, const char *);
|
||||||
extern VSTRING *vstring_strncat(VSTRING *, const char *, int);
|
extern VSTRING *vstring_strncat(VSTRING *, const char *, int);
|
||||||
|
extern VSTRING *vstring_memcpy(VSTRING *, const char *, int);
|
||||||
|
extern VSTRING *vstring_memcat(VSTRING *, const char *, int);
|
||||||
extern VSTRING *PRINTFLIKE(2, 3) vstring_sprintf(VSTRING *, const char *,...);
|
extern VSTRING *PRINTFLIKE(2, 3) vstring_sprintf(VSTRING *, const char *,...);
|
||||||
extern VSTRING *PRINTFLIKE(2, 3) vstring_sprintf_append(VSTRING *, const char *,...);
|
extern VSTRING *PRINTFLIKE(2, 3) vstring_sprintf_append(VSTRING *, const char *,...);
|
||||||
extern char *vstring_export(VSTRING *);
|
extern char *vstring_export(VSTRING *);
|
||||||
|
Reference in New Issue
Block a user