mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 05:38:06 +00:00
snapshot-20010707
This commit is contained in:
parent
14829b5994
commit
7e8044da83
3
postfix/.indent.pro
vendored
3
postfix/.indent.pro
vendored
@ -24,10 +24,10 @@
|
||||
-TDICT
|
||||
-TDICT_DB
|
||||
-TDICT_DBM
|
||||
-TDICT_DEBUG
|
||||
-TDICT_ENV
|
||||
-TDICT_HT
|
||||
-TDICT_LDAP
|
||||
-TDICT_DEBUG
|
||||
-TDICT_MYSQL
|
||||
-TDICT_NI
|
||||
-TDICT_NIS
|
||||
@ -93,6 +93,7 @@
|
||||
-TQMGR_RECIPIENT
|
||||
-TQMGR_SCAN
|
||||
-TQMGR_TRANSPORT
|
||||
-TQMQPD_STATE
|
||||
-TRECIPIENT
|
||||
-TRECIPIENT_LIST
|
||||
-TREC_TYPE_NAME
|
||||
|
@ -5261,3 +5261,51 @@ Apologies for any names omitted.
|
||||
|
||||
Feature: address quoting and case folding flags for the
|
||||
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/showq src/postalias src/postcat src/postconf src/postdrop \
|
||||
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
|
||||
|
||||
|
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
|
||||
===========================================
|
||||
|
||||
|
@ -69,6 +69,7 @@
|
||||
# (yes) (yes) (yes) (never) (50)
|
||||
# ==========================================================================
|
||||
smtp inet n - n - - smtpd
|
||||
#628 inet n - n - - qmqpd
|
||||
pickup fifo n n n 60 1 pickup
|
||||
cleanup unix - - n - 0 cleanup
|
||||
qmgr fifo n - n 300 1 qmgr
|
||||
|
@ -1,7 +1,7 @@
|
||||
*** postfix-script-nosgid Wed Mar 24 11:20:49 1999
|
||||
--- postfix-script-sgid Wed Mar 24 11:20:53 1999
|
||||
*** postfix-script-nosgid Thu May 24 17:13:59 2001
|
||||
--- postfix-script-sgid Fri Jun 29 10:28:19 2001
|
||||
***************
|
||||
*** 174,181 ****
|
||||
*** 177,184 ****
|
||||
test -d maildrop || {
|
||||
$WARN creating missing Postfix maildrop directory
|
||||
mkdir maildrop || exit 1
|
||||
@ -10,13 +10,13 @@
|
||||
}
|
||||
test -d pid || {
|
||||
$WARN creating missing Postfix pid directory
|
||||
--- 174,182 ----
|
||||
--- 177,185 ----
|
||||
test -d maildrop || {
|
||||
$WARN creating missing Postfix maildrop directory
|
||||
mkdir maildrop || exit 1
|
||||
! chmod 1730 maildrop
|
||||
chown $mail_owner maildrop
|
||||
+ chgrp maildrop maildrop
|
||||
+ (. $config_directory/install.cf; chgrp $setgid maildrop)
|
||||
}
|
||||
test -d pid || {
|
||||
$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
|
||||
chmod 1730 maildrop
|
||||
chown $mail_owner maildrop
|
||||
chgrp maildrop maildrop
|
||||
(. $config_directory/install.cf; chgrp $setgid maildrop)
|
||||
}
|
||||
test -d pid || {
|
||||
$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
|
||||
|
||||
# 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
|
||||
# an SMTP server greets us with a 4XX status code (go away, try
|
||||
# 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 \
|
||||
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 \
|
||||
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 \
|
||||
postconf.1.html postfix.1.html postkick.1.html postlock.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
|
||||
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
|
||||
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
|
||||
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>
|
||||
|
||||
<p>
|
||||
@ -1033,7 +1039,7 @@ Berkeley DB library version.
|
||||
|
||||
<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>
|
||||
|
||||
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>
|
||||
|
||||
To set kernel parameters at boot time, add the following lines to
|
||||
the <b>/boot/loader.conf</b> file (this is specific to FreeBSD 4.x):
|
||||
To set the following kernel parameters at boot time, add the
|
||||
following lines to the <b>/boot/loader.conf</b> file (this is
|
||||
specific to FreeBSD 4.x):
|
||||
|
||||
<p>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
kern.ipc.maxsockets="5000"
|
||||
kern.maxfiles="16384"
|
||||
kern.maxfilesperproc="16384"
|
||||
kern.ipc.nmbclusters="65536"
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>
|
||||
|
||||
To set kernel parameters at run time execute the following commands
|
||||
as root (this is specific to FreeBSD 4.x):
|
||||
These parameters cannot be set at run time (verified with FreeBSD
|
||||
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>
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
# sysctl -w kern.ipc.maxsockets=5000
|
||||
# sysctl -w kern.maxfiles=16384
|
||||
# sysctl -w kern.maxfilesperproc=16384
|
||||
# sysctl -w kern.ipc.nmbclusters=65536
|
||||
</pre>
|
||||
</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>
|
||||
|
||||
<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>
|
||||
|
||||
<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
|
||||
|
||||
</body>
|
||||
|
@ -108,7 +108,7 @@ LMTP(8) LMTP(8)
|
||||
found in <b>services</b>(4).
|
||||
|
||||
<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>
|
||||
(SASL). By default, Postfix is built without SASL
|
||||
support.
|
||||
|
@ -78,7 +78,7 @@ PIPE(8) PIPE(8)
|
||||
|
||||
The <b>q</b> flag affects only entire addresses,
|
||||
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.
|
||||
|
||||
<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>
|
||||
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>
|
||||
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 \
|
||||
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/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 \
|
||||
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.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
|
||||
../mantools/srctoman $? >$@
|
||||
|
||||
man8/qmqpd.8: ../src/qmqpd/qmqpd.c
|
||||
../mantools/srctoman $? >$@
|
||||
|
||||
man8/showq.8: ../src/showq/showq.c
|
||||
../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
|
||||
backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
||||
.SH "Authentication controls"
|
||||
.IP \fBlmtp_enable_sasl_auth\fR
|
||||
.IP \fBlmtp_sasl_auth_enable\fR
|
||||
Enable per-session authentication as per RFC 2554 (SASL).
|
||||
By default, Postfix is built without SASL support.
|
||||
.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.
|
||||
.sp
|
||||
The \fBq\fR flag affects only entire addresses, not the partial
|
||||
address information from the \fB$user\fR, \fBextension\fR or
|
||||
\fBmailbox\fR command-line macros.
|
||||
address information from the \fB$user\fR, \fB$extension\fR or
|
||||
\fB$mailbox\fR command-line macros.
|
||||
.IP \fBu\fR
|
||||
Fold the command-line \fB$recipient\fR address localpart (text to
|
||||
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.
|
||||
.IP \fBsmtp_never_send_ehlo\fR
|
||||
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
|
||||
Skip servers that greet us with a 4xx status code.
|
||||
.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>]*pipe[</bB>]*(8)/<a href="pipe.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>]*smtp[</bB>]*(8)/<a href="smtp.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 \
|
||||
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 \
|
||||
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
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||
|
@ -714,6 +714,10 @@ extern char *var_smtp_bind_addr;
|
||||
#define DEF_SMTP_RAND_ADDR 1
|
||||
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
|
||||
* 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"
|
||||
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
|
||||
/* .ad
|
||||
/* .fi
|
||||
|
@ -76,7 +76,7 @@
|
||||
/* mail_queue_rename() renames a queue file. A non-zero result
|
||||
/* 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.
|
||||
/*
|
||||
/* mail_queue_name_ok() validates a mail queue name and returns
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20010610"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20010707"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* 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
|
||||
/* backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
||||
/* .SH "Authentication controls"
|
||||
/* .IP \fBlmtp_enable_sasl_auth\fR
|
||||
/* .IP \fBlmtp_sasl_auth_enable\fR
|
||||
/* Enable per-session authentication as per RFC 2554 (SASL).
|
||||
/* By default, Postfix is built without SASL support.
|
||||
/* .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:
|
||||
if (!mail_from_rejected) {
|
||||
#ifndef notRFC821_SYNTAX
|
||||
#ifdef notdef
|
||||
if (resp->code == 552)
|
||||
resp->code = 452;
|
||||
#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);
|
||||
|
||||
/*
|
||||
* Deliver to mailbox or to external command.
|
||||
* Deliver to mailbox, maildir or to external command.
|
||||
*/
|
||||
#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);
|
||||
status = deliver_maildir(state, usr_attr, 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
|
||||
status = deliver_mailbox_file(state, usr_attr);
|
||||
|
||||
|
@ -70,8 +70,8 @@
|
||||
/* recipients by the Postfix \fBsendmail\fR mail submission command.
|
||||
/* .sp
|
||||
/* The \fBq\fR flag affects only entire addresses, not the partial
|
||||
/* address information from the \fB$user\fR, \fBextension\fR or
|
||||
/* \fBmailbox\fR command-line macros.
|
||||
/* address information from the \fB$user\fR, \fB$extension\fR or
|
||||
/* \fB$mailbox\fR command-line macros.
|
||||
/* .IP \fBu\fR
|
||||
/* Fold the command-line \fB$recipient\fR address localpart (text to
|
||||
/* 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.
|
||||
/* .IP \fBsmtp_never_send_ehlo\fR
|
||||
/* 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
|
||||
/* Skip servers that greet us with a 4xx status code.
|
||||
/* .IP \fBsmtp_skip_5xx_greeting\fR
|
||||
@ -250,6 +253,7 @@ char *var_smtp_sasl_passwd;
|
||||
bool var_smtp_sasl_enable;
|
||||
char *var_smtp_bind_addr;
|
||||
bool var_smtp_rand_addr;
|
||||
bool var_smtp_break_lines;
|
||||
|
||||
/*
|
||||
* 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_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -79,11 +79,33 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE 0xffffffff
|
||||
#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. */
|
||||
|
||||
#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) {
|
||||
memset((char *) &fixed, 0, sizeof(fixed));
|
||||
if ((hp = gethostbyname(host)) == 0) {
|
||||
vstring_sprintf(why, "%s: host not found", host);
|
||||
smtp_errno = SMTP_FAIL;
|
||||
vstring_sprintf(why, "%s: %s", host, HSTRERROR(h_errno));
|
||||
smtp_errno = (h_errno == TRY_AGAIN ? SMTP_RETRY : SMTP_FAIL);
|
||||
} else if (hp->h_addrtype != AF_INET) {
|
||||
vstring_sprintf(why, "%s: host not found", host);
|
||||
msg_warn("%s: unknown address family %d for %s",
|
||||
|
@ -394,7 +394,7 @@ SMTP_SESSION *smtp_connect(char *destination, VSTRING *why)
|
||||
char *save;
|
||||
char *dest;
|
||||
char *cp;
|
||||
int found_myself;
|
||||
int found_myself = 0;
|
||||
|
||||
/*
|
||||
* 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:
|
||||
if (!mail_from_rejected) {
|
||||
#ifndef notRFC821_SYNTAX
|
||||
#ifdef notdef
|
||||
if (resp->code == 552)
|
||||
resp->code = 452;
|
||||
#endif
|
||||
@ -642,6 +642,8 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
if (prev_type != REC_TYPE_CONT)
|
||||
if (vstring_str(state->scratch)[0] == '.')
|
||||
smtp_fputc('.', session->stream);
|
||||
if (var_smtp_break_lines)
|
||||
rec_type = REC_TYPE_NORM;
|
||||
if (rec_type == REC_TYPE_CONT)
|
||||
smtp_fwrite(vstring_str(state->scratch),
|
||||
VSTRING_LEN(state->scratch),
|
||||
|
@ -139,11 +139,11 @@ static int smtp_sasl_log(void *unused_context, int priority,
|
||||
switch (priority) {
|
||||
case SASL_LOG_ERR:
|
||||
case SASL_LOG_WARNING:
|
||||
msg_warn("%s", message);
|
||||
msg_warn("SASL authentication problem: %s", message);
|
||||
break;
|
||||
case SASL_LOG_INFO:
|
||||
if (msg_verbose)
|
||||
msg_info("%s", message);
|
||||
msg_info("SASL authentication info: %s", message);
|
||||
break;
|
||||
}
|
||||
return (SASL_OK);
|
||||
|
@ -339,6 +339,7 @@ bool var_disable_vrfy_cmd;
|
||||
char *var_canonical_maps;
|
||||
char *var_rcpt_canon_maps;
|
||||
char *var_virtual_maps;
|
||||
char *var_virt_mailbox_maps;
|
||||
char *var_relocated_maps;
|
||||
char *var_alias_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_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_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_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_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 *canonical_maps;
|
||||
static MAPS *virtual_maps;
|
||||
static MAPS *virt_mailbox_maps;
|
||||
static MAPS *relocated_maps;
|
||||
|
||||
/*
|
||||
@ -467,6 +468,8 @@ void smtpd_check_init(void)
|
||||
DICT_FLAG_LOCK);
|
||||
virtual_maps = maps_create(VAR_VIRTUAL_MAPS, var_virtual_maps,
|
||||
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,
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
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)
|
||||
|| (*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);
|
||||
|
||||
/*
|
||||
@ -1032,7 +1037,9 @@ static int permit_mx_backup(SMTPD_STATE *state, const char *recipient)
|
||||
domain += 1;
|
||||
if (resolve_local(domain)
|
||||
|| (*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);
|
||||
|
||||
if (msg_verbose)
|
||||
@ -1174,7 +1181,9 @@ static int reject_unknown_address(SMTPD_STATE *state, char *addr,
|
||||
domain += 1;
|
||||
if (resolve_local(domain)
|
||||
|| (*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);
|
||||
if (domain[0] == '#')
|
||||
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))
|
||||
&& 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))) {
|
||||
(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))) {
|
||||
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||
"%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))
|
||||
&& 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(local_rcpt_maps, STR(reply.recipient))) {
|
||||
(void) smtpd_check_reject(state, MAIL_ERROR_BOUNCE,
|
||||
@ -2175,6 +2202,7 @@ char *var_alias_maps;
|
||||
char *var_rcpt_canon_maps;
|
||||
char *var_canonical_maps;
|
||||
char *var_virtual_maps;
|
||||
char *var_virt_mailbox_maps;
|
||||
char *var_relocated_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_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_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_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps,
|
||||
0,
|
||||
@ -2503,6 +2532,13 @@ main(int argc, char **argv)
|
||||
resp = 0;
|
||||
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) {
|
||||
UPDATE_STRING(var_local_rcpt_maps, args->argv[1]);
|
||||
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 (errno == ECONNRESET || errno == ECONNABORTED) {
|
||||
msg_info("errno %d %m", errno);
|
||||
state->name = mystrdup("unknown");
|
||||
state->addr = mystrdup("unknown");
|
||||
state->peer_code = 5;
|
||||
|
@ -118,11 +118,11 @@ static int smtpd_sasl_log(void *unused_context, int priority,
|
||||
switch (priority) {
|
||||
case SASL_LOG_ERR:
|
||||
case SASL_LOG_WARNING:
|
||||
msg_warn("%s", message);
|
||||
msg_warn("SASL authentication problem: %s", message);
|
||||
break;
|
||||
case SASL_LOG_INFO:
|
||||
if (msg_verbose)
|
||||
msg_info("%s", message);
|
||||
msg_info("SASL authentication info: %s", message);
|
||||
break;
|
||||
}
|
||||
return SASL_OK;
|
||||
|
@ -1,6 +1,6 @@
|
||||
SHELL = /bin/sh
|
||||
SRCS = smtp-source.c smtp-sink.c
|
||||
OBJS = smtp-source.o smtp-sink.o
|
||||
SRCS = smtp-source.c smtp-sink.c qmqp-source.c qmqp-sink.c
|
||||
OBJS = smtp-source.o smtp-sink.o qmqp-source.o qmqp-sink.o
|
||||
HDRS =
|
||||
TESTSRC =
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
@ -10,7 +10,7 @@ DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||
TESTPROG=
|
||||
INC_DIR = ../../include
|
||||
PROG = smtp-source smtp-sink
|
||||
PROG = smtp-source smtp-sink qmqp-source qmqp-sink
|
||||
LIBS = ../../lib/libglobal.a ../../lib/libutil.a
|
||||
|
||||
.c.o:; $(CC) $(CFLAGS) -c $*.c
|
||||
@ -26,9 +26,15 @@ smtp-sink: smtp-sink.o $(LIBS)
|
||||
smtp-source: smtp-source.o $(LIBS)
|
||||
$(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)
|
||||
|
||||
update: ../../bin/smtp-source ../../bin/smtp-sink
|
||||
update: ../../bin/smtp-source ../../bin/smtp-sink ../../bin/qmqp-source
|
||||
|
||||
../../bin/smtp-source: smtp-source
|
||||
cp $? $@
|
||||
@ -36,6 +42,12 @@ update: ../../bin/smtp-source ../../bin/smtp-sink
|
||||
../../bin/smtp-sink: smtp-sink
|
||||
cp $? $@
|
||||
|
||||
../../bin/qmqp-source: qmqp-source
|
||||
cp $? $@
|
||||
|
||||
../../bin/qmqp-sink: qmqp-sink
|
||||
cp $? $@
|
||||
|
||||
printfck: $(OBJS) $(PROG)
|
||||
rm -rf printfck
|
||||
mkdir printfck
|
||||
@ -61,6 +73,36 @@ depend: $(MAKES)
|
||||
@$(EXPORT) make -f Makefile.in Makefile 1>&2
|
||||
|
||||
# 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: ../../include/sys_defs.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
|
||||
/* DESCRIPTION
|
||||
/* smtp-source connects to the named host and port (default 25)
|
||||
/* and sends one or more little messages to it, either sequentially
|
||||
/* smtp-source connects to the named host and TCP port (default port 25)
|
||||
/* and sends one or more messages to it, either sequentially
|
||||
/* or in parallel. The program speaks either SMTP (default) or
|
||||
/* LMTP. Connections can be made to UNIX-domain and IPV4 servers.
|
||||
/* IPV4 is the default.
|
||||
@ -32,7 +32,8 @@
|
||||
/* .IP -o
|
||||
/* Old mode: don't send HELO, and don't send message headers.
|
||||
/* .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
|
||||
/* Speak LMTP rather than SMTP.
|
||||
/* .IP "-m message_count"
|
||||
@ -40,7 +41,7 @@
|
||||
/* .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. The default is one recipient per transaction.
|
||||
/* recipient address.
|
||||
/* .IP "-s session_count"
|
||||
/* Run the specified number of SMTP sessions in parallel (default: 1).
|
||||
/* .IP "-t to"
|
||||
@ -781,7 +782,7 @@ int main(int argc, char **argv)
|
||||
message_data = mymalloc(message_length);
|
||||
memset(message_data, 'X', message_length);
|
||||
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 - 1] = '\n';
|
||||
}
|
||||
@ -848,7 +849,7 @@ int main(int argc, char **argv)
|
||||
} else {
|
||||
if (strncmp(argv[optind], "inet:", 5) == 0)
|
||||
argv[optind] += 5;
|
||||
if ((port = split_at(host = argv[optind], ':')) == 0)
|
||||
if ((port = split_at(host = argv[optind], ':')) == 0 || *port == 0)
|
||||
port = "smtp";
|
||||
memset((char *) &sin, 0, sizeof(sin));
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
@ -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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
@ -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 \
|
||||
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 \
|
||||
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 \
|
||||
stream_test.c dup2_pass_on_exec.c
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||
-Wunused
|
||||
-Wunused
|
||||
DEFS = -I. -D$(SYSTYPE)
|
||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||
FILES = Makefile $(SRCS) $(HDRS)
|
||||
@ -770,6 +770,13 @@ name_mask.o: stringops.h
|
||||
name_mask.o: vstring.h
|
||||
name_mask.o: vbuf.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: sys_defs.h
|
||||
non_blocking.o: msg.h
|
||||
|
@ -274,14 +274,14 @@ static MYSQL_RES *plmysql_query(PLMYSQL *PLDB,
|
||||
if (res == 0 && host->stat == STATACTIVE) {
|
||||
if (!(mysql_query(host->db, query))) {
|
||||
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);
|
||||
} else {
|
||||
if (msg_verbose)
|
||||
msg_info("dict_mysql: successful query from host %s", host->hostname);
|
||||
}
|
||||
} else {
|
||||
msg_warn("%s", mysql_error(host->db));
|
||||
msg_warn("mysql query failed: %s", mysql_error(host->db));
|
||||
plmysql_down_host(host);
|
||||
}
|
||||
}
|
||||
@ -323,7 +323,8 @@ static void plmysql_connect_single(HOST *host, char *dbname, char *username, cha
|
||||
host->hostname);
|
||||
host->stat = STATACTIVE;
|
||||
} 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);
|
||||
}
|
||||
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)
|
||||
msg_fatal("couldn't intialize pldb!\n");
|
||||
dict_register(name, (DICT *) dict_mysql);
|
||||
return (DICT_DEBUG(&dict_mysql->dict));
|
||||
return (DICT_DEBUG (&dict_mysql->dict));
|
||||
}
|
||||
|
||||
/* mysqlname_parse - parse mysql configuration file */
|
||||
|
@ -173,10 +173,10 @@ char *mystrdup(const char *str)
|
||||
char *mystrndup(const char *str, int len)
|
||||
{
|
||||
char *result;
|
||||
int slen;
|
||||
char *cp;
|
||||
|
||||
if ((slen = strlen(str)) < len)
|
||||
len = slen;
|
||||
if ((cp = memchr(str, 0, len)) != 0)
|
||||
len = cp - str;
|
||||
result = memcpy(mymalloc(len + 1), str, len);
|
||||
result[len] = 0;
|
||||
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_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.
|
||||
/* It is an error to push back before reading (or immediately after
|
||||
/* 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
|
||||
/* specified buffered stream. The result is 0 in case of success,
|
||||
|
@ -67,6 +67,16 @@
|
||||
/* const char *src;
|
||||
/* 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 *vp;
|
||||
/* const char *format;
|
||||
@ -174,6 +184,14 @@
|
||||
/* vstring_strncat() copies at most \fIlen\fR characters. Otherwise it is
|
||||
/* 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
|
||||
/* \fIformat\fR argument. See vstring_vsprintf() for details.
|
||||
/*
|
||||
@ -392,6 +410,29 @@ VSTRING *vstring_strncat(VSTRING *vp, const char *src, int len)
|
||||
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 */
|
||||
|
||||
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_strcat(VSTRING *, const char *);
|
||||
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_append(VSTRING *, const char *,...);
|
||||
extern char *vstring_export(VSTRING *);
|
||||
|
Loading…
x
Reference in New Issue
Block a user