Bugfix: missing terminator in new attribute-based function
call caused signal 11. File: src/cleanup/cleanup.c.
+ Lame workaround for ESTALE errors with mail delivery over
+ NFS. Additional bandages were added to the local delivery
+ agent. However, Wietse maintains that Postfix offers no
+ guarantee for reliable delivery over NFS.
+
+ Feature: put "warn_if_reject" before an smtpd restriction,
+ and that restriction logs warnings without rejecting mail.
+ This makes it easier to test configurations "live" without
+ having to lose mail. File: smtpd/smtpd_check.c.
+
+20011107
+
+ Workaround: in order to get mail past PIX firewall bugs,
+ the Postfix SMTP client now blocks until the socket send
+ buffer is empty before sending the final ".<CR><LF>". Files:
+ util/sock_empty_wait.c, smtp/smtp_proto.c. Changed into
+ sleep(10) on 20011119. Sleep suggested by Hobbit.
+
+20011108
+
+ Feature: added string-null encoding for internal protocols.
+ Files: util/attr_print0.c, util/attr_scan0.c.
+
+ Feature: configurable parent domain matching for domain
+ and hostname/address match lists: either .domain or the
+ domain name itself. Files: util/match_ops.c util/match_list.c
+
+ Feature: added pretend-to-be-behind-PIX mode to the smtp-sink
+ test program, in order to stress test some PIX bug workaround
+ code.
+
+20011109
+
+ Workaround: Linux and Solaris systems have no reasonable
+ way to block until a socket drains. On these systems Postfix
+ simply waits for 10 seconds, in order to work around PIX
+ ".<CR><LF>" bugs. File: util/sock_empty_wait.c.
+
20011114
Bugfix: reset the smtpd command transaction log between
20011115
+ Feature: mailbox_command_maps no longer requires that every
+ user has an entry. If the user does not have a command
+ entry, the local delivery agent tries the other delivery
+ methods (mailbox_command, home_mailbox). File: local/mailbox.c.
+
Bugfix: reset the smtpd command transaction log between
non-deliveries. File: smtpd/smtpd.c.
20011116
- Bugfix: consolidated all the command transaction log
- resets and eliminated one other case (Victor Duchovny,
- Morgan Stanley). File: smtpd/smtpd.c.
+ Bugfix: consolidated all the command transaction log resets
+ and eliminated one missing reset (Victor Duchovny, Morgan
+ Stanley). File: smtpd/smtpd.c.
+
+20011118
+
+ Cleanup: replaced unnecessary match_list wrapper code by
+ macros. Files: global/{string,domain,namadr}_list.[hc].
+
+20011119
+
+ Feature: configurable parent domain matching strategy for
+ transport map lookups. File: trivial-rewrite/transport.c.
+
+ New parent_domain_matches_subdomains parameter. This lists
+ all the Postfix features where a domain name matches itself
+ and all its subdomains (instead of requiring ".domain.name"
+ for subdomain matches). Planning for future backwards
+ compatibility :-) File: global/match_parent_style.c.
+
+ Workaround: simplified the PIX ".<CR><LF>" bug to always
+ sleep for 10 seconds. File: smtp/smtp_proto.c.
20011120
Workaround: disable attribute string length restriction so
that trivial-rewrite does not refuse to rewrite broken mail
- headers. File: util/attr_scan.c.
+ headers. Files: util/attr_scan*.c.
+
+20011121
+
+ Bugfix: missing long integer support in the new IPC protocols.
+ Files: util/attr_scan*.c, util/attr_print*.c.
Open problems:
Medium: smtpd access maps don't understand the recipient
delimiter setting.
+ Low: default domain for appending to unqualified recipients.
+
Low: The $process_id_directory setting is not used anywhere
in Postfix. Problem reported by Michael Smith, texas.net.
This should be documented, or better, the code should warn
- Run the INSTALL.sh script as the super-user:
- # make install (interactive version, first time install)
- # make install </dev/null (non-interactive version, for upgrades)
+ # make install (interactive version, first time install)
+ # make upgrade (non-interactive version, for upgrades)
The non-interactive version needs the /etc/postfix/install.cf
file from a previous installation. If the file does not exist,
install: update
sh INSTALL.sh
+upgrade: update
+ sh INSTALL.sh </dev/null
+
depend clean:
set -e; for i in $(DIRS); do \
(set -e; echo "[$$i]"; cd $$i; $(MAKE) $@) || exit 1; \
-Snapshot 20011103 introduces a negligible amount of features and
-is all about revision of Postfix internals. With more than 70 pages
-of context diffs compared to the previous snapshot, this release
-is a baseline for upcoming feature changes.
+Incompatible changes with snapshot-20011121
+===========================================
+
+The internal protocols have changed again, so you must "postfix
+reload" if upgrading from a previous release. The change is from
+base64 encoded strings to null-terminated strings (Postfix now
+supports multiple encodings).
+
+Major changes with snapshot-20011121
+====================================
+
+Configurable host/domain name wildcard matching behavior: choice
+between "pattern `domain.name' matches string `host.domain.name'"
+(to be deprecated in the future) and "pattern `.domain.name' matches
+string `host.domain.name'" (to be preferred in the future). The
+configuration parameter "parent_domain_matches_subdomains" specifies
+which Postfix features use the behavior that will become deprecated.
+
+New "warn_if_reject" smtpd pseudo restriction that only warns if
+the restriction that follows would reject mail. Look for file
+records that contain the string "reject_warning".
+
+Disgusting workaround for a well-known CISCO PIX firewall bug that
+causes the .<CR>LF> at the end of mail to be lost. The workaround
+has no effect for other mail deliveries.
+
+mailbox_command_maps allows you to configure the external delivery
+command per user (local delivery agent only). This feature has
+precedence over mailbox_command and home_mailbox settings.
Major changes with snapshot-20011103
====================================
# Specify "mynetworks_style = host" when Postfix should "trust"
# only the local machine.
#
-# mynetworks_style = class
-# mynetworks_style = subnet
-# mynetworks_style = host
+#mynetworks_style = class
+#mynetworks_style = subnet
+#mynetworks_style = host
# Alternatively, you can specify the mynetworks list by hand, in
# which case Postfix ignores the mynetworks_style setting.
#
# If you're connected via UUCP, see also the default_transport parameter.
#
-# relayhost = $mydomain
-# relayhost = gateway.my.domain
-# relayhost = uucphost
-# relayhost = [an.ip.add.ress]
+#relayhost = $mydomain
+#relayhost = gateway.my.domain
+#relayhost = uucphost
+#relayhost = [an.ip.add.ress]
# REJECTING UNKNOWN LOCAL USERS
#
# Basically, the software tries user+foo and .forward+foo before
# trying user and .forward.
#
-# recipient_delimiter = +
+#recipient_delimiter = +
# DELIVERY TO MAILBOX
#
# UNIX-style mailboxes are kept. The default setting depends on the
# system type.
#
-# mail_spool_directory = /var/mail
-# mail_spool_directory = /var/spool/mail
+#mail_spool_directory = /var/mail
+#mail_spool_directory = /var/spool/mail
# The mailbox_command parameter specifies the optional external
# command to use instead of mailbox delivery. The command is run as
#
# luser_relay works only for the default Postfix local delivery agent.
#
-# luser_relay = $user@other.host
-# luser_relay = $local@other.host
-# luser_relay = admin+$local
+#luser_relay = $user@other.host
+#luser_relay = $local@other.host
+#luser_relay = admin+$local
# JUNK MAIL CONTROLS
#
# increase the verbose logging level by the amount specified in the
# debug_peer_level parameter.
#
-# debug_peer_list = 127.0.0.1
-# debug_peer_list = some.domain
+#debug_peer_list = 127.0.0.1
+#debug_peer_list = some.domain
# The debugger_command specifies the external command that is executed
# when a Postfix daemon program is run with the -D option.
# specify multiple tables, not necessarily all under control by
# Postfix.
#
-# alias_database = dbm:/etc/aliases
-# alias_database = dbm:/etc/mail/aliases
+#alias_database = dbm:/etc/aliases
+#alias_database = dbm:/etc/mail/aliases
alias_database = hash:/etc/aliases
# The alias_maps parameter specifies the list of alias databases used
# It will take a minute or so before changes become visible. Use
# "postfix reload" to eliminate the delay.
#
-# alias_maps = dbm:/etc/aliases, nis:mail.aliases
-# alias_maps = hash:/etc/aliases
+#alias_maps = dbm:/etc/aliases, nis:mail.aliases
+#alias_maps = hash:/etc/aliases
alias_maps = hash:/etc/aliases
# By default, the local authentication realm name is the name of the
# machine.
#
-# smtpd_sasl_local_domain = $mydomain
+#smtpd_sasl_local_domain = $mydomain
smtpd_sasl_local_domain = $myhostname
# SMTP CLIENT CONTROLS
# will become visible after a minute or so. Use "postfix reload"
# to eliminate the delay.
#
-# canonical_maps = dbm:/etc/postfix/canonical
-# canonical_maps = hash:/etc/postfix/canonical
-# canonical_maps = hash:/etc/postfix/canonical, nis:canonical
-# canonical_maps = hash:/etc/postfix/canonical, netinfo:/canonical
+#canonical_maps = dbm:/etc/postfix/canonical
+#canonical_maps = hash:/etc/postfix/canonical
+#canonical_maps = hash:/etc/postfix/canonical, nis:canonical
+#canonical_maps = hash:/etc/postfix/canonical, netinfo:/canonical
canonical_maps =
# The recipient_canonical_maps parameter specifies optional address
#
# $recipient_canonical_maps is used before $canonical_maps lookups.
#
-# recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
+#recipient_canonical_maps = hash:/etc/postfix/recipient_canonical
recipient_canonical_maps =
# The sender_canonical_maps parameter specifies optional address
#
# $sender_canonical_maps is used before $canonical_maps lookups.
#
-# sender_canonical_maps = hash:/etc/postfix/sender_canonical
+#sender_canonical_maps = hash:/etc/postfix/sender_canonical
sender_canonical_maps =
# increase the verbose logging level by the amount specified in the
# debug_peer_level parameter.
#
-# debug_peer_list = 127.0.0.1
-# debug_peer_list = some.domain
+#debug_peer_list = 127.0.0.1
+#debug_peer_list = some.domain
debug_peer_list =
# The debugger_command specifies the external command that is executed
# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
# The default time unit is s (seconds).
#
-# lmtp_connect_timeout = 30s
+#lmtp_connect_timeout = 30s
lmtp_connect_timeout = 0s
# The lmtp_lhlo_timeout parameter specifies the LMTP client timeout
#
# See the sample-aliases.cf file for parameters that are specific to
# alias database lookup.
+#
+# Mailbox delivery is controlled by a series of parameters. The
+# precedence, from highest to lowest priority: mailbox_transport,
+# mailbox_command_maps, mailbox_command, home_mailbox.
# The biff parameter specifies whether or not to contact the biff
# server. This server sends "new mail" notifications to users who
# with lots of interactive users, this "protocol" can be a real
# performance pig. Specify "biff = no" to disable.
#
-# biff = no
+#biff = no
biff = yes
# The require_home_directory parameter controls whether a local
# external commands. The default is to disallow delivery to "|command"
# in :include: files.
#
-# allow_mail_to_commands = alias,forward,include
+#allow_mail_to_commands = alias,forward,include
allow_mail_to_commands = alias,forward
# The allow_mail_to_files parameter restricts mail delivery to external
# file. The default is to disallow delivery to /file/name in :include:
# files.
#
-# allow_mail_to_files = alias,forward,include
+#allow_mail_to_files = alias,forward,include
allow_mail_to_files = alias,forward
# The default_privs parameter specifies the default rights used by
# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
# "Maildir/" for qmail-style delivery (the / is required).
#
-# home_mailbox = Mailbox
-# home_mailbox = Maildir/
+#home_mailbox = Mailbox
+#home_mailbox = Maildir/
home_mailbox =
# The luser_relay parameter specifies an optional destination address
#
# luser_relay works only for the default Postfix local delivery agent.
#
-# luser_relay = $user@other.host
-# luser_relay = $local@other.host
-# luser_relay = admin+$local
+#luser_relay = $user@other.host
+#luser_relay = $local@other.host
+#luser_relay = admin+$local
# The mail_spool_directory parameter specifies the directory where
# UNIX-style mailboxes are kept. The default setting depends on the
# system type.
#
-# mail_spool_directory = /var/mail
-# mail_spool_directory = /var/spool/mail
+#mail_spool_directory = /var/mail
+#mail_spool_directory = /var/spool/mail
# The mailbox_command parameter specifies the optional external
# command to use instead of mailbox delivery. The command is run
# IF YOU USE THIS TO DELIVER MAIL SYSTEM-WIDE, YOU MUST SET UP AN
# ALIAS THAT FORWARDS MAIL FOR ROOT TO A REAL USER.
#
-# mailbox_command = /some/where/procmail
-# mailbox_command = /some/where/procmail -a "$EXTENSION"
+#mailbox_command = /some/where/procmail
+#mailbox_command = /some/where/procmail -a "$EXTENSION"
mailbox_command =
# The mailbox_command_maps allows you to specify a per-user mailbox
# command. The maps are keyed by username (not including the domain).
-# Specify one or more maps. If this feature is used then every user
-# must have a matching entry.
+# Specify one or more maps. If a user is not found in the maps then
+# lower precedence delivery mechanisms take effect. See the top of
+# this file for the precedences of mailbox delivery mechanisms.
#
-# mailbox_command_maps = hash:/etc/postfix/mailbox_commands
+#mailbox_command_maps = hash:/etc/postfix/mailbox_commands
# The mailbox_transport specifies the optional transport in master.cf
# to use after processing aliases and .forward files. This parameter
# :nexthop part is optional. For more details see the sample transport
# configuration file.
#
-# mailbox_transport = lmtp:unix:/file/name
-# mailbox_transport = cyrus
+#mailbox_transport = lmtp:unix:/file/name
+#mailbox_transport = cyrus
mailbox_transport =
# The fallback_transport specifies the optional transport in master.cf
# :nexthop part is optional. For more details see the sample transport
# configuration file.
#
-# fallback_transport = lmtp:unix:/file/name
-# fallback_transport = cyrus
+#fallback_transport = lmtp:unix:/file/name
+#fallback_transport = cyrus
fallback_transport =
#
# and command. Turning off the Delivered-To: header when forwarding
# mail is not recommended.
#
-# prepend_delivered_header = command, file, forward
-# prepend_delivered_header = forward
+#prepend_delivered_header = command, file, forward
+#prepend_delivered_header = forward
# systems the default type is either `dbm' or `hash'. The default is
# determined when the Postfix system is built.
#
-# default_database_type = hash
-# default_database_type = dbm
+#default_database_type = hash
+#default_database_type = dbm
# The default_transport parameter specifies the default message
# delivery transport to use when no transport is explicitly given in
# transport or nexthop are optional. For more details see the sample
# transports file.
#
-# default_transport = uucp:relayhostname
+#default_transport = uucp:relayhostname
default_transport = smtp
# The double_bounce_sender parameter specifies the sender address
#
# Specify a list of names separated by whitespace or comma.
#
-# import_environment = MAIL_CONFIG TZ XAUTHORITY DISPLAY HOME PURIFYOPTIONS
+#import_environment = MAIL_CONFIG TZ XAUTHORITY DISPLAY HOME PURIFYOPTIONS
import_environment = MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG TZ XAUTHORITY DISPLAY
# The inet_interfaces parameter specifies the network interface
# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
# The default time unit is s (seconds).
#
-#ipc_timeout = 3600s
+ipc_timeout = 3600s
# The mail_name parameter specifies the mail system name that is used
# in Received: headers, in the SMTP greeting banner, and in bounced
# a name matches a lookup key. Continue long lines by starting the
# next line with whitespace.
#
-# mydestination = $myhostname, localhost.$mydomain $mydomain
-# mydestination = $myhostname, localhost.$mydomain www.$mydomain, ftp.$mydomain
+#mydestination = $myhostname, localhost.$mydomain $mydomain
+#mydestination = $myhostname, localhost.$mydomain www.$mydomain, ftp.$mydomain
mydestination = $myhostname, localhost.$mydomain
# The mydomain parameter specifies the local internet domain name.
# a domain-wide alias database that aliases each user to
# user@that.users.mailhost.
#
-# myorigin = $mydomain
+#myorigin = $mydomain
myorigin = $myhostname
# The mynetworks parameter specifies the list of "trusted" SMTP
# Specify "mynetworks_style = host" when Postfix should "trust"
# only the local machine.
#
-# mynetworks_style = class
-# mynetworks_style = subnet
-# mynetworks_style = host
+#mynetworks_style = class
+#mynetworks_style = subnet
+#mynetworks_style = host
# Alternatively, you can specify the mynetworks list by hand, in
# which case Postfix ignores the mynetworks_style setting.
# policy (anti-UCE violations) and protocol error (broken mailers)
# reports.
#
-# notify_classes = bounce,delay,policy,protocol,resource,software
-# notify_classes = 2bounce,resource,software
+#notify_classes = bounce,delay,policy,protocol,resource,software
+#notify_classes = 2bounce,resource,software
notify_classes = resource,software
# The following parameters specify who gets postmaster notices if
delay_notice_recipient = postmaster
error_notice_recipient = postmaster
+# The parent_domain_matches_subdomains parameter specifies what
+# Postfix features use "domain.name matches sub.domain.name" style
+# pattern matching instead of requiring ".domain.name". This is
+# planned backwards compatibility: eventually, all Postfix features
+# are expected to require ".domain.name" style patterns.
+#
+parent_domain_matches_subdomains = debug_peer_list,fast_flush_domains,
+ mynetworks,permit_mx_backup_networks,qmqpd_authorized_clients,
+ relay_domains,smtpd_access_maps
+
# The process_id_directory specifies a lock file directory relative
# to the Postfix queue directory. This facility is used by the master
# daemon to lock out other master daemon instances.
# Basically, the software tries user+foo and .forward+foo before
# trying user and .forward.
#
-# recipient_delimiter = +
+#recipient_delimiter = +
recipient_delimiter =
# The propagate_unmatched_extensions parameter specifies what lookup
#
# If you're connected via UUCP, see also the default_transport parameter.
#
-# relayhost = $mydomain
-# relayhost = gateway.my.domain
-# relayhost = uucphost
-# relayhost = [an.ip.add.ress]
+#relayhost = $mydomain
+#relayhost = gateway.my.domain
+#relayhost = uucphost
+#relayhost = [an.ip.add.ress]
relayhost =
# The relocated_maps parameter specifies optional tables with contact
# Specify the types and names of databases to use. After change,
# run "postmap /etc/postfix/relocated", then "postfix reload".
#
-# relocated_maps = hash:/etc/postfix/relocated
+#relocated_maps = hash:/etc/postfix/relocated
relocated_maps =
# The syslog_facility parameter controls where Postfix logging is
# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
# The default time unit is h (hours).
#
-# delay_warning_time = 0h
+#delay_warning_time = 0h
# build the necessary DBM or DB file after change, then "postfix
# reload" to make the changes visible.
#
-# relocated_maps = dbm:/etc/postfix/relocated
-# relocated_maps = hash:/etc/postfix/relocated
-# relocated_maps = hash:/etc/postfix/relocated, nis:virtual
-# relocated_maps = hash:/etc/postfix/relocated, netinfo:/relocated
+#relocated_maps = dbm:/etc/postfix/relocated
+#relocated_maps = hash:/etc/postfix/relocated
+#relocated_maps = hash:/etc/postfix/relocated, nis:virtual
+#relocated_maps = hash:/etc/postfix/relocated, netinfo:/relocated
relocated_maps =
# The allow_percent_hack parameter controls the rewriting of the form
# "user%domain" to "user@domain". This is enabled by default.
#
-# allow_percent_hack = no
+#allow_percent_hack = no
allow_percent_hack = yes
# The append_at_myorigin controls the rewriting of the form "user" to
# The append_dot_mydomain controls the rewriting of the form
# "user@host" to "user@host.$mydomain". This is enabled by default.
#
-# append_dot_mydomain = no
+#append_dot_mydomain = no
append_dot_mydomain = yes
# The empty_address_recipient specifies the destination for mail from
#
# By default, address masquerading is disabled.
#
-# masquerade_domains = $mydomain
+#masquerade_domains = $mydomain
masquerade_domains =
# The masquerade_exceptions parameter gives an optional list of user
# "site!user" to "user@site". This is necessary if your machine is
# connected to UUCP networks. It is enabled by default.
#
-# swap_bangpath = no
+#swap_bangpath = no
swap_bangpath = yes
# Time units: s (seconds), m (minutes), h (hours), d (days), w (weeks).
# The default time unit is s (seconds).
#
-# smtp_connect_timeout = 30s
+#smtp_connect_timeout = 30s
smtp_connect_timeout = 0s
# The smtp_helo_timeout parameter specifies the SMTP client timeout
# status code in the SMTP greeting banner. Some people like to see
# the mail version advertised. By default, Postfix shows no version.
#
-# You MUST specify the $myhostname at the start of the text. When
-# the SMTP client sees its own hostname at the start of an SMTP
-# greeting banner it will report a mailer loop. That's better than
-# having a machine meltdown.
+# You MUST specify the $myhostname at the start of the text.
#
-# smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
+#smtpd_banner = $myhostname ESMTP $mail_name ($mail_version)
smtpd_banner = $myhostname ESMTP $mail_name
# The smtpd_etrn_restrictions parameter restricts what clients are
-# allowed to issue the ETRN command. The present Postfix ETRN differs
-# from other ETRN implementations in that it flushes mail for all
-# destinations. This will change in the future.
+# allowed to issue the ETRN command.
+#
+# The Postfix ETRN command is available only for destinations that
+# that are eligible for the Postfix "fast flush" service. See the
+# sample-flush.cf file for details.
#
# The default is to allow ETRN from any host. The following restrictions
# are available:
# is listed under $maps_rbl_domains.
# reject: reject the request. Place this at the end of a restriction.
# permit: permit the request. Place this at the end of a restriction.
+# warn_if_reject: next restriction logs a warning instead of rejecting.
smtpd_etrn_restrictions =
# The smtpd_recipient_limit parameter restricts the number of recipients
# Specify "mynetworks_style = host" when Postfix should "trust"
# only the local machine.
#
-# mynetworks_style = class
+#mynetworks_style = class
mynetworks_style = subnet
-# mynetworks_style = host
+#mynetworks_style = host
# Alternatively, you can specify the mynetworks list by hand, in
# which case Postfix ignores the mynetworks_style setting.
# reject_maps_rbl: reject if the client is listed under $maps_rbl_domains.
# reject: reject the request. Place this at the end of a restriction.
# permit: permit the request. Place this at the end of a restriction.
+# warn_if_reject: next restriction logs a warning instead of rejecting.
#
# Restrictions are applied in the order as specified; the first
# restriction that matches wins.
# that SMTP clients must introduce themselves at the beginning of an
# SMTP session.
#
-# smtpd_helo_required = yes
+#smtpd_helo_required = yes
smtpd_helo_required = no
# The smtpd_helo_restrictions parameter specifies optional restrictions
# check_client_access maptype:mapname: see smtpd_client_restrictions.
# reject: reject the request. Place this at the end of a restriction.
# permit: permit the request. Place this at the end of a restriction.
+# warn_if_reject: next restriction logs a warning instead of rejecting.
#
# Restrictions are applied in the order as specified; the first
# restriction that matches wins.
# Specify a list of restrictions, separated by commas and/or whitespace.
# Continue long lines by starting the next line with whitespace.
#
-# smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname
-# smtpd_helo_restrictions = permit_mynetworks, reject_unknown_hostname
+#smtpd_helo_restrictions = permit_mynetworks, reject_invalid_hostname
+#smtpd_helo_restrictions = permit_mynetworks, reject_unknown_hostname
smtpd_helo_restrictions =
# The smtpd_sender_restrictions parameter specifies optional restrictions
# reject_non_fqdn_sender: reject sender address that is not in FQDN form
# reject: reject the request. Place this at the end of a restriction.
# permit: permit the request. Place this at the end of a restriction.
+# warn_if_reject: next restriction logs a warning instead of rejecting.
#
# Restrictions are applied in the order as specified; the first
# restriction that matches wins.
# Specify a list of restrictions, separated by commas and/or whitespace.
# Continue long lines by starting the next line with whitespace.
#
-# smtpd_sender_restrictions = reject_unknown_sender_domain
-# smtpd_sender_restrictions = reject_unknown_sender_domain, hash:/etc/postfix/access
+#smtpd_sender_restrictions = reject_unknown_sender_domain
+#smtpd_sender_restrictions = reject_unknown_sender_domain, hash:/etc/postfix/access
smtpd_sender_restrictions =
# The smtpd_recipient_restrictions parameter specifies restrictions on
# reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
# reject: reject the request. Place this at the end of a restriction.
# permit: permit the request. Place this at the end of a restriction.
+# warn_if_reject: next restriction logs a warning instead of rejecting.
#
# Restrictions are applied in the order as specified; the first
# restriction that matches wins.
# to use. If you use this feature, run "postmap /etc/postfix/transport"
# after change, then "postfix reload".
#
-# transport_maps = dbm:/etc/postfix/transport
-# transport_maps = hash:/etc/postfix/transport
-# transport_maps = hash:/etc/postfix/transport, nis:transport
-# transport_maps = hash:/etc/postfix/transport, netinfo:/transport
+#transport_maps = dbm:/etc/postfix/transport
+#transport_maps = hash:/etc/postfix/transport
+#transport_maps = hash:/etc/postfix/transport, nis:transport
+#transport_maps = hash:/etc/postfix/transport, netinfo:/transport
transport_maps =
# It may take a minute or so before the change becomes visible.
# Use "postfix reload" to eliminate the delay.
#
-# virtual_maps = dbm:/etc/postfix/virtual
-# virtual_maps = hash:/etc/postfix/virtual
-# virtual_maps = hash:/etc/postfix/virtual, nis:virtual
-# virtual_maps = hash:/etc/postfix/virtual, netinfo:/virtual
+#virtual_maps = dbm:/etc/postfix/virtual
+#virtual_maps = hash:/etc/postfix/virtual
+#virtual_maps = hash:/etc/postfix/virtual, nis:virtual
+#virtual_maps = hash:/etc/postfix/virtual, netinfo:/virtual
virtual_maps =
updated in this amount of time (default time unit:
days).
+ <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> (versions >= 20011119)
+ List of Postfix features that use <i>domain.name</i> pat-
+ terns to match <i>sub.domain.name</i> (as opposed to
+ requiring <i>.domain.name</i> patterns).
+
<b>SEE</b> <b>ALSO</b>
<a href="smtpd.8.html">smtpd(8)</a> Postfix SMTP server
<a href="qmgr.8.html">qmgr(8)</a> Postfix queue manager
delays.
<b>UCE</b> <b>control</b> <b>restrictions</b>
+ <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> (versions >= 20011119)
+ List of Postfix features that use <i>domain.name</i> pat-
+ terns to match <i>sub.domain.name</i> (as opposed to
+ requiring <i>.domain.name</i> patterns).
+
<b>smtpd</b><i>_</i><b>client</b><i>_</i><b>restrictions</b>
Restrict what clients may connect to this mail sys-
tem.
details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
+ <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> (versions >= 20011119)
+ List of Postfix features that use <i>domain.name</i> pat-
+ terns to match <i>sub.domain.name</i> (as opposed to
+ requiring <i>.domain.name</i> patterns).
+
<b>transport</b><i>_</i><b>maps</b>
List of transport lookup tables.
Syntax is <i>transport</i>:<i>nexthop</i>; see <a href="transport.5.html"><b>transport</b>(5)</a> for
details. The :<i>nexthop</i> part is optional.
+ <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> (versions >= 20011119)
+ List of Postfix features that use <i>domain.name</i> pat-
+ terns to match <i>sub.domain.name</i> (as opposed to
+ requiring <i>.domain.name</i> patterns).
+
<b>relayhost</b>
The default host to send non-local mail to when no
entry is matched in the <a href="transport.5.html"><b>transport</b>(5)</a> table.
<dt> <b><a href="#reject">reject</a></b>
+<dt> <b><a href="#warn_if_reject">warn_if_reject</a></b>
+
<dt> <b><a href="#reject_unauth_pipelining">reject_unauth_pipelining</a></b>
<dd> See generic restrictions.
<dt> <b><a href="#reject">reject</a></b>
+<dt> <b><a href="#warn_if_reject">warn_if_reject</a></b>
+
<dt> <b><a href="#reject_unauth_pipelining">reject_unauth_pipelining</a></b>
<dd> See generic restrictions.
<dt> <b><a href="#reject">reject</a></b>
+<dt> <b><a href="#warn_if_reject">warn_if_reject</a></b>
+
<dt> <b><a href="#reject_unauth_pipelining">reject_unauth_pipelining</a></b>
<dd> See generic restrictions.
<dt> <b><a href="#reject">reject</a></b>
+<dt> <b><a href="#warn_if_reject">warn_if_reject</a></b>
+
<dt> <b><a href="#reject_unauth_pipelining">reject_unauth_pipelining</a></b>
<dd> See generic restrictions.
<dt> <b><a href="#reject">reject</a></b>
+<dt> <b><a href="#warn_if_reject">warn_if_reject</a></b>
+
<dt> <b><a href="#reject_unauth_pipelining">reject_unauth_pipelining</a></b>
<dd> See generic restrictions.
<p>
+<a name="warn_if_reject">
+
+<dt> <b>warn_if_reject</b> (Postfix versions 20011119 and later)
+<dd> Change the meaning of the next restriction, so that it logs
+a warning instead of rejecting a request (look for logfile records
+that contain "reject_warning"). This is useful for testing new
+restrictions in a "live" environment without risking unnecessary
+loss of mail.
+
+<p>
+
<a name="reject_unauth_pipelining">
<dt> <b>reject_unauth_pipelining</b> <dd> Reject the request when
<b>tual</b><i>_</i><b>owner</b><i>_</i><b>maps</b> or <b>virtual</b><i>_</i><b>uid</b><i>_</i><b>maps</b>.
<b>SECURITY</b>
- The virtual delivery agent is not security sensitive, provided
- that the lookup tables with recipient information are adequately
- protected. This program is not designed to run chrooted.
+ The virtual delivery agent is not security sensitive, pro-
+ vided that the lookup tables with recipient user/group ID
+ information are adequately protected. This program is not
+ designed to run chrooted.
<b>STANDARDS</b>
<a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages)
recipient is over disk quota. In all other cases, mail for
an existing recipient is deferred and a warning is logged.
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the <b>corrupt</b> queue afterwards.
- Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
- the postmaster is notified of bounces and of other trou-
+ Depending on the setting of the <b>notify</b><i>_</i><b>classes</b> parameter,
+ the postmaster is notified of bounces and of other trou-
ble.
<b>BUGS</b>
This delivery agent silently ignores address extensions.
Postfix should have lookup tables that can return multiple
- result attributes. In order to avoid the inconvenience of
+ result attributes. In order to avoid the inconvenience of
maintaining three tables, use an LDAP or MYSQL database.
<b>CONFIGURATION</b> <b>PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
- to this program. See the Postfix <b>main.cf</b> file for syntax
- details and for default values. Use the <b>postfix</b> <b>reload</b>
+ The following <b>main.cf</b> parameters are especially relevant
+ to this program. See the Postfix <b>main.cf</b> file for syntax
+ details and for default values. Use the <b>postfix</b> <b>reload</b>
command after a configuration change.
<b>Mailbox</b> <b>delivery</b>
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>base</b>
- Specifies a path that is prepended to all mailbox
- or maildir paths. This is a safety measure to
- ensure that an out of control map in <b>virtual</b><i>_</i><b>mail-</b>
- <b>box</b><i>_</i><b>maps</b> doesn't litter the filesystem with mail-
- boxes. While it could be set to "/", this setting
+ Specifies a path that is prepended to all mailbox
+ or maildir paths. This is a safety measure to
+ ensure that an out of control map in <b>virtual</b><i>_</i><b>mail-</b>
+ <b>box</b><i>_</i><b>maps</b> doesn't litter the filesystem with mail-
+ boxes. While it could be set to "/", this setting
isn't recommended.
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>maps</b> (regexp maps disallowed)
Recipients are looked up in these maps to determine
- the path to their mailbox or maildir. If the
- returned path ends in a slash ("/"), maildir-style
- delivery is carried out, otherwise the path is
+ the path to their mailbox or maildir. If the
+ returned path ends in a slash ("/"), maildir-style
+ delivery is carried out, otherwise the path is
assumed to specify a UNIX-style mailbox file.
- Note that <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>base</b> is unconditionally
+ Note that <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>base</b> is unconditionally
prepended to this path.
<b>virtual</b><i>_</i><b>minimum</b><i>_</i><b>uid</b>
- Specifies a minimum uid that will be accepted as a
- return from a <b>virtual</b><i>_</i><b>owner</b><i>_</i><b>maps</b> or <b>vir-</b>
- <b>tual</b><i>_</i><b>uid</b><i>_</i><b>maps</b> lookup. Returned values less than
- this will be rejected, and the message will be
+ Specifies a minimum uid that will be accepted as a
+ return from a <b>virtual</b><i>_</i><b>owner</b><i>_</i><b>maps</b> or <b>vir-</b>
+ <b>tual</b><i>_</i><b>uid</b><i>_</i><b>maps</b> lookup. Returned values less than
+ this will be rejected, and the message will be
deferred.
<b>virtual</b><i>_</i><b>uid</b><i>_</i><b>maps</b> (regexp maps disallowed)
Recipients are looked up in these maps to determine
- the user ID to be used when writing to the target
+ the user ID to be used when writing to the target
mailbox.
<b>virtual</b><i>_</i><b>gid</b><i>_</i><b>maps</b> (regexp maps disallowed)
Recipients are looked up in these maps to determine
- the group ID to be used when writing to the target
+ the group ID to be used when writing to the target
mailbox.
<b>Locking</b> <b>controls</b>
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>lock</b>
- How to lock UNIX-style mailboxes: one or more of
- <b>flock</b>, <b>fcntl</b> or <b>dotlock</b>. The <b>dotlock</b> method
- requires that the recipient UID or GID has write
+ How to lock UNIX-style mailboxes: one or more of
+ <b>flock</b>, <b>fcntl</b> or <b>dotlock</b>. The <b>dotlock</b> method
+ requires that the recipient UID or GID has write
access to the parent directory of the mailbox file.
- This setting is ignored with <b>maildir</b> style deliv-
+ This setting is ignored with <b>maildir</b> style deliv-
ery, because such deliveries are safe without
explicit locks.
- Use the command <b>postconf</b> <b>-m</b> to find out what lock-
+ Use the command <b>postconf</b> <b>-l</b> to find out what lock-
ing methods are available on your system.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>attempts</b>
- Limit the number of attempts to acquire an exclu-
+ Limit the number of attempts to acquire an exclu-
sive lock on a UNIX-style mailbox file.
<b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b>
Time (default: seconds) between successive attempts
- to acquire an exclusive lock on a UNIX-style mail-
- box file. The actual delay is slightly randomized.
+ to acquire an exclusive lock on a UNIX-style mail-
+ box file. The actual delay is slightly randomized.
<b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b>
- Limit the time after which a stale lockfile is
- removed (applicable to UNIX-style mailboxes only).
+ Limit the time after which a stale lockfile is
+ removed (applicable to UNIX-style mailboxes only).
<b>Resource</b> <b>controls</b>
<b>virtual</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b>
Limit the number of parallel deliveries to the same
domain via the <b>virtual</b> delivery agent. The default
limit is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>concur-</b>
- <b>rency</b><i>_</i><b>limit</b> parameter. The limit is enforced by
+ <b>rency</b><i>_</i><b>limit</b> parameter. The limit is enforced by
the Postfix queue manager.
<b>virtual</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b>
Limit the number of recipients per message delivery
- via the <b>virtual</b> delivery agent. The default limit
- is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipi-</b>
- <b>ent</b><i>_</i><b>limit</b> parameter. The limit is enforced by the
+ via the <b>virtual</b> delivery agent. The default limit
+ is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipi-</b>
+ <b>ent</b><i>_</i><b>limit</b> parameter. The limit is enforced by the
Postfix queue manager.
<b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>limit</b>
- The maximal size in bytes of a mailbox or maildir
+ The maximal size in bytes of a mailbox or maildir
file. Set to zero to disable the limit.
<b>HISTORY</b>
- This agent was originally based on the Postfix local
+ This agent was originally based on the Postfix local
delivery agent. Modifications mainly consisted of removing
- code that either was not applicable or that was not safe
- in this context: aliases, ~user/.forward files, delivery
+ code that either was not applicable or that was not safe
+ in this context: aliases, ~user/.forward files, delivery
to "|command" or to /file/name.
- The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
+ The <b>Delivered-To:</b> header appears in the <b>qmail</b> system by
Daniel Bernstein.
- The <b>maildir</b> structure appears in the <b>qmail</b> system by
+ The <b>maildir</b> structure appears in the <b>qmail</b> system by
Daniel Bernstein.
<b>SEE</b> <b>ALSO</b>
<a href="qmgr.8.html">qmgr(8)</a> queue manager
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
RANLIB=echo
SYSLIBS="-lresolv -lsocket -lnsl"
;;
-Rhapsody.5*|Darwin.1.*)
+Rhapsody.5*|Darwin.*)
SYSTYPE=RHAPSODY5
# Use the native compiler by default
: ${CC=cc}
this topic. See the Postfix \fBmain.cf\fR file for syntax details
and for default values. Use the \fBpostfix reload\fR command after
a configuration change.
+.IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+List of Postfix features that use \fIdomain.name\fR patterns
+to match \fIsub.domain.name\fR (as opposed to
+requiring \fI.domain.name\fR patterns).
.IP \fBtransport_maps\fR
List of transport lookup tables.
.PP
.IP \fBfast_flush_purge_time\fR
Remove an empty "fast flush" logfile that was not updated in
this amount of time (default time unit: days).
+.IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+List of Postfix features that use \fIdomain.name\fR patterns
+to match \fIsub.domain.name\fR (as opposed to
+requiring \fI.domain.name\fR patterns).
.SH SEE ALSO
.na
.nf
.SH "UCE control restrictions"
.ad
.fi
+.IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+List of Postfix features that use \fIdomain.name\fR patterns
+to match \fIsub.domain.name\fR (as opposed to
+requiring \fI.domain.name\fR patterns).
.IP \fBsmtpd_client_restrictions\fR
Restrict what clients may connect to this mail system.
.IP \fBsmtpd_helo_required\fR
.sp
Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
for details. The :\fInexthop\fR part is optional.
+.IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+List of Postfix features that use \fIdomain.name\fR patterns
+to match \fIsub.domain.name\fR (as opposed to
+requiring \fI.domain.name\fR patterns).
.IP \fBrelayhost\fR
The default host to send non-local mail to when no entry is matched
in the \fBtransport\fR(5) table.
.SH SECURITY
.na
.nf
+.ad
+.fi
The virtual delivery agent is not security sensitive, provided
-that the lookup tables with recipient information are adequately
-protected. This program is not designed to run chrooted.
+that the lookup tables with recipient user/group ID information are
+adequately protected. This program is not designed to run chrooted.
.SH STANDARDS
.na
.nf
This setting is ignored with \fBmaildir\fR style delivery,
because such deliveries are safe without explicit locks.
-Use the command \fBpostconf -m\fR to find out what locking methods
+Use the command \fBpostconf -l\fR to find out what locking methods
are available on your system.
.IP \fBdeliver_lock_attempts\fR
Limit the number of attempts to acquire an exclusive lock
# this topic. See the Postfix \fBmain.cf\fR file for syntax details
# and for default values. Use the \fBpostfix reload\fR command after
# a configuration change.
+# .IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+# List of Postfix features that use \fIdomain.name\fR patterns
+# to match \fIsub.domain.name\fR (as opposed to
+# requiring \fI.domain.name\fR patterns).
# .IP \fBtransport_maps\fR
# List of transport lookup tables.
# .PP
flush.o: ../../include/mail_scan_dir.h
flush.o: ../../include/maps.h
flush.o: ../../include/domain_list.h
+flush.o: ../../include/match_list.h
+flush.o: ../../include/match_ops.h
+flush.o: ../../include/match_parent_style.h
flush.o: ../../include/mail_server.h
/* .IP \fBfast_flush_purge_time\fR
/* Remove an empty "fast flush" logfile that was not updated in
/* this amount of time (default time unit: days).
+/* .IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+/* List of Postfix features that use \fIdomain.name\fR patterns
+/* to match \fIsub.domain.name\fR (as opposed to
+/* requiring \fI.domain.name\fR patterns).
/* SEE ALSO
/* smtpd(8) Postfix SMTP server
/* qmgr(8) Postfix queue manager
#include <mail_scan_dir.h>
#include <maps.h>
#include <domain_list.h>
+#include <match_parent_style.h>
/* Single server skeleton. */
static void pre_jail_init(char *unused_name, char **unused_argv)
{
- flush_domains = domain_list_init(var_fflush_domains);
+ flush_domains = domain_list_init(match_parent_style(VAR_FFLUSH_DOMAINS),
+ var_fflush_domains);
}
/* main - pass control to the single-threaded skeleton */
timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \
flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
- verp_sender.c
+ verp_sender.c match_parent_style.c
OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
debug_peer.o debug_process.o defer.o deliver_completed.o \
deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \
flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
- verp_sender.o
+ verp_sender.o match_parent_style.o
HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
deliver_flock.h deliver_pass.h deliver_request.h domain_list.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 qmqp_proto.h verp_sender.h
+ mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \
+ match_parent_style.h
TESTSRC = rec2stream.c stream2rec.c recdump.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
debug_peer.o: ../../include/msg.h
debug_peer.o: mail_params.h
debug_peer.o: namadr_list.h
+debug_peer.o: ../../include/match_list.h
+debug_peer.o: ../../include/match_ops.h
debug_peer.o: debug_peer.h
+debug_peer.o: match_parent_style.h
debug_process.o: debug_process.c
debug_process.o: ../../include/sys_defs.h
debug_process.o: ../../include/msg.h
domain_list.o: domain_list.c
domain_list.o: ../../include/sys_defs.h
domain_list.o: ../../include/match_list.h
-domain_list.o: ../../include/match_ops.h
domain_list.o: domain_list.h
+domain_list.o: ../../include/match_ops.h
dot_lockfile.o: dot_lockfile.c
dot_lockfile.o: ../../include/sys_defs.h
dot_lockfile.o: ../../include/vstring.h
mark_corrupt.o: mail_queue.h
mark_corrupt.o: ../../include/vstring.h
mark_corrupt.o: mark_corrupt.h
+match_parent_style.o: match_parent_style.c
+match_parent_style.o: ../../include/sys_defs.h
+match_parent_style.o: string_list.h
+match_parent_style.o: ../../include/match_list.h
+match_parent_style.o: ../../include/match_ops.h
+match_parent_style.o: mail_params.h
+match_parent_style.o: match_parent_style.h
mbox_conf.o: mbox_conf.c
mbox_conf.o: ../../include/sys_defs.h
mbox_conf.o: ../../include/name_mask.h
namadr_list.o: namadr_list.c
namadr_list.o: ../../include/sys_defs.h
namadr_list.o: ../../include/match_list.h
-namadr_list.o: ../../include/match_ops.h
namadr_list.o: namadr_list.h
+namadr_list.o: ../../include/match_ops.h
off_cvt.o: off_cvt.c
off_cvt.o: ../../include/sys_defs.h
off_cvt.o: ../../include/msg.h
resolve_local.o: ../../include/msg.h
resolve_local.o: ../../include/mymalloc.h
resolve_local.o: string_list.h
+resolve_local.o: ../../include/match_list.h
+resolve_local.o: ../../include/match_ops.h
resolve_local.o: mail_params.h
resolve_local.o: own_inet_addr.h
resolve_local.o: resolve_local.h
+resolve_local.o: match_parent_style.h
rewrite_clnt.o: rewrite_clnt.c
rewrite_clnt.o: ../../include/sys_defs.h
rewrite_clnt.o: ../../include/msg.h
string_list.o: string_list.c
string_list.o: ../../include/sys_defs.h
string_list.o: ../../include/match_list.h
-string_list.o: ../../include/match_ops.h
string_list.o: string_list.h
+string_list.o: ../../include/match_ops.h
sys_exits.o: sys_exits.c
sys_exits.o: ../../include/sys_defs.h
sys_exits.o: ../../include/msg.h
#include <mail_params.h>
#include <namadr_list.h>
#include <debug_peer.h>
+#include <match_parent_style.h>
/* Application-specific. */
* Finally.
*/
if (*var_debug_peer_list)
- debug_peer_list = namadr_list_init(var_debug_peer_list);
+ debug_peer_list =
+ namadr_list_init(match_parent_style(VAR_DEBUG_PEER_LIST),
+ var_debug_peer_list);
}
/* debug_peer_check - see if this peer needs verbose logging */
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, request->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, request->queue_id,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, request->data_offset,
- ATTR_TYPE_NUM, MAIL_ATTR_SIZE, request->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, request->data_offset,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, request->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, request->sender,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, request->errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, request->return_receipt,
- ATTR_TYPE_NUM, MAIL_ATTR_TIME, request->arrival_time,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, offs,
+ ATTR_TYPE_LONG, MAIL_ATTR_TIME, request->arrival_time,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, offs,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, addr,
ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0,
ATTR_TYPE_END);
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &request->flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, &request->data_offset,
- ATTR_TYPE_NUM, MAIL_ATTR_SIZE, &request->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &request->data_offset,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, &request->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, address,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, return_receipt,
- ATTR_TYPE_NUM, MAIL_ATTR_TIME, &request->arrival_time,
+ ATTR_TYPE_LONG, MAIL_ATTR_TIME, &request->arrival_time,
ATTR_TYPE_END) != 10)
return (-1);
if (mail_open_ok(vstring_str(queue_name),
*/
for (;;) {
if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, &offset,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset,
ATTR_TYPE_END) != 1)
return (-1);
if (offset == 0)
/* SYNOPSIS
/* #include <domain_list.h>
/*
-/* DOMAIN_LIST *domain_list_init(pattern_list)
+/* DOMAIN_LIST *domain_list_init(flags, pattern_list)
+/* int flags;
/* const char *pattern_list;
/*
/* int domain_list_match(list, name)
/* void domain_list_free(list)
/* DOMAIN_LIST *list;
/* DESCRIPTION
+/* This is a convenience wrapper around the match_list module.
+/*
/* This module implements tests for list membership of a host or
/* domain name.
/*
/* insensitive. In order to reverse the result, precede a non-file
/* name pattern with an exclamation point (!).
/*
-/* domain_list_init() performs initializations. The argument is a
-/* list of domain patterns, or the name of a file containing domain
-/* patterns.
+/* domain_list_init() performs initializations. The first argument
+/* is the bit-wise OR of zero or more of the following:
+/* .RS
+/* .IP MATCH_FLAG_PARENT
+/* The hostname pattern foo.com matches itself and any name below
+/* the domain foo.com. If this flag is cleared, foo.com matches itself
+/* only, and .foo.com matches any name below the domain foo.com.
+/* .RE
+/* Specify MATCH_FLAG_NONE to request none of the above.
+/* The second argument is a list of domain patterns, or the name of
+/* a file containing domain patterns.
/*
/* domain_list_match() matches the specified host or domain name
/* against the specified pattern list.
/* Utility library. */
#include <match_list.h>
-#include <match_ops.h>
/* Global library. */
#include "domain_list.h"
-/* domain_list_init - initialize domain list */
-
-DOMAIN_LIST *domain_list_init(const char *patterns)
-{
- return (match_list_init(patterns, 1, match_hostname));
-}
-
-/* domain_list_match - match host against domain list */
-
-int domain_list_match(DOMAIN_LIST *list, const char *name)
-{
- return (match_list_match(list, name));
-}
-
-/* domain_list_free - release storage */
-
-void domain_list_free(DOMAIN_LIST *list)
-{
- match_list_free(list);
-}
-
#ifdef TEST
#include <msg.h>
}
if (argc != optind + 2)
usage(argv[0]);
- list = domain_list_init(argv[optind]);
+ list = domain_list_init(MATCH_FLAG_PARENT, argv[optind]);
host = argv[optind + 1];
vstream_printf("%s: %s\n", host, domain_list_match(list, host) ?
"YES" : "NO");
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <match_list.h>
+#include <match_ops.h>
+
/*
* External interface.
*/
-typedef struct MATCH_LIST DOMAIN_LIST;
+#define DOMAIN_LIST MATCH_LIST
-extern DOMAIN_LIST *domain_list_init(const char *);
-extern int domain_list_match(DOMAIN_LIST *, const char *);
-extern void domain_list_free(DOMAIN_LIST *);
+#define domain_list_init(f, p) match_list_init((f), (p), 1, match_hostname)
+#define domain_list_match match_list_match
+#define domain_list_free match_list_free
/* LICENSE
/* .ad
/* char *var_mynetworks_style;
/* char *var_verp_delims;
/* char *var_verp_filter;
+/* char *var_par_dom_match;
/*
/* char *var_import_environ;
/* char *var_export_environ;
char *var_verp_delims;
char *var_verp_filter;
int var_in_flow_delay;
+char *var_par_dom_match;
char *var_import_environ;
char *var_export_environ;
VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
VAR_VERP_DELIMS, DEF_VERP_DELIMS, &var_verp_delims, 2, 2,
VAR_VERP_FILTER, DEF_VERP_FILTER, &var_verp_filter, 1, 0,
+ VAR_PAR_DOM_MATCH, DEF_PAR_DOM_MATCH, &var_par_dom_match, 0, 0,
0,
};
static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
#define CHECK_RECIP_ACL "check_recipient_access"
#define CHECK_ETRN_ACL "check_etrn_access"
+#define WARN_IF_REJECT "warn_if_reject"
+
#define REJECT_MAPS_RBL "reject_maps_rbl"
#define VAR_MAPS_RBL_CODE "maps_rbl_reject_code"
#define DEF_MAPS_RBL_CODE 554
#define DEF_IN_FLOW_DELAY "1s"
extern int var_in_flow_delay;
+ /*
+ * Backwards compatibility: foo.com matches itself and names below foo.com.
+ */
+#define VAR_PAR_DOM_MATCH "parent_domain_matches_subdomains"
+#define DEF_PAR_DOM_MATCH VAR_DEBUG_PEER_LIST "," \
+ VAR_FFLUSH_DOMAINS "," \
+ VAR_MYNETWORKS "," \
+ VAR_PERM_MX_NETWORKS "," \
+ VAR_QMQPD_CLIENTS "," \
+ VAR_RELAY_DOMAINS "," \
+ SMTPD_ACCESS_MAPS
+extern char *var_par_dom_match;
+
+#define SMTPD_ACCESS_MAPS "smtpd_access_maps"
+
/* LICENSE
/* .ad
/* .fi
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20011120"
+#define DEF_MAIL_VERSION "Snapshot-20011121"
extern char *var_mail_version;
/* LICENSE
--- /dev/null
+/*++
+/* NAME
+/* match_parent_style 3
+/* SUMMARY
+/* parent domain matching control
+/* SYNOPSIS
+/* #include <match_parent_style.h>
+/*
+/* int match_parent_style(name)
+/* const char *name;
+/* DESCRIPTION
+/* This module queries configuration parameters for the policy that
+/* controls how wild-card parent domain names are used by various
+/* postfix lookup mechanisms.
+/*
+/* match_parent_style() looks up "name" in the
+/* parent_domain_matches_subdomain configuration parameter
+/* and returns either MATCH_FLAG_PARENT or MATCH_PARENT_NONE.
+/* DIAGNOSTICS
+/* Fatal error: out of memory, name listed under both parent wild card
+/* matching policies.
+/* SEE ALSO
+/* string_list(3) plain string matching
+/* domain_list(3) match host name patterns
+/* namadr_list(3) match host name/address patterns
+/* 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>
+
+/* Utility library. */
+
+/* Global library. */
+
+#include <string_list.h>
+#include <mail_params.h>
+#include <match_parent_style.h>
+
+/* Application-specific. */
+
+static STRING_LIST *match_par_dom_list;
+
+int match_parent_style(const char *name)
+{
+ int result;
+
+ /*
+ * Initialize on the fly.
+ */
+ if (match_par_dom_list == 0)
+ match_par_dom_list =
+ string_list_init(MATCH_FLAG_NONE, var_par_dom_match);
+
+ /*
+ * Look up the parent domain matching policy.
+ */
+ if (string_list_match(match_par_dom_list, name))
+ result = MATCH_FLAG_PARENT;
+ else
+ result = 0;
+ return (result);
+}
--- /dev/null
+#ifndef _MATCH_PARENT_STYLE_H_INCLUDED_
+#define _MATCH_PARENT_STYLE_H_INCLUDED_
+
+/*++
+/* NAME
+/* match_parent_style 3h
+/* SUMMARY
+/* parent domain matching control
+/* SYNOPSIS
+/* #include <match_parent_style.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <match_ops.h>
+
+ /*
+ * External interface.
+ */
+extern int match_parent_style(const char *);
+
+/* 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
/* SYNOPSIS
/* #include <namadr_list.h>
/*
-/* NAMADR_LIST *namadr_list_init(pattern_list)
+/* NAMADR_LIST *namadr_list_init(flags, pattern_list)
+/* int flags;
/* const char *pattern_list;
/*
/* int namadr_list_match(list, name, addr)
/* void namadr_list_free(list)
/* NAMADR_LIST *list;
/* DESCRIPTION
+/* This is a convenience wrapper around the match_list module.
+/*
/* This module implements tests for list membership of a
/* hostname or network address.
/*
/* a pattern, or when any of its parent domains matches a
/* pattern. The matching process is case insensitive.
/*
-/* namadr_list_init() performs initializations. The argument
-/* is a list of patterns, or the absolute pathname of a file
-/* with patterns.
+/* namadr_list_init() performs initializations. The first
+/* argument is the bit-wise OR of zero or more of the
+/* following:
+/* .RS
+/* .IP MATCH_FLAG_PARENT
+/* The hostname pattern foo.com matches itself and any name below
+/* the domain foo.com. If this flag is cleared, foo.com matches itself
+/* only, and .foo.com matches any name below the domain foo.com.
+/* .RE
+/* Specify MATCH_FLAG_NONE to request none of the above.
+/* The second argument is a list of patterns, or the absolute
+/* pathname of a file with patterns.
/*
/* namadr_list_match() matches the specified host name and
/* address against the specified list of patterns.
/* Utility library. */
#include <match_list.h>
-#include <match_ops.h>
/* Global library. */
#include "namadr_list.h"
-/* namadr_list_init - initialize domain list */
-
-NAMADR_LIST *namadr_list_init(const char *patterns)
-{
- return (match_list_init(patterns, 2, match_hostaddr, match_hostname));
-}
-
-/* namadr_list_match - match host against set of namadr_list patterns */
-
-int namadr_list_match(NAMADR_LIST *list, const char *name, const char *addr)
-{
- return (match_list_match(list, addr, name));
-}
-
-/* namadr_list_free - release storage */
-
-void namadr_list_free(NAMADR_LIST *list)
-{
- match_list_free(list);
-}
-
#ifdef TEST
#include <msg.h>
}
if (argc != optind + 3)
usage(argv[0]);
- list = namadr_list_init(argv[optind]);
+ list = namadr_list_init(MATCH_FLAG_PARENT, argv[optind]);
host = argv[optind + 1];
addr = argv[optind + 2];
vstream_printf("%s/%s: %s\n", host, addr,
/* SUMMARY
/* name/address membership
/* SYNOPSIS
-/* #include <namadr_list_list.h>
+/* #include <namadr_list.h>
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <match_list.h>
+#include <match_ops.h>
+
/*
* External interface.
*/
-typedef struct MATCH_LIST NAMADR_LIST;
+#define NAMADR_LIST MATCH_LIST
-extern NAMADR_LIST *namadr_list_init(const char *);
-extern int namadr_list_match(NAMADR_LIST *, const char *, const char *);
-extern void namadr_list_free(NAMADR_LIST *);
+#define namadr_list_init(f, p) \
+ match_list_init((f), (p), 2, match_hostname, match_hostaddr)
+#define namadr_list_match match_list_match
+#define namadr_list_free match_list_free
/* LICENSE
/* .ad
#include <mail_params.h>
#include <own_inet_addr.h>
#include <resolve_local.h>
+#include <match_parent_style.h>
/* Application-specific */
{
if (resolve_local_list)
msg_panic("resolve_local_init: duplicate initialization");
- resolve_local_list = string_list_init(var_mydest);
+ resolve_local_list = string_list_init(MATCH_FLAG_NONE, var_mydest);
}
/* resolve_local - match address against list of local destinations */
/* SYNOPSIS
/* #include <string_list.h>
/*
-/* STRING_LIST *string_list_init(pattern_list)
+/* STRING_LIST *string_list_init(flags, pattern_list)
+/* int flags;
/* const char *pattern_list;
/*
/* int string_list_match(list, name)
/* void string_list_free(list)
/* STRING_LIST *list;
/* DESCRIPTION
+/* This is a convenience wrapper around the match_list module.
+/*
/* This module implements tests for list membership of a string.
/*
/* Patterns are separated by whitespace and/or commas. A pattern
/* In order to reverse the result, precede a non-file name pattern
/* with an exclamation point (!).
/*
-/* string_list_init() performs initializations. The argument is a
-/* list of string patterns.
+/* string_list_init() performs initializations. The flags argument
+/* is ignored; pattern_list specifies a list of string patterns.
/*
/* string_list_match() matches the specified string against the
/* compiled pattern list.
/* Utility library. */
#include <match_list.h>
-#include <match_ops.h>
/* Global library. */
#include "string_list.h"
-/* string_list_init - initialize string list */
-
-STRING_LIST *string_list_init(const char *patterns)
-{
- return (match_list_init(patterns, 1, match_string));
-}
-
-/* string_list_match - match string against list */
-
-int string_list_match(STRING_LIST * list, const char *string)
-{
- return (match_list_match(list, string));
-}
-
-/* string_list_free - release storage */
-
-void string_list_free(STRING_LIST * list)
-{
- match_list_free(list);
-}
-
#ifdef TEST
#include <msg.h>
}
if (argc != optind + 2)
usage(argv[0]);
- list = string_list_init(argv[optind]);
+ list = string_list_init(MATCH_FLAG_NONE, argv[optind]);
string = argv[optind + 1];
vstream_printf("%s: %s\n", string, string_list_match(list, string) ?
"YES" : "NO");
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <match_list.h>
+#include <match_ops.h>
+
/*
* External interface.
*/
-typedef struct MATCH_LIST STRING_LIST;
+#define STRING_LIST MATCH_LIST
-extern STRING_LIST *string_list_init(const char *);
-extern int string_list_match(STRING_LIST *, const char *);
-extern void string_list_free(STRING_LIST *);
+#define string_list_init(f, p) match_list_init((f), (p), 1, match_string)
+#define string_list_match match_list_match
+#define string_list_free match_list_free
/* LICENSE
/* .ad
lmtp_sasl_glue.o: ../../include/name_mask.h
lmtp_sasl_glue.o: ../../include/mail_params.h
lmtp_sasl_glue.o: ../../include/string_list.h
+lmtp_sasl_glue.o: ../../include/match_list.h
+lmtp_sasl_glue.o: ../../include/match_ops.h
lmtp_sasl_glue.o: ../../include/maps.h
lmtp_sasl_glue.o: ../../include/dict.h
lmtp_sasl_glue.o: ../../include/vstream.h
* As the mail system, bounce, defer delivery, or report success.
*/
if (status != 0) {
- status = (errno == EAGAIN || errno == ENOSPC ?
+ status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
defer_append : bounce_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"cannot append message to destination file %s: %s",
* As the mail system, bounce, defer delivery, or report success.
*/
if (status != 0) {
- status = (errno == EAGAIN || errno == ENOSPC ?
+ status = (errno == EAGAIN || errno == ENOSPC || errno == ESTALE ?
defer_append : bounce_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"cannot access mailbox %s for user %s. %s",
*/
#define LAST_CHAR(s) (s[strlen(s) - 1])
- if (*var_mailbox_cmd_maps) {
- if (cmd_maps == 0)
- cmd_maps = maps_create(VAR_MAILBOX_CMD_MAPS, var_mailbox_cmd_maps,
- DICT_FLAG_LOCK);
- if ((map_command = maps_find(cmd_maps, state.msg_attr.user,
- DICT_FLAG_FIXED)) != 0) {
- status = deliver_command(state, usr_attr, map_command);
- } else {
- msg_warn("user %s not found in %s",
- state.msg_attr.user, var_mailbox_cmd_maps);
- return (NO);
- }
+ if (*var_mailbox_cmd_maps && cmd_maps == 0)
+ cmd_maps = maps_create(VAR_MAILBOX_CMD_MAPS, var_mailbox_cmd_maps,
+ DICT_FLAG_LOCK);
+
+ if (*var_mailbox_cmd_maps
+ && (map_command = maps_find(cmd_maps, state.msg_attr.user,
+ DICT_FLAG_FIXED)) != 0) {
+ status = deliver_command(state, usr_attr, map_command);
} else if (*var_mailbox_command) {
status = deliver_command(state, usr_attr, var_mailbox_command);
} else if (*var_home_mailbox && LAST_CHAR(var_home_mailbox) == '/') {
set_eugid(var_owner_uid, var_owner_gid);
if (status)
- status = (errno == ENOSPC ? defer_append : bounce_append)
+ status = (errno == ENOSPC || errno == ESTALE ?
+ defer_append : bounce_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"maildir delivery failed: %s", vstring_str(why));
else
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, message->data_offset,
- ATTR_TYPE_NUM, MAIL_ATTR_SIZE, message->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, message->return_receipt,
- ATTR_TYPE_NUM, MAIL_ATTR_TIME, message->arrival_time,
+ ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time,
ATTR_TYPE_END);
if (sender_buf != 0)
vstring_free(sender_buf);
for (recipient = list.info; recipient < list.info + list.len; recipient++)
attr_print(stream, ATTR_FLAG_MORE,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, recipient->offset,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, recipient->offset,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient->address,
ATTR_TYPE_END);
attr_print(stream, ATTR_FLAG_NONE,
../../conf/main.cf.default: $(PROG) Makefile
rm -f $@
- ./$(PROG) -d |egrep -v '^(myhostname|mydomain|mynetworks) ' >$@
+ (echo "# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE"; \
+ echo "# TEXT HERE JUST SHOWS DEFAULT SETTINGS BUILT INTO POSTFIX."; \
+ echo "#"; \
+ ./$(PROG) -d) |egrep -v '^(myhostname|mydomain|mynetworks) ' >$@
Makefile: Makefile.in
(set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name,
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, message->data_offset,
- ATTR_TYPE_NUM, MAIL_ATTR_SIZE, message->data_size,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset,
+ ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->data_size,
ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
ATTR_TYPE_STR, MAIL_ATTR_ERRTO, message->errors_to,
ATTR_TYPE_STR, MAIL_ATTR_RRCPT, message->return_receipt,
- ATTR_TYPE_NUM, MAIL_ATTR_TIME, message->arrival_time,
+ ATTR_TYPE_LONG, MAIL_ATTR_TIME, message->arrival_time,
ATTR_TYPE_END);
if (sender_buf != 0)
vstring_free(sender_buf);
for (recipient = list.info; recipient < list.info + list.len; recipient++)
attr_print(stream, ATTR_FLAG_MORE,
- ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, recipient->offset,
+ ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, recipient->offset,
ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient->address,
ATTR_TYPE_END);
attr_print(stream, ATTR_FLAG_NONE,
qmqpd.o: ../../include/debug_peer.h
qmqpd.o: ../../include/mail_stream.h
qmqpd.o: ../../include/namadr_list.h
+qmqpd.o: ../../include/match_list.h
+qmqpd.o: ../../include/match_ops.h
qmqpd.o: ../../include/quote_822_local.h
+qmqpd.o: ../../include/match_parent_style.h
qmqpd.o: ../../include/mail_server.h
qmqpd.o: qmqpd.h
qmqpd_peer.o: qmqpd_peer.c
#include <mail_stream.h>
#include <namadr_list.h>
#include <quote_822_local.h>
+#include <match_parent_style.h>
/* Single-threaded server skeleton. */
static void pre_jail_init(char *unused_name, char **unused_argv)
{
debug_peer_init();
- qmqpd_clients = namadr_list_init(var_qmqpd_clients);
+ qmqpd_clients =
+ namadr_list_init(match_parent_style(VAR_QMQPD_CLIENTS),
+ var_qmqpd_clients);
}
/* main - the main program */
smtp_get(buf, fp, var_line_limit);
if (STR(buf)[0] != '2')
- msg_fatal("server rejected request: %s", STR(buf));
+ msg_fatal("server rejected ETRN request: %s", STR(buf));
if (msg_verbose)
msg_info("<<< %s", STR(buf));
smtp_proto.o: ../../include/vstring_vstream.h
smtp_proto.o: ../../include/stringops.h
smtp_proto.o: ../../include/mymalloc.h
+smtp_proto.o: ../../include/iostuff.h
smtp_proto.o: ../../include/mail_params.h
smtp_proto.o: ../../include/smtp_stream.h
smtp_proto.o: ../../include/mail_queue.h
smtp_sasl_glue.o: ../../include/name_mask.h
smtp_sasl_glue.o: ../../include/mail_params.h
smtp_sasl_glue.o: ../../include/string_list.h
+smtp_sasl_glue.o: ../../include/match_list.h
+smtp_sasl_glue.o: ../../include/match_ops.h
smtp_sasl_glue.o: ../../include/maps.h
smtp_sasl_glue.o: ../../include/dict.h
smtp_sasl_glue.o: ../../include/vstream.h
#include <vstring_vstream.h>
#include <stringops.h>
#include <mymalloc.h>
+#include <iostuff.h>
/* Global library. */
* does not span a packet boundary. This hurts performance so it is not
* on by default.
*/
- if (resp->str[strspn(resp->str, "20 *\t\n")] == 0)
+ if (resp->str[strspn(resp->str, "20 *\t\n")] == 0) {
+ msg_info("enabling PIX <CRLF>.<CRLF> workaround for %s",
+ session->namaddr);
state->features |= SMTP_FEATURE_MAYBEPIX;
+ }
/*
* See if we are talking to ourself. This should not be possible with the
} else if (strcasecmp(word, "ESMTP") == 0)
state->features |= SMTP_FEATURE_ESMTP;
}
- if (var_smtp_always_ehlo)
+ if (var_smtp_always_ehlo && (state->features & SMTP_FEATURE_MAYBEPIX) == 0)
state->features |= SMTP_FEATURE_ESMTP;
- if (var_smtp_never_ehlo)
+ if (var_smtp_never_ehlo || (state->features & SMTP_FEATURE_MAYBEPIX) != 0)
state->features &= ~SMTP_FEATURE_ESMTP;
/*
if (prev_type == REC_TYPE_CONT) /* missing newline at end */
smtp_fputs("", 0, session->stream);
- if ((state->features & SMTP_FEATURE_ESMTP) == 0
- && (state->features & SMTP_FEATURE_MAYBEPIX) != 0)
+ if ((state->features & SMTP_FEATURE_MAYBEPIX) != 0) {
vstream_fflush(session->stream);/* hurts performance */
+ sleep(10); /* not to mention this */
+ }
if (vstream_ferror(state->src))
msg_fatal("queue file read error");
if (rec_type != REC_TYPE_XTRA)
smtpd_check.o: ../../include/ctable.h
smtpd_check.o: ../../include/dns.h
smtpd_check.o: ../../include/namadr_list.h
+smtpd_check.o: ../../include/match_list.h
+smtpd_check.o: ../../include/match_ops.h
smtpd_check.o: ../../include/domain_list.h
smtpd_check.o: ../../include/mail_params.h
smtpd_check.o: ../../include/canon_addr.h
smtpd_check.o: ../../include/mail_conf.h
smtpd_check.o: ../../include/maps.h
smtpd_check.o: ../../include/mail_addr_find.h
+smtpd_check.o: ../../include/match_parent_style.h
smtpd_check.o: smtpd.h
smtpd_check.o: ../../include/mail_stream.h
smtpd_check.o: smtpd_sasl_glue.h
smtpd_sasl_glue.o: ../../include/msg.h
smtpd_sasl_glue.o: ../../include/mymalloc.h
smtpd_sasl_glue.o: ../../include/namadr_list.h
+smtpd_sasl_glue.o: ../../include/match_list.h
+smtpd_sasl_glue.o: ../../include/match_ops.h
smtpd_sasl_glue.o: ../../include/name_mask.h
smtpd_sasl_glue.o: ../../include/mail_params.h
smtpd_sasl_glue.o: ../../include/smtp_stream.h
/* .SH "UCE control restrictions"
/* .ad
/* .fi
+/* .IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+/* List of Postfix features that use \fIdomain.name\fR patterns
+/* to match \fIsub.domain.name\fR (as opposed to
+/* requiring \fI.domain.name\fR patterns).
/* .IP \fBsmtpd_client_restrictions\fR
/* Restrict what clients may connect to this mail system.
/* .IP \fBsmtpd_helo_required\fR
* report problems when running in stand-alone mode: postmaster notices
* require availability of the cleanup service.
*/
- if (state->history != 0 && state->client != VSTREAM_IN
+ if (state->history != 0 && SMTPD_STAND_ALONE(state) == 0
&& (state->error_mask & state->notify_mask))
smtpd_chat_notify(state);
smtpd_chat_reset(state);
VSTRING *sasl_encoded;
VSTRING *sasl_decoded;
#endif
+ int warn_if_reject;
} SMTPD_STATE;
extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
#include <mail_conf.h>
#include <maps.h>
#include <mail_addr_find.h>
+#include <match_parent_style.h>
/* Application-specific. */
static NAMADR_LIST *mynetworks;
static NAMADR_LIST *perm_mx_networks;
+ /*
+ * How to do parent domain wildcard matching, if any.
+ */
+static int access_parent_style;
+
/*
* Pre-parsed restriction lists.
*/
* Recursively check list membership.
*/
for (rest = restrictions->argv; *rest; rest++) {
+ if (strcmp(*rest, WARN_IF_REJECT) == 0 && rest[1] != 0) {
+ rest += 1;
+ continue;
+ }
for (reqd = required; *reqd; reqd++)
if (strcmp(*rest, *reqd) == 0)
return (1);
*/
example = vstring_alloc(10);
for (reqd = required; *reqd; reqd++)
- vstring_sprintf_append(example, "%s ", *reqd);
- msg_fatal("parameter \"%s\": specify at least one explicit instance of: %s",
+ vstring_sprintf_append(example, "%s%s", *reqd,
+ reqd[1] == 0 ? "" : reqd[2] == 0 ? " or " : ", ");
+ msg_fatal("parameter \"%s\": specify at least one working instance of: %s",
name, STR(example));
}
/*
* Pre-open access control lists before going to jail.
*/
- mynetworks = namadr_list_init(var_mynetworks);
- relay_domains = domain_list_init(var_relay_domains);
- perm_mx_networks = namadr_list_init(var_perm_mx_networks);
+ mynetworks =
+ namadr_list_init(match_parent_style(VAR_MYNETWORKS),
+ var_mynetworks);
+ relay_domains =
+ domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
+ var_relay_domains);
+ perm_mx_networks =
+ namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS),
+ var_perm_mx_networks);
/*
* Pre-parse and pre-open the recipient maps.
relocated_maps = maps_create(VAR_RELOCATED_MAPS, var_relocated_maps,
DICT_FLAG_LOCK);
+ access_parent_style = match_parent_style(SMTPD_ACCESS_MAPS);
+
/*
* error_text is used for returning error responses.
*/
char *format,...)
{
va_list ap;
+ int warn_if_reject;
+ const char *whatsup;
+
+ /*
+ * Do not reject mail if we were asked to warn only. However,
+ * configuration errors cannot be converted into warnings.
+ */
+ if (state->warn_if_reject && error_class != MAIL_ERROR_SOFTWARE) {
+ warn_if_reject = 1;
+ whatsup = "reject_warning";
+ } else {
+ warn_if_reject = 0;
+ whatsup = "reject";
+ }
/*
* Update the error class mask, and format the response. XXX What about
* rejected. Print the request, client name/address, and response.
*/
if (state->recipient && state->sender) {
- msg_info("reject: %s from %s: %s; from=<%s> to=<%s>",
- state->where, state->namaddr, STR(error_text),
+ msg_info("%s: %s from %s: %s; from=<%s> to=<%s>",
+ whatsup, state->where, state->namaddr, STR(error_text),
state->sender, state->recipient);
} else if (state->recipient) {
- msg_info("reject: %s from %s: %s; to=<%s>",
- state->where, state->namaddr, STR(error_text),
+ msg_info("%s: %s from %s: %s; to=<%s>",
+ whatsup, state->where, state->namaddr, STR(error_text),
state->recipient);
} else if (state->sender) {
- msg_info("reject: %s from %s: %s; from=<%s>",
- state->where, state->namaddr, STR(error_text),
+ msg_info("%s: %s from %s: %s; from=<%s>",
+ whatsup, state->where, state->namaddr, STR(error_text),
state->sender);
} else {
- msg_info("reject: %s from %s: %s",
- state->where, state->namaddr, STR(error_text));
+ msg_info("%s: %s from %s: %s",
+ whatsup, state->where, state->namaddr, STR(error_text));
}
- return (SMTPD_CHECK_REJECT);
+ return (warn_if_reject ? 0 : SMTPD_CHECK_REJECT);
}
/* reject_dict_retry - reject with temporary failure if dict lookup fails */
if ((dict = dict_handle(table)) == 0)
msg_panic("%s: dictionary not found: %s", myname, table);
- for (name = low_domain; /* void */ ; name = next + 1) {
+ for (name = low_domain; /* void */ ; name = next) {
if (flags == 0 || (flags & dict->flags) != 0) {
if ((value = dict_get(dict, name)) != 0)
CHK_DOMAIN_RETURN(check_table_result(state, table, value,
if (dict_errno != 0)
msg_fatal("%s: table lookup problem", table);
}
- if ((next = strchr(name, '.')) == 0)
+ if ((next = strchr(name + 1, '.')) == 0)
break;
+ if (access_parent_style == MATCH_FLAG_PARENT)
+ next += 1;
flags = PARTIAL;
}
CHK_DOMAIN_RETURN(SMTPD_CHECK_DUNNO, MISSED);
int status = 0;
ARGV *list;
int found;
+ int saved_recursion = state->recursion;
if (msg_verbose)
msg_info("%s: START", myname);
if (msg_verbose)
msg_info("%s: name=%s", myname, name);
+ /*
+ * Pseudo restrictions.
+ */
+ if (strcasecmp(name, WARN_IF_REJECT) == 0) {
+ if (state->warn_if_reject == 0)
+ state->warn_if_reject = state->recursion;
+ continue;
+ }
+
/*
* Spoof the is_map_command() routine, so that we do not have to make
* special cases for the implicit short-hand access map notation.
*/
if (strcasecmp(name, PERMIT_ALL) == 0) {
status = SMTPD_CHECK_OK;
- if (cpp[1] != 0)
+ if (cpp[1] != 0 && state->warn_if_reject == 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], PERMIT_ALL);
} else if (strcasecmp(name, REJECT_ALL) == 0) {
status = smtpd_check_reject(state, MAIL_ERROR_POLICY,
"%d <%s>: %s rejected: Access denied",
var_reject_code, reply_name, reply_class);
- if (cpp[1] != 0)
+ if (cpp[1] != 0 && state->warn_if_reject == 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], REJECT_ALL);
} else if (strcasecmp(name, REJECT_UNAUTH_PIPE) == 0) {
if (state->recipient)
status = check_relay_domains(state, state->recipient,
state->recipient, SMTPD_NAME_RECIPIENT);
- if (cpp[1] != 0)
+ if (cpp[1] != 0 && state->warn_if_reject == 0)
msg_warn("restriction `%s' after `%s' is ignored",
cpp[1], CHECK_RELAY_DOMAINS);
#ifdef USE_SASL_AUTH
if (msg_verbose)
msg_info("%s: name=%s status=%d", myname, name, status);
+ if (state->warn_if_reject >= state->recursion)
+ state->warn_if_reject = 0;
+
if (status != 0)
break;
}
if (msg_verbose && name == 0)
msg_info("%s: END", myname);
+ state->recursion = saved_recursion;
+
return (status);
}
/*
* Apply restrictions in the order as specified.
*/
- state->recursion = 0;
+ state->recursion = 1;
status = setjmp(smtpd_check_buf);
if (status == 0 && client_restrctions->argc)
status = generic_checks(state, client_restrctions, state->namaddr,
/*
* Apply restrictions in the order as specified.
*/
- state->recursion = 0;
+ state->recursion = 1;
status = setjmp(smtpd_check_buf);
if (status == 0 && helo_restrctions->argc)
status = generic_checks(state, helo_restrctions, state->helo_name,
/*
* Apply restrictions in the order as specified.
*/
- state->recursion = 0;
+ state->recursion = 1;
status = setjmp(smtpd_check_buf);
if (status == 0 && mail_restrctions->argc)
status = generic_checks(state, mail_restrctions, sender,
/*
* Apply restrictions in the order as specified.
*/
- state->recursion = 0;
+ state->recursion = 1;
status = setjmp(smtpd_check_buf);
if (status == 0 && rcpt_restrctions->argc)
status = generic_checks(state, rcpt_restrctions,
/*
* Apply restrictions in the order as specified.
*/
- state->recursion = 0;
+ state->recursion = 1;
status = setjmp(smtpd_check_buf);
if (status == 0 && etrn_restrctions->argc)
status = generic_checks(state, etrn_restrctions, domain,
char *var_relocated_maps;
char *var_local_rcpt_maps;
char *var_perm_mx_networks;
+char *var_par_dom_match;
typedef struct {
char *name;
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,
- VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks, 0, 0,
+ VAR_PERM_MX_NETWORKS, DEF_PERM_MX_NETWORKS, &var_perm_mx_networks,
+ VAR_PAR_DOM_MATCH, DEF_PAR_DOM_MATCH, &var_par_dom_match,
0,
};
}
if (strcasecmp(args->argv[0], "mynetworks") == 0) {
namadr_list_free(mynetworks);
- mynetworks = namadr_list_init(args->argv[1]);
+ mynetworks =
+ namadr_list_init(match_parent_style(VAR_MYNETWORKS),
+ args->argv[1]);
resp = 0;
break;
}
if (strcasecmp(args->argv[0], "relay_domains") == 0) {
domain_list_free(relay_domains);
- relay_domains = domain_list_init(args->argv[1]);
+ relay_domains =
+ domain_list_init(match_parent_style(VAR_RELAY_DOMAINS),
+ args->argv[1]);
resp = 0;
break;
}
smtpd_delay_reject 0
mynetworks 127.0.0.0/8,168.100.189.0/28
relay_domains porcupine.org
+maps_rbl_domains blackholes.mail-abuse.org
#
# Test the client restrictions.
#
smtpd_delay_reject 0
mynetworks 127.0.0.0/8,168.100.189.0/28
relay_domains porcupine.org
+maps_rbl_domains blackholes.mail-abuse.org
#
# Test the client restrictions.
#
OK
>>> relay_domains porcupine.org
OK
+>>> maps_rbl_domains blackholes.mail-abuse.org
+OK
>>> #
>>> # Test the client restrictions.
>>> #
OK
>>> relay_domains porcupine.org
OK
+>>> maps_rbl_domains blackholes.mail-abuse.org
+OK
>>> #
>>> # Test the client restrictions.
>>> #
state->recursion = 0;
state->msg_size = 0;
state->junk_cmds = 0;
+ state->warn_if_reject = 0;
#ifdef USE_SASL_AUTH
if (SMTPD_STAND_ALONE(state))
/* Terminate after \fIcount\fR sessions. This is for testing purposes.
/* .IP \fB-p\fR
/* Disable ESMTP command pipelining.
+/* .IP \fB-P\fR
+/* Change the server greeting so that it appears to come through
+/* a CISCO PIX system.
/* .IP \fB-v\fR
/* Show the SMTP conversations.
/* .IP "\fB-w \fIdelay\fR"
static int disable_pipelining;
static int fixed_delay;
static int enable_lmtp;
+static int pretend_pix;
/* ehlo_response - respond to EHLO command */
state->read = command_read;
state->data_state = ST_ANY;
smtp_timeout_setup(state->stream, var_tmout);
+if (pretend_pix)
+ smtp_printf(state->stream, "220 ********");
+else
smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
event_enable_read(fd, read_event, (char *) state);
}
static void usage(char *myname)
{
- msg_fatal("usage: %s [-cLpv] [-n count] [-w delay] [host]:port backlog", myname);
+ msg_fatal("usage: %s [-cLpPv] [-n count] [-w delay] [host]:port backlog", myname);
}
int main(int argc, char **argv)
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "cLn:pvw:")) > 0) {
+ while ((ch = GETOPT(argc, argv, "cLn:pPvw:")) > 0) {
switch (ch) {
case 'c':
count++;
case 'p':
disable_pipelining = 1;
break;
+ case 'P':
+ pretend_pix=1;
+ break;
case 'v':
msg_verbose++;
break;
#include <mail_params.h>
#include <maps.h>
+#include <match_parent_style.h>
/* Application-specific. */
#include "transport.h"
static MAPS *transport_path;
+static int transport_match_parent_style;
/* transport_init - pre-jail initialization */
msg_panic("transport_init: repeated call");
transport_path = maps_create("transport", var_transport_maps,
DICT_FLAG_LOCK);
+ transport_match_parent_style = match_parent_style(VAR_TRANSPORT_MAPS);
}
/* transport_lookup - map a transport domain */
{
char *low_domain = lowercase(mystrdup(domain));
const char *name;
+ const char *next;
const char *value;
const char *host;
char *saved_value;
* Specify if a key is partial or full, to avoid matching partial keys with
* regular expressions.
*/
- for (name = low_domain; name != 0; name = strchr(name + 1, '.')) {
+ for (name = low_domain; /* void */; name = next) {
if ((value = maps_find(transport_path, name, maps_flag)) != 0) {
saved_value = mystrdup(value);
if ((host = split_at(saved_value, ':')) == 0 || *host == 0)
} else if (dict_errno != 0) {
msg_fatal("transport table lookup problem");
}
+ if ((next = strchr(name + 1, '.')) == 0)
+ break;
+ if (transport_match_parent_style == MATCH_FLAG_PARENT)
+ next++;
maps_flag = PARTIAL;
}
myfree(low_domain);
/* .sp
/* Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
/* for details. The :\fInexthop\fR part is optional.
+/* .IP "\fBparent_domain_matches_subdomains\fR (versions >= 20011119)"
+/* List of Postfix features that use \fIdomain.name\fR patterns
+/* to match \fIsub.domain.name\fR (as opposed to
+/* requiring \fI.domain.name\fR patterns).
/* .IP \fBrelayhost\fR
/* The default host to send non-local mail to when no entry is matched
/* in the \fBtransport\fR(5) table.
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 netstring.c ctable.c attr_print.c intv.c \
- attr_scan.c base64_code.c
+ sane_socketpair.c myrand.c netstring.c ctable.c attr_print64.c intv.c \
+ attr_scan64.c base64_code.c sock_empty_wait.c attr_print0.c attr_scan0.c
OBJS = argv.o argv_split.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 \
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 netstring.o ctable.o attr_print.o intv.o \
- attr_scan.o base64_code.o
+ sane_socketpair.o myrand.o netstring.o ctable.o attr_print64.o intv.o \
+ attr_scan64.o base64_code.o sock_empty_wait.o attr_print0.o attr_scan0.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 \
mystrtok sigdelay translit valid_hostname vstream_popen \
vstring vstring_vstream doze select_bug stream_test mac_expand \
watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
- inet_addr_list attr_print attr_scan base64_code
+ inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \
+ attr_scan0
LIB_DIR = ../../lib
INC_DIR = ../../include
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-attr_print: $(LIB) $@.o
+attr_print64: $(LIB) $@.o
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
-attr_scan: $(LIB) $@.o
+attr_scan64: $(LIB) $@.o
mv $@.o junk
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+attr_print0: $(LIB) $@.o
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
+attr_scan0: $(LIB) $@.o
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
- attr_scan_test
+ attr_scan64_test attr_scan0_test
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
base64_code_test: base64_code
./base64_code
-attr_scan_test: attr_print attr_scan attr_scan.ref
- (./attr_print 2>&3 | (sleep 1; ./attr_scan)) >attr_scan.tmp 2>&1 3>&1
- diff attr_scan.ref attr_scan.tmp
- rm -f attr_scan.tmp
+attr_scan64_test: attr_print64 attr_scan64 attr_scan64.ref
+ (./attr_print64 2>&3 | (sleep 1; ./attr_scan64)) >attr_scan64.tmp 2>&1 3>&1
+ diff attr_scan64.ref attr_scan64.tmp
+ rm -f attr_scan64.tmp
+
+attr_scan0_test: attr_print0 attr_scan0 attr_scan0.ref
+ (./attr_print0 2>&3 | (sleep 1; ./attr_scan0)) >attr_scan0.tmp 2>&1 3>&1
+ diff attr_scan0.ref attr_scan0.tmp
+ rm -f attr_scan0.tmp
DB_TYPE = `../postconf/postconf -h default_database_type`
attr_print.o: base64_code.h
attr_print.o: vstring.h
attr_print.o: attr.h
+attr_print0.o: attr_print0.c
+attr_print0.o: sys_defs.h
+attr_print0.o: msg.h
+attr_print0.o: mymalloc.h
+attr_print0.o: vstream.h
+attr_print0.o: vbuf.h
+attr_print0.o: htable.h
+attr_print0.o: attr.h
+attr_print64.o: attr_print64.c
+attr_print64.o: sys_defs.h
+attr_print64.o: msg.h
+attr_print64.o: mymalloc.h
+attr_print64.o: vstream.h
+attr_print64.o: vbuf.h
+attr_print64.o: htable.h
+attr_print64.o: base64_code.h
+attr_print64.o: vstring.h
+attr_print64.o: attr.h
attr_scan.o: attr_scan.c
attr_scan.o: sys_defs.h
attr_scan.o: msg.h
attr_scan.o: htable.h
attr_scan.o: base64_code.h
attr_scan.o: attr.h
+attr_scan0.o: attr_scan0.c
+attr_scan0.o: sys_defs.h
+attr_scan0.o: msg.h
+attr_scan0.o: mymalloc.h
+attr_scan0.o: vstream.h
+attr_scan0.o: vbuf.h
+attr_scan0.o: vstring.h
+attr_scan0.o: vstring_vstream.h
+attr_scan0.o: htable.h
+attr_scan0.o: attr.h
+attr_scan64.o: attr_scan64.c
+attr_scan64.o: sys_defs.h
+attr_scan64.o: msg.h
+attr_scan64.o: mymalloc.h
+attr_scan64.o: vstream.h
+attr_scan64.o: vbuf.h
+attr_scan64.o: vstring.h
+attr_scan64.o: htable.h
+attr_scan64.o: base64_code.h
+attr_scan64.o: attr.h
base64_code.o: base64_code.c
base64_code.o: sys_defs.h
base64_code.o: msg.h
match_list.o: stringops.h
match_list.o: argv.h
match_list.o: dict.h
+match_list.o: match_ops.h
match_list.o: match_list.h
match_ops.o: match_ops.c
match_ops.o: sys_defs.h
skipblanks.o: stringops.h
skipblanks.o: vstring.h
skipblanks.o: vbuf.h
+sock_empty_wait.o: sock_empty_wait.c
+sock_empty_wait.o: sys_defs.h
+sock_empty_wait.o: msg.h
+sock_empty_wait.o: iostuff.h
spawn_command.o: spawn_command.c
spawn_command.o: sys_defs.h
spawn_command.o: msg.h
#define ATTR_TYPE_NUM 1 /* Unsigned integer */
#define ATTR_TYPE_STR 2 /* Character string */
#define ATTR_TYPE_HASH 3 /* Hash table */
+#define ATTR_TYPE_LONG 4 /* Unsigned long */
/*
* Flags that control processing. See attr_scan(3) for documentation.
#define ATTR_FLAG_STRICT (ATTR_FLAG_MISSING | ATTR_FLAG_EXTRA)
#define ATTR_FLAG_ALL (07)
+#define attr_print attr_print0
+#define attr_vprint attr_vprint0
+#define attr_scan attr_scan0
+#define attr_vscan attr_vscan0
+
+ /*
+ * attr_print64.c.
+ */
+extern int attr_print64(VSTREAM *, int,...);
+extern int attr_vprint64(VSTREAM *, int, va_list);
+
+ /*
+ * attr_scan64.c.
+ */
+extern int attr_scan64(VSTREAM *, int,...);
+extern int attr_vscan64(VSTREAM *, int, va_list);
+
/*
- * attr_print.c.
+ * attr_print0.c.
*/
-extern int attr_print(VSTREAM *, int,...);
-extern int attr_vprint(VSTREAM *, int, va_list);
+extern int attr_print0(VSTREAM *, int,...);
+extern int attr_vprint0(VSTREAM *, int, va_list);
/*
- * attr_scan.c.
+ * attr_scan0.c.
*/
-extern int attr_scan(VSTREAM *, int,...);
-extern int attr_vscan(VSTREAM *, int, va_list);
+extern int attr_scan0(VSTREAM *, int,...);
+extern int attr_vscan0(VSTREAM *, int, va_list);
/*
* Attribute names for testing the compatibility of the read and write
#ifdef TEST
#define ATTR_NAME_NUM "number"
#define ATTR_NAME_STR "string"
+#define ATTR_NAME_LONG "long_number"
#endif
/* LICENSE
--- /dev/null
+/*++
+/* NAME
+/* attr_print0 3
+/* SUMMARY
+/* send attributes over byte stream
+/* SYNOPSIS
+/* #include <attr.h>
+/*
+/* int attr_print0(fp, flags, type, name, ...)
+/* VSTREAM fp;
+/* int flags;
+/* int type;
+/* char *name;
+/*
+/* int attr_vprint0(fp, flags, ap)
+/* VSTREAM fp;
+/* int flags;
+/* va_list ap;
+/* DESCRIPTION
+/* attr_print0() takes zero or more (name, value) simple attributes
+/* or (name, count, value) list attributes, and converts its input
+/* to a byte stream that can be recovered with attr_scan0(). The stream
+/* is not flushed.
+/*
+/* attr_vprint0() provides an alternate interface that is convenient
+/* for calling from within variadoc functions.
+/*
+/* Attributes are sent in the requested order as specified with the
+/* attr_print0() argument list. This routine satisfies the formatting
+/* rules as outlined in attr_scan0(3).
+/*
+/* Arguments:
+/* .IP fp
+/* Stream to write the result to.
+/* .IP flags
+/* The bit-wise OR of zero or more of the following.
+/* .RS
+/* .IP ATTR_FLAG_MORE
+/* After sending the requested attributes, leave the output stream in
+/* a state that is usable for more attribute sending operations on
+/* the same output attribute list.
+/* By default, attr_print0() automatically appends an attribute list
+/* terminator when it has sent the last requested attribute.
+/* .RE
+/* .IP type
+/* The type determines the arguments that follow.
+/* .RS
+/* .IP "ATTR_TYPE_NUM (char *, int)"
+/* This argument is followed by an attribute name and an integer.
+/* .IP "ATTR_TYPE_NUM (char *, long)"
+/* This argument is followed by an attribute name and a long integer.
+/* .IP "ATTR_TYPE_STR (char *, char *)"
+/* This argument is followed by an attribute name and a null-terminated
+/* string.
+/* .IP "ATTR_TYPE_HASH (HTABLE *)"
+/* The content of the hash table is sent as a sequence of string-valued
+/* attributes with names equal to the hash table lookup key.
+/* .IP ATTR_TYPE_END
+/* This terminates the attribute list.
+/* .RE
+/* DIAGNOSTICS
+/* The result value is 0 in case of success, VSTREAM_EOF in case
+/* of trouble.
+/*
+/* Panic: interface violation. All system call errors are fatal.
+/* SEE ALSO
+/* attr_scan0(3) recover attributes from byte stream
+/* 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 <stdarg.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstream.h>
+#include <htable.h>
+#include <attr.h>
+
+/* attr_vprint0 - send attribute list to stream */
+
+int attr_vprint0(VSTREAM *fp, int flags, va_list ap)
+{
+ const char *myname = "attr_print0";
+ int attr_type;
+ char *attr_name;
+ unsigned int_val;
+ unsigned long long_val;
+ char *str_val;
+ HTABLE_INFO **ht_info_list;
+ HTABLE_INFO **ht;
+
+ /*
+ * Sanity check.
+ */
+ if (flags & ~ATTR_FLAG_ALL)
+ msg_panic("%s: bad flags: 0x%x", myname, flags);
+
+ /*
+ * Iterate over all (type, name, value) triples, and produce output on
+ * the fly.
+ */
+ while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) {
+ switch (attr_type) {
+ case ATTR_TYPE_NUM:
+ attr_name = va_arg(ap, char *);
+ vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
+ int_val = va_arg(ap, int);
+ vstream_fprintf(fp, "%u", (unsigned) int_val);
+ VSTREAM_PUTC('\0', fp);
+ if (msg_verbose)
+ msg_info("send attr %s = %u", attr_name, int_val);
+ break;
+ case ATTR_TYPE_LONG:
+ attr_name = va_arg(ap, char *);
+ vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
+ long_val = va_arg(ap, unsigned long);
+ vstream_fprintf(fp, "%lu", (unsigned long) long_val);
+ VSTREAM_PUTC('\0', fp);
+ if (msg_verbose)
+ msg_info("send attr %s = %lu", attr_name, long_val);
+ break;
+ case ATTR_TYPE_STR:
+ attr_name = va_arg(ap, char *);
+ vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
+ str_val = va_arg(ap, char *);
+ vstream_fwrite(fp, str_val, strlen(str_val) + 1);
+ if (msg_verbose)
+ msg_info("send attr %s = %s", attr_name, str_val);
+ break;
+ case ATTR_TYPE_HASH:
+ ht_info_list = htable_list(va_arg(ap, HTABLE *));
+ for (ht = ht_info_list; *ht; ht++) {
+ vstream_fwrite(fp, ht[0]->key, strlen(ht[0]->key) + 1);
+ vstream_fwrite(fp, ht[0]->value, strlen(ht[0]->value) + 1);
+ if (msg_verbose)
+ msg_info("send attr name %s value %s",
+ ht[0]->key, ht[0]->value);
+ }
+ myfree((char *) ht_info_list);
+ break;
+ default:
+ msg_panic("%s: unknown type code: %d", myname, attr_type);
+ }
+ }
+ if ((flags & ATTR_FLAG_MORE) == 0)
+ VSTREAM_PUTC('\0', fp);
+ return (vstream_ferror(fp));
+}
+
+int attr_print0(VSTREAM *fp, int flags,...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, flags);
+ ret = attr_vprint0(fp, flags, ap);
+ va_end(ap);
+ return (ret);
+}
+
+#ifdef TEST
+
+ /*
+ * Proof of concept test program. Mirror image of the attr_scan0 test
+ * program.
+ */
+#include <msg_vstream.h>
+
+int main(int unused_argc, char **argv)
+{
+ HTABLE *table = htable_create(1);
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+ msg_verbose = 1;
+ htable_enter(table, "foo-name", mystrdup("foo-value"));
+ htable_enter(table, "bar-name", mystrdup("bar-value"));
+ attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
+ ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+ ATTR_TYPE_HASH, table,
+ ATTR_TYPE_END);
+ attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
+ ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+ ATTR_TYPE_END);
+ if (vstream_fflush(VSTREAM_OUT) != 0)
+ msg_fatal("write error: %m");
+
+ htable_free(table, myfree);
+ return (0);
+}
+
+#endif
/*++
/* NAME
-/* attr_print 3
+/* attr_print64 3
/* SUMMARY
/* send attributes over byte stream
/* SYNOPSIS
/* #include <attr.h>
/*
-/* int attr_print(fp, flags, type, name, ...)
+/* int attr_print64(fp, flags, type, name, ...)
/* VSTREAM fp;
/* int flags;
/* int type;
/* char *name;
/*
-/* int attr_vprint(fp, flags, ap)
+/* int attr_vprint64(fp, flags, ap)
/* VSTREAM fp;
/* int flags;
/* va_list ap;
/* DESCRIPTION
-/* attr_print() takes zero or more (name, value) simple attributes
+/* attr_print64() takes zero or more (name, value) simple attributes
/* or (name, count, value) list attributes, and converts its input
-/* to a byte stream that can be recovered with attr_scan(). The stream
+/* to a byte stream that can be recovered with attr_scan64(). The stream
/* is not flushed.
/*
-/* attr_vprint() provides an alternate interface that is convenient
+/* attr_vprint64() provides an alternate interface that is convenient
/* for calling from within variadoc functions.
/*
/* Attributes are sent in the requested order as specified with the
-/* attr_print() argument list. This routine satisfies the formatting
-/* rules as outlined in attr_scan(3).
+/* attr_print64() argument list. This routine satisfies the formatting
+/* rules as outlined in attr_scan64(3).
/*
/* Arguments:
/* .IP fp
/* After sending the requested attributes, leave the output stream in
/* a state that is usable for more attribute sending operations on
/* the same output attribute list.
-/* By default, attr_print() automatically appends an attribute list
+/* By default, attr_print64() automatically appends an attribute list
/* terminator when it has sent the last requested attribute.
/* .RE
/* .IP type
/* .RS
/* .IP "ATTR_TYPE_NUM (char *, int)"
/* This argument is followed by an attribute name and an integer.
+/* .IP "ATTR_TYPE_NUM (char *, long)"
+/* This argument is followed by an attribute name and a long integer.
/* .IP "ATTR_TYPE_STR (char *, char *)"
/* This argument is followed by an attribute name and a null-terminated
/* string.
/*
/* Panic: interface violation. All system call errors are fatal.
/* SEE ALSO
-/* attr_scan(3) recover attributes from byte stream
+/* attr_scan64(3) recover attributes from byte stream
/* LICENSE
/* .ad
/* .fi
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
-/* attr_print_str - encode and send attribute information */
+/* attr_print64_str - encode and send attribute information */
-static void attr_print_str(VSTREAM *fp, const char *str, int len)
+static void attr_print64_str(VSTREAM *fp, const char *str, int len)
{
static VSTRING *base64_buf;
vstream_fputs(STR(base64_buf), fp);
}
-static void attr_print_num(VSTREAM *fp, unsigned num)
+static void attr_print64_num(VSTREAM *fp, unsigned num)
{
static VSTRING *plain;
plain = vstring_alloc(10);
vstring_sprintf(plain, "%u", num);
- attr_print_str(fp, STR(plain), LEN(plain));
+ attr_print64_str(fp, STR(plain), LEN(plain));
}
-/* attr_vprint - send attribute list to stream */
+static void attr_print64_long_num(VSTREAM *fp, unsigned long long_num)
+{
+ static VSTRING *plain;
+
+ if (plain == 0)
+ plain = vstring_alloc(10);
+
+ vstring_sprintf(plain, "%lu", long_num);
+ attr_print64_str(fp, STR(plain), LEN(plain));
+}
+
+/* attr_vprint64 - send attribute list to stream */
-int attr_vprint(VSTREAM *fp, int flags, va_list ap)
+int attr_vprint64(VSTREAM *fp, int flags, va_list ap)
{
- const char *myname = "attr_print";
+ const char *myname = "attr_print64";
int attr_type;
char *attr_name;
unsigned int_val;
+ unsigned long long_val;
char *str_val;
HTABLE_INFO **ht_info_list;
HTABLE_INFO **ht;
switch (attr_type) {
case ATTR_TYPE_NUM:
attr_name = va_arg(ap, char *);
- attr_print_str(fp, attr_name, strlen(attr_name));
+ attr_print64_str(fp, attr_name, strlen(attr_name));
int_val = va_arg(ap, int);
VSTREAM_PUTC(':', fp);
- attr_print_num(fp, (unsigned) int_val);
+ attr_print64_num(fp, (unsigned) int_val);
if (msg_verbose)
msg_info("send attr %s = %u", attr_name, int_val);
break;
+ case ATTR_TYPE_LONG:
+ attr_name = va_arg(ap, char *);
+ attr_print64_str(fp, attr_name, strlen(attr_name));
+ long_val = va_arg(ap, long);
+ VSTREAM_PUTC(':', fp);
+ attr_print64_long_num(fp, (unsigned long) long_val);
+ if (msg_verbose)
+ msg_info("send attr %s = %lu", attr_name, long_val);
+ break;
case ATTR_TYPE_STR:
attr_name = va_arg(ap, char *);
- attr_print_str(fp, attr_name, strlen(attr_name));
+ attr_print64_str(fp, attr_name, strlen(attr_name));
str_val = va_arg(ap, char *);
VSTREAM_PUTC(':', fp);
- attr_print_str(fp, str_val, strlen(str_val));
+ attr_print64_str(fp, str_val, strlen(str_val));
if (msg_verbose)
msg_info("send attr %s = %s", attr_name, str_val);
break;
case ATTR_TYPE_HASH:
ht_info_list = htable_list(va_arg(ap, HTABLE *));
for (ht = ht_info_list; *ht; ht++) {
- attr_print_str(fp, ht[0]->key, strlen(ht[0]->key));
+ attr_print64_str(fp, ht[0]->key, strlen(ht[0]->key));
VSTREAM_PUTC(':', fp);
- attr_print_str(fp, ht[0]->value, strlen(ht[0]->value));
+ attr_print64_str(fp, ht[0]->value, strlen(ht[0]->value));
if (msg_verbose)
msg_info("send attr name %s value %s",
ht[0]->key, ht[0]->value);
return (vstream_ferror(fp));
}
-int attr_print(VSTREAM *fp, int flags,...)
+int attr_print64(VSTREAM *fp, int flags,...)
{
va_list ap;
int ret;
va_start(ap, flags);
- ret = attr_vprint(fp, flags, ap);
+ ret = attr_vprint64(fp, flags, ap);
va_end(ap);
return (ret);
}
#ifdef TEST
/*
- * Proof of concept test program. Mirror image of the attr_scan test
+ * Proof of concept test program. Mirror image of the attr_scan64 test
* program.
*/
#include <msg_vstream.h>
msg_verbose = 1;
htable_enter(table, "foo-name", mystrdup("foo-value"));
htable_enter(table, "bar-name", mystrdup("bar-value"));
- attr_print(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
- ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
- ATTR_TYPE_HASH, table,
- ATTR_TYPE_END);
- attr_print(VSTREAM_OUT, ATTR_FLAG_NONE,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
- ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
- ATTR_TYPE_END);
+ attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
+ ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+ ATTR_TYPE_HASH, table,
+ ATTR_TYPE_END);
+ attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
+ ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+ ATTR_TYPE_END);
if (vstream_fflush(VSTREAM_OUT) != 0)
msg_fatal("write error: %m");
--- /dev/null
+/*++
+/* NAME
+/* attr_scan0 3
+/* SUMMARY
+/* recover attributes from byte stream
+/* SYNOPSIS
+/* #include <attr.h>
+/*
+/* int attr_scan0(fp, flags, type, name, ...)
+/* VSTREAM fp;
+/* int flags;
+/* int type;
+/* char *name;
+/*
+/* int attr_vscan0(fp, flags, ap)
+/* VSTREAM fp;
+/* int flags;
+/* va_list ap;
+/* DESCRIPTION
+/* attr_scan0() takes zero or more (name, value) request attributes
+/* and recovers the attribute values from the byte stream that was
+/* possibly generated by attr_print0().
+/*
+/* attr_vscan0() provides an alternative interface that is convenient
+/* for calling from within a variadic function.
+/*
+/* The input stream is formatted as follows, where (item)* stands
+/* for zero or more instances of the specified item, and where
+/* (item1 | item2) stands for choice:
+/*
+/* .in +5
+/* attr-list :== simple-attr* null
+/* .br
+/* simple-attr :== attr-name null attr-value null
+/* .br
+/* attr-name :== any string not containing null
+/* .br
+/* attr-value :== any string not containing null
+/* .br
+/* null :== the ASCII null character
+/* .in
+/*
+/* All attribute names and attribute values are sent as null terminated
+/* strings. Each string must be no longer than 2*var_line_limit
+/* characters. The formatting rules favor implementations in C.
+/*
+/* Normally, attributes must be received in the sequence as specified with
+/* the attr_scan0() argument list. The input stream may contain additional
+/* attributes at any point in the input stream, including additional
+/* instances of requested attributes.
+/*
+/* Additional input attributes or input attribute instances are silently
+/* skipped over, unless the ATTR_FLAG_EXTRA processing flag is specified
+/* (see below). This allows for some flexibility in the evolution of
+/* protocols while still providing the option of being strict where
+/* this is desirable.
+/*
+/* Arguments:
+/* .IP fp
+/* Stream to recover the input attributes from.
+/* .IP flags
+/* The bit-wise OR of zero or more of the following.
+/* .RS
+/* .IP ATTR_FLAG_MISSING
+/* Log a warning when the input attribute list terminates before all
+/* requested attributes are recovered. It is always an error when the
+/* input stream ends without the newline attribute list terminator.
+/* .IP ATTR_FLAG_EXTRA
+/* Log a warning and stop attribute recovery when the input stream
+/* contains an attribute that was not requested. This includes the
+/* case of additional instances of a requested attribute.
+/* .IP ATTR_FLAG_MORE
+/* After recovering the requested attributes, leave the input stream
+/* in a state that is usable for more attr_scan0() operations from the
+/* same input attribute list.
+/* By default, attr_scan0() skips forward past the input attribute list
+/* terminator.
+/* .IP ATTR_FLAG_STRICT
+/* For convenience, this value combines both ATTR_FLAG_MISSING and
+/* ATTR_FLAG_EXTRA.
+/* .IP ATTR_FLAG_NONE
+/* For convenience, this value requests none of the above.
+/* .RE
+/* .IP type
+/* The type argument determines the arguments that follow.
+/* .RS
+/* .IP "ATTR_TYPE_NUM (char *, int *)"
+/* This argument is followed by an attribute name and an integer pointer.
+/* .IP "ATTR_TYPE_LONG (char *, long *)"
+/* This argument is followed by an attribute name and a long pointer.
+/* .IP "ATTR_TYPE_STR (char *, VSTRING *)"
+/* This argument is followed by an attribute name and a VSTRING pointer.
+/* .IP "ATTR_TYPE_HASH (HTABLE *)"
+/* All further input attributes are processed as string attributes.
+/* No specific attribute sequence is enforced.
+/* All attributes up to the attribute list terminator are read,
+/* but only the first instance of each attribute is stored.
+/* .sp
+/* The attribute string values are stored in the hash table under
+/* keys equal to the attribute name (obtained from the input stream).
+/* Values from the input stream are added to the hash table. Existing
+/* hash table entries are not replaced.
+/* .sp
+/* N.B. This construct must be followed by an ATTR_TYPE_END argument.
+/* .IP ATTR_TYPE_END
+/* This argument terminates the requested attribute list.
+/* .RE
+/* BUGS
+/* ATTR_TYPE_HASH accepts attributes with arbitrary names from possibly
+/* untrusted sources. This is unsafe, unless the resulting table is
+/* queried only with known to be good attribute names.
+/* DIAGNOSTICS
+/* attr_scan0() and attr_vscan0() return -1 when malformed input is
+/* detected (string too long, incomplete line, missing end marker).
+/* Otherwise, the result value is the number of attributes that were
+/* successfully recovered from the input stream (a hash table counts
+/* as the number of entries stored into the table).
+/*
+/* Panic: interface violation. All system call errors are fatal.
+/* SEE ALSO
+/* attr_print0(3) send attributes over byte stream.
+/* 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 <stdarg.h>
+#include <stdio.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstream.h>
+#include <vstring.h>
+#include <vstring_vstream.h>
+#include <htable.h>
+#include <attr.h>
+
+/* Application specific. */
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
+
+/* attr_scan0_string - pull a string from the input stream */
+
+static int attr_scan0_string(VSTREAM *fp, VSTRING *plain_buf, const char *context)
+{
+ extern int var_line_limit; /* XXX */
+ int limit = var_line_limit * 2;
+ int ch;
+
+ if ((ch = vstring_get_null(plain_buf, fp)) == VSTREAM_EOF) {
+ msg_warn("premature end-of-input from %s while reading %s",
+ VSTREAM_PATH(fp), context);
+ return (-1);
+ }
+ if (ch != 0) {
+ msg_warn("string length > %d characters from %s while reading %s",
+ limit, VSTREAM_PATH(fp), context);
+ return (-1);
+ }
+ if (msg_verbose)
+ msg_info("%s: %s", context, *STR(plain_buf) ? STR(plain_buf) : "(end)");
+ return (ch);
+}
+
+/* attr_scan0_number - pull a number from the input stream */
+
+static int attr_scan0_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf,
+ const char *context)
+{
+ char junk = 0;
+ int ch;
+
+ if ((ch = attr_scan0_string(fp, str_buf, context)) < 0)
+ return (-1);
+ if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) {
+ msg_warn("malformed numerical data from %s while reading %s: %.100s",
+ VSTREAM_PATH(fp), context, STR(str_buf));
+ return (-1);
+ }
+ return (ch);
+}
+
+/* attr_scan0_long_number - pull a number from the input stream */
+
+static int attr_scan0_long_number(VSTREAM *fp, unsigned long *ptr,
+ VSTRING *str_buf,
+ const char *context)
+{
+ char junk = 0;
+ int ch;
+
+ if ((ch = attr_scan0_string(fp, str_buf, context)) < 0)
+ return (-1);
+ if (sscanf(STR(str_buf), "%lu%c", ptr, &junk) != 1 || junk != 0) {
+ msg_warn("malformed numerical data from %s while reading %s: %.100s",
+ VSTREAM_PATH(fp), context, STR(str_buf));
+ return (-1);
+ }
+ return (ch);
+}
+
+/* attr_vscan0 - receive attribute list from stream */
+
+int attr_vscan0(VSTREAM *fp, int flags, va_list ap)
+{
+ const char *myname = "attr_scan0";
+ static VSTRING *str_buf = 0;
+ static VSTRING *name_buf = 0;
+ int wanted_type = -1;
+ char *wanted_name;
+ unsigned int *number;
+ unsigned long *long_number;
+ VSTRING *string;
+ HTABLE *hash_table;
+ int ch;
+ int conversions;
+
+ /*
+ * Sanity check.
+ */
+ if (flags & ~ATTR_FLAG_ALL)
+ msg_panic("%s: bad flags: 0x%x", myname, flags);
+
+ /*
+ * Initialize.
+ */
+ if (str_buf == 0) {
+ str_buf = vstring_alloc(10);
+ name_buf = vstring_alloc(10);
+ }
+
+ /*
+ * Iterate over all (type, name, value) triples.
+ */
+ for (conversions = 0; /* void */ ; conversions++) {
+
+ /*
+ * Determine the next attribute type and attribute name on the
+ * caller's wish list.
+ *
+ * If we're reading into a hash table, we already know that the
+ * attribute value is string-valued, and we get the attribute name
+ * from the input stream instead. This is secure only when the
+ * resulting table is queried with known to be good attribute names.
+ */
+ if (wanted_type != ATTR_TYPE_HASH) {
+ wanted_type = va_arg(ap, int);
+ if (wanted_type == ATTR_TYPE_END) {
+ if ((flags & ATTR_FLAG_MORE) != 0)
+ return (conversions);
+ wanted_name = "(list terminator)";
+ } else if (wanted_type == ATTR_TYPE_HASH) {
+ wanted_name = "(any attribute name or list terminator)";
+ hash_table = va_arg(ap, HTABLE *);
+ if (va_arg(ap, int) !=ATTR_TYPE_END)
+ msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END",
+ myname);
+ } else {
+ wanted_name = va_arg(ap, char *);
+ }
+ }
+
+ /*
+ * Locate the next attribute of interest in the input stream.
+ */
+ for (;;) {
+
+ /*
+ * Get the name of the next attribute. Hitting EOF is always bad.
+ * Hitting the end-of-input early is OK if the caller is prepared
+ * to deal with missing inputs.
+ */
+ if (msg_verbose)
+ msg_info("%s: wanted attribute: %s",
+ VSTREAM_PATH(fp), wanted_name);
+ if ((ch = attr_scan0_string(fp, name_buf,
+ "input attribute name")) == VSTREAM_EOF)
+ return (-1);
+ if (LEN(name_buf) == 0) {
+ if (wanted_type == ATTR_TYPE_END
+ || wanted_type == ATTR_TYPE_HASH)
+ return (conversions);
+ if ((flags & ATTR_FLAG_MISSING) != 0)
+ msg_warn("missing attribute %s in input from %s",
+ wanted_name, VSTREAM_PATH(fp));
+ return (conversions);
+ }
+
+ /*
+ * See if the caller asks for this attribute.
+ */
+ if (wanted_type == ATTR_TYPE_HASH
+ || (wanted_type != ATTR_TYPE_END
+ && strcmp(wanted_name, STR(name_buf)) == 0))
+ break;
+ if ((flags & ATTR_FLAG_EXTRA) != 0) {
+ msg_warn("spurious attribute %s in input from %s",
+ STR(name_buf), VSTREAM_PATH(fp));
+ return (conversions);
+ }
+
+ /*
+ * Skip over this attribute. The caller does not ask for it.
+ */
+ (void) attr_scan0_string(fp, str_buf, "input attribute value");
+ }
+
+ /*
+ * Do the requested conversion.
+ */
+ switch (wanted_type) {
+ case ATTR_TYPE_NUM:
+ number = va_arg(ap, unsigned int *);
+ if ((ch = attr_scan0_number(fp, number, str_buf,
+ "input attribute value")) < 0)
+ return (-1);
+ break;
+ case ATTR_TYPE_LONG:
+ long_number = va_arg(ap, unsigned long *);
+ if ((ch = attr_scan0_long_number(fp, long_number, str_buf,
+ "input attribute value")) < 0)
+ return (-1);
+ break;
+ case ATTR_TYPE_STR:
+ string = va_arg(ap, VSTRING *);
+ if ((ch = attr_scan0_string(fp, string,
+ "input attribute value")) < 0)
+ return (-1);
+ break;
+ case ATTR_TYPE_HASH:
+ if ((ch = attr_scan0_string(fp, str_buf,
+ "input attribute value")) < 0)
+ return (-1);
+ if (htable_locate(hash_table, STR(name_buf)) != 0) {
+ if ((flags & ATTR_FLAG_EXTRA) != 0) {
+ msg_warn("duplicate attribute %s in input from %s",
+ STR(name_buf), VSTREAM_PATH(fp));
+ return (conversions);
+ }
+ } else {
+ htable_enter(hash_table, STR(name_buf),
+ mystrdup(STR(str_buf)));
+ }
+ break;
+ default:
+ msg_panic("%s: unknown type code: %d", myname, wanted_type);
+ }
+ }
+}
+
+/* attr_scan0 - read attribute list from stream */
+
+int attr_scan0(VSTREAM *fp, int flags,...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, flags);
+ ret = attr_vscan0(fp, flags, ap);
+ va_end(ap);
+ return (ret);
+}
+
+#ifdef TEST
+
+ /*
+ * Proof of concept test program. Mirror image of the attr_scan0 test
+ * program.
+ */
+#include <msg_vstream.h>
+
+int var_line_limit = 2048;
+
+int main(int unused_argc, char **used_argv)
+{
+ VSTRING *str_val = vstring_alloc(1);
+ HTABLE *table = htable_create(1);
+ HTABLE_INFO **ht_info_list;
+ HTABLE_INFO **ht;
+ int int_val;
+ long long_val;
+ int ret;
+
+ msg_verbose = 1;
+ msg_vstream_init(used_argv[0], VSTREAM_ERR);
+ if ((ret = attr_scan0(VSTREAM_IN,
+ ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
+ ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+ ATTR_TYPE_HASH, table,
+ ATTR_TYPE_END)) > 3) {
+ vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
+ vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+ ht_info_list = htable_list(table);
+ for (ht = ht_info_list; *ht; ht++)
+ vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
+ myfree((char *) ht_info_list);
+ } else {
+ vstream_printf("return: %d\n", ret);
+ }
+ if ((ret = attr_scan0(VSTREAM_IN,
+ ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
+ ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+ ATTR_TYPE_END)) == 3) {
+ vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
+ vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+ ht_info_list = htable_list(table);
+ for (ht = ht_info_list; *ht; ht++)
+ vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
+ myfree((char *) ht_info_list);
+ } else {
+ vstream_printf("return: %d\n", ret);
+ }
+ if (vstream_fflush(VSTREAM_OUT) != 0)
+ msg_fatal("write error: %m");
+
+ vstring_free(str_val);
+ htable_free(table, myfree);
+
+ return (0);
+}
+
+#endif
--- /dev/null
+./attr_print0: send attr number = 4711
+./attr_print0: send attr long_number = 1234
+./attr_print0: send attr string = whoopee
+./attr_print0: send attr name foo-name value foo-value
+./attr_print0: send attr name bar-name value bar-value
+./attr_print0: send attr number = 4711
+./attr_print0: send attr long_number = 1234
+./attr_print0: send attr string = whoopee
+./attr_scan0: unknown_stream: wanted attribute: number
+./attr_scan0: input attribute name: number
+./attr_scan0: input attribute value: 4711
+./attr_scan0: unknown_stream: wanted attribute: long_number
+./attr_scan0: input attribute name: long_number
+./attr_scan0: input attribute value: 1234
+./attr_scan0: unknown_stream: wanted attribute: string
+./attr_scan0: input attribute name: string
+./attr_scan0: input attribute value: whoopee
+./attr_scan0: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan0: input attribute name: foo-name
+./attr_scan0: input attribute value: foo-value
+./attr_scan0: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan0: input attribute name: bar-name
+./attr_scan0: input attribute value: bar-value
+./attr_scan0: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan0: input attribute name: (end)
+./attr_scan0: unknown_stream: wanted attribute: number
+./attr_scan0: input attribute name: number
+./attr_scan0: input attribute value: 4711
+./attr_scan0: unknown_stream: wanted attribute: long_number
+./attr_scan0: input attribute name: long_number
+./attr_scan0: input attribute value: 1234
+./attr_scan0: unknown_stream: wanted attribute: string
+./attr_scan0: input attribute name: string
+./attr_scan0: input attribute value: whoopee
+./attr_scan0: unknown_stream: wanted attribute: (list terminator)
+./attr_scan0: input attribute name: (end)
+number 4711
+long_number 1234
+string whoopee
+(hash) foo-name foo-value
+(hash) bar-name bar-value
+number 4711
+long_number 1234
+string whoopee
+(hash) foo-name foo-value
+(hash) bar-name bar-value
/*++
/* NAME
-/* attr_scan 3
+/* attr_scan64 3
/* SUMMARY
/* recover attributes from byte stream
/* SYNOPSIS
/* #include <attr.h>
/*
-/* int attr_scan(fp, flags, type, name, ...)
+/* int attr_scan64(fp, flags, type, name, ...)
/* VSTREAM fp;
/* int flags;
/* int type;
/* char *name;
/*
-/* int attr_vscan(fp, flags, ap)
+/* int attr_vscan64(fp, flags, ap)
/* VSTREAM fp;
/* int flags;
/* va_list ap;
/* DESCRIPTION
-/* attr_scan() takes zero or more (name, value) request attributes
+/* attr_scan64() takes zero or more (name, value) request attributes
/* and recovers the attribute values from the byte stream that was
-/* possibly generated by attr_print().
+/* possibly generated by attr_print64().
/*
-/* attr_vscan() provides an alternative interface that is convenient
+/* attr_vscan64() provides an alternative interface that is convenient
/* for calling from within a variadic function.
/*
/* The input stream is formatted as follows, where (item)* stands
/* characters. The formatting rules aim to make implementations in PERL
/* and other languages easy.
/*
-/* Normally, attributes must be received in the sequence as specified with
-/* the attr_scan() argument list. The input stream may contain additional
-/* attributes at any point in the input stream, including additional
+/* Normally, attributes must be received in the sequence as specified with
+/* the attr_scan64() argument list. The input stream may contain additional
+/* attributes at any point in the input stream, including additional
/* instances of requested attributes.
/*
/* Additional input attributes or input attribute instances are silently
/* case of additional instances of a requested attribute.
/* .IP ATTR_FLAG_MORE
/* After recovering the requested attributes, leave the input stream
-/* in a state that is usable for more attr_scan() operations from the
+/* in a state that is usable for more attr_scan64() operations from the
/* same input attribute list.
-/* By default, attr_scan() skips forward past the input attribute list
+/* By default, attr_scan64() skips forward past the input attribute list
/* terminator.
/* .IP ATTR_FLAG_STRICT
/* For convenience, this value combines both ATTR_FLAG_MISSING and
/* .RS
/* .IP "ATTR_TYPE_NUM (char *, int *)"
/* This argument is followed by an attribute name and an integer pointer.
+/* .IP "ATTR_TYPE_LONG (char *, long *)"
+/* This argument is followed by an attribute name and a long pointer.
/* .IP "ATTR_TYPE_STR (char *, VSTRING *)"
/* This argument is followed by an attribute name and a VSTRING pointer.
/* .IP "ATTR_TYPE_HASH (HTABLE *)"
/* untrusted sources. This is unsafe, unless the resulting table is
/* queried only with known to be good attribute names.
/* DIAGNOSTICS
-/* attr_scan() and attr_vscan() return -1 when malformed input is
+/* attr_scan64() and attr_vscan64() return -1 when malformed input is
/* detected (string too long, incomplete line, missing end marker).
/* Otherwise, the result value is the number of attributes that were
/* successfully recovered from the input stream (a hash table counts
/*
/* Panic: interface violation. All system call errors are fatal.
/* SEE ALSO
-/* attr_print(3) send attributes over byte stream.
+/* attr_print64(3) send attributes over byte stream.
/* LICENSE
/* .ad
/* .fi
#define STR(x) vstring_str(x)
#define LEN(x) VSTRING_LEN(x)
-/* attr_scan_string - pull a string from the input stream */
+/* attr_scan64_string - pull a string from the input stream */
-static int attr_scan_string(VSTREAM *fp, VSTRING *plain_buf, const char *context)
+static int attr_scan64_string(VSTREAM *fp, VSTRING *plain_buf, const char *context)
{
static VSTRING *base64_buf = 0;
extern int var_line_limit; /* XXX */
return (ch);
}
-/* attr_scan_number - pull a number from the input stream */
+/* attr_scan64_number - pull a number from the input stream */
-static int attr_scan_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf,
- const char *context)
+static int attr_scan64_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf,
+ const char *context)
{
char junk = 0;
int ch;
- if ((ch = attr_scan_string(fp, str_buf, context)) < 0)
+ if ((ch = attr_scan64_string(fp, str_buf, context)) < 0)
return (-1);
if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) {
msg_warn("malformed numerical data from %s while reading %s: %.100s",
return (ch);
}
-/* attr_vscan - receive attribute list from stream */
+/* attr_scan64_long_number - pull a number from the input stream */
-int attr_vscan(VSTREAM *fp, int flags, va_list ap)
+static int attr_scan64_long_number(VSTREAM *fp, unsigned long *ptr,
+ VSTRING *str_buf,
+ const char *context)
{
- const char *myname = "attr_scan";
+ char junk = 0;
+ int ch;
+
+ if ((ch = attr_scan64_string(fp, str_buf, context)) < 0)
+ return (-1);
+ if (sscanf(STR(str_buf), "%lu%c", ptr, &junk) != 1 || junk != 0) {
+ msg_warn("malformed numerical data from %s while reading %s: %.100s",
+ VSTREAM_PATH(fp), context, STR(str_buf));
+ return (-1);
+ }
+ return (ch);
+}
+
+/* attr_vscan64 - receive attribute list from stream */
+
+int attr_vscan64(VSTREAM *fp, int flags, va_list ap)
+{
+ const char *myname = "attr_scan64";
static VSTRING *str_buf = 0;
static VSTRING *name_buf = 0;
int wanted_type = -1;
char *wanted_name;
unsigned int *number;
+ unsigned long *long_number;
VSTRING *string;
HTABLE *hash_table;
int ch;
if (msg_verbose)
msg_info("%s: wanted attribute: %s",
VSTREAM_PATH(fp), wanted_name);
- if ((ch = attr_scan_string(fp, name_buf,
+ if ((ch = attr_scan64_string(fp, name_buf,
"input attribute name")) == VSTREAM_EOF)
return (-1);
if (ch == '\n' && LEN(name_buf) == 0) {
return (-1);
}
number = va_arg(ap, unsigned int *);
- if ((ch = attr_scan_number(fp, number, str_buf,
- "input attribute value")) < 0)
+ if ((ch = attr_scan64_number(fp, number, str_buf,
+ "input attribute value")) < 0)
+ return (-1);
+ if (ch != '\n') {
+ msg_warn("multiple values for attribute %s from %s",
+ STR(name_buf), VSTREAM_PATH(fp));
+ return (-1);
+ }
+ break;
+ case ATTR_TYPE_LONG:
+ if (ch != ':') {
+ msg_warn("missing value for number attribute %s from %s",
+ STR(name_buf), VSTREAM_PATH(fp));
+ return (-1);
+ }
+ long_number = va_arg(ap, unsigned long *);
+ if ((ch = attr_scan64_long_number(fp, long_number, str_buf,
+ "input attribute value")) < 0)
return (-1);
if (ch != '\n') {
msg_warn("multiple values for attribute %s from %s",
return (-1);
}
string = va_arg(ap, VSTRING *);
- if ((ch = attr_scan_string(fp, string,
- "input attribute value")) < 0)
+ if ((ch = attr_scan64_string(fp, string,
+ "input attribute value")) < 0)
return (-1);
if (ch != '\n') {
msg_warn("multiple values for attribute %s from %s",
STR(name_buf), VSTREAM_PATH(fp));
return (-1);
}
- if ((ch = attr_scan_string(fp, str_buf,
- "input attribute value")) < 0)
+ if ((ch = attr_scan64_string(fp, str_buf,
+ "input attribute value")) < 0)
return (-1);
if (ch != '\n') {
msg_warn("multiple values for attribute %s from %s",
}
}
-/* attr_scan - read attribute list from stream */
+/* attr_scan64 - read attribute list from stream */
-int attr_scan(VSTREAM *fp, int flags,...)
+int attr_scan64(VSTREAM *fp, int flags,...)
{
va_list ap;
int ret;
va_start(ap, flags);
- ret = attr_vscan(fp, flags, ap);
+ ret = attr_vscan64(fp, flags, ap);
va_end(ap);
return (ret);
}
#ifdef TEST
/*
- * Proof of concept test program. Mirror image of the attr_scan test
+ * Proof of concept test program. Mirror image of the attr_scan64 test
* program.
*/
#include <msg_vstream.h>
HTABLE_INFO **ht_info_list;
HTABLE_INFO **ht;
int int_val;
+ long long_val;
int ret;
msg_verbose = 1;
msg_vstream_init(used_argv[0], VSTREAM_ERR);
- if ((ret = attr_scan(VSTREAM_IN,
- ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
- ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
- ATTR_TYPE_HASH, table,
- ATTR_TYPE_END)) > 2) {
+ if ((ret = attr_scan64(VSTREAM_IN,
+ ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
+ ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+ ATTR_TYPE_HASH, table,
+ ATTR_TYPE_END)) > 3) {
vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
ht_info_list = htable_list(table);
for (ht = ht_info_list; *ht; ht++)
} else {
vstream_printf("return: %d\n", ret);
}
- if ((ret = attr_scan(VSTREAM_IN,
- ATTR_FLAG_STRICT,
- ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
- ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
- ATTR_TYPE_END)) == 2) {
+ if ((ret = attr_scan64(VSTREAM_IN,
+ ATTR_FLAG_STRICT,
+ ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
+ ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
+ ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+ ATTR_TYPE_END)) == 3) {
vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
+ vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
ht_info_list = htable_list(table);
for (ht = ht_info_list; *ht; ht++)
--- /dev/null
+./attr_print64: send attr number = 4711
+./attr_print64: send attr long_number = 1234
+./attr_print64: send attr string = whoopee
+./attr_print64: send attr name foo-name value foo-value
+./attr_print64: send attr name bar-name value bar-value
+./attr_print64: send attr number = 4711
+./attr_print64: send attr long_number = 1234
+./attr_print64: send attr string = whoopee
+./attr_scan64: unknown_stream: wanted attribute: number
+./attr_scan64: input attribute name: number
+./attr_scan64: input attribute value: 4711
+./attr_scan64: unknown_stream: wanted attribute: long_number
+./attr_scan64: input attribute name: long_number
+./attr_scan64: input attribute value: 1234
+./attr_scan64: unknown_stream: wanted attribute: string
+./attr_scan64: input attribute name: string
+./attr_scan64: input attribute value: whoopee
+./attr_scan64: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan64: input attribute name: foo-name
+./attr_scan64: input attribute value: foo-value
+./attr_scan64: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan64: input attribute name: bar-name
+./attr_scan64: input attribute value: bar-value
+./attr_scan64: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan64: input attribute name: (end)
+./attr_scan64: unknown_stream: wanted attribute: number
+./attr_scan64: input attribute name: number
+./attr_scan64: input attribute value: 4711
+./attr_scan64: unknown_stream: wanted attribute: long_number
+./attr_scan64: input attribute name: long_number
+./attr_scan64: input attribute value: 1234
+./attr_scan64: unknown_stream: wanted attribute: string
+./attr_scan64: input attribute name: string
+./attr_scan64: input attribute value: whoopee
+./attr_scan64: unknown_stream: wanted attribute: (list terminator)
+./attr_scan64: input attribute name: (end)
+number 4711
+long_number 1234
+string whoopee
+(hash) foo-name foo-value
+(hash) bar-name bar-value
+number 4711
+long_number 1234
+string whoopee
+(hash) foo-name foo-value
+(hash) bar-name bar-value
msg_warn("%s: connect to %s: %m", myname, service);
return (-1);
}
+ close_on_exec(fd, CLOSE_ON_EXEC);
ip = (struct inet_trigger *) mymalloc(sizeof(*ip));
ip->fd = fd;
ip->service = mystrdup(service);
extern void doze(unsigned);
extern void rand_sleep(unsigned, unsigned);
extern int duplex_pipe(int *);
+extern int sock_empty_wait(int, int);
+extern int sock_maximize_send_lowat(int);
+extern void sock_set_send_lowat(int, int);
#define BLOCKING 0
#define NON_BLOCKING 1
int saved_ch;
struct stat st;
int ret;
- mode_t saved_mode;
+ mode_t saved_mode = 0;
/*
* Initialize. Make a copy of the path that we can safely clobber.
/* SYNOPSIS
/* #include <match_list.h>
/*
-/* MATCH_LIST *match_list_init(pattern_list, count, func,...)
+/* MATCH_LIST *match_list_init(flags, pattern_list, count, func,...)
+/* int flags;
/* const char *pattern_list;
/* int count;
-/* int (*func)(const char *string, const char *pattern);
+/* int (*func)(int flags, const char *string, const char *pattern);
/*
/* int match_list_match(list, string,...)
/* MATCH_LIST *list;
/* a pattern match, precede a non-file name pattern with an
/* exclamation point (!).
/*
-/* match_list_init() performs initializations. The first argument is
-/* a list of patterns. The second argument specifies how many match
-/* functions follow.
+/* match_list_init() performs initializations. The flags argument
+/* specifies the bit-wise OR of zero or more of the following:
+/* .RS
+/* .IP MATCH_FLAG_PARENT
+/* The hostname pattern foo.com matches any name within the domain
+/* foo.com. If this flag is cleared, foo.com matches itself
+/* only, and .foo.com matches any name below the domain foo.com.
+/* .RE
+/* Specify MATCH_FLAG_NONE to request none of the above.
+/* The pattern_list argument specifies a list of patterns. The third
+/* argument specifies how many match functions follow.
/*
/* match_list_match() matches strings against the specified pattern
/* list, passing the first string to the first function given to
#include <stringops.h>
#include <argv.h>
#include <dict.h>
+#include <match_ops.h>
#include <match_list.h>
/* Application-specific */
struct MATCH_LIST {
+ int flags; /* processing options */
ARGV *patterns; /* one pattern each */
int match_count; /* match function/argument count */
MATCH_LIST_FN *match_func; /* match functions */
/* match_list_init - initialize pattern list */
-MATCH_LIST *match_list_init(const char *patterns, int match_count,...)
+MATCH_LIST *match_list_init(int flags, const char *patterns, int match_count,...)
{
MATCH_LIST *list;
char *saved_patterns;
va_list ap;
int i;
+ if (flags & ~MATCH_FLAG_ALL)
+ msg_panic("match_list_init: bad flags 0x%x", flags);
+
list = (MATCH_LIST *) mymalloc(sizeof(*list));
+ list->flags = flags;
list->match_count = match_count;
list->match_func =
(MATCH_LIST_FN *) mymalloc(match_count * sizeof(MATCH_LIST_FN));
for (match = 1; *pat == '!'; pat++)
match = !match;
for (i = 0; i < list->match_count; i++)
- if (list->match_func[i] (list->match_args[i], pat) != 0)
+ if (list->match_func[i] (list->flags, list->match_args[i], pat))
return (match);
}
if (msg_verbose)
* External interface.
*/
typedef struct MATCH_LIST MATCH_LIST;
-typedef int (*MATCH_LIST_FN) (const char *, const char *);
+typedef int (*MATCH_LIST_FN) (int, const char *, const char *);
-extern MATCH_LIST *match_list_init(const char *, int,...);
+extern MATCH_LIST *match_list_init(int, const char *, int,...);
extern int match_list_match(MATCH_LIST *,...);
extern void match_list_free(MATCH_LIST *);
/* SYNOPSIS
/* #include <match_ops.h>
/*
-/* int match_string(string, pattern)
+/* int match_string(flags, string, pattern)
+/* int flags;
/* const char *string;
/* const char *pattern;
/*
-/* int match_hostname(name, pattern)
+/* int match_hostname(flags, name, pattern)
+/* int flags;
/* const char *name;
/* const char *pattern;
/*
-/* int match_hostaddr(addr, pattern)
+/* int match_hostaddr(flags, addr, pattern)
+/* int flags;
/* const char *addr;
/* const char *pattern;
/* DESCRIPTION
/* or address comparison.
/*
/* match_string() matches the string against the pattern, requiring
-/* an exact (case-insensitive) match.
+/* an exact (case-insensitive) match. The flags argument is not used.
/*
/* match_hostname() matches the host name when the hostname matches
/* the pattern exactly, or when the pattern matches a parent domain
-/* of the named host.
+/* of the named host. The flags argument specifies the bit-wise OR
+/* of zero or more of the following:
+/* .IP MATCH_FLAG_PARENT
+/* The hostname pattern foo.com matches itself and any name below
+/* the domain foo.com. If this flag is cleared, foo.com matches itself
+/* only, and .foo.com matches any name below the domain foo.com.
+/* .RE
+/* Specify MATCH_FLAG_NONE to request none of the above.
/*
/* match_hostaddr() matches a host address when the pattern is
/* identical to the host address, or when the pattern is a net/mask
/* that contains the address. The mask specifies the number of
-/* bits in the network part of the pattern.
+/* bits in the network part of the pattern. The flags argument is
+/* not used.
/* LICENSE
/* .ad
/* .fi
/* match_string - match a string literal */
-int match_string(const char *string, const char *pattern)
+int match_string(int unused_flags, const char *string, const char *pattern)
{
char *myname = "match_string";
int match;
/* match_hostname - match a host by name */
-int match_hostname(const char *name, const char *pattern)
+int match_hostname(int flags, const char *name, const char *pattern)
{
char *myname = "match_hostname";
const char *pd;
if (strchr(pattern, ':') != 0) {
temp = lowercase(mystrdup(name));
match = 0;
- for (entry = temp; /* void */ ; entry = next + 1) {
+ for (entry = temp; /* void */ ; entry = next) {
if ((match = (dict_lookup(pattern, entry) != 0)) != 0)
break;
if (dict_errno != 0)
msg_fatal("%s: table lookup problem", pattern);
- if ((next = strchr(entry, '.')) == 0)
+ if ((next = strchr(entry + 1, '.')) == 0)
break;
+ if (flags & MATCH_FLAG_PARENT)
+ next += 1;
}
myfree(temp);
return (match);
* See if the pattern is a parent domain of the hostname.
*/
else {
- pd = name + strlen(name) - strlen(pattern);
- if (pd > name && pd[-1] == '.' && strcasecmp(pd, pattern) == 0)
- return (1);
+ if (flags & MATCH_FLAG_PARENT) {
+ pd = name + strlen(name) - strlen(pattern);
+ if (pd > name && pd[-1] == '.' && strcasecmp(pd, pattern) == 0)
+ return (1);
+ } else if (pattern[0] == '.') {
+ pd = name + strlen(name) - strlen(pattern);
+ if (pd > name && strcasecmp(pd, pattern) == 0)
+ return (1);
+ }
}
return (0);
}
/* match_hostaddr - match host by address */
-int match_hostaddr(const char *addr, const char *pattern)
+int match_hostaddr(int unused_flags, const char *addr, const char *pattern)
{
char *myname = "match_hostaddr";
int mask_shift;
/* External interface. */
-extern int match_string(const char *, const char *);
-extern int match_hostname(const char *, const char *);
-extern int match_hostaddr(const char *, const char *);
+#define MATCH_FLAG_NONE 0
+#define MATCH_FLAG_PARENT (1<<0)
+#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT)
+
+extern int match_string(int, const char *, const char *);
+extern int match_hostname(int, const char *, const char *);
+extern int match_hostaddr(int, const char *, const char *);
/* LICENSE
/* .ad
--- /dev/null
+/*++
+/* NAME
+/* sock_empty_wait 3
+/* SUMMARY
+/* wait until socket send buffer is near empty
+/* SYNOPSIS
+/* #include <iostuff.h>
+/*
+/* int sock_empty_wait(fd, timeout)
+/* int fd;
+/* int timeout;
+/* AUXILIARY ROUTINES
+/* int sock_maximize_send_lowat(fd)
+/* int fd;
+/*
+/* void sock_set_send_lowat(fd, send_lowat)
+/* int fd;
+/* int send_lowat;
+/* DESCRIPTION
+/* sock_empty_wait() blocks the process until the specified socket's
+/* send buffer is near empty, in the hope that the contents of the
+/* next write() operation will not be merged with preceding data.
+/*
+/* sock_maximize_send_lowat() maximizes the socket send buffer
+/* low-water mark, which controls how much free buffer space must
+/* be available before the socket is considered writable.
+/* The result value is the old low-water mark value.
+/*
+/* sock_set_send_lowat() sets the socket send buffer low-water mark
+/* to the specified value.
+/*
+/* Arguments:
+/* .IP fd
+/* File descriptor in the range 0..FD_SETSIZE.
+/* .IP timeout
+/* If positive, deadline in seconds. A zero value effects a poll.
+/* A negative value means wait until something happens.
+/* DIAGNOSTICS
+/* sock_maximize_send_lowat() returns -1 if the kernel does not
+/* support access to or control over the send buffer low-water mark.
+/* Otherwise, all system call errors are fatal.
+/*
+/* A zero result means success. When the specified deadline is
+/* exceeded, sock_empty_wait() returns -1 and sets errno to ETIMEDOUT.
+/* BUGS
+/* Linux and Solaris do not provide the necessary support. Until
+/* they become better citizens they are punished by having to sleep
+/* for 10 seconds, and even then there is no reasonable way to find
+/* out if all the written data was acknowledged by the remote TCP.
+/* 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 <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <iostuff.h>
+
+/* sock_maximize_send_lowat - maximize the send buffer low-water mark */
+
+int sock_maximize_send_lowat(int fd)
+{
+ char *myname = "sock_maximize_send_lowat";
+ int send_buffer_size;
+ int saved_low_water_mark;
+ int want_low_water_mark;
+ int got_low_water_mark;
+ SOCKOPT_SIZE optlen;
+
+ /*
+ * Get the send buffer size. If this succeeds then we know the file
+ * handle is a socket.
+ */
+ optlen = sizeof(send_buffer_size);
+ if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF,
+ (char *) &send_buffer_size, &optlen) < 0)
+ msg_fatal("%s: getsockopt SO_SNDBUF: %m", myname);
+
+ /*
+ * Save the send buffer low-water mark. XXX Solaris 8 does not support
+ * this operation.
+ */
+ optlen = sizeof(saved_low_water_mark);
+ if (getsockopt(fd, SOL_SOCKET, SO_SNDLOWAT,
+ (char *) &saved_low_water_mark, &optlen) < 0) {
+ if (msg_verbose)
+ msg_info("%s: getsockopt SO_SNDLOWAT: %m", myname);
+ return (-1);
+ }
+
+ /*
+ * Max out the send buffer low-water mark. XXX Linux 2.4.14 does not
+ * support this operation.
+ */
+ want_low_water_mark = send_buffer_size;
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT,
+ (char *) &want_low_water_mark,
+ sizeof(want_low_water_mark)) < 0) {
+ if (msg_verbose)
+ msg_info("%s: setsockopt SO_SNDLOWAT: %m", myname);
+ return (-1);
+ }
+
+ /*
+ * Make sure the kernel did not cheat.
+ */
+ optlen = sizeof(got_low_water_mark);
+ if (getsockopt(fd, SOL_SOCKET, SO_SNDLOWAT,
+ (char *) &got_low_water_mark, &optlen) < 0)
+ msg_fatal("%s: getsockopt SO_SNDLOWAT: %m", myname);
+ if (got_low_water_mark == 1)
+ return (-1);
+
+ /*
+ * Make debugging a bit easier.
+ */
+ if (msg_verbose) {
+ msg_info("%s: send buffer %d, low-water mark was %d, wanted %d, got %d",
+ myname, send_buffer_size, saved_low_water_mark,
+ want_low_water_mark, got_low_water_mark);
+
+ }
+ return (saved_low_water_mark);
+}
+
+/* sock_set_send_lowat - restore socket send buffer low-water mark */
+
+void sock_set_send_lowat(int fd, int want_low_water_mark)
+{
+ char *myname = "sock_set_send_lowat";
+ int got_low_water_mark;
+ SOCKOPT_SIZE optlen;
+
+ /*
+ * Set the send buffer low-water mark.
+ */
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDLOWAT,
+ (char *) &want_low_water_mark,
+ sizeof(want_low_water_mark)) < 0)
+ msg_fatal("%s: setsockopt SO_SNDLOWAT: %m", myname);
+
+ /*
+ * Make debugging a bit easier.
+ */
+ if (msg_verbose) {
+ optlen = sizeof(got_low_water_mark);
+ if (getsockopt(fd, SOL_SOCKET, SO_SNDLOWAT,
+ (char *) &got_low_water_mark, &optlen) < 0)
+ msg_fatal("%s: getsockopt SO_SNDLOWAT: %m", myname);
+ msg_info("%s: low-water mark wanted %d, got %d",
+ myname, want_low_water_mark, got_low_water_mark);
+ }
+}
+
+/* sock_empty_wait - wait until socket send buffer is near empty */
+
+int sock_empty_wait(int fd, int timeout)
+{
+ int saved_errno;
+ int saved_low_water_mark;
+ int result;
+
+ /*
+ * Max out the send buffer low-water mark.
+ */
+ saved_low_water_mark = sock_maximize_send_lowat(fd);
+
+ /*
+ * Wait until the socket is considered writable.
+ */
+ result = write_wait(fd, timeout);
+
+ /*
+ * Work around systems that have no functional SO_SNDLOWAT control.
+ */
+ if (result == 0 && saved_low_water_mark <= 0)
+ sleep(10);
+
+ /*
+ * Restore the send buffer low-water mark.
+ */
+ if (saved_low_water_mark > 0) {
+ saved_errno = errno;
+ sock_set_send_lowat(fd, saved_low_water_mark);
+ errno = saved_errno;
+ }
+
+ /*
+ * Done.
+ */
+ return (result);
+}
msg_warn("%s: connect to %s: %m", myname, service);
return (-1);
}
+ close_on_exec(fd, CLOSE_ON_EXEC);
/*
* Stash away context.
msg_warn("%s: connect to %s: %m", myname, service);
return (-1);
}
+ close_on_exec(fd, CLOSE_ON_EXEC);
/*
* Stash away context.
/* VSTRING *vp;
/* VSTREAM *fp;
/* int bound;
+/*
+/* int vstring_get_null_bound(vp, fp, bound)
+/* VSTRING *vp;
+/* VSTREAM *fp;
+/* int bound;
/* DESCRIPTION
/* The routines in this module each read one newline or null-terminated
/* string from an input stream. In all cases the result is either the
/* vstring_get_null() reads a null-terminated string from the named
/* stream.
/*
-/* vstring_get_bound() and vstring_get_nonl_bound() read no more
+/* the vstring_get<whatever>_bound() routines read no more
/* than \fIbound\fR characters. Otherwise they behave like the
/* unbounded versions documented above.
/* DIAGNOSTICS
return (c == '\n' ? c : VSTRING_GET_RESULT(vp));
}
+/* vstring_get_null_bound - read null-terminated string from file */
+
+int vstring_get_null_bound(VSTRING *vp, VSTREAM *fp, int bound)
+{
+ int c;
+
+ if (bound <= 0)
+ msg_panic("vstring_get_nonl_bound: invalid bound %d", bound);
+
+ VSTRING_RESET(vp);
+ while (bound-- > 0 && (c = VSTREAM_GETC(fp)) != VSTREAM_EOF && c != 0)
+ VSTRING_ADDCH(vp, c);
+ VSTRING_TERMINATE(vp);
+ return (c == 0 ? c : VSTRING_GET_RESULT(vp));
+}
+
#ifdef TEST
/*
extern int vstring_get_null(VSTRING *, VSTREAM *);
extern int vstring_get_bound(VSTRING *, VSTREAM *, int);
extern int vstring_get_nonl_bound(VSTRING *, VSTREAM *, int);
+extern int vstring_get_null_bound(VSTRING *, VSTREAM *, int);
/*
* Backwards compatibility for code that still uses the vstring_fgets()
/* numerical user ID values that may be specified in any
/* \fBvirtual_owner_maps\fR or \fBvirtual_uid_maps\fR.
/* SECURITY
+/* .ad
+/* .fi
/* The virtual delivery agent is not security sensitive, provided
-/* that the lookup tables with recipient information are adequately
-/* protected. This program is not designed to run chrooted.
+/* that the lookup tables with recipient user/group ID information are
+/* adequately protected. This program is not designed to run chrooted.
/* STANDARDS
/* RFC 822 (ARPA Internet Text Messages)
/* DIAGNOSTICS
/* This setting is ignored with \fBmaildir\fR style delivery,
/* because such deliveries are safe without explicit locks.
/*
-/* Use the command \fBpostconf -m\fR to find out what locking methods
+/* Use the command \fBpostconf -l\fR to find out what locking methods
/* are available on your system.
/* .IP \fBdeliver_lock_attempts\fR
/* Limit the number of attempts to acquire an exclusive lock