diff options
| author | perry <perry@NetBSD.org> | 2002-02-02 23:10:24 +0000 |
|---|---|---|
| committer | perry <perry@NetBSD.org> | 2002-02-02 23:10:24 +0000 |
| commit | 6f59dc7aebbf705da79e61ef3fd24b48ed99d327 (patch) | |
| tree | c6e9fd356c8aac78b966a9dd53f5d0d14d5e62cd /gnu | |
| parent | ecf43984517b4cfb837e78958769cc8207ea5288 (diff) | |
Postfix 1.1.2
(Postfix releases are now numbered -- 1.1.2 means 1.1, patchlevel 2.)
Lots of new features, same great security.
Diffstat (limited to 'gnu')
432 files changed, 29125 insertions, 4952 deletions
diff --git a/gnu/dist/postfix/.indent.pro b/gnu/dist/postfix/.indent.pro index c35b4962ff8..64dbb3f5e4a 100644 --- a/gnu/dist/postfix/.indent.pro +++ b/gnu/dist/postfix/.indent.pro @@ -1,5 +1,7 @@ +-TABOUNCE -TALIAS_TOKEN -TARGV +-TATTR_TABLE -TBH_TABLE -TBINATTR -TBINATTR_INFO @@ -19,15 +21,17 @@ -TCONFIG_STR_TABLE -TCONFIG_TIME_FN_TABLE -TCONFIG_TIME_TABLE +-TCTABLE +-TCTABLE_ENTRY -TDELIVER_ATTR -TDELIVER_REQUEST -TDICT -TDICT_DB -TDICT_DBM +-TDICT_DEBUG -TDICT_ENV -TDICT_HT -TDICT_LDAP --TDICT_DEBUG -TDICT_MYSQL -TDICT_NI -TDICT_NIS @@ -51,6 +55,7 @@ -THTABLE -THTABLE_INFO -TINET_ADDR_LIST +-TINTV -TINT_TABLE -TJMP_BUF_WRAPPER -TLMTP_ATTR @@ -93,11 +98,13 @@ -TQMGR_RECIPIENT -TQMGR_SCAN -TQMGR_TRANSPORT +-TQMQPD_STATE -TRECIPIENT -TRECIPIENT_LIST -TREC_TYPE_NAME -TRESOLVE_REPLY -TRESPONSE +-TREST_TABLE -TSCAN_DIR -TSCAN_INFO -TSCAN_OBJ diff --git a/gnu/dist/postfix/0README b/gnu/dist/postfix/0README index 8538cebe205..0b13f9ca3d2 100644 --- a/gnu/dist/postfix/0README +++ b/gnu/dist/postfix/0README @@ -103,6 +103,7 @@ wietse@porcupine.org to avoid duplication of effort. Documentation: + README_FILES/ Instructions for specific Postfix features html/ HTML format man/ UNIX on-line manual page format @@ -127,6 +128,7 @@ Command-line utilities: src/postlock/ Postfix locking for shell scripts src/postlog/ Postfix logging for shell scripts src/postmap/ Postfix lookup table management + src/postqueue/ Postfix queue control program src/postsuper/ Postfix house keeping program src/sendmail/ Sendmail compatibility interface @@ -151,7 +153,7 @@ Postfix daemons: Test programs: src/fsstone/ Measure file system overhead - src/smtpstone/ SMTP server torture test + src/smtpstone/ SMTP and QMQP server torture test Miscellaneous: diff --git a/gnu/dist/postfix/COMPATIBILITY b/gnu/dist/postfix/COMPATIBILITY index bb754a363b1..e9a27b111c0 100644 --- a/gnu/dist/postfix/COMPATIBILITY +++ b/gnu/dist/postfix/COMPATIBILITY @@ -7,10 +7,10 @@ aliases yes (can enable/disable mail to /file or |command) bare newlines yes (but will send CRLF) blacklisting yes (client name/addr; helo hostname; mail from; rcpt to) -content filter yes +content filter yes (see FILTER_README) db tables yes (compile time option) dbm tables yes (compile time option) -delivered-to yes +delivered-to yes (configurable with prepend_delivered_header) dsn not yet (bounces have DSN form) errors-to: yes esmtp yes @@ -20,40 +20,42 @@ flock locking yes (runtime configurable) home mailbox yes ident lookup no ldap tables yes (contributed) -luser relay yes lmtp support yes (client) +luser relay yes m4 config no mail to command yes (configurable for .forward, aliases, :include:) mail to file yes (configurable for .forward, aliases, :include:) -maildir yes (with procmail) +maildir yes (in home, system mailspool, /file/name/ alias) mailertable yes (it's called transport) mailq yes majordomo yes (edit approve script to delete /delivered-to/i) mime conversion not yet; postfix uses just-send-eight -missing <> yes (most common address forms) mysql tables yes (contributed) netinfo tables yes (contributed) newaliases yes (main alias database only) nis tables yes nis+ tables not yet +no <> in smtp yes (most common address forms) pipeline option yes (server and client) pop/imap yes (with third-party daemons that use /var[/spool]/mail) +qmqp server yes (with verp support) rbl support yes return-receipt: not yet sasl support yes (compile time option) sendmail -bt no sendmail -q yes -sendmail -qRxxx yes +sendmail -qRxxx yes (for domains specified in fast_flush_domains) sendmail -qSxxx no sendmail -qtime ignored -sendmail -v no +sendmail -v yes (but does not show delivery) sendmail.cf no (uses table-driven address rewriting) size option yes, server and client -smarthost yes +smarthost yes (specify relayhost in main.cf) tcp wrapper no (use built-in blacklist facility) user+extension yes (also: .forward+extension) user-extension yes (also: .forward-extension) user.lock yes (runtime configurable) uucp support yes (sends user@domain recipients) -virtual domains yes +verp support yes (delimiters are configurable) +virtual domains yes (via local delivery agent and via dedicated delivery agent) year 2000 safe yes diff --git a/gnu/dist/postfix/HISTORY b/gnu/dist/postfix/HISTORY index ba04c758675..47ecf43a52c 100644 --- a/gnu/dist/postfix/HISTORY +++ b/gnu/dist/postfix/HISTORY @@ -1616,7 +1616,7 @@ Apologies for any names omitted. wrong place. Problem tackled with help of Chip Christian. Portability: reportedly, Solaris 2.5.1 can hang waiting - for a UNIX-domain connection to be accepted, to it gets + for a UNIX-domain connection to be accepted, so it gets the same workaround that was designed for LINUX. Problem reported by Scott Cotton. @@ -3987,6 +3987,13 @@ Apologies for any names omitted. Bugfix: the code for masquerade_exceptions was case sensitive. Reported by Eduard Vopicka. File: cleanup/cleanup_masquerade.c. +20000526 + + Feature: experimental queue manager by Patrik Rak with a + fancy pre-emptive scheduling algorithm that improves delivery + performance of mail with few recipients. This queue manager + is made available as "nqmgr". + 20000528 Feature: the SMTP client SASL password file can contain @@ -4019,6 +4026,9 @@ Apologies for any names omitted. Added a simple shell-script based content filtering example to the FILTER_README file. + Content filtering support for nqmgr by Patrik Rak. File: + nqmgr/qmgr_message.c. + Renamed "content inspection" etc. to "content filtering" in anticipation of a new hook for content inspection that only inspects mail without re-injecting it into Postfix. @@ -4251,6 +4261,9 @@ Apologies for any names omitted. 20000922 + nqmgr update from Patrik Rak for the changed queue manager + to delivery agent protocol. + Lame feature: syslog_facility parameter to control where syslogd sends Postfix logging (default: syslog_facility = mail). However, errors during command-line parsing are @@ -4462,6 +4475,11 @@ Apologies for any names omitted. Bugfix: the recipient home directory test broke mailbox_transport support for non-UNIX recipients. File: local/recipient.c. +20001117 + + Robustness: additional integrity tests for the nqmgr by + Patrik Rak. File: nqmgr/qmgr_message.c. + 20001118 Bugfix: the new LDAP client code did not work properly if @@ -4767,8 +4785,24 @@ Apologies for any names omitted. and documentation by LaMont Jones. Files: LDAP_README, conf/sample-ldap.cf, util/dict_ldap.c. + Update: merged in the virtual delivery agent by Andrew + McNamara. See VIRTUAL_README for detailed examples. + + Update: merged a re-vamped nqmgr by Patrik Rak. + 20010129 + Tweak: several little nqmgr tweaks by Patrik Rak. Files: + global/mail_params.h, nqmgr/qmgr_job.c. + + Bugfix: the virtual delivery agent did not save maps_find() + results timely. J?rgen Thomsen, postfix.jth.net. File: + virtual/mailbox.c. + + Security: disallow regexp tables in the virtual delivery + agent. The $1 etc. substitution mechanism gives too much + power to the sender. File: virtual/mailbox.c. + Cleanup: clarified documentation and boundary cases in the random_sleep() routine. @@ -4802,6 +4836,10 @@ Apologies for any names omitted. Bugfix: another missing initialization in the mysql client. File: util/dict_mysql.c. + Sanitized time routine by Patrik Rak, to make his nqmgr + robust against people who set their clock back. Files: + util/sane_time.[hc]. + Bumped the default mailbox file size limits to 50MB. 20010202 @@ -4818,6 +4856,9 @@ Apologies for any names omitted. 20010203 + Update: null candidate patch from Patrik Rak. Files: + nqmgr/qmgr_entry.c nqmgr/qmgr_job.c nqmgr/qmgr_message.c. + Cleanup: added one gruesome command to the postlink script for hyperlinking nroff manual page output. Word abbreviation broke some <a href...> </a> instances across line boundaries. @@ -4920,6 +4961,18 @@ Apologies for any names omitted. moved, after the code cleanup of the recipient/concurrency limit handling. Patrik Rak. Files: *qmgr/qmgr_message.c. +20010301 + + Feature: configurable name in syslog output (default: + "syslog_name = postfix") so that different Postfix instances + can be recognized by their logging. File: global/mail_task.c. + +20010313 + + Workaround for logic mismatch in nqmgr that was exposed + with the introduction of the asynchronous bounce client. + Patrik Rak. + 20010313 Bugfix: the RFC 822 untokenizer quoted newlines inside @@ -4970,15 +5023,24 @@ Apologies for any names omitted. dict_ldap.c. This module should move to the global directory, because it depends on Postfix main.cf parameter information. + Workaround: after sending a trigger message over a socket, + do not immediately close the client side, but close it from + a background thread that waits until the server closes the + socket first. This avoids trouble with socket implementations + that destroy a socket when the client closes a socket + before the server has received the client's data. Files: + util/{inet,unix,stream}_trigger.c, util/events.c, + master/master_trigger.c, postkick/postkick.c. + 20010403 Workaround: the mysql library can return null pointers - rather than zero-length strings. + rather than zero-length strings. File: util/dict_mysql.c. 20010404 Ergonomics: log additional information about the reason - why "mail for XXX loops back to myself", when the local + why "mail for XXX loops back to myself" when the local machine is the best MX host. File: smtp/smtp_addr.c. 20010406 @@ -5006,6 +5068,11 @@ Apologies for any names omitted. 20010414 + Feature: specify a key of "-" to the postmap or postalias + -q or -d option, and the keys will be read from standard + input, one key per line. Files: postmap/postmap.c, + postalias/postalias.c. + Bugfix: with a non-default inet_interfaces setting, the master ignored host information in master.cf host:port settings. Fix by Jun-ichiro itojun Hagino @ iijlab.net. @@ -5025,6 +5092,14 @@ Apologies for any names omitted. mysql server was unavailable. Remotely based on a fix by Robert Kiessling @ de.easynet.net. File: smtpd/smtpd_check.c. +20010429 + + Feature: the Postfix SMTP client now by default randomly + shuffles destination IP addresses of equal preference. + Specify "smtp_randomize_addresses = no" to disable. + Shuffling code by Elias Levy @ SecurityFocus.com Files: + dns/dns_rr.c, smtp/smtp_addr.c. + 20010501 Bugfix: The SMTP server's 550 in reply to DATA should be @@ -5037,22 +5112,105 @@ Apologies for any names omitted. Bugfix: mailq output is now really flushed one message at a time. File: sendmail/sendmail.c. + Feature: "postsuper -d queueID" deletes one message queue + file; "postsuper -d -" reads zero or more queue IDs from + standard input, and deletes one instance of each file. + File: postsuper/postsuper.c. + + Code cleanup: in order to make postsuper -d safe with a + running Postfix mail system, some routines had to be made + tolerant for sudden queue file disappearances. Files: + global/deliver_request.c, *qmgr/qmgr_move.c. + + Code cleanup: in order to make postsuper -d more usable, + the showq command was extended to safely list the possibly + world-writable maildrop directory. File: showq/showq.c. + +20010504 + + Feature: postsuper -d will also delete defer and bounce + logfiles when the named queue file is found. + +20010505 + + RFC 2821 feature: an SMTP server must reset all buffers + upon receipt of EHLO. File: smtpd/smtpd_check.c. + + RFC 2821 feature: an SMTP server must accept a recipient + address of "postmaster" without domain name. File: + smtpd/smtpd_check.c. + + RFC 2821 recommendation: reply with 503 to commands sent + after 554 greeting. File: smtpd/smtpd.c. + + RFC 2821 recommendation: if VRFY is enabled, list it in + the EHLO response. File: smtpd/smtpd.c. + + RFC 2821 recommendation: SMTP clients should use EHLO. + The default setting of smtp_always_send_ehlo has changed + from 0 (send EHLO if server greets with ESMTP) to 1 (always + send EHLO). In all cases, Postfix falls back to HELO if + the server does not support EHLO. File: smtp/smtp_proto.c. + 20010507 Bugfix: with soft_bounce=yes, the SMTP server would log 5xx replies even though it would send 4xx replies to the client (Phil Howard, ipal.net). File: smtpd/smtpd_check.c. +20010515 + + Compatibility: Microsoft sends "AUTH=MBS_BASIC LOGIN". + Updated the parsing code in smtp/smtp_proto.c. Problem + reported by Ralf Tessmann, Godot GmbH. + +20010520 + + Standard: deleted the non-standard "via" portion from + Received: headers generated by Postfix bounce or other + notification processes. File: global/post_mail.c. + + Robustness: eliminated stack-based recursion from the RFC + 822 address parser. File: global/tok822_parse.c. + + Standard: annotated the source code with comments based on + RFC 2821 and 2822. Not all the RFC changes make sense. + + RFC 2821 recommendation: treat a RCPT 552 reply as if the + server sent 452. Files: smtp/smtp_proto.c, lmtp/lmtp_proto.c. + + Cleanup: moved ownership of the debug_peer parameters from + the applications to the library, so that a Postfix shared + library does not suffer from undefined references. Files: + smtp/smtp.c, lmtp/lmtp.c, smtpd/smtpd.c, global/mail_params.c. + LaMont Jones, for Debian. + +20010522 + + Feature: "postsuper -r queueID" re-queues a message, and + "postsuper -r ALL" re-queues all mail. The message is moved + to the maildrop queue so that the pickup daemon will copy + it to a new queue file, and so that address rewriting will + be done again. This is useful after changes of address + rewriting or virtual mappings. + + Feature: "postsuper -d ALL [queue-name]" deletes a bunch + of mail. + 20010523 - Bugfix: postsuper's temporary file detection logic needed - fixing. + Feature: "postsuper -s" (which is done by default) renames + queue files whose name (queue ID) does not match the message + file inode number. Bugfix: memory leak in the LDAP client module. Alain Thivillon, France Teaser - Groupe Firstream. 20010525 + Portability: gcc 2.6.3 does not have __attribute__ (Clive + Jones, dgw.co.uk). File: util/sys_defs.h. + Bugfix: the SMTP and LMTP clients claimed that a queue file needed to be delivered again (even when all recipients were erased from the queue file) when no QUIT or RSET reply was @@ -5064,6 +5222,145 @@ Apologies for any names omitted. server had disconnected. Files: smtp/smtp_proto.c, lmtp/lmtp_proto.c. +20010526 + + newaliases no longer complains when an empty list is + specified with the alias_database configuration parameter. + File: sendmail/sendmail.c. + +20010529 + + Workaround: old PIX firewall code messes up when the final + ".<CR><LF>" at the end of DATA spans a packet boundary. + When Postfix detects PIX SMTP fixup mode, Postfix flushes + the output buffers before sending the final ".<CR><LF>". + File: smtp/smtp_proto.c. + +20010530 + + Portability: updated code for Mac OS X, accounting for the + post-Beta changes. Code by Joe Block, UCF School of + Optics/CREOL. + +20010601 + + Safety: postdrop turns off interrupts when cleaning up + after interrupt. The additional safety does not hurt anyone. + File: src/postdrop/postdrop.c. + +20010607 + + Safety: dropped the RFC 2821 compliant code that treats + 552 RCPT TO replies as 452. It created more problems than + it solved. Files: smtp/smtp_proto.c, lmtp/lmtp_proto.c. + + Logging: the SMTP server now logs a warning if RBL lookups + have problems other than "not found". file: smtpd/smtpd_check.c. + +20010610 + + Feature: address quoting and case folding flags for the + pipe(8) mailer. + +20010611 + + Workaround: some MTAs fall on their face when they receive + unexpectedly long lines. From now on, Postfix defaults to + breaking long lines at 2048 (like Sendmail so it has got to + be right). To get the old, content preserving, behavior + specify "smtp_truncate_lines = no". File: smtp/smtp_proto.c. + +20010614 + + Bugfix: did not really undo 2821 552->452 mapping. + +20010628 + + Bugfix: postfix-script used a hard-coded maildrop group + owner instead of using the install-time specified name + stored in /etc/postfix/install.cf. Problem reported by + David Terrell @ meat.net. + +20010701 + + Feature: mail_spool_directory ending in / causes maildir + style delivery. + + Bugfix: the FreeBSD kernel parameters kern.ipc.nmbclusters + and kern.ipc.maxsockets cannot be set with sysctl commands. + File: html/faq.html. Len Conrad @ Go2France.com. + + Cleanup: the virtual delivery agent was poorly integrated + so that the SMTP server and queue manager did not reject + mail for unknown users. Files: smtpd/smtpd_check.c. + +20010705 + + Feature: QMQP server, compatible with qmail and the ezmlm + list manager. Files: util/netstring.[hc], qmqpd/qmqpd*.c. + +20010706 + + Feature: QMQP stress test message generator program. Files: + smtpstone/qmqp-source.c, smtpstone/qmqp-sink.c. + +20010708 + + Bugfix: with disable_dns=yes, the SMTP client treated all + host lookup errors as permanent. File: smtp/smtp_addr.c. + +20010709 + + Feature: VERP support, based on a patch by Peng Yong, and + with the missing parts filled in so that the Postfix bounce + daemon can send one VERP bounce per undeliverable recipient. + Files: , sendmail/sendmail.c, smtpd/smtpd.c, qmgr/qmgr_deliver.c, + bounce/bounce_notify_verp.c, qmqpd/qmqpd.c, plus a couple + support routines in the global library. + + Cleanup: with recipient_delimiter=+ (or any character other + than -) Postfix will now recognize address extensions even + with owner-foo+extension addresses. This is necessary to + make VERP work for mailing lists. + +20010710 + + Bugfix: potential memory leak in the queue managers with + the new VERP delimiter record. Fix by Patrik Rak. + +20010711 + + Cleanup: you can now specify the VERP delimiter characters + on the sendmail(1) command line, but they are still optional. + + Safety: with maildir style delivery and with hashed mailboxes + the system mail spool directory must not be world writable. + +20010713 + + Safety: the verp_delimiter_filter parameter (default: -=+) + limits what characters Postfix accepts as VERP delimiter + characters. + +20010714 + + Logging: the queue manager now logs a "status=expired" + record when it returns a message that is too old. Files: + *qmgr/qmgr_active.c. + +20010719 + + Feature: stiffer coupling between mail receiving rates and + mail delivery rates, using a trivial token-based scheme, + implemented by reading and writing an in-memory pipe. The + queue manager produces one token when it retrieves mail + from the incoming queue. The cleanup daemon consumes one + token when it adds mail to the incoming queue. If no token + is available the cleanup server pauses for $in_flow_delay + seconds and proceeds anyway. The delay allows mail sending + process to catch up and access the disk while not blocking + inbound mail. Valid delays are 0..10 seconds. + 20010727 Bugfix: updated LDAP client module from LaMont Jones, HP. @@ -5097,18 +5394,78 @@ Apologies for any names omitted. suddenly refuse to start up after someone changes the DNS. Files: util/inet_addr_list.c global/own_inet_addr.c. + Feature: specify "disable_verp_bounces = yes" to have + Postfix send one RFC-standard, non-VERP, bounce report for + multi-recipient mail, even when VERP style delivery was + requested. + +20010801 + + Bugfix: postconf was using unexpanded values internally + for myhostname, inet_interfaces, and mynetworks_style. + This broke the "postconf -d" mynetworks computation. File: + postconf/postconf.c. + +20010803 + + Feature: masquerade_classes parameter for fine control of + address masquerading. The default setting is backwards + compatible: envelope_sender header_sender header_recipient. + Files: cleanup/whatever.c. + +20010822 + + Code cleanup: the bounce daemon complained about data that + it was not going to send back anyway. Fix: stop reading + the original message when the bounce message reaches the + bounce message size limit. File: bounce/bounce_notify_util.c. + +20010826 + + Logging: postsuper now logs the queue ID when it requeues + a message, or when it deletes a message from the mail queue. + File: postsuper/postsuper.c. + +20010830 + + Safety: the SMTP server now sends a 4xx (try again later) + response when an UCE restriction is misconfigured, instead + of ignoring the bad restriction and possibly accepting mail + that it should not accept. File: smtpd/smtpd_check.c. + +20010907 + + Workaround: the Postfix qmqp-source program produced mail + not ending in newline. qmail-qmqpd accepts such mail, but + qmail-remote is unable to deliver it. Matthias Andree, + uni-dortmund.de. File: smtpstone/qmqp-source.c. + +20010910 + + Bugfix: the smtp-sink stress test program broke when RCPT + TO commands crossed network packet boundaries. Problem + reported by Matthias Andree, uni-dortmund.de. File: + smtpstone/smtp-sink.c. + 20010917 + Code cleanup: permit_mx_backup implements the old behavior + (accept mail if the local MTA is MX relay), and allows an + additional restriction via the permit_mx_backup_networks + parameter (accept mail only if the primary MX hosts match + the specified list of network blocks). This second restriction + is now entirely optional, for backwards compatibility. + Bugfix: an address extension could be appended multiple times to the result of a canonical or virtual map lookup. File: global/mail_addr_map.c. Fix by Victor Duchovni, Morgan Stanley. - Bugfix: because split_addr() would split an address even - when there was no data before the recipient delimiter, the - above bug could cause an address to grow exponentially in - size. Problem reported by Victor Duchovni, Morgan Stanley. - File: global/split_addr.c. + Bugfix: split_addr() would split an address even when there + was no data before the recipient delimiter. In combination + with the above bug, this could cause an address to grow + exponentially in size. Problem reported by Victor Duchovni, + Morgan Stanley. File: global/split_addr.c. 20010918 @@ -5117,6 +5474,44 @@ Apologies for any names omitted. email to really fix the mail_addr_map() problem. Thanks to Victor Duchovni and Liviu Daia. +20011006 + + Cleanup: Postfix no longer flushes the whole deferred queue + after an ETRN request for a random domain name (i.e. a + domain name not matched by $fast_flush_domains); the SMTP + server instead replies with "459 service unavailable". + Files: smtpd/smtpd.c, global/flush_clnt.c, flush/flush.c. + +20011008 + + Bugfix: there was a minute memory leak when an smtpd access + restriction was misconfigured. File: smtpd/smtpd_check.c. + +20011010 + + Code cleanup: Postfix daemons now print the name of the + UNIX-domain socket (instead of "unknown stream") in case + of a malformed client request. Files: master/*server.c. + +20011010-14 + + Code cleanup: replaced the ugly mail_print() and mail-scan() + protocols by (name,value) attribute lists. This gives better + error detection when we make changes to internal protocols, + and allows new attributes to be introduced without breaking + everything immediately. Files: util/attr_print.c util/attr_scan.c + global/mail_command_server.c global/mail_command_client.c + as wel as most Postfix applications and daemons. + +20011015 + + Put base 64 encoding into place on the replaced internal + protocols. Files: util/base64_code.[hc]. + + Feature: header/body REJECT rules can now provide text that + is sent to the originator. Files: cleanup/cleanup.c, + cleanup/cleanup_message.c, conf/sample-filter.cf. + 20011016 Bugfix: As of 20000625, Errors-To: was broken, because the @@ -5125,12 +5520,6 @@ Apologies for any names omitted. reported by Roelof Osinga @ nisser.com. File: cleanup/cleanup_message.c. -20011023 - - Bugfix: the FILTER_README content filtering example had - not been updated to include the sendmail "-i" command line - option. - 20011029 Bugfix: virtual map expansion terminated early because the @@ -5143,6 +5532,26 @@ Apologies for any names omitted. with fractional hours (-03-30 instead of -0330). Fix by Chad House, greyfirst.ca. File: global/mail_date.c. +20011102 + + Feature: new -f option to postmap and postalias (do not + lowercase the lookup key while creating a table). Files: + util/dict.h postmap/postmap.c postalias/postalias.c. + + Code cleanup: simplified the attribute print/scan routines, + and removed the never-used support for sending and receiving + integer arrays and string arrays. Files: util/attr_print.c, + util/attr_scan.c. + + Bugfix: qmqpd could read past the end of a string while + looking for qmail's VERP magic token in the envelope sender + address. File: qmqpd/qmqpd.c. + + Code cleanup: finished testing the new internal protocols. + The only bug was with the flush server, which still needs + to support the old (string + null byte) protocol for triggers + from the Postfix master daemon. + 20011103 Bugfix: Postfix would log the wrong error text when locally @@ -5154,6 +5563,57 @@ Apologies for any names omitted. DN's in a special result attribute expansion the same as DN's with no attribute. LaMont Jones, HP. +20011104 + + Bugfix: the new smtp-sink -n option (terminate after the + specified number of deliveries) wasn't optional. + + Portability: updated Mac OS X documentation and install + scripts by Gerben Wierda. + +20011105 + + 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 @@ -5161,5 +5621,439 @@ Apologies for any names omitted. 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 missing reset (Victor Duchovni, 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. 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. + + Portability: AIX5 (Adrian P. van Bloois), MAC OS X 10.1.1 + (Gerben Wierda). + +20011125 + + Bugfix: spurious postmaster notifications because some flag + was not reset. + + Feature: new parameter smtpd_sender_login_maps that specifies + the (SASL) login name that owns a MAIL FROM address. + Specify a regexp table in order to require a simple one-to-one + mapping. This is used in the reject_sender_login_mismatch + sender anti-spoofing feature. + + Feature: restriction reject_sender_login_mismatch refuses + a MAIL FROM address when $smtpd_sender_login_maps specifies + an owner but the client is not (SASL) logged in as the MAIL + FROM address owner, or when a client is (SASL) logged in + but the client login name does not own the MAIL FROM address + according to $smtpd_sender_login_maps. File: smtpd/smpd_check.c. + + Documentation: added some redundancy to the LMTP_README + file so people can keep track of the difference between + the Postfix LMTP client and the non-Postfix LMTP server. + +20011126 + + Feature: smtpd_noop_commands specifies a list of commands + that are treated as NOOP (no operation) commands, without + syntax check or state change. File: smtpd/smtpd.c. + + Bugfix: the "mark queue file as corrupt" code did not work + because it was never used. Files: global/mark_corrupt.c, + global/mail_copy.c, global/pipe_command.c, *qmgr/qmgr_active.c, + local/maildir.c, local/mailbox.c, local/command.c, pipe/pipe.c, + virtual/mailbox.c, virtual/maildir.c. + + Bugfix: the bounce daemon broke in the unlikely case of a + non-existing queue file. File: bounce/bounce_notify_util.c. + +20011127 + + Feature: added WARN command to header/body_checks files as + proposed by Michael Tokarev. File: cleanup/cleanup_message.c. + + Bugfix: the postdrop program was broken after the change + of Postfix internal protocols. This broke "sendmail -bs" + mail submissions with "secure" maildrop directory. Reported + by Craig Loomis, apo.nmsu.edu. File: postdrop/postdrop.c. + + Feature: a first start at fault injection for testing + unlikely error scenarios (such as corrupt queue files). + Parameter: fault_injection_code, must be left at zero for + production use. + +20011128 + + Robustness: add a file size limit to the sendmail and + postdrop submission programs to stop run-away process + accidents. This is not a defense against DOS attack. + Files: sendmail/sendmail.c, postdrop/postdrop.c. + + That resulted in a considerable amount of work to properly + propagate "file too large" conditions back to the sendmail + mail posting user interface. Took the opportunity to express + other mail submission fatal exits with the <sysexits.h> + exit status codes. Files: sendmail/sendmail.c, + postdrop/postdrop.c. + +20011129 + + Maintenance: dict_ldap.c wasn't updated after the revision + of the string matching routines. File: util/dict_ldap.c. + +20011208 + + Maintenance: LDAP module and documentation from LaMont + Jones. This version adds verbose logging for LDAP library + routines. Files: src/util/dict_ldap.[hc], LDAP_README, + conf/sample-ldap.cf + + Portability: made memory alignment restrictions configurable. + File: util/mymalloc.c. + + Bugfix? Avoid surprises with source routed destinations + and OK entries in SMTPD access maps. File: smtpd/smtpd_access.c. + + Security: "postfix check" looks for damage by well-intended + but misguided use of "chown -R postfix /var/spool/postfix". + That would make chrooted Postfix less secure than non-chrooted + Postfix. These extra tests may cause complaints with + third-party patches such as TLS that introduce their own + files into the jail. + + Feature: static map type that always returns the map name + as lookup value, regardless of lookup key value. Contributed + Jeff Miller (jeffm at ghostgun.com) + + Feature: turn off the PIX <CR><LF>.<CR><LF> workaround for + the first mail delivery attempt, i.e. when mail is queued + for less than $smtp_pix_workaround_threshold_time (default: + 500) seconds. New parameter $smtp_pix_workaround_delay_time + to control the delay before sending .<CR><LF> (default: 10 + seconds) when doing the PIX <CR><LF>.<CR><LF> workaround. + +20011210 + + Bugfix: the 20011128 change in sendmail and postdrop did + not handle the case of message_size_limit=0. Fix by Will + Day, Georgia Tech. + +20011212 + + Compatibility: The SMTP server now accepts <CR><CR><LF> as + if the client sent <CR><LF>. Reportedly, some badly written + windows software produces such garbage, and some badly + written windows anti-VIRUS software cannot handle such + garbage. File: global/smtp_stream.c. + +20011214 + + Bugfix: postmap/postalias queries ignored the -f flag. + Reported by Hamish Marson. + +20011217 + + Compatibility: Sendmail now has a -L option to set the + syslogging label. Postfix sendmail uses syslog_name instead, + and ignores the -L option. + + Security: subtle hardening of the Postfix chroot jail, + Postfix queue file permissions and access methods, in case + someone compromises the postfix account. Michael Tokarev, + who received the insights from Solar Designer, who tested + Postfix with a kernel module that is paranoid about open() + calls. Files: master/master_wakeup.c, util/fifo_trigger.c, + postfix-script. + + Convenience: issue a warning instead of aborting when the + local machine name is not in fully-qualified domain form. + This would otherwise break initial postfix installation + which needs the postconf command. File: global/mail_params.c. + +20011220 + + Added more garbage detection to postconf -e input processing. + +20011221 + + Feature: SMTPD access map lookups of null sender addresses. + If your access maps cannot store or look up null string + key values, specify "smtpd_null_access_lookup_key = <>" + and the null sender address will be looked up as <> instead. + File: src/smtpd_access.c. + +20011223 + + Safety: configuration file comments no longer span multiple + lines when the next line begins with whitespace; multi-line + input is no longer terminated by a comment line, by an all + white space line, or by an empty line. Michael Tokarev made + the crucial suggestion to simplify the readline routine. + Files: util/readlline.c, postconf/postconf.c. + + Cleanup: proper detection of big number overflow in EHLO + and MAIL FROM size announcements, with input from Victor + Duchovni, Morgan Stanley. Files: global/off_cvt.c, + smtpd/smtpd.c, smtp/smtp_proto.c, util/alldig.c. + + Forward compatibility: added queue file record types for + original recipient and for generic named attributes. + + Cleanup: safe_open() now returns sensible errno values so + that the fifo_trigger() external interface is restored. + +20011225 + + Upgrade: PCRE_README now describes PCRE version 3.x. + + Cleanup: flush SMTPD command history upon receipt of EHLO, + RSET, and upon DATA completion, only if it exceeds + $smtpd_history_flush_threshold lines (default: 100). + Distant derivative of code by Michael Tokarev. File: + smtpd/smtpd.c. + +20011228 + + Bugfix: a readlline() error message showed less text than + intended. Christian von Roques. + + Cleanup: postfix now installs with group-writable maildrop + directory and with a set-gid postdrop mail submission + command. The pickup service is now unprivileged. The + world-writable maildrop directory no longer exists. + + The cleanup service is now public, in preparation for local + sendmail/postdrop mail submission that avoids the maildrop + queue directory while Postfix is up. + + Cleanup: moved the main.cf/master.cf file editing from the + postfix-script file to the INSTALL.sh file. + + Cleanup: INSTALL.sh no longer accepts "no" as the destination + of Postfix manual pages. + +20011230 + + Cleanup: the code for "mailq", "sendmail -q", and for + "sendmail -qRsite" was moved from the sendmail command to + a new set-gid postqueue command. The pickup and qmgr FIFOs + are no longer world writable. Files: sendmail/sendmail.c, + postqueue/postqueue.c. + +20020101 + + Security: new alternate_config_directories parameter that + specifies what directories a set-gid command will accept + as its configuration directory. The list must be specified + in the default main.cf file. File: global/mail_conf.c. + + Cleanup: "sendmail -qRsite" is no longer implemented by + connecting to the SMTP port. It is now implemented by + talking to the fast flush service. File: postqueue/postqueue.c. + +20020203 + + Cleanup: INSTALL.sh now records all installation information + in the main.cf file. The now obsolete install.cf file is + used only when upgrading from an older Postfix release. + + Cleanup: INSTALL.sh now takes name=value settings on the + command line, and has a new "-upgrade" command line option + to turn on non-interactive installation. + + Security: additional run-time checks to discourage sharing + of Postfix user/group ID values with other accounts. + +20020105 + + Cleanup: SMTPD access maps now return DUNNO (undetermined) + instead of OK when a recipient address contains multiple + domains (user@dom1@dom2, etcetera). Victor Duchovni, Morgan + Stanley. File: smtpd/smtpd_check.c. + +20020106 + + Bugfix: SMTPD access maps did not handle address extensions. + File: smtpd/smtpd_check.c. + +20020107 + + Bugfix: postfix-script, when creating a missing maildrop + queue directory, still referenced install.cf when setting + maildrop directory group ownership; and the postfix command + did not export the setgid_group parameter to the postfix-script + shell script. Victor Duchovni. + + Bugfix: postfix-script, when creating a missing public + queue directory, did not set group ownership of the public + directory. + +20020109 + + Cleanup: rewrote the Postfix installation procedure again. + It is now separated into 1) a primary installation script + (postfix-install) that installs files locally or that builds + a package for distribution and that stores file owner and + permission information in /etc/postfix/post-files, and 2) + a post-installation script (/etc/postfix/post-install) that + creates missing directories, that sets file/directory + ownership and permissions, and that upgrades existing + configuration files if necessary. + +20020110 + + Workaround: AIX null read() return on an empty but open + non-blocking pipe. File: master/master_flow.c. Report: + Hamish Marson. + +20020111 + + Feedback: feedback, bugfixes, and brain-dead shell workarounds + for the install scripts by Victor Duchovni and Simon Mudd. + +20020113 + + Rewrote postfix-install. The postfix-files file now controls + what is installed. Refined the semantics of many post-install + operations. post-install now auto-saves settings that + override main.cf. + +20020114 + + Bugfix: alternate_config_directories did not take comma + or whitespace as separators. File: global/mail_conf.c. + Victor Duchovni, Morgan Stanley. + + Bugfix: the rewritten postfix-install script did not chattr + +S the Postfix queue. + +20020115 + + Cleanup: added sample_directory and readme_directory + installation parameters for sample configuration files and + for README files. Files: postconf.c, postfix-install, + conf/postfix-files, conf/post-install. + + Robustness: the postfix command now exports all installation + parameter settings, and input filters the environment, so + that the startup shell scripts produce a consistent result. + Files: postconf.c. + +20020117 + + Portability: patch from LaMont Jones for compiling dict_ldap.c + with the Netscape SDK. + + Feature: added "r" (recursive chown/chgrp) flag to the + postfix-files database, for more convenient change of + Postfix queue ownership. Files: conf/postfix-files, + conf/post-install. + +20020122 + + Documentation: lots of little fixes. + + Documentation: updates for the VIRTUAL_README file by Victor + Duchovni, Morgan Stanley. + + Bugfix: postqueue -s dereferenced a null pointer when given + a numerical domain argument. LaMont Jones, HP. + + Cleanup: smtpd now logs a warning when permit_sasl_authenticated + is used while SASL authentication is disabled, instead of + simply ignoring the restriction. LaMont Jones, HP. File: + smtpd/smtpd.c. + + Safety: when postmap creates a non-existent file, the new + file inherits group/other read permissions from the source + file. Based on code by LaMont Jones, HP. File: + postmap/postmap.c. + +20020124 + + Portability: some Linux systems install libnsl.so without + libnsl.a file, causing an yp_match undefined reference + problem. File: makedefs. + +20020124 + + Portability: post-install now requests that command_directory + is given on the command line when the postconf command is + in an unusual place. + + Safety: extra code to detect and report Berkeley DB version + mismatches between compile time and run time. This test + is limited to mismatches in the major version number only. + File: util/dict_db.c. Based on code by Lawrence Greenfield, + Carnegie-Mellon university. + + Safety: the postfix command and the master daemon abort if + they are running set-uid. + + Documentation: the postmap manual page described an out of + date input file format. + +Open problems: + + Low: don't do user@domain and @domain lookups in + local_recipient_maps queries. + + Low: after reorganizing configuration parameters, add flags + to all parameters whose value can be read from file. + + Medium: need in-process caching for map lookups. LDAP + servers seem to need this in particular. Need a way to + expire cached results that are too old. + + Medium: make address rewriting on/off configurable for + envelopes and/or headers. + + Low: generic showq protocol, to allow for more intelligent + processing than just mailq. Maybe marry this with postsuper. + + 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 + about attempts to set read-only parameters. + + Low: postconf -e edits parameters that postconf won't list. diff --git a/gnu/dist/postfix/INSTALL b/gnu/dist/postfix/INSTALL index 6e74ebcbf16..117cd6d6ec8 100644 --- a/gnu/dist/postfix/INSTALL +++ b/gnu/dist/postfix/INSTALL @@ -52,6 +52,7 @@ If your system is supported, it is one of BSD/OS 2.x BSD/OS 3.x BSD/OS 4.x + Darwin 1.x FreeBSD 2.x FreeBSD 3.x FreeBSD 4.x @@ -73,8 +74,7 @@ If your system is supported, it is one of Linux SuSE 5.x Linux SuSE 6.x Linux SuSE 7.x - Mac OS X server - Mac OS X Public Beta + Mac OS X NEXTSTEP 3.x NetBSD 1.x OPENSTEP 4.x @@ -84,7 +84,7 @@ If your system is supported, it is one of OpenBSD 2.x Reliant UNIX 5.x Rhapsody 5.x - SunOS 4.1.x + SunOS 4.1.x (with Postfix 1.1.0) SunOS 5.4..5.8 (Solaris 2.4..8) Ultrix 4.x (well, that was long ago) @@ -152,15 +152,16 @@ In any case, if the command % make produces compiler error messages, it may be time to examine the -FAQ document. +FAQ document (see htlm/faq.html). 5 - Porting to on an unsupported system ======================================= -- Choose a SYSTEMTYPE name for the new system. Please use a name -that includes the major version of the operating system (such as -SUNOS4 or LINUX2), so that different releases of the same system -can be supported without confusion. +- Each system type is identified by a unique name. Examples: +SUNOS5, FREEBSD4, and so on. Choose a SYSTEMTYPE name for the new +system. You must use a name that includes at least the major version +of the operating system (such as SUNOS4 or LINUX2), so that different +releases of the same system can be supported without confusion. - Add a case statement to the "makedefs" shell script in the top-level directory that recognizes the new system reliably, and @@ -182,6 +183,10 @@ again. 6 - Installing the software after successful compilation ======================================================== +This text describes how to install Postfix from source code. See +the PACKAGE_README file if you are building a package for distribution +to other systems. + IMPORTANT: if you are REPLACING an existing sendmail installation with Postfix, you may need to keep the old sendmail program running for some time in order to flush the mail queue. As superuser, @@ -196,10 +201,11 @@ programs may be in a different place): In order to install or upgrade Postfix: -- Create a user "postfix" with a unique user id and group id. - Preferably, this is an account that no-one can log into. The - account does not need an executable login shell, and needs no - existing home directory. My password file entry looks like this: +- Create a user account "postfix" with a user id and group id that + are not used by any other user account. Preferably, this is an + account that no-one can log into. The account does not need an + executable login shell, and needs no existing home directory. + My password file entry looks like this: postfix:*:12345:12345:postfix:/no/where:/no/shell @@ -207,22 +213,27 @@ In order to install or upgrade Postfix: postfix: root -- Review section 12 of this file, and decide if a world-writable - maildrop is OK, or if Postfix needs a set-gid posting agent. +- Create a group "postdrop" with a group id that is not used by + any other user account. Not even by the postfix user account. + My group file entry looks like: + + postdrop:*:54321: + + NB: this group was optional with older Postfix releases; it is + now required. -- Run the INSTALL.sh script as the super-user: +- Run one of the following commands 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, - use interactive installation instead. + The non-interactive version needs the /etc/postfix/main.cf file + from a previous installation. If the file does not exist, use + interactive installation instead. - The INSTALL.sh script offers suggestions for pathnames that you - can override, either by editing INSTALL.sh or by specifying your - preferences interactively. INSTALL.sh stores your preferences in - the Postfix configuration directory in order to ease future installs. + The interactive version offers suggestions for pathnames that + you can override interactively, and stores your preferences in + /etc/postfix/main.cf for convenient future upgrades. - Proceed to the section on how you wish to run Postfix on your particular machine: @@ -244,8 +255,8 @@ to change your existing sendmail setup. Instead, set up your mail user agent so that it calls the Postfix sendmail program directly. Follow the instructions in the "Mandatory configuration file edits" -in section 10, review the "To chroot or not to chroot" text in -section 11, and choose a security model according to section 12. +in section 10, and review the "To chroot or not to chroot" text in +section 11. You MUST comment out the `smtp inet' entry in /etc/postfix/master.cf, in order to avoid conflicts with the real sendmail. @@ -265,10 +276,6 @@ and watch your syslog file for any error messages. Typical logfile names are: /var/log/maillog or /var/log/syslog. See /etc/syslog.conf for actual logfile names. -When it is run for the first time, the Postfix startup shell script -will create a bunch of subdirectories below the Postfix spool -directory. - In order to inspect the mail queue, use % sendmail -bp @@ -293,8 +300,8 @@ In the /etc/postfix/main.cf file, I would specify mydestination = $myhostname Follow the instructions in the "Mandatory configuration file edits" -in section 10, review the "To chroot or not to chroot" text in -section 11, and choose a security model according to section 12. +in section 10, and review the "To chroot or not to chroot" text in +section 11. Start the mail system: @@ -311,10 +318,6 @@ and watch your syslog file for any error messages. Typical logfile names are: /var/log/maillog or /var/log/syslog. See /etc/syslog.conf for actual logfile names. -When it is run for the first time, the Postfix startup shell script -will create a bunch of subdirectories below the Postfix spool -directory. - In order to inspect the mail queue, use % sendmail -bp @@ -349,10 +352,6 @@ and watch the syslog file for any complaints from the mail system. Typical logfile names are: /var/log/maillog or /var/log/syslog. See /etc/syslog.conf for actual logfile names. -When it is run for the first time, the Postfix startup shell script -will create a bunch of subdirectories below the Postfix spool -directory. - See also the "Care and feeding" section 13 below. 10 - Mandatory configuration file edits @@ -472,52 +471,7 @@ files or device nodes. The examples/chroot-setup directory has a collection of scripts that help you set up chroot environments for Postfix systems. -12 - Security: writable versus protected maildrop directory -=========================================================== - -Postfix offers a choice of submission mechanisms. - -1 - Postfix can use a world-writable, sticky, mode 1733 maildrop - directory where local users can submit mail. This approach - avoids the need for set-uid or set-gid software. Mail can be - posted even while the mail system is down. Queue files in the - maildrop directory have no read/write/execute permission for - other users. The maildrop directory is not used for mail - received via the network. - - With directory world write permission come opportunities for - annoyance: a local user can make hard links to someone else's - maildrop files so they don't go away and may be delivered - multiple times; a local user can fill the maildrop directory - with junk and try to crash the mail system; and a local user - can hard link someone else's files into the maildrop directory - and try to have them delivered as mail. However, Postfix queue - files have a specific format; less than one in 10^12 non-Postfix - files would be recognized as a valid Postfix queue file. - - In order to enable maildrop world-write permission: - - - Specify "no" when asked by the INSTALL.sh script whether - Postfix needs set-gid privileges. - -2 - On systems with many users it may be desirable to revoke maildrop - directory world write permission, and to enable set-gid privileges - on a small "maildrop" command that is provided for this purpose. - - In order to revoke maildrop world-write permission: - - - Create a group "maildrop" that is unique and that does not - share its group ID with any other user, certainly not with - the postfix account, - - - Specify "maildrop" when asked by the INSTALL.sh script whether - Postfix needs set-gid privileges. - - The sendmail posting program will automatically invoke the - postdrop command when maildrop directory write permission is - restricted. - -13 - Care and feeding of the Postfix system +12 - Care and feeding of the Postfix system =========================================== The Postfix programs log all problems to the syslog daemon. The diff --git a/gnu/dist/postfix/Makefile b/gnu/dist/postfix/Makefile index 8d9e069d987..e93de9fbf35 100644 --- a/gnu/dist/postfix/Makefile +++ b/gnu/dist/postfix/Makefile @@ -14,5 +14,8 @@ default: update update depend printfck clean tidy depend_update: Makefiles $(MAKE) MAKELEVEL= $@ +install upgrade: + @echo Please review the INSTALL instructions first. + makefiles Makefiles: $(MAKE) -f Makefile.in MAKELEVEL= Makefiles diff --git a/gnu/dist/postfix/Makefile.in b/gnu/dist/postfix/Makefile.in index ec32d0b78b8..429d62f1c52 100644 --- a/gnu/dist/postfix/Makefile.in +++ b/gnu/dist/postfix/Makefile.in @@ -5,8 +5,9 @@ DIRS = src/util src/global src/dns src/master src/postfix src/smtpstone \ src/sendmail src/error src/pickup src/cleanup src/smtpd src/local \ src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \ src/showq src/postalias src/postcat src/postconf src/postdrop \ - src/postkick src/postlock src/postlog src/postmap src/postsuper \ - src/spawn src/flush # proto man html + src/postkick src/postlock src/postlog src/postmap src/postqueue \ + src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/virtual +MANDIRS = proto man html default: update @@ -22,10 +23,18 @@ update printfck: (set -e; echo "[$$i]"; cd $$i; $(MAKE) $(OPTS) $@ MAKELEVEL=) || exit 1; \ done +manpages: + set -e; for i in $(MANDIRS); do \ + (set -e; echo "[$$i]"; cd $$i; $(MAKE) -f Makefile.in $(OPTS) MAKELEVEL=) || exit 1; \ + done + printfck: update install: update - sh INSTALL.sh + $(SHELL) postfix-install + +upgrade: update + $(SHELL) postfix-install -non-interactive depend clean: set -e; for i in $(DIRS); do \ @@ -38,18 +47,10 @@ depend_update: || exit 1; \ done -cleanmakefiles: - set -e; for i in $(DIRS); do \ - (set -e; echo "[$$i]"; cd $$i; rm -f Makefile; \ - ../cleanup_makefile.pl Makefile.in >Makefile.new; \ - rm Makefile.in ; mv Makefile.new Makefile.in); \ - done; - rm -f Makefile; (set -e; sh makedefs && cat Makefile.in) >Makefile - tidy: clean rm -f Makefile */Makefile src/*/Makefile cp Makefile.init Makefile - rm -f bin/* lib/* include/* libexec/* \ + rm -f bin/[!CRS]* lib/[!CRS]* include/[!CRS]* libexec/[!CRS]* \ junk */junk */*/junk \ *core */*core */*/*core \ .nfs* */.nfs* */*/.nfs* \ diff --git a/gnu/dist/postfix/Makefile.init b/gnu/dist/postfix/Makefile.init index 8d9e069d987..e93de9fbf35 100644 --- a/gnu/dist/postfix/Makefile.init +++ b/gnu/dist/postfix/Makefile.init @@ -14,5 +14,8 @@ default: update update depend printfck clean tidy depend_update: Makefiles $(MAKE) MAKELEVEL= $@ +install upgrade: + @echo Please review the INSTALL instructions first. + makefiles Makefiles: $(MAKE) -f Makefile.in MAKELEVEL= Makefiles diff --git a/gnu/dist/postfix/PORTING b/gnu/dist/postfix/PORTING index 2a494420bde..672eff62e3e 100644 --- a/gnu/dist/postfix/PORTING +++ b/gnu/dist/postfix/PORTING @@ -1,9 +1,10 @@ In order to port software to a new platform: -- Choose a SYSTEMTYPE name for the new system. Please use a name -that includes the major version of the operating system (such as -SUNOS4 or LINUX2), so that different releases of the same system -can be supported without confusion. +- Each system type needs to be identified by a unique name. Examples: +SUNOS5, FREEBSD4, and so on. Choose a SYSTEMTYPE name for the new +system. You must use a name that includes at least the major version +of the operating system (such as SUNOS4 or LINUX2), so that different +releases of the same system can be supported without confusion. - Add a case statement to the "makedefs" shell script in the top-level directory that recognizes the new system reliably, and diff --git a/gnu/dist/postfix/README_FILES/DB_README b/gnu/dist/postfix/README_FILES/DB_README new file mode 100644 index 00000000000..6d1bb797c92 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/DB_README @@ -0,0 +1,86 @@ +Purpose of this document +======================== + +This document describes how to build Postfix with third-party +Berkeley DB from www.sleepycat.com, or how to choose a specific +Berkeley DB version when your system provides multiple implementations. + +Building Postfix with Sleepycat Berkeley DB +=========================================== + +Many commercial UNIXes ship without Berkeley DB support. Examples +are Solaris, HP-UX, IRIX, UNIXWARE. In order to build Postfix with +Berkeley DB support you need to download and install the source +code from www.sleepycat.com. + +To build Postfix after you installed the Berkeley DB from Sleepycat, +use something like: + + % make tidy + % make makefiles CCARGS="-DHAS_DB -I/usr/local/BerkeleyDB.3.1/include" \ + AUXLIBS="-L/usr/local/BerkeleyDB.3.1/lib -ldb" + % make + +The exact pathnames depend on the DB version that you installed. +For example, Berkeley DB version 2 installs in /usr/local/BerkeleyDB. + +Warning: the file format produced by Berkeley DB version 1 is not +compatible with that of versions 2 and 3 (versions 2 and 3 have +the same format). If you switch between DB versions, then you may +have to rebuild all your Postfix DB files. + +Warning: if you use Berkeley DB version 2 or later, do not enable +DB 1.85 compatibility mode. Doing so would break fcntl file locking. + +Warning: if you use PERL to manipulate Postfix .db files, then you +need to use the same Berkeley DB version in PERL as in Postfix. + +Building Postfix on BSD systems with a specific Berkeley DB version +=================================================================== + +Some BSD systems ship with multiple Berkeley DB implementations. +Normally, Postfix builds with the default DB version that ships +with the system. + +To build Postfix on BSD systems with a specific DB version, use a +variant of the following commands: + + % make tidy + % make makefiles CCARGS=-I/usr/include/db2 AUXLIBS=-ldb2 + % make + +Warning: the file format produced by Berkeley DB version 1 is not +compatible with that of versions 2 and 3 (versions 2 and 3 have +the same format). If you switch between DB versions, then you may +have to rebuild all your Postfix DB files. + +Warning: if you use Berkeley DB version 2 or later, do not enable +DB 1.85 compatibility mode. Doing so would break fcntl file locking. + +Warning: if you use PERL to manipulate Postfix .db files, then you +need to use the same Berkeley DB version in PERL as in Postfix. + +Building Postfix on Linux with a specific Berkeley DB version +============================================================= + +Some Linux systems ship with multiple Berkeley DB implementations. +Normally, Postfix builds with the default DB version that ships +with the system. + +On Linux, you need to edit the makedefs script in order to specify +a non-default DB library. + +The reason is that the location of the default db.h include file +changes randomly between vendors and between versions, so that +Postfix has to choose the file for you. + +Warning: the file format produced by Berkeley DB version 1 is not +compatible with that of versions 2 and 3 (versions 2 and 3 have +the same format). If you switch between DB versions, then you may +have to rebuild all your Postfix DB files. + +Warning: if you use Berkeley DB version 2 or later, do not enable +DB 1.85 compatibility mode. Doing so would break fcntl file locking. + +Warning: if you use PERL to manipulate Postfix .db files, then you +need to use the same Berkeley DB version in PERL as in Postfix. diff --git a/gnu/dist/postfix/README_FILES/DEBUG_README b/gnu/dist/postfix/README_FILES/DEBUG_README new file mode 100644 index 00000000000..43b2b889eca --- /dev/null +++ b/gnu/dist/postfix/README_FILES/DEBUG_README @@ -0,0 +1,158 @@ +1 - Purpose of this document +============================ + +This document describes how to debug parts of the Postfix mail +system, either by making the software log a lot of detail to the +syslog daemon, or by running some daemon processes under control +of an interactive debugger. + +2 - Verbose logging for specific SMTP connections +================================================= + +In /etc/postfix/main.cf, list the remote site name or address in +the "debug_peer_list" parameter. For example, in order to make the +software log a lot of information to the syslog daemon for connections +from or to the loopback interface: + + debug_peer_list = 127.0.0.1 + +You can specify one or more hosts, domains, addresses or net/masks. + +2b - Record the SMTP connection with a sniffer +============================================== + +This example uses tcpdump. In order to record a conversation you +need to specify a large enough buffer or else you will miss some +or all of the packet payload. + + tcpdump -w /file/name -s 2000 host hostname and port 25 + +Run this for a while, stop with Ctrl-C when done. To view the data +use a binary viewer, or use my tcpdumpx utility that is available +from ftp://ftp.porcupine.org/pub/debugging. + +3 - Making Postfix daemon programs more verbose +=============================================== + +Append one or more -v options to selected daemon definitions in +/etc/postfix/master.cf and type "postfix reload". This will cause +a lot of activity to be logged to the syslog daemon. + +4 - Manually tracing a Postfix daemon process +============================================= + +Some systems allow you to inspect a running process with a system +call tracer. For example: + + # trace -p process-id (SunOS 4) + # strace -p process-id (Linux and many others) + # truss -p process-id (Solaris, FreeBSD) + # ktrace -p process-id (generic 4.4BSD) + +Even more informative are traces of system library calls. Examples: + + # ltrace -p process-id (Linux, also ported to FreeBSD and BSD/OS) + # sotruss -p process-id (Solaris) + +See your system documentation for details. + +Tracing a running process can give valuable information about what +a process is attempting to do. This is as much information as you +can get without running an interactive debugger program, as described +in a later section. + +5 - Automatically tracing a Postfix daemon process +================================================== + +Postfix can attach a call tracer whenever a daemon process starts. + +Append a -D option to the suspect command in /etc/postfix/master.cf, +for example: + + smtp inet n - n - - smtpd -D + +Edit the debugger_command definition in /etc/postfix/main.cf so +that it invokes the call tracer of your choice, for example: + + debugger_command = + PATH=/bin:/usr/bin:/usr/local/bin + (truss -p $process_id 2>&1 | logger -p mail.info) & sleep 5 + +Instead of truss use trace or strace. + +Type "postfix reload" and watch the logfile. + +6 - Running daemon programs under an interactive debugger +========================================================= + +Append a -D option to the suspect command in /etc/postfix/master.cf, +for example: + + smtp inet n - n - - smtpd -D + +Edit the debugger_command definition in /etc/postfix/main.cf so +that it invokes the debugger of your choice, for example: + + debugger_command = + PATH=/usr/bin:/usr/X11R6/bin + xxgdb $daemon_directory/$process_name $process_id & sleep 5 + +If you use xxgdb, be sure that gdb is in the command search path. + +Export XAUTHORITY so that X access control works, for example: + + % setenv XAUTHORITY ~/.Xauthority + +Stop and start the Postfix system. + +Whenever the suspect daemon process is started, a debugger window +pops up and you can watch in detail what happens. + +7 - Unreasonable behavior +========================= + +Sometimes the behavior exhibit by Postfix just does not match the +source code. Why can a program deviate from the instructions given +by its author? There are two possibilities. + +1 - The compiler has messed up. + +2 - The hardware has messed up. + +In both cases, the program being executed is not the program that +was supposed to be executed, so anything can happen. + +There is a third possibility: + +3 - Bugs in system software (kernel or libraries). + +Hardware-related failures happen erratically, and they usually do +not reproduce after power cycling and rebooting the system. There's +little I can do about bad hardware. Be sure to use hardware that +at the very least can detect memory errors. Otherwise, Postfix will +just be a sitting duck waiting to be hit by a bit error. Critical +systems deserve real hardware. + +When a compiler messes up, the problem can be reproduced whenever +the resulting program is run. Compiler errors are most likely to +happen in the code optimizer. If a problem is reproducible across +power cycles and system reboots, it can be worthwhile to rebuild +Postfix with optimization disabled, and to see if optimization +makes a difference. + +In order to compile Postfix with optimizations turned off: + + % make tidy + % make makefiles OPT= + +This produces a set of Makefiles that do not request compiler +optimization. + +Once the makefiles are set up, build the software: + + % make + % su + # make install + +And see if the problem reproduces. If the problem goes away, talk +to your vendor. diff --git a/gnu/dist/postfix/README_FILES/ETRN_README b/gnu/dist/postfix/README_FILES/ETRN_README new file mode 100644 index 00000000000..c7b18d31dae --- /dev/null +++ b/gnu/dist/postfix/README_FILES/ETRN_README @@ -0,0 +1,117 @@ +Purpose of this document +======================== + +This document describes the purpose of the Postfix fast ETRN service, +how the service works, and how it can be tested. + +Other documents with information on this subject: + +- conf/sample-flush.cf, sample configuration file +- conf/main.cf, sample configuration file +- flush(8), flush service implementation + +The Postfix fast ETRN service +============================= + +The SMTP ETRN command was designed for sites that have intermittent +Internet connectivity. With ETRN, a site can tell the mail server +of its provider to "Please deliver all my mail now". + +Postfix versions before 20001005 implemented the ETRN command in +a lame manner: they simply attempted to deliver all queued mail. +This is slow on mail servers that queue mail for many customers. + +As of version 20001005, Postfix has a fast ETRN implementation that +does not require Postfix to examine every queue file. The command +"sendmail -qR" is now implemented by sending an ETRN command to +the local SMTP server. + +Postfix "fast ETRN/sendmail -qR" speeds up deliveries by attempting +to deliver only mail that is queued for a given destination site. +The old Postfix "slow ETRN" is still used as a fall-back method. + +How Postfix fast ETRN works +=========================== + +The "fast ETRN" service uses the new "flush" daemon which maintains +per-destination logfiles of queued mail. These logfiles are kept +below /var/spool/postfix/flush. Each logfile is named after its +destination domain name. Only destinations with syntactically valid +domain names can have per-destination logfiles. + +The behavior of the new "flush" daemon is controlled by parameters +in the main.cf configuration file. + +By default, Postfix "fast ETRN/sendmail -qR" service is available +only for destinations that Postfix is willing to relay mail to: + + fast_flush_domains = $relay_domains + +The "relay_domains" parameter specifies what destinations Postfix +will relay to. + +For destinations that are not eligible for the new "fast ETRN/sendmail +-qR" service, Postfix falls back to the old "slow ETRN" method +which attempts to deliver all queued mail. + +To enable "fast ETRN/sendmail -qR" for some other destination, specify: + + fast_flush_domains = $relay_domains, some.other.domain + +To disable "fast ETRN/sendmail -qR", so that Postfix always uses +the old "slow ETRN" which delivers all queued mail, specify: + + fast_flush_domains = + +Testing the fast ETRN service +============================= + +If you run Postfix with "fast ETRN" service for the very first +time, you need to run "sendmail -q" to populate the per-site deferred +mail logfiles. If you omit this step, the logfiles will eventually +become populated as Postfix routinely attempts to deliver delayed +mail, but that will take a couple hours. + +After the "sendmail -q" has completed all delivery attempts (that +can take a while), you're ready to test the "fast ETRN" service. +Telnet to the Postfix SMTP server from a client that is allowed to +execute ETRN commands (by default, that's every client), and type: + + helo my.client.name + etrn some.customer.domain + +where "some.customer.domain" is the name of a domain that has a +non-empty logfile somewhere under /var/spool/postfix/flush. + +In the maillog file, you should immediately see a couple of logfile +records, as evidence that the queue manager has opened queue files: + + Oct 2 10:51:19 localhost postfix/qmgr[51999]: 682E8440A4: + from=<whatever>, size=12345, nrcpt=1 (queue active) + Oct 2 10:51:19 localhost postfix/qmgr[51999]: 02249440B7: + from=<whatever>, size=4711, nrcpt=1 (queue active) + +What happens next depends on whether the destination is reachable. +If it's not reachable, the mail queue IDs will be added back to +the some.customer.domain logfile under /var/spool/postfix/flush. + +Repeat the exercise with another domain that your server is willing +to relay to (domain listed in "relay_domains"), but that has no mail +queued. + + helo my.client.name + etrn some.other.customer.domain + +This time, the "etrn" command should trigger NO mail deliveries at +all. If this triggers delivery of all mail, then you used the wrong +domain name, or "fast ETRN" service is turned off. + +Finally, repeat the exercise with a destination that your mail +server is not willing to relay to. It does not matter if your +server has mail queued for that destination. + + helo my.client.name + etrn not.a.customer.domain + +If your "fast ETRN" caching policy is left at its default setting, +then the "etrn" command should trigger delivery of all queued mail. diff --git a/gnu/dist/postfix/README_FILES/FILTER_README b/gnu/dist/postfix/README_FILES/FILTER_README new file mode 100644 index 00000000000..a325aa7abdf --- /dev/null +++ b/gnu/dist/postfix/README_FILES/FILTER_README @@ -0,0 +1,229 @@ +This is a very first implementation of Postfix content filtering. +A Postfix content filter receives unfiltered mail from Postfix and +either bounces the mail or re-injects filtered mail back into Postfix. + +This document describes two approaches to content filtering. + +Simple content filtering example +================================ + +The first example is simple to set up. It uses a shell script that +receives unfiltered mail from the Postfix pipe delivery agent, and +that feeds filtered mail back into the Postfix sendmail command. +Only mail arriving via SMTP will be content filtered. + + .................................. + : Postfix : +Unfiltered mail----->smtpd \ /local---->Filtered mail + : -cleanup->queue- : + ---->pickup / \smtp----->Filtered mail + ^ : | : + | : \pipe-----+ + | .................................. | + | | + | | + +-Postfix sendmail<----filter script<--+ + +The /some/where/filter program can be a simple shell script like this: + + #!/bin/sh + + # Localize these. + INSPECT_DIR=/var/spool/filter + SENDMAIL="/usr/sbin/sendmail -i" + + # Exit codes from <sysexits.h> + EX_TEMPFAIL=75 + EX_UNAVAILABLE=69 + + # Clean up when done or when aborting. + trap "rm -f in.$$" 0 1 2 3 15 + + # Start processing. + cd $INSPECT_DIR || { echo $INSPECT_DIR does not exist; exit $EX_TEMPFAIL; } + + cat >in.$$ || { echo Cannot save mail to file; exit $EX_TEMPFAIL; } + + # filter <in.$$ || { echo Message content rejected; exit $EX_UNAVAILABLE; } + + $SENDMAIL "$@" <in.$$ + + exit $? + +The idea is to first capture the message to file and then run the +content through run a third-party content filter program. If the +mail cannot be captured to file, mail delivery is deferred by +terminating with exit status 75 (EX_TEMPFAIL). If the content +filter program finds a problem, the mail is bounced by terminating +the shell script with exit status 69 (EX_UNAVAILABLE). If the +content is OK, it is given as input to Postfix sendmail, and the +exit status of the filter command is whatever exit status Postfix +sendmail produces. + +I suggest that you play with this script for a while until you are +satisfied with the results. Run it with a real message (headers+body) +as input: + + % /some/where/filter -f sender recipient... <message-file + +Once you're satisfied with the content filtering script: + +1 - Create a dedicated local user account called "filter". This + user handles all potentially dangerous mail content - that is + why it should be a separate account. Do not use "nobody", and + most certainly do not use "root" or "postfix". The user will + never log in, and can be given a "*" password and non-existent + shell and home directory. + +2 - Create a directory /var/spool/filter that is accessible only + to the "filter" user. This is where the content filtering script + is supposed to store its temporary files. + +3 - Define the content filter in the Postfix master file: + + /etc/postfix/master.cf: + filter unix - n n - - pipe + flags=Rq user=filter argv=/somewhere/filter -f ${sender} -- ${recipient} + +To turn on content filtering for mail arriving via SMTP only, append +"-o content_filter=filter:" to the master.cf entry that defines +the Postfix SMTP server: + + /etc/postfix/master.cf: + smtp inet ...stuff... smtpd + -o content_filter=filter: + +Note the ":" at the end!! The content_filter configuration parameter +accepts the same syntax as the right-hand side in a Postfix transport +table. Execute "postfix reload" to complete the change. + +To turn off content filtering, edit the master.cf file, remove the +"-o content_filter=filter:" text from the entry that defines the +Postfix SMTP server, and execute another "postfix reload". + +With the shell script as shown above you will lose a factor of four +in Postfix performance for transit mail that arrives and leaves +via SMTP. You will lose another factor in transit performance for +each additional temporary file that is created and deleted in the +process of content filtering. The performance impact is less for +mail that is submitted or delivered locally, because such deliveries +are already slower than SMTP transit mail. + +Simple content filter limitations +================================= + +The problem with content filters like the one above is that they +are not very robust, because the software does not talk a well-defined +protocol with Postfix. If the filter shell script aborts because +the shell runs into some memory allocation problem, the script will +not produce a nice exit status as per /usr/include/sysexits.h and +mail will probably bounce. The same lack of robustness is possible +when the content filtering software itself runs into a resource +problem. + +Advanced content filtering example +=================================== + +The second example is considerably more complex, but can give much +better performance, and is less likely to bounce mail when the +machine runs into a resource problem. This approach uses content +filtering software that can receive and deliver mail via SMTP. +You can expect to lose about a factor of two in Postfix performance +for transit mail that arrives and leaves via SMTP, provided that +you create no temporary files. Each temporary file adds another +factor to the performance loss. + +We will set up a content filtering program that receives SMTP mail +via localhost port 10025, and that submits SMTP mail back into +Postfix via localhost port 10026. + + .................................. + : Postfix : + ----->smtpd \ /local----> + : -cleanup->queue- : + ---->pickup / ^ | \smtp-----> + : | v : + : smtpd smtp : + : 10026 | : + ......................|........... + ^ | + | v + ....|............ + : | 10025 : + : filter : + : : + ................. + +To enable content filtering in this manner, specify in main.cf a +new parameter: + + /etc/postfix/main.cf: + content_filter = smtp:localhost:10025 + +This causes Postfix to add one extra content filtering record to +each incoming mail message, with content smtp:localhost:10025. +You can use the same syntax as in the right-hand side of a Postfix +transport table. The content filtering records are added by the +smtpd and pickup servers. + +When a queue file has content filtering information, the queue +manager will deliver the mail to the specified content filter +regardless of its final destination. + +The content filter can be set up with the Postfix spawn service, +which is the Postfix equivalent of inetd. For example, to instantiate +up to 10 content filtering processes on demand: + + /etc/postfix/master.cf: + localhost:10025 inet n n n - 10 spawn + user=filter argv=/some/where/filter localhost 10026 + +"filter" is a dedicated local user account. The user will never +log in, and can be given a "*" password and non-existent shell and +home directory. This user handles all potentially dangerous mail +content - that is why it should be a separate account. + +In the above example, Postfix listens on port localhost:10025. If +you want to have your filter listening on port localhost:10025 +instead of Postfix, then you must run your filter as a stand-alone +program. + +Note: the localhost port 10025 SMTP server filter should announce +itself as "220 localhost...", to silence warnings in the log. + +The /some/where/filter command is most likely a PERL script. PERL +has modules that make talking SMTP easy. The command-line specifies +that mail should be sent back into Postfix via localhost port 10026. + +For now, it is left up to the Postfix users to come up with a +PERL/SMTP framework for Postfix content filtering. If done well, +it can be used with other mailers too, which is a nice spin-off. + +The simplest content filter just copies SMTP commands and data +between its inputs and outputs. If it has a problem, all it has to +do is to reply to an input of `.' with `550 content rejected', and +to disconnect without sending `.' on the connection that injects +mail back into Postfix. + +The job of the content filter is to either bounce mail with a +suitable diagnostic, or to feed the mail back into Postfix through +a dedicated listener on port localhost 10026: + + /etc/postfix/master.cf: + localhost:10026 inet n - n - 10 smtpd + -o content_filter= + -o local_recipient_maps= + -o myhostname=localhost.domain.name + +This is just another SMTP server. It is configured NOT to request +content filtering for incoming mail. The server has the same process +limit as the filter master.cf entry. + +The "-o local_recipient_maps=" is a safety in case you have specified +local_recipient_maps in the main.cf file. That setting could +interfere with content filtering. + +The SMTP server is configured to use a different hostname in the +greeting message (this is necessary for testing when I simply use +no filtering program and let the SMTP content filtering interfaces +talk directly to each other). diff --git a/gnu/dist/postfix/README_FILES/INSTALL b/gnu/dist/postfix/README_FILES/INSTALL new file mode 100644 index 00000000000..117cd6d6ec8 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/INSTALL @@ -0,0 +1,499 @@ +1 - Purpose of this document +============================ + +This document describes how to build, install and configure a +Postfix system so that it can do one of the following: + + - Send mail only, without changing an existing sendmail + installation. + + - Send and receive mail via a virtual host interface, still + without any change to an existing sendmail installation. + + - Replace sendmail altogether. + +2 - Typographical conventions +============================= + +In the instructions below, a command written as + + # command + +should be executed as the superuser. + +A command written as + + % command + +should be executed as an unprivileged user. + +3 - Documentation +================= + +Documentation is available as HTML web pages (point your browser +to html/index.html) and as UNIX-style man pages (point your MANPATH +environment variable to the `man' subdirectory; be sure to use an +absolute path). + +The sample configuration files in the `conf' directory have extensive +comments, but they may not describe every nuance of every feature. + +Many files have their own built-in manual page. Tools to extract +those embedded manual pages are available in the mantools directory. + +4 - Building on a supported system +================================== + +If your system is supported, it is one of + + AIX 3.2.5 + AIX 4.1.x + AIX 4.2.0 + BSD/OS 2.x + BSD/OS 3.x + BSD/OS 4.x + Darwin 1.x + FreeBSD 2.x + FreeBSD 3.x + FreeBSD 4.x + FreeBSD 5.x + HP-UX 9.x + HP-UX 10.x + HP-UX 11.x + IRIX 5.x + IRIX 6.x + Linux Debian 1.3.1 + Linux Debian 2.x + Linux RedHat 4.x + Linux RedHat 5.x + Linux RedHat 6.x + Linux RedHat 7.x + Linux Slackware 3.x + Linux Slackware 4.x + Linux Slackware 7.x + Linux SuSE 5.x + Linux SuSE 6.x + Linux SuSE 7.x + Mac OS X + NEXTSTEP 3.x + NetBSD 1.x + OPENSTEP 4.x + OSF1.V3 (Digital UNIX) + OSF1.V4 aka Digital UNIX V4 + OSF1.V5 aka Digital UNIX V5 + OpenBSD 2.x + Reliant UNIX 5.x + Rhapsody 5.x + SunOS 4.1.x (with Postfix 1.1.0) + SunOS 5.4..5.8 (Solaris 2.4..8) + Ultrix 4.x (well, that was long ago) + +or something closely resemblant. + +On Solaris, the "make" command and other utilities for software +development are in /usr/ccs/bin, so you MUST have /usr/ccs/bin in +your command search path. + +If you need to build Postfix for multiple architectures, use the +lndir command to build a shadow tree with symbolic links to the +source files. lndir is part of X11R6. + +If at any time in the build process you get messages like: "make: +don't know how to ..." you should be able to recover by running +the following command from the Postfix top-level directory: + + % make -f Makefile.init makefiles + +If you copied the Postfix source code after building it on another +machine, it is a good idea to cd into the top-level directory and + + % make tidy + +first. This will get rid of any system dependencies left over from +compiling the software elsewhere. + +To build with GCC, or with the native compiler if people told me +that is better for your system, just cd into the top-level Postfix +directory of the source tree and type: + + % make + +To build with a non-default compiler, you need to specify the name +of the compiler: + + % make makefiles CC=/opt/SUNWspro/bin/cc (Solaris) + % make + + % make makefiles CC="/opt/ansic/bin/cc -Ae" (HP-UX) + % make + + % make makefiles CC="purify cc" + % make + +and so on. In some cases, optimization is turned off automatically. + +In order to build with non-default settings, for example, with a +configuration directory other than /etc/postfix, use: + + % make makefiles CCARGS=-DDEF_CONFIG_DIR=\\\\\\\"/some/where\\\\\\\" + % make + +That's seven backslashes :-) But at least this works with sh and csh. + +In order to build Postfix for very large applications, where you +expect to run more than 1000 delivery processes, you may need to +override the definition of the FD_SETSIZE macro to make select() +work correctly: + + % make makefiles CCARGS=-DFD_SETSIZE=2048 + +In any case, if the command + + % make + +produces compiler error messages, it may be time to examine the +FAQ document (see htlm/faq.html). + +5 - Porting to on an unsupported system +======================================= + +- Each system type is identified by a unique name. Examples: +SUNOS5, FREEBSD4, and so on. Choose a SYSTEMTYPE name for the new +system. You must use a name that includes at least the major version +of the operating system (such as SUNOS4 or LINUX2), so that different +releases of the same system can be supported without confusion. + +- Add a case statement to the "makedefs" shell script in the +top-level directory that recognizes the new system reliably, and +that emits the right system-specific information. Be sure to make +the code robust against user PATH settings; if the system offers +multiple UNIX flavors (e.g. BSD and SYSV) be sure to build for the +native flavor, not the emulated one. + +- Add an #ifdef SYSTEMTYPE section to the central util/sys_defs.h +include file. You may have to invent new feature macros. Please +choose sensible feature macro names such as HAS_DBM or +FIONREAD_IN_SYS_FILIO_H. I strongly recommend against #ifdef +SYSTEMTYPE dependencies in individual source files. This may seem +to be the quickest solution, but it will create a mess that becomes +increasingly difficult to maintain over time. Moreover, with the +next port you'd have to place #ifdefs all over the source code +again. + +6 - Installing the software after successful compilation +======================================================== + +This text describes how to install Postfix from source code. See +the PACKAGE_README file if you are building a package for distribution +to other systems. + +IMPORTANT: if you are REPLACING an existing sendmail installation +with Postfix, you may need to keep the old sendmail program running +for some time in order to flush the mail queue. As superuser, +execute the following commands (your sendmail, newaliases and mailq +programs may be in a different place): + + # mv /usr/sbin/sendmail /usr/sbin/sendmail.OFF + # mv /usr/bin/newaliases /usr/bin/newaliases.OFF + # mv /usr/bin/mailq /usr/bin/mailq.OFF + # chmod 755 /usr/sbin/sendmail.OFF /usr/bin/newaliases.OFF \ + /usr/bin/mailq.OFF + +In order to install or upgrade Postfix: + +- Create a user account "postfix" with a user id and group id that + are not used by any other user account. Preferably, this is an + account that no-one can log into. The account does not need an + executable login shell, and needs no existing home directory. + My password file entry looks like this: + + postfix:*:12345:12345:postfix:/no/where:/no/shell + +- Make sure there is a corresponding alias in /etc/aliases: + + postfix: root + +- Create a group "postdrop" with a group id that is not used by + any other user account. Not even by the postfix user account. + My group file entry looks like: + + postdrop:*:54321: + + NB: this group was optional with older Postfix releases; it is + now required. + +- Run one of the following commands as the super-user: + + # make install (interactive version, first time install) + # make upgrade (non-interactive version, for upgrades) + + The non-interactive version needs the /etc/postfix/main.cf file + from a previous installation. If the file does not exist, use + interactive installation instead. + + The interactive version offers suggestions for pathnames that + you can override interactively, and stores your preferences in + /etc/postfix/main.cf for convenient future upgrades. + +- Proceed to the section on how you wish to run Postfix on your + particular machine: + + - Send mail only, without changing an existing sendmail + installation (section 7). + + - Send and receive mail via a virtual host interface, still + without any change to an existing sendmail installation + (section 8). + + - Replace sendmail altogether (section 9). + +7 - Configuring Postfix to send mail only +========================================= + +If you are going to use Postfix to send mail only, there is no need +to change your existing sendmail setup. Instead, set up your mail +user agent so that it calls the Postfix sendmail program directly. + +Follow the instructions in the "Mandatory configuration file edits" +in section 10, and review the "To chroot or not to chroot" text in +section 11. + +You MUST comment out the `smtp inet' entry in /etc/postfix/master.cf, +in order to avoid conflicts with the real sendmail. + +Start the Postfix system: + + # postfix start + +or, if you feel nostalgic, use the Postfix sendmail command: + + # sendmail -bd -qwhatever + +and watch your syslog file for any error messages. + + % egrep '(reject|warning|error|fatal|panic):' /some/log/file + +Typical logfile names are: /var/log/maillog or /var/log/syslog. +See /etc/syslog.conf for actual logfile names. + +In order to inspect the mail queue, use + + % sendmail -bp + +See also the "Care and feeding" section 13 below. + +8 - Configuring Postfix to send and receive mail (virtual interface) +==================================================================== + +Alternatively, you can use the Postfix system to send AND receive +mail while leaving your sendmail setup intact, by running Postfix +on a virtual interface address. Simply configure your mail user +agent to directly invoke the Postfix sendmail program. + +The examples/virtual-setup directory gives instructions for setting +up virtual interfaces for a variety of UNIX versions. + +In the /etc/postfix/main.cf file, I would specify + + myhostname = virtual.host.name + inet_interfaces = $myhostname + mydestination = $myhostname + +Follow the instructions in the "Mandatory configuration file edits" +in section 10, and review the "To chroot or not to chroot" text in +section 11. + +Start the mail system: + + # postfix start + +or, if you feel nostalgic, use the Postfix sendmail program: + + # sendmail -bd -qwhatever + +and watch your syslog file for any error messages. + + % egrep '(reject|warning|error|fatal|panic):' /some/log/file + +Typical logfile names are: /var/log/maillog or /var/log/syslog. +See /etc/syslog.conf for actual logfile names. + +In order to inspect the mail queue, use + + % sendmail -bp + +See also the "Care and feeding" section 13 below. + +9 - Turning off sendmail forever +================================ + +Prior to installing Postfix you should save the existing sendmail +program files as described in section 6. + +Be sure to keep the old sendmail running for at least a couple +days to flush any unsent mail. To do so, stop the sendmail daemon +and restart it as: + + # /usr/sbin/sendmail.OFF -q + +After you have visited the "Mandatory configuration file edits" +section below, you can start the Postfix system with + + # postfix start + +But the good old sendmail way works just as well: + + # sendmail -bd -qwhatever + +and watch the syslog file for any complaints from the mail system. + + % egrep '(reject|warning|error|fatal|panic):' /some/log/file + +Typical logfile names are: /var/log/maillog or /var/log/syslog. +See /etc/syslog.conf for actual logfile names. + +See also the "Care and feeding" section 13 below. + +10 - Mandatory configuration file edits +======================================= + +By default, Postfix configuration files are in /etc/postfix, and +must be owned by root. Giving someone else write permission to +main.cf or master.cf means giving root privileges to that person. + +Whenever you make a change to a config file, execute the following +command in order to refresh a running mail system: + + # postfix reload + +In /etc/postfix/main.cf you will have to set up a minimal number of +configuration parameters. Postfix configuration parameters +resemble shell variables. You specify a variable as + + parameter = value + +and you use it by putting a $ in front of its name: + + other_parameter = $parameter + +You can use $parameter before it is given a value. The Postfix +configuration language uses lazy evaluation, and does not look at +a parameter value until it is needed at runtime. + +First of all, you must specify what domain will be appended to an +unqualified address (i.e. an address without @domain.name). The +"myorigin" parameter defaults to the local hostname, but that is +probably OK only for very small sites. + +Some examples: + + myorigin = $myhostname + myorigin = $mydomain + +In the first case, local mail goes out as user@$myhostname, in +the second case the sender address is user@$mydomain. + +Next you need to specify what mail addresses Postfix should deliver +locally. + +Some examples: + + mydestination = $myhostname, localhost.$mydomain + mydestination = $myhostname, localhost.$mydomain, $mydomain + mydestination = $myhostname + +The first example is appropriate for a workstation, the second is +appropriate for the mailserver for an entire domain. The third +example should be used when running on a virtual host interface. + +If your machine is on an open network then you must specify what +client IP addresses are authorized to relay their mail through your +machine. The default setting includes all class A, B or C networks +that the machine is attached to. Often, that gives relay permission +to too many clients. My own settings are: + + mynetworks = 168.100.189.0/28, 127.0.0.0/8 + +If you're behind a firewall, you should set up a relayhost. If +you can, specify the organizational domain name so that Postfix +can use DNS lookups, and so that it can fall back to a secondary +MX host when the primary MX host is down. Otherwise just specify +a hard-coded hostname. + +Some examples: + + relayhost = $mydomain + relayhost = mail.$mydomain + relayhost = [mail.$mydomain] + +The form enclosed with [] eliminates DNS MX lookups. + +By default, the SMTP client will do DNS lookups for sender and +recipient addresses even when you specify a relay host. If your +machine has no access to a DNS server, turn off SMTP client DNS +lookups like this: + + disable_dns_lookups = yes + +The FAQ (html/faq.html) has more hints and tips for firewalled +and/or dial-up networks. + +Finally, if you haven't used Sendmail prior to using Postfix, you +will have to build the alias database (with: sendmail -bi, or: +newaliases). Be sure to set up aliases for root and postmaster that +forward mail to a real person. Postfix has a sample aliases file +conf/aliases that you can adapt to local conditions. + +11 - To chroot or not to chroot +=============================== + +Postfix can run most daemon processes in a chroot jail, that is, +the processes run at a fixed low privilege and with access only to +the Postfix queue directories (/var/spool/postfix). This provides +a significant barrier against intrusion. The barrier is not +impenetrable, but every little bit helps. + +With the exception of the Postfix local delivery and `pipe' daemons, +every Postfix daemon can run chrooted. + +Sites with high security requirements should consider to chroot +all daemons that talk to the network: the smtp and smtpd processes, +and perhaps also the lmtp client. + +The default /etc/postfix/master.cf file specifies that no Postfix +daemon runs chrooted. In order to enable chroot operation, edit +the file /etc/postfix/master.cf. Instructions are in the file. + +Note that a chrooted daemon resolves all filenames relative to the +Postfix queue directory (/var/spool/postfix). For successful use +of a chroot jail, most UNIX systems require you to bring in some +files or device nodes. The examples/chroot-setup directory has a +collection of scripts that help you set up chroot environments for +Postfix systems. + +12 - Care and feeding of the Postfix system +=========================================== + +The Postfix programs log all problems to the syslog daemon. The +names of logfiles are specified in /etc/syslog.conf. Note: the +syslogd will not create files. You must create them ahead of time +before (re)starting syslogd. At the very least you need something +like: + + mail.err /dev/console + mail.debug /var/log/maillog + +Hopefully, the number of problems will be small, but it is a good +idea to run every night before the syslog files are rotated: + + # postfix check + # egrep '(reject|warning|error|fatal|panic):' /some/log/file + +Typical logfile names are: /var/log/maillog or /var/log/syslog. +See /etc/syslog.conf for actual logfile names. + +The first line (postfix check) causes Postfix to report file +permission/ownership discrepancies. + +The second line looks for problem reports from the mail software, +and reports how effective the anti-relay and anti-UCE blocks are. diff --git a/gnu/dist/postfix/README_FILES/LDAP_README b/gnu/dist/postfix/README_FILES/LDAP_README new file mode 100644 index 00000000000..a69ebde3b99 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/LDAP_README @@ -0,0 +1,331 @@ +LDAP SUPPORT IN POSTFIX +======================= + +Postfix can use an LDAP directory as a source for any of its lookups: +aliases, virtual, canonical, etc. This allows you to keep information +for your mail service in a replicated network database with fine-grained +access controls. By not storing it locally on the mail server, the +administrators can maintain it from anywhere, and the users can control +whatever bits of it you think appropriate. You can have multiple mail +servers using the same information, without the hassle and delay of +having to copy it to each. + +BUILDING WITH LDAP SUPPORT +========================== + +You need to have LDAP libraries and include files installed somewhere on +your system, and you need to configure the Postfix Makefiles +accordingly. + +If you're using the libraries from the UM distribution +(http://www.umich.edu/~dirsvcs/ldap/ldap.html) or OpenLDAP +(http://www.openldap.org), something like this in the top level of your +Postfix source tree should work: + + % make tidy + % make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \ + AUXLIBS="-L/usr/local/lib -lldap -L/usr/local/lib -llber" + +On Solaris 2.x you may have to specify run-time link information, +otherwise ld.so will not find some of the shared libraries: + + % make tidy + % make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \ + AUXLIBS="-L/usr/local/lib -R/usr/local/lib -lldap \ + -L/usr/local/lib -R/usr/local/lib -llber" + +The 'make tidy' command is needed only if you have previously built +Postfix without LDAP support. + +Instead of '/usr/local' specify the actual locations of your LDAP +include files and libraries. Be sure to not mix LDAP include files +and LDAP libraries of different versions!! + +If your LDAP libraries were built with Kerberos support, you'll also +need to include your Kerberos libraries in this line. Note that the KTH +Kerberos IV libraries might conflict with Postfix's lib/libdns.a, which +defines dns_lookup. If that happens, you'll probably want to link with +LDAP libraries that lack Kerberos support just to build Postfix, as it +doesn't support Kerberos binds to the LDAP server anyway. Sorry about +the bother. + +If you're using one of the Netscape LDAP SDKs, you'll need to change the +AUXLIBS line to point to libldap10.so or libldapssl30.so or whatever you +have, and you may need to use the appropriate linker option (e.g. '-R') +so the executables can find it at runtime. + +CONFIGURING LDAP LOOKUPS +======================== + +In order to use LDAP lookups, define at least one LDAP source as a table +lookup in main.cf, for example: + + alias_maps = hash:/etc/aliases, ldap:ldapsource + +Each LDAP source can have the following parameters, which should be +prefixed in main.cf with the name you've given the source in its +definition and an underscore. To continue the example, the first +parameter below, "server_host", would be defined in main.cf as +"ldapsource_server_host". Defaults are given in parentheses: + + server_host (localhost) + The name of the host running the LDAP server, e.g. + ldapsource_server_host = ldap.your.com + It should be possible with all the libraries mentioned above to + specify multiple servers separated by spaces, with the libraries + trying them in order should the first one fail. It should also + be possible to give each server in the list a different port, by + naming them like "ldap.your.com:1444". + + server_port (389) + The port the LDAP server listens on, e.g. + ldapsource_server_port = 778 + + search_base (No default; you must configure this.) + The base at which to conduct the search, e.g. + ldapsource_search_base = dc=your, dc=com + + timeout (10 seconds) + The number of seconds a search can take before timing out, e.g. + ldapsource_timeout = 5 + + query_filter (mailacceptinggeneralid=%s) + The RFC2254 filter used to search the directory, where %s is a + substitute for the address Postfix is trying to resolve, e.g. + ldapsource_query_filter = (&(mail=%s)(paid_up=true)) + + domain (Default is to ignore this.) + This is a list of domain names, paths to files, or dictionaries. + If specified, only lookups for the domains on this list will be + performed. This means that the LDAP map won't get searched for + 'user', nor will it get searched for any domain not listed. This + can significantly reduce the query load on the LDAP server. + ldapsource_domain = postfix.org, hash:/etc/postfix/searchdomains + + result_attribute (maildrop) + The attribute(s) Postfix will read from any directory entries + returned by the lookup, to be resolved to an email address. + ldapsource_result_attribute = mailbox,maildrop + + special_result_attribute (No default) + The attribute(s) of directory entries that can contain DNs or URLs. + If found, a recursive subsequent search is done using their values. + ldapsource_special_result_attribute = member + + scope (sub) + The LDAP search scope: sub, base, or one. These translate into + LDAP_SCOPE_SUBTREE, LDAP_SCOPE_BASE, and LDAP_SCOPE_ONELEVEL. + + bind (yes) + Whether or not to bind to the LDAP server. Newer LDAP + implementations don't require clients to bind, which saves + time. Example: + ldapsource_bind = no + + If you do need to bind, you might consider configuring Postfix + to connect to the local machine on a port that's an SSL tunnel + to your LDAP server. If your LDAP server doesn't natively + support SSL, put a tunnel (wrapper, proxy, whatever you want to + call it) on that system too. This should prevent the password + from traversing the network in the clear. + + bind_dn ("") + If you do have to bind, do it with this distinguished name. + Example: + ldapsource_bind_dn = uid=postfix, dc=your, dc=com + + bind_pw ("") + The password for the distinguished name above. If you have to + use this, you probably want to make main.cf readable only by + the Postfix user. Example: + ldapsource_bind_pw = postfixpw + + cache (no) + Whether to use a client-side cache for the LDAP connection. See + ldap_enable_cache(3). It's off by default. + + cache_expiry (30 seconds) + If the client-side cache is enabled, cached results will expire + after this many seconds. + + cache_size (32768 bytes) + If the client-side cache is enabled, this is its size in bytes. + + dereference (0) + When to dereference LDAP aliases. (Note that this has nothing + do with Postfix aliases.) The permitted values are those + legal for the OpenLDAP/UM LDAP implementations: + + 0 never + 1 when searching + 2 when locating the base object for the search + 3 always + + See ldap.h or the ldap_open(3) or ldapsearch(1) man pages for + more information. And if you're using an LDAP package that has + other possible values, please bring it to the attention of the + postfix-users@postfix.org mailing list. + + debuglevel (0) + What level to set for debugging in the OpenLDAP libraries. + +Don't use quotes in these variables; at least, not until the Postfix +configuration routines understand how to deal with quoted strings. + +EXAMPLES +======== + +ALIASES +------- + +Here's a basic example for using LDAP to look up aliases. Assume that in +main.cf, you have these configuration parameters defined: + +alias_maps = hash:/etc/aliases, ldap:ldapsource +ldapsource_server_host = ldap.my.com +ldapsource_search_base = dc=my, dc=com + +Upon receiving mail for a local address "ldapuser" that isn't found in +the /etc/aliases database, Postfix will search the LDAP server listening +at port 389 on ldap.my.com. It will bind anonymously, search for any +directory entries whose mailacceptinggeneralid attribute is "ldapuser", +read the "maildrop" attributes of those found, and build a list of their +maildrops, which will be treated as RFC822 addresses to which the +message will be delivered. + +VIRTUAL DOMAINS/ADDRESSES +------------------------- + +If you want to keep information for virtual lookups in your directory, +it's only a little more complicated. First you need to make sure Postfix +knows about the virtual domain. An easy way to do that is to add the +domain to the mailacceptinggeneralid attribute of some entry in the +directory. Next you'll want to make sure all of your virtual recipients' +mailacceptinggeneralid attributes are fully qualified with their virtual +domains. Finally, if you want to designate a directory entry as the +default user for a virtual domain, just give it an additional +mailacceptinggeneralid (or the equivalent in your directory) of +"@virtual.dom". That's right, no user part. If you don't want a catchall +user, omit this step and mail to unknown users in the domain will simply +bounce. + +If you're using a version of Postfix newer than 19991226, that should do +it. If not, you also need to add your virtual domains to relay_domains. +Simply add "$virtual_maps" to your relay_domains line. Then you can use +the same map you use to find virtual recipients to determine if a domain +is a valid virtual domain and should be allowed to relay. + +In summary, you might have a catchall user for a virtual domain that +looks like this: + + dn: cn=defaultrecipient, dc=fake, dc=dom + objectclass: top + objectclass: virtualaccount + cn: defaultrecipient + owner: uid=root, dc=someserver, dc=isp, dc=dom + 1 -> mailacceptinggeneralid: fake.dom + 2 -> mailacceptinggeneralid: @fake.dom + 3 -> maildrop: realuser@real.dom + +1: Postfix knows fake.dom is a valid virtual domain when it looks for + this and gets something (the maildrop) back. + +2: This causes any mail for unknown users in fake.dom to go to this entry ... + +3: ... and then to its maildrop. + +Normal users might simply have one mailacceptinggeneralid and maildrop, +e.g. "normaluser@fake.dom" and "normaluser@real.dom". + +OTHER USES +---------- + +Other common uses for LDAP lookups include rewriting senders and +recipients with Postfix' canonical lookups, for example in order to make +mail leaving your site appear to be coming from "First.Last@site.dom" +instead of "userid@site.dom". + +NOTES AND THINGS TO THINK ABOUT +=============================== + +- The bits of schema and attribute names used in this document are just + examples. There's nothing special about them, other than that some are + the defaults in the LDAP configuration parameters. You can use + whatever schema you like, and configure Postfix accordingly. + +- You probably want to make sure that mailacceptinggeneralids are + unique, and that not just anyone can specify theirs as postmaster or + root, say. + +- An entry can have an arbitrary number of mailacceptinggeneralids or + maildrops. Maildrops can also be comma-separated lists of addresses. + They will all be found and returned by the lookups. For example, you + could define an entry intended for use as a mailing list that looks + like this (Warning! Schema made up just for this example): + + dn: cn=Accounting Staff List, dc=my, dc=com + cn: Accounting Staff List + o: my.com + objectclass: maillist + mailacceptinggeneralid: accountingstaff + mailacceptinggeneralid: accounting-staff + maildrop: mylist-owner + maildrop: an-accountant + maildrop: some-other-accountant + maildrop: this, that, theother + +- If you use an LDAP map for lookups other than aliases, you may have to + make sure the lookup makes sense. In the case of virtual lookups, + maildrops other than mail addresses are pretty useless, because + Postfix can't know how to set the ownership for program or file + delivery. Your query_filter should probably look something like this: + + virtual_query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*")(maildrop="*/*")))) + +- And for that matter, even for aliases, you may not want users able to + specify their maildrops as programs, includes, etc. This might be + particularly pertinent on a "sealed" server where they don't have + local UNIX accounts, but exist only in LDAP and Cyrus. You might allow + the fun stuff only for directory entries owned by an administrative + account: + + local_query_filter = (&(mailacceptinggeneralid=%s)(|(!(maildrop="*|*")(maildrop="*:*")(maildrop="*/*"))(owner=cn=root, dc=your, dc=com))) + + So that if the object had a program as its maildrop and weren't owned + by "cn=root" it wouldn't be returned as a valid local user. This will + require some thought on your part to implement safely, considering the + ramifications of this type of delivery. You may decide it's not worth + the bother to allow any of that nonsense in LDAP lookups, ban it in + the query_filter, and keep things like majordomo lists in local alias + databases. + +- LDAP lookups are slower than local DB or DBM lookups. For most sites + they won't be a bottleneck, but it's a good idea to know how to tune + your directory service. + +FEEDBACK +======== + +If you have questions, send them to postfix-users@postfix.org. Please +include relevant information about your Postfix setup: LDAP-related +output from postconf, which LDAP libraries you built with, and which +directory server you're using. If your question involves your directory +contents, please include the applicable bits of some directory entries. + +CREDITS +======= + +Manuel Guesdon: Spotted a bug with the ldapsource_timeout attribute. +John Hensley: Multiple LDAP sources with more configurable attributes. +Carsten Hoeger: Search scope handling. +LaMont Jones: Domain restriction, URL and DN searches, multiple result + attributes. +Mike Mattice: Alias dereferencing control. +Hery Rakotoarisoa: Patches for LDAPv3 updating. +Prabhat K Singh: Wrote the initial Postfix LDAP lookups and connection caching. +Keith Stevenson: RFC 2254 escaping in queries. +Samuel Tardieu: Noticed that searches could include wildcards, prompting + the work on RFC 2254 escaping in queries. Spotted a bug + in binding. + +And of course Wietse. diff --git a/gnu/dist/postfix/README_FILES/LINUX_README b/gnu/dist/postfix/README_FILES/LINUX_README new file mode 100644 index 00000000000..410cd7f0842 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/LINUX_README @@ -0,0 +1,20 @@ +LINUX PORTABILITY +================= + +On RedHat Linux 7.0 you must install the db3-devel RPM before you +can compile the Postfix source code. + +On RedHat Linux 7.1 procmail no longer has permission to write the +mail spool directory. Workaround: chmod 1777 /var/spool/mail. + +LINUX SYSLOGD PERFORMANCE +========================= + +LINUX syslogd uses synchronous writes by default. Because of this, +syslogd can actually use more system resources than Postfix. To +avoid such madness, disable synchronous mail logfile writes by +editing /etc/syslog.conf and by prepending a - to the logfile name: + + mail.* -/var/log/mail.log + +Send a "kill -HUP" to the syslogd to make the change effective. diff --git a/gnu/dist/postfix/README_FILES/LMTP_README b/gnu/dist/postfix/README_FILES/LMTP_README new file mode 100644 index 00000000000..ca051466b77 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/LMTP_README @@ -0,0 +1,485 @@ +[This file still needs to be updated - some information is obsolete] + +1 - Postfix LMTP support +======================== + +LMTP stands for Local Mail Transfer Protocol, and is detailed in +RFC2033. Postfix uses this protocol to communicate with the final +delivery agent, which may run on the local host or a remote host. + +This protocol opens up interesting possibilities: one Postfix front +end machine can drive multiple mailbox back end machines over LMTP. +As the mail load increases, you add more Postfix front end systems +and more LMTP mailbox back end systems. This is the model that I +had in mind when I began drafting the design for Postfix - a scalable +architecture that allows you to keep adding SMTP servers and mailbox +servers painlessly. + +Such a distributed architecture needs glue to keep things together. +You can use a networked database LDAP or mysql to share the user +database among the front end and back end systems. Use a replicated +database so that no machine becomes a single point of failure for +the entire mail infrastructure. + +Postfix LMTP support is based on a modified version of the Postfix +SMTP client. The initial version was by Philip A. Prindeville of +Mirapoint, Inc., USA. This code was modified further by Amos Gouaux +of University of Texas at Dallas, Richardson, USA, who also revised +much of the documentation. Wietse Venema reduced the code to its +present shape. + + +2 - Overview +============ + +Most of the examples in this document involve the CMU Cyrus IMAP/POP +server, available from: + + http://asg.web.cmu.edu/cyrus/ + +While certainly not the only application that could make use of +LMTP, it tends to be the most discussed. These examples are based +on the forthcoming Cyrus 2.0.10, at least at the time of writing. +The 2.x branch of Cyrus places greater emphasis on LMTP delivery +than the previous releases. Those using older releases of Cyrus +can find a discussion in the appendix of this document. + +There are a variety of ways LMTP delivery can be configured in +Postfix. The two basic flavors are delivery over UNIX-domain +sockets and delivery over TCP sockets. + + o Connections from the Postfix LMTP client over UNIX-domain + sockets allow you to deliver to non-Postfix LMTP servers running + on the same machine. + + o Connections from the Postfix LMTP client over TCP sockets allow + you to deliver to non-Postfix LMTP servers across a local + network. + +Note: the above is not to be confused with the UNIX-domain sockets +that Postfix uses internally to speak its own protocols with the +Postfix LMTP client. + +The precise syntax for UNIX-domain and TCP connection endpoints is +given in the lmtp(8) manual page. Examples are also given in the +text below. + +Both socket flavors can be specified in either the Postfix main.cf +file (see section 5) or in a Postfix transport map (section 6). +What is the best approach for you depends upon the arrangement of +your servers and the desired level of parallelization. + +Please be sure to study this entire document as there are trade-offs +in convenience and in performance with these different approaches. + +3 - LMTP over UNIX-domain sockets +================================= + +Use this to deliver mail from the Postfix LMTP client to an LMTP +server that is running on the same system. + +A UNIX-domain socket is specified as the socket type ("unix") and +a name in the local file system: + + unix:/path/name + +The "/path/name" part should be the name of a socket created by +the LMTP server on the local machine. See the specific examples +later in this document. + +NOTE: + + If you run the Postfix LMTP client chrooted, the interpretation + of the /path/name is relative to the Postfix queue directory + (typically, /var/spool/postfix). + + By default, the Postfix LMTP client does not run chrooted. + With LMTP delivery to the local machine there is no good reason + to run the Postfix LMTP client chrooted. + +4 - LMTP over TCP sockets +========================= + +Use this to deliver mail from the Postfix LMTP client to an LMTP +server that is running on the same system or on a different system. + +A TCP destination is specified as the socket type ("inet"), the +destination hostname and the TCP port: + + inet:hostname:port + +The "inet:" part can be omitted, as it is the default socket type. + +The destination port can be omitted as well. Currently the default +TCP port number for this type of connection is 24, but this can be +customized in the "/etc/services" file. Specific examples are +given later in this document. + +NOTE: + + With connections over TCP sockets, later Cyrus LMTP server + implementations insist on SASL-style authentication. This means + that Postfix must be built with SASL support (see SASL_README). + The examples below show how to enable this in the Postfix LMTP + client. + + Some Cyrus LMTP server implementations do not allow SASL-style + authentication via plaintext passwords. You will have to jump + some extra hoops in order to enable MD5 password support, or + you will have to wait until this restriction is relaxed. + + +5 - Configuring LMTP using main.cf configuration +================================================ + +This is the simplest LMTP configuration. + +5.1 - Delivery mechanisms +------------------------- + +Postfix main.cf supports three mechanisms to deliver mail to an +LMTP server. Each method can use UNIX-domain or TCP sockets as +described in a later section. + +main.cf mechanism 1 +------------------- + +mailbox_transport = lmtp:unix:/path/name (UNIX-domain socket example) +mailbox_transport = lmtp:hostname:port (TCP socket example) + +Mail that resolves as local (domain is listed in $mydestination) +is given to the Postfix local delivery agent. The Postfix local +delivery agent expands aliases and .forward files, and delegates +mailbox delivery to the Postfix LMTP client which then sends it to +the non-Postfix LMTP server. + +main.cf mechanism 2 +------------------- + +local_transport = lmtp:unix:/path/name (UNIX-domain socket example) +local_transport = lmtp:hostname:port (TCP socket example) + +Mail that resolves as local (domain is listed in $mydestination) +is directly given to the Postfix LMTP client which then sends it +to the non-Postfix LMTP server. The mail is not processed by the +Postfix local delivery agent; therefore aliases and .forward files +are not processed. + +main.cf mechanism 3 +------------------- + +fallback_transport = lmtp:unix:/path/name (UNIX-domain socket example) +fallback_transport = lmtp:hostname:port (TCP socket example) + +Mail that resolves as local (domain is listed in $mydestination) +is given to the Postfix local delivery agent. The Postfix local +delivery agent processes aliases and .forward files, and delivers +to /var[/spool]/mail/$user for users that have a UNIX account. +Mail for other local users is delegated to the Postfix LMTP client +which then sends it to the non-Postfix LMTP server. + +5.2 - Examples +-------------- + +5.2.1 - LMTP over UNIX-domain sockets +------------------------------------- + +To utilize UNIX-domain sockets for the communication between +Postfix and Cyrus, the corresponding configuration files should +look something like this: + +/etc/cyrus.conf: + + SERVICES { + ... + lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1 + ... + } + +/etc/postfix/main.cf: + + mailbox_transport = lmtp:unix:/var/imap/socket/lmtp + +/etc/postfix/master.cf: + + lmtp unix - - n - - lmtp + +In this case, the Postfix local delivery agent expands aliases +and .forward files, and delegates mailbox delivery to the Cyrus +lmtpd server via the socket "/var/imap/socket/lmtp". + +5.2.2 - LMTP over TCP sockets +----------------------------- + +For this example, suppose the following files are configured +thusly: + +/etc/cyrus.conf: + + SERVICES { + ... + lmtp cmd="lmtpd" listen="127.0.0.1:lmtp" prefork=0 + ... + } + +/etc/services: + + lmtp 24/tcp + +/etc/postfix/main.cf: + + mailbox_transport = lmtp:localhost + lmtp_sasl_auth_enable = yes + lmtp_sasl_password_maps = hash:/etc/postfix/lmtp_sasl_pass + +/etc/postfix/lmtp_sasl_pass: + localhost.my.domain username:password + +/etc/postfix/master.cf: + + lmtp unix - - n - - lmtp + +Instead of "hash", use the map type of your choice. Some systems +use "dbm" instead. Use "postconf -m" to find out what map types +are supported. + +With the above settings, the Postfix local delivery agent expands +aliases and .forward files, and delegates mailbox delivery to the +Cyrus LMTP server. Postfix makes a connection to port 24 on the +local host, subsequently transmitting the message to the lmtpd +server managed by the Cyrus master process. + + +6 - Configuring LMTP using transport map configuration +====================================================== + +This approach is quite similar to specifying the LMTP service in +the Postfix main.cf configuration file. However, now we will use +a transport map to route mail to the appropriate LMTP server, +instead of depending on delegation by the Postfix local delivery +agent. + +Why might this approach be useful? This could be handy if you wish +to route mail for multiple domains to their respective mail retrieval +(IMAP/POP) server. Example: + + /etc/postfix/transport: + + domain1.name lmtp1:unix:/path/name + domain2.name lmtp2:lmtp2host + + /etc/postfix/master.cf: + + lmtp1 unix - - n - - lmtp + lmtp2 unix - - n - - lmtp + + /etc/postfix/main.cf: + + transport_maps = hash:/etc/postfix/transport + +For details of the Cyrus LMTP server configuration, see section 5. + +Instead of "hash", use the map type of your choice. Some systems use +"dbm" instead. Use "postconf -m" to find out what map types are +supported. + + +7 - Performance considerations +============================== + +Hopefully the preceding discussion has seemed pretty straight +forward. Now things get interesting. After reading the following +you will see that there are more factors to consider when setting +up LMTP services. + + +8 - Single instance message store +================================= + +Presently this topic is more pertinent to sites running Cyrus, but +may be a factor with other applications as well. + +Since 1.6.22, Cyrus has had the feature that if a message containing +multiple recipients is received via the LMTP protocol, and all +these recipients were on the same Cyrus partition, only one instance +of this message would be written to the file system. The other +recipients would then see a hard link of this single instance. +Depending on your user base, this can be considerable motivation +to using LMTP. + +However, there is a catch: the Postfix local delivery agent is +designed to deliver one recipient at a time, which in most cases +is more than adequate. So, if you wish to support single instance +message store delivery, you will have to use a virtual table to +map these users to the appropriate LMTP destination (at the time +of writing, the Postfix transport table supports only per-domain +routing, and not per-recipient routing). + +While the simplest thing to do would be to list the entire domain +in the transport map for LMTP delivery, this by-passes alias +expansion for otherwise local addresses (see section 5.1, delivery +mechanism 2). If the site is to run software via aliases, like +most Mailing List Management (MLM) software, a more complex solution +is required. A virtual table should do the trick. + +As an example, suppose we wanted to support single instance message +store delivery for the hosted (not local) domain "example.org". +The configuration files for this domain could look something like +this: + + /etc/postfix/virtual: + + mlist@example.org mlist@localhost + + /etc/postfix/transport: + + example.org lmtp:unix:/var/imap/socket/lmtp + + /etc/postfix/aliases: + + mlist: "|/path/to/mlm/software" + + /etc/postfix/master.cf: + + lmtp unix - - n - - lmtp + + /etc/postfix/main.cf: + + mydestination = localhost, $myhostname, $mydomain + virtual_maps = hash:/etc/postfix/virtual + transport_maps = hash:/etc/postfix/transport + alias_maps = hash:/etc/postfix/aliases + alias_database = hash:/etc/postfix/aliases + + /etc/cyrus.conf: + + SERVICES { + ... + lmtpunix cmd="lmtpd" listen="/var/imap/socket/lmtp" prefork=1 + ... + } + +Breaking things down, we begin with the address "mlist@example.org", +which represents a mailing list. By placing an entry in the virtual +map to direct this mail to "mlist@localhost", we can override the +transport map that would by default route all "@example.org" mail +to a LMTP server via a UNIX-domain socket. + +To summarize, all mail that is to be processed by an alias entry +must first be diverted with a virtual table entry so that it does +not fall into the more general routing established by the transport +table. + + +9 - Improving connection caching performance +============================================ + +After delivering a message via LMTP, Postfix will keep the connection +open for a while, so that it can be reused for a subsequent delivery. +This reduces overhead of LMTP servers that create one process per +connection. + +For LMTP connection caching to work, the Postfix LMTP client should +not switch destination hosts. This is no problem when you run only +one LMTP server. However, if you run multiple LMTP servers, this +can be an issue. + +You can prevent the LMTP client from switching between servers by +configuring a separate LMTP delivery transport for each LMTP server: + + /etc/postfix/master.cf: + + lmtp1 unix - - n - - lmtp + lmtp2 unix - - n - - lmtp + . . . . . . . . + +Configure transport table entries such that the lmtp1 mail delivery +transport is used for all deliveries to the LMTP server #1, the +mail lmtp2 transport for the LMTP server #2, and so on. + + /etc/postfix/transport: + + foo.com lmtp1:lmtp1host + bar.com lmtp2:lmtp2host + + +10 - Appendix: Older Cyrus versions +=================================== + +First of all, if you are using a Cyrus 2.x version prior to 2.0.10, +it would be good to upgrade. The previous 2.x releases were beta +releases, and numerous bug fixes and enhancements have been +incorporated into the 2.0.10 release. + +Further back, 1.6.24 was the last pre-2.x production release. +(Actually, there was a 1.6.25-BETA, but it is uncertain whether this +will be released officially as CMU is now focusing support on the 2.x +branch.) The following discussion touches on how to configure the +Postfix LMTP facilities with Cyrus 1.6.24. + +One of the significant differences between Cyrus 1.x and 2.x is the +inclusion of the "master" process in 2.x. This "master" process is +responsible for running the various components of Cyrus, such as +imapd, pop3d, and lmtpd. Prior to 2.x, these services were managed +by inetd, the Internet services daemon. + +To utilize LMTP delivery with Cyrus 1.6.24, the first thing to do is +configure inetd. This involves the following file edits: + + /etc/services: + + lmtp 24/tcp + + /etc/inetd.conf: + + lmtp stream tcp nowait cyrus /usr/sbin/tcpd /usr/cyrus/bin/deliver -e -l + + /etc/hosts.allow: + + deliver : localhost : ALLOW + deliver : ALL@ALL : DENY + +The "/usr/sbin/tcpd" is from the tcp_wrappers package, which is +discussed in the example "LMTP over TCP sockets, using hosts.allow." +It is important that you wrap this LMTP port to protect it from +unauthorized access. + +On some systems, tcpd is built into inetd, so you do not have to +specify tcpd in the inetd.conf file. Instead of tcpd/inetd, xinetd +can do a similar job of logging and access control. + +Now comes the Postfix configuration. Basically, the Cyrus 2.x +discussions regarding LMTP delivery over TCP are also applicable to +Cyrus 1.x, with the exception of the "/etc/cyrus.conf" file. A +typical Postfix configuration might look like this: + + /etc/postfix/master.cf: + + lmtp unix - - n - - lmtp + + /etc/postfix/main.cf: + + mailbox_transport = lmtp + +It is also possible to use the transport map to route mail to your +Cyrus 1.6.24 LMTP server: + + /etc/postfix/transport: + + domain1.name lmtp1:lmtp1host + domain2.name lmtp2:lmtp2host + + /etc/postfix/master.cf: + + lmtp1 unix - - n - - lmtp + lmtp2 unix - - n - - lmtp + + /etc/postfix/main.cf: + + transport_maps = hash:/etc/postfix/transport + +If you have read the discussion covering the Cyrus 2.x installation, +you will notice the one significant difference with the Postfix +configuration is the lack of mention of the UNIX-domain sockets. +That is because delivery over UNIX-domain sockets is new with Cyrus +2.x, yet another reason to upgrade. :-) diff --git a/gnu/dist/postfix/README_FILES/MACOSX_README b/gnu/dist/postfix/README_FILES/MACOSX_README new file mode 100644 index 00000000000..24f37094de2 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/MACOSX_README @@ -0,0 +1,2 @@ +See the files in auxiliary/MacOSX for hints and tips to set up +Postfix. diff --git a/gnu/dist/postfix/README_FILES/MYSQL_README b/gnu/dist/postfix/README_FILES/MYSQL_README new file mode 100644 index 00000000000..2f11bd9566e --- /dev/null +++ b/gnu/dist/postfix/README_FILES/MYSQL_README @@ -0,0 +1,92 @@ +[Code contributed by Scott Cotton and Joshua Marcus, IC Group, Inc.] + +We've written code to add a mysql map type. It utilizes the mysql +client library, which can be obtained from: + + http://www.mysql.com/downloads/ + http://sourceforge.net/projects/mysql/ + +In order to build postfix with mysql map support, you will need to add +-DHAS_MYSQL and -I for the directory containing the mysql headers, and +the mysqlclient library (and libm) to AUXLIBS, for example: + +make -f Makefile.init makefiles \ + 'CCARGS=-DHAS_MYSQL -I/usr/local/mysql/include' \ + 'AUXLIBS=-L/usr/local/mysql/lib -lmysqlclient -lz -lm' + +then, just run 'make'. This requires libz, the compression library. +Older mysql implementations build without libz. + +Postfix installations which may benefit from using mysql map types +include sites that have a need for instantaneous updates of +forwarding, and sites that may benefit from having mail exchangers +reference a networked database, possibly working in conjunction with a +customer database of sorts. + +Once postfix is built with mysql support, you can specify a map type +in main.cf like this: + +alias_maps = mysql:/etc/postfix/mysql-aliases.cf + +The file /etc/postfix/mysql-aliases.cf specifies lots of information +telling postfix how to reference the mysql database. An example mysql +map config file follows: + +# +# mysql config file for alias lookups on postfix +# comments are ok. +# + +# the user name and password to log into the mysql server +user = someone +password = some_password + +# the database name on the servers +dbname = customer_database + +# the table name +table = mxaliases + +# +select_field = forw_addr +where_field = alias + +# you may specify additional_conditions here +additional_conditions = and status = 'paid' + +# the above variables will result in a query of +# the form: +# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid' +# ($lookup is escaped so if it contains single quotes or other odd +# characters, it will not cause a parse error in the sql). +# +# the hosts that postfix will try to connect to +# and query from (in the order listed) +# specify unix: for unix-domain sockets, inet: for TCP connections (default) +hosts = host1.some.domain host2.some.domain unix:/file/name + +# end mysql config file + +Some notes: + +This configuration interface setup allows for multiple mysql +databases: you can use one for a virtual table, one for an access +table, and one for an aliases table if you want. + +Since sites that have a need for multiple mail exchangers may enjoy +the convenience of using a networked mailer database, but do not want +to introduce a single point of failure to their system, we've included +the ability to have postfix reference multiple hosts for access to a +single mysql map. This will work if sites set up mirrored mysql +databases on two or more hosts. Whenever queries fail with an error +at one host, the rest of the hosts will be tried in order. Each host +that is in an error state will undergo a reconnection attempt every so +often, and if no mysql server hosts are reachable, then mail will be +deferred until at least one of those hosts is reachable. + +Performance of postfix with mysql has not been thoroughly tested, +however, we have found it to be stable. Busy mail servers using mysql +maps will generate lots of concurrent mysql clients, so the mysql +server(s) should be run with this fact in mind. Any further +performance information, in addition to any feedback is most welcome. + diff --git a/gnu/dist/postfix/README_FILES/NFS_README b/gnu/dist/postfix/README_FILES/NFS_README new file mode 100644 index 00000000000..ac489de7d9e --- /dev/null +++ b/gnu/dist/postfix/README_FILES/NFS_README @@ -0,0 +1,37 @@ +> Also, what considerations are there for file locking or other potential +> problems when running Postfix with a Netapp-style box for /var/mail +> delivery? I know that FreeBSD has broken NFS file locking (both client +> and server?) but I'm not sure if this is something Postfix can work around +> or not. + +Postfix jumps several hoops in order to deal with NFS-specific +brain damage, however some operations can fail irrecoverably. This +is why Wietse makes no promises about Postfix reliability on NFS. + +For queue locking, NFS is not an issue because you cannot share +Postfix queues between Postfix instances anyawy. + +For mailbox locking, some systems use flock() by default (use: +``postconf mailbox_delivery_lock'' and ``postconf virtual_mailbox_lock'' +to find out about your system). flock() does not work over NFS. +This causes loss of mail when multiple hosts access the same +mailboxes. + +In order to have mailbox locking over NFS you have to configure +everything to use fcntl() locks for mailbox access (or switch to +maildir style, which needs no application-level lock controls). + +To turn on fcntl locks with Postfix you specify: + + virtual_mailbox_lock = fcntl + mailbox_delivery_lock = fcntl + +This is useful only if all mailbox access software uses fcntl() +locks. I have no information on how well fcntl() locks work on NFS. + +You can also "play safe" and throw in username.lock files: + + virtual_mailbox_lock = fcntl, dotlock + mailbox_delivery_lock = fcntl, dotlock + +this is the mix that many applications end up using. diff --git a/gnu/dist/postfix/README_FILES/PACKAGE_README b/gnu/dist/postfix/README_FILES/PACKAGE_README new file mode 100644 index 00000000000..11113515b8c --- /dev/null +++ b/gnu/dist/postfix/README_FILES/PACKAGE_README @@ -0,0 +1,103 @@ +Purpose of this document +======================== + +This document has hints and tips for those who manage their own +Postfix distribution for internal use, and for those who maintain +Postfix distributions for general use. + +General distributions: please provide a small default main.cf file +================================================================== + +The installed main.cf file must be small. PLEASE resist the temptation +to list all 100 million Postfix parameters in the main.cf file. +Postfix is supposed to be easy to configure. Listing all 100 million +parameters in main.cf defeats the purpose. + +General distributions: please include the sample configuration files +==================================================================== + +Please provide the sample-xxx files. If these files are not installed +in the same directory as main.cf, PLEASE update the notice at the +top of main.cf that advises the user of the existence of the +sample-xxx files. Without the sample-xxx files, Postfix will be +much more difficult to configure. + +Postfix Installation parameters +=============================== + +Postfix installation is controlled by a dozen installation parameters. +See the postfix-install and post-install files for details. Most +parameters have system-dependent default settings that aren't +configurable at compile time. This will hopefully be rectified in +a later release. + +Preparing a pre-built package for distribution to other systems +=============================================================== + +You can build a Postfix package on a machine that does not have +Postfix installed on it. All you need is Postfix source code and +a compilation environment that is compatible with the target system. + +You can build a pre-built Postfix package as an unprivileged user, +but the result will be cleaner if you build the package as root. + +After successful Postfix compilation, execute: + + % sh postfix-install + +You will be prompted for installation parameters. Specify an +install_root directory other than /. The mail_owner and setgid_group +installation parameter settings will be recorded in the main.cf +file, but they won't take effect until the package is unpacked and +installed on the destination machine. + +If you want to fully automate this process, specify all the +non-default installation parameters on the command line: + + % sh postfix-install -non-interactive install_root=/some/where ... + +Begin Security Alert. +--------------------- + +When building an archive for distribution, be sure to archive only +files and symbolic links, not their parent directories. Otherwise, +unpacking a pre-built Postfix package may mess up permission and/or +ownership of system directories such as / /etc /usr /usr/bin /var +/var/spool and so on. This is especially an issue if you executed +postfix-install (see above) as an unprivileged user. + +End Security Alert. +------------------- + +Thus, to tar up the pre-built package, take the following steps: + + % cd INSTALL_ROOT + % rm -f SOMEWHERE/outputfile + % find . \! -type d -print | xargs tar rf SOMEWHERE/outputfile + % gzip SOMEWHERE/outputfile + +This way you will not include any directories that might cause trouble +upon extraction. + +Installing a pre-built Postfix package +====================================== + +To unpack a pre-built Postfix package, execute the equivalent of: + + # umask 022 + # gzip -d <outputfile.tar.gz | (cd / ; tar xvpf -) + +The umask command is necessary for getting the correct permissions +on non-Postfix directories that need to be created in the process. + +Create the necessary mail_owner account and setgid_group group for +exclusive use by Postfix. + +Execute the post-install script in the Postfix configuration +directory to set ownership and permission of Postfix files and +directories. Specify any non-default settings for mail_owner or +setgid_group on the post-install command line: + + # sh post-install upgrade-package setgid_group=xxx mail_owner=yyy + +This will also update the main.cf and master.cf files if necessary. diff --git a/gnu/dist/postfix/README_FILES/PCRE_README b/gnu/dist/postfix/README_FILES/PCRE_README new file mode 100644 index 00000000000..2a2244cf3b0 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/PCRE_README @@ -0,0 +1,48 @@ +PCRE (Perl Compatible Regular Expressions) map support +====================================================== + +The optional "pcre" map type allows you to specify regular expressions +with the PERL style notation such as \s for space and \S for +non-space. + +One possible use is to add a restriction to main.cf: + + smtpd_recipient_restrictions = ... pcre:/etc/postfix/smtprecipient ... + +The regular expressions are read from the file specified - sample +regexp patterns are shown in the Postfix pcre_table(5) manual page. + +Building Postfix with PCRE support +================================== + +In the future, Postfix will have a plug-in interface for adding +map types. Until then you need to compile PCRE support into Postfix. + +You need the PCRE library (Perl Compatible Regular Expressions), +which can be obtained from: + + ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ + +Postfix was tested with PCRE versions 2.8 and 3.7. + +In order to build Postfix with PCRE support you need to add -DHAS_PCRE +and a -I for the PCRE include file to CCARGS, and add the path to the +PCRE library to AUXLIBS, for example: + + make -f Makefile.init makefiles \ + "CCARGS=-DHAS_PCRE -I/usr/local/include" \ + "AUXLIBS=-L/usr/local/lib -lpcre" + +NOTE: pcre versions prior to 2.06 cannot be used. + +Things to know +============== + +For the sake of robustness, Postfix disables the matching of partial +addresses (breaking down user@domain into user@, domain, user, +@domain) that is normally done with Postfix access control tables, +canonical maps and virtual maps. + +An additional restriction is that regular expression tables cannot +be used for local alias database lookups. That would be a security +exposure anyway. diff --git a/gnu/dist/postfix/README_FILES/QMQP_README b/gnu/dist/postfix/README_FILES/QMQP_README new file mode 100644 index 00000000000..a23e1a3ef14 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/QMQP_README @@ -0,0 +1,73 @@ +Postfix QMQP server support +=========================== + +Postfix has preliminary server support for the QMQP protocol, so +that Postfix can be used as a backend for the Ezmlm-idx mailing +list manager. This support includes the qmqp-source and qmqp-sink +programs for protocol stress testing. + +Turning on the Postfix QMQP service +=================================== + +To enable QMQP server support on an existing Postfix system you +have to add the following line to /etc/postfix/master.cf: + +628 inet n - n - - qmqpd + +A "postfix reload" command is necessary to enable the service. + +Postfix QMQP server access control +================================== + +By default, the QMQP server does not accept mail from any client. +This is because the QMQP server relays mail to any destination +(the "protocol" has no provision to reject specific recipients). + +To authorize QMQP clients, edit /etc/postfix/main.cf and specify +a list of client patterns. + +qmqpd_authorized_clients = client, client, ... + +Example: + +qmqpd_authorized_clients = $mynetworks + +A list pattern specifies a host name, a domain name, an internet +address, or a network/mask pattern, where the mask specifies the +number of bits in the network part. When a pattern specifies a +file name, its contents are substituted for the file name; when a +pattern is a type:name table specification, table lookup is used +instead. This allows you to administer the trusted clients in LDAP +or regular expression maps, both of which are probably overkill. + +Patterns are separated by whitespace and/or commas. In order to +reverse the result, precede a non-file name pattern with an +exclamation point (!). + +Setting up ezmlm-idx to use Postfix QMQP support +================================================ + +Note: you still need qmail to feed the messages INTO ezmlm-idx. +Postfix presently only supports distribution of mailing list traffic +FROM ezmlm-idx. + +http://www.ezmlm.org/faq-0.40/FAQ-4.html#ss4.19 describes how to +make ezmlm-idx work over QMQP. + +The following is based on hearsay. Do not ask Wietse how to make +ezmlm-idx work. Wietse does not have the time to personally install +and play with every mailing list manager. + +1 - You must list QMQP servers with numerical IP address. Hostnames + do not work. This means you cannot DNS-based load balancing to + spread the load over multiple QMQP servers. + +2 - QMQP support is incomplete with ezmlm-idx-0.40. + + - ezmlm-send will use QMQP if you specify the undocumented -Q + command-line option in your .qmail-listname file. + + - ezmlm-get will use QMQP if the file qmpqservers/0 exists. + + - ezmlm-moderate does not support QMQP. This is not a problem + if you only use unmoderated mailing lists. diff --git a/gnu/dist/postfix/README_FILES/RESTRICTION_CLASS_README b/gnu/dist/postfix/README_FILES/RESTRICTION_CLASS_README new file mode 100644 index 00000000000..f623d28786b --- /dev/null +++ b/gnu/dist/postfix/README_FILES/RESTRICTION_CLASS_README @@ -0,0 +1,24 @@ +Per client/helo/sender/recipient UCE restrictions +================================================= + +The Postfix SMTP server allows you to specify UCE restrictions on +the right-hand side of SMTPD access tables, so that you can have +different UCE restrictions for different clients or users. + +The only anomalies in this scheme are that (1) message header_checks +and body_checks are still the same for every message, and (2) you +must use a restriction class name (see below) if you want to specify +a lookup table on the right-hand side of an access table (this is +because Postfix needs to open those tables ahead of time). + +Restriction classes allow you to give easy-to-remember names to +groups of UCE restrictions (such as permissive, restrictive, and +so on). For example in main.cf: + + smtpd_restriction_classes = restrictive, permissive + restrictive = reject_unknown_sender reject_unknown_client ... + permissive = permit + +With this in place, you can use "restrictive" or "permissive" on +the right-hand side of your per-client/helo/sender/recipient SMTPD +access tables. diff --git a/gnu/dist/postfix/README_FILES/SASL_README b/gnu/dist/postfix/README_FILES/SASL_README new file mode 100644 index 00000000000..e334ca9fc0f --- /dev/null +++ b/gnu/dist/postfix/README_FILES/SASL_README @@ -0,0 +1,206 @@ +WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +=============================================================== + +This code is not blessed by Wietse. + +People who go to the trouble of installing Postfix may have the +expectation that Postfix is more secure than some other mailers. + +With SASL authentication enabled in the Postfix SMTP client and +SMTP server, Postfix becomes no more secure than other mail systems +that use the Cyrus SASL library. + +The Cyrus SASL library has too little documentation about how the +software is supposed to work; and it is too much code to be used +in a security-sensitive program such as an SMTP client or server. + +However, you are pretty much required to build with SASL support +if you are going to use the LMTP interface of the Cyrus delivery +agent. This interface is much faster than forking a new process +for every message delivery. + +Postfix+SASL 1.5.5 appears to work on RedHat 6.1 (pwcheck_method +set to shadow or sasldb), Solaris 2.7 (pwcheck_method set to shadow +or sasldb), and FreeBSD 3.4 (pwcheck_method set to sasldb). On +RedHat 6.1, SASL 1.5.5 insisted on write access to /etc/sasldb. +Note that this seems to be related to the auto_transition switch in +SASL. Note also that the Cyrus SASL documentation says that it is +pointless to enable that if you use "sasldb" for "pwcheck_method". + +Introduction +============ + +The Postfix SASL support (RFC 2554) was originally implemented by +Till Franke of SuSE Rhein/Main AG. The present code is a trimmed-down +version with only the bare necessities. + +When receiving mail, Postfix logs the client-provided username, +authentication method, and sender address to the maillog file, and +optionally grants mail access via the permit_sasl_authenticated +UCE restriction. SASL authentication information is not passed on +via message headers or via SMTP. It is no-one's business what +username and authentication method the poster was using in order +to access the mail server. + +When sending mail, Postfix looks up the server hostname or destination +domain (the address remote part) in a table, and if a username/password +is found, it will use that username and password to authenticate +to the server. + +Building the SASL library +========================= + +Postfix appears to work with cyrus-sasl-1.5.5, which is available +from: + + ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/ + +IMPORTANT: if you install the Cyrus SASL libraries as per the default, +you will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl. + +Reportedly, Microsoft Internet Explorer version 5 requires the +non-standard SASL LOGIN authentication method. To enable this +authentication method, specify ``./configure --enable-login''. + +If you install the Cyrus SASL libraries as per the default, you +will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl. + +Building Postfix with SASL authentication support +================================================= + +To build Postfix with SASL authentication support, the following +assumes that the Cyrus SASL include files are in /usr/local/include, +and that the Cyrus SASL libraries are in /usr/local/lib. + +On some systems this generates the necessary Makefile definitions: + + % make tidy # if you have left-over files from a previous build + % make makefiles CCARGS="-DUSE_SASL_AUTH -I/usr/local/include" \ + AUXLIBS="-L/usr/local/lib -lsasl" + +On Solaris 2.x you need to specify run-time link information, +otherwise ld.so will not find the SASL shared library: + + % make tidy # if you have left-over files from a previous build + % make makefiles CCARGS="-DUSE_SASL_AUTH -I/usr/local/include" \ + AUXLIBS="-L/usr/local/lib -R/usr/local/lib -lsasl" + +Enabling SASL authentication in the Postfix SMTP server +======================================================= + +See conf/sample-auth.cf for examples. + +In order to enable SASL support in the SMTP server: + + /etc/postfix/main.cf: + smtpd_sasl_auth_enable = yes + +In order to allow mail relaying by authenticated clients: + + /etc/postfix/main.cf: + smtpd_recipient_restrictions = + permit_mynetworks permit_sasl_authenticated ... + +In /usr/local/lib/sasl/smtpd.conf you need to specify how the server +should validate client passwords. + +In order to authenticate against the UNIX password database, try: + + /usr/local/lib/sasl/smtpd.conf: + pwcheck_method: pwcheck + +The pwcheck daemon is contained in the cyrus-sasl source tarball. + +In order to authenticate against SASL's own password database: + + /usr/local/lib/sasl/smtpd.conf: + pwcheck_method: sasldb + +This will use the SASL password file (default: /etc/sasldb), which +is maintained with the saslpasswd command (part of the Cyrus SASL +software). On some poorly-supported systems the saslpasswd command +needs to be run multiple times before it stops complaining. The +Postfix SMTP server needs read access to the sasldb file - you may +have to play games with group access permissions. On RedHat 6.1, +SASL 1.5.5 insists on write access to /etc/sasldb. + +IMPORTANT: To get sasldb running, make sure that you set the SASL domain +(realm) to a fully qualified domain name. + +EXAMPLE: saslpasswd -c -u `postconf -h myhostname` exampleuser + +To run software chrooted with SASL support is an interesting +exercise. It probably is not worth the trouble. + +Older Microsoft SMTP client software implements a non-standard +version of the AUTH protocol syntax, and expects that the SMTP +server replies to EHLO with "250 AUTH=stuff" instead of "250 AUTH +stuff". To accomodate such clients in addition to conformant +clients, set "broken_sasl_auth_clients = yes" in the main.cf file. + +Testing SASL authentication in the Postfix SMTP server +====================================================== + +To test the whole mess, connect to the SMTP server, and you should +be able to have a conversation like this: + + 220 server.host.name ESMTP Postfix + EHLO client.host.name + 250-server.host.name + 250-PIPELINING + 250-SIZE 10240000 + 250-ETRN + 250-AUTH DIGEST-MD5 PLAIN CRAM-MD5 + 250 8BITMIME + AUTH PLAIN dGVzdAB0ZXN0AHRlc3RwYXNz + 235 Authentication successful + +Instead of dGVzdAB0ZXN0AHRlc3RwYXNz, specify the base64 encoded +form of username\0username\0password (the \0 is a null byte). The +example above is for a user named `test' with password `testpass'. + +In order to generate base64 encoded authentication information you +can use one of the following commands: + + % printf 'username\0username\0password' | mmencode + + % perl -MMIME::Base64 -e \ + 'print encode_base64("username\0username\0password");' + +MIME::Base64 is available from www.cpan.org. + +Enabling SASL authentication in the Postfix SMTP client +======================================================= + +Turn on client-side SASL authentication, and specify a table with +per-host or per-destination username and password information. +Postfix first looks up the server hostname; if no entry is found, +then Postfix looks up the destination domain name (usually, the +remote part of an email address). + + /etc/postfix/main.cf: + smtp_sasl_auth_enable = yes + smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd + + /etc/postfix/sasl_passwd: + foo.com username:password + bar.com username + +Note: some SMTP servers support PLAIN or LOGIN authentication only. +By default, the Postfix SMTP client does not use authentication +methods that send plaintext passwords, and defers delivery with +the following error message: "Authentication failed: cannot SASL +authenticate to server". To enable plaintext authentication specify, +for example: + + /etc/postfix/main.cf: + smtp_sasl_security_options = + +The SASL client password file is opened before the SMTP server +enters the optional chroot jail, so you can keep the file in +/etc/postfix. + +The Postfix SMTP client is backwards compatible with SMTP servers +that use the non-standard AUTH=stuff... syntax in response to the +EHLO command. + diff --git a/gnu/dist/postfix/README_FILES/ULTRIX_README b/gnu/dist/postfix/README_FILES/ULTRIX_README new file mode 100644 index 00000000000..ef43fe6d02b --- /dev/null +++ b/gnu/dist/postfix/README_FILES/ULTRIX_README @@ -0,0 +1,34 @@ +To: wietse@porcupine.org (Wietse Venema) +Subject: postfix-19990317-pl05 on Ultrix4.3a +From: Christian von Roques <roques@pond.sub.org> +Date: 02 Jun 1999 18:44:34 +0200 +Message-ID: <87iu96wo0d.fsf_-_@scalar.pond.sub.org> + +I've upgraded the MTA of our DECstation-3100 running Ultrix4.3a to +postfix-19990317-pl05 and am sending you the patches I needed to get +it running under Ultrix. + + ... + + o One of the bugs of Ultrix's /bin/sh is that shell-variables set in + arguments of `:' expand to garbage if expanded in here-documents. + Using a different shell helps. I needed to replace all calls of + ``sh .../makedefs'' by ``$(SHELL) .../makedefs'' in all the + Makefile.in and am now able to use + + make SHELL=/bin/sh5 or zsh. + + ... + + o Ultrix's FD_SET_SIZE is 4096, but getdtablesize() returns 64 by + default, if not increased when building a new kernel. getrlimit() + doesn't know RLIMIT_NOFILE. This makes event_init() always log + the warning: `could allocate space for only 64 open files'. + + I just reduced the threshold from 256 to 64, but this is not good. + The initial problem still remains: How to disable this warning on + Ultrix without making the source ugly? + +[I have updated util/sys_defs.h, and by default set FD_SETSIZE to +100. This should be sufficient for a workstation. No-one would +run a major mail hub on Ultrix 4. -- Wietse] diff --git a/gnu/dist/postfix/README_FILES/UUCP_README b/gnu/dist/postfix/README_FILES/UUCP_README new file mode 100644 index 00000000000..e6fbd56e4f5 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/UUCP_README @@ -0,0 +1,6 @@ +In order to receive mail via UUCP, your system needs to have an +rmail command installed. A minimal rmail command can be found in +the "auxiliary/rmail" directory. Install the command, mode 755, in +a place that can be found by the UUCP "uuxqt" command. + +In order to send mail via UUCP, see html/faq.html. diff --git a/gnu/dist/postfix/README_FILES/VERP_README b/gnu/dist/postfix/README_FILES/VERP_README new file mode 100644 index 00000000000..3ed89f1ad2e --- /dev/null +++ b/gnu/dist/postfix/README_FILES/VERP_README @@ -0,0 +1,131 @@ +[Note: this document still needs more examples] + +Postfix VERP support +==================== + +Postfix supports variable envelope return path addresses on request. +When VERP style delivery is requested, each recipient of a message +receives a customized copy of the message, with his/her own recipient +address encoded in the envelope sender address. + +For example, when VERP style delivery is requested, Postfix delivers +mail from owner-listname@origin for a recipient user@domain, with +a sender address that encodes the recipient as follows: + + owner-listname+user=domain@origin + +Thus, undeliverable mail can reveal the undeliverable recipient +address without requiring the list owner to parse bounce messages. + +The VERP concept was popularized by the qmail MTA and by the ezmlm +mailing list manager. + +The whole process is controlled by two configuration parameters. + +- default_verp_delimiters (default value: +=) controls what VERP +delimiter characters Postfix uses when VERP style delivery is +requested but no explicit delimiters are specified. + +- verp_delimiter_filter (default: -+=) controls what characters +Postfix accepts as VERP delimiter characters on the sendmail command +line and in SMTP commands. Many characters must not be used as VERP +delimiter characters, either because they already have a special +meaning in email addresses (such as the @ or the %), because they +are used as part of a username or domain name (such as alphanumerics), +or because they are non-ASCII or control characters. And who knows, +some characters may tickle bugs in vulnerable software. + +Using VERP with majordomo etc. mailing lists +============================================ + +In order to make VERP useful with majordomo etc. mailing lists, +you would configure the list manager to submit mail according +to one of the following two forms: + + sendmail -V -f owner-listname other-arguments... + + sendmail -V+= -f owner-listname other-arguments... + +The first form uses the default main.cf VERP delimiter characters. +The second form allows you to explicitly specify the VERP delimiter +characters. The example shows the recommended values. + +This text assumes that you have set up an owner-listname alias that +routes undeliverable mail to a real person: + + /etc/aliases: + owner-listname: yourname+listname + +In order to process bounces we are going to make extensive use of +address extension tricks. + +You need to tell Postfix that + is the separator between an address +and its optional address extension, that address extensions are +appended to .forward file names, and that address extensions are +to be discarded when doing alias expansions: + + /etc/postfix/main.cf: + recipient_delimiter = + + forward_path = $home/.forward${recipient_delimiter}${extension},$home/.forward + propagate_unmatched_extensions = canonical, virtual + +(the last two parameter settings are default settings). + +You need to set up a file named .forward+listname with the commands +that process all the mail that is sent to the owner-listname address: + + ~/.forward+listname: + "|/some/where/command ..." + +With this set up, undeliverable mail for user@domain will be returned +to the following address: + + owner-listname+user=domain@your.domain + +which is processed by the command in your .forward+listname file. +The message should contain, among others, a To: header with the +encapsulated recipient sender address: + + To: owner-listname+user=domain@your.domain + +It is left as an exercise for the reader to parse the To: header +line and to pull out the user=domain part from the recipient address. + +VERP support in the Postfix SMTP server +======================================= + +The Postfix SMTP server has a new command XVERP to enable VERP +style delivery. The syntax allows two forms: + + MAIL FROM:<sender@domain> XVERP + + MAIL FROM:<sender@domain> XVERP=+= + +The first form uses the default main.cf VERP delimiters, the second +form overrides them explicitly. The values shown are the recommended +ones. + +VERP support in the Postfix sendmail command +============================================ + +The Postfix sendmail command has a -V flag to request VERP style +delivery. Specify one of the following two forms: + + sendmail -V -f owner-listname .... + + sendmail -V+= -f owner-listname .... + +The first form uses the default main.cf VERP delimiters, the second +form overrides them explicitly. The values shown are the recommended +ones. + +VERP support in the Postfix QMQP server +======================================= + +When the Postfix QMQP server receives mail with an envelope sender +address of the form: + + listname-@your.domain-@[] + +Postfix generates sender addresses listname-user=domain@your.domain, +using "-=" as the VERP delimiters because qmail/ezmlm expect this. diff --git a/gnu/dist/postfix/README_FILES/VIRTUAL_README b/gnu/dist/postfix/README_FILES/VIRTUAL_README new file mode 100644 index 00000000000..0a648ab0861 --- /dev/null +++ b/gnu/dist/postfix/README_FILES/VIRTUAL_README @@ -0,0 +1,280 @@ +This code was created by Andrew McNamara <andrew@connect.com.au> +and adapted to snapshot 20001121 by Xavier Beaudouin. It was merged +with mainstream Postfix for snapshot 20010128 by Wietse. + +Purpose of this software +======================== + +You can use the virtual delivery agent for mailbox delivery of some +or all domains that are handled by a machine. + +This mechanism is different from virtual domains that are implemented +by translating each virtual address into a real local user. For +that, see the virtual(5) manual page. + +This is what Andrew McNamara wrote when he made the virtual delivery +agent available. + +"This code is designed for ISP's who offer virtual mail hosting. +It looks up the user mailbox location, uid and gid via separate +maps, and the mailbox location map can specify either mailbox or +maildir delivery (controlled by trailing slash on mailbox name). + +The agent does not support user+foo address extensions, aliases or +.forward files (use the virtual table instead), and therefore +doesn't support file or program aliases. This choice was made to +simplify and streamline the code (it allowed me to dispense with +70% of local's code - mostly the bits that are a security headache) +- if you need this functionality, this agent isn't for you. + +It also doesn't support writing to a common spool as root and then +chowning the mailbox to the user - I felt this functionality didn't +fit with my overall aims." + +[End of Andrew McNamara's words] + +The result is the most secure local delivery agent that you will +find with Postfix. + +This delivery agent requires three different lookup tables in order +to define its recipients as (mailbox path, user ID, group ID). This +is because Postfix table lookups can't return multiple results. + +If your virtual mailboxes are all owned by the same user/group ID, +just specify "static" maps that always return the same result. See +below for examples. + +If your virtual mailboxes must be owned by different user/group +IDs, and if it is too inconvenient for you to maintain three parallel +tables, use an LDAP or MYSQL database (or generate the three parallel +tables from one common template). + +Configuration parameters +======================== + +virtual_mailbox_base + + Specifies a path that is prepended to all mailbox paths. This + is a safety measure to ensure an that out of control map doesn't + litter the filesystem with mailboxes (or worse). While it could + be set to "/", this isn't recommended. + +virtual_mailbox_maps + + Recipients are looked up in this map to determine the path to + their mailbox. If the returned path ends in a slash ("/"), + maildir-style delivery is carried out, otherwise the path is + assumed to specify a mailbox file. The virtual_mailbox_base + directory is unconditionally prepended to this path. If the + recipient is not found the mail is bounced. + + If a recipient is not found the mail is returned to the sender. + + For security reasons, regexp maps are not allowed here, because + their $1 etc. substitutions would open a security hole. + + The mail administrator is expected to create and chown recipient + mailbox files or maildir directories ahead of time. + +virtual_minimum_uid + + Specifies a minimum uid that will be accepted as a return from + a virtual_uid_maps lookup. Returned values less than this will + be rejected, and the message will be deferred. + +virtual_uid_maps + + Recipients are looked up in this map to determine the UID (owner + privileges) to be used when writing to the target mailbox. + + For security reasons, regexp maps are not allowed here, because + their $1 etc. substitutions would open a security hole. + + Specify a static map if all mailboxes should be owned by the same + UID. For example, to specify that all mailboxes are owned by the + UID 5000, specify: + + virtual_uid_maps = static:5000 + +virtual_gid_maps + + Recipients are looked up in this map to determine the GID (group + privileges) to be used when writing to the target mailbox. + + For security reasons, regexp maps are not allowed here, because + their $1 etc. substitutions would open a security hole. + + Specify a static map if all mailboxes should be owned by the same + GID. For example, to specify that all mailboxes are owned by the + GID 5000, specify: + + virtual_gid_maps = static:5000 + +virtual_mailbox_lock + + This setting is ignored in case of maildir delivery. + + Locking method to use when updating a mailbox. Defaults to + fcntl or flock depending on the system. Depending on the POP + or IMAP server you may have to specify dotlock locking, which + requires that the recipient UID or GID has write access to the + parent directory of the mailbox file. + + Use the "postconf -m" command to find out what locking methods + Postfix supports on your system. + +virtual_mailbox_size + + An upper limit on the size of a mailbox file or maildir file. + +Example 1: using the virtual delivery agent for all local mail +============================================================== + +This example does not use the Postfix local delivery agent at all. +With this configuration Postfix does no user+foo address extension, +no alias expansion, no .forward file expansion, and no lookups of +recipients in /etc/passwd. + +Instead of "hash" specify "dbm" or "btree", depending on your system +type. The command "postconf -m" displays possible lookup table +types. + + /etc/postfix/main.cf: + local_transport = virtual + virtual_mailbox_base = /var/mail/vhosts + virtual_mailbox_maps = hash:/etc/postfix/vmailbox + virtual_minimum_uid = 100 + virtual_uid_maps = hash:/etc/postfix/vuid + virtual_gid_maps = hash:/etc/postfix/vgid + + # All domains that are listed in $mydestination are delivered + # with $local_transport, which is the virtual delivery agent. + + mydestination = + $myhostname localhost.$mydomain virtual1.domain virtual2.domain + +Define a virtual delivery agent if the entry doesn't already exist: + + /etc/postfix/master.cf: + virtual unix - n n - - virtual + +Example recipients, one UNIX-style mailbox, one qmail-style maildir: + + /etc/postfix/vmailbox: + test1@virtual1.domain test1 + test2@virtual2.domain test2/ + + /etc/postfix/vuid: + test1@virtual1.domain 5001 + test2@virtual2.domain 5002 + + /etc/postfix/vgid: + test1@virtual1.domain 5001 + test2@virtual2.domain 5002 + +Execute something like the following commands for each mailbox recipient: + + # touch /var/mail/vhosts/test1 + # chown 5001:5001 /var/mail/vhosts/test1 + +Execute something like the following commands for each maildir recipient: + + # mkdir /var/mail/vhosts/test2 + # chown 5002:5002 /var/mail/vhosts/test2 + +Be sure to make the necessary entries for root@$myhostname, +postmaster@$myhostname and for any other necessary addresses. + +Example 2: co-existing with the default local delivery agent +============================================================ + +In this example, the default Postfix local delivery agent handles +the mail for non-virtual recipients; the virtual delivery agent +handles virtual recipients, and all virtual mailboxes are owned +by user ID 5000, group ID 5000. + +Instead of "hash" specify "dbm" or "btree", depending on your system +type. The command "postconf -m" displays possible lookup table +types. + + /etc/postfix/main.cf: + virtual_mailbox_base = /var/mail/vhosts + virtual_mailbox_maps = hash:/etc/postfix/vmailbox + virtual_minimum_uid = 100 + virtual_uid_maps = static:5000 + virtual_gid_maps = static:5000 + transport_maps = hash:/etc/postfix/transport + + # All domains that are delivered by the local delivery agent. + + mydestination = $myhostname $localhost.$mydomain + + # Reject unknown local recipients at the SMTP port. + + local_recipient_maps = unix:passwd.byname $alias_maps + +Define a virtual delivery agent if the entry doesn't already exist: + + /etc/postfix/master.cf: + virtual unix - n n - - virtual + +Route virtual domains to the virtual delivery agent: + + /etc/postfix/transport: + virtual1.domain virtual + virtual2.domain virtual + +Example recipients, one UNIX-style mailbox, one qmail-style maildir: + + /etc/postfix/vmailbox: + virtual1.domain required to prevent relay access denied errors + virtual2.domain required to prevent relay access denied errors + test1@virtual1.domain test1 + test2@virtual2.domain test2/ + +Execute something like the following commands for each mailbox recipient: + + # touch /var/mail/vhosts/test1 + # chown 5000:5000 /var/mail/vhosts/test1 + +Execute something like the following commands for each maildir recipient: + + # mkdir /var/mail/vhosts/test2 + # chown 5000:5000 /var/mail/vhosts/test2 + +Remember that each domain is required to have a postmaster contact +address. + +Example 3: forwarding mail for an old account to a new address +============================================================== + +In order to forward mail for a user who no longer exists, one would +set up a rule in a virtual table (please ignore the text in the +virtual configuration file about virtual domains): + + /etc/postfix/main.cf: + virtual_maps = hash:/etc/postfix/virtual + + /etc/postfix/virtual: + old_user@old.domain new_user@new.domain + +Example 4: setting up a virtual vacation autoresponder +====================================================== + +In order to set up an autoreply for virtual recipients while still +delivering mail as normal, set up a rule in a virtual table (please +ignore the text in the virtual configuration file about virtual +domains): + + /etc/postfix/main.cf: + virtual_maps = hash:/etc/postfix/virtual + + /etc/postfix/virtual: + user@domain.name user@domain.name, user@autoreply.domain.name + +This delivers mail to the recipient, and sends a copy of the mail +to the address that produces automatic replies. The address can be +serviced on a different machine, or it can be serviced locally by +setting up a transport map entry that pipes all mail for the +autoreply.domain.name into some script that sends an automatic +reply back to the sender. diff --git a/gnu/dist/postfix/RELEASE_NOTES b/gnu/dist/postfix/RELEASE_NOTES index 12117471b37..9c1c8e2e828 100644 --- a/gnu/dist/postfix/RELEASE_NOTES +++ b/gnu/dist/postfix/RELEASE_NOTES @@ -1,14 +1,365 @@ -Release 20010228 is the first official Postfix release that is not -called BETA. May it help the people who cannot get BETA software -past their management. - In the text below, incompatible changes are labeled with the Postfix -version that introduced the change. If you upgrade from a later +snapshot that introduced the change. If you upgrade from a later Postfix version, then you do not have to worry about that particular incompatibility. -Major incompatible changes with release-20010228 Patch 01 -========================================================= +Official Postfix releases are called a.b.c where a=major release +number, b=minor release number, c=patchlevel. Snapshot releases +are now called a.b.c-yyyymmdd where yyyymmdd is the release date +(yyyy=year, mm=month, dd=day). The mail_release_date configuration +parameter contains the release date (both for official release and +snapshot release). Patches change the patchlevel and the release +date. Snapshots change only the release date, unless they include +the same bugfix as a patch release. + +Incompatible changes with Postfix version 1.1.2 (released 20020125) +=================================================================== + +Postfix now detects if the run-time Berkeley DB library routines +do not match the major version number of the compile-time include +file that was used for compiling Postfix. The software issues a +warning and aborts in case of a discrepancy. If it didn't, the +software was certain to crash with a segmentation violation. + +Incompatible changes with Postfix version 1.1.1 (released 20020122) +=================================================================== + +When the postmap command creates a non-existent result file, the +new file inherits the group/other read permissions of the source +file. + +Incompatible changes with Postfix version 1.1.0 (released 20020117) +=================================================================== + +Changes are listed in order of decreasing importance, not release +date. + +[snapshot-20010709] This release introduces a new queue file record +type that is used only for messages that actually use VERP (variable +envelope return path) support. With this sole exception, the queue +file format is entirely backwards compatible with the previous +official Postfix release (20010228, a.k.a. Postfix 1.0.0). + +[snapshot-20020106] This release modifies the existing master.cf +file. The local pickup service is now unprivileged, and the cleanup +and flush service are now "public". Should you have to back out to +a previous release, then you must 1) edit the master.cf file, make +the pickup service "privileged", and make the cleanup and flush +services "private"; 2) "chmod 755 /var/spool/postfix/public". To +revert to a world-writable mail submission directory, "chmod 1733 +/var/spool/postfix/maildrop". + +[snapshot-20020106, snapshot-20010808, snapshot-20011103, +snapshot-20011121] You must stop and restart Postfix because of +incompatible changes in the local Postfix security model and in +the Postfix internal protocols. Old and new components will not +work together. + +[snapshot-20020106] Simpler local Postfix security model. + +- No world-writable maildrop directory. Postfix now always uses + the set-gid postdrop command for local mail submissions. The + local mail pickup daemon is now an unprivileged process. + +- No world-accessible pickup and queue manager server FIFOs. + +- New set-gid postqueue command for the queue list/flush operations + that used to implemented by the Postfix sendmail command. + +[snapshot-20020106..15] Simpler Postfix installation and upgrading. + +- All installation settings are now kept in the main.cf file, and + better default settings are now generated for system dependent + pathnames such as sendmail_path etc. The install.cf file is no + longer used, except when upgrading from an older Postfix version. + +- Non-default installation parameter settings can (but do not have + to) be specified on the "make install" or "make upgrade" command + line as name=value arguments. + +- New postfix-files database (in /etc/postfix) with (pathname, + owner, permission) information about all Postfix-related files. + +- New postfix-install script replaces the awkward INSTALL.sh script. + This is driven by the postfix-files database. It has better + support for building packages for distribution to other systems. + See PACKAGE_README for details. + +- New post-install script (in /etc/postfix) for post-installation + maintenance of directory/file permissions and ownership (this is + used by "postfix check"). Example: + + # postfix stop + # post-install set-permissions mail_owner=username setgid_group=groupname + # postfix start + +[snapshot-20020106] Postfix will not run if it detects that the +postfix user or group ID are shared with other accounts on the +system. The checks aren't exhaustive (that would be too resource +consuming) but should be sufficient to encourage packagers and +developers to do the right thing. To fix the problem, use the above +post-install command, after you have created the appropriate new +mail_owner or setgid_group user or group IDs. + +[snapshot-20020106] If you run multiple Postfix instances on the +same machine you now have to specify their configuration directories +in the default main.cf file as "alternate_config_directories = +/dir1 /dir2 ...". Otherwise, some Postfix commands will no longer +work: the set-group ID postdrop command for mail submission and +the set-group ID postqueue command for queue listing/flushing. + +[snapshot-20010808] The default setting for the maps_rbl_domains +parameter is now "empty", because mail-abuse.org has become a +subscription-based service. The names of the RBL parameters haven't +changed. + +[snapshot-20020106] Postfix SMTP access maps will no longer return +OK for non-local multi-domain recipient mail addresses (user@dom1@dom2, +user%dom1@dom2, etcetera); the lookup now returns DUNNO (undetermined). +Non-local multi-domain recipient addresses were already prohibited +from matching the permit_mx_backup and the relay_domains-based +restrictions. + +[snapshot-20011210] Stricter checking of Postfix chroot configurations. +The Postfix startup procedure now warns if "system" directories +(etc, bin, lib, usr) under the Postfix top-level queue directory +are not owned by the super-user (usually the result of well-intended, +but misguided, applications of "chown -R postfix /var/spool/postfix). + +[snapshot-20011008] The Postfix SMTP server now rejects requests +with a generic "try again later" status (451 Server configuration +error) when it detects an error in smtp_{client, helo, sender, +recipient, etrn}_restrictions settings. More details about the +problem are logged to the syslogd; sending such information to +random clients would be inappropriate. + +[snapshot-20011008] Postfix no longer flushes the entire mail queue +after receiving an ETRN request for a random domain name. Requests +for domains that do not match $fast_flush_domains are now rejected +instead. + +[snapshot-20011226] Postfix configuration file comments no longer +continue on the next line when that next line starts with whitespace. +This change avoids surprises, but it may cause unexpected behavior +with existing, improperly formatted, configuration files. Caveat +user. Comment lines are allowed to begin with whitespace. Multi-line +input is no longer terminated by a comment line, by an all whitespace +line, or by an empty line. + +[snapshot-20010714] Postfix delivery agents now refuse to create +a missing maildir or mail spool subdirectory when its parent +directory is world writable. This is necessary to prevent security +problems with maildirs or with hashed mailboxes under a world +writable mail spool directory. + +[snapshot-20010525] As per RFC 2821, the Postfix SMTP client now +always sends EHLO at the beginning of an SMTP session. Specify +"smtp_always_send_ehlo = no" for the old behavior, which is to send +EHLO only when the server greeting banner contains the word ESMTP. + +[snapshot-20010525] As per RFC 2821, an EHLO command in the middle +of an SMTP session resets the Postfix SMTP server state just like +RSET. This behavior cannot be disabled. + +[snapshot-20010709] The SMTP client now by default breaks lines > +2048 characters, to avoid mail delivery problems with fragile SMTP +server software. To get the old behavior back, specify "smtp_break_lines += no" in the Postfix main.cf file. + +[snapshot-20010709] With recipient_delimiter=+ (or any character +other than -) Postfix will now recognize address extensions even +with owner-foo+extension addresses. This change was necessary to +make VERP useful for mailing list bounce processing. + +[snapshot-20010610] The Postfix pipe delivery agent no longer +automatically case-folds the expansion of $user, $extension or +$mailbox command-line macros. Specify the 'u' flag to get the old +behavior. + +[snapshot-20011210] The Postfix sendmail command no longer exits +with status 1 when mail submission fails, but instead returns a +sendmail-compatible status code as defined in /usr/include/sysexits.h. + +Major changes with Postfix version 1.1.0 (Released 20020117) +============================================================ + +Changes are listed in order of decreasing importance, not release +date. + +The nqmgr queue manager is now bundled with Postfix. It implements +a smarter scheduling strategy that allows ordinary mail to slip +past mailing list mail, resulting in better response. This queue +manager is expected to become the default queue manager shortly. + +[snapshot-20010709, snapshot-20010808] VERP (variable envelope +return path) support. This is enabled by default, including in +the SMTP server. See the VERP_README file for instructions. Specify +"disable_verp_bounces = yes" to have Postfix send one RFC-standard, +non-VERP, bounce report for multi-recipient mail, even when VERP +style delivery was requested. This reduces the explosive behavior +of bounces when sending mail to a list. + +[snapshot-20010709] QMQP server support, so that Postfix can be +used as a backend mailer for the ezmlm-idx mailing list manager. +You still need qmail to drive ezmlm and to process mailing list +bounces. The QMQP service is disabled by default. To enable, follow +the instructions in the QMQP_README file. + +[snapshot-20010709] You can now reject unknown virtual(8) recipients +at the SMTP port by specifying a "domain.name whatever" entry in +the tables specified with virtual_mailbox_maps, similar to Postfix +virtual(5) domains. [virtual(8) is the Postfix virtual delivery +agent, virtual(5) is the Postfix virtual map. The two implement +virtual domains in a very different manner.] + +[snapshot-20011121] Configurable host/domain name wildcard matching +behavior: choice between "pattern `domain.name' matches string +`host.domain.name'" (this is to be deprecated in the future) and +"pattern `.domain.name' matches string `host.domain.name'" (this +is to be preferred in the future). The configuration parameter +"parent_domain_matches_subdomains" specifies which Postfix features +use the behavior that will become deprecated. + +[snapshot-20010808] Variable coupling between message receiving +rates and message delivery rates. When the message receiving rate +exceeds the message delivery rate, an SMTP server will pause for +$in_flow_delay seconds before accepting a message. This delay +gives Postfix a chance catch up and access the disk, while still +allowing new mail to arrive. This feature currently has effect +only when mail arrives via a small number of SMTP clients. + +[snapshot-20010610, snapshot-20011121, snapshot-20011210] Workarounds +for a bug in old versions of the CISCO PIX firewall software that +caused mail to be resent repeatedly. The workaround has no effect +for other mail deliveries. The workaround is turned off when mail +is queued for less than $smtp_pix_workaround_threshold_time seconds +(default: 500 seconds) so that the workaround is normally enabled +only for deferred mail. The delay before sending .<CR><LF> is now +controlled by the $smtp_pix_workaround_delay_time setting (default: +10 seconds). + +[snapshot-20011226] Postfix will now do null address lookups in +SMTPD access maps. If your access maps cannot store or look up +null string key values, specify "smtpd_null_access_lookup_key = +<>" and the null sender address will be looked up as <> instead. + +[snapshot-20011210] More usable virtual delivery agent, thanks to +a new "static" map type by Jeff Miller that always returns its map +name as the lookup result. This eliminates the need for per-recipient +user ID and group ID tables. See the VIRTUAL_README file for more +details. + +[snapshot-20011125] Anti-sender spoofing. New main.cf parameter +smtpd_sender_login_maps that specifies the (SASL) login name that +owns a MAIL FROM sender address. Specify a regexp table in order +to require a simple one-to-one mapping. New SMTPD restriction +reject_sender_login_mismatch that refuses a MAIL FROM address when +$smtpd_sender_login_maps specifies an owner but the client is not +(SASL) logged in as the MAIL FROM address owner, or when a client +is (SASL) logged in but does not own the address according to +$smtpd_sender_login_maps. + +[snapshot-20011121] The mailbox_command_maps parameter allows you +to configure the external delivery command per user (local delivery +agent only). This feature has precedence over the mailbox_command +and home_mailbox settings. + +[snapshot-20011121] New "warn_if_reject" smtpd UCE restriction that +only warns if the restriction that follows would reject mail. Look +for file records that contain the string "reject_warning". + +[snapshot-20011127] New header/body_check result "WARN" to make +Postfix log a warning about a header/body line without rejecting +the content. + +[snapshot-20011103] In header/body_check files, REJECT can now be +followed by text that is sent to the originator. That feature was +stuck waiting for years, pending the internal protocol revision. + +[snapshot-20011008] The permit_mx_backup feature allows you to +specify network address blocks via the permit_mx_backup_networks +parameter. This requires that the primary MX hosts for the given +destination match the specified network blocks. When no value is +given for permit_mx_backup_networks, Postfix will accept mail +whenever the local MTA is listed in the DNS as an MX relay host +for a destination, even when you never gave permission to do so. + +[snapshot-20010709] Specify "mail_spool_directory = /var/mail/" +(note the trailing "/" character) to enable maildir format for +/var/mail/username. + +[snapshot-20010808] Finer control over address masquerading. The +masquerade_classes parameter now controls header and envelope sender +and recipient addresses. With earlier Postfix versions, address +masquerading rewrote all addresses except for the envelope recipient. + +[snapshot-20010610] The pipe mail delivery agent now supports proper +quoting of white space and other special characters in the expansions +of the $sender and $recipient command-line macros. This was necessary +for correct operation of the "simple" content filter, and is also +recommended for delivery via UUCP or BSMTP. + +[snapshot-20010610] The pipe mail delivery agent now supports case +folding the localpart and/or domain part of expansions of the +$nexthop, $recipient, $user, $extension or $mailbox command-line +macros. This is recommended for mail delivery via UUCP. Bug: $nexthop +is always case folded because of problems in the queue manager +code. + +[snapshot-20010525] This release contains many little revisions of +little details in the light of the new RFC 2821 and RFC 2822 +standards. Changes that may affect interoperability are listed +above under "incompatible changes". Other little details are +discussed in comments in the source code. + +[snapshot-20010502] The Postfix SMTP client now by default randomly +shuffles destination IP addresses of equal preference (whether +obtained via MX lookup or otherwise). Reportedly, this is needed +for sites that use Bernstein's dnscache program. Specify +"smtp_randomize_addresses = no" to disable this behavior. Based on +shuffling code by Aleph1. + +[snapshot-20011127] New parameter smtpd_noop_commands to specify +a list of commands that the Postfix SMTP server treats as NOOP +commands (no syntax check, no state change). This is a workaround +for misbehaving clients that send unsupported commands such as +ONEX. + +[snapshot-20010502] "postmap -q -" and "postmap -d -" read key +values from standard input, which makes it easier to drive them +from another program. The same feature was added to the postalias +command. + +[snapshot-20010502] The postsuper command now has a command-line +option to delete queue files. In principle this command can be +used while Postfix is running, but there is a possibility of deleting +the wrong queue file when Postfix deletes a queue file and reuses +the queue ID for a new message. In that case, postsuper will delete +the new message. + +[snapshot-20010525] The postsuper queue maintenance tool now renames +files whose name (queue ID) does not match the message file inode +number. This is necessary after a Postfix mail queue is restored +from another machine or from backups. The feature is selected with +the -s option, which is the default, and runs whenever Postfix is +started. + +[snapshot-20010525] The postsuper queue maintenance tool has a new +-r (requeue) option for subjecting some or all queue files to +another iteration of address rewriting. This is useful after the +virtual or canonical maps have changed. + +[snapshot-20010525] The postsuper queue maintenance tool was extended +with options to read queue IDs from standard input. This makes the +tool easier to drive from scripts. + +[snapshot-20010329] Better support for running multiple Postfix +instances on one machine. Each instance can be recognized by its +logging (defaults: "syslog_name = postfix", "syslog_facility = +mail"). + +Major incompatible changes with release-20010228 Patch 01 (a.k.a. Postfix 1.0.1) +================================================================================ This release changes the names of the "fast ETRN" logfiles with delayed mail per destination. These files are maintained by the @@ -18,8 +369,8 @@ populate the new "fast ETRN" logfiles, execute the command "sendmail -q". The old "fast ETRN" logfiles go away by themselves (default: after 7 days). -Major incompatible changes with release-20010228 -================================================ +Major incompatible changes with release-20010228 (a.k.a. Postfix 1.0.0) +======================================================================= [snapshot-20010225] POSTFIX NO LONGER RELAYS MAIL FOR CLIENTS IN THE ENTIRE CLASS A/B/C NETWORK. To get the old behavior, specify diff --git a/gnu/dist/postfix/auxiliary/MacOSX/Postfix.StartupItem/Postfix b/gnu/dist/postfix/auxiliary/MacOSX/Postfix.StartupItem/Postfix new file mode 100755 index 00000000000..01bd81cad71 --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/Postfix.StartupItem/Postfix @@ -0,0 +1,35 @@ +#!/bin/sh + +# Gerben Wierda, Oct 2001. Adapted from an existing example. I waive every +# copyright on this and I also do not give any warranty. + +. /etc/rc.common + +## +# Start mail server +## + +if [ "$1" == "start" ] +then + if [ "${MAILSERVER:=-NO-}" = "-YES-" ] + then + ConsoleMessage "Starting Postfix mail services" + /usr/sbin/postfix start + fi +elif [ "$1" == "stop" ] +then + ConsoleMessage "Stopping Postfix mail services" + /usr/sbin/postfix stop +elif [ "$1" == "restart" ] +then + if [ "${MAILSERVER:=-NO-}" = "-YES-" ] + then + ConsoleMessage "Reloading Postfix configuration" + /usr/sbin/postfix reload + else + ConsoleMessage "Stopping Postfix mail services" + /usr/sbin/postfix stop + fi +fi + + diff --git a/gnu/dist/postfix/auxiliary/MacOSX/Postfix.StartupItem/StartupParameters.plist b/gnu/dist/postfix/auxiliary/MacOSX/Postfix.StartupItem/StartupParameters.plist new file mode 100644 index 00000000000..b41a9a02bc3 --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/Postfix.StartupItem/StartupParameters.plist @@ -0,0 +1,13 @@ +{ + Description = "Postfix mail server"; + Provides = ("SMTP"); + Requires = ("Resolver"); + Uses = ("Network Time", "NFS"); + Preference = "None"; + Messages = + { + start = "Starting Postfix"; + stop = "Stopping Postfix"; + restart = "Reloading Postfix Configuration"; + }; +} diff --git a/gnu/dist/postfix/auxiliary/MacOSX/README-INSTALL.OSX b/gnu/dist/postfix/auxiliary/MacOSX/README-INSTALL.OSX new file mode 100644 index 00000000000..32f1d9ef4b6 --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/README-INSTALL.OSX @@ -0,0 +1,63 @@ +# Adapted from an existing example by Gerben Wierda, Oct 2001. I waive every +# copyright on this and I also do not give any warranty. + +Let's start with the important warning: + +DO NOT USE THE MULTIPLE USERS APPLICATION TO CREATE THE POSTFIX USER! + +Run the commands below in the order that they are presented + +A. INSTALLING POSTFIX for the first time and selecting it as the active + Mail Transfer Agent (MTA): + + # All these commands are written to be run from this directory. + + # this creates the necessary users & groups for proper operation + # of postfix: + sudo ./niscript + + # Prepare for reactivating sendmail if you want to + sudo ./backup-sendmail-binaries + + # Install postfix: + # When the script asks you for setgid (the default will be no) tell it + # maildrop + (cd ../..; sudo make install) + + # Prepare for reactivating postfix if you want to + sudo ./backup-postfix-binaries + + # edit /etc/postfix/main.cf to suit your requirements + + ### add your own command here ### + + # Install the startup item and move the existing sendmail startup item + # out of the way + sudo ./activate-postfix + + # Restart your computer + + # Test. Read INSTALL for a series of suggested tests. + +B. RESTORING Sendmail as the MTA when Postfix is the active MTA + + # Stop postfix + # Restore the sendmail binaries + # Restore the Sendmail startup item and move the Postfix startup item + # out of the way + sudo ./activate-sendmail + + # Restart your computer + +C. RESTORING postfix as the MTA when Sendmail is the active MTA + + # The first time you have to follow the steps of A. + + # Kill the running sendmail daemon if you know how + + # Restore the postfix binaries + # Restore the Postfix startup item and move the Sendmail startup item + # out of the way + sudo ./activate-postfix + + # Restart your computer diff --git a/gnu/dist/postfix/auxiliary/MacOSX/activate-postfix b/gnu/dist/postfix/auxiliary/MacOSX/activate-postfix new file mode 100755 index 00000000000..50d5b990add --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/activate-postfix @@ -0,0 +1,61 @@ +#!/bin/sh + +# Written by Gerben Wierda, Oct 2001. I waive every copyright on this and +# I also do not give any warranty. + +. ./defines + +if [ ! -e ${POSTFIXBACKUPDIR}/sendmail ] +then + echo "Something is wrong: there is no existing postfix binary backup" + exit 1; +else + echo "Restoring postfix versions of sendmail programs from backup..." + (cd ${POSTFIXBACKUPDIR}; tar cf - sendmail) | (cd /usr/sbin; tar xf -) + (cd ${POSTFIXBACKUPDIR}; tar cf - newaliases) | (cd /usr/bin; tar xf -) + (cd ${POSTFIXBACKUPDIR}; tar cf - mailq) | (cd /usr/bin; tar xf -) +fi + +if [ -e "${PSI}" ] +then + echo "Postfix StartupItem already exists." +else + if [ -e "${PSIDISABLED}" ] + then + echo "Reinstating disabled Postfix StartupItem..." + mv "${PSIDISABLED}" "${PSI}" + else + echo "Installing new default Postfix StartupItem..." + cp -R Postfix.StartupItem "${PSI}" + fi +fi + +if [ -e "${SSI}" ] +then + if [ ! -d "${SIDISABLEDDIR}" ] + then + mkdir -p "${SIDISABLEDDIR}" + fi + echo "Moving existing Sendmail StartupItem to ${SIDISABLEDDIR}..." + if [ -e "${SSIDISABLED}" ] + then + echo "Something is wrong. A disabled Sendmail StartupItem already exists." + DATETIME=`date +"%Y%b%e-%H%M%S"` + echo "Moving Sendmail to Sendmail.${DATETIME}" + mv "${SSI}" "${SSIDISABLED}.${DATETIME}" + echo "You should have just one ${SSIDISABLED}" + else + mv "${SSI}" "${SSIDISABLED}" + fi +fi + +. /etc/hostconfig + +if [ "${MAILSERVER:=-NO-}" = "-YES-" ] +then + echo "Postfix will start on reboot" +else + echo "Note: Postfix needs MAILSERVER set to -YES- in /etc/hostconfig" + echo "Postfix will NOT start on reboot" +fi + diff --git a/gnu/dist/postfix/auxiliary/MacOSX/activate-sendmail b/gnu/dist/postfix/auxiliary/MacOSX/activate-sendmail new file mode 100755 index 00000000000..15f68eb7816 --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/activate-sendmail @@ -0,0 +1,60 @@ +#!/bin/sh + +# Written by Gerben Wierda, Oct 2001. I waive every copyright on this and +# I also do not give any warranty. + +. ./defines + +if [ ! -e ${SENDMAILBACKUPDIR}/sendmail ] +then + echo "Something is wrong: there is no existing postfix binary backup" + exit 1; +else + echo "Restoring sendmail versions of sendmail programs from backup..." + (cd ${SENDMAILBACKUPDIR}; tar cf - sendmail) | (cd /usr/sbin; tar xf -) + (cd ${SENDMAILBACKUPDIR}; tar cf - newaliases) | (cd /usr/bin; tar xf -) + (cd ${SENDMAILBACKUPDIR}; tar cf - mailq) | (cd /usr/bin; tar xf -) +fi + +if [ -e "${SSI}" ] +then + echo "Sendmail StartupItem already exists." +else + if [ -e "${SSIDISABLED}" ] + then + echo "Reinstating disabled Sendmail StartupItem..." + mv "${SSIDISABLED}" "${SSI}" + else + echo "Something is wrong. I cannot find ${SSIDISABLED}" + echo "Postfix will be uninstalled, Sendmail not reinstalled." + fi +fi + +if [ -e "${PSI}" ] +then + if [ ! -d "${SIDISABLEDDIR}" ] + then + mkdir -p "${SIDISABLEDDIR}" + fi + echo "Moving existing Postfix StartupItem to ${SIDISABLEDDIR}..." + if [ -e "${PSIDISABLED}" ] + then + echo "Something is wrong. A disabled Postfix StartupItem already exists." + DATETIME=`date +"%Y%b%e-%H%M%S"` + echo "Moving Postfix to Postfix.${DATETIME}" + mv "${PSI}" "${PSIDISABLED}.${DATETIME}" + echo "You should have just one ${PSIDISABLED}" + else + mv "${PSI}" "${PSIDISABLED}" + fi +fi + +. /etc/hostconfig + +if [ "${MAILSERVER:=-NO-}" = "-YES-" ] +then + echo "Sendmail will start on reboot" +else + echo "Note: Sendmail needs MAILSERVER set to -YES- in /etc/hostconfig" + echo "Sendmail will NOT start on reboot" +fi diff --git a/gnu/dist/postfix/auxiliary/MacOSX/backup-postfix-binaries b/gnu/dist/postfix/auxiliary/MacOSX/backup-postfix-binaries new file mode 100755 index 00000000000..37c2b74c2fd --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/backup-postfix-binaries @@ -0,0 +1,20 @@ +#! /bin/sh + +# Written by Gerben Wierda, Oct 2001. I waive every copyright on this and +# I also do not give any warranty. + +# We use tar, as we do not know beforehand if we are dealing with real +# files or symbolic links. Since we use tar, we cannot change filenames +# we need to create a directory to hold our backup binaries. + +. ./defines + +if [ ! -d ${POSTFIXBACKUPDIR} ] +then + mkdir -p ${POSTFIXBACKUPDIR} +fi + +(cd /usr/sbin; tar cf - sendmail) | (cd ${POSTFIXBACKUPDIR}; tar xf -) +(cd /usr/bin; tar cf - newaliases) | (cd ${POSTFIXBACKUPDIR}; tar xf -) +(cd /usr/bin; tar cf - mailq) | (cd ${POSTFIXBACKUPDIR}; tar xf -) + diff --git a/gnu/dist/postfix/auxiliary/MacOSX/backup-sendmail-binaries b/gnu/dist/postfix/auxiliary/MacOSX/backup-sendmail-binaries new file mode 100755 index 00000000000..ae624f8a204 --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/backup-sendmail-binaries @@ -0,0 +1,20 @@ +#! /bin/sh + +# Written by Gerben Wierda, Oct 2001. I waive every copyright on this and +# I also do not give any warranty. + +# We use tar, as we do not know beforehand if we are dealing with real +# files or symbolic links. Since we use tar, we cannot change filenames +# we need to create a directory to hold our backup binaries. + +. ./defines + +if [ ! -d ${SENDMAILBACKUPDIR} ] +then + mkdir -p ${SENDMAILBACKUPDIR} +fi + +(cd /usr/sbin; tar cf - sendmail) | (cd ${SENDMAILBACKUPDIR}; tar xf -) +(cd /usr/bin; tar cf - newaliases) | (cd ${SENDMAILBACKUPDIR}; tar xf -) +(cd /usr/bin; tar cf - mailq) | (cd ${SENDMAILBACKUPDIR}; tar xf -) + diff --git a/gnu/dist/postfix/auxiliary/MacOSX/defines b/gnu/dist/postfix/auxiliary/MacOSX/defines new file mode 100644 index 00000000000..3aa667d7ff9 --- /dev/null +++ b/gnu/dist/postfix/auxiliary/MacOSX/defines @@ -0,0 +1,15 @@ +#! /bin/sh + +# Written by Gerben Wierda, Oct 2001. I waive every copyright on this and +# I also do not give any warranty. + +SIDIR="/System/Library/StartupItems" +SIDISABLEDDIR="/System/Library/DisabledStartupItems" + +PSI="${SIDIR}/Postfix" +SSI="${SIDIR}/Sendmail" +PSIDISABLED="${SIDISABLEDDIR}/Postfix" +SSIDISABLED="${SIDISABLEDDIR}/Sendmail" + +POSTFIXBACKUPDIR=/usr/sbin/.postfixbackup +SENDMAILBACKUPDIR=/usr/sbin/.sendmailbackup diff --git a/gnu/dist/postfix/auxiliary/MacOSX/niscript b/gnu/dist/postfix/auxiliary/MacOSX/niscript index 4b3b4df8b8e..1c7fb888b8e 100755 --- a/gnu/dist/postfix/auxiliary/MacOSX/niscript +++ b/gnu/dist/postfix/auxiliary/MacOSX/niscript @@ -1,118 +1,158 @@ -#! /bin/sh -# -# Written 9/20/00 by Joe Block <jpb@creol.ucf.edu> -# -# It shouldn't matter, but this script is GPL. +#!/usr/bin/perl + +# niscript.pl by Gerben Wierda <gerben_wierda@rna.nl> + +# This little script is an adaptation of the original niscript sh script by +# Joe Block <jpb@creol.ucf.edu> +# instead of using fixed uid/gid and thus not robust if you run it on a +# system where groups and/or users have been added, this script checks +# if the users/groups are there and if not creates them with free id's. + +print <<_WARNING -cat <<EOF This script massages your netinfo database. This can severely break your system. If your netinfo database breaks, you get to keep the parts. -If you've already created a postfix user using Multiple Users, you'll need -to edit this script. do: - - niutil -read / /users/postfix - -to find out what uid was assigned to postfix. Comment out the stanza in -this script that creates the postfix user - -Also note that this script assumes that you are - A) running MacOS X Public Beta - B) have not added any groups to the base system - -If you've added groups or are not running Public Beta, you should -make sure the gids in this script have not already been used. - -You'll need to edit the script to remove the exit statement before the first -call to niutil to show you read the directions and understand the risks. - -EOF - -PFSHELL=/usr/bin/false -PFUID=88 -PFGID=88 -PFHOME=/Users/postfix -MDGID=99 - -echo -n "shell for user postfix? [$PFSHELL]" -read pfshell -if ["$pfshell" = ""] -then - pfshell=$PFSHELL -fi -echo - -echo -n "uid for user postfix? [$PFUID]" -read pfuid -if ["$pfuid" = ""] -then - pfuid=$PFUID -fi -echo - -echo -n "gid for user postfix? [$PFGID]" -read pfgid -if ["$pfgid" = ""] -then - pfgid=$PFGID -fi -echo - -echo -n "Home directory for user postfix (we won't actually create it as postfix doesn't use it)? [$PFHOME]" -read pfhome -if ["$pfhome" = ""] -then - pfhome=$PFHOME -fi -echo - -echo -n "gid for maildrop group? [$MDGID]" -read mdgid -if ["$mdgid" = ""] -then - mdgid=$MDGID -fi -echo - -echo "postfix user: shell=$pfshell, uid=$pfuid, gid=$pfgid,home=$pfhome" -echo "maildrop group: $mdgid" -echo -echo -n "You're sure you want to massage your netinfo database? [yes/NO]" -read arewesure - -case $arewesure in - yes|YES) - echo "remember, you were warned" - ;; - *) - echo "OK, exiting" - exit 0 - ;; -esac -exit 0 - -echo "Tweaking netinfo now" -echo "Creating postfix user" -niutil -create / /users/postfix -niutil -createprop / /users/postfix realname "Postfix user" -niutil -createprop / /users/postfix shell $pfshell -niutil -createprop / /users/postfix uid $pfuid -niutil -createprop / /users/postfix gid $pfgid -niutil -createprop / /users/postfix home $pfhome -niutil -createprop / /users/postfix _shadow_passwd -passwd postfix - -echo "Creating postfix group" -niutil -create / /groups/postfix -niutil -createprop / /groups/postfix name postfix -niutil -createprop / /groups/postfix gid $pfgid -niutil -createprop / /groups/postfix passwd '*' -echo "Adding postfix user to postfix group" -niutil -appendprop / /groups/postfix users postfix - -echo "Creating maildrop group. Remember not to add any users to this group," -echo "or you might as well have made your maildrop directory world writable." -niutil -create / /groups/maildrop -niutil -createprop / /groups/maildrop name maildrop -niutil -createprop / /groups/maildrop gid $mdgid -niutil -createprop / /groups/maildrop passwd '*' +No Warranty. Really. + +This script tries to create two groups (if they do not already exist): +- postfix +- maildrop +and tries to create a user (if it does not already exist) +- postfix +which is member of group postfix. + +_WARNING +; + +# The script starts to look at id 88 (both for user and group) and up to 65535 +# It dies if no free id is found. + +my $postfixgid = undef; +my $maildropgid = undef; +my $postfixuid = undef; + +# First create + +my @groups = readgroups(); +foreach $group (@groups) { + (my $groupname, undef, my $gid, undef) = split( ':', $group); + if ($groupname eq 'postfix') { + warn "You already have a postfix group (with gid $gid)\n"; + $postfixgid = $gid; + } + if ($groupname eq 'maildrop') { + warn "You already have a maildrop group (with gid $gid)\n"; + $maildropgid = $gid; + } +} + +if (not defined $postfixgid) { + $postfixgid = creategroup( 'postfix'); +} + +if (not defined $maildropgid) { + $maildropgid = creategroup( 'maildrop'); +} + +my @users = readusers(); +foreach $user (@users) { + (my $username, undef, my $uid, undef) = split( ':', $user); + if ($username eq 'postfix') { + warn "You already have a postfix user (with uid $uid)\n"; + $postfixuid = $uid; + } +} + +if (not defined $postfixuid) { + $postfixuid = createuser( 'postfix', '"Postfix User"', + '/usr/bin/false', '/etc/postfix', + $postfixgid); + addusertogroup( 'postfix', 'postfix'); +} + +warn "\n"; + +sub creategroup +{ + my $name = shift; + open( NIDUMP, "nidump group /|") or die "Cannot run nidump\n"; + my @groups=<NIDUMP>; + close( NIDUMP); + + my $tryno; + NEXTNO: for ($tryno = 88; $tryno <= 65535; $tryno++) { + foreach my $group (@groups) { + (my $groupname, undef, my $gid, undef) = + split( ':', $group); + next NEXTNO if $gid == $tryno; + } + last NEXTNO; + } + die "Cannot find free gid\n" if $tryno == 65536; + warn "Will create $name as gid $tryno\n"; + system "niutil -create / /groups/$name"; + system "niutil -createprop / /groups/$name name $name"; + system "niutil -createprop / /groups/$name gid $tryno"; + system "niutil -createprop / /groups/$name passwd '*'"; + return $tryno; +} + +sub addusertogroup +{ + my $user = shift; + my $group = shift; + system "niutil -appendprop / /groups/$group users $user"; +} + +sub readgroups +{ + open( NIDUMP, "nidump group /|") or die "Cannot run nidump\n"; + my @groups=<NIDUMP>; + close( NIDUMP); + return @groups; +} + +sub readusers +{ + my @passwd; + open( NIDUMP, "nidump passwd /|") or die "Cannot run nidump\n"; + @passwd=<NIDUMP>; + close( NIDUMP); + return @passwd; +} + +sub createuser +{ + my $name = shift; + my $realname = shift; + my $shell = shift; + my $home = shift; + my $gid = shift; + + open( NIDUMP, "nidump passwd /|") or die "Cannot run nidump\n"; + my @passwd=<NIDUMP>; + close( NIDUMP); + + my $tryno; + NEXTNO: for ($tryno = 88; $tryno <= 65535; $tryno++) { + foreach my $passwd (@passwds) { + (my $passwdname, undef, my $uid, undef) = + split( ':', $passwd); + next NEXTNO if $uid == $tryno; + } + last NEXTNO; + } + die "Cannot find free uid\n" if $tryno == 65536; + warn "Will create $name as uid $tryno\n"; + system "niutil -create / /users/$name"; + system "niutil -createprop / /users/$name realname $realname"; + system "niutil -createprop / /users/$name shell $shell"; + system "niutil -createprop / /users/$name uid $tryno"; + system "niutil -createprop / /users/$name gid $gid"; + system "niutil -createprop / /users/$name home $home"; + system "niutil -createprop / /users/$name _shadow_passwd"; + system "niutil -createprop / /users/$name passwd '*'"; + return $tryno; +} + diff --git a/gnu/dist/postfix/conf/access b/gnu/dist/postfix/conf/access index 59a855eb32b..21a30fa370d 100644 --- a/gnu/dist/postfix/conf/access +++ b/gnu/dist/postfix/conf/access @@ -9,9 +9,9 @@ # # DESCRIPTION # The optional access table directs the Postfix SMTP server -# to selectively reject or accept mail from or to specific -# hosts, domains, networks, host addresses or mail -# addresses. +# to selectively reject or accept mail. Access can be +# allowed or denied for specific host names, domain names, +# networks, host network addresses or mail addresses. # # Normally, the access table is specified as a text file # that serves as input to the postmap(1) command. The @@ -32,39 +32,69 @@ # TABLE FORMAT # The format of the access table is as follows: # -# blanks and comments -# Blank lines are ignored, as are lines beginning -# with `#'. -# -# leading whitespace -# Lines that begin with whitespace continue the pre- -# vious line. -# # pattern action # When pattern matches a mail address, domain or host # address, perform the corresponding action. # -# PATTERNS +# blank lines and comments +# Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. +# +# multi-line text +# A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. +# +# EMAIL ADDRESS PATTERNS # With lookups from indexed files such as DB or DBM, or from -# networked tables such as NIS, LDAP or SQL, patterns are -# tried in the order as listed below: +# networked tables such as NIS, LDAP or SQL, the following +# lookup patterns are examined in the order as listed: # # user@domain # Matches the specified mail address. # # domain.name -# Matches the domain.name itself and any subdomain -# thereof, either in hostnames or in mail addresses. -# -# 1 -# -# ACCESS(5) ACCESS(5) +# Matches domain.name as the domain part of an email +# address. # -# Top-level domains will never be matched. +# The pattern domain.name also matches subdomains, +# but only when the string smtpd_access_maps is +# listed in the Postfix parent_domain_matches_subdo- +# mains configuration setting. Otherwise, specify +# .domain.name (note the initial dot) in order to +# match subdomains. # # user@ Matches all mail addresses with the specified user # part. # +# Note: lookup of the null sender address may not be possi- +# ble with all supported types of lookup table. A workaround +# is to specify smtpd_null_access_lookup_key = <> in the +# Postfix main.cf file, and to specify <> as the left-hand +# field in the access table. +# +# ADDRESS EXTENSION +# When a mail address localpart contains the optional recip- +# ient delimiter (e.g., user+foo@domain), the lookup order +# becomes: user+foo@domain, user@domain, domain, user+foo@, +# and user@. +# +# HOST NAME/ADDRESS PATTERNS +# With lookups from indexed files such as DB or DBM, or from +# networked tables such as NIS, LDAP or SQL, the following +# lookup patterns are examined in the order as listed: +# +# domain.name +# Matches domain.name. +# +# The pattern domain.name also matches subdomains, +# but only when the string smtpd_access_maps is +# listed in the Postfix parent_domain_matches_subdo- +# mains configuration setting. Otherwise, specify +# .domain.name (note the initial dot) in order to +# match subdomains. +# # net.work.addr.ess # # net.work.addr @@ -99,25 +129,22 @@ # the entire string being looked up. Depending on the appli- # cation, that string is an entire client hostname, an # entire client IP address, or an entire mail address. Thus, -# no parent domain or parent network search is done, and +# no parent domain or parent network search is done, # user@domain mail addresses are not broken up into their -# user@ and domain constituent parts. +# user@ and domain constituent parts, nor is user+foo broken +# up into user and foo. # -# Patterns are applied in the order as specified in the -# table, until a pattern is found that matches the search +# Patterns are applied in the order as specified in the +# table, until a pattern is found that matches the search # string. # -# Actions are the same as with normal indexed file lookups, -# with the additional feature that parenthesized substrings -# from the pattern can be interpolated as $1, $2 and so on. +# Actions are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from +# the pattern can be interpolated as $1, $2 and so on. # # BUGS # The table format does not understand quoting conventions. # -# 2 -# -# ACCESS(5) ACCESS(5) -# # SEE ALSO # postmap(1) create mapping table # smtpd(8) smtp server @@ -134,5 +161,5 @@ # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 3 +# 1 # diff --git a/gnu/dist/postfix/conf/aliases b/gnu/dist/postfix/conf/aliases index a836b8700c5..9e43ebc241d 100644 --- a/gnu/dist/postfix/conf/aliases +++ b/gnu/dist/postfix/conf/aliases @@ -1,4 +1,8 @@ # +# Sample aliases file. Install in the location as specified by the +# output from the command "postconf alias_maps". Typical path names +# are /etc/aliases or /etc/mail/aliases. +# # >>>>>>>>>> The program "newaliases" must be run after # >> NOTE >> this file is updated for any changes to # >>>>>>>>>> show through to Postfix. @@ -68,11 +72,13 @@ decode: root # # name: value1, value2, ... # -# o Lines that begin with whitespace continue the pre- -# vious line. +# o Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. # -# o Blank lines are ignored, as are lines beginning -# with `#'. +# o A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. # # The name is a local address (no domain part). Use double # quotes when the name contains any special characters such @@ -89,10 +95,6 @@ decode: root # # The value contains one or more of the following: # -# 1 -# -# ALIASES(5) ALIASES(5) -# # address # Mail is forwarded to address, which is compatible # with the RFC 822 standard. @@ -146,10 +148,6 @@ decode: root # Restrict the usage of mail delivery to external # command. # -# 2 -# -# ALIASES(5) ALIASES(5) -# # allow_mail_to_files # Restrict the usage of mail delivery to external # file. @@ -185,5 +183,5 @@ decode: root # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 3 +# 1 # diff --git a/gnu/dist/postfix/conf/canonical b/gnu/dist/postfix/conf/canonical index 6be24c04083..b7528ae7a9f 100644 --- a/gnu/dist/postfix/conf/canonical +++ b/gnu/dist/postfix/conf/canonical @@ -47,22 +47,20 @@ # TABLE FORMAT # The format of the canonical table is as follows: # -# blanks and comments -# Blank lines are ignored, as are lines beginning -# with `#'. -# -# leading whitespace -# Lines that begin with whitespace continue the pre- -# vious line. -# -# 1 -# -# CANONICAL(5) CANONICAL(5) -# # pattern result # When pattern matches a mail address, replace it by # the corresponding result. # +# blank lines and comments +# Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. +# +# multi-line text +# A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. +# # With lookups from indexed files such as DB or DBM, or from # networked tables such as NIS, LDAP or SQL, patterns are # tried in the order as listed below: @@ -92,13 +90,11 @@ # domain, the result is the same user in otherdomain. # # ADDRESS EXTENSION -# When table lookup fails, and the address localpart con- -# tains the optional recipient delimiter (e.g., -# user+foo@domain), the search is repeated for the unex- -# tended address (e.g. user@domain), and the unmatched -# extension is propagated to the result of table lookup. The -# matching order is: user+foo@domain, user@domain, user+foo, -# user, and @domain. +# When a mail address localpart contains the optional recip- +# ient delimiter (e.g., user+foo@domain), the lookup order +# becomes: user+foo@domain, user@domain, user+foo, user, and +# @domain. An unmatched address extension (+foo) is propa- +# gated to the result of table lookup. # # REGULAR EXPRESSION TABLES # This section describes how the table lookups change when @@ -113,25 +109,20 @@ # foo. # # Patterns are applied in the order as specified in the -# -# 2 -# -# CANONICAL(5) CANONICAL(5) -# # table, until a pattern is found that matches the search # string. # -# Results are the same as with normal indexed file lookups, -# with the additional feature that parenthesized substrings -# from the pattern can be interpolated as $1, $2 and so on. +# Results are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from +# the pattern can be interpolated as $1, $2 and so on. # # BUGS -# The table format does not understand quoting conventions. +# The table format does not understand quoting conventions. # # CONFIGURATION PARAMETERS -# The following main.cf parameters are especially relevant -# to this topic. See the Postfix main.cf file for syntax -# details and for default values. Use the postfix reload +# The following main.cf parameters are especially relevant +# to this topic. See the Postfix main.cf file for syntax +# details and for default values. Use the postfix reload # command after a configuration change. # # canonical_maps @@ -148,19 +139,24 @@ # Other parameters of interest: # # inet_interfaces -# The network interface addresses that this system +# The network interface addresses that this system # receives mail on. # +# masquerade_classes +# List of address classes subject to masquerading: +# zero or more of envelope_sender, envelope_recipi- +# ent, header_sender, header_recipient. +# # masquerade_domains -# List of domains that hide their subdomain struc- +# List of domains that hide their subdomain struc- # ture. # # masquerade_exceptions -# List of user names that are not subject to address +# List of user names that are not subject to address # masquerading. # # mydestination -# List of domains that this mail system considers +# List of domains that this mail system considers # local. # # myorigin @@ -172,18 +168,13 @@ # # SEE ALSO # cleanup(8) canonicalize and enqueue mail -# -# 3 -# -# CANONICAL(5) CANONICAL(5) -# # postmap(1) create mapping table # virtual(5) virtual domain mapping # pcre_table(5) format of PCRE tables # regexp_table(5) format of POSIX regular expression tables # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # # AUTHOR(S) @@ -192,5 +183,5 @@ # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 4 +# 1 # diff --git a/gnu/dist/postfix/conf/main.cf b/gnu/dist/postfix/conf/main.cf index 1612b1d4546..c90780737c1 100644 --- a/gnu/dist/postfix/conf/main.cf +++ b/gnu/dist/postfix/conf/main.cf @@ -44,9 +44,10 @@ daemon_directory = /usr/libexec/postfix # # The mail_owner parameter specifies the owner of the Postfix queue # and of most Postfix daemon processes. Specify the name of a user -# account THAT DOES NOT SHARE A GROUP WITH OTHER ACCOUNTS AND THAT -# OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In particular, -# don't specify nobody or daemon. PLEASE USE A DEDICATED USER. +# account THAT DOES NOT SHARE ITS USER OR GROUP ID WITH OTHER ACCOUNTS +# AND THAT OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In +# particular, don't specify nobody or daemon. PLEASE USE A DEDICATED +# USER. # mail_owner = postfix @@ -108,7 +109,7 @@ mail_owner = postfix # gateway, you should also include $mydomain. Do not specify the # names of domains that this machine is backup MX host for. Specify # those names via the relay_domains or permit_mx_backup settings for -# the SMTP server (see sample-smtpd.cf. +# the SMTP server (see sample-smtpd.cf). # # The local machine is always the final destination for mail addressed # to user@[the.net.work.address] of an interface that the mail system @@ -151,9 +152,9 @@ mail_owner = postfix # 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. @@ -163,10 +164,12 @@ mail_owner = postfix # address. # # You can also specify the absolute pathname of a pattern file instead -# of listing the patterns here. +# of listing the patterns here. Specify type:table for table-based lookups +# (the value on the table right-hand side is not used). # #mynetworks = 168.100.189.0/28, 127.0.0.0/8 #mynetworks = $config_directory/mynetworks +#mynetworks = hash:/etc/postfix/network_table # The relay_domains parameter restricts what clients this mail system # will relay mail from, or what destinations this system will relay @@ -211,15 +214,13 @@ mail_owner = postfix # # In the case of SMTP, specify a domain, host, host:port, [host]:port, # [address] or [address]:port; the form [host] turns off MX lookups. -# If you specify multiple SMTP destinations, Postfix will try them -# in the specified order. # # 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 # @@ -234,9 +235,29 @@ mail_owner = postfix # Beware: if the Postfix SMTP server runs chrooted, you may have to # copy the passwd (not shadow) database into the jail. This is # system dependent. -# +# #local_recipient_maps = $alias_maps unix:passwd.byname +# If you use both the Postfix local and virtual delivery agents, specify: +# +#local_recipient_maps = $alias_maps unix:passwd.byname $virtual_mailbox_maps + +# INPUT RATE CONTROL +# +# The in_flow_delay configuration parameter implements mail input +# flow control. This feature is turned off by default because it +# needs further development. +# +# A Postfix process will pause for $in_flow_delay seconds before +# accepting a new message, when the message arrival rate exceeds the +# message delivery rate. With the default 50 SMTP server process +# limit, this limits the mail inflow to 50 messages a second more +# than the number of messages delivered per second. +# +# Specify 0 to disable the feature. Valid delays are 0..10. +# +#in_flow_delay = 1 + # ADDRESS REWRITING # # Insert text from sample-rewrite.cf if you need to do address @@ -298,7 +319,7 @@ mail_owner = postfix # Basically, the software tries user+foo and .forward+foo before # trying user and .forward. # -# recipient_delimiter = + +#recipient_delimiter = + # DELIVERY TO MAILBOX # @@ -314,8 +335,8 @@ mail_owner = postfix # 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 @@ -378,25 +399,32 @@ mail_owner = postfix # # 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 # # The controls listed here are only a very small subset. See the file # sample-smtpd.cf for an elaborate list of anti-UCE controls. -# The header_checks parameter restricts what may appear in message -# headers. This requires that POSIX or PCRE regular expression support -# is built-in. Specify "/^header-name: stuff you do not want/ REJECT" -# in the pattern file. Patterns are case-insensitive by default. Note: -# specify only patterns ending in REJECT (reject entire message) or -# IGNORE (silently discard this header). Patterns ending in OK are -# mostly a waste of cycles. +# The header_checks parameter specifies an optional table with patterns +# that each logical message header is matched against, including +# headers that span multiple physical lines. Patterns are matched +# in the specified order, and the search stops upon the first match. +# When a pattern matches, what happens next depends on the associated +# action that is specified in the right-hand side of the table: +# +# REJECT the entire message is rejected. +# REJECT text.... The text is sent to the originator. +# IGNORE the header line is silently discarded. +# WARN the header is logged (not rejected) with a warning message. +# +# These patterns do not apply to MIME headers in the message body. # -#header_checks = regexp:/etc/postfix/filename -#header_checks = pcre:/etc/postfix/filename +# See also the body_checks example in the sample-filter.cf file. +# +#header_checks = regexp:/etc/postfix/header_checks # FAST ETRN SERVICE # @@ -460,8 +488,8 @@ debug_peer_level = 2 # 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. @@ -474,4 +502,39 @@ debugger_command = PATH=/usr/bin:/usr/X11R6/bin xxgdb $daemon_directory/$process_name $process_id & sleep 5 -# Other configurable parameters. +# INSTALL-TIME CONFIGURATION INFORMATION +# +# The following parameters are used when installing a new Postfix version. +# +# sendmail_path: The full pathname of the Postfix sendmail command. +# This is the Sendmail-compatible mail posting interface. +# +sendmail_path = + +# newaliases_path: The full pathname of the Postfix newaliases command. +# This is the Sendmail-compatible command to build alias databases. +# +newaliases_path = + +# mailq_path: The full pathname of the Postfix mailq command. This +# is the Sendmail-compatible mail queue listing command. +# +mailq_path = + +# setgid_group: The group for mail submission and queue management +# commands. This must be a group name with a numerical group ID that +# is not shared with other accounts, not even with the Postfix account. +# +setgid_group = + +# manpage_directory: The location of the Postfix on-line manual pages. +# +manpage_directory = + +# sample_directory: The location of the Postfix sample configuration files. +# +sample_directory = + +# readme_directory: The location of the Postfix README files. +# +readme_directory = diff --git a/gnu/dist/postfix/conf/master.cf b/gnu/dist/postfix/conf/master.cf index 7f3f3038ab8..622615671d2 100644 --- a/gnu/dist/postfix/conf/master.cf +++ b/gnu/dist/postfix/conf/master.cf @@ -69,25 +69,31 @@ # (yes) (yes) (yes) (never) (50) # ========================================================================== smtp inet n - n - - smtpd -pickup fifo n n n 60 1 pickup -cleanup unix - - n - 0 cleanup +#628 inet n - n - - qmqpd +pickup fifo n - n 60 1 pickup +cleanup unix n - n - 0 cleanup qmgr fifo n - n 300 1 qmgr #qmgr fifo n - n 300 1 nqmgr rewrite unix - - n - - trivial-rewrite bounce unix - - n - 0 bounce defer unix - - n - 0 bounce -flush unix - - n 1000? 0 flush +flush unix n - n 1000? 0 flush smtp unix - - n - - smtp showq unix n - n - - showq error unix - - n - - error local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - n - - lmtp +# +# Interfaces to non-Postfix software. Be sure to examine the manual +# pages of the non-Postfix software to find out what options it wants. +# The Cyrus deliver program has changed incompatibly. +# cyrus unix - n n - - pipe - flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} + flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} uucp unix - n n - - pipe - flags=F user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) + flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) ifmail unix - n n - - pipe - flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) + flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) bsmtp unix - n n - - pipe - flags=F. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient + flags=Fq. user=foo argv=/usr/local/sbin/bsmtp -f $sender $nexthop $recipient diff --git a/gnu/dist/postfix/conf/pcre_table b/gnu/dist/postfix/conf/pcre_table index 3894663833b..ebedffe48c8 100644 --- a/gnu/dist/postfix/conf/pcre_table +++ b/gnu/dist/postfix/conf/pcre_table @@ -18,67 +18,68 @@ # # The general form of a PCRE table is: # -# blanks and comments -# Blank lines are ignored, as are lines beginning -# with `#'. -# -# leading whitespace -# Lines that begin with whitespace continue the pre- -# vious line. -# # pattern result # When pattern matches a search string, use the cor- -# responding result. A line that starts with white -# space continues the preceding line. +# responding result. +# +# blank lines and comments +# Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. +# +# multi-line text +# A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. # # Each pattern is a perl-like regular expression. The -# expression delimiter can be any character, except whites- -# pace or characters that have special meaning (tradition- -# ally the forward slash is used). The regular expression +# expression delimiter can be any character, except whites- +# pace or characters that have special meaning (tradition- +# ally the forward slash is used). The regular expression # can contain whitespace. # # By default, matching is case-insensitive, although follow- -# ing the second slash with an `i' flag will reverse this. -# Other flags are supported, but the only other useful one +# ing the second slash with an `i' flag will reverse this. +# Other flags are supported, but the only other useful one # is `U', which makes matching ungreedy (see PCRE documenta- # tion and source for more info). # -# Each pattern is applied to the entire string being looked -# up. Depending on the application, that string is an -# entire client hostname, an entire client IP address, or an -# entire mail address. Thus, no parent domain or parent -# network search is done, and user@domain mail addresses are -# not broken up into their user and domain constituent -# parts, nor is user+foo broken up into user and foo. +# Each pattern is applied to the entire lookup key string. +# Depending on the application, that string is an entire +# client hostname, an entire client IP address, or an entire +# mail address. Thus, no parent domain or parent network +# search is done, and user@domain mail addresses are not +# broken up into their user and domain constituent parts, +# nor is user+foo broken up into user and foo. # -# Patterns are applied in the order as specified in the -# table, until a pattern is found that matches the search +# Patterns are applied in the order as specified in the +# table, until a pattern is found that matches the search # string. # -# 1 -# -# PCRE_TABLE(5) PCRE_TABLE(5) -# -# Substitution of sub-strings from the matched expression is -# possible using the conventional perl syntax ($1, $2, -# etc.). The macros in the replacement string may need to be -# written as ${n} or $(n) if they aren't followed by whites- -# pace. +# Substitution of substrings from the matched expression +# into the result string is possible using the conventional +# perl syntax ($1, $2, etc.). The macros in the result +# string may need to be written as ${n} or $(n) if they +# aren't followed by whitespace. # -# EXAMPLES +# EXAMPLE SMTPD ACCESS MAP # # Protect your outgoing majordomo exploders -# /^(?!owner-)(.*)-outgoing@(my.domain)$/ 550 Use ${1}@${2} instead +# /^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead # # # Bounce friend@whatever, except when whatever is our domain (you would # # be better just bouncing all friend@ mail - this is just an example). -# /^friend@(?!my.domain).*$/ 550 Stick this in your pipe $0 +# /^friend@(?!my\.domain)/ 550 Stick this in your pipe $0 # # # A multi-line entry. The text is sent as one line. # # -# /^noddy@connect.com.au$/ +# /^noddy@my\.domain$/ # 550 This user is a funny one. You really don't want to send mail to # them as it only makes their head spin. # +# EXAMPLE HEADER FILTER MAP +# /^Subject: make money fast/ REJECT +# /^To: friend@public\.com/ REJECT +# # SEE ALSO # regexp_table(5) format of POSIX regular expression tables # @@ -96,5 +97,5 @@ # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 2 +# 1 # diff --git a/gnu/dist/postfix/conf/post-install b/gnu/dist/postfix/conf/post-install new file mode 100644 index 00000000000..3feeb4a2e97 --- /dev/null +++ b/gnu/dist/postfix/conf/post-install @@ -0,0 +1,549 @@ +#!/bin/sh + +# To view the formatted manual page of this file, type: +# POSTFIXSOURCE/mantools/srctoman - post-install | nroff -man + +#++ +# NAME +# post-install +# SUMMARY +# Postfix post-installation script +# SYNOPSIS +# post-install [name=value] command ... +# DESCRIPTION +# The post-install script performs the finishing touch of a Postfix +# installation, after the executable programs and configuration +# files are installed. Usage is one of the following: +# .IP o +# While installing Postfix from source code on the local machine, the +# script is run by the postfix-install script to update selected file +# or directory permissions and to update Postfix configuration files. +# .IP o +# While installing Postfix from a pre-built package, the script is run +# by the package management procedure to set all file or directory +# permissions and to update Postfix configuration files. +# .IP o +# The script can be used to change installation parameter settings such +# as mail_owner or setgid_group after Postfix is already installed. +# .IP o +# The script can be used to upgrade configuration files and to upgrade +# file/directory permissions of a secondary Postfix instance. +# .IP o +# At Postfix start-up time, the script is run from "postfix check" to +# create missing queue directories. +# .PP +# The post-install script is controlled by installation parameters. +# Specific parameters are described at the end of this document. +# All installation parameters must be specified ahead of time via +# one of the methods described below. +# +# Arguments +# .IP create-missing +# Create missing queue directories with ownerships and permissions +# according to the contents of $config_directory/postfix-files, using +# the mail_owner and setgid_group parameter settings from the command +# line, process environment or from the installed main.cf file. +# +# This is required at Postfix start-up time. +# .IP set-permissions +# Set all file/directory ownerships and permissions according to the +# contents of $config_directory/postfix-files, using the mail_owner +# and setgid_group parameter settings from the command line, process +# environment or from the installed main.cf file. Implies create-missing. +# +# This is required when installing Postfix from a pre-built package, +# or when changing the mail_owner or setgid_group installation parameter +# settings after Postfix is already installed. +# .IP upgrade-permissions +# Update ownership and permission of existing files/directories as +# specified in $config_directory/postfix-files, using the mail_owner +# and setgid_group parameter settings from the command line, process +# environment or from the installed main.cf file. Implies create-missing. +# +# This is required when upgrading an existing Postfix instance. +# .IP upgrade-configuration +# Edit the installed main.cf and master.cf files, in order to account +# for missing services and to fix deprecated parameter settings. +# +# This is required when upgrading an existing Postfix instance. +# .IP upgrade-source +# Short-hand for: upgrade-permissions upgrade-configuration. +# +# This is recommended when upgrading Postfix from source code. +# .IP upgrade-package +# Short-hand for: set-permissions upgrade-configuration. +# +# This is recommended when upgrading Postfix from a pre-built package. +# .IP first-install-reminder +# Remind the user that they still need to configure main.cf and the +# aliases file, and that newaliases still needs to be run. +# +# This is recommended when Postfix is installed for the first time. +# MULTIPLE POSTFIX INSTANCES +# .ad +# .fi +# Multiple Postfix instances on the same machine can share command and +# daemon program files but must have separate configuration and queue +# directories. +# +# To create a secondary Postfix installation on the same machine, +# copy the configuration files from the primary Postfix instance to +# a secondary configuration directory and execute: +# +# post-install config_directory=secondary-config-directory \e +# .in +4 +# queue_directory=secondary-queue-directory \e +# .br +# create-missing +# .PP +# This creates secondary Postfix queue directories, sets their access +# permissions, and saves the specified installation parameters to the +# secondary main.cf file. +# +# Be sure to list the secondary configuration directory in the +# alternate_config_directories parameter in the primary main.cf file. +# +# To upgrade a secondary Postfix installation on the same machine, +# execute: +# +# post-install config_directory=secondary-config-directory \e +# .in +4 +# upgrade-permissions upgrade-configuration +# INSTALLATION PARAMETER INPUT METHODS +# .ad +# .fi +# Parameter settings can be specified through a variety of +# mechanisms. In order of decreasing precedence these are: +# .IP "command line" +# Parameter settings can be given as name=value arguments on +# the post-install command line. These have the highest precedence. +# Settings that override the installed main.cf file are saved. +# .IP "process environment" +# Parameter settings can be given as name=value environment +# variables. +# Settings that override the installed main.cf file are saved. +# .IP "installed configuration files" +# If a parameter is not specified via the command line or via the +# process environment, post-install will attempt to extract its +# value from the already installed Postfix main.cf configuration file. +# These settings have the lowest precedence. +# INSTALLATION PARAMETER DESCRIPTION +# .ad +# .fi +# The description of installation parameters is as follows: +# .IP config_directory +# The directory for Postfix configuration files. +# .IP daemon_directory +# The directory for Postfix daemon programs. This directory +# should not be in the command search path of any users. +# .IP command_directory +# The directory for Postfix administrative commands. This +# directory should be in the command search path of adminstrative users. +# .IP queue_directory +# The directory for Postfix queues. +# .IP sendmail_path +# The full pathname for the Postfix sendmail command. +# This is the Sendmail-compatible mail posting interface. +# .IP newaliases_path +# The full pathname for the Postfix newaliases command. +# This is the Sendmail-compatible command to build alias databases +# for the Postfix local delivery agent. +# .IP mailq_path +# The full pathname for the Postfix mailq command. +# This is the Sendmail-compatible command to list the mail queue. +# .IP mail_owner +# The owner of the Postfix queue. Its numerical user ID and group ID +# must not be used by any other accounts on the system. +# .IP setgid_group +# The group for mail submission and for queue management commands. +# Its numerical group ID must not be used by any other accounts on the +# system, not even by the mail_owner account. +# .IP manpage_directory +# The directory for the Postfix on-line manual pages. +# .IP sample_directory +# The directory for the Postfix sample configuration files. +# .IP readme_directory +# The directory for the Postfix README files. +# SEE ALSO +# postfix-install(1) Postfix primary installation script. +# FILES +# $config_directory/main.cf, Postfix installation parameters. +# $config_directory/postfix-files, installation control file. +# $config_directory/install.cf, obsolete configuration file. +# 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 +#-- + +umask 022 + +PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc:/usr/contrib/bin:/usr/gnu/bin:/usr/ucb:/usr/bsd +SHELL=/bin/sh +IFS=" +" +BACKUP_IFS="$IFS" + +USAGE="Usage: $0 [name=value] command + create-missing Create missing queue directories. + upgrade-source When installing or upgrading from source code. + upgrade-package When installing or upgrading from pre-built package. + first-install-reminder Remind of mandatory first-time configuration steps. + name=value Specify an installation parameter". + +# Process command-line options and parameter settings. Work around +# brain damaged shells. "IFS=value command" should not make the +# IFS=value setting permanent. But some broken standard allows it. + +create=; set_perms=; upgrade_perms=; upgrade_conf=; first_install_reminder= + +for arg +do + case $arg in + *=*) IFS= eval $arg; IFS="$BACKUP_IFS";; + create-missing) create=1;; + set-perm*) create=1; set_perms=1;; + upgrade-perm*) create=1; upgrade_perms=1;; + upgrade-conf*) upgrade_conf=1;; + upgrade-source) create=1; upgrade_conf=1; upgrade_perms=1;; + upgrade-package) create=1; upgrade_conf=1; set_perms=1;; + first-install*) first_install_reminder=1;; + *) echo "$0: Error: $USAGE" 1>&2; exit 1;; + esac + shift +done + +# Sanity checks. + +test -n "$create$upgrade_conf$first_install_reminder" || { + echo "$0: Error: $USAGE" 1>&2 + exit 1 +} + +# Bootstrapping problem. + +if [ -n "$command_directory" ] +then + POSTCONF="$command_directory/postconf" +else + POSTCONF="postconf" +fi + +$POSTCONF -d mail_version >/dev/null 2>/dev/null || { + echo $0: Error: no $POSTCONF command found. 1>&2 + echo Re-run this command as $0 command_directory=/some/where. 1>&2 + exit 1 +} + +test -n "$config_directory" || + config_directory=`$POSTCONF -d -h config_directory` || exit 1 + +test -d "$config_directory" || { + echo $0: Error: $config_directory is not a directory. 1>&2 + exit 1 +} + +test -f $config_directory/postfix-files || { + $0: Error: $config_directory/postfix-files is not a file. 1>&2 + exit 1 +} + +# +# LINUX by default does not synchronously update directories - +# that's dangerous for mail. +# +if [ -f /usr/bin/chattr ] +then + CHATTR="/usr/bin/chattr +S" +else + CHATTR=echo +fi + +case `uname -s` in +HP-UX*) FMT=cat;; + *) FMT=fmt;; +esac + +# If a parameter is not set via the command line or environment, +# try to use settings from installed configuration files. + +# Extract parameter settings from the obsolete install.cf file, as +# a transitional aid. + +grep setgid_group $config_directory/main.cf >/dev/null 2>&1 || { + test -f $config_directory/install.cf && { + for name in sendmail_path newaliases_path mailq_path setgid manpages + do + eval junk=\$$name + case "$junk" in + "") eval unset $name;; + esac + eval : \${$name="\`. $config_directory/install.cf; echo \$$name\`"} \ + || exit 1 + done + : ${setgid_group=$setgid} + : ${manpage_directory=$manpages} + } +} + +# Extract parameter settings from the installed main.cf file. + +test -f $config_directory/main.cf && { + for name in daemon_directory command_directory queue_directory mail_owner \ + setgid_group sendmail_path newaliases_path mailq_path \ + manpage_directory sample_directory readme_directory + do + eval junk=\$$name + case "$junk" in + "") eval unset $name;; + esac + eval : \${$name=\`$POSTCONF -c $config_directory -h $name\`} || exit 1 + done +} + +# Sanity checks + +case $manpage_directory in + no) echo $0: Error: manpage_directory no longer accepts \"no\" values. 1>&2 + echo Try again with \"$0 manpage_directory=/pathname ...\". 1>&2; exit 1;; +esac + +case $setgid_group in + no) echo $0: Error: setgid_group no longer accepts \"no\" values. 1>&2 + echo Try again with \"$0 setgid_group=groupname ...\" 1>&2; exit 1;; +esac + +for path in "$daemon_directory" "$command_directory" "$queue_directory" \ + "$sendmail_path" "$newaliases_path" "$mailq_path" "$manpage_directory" \ + "$sample_directory" +do + case "$path" in + /*) ;; + *) echo $0: Error: \"$path\" should be an absolute path name. 1>&2; exit 1;; + esac +done + +for path in "$readme_directory" +do + case "$path" in + /*) ;; + no) ;; + *) echo $0: Error: \"$path\" should be \"no\" or an absolute path name. 1>&2; exit 1;; + esac +done + +# Find out what parameters were not specified via command line, +# via environment, or via installed configuration files. + +missing= +for name in daemon_directory command_directory queue_directory mail_owner \ + setgid_group sendmail_path newaliases_path mailq_path manpage_directory \ + sample_directory readme_directory +do + eval test -n \"\$$name\" || missing="$missing $name" +done + +# All parameters must be specified at this point. + +test -n "$non_interactive" -a -n "$missing" && { + cat <<EOF | ${FMT} 1>&2 +$0: Error: some required installation parameters are not defined. + +- Either the parameters need to be given in the $config_directory/main.cf +file from a recent Postfix installation, + +- Or the parameters need to be specified through the process +environment. + +- Or the parameters need to be specified as name=value arguments +on the $0 command line, + +The following parameters were missing: + + $missing + +EOF + exit 1 +} + +POSTCONF="$command_directory/postconf" + +# Save settings, allowing command line/environment override. + +override= +for name in daemon_directory command_directory queue_directory mail_owner \ + setgid_group sendmail_path newaliases_path mailq_path manpage_directory \ + sample_directory readme_directory +do + eval test \"\$$name\" = \"`$POSTCONF -c $config_directory -h $name`\" || { + override=1 + break + } +done + +test -n "$override" && { + $POSTCONF -c $config_directory -e \ + "daemon_directory = $daemon_directory" \ + "command_directory = $command_directory" \ + "queue_directory = $queue_directory" \ + "mail_owner = $mail_owner" \ + "setgid_group = $setgid_group" \ + "sendmail_path = $sendmail_path" \ + "mailq_path = $mailq_path" \ + "newaliases_path = $newaliases_path" \ + "manpage_directory = $manpage_directory" \ + "sample_directory = $sample_directory" \ + "readme_directory = $readme_directory" \ + || exit 1 +} + +# Use file/directory status information in $config_directory/postfix-files. + +test -n "$create" && { + exec <$config_directory/postfix-files || exit 1 + while IFS=: read path type owner group mode flags junk + do + IFS="$BACKUP_IFS" + set_permission= + # Skip comments. + case $path in + [$]*) ;; + *) continue;; + esac + # Expand $name, and canonicalize null fields. + for name in path owner group flags + do + eval junk=\${$name} + case $junk in + [$]*) eval $name=$junk;; + -) eval $name=;; + *) ;; + esac + done + # Skip uninstalled files. + case $path in + no|no/*) continue;; + esac + # Pick up the flags. + case $flags in *u*) upgrade_flag=1;; *) upgrade_flag=;; esac + case $flags in *c*) create_flag=1;; *) create_flag=;; esac + case $flags in *r*) recursive="-R";; *) recursive=;; esac + # Create missing directories with proper owner/group/mode settings. + if [ -n "$create" -a "$type" = "d" -a -n "$create_flag" -a ! -d "$path" ] + then + mkdir $path || exit 1 + $CHATTR $path >/dev/null 2>/dev/null + set_permission=1 + # Update all owner/group/mode settings. + elif [ -n "$set_perms" ] + then + set_permission=1 + # Update obsolete owner/group/mode settings. + elif [ -n "$upgrade_perms" -a -n "$upgrade_flag" ] + then + set_permission=1 + fi + test -n "$set_permission" && { + chown $recursive $owner $path || exit 1 + test -z "$group" || chgrp $recursive $group $path || exit 1 + chmod $mode $path || exit 1 + } + done +} + +# Upgrade existing Postfix configuration files if necessary. + +test -n "$upgrade_conf" && { + + # Add missing flush service to master.cf. + + grep 'flush.*flush' $config_directory/master.cf >/dev/null || { + echo Editing $config_directory/master.cf, adding missing entry for flush service + cat >>$config_directory/master.cf <<EOF || exit 1 +flush unix - - n 1000? 0 flush +EOF + } + + # Change privileged pickup service into unprivileged. + + grep "^pickup[ ]*fifo[ ]*n[ ]*n" \ + $config_directory/master.cf >/dev/null && { + echo Editing $config_directory/master.cf, making the pickup service unprivileged + ed $config_directory/master.cf <<EOF || exit 1 +/^pickup[ ]*fifo[ ]*n[ ]*n/ +s/\(n[ ]*\)n/\1-/ +p +w +q +EOF + } + + # Change private cleanup and flush services into public. + + for name in cleanup flush + do + grep "^$name[ ]*unix[ ]*-" \ + $config_directory/master.cf >/dev/null && { + echo Editing $config_directory/master.cf, making the $name service public + ed $config_directory/master.cf <<EOF || exit 1 +/^$name[ ]*unix[ ]*-/ +s/-/n/ +p +w +q +EOF + } + done + + # With 10000 active queue files, the active queue directory should + # be hashed, and so should the other directories, because they + # can contain even more mail. + # + # Unfortunately, this sucks mailq performance on unloaded systems. + # + # If you don't want slow mailq, be sure to hash defer and deferred, + # because those two directories can contain lots of files. + + found=`$POSTCONF -c $config_directory -h hash_queue_names` + missing= + (echo "$found" | grep active >/dev/null) || missing="$missing active" + (echo "$found" | grep bounce >/dev/null) || missing="$missing bounce" + (echo "$found" | grep defer >/dev/null) || missing="$missing defer" + (echo "$found" | grep flush >/dev/null) || missing="$missing flush" + (echo "$found" | grep incoming>/dev/null)|| missing="$missing incoming" + (echo "$found" | grep deferred>/dev/null)|| missing="$missing deferred" + test -n "$missing" && { + echo fixing main.cf hash_queue_names for missing $missing + $POSTCONF -c $config_directory -e hash_queue_names="$found$missing" || + exit 1 + } +} + +# A reminder if this is the first time Postfix is being installed. + +test -n "$first_install_reminder" && { + + ALIASES=`$POSTCONF -h alias_database | sed 's/^[^:]*://'` + NEWALIASES_PATH=`$POSTCONF -h newaliases_path` + cat <<EOF | ${FMT} + + Warning: you still need to edit myorigin/mydestination/mynetworks + parameter settings in $config_directory/main.cf. + + See also http://www.postfix.org/faq.html for information about + dialup sites or about sites inside a firewalled network. + + BTW: Check your $ALIASES file and be sure to set up aliases + that send mail for root and postmaster to a real person, then + run $NEWALIASES_PATH. + +EOF + +} + +exit 0 diff --git a/gnu/dist/postfix/conf/postfix-files b/gnu/dist/postfix/conf/postfix-files new file mode 100644 index 00000000000..095d616544c --- /dev/null +++ b/gnu/dist/postfix/conf/postfix-files @@ -0,0 +1,189 @@ +# +# Do not edit this file. +# +# This file controls the postfix-install script for installation of +# Postfix programs, configuration files and documentation, as well +# as the post-install script for setting permissions and for updating +# Postfix configuration files. See the respective manual pages within +# the script files. +# +# Do not list $command_directory in this file, or it will be blown +# away by a future Postfix uninstallation procedure. You would not +# want to lose all files in /usr/sbin. +# +# Each record in this file describes one file or directory. +# Fields are separated by ":". Specify a null field as "-". +# Missing fields or separators at the end are OK. +# +# File format: +# name:type:owner:group:permission:flags +# No group means don't change group ownership. +# +# File types: +# d=directory +# f=regular file +# l=symlink to $sendmail_path +# +# File flags: +# No flag means the flag is not active. +# p=preserve existing file, do not replace (postfix-install). +# u=update owner/group/mode (post-install upgrade-permissions). +# c=create missing directory (post-install create-missing). +# r=apply owner/group recursively (post-install set/upgrade-permissions). +# +# Note: the "u" flag is for upgrading the permissions of existing files +# or directories after changes in Postfix architecture. For robustness +# it is a good idea to "u" all the files that have special ownership or +# permissions, so that running "make install" fixes any glitches. +# +$config_directory:d:root:-:755:u +$daemon_directory:d:root:-:755:u +$queue_directory:d:root:-:755:uc +$sample_directory:d:root:-:755 +$readme_directory:d:root:-:755 +$queue_directory/active:d:$mail_owner:-:700:ucr +$queue_directory/bounce:d:$mail_owner:-:700:ucr +$queue_directory/corrupt:d:$mail_owner:-:700:ucr +$queue_directory/defer:d:$mail_owner:-:700:ucr +$queue_directory/deferred:d:$mail_owner:-:700:ucr +$queue_directory/flush:d:$mail_owner:-:700:ucr +$queue_directory/incoming:d:$mail_owner:-:700:ucr +$queue_directory/private:d:$mail_owner:-:700:uc +$queue_directory/saved:d:$mail_owner:-:700:ucr +$queue_directory/maildrop:d:$mail_owner:$setgid_group:730:uc +$queue_directory/public:d:$mail_owner:$setgid_group:710:uc +$queue_directory/pid:d:root:-:755:uc +$daemon_directory/bounce:f:root:-:755 +$daemon_directory/cleanup:f:root:-:755 +$daemon_directory/error:f:root:-:755 +$daemon_directory/flush:f:root:-:755 +$daemon_directory/lmtp:f:root:-:755 +$daemon_directory/local:f:root:-:755 +$daemon_directory/master:f:root:-:755 +$daemon_directory/nqmgr:f:root:-:755 +$daemon_directory/pickup:f:root:-:755 +$daemon_directory/pipe:f:root:-:755 +$daemon_directory/qmgr:f:root:-:755 +$daemon_directory/qmqpd:f:root:-:755 +$daemon_directory/showq:f:root:-:755 +$daemon_directory/smtp:f:root:-:755 +$daemon_directory/smtpd:f:root:-:755 +$daemon_directory/spawn:f:root:-:755 +$daemon_directory/trivial-rewrite:f:root:-:755 +$daemon_directory/virtual:f:root:-:755 +$command_directory/postalias:f:root:-:755 +$command_directory/postcat:f:root:-:755 +$command_directory/postconf:f:root:-:755 +$command_directory/postfix:f:root:-:755 +$command_directory/postkick:f:root:-:755 +$command_directory/postlock:f:root:-:755 +$command_directory/postlog:f:root:-:755 +$command_directory/postmap:f:root:-:755 +$command_directory/postsuper:f:root:-:755 +$command_directory/postdrop:f:root:$setgid_group:2755:u +$command_directory/postqueue:f:root:$setgid_group:2755:u +$sendmail_path:f:root:-:755 +$newaliases_path:l:root:-:755 +$mailq_path:l:root:-:755 +$config_directory/LICENSE:f:root:-:644 +$config_directory/access:f:root:-:644:p +$config_directory/aliases:f:root:-:644:p +$config_directory/canonical:f:root:-:644:p +$config_directory/main.cf:f:root:-:644:p +$config_directory/main.cf.default:f:root:-:644 +$config_directory/master.cf:f:root:-:644:p +$config_directory/pcre_table:f:root:-:644:p +$config_directory/postfix-files:f:root:-:644 +$config_directory/regexp_table:f:root:-:644:p +$config_directory/relocated:f:root:-:644:p +$config_directory/transport:f:root:-:644:p +$config_directory/virtual:f:root:-:644:p +$config_directory/postfix-script:f:root:-:755 +$config_directory/post-install:f:root:-:755 +$manpage_directory/man1/mailq.1:f:root:-:644 +$manpage_directory/man1/newaliases.1:f:root:-:644 +$manpage_directory/man1/postalias.1:f:root:-:644 +$manpage_directory/man1/postcat.1:f:root:-:644 +$manpage_directory/man1/postconf.1:f:root:-:644 +$manpage_directory/man1/postdrop.1:f:root:-:644 +$manpage_directory/man1/postfix.1:f:root:-:644 +$manpage_directory/man1/postkick.1:f:root:-:644 +$manpage_directory/man1/postlock.1:f:root:-:644 +$manpage_directory/man1/postlog.1:f:root:-:644 +$manpage_directory/man1/postmap.1:f:root:-:644 +$manpage_directory/man1/postqueue.1:f:root:-:644 +$manpage_directory/man1/postsuper.1:f:root:-:644 +$manpage_directory/man1/sendmail.1:f:root:-:644 +$manpage_directory/man5/access.5:f:root:-:644 +$manpage_directory/man5/aliases.5:f:root:-:644 +$manpage_directory/man5/canonical.5:f:root:-:644 +$manpage_directory/man5/pcre_table.5:f:root:-:644 +$manpage_directory/man5/regexp_table.5:f:root:-:644 +$manpage_directory/man5/relocated.5:f:root:-:644 +$manpage_directory/man5/transport.5:f:root:-:644 +$manpage_directory/man5/virtual.5:f:root:-:644 +$manpage_directory/man8/bounce.8:f:root:-:644 +$manpage_directory/man8/cleanup.8:f:root:-:644 +$manpage_directory/man8/defer.8:f:root:-:644 +$manpage_directory/man8/error.8:f:root:-:644 +$manpage_directory/man8/flush.8:f:root:-:644 +$manpage_directory/man8/lmtp.8:f:root:-:644 +$manpage_directory/man8/local.8:f:root:-:644 +$manpage_directory/man8/master.8:f:root:-:644 +$manpage_directory/man8/nqmgr.8:f:root:-:644 +$manpage_directory/man8/pickup.8:f:root:-:644 +$manpage_directory/man8/pipe.8:f:root:-:644 +$manpage_directory/man8/qmgr.8:f:root:-:644 +$manpage_directory/man8/qmqpd.8:f:root:-:644 +$manpage_directory/man8/showq.8:f:root:-:644 +$manpage_directory/man8/smtp.8:f:root:-:644 +$manpage_directory/man8/smtpd.8:f:root:-:644 +$manpage_directory/man8/spawn.8:f:root:-:644 +$manpage_directory/man8/trivial-rewrite.8:f:root:-:644 +$manpage_directory/man8/virtual.8:f:root:-:644 +$sample_directory/sample-aliases.cf:f:root:-:644 +$sample_directory/sample-auth.cf:f:root:-:644 +$sample_directory/sample-canonical.cf:f:root:-:644 +$sample_directory/sample-compatibility.cf:f:root:-:644 +$sample_directory/sample-debug.cf:f:root:-:644 +$sample_directory/sample-filter.cf:f:root:-:644 +$sample_directory/sample-flush.cf:f:root:-:644 +$sample_directory/sample-ldap.cf:f:root:-:644 +$sample_directory/sample-lmtp.cf:f:root:-:644 +$sample_directory/sample-local.cf:f:root:-:644 +$sample_directory/sample-misc.cf:f:root:-:644 +$sample_directory/sample-pcre-access.cf:f:root:-:644 +$sample_directory/sample-pcre-body.cf:f:root:-:644 +$sample_directory/sample-pcre-header.cf:f:root:-:644 +$sample_directory/sample-qmqpd.cf:f:root:-:644 +$sample_directory/sample-rate.cf:f:root:-:644 +$sample_directory/sample-regexp-access.cf:f:root:-:644 +$sample_directory/sample-regexp-body.cf:f:root:-:644 +$sample_directory/sample-regexp-header.cf:f:root:-:644 +$sample_directory/sample-relocated.cf:f:root:-:644 +$sample_directory/sample-resource.cf:f:root:-:644 +$sample_directory/sample-rewrite.cf:f:root:-:644 +$sample_directory/sample-smtp.cf:f:root:-:644 +$sample_directory/sample-smtpd.cf:f:root:-:644 +$sample_directory/sample-transport.cf:f:root:-:644 +$sample_directory/sample-virtual.cf:f:root:-:644 +$readme_directory/DB_README:f:root:-:644 +$readme_directory/DEBUG_README:f:root:-:644 +$readme_directory/ETRN_README:f:root:-:644 +$readme_directory/FILTER_README:f:root:-:644 +$readme_directory/INSTALL:f:root:-:644 +$readme_directory/LDAP_README:f:root:-:644 +$readme_directory/LINUX_README:f:root:-:644 +$readme_directory/LMTP_README:f:root:-:644 +$readme_directory/MACOSX_README:f:root:-:644 +$readme_directory/MYSQL_README:f:root:-:644 +$readme_directory/NFS_README:f:root:-:644 +$readme_directory/PACKAGE_README:f:root:-:644 +$readme_directory/PCRE_README:f:root:-:644 +$readme_directory/QMQP_README:f:root:-:644 +$readme_directory/RESTRICTION_CLASS_README:f:root:-:644 +$readme_directory/SASL_README:f:root:-:644 +$readme_directory/ULTRIX_README:f:root:-:644 +$readme_directory/UUCP_README:f:root:-:644 +$readme_directory/VERP_README:f:root:-:644 +$readme_directory/VIRTUAL_README:f:root:-:644 diff --git a/gnu/dist/postfix/conf/postfix-script b/gnu/dist/postfix/conf/postfix-script index 3cc2ef9ff55..9b53a4d62d7 100755 --- a/gnu/dist/postfix/conf/postfix-script +++ b/gnu/dist/postfix/conf/postfix-script @@ -1,3 +1,223 @@ #!/bin/sh -echo Please read the SECURITY notes at the end of the INSTALL document 1>&2 +#++ +# NAME +# postfix-script 1 +# SUMMARY +# execute Postfix administrative commands +# SYNOPSIS +# \fBpostfix-script\fR \fIcommand\fR +# DESCRIPTION +# The \fBpostfix-script\fR script executes Postfix administrative +# commands in an environment that is set up by the \fBpostfix\fR(1) +# command. +# SEE ALSO +# master(8) Postfix master program +# postfix(1) Postfix administrative interface +# 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 +#-- + +# Avoid POSIX death due to SIGHUP when some parent process exits. + +trap '' 1 + +case $daemon_directory in +"") echo This script must be run by the postfix command. 1>&2 + echo Do not run directly. 1>&2 + exit 1 +esac + +LOGGER="$command_directory/postlog -t $MAIL_LOGTAG/postfix-script" +INFO="$LOGGER -p info" +WARN="$LOGGER -p warn" +ERROR="$LOGGER -p error" +FATAL="$LOGGER -p fatal" +PANIC="$LOGGER -p panic" + +umask 022 +SHELL=/bin/sh + +# +# Can't do much without these in place. +# +cd $command_directory || { + $FATAL no Postfix command directory $command_directory! + exit 1 +} +cd $daemon_directory || { + $FATAL no Postfix daemon directory $daemon_directory! + exit 1 +} +test -f master || { + $FATAL no Postfix master program $daemon_directory/master! + exit 1 +} +cd $config_directory || { + $FATAL no Postfix configuration directory $config_directory! + exit 1 +} +cd $queue_directory || { + $FATAL no Postfix queue directory $queue_directory! + exit 1 +} + +# +# Parse JCL +# +case $1 in + +start_msg) + + echo "Start postfix" + ;; + +stop_msg) + + echo "Stop postfix" + ;; + +start) + + $daemon_directory/master -t 2>/dev/null || { + $FATAL the Postfix mail system is already running + exit 1 + } + $config_directory/postfix-script check || { + $FATAL Postfix integrity check failed! + exit 1 + } + $INFO starting the Postfix mail system + $daemon_directory/master & + ;; + +drain) + + $daemon_directory/master -t 2>/dev/null && { + $FATAL the Postfix mail system is not running + exit 1 + } + $INFO stopping the Postfix mail system + kill -9 `sed 1q pid/master.pid` + ;; + +stop) + + $daemon_directory/master -t 2>/dev/null && { + $FATAL the Postfix mail system is not running + exit 1 + } + $INFO stopping the Postfix mail system + kill `sed 1q pid/master.pid` + ;; + +abort) + + $daemon_directory/master -t 2>/dev/null && { + $FATAL the Postfix mail system is not running + exit 1 + } + $INFO aborting the Postfix mail system + kill `sed 1q pid/master.pid` + ;; + +reload) + + $daemon_directory/master -t 2>/dev/null && { + $FATAL the Postfix mail system is not running + exit 1 + } + $INFO refreshing the Postfix mail system + $command_directory/postsuper active || exit 1 + kill -HUP `sed 1q pid/master.pid` + $command_directory/postsuper & + ;; + +flush) + + cd $queue_directory || { + $FATAL no Postfix queue directory $queue_directory! + exit 1 + } + $command_directory/postqueue -f + ;; + +check) + + for dir in $daemon_directory $config_directory $queue_directory + do + ls -lLd $dir | (grep " root " >/dev/null || + $WARN not owned by root: $dir) + done + + find $daemon_directory/* $config_directory/* ! -user root \ + -exec $WARN not owned by root: {} \; + + find $daemon_directory/. $config_directory/. \ + \( -perm -020 -o -perm -002 \) -type f \ + -exec $WARN group or other writable: {} \; + + $SHELL $config_directory/post-install create-missing || { + $WARN unable to create missing queue directories + exit 1 + } + + find `ls -d $queue_directory/* | \ + egrep '/(incoming|active|defer|deferred|bounce|saved|corrupt|public|private|flush)$'` \ + ! \( -type p -o -type s \) ! -user $mail_owner \ + -exec $WARN not owned by $mail_owner: {} \; + + for name in `ls -d $queue_directory/* | \ + egrep '/(bin|etc|lib|usr)$'` ; \ + do \ + find $name ! -user root \ + -exec $WARN not owned by root: {} \; ; \ + done + + for dir in $queue_directory/maildrop + do + ls -lLd $dir | (grep " $mail_owner " >/dev/null || + $WARN not owned by $mail_owner: $dir) + done + + for dir in bin etc lib sbin usr + do + test -d $dir && find $dir -type f -print | while read path + do + cmp -s $path /$path || + $WARN $queue_directory/$path and /$path differ + done + done + + # Look for incomplete installations. + + test -f $config_directory/master.cf || { + $FATAL no $config_directory/master.cf file found + exit 1 + } + + # See if all queue files are in the right place. This is slow. + # We must scan all queues for mis-named queue files before the + # mail system can run. + + $command_directory/postsuper || exit 1 + + find corrupt -type f -exec $WARN damaged message: {} \; + + # XXX also: look for weird stuff, weird permissions, etc. + ;; + +*) + + $FATAL "usage: postfix start (or stop, reload, abort, flush, or check)" + exit 1 + ;; + +esac diff --git a/gnu/dist/postfix/conf/regexp_table b/gnu/dist/postfix/conf/regexp_table index f9b8a5e2eb4..40acc1a0bd7 100644 --- a/gnu/dist/postfix/conf/regexp_table +++ b/gnu/dist/postfix/conf/regexp_table @@ -18,18 +18,19 @@ # # The general form of a Postfix regular expression table is: # -# blanks and comments -# Blank lines are ignored, as are lines beginning -# with `#'. -# -# leading whitespace -# Lines that begin with whitespace continue the pre- -# vious line. -# # pattern result # When pattern matches a search string, use the cor- -# responding result. A line that starts with white -# space continues the preceding line. +# responding result. +# +# blank lines and comments +# Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. +# +# multi-line text +# A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. # # pattern1!pattern2 result # Matches pattern1 but not pattern2. @@ -37,48 +38,48 @@ # Each pattern is a regular expression enclosed by a pair of # delimiters. The regular expression syntax is described in # re_format(7). The expression delimiter can be any charac- -# ter, except whitespace or characters that have special -# meaning (traditionally the forward slash is used). The +# ter, except whitespace or characters that have special +# meaning (traditionally the forward slash is used). The # regular expression can contain whitespace. # # By default, matching is case-insensitive, although follow- -# ing the second slash with an `i' flag will reverse this. -# Other flags are `x' (disable extended expression syntax), +# ing the second slash with an `i' flag will reverse this. +# Other flags are `x' (disable extended expression syntax), # and `m' (enable multi-line mode). # -# Each pattern is applied to the entire string being looked -# up. Depending on the application, that string is an -# entire client hostname, an entire client IP address, or an -# entire mail address. Thus, no parent domain or parent -# network search is done, and user@domain mail addresses are -# not broken up into their user and domain constituent -# parts, nor is user+foo broken up into user and foo. -# -# Patterns are applied in the order as specified in the +# Each pattern is applied to the entire lookup key string. +# Depending on the application, that string is an entire +# client hostname, an entire client IP address, or an entire +# mail address. Thus, no parent domain or parent network +# search is done, and user@domain mail addresses are not +# broken up into their user and domain constituent parts, +# nor is user+foo broken up into user and foo. # -# 1 -# -# REGEXP_TABLE(5) REGEXP_TABLE(5) -# -# table, until a pattern is found that matches the search +# Patterns are applied in the order as specified in the +# table, until a pattern is found that matches the search # string. # -# Substitution of sub-strings from the matched expression is -# possible using $1, $2, etc.. The macros in the replacement -# string may need to be written as ${n} or $(n) if they -# aren't followed by whitespace. +# Substitution of substrings from the matched expression +# into the result string is possible using $1, $2, etc.. The +# macros in the result string may need to be written as ${n} +# or $(n) if they aren't followed by whitespace. # -# EXAMPLES +# EXAMPLE SMTPD ACCESS MAP # # Disallow sender-specified routing. This is a must if you relay mail # # for other domains. -# /[%!@].*[%!@]/ 550 Sender-specified routing rejected +# /[%!@].*[%!@]/ 550 Sender-specified routing rejected # # # Postmaster is OK, that way they can talk to us about how to fix # # their problem. -# /^postmaster@.*$/ OK +# /^postmaster@/ OK # # # Protect your outgoing majordomo exploders -# /^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead +# /^(.*)-outgoing@(.*)$/!/^owner-/ 550 Use ${1}@${2} instead +# +# EXAMPLE HEADER FILTER MAP +# # These were once common in junk mail. +# /^Subject: make money fast/ REJECT +# /^To: friend@public\.com/ REJECT # # SEE ALSO # pcre_table(5) format of PCRE tables @@ -101,5 +102,5 @@ # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 2 +# 1 # diff --git a/gnu/dist/postfix/conf/relocated b/gnu/dist/postfix/conf/relocated index 37e2f29d0c5..28ec6afa1dd 100644 --- a/gnu/dist/postfix/conf/relocated +++ b/gnu/dist/postfix/conf/relocated @@ -33,18 +33,20 @@ # TABLE FORMAT # The format of the table is as follows: # -# o Blank lines are ignored, as are lines beginning -# with `#'. -# -# o Lines that begin with whitespace continue the pre- -# vious line. -# # o An entry has one of the following form: # key new_location # Where new_location specifies contact information # such as an email address, or perhaps a street # address or telephone number. # +# o Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. +# +# o A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. +# # With lookups from indexed files such as DB or DBM, or from # networked tables such as NIS, LDAP or SQL, the key field # is one of the following: @@ -55,11 +57,6 @@ # # user Matches user@site when site is $myorigin, when site # is listed in $mydestination, or when site is listed -# -# 1 -# -# RELOCATED(5) RELOCATED(5) -# # in $inet_interfaces. # # @domain @@ -67,10 +64,10 @@ # lowest precedence. # # ADDRESS EXTENSION -# When the search fails, and the address localpart contains -# the optional recipient delimiter (e.g., user+foo@domain), -# the search is repeated for the unextended address (e.g. -# user@domain). +# When a mail address localpart contains the optional recip- +# ient delimiter (e.g., user+foo@domain), the lookup order +# becomes: user+foo@domain, user@domain, user+foo, user, and +# @domain. # # REGULAR EXPRESSION TABLES # This section describes how the table lookups change when @@ -88,17 +85,17 @@ # table, until a pattern is found that matches the search # string. # -# Results are the same as with normal indexed file lookups, -# with the additional feature that parenthesized substrings -# from the pattern can be interpolated as $1, $2 and so on. +# Results are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from +# the pattern can be interpolated as $1, $2 and so on. # # BUGS -# The table format does not understand quoting conventions. +# The table format does not understand quoting conventions. # # CONFIGURATION PARAMETERS -# The following main.cf parameters are especially relevant -# to this topic. See the Postfix main.cf file for syntax -# details and for default values. Use the postfix reload +# The following main.cf parameters are especially relevant +# to this topic. See the Postfix main.cf file for syntax +# details and for default values. Use the postfix reload # command after a configuration change. # # relocated_maps @@ -107,17 +104,13 @@ # Other parameters of interest: # # inet_interfaces -# The network interface addresses that this system +# The network interface addresses that this system # receives mail on. # # mydestination -# List of domains that this mail system considers +# List of domains that this mail system considers # local. # -# 2 -# -# RELOCATED(5) RELOCATED(5) -# # myorigin # The domain that is appended to locally-posted mail. # @@ -127,7 +120,7 @@ # regexp_table(5) format of POSIX regular expression tables # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # # AUTHOR(S) @@ -136,5 +129,5 @@ # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 3 +# 1 # diff --git a/gnu/dist/postfix/conf/sample-aliases.cf b/gnu/dist/postfix/conf/sample-aliases.cf index 80dd4a6e82e..6ebebb66de1 100644 --- a/gnu/dist/postfix/conf/sample-aliases.cf +++ b/gnu/dist/postfix/conf/sample-aliases.cf @@ -13,8 +13,8 @@ # 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 @@ -30,6 +30,6 @@ alias_database = hash:/etc/aliases # 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 diff --git a/gnu/dist/postfix/conf/sample-auth.cf b/gnu/dist/postfix/conf/sample-auth.cf index be003437de8..00920bde736 100644 --- a/gnu/dist/postfix/conf/sample-auth.cf +++ b/gnu/dist/postfix/conf/sample-auth.cf @@ -70,7 +70,7 @@ smtpd_sasl_security_options = noanonymous # 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 diff --git a/gnu/dist/postfix/conf/sample-canonical.cf b/gnu/dist/postfix/conf/sample-canonical.cf index 1e3b0a57c8c..474976b70a8 100644 --- a/gnu/dist/postfix/conf/sample-canonical.cf +++ b/gnu/dist/postfix/conf/sample-canonical.cf @@ -17,10 +17,10 @@ # 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 @@ -30,7 +30,7 @@ canonical_maps = # # $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 @@ -44,5 +44,5 @@ recipient_canonical_maps = # # $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 = diff --git a/gnu/dist/postfix/conf/sample-debug.cf b/gnu/dist/postfix/conf/sample-debug.cf index c8a8e97a66c..5f850ddc751 100644 --- a/gnu/dist/postfix/conf/sample-debug.cf +++ b/gnu/dist/postfix/conf/sample-debug.cf @@ -16,8 +16,8 @@ debug_peer_level = 2 # 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 diff --git a/gnu/dist/postfix/conf/sample-filter.cf b/gnu/dist/postfix/conf/sample-filter.cf index 9093de5745a..8b9c960384e 100644 --- a/gnu/dist/postfix/conf/sample-filter.cf +++ b/gnu/dist/postfix/conf/sample-filter.cf @@ -9,14 +9,12 @@ # headers that span multiple physical lines. Patterns are matched # in the specified order, and the search stops upon the first match. # When a pattern matches, what happens next depends on the associated -# action: +# action that is specified in the right-hand side of the table: # # REJECT the entire message is rejected. -# +# REJECT text.... The text is sent to the originator. # IGNORE the header line is silently discarded. -# -# OK Nothing happens. the message will still be rejected when some -# other header line matches a REJECT pattern. +# WARN the header is logged (not rejected) with a warning message. # # These patterns do not apply to MIME headers in the message body. # @@ -25,17 +23,16 @@ header_checks = regexp:/etc/postfix/header_checks # The body_checks parameter specifies an optional table with patterns # that each physical line in the message body is matched against # (including MIME headers inside the message body - Postfix does not -# recognize multi-line MIME headers). Lines are matched one at a -# time. Long lines are matched in chunks of at most $line_length_limit -# characters. Patterns are matched in the specified order, and the -# search stops upon the first match. When a pattern matches, what -# happens next depends on the associated action: +# recognize multi-line MIME headers in the message body). +# Lines are matched one at a time. Long lines are matched in chunks +# of at most $line_length_limit characters. Patterns are matched in +# the specified order, and the search stops upon the first match. +# When a pattern matches, what happens next depends on the associated +# action that is specified in the right-hand side of the table: # # REJECT the entire message is rejected. -# +# REJECT text.... The text is sent to the originator. # IGNORE the body line is silently discarded. -# -# OK Nothing happens. The message will still be rejected when some -# other body line matches a REJECT pattern. +# WARN the body line is logged (not rejected) with a warning message. # body_checks = regexp:/etc/postfix/body_checks diff --git a/gnu/dist/postfix/conf/sample-flush.cf b/gnu/dist/postfix/conf/sample-flush.cf index 273fde3c9c8..2db8143686b 100644 --- a/gnu/dist/postfix/conf/sample-flush.cf +++ b/gnu/dist/postfix/conf/sample-flush.cf @@ -4,26 +4,28 @@ # This file contains example settings of Postfix parameters that # control the fast flush service, which is the code that implements # fast ETRN and fast "sendmail -qR". - -# The fast_flush_domains parameter specifies what destinations are -# eligible for per-destination logfiles with mail that is queued to -# those destinations. # -# When a destination is eligible for "fast flush" logfiles, ETRN and +# When a destination is eligible for "fast flush" service, ETRN and # "sendmail -qR" are implemented by delivering only messages that # are listed in the logfile for that destination (in fact, Postfix # will deliver to all recipients of those messages, regardless of # their destination, but that is not an issue when you relay mail # for an eligible site). -# -# When a destination is not eligible for "fast flush" logfiles, ETRN -# and "sendmail -qR" are implemented simply by attempting to deliver -# all queued mail. That's the slow service that Postfix used to -# implement before 20001005. + +# The fast_flush_domains parameter specifies what destinations are +# eligible for per-destination logfiles with mail that is queued to +# those destinations. # # By default, Postfix maintains "fast flush" logfiles only for # destinations that the Postfix SMTP server is willing to relay to -# (see the relay_domains parameter in sample-smtpd.cf). +# (i.e. the default is: "fast_flush_domains = $relay_domains"; see +# the relay_domains parameter in sample-smtpd.cf). +# +# Specify a list of hosts or domains, /file/name patterns or type:name +# lookup tables, separated by commas and/or whitespace. Continue +# long lines by starting the next line with whitespace. A file name +# is replaced by its contents; a type:name table is matched when a +# (parent) domain appears as lookup key. # # Specify "fast_flush_domains =" to disable the feature altogether. # diff --git a/gnu/dist/postfix/conf/sample-ldap.cf b/gnu/dist/postfix/conf/sample-ldap.cf index 8badb402609..58a752a33b2 100644 --- a/gnu/dist/postfix/conf/sample-ldap.cf +++ b/gnu/dist/postfix/conf/sample-ldap.cf @@ -43,7 +43,7 @@ # The entries referenced by these links are (recursively) treated as if # they were contained in the referencing entity. # -# ldap_special_result_attribute = +#ldap_special_result_attribute = # The ldap_scope parameter specifies the LDAP search scope: sub, base, or one. # @@ -86,3 +86,7 @@ # (exactly) the specified list of domains. # #ldap_domain = + +# The ldap_debuglevel parameter sets the debug level in the OpenLDAP +# libraries. +#ldap_debuglevel = 0 diff --git a/gnu/dist/postfix/conf/sample-lmtp.cf b/gnu/dist/postfix/conf/sample-lmtp.cf index 64419a35b36..9e2699cccbd 100644 --- a/gnu/dist/postfix/conf/sample-lmtp.cf +++ b/gnu/dist/postfix/conf/sample-lmtp.cf @@ -68,7 +68,7 @@ lmtp_destination_recipient_limit = $default_destination_recipient_limit # 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 diff --git a/gnu/dist/postfix/conf/sample-local.cf b/gnu/dist/postfix/conf/sample-local.cf index eab49fd8776..5e61971bb20 100644 --- a/gnu/dist/postfix/conf/sample-local.cf +++ b/gnu/dist/postfix/conf/sample-local.cf @@ -6,6 +6,10 @@ # # 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 @@ -15,7 +19,7 @@ # 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 @@ -84,14 +88,14 @@ forward_path = $home/.forward$recipient_delimiter$extension,$home/.forward # 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 @@ -110,8 +114,8 @@ default_privs = nobody # 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 @@ -127,16 +131,16 @@ home_mailbox = # # 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. +# system type. Specify a name ending in / for maildir-style delivery. # -# 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 @@ -157,10 +161,18 @@ home_mailbox = # 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 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 + # The mailbox_transport specifies the optional transport in master.cf # to use after processing aliases and .forward files. This parameter # has precedence over the mailbox_command, fallback_transport and @@ -171,8 +183,8 @@ mailbox_command = # :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 @@ -184,8 +196,8 @@ mailbox_transport = # :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 = # @@ -229,5 +241,5 @@ local_destination_recipient_limit = 1 # 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 diff --git a/gnu/dist/postfix/conf/sample-misc.cf b/gnu/dist/postfix/conf/sample-misc.cf index e672fb89522..d848d911975 100644 --- a/gnu/dist/postfix/conf/sample-misc.cf +++ b/gnu/dist/postfix/conf/sample-misc.cf @@ -24,8 +24,8 @@ daemon_timeout = 18000s # 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 @@ -36,7 +36,7 @@ daemon_timeout = 18000s # 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 @@ -98,8 +98,8 @@ hopcount_limit = 50 # # Specify a list of names separated by whitespace or comma. # -# import_environment = MAIL_CONFIG TZ XAUTHORITY DISPLAY HOME PURIFYOPTIONS -import_environment = MAIL_CONFIG MAIL_DEBUG TZ XAUTHORITY DISPLAY +#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 # addresses that this mail system receives mail on. By default, @@ -127,7 +127,7 @@ ipc_idle = 100s # 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 @@ -175,7 +175,7 @@ max_use = 100 # gateway, you should also include $mydomain. Do not specify the # names of domains that this machine is backup MX host for. Specify # those names via the relay_domains or permit_mx_backup settings for -# the SMTP server (see sample-smtpd.cf. +# the SMTP server (see sample-smtpd.cf). # # The local machine is always the final destination for mail addressed # to user@[the.net.work.address] of an interface that the mail system @@ -187,8 +187,8 @@ max_use = 100 # 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. @@ -212,7 +212,7 @@ mydestination = $myhostname, localhost.$mydomain # 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 @@ -237,9 +237,9 @@ myorigin = $myhostname # 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. @@ -259,8 +259,8 @@ myorigin = $myhostname # 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 @@ -272,10 +272,22 @@ bounce_notice_recipient = postmaster 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. # +# Note: this is a read-only variable. +# process_id_directory = pid # The program_directory parameter specifies the location of Postfix @@ -297,7 +309,7 @@ queue_directory = /var/spool/postfix # 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 @@ -329,15 +341,13 @@ recipient_delimiter = # # In the case of SMTP, specify a domain, host, host:port, [host]:port, # [address] or [address]:port; the form [host] turns off MX lookups. -# If you specify multiple SMTP destinations, Postfix will try them -# in the specified order. # # 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 @@ -349,7 +359,7 @@ relayhost = # 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 @@ -364,6 +374,18 @@ relocated_maps = # syslog_facility = mail +# The syslog_name parameter specifies the mail system name that is +# prepended to the process name in syslog records, so that "smtpd" +# becomes, for example, "postfix/smtpd". +# +# Beware: a non-default syslog_name setting takes effect only +# after process initialization. Some initialization errors will be +# logged with the default name, especially errors while parsing +# the command line and errors while accessing the Postfix main.cf +# configuration file. +# +syslog_name = postfix + # The trigger_timeout parameter limits the time to send a trigger to # a Postfix daemon. This prevents programs from getting stuck when the # mail system is under heavy load. @@ -380,4 +402,4 @@ trigger_timeout = 10s # 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 diff --git a/gnu/dist/postfix/conf/sample-pcre-access.cf b/gnu/dist/postfix/conf/sample-pcre-access.cf new file mode 100644 index 00000000000..849641fc0e7 --- /dev/null +++ b/gnu/dist/postfix/conf/sample-pcre-access.cf @@ -0,0 +1,54 @@ +# +# Sample pcre (PERL-compatible regular expression) map file for +# SMTPD access control. See pcre_table(5) and access(5) for +# syntax descriptions. +# +# The first field is a perl-like regular expression. The expression +# delimiter can be any character except whitespace, or characters +# that have special meaning to the regexp library (traditionally +# the forward slash is used). The regular expression can contain +# whitespace. +# +# By default, matching is case-INsensitive, although following +# the second slash with an 'i' will reverse this. Other flags are +# supported, but the only other useful one is 'U', which makes +# matching ungreedy (see PCRE documentation and source for more +# info). +# +# The second field is the "replacement" string - the text +# returned by the match. When used for smtpd checks, this would +# be a helpful message to misguided users (or an offensive +# message to spammers), although it could also be a domain name +# or other data for use as a transport, virtual, or other map. +# +# Substitution of sub-strings from the matched expression is +# possible using the conventional perl syntax. The macros in the +# replacement string may need to be protected with curly braces +# if they aren't followed by whitespace (see the examples +# below). +# +# Lines starting with whitespace are continuation lines - they are +# appended to the previous line (there should be no whitespace +# before your regular expression!) +# +# This code was originally developed for SPAM control. However +# it seems that it can be used equally well for address rewriting +# by virtual or canonical lookups. Using this for aliases might +# be stretching things, though. +# + +# Protect your outgoing majordomo exploders +# +/^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead + + +# Bounce friend@whatever, except when whatever is our domain (you would +# be better just bouncing all friend@ mail - this is just an example). +# +/^friend@(?!my\.domain)/ 550 Stick this in your pipe $0 + +# A multi-line response +# +/^noddy@my\.domain$/ + 550 This user is a funny one. You really don't want to send mail to them + as it only makes their head spin. diff --git a/gnu/dist/postfix/conf/sample-pcre-body.cf b/gnu/dist/postfix/conf/sample-pcre-body.cf new file mode 100644 index 00000000000..df3c6e03b6a --- /dev/null +++ b/gnu/dist/postfix/conf/sample-pcre-body.cf @@ -0,0 +1,38 @@ +# +# Sample pcre (PERL-compatible regular expression) map file for +# mail body filtering. See pcre_table(5) for syntax description. +# +# Mail body lines are filtered one line at a time. In particular, +# multi-line MIME headers in the message body are filtered one text +# line at a time. +# +# The first field is a perl-like regular expression. The expression +# delimiter can be any character except whitespace, or characters +# that have special meaning to the regexp library (traditionally +# the forward slash is used). The regular expression can contain +# whitespace. +# +# By default, matching is case-INsensitive, although following +# the second slash with an 'i' will reverse this. Other flags are +# supported, but the only other useful one is 'U', which makes +# matching ungreedy (see PCRE documentation and source for more +# info). +# +# The second field is the "replacement" string - the text +# returned by the match. +# +# REJECT The entire message is rejected. +# REJECT text.... The text is sent to the originator. +# IGNORE The line is silently discarded. +# WARN The line is logged (not rejected) with a warning. +# +# Substitution of sub-strings from the matched expression is +# possible using the conventional perl syntax. The macros in the +# replacement string may need to be protected with curly braces +# if they aren't followed by whitespace (see the examples +# below). +# +# Lines starting with whitespace are continuation lines - they are +# appended to the previous line (there should be no whitespace +# before your regular expression!) +# diff --git a/gnu/dist/postfix/conf/sample-pcre-header.cf b/gnu/dist/postfix/conf/sample-pcre-header.cf new file mode 100644 index 00000000000..6e5af4178cd --- /dev/null +++ b/gnu/dist/postfix/conf/sample-pcre-header.cf @@ -0,0 +1,41 @@ +# +# Sample pcre (PERL-compatible regular expression) map file for +# message header filtering. See pcre_table(5) for syntax description. +# +# Message headers are filtered one at a time. This filter understands +# multi-line message headers. However, the message header filter has +# no knowledge of MIME headers that are embedded in the message body. +# +# The first field is a perl-like regular expression. The expression +# delimiter can be any character except whitespace, or characters +# that have special meaning to the regexp library (traditionally +# the forward slash is used). The regular expression can contain +# whitespace. +# +# By default, matching is case-INsensitive, although following +# the second slash with an 'i' will reverse this. Other flags are +# supported, but the only other useful one is 'U', which makes +# matching ungreedy (see PCRE documentation and source for more +# info). +# +# The second field is the "replacement" string - the text +# returned by the match. +# +# REJECT The entire message is rejected. +# REJECT text.... The text is sent to the originator. +# IGNORE The header line is silently discarded. +# WARN The header is logged (not rejected) with a warning. +# +# Substitution of sub-strings from the matched expression is +# possible using the conventional perl syntax. The macros in the +# replacement string may need to be protected with curly braces +# if they aren't followed by whitespace (see the examples +# below). +# +# Lines starting with whitespace are continuation lines - they are +# appended to the previous line (there should be no whitespace +# before your regular expression!) +# + +/^Subject: Make Money Fast/ REJECT +/^To: friend@public.com/ REJECT diff --git a/gnu/dist/postfix/conf/sample-qmqpd.cf b/gnu/dist/postfix/conf/sample-qmqpd.cf new file mode 100644 index 00000000000..03d26ee3c4f --- /dev/null +++ b/gnu/dist/postfix/conf/sample-qmqpd.cf @@ -0,0 +1,40 @@ +# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF +# HERE JUST SERVES AS AN EXAMPLE. +# +# This file contains example settings of Postfix configuration parameters +# that control the QMQP server program. + +# The qmqpd_authorized_clients parameter specifies what clients are +# allowed to connect to the QMQP server port. +# +# By default, no client is allowed to use the service. This is +# because the QMQP server will relay mail to any destination. +# +# Specify a list of client patterns. A list pattern specifies a host +# name, a domain name, an internet address, or a network/mask pattern, +# where the mask specifies the number of bits in the network part. +# When a pattern specifies a file name, its contents are substituted +# for the file name; when a pattern is a type:name table specification, +# table lookup is used instead. +# +# Patterns are separated by whitespace and/or commas. In order to +# reverse the result, precede a non-file name pattern with an +# exclamation point (!). +# +#qmqpd_authorized_clients = + +# The qmqpd_error_delay parameter specifies how long the QMQP server +# will pause before sending a negative reply to the client. The +# purpose is to slow down confused or malicious clients. +# +# By default, the QMQP server pauses for 5 seconds. +# +#qmqpd_error_delay = 5s + +# The qmqpd_timeout parameter specifies a time limit for network I/O +# operations. If a read or write operation blocks for more than +# $qmqpd_timeout seconds the QMQP server gives up and disconnects. +# +# By default, the QMQP server runs out of patience after 300 seconds. +# +#qmqpd_timeout = 300s diff --git a/gnu/dist/postfix/conf/sample-regexp-access.cf b/gnu/dist/postfix/conf/sample-regexp-access.cf new file mode 100644 index 00000000000..9ac54c1ab76 --- /dev/null +++ b/gnu/dist/postfix/conf/sample-regexp-access.cf @@ -0,0 +1,26 @@ +# Sample regexp SMTPD access lookup "table". See regexp_table(5) +# and access(5) for a description of the syntax. +# +# The general format of a table entry is PATTERN RESULT. +# +# The pattern format is /regexp/flags or /regexp/flags!/regexp/flags +# where regexp is a regular expression as found in regexp(5), and flags are +# i: toggle ignore case (REG_ICASE - default is to ignore case) +# x: toggle extended expression (REG_EXTENDED - default is extended) +# m: toggle multiline mode (REG_NEWLINE - default is non-multiline mode) +# +# In order for a line to match, the first regexp must match, and the +# second (if present) must not match. The first matching line wins, +# terminating processing of the ruleset. +# +# The result syntax is described in the access(5) manual page. + +# Disallow sender-specified routing. This is a must if you relay mail +#for other domains. +/[%!@].*@/ 550 Sender-specified routing rejected + +# Postmaster is OK, that way they can talk to us about how to fix their problem. +/^postmaster@/ OK + +# Protect your outgoing majordomo exploders +/^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead diff --git a/gnu/dist/postfix/conf/sample-regexp-body.cf b/gnu/dist/postfix/conf/sample-regexp-body.cf new file mode 100644 index 00000000000..f9d3172dab3 --- /dev/null +++ b/gnu/dist/postfix/conf/sample-regexp-body.cf @@ -0,0 +1,23 @@ +# Sample regexp message body filter lookup "table". See regexp_table(5) +# for a description of the syntax. +# +# Mail body lines are filtered one line at a time. In particular, multi-line +# MIME headers in the message body are filtered one text line at a time. +# +# The general format of a table entry is PATTERN RESULT. +# +# The pattern format is /regexp/flags or /regexp/flags!/regexp/flags +# where regexp is a regular expression as found in regexp(5), and flags are +# i: toggle ignore case (REG_ICASE - default is to ignore case) +# x: toggle extended expression (REG_EXTENDED - default is extended) +# m: toggle multiline mode (REG_NEWLINE - default is non-multiline mode) +# +# In order for a line to match, the first regexp must match, and the +# second (if present) must not match. The first matching line wins, +# terminating processing of the ruleset. +# +# The result is one of the following: +# REJECT The entire message is rejected. +# REJECT text.... The text is sent to the originator. +# IGNORE The header line is silently discarded. +# WARN The header is logged (not rejected) with a warning. diff --git a/gnu/dist/postfix/conf/sample-regexp-header.cf b/gnu/dist/postfix/conf/sample-regexp-header.cf new file mode 100644 index 00000000000..6d46bdad2eb --- /dev/null +++ b/gnu/dist/postfix/conf/sample-regexp-header.cf @@ -0,0 +1,27 @@ +# Sample regexp message header filter lookup "table". See regexp_table(5) +# for a description of the syntax. +# +# Message headers are filtered one at a time. This filter understands +# multi-line mail headers. However, the message header filter has no +# knowledge of MIME headers that are embedded in the message body. +# +# The general format of a table entry is PATTERN RESULT. +# +# The pattern format is /regexp/flags or /regexp/flags!/regexp/flags +# where regexp is a regular expression as found in regexp(5), and flags are +# i: toggle ignore case (REG_ICASE - default is to ignore case) +# x: toggle extended expression (REG_EXTENDED - default is extended) +# m: toggle multiline mode (REG_NEWLINE - default is non-multiline mode) +# +# In order for a line to match, the first regexp must match, and the +# second (if present) must not match. The first matching line wins, +# terminating processing of the ruleset. +# +# The result is one of the following: +# REJECT the entire message is rejected. +# REJECT text.... The text is sent to the originator. +# IGNORE the header line is silently discarded. +# WARN the header is logged (not rejected) with a warning. + +/^Subject: Make Money Fast/ REJECT +/^To: friend@public.com/ REJECT diff --git a/gnu/dist/postfix/conf/sample-relocated.cf b/gnu/dist/postfix/conf/sample-relocated.cf index 1c83ca53877..611134b0a64 100644 --- a/gnu/dist/postfix/conf/sample-relocated.cf +++ b/gnu/dist/postfix/conf/sample-relocated.cf @@ -14,8 +14,8 @@ # 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 = diff --git a/gnu/dist/postfix/conf/sample-rewrite.cf b/gnu/dist/postfix/conf/sample-rewrite.cf index b4073fb4be0..c4d5e1ea194 100644 --- a/gnu/dist/postfix/conf/sample-rewrite.cf +++ b/gnu/dist/postfix/conf/sample-rewrite.cf @@ -7,7 +7,7 @@ # 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 @@ -18,7 +18,7 @@ append_at_myorigin = yes # 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 @@ -27,12 +27,25 @@ append_dot_mydomain = yes # empty_address_recipient = MAILER-DAEMON +# The masquerade_classes parameter controls what addresses are +# subject to address masquerading. +# +# By default, address masquerading is limited to envelope recipient +# addresses, and to header sender and header recipient addresses. +# This allows you to use address masquerading on a mail gateway while +# still being able to forward mail to users on individual machines. +# +# Specify zero or more of: envelope_sender, envelope_recipient, +# header_sender, header_recipient +# +masquerade_classes = envelope_sender, header_sender, header_recipient + # The masquerade_domains parameter gives an optional list of domains # that must have their subdomain structure stripped off. # # By default, address masquerading is disabled. # -# masquerade_domains = $mydomain +#masquerade_domains = $mydomain masquerade_domains = # The masquerade_exceptions parameter gives an optional list of user @@ -48,5 +61,5 @@ masquerade_exceptions = # "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 diff --git a/gnu/dist/postfix/conf/sample-smtp.cf b/gnu/dist/postfix/conf/sample-smtp.cf index ccaf5ec64d5..d2648e42ce4 100644 --- a/gnu/dist/postfix/conf/sample-smtp.cf +++ b/gnu/dist/postfix/conf/sample-smtp.cf @@ -65,6 +65,14 @@ smtp_never_send_ehlo = no # #smtp_bind_address=111.222.333.444 +# The smtp_break_lines parameter controls whether the SMTP client +# will break lines longer than $line_length_limit characters. +# +# By default, line breaking is turned on, because some fragile SMTP +# server implementations cannot receive mail with long lines. +# +#smtp_break_lines = yes + # The smtp_skip_4xx_greeting parameter controls what happens when # an SMTP server greets us with a 4XX status code (go away, try # again later). @@ -91,6 +99,29 @@ smtp_skip_5xx_greeting = yes # smtp_skip_quit_response = yes +# The smtp_pix_workaround_sleep_time parameter specifies how long +# the Postfix SMTP client pauses before sending .<CR><LF>, in order +# to work around the PIX firewall <CR><LF>.<CR><LF> bug. +# +# The default delay is 10 seconds. Choosing a too short time makes +# this workaround ineffective while sending large messages over slow +# network connections. +# +smtp_pix_workaround_delay_time = 10s + +# The smtp_pix_workaround_threshold_time parameter specifies how +# long a message must be queued before the PIX firewall <CR><LF>.<CR><LF> +# bug workaround is turned on. +# +# By default, the workaround is turned off for mail that is queued +# for less than 500 seconds. In other words, the workaround is normally +# turned off for the first delivery attempt. +# +# Specify 0 to enable the PIX firewall <CR><LF>.<CR><LF> bug workaround +# upon the first delivery attempt. +# +smtp_pix_workaround_threshold_time = 500s + # # RATE CONTROLS # @@ -130,7 +161,7 @@ smtp_destination_recipient_limit = $default_destination_recipient_limit # 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 diff --git a/gnu/dist/postfix/conf/sample-smtpd.cf b/gnu/dist/postfix/conf/sample-smtpd.cf index c0ff345f407..2882009b695 100644 --- a/gnu/dist/postfix/conf/sample-smtpd.cf +++ b/gnu/dist/postfix/conf/sample-smtpd.cf @@ -5,6 +5,36 @@ # that control the SMTP server program. # +# SENDER ANTI-SPOOFING +# + +# The smtpd_sender_login_maps parameter specifies the (SASL) login +# name that owns a sender (MAIL FROM) address. +# +# Specify zero or more maptype:mapname entries. Maps are created with +# postmap(1) or with equivalent means. The maps are searched in the +# specified order. Regexp tables are allowed. +# +# Each map entry specifies a sender address and the login name that +# owns the address. The search order is: +# +# 1) user@domain owner +# +# This form has the highest precedence. +# +# 2) user owner +# +# This matches user@site when site is equal to $myorigin, when site +# is listed in $mydestination, or when it is listed in $inet_interfaces. +# +# 3) @domain owner +# +# This matches every address in the specified domain, and has the +# lowest precedence. +# +#smtpd_sender_login_maps = + +# # MISCELLANEOUS # @@ -18,18 +48,17 @@ # 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 accepts only destinations 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: @@ -40,13 +69,27 @@ smtpd_banner = $myhostname ESMTP $mail_name # maptype:mapname: look up client name, parent domains, client address, # or networks obtained by stripping octets. # Reject if result is REJECT or "[45]xx text" -# Permit otherwise. +# Permit if result is OK or all numerical. # reject_maps_rbl: reject if the reverse client network address # 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_history_flush_threshold specifies how many lines the SMTP +# server command history is allowed to contain before it is flushed +# to postmaster upon receipt of EHLO, RSET, or end of DATA. +# +smtpd_history_flush_threshold = 100 + +# The smtpd_noop_commands parameter specifies a list of commands that +# the Postfix SMTP server replies to with "250 Ok", without doing any +# syntax checks and without changing state. This list overrides any +# commands built into the Postfix SMTP server. +# +smtpd_noop_commands = + # The smtpd_recipient_limit parameter restricts the number of recipients # that the SMTP server accepts per message delivery. # @@ -123,9 +166,9 @@ smtpd_hard_error_limit = 100 # 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. @@ -135,10 +178,12 @@ mynetworks_style = subnet # address. # # You can also specify the absolute pathname of a pattern file instead -# of listing the patterns here. +# of listing the patterns here. Specify type:table for table-based lookups +# (the value on the table right-hand side is not used). # #mynetworks = 168.100.189.0/28, 127.0.0.0/8 #mynetworks = $config_directory/mynetworks +#mynetworks = hash:/etc/postfix/network_table # The smtpd_client_restrictions parameter specifies optional restrictions # on SMTP client host names and addresses. @@ -152,10 +197,11 @@ mynetworks_style = subnet # maptype:mapname: look up client name, parent domains, client address, # or networks obtained by stripping octets. # Reject if result is REJECT or "[45]xx text" -# Permit otherwise. +# Permit if result is OK or all numerical. # 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. @@ -171,7 +217,7 @@ smtpd_client_restrictions = # 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 @@ -189,10 +235,11 @@ smtpd_helo_required = no # check_helo_access maptype:mapname # maptype:mapname: look up HELO hostname or parent domains. # Reject if result is REJECT or "[45]xx text" -# Permit otherwise. +# Permit if result is OK or all numerical. # 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. @@ -200,8 +247,8 @@ smtpd_helo_required = no # 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 @@ -219,13 +266,19 @@ smtpd_helo_restrictions = # check_sender_access maptype:mapname # maptype:mapname: look up sender address, parent domain, or localpart@. # Reject if result is REJECT or "[45]xx text" -# Permit otherwise. +# Permit if result is OK or all numerical. # check_client_access maptype:mapname: see smtpd_client_restrictions. # check_helo_access maptype:mapname: see smtpd_helo_restrictions. +# reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies +# a MAIL FROM address owner, but the client is not (SASL) logged in as +# that MAIL FROM address owner; or if the client is (SASL) logged in, but +# the client login name doesn't own the MAIL FROM address according to +# $smtpd_sender_login_maps (see above). # reject_non_fqdn_hostname: reject HELO hostname that is not in FQDN form # 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. @@ -233,8 +286,8 @@ smtpd_helo_restrictions = # 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 @@ -281,19 +334,27 @@ smtpd_sender_restrictions = # except for addresses with sender-specified routing. # reject_unauth_pipelining: reject mail from improperly pipelining spamware # permit_mx_backup: accept mail for sites that list me as MX host. +# Use the optional permit_mx_backup_networks parameter to also +# require that the primary MX hosts match a list of network blocks. # reject_unknown_recipient_domain: reject domains without A or MX record. # check_recipient_access maptype:mapname # maptype:mapname: look up recipient address, parent domain, or localpart@. # Reject if result is REJECT or "[45]xx text" -# Permit otherwise. +# Permit if result is OK or all numerical. # check_client_access maptype:mapname: see smtpd_client_restrictions. # check_helo_access maptype:mapname: see smtpd_helo_restrictions. # check_sender_access maptype:mapname: see smtpd_sender_restrictions. +# reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies +# a MAIL FROM address owner, but the client is not (SASL) logged in as +# that MAIL FROM address owner; or if the client is (SASL) logged in, but +# the client login name doesn't own the MAIL FROM address according to +# $smtpd_sender_login_maps (see above). # reject_non_fqdn_hostname: reject HELO hostname that is not in FQDN form # reject_non_fqdn_sender: reject sender address that is not in FQDN form # 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. @@ -321,6 +382,10 @@ smtpd_recipient_restrictions = permit_mynetworks,check_relay_domains # be tricked into forwarding junk mail to a primary MX host which # then spams it out to the world. # +# This parameter also controls if non-local addresses with sender-specified +# routing can match Postfix access tables. By default, such addresses +# cannot match Postfix access tables, because the address is ambigous. +# allow_untrusted_routing = no # The maps_rbl_domains parameter specifies an optional list of DNS diff --git a/gnu/dist/postfix/conf/sample-transport.cf b/gnu/dist/postfix/conf/sample-transport.cf index 8ecd2b56bc2..79d6f87d0f6 100644 --- a/gnu/dist/postfix/conf/sample-transport.cf +++ b/gnu/dist/postfix/conf/sample-transport.cf @@ -11,8 +11,8 @@ # 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 = diff --git a/gnu/dist/postfix/conf/sample-virtual.cf b/gnu/dist/postfix/conf/sample-virtual.cf index d660d6b797b..f11ccc317c3 100644 --- a/gnu/dist/postfix/conf/sample-virtual.cf +++ b/gnu/dist/postfix/conf/sample-virtual.cf @@ -16,8 +16,8 @@ # 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 = diff --git a/gnu/dist/postfix/conf/transport b/gnu/dist/postfix/conf/transport index 33ccfc00f58..3d6e07f0dcb 100644 --- a/gnu/dist/postfix/conf/transport +++ b/gnu/dist/postfix/conf/transport @@ -32,18 +32,20 @@ # TABLE FORMAT # The format of the transport table is as follows: # -# blanks and comments -# Blank lines are ignored, as are lines beginning -# with `#'. -# -# leading whitespace -# Lines that begin with whitespace continue the pre- -# vious line. -# # pattern result # When pattern matches the domain, use the corre- # sponding result. # +# blank lines and comments +# Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. +# +# multi-line text +# A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. +# # With lookups from indexed files such as DB or DBM, or from # networked tables such as NIS, LDAP or SQL, patterns are # tried in the order as listed below: @@ -54,11 +56,11 @@ # # .domain transport:nexthop # Mail for any subdomain of domain is delivered -# through transport to nexthop. -# -# 1 -# -# TRANSPORT(5) TRANSPORT(5) +# through transport to nexthop. This applies only +# when the string transport_maps is not listed in the +# parent_domain_matches_subdomains configuration set- +# ting. Otherwise, a domain name matches itself and +# its subdomains. # # Note: transport map entries take precedence over domains # specified in the mydestination parameter. If you use the @@ -114,10 +116,6 @@ # used. Specify [] around the hostname in order to disable # MX lookups. # -# 2 -# -# TRANSPORT(5) TRANSPORT(5) -# # The error mailer can be used to bounce mail: # # .foo.org error:mail for *.foo.org is not deliv- @@ -140,23 +138,28 @@ # table, until a pattern is found that matches the search # string. # -# Results are the same as with normal indexed file lookups, -# with the additional feature that parenthesized substrings -# from the pattern can be interpolated as $1, $2 and so on. +# Results are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from +# the pattern can be interpolated as $1, $2 and so on. # # CONFIGURATION PARAMETERS -# The following main.cf parameters are especially relevant -# to this topic. See the Postfix main.cf file for syntax -# details and for default values. Use the postfix reload +# The following main.cf parameters are especially relevant +# to this topic. See the Postfix main.cf file for syntax +# details and for default values. Use the postfix reload # command after a configuration change. # +# parent_domain_matches_subdomains +# List of Postfix features that use domain.name pat- +# terns to match sub.domain.name (as opposed to +# requiring .domain.name patterns). +# # transport_maps # List of transport lookup tables. # # Other parameters of interest: # # default_transport -# The transport to use when no transport is explic- +# The transport to use when no transport is explic- # itly specified. # # relayhost @@ -170,18 +173,14 @@ # regexp_table(5) format of POSIX regular expression tables # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # -# 3 -# -# TRANSPORT(5) TRANSPORT(5) -# # AUTHOR(S) # Wietse Venema # IBM T.J. Watson Research # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 4 +# 1 # diff --git a/gnu/dist/postfix/conf/virtual b/gnu/dist/postfix/conf/virtual index d0a3d7b8ac3..1a093feb3a5 100644 --- a/gnu/dist/postfix/conf/virtual +++ b/gnu/dist/postfix/conf/virtual @@ -54,13 +54,8 @@ # user1@virtual.domain address1 # user2@virtual.domain address2, address3 # -# The virtual.domain anything entry is required for a -# -# 1 -# -# VIRTUAL(5) VIRTUAL(5) -# -# Postfix-style virtual domain. +# The virtual.domain anything entry is required for a Post- +# fix-style virtual domain. # # Do not list a Postfix-style virtual domain in the main.cf # mydestination configuration parameter. Such an entry is @@ -94,7 +89,7 @@ # The main.cf mydestination entry is required for a Send- # mail-style virtual domain. # -# Do not specify a virtual.domain whatever virtual map entry +# Do not specify a virtual.domain anything virtual map entry # for a Sendmail-style virtual domain. Such an entry is # required only with a Postfix-style virtual domain. # @@ -108,23 +103,20 @@ # The format of the virtual table is as follows, mappings # being tried in the order as listed in this manual page: # -# blanks and comments -# Blank lines are ignored, as are lines beginning -# with `#'. -# -# leading whitespace -# Lines that begin with whitespace continue the -# -# 2 -# -# VIRTUAL(5) VIRTUAL(5) -# -# previous line. -# # pattern result # When pattern matches a mail address, replace it by # the corresponding result. # +# blank lines and comments +# Empty lines and whitespace-only lines are ignored, +# as are lines whose first non-whitespace character +# is a `#'. +# +# multi-line text +# A logical line starts with non-whitespace text. A +# line that starts with whitespace continues a logi- +# cal line. +# # With lookups from indexed files such as DB or DBM, or from # networked tables such as NIS, LDAP or SQL, patterns are # tried in the order as listed below: @@ -153,12 +145,11 @@ # works for the first address in the expansion only. # # ADDRESS EXTENSION -# When the search fails, and the address localpart contains -# the optional recipient delimiter (e.g., user+foo@domain), -# the search is repeated for the unextended address (e.g. -# user@domain), and the unmatched address extension is prop- -# agated to the result of expansion. The matching order is: -# user+foo@domain, user@domain, user+foo, user, and @domain. +# When a mail address localpart contains the optional recip- +# ient delimiter (e.g., user+foo@domain), the lookup order +# becomes: user+foo@domain, user@domain, user+foo, user, and +# @domain. An unmatched address extension (+foo) is propa- +# gated to the result of table lookup. # # REGULAR EXPRESSION TABLES # This section describes how the table lookups change when @@ -173,25 +164,20 @@ # foo. # # Patterns are applied in the order as specified in the -# -# 3 -# -# VIRTUAL(5) VIRTUAL(5) -# # table, until a pattern is found that matches the search # string. # -# Results are the same as with normal indexed file lookups, -# with the additional feature that parenthesized substrings -# from the pattern can be interpolated as $1, $2 and so on. +# Results are the same as with indexed file lookups, with +# the additional feature that parenthesized substrings from +# the pattern can be interpolated as $1, $2 and so on. # # BUGS -# The table format does not understand quoting conventions. +# The table format does not understand quoting conventions. # # CONFIGURATION PARAMETERS -# The following main.cf parameters are especially relevant -# to this topic. See the Postfix main.cf file for syntax -# details and for default values. Use the postfix reload +# The following main.cf parameters are especially relevant +# to this topic. See the Postfix main.cf file for syntax +# details and for default values. Use the postfix reload # command after a configuration change. # # virtual_maps @@ -200,11 +186,11 @@ # Other parameters of interest: # # inet_interfaces -# The network interface addresses that this system +# The network interface addresses that this system # receives mail on. # # mydestination -# List of domains that this mail system considers +# List of domains that this mail system considers # local. # # myorigin @@ -221,7 +207,7 @@ # regexp_table(5) format of POSIX regular expression tables # # LICENSE -# The Secure Mailer license must be distributed with this +# The Secure Mailer license must be distributed with this # software. # # AUTHOR(S) @@ -230,5 +216,5 @@ # P.O. Box 704 # Yorktown Heights, NY 10598, USA # -# 4 +# 1 # diff --git a/gnu/dist/postfix/examples/chroot-setup/LINUX2 b/gnu/dist/postfix/examples/chroot-setup/LINUX2 index cd63d099bbc..f63c22c1747 100644 --- a/gnu/dist/postfix/examples/chroot-setup/LINUX2 +++ b/gnu/dist/postfix/examples/chroot-setup/LINUX2 @@ -39,10 +39,6 @@ # remove /etc/localtime in case it's a broken symlink # restrict find to maxdepth 1 (faster) -# $Log: LINUX2,v $ -# Revision 1.1.1.3 2001/04/02 10:55:36 itojun -# postfix 20010228-pl01 -# # Revision 1.4 2001/01/15 09:36:35 emma # add note it was successfully tested on Debian sid # diff --git a/gnu/dist/postfix/html/Makefile.in b/gnu/dist/postfix/html/Makefile.in index 8f7e91ac162..ca3515cb256 100644 --- a/gnu/dist/postfix/html/Makefile.in +++ b/gnu/dist/postfix/html/Makefile.in @@ -5,14 +5,16 @@ SHELL = /bin/sh DAEMONS = bounce.8.html cleanup.8.html defer.8.html error.8.html local.8.html \ lmtp.8.html master.8.html pickup.8.html pipe.8.html qmgr.8.html \ showq.8.html smtp.8.html smtpd.8.html trivial-rewrite.8.html \ - spawn.8.html flush.8.html # nqmgr.8.html virtual.8.html + nqmgr.8.html spawn.8.html flush.8.html virtual.8.html qmqpd.8.html COMMANDS= mailq.1.html newaliases.1.html postalias.1.html postcat.1.html \ postconf.1.html postfix.1.html postkick.1.html postlock.1.html \ postlog.1.html postdrop.1.html postmap.1.html sendmail.1.html \ - postsuper.1.html + postqueue.1.html postsuper.1.html CONFIG = access.5.html aliases.5.html canonical.5.html relocated.5.html \ transport.5.html virtual.5.html pcre_table.5.html regexp_table.5.html +AWK = awk '{ print; if (NR == 1) print ".pl 9999" }' + update: $(DAEMONS) $(COMMANDS) $(CONFIG) Makefile: Makefile.in @@ -27,124 +29,170 @@ clobber: rm -f $(DAEMONS) $(COMMANDS) $(CONFIG) bounce.8.html: ../src/bounce/bounce.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ defer.8.html: bounce.8.html rm -f $@ ln -s $? $@ error.8.html: ../src/error/error.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ flush.8.html: ../src/flush/flush.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ cleanup.8.html: ../src/cleanup/cleanup.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ lmtp.8.html: ../src/lmtp/lmtp.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ local.8.html: ../src/local/local.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ master.8.html: ../src/master/master.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ nqmgr.8.html: ../src/nqmgr/qmgr.c + PATH=../mantools:$$PATH; \ srctoman $? | sed -e 's/qmgr[^_]/n&/' \ -e 's/qmgr$$/n&/' \ -e 's/QMGR[^_]/N&/' | \ - nroff -man | man2html | postlink >$@ + $(AWK) | nroff -man | uniq | man2html | postlink >$@ pickup.8.html: ../src/pickup/pickup.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ pipe.8.html: ../src/pipe/pipe.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ qmgr.8.html: ../src/qmgr/qmgr.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ + +qmqpd.8.html: ../src/qmqpd/qmqpd.c + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ showq.8.html: ../src/showq/showq.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ spawn.8.html: ../src/spawn/spawn.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ smtp.8.html: ../src/smtp/smtp.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ smtpd.8.html: ../src/smtpd/smtpd.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ virtual.8.html: ../src/virtual/virtual.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ trivial-rewrite.8.html: ../src/trivial-rewrite/trivial-rewrite.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postalias.1.html: ../src/postalias/postalias.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postcat.1.html: ../src/postcat/postcat.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postconf.1.html: ../src/postconf/postconf.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postdrop.1.html: ../src/postdrop/postdrop.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postfix.1.html: ../src/postfix/postfix.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postkick.1.html: ../src/postkick/postkick.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postlock.1.html: ../src/postlock/postlock.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postlog.1.html: ../src/postlog/postlog.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postmap.1.html: ../src/postmap/postmap.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ + +postqueue.1.html: ../src/postqueue/postqueue.c + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ postsuper.1.html: ../src/postsuper/postsuper.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ sendmail.1.html: ../src/sendmail/sendmail.c - srctoman $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ mailq.1.html: sendmail.1.html + PATH=../mantools:$$PATH; \ rm -f $@ ln -s $? $@ newaliases.1.html: sendmail.1.html + PATH=../mantools:$$PATH; \ rm -f $@ ln -s $? $@ access.5.html: ../proto/access - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ aliases.5.html: ../proto/aliases - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ canonical.5.html: ../proto/canonical - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ pcre_table.5.html: ../proto/pcre_table - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ regexp_table.5.html: ../proto/regexp_table - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ relocated.5.html: ../proto/relocated - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ transport.5.html: ../proto/transport - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ virtual.5.html: ../proto/virtual - srctoman - $? | nroff -man | man2html | postlink >$@ + PATH=../mantools:$$PATH; \ + srctoman - $? | $(AWK) | nroff -man | uniq | man2html | postlink >$@ diff --git a/gnu/dist/postfix/html/access.5.html b/gnu/dist/postfix/html/access.5.html index 89db2dcb3a7..ce041680ba5 100644 --- a/gnu/dist/postfix/html/access.5.html +++ b/gnu/dist/postfix/html/access.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - ACCESS(5) ACCESS(5) - <b>NAME</b> access - format of Postfix access table @@ -13,9 +10,9 @@ ACCESS(5) ACCESS(5) <b>DESCRIPTION</b> The optional <b>access</b> table directs the Postfix SMTP server - to selectively reject or accept mail from or to specific - hosts, domains, networks, host addresses or mail - addresses. + to selectively reject or accept mail. Access can be + allowed or denied for specific host names, domain names, + networks, host network addresses or mail addresses. Normally, the <b>access</b> table is specified as a text file that serves as input to the <a href="postmap.1.html"><b>postmap</b>(1)</a> command. The @@ -36,45 +33,68 @@ ACCESS(5) ACCESS(5) <b>TABLE</b> <b>FORMAT</b> The format of the access table is as follows: - blanks and comments - Blank lines are ignored, as are lines beginning - with `#'. - - leading whitespace - Lines that begin with whitespace continue the pre- - vious line. - <i>pattern</i> <i>action</i> When <i>pattern</i> matches a mail address, domain or host address, perform the corresponding <i>action</i>. -<b>PATTERNS</b> + blank lines and comments + Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + multi-line text + A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. + +<b>EMAIL</b> <b>ADDRESS</b> <b>PATTERNS</b> With lookups from indexed files such as DB or DBM, or from - networked tables such as NIS, LDAP or SQL, patterns are - tried in the order as listed below: + networked tables such as NIS, LDAP or SQL, the following + lookup patterns are examined in the order as listed: <i>user</i>@<i>domain</i> Matches the specified mail address. <i>domain.name</i> - Matches the <i>domain.name</i> itself and any subdomain - thereof, either in hostnames or in mail addresses. - - - - 1 - + Matches <i>domain.name</i> as the domain part of an email + address. + The pattern <i>domain.name</i> also matches subdomains, + but only when the string <b>smtpd</b><i>_</i><b>access</b><i>_</i><b>maps</b> is + listed in the Postfix <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdo-</b> + <b>mains</b> configuration setting. Otherwise, specify + <i>.domain.name</i> (note the initial dot) in order to + match subdomains. + <i>user</i>@ Matches all mail addresses with the specified user + part. + Note: lookup of the null sender address may not be possi- + ble with all supported types of lookup table. A workaround + is to specify <b>smtpd</b><i>_</i><b>null</b><i>_</i><b>access</b><i>_</i><b>lookup</b><i>_</i><b>key</b> <b>=</b> <> in the + Postfix <b>main.cf</b> file, and to specify <> as the left-hand + field in the access table. -ACCESS(5) ACCESS(5) +<b>ADDRESS</b> <b>EXTENSION</b> + When a mail address localpart contains the optional recip- + ient delimiter (e.g., <i>user+foo</i>@<i>domain</i>), the lookup order + becomes: <i>user+foo</i>@<i>domain</i>, <i>user</i>@<i>domain</i>, <i>domain</i>, <i>user+foo</i>@, + and <i>user</i>@. +<b>HOST</b> <b>NAME/ADDRESS</b> <b>PATTERNS</b> + With lookups from indexed files such as DB or DBM, or from + networked tables such as NIS, LDAP or SQL, the following + lookup patterns are examined in the order as listed: - Top-level domains will never be matched. + <i>domain.name</i> + Matches <i>domain.name</i>. - <i>user</i>@ Matches all mail addresses with the specified user - part. + The pattern <i>domain.name</i> also matches subdomains, + but only when the string <b>smtpd</b><i>_</i><b>access</b><i>_</i><b>maps</b> is + listed in the Postfix <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdo-</b> + <b>mains</b> configuration setting. Otherwise, specify + <i>.domain.name</i> (note the initial dot) in order to + match subdomains. <i>net.work.addr.ess</i> @@ -110,33 +130,22 @@ ACCESS(5) ACCESS(5) the entire string being looked up. Depending on the appli- cation, that string is an entire client hostname, an entire client IP address, or an entire mail address. Thus, - no parent domain or parent network search is done, and + no parent domain or parent network search is done, <i>user@domain</i> mail addresses are not broken up into their - <i>user@</i> and <i>domain</i> constituent parts. + <i>user@</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken + up into <i>user</i> and <i>foo</i>. - Patterns are applied in the order as specified in the - table, until a pattern is found that matches the search + Patterns are applied in the order as specified in the + table, until a pattern is found that matches the search string. - Actions are the same as with normal indexed file lookups, - with the additional feature that parenthesized substrings - from the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. + Actions are the same as with indexed file lookups, with + the additional feature that parenthesized substrings from + the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. <b>BUGS</b> The table format does not understand quoting conventions. - - - - 2 - - - - - -ACCESS(5) ACCESS(5) - - <b>SEE</b> <b>ALSO</b> <a href="postmap.1.html">postmap(1)</a> create mapping table <a href="smtpd.8.html">smtpd(8)</a> smtp server @@ -153,48 +162,6 @@ ACCESS(5) ACCESS(5) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/aliases.5.html b/gnu/dist/postfix/html/aliases.5.html index 50b5aaa3f91..2992fc0c4de 100644 --- a/gnu/dist/postfix/html/aliases.5.html +++ b/gnu/dist/postfix/html/aliases.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - ALIASES(5) ALIASES(5) - <b>NAME</b> aliases - format of the Postfix alias database @@ -38,11 +35,13 @@ ALIASES(5) ALIASES(5) <i>name</i>: <i>value1</i>, <i>value2</i>, <i>...</i> - <b>o</b> Lines that begin with whitespace continue the pre- - vious line. + <b>o</b> Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. - <b>o</b> Blank lines are ignored, as are lines beginning - with `#'. + <b>o</b> A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. The <i>name</i> is a local address (no domain part). Use double quotes when the name contains any special characters such @@ -59,18 +58,6 @@ ALIASES(5) ALIASES(5) The <i>value</i> contains one or more of the following: - - - - 1 - - - - - -ALIASES(5) ALIASES(5) - - <i>address</i> Mail is forwarded to <i>address</i>, which is compatible with the <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> standard. @@ -124,19 +111,6 @@ ALIASES(5) ALIASES(5) Restrict the usage of mail delivery to external command. - - - - - 2 - - - - - -ALIASES(5) ALIASES(5) - - <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> Restrict the usage of mail delivery to external file. @@ -172,29 +146,6 @@ ALIASES(5) ALIASES(5) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/backstage.html b/gnu/dist/postfix/html/backstage.html index 577a3c0323f..5ee7aeef834 100644 --- a/gnu/dist/postfix/html/backstage.html +++ b/gnu/dist/postfix/html/backstage.html @@ -62,8 +62,7 @@ href="mailq.1.html">mailq</a> command. <li>The <a href="flush.8.html">flush</a> daemon improves the performance of the SMTP <b>ETRN</b> request, and of its command-line equivalent, <b>sendmail -qR</b><i>destination</i>, for selected -destinations. For other destinations, Postfix silently falls -back to the equivalent of <b>sendmail -q</b>. +destinations. <p> diff --git a/gnu/dist/postfix/html/bounce.8.html b/gnu/dist/postfix/html/bounce.8.html index 63e760535e6..76cde51963f 100644 --- a/gnu/dist/postfix/html/bounce.8.html +++ b/gnu/dist/postfix/html/bounce.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - BOUNCE(8) BOUNCE(8) - <b>NAME</b> bounce - Postfix message bounce or defer daemon @@ -59,18 +56,6 @@ BOUNCE(8) BOUNCE(8) <b>bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b> The recipient of single bounce postmaster notices. - - - - 1 - - - - - -BOUNCE(8) BOUNCE(8) - - <b>2bounce</b><i>_</i><b>notice</b><i>_</i><b>recipient</b> The recipient of double bounce postmaster notices. @@ -105,30 +90,6 @@ BOUNCE(8) BOUNCE(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/canonical.5.html b/gnu/dist/postfix/html/canonical.5.html index aedf505260f..2ec7403ca72 100644 --- a/gnu/dist/postfix/html/canonical.5.html +++ b/gnu/dist/postfix/html/canonical.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - CANONICAL(5) CANONICAL(5) - <b>NAME</b> canonical - format of Postfix canonical table @@ -51,30 +48,20 @@ CANONICAL(5) CANONICAL(5) <b>TABLE</b> <b>FORMAT</b> The format of the <b>canonical</b> table is as follows: - blanks and comments - Blank lines are ignored, as are lines beginning - with `#'. - - leading whitespace - Lines that begin with whitespace continue the pre- - vious line. - - - - - 1 - - - - - -CANONICAL(5) CANONICAL(5) - - <i>pattern</i> <i>result</i> When <i>pattern</i> matches a mail address, replace it by the corresponding <i>result</i>. + blank lines and comments + Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + multi-line text + A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. + With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, patterns are tried in the order as listed below: @@ -104,13 +91,11 @@ CANONICAL(5) CANONICAL(5) <i>domain</i>, the result is the same user in <i>otherdomain</i>. <b>ADDRESS</b> <b>EXTENSION</b> - When table lookup fails, and the address localpart con- - tains the optional recipient delimiter (e.g., - <i>user+foo</i>@<i>domain</i>), the search is repeated for the unex- - tended address (e.g. <i>user</i>@<i>domain</i>), and the unmatched - extension is propagated to the result of table lookup. The - matching order is: <i>user+foo</i>@<i>domain</i>, <i>user</i>@<i>domain</i>, <i>user+foo</i>, - <i>user</i>, and @<i>domain</i>. + When a mail address localpart contains the optional recip- + ient delimiter (e.g., <i>user+foo</i>@<i>domain</i>), the lookup order + becomes: <i>user+foo</i>@<i>domain</i>, <i>user</i>@<i>domain</i>, <i>user+foo</i>, <i>user</i>, and + @<i>domain</i>. An unmatched address extension (<i>+foo</i>) is propa- + gated to the result of table lookup. <b>REGULAR</b> <b>EXPRESSION</b> <b>TABLES</b> This section describes how the table lookups change when @@ -125,32 +110,20 @@ CANONICAL(5) CANONICAL(5) <i>foo</i>. Patterns are applied in the order as specified in the - - - - 2 - - - - - -CANONICAL(5) CANONICAL(5) - - table, until a pattern is found that matches the search string. - Results are the same as with normal indexed file lookups, - with the additional feature that parenthesized substrings - from the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. + Results are the same as with indexed file lookups, with + the additional feature that parenthesized substrings from + the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. <b>BUGS</b> - The table format does not understand quoting conventions. + The table format does not understand quoting conventions. <b>CONFIGURATION</b> <b>PARAMETERS</b> - The following <b>main.cf</b> parameters are especially relevant - to this topic. 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 topic. 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>canonical</b><i>_</i><b>maps</b> @@ -167,19 +140,24 @@ CANONICAL(5) CANONICAL(5) Other parameters of interest: <b>inet</b><i>_</i><b>interfaces</b> - The network interface addresses that this system + The network interface addresses that this system receives mail on. + <b>masquerade</b><i>_</i><b>classes</b> + List of address classes subject to masquerading: + zero or more of <b>envelope</b><i>_</i><b>sender</b>, <b>envelope</b><i>_</i><b>recipi-</b> + <b>ent</b>, <b>header</b><i>_</i><b>sender</b>, <b>header</b><i>_</i><b>recipient</b>. + <b>masquerade</b><i>_</i><b>domains</b> - List of domains that hide their subdomain struc- + List of domains that hide their subdomain struc- ture. <b>masquerade</b><i>_</i><b>exceptions</b> - List of user names that are not subject to address + List of user names that are not subject to address masquerading. <b>mydestination</b> - List of domains that this mail system considers + List of domains that this mail system considers local. <b>myorigin</b> @@ -191,25 +169,13 @@ CANONICAL(5) CANONICAL(5) <b>SEE</b> <b>ALSO</b> <a href="cleanup.8.html">cleanup(8)</a> canonicalize and enqueue mail - - - - 3 - - - - - -CANONICAL(5) CANONICAL(5) - - <a href="postmap.1.html">postmap(1)</a> create mapping table <a href="virtual.5.html">virtual(5)</a> virtual domain mapping <a href="pcre_table.5.html">pcre_table(5)</a> format of PCRE tables <a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables <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> @@ -218,49 +184,6 @@ CANONICAL(5) CANONICAL(5) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/cleanup.8.html b/gnu/dist/postfix/html/cleanup.8.html index 2c1722d5c27..f1ce6052662 100644 --- a/gnu/dist/postfix/html/cleanup.8.html +++ b/gnu/dist/postfix/html/cleanup.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - CLEANUP(8) CLEANUP(8) - <b>NAME</b> cleanup - canonicalize and enqueue Postfix message @@ -43,62 +40,51 @@ CLEANUP(8) CLEANUP(8) and message header addresses (i.e. strip host or domain information below all domains listed in the <b>masquerade</b><i>_</i><b>domains</b> parameter, except for user names - listed in <b>masquerade</b><i>_</i><b>exceptions</b>). Address mas- - querading does not affect envelope recipients. + listed in <b>masquerade</b><i>_</i><b>exceptions</b>). By default, + address masquerading does not affect envelope + recipients. <b>o</b> Optionally, expand envelope recipients according to - information found in the <a href="virtual.5.html"><b>virtual</b>(5)</a> lookup tables. + information found in the <a href="virtual.5.html"><b>virtual</b>(5)</a> lookup tables. - The <b>cleanup</b> daemon performs sanity checks on the content - of each message. When it finds a problem, by default it - returns a diagnostic status to the client, and leaves it - up to the client to deal with the problem. Alternatively, - the client can request the <b>cleanup</b> daemon to bounce the + The <b>cleanup</b> daemon performs sanity checks on the content + of each message. When it finds a problem, by default it + returns a diagnostic status to the client, and leaves it + up to the client to deal with the problem. Alternatively, + the client can request the <b>cleanup</b> daemon to bounce the message back to the sender in case of trouble. <b>STANDARDS</b> <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a> (ARPA Internet Text Messages) - - - - 1 - - - - - -CLEANUP(8) CLEANUP(8) - - <b>DIAGNOSTICS</b> Problems and transactions are logged to <b>syslogd</b>(8). <b>BUGS</b> - Table-driven rewriting rules make it hard to express <b>if</b> + Table-driven rewriting rules make it hard to express <b>if</b> <b>then</b> <b>else</b> and other logical relationships. <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>Content</b> <b>filtering</b> <b>body</b><i>_</i><b>checks</b> Lookup tables with content filters for message body - lines. These filters see physical lines one at a + lines. These filters see physical lines one at a time, in chunks of at most line_length_limit bytes. <b>header</b><i>_</i><b>checks</b> - Lookup tables with content filters for message - header lines. These filters see logical headers + Lookup tables with content filters for message + header lines. These filters see logical headers one at a time, including headers that span multiple lines. <b>Miscellaneous</b> <b>always</b><i>_</i><b>bcc</b> - Address to send a copy of each message that enters + Address to send a copy of each message that enters the system. <b>hopcount</b><i>_</i><b>limit</b> @@ -111,8 +97,8 @@ CLEANUP(8) CLEANUP(8) <b>Address</b> <b>transformations</b> <b>empty</b><i>_</i><b>address</b><i>_</i><b>recipient</b> - The destination for undeliverable mail from <>. - This substitution is done before all other address + The destination for undeliverable mail from <>. + This substitution is done before all other address rewriting. <b>canonical</b><i>_</i><b>maps</b> @@ -125,26 +111,19 @@ CLEANUP(8) CLEANUP(8) <b>sender</b><i>_</i><b>canonical</b><i>_</i><b>maps</b> Address mapping lookup table for envelope and - - - - 2 - - - - - -CLEANUP(8) CLEANUP(8) - - header sender addresses. + <b>masquerade</b><i>_</i><b>classes</b> + List of address classes subject to masquerading: + zero or more of <b>envelope</b><i>_</i><b>sender</b>, <b>envelope</b><i>_</i><b>recipi-</b> + <b>ent</b>, <b>header</b><i>_</i><b>sender</b>, <b>header</b><i>_</i><b>recipient</b>. + <b>masquerade</b><i>_</i><b>domains</b> - List of domains that hide their subdomain struc- + List of domains that hide their subdomain struc- ture. <b>masquerade</b><i>_</i><b>exceptions</b> - List of user names that are not subject to address + List of user names that are not subject to address masquerading. <b>virtual</b><i>_</i><b>maps</b> @@ -153,15 +132,20 @@ CLEANUP(8) CLEANUP(8) <b>Resource</b> <b>controls</b> <b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b> - Limit the number of envelope recipients that are + Limit the number of envelope recipients that are remembered. <b>header</b><i>_</i><b>size</b><i>_</i><b>limit</b> Limit the amount of memory in bytes used to process a message header. + <b>in</b><i>_</i><b>flow</b><i>_</i><b>delay</b> + Amount of time to pause before accepting a message, + when the message arrival rate exceeds the message + delivery rate. + <b>extract</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> - Limit the amount of recipients extracted from mes- + Limit the amount of recipients extracted from mes- sage headers. <b>SEE</b> <b>ALSO</b> @@ -176,7 +160,7 @@ CLEANUP(8) CLEANUP(8) /etc/postfix/virtual*, virtual mapping table <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> @@ -185,16 +169,6 @@ CLEANUP(8) CLEANUP(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/commands.html b/gnu/dist/postfix/html/commands.html index 0b1e5ce63e9..e4bb9d57b76 100644 --- a/gnu/dist/postfix/html/commands.html +++ b/gnu/dist/postfix/html/commands.html @@ -61,8 +61,8 @@ something more powerful that can not only list but also edit the <p> <li>The <a href="postdrop.1.html">postdrop</a> command is the mail -posting agent that is run by the <a href="sendmail.1.html">sendmail</a> -command on systems that have no world-writable <b>maildrop</b> queue +posting utility that is run by the <a href="sendmail.1.html">sendmail</a> +command in order to deposit mail into the <b>maildrop</b> queue directory. <p> @@ -91,6 +91,12 @@ the UNIX <b>makemap</b> command. <p> +<li>The <a href="postqueue.1.html">postqueue</a> command is the +utility that is run by the <a href="sendmail.1.html">sendmail</a> +command in order to flush or list the mail queue. + +<p> + <li>The <a href="postsuper.1.html">postsuper</a> command maintains the Postfix queue. It removes old temporary files, and moves queue files into the right directory after a change in the hashing depth diff --git a/gnu/dist/postfix/html/error.8.html b/gnu/dist/postfix/html/error.8.html index d36ab9919bd..a96801b3250 100644 --- a/gnu/dist/postfix/html/error.8.html +++ b/gnu/dist/postfix/html/error.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - ERROR(8) ERROR(8) - <b>NAME</b> error - Postfix error mailer @@ -59,18 +56,6 @@ ERROR(8) ERROR(8) mail to the postmaster with with the headers of the bounced mail. - - - - 1 - - - - - -ERROR(8) ERROR(8) - - <b>SEE</b> <b>ALSO</b> <a href="bounce.8.html">bounce(8)</a> non-delivery status reports <a href="master.8.html">master(8)</a> process manager @@ -87,48 +72,6 @@ ERROR(8) ERROR(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/faq.html b/gnu/dist/postfix/html/faq.html index 425304fddb9..85f8cb644e4 100644 --- a/gnu/dist/postfix/html/faq.html +++ b/gnu/dist/postfix/html/faq.html @@ -94,6 +94,12 @@ domains with "relay access denied"</a> <li><a href="#broken_transport">Mail delivery fails with: "unknown mail transport error"</a> +<li><a href="#msql_limit">Too many connections</a> + +<li><a href="#reiser_bugs">write queue file: No such file or directory</a> + +<li><a href="#reiser_bugs">write queue file: Unknown error 4294967289</a> + </ul> <p> @@ -153,6 +159,10 @@ distribution list</a> <li><a href="#moby-linux">Running hundreds of Postfix processes on Linux</a> +<li><a href="#moby-sun">Running hundreds of Postfix processes on Solaris</a> + +<li><a href="#moby-postfix">Running thousands of Postfix delivery agents</a> + </ul> @@ -286,6 +296,9 @@ domains with "relay access denied"</a> <li><a href="#domain_mailbox">Receiving a virtual domain in a mailbox</a> +<li><a href="#virtual_logging">Postfix logs delivery to virtual +address with the wrong name</a> + </ul> <a name="address_rewriting"><h3>Address rewriting</h3> @@ -308,6 +321,8 @@ mailbox</a> <ul> +<li><a href="#uucp-tcp">Using UUCP over TCP</a> + <li><a href="#internet-uucp">Setting up an Internet to UUCP gateway</a> <li><a href="#uucp-only">Using UUCP as the default transport</a> @@ -394,7 +409,7 @@ implements its own private mail database system. Not for beginners. <p> <li><a href="http://www.inter7.com/courierimap/">Courier-Imap</a> -provides POP3, IMAP, POP3 and IMAP, and supports access over SSL. +provides POP3 and IMAP, and supports access over SSL. This software supports the maildir-style mailbox format only (one message per file, same format as qmail). @@ -656,6 +671,7 @@ to send mail only to <i>user@domain.com</i>. transport_maps = hash:/etc/postfix/transport mynetworks = 12.34.56.0/24 smtpd_recipient_restrictions = permit_mynetworks reject_unauth_destination + local_transport = error:local mail delivery is disabled on this machine /etc/postfix/transport: domain.com smtp:inside-gateway.domain.com (forwards user@domain) @@ -1120,36 +1136,43 @@ run out of file handles; after that, it will run out of sockets. <p> -To set kernel parameters at boot time, add the following lines to -the <b>/boot/loader.conf</b> file (this is specific to FreeBSD 4.x): +To set the following kernel parameters at boot time, add the +following lines to the <b>/boot/loader.conf</b> file (this is +verified with FreeBSD 4.4): <p> <blockquote> <pre> kern.ipc.maxsockets="5000" +kern.ipc.nmbclusters="65536" +kern.maxproc="2048" kern.maxfiles="16384" kern.maxfilesperproc="16384" -kern.ipc.nmbclusters="65536" </pre> </blockquote> <p> -To set kernel parameters at run time execute the following commands -as root (this is specific to FreeBSD 4.x): +With FreeBSD 4.2, the last three parameters cannot be set from +<b>/boot/loader.conf</b>. To set the open file limits, execute the +following commands as root: <p> <blockquote> <pre> -# sysctl -w kern.ipc.maxsockets=5000 # sysctl -w kern.maxfiles=16384 # sysctl -w kern.maxfilesperproc=16384 -# sysctl -w kern.ipc.nmbclusters=65536 </pre> </blockquote> +<p> + +With FreeBSD 4.2, <b>kern.maxproc</b> can be set only by recompiling +the kernel with a different <b>maxusers</b> setting in the kernel +configuration file. + <hr> <a name="moby-linux"><h3>Running hundreds of Postfix processes on Linux</h3></a> @@ -1192,6 +1215,42 @@ commands as <b>root</b>: <hr> +<a name="moby-sun"><h3>Running hundreds of Postfix processes on Solaris</h3></a> + +In order to run hundreds of processes you may have to adjust the +per-process open file limit. According to the <a +href="http://www.science.uva.nl/pub/solaris/solaris2.html#q3.45">Solaris +FAQ</a>, add the following lines to /etc/system on Solaris 2.4 and later: + +<p> +<blockquote> +<pre> +* set hard limit on file descriptors +set rlim_fd_max = 4096 +* set soft limit on file descriptors +set rlim_fd_cur = 2048 +</pre> +</blockquote> + +<hr> + +<a name="moby-postfix"><h3>Running thousands of Postfix delivery agents</h3></a> + +In order to run Postfix with more than a thousand delivery agents you +need to recompile the software with an appropriate value of the +<b>FD_SETSIZE</b> constant. + +<p> +<blockquote> +<pre> +% make tidy +% make makefiles "CCARGS=-DFD_SETSIZE=2048" +% make +</pre> +</blockquote> + +<hr> + <a name="incoming"><h3>Mail stays queued in the incoming queue</h3></a> <blockquote> @@ -1456,7 +1515,11 @@ href="uce.html#reject_unauth_destination">reject_unauth_destination</a>: reject when the destination is not local. <li> <a href="uce.html#permit_mx_backup">permit_mx_backup</a>: -reject when the destination is not local. +permit if the local system is listed as MX host for the recipient +domain. Use the optional <a +href="#permit_mx_backup_networks">permit_mx_backup_networks</a> +parameter to also require that the primary MX hosts match a list +of network blocks (Postfix versions 20011008 and later). <li> Other UCE restrictions (e.g., SMTPD access maps) are not aware of sender-provided routing information. @@ -1809,9 +1872,9 @@ like: A little background is in order. With the SMTP protocol, the HELO, MAIL FROM and RCPT TO commands and responses are relatively short. -When you're talking to sendmail, every command and every response -is sent as a separate packet, because sendmail cannot implement -ESMTP command pipelining. +When you're talking to old versions of sendmail, every command and +every response is sent as a separate packet, because sendmail didn't +implement ESMTP command pipelining until recently. <p> @@ -2599,7 +2662,9 @@ that the mail was sent to. Answer: I hope we all agree that delivering a domain to a mailbox is disgusting practice. Forwarding mail via SMTP or UUCP would be a much better choice. Unfortunately, neither SMTP nor UUCP are a -usable alternative for legions of windows users. +usable alternative for legions of windows users. However, if this +is an option for you see the <a href="#uucp-tcp">UUCP over TCP</a> +guide below. <p> @@ -2652,6 +2717,44 @@ your system supports, use the command <b>postconf -m</b>. <hr> +<a name="virtual_logging"><h3>Postfix logs delivery to virtual +address with the wrong name</h3></a> + +When Postfix delivers mail for a virtual address <i>vuser@vdomain.name</i> +that is aliased to a local user, then Postfix logs the local username +instead of the virtual one. + +<p> + +Changing this requires non-trivial changes, because Postfix only +remembers the address that it delivers to, not the address that +was original specified in, for example, the SMTP MAIL FROM command. + +<p> + +A workaround exists. It uses regular expressions. This +can be expensive if you have many virtual domains. + +<p> +<blockquote> +<pre> +/etc/postfix/main.cf: + virtual_maps = regexp:/etc/postfix/virtual_regexp + recipient_delimiter = + + +/etc/postfix/virtual_regexp: + /^vdomain\.name$/ whatever + /(.*)@vdomain\.name$/ localuser+$1=vdomain.name +</pre> +</blockquote> + +<p> + +This delivers the mail as +<i>localuser+vuser=vdomain.name@your.domain</i>. + +<hr> + <a name="masquerade"><h3>Address masquerading with exceptions</h3></a> For people outside your organization it can be desirable to only @@ -2784,6 +2887,28 @@ See examples in <b>master.cf</b>. <hr> +<a name="uucp-tcp"><h3>Using UUCP over TCP</h3> + +This subject comes up whenever someone asks about a "domain in +a mailbox" solution. For first-hand information, see the guides +listed below. + +<ul> + +<li>Jim Seymour's guide for using <a +href="http://jimsun.LinxNet.com/jdp/uucp_over_tcp/index.html"> UUCP +over TCP</a>. + +<p> + +<li>Craig Sanders's guide for using <a +href="http://taz.net.au/postfix/uucp/"> SSL-encrypted UUCP over +tcp using stunnel</a>. + +</ul> + +<hr> + <a name="internet-uucp"><h3>Setting up an Internet to UUCP gateway</h3> </a> Here is how to set up a machine that sits on the Internet and that @@ -2889,7 +3014,7 @@ changes effective. Here is how to relay all your mail over a UUCP link. See the <a href="#internet-uucp">Internet to UUCP</a> FAQ entry for setting -up a machine that gateways between UUCP and SMTP. +up a machine that gateways between UUCP and SMTP. <p> @@ -2988,41 +3113,59 @@ Note: be sure to not advertise <b>fax.your.domain</b> in the DNS :-) <a name="deleting"><h3>Deleting a message from the Postfix queue</h3></a> -To delete ONE message with queue id ABCDEF (e.g., from <b>mailq</b> -output) from the Postfix queue, it is not necessary to stop Postfix. +As of Postfix version 20010502, the <b>postsuper</b> command +has an option to delete Postfix message queue files. To delete +the message with queue id ABCDEF, perhaps obtained from <b>mailq</b> +output, one would use: <p> +<blockquote> <pre> - # cd /var/spool/postfix - # find incoming active deferred -name ABCDEF -print | sed 1q | xargs rm +# postsuper -d ABCDEF </pre> +</blockquote> <p> -The above command is safe because it deletes at most one file. -There is no risk of deleting newly arrived mail that happens to get -the same queue file name. +To delete a large number of files one would use: <p> -If you have to delete a large amount of mail, you must stop Postfix -first. - -<p> +<blockquote> <pre> - # postfix stop - # cd /var/spool/postfix - # find incoming active deferred defer -type f -print | - fgrep -xf /file/with/queue-ids | xargs rm - # postfix start +# postsuper -d - < <i>filename-with-queue-ids</i> </pre> +</blockquote> <p> -Do not use the above <b>find</b> command on a running Postfix -system, because it can delete files that belong to new mail that -arrives while you are deleting queue files. +It is usually safe to do this while the Postfix system is running. +However, there is a small chance of deleting the wrong queue +file. The scenario goes like this: + +<p> + +<ul> + +<li>The Postfix queue manager deletes the file that <b>postsuper</b> +was supposed to delete, because Postfix was finished with the +message. + +<p> + +<li>New mail arrives, and the new message is given the same queue +ID as the message that <b>postsuper</b> was supposed to delete. +The probability for reusing a deleted queue ID is about 1 in +2<sup>15</sup> (the number of different microsecond values that +the system clock can distinguish). + +<p> + +<li><b>postsuper</b> deletes the new message file, instead of the +old file that should have been deleted. + +</ul> <hr> @@ -3045,35 +3188,110 @@ that the file name will collide with another queue file. <p> -To avoid queue file name collisions when copying queue files, -restore the incoming, active and deferred queue files under the -maildrop directory instead. +The text below describes two different procedures to restore +queue files from another machine or from backup. + +<h4> Procedure 1: Your Postfix queue is empty, and you run Postfix +release 20010525 or later</h4> + +<ul> + +<li> Stop Postfix, if it was running. + +<blockquote> +<pre> +# postfix stop +</pre> +</blockquote> + +<p> + +<li> Execute the <b>mailq</b> command. If there is any output, do +not complete this procedure, but use <b>procedure 2</b> instead. + +<blockquote> +<pre> +# mailq +</pre> +</blockquote> + +<p> + +<li> Copy or restore the queue to the usual place. + +<blockquote> +<pre> +# cd /var/spool/postfix +<i>...restore maildrop, incoming, active, deferred, defer, bounce here...</i> +</pre> +</blockquote> + +<p> + +<li> Run the <b>postsuper</b> command. This command will rename +queue files so that the file names match their message file inode +numbers. + +<blockquote> +<pre> +# postsuper +</pre> +</blockquote> + +</ul> + +<h4> Procedure 2: Your Postfix queue is not empty, or you are +running a Postfix release prior to 20010525</h4> + +<ul> + +<li>Stop Postfix, if it was running. + +<blockquote> +<pre> +# postfix stop +</pre> +</blockquote> + +<p> + +<li> To avoid queue file name collisions when restoring queue files, +copy or restore the incoming, active and deferred queue files under +the maildrop directory instead. + +<blockquote> +<pre> +# cd /var/spool/postfix/maildrop +<i>...restore incoming, active, deferred here...</i> +</pre> +</blockquote> + +<p> + +<li>While the next step is going on, don't submit new mail locally, +because that could collide with the files you are restoring under +the maildrop directory. <p> -As of late 2000, Postfix queues are all hashed (for example, file +<li>As of late 2000, Postfix queues are all hashed (for example, file ABCDEF is stored as A/B/ABCDEF), so you need an additional step to move files down from their subdirectories. <p> <pre> - # postfix stop - # cd /var/spool/postfix/maildrop - ... restore incoming/active/deferred queue files under the maildrop directory... # find incoming active deferred -type f -exec mv '{}' . ';' # rm -rf incoming active deferred # postfix start </pre> -While all this is going on, don't submit new mail locally, because -that could collide with the files you are restoring under the -maildrop directory. - <p> -When Postfix is started, it will pick up queue files from the +<li>When Postfix is started, it will pick up queue files from the maildrop directory and will give them proper queue file names. +</ul> + <hr> <a name="bind"><h3>Undefined symbols: ___dn_expand, ___res_init etc.</h3></a> @@ -3208,6 +3426,27 @@ files, and to mount the Postfix queue file system with the <hr> +<a name="msql_limit"><h3>Too many connections</h3></a> + +This message is produced by the MYQSL server. You need to increase +the number of connections that it can handle. Things to bear in +mind: the <b>virtual</b> and <b>canonical</b> maps are accessed by +every <b>smtpd</b> and <b>cleanup</b> process. + +<hr> + +<a name="reiser_bugs"><h3>write queue file: No such file or directory</h3></a> + +<h3>write queue file: Unknown error 4294967289</h3> + +Reiserfs reports the wrong error code when a message exceeds the +<b>message_size_limit</b> setting. As a result, the Postfix SMTP +server reports a "queue file write error" to the SMTP client, rather +than reporting a "file too large" condition. The client will keep +sending the same email again and again until the mail is too old. + +<hr> + <a href="index.html">Up one level</a> | Postfix FAQ </body> diff --git a/gnu/dist/postfix/html/flush.8.html b/gnu/dist/postfix/html/flush.8.html index c9b6185883a..93223e406a7 100644 --- a/gnu/dist/postfix/html/flush.8.html +++ b/gnu/dist/postfix/html/flush.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - FLUSH(8) FLUSH(8) - <b>NAME</b> flush - Postfix fast flush server @@ -47,8 +44,8 @@ FLUSH(8) FLUSH(8) undeliverable it will be added back to the logfile. If the destination is not eligible for a fast flush - logfile, this request triggers delivery of all - queued mail. + logfile, this request is rejected (see below for + status codes). <b>TRIGGER</b><i>_</i><b>REQ</b><i>_</i><b>WAKEUP</b> This wakeup request from the master is an alterna- @@ -60,17 +57,6 @@ FLUSH(8) FLUSH(8) simulating send requests (see above) for the corre- sponding destinations. - - - 1 - - - - - -FLUSH(8) FLUSH(8) - - Delete empty per-destination logfiles that were not updated in <b>fast</b><i>_</i><b>flush</b><i>_</i><b>purge</b><i>_</i><b>time</b> days. @@ -96,6 +82,11 @@ FLUSH(8) FLUSH(8) <b>FLUSH</b><i>_</i><b>STAT</b><i>_</i><b>FAIL</b> The request failed. + <b>FLUSH</b><i>_</i><b>STAT</b><i>_</i><b>DENY</b> + The request was denied because the destination + domain is not eligible for fast flush service, or + because the fast flush service is disabled. + <b>SECURITY</b> The fast flush server is not security-sensitive. It does not talk to the network, and it does not talk to local @@ -125,18 +116,6 @@ FLUSH(8) FLUSH(8) <b>FILES</b> /var/spool/postfix/flush, location of "fast flush" logfiles. - - - - 2 - - - - - -FLUSH(8) FLUSH(8) - - <b>CONFIGURATION</b> <b>PARAMETERS</b> 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 @@ -157,6 +136,11 @@ FLUSH(8) FLUSH(8) 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> + 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 @@ -172,29 +156,6 @@ FLUSH(8) FLUSH(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/lmtp.8.html b/gnu/dist/postfix/html/lmtp.8.html index 653d5d8e40c..a4428fa0be6 100644 --- a/gnu/dist/postfix/html/lmtp.8.html +++ b/gnu/dist/postfix/html/lmtp.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - LMTP(8) LMTP(8) - <b>NAME</b> lmtp - Postfix local delivery via LMTP @@ -59,22 +56,11 @@ LMTP(8) LMTP(8) <b>STANDARDS</b> <a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol) <a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions) - - - - 1 - - - - - -LMTP(8) LMTP(8) - - <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration) <a href="http://www.faqs.org/rfcs/rfc2033.html">RFC 2033</a> (LMTP protocol) <a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining) <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command) + <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol) <b>DIAGNOSTICS</b> Problems and transactions are logged to <b>syslogd</b>(8). Cor- @@ -122,21 +108,9 @@ LMTP(8) LMTP(8) found in <b>services</b>(4). <b>Authentication</b> <b>controls</b> - <b>lmtp</b><i>_</i><b>enable</b><i>_</i><b>sasl</b><i>_</i><b>auth</b> + <b>lmtp</b><i>_</i><b>sasl</b><i>_</i><b>auth</b><i>_</i><b>enable</b> Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (SASL). By default, Postfix is built without SASL - - - - 2 - - - - - -LMTP(8) LMTP(8) - - support. <b>lmtp</b><i>_</i><b>sasl</b><i>_</i><b>password</b><i>_</i><b>maps</b> @@ -191,18 +165,6 @@ LMTP(8) LMTP(8) <i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> Limit the number of parallel deliveries to the same destination via this mail delivery transport. - - - - 3 - - - - - -LMTP(8) LMTP(8) - - <i>transport</i> is the name of the service as specified in the <b>master.cf</b> file. The default limit is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> @@ -256,19 +218,6 @@ LMTP(8) LMTP(8) Timeout for sending the <b>DATA</b> command, and for receiving the server response. - - - - - 4 - - - - - -LMTP(8) LMTP(8) - - <b>lmtp</b><i>_</i><b>data</b><i>_</i><b>xfer</b><i>_</i><b>timeout</b> Timeout for sending the message content. @@ -316,17 +265,6 @@ LMTP(8) LMTP(8) P.O. Box 830688, MC34 Richardson, TX 75083, USA - - - - - - - - - - - 5 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/local.8.html b/gnu/dist/postfix/html/local.8.html index e909eaa2848..d08a2ffa530 100644 --- a/gnu/dist/postfix/html/local.8.html +++ b/gnu/dist/postfix/html/local.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - LOCAL(8) LOCAL(8) - <b>NAME</b> local - Postfix local mail delivery @@ -59,18 +56,6 @@ LOCAL(8) LOCAL(8) When an address is found in its own alias expansion, delivery is made to the user instead. When a user is listed in the user's own ~/.<b>forward</b> file, delivery is made - - - - 1 - - - - - -LOCAL(8) LOCAL(8) - - to the user's mailbox instead. An empty ~/.<b>forward</b> file means do not forward mail. @@ -99,78 +84,67 @@ LOCAL(8) LOCAL(8) The default per-user mailbox is a file in the UNIX mail spool directory (<b>/var/mail/</b><i>user</i> or <b>/var/spool/mail/</b><i>user</i>); the location can be specified with the <b>mail</b><i>_</i><b>spool</b><i>_</i><b>direc-</b> - <b>tory</b> configuration parameter. + <b>tory</b> configuration parameter. Specify a name ending in <b>/</b> + for <b>qmail</b>-compatible <b>maildir</b> delivery. - Alternatively, the per-user mailbox can be a file in the - user's home directory with a name specified via the - <b>home</b><i>_</i><b>mailbox</b> configuration parameter. Specify a relative + Alternatively, the per-user mailbox can be a file in the + user's home directory with a name specified via the + <b>home</b><i>_</i><b>mailbox</b> configuration parameter. Specify a relative path name. Specify a name ending in <b>/</b> for <b>qmail</b>-compatible <b>maildir</b> delivery. - Mailbox delivery can be delegated to an external command - specified with the <b>mailbox</b><i>_</i><b>command</b> configuration parame- - ter. The command executes with the privileges of the - recipient user (exception: in case of delivery as root, - the command executes with the privileges of + Mailbox delivery can be delegated to an external command + specified with the <b>mailbox</b><i>_</i><b>command</b> configuration parame- + ter. The command executes with the privileges of the + recipient user (exception: in case of delivery as root, + the command executes with the privileges of <b>default</b><i>_</i><b>privs</b>). - Mailbox delivery can be delegated to alternative message - transports specified in the <b>master.cf</b> file. The <b>mail-</b> - <b>box</b><i>_</i><b>transport</b> configuration parameter specifies a message - transport that is to be used for all local recipients, - regardless of whether they are found in the UNIX passwd - database. The <b>fallback</b><i>_</i><b>transport</b> parameter specifies a + Mailbox delivery can be delegated to alternative message + transports specified in the <b>master.cf</b> file. The <b>mail-</b> + <b>box</b><i>_</i><b>transport</b> configuration parameter specifies a message + transport that is to be used for all local recipients, + regardless of whether they are found in the UNIX passwd + database. The <b>fallback</b><i>_</i><b>transport</b> parameter specifies a message transport for recipients that are not found in the UNIX passwd database. In the case of UNIX-style mailbox delivery, the <b>local</b> dae- mon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope header to - - - - 2 - - - - - -LOCAL(8) LOCAL(8) - - - each message, prepends an optional <b>Delivered-To:</b> header - with the envelope recipient address, prepends a <b>Return-</b> - <b>Path:</b> header with the envelope sender address, prepends a - > character to lines beginning with "<b>From</b> ", and appends + each message, prepends an optional <b>Delivered-To:</b> header + with the envelope recipient address, prepends a <b>Return-</b> + <b>Path:</b> header with the envelope sender address, prepends a + > character to lines beginning with "<b>From</b> ", and appends an empty line. The mailbox is locked for exclusive access - while delivery is in progress. In case of problems, an - attempt is made to truncate the mailbox to its original + while delivery is in progress. In case of problems, an + attempt is made to truncate the mailbox to its original length. In the case of <b>maildir</b> delivery, the local daemon prepends an optional <b>Delivered-To:</b> header with the envelope recipi- - ent address and prepends a <b>Return-Path:</b> header with the + ent address and prepends a <b>Return-Path:</b> header with the envelope sender address. <b>EXTERNAL</b> <b>COMMAND</b> <b>DELIVERY</b> - The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b> configuration parameter - restricts delivery to external commands. The default set- - ting (<b>alias,</b> <b>forward</b>) forbids command destinations in + The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b> configuration parameter + restricts delivery to external commands. The default set- + ting (<b>alias,</b> <b>forward</b>) forbids command destinations in <b>:include:</b> files. - The command is executed directly where possible. Assis- - tance by the shell (<b>/bin/sh</b> on UNIX systems) is used only - when the command contains shell magic characters, or when + The command is executed directly where possible. Assis- + tance by the shell (<b>/bin/sh</b> on UNIX systems) is used only + when the command contains shell magic characters, or when the command invokes a shell built-in command. - A limited amount of command output (standard output and - standard error) is captured for inclusion with non-deliv- - ery status reports. A command is forcibly terminated if - it does not complete within <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> seconds. - Command exit status codes are expected to follow the con- + A limited amount of command output (standard output and + standard error) is captured for inclusion with non-deliv- + ery status reports. A command is forcibly terminated if + it does not complete within <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> seconds. + Command exit status codes are expected to follow the con- ventions defined in <<b>sysexits.h</b>>. - A limited amount of message context is exported via envi- - ronment variables. Characters that may have special mean- + A limited amount of message context is exported via envi- + ronment variables. Characters that may have special mean- ing to the shell are replaced by underscores. The list of acceptable characters is specified with the <b>command</b><i>_</i><b>expan-</b> <b>sion</b><i>_</i><b>filter</b> configuration parameter. @@ -192,17 +166,6 @@ LOCAL(8) LOCAL(8) <b>LOCAL</b> The entire recipient address localpart (text to the left of the rightmost @ character). - - - 3 - - - - - -LOCAL(8) LOCAL(8) - - <b>RECIPIENT</b> The entire recipient address. @@ -213,28 +176,31 @@ LOCAL(8) LOCAL(8) The current working directory is the mail queue directory. The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve- - lope header to each message, prepends an optional <b>Deliv-</b> + lope header to each message, prepends an optional <b>Deliv-</b> <b>ered-To:</b> header with the recipient envelope address, - prepends a <b>Return-Path:</b> header with the sender envelope + prepends a <b>Return-Path:</b> header with the sender envelope address, and appends no empty line. <b>EXTERNAL</b> <b>FILE</b> <b>DELIVERY</b> + The delivery format depends on the destination filename + syntax. The default is to use UNIX-style mailbox format. + Specify a name ending in <b>/</b> for <b>qmail</b>-compatible <b>maildir</b> + delivery. + The <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> configuration parameter restricts delivery to external files. The default setting (<b>alias,</b> - <b>forward</b>) forbids file destinations in <b>:include:</b> files. - Specify a pathname ending in <b>/</b> for <b>qmail</b>-compatible - <b>maildir</b> delivery. + <b>forward</b>) forbids file destinations in <b>:include:</b> files. - The <b>local</b> daemon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" enve- - lope header to each message, prepends an optional <b>Deliv-</b> - <b>ered-To:</b> header with the recipient envelope address, - prepends a > character to lines beginning with "<b>From</b> ", - and appends an empty line. The envelope sender address is - available in the <b>Return-Path:</b> header. When the destina- - tion is a regular file, it is locked for exclusive access - while delivery is in progress. In case of problems, an - attempt is made to truncate a regular file to its original - length. + In the case of UNIX-style mailbox delivery, the <b>local</b> dae- + mon prepends a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope header to + each message, prepends an optional <b>Delivered-To:</b> header + with the recipient envelope address, prepends a > charac- + ter to lines beginning with "<b>From</b> ", and appends an empty + line. The envelope sender address is available in the + <b>Return-Path:</b> header. When the destination is a regular + file, it is locked for exclusive access while delivery is + in progress. In case of problems, an attempt is made to + truncate a regular file to its original length. In the case of <b>maildir</b> delivery, the local daemon prepends an optional <b>Delivered-To:</b> header with the envelope recipi- @@ -257,18 +223,6 @@ LOCAL(8) LOCAL(8) <b>DELIVERY</b> <b>RIGHTS</b> Deliveries to external files and external commands are - - - - 4 - - - - - -LOCAL(8) LOCAL(8) - - made with the rights of the receiving user on whose behalf the delivery is made. In the absence of a user context, the <b>local</b> daemon uses the owner rights of the <b>:include:</b> @@ -322,19 +276,6 @@ LOCAL(8) LOCAL(8) List of names of environment parameters that can be exported to non-Postfix processes. - - - - - 5 - - - - - -LOCAL(8) LOCAL(8) - - <b>forward</b><i>_</i><b>path</b> Search list for .forward files. The names are sub- ject to <i>$name</i> expansion. @@ -383,120 +324,103 @@ LOCAL(8) LOCAL(8) <b>mail</b><i>_</i><b>spool</b><i>_</i><b>directory</b> Directory with UNIX-style mailboxes. The default - pathname is system dependent. + pathname is system dependent. Specify a path end- + ing in <b>/</b> for maildir-style delivery. <b>mailbox</b><i>_</i><b>command</b> - External command to use for mailbox delivery. The + External command to use for mailbox delivery. The command executes with the recipient privileges - (exception: root). The string is subject to $name - - - - 6 - - - - - -LOCAL(8) LOCAL(8) - - + (exception: root). The string is subject to $name expansions. + <b>mailbox</b><i>_</i><b>command</b><i>_</i><b>maps</b> + Lookup tables with per-recipient external commands + to use for mailbox delivery. Behavior is as with + <b>mailbox</b><i>_</i><b>command</b>. + <b>mailbox</b><i>_</i><b>transport</b> - Message transport to use for mailbox delivery to + Message transport to use for mailbox delivery to all local recipients, whether or not they are found - in the UNIX passwd database. This parameter over- - rides all other configuration parameters that con- + in the UNIX passwd database. This parameter over- + rides all other configuration parameters that con- trol mailbox delivery, including <b>luser</b><i>_</i><b>relay</b>. <b>Locking</b> <b>controls</b> <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 mailbox or external file. <b>deliver</b><i>_</i><b>lock</b><i>_</i><b>delay</b> - Time in seconds between successive attempts to + Time in seconds between successive attempts to acquire an exclusive lock. <b>stale</b><i>_</i><b>lock</b><i>_</i><b>time</b> Limit the time after which a stale lock is removed. <b>mailbox</b><i>_</i><b>delivery</b><i>_</i><b>lock</b> - What file locking method(s) to use when delivering - to a UNIX-style mailbox. The default setting is - system dependent. For a list of available file + What file locking method(s) to use when delivering + to a UNIX-style mailbox. The default setting is + system dependent. For a list of available file locking methods, use the <b>postconf</b> <b>-l</b> command. <b>Resource</b> <b>controls</b> <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> - Limit the amount of time for delivery to external + Limit the amount of time for delivery to external command. <b>duplicate</b><i>_</i><b>filter</b><i>_</i><b>limit</b> - Limit the size of the duplicate filter for results + Limit the size of the duplicate filter for results from alias etc. expansion. <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b> - Limit the amount of memory used for processing a + Limit the amount of memory used for processing a partial input line. <b>local</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 - user. The default limit is taken from the + user. The default limit is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. <b>local</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> - Limit the number of recipients per message deliv- - ery. The default limit is taken from the + Limit the number of recipients per message deliv- + ery. The default limit is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. <b>mailbox</b><i>_</i><b>size</b><i>_</i><b>limit</b> - Limit the size of a mailbox etc. file (any file - that is written to upon delivery). Set to zero to + Limit the size of a mailbox etc. file (any file + that is written to upon delivery). Set to zero to disable the limit. - - - 7 - - - - - -LOCAL(8) LOCAL(8) - - <b>Security</b> <b>controls</b> <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>commands</b> - Restrict the usage of mail delivery to external - command. Specify zero or more of: <b>alias</b>, <b>forward</b>, + Restrict the usage of mail delivery to external + command. Specify zero or more of: <b>alias</b>, <b>forward</b>, <b>include</b>. <b>allow</b><i>_</i><b>mail</b><i>_</i><b>to</b><i>_</i><b>files</b> - Restrict the usage of mail delivery to external - file. Specify zero or more of: <b>alias</b>, <b>forward</b>, + Restrict the usage of mail delivery to external + file. Specify zero or more of: <b>alias</b>, <b>forward</b>, <b>include</b>. <b>command</b><i>_</i><b>expansion</b><i>_</i><b>filter</b> - What characters are allowed to appear in $name - expansions of mailbox_command. Illegal characters + What characters are allowed to appear in $name + expansions of mailbox_command. Illegal characters are replaced by underscores. <b>default</b><i>_</i><b>privs</b> - Default rights for delivery to external file or + Default rights for delivery to external file or command. <b>forward</b><i>_</i><b>expansion</b><i>_</i><b>filter</b> - What characters are allowed to appear in $name - expansions of forward_path. Illegal characters are + What characters are allowed to appear in $name + expansions of forward_path. Illegal characters are replaced by underscores. <b>HISTORY</b> - 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 <i>maildir</i> structure appears in the <b>qmail</b> system by + The <i>maildir</i> structure appears in the <b>qmail</b> system by Daniel Bernstein. <b>SEE</b> <b>ALSO</b> @@ -507,7 +431,7 @@ LOCAL(8) LOCAL(8) <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> @@ -516,15 +440,6 @@ LOCAL(8) LOCAL(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - 8 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/master.8.html b/gnu/dist/postfix/html/master.8.html index c767d6dc307..82c09b5545c 100644 --- a/gnu/dist/postfix/html/master.8.html +++ b/gnu/dist/postfix/html/master.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - MASTER(8) MASTER(8) - <b>NAME</b> master - Postfix master process @@ -59,18 +56,6 @@ MASTER(8) MASTER(8) Signals: <b>SIGHUP</b> Upon receipt of a <b>HUP</b> signal (e.g., after <b>postfix</b> - - - - 1 - - - - - -MASTER(8) MASTER(8) - - <b>reload</b>), the master process re-reads its configura- tion files. If a service has been removed from the <b>master.cf</b> file, its running processes are termi- @@ -124,19 +109,6 @@ MASTER(8) MASTER(8) <b>daemon</b><i>_</i><b>directory</b> Directory with Postfix daemon programs. - - - - - 2 - - - - - -MASTER(8) MASTER(8) - - <b>queue</b><i>_</i><b>directory</b> Top-level directory of the Postfix queue. This is also the root directory of Postfix daemons that run @@ -179,22 +151,6 @@ MASTER(8) MASTER(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/nqmgr.8.html b/gnu/dist/postfix/html/nqmgr.8.html new file mode 100644 index 00000000000..405e14d2ff9 --- /dev/null +++ b/gnu/dist/postfix/html/nqmgr.8.html @@ -0,0 +1,343 @@ +<html> <head> </head> <body> <pre> + +NQMGR(8) NQMGR(8) + +<b>NAME</b> + nqmgr - Postfix queue manager + +<b>SYNOPSIS</b> + <b>nqmgr</b> [generic Postfix daemon options] + +<b>DESCRIPTION</b> + The <b>nqmgr</b> daemon awaits the arrival of incoming mail and + arranges for its delivery via Postfix delivery processes. + The actual mail routing strategy is delegated to the <a href="trivial-rewrite.8.html"><b>triv-</b></a> + <a href="trivial-rewrite.8.html"><b>ial-rewrite</b>(8)</a> daemon. This program expects to be run + from the <a href="master.8.html"><b>master</b>(8)</a> process manager. + + Mail addressed to the local <b>double-bounce</b> address is + silently discarded. This stops potential loops caused by + undeliverable bounce notifications. + + Mail addressed to a user listed in the optional <b>relocated</b> + database is bounced with a "user has moved to <i>new_loca-</i> + <i>tion</i>" message. See <a href="relocated.5.html"><b>relocated</b>(5)</a> for a precise description. + +<b>MAIL</b> <b>QUEUES</b> + The <b>nqmgr</b> daemon maintains the following queues: + + <b>incoming</b> + Inbound mail from the network, or mail picked up by + the local <b>pickup</b> agent from the <b>maildrop</b> directory. + + <b>active</b> Messages that the queue manager has opened for + delivery. Only a limited number of messages is + allowed to enter the <b>active</b> queue (leaky bucket + strategy, for a fixed delivery rate). + + <b>deferred</b> + Mail that could not be delivered upon the first + attempt. The queue manager implements exponential + backoff by doubling the time between delivery + attempts. + + <b>corrupt</b> + Unreadable or damaged queue files are moved here + for inspection. + +<b>DELIVERY</b> <b>STATUS</b> <b>REPORTS</b> + The <b>nqmgr</b> daemon keeps an eye on per-message delivery sta- + tus reports in the following directories. Each status + report file has the same name as the corresponding message + file: + + <b>bounce</b> Per-recipient status information about why mail is + bounced. These files are maintained by the + <a href="bounce.8.html"><b>bounce</b>(8)</a> daemon. + + <b>defer</b> Per-recipient status information about why mail is + delayed. These files are maintained by the + <a href="defer.8.html"><b>defer</b>(8)</a> daemon. + + The <b>nqmgr</b> daemon is responsible for asking the <a href="bounce.8.html"><b>bounce</b>(8)</a> + or <a href="defer.8.html"><b>defer</b>(8)</a> daemons to send non-delivery reports. + +<b>STRATEGIES</b> + The queue manager implements a variety of strategies for + either opening queue files (input) or for message delivery + (output). + + <b>leaky</b> <b>bucket</b> + This strategy limits the number of messages in the + <b>active</b> queue and prevents the queue manager from + running out of memory under heavy load. + + <b>fairness</b> + When the <b>active</b> queue has room, the queue manager + takes one message from the <b>incoming</b> queue and one + from the <b>deferred</b> queue. This prevents a large mail + backlog from blocking the delivery of new mail. + + <b>slow</b> <b>start</b> + This strategy eliminates "thundering herd" problems + by slowly adjusting the number of parallel deliver- + ies to the same destination. + + <b>round</b> <b>robin</b> + The queue manager sorts delivery requests by desti- + nation. Round-robin selection prevents one desti- + nation from dominating deliveries to other destina- + tions. + + <b>exponential</b> <b>backoff</b> + Mail that cannot be delivered upon the first + attempt is deferred. The time interval between + delivery attempts is doubled after each attempt. + + <b>destination</b> <b>status</b> <b>cache</b> + The queue manager avoids unnecessary delivery + attempts by maintaining a short-term, in-memory + list of unreachable destinations. + + <b>preemptive</b> <b>message</b> <b>scheduling</b> + The queue manager attempts to minimize the average + per-recipient delay while still preserving the cor- + rect per-message delays, using a sophisticated pre- + emptive message scheduling. + +<b>TRIGGERS</b> + On an idle system, the queue manager waits for the arrival + of trigger events, or it waits for a timer to go off. A + trigger is a one-byte message. Depending on the message + received, the queue manager performs one of the following + actions (the message is followed by the symbolic constant + used internally by the software): + + <b>D</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>DEFERRED)</b> + Start a deferred queue scan. If a deferred queue + scan is already in progress, that scan will be + restarted as soon as it finishes. + + <b>I</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>INCOMING)</b> + Start an incoming queue scan. If an incoming queue + scan is already in progress, that scan will be + restarted as soon as it finishes. + + <b>A</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>ALL)</b> + Ignore deferred queue file time stamps. The request + affects the next deferred queue scan. + + <b>F</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>FLUSH</b><i>_</i><b>DEAD)</b> + Purge all information about dead transports and + destinations. + + <b>W</b> <b>(TRIGGER</b><i>_</i><b>REQ</b><i>_</i><b>WAKEUP)</b> + Wakeup call, This is used by the master server to + instantiate servers that should not go away for- + ever. The action is to start an incoming queue + scan. + + The <b>nqmgr</b> daemon reads an entire buffer worth of triggers. + Multiple identical trigger requests are collapsed into + one, and trigger requests are sorted so that <b>A</b> and <b>F</b> pre- + cede <b>D</b> and <b>I</b>. Thus, in order to force a deferred queue + run, one would request <b>A</b> <b>F</b> <b>D</b>; in order to notify the queue + manager of the arrival of new mail one would request <b>I</b>. + +<b>STANDARDS</b> + None. The <b>nqmgr</b> daemon does not interact with the outside + world. + +<b>SECURITY</b> + The <b>nqmgr</b> daemon is not security sensitive. It reads sin- + gle-character messages from untrusted local users, and + thus may be susceptible to denial of service attacks. The + <b>nqmgr</b> daemon does not talk to the outside world, and it + can be run at fixed low privilege in a chrooted environ- + ment. + +<b>DIAGNOSTICS</b> + Problems and transactions are logged to the syslog daemon. + Corrupted message files are saved to the <b>corrupt</b> queue for + further inspection. + + 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> + A single queue manager process has to compete for disk + access with multiple front-end processes such as <b>smtpd</b>. A + sudden burst of inbound mail can negatively impact out- + bound delivery rates. + +<b>CONFIGURATION</b> <b>PARAMETERS</b> + The following <b>main.cf</b> parameters are especially relevant + to this program. See the Postfix <b>main.cf</b> file for syntax + details and for default values. Use the <b>postfix</b> <b>reload</b> + command after a configuration change. + +<b>Miscellaneous</b> + <b>allow</b><i>_</i><b>min</b><i>_</i><b>user</b> + Do not bounce recipient addresses that begin with + '-'. + + <b>relocated</b><i>_</i><b>maps</b> + Tables with contact information for users, hosts or + domains that no longer exist. See <a href="relocated.5.html"><b>relocated</b>(5)</a>. + + <b>queue</b><i>_</i><b>directory</b> + Top-level directory of the Postfix queue. + +<b>Active</b> <b>queue</b> <b>controls</b> + In the text below, <i>transport</i> is the first field in a <b>mas-</b> + <b>ter.cf</b> entry. + + <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>active</b><i>_</i><b>limit</b> + Limit the number of messages in the active queue. + + <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> + Limit the number of in-memory recipients. + + This parameter also limits the size of the short- + term, in-memory destination cache. + + <b>qmgr</b><i>_</i><b>message</b><i>_</i><b>recipient</b><i>_</i><b>minimum</b> + Per message minimum of in-memory recipients. + + <b>default</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> + Default limit on the number of in-memory recipients + per transport. + + <i>transport_</i><b>recipient</b><i>_</i><b>limit</b> + Limit on the number of in-memory recipients, for + the named message <i>transport</i>. + + <b>default</b><i>_</i><b>extra</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> + Default limit on the total number of per transport + in-memory recipients that the preempting messages + can have. + + <i>transport_</i><b>extra</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> + Limit on the number of in-memory recipients which + all preempting messages delivered by the transport + <i>transport</i> can have. + +<b>Timing</b> <b>controls</b> + <b>min</b><i>_</i><b>backoff</b> + Minimal time in seconds between delivery attempts + of a deferred message. + + This parameter also limits the time an unreachable + destination is kept in the short-term, in-memory + destination status cache. + + <b>max</b><i>_</i><b>backoff</b> + Maximal time in seconds between delivery attempts + of a deferred message. + + <b>maximal</b><i>_</i><b>queue</b><i>_</i><b>lifetime</b> + Maximal time in days a message is queued before it + is sent back as undeliverable. + + <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> + Time in seconds between deferred queue scans. Queue + scans do not overlap. + + <b>transport</b><i>_</i><b>retry</b><i>_</i><b>time</b> + Time in seconds between attempts to contact a bro- + ken delivery transport. + +<b>Concurrency</b> <b>controls</b> + <b>initial</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b> + Initial per-destination concurrency level for par- + allel delivery to the same destination. + + <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> + Default limit on the number of parallel deliveries + to the same destination. + + <i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> + Limit on the number of parallel deliveries to the + same destination, for delivery via the named mes- + sage <i>transport</i>. + +<b>Recipient</b> <b>controls</b> + <b>default</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> + Default limit on the number of recipients per mes- + sage transfer. + + <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> + Limit on the number of recipients per message + transfer, for the named message <i>transport</i>. + +<b>Message</b> <b>scheduling</b> + <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b> (valid range: 0,2,3...) + This parameter basically controls how often a mes- + sage delivered by <i>transport</i> can be preempted by + another message. An internal per-message/transport + counter is incremented by one for each <i>trans-</i> + <i>port_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b> deliveries handled by + <i>transport</i>. This counter represents the number of + "available delivery slots" for use by other mes- + sages. Current message can be preempted by another + message when that other message can be delivered + using less <i>transport</i> agents than the value of the + "available delivery slots" counter. + + Value equal to 0 disables the message preemption + for <i>transport</i>. + + <i>transport_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b> + Message preemption is not attempted at all whenever + a message that can't ever accumulate at least + <i>transport_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b> available delivery + slots is being delivered by <i>transport</i>. + + <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b> (valid range: 0..100) + + <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b> + These parameters speed up the moment when a message + preemption can happen. Instead of waiting until + the full amount of delivery slots required is + available, the preemption can happen when <i>trans-</i> + <i>port_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b> percent of the required + amount plus <i>transport_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b> still + remains to be accumulated. Note that the full + amount will still have to be accumulated before + another preemption can take place later. + + <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>cost</b> + + <b>default</b><i>_</i><b>minimum</b><i>_</i><b>delivery</b><i>_</i><b>slots</b> + + <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>discount</b> + + <b>default</b><i>_</i><b>delivery</b><i>_</i><b>slot</b><i>_</i><b>loan</b> + Default values for the transport specific parame- + ters described above. + +<b>SEE</b> <b>ALSO</b> + <a href="master.8.html">master(8)</a>, process manager + <a href="relocated.5.html">relocated(5)</a>, format of the "user has moved" table + syslogd(8) system logging + <a href="trivial-rewrite.8.html">trivial-rewrite(8)</a>, address routing + +<b>LICENSE</b> + The Secure Mailer license must be distributed with this + software. + +<b>AUTHOR(S)</b> + Wietse Venema + IBM T.J. Watson Research + P.O. Box 704 + Yorktown Heights, NY 10598, USA + + Scheduler enhancements: + Patrik Rak + Modra 6 + 155 00, Prague, Czech Republic + + 1 + +</pre> </body> </html> diff --git a/gnu/dist/postfix/html/pcre_table.5.html b/gnu/dist/postfix/html/pcre_table.5.html index b04bc607b74..55d1e714830 100644 --- a/gnu/dist/postfix/html/pcre_table.5.html +++ b/gnu/dist/postfix/html/pcre_table.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - PCRE_TABLE(5) PCRE_TABLE(5) - <b>NAME</b> pcre_table - format of Postfix PCRE tables @@ -22,75 +19,68 @@ PCRE_TABLE(5) PCRE_TABLE(5) The general form of a PCRE table is: - blanks and comments - Blank lines are ignored, as are lines beginning - with `#'. - - leading whitespace - Lines that begin with whitespace continue the pre- - vious line. - <i>pattern</i> <i>result</i> When <i>pattern</i> matches a search string, use the cor- - responding <i>result</i>. A line that starts with white - space continues the preceding line. + responding <i>result</i>. + + blank lines and comments + Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + multi-line text + A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. Each pattern is a perl-like regular expression. The - expression delimiter can be any character, except whites- - pace or characters that have special meaning (tradition- - ally the forward slash is used). The regular expression + expression delimiter can be any character, except whites- + pace or characters that have special meaning (tradition- + ally the forward slash is used). The regular expression can contain whitespace. By default, matching is case-insensitive, although follow- - ing the second slash with an `i' flag will reverse this. - Other flags are supported, but the only other useful one + ing the second slash with an `i' flag will reverse this. + Other flags are supported, but the only other useful one is `U', which makes matching ungreedy (see PCRE documenta- tion and source for more info). - Each pattern is applied to the entire lookup key string. - Depending on the application, that string is an entire + Each pattern is applied to the entire lookup key string. + Depending on the application, that string is an entire client hostname, an entire client IP address, or an entire - mail address. Thus, no parent domain or parent network - search is done, and <i>user@domain</i> mail addresses are not - broken up into their <i>user</i> and <i>domain</i> constituent parts, + mail address. Thus, no parent domain or parent network + search is done, and <i>user@domain</i> mail addresses are not + broken up into their <i>user</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken up into <i>user</i> and <i>foo</i>. - Patterns are applied in the order as specified in the - table, until a pattern is found that matches the search + Patterns are applied in the order as specified in the + table, until a pattern is found that matches the search string. - - - - 1 - - - - - -PCRE_TABLE(5) PCRE_TABLE(5) - - - Substitution of substrings from the matched expression - into the result string is possible using the conventional - perl syntax ($1, $2, etc.). The macros in the result - string may need to be written as ${n} or $(n) if they + Substitution of substrings from the matched expression + into the result string is possible using the conventional + perl syntax ($1, $2, etc.). The macros in the result + string may need to be written as ${n} or $(n) if they aren't followed by whitespace. -<b>EXAMPLES</b> +<b>EXAMPLE</b> <b>SMTPD</b> <b>ACCESS</b> <b>MAP</b> # Protect your outgoing majordomo exploders - /^(?!owner-)(.*)-outgoing@(my.domain)$/ 550 Use ${1}@${2} instead + /^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead # Bounce friend@whatever, except when whatever is our domain (you would # be better just bouncing all friend@ mail - this is just an example). - /^friend@(?!my.domain).*$/ 550 Stick this in your pipe $0 + /^friend@(?!my\.domain)/ 550 Stick this in your pipe $0 # A multi-line entry. The text is sent as one line. # - /^noddy@connect.com.au$/ + /^noddy@my\.domain$/ 550 This user is a funny one. You really don't want to send mail to them as it only makes their head spin. +<b>EXAMPLE</b> <b>HEADER</b> <b>FILTER</b> <b>MAP</b> + /^Subject: make money fast/ REJECT + /^To: friend@public\.com/ REJECT + <b>SEE</b> <b>ALSO</b> <a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables @@ -108,27 +98,6 @@ PCRE_TABLE(5) PCRE_TABLE(5) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/pickup.8.html b/gnu/dist/postfix/html/pickup.8.html index b70e54e765a..428f0e187f1 100644 --- a/gnu/dist/postfix/html/pickup.8.html +++ b/gnu/dist/postfix/html/pickup.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - PICKUP(8) PICKUP(8) - <b>NAME</b> pickup - Postfix local mail pickup @@ -13,66 +10,55 @@ PICKUP(8) PICKUP(8) <b>DESCRIPTION</b> The <b>pickup</b> daemon waits for hints that new mail has been - dropped into the world-writable <b>maildrop</b> directory, and - feeds it into the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon. Ill-formatted files - are deleted without notifying the originator. This pro- - gram expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process manager. + dropped into the <b>maildrop</b> directory, and feeds it into the + <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon. Ill-formatted files are deleted with- + out notifying the originator. This program expects to be + run from the <a href="master.8.html"><b>master</b>(8)</a> process manager. <b>STANDARDS</b> None. The <b>pickup</b> daemon does not interact with the outside world. <b>SECURITY</b> - The <b>pickup</b> daemon runs with superuser privileges so that + The <b>pickup</b> daemon runs with superuser privileges so that it 1) can open a queue file with the rights of the submit- - ting user and 2) can access the Postfix private IPC chan- + ting user and 2) can access the Postfix private IPC chan- nels. On the positive side, the program can run chrooted, opens no files for writing, is careful about what files it - opens for reading, and does not actually touch any data + opens for reading, and does not actually touch any data that is sent to its public service endpoint. <b>DIAGNOSTICS</b> Problems and transactions are logged to <b>syslogd</b>(8). <b>BUGS</b> - The <b>pickup</b> daemon copies mail from file to the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> - daemon. It could avoid message copying overhead by send- - ing a file descriptor instead of file data, but then the - already complex <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon would have to deal with + The <b>pickup</b> daemon copies mail from file to the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> + daemon. It could avoid message copying overhead by send- + ing a file descriptor instead of file data, but then the + already complex <a href="cleanup.8.html"><b>cleanup</b>(8)</a> daemon would have to deal with unfiltered user data. <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>Content</b> <b>inspection</b> <b>controls</b> <b>content</b><i>_</i><b>filter</b> - The name of a mail delivery transport that filters + The name of a mail delivery transport that filters mail and that either bounces mail or re-injects the - result back into Postfix. This parameter uses the - same syntax as the right-hand side of a Postfix + result back into Postfix. This parameter uses the + same syntax as the right-hand side of a Postfix transport table. <b>Miscellaneous</b> <b>always</b><i>_</i><b>bcc</b> - Address to send a copy of each message that enters + Address to send a copy of each message that enters the system. - - - 1 - - - - - -PICKUP(8) PICKUP(8) - - <b>mail</b><i>_</i><b>owner</b> - The process privileges used while not opening a + The process privileges used while not opening a <b>maildrop</b> file. <b>queue</b><i>_</i><b>directory</b> @@ -81,10 +67,11 @@ PICKUP(8) PICKUP(8) <b>SEE</b> <b>ALSO</b> <a href="cleanup.8.html">cleanup(8)</a> message canonicalization <a href="master.8.html">master(8)</a> process manager + <a href="sendmail.1.html">sendmail(1)</a>, postdrop(8) mail posting agent syslogd(8) system logging <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. <b>AUTHOR(S)</b> @@ -93,42 +80,6 @@ PICKUP(8) PICKUP(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/pipe.8.html b/gnu/dist/postfix/html/pipe.8.html index 4c79983a037..372fce1b6f2 100644 --- a/gnu/dist/postfix/html/pipe.8.html +++ b/gnu/dist/postfix/html/pipe.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - PIPE(8) PIPE(8) - <b>NAME</b> pipe - Postfix delivery to external command @@ -17,23 +14,28 @@ PIPE(8) PIPE(8) program expects to be run from the <a href="master.8.html"><b>master</b>(8)</a> process man- ager. - The <b>pipe</b> daemon updates queue files and marks recipients + Message attributes such as sender address, recipient + address and next-hop host name can be specified as com- + mand-line macros that are expanded before the external + command is executed. + + The <b>pipe</b> daemon updates queue files and marks recipients as finished, or it informs the queue manager that delivery - should be tried again at a later time. Delivery problem - reports are sent to the <a href="bounce.8.html"><b>bounce</b>(8)</a> or <a href="defer.8.html"><b>defer</b>(8)</a> daemon as + should be tried again at a later time. Delivery problem + reports are sent to the <a href="bounce.8.html"><b>bounce</b>(8)</a> or <a href="defer.8.html"><b>defer</b>(8)</a> daemon as appropriate. <b>SINGLE-RECIPIENT</b> <b>DELIVERY</b> Some external commands cannot handle more than one recipi- - ent per delivery request. Examples of such transports are + ent per delivery request. Examples of such transports are pagers, fax machines, and so on. - To prevent Postfix from sending multiple recipients per + To prevent Postfix from sending multiple recipients per delivery request, specify <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> <b>=</b> <b>1</b> - in the Postfix <b>main.cf</b> file, where <i>transport</i> is the name + in the Postfix <b>main.cf</b> file, where <i>transport</i> is the name in the first column of the Postfix <b>master.cf</b> entry for the pipe-based delivery transport. @@ -42,38 +44,52 @@ PIPE(8) PIPE(8) file at the end of a service definition. The syntax is as follows: - <b>flags=BFR.</b>> (optional) - Optional message processing flags. By default, a + <b>flags=BFRhqu.</b>> (optional) + Optional message processing flags. By default, a message is copied unchanged. - <b>B</b> Append a blank line at the end of each mes- - sage. This is required by some mail user - agents that recognize "<b>From</b> " lines only + <b>B</b> Append a blank line at the end of each mes- + sage. This is required by some mail user + agents that recognize "<b>From</b> " lines only when preceded by a blank line. - <b>F</b> Prepend a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope - header to the message content. This is + <b>F</b> Prepend a "<b>From</b> <i>sender</i> <i>time_stamp</i>" envelope + header to the message content. This is expected by, for example, <b>UUCP</b> software. - <b>R</b> Prepend a <b>Return-Path:</b> message header with + <b>R</b> Prepend a <b>Return-Path:</b> message header with the envelope sender address. - <b>.</b> Prepend <b>.</b> to lines starting with "<b>.</b>". This - - - - 1 - - - - - -PIPE(8) PIPE(8) - - + <b>h</b> Fold the command-line <b>$recipient</b> domain name + and <b>$nexthop</b> host name to lower case. This + is recommended for delivery via <b>UUCP</b>. + + <b>q</b> Quote white space and other special charac- + ters in the command-line <b>$sender</b> and <b>$recip-</b> + <b>ient</b> address localparts (text to the left of + the right-most <b>@</b> character), according to an + 8-bit transparent version of <a href="http://www.faqs.org/rfcs/rfc822.html">RFC 822</a>. This + is recommended for delivery via <b>UUCP</b> or + <b>BSMTP</b>. + + The result is compatible with the address + parsing of command-line recipients by the + Postfix <b>sendmail</b> mail submission command. + + The <b>q</b> flag affects only entire addresses, + not the partial address information from the + <b>$user</b>, <b>$extension</b> or <b>$mailbox</b> command-line + macros. + + <b>u</b> Fold the command-line <b>$recipient</b> address + localpart (text to the left of the right- + most <b>@</b> character) to lower case. This is + recommended for delivery via <b>UUCP</b>. + + <b>.</b> Prepend <b>.</b> to lines starting with "<b>.</b>". This is needed by, for example, <b>BSMTP</b> software. - > Prepend > to lines starting with "<b>From</b> ". + > Prepend > to lines starting with "<b>From</b> ". This is expected by, for example, <b>UUCP</b> soft- ware. @@ -81,16 +97,16 @@ PIPE(8) PIPE(8) <b>user</b>=<i>username</i>:<i>groupname</i> The external command is executed with the rights of - the specified <i>username</i>. The software refuses to - execute commands with root privileges, or with the - privileges of the mail system owner. If <i>groupname</i> - is specified, the corresponding group ID is used + the specified <i>username</i>. The software refuses to + execute commands with root privileges, or with the + privileges of the mail system owner. If <i>groupname</i> + is specified, the corresponding group ID is used instead of the group ID of <i>username</i>. <b>eol=string</b> (default: <b>\n</b>) - The output record delimiter. Typically one would - use either <b>\r\n</b> or <b>\n</b>. The usual C-style backslash - escape sequences are recognized: <b>\a</b> <b>\b</b> <b>\f</b> <b>\n</b> <b>\r</b> <b>\t</b> + The output record delimiter. Typically one would + use either <b>\r\n</b> or <b>\n</b>. The usual C-style backslash + escape sequences are recognized: <b>\a</b> <b>\b</b> <b>\f</b> <b>\n</b> <b>\r</b> <b>\t</b> <b>\v</b> <b>\</b><i>octal</i> and <b>\\</b>. <b>size</b>=<i>size_limit</i> (optional) @@ -98,52 +114,49 @@ PIPE(8) PIPE(8) will be bounced back to the sender. <b>argv</b>=<i>command</i>... (required) - The command to be executed. This must be specified + The command to be executed. This must be specified as the last command attribute. The command is exe- cuted directly, i.e. without interpretation of - shell meta characters by a shell command inter- + shell meta characters by a shell command inter- preter. In the command argument vector, the following macros are recognized and replaced with correspond- - ing information from the Postfix queue manager + ing information from the Postfix queue manager delivery request: <b>${extension</b>} - This macro expands to the extension part of - a recipient address. For example, with an + This macro expands to the extension part of + a recipient address. For example, with an address <i>user+foo@domain</i> the extension is <i>foo</i>. - A command-line argument that contains - <b>${extension</b>} expands into as many command- + A command-line argument that contains + <b>${extension</b>} expands into as many command- line arguments as there are recipients. + This information is modified by the <b>u</b> flag + for case folding. + <b>${mailbox</b>} This macro expands to the complete local part of a recipient address. For example, with an address <i>user+foo@domain</i> the mailbox is <i>user+foo</i>. - - - - 2 - - - - - -PIPE(8) PIPE(8) - - A command-line argument that contains <b>${mailbox</b>} expands into as many command-line arguments as there are recipients. + This information is modified by the <b>u</b> flag + for case folding. + <b>${nexthop</b>} This macro expands to the next-hop hostname. + This information is modified by the <b>h</b> flag + for case folding. + <b>${recipient</b>} This macro expands to the complete recipient address. @@ -152,10 +165,16 @@ PIPE(8) PIPE(8) <b>${recipient</b>} expands into as many command- line arguments as there are recipients. + This information is modified by the <b>hqu</b> + flags for quoting and case folding. + <b>${sender</b>} - This macro expands to the envelope sender + This macro expands to the envelope sender address. + This information is modified by the <b>q</b> flag + for quoting. + <b>${size</b>} This macro expands to Postfix's idea of the message size, which is an approximation of @@ -171,40 +190,31 @@ PIPE(8) PIPE(8) <b>${user</b>} expands into as many command-line arguments as there are recipients. - In addition to the form ${<i>name</i>}, the forms $<i>name</i> and - $(<i>name</i>) are also recognized. Specify <b>$$</b> where a single <b>$</b> + This information is modified by the <b>u</b> flag + for case folding. + + In addition to the form ${<i>name</i>}, the forms $<i>name</i> and + $(<i>name</i>) are also recognized. Specify <b>$$</b> where a single <b>$</b> is wanted. <b>DIAGNOSTICS</b> - Command exit status codes are expected to follow the con- + Command exit status codes are expected to follow the con- ventions defined in <<b>sysexits.h</b>>. - Problems and transactions are logged to <b>syslogd</b>(8). Cor- - rupted message files are marked so that the queue manager + Problems and transactions are logged to <b>syslogd</b>(8). Cor- + rupted message files are marked so that the queue manager can move them to the <b>corrupt</b> queue for further inspection. <b>SECURITY</b> - This program needs a dual personality 1) to access the - private Postfix queue and IPC mechanisms, and 2) to exe- + This program needs a dual personality 1) to access the + private Postfix queue and IPC mechanisms, and 2) to exe- cute external commands as the specified user. It is there- fore security sensitive. <b>CONFIGURATION</b> <b>PARAMETERS</b> - The following <b>main.cf</b> parameters are especially relevant - - - - 3 - - - - - -PIPE(8) PIPE(8) - - - to this program. See the Postfix <b>main.cf</b> file for syntax - details and for default values. Use the <b>postfix</b> <b>reload</b> + The following <b>main.cf</b> parameters are especially relevant + to this program. See the Postfix <b>main.cf</b> file for syntax + details and for default values. Use the <b>postfix</b> <b>reload</b> command after a configuration change. <b>Miscellaneous</b> @@ -213,32 +223,32 @@ PIPE(8) PIPE(8) exported to non-Postfix processes. <b>mail</b><i>_</i><b>owner</b> - The process privileges used while not running an + The process privileges used while not running an external command. <b>Resource</b> <b>controls</b> - In the text below, <i>transport</i> is the first field in a <b>mas-</b> + In the text below, <i>transport</i> is the first field in a <b>mas-</b> <b>ter.cf</b> entry. <i>transport_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> Limit the number of parallel deliveries to the same - destination, for delivery via the named <i>transport</i>. - The default limit is taken from the <b>default</b><i>_</i><b>desti-</b> - <b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. The limit is + destination, for delivery via the named <i>transport</i>. + The default limit is taken from the <b>default</b><i>_</i><b>desti-</b> + <b>nation</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. The limit is enforced by the Postfix queue manager. <i>transport_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> - Limit the number of recipients per message deliv- - ery, for delivery via the named <i>transport</i>. The - default limit is taken from the <b>default</b><i>_</i><b>destina-</b> - <b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is + Limit the number of recipients per message deliv- + ery, for delivery via the named <i>transport</i>. The + default limit is taken from the <b>default</b><i>_</i><b>destina-</b> + <b>tion</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> parameter. The limit is enforced by the Postfix queue manager. <i>transport_</i><b>time</b><i>_</i><b>limit</b> - Limit the time for delivery to external command, - for delivery via the named <b>transport</b>. The default - limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame- - ter. The limit is enforced by the Postfix queue + Limit the time for delivery to external command, + for delivery via the named <b>transport</b>. The default + limit is taken from the <b>command</b><i>_</i><b>time</b><i>_</i><b>limit</b> parame- + ter. The limit is enforced by the Postfix queue manager. <b>SEE</b> <b>ALSO</b> @@ -248,7 +258,7 @@ PIPE(8) PIPE(8) syslogd(8) system logging <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. <b>AUTHOR(S)</b> @@ -257,10 +267,6 @@ PIPE(8) PIPE(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - 4 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postalias.1.html b/gnu/dist/postfix/html/postalias.1.html index 4d6e097bb92..75168f09ff9 100644 --- a/gnu/dist/postfix/html/postalias.1.html +++ b/gnu/dist/postfix/html/postalias.1.html @@ -1,15 +1,12 @@ <html> <head> </head> <body> <pre> - - POSTALIAS(1) POSTALIAS(1) - <b>NAME</b> postalias - Postfix alias database maintenance <b>SYNOPSIS</b> - <b>postalias</b> [<b>-Ninrvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>] + <b>postalias</b> [<b>-Nfinrvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>] [<i>file_type</i>:]<i>file_name</i> ... <b>DESCRIPTION</b> @@ -37,8 +34,16 @@ POSTALIAS(1) POSTALIAS(1) directory. <b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one - entry per map. The exit status is non-zero if the - requested information was not found. + entry per map. The exit status is zero when the + requested information was found. + + If a key value of <b>-</b> is specified, the program reads + key values from the standard input stream. The exit + status is zero when at least one of the requested + keys was found. + + <b>-f</b> Do not fold the lookup key to lower case while cre- + ating or querying a map. <b>-i</b> Incremental mode. Read entries from standard input and do not truncate an existing database. By @@ -52,26 +57,20 @@ POSTALIAS(1) POSTALIAS(1) <b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the first value found on the standard output stream. - The exit status is non-zero if the requested infor- - mation was not found. + The exit status is zero when the requested informa- + tion was found. + + If a key value of <b>-</b> is specified, the program reads + key values from the standard input stream and + prints one line of <i>key:</i> <i>value</i> output for each key + that was found. The exit status is zero when at + least one of the requested keys was found. <b>-r</b> When updating a table, do not warn about duplicate entries; silently replace them. - <b>-v</b> Enable verbose logging for debugging purposes. - - - - 1 - - - - - -POSTALIAS(1) POSTALIAS(1) - - - Multiple <b>-v</b> options make the software increasingly + <b>-v</b> Enable verbose logging for debugging purposes. Mul- + tiple <b>-v</b> options make the software increasingly verbose. <b>-w</b> When updating a table, do not warn about duplicate @@ -113,10 +112,6 @@ POSTALIAS(1) POSTALIAS(1) cess (including successful <b>postmap</b> <b>-q</b> lookup) and termi- nates with non-zero exit status in case of failure. -<b>BUGS</b> - The "delete key" support is limited to one delete opera- - tion per command invocation. - <b>ENVIRONMENT</b> <b>MAIL</b><i>_</i><b>CONFIG</b> Directory with Postfix configuration files. @@ -124,26 +119,13 @@ POSTALIAS(1) POSTALIAS(1) <b>MAIL</b><i>_</i><b>VERBOSE</b> Enable verbose logging for debugging purposes. - - - - - 2 - - - - - -POSTALIAS(1) POSTALIAS(1) - - <b>CONFIGURATION</b> <b>PARAMETERS</b> - The following <b>main.cf</b> parameters are especially relevant - to this program. See the Postfix <b>main.cf</b> file for syntax + The following <b>main.cf</b> parameters are especially relevant + to this program. See the Postfix <b>main.cf</b> file for syntax details and for default values. <b>database</b><i>_</i><b>type</b> - Default alias database type. On many UNIX systems, + Default alias database type. On many UNIX systems, the default type is either <b>dbm</b> or <b>hash</b>. <b>STANDARDS</b> @@ -154,7 +136,7 @@ POSTALIAS(1) POSTALIAS(1) <a href="sendmail.1.html">sendmail(1)</a> mail posting and compatibility interface. <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. <b>AUTHOR(S)</b> @@ -163,38 +145,6 @@ POSTALIAS(1) POSTALIAS(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postcat.1.html b/gnu/dist/postfix/html/postcat.1.html index 57d03a854cd..a2b89ddf466 100644 --- a/gnu/dist/postfix/html/postcat.1.html +++ b/gnu/dist/postfix/html/postcat.1.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - POSTCAT(1) POSTCAT(1) - <b>NAME</b> postcat - show Postfix queue file contents @@ -36,33 +33,6 @@ POSTCAT(1) POSTCAT(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postconf.1.html b/gnu/dist/postfix/html/postconf.1.html index 1e8e55cb908..d43547e4527 100644 --- a/gnu/dist/postfix/html/postconf.1.html +++ b/gnu/dist/postfix/html/postconf.1.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - POSTCONF(1) POSTCONF(1) - <b>NAME</b> postconf - Postfix configuration utility @@ -59,76 +56,9 @@ POSTCONF(1) POSTCONF(1) <b>AUTHOR(S)</b> Wietse Venema IBM T.J. Watson Research - - - - 1 - - - - - -POSTCONF(1) POSTCONF(1) - - P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postdrop.1.html b/gnu/dist/postfix/html/postdrop.1.html index 372b037a392..b1dd861d5da 100644 --- a/gnu/dist/postfix/html/postdrop.1.html +++ b/gnu/dist/postfix/html/postdrop.1.html @@ -1,37 +1,38 @@ <html> <head> </head> <body> <pre> - - POSTDROP(1) POSTDROP(1) - <b>NAME</b> - postdrop - Postfix mail posting agent + postdrop - Postfix mail posting utility <b>SYNOPSIS</b> - <b>postdrop</b> [<i>option</i> <i>...</i>] + <b>postdrop</b> [<b>-rv</b>] [<b>-c</b> <i>config_dir</i>] <b>DESCRIPTION</b> The <b>postdrop</b> command creates a file in the <b>maildrop</b> direc- tory and copies its standard input to the file. - The command is designed to run with set-gid privileges, - and with group write permission to the <b>maildrop</b> queue - directory. + Options: - The <b>postdrop</b> command is automatically invoked by the <a href="sendmail.1.html"><b>send-</b></a> - <a href="sendmail.1.html"><b>mail</b>(1)</a> mail posting agent when the <b>maildrop</b> queue direc- - tory is not world-writable. + <b>-c</b> The <b>main.cf</b> configuration file is in the named + directory instead of the default configuration + directory. See also the MAIL_CONFIG environment + setting below. - Options: + <b>-r</b> Use a Postfix-internal protocol for reading the + message from standard input, and for reporting sta- + tus information on standard output. This is cur- + rently the only supported method. <b>-v</b> Enable verbose logging for debugging purposes. Mul- tiple <b>-v</b> options make the software increasingly verbose. <b>SECURITY</b> - This program is designed so that it can run with set-user - (or group) id privileges. + The command is designed to run with set-group ID privi- + leges, so that it can write to the <b>maildrop</b> queue direc- + tory and so that it can connect to Postfix daemon pro- + cesses. <b>DIAGNOSTICS</b> Fatal errors: malformed input, I/O error, out of memory. @@ -41,16 +42,26 @@ POSTDROP(1) POSTDROP(1) queue file is deleted. <b>ENVIRONMENT</b> - The program deletes all environment information, because - the C library can't be trusted. + MAIL_CONFIG + Directory with the <b>main.cf</b> file. In order to avoid + exploitation of set-group ID privileges, it is not + possible to specify arbitrary directory names. + + A non-standard directory is allowed only if the + name is listed in the standard <b>main.cf</b> file, in the + <b>alternate</b><i>_</i><b>config</b><i>_</i><b>directories</b> configuration parame- + ter value. + + Only the super-user is allowed to specify arbitrary + directory names. <b>FILES</b> /var/spool/postfix, mail queue /etc/postfix, configuration files <b>CONFIGURATION</b> <b>PARAMETERS</b> - 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 + 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>import</b><i>_</i><b>environment</b> @@ -58,19 +69,7 @@ POSTDROP(1) POSTDROP(1) imported from non-Postfix processes. <b>queue</b><i>_</i><b>directory</b> - Top-level directory of the Postfix queue. This is - - - - 1 - - - - - -POSTDROP(1) POSTDROP(1) - - + Top-level directory of the Postfix queue. This is also the root directory of Postfix daemons that run chrooted. @@ -79,7 +78,7 @@ POSTDROP(1) POSTDROP(1) syslogd(8) system logging <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. <b>AUTHOR(S)</b> @@ -88,47 +87,6 @@ POSTDROP(1) POSTDROP(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postfix.1.html b/gnu/dist/postfix/html/postfix.1.html index 8db5ad60250..39b37cbdec6 100644 --- a/gnu/dist/postfix/html/postfix.1.html +++ b/gnu/dist/postfix/html/postfix.1.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - POSTFIX(1) POSTFIX(1) - <b>NAME</b> postfix - Postfix control program @@ -12,36 +9,41 @@ POSTFIX(1) POSTFIX(1) <b>postfix</b> [<b>-c</b> <i>config_dir</i>] [<b>-D</b>] [<b>-v</b>] <i>command</i> <b>DESCRIPTION</b> - The <b>postfix</b> command controls the operation of the Postfix - mail system: start or stop the <b>master</b> daemon, do a health - check, and other maintenance. The command sets up a stan- - dardized environment and runs the <b>postfix-script</b> shell - script to do the actual work. + This command is reserved for the super-user. To submit + mail, use the Postfix <b>sendmail</b> command. + + The <b>postfix</b> command controls the operation of the Postfix + mail system: start or stop the <b>master</b> daemon, do a health + check, and other maintenance. + + The <b>postfix</b> command sets up a standardized environment and + runs the <b>postfix-script</b> shell script to do the actual + work. The following commands are implemented: - <b>check</b> Validate the Postfix mail system configuration. - Warn about bad directory/file ownership or permis- + <b>check</b> Validate the Postfix mail system configuration. + Warn about bad directory/file ownership or permis- sions, and create missing directories. - <b>start</b> Start the Postfix mail system. This also runs the + <b>start</b> Start the Postfix mail system. This also runs the configuration check described above. <b>stop</b> Stop the Postfix mail system in an orderly fashion. Running processes are allowed to terminate at their earliest convenience. - Note: in order to refresh the Postfix mail system - after a configuration change, do not use the <b>start</b> - and <b>stop</b> commands in succession. Use the <b>reload</b> + Note: in order to refresh the Postfix mail system + after a configuration change, do not use the <b>start</b> + and <b>stop</b> commands in succession. Use the <b>reload</b> command instead. <b>abort</b> Stop the Postfix mail system abruptly. Running pro- cesses are signaled to stop immediately. <b>flush</b> Force delivery: attempt to deliver every message in - the deferred mail queue. Normally, attempts to - deliver delayed mail happen at regular intervals, + the deferred mail queue. Normally, attempts to + deliver delayed mail happen at regular intervals, the interval doubling after each failed attempt. <b>reload</b> Re-read configuration files. Running processes ter- @@ -50,35 +52,23 @@ POSTFIX(1) POSTFIX(1) The following options are implemented: <b>-c</b> <i>config_dir</i> - Read the <b>main.cf</b> and <b>master.cf</b> configuration files - in the named directory instead of the default con- + Read the <b>main.cf</b> and <b>master.cf</b> configuration files + in the named directory instead of the default con- figuration directory. Use this to distinguish - between multiple Postfix instances on the same + between multiple Postfix instances on the same host. <b>-D</b> (with <b>postfix</b> <b>start</b> only) Run each Postfix daemon under control of a debugger as specified via the <b>debugger</b><i>_</i><b>command</b> configuration - - - - 1 - - - - - -POSTFIX(1) POSTFIX(1) - - parameter. <b>-v</b> Enable verbose logging for debugging purposes. Mul- - tiple <b>-v</b> options make the software increasingly + tiple <b>-v</b> options make the software increasingly verbose. <b>ENVIRONMENT</b> - The <b>postfix</b> command sets the following environment vari- + The <b>postfix</b> command sets the following environment vari- ables: <b>MAIL</b><i>_</i><b>CONFIG</b> @@ -92,50 +82,71 @@ POSTFIX(1) POSTFIX(1) This is set when the -D command-line option is pre- sent. - The following configuration parameters are made available - as process environment variables with the same names: +<b>CONFIGURATION</b> <b>PARAMETERS</b> + The following <b>main.cf</b> configuration parameters are made + available as process environment variables with the same + names: <b>command</b><i>_</i><b>directory</b> - Directory with Postfix support commands (default: - <b>$program</b><i>_</i><b>directory</b>). + Directory with Postfix administrative commands. <b>daemon</b><i>_</i><b>directory</b> - Directory with Postfix daemon programs (default: - <b>$program</b><i>_</i><b>directory</b>). + Directory with Postfix daemon programs. <b>config</b><i>_</i><b>directory</b> Directory with Postfix configuration files and with administrative shell scripts. <b>queue</b><i>_</i><b>directory</b> - The directory with the Postfix queue directory (and - with some files needed for programs running in a - chrooted environment). + The directory with Postfix queue files, with local + inter-process communication endpoints, and with + files needed for daemon programs that run in the + optional chrooted environment. <b>mail</b><i>_</i><b>owner</b> - The owner of the Postfix queue and of most Postfix - processes. + The owner of Postfix queue files and of most Post- + fix processes. -<b>FILES</b> - $<b>config</b><i>_</i><b>directory/postfix-script</b>, administrative commands - -<b>SEE</b> <b>ALSO</b> - <a href="master.8.html">master(8)</a> Postfix master program + <b>setgid</b><i>_</i><b>group</b> + The group for mail submission and queue management + commands. -<b>LICENSE</b> - The Secure Mailer license must be distributed with this - software. + <b>sendmail</b><i>_</i><b>path</b> + The full pathname for the Postfix sendmail command. + <b>newaliases</b><i>_</i><b>path</b> + The full pathname for the Postfix newaliases com- + mand. + <b>mailq</b><i>_</i><b>path</b> + The full pathname for the Postfix mailq command. - 2 + <b>manpage</b><i>_</i><b>directory</b> + The directory for the Postfix on-line manual pages. + <b>sample</b><i>_</i><b>directory</b> + The directory for the Postfix sample configuration + files. + <b>readme</b><i>_</i><b>directory</b> + The directory for the Postfix README files. +<b>Other</b> <b>configuration</b> <b>parameters</b> + <b>import</b><i>_</i><b>environment</b> + List of names of environment parameters that can be + imported from non-Postfix processes. +<b>FILES</b> + $<b>config</b><i>_</i><b>directory/postfix-script</b>, administrative commands + $<b>config</b><i>_</i><b>directory/main.cf</b>, configuration parameters + $<b>config</b><i>_</i><b>directory/master.cf</b>, Postfix daemon processes -POSTFIX(1) POSTFIX(1) +<b>SEE</b> <b>ALSO</b> + <a href="master.8.html">master(8)</a> Postfix master program +<b>LICENSE</b> + The Secure Mailer license must be distributed with this + software. <b>AUTHOR(S)</b> Wietse Venema @@ -143,58 +154,6 @@ POSTFIX(1) POSTFIX(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postkick.1.html b/gnu/dist/postfix/html/postkick.1.html index 0a5a5a3a9a8..e4890bd6fd0 100644 --- a/gnu/dist/postfix/html/postkick.1.html +++ b/gnu/dist/postfix/html/postkick.1.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - POSTKICK(1) POSTKICK(1) - <b>NAME</b> postkick - kick a Postfix service @@ -58,19 +55,6 @@ POSTKICK(1) POSTKICK(1) to this program. See the Postfix <b>main.cf</b> file for syntax details and for default values. - - - - - 1 - - - - - -POSTKICK(1) POSTKICK(1) - - <b>queue</b><i>_</i><b>directory</b> Location of the Postfix queue, and of the local IPC communication endpoints. @@ -89,46 +73,6 @@ POSTKICK(1) POSTKICK(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postlock.1.html b/gnu/dist/postfix/html/postlock.1.html index 8cc19092f14..fe78acdf17c 100644 --- a/gnu/dist/postfix/html/postlock.1.html +++ b/gnu/dist/postfix/html/postlock.1.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - POSTLOCK(1) POSTLOCK(1) - <b>NAME</b> postlock - lock mail folder and execute command @@ -58,19 +55,6 @@ POSTLOCK(1) POSTLOCK(1) <b>MAIL</b><i>_</i><b>CONFIG</b> Directory with Postfix configuration files. - - - - - 1 - - - - - -POSTLOCK(1) POSTLOCK(1) - - <b>MAIL</b><i>_</i><b>VERBOSE</b> Enable verbose logging for debugging purposes. @@ -116,19 +100,6 @@ POSTLOCK(1) POSTLOCK(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postlog.1.html b/gnu/dist/postfix/html/postlog.1.html index c6d6247a839..a4fd0bcfe3f 100644 --- a/gnu/dist/postfix/html/postlog.1.html +++ b/gnu/dist/postfix/html/postlog.1.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - POSTLOG(1) POSTLOG(1) - <b>NAME</b> postlog - Postfix-compatible logging utility @@ -59,10 +56,6 @@ POSTLOG(1) POSTLOG(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - 1 - </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postmap.1.html b/gnu/dist/postfix/html/postmap.1.html index 77833681c9d..92581834245 100644 --- a/gnu/dist/postfix/html/postmap.1.html +++ b/gnu/dist/postfix/html/postmap.1.html @@ -1,15 +1,12 @@ <html> <head> </head> <body> <pre> - - POSTMAP(1) POSTMAP(1) - <b>NAME</b> postmap - Postfix lookup table management <b>SYNOPSIS</b> - <b>postmap</b> [<b>-Ninrvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>] + <b>postmap</b> [<b>-Nfinrvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>] [<i>file_type</i>:]<i>file_name</i> ... <b>DESCRIPTION</b> @@ -19,6 +16,10 @@ POSTMAP(1) POSTMAP(1) <b>makemap</b> <i>file_type</i> <i>file_name</i> < <i>file_name</i> + If the result files do not exist they will be created with + the same group and other read permissions as the source + file. + While the table update is in progress, signal delivery is postponed, and an exclusive, advisory, lock is placed on the entire table, in order to avoid surprises in spectator @@ -26,15 +27,17 @@ POSTMAP(1) POSTMAP(1) The format of a lookup table input file is as follows: - <b>o</b> Blank lines are ignored. So are lines beginning - with `#'. - <b>o</b> A table entry has the form <i>key</i> whitespace <i>value</i> - <b>o</b> A line that starts with whitespace continues the - preceding line. + <b>o</b> Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + <b>o</b> A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. The <i>key</i> and <i>value</i> are processed as is, except that sur- rounding white space is stripped off. Unlike with Postfix @@ -56,20 +59,16 @@ POSTMAP(1) POSTMAP(1) directory. <b>-d</b> <i>key</i> Search the specified maps for <i>key</i> and remove one - entry per map. The exit status is non-zero if the - requested information was not found. - - - - - 1 - - - + entry per map. The exit status is zero when the + requested information was found. + If a key value of <b>-</b> is specified, the program reads + key values from the standard input stream. The exit + status is zero when at least one of the requested + keys was found. -POSTMAP(1) POSTMAP(1) - + <b>-f</b> Do not fold the lookup key to lower case while cre- + ating or querying a map. <b>-i</b> Incremental mode. Read entries from standard input and do not truncate an existing database. By @@ -83,8 +82,14 @@ POSTMAP(1) POSTMAP(1) <b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the first value found on the standard output stream. - The exit status is non-zero if the requested infor- - mation was not found. + The exit status is zero when the requested informa- + tion was found. + + If a key value of <b>-</b> is specified, the program reads + key values from the standard input stream and + prints one line of <i>key</i> <i>value</i> output for each key + that was found. The exit status is zero when at + least one of the requested keys was found. <b>-r</b> When updating a table, do not warn about duplicate entries; silently replace them. @@ -125,28 +130,12 @@ POSTMAP(1) POSTMAP(1) <b>DIAGNOSTICS</b> Problems and transactions are logged to the standard error stream. No output means no problems. Duplicate entries are - - - - 2 - - - - - -POSTMAP(1) POSTMAP(1) - - skipped and are flagged with a warning. <b>postmap</b> terminates with zero exit status in case of suc- cess (including successful <b>postmap</b> <b>-q</b> lookup) and termi- nates with non-zero exit status in case of failure. -<b>BUGS</b> - The "delete key" support is limited to one delete opera- - tion per command invocation. - <b>ENVIRONMENT</b> <b>MAIL</b><i>_</i><b>CONFIG</b> Directory with Postfix configuration files. @@ -156,12 +145,12 @@ POSTMAP(1) POSTMAP(1) <b>CONFIGURATION</b> <b>PARAMETERS</b> <b>database</b><i>_</i><b>type</b> - Default output database type. On many UNIX sys- - tems, the default database type is either <b>hash</b> or + Default output database type. On many UNIX sys- + tems, the default database type is either <b>hash</b> or <b>dbm</b>. <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. <b>AUTHOR(S)</b> @@ -170,31 +159,6 @@ POSTMAP(1) POSTMAP(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/postqueue.1.html b/gnu/dist/postfix/html/postqueue.1.html new file mode 100644 index 00000000000..64b005a4567 --- /dev/null +++ b/gnu/dist/postfix/html/postqueue.1.html @@ -0,0 +1,115 @@ +<html> <head> </head> <body> <pre> + +POSTQUEUE(1) POSTQUEUE(1) + +<b>NAME</b> + postqueue - Postfix queue control + +<b>SYNOPSIS</b> + <b>postqueue</b> [<b>-c</b> <i>config_dir</i>] <b>-f</b> + <b>postqueue</b> [<b>-c</b> <i>config_dir</i>] <b>-p</b> + <b>postqueue</b> [<b>-c</b> <i>config_dir</i>] <b>-s</b> <i>site</i> + +<b>DESCRIPTION</b> + The <b>postqueue</b> program implements the Postfix user inter- + face for queue management. It implements all the opera- + tions that are traditionally available via the <a href="sendmail.1.html"><b>sendmail</b>(1)</a> + command. + + The following options are recognized: + + <b>-c</b> <i>config_dir</i> + The <b>main.cf</b> configuration file is in the named + directory instead of the default configuration + directory. See also the MAIL_CONFIG environment + setting below. + + <b>-f</b> Flush the queue: attempt to deliver all queued + mail. + + This option implements the traditional <b>sendmail</b> <b>-q</b> + command, by contacting the Postfix <a href="qmgr.8.html"><b>qmgr</b>(8)</a> daemon. + + <b>-p</b> Produce a traditional sendmail-style queue listing. + + This option implements the traditional <b>mailq</b> com- + mand, by contacting the Postfix <a href="showq.8.html"><b>showq</b>(8)</a> daemon. + + <b>-s</b> <i>site</i> + Schedule immediate delivery of all mail that is + queued for the named <i>site</i>. The site must be eligi- + ble for the "fast flush" service. See <a href="flushd.8.html"><b>flush</b>(8)</a> for + more information about the "fast flush" service. + + This option implements the traditional <b>sendmail</b> + <b>-qR</b><i>site</i> command, by contacting the Postfix <a href="flushd.8.html"><b>flush</b>(8)</a> + daemon. + + <b>-v</b> Enable verbose logging for debugging purposes. Mul- + tiple <b>-v</b> options make the software increasingly + verbose. + +<b>SECURITY</b> + This program is designed to run with set-group ID privi- + leges, so that it can connect to Postfix daemon processes. + +<b>DIAGNOSTICS</b> + Problems are logged to <b>syslogd</b>(8) and to the standard + error stream. + +<b>ENVIRONMENT</b> + MAIL_CONFIG + Directory with the <b>main.cf</b> file. + + In order to avoid exploitation of set-group ID + privileges, it is not possible to specify arbitrary + directory names. + + A non-standard directory is allowed only if the + name is listed in the standard <b>main.cf</b> file, in the + <b>alternate</b><i>_</i><b>config</b><i>_</i><b>directories</b> configuration parame- + ter value. + + Only the super-user is allowed to specify arbitrary + directory names. + +<b>FILES</b> + /var/spool/postfix, mail queue + /etc/postfix, configuration files + +<b>CONFIGURATION</b> <b>PARAMETERS</b> + <b>import</b><i>_</i><b>environment</b> + List of names of environment parameters that can be + imported from non-Postfix processes. + + <b>queue</b><i>_</i><b>directory</b> + Top-level directory of the Postfix queue. This is + also the root directory of Postfix daemons that run + chrooted. + + <b>fast</b><i>_</i><b>flush</b><i>_</i><b>domains</b> + List of domains that will receive "fast flush" ser- + vice (default: all domains that this system is + willing to relay mail to). This list specifies the + domains that Postfix accepts in the SMTP <b>ETRN</b> + request and in the <b>sendmail</b> <b>-qR</b> command. + +<b>SEE</b> <b>ALSO</b> + sendmail(8) sendmail-compatible user interface + <a href="qmgr.8.html">qmgr(8)</a> queue manager + <a href="showq.8.html">showq(8)</a> list mail queue + <a href="flushd.8.html">flush(8)</a> fast flush service + +<b>LICENSE</b> + The Secure Mailer license must be distributed with this + software. + +<b>AUTHOR(S)</b> + Wietse Venema + IBM T.J. Watson Research + P.O. Box 704 + Yorktown Heights, NY 10598, USA + + 1 + +</pre> </body> </html> diff --git a/gnu/dist/postfix/html/postsuper.1.html b/gnu/dist/postfix/html/postsuper.1.html index 15aa92cc5de..d4dbb09a55d 100644 --- a/gnu/dist/postfix/html/postsuper.1.html +++ b/gnu/dist/postfix/html/postsuper.1.html @@ -1,134 +1,140 @@ <html> <head> </head> <body> <pre> - - POSTSUPER(1) POSTSUPER(1) - <b>NAME</b> - postsuper - Postfix super intendent + postsuper - Postfix superintendent <b>SYNOPSIS</b> - <b>postsuper</b> [<b>-p</b>] [<b>-s</b>] [<b>-v</b>] [<i>directory</i> <i>...</i>] + <b>postsuper</b> [<b>-psv</b>] [<b>-d</b> <i>queue_id</i>] [<b>-r</b> <i>queue_id</i>] [<i>directory</i> + <i>...</i>] <b>DESCRIPTION</b> - The <b>postsuper</b> command does small maintenance jobs on the - named Postfix queue directories (default: all). Directory - names are relative to the Postfix top-level queue direc- - tory. + The <b>postsuper</b> command does maintenance jobs on the Postfix + queue. Use of the command is restricted to the super-user. By default, <b>postsuper</b> performs the operations requested - with the <b>-s</b> and <b>-p</b> command-line options. <b>postsuper</b> always - tries to remove objects that are neither files nor direc- - tories. Use of this command is restricted to the super- - user. + with the <b>-s</b> and <b>-p</b> command-line options on all Postfix + queue directories - this includes the <b>incoming</b>, <b>active</b> and + <b>deferred</b> directories with mail files and the <b>bounce</b>, <b>defer</b> + and <b>flush</b> directories with log files. Options: - <b>-s</b> Structure check. Move queue files that are in the - wrong place in the file system hierarchy and remove - subdirectories that are no longer needed. File - rearrangements are necessary after a change in the - <b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b> and/or <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b> configura- - tion parameters. It is highly recommended to run - this check once before Postfix startup. - - <b>-p</b> Purge stale files (files that are left over after - system or software crashes). + <b>-d</b> <i>queue_id</i> + Delete one message with the named queue ID from the + named mail queue(s) (default: <b>incoming</b>, <b>active</b> and + <b>deferred</b>). If a <i>queue_id</i> of <b>-</b> is specified, the + program reads queue IDs from standard input. + + Specify <b>-d</b> <b>ALL</b> to remove all messages; for example, + specify <b>-d</b> <b>ALL</b> <b>deferred</b> to delete mail in the + <b>deferred</b> queue. As a safety measure, the word <b>ALL</b> + must be specified in upper case. + + <b>Postfix</b> <b>queue</b> <b>IDs</b> <b>are</b> <b>reused.</b> <b>There</b> <b>is</b> <b>a</b> <b>very</b> + <b>small</b> <b>possibility</b> <b>that</b> <b>postsuper</b> <b>deletes</b> <b>the</b> <b>wrong</b> + <b>message</b> <b>file</b> <b>when</b> <b>it</b> <b>is</b> <b>executed</b> <b>while</b> <b>the</b> <b>Postfix</b> + <b>mail</b> <b>system</b> <b>is</b> <b>running.</b> + + The scenario is as follows: + + 1) The Postfix queue manager deletes the mes- + sage that <b>postsuper</b> is supposed to delete, + because Postfix is finished with the mes- + sage. + + 2) New mail arrives, and the new message is + given the same queue ID as the message that + <b>postsuper</b> is supposed to delete. The proba- + bility for reusing a deleted queue ID is + about 1 in 2**15 (the number of different + microsecond values that the system clock can + distinguish within a second). + + 3) <b>postsuper</b> deletes the new message, instead + of the old message that it should have + deleted. + + <b>-p</b> Purge old temporary files that are left over after + system or software crashes. + + <b>-r</b> <i>queue_id</i> + Requeue the message with the named queue ID from + the named mail queue(s) (default: <b>incoming</b>, <b>active</b> + and <b>deferred</b>). To requeue multiple messages, spec- + ify multiple <b>-r</b> command-line options. Alterna- + tively, if a <i>queue_id</i> of <b>-</b> is specified, the pro- + gram reads queue IDs from standard input. + + Specify <b>-r</b> <b>ALL</b> to requeue all messages. As a safety + measure, the word <b>ALL</b> must be specified in upper + case. + + A requeued message is moved to the <b>maildrop</b> queue, + from where it is copied by the pickup daemon to a + new file whose name is guaranteed to match the new + queue file inode number. The new queue file is sub- + jected again to mail address rewriting and substi- + tution. This is useful when rewriting rules or vir- + tual mappings have changed. + + Postfix queue IDs are reused. There is a very + small possibility that <b>postsuper</b> requeues the wrong + message file when it is executed while the Postfix + mail system is running, but no harm should be done. + + <b>-s</b> Structure check and structure repair. It is highly + recommended to perform this operation once before + Postfix startup. + + <b>o</b> Rename files whose name does not match the + message file inode number. This operation is + necessary after restoring a mail queue from + a different machine, or from backup media. + + <b>o</b> Move queue files that are in the wrong place + in the file system hierarchy and remove sub- + directories that are no longer needed. File + position rearrangements are necessary after + a change in the <b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b> and/or + <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b> configuration parameters. <b>-v</b> Enable verbose logging for debugging purposes. Mul- - tiple <b>-v</b> options make the software increasingly + tiple <b>-v</b> options make the software increasingly verbose. <b>DIAGNOSTICS</b> - Problems are reported to the standard error stream and to + Problems are reported to the standard error stream and to <b>syslogd</b>. + <b>postsuper</b> reports the number of messages deleted with <b>-d</b>, + the number of messages requeued with <b>-r</b>, and the number of + messages whose queue file name was fixed with <b>-s</b>. The + report is written to the standard error stream and to <b>sys-</b> + <b>logd</b>. + <b>CONFIGURATION</b> <b>PARAMETERS</b> - See the Postfix <b>main.cf</b> file for syntax details and for + See the Postfix <b>main.cf</b> file for syntax details and for default values. <b>hash</b><i>_</i><b>queue</b><i>_</i><b>depth</b> Number of subdirectory levels for hashed queues. <b>hash</b><i>_</i><b>queue</b><i>_</i><b>names</b> - The names of queues that are organized into multi- + The names of queues that are organized into multi- ple levels of subdirectories. <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. - - - - 1 - - - - - -POSTSUPER(1) POSTSUPER(1) - - <b>AUTHOR(S)</b> Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/qmgr.8.html b/gnu/dist/postfix/html/qmgr.8.html index 032e6dfdbc6..6cc03ee15ae 100644 --- a/gnu/dist/postfix/html/qmgr.8.html +++ b/gnu/dist/postfix/html/qmgr.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - QMGR(8) QMGR(8) - <b>NAME</b> qmgr - Postfix queue manager @@ -59,18 +56,6 @@ QMGR(8) QMGR(8) <a href="bounce.8.html"><b>bounce</b>(8)</a> daemon. <b>defer</b> Per-recipient status information about why mail is - - - - 1 - - - - - -QMGR(8) QMGR(8) - - delayed. These files are maintained by the <a href="defer.8.html"><b>defer</b>(8)</a> daemon. @@ -125,18 +110,6 @@ QMGR(8) QMGR(8) <b>D</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>DEFERRED)</b> Start a deferred queue scan. If a deferred queue scan is already in progress, that scan will be - - - - 2 - - - - - -QMGR(8) QMGR(8) - - restarted as soon as it finishes. <b>I</b> <b>(QMGR</b><i>_</i><b>REQ</b><i>_</i><b>SCAN</b><i>_</i><b>INCOMING)</b> @@ -191,18 +164,6 @@ QMGR(8) QMGR(8) sudden burst of inbound mail can negatively impact out- bound delivery rates. - - - - 3 - - - - - -QMGR(8) QMGR(8) - - <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 @@ -256,19 +217,6 @@ QMGR(8) QMGR(8) Time in seconds between attempts to contact a bro- ken delivery transport. - - - - - 4 - - - - - -QMGR(8) QMGR(8) - - <b>Concurrency</b> <b>controls</b> In the text below, <i>transport</i> is the first field in a <b>mas-</b> <b>ter.cf</b> entry. @@ -323,18 +271,6 @@ QMGR(8) QMGR(8) Limit on the number of recipients per message transfer, for the named message <i>transport</i>. - - - - 5 - - - - - -QMGR(8) QMGR(8) - - <b>SEE</b> <b>ALSO</b> <a href="master.8.html">master(8)</a>, process manager <a href="relocated.5.html">relocated(5)</a>, format of the "user has moved" table @@ -351,48 +287,6 @@ QMGR(8) QMGR(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/qmqpd.8.html b/gnu/dist/postfix/html/qmqpd.8.html new file mode 100644 index 00000000000..5d5792ef300 --- /dev/null +++ b/gnu/dist/postfix/html/qmqpd.8.html @@ -0,0 +1,122 @@ +<html> <head> </head> <body> <pre> + +QMQPD(8) QMQPD(8) + +<b>NAME</b> + qmqpd - Postfix QMQP server + +<b>SYNOPSIS</b> + <b>qmqpd</b> [generic Postfix daemon options] + +<b>DESCRIPTION</b> + The Postfix QMQP server receives one message per connec- + tion. Each message is piped through the <a href="cleanup.8.html"><b>cleanup</b>(8)</a> dae- + mon, and is placed into the <b>incoming</b> queue as one single + queue file. The program expects to be run from the <a href="master.8.html"><b>mas-</b></a> + <a href="master.8.html"><b>ter</b>(8)</a> process manager. + + The QMQP server implements one access policy: only explic- + itly authorized client hosts are allowed to use the ser- + vice. + +<b>SECURITY</b> + The QMQP server is moderately security-sensitive. It talks + to QMQP clients and to DNS servers on the network. The + QMQP server can be run chrooted at fixed low privilege. + +<b>DIAGNOSTICS</b> + Problems and transactions are logged to <b>syslogd</b>(8). + +<b>BUGS</b> + The QMQP protocol provides only one server reply per mes- + sage delivery. It is therefore not possible to reject + individual recipients. + + The QMQP protocol requires the server to receive the + entire message before replying. If a message is malformed, + or if any netstring component is longer than acceptable, + Postfix replies immediately and closes the connection. It + is left up to the client to handle the situation. + +<b>CONFIGURATION</b> <b>PARAMETERS</b> + The following <b>main.cf</b> parameters are especially relevant + to this program. See the Postfix <b>main.cf</b> file for syntax + details and for default values. Use the <b>postfix</b> <b>reload</b> + command after a configuration change. + +<b>Miscellaneous</b> + <b>always</b><i>_</i><b>bcc</b> + Address to send a copy of each message that enters + the system. + + <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> + Increment in verbose logging level when a remote + host matches a pattern in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> + parameter. + + <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> + List of domain or network patterns. When a remote + host matches a pattern, increase the verbose log- + ging level by the amount specified in the + <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter. + + <b>hopcount</b><i>_</i><b>limit</b> + Limit the number of <b>Received:</b> message headers. + + <b>qmqpd</b><i>_</i><b>authorized</b><i>_</i><b>clients</b> + A list of domain or network patterns that specifies + what clients are allowed to use the service. + + <b>qmqpd</b><i>_</i><b>timeout</b> + Limit the time to send a server response and to + receive a client request. + + <b>soft</b><i>_</i><b>bounce</b> + Change hard (D) reject responses into soft (Z) + reject responses. This can be useful for testing + purposes. + +<b>Content</b> <b>inspection</b> <b>controls</b> + <b>content</b><i>_</i><b>filter</b> + The name of a mail delivery transport that filters + mail and that either bounces mail or re-injects the + result back into Postfix. This parameter uses the + same syntax as the right-hand side of a Postfix + transport table. + +<b>Resource</b> <b>controls</b> + <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b> + Limit the amount of memory in bytes used for the + handling of partial input lines, and the length of + sender and recipient addresses that are received + from client. + + <b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b> + Limit the total size in bytes of a message, includ- + ing on-disk storage for sender and recipient + address information. + +<b>Tarpitting</b> + <b>qmqpd</b><i>_</i><b>error</b><i>_</i><b>sleep</b><i>_</i><b>time</b> + Time to wait in seconds before informing the client + of a problem. This slows down run-away errors. + +<b>SEE</b> <b>ALSO</b> + <a href="http://cr.yp.to/proto/qmqp.html">http://cr.yp.to/proto/qmqp.html</a>, QMQP protocol + <a href="cleanup.8.html">cleanup(8)</a> message canonicalization + <a href="master.8.html">master(8)</a> process manager + syslogd(8) system logging + +<b>LICENSE</b> + The Secure Mailer license must be distributed with this + software. + +<b>AUTHOR(S)</b> + Wietse Venema + IBM T.J. Watson Research + P.O. Box 704 + Yorktown Heights, NY 10598, USA + + 1 + +</pre> </body> </html> diff --git a/gnu/dist/postfix/html/receiving.html b/gnu/dist/postfix/html/receiving.html index 5168e643448..62318562ef2 100644 --- a/gnu/dist/postfix/html/receiving.html +++ b/gnu/dist/postfix/html/receiving.html @@ -39,13 +39,12 @@ left-hand corner of this page. <ul> <li>Mail is posted locally. The Postfix <a -href="sendmail.1.html">sendmail</a> program deposits the message -into the world-writable <b>maildrop</b> directory, where the message -is picked up by the <a href="pickup.8.html">pickup</a> daemon. -This daemon does some sanity checks, in order to protect the rest -of the Postfix system. In order to avoid accidents, the directory -permissions on the <b>maildrop</b> directory must be such that a -user cannot delete someone elses mail. +href="sendmail.1.html">sendmail</a> program invokes the privileged +<a href="postdrop.1.html">postdrop</a> program which deposits the +message into the <b>maildrop</b> directory, where the message is +picked up by the <a href="pickup.8.html">pickup</a> daemon. This +daemon does some sanity checks, in order to protect the rest of +the Postfix system. <p> diff --git a/gnu/dist/postfix/html/regexp_table.5.html b/gnu/dist/postfix/html/regexp_table.5.html index 3487c922c6b..704b8abc3d4 100644 --- a/gnu/dist/postfix/html/regexp_table.5.html +++ b/gnu/dist/postfix/html/regexp_table.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - REGEXP_TABLE(5) REGEXP_TABLE(5) - <b>NAME</b> regexp_table - format of Postfix regular expression tables @@ -22,18 +19,19 @@ REGEXP_TABLE(5) REGEXP_TABLE(5) The general form of a Postfix regular expression table is: - blanks and comments - Blank lines are ignored, as are lines beginning - with `#'. - - leading whitespace - Lines that begin with whitespace continue the pre- - vious line. - <i>pattern</i> <i>result</i> When <i>pattern</i> matches a search string, use the cor- - responding <i>result</i>. A line that starts with white - space continues the preceding line. + responding <i>result</i>. + + blank lines and comments + Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + multi-line text + A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. <i>pattern1!pattern2</i> <i>result</i> Matches <i>pattern1</i> but not <i>pattern2</i>. @@ -41,55 +39,48 @@ REGEXP_TABLE(5) REGEXP_TABLE(5) Each pattern is a regular expression enclosed by a pair of delimiters. The regular expression syntax is described in <i>re_format</i>(7). The expression delimiter can be any charac- - ter, except whitespace or characters that have special - meaning (traditionally the forward slash is used). The + ter, except whitespace or characters that have special + meaning (traditionally the forward slash is used). The regular expression can contain whitespace. By default, matching is case-insensitive, although follow- - ing the second slash with an `i' flag will reverse this. - Other flags are `x' (disable extended expression syntax), + ing the second slash with an `i' flag will reverse this. + Other flags are `x' (disable extended expression syntax), and `m' (enable multi-line mode). - Each pattern is applied to the entire lookup key string. - Depending on the application, that string is an entire + Each pattern is applied to the entire lookup key string. + Depending on the application, that string is an entire client hostname, an entire client IP address, or an entire - mail address. Thus, no parent domain or parent network - search is done, and <i>user@domain</i> mail addresses are not - broken up into their <i>user</i> and <i>domain</i> constituent parts, + mail address. Thus, no parent domain or parent network + search is done, and <i>user@domain</i> mail addresses are not + broken up into their <i>user</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken up into <i>user</i> and <i>foo</i>. - Patterns are applied in the order as specified in the - - - - 1 - - - - - -REGEXP_TABLE(5) REGEXP_TABLE(5) - - - table, until a pattern is found that matches the search + Patterns are applied in the order as specified in the + table, until a pattern is found that matches the search string. - Substitution of substrings from the matched expression + Substitution of substrings from the matched expression into the result string is possible using $1, $2, etc.. The macros in the result string may need to be written as ${n} or $(n) if they aren't followed by whitespace. -<b>EXAMPLES</b> +<b>EXAMPLE</b> <b>SMTPD</b> <b>ACCESS</b> <b>MAP</b> # Disallow sender-specified routing. This is a must if you relay mail # for other domains. - /[%!@].*[%!@]/ 550 Sender-specified routing rejected + /[%!@].*[%!@]/ 550 Sender-specified routing rejected # Postmaster is OK, that way they can talk to us about how to fix # their problem. - /^postmaster@.*$/ OK + /^postmaster@/ OK # Protect your outgoing majordomo exploders - /^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead + /^(.*)-outgoing@(.*)$/!/^owner-/ 550 Use ${1}@${2} instead + +<b>EXAMPLE</b> <b>HEADER</b> <b>FILTER</b> <b>MAP</b> + # These were once common in junk mail. + /^Subject: make money fast/ REJECT + /^To: friend@public\.com/ REJECT <b>SEE</b> <b>ALSO</b> <a href="pcre_table.5.html">pcre_table(5)</a> format of PCRE tables @@ -112,23 +103,6 @@ REGEXP_TABLE(5) REGEXP_TABLE(5) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/relocated.5.html b/gnu/dist/postfix/html/relocated.5.html index d25a045978e..5ad6c76fcb7 100644 --- a/gnu/dist/postfix/html/relocated.5.html +++ b/gnu/dist/postfix/html/relocated.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - RELOCATED(5) RELOCATED(5) - <b>NAME</b> relocated - format of Postfix relocated table @@ -37,18 +34,20 @@ RELOCATED(5) RELOCATED(5) <b>TABLE</b> <b>FORMAT</b> The format of the table is as follows: - <b>o</b> Blank lines are ignored, as are lines beginning - with `#'. - - <b>o</b> Lines that begin with whitespace continue the pre- - vious line. - <b>o</b> An entry has one of the following form: <i>key</i> <i>new_location</i> Where <i>new_location</i> specifies contact information such as an email address, or perhaps a street address or telephone number. + <b>o</b> Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + <b>o</b> A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. + With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, the <i>key</i> field is one of the following: @@ -59,18 +58,6 @@ RELOCATED(5) RELOCATED(5) <i>user</i> Matches <i>user</i>@<i>site</i> when <i>site</i> is $<b>myorigin</b>, when <i>site</i> is listed in $<b>mydestination</b>, or when <i>site</i> is listed - - - - 1 - - - - - -RELOCATED(5) RELOCATED(5) - - in $<b>inet</b><i>_</i><b>interfaces</b>. @<i>domain</i> @@ -78,10 +65,10 @@ RELOCATED(5) RELOCATED(5) lowest precedence. <b>ADDRESS</b> <b>EXTENSION</b> - When the search fails, and the address localpart contains - the optional recipient delimiter (e.g., <i>user+foo</i>@<i>domain</i>), - the search is repeated for the unextended address (e.g. - <i>user</i>@<i>domain</i>). + When a mail address localpart contains the optional recip- + ient delimiter (e.g., <i>user+foo</i>@<i>domain</i>), the lookup order + becomes: <i>user+foo</i>@<i>domain</i>, <i>user</i>@<i>domain</i>, <i>user+foo</i>, <i>user</i>, and + @<i>domain</i>. <b>REGULAR</b> <b>EXPRESSION</b> <b>TABLES</b> This section describes how the table lookups change when @@ -99,17 +86,17 @@ RELOCATED(5) RELOCATED(5) table, until a pattern is found that matches the search string. - Results are the same as with normal indexed file lookups, - with the additional feature that parenthesized substrings - from the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. + Results are the same as with indexed file lookups, with + the additional feature that parenthesized substrings from + the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. <b>BUGS</b> - The table format does not understand quoting conventions. + The table format does not understand quoting conventions. <b>CONFIGURATION</b> <b>PARAMETERS</b> - The following <b>main.cf</b> parameters are especially relevant - to this topic. 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 topic. 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>relocated</b><i>_</i><b>maps</b> @@ -118,25 +105,13 @@ RELOCATED(5) RELOCATED(5) Other parameters of interest: <b>inet</b><i>_</i><b>interfaces</b> - The network interface addresses that this system + The network interface addresses that this system receives mail on. <b>mydestination</b> - List of domains that this mail system considers + List of domains that this mail system considers local. - - - - 2 - - - - - -RELOCATED(5) RELOCATED(5) - - <b>myorigin</b> The domain that is appended to locally-posted mail. @@ -146,7 +121,7 @@ RELOCATED(5) RELOCATED(5) <a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables <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> @@ -155,46 +130,6 @@ RELOCATED(5) RELOCATED(5) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/rewrite.html b/gnu/dist/postfix/html/rewrite.html index fae9e4a48e3..0d87a8a5a4e 100644 --- a/gnu/dist/postfix/html/rewrite.html +++ b/gnu/dist/postfix/html/rewrite.html @@ -226,7 +226,7 @@ send mail to the those ugly address without creating a mailer loop. <a name="masquerade"> <h2> Address masquerading</h2> -Address masquerading is a method to hide all hosts below a domain +Address masquerading is a method to hide all hosts inside a domain behind their mail gateway, and to make it appear as if the mail comes from the gateway itself, instead of from individual machines. @@ -263,12 +263,32 @@ For example, <p> - By default, Postfix makes no exceptions. + +<p> + +Subtle point: by default, address masquerading is applied only to +message headers and to envelope sender addresses, but not to envelope +recipients. This allows you to use address masquerading on a mail +gateway machine, while still being able to forward mail from outside +to users on individual machines. + +<p> + +In order to subject envelope recipient addresses to masquerading, +too, specify (only available with Postfix versions after 20010802): + +<dl> + +<dd><b>masquerade_classes = envelope_sender, envelope_recipient, +header_sender, header_recipient</b> + +</dl> + <p> -Subtle point: address masquerading is applied only to message -headers and envelope sender addresses, not to envelope recipients. +If you do this, Postfix will no longer be able to send mail to +individual machines. <a name="virtual"> <h2> Virtual address mapping</h2> diff --git a/gnu/dist/postfix/html/security.html b/gnu/dist/postfix/html/security.html index 0619ef51e7c..c3264f175fe 100644 --- a/gnu/dist/postfix/html/security.html +++ b/gnu/dist/postfix/html/security.html @@ -79,11 +79,11 @@ per-process file system name spaces. <p> -By default, the <b>maildrop</b> queue directory is world-writable, -so that local processes can submit mail without assistance from a -set-uid or set-gid command or from a mail daemon process. The -maildrop directory is not used for mail coming in via the network, -and queue files are not readable for other users. +Initially, the <b>maildrop</b> queue directory was world-writable, +so that local processes could submit mail without assistance from +a set-uid or set-gid command or from a mail daemon process. The +maildrop directory was not used for mail coming in via the network, +and its queue files were not readable for unprivileged users. <p> @@ -99,10 +99,9 @@ Postfix queue file. <p> -If a world-writable <b>maildrop</b> directory is not acceptable, -sites can revoke world write permission, and enable <b>set-gid</b> -privileges for a small helper program that is provided for this -purpose. +Because of the potential for misbehavior, Postfix has abandoned +the world-writable <b>maildrop</b> directory, and uses a small +set-gid <b>postdrop</b> helper program for mail submission. <h2>Trust</h2> diff --git a/gnu/dist/postfix/html/sendmail.1.html b/gnu/dist/postfix/html/sendmail.1.html index 43b48ba1426..fba1afd8fa0 100644 --- a/gnu/dist/postfix/html/sendmail.1.html +++ b/gnu/dist/postfix/html/sendmail.1.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - SENDMAIL(1) SENDMAIL(1) - <b>NAME</b> sendmail - Postfix to Sendmail compatibility interface @@ -25,11 +22,9 @@ SENDMAIL(1) SENDMAIL(1) By default, <b>sendmail</b> reads a message from standard input until EOF or until it reads a line with only a <b>.</b> charac- - ter, and arranges for delivery. <b>sendmail</b> attempts to cre- - ate a queue file in the <b>maildrop</b> directory. If that direc- - tory is not world-writable, the message is piped through - the <a href="postdrop.1.html"><b>postdrop</b>(1)</a> command, which is expected to execute with - suitable privileges. + ter, and arranges for delivery. <b>sendmail</b> relies on the + <a href="postdrop.1.html"><b>postdrop</b>(1)</a> command to create a queue file in the <b>maildrop</b> + directory. Specific command aliases are provided for other common modes of operation: @@ -39,18 +34,18 @@ SENDMAIL(1) SENDMAIL(1) the recipients that still need to be delivered. If mail could not be delivered upon the last attempt, the reason for failure is shown. This mode of oper- - ation is implemented by connecting to the <a href="showq.8.html"><b>showq</b>(8)</a> - daemon. + ation is implemented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> + command. <b>newaliases</b> - Initialize the alias database. If no alias database - type is specified, the program uses the type speci- - fied in the <b>database</b><i>_</i><b>type</b> configuration parameter; - if no input file is specified, the program pro- - cesses the file(s) specified with the - <b>alias</b><i>_</i><b>database</b> configuration parameter. This mode - of operation is implemented by running the <b>postal-</b> - <b>ias</b>(1) command. + Initialize the alias database. If no input file is + specified (with the <b>-oA</b> option, see below), the + program processes the file(s) specified with the + <b>alias</b><i>_</i><b>database</b> configuration parameter. If no + alias database type is specified, the program uses + the type specified with the <b>database</b><i>_</i><b>type</b> configu- + ration parameter. This mode of operation is imple- + mented by running the <a href="postalias.1.html"><b>postalias</b>(1)</a> command. Note: it may take a minute or so before an alias database update becomes visible. Use the <b>postfix</b> @@ -58,20 +53,8 @@ SENDMAIL(1) SENDMAIL(1) These and other features can be selected by specifying the appropriate combination of command-line options. Some fea- - tures are controlled by parameters in the <b>main.cf</b> - - - - 1 - - - - - -SENDMAIL(1) SENDMAIL(1) - - - configuration file. + tures are controlled by parameters in the <b>main.cf</b> configu- + ration file. The following options are recognized: @@ -94,60 +77,68 @@ SENDMAIL(1) SENDMAIL(1) <b>-I</b> Initialize alias database. See the <b>newaliases</b> com- mand above. + <b>-L</b> <i>label</i> (ignored) + The logging label. Use the <b>syslog</b><i>_</i><b>name</b> configura- + tion parameter instead. + <b>-N</b> <i>dsn</i> (ignored) - Delivery status notification control. Currently, + Delivery status notification control. Currently, Postfix does not implement <b>DSN</b>. <b>-R</b> <i>return_limit</i> (ignored) - Limit the size of bounced mail. Use the - <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b> configuration parameter instead. + Limit the size of bounced mail. Use the + <b>bounce</b><i>_</i><b>size</b><i>_</i><b>limit</b> configuration parameter instead. <b>-X</b> <i>log_file</i> (ignored) - Log mailer traffic. Use the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> and - <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> configuration parameters instead. + Log mailer traffic. Use the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>list</b> and + <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> configuration parameters instead. <b>-U</b> (ignored) Initial user submission. - <b>-bd</b> Go into daemon mode. This mode of operation is + <b>-V</b> Variable Envelope Return Path. Given an envelope + sender address of the form <i>owner-listname</i>@<i>origin</i>, + each recipient <i>user</i>@<i>domain</i> receives mail with a + personalized envelope sender address. + + By default, the personalized envelope sender + address is <i>owner-listname</i><b>+</b><i>user</i><b>=</b><i>domain</i>@<i>origin</i>. The + default <b>+</b> and <b>=</b> characters are configurable with + the <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> configuration parame- + ter. + + <b>-V</b><i>xy</i> As <b>-V</b>, but uses <i>x</i> and <i>y</i> as the VERP delimiter char- + acters, instead of the characters specified with + the <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> configuration parame- + ter. + + <b>-bd</b> Go into daemon mode. This mode of operation is implemented by executing the <b>postfix</b> <b>start</b> command. - <b>-bi</b> Initialize alias database. See the <b>newaliases</b> com- + <b>-bi</b> Initialize alias database. See the <b>newaliases</b> com- mand above. - <b>-bm</b> Read mail from standard input and arrange for + <b>-bm</b> Read mail from standard input and arrange for delivery. This is the default mode of operation. <b>-bp</b> List the mail queue. See the <b>mailq</b> command above. - <b>-bs</b> Stand-alone SMTP server mode. Read SMTP commands - from standard input, and write responses to stan- + <b>-bs</b> Stand-alone SMTP server mode. Read SMTP commands + from standard input, and write responses to stan- dard output. This mode of operation is implemented by running the <a href="smtpd.8.html"><b>smtpd</b>(8)</a> daemon. - - - - 2 - - - - - -SENDMAIL(1) SENDMAIL(1) - - <b>-f</b> <i>sender</i> Set the envelope sender address. This is the address where delivery problems are sent to, unless - the message contains an <b>Errors-To:</b> message header. + the message contains an <b>Errors-To:</b> message header. <b>-h</b> <i>hop_count</i> (ignored) - Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura- + Hop count limit. Use the <b>hopcount</b><i>_</i><b>limit</b> configura- tion parameter instead. - <b>-i</b> When reading a message from standard input, don't - treat a line with only a <b>.</b> character as the end of + <b>-i</b> When reading a message from standard input, don't + treat a line with only a <b>.</b> character as the end of input. <b>-m</b> (ignored) @@ -157,60 +148,46 @@ SENDMAIL(1) SENDMAIL(1) Backwards compatibility. <b>-oA</b><i>alias_database</i> - Non-default alias database. Specify <i>pathname</i> or + Non-default alias database. Specify <i>pathname</i> or <i>type</i>:<i>pathname</i>. See <a href="postalias.1.html"><b>postalias</b>(1)</a> for details. <b>-o7</b> (ignored) <b>-o8</b> (ignored) - The message body type. Currently, Postfix imple- + The message body type. Currently, Postfix imple- ments <b>just-send-eight</b>. - <b>-oi</b> When reading a message from standard input, don't - treat a line with only a <b>.</b> character as the end of + <b>-oi</b> When reading a message from standard input, don't + treat a line with only a <b>.</b> character as the end of input. <b>-om</b> (ignored) - The sender is never eliminated from alias etc. + The sender is never eliminated from alias etc. expansions. <b>-o</b> <i>x</i> <i>value</i> (ignored) - Set option <i>x</i> to <i>value</i>. Use the equivalent configu- + Set option <i>x</i> to <i>value</i>. Use the equivalent configu- ration parameter in <b>main.cf</b> instead. <b>-r</b> <i>sender</i> Set the envelope sender address. This is the address where delivery problems are sent to, unless - the message contains an <b>Errors-To:</b> message header. + the message contains an <b>Errors-To:</b> message header. - <b>-q</b> Attempt to deliver all queued mail. This is imple- - mented by kicking the <a href="qmgr.8.html"><b>qmgr</b>(8)</a> daemon. + <b>-q</b> Attempt to deliver all queued mail. This is imple- + mented by executing the <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command. <b>-q</b><i>interval</i> (ignored) - The interval between queue runs. Use the + The interval between queue runs. Use the <b>queue</b><i>_</i><b>run</b><i>_</i><b>delay</b> configuration parameter instead. - - - - - 3 - - - - - -SENDMAIL(1) SENDMAIL(1) - - <b>-qR</b><i>site</i> - Schedule immediate delivery of all mail that is - queued for the named <i>site</i>. Depending on the desti- - nation, this uses "fast flush" service, or it has - the same effect as <b>sendmail</b> <b>-q</b>. This is imple- - mented by connecting to the local SMTP server. See - <a href="smtpd.8.html"><b>smtpd</b>(8)</a> for more information about the "fast - flush" service. + Schedule immediate delivery of all mail that is + queued for the named <i>site</i>. This option accepts only + <i>site</i> names that are eligible for the "fast flush" + service, and is implemented by executing the + <a href="postqueue.1.html"><b>postqueue</b>(1)</a> command. See <a href="flushd.8.html"><b>flush</b>(8)</a> for more infor- + mation about the "fast flush" service. <b>-qS</b><i>site</i> This command is not implemented. Use the slower @@ -257,18 +234,6 @@ SENDMAIL(1) SENDMAIL(1) <b>alias</b><i>_</i><b>database</b> Default alias database(s) for <b>newaliases</b>. The - - - - 4 - - - - - -SENDMAIL(1) SENDMAIL(1) - - default value for this parameter is system-spe- cific. @@ -295,14 +260,17 @@ SENDMAIL(1) SENDMAIL(1) ging level by the amount specified in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter. + <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> + The VERP delimiter characters that are used when + the <b>-V</b> command line option is specified without + delimiter characters. + <b>fast</b><i>_</i><b>flush</b><i>_</i><b>domains</b> List of domains that will receive "fast flush" ser- vice (default: all domains that this system is - willing to relay mail to). This greatly improves - the performance of the SMTP <b>ETRN</b> request, and of - the <b>sendmail</b> <b>-qR</b> command. For domains not in the - list, Postfix simply attempts to deliver all queued - mail. + willing to relay mail to). This list specifies the + domains that Postfix accepts in the SMTP <b>ETRN</b> + request and in the <b>sendmail</b> <b>-qR</b> command. <b>fork</b><i>_</i><b>attempts</b> Number of attempts to <b>fork</b>() a process before giv- @@ -323,18 +291,6 @@ SENDMAIL(1) SENDMAIL(1) Directory with Postfix support commands (default: <b>$program</b><i>_</i><b>directory</b>). - - - - 5 - - - - - -SENDMAIL(1) SENDMAIL(1) - - <b>daemon</b><i>_</i><b>directory</b> Directory with Postfix daemon programs (default: <b>$program</b><i>_</i><b>directory</b>). @@ -348,20 +304,23 @@ SENDMAIL(1) SENDMAIL(1) The time between successive scans of the deferred queue. + <b>verp</b><i>_</i><b>delimiter</b><i>_</i><b>filter</b> + The characters that Postfix accepts as VERP delim- + iter characters. + <b>SEE</b> <b>ALSO</b> <a href="pickup.8.html">pickup(8)</a> mail pickup daemon <a href="postalias.1.html">postalias(1)</a> maintain alias database - <a href="postdrop.1.html">postdrop(1)</a> privileged posting agent + <a href="postdrop.1.html">postdrop(1)</a> mail posting utility <a href="postfix.1.html">postfix(1)</a> mail system control - <a href="postkick.1.html">postkick(1)</a> kick a Postfix daemon + <a href="postqueue.1.html">postqueue(1)</a> mail queue control <a href="qmgr.8.html">qmgr(8)</a> queue manager - <a href="showq.8.html">showq(8)</a> list mail queue <a href="smtpd.8.html">smtpd(8)</a> SMTP server - flushd(8) fast flush service + <a href="flushd.8.html">flush(8)</a> fast flush service syslogd(8) system logging <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. <b>AUTHOR(S)</b> @@ -370,29 +329,6 @@ SENDMAIL(1) SENDMAIL(1) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - 6 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/showq.8.html b/gnu/dist/postfix/html/showq.8.html index 5b266e7c2f6..cec8cf9f1b8 100644 --- a/gnu/dist/postfix/html/showq.8.html +++ b/gnu/dist/postfix/html/showq.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - SHOWQ(8) SHOWQ(8) - <b>NAME</b> showq - list the Postfix mail queue @@ -54,15 +51,6 @@ SHOWQ(8) SHOWQ(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - 1 - </pre> </body> </html> diff --git a/gnu/dist/postfix/html/smtp.8.html b/gnu/dist/postfix/html/smtp.8.html index b493e7090e4..0e166ab1b5a 100644 --- a/gnu/dist/postfix/html/smtp.8.html +++ b/gnu/dist/postfix/html/smtp.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - SMTP(8) SMTP(8) - <b>NAME</b> smtp - Postfix remote delivery via SMTP @@ -50,6 +47,7 @@ SMTP(8) SMTP(8) <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration) <a href="http://www.faqs.org/rfcs/rfc2197.html">RFC 2197</a> (Pipelining) <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command) + <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol) <b>DIAGNOSTICS</b> Problems and transactions are logged to <b>syslogd</b>(8). Cor- @@ -60,17 +58,6 @@ SMTP(8) SMTP(8) the postmaster is notified of bounces, protocol problems, and of other trouble. - - - 1 - - - - - -SMTP(8) SMTP(8) - - <b>BUGS</b> <b>CONFIGURATION</b> <b>PARAMETERS</b> The following <b>main.cf</b> parameters are especially relevant @@ -124,38 +111,40 @@ SMTP(8) SMTP(8) send mail to the postmaster with transcripts of SMTP sessions with protocol errors. - - - - - 2 - - - - - -SMTP(8) SMTP(8) - - <b>smtp</b><i>_</i><b>always</b><i>_</i><b>send</b><i>_</i><b>ehlo</b> Always send EHLO at the start of a connection. <b>smtp</b><i>_</i><b>never</b><i>_</i><b>send</b><i>_</i><b>ehlo</b> Never send EHLO at the start of a connection. + <b>smtp</b><i>_</i><b>bind</b><i>_</i><b>address</b> + Numerical source network address to bind to when + making a connection. + + <b>smtp</b><i>_</i><b>break</b><i>_</i><b>lines</b> + Break lines > <b>$line</b><i>_</i><b>length</b><i>_</i><b>limit</b> into multiple + shorter lines. Some SMTP servers misbehave on long + lines. + <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>4xx</b><i>_</i><b>greeting</b> - Skip servers that greet us with a 4xx status code. + Skip servers that greet us with a 4xx status code. <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>5xx</b><i>_</i><b>greeting</b> - Skip servers that greet us with a 5xx status code. + Skip servers that greet us with a 5xx status code. <b>smtp</b><i>_</i><b>skip</b><i>_</i><b>quit</b><i>_</i><b>response</b> - Do not wait for the server response after sending + Do not wait for the server response after sending QUIT. - <b>smtp</b><i>_</i><b>bind</b><i>_</i><b>address</b> - Numerical network address to bind to when making a - connection. + <b>smtp</b><i>_</i><b>pix</b><i>_</i><b>workaround</b><i>_</i><b>delay</b><i>_</i><b>time</b> + The time to pause before sending .<CR><LF>, while + working around the CISCO PIX firewall + <CR><LF>.<CR><LF> bug. + + <b>smtp</b><i>_</i><b>pix</b><i>_</i><b>workaround</b><i>_</i><b>threshold</b><i>_</i><b>time</b> + The time a message must be queued before the CISCO + PIX firewall <CR><LF>.<CR><LF> bug workaround is + turned on. <b>Authentication</b> <b>controls</b> <b>smtp</b><i>_</i><b>enable</b><i>_</i><b>sasl</b><i>_</i><b>auth</b> @@ -192,17 +181,6 @@ SMTP(8) SMTP(8) destination. The default limit is taken from the <b>default</b><i>_</i><b>destination</b><i>_</i><b>concurrency</b><i>_</i><b>limit</b> parameter. - - - 3 - - - - - -SMTP(8) SMTP(8) - - <b>smtp</b><i>_</i><b>destination</b><i>_</i><b>recipient</b><i>_</i><b>limit</b> Limit the number of recipients per message deliv- ery. The default limit is taken from the @@ -256,19 +234,6 @@ SMTP(8) SMTP(8) Timeout for sending the <b>QUIT</b> command, and for receiving the server response. - - - - - 4 - - - - - -SMTP(8) SMTP(8) - - <b>SEE</b> <b>ALSO</b> <a href="bounce.8.html">bounce(8)</a> non-delivery status reports <a href="master.8.html">master(8)</a> process manager @@ -285,48 +250,6 @@ SMTP(8) SMTP(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/smtpd.8.html b/gnu/dist/postfix/html/smtpd.8.html index 0e96e6860a5..a579778b107 100644 --- a/gnu/dist/postfix/html/smtpd.8.html +++ b/gnu/dist/postfix/html/smtpd.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - SMTPD(8) SMTPD(8) - <b>NAME</b> smtpd - Postfix SMTP server @@ -38,12 +35,13 @@ SMTPD(8) SMTPD(8) <b>STANDARDS</b> <a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> (SMTP protocol) <a href="http://www.faqs.org/rfcs/rfc1123.html">RFC 1123</a> (Host requirements) - <a href="http://www.faqs.org/rfcs/rfc1651.html">RFC 1651</a> (SMTP service extensions) <a href="http://www.faqs.org/rfcs/rfc1652.html">RFC 1652</a> (8bit-MIME transport) + <a href="http://www.faqs.org/rfcs/rfc1869.html">RFC 1869</a> (SMTP service extensions) <a href="http://www.faqs.org/rfcs/rfc1854.html">RFC 1854</a> (SMTP Pipelining) <a href="http://www.faqs.org/rfcs/rfc1870.html">RFC 1870</a> (Message Size Declaration) <a href="http://www.faqs.org/rfcs/rfc1985.html">RFC 1985</a> (ETRN command) <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> (AUTH command) + <a href="http://www.faqs.org/rfcs/rfc2821.html">RFC 2821</a> (SMTP protocol) <b>DIAGNOSTICS</b> Problems and transactions are logged to <b>syslogd</b>(8). @@ -58,42 +56,35 @@ SMTPD(8) SMTPD(8) details and for default values. Use the <b>postfix</b> <b>reload</b> command after a configuration change. - - - - - 1 - - - - - -SMTPD(8) SMTPD(8) - - <b>Compatibility</b> <b>controls</b> <b>strict</b><i>_</i><b>rfc821</b><i>_</i><b>envelopes</b> - Disallow non-<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> style addresses in envelopes. - For example, allow <a href="http://www.faqs.org/rfcs/rfc822.html">RFC822</a>-style address forms with - comments, like Sendmail does. + Disallow non-<a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a> style addresses in SMTP com- + mands. For example, the RFC822-style address forms + with comments that Sendmail allows. <b>broken</b><i>_</i><b>sasl</b><i>_</i><b>auth</b><i>_</i><b>clients</b> Support older Microsoft clients that mis-implement the AUTH protocol, and that expect an EHLO response of "250 AUTH=list" instead of "250 AUTH list". + <b>smtpd</b><i>_</i><b>noop</b><i>_</i><b>commands</b> + List of commands that are treated as NOOP (no oper- + ation) commands, without any parameter syntax + checking and without any state change. This list + overrides built-in command definitions. + <b>Content</b> <b>inspection</b> <b>controls</b> <b>content</b><i>_</i><b>filter</b> - The name of a mail delivery transport that filters + The name of a mail delivery transport that filters mail and that either bounces mail or re-injects the - result back into Postfix. This parameter uses the - same syntax as the right-hand side of a Postfix + result back into Postfix. This parameter uses the + same syntax as the right-hand side of a Postfix transport table. <b>Authentication</b> <b>controls</b> <b>enable</b><i>_</i><b>sasl</b><i>_</i><b>authentication</b> - Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> - (SASL). This functionality is available only when + Enable per-session authentication as per <a href="http://www.faqs.org/rfcs/rfc2554.html">RFC 2554</a> + (SASL). This functionality is available only when explicitly selected at program build time and explicitly enabled at runtime. @@ -118,6 +109,12 @@ SMTPD(8) SMTPD(8) <b>noanonymous</b> Disallow anonymous logins. + <b>smtpd</b><i>_</i><b>sender</b><i>_</i><b>login</b><i>_</i><b>maps</b> + Maps that specify the SASL login name that owns a + MAIL FROM sender address. Used by the + <b>reject</b><i>_</i><b>sender</b><i>_</i><b>login</b><i>_</i><b>mismatch</b> sender anti-spoofing + restriction. + <b>Miscellaneous</b> <b>always</b><i>_</i><b>bcc</b> Address to send a copy of each message that enters @@ -125,18 +122,6 @@ SMTPD(8) SMTPD(8) <b>command</b><i>_</i><b>directory</b> Location of Postfix support commands (default: - - - - 2 - - - - - -SMTPD(8) SMTPD(8) - - <b>$program</b><i>_</i><b>directory</b>). <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> @@ -150,6 +135,11 @@ SMTPD(8) SMTPD(8) ging level by the amount specified in the <b>debug</b><i>_</i><b>peer</b><i>_</i><b>level</b> parameter. + <b>default</b><i>_</i><b>verp</b><i>_</i><b>delimiters</b> + The default VERP delimiter characters that are used + when the XVERP command is specified without + explicit delimiters. + <b>error</b><i>_</i><b>notice</b><i>_</i><b>recipient</b> Recipient of protocol/policy/resource/software error notices. @@ -191,23 +181,15 @@ SMTPD(8) SMTPD(8) <b>soft</b><i>_</i><b>bounce</b> Change hard (5xx) reject responses into soft (4xx) reject responses. This can be useful for testing - - - - 3 - - - - - -SMTPD(8) SMTPD(8) - - purposes. + <b>verp</b><i>_</i><b>delimiter</b><i>_</i><b>filter</b> + The characters that Postfix accepts as VERP delim- + iter characters. + <b>Resource</b> <b>controls</b> <b>line</b><i>_</i><b>length</b><i>_</i><b>limit</b> - Limit the amount of memory in bytes used for the + Limit the amount of memory in bytes used for the handling of partial input lines. <b>message</b><i>_</i><b>size</b><i>_</i><b>limit</b> @@ -215,10 +197,15 @@ SMTPD(8) SMTPD(8) ing on-disk storage for envelope information. <b>queue</b><i>_</i><b>minfree</b> - Minimal amount of free space in bytes in the queue - file system for the SMTP server to accept any mail + Minimal amount of free space in bytes in the queue + file system for the SMTP server to accept any mail at all. + <b>smtpd</b><i>_</i><b>history</b><i>_</i><b>flush</b><i>_</i><b>threshold</b> + Flush the command history to postmaster after + receipt of RSET etc. only if the number of history + lines exceeds the given threshold. + <b>Tarpitting</b> <b>smtpd</b><i>_</i><b>error</b><i>_</i><b>sleep</b><i>_</i><b>time</b> Time to wait in seconds before sending a 4xx or 5xx @@ -226,51 +213,43 @@ SMTPD(8) SMTPD(8) <b>smtpd</b><i>_</i><b>soft</b><i>_</i><b>error</b><i>_</i><b>limit</b> When an SMTP client has made this number of errors, - wait <i>error_count</i> seconds before responding to any + wait <i>error_count</i> seconds before responding to any client request. <b>smtpd</b><i>_</i><b>hard</b><i>_</i><b>error</b><i>_</i><b>limit</b> - Disconnect after a client has made this number of + Disconnect after a client has made this number of errors. <b>smtpd</b><i>_</i><b>junk</b><i>_</i><b>command</b><i>_</i><b>limit</b> Limit the number of times a client can issue a junk - command such as NOOP, VRFY, ETRN or RSET in one - SMTP session before it is penalized with tarpit + command such as NOOP, VRFY, ETRN or RSET in one + SMTP session before it is penalized with tarpit 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> + 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. <b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>required</b> - Require that clients introduce themselves at the + Require that clients introduce themselves at the beginning of an SMTP session. <b>smtpd</b><i>_</i><b>helo</b><i>_</i><b>restrictions</b> - Restrict what client hostnames are allowed in <b>HELO</b> + Restrict what client hostnames are allowed in <b>HELO</b> and <b>EHLO</b> commands. <b>smtpd</b><i>_</i><b>sender</b><i>_</i><b>restrictions</b> - Restrict what sender addresses are allowed in <b>MAIL</b> + Restrict what sender addresses are allowed in <b>MAIL</b> <b>FROM</b> commands. - - - - - 4 - - - - - -SMTPD(8) SMTPD(8) - - <b>smtpd</b><i>_</i><b>recipient</b><i>_</i><b>restrictions</b> - Restrict what recipient addresses are allowed in + Restrict what recipient addresses are allowed in <b>RCPT</b> <b>TO</b> commands. <b>smtpd</b><i>_</i><b>etrn</b><i>_</i><b>restrictions</b> @@ -278,70 +257,67 @@ SMTPD(8) SMTPD(8) mands, and what clients may issue <b>ETRN</b> commands. <b>allow</b><i>_</i><b>untrusted</b><i>_</i><b>routing</b> - Allow untrusted clients to specify addresses with - sender-specified routing. Enabling this opens up - nasty relay loopholes involving trusted backup MX + Allow untrusted clients to specify addresses with + sender-specified routing. Enabling this opens up + nasty relay loopholes involving trusted backup MX hosts. <b>smtpd</b><i>_</i><b>restriction</b><i>_</i><b>classes</b> - Declares the name of zero or more parameters that - contain a list of UCE restrictions. The names of - these parameters can then be used instead of the + Declares the name of zero or more parameters that + contain a list of UCE restrictions. The names of + these parameters can then be used instead of the restriction lists that they represent. + <b>smtpd</b><i>_</i><b>null</b><i>_</i><b>access</b><i>_</i><b>lookup</b><i>_</i><b>key</b> + The lookup key to be used in SMTPD access tables + instead of the null sender address. A null sender + address cannot be looked up. + <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> - List of DNS domains that publish the addresses of + List of DNS domains that publish the addresses of blacklisted hosts. + <b>permit</b><i>_</i><b>mx</b><i>_</i><b>backup</b><i>_</i><b>networks</b> + Only domains whose primary MX hosts match the + listed networks are eligible for the <b>per-</b> + <b>mit</b><i>_</i><b>mx</b><i>_</i><b>backup</b> feature. + <b>relay</b><i>_</i><b>domains</b> - Restrict what domains or networks this mail system + Restrict what domains or networks this mail system will relay mail from or to. <b>UCE</b> <b>control</b> <b>responses</b> <b>access</b><i>_</i><b>map</b><i>_</i><b>reject</b><i>_</i><b>code</b> - Server response when a client violates an access + Server response when a client violates an access database restriction. <b>invalid</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b> - Server response when a client violates the + Server response when a client violates the <b>reject</b><i>_</i><b>invalid</b><i>_</i><b>hostname</b> restriction. <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>reject</b><i>_</i><b>code</b> - Server response when a client violates the + Server response when a client violates the <b>maps</b><i>_</i><b>rbl</b><i>_</i><b>domains</b> restriction. <b>reject</b><i>_</i><b>code</b> - Response code when the client matches a <b>reject</b> + Response code when the client matches a <b>reject</b> restriction. <b>relay</b><i>_</i><b>domains</b><i>_</i><b>reject</b><i>_</i><b>code</b> - Server response when a client attempts to violate + Server response when a client attempts to violate the mail relay policy. <b>unknown</b><i>_</i><b>address</b><i>_</i><b>reject</b><i>_</i><b>code</b> - Server response when a client violates the + Server response when a client violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>address</b> restriction. - - - - - 5 - - - - - -SMTPD(8) SMTPD(8) - - <b>unknown</b><i>_</i><b>client</b><i>_</i><b>reject</b><i>_</i><b>code</b> - Server response when a client without address to - name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b> + Server response when a client without address to + name mapping violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>clients</b> restriction. <b>unknown</b><i>_</i><b>hostname</b><i>_</i><b>reject</b><i>_</i><b>code</b> - Server response when a client violates the + Server response when a client violates the <b>reject</b><i>_</i><b>unknown</b><i>_</i><b>hostname</b> restriction. <b>SEE</b> <b>ALSO</b> @@ -350,7 +326,7 @@ SMTPD(8) SMTPD(8) syslogd(8) system logging <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. <b>AUTHOR(S)</b> @@ -359,40 +335,6 @@ SMTPD(8) SMTPD(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 6 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/spawn.8.html b/gnu/dist/postfix/html/spawn.8.html index b844abf3ac3..34b3427981f 100644 --- a/gnu/dist/postfix/html/spawn.8.html +++ b/gnu/dist/postfix/html/spawn.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - SPAWN(8) SPAWN(8) - <b>NAME</b> spawn - Postfix external command spawner @@ -59,18 +56,6 @@ SPAWN(8) SPAWN(8) <b>SECURITY</b> This program needs root privilege in order to execute - - - - 1 - - - - - -SPAWN(8) SPAWN(8) - - external commands as the specified user. It is therefore security sensitive. However the <b>spawn</b> daemon does not talk to the external command and thus is not vulnerable to @@ -113,22 +98,6 @@ SPAWN(8) SPAWN(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - 2 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/transport.5.html b/gnu/dist/postfix/html/transport.5.html index c384739dde4..737c09c1e78 100644 --- a/gnu/dist/postfix/html/transport.5.html +++ b/gnu/dist/postfix/html/transport.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - TRANSPORT(5) TRANSPORT(5) - <b>NAME</b> transport - format of Postfix transport table @@ -36,18 +33,20 @@ TRANSPORT(5) TRANSPORT(5) <b>TABLE</b> <b>FORMAT</b> The format of the transport table is as follows: - blanks and comments - Blank lines are ignored, as are lines beginning - with `#'. - - leading whitespace - Lines that begin with whitespace continue the pre- - vious line. - <i>pattern</i> <i>result</i> When <i>pattern</i> matches the domain, use the corre- sponding <i>result</i>. + blank lines and comments + Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + multi-line text + A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. + With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, patterns are tried in the order as listed below: @@ -58,18 +57,11 @@ TRANSPORT(5) TRANSPORT(5) <i>.domain</i> <i>transport</i>:<i>nexthop</i> Mail for any subdomain of <i>domain</i> is delivered - through <i>transport</i> to <i>nexthop</i>. - - - - 1 - - - - - -TRANSPORT(5) TRANSPORT(5) - + through <i>transport</i> to <i>nexthop</i>. This applies only + when the string <b>transport</b><i>_</i><b>maps</b> is not listed in the + <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> configuration set- + ting. Otherwise, a domain name matches itself and + its subdomains. Note: transport map entries take precedence over domains specified in the <b>mydestination</b> parameter. If you use the @@ -125,18 +117,6 @@ TRANSPORT(5) TRANSPORT(5) used. Specify [] around the hostname in order to disable MX lookups. - - - - 2 - - - - - -TRANSPORT(5) TRANSPORT(5) - - The error mailer can be used to bounce mail: <b>.foo.org</b> <b>error:mail</b> <b>for</b> <b>*.foo.org</b> <b>is</b> <b>not</b> <b>deliv-</b> @@ -159,23 +139,28 @@ TRANSPORT(5) TRANSPORT(5) table, until a pattern is found that matches the search string. - Results are the same as with normal indexed file lookups, - with the additional feature that parenthesized substrings - from the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. + Results are the same as with indexed file lookups, with + the additional feature that parenthesized substrings from + the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. <b>CONFIGURATION</b> <b>PARAMETERS</b> - The following <b>main.cf</b> parameters are especially relevant - to this topic. 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 topic. 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>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> + 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. Other parameters of interest: <b>default</b><i>_</i><b>transport</b> - The transport to use when no transport is explic- + The transport to use when no transport is explic- itly specified. <b>relayhost</b> @@ -189,78 +174,15 @@ TRANSPORT(5) TRANSPORT(5) <a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables <b>LICENSE</b> - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. - - - 3 - - - - - -TRANSPORT(5) TRANSPORT(5) - - <b>AUTHOR(S)</b> Wietse Venema IBM T.J. Watson Research P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 4 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/trivial-rewrite.8.html b/gnu/dist/postfix/html/trivial-rewrite.8.html index f2412581479..92f478d06ae 100644 --- a/gnu/dist/postfix/html/trivial-rewrite.8.html +++ b/gnu/dist/postfix/html/trivial-rewrite.8.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) - <b>NAME</b> trivial-rewrite - Postfix address rewriting and resolving daemon @@ -59,18 +56,6 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) users. It can run at a fixed low privilege in a chrooted environment. - - - - 1 - - - - - -TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) - - <b>DIAGNOSTICS</b> Problems and transactions are logged to <b>syslogd</b>(8). @@ -125,17 +110,10 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) 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. - - - - 2 - - - - - -TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) - + <b>parent</b><i>_</i><b>domain</b><i>_</i><b>matches</b><i>_</i><b>subdomains</b> + 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 @@ -163,38 +141,6 @@ TRIVIAL-REWRITE(8) TRIVIAL-REWRITE(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/uce.html b/gnu/dist/postfix/html/uce.html index b756a43be30..7ea7a14e9df 100644 --- a/gnu/dist/postfix/html/uce.html +++ b/gnu/dist/postfix/html/uce.html @@ -109,8 +109,22 @@ is allowed in message headers. <dt>Syntax: <dd>Specify a list of zero or more lookup tables. Whenever a header -matches a table, a REJECT result means reject the message, and an -IGNORE result means delete the header from the message. +matches a table, the action depends on the lookup result: + +<p> + +<dl> + +<dt>REJECT <dd> Reject the message, and log the header. + +<dt>REJECT text... <dd> As above, and also send the text to +the originator. + +<dt>IGNORE <dd> Delete the header from the message. + +<dt>WARN <dd> Log (but do not reject) the header with a warning. + +</dl> <p> @@ -133,7 +147,7 @@ mail still to be rejected.</i> <dt>Example (header_checks): -<dd> /^to: *friend@public\.com$/ REJECT +<dd> <tt>/^to: *friend@public\.com$/ REJECT</tt> <p> @@ -146,6 +160,14 @@ clients this system accepts SMTP connections from. <p> +By default, this restriction is applied when the client sends the +RCPT TO command. In order to have the restriction take effect +as soon as possible, specify <b>smtpd_delay_reject = no</b> in +the Postfix <b>main.cf</b> configuration file. Doing so may cause +unexpected results with poorly implemented client software. + +<p> + <dl> <dt>Default: @@ -229,6 +251,8 @@ rejected requests (default: <b>554</b>). <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. @@ -280,6 +304,14 @@ The <b>smtpd_helo_restrictions</b> parameter restricts what hostnames clients may send with the <b>HELO</b> (<b>EHLO</b>) command. Some UCE software can be stopped by being strict here. +<p> + +By default, this restriction is applied when the client sends the +RCPT TO command. In order to have the restriction take effect +as soon as possible, specify <b>smtpd_delay_reject = yes</b> in +the Postfix <b>main.cf</b> configuration file. Doing so may cause +unexpected results with poorly implemented client software. + <dl> <dt>Default: @@ -390,6 +422,8 @@ the response code for <b>REJECT</b> results (default: <b>554</b>). <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. @@ -443,6 +477,14 @@ addresses this system accepts in MAIL FROM commands. <p> +By default, this restriction is applied when the client sends the +RCPT TO command. In order to have the restriction take effect +as soon as possible, specify <b>smtpd_delay_reject = yes</b> in +the Postfix <b>main.cf</b> configuration file. Doing so may cause +unexpected results with poorly implemented client software. + +<p> + <dl> <dt> Default: @@ -516,6 +558,19 @@ response code to rejected requests (default: <b>504</b>). <p> +<a name="reject_sender_login_mismatch"> + +<dt> <b>reject_sender_login_mismatch</b> + +<dd> Reject the request when <a href="#smtpd_sender_login_maps"> +$smtpd_sender_owner_maps</a> specifies an owner for the MAIL FROM +address, but the client is not (SASL) logged in as that MAIL FROM +address owner; or when the client is (SASL) logged in, but the +client login name doesn't own the MAIL FROM address according to +<a href="#smtpd_sender_login_maps"> $smtpd_sender_login_maps</a>. + +<p> + <dt> <b><a href="#permit_naked_ip_address">permit_naked_ip_address</a></b> <dt> <b><a href="#reject_invalid_hostname">reject_invalid_hostname</a></b> @@ -546,6 +601,8 @@ response code to rejected requests (default: <b>504</b>). <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. @@ -722,17 +779,24 @@ code for rejected requests (default: <b>554</b>). <a name="permit_mx_backup"> <dt> <b>permit_mx_backup</b> <dd> Permit the request when the local -mail system is MX host for the resolved destination. This includes -the case that the local mail system is the final destination. -However, the SMTP server will not forward mail with addresses that -have sender-specified routing information (example: +mail system is MX host for the resolved destination. +This includes the case that the local mail system is the final +destination. However, the SMTP server will not forward mail with +addresses that have sender-specified routing information (example: <i>user@elsewhere@domain</i>), <p> -Relevant configuration parameters: <a href="basic.html#mydestination"> -$mydestination</a>, <a href="basic.html#inet_interfaces"> -$inet_interfaces</a>. +Use the optional <a href="#permit_mx_backup_networks"> +permit_mx_backup_networks</a> parameter to also require that the +primary MX hosts match a list of network blocks. + +<p> + +Relevant configuration parameters: <a +href="#permit_mx_backup_networks">permit_mx_backup_networks</a>, +<a href="basic.html#mydestination"> $mydestination</a>, <a +href="basic.html#inet_interfaces"> $inet_interfaces</a>. <p> @@ -774,6 +838,9 @@ response code to rejected requests (default: <b>504</b>). <dt> <b><a href="#check_sender_access">check_sender_access</a></b> <i>maptype</i>:<i>mapname</i> +<dt> <b><a href="#reject_sender_login_mismatch">reject_sender_login_mismatch +</a></b> + <dd> See sender address restrictions. <p> @@ -808,6 +875,8 @@ response code to rejected requests (default: <b>504</b>). <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. @@ -906,6 +975,8 @@ the result code for rejected requests (default: <b>554</b>). <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. @@ -948,6 +1019,17 @@ specifies the response code to rejected requests (default: <p> +<a name="warn_if_reject"> + +<dt> <b>warn_if_reject</b> +<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 @@ -966,6 +1048,52 @@ to speed up deliveries. <dl> +<a name="permit_mx_backup_networks"> + +<dt> <b>permit_mx_backup_networks</b> + +<dd>Restrict the use of the <a href="#permit_mx_backup"> +permit_mx_backup</a> relay control feature to destinations whose +primary MX hosts match a list of network blocks. + +<p> + +<dl> + +<dt>Default: + +<dd><b>permit_mx_backup_networks = </b> + +<p> + +That is, all networks are authorized by default. + +<p> + +<dt>Syntax: + +<dd> Specify a list of network +blocks in CIDR (network/mask) notation, for example: + +<p> + +<dl> + +<dd> <b>permit_mx_backup_networks = 168.100.0.0/16</b> + +</dl> + +<p> + +You can also specify the absolute pathname of a pattern file instead +of listing the patterns in the <b>main.cf</b> file. + +</dl> + +</dl> + +<dl> + <a name="maps_rbl_domains"> <dt> <b>maps_rbl_domains</b> @@ -1060,6 +1188,68 @@ tables listed in <b>$relay_domains.</b> </dl> +<dl> + +<a name="smtpd_sender_login_maps"> + +<dt> <b>smtpd_sender_login_maps</b> + +<dd>This parameter specifies ownership of MAIL FROM addresses, as +used by the <a href="#reject_sender_login_mismatch"> +reject_sender_login_mismatch</a> sender address restriction. + +<p> + +<dl> + +<dt>Default: + +<dd><b>smtpd_sender_login_maps = </b> + +<p> + +<dt>Syntax: + +<dd> Specify zero or more type:name lookup tables, separated by +whitespace and/or commas. The maps are searched in the +specified order. Regexp tables are allowed. + +<p> + +Each map entry specifies a sender address and the login name that +owns the address. The search order is: + +<p> + +<dl> + +<dt><i>user@domain owner</i> + +<dd>This form has the highest precedence. + +<p> + +<dt><i>user owner</i> + +<dd>This matches <i>user@site</i> when <i>site</i> is equal to <a +href="basic.html#myorigin"> $myorigin</a>, when <i>site</i> is +listed in <a href="basic.html#mydestination"> $mydestination</a>, +or when it is listed in <a href="basic.html#inet_interfaces"> +$inet_interfaces</a>. + +<p> + +<dt><i>@domain owner</i> + +<dd>This matches every address in the specified domain, and has +the lowest precedence. + +</dl> + +</dl> + +</dl> + <hr> <a href="index.html">Up one level</a> | <a href="basic.html">Basic diff --git a/gnu/dist/postfix/html/virtual.5.html b/gnu/dist/postfix/html/virtual.5.html index 720d763b6ae..4e716c41e43 100644 --- a/gnu/dist/postfix/html/virtual.5.html +++ b/gnu/dist/postfix/html/virtual.5.html @@ -1,10 +1,7 @@ <html> <head> </head> <body> <pre> - - VIRTUAL(5) VIRTUAL(5) - <b>NAME</b> virtual - format of Postfix virtual table @@ -58,20 +55,8 @@ VIRTUAL(5) VIRTUAL(5) <i>user1@virtual.domain</i> <i>address1</i> <i>user2@virtual.domain</i> <i>address2,</i> <i>address3</i> - The <i>virtual.domain</i> <i>anything</i> entry is required for a - - - - 1 - - - - - -VIRTUAL(5) VIRTUAL(5) - - - Postfix-style virtual domain. + The <i>virtual.domain</i> <i>anything</i> entry is required for a Post- + fix-style virtual domain. Do not list a Postfix-style virtual domain in the <b>main.cf</b> <b>mydestination</b> configuration parameter. Such an entry is @@ -105,7 +90,7 @@ VIRTUAL(5) VIRTUAL(5) The <b>main.cf</b> <b>mydestination</b> entry is required for a Send- mail-style virtual domain. - Do not specify a <i>virtual.domain</i> <i>whatever</i> virtual map entry + Do not specify a <i>virtual.domain</i> <i>anything</i> virtual map entry for a Sendmail-style virtual domain. Such an entry is required only with a Postfix-style virtual domain. @@ -119,30 +104,20 @@ VIRTUAL(5) VIRTUAL(5) The format of the virtual table is as follows, mappings being tried in the order as listed in this manual page: - blanks and comments - Blank lines are ignored, as are lines beginning - with `#'. - - leading whitespace - Lines that begin with whitespace continue the - - - - 2 - - - - - -VIRTUAL(5) VIRTUAL(5) - - - previous line. - <i>pattern</i> <i>result</i> When <i>pattern</i> matches a mail address, replace it by the corresponding <i>result</i>. + blank lines and comments + Empty lines and whitespace-only lines are ignored, + as are lines whose first non-whitespace character + is a `#'. + + multi-line text + A logical line starts with non-whitespace text. A + line that starts with whitespace continues a logi- + cal line. + With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, patterns are tried in the order as listed below: @@ -171,12 +146,11 @@ VIRTUAL(5) VIRTUAL(5) works for the first address in the expansion only. <b>ADDRESS</b> <b>EXTENSION</b> - When the search fails, and the address localpart contains - the optional recipient delimiter (e.g., <i>user+foo</i>@<i>domain</i>), - the search is repeated for the unextended address (e.g. - <i>user</i>@<i>domain</i>), and the unmatched address extension is prop- - agated to the result of expansion. The matching order is: - <i>user+foo</i>@<i>domain</i>, <i>user</i>@<i>domain</i>, <i>user+foo</i>, <i>user</i>, and @<i>domain</i>. + When a mail address localpart contains the optional recip- + ient delimiter (e.g., <i>user+foo</i>@<i>domain</i>), the lookup order + becomes: <i>user+foo</i>@<i>domain</i>, <i>user</i>@<i>domain</i>, <i>user+foo</i>, <i>user</i>, and + @<i>domain</i>. An unmatched address extension (<i>+foo</i>) is propa- + gated to the result of table lookup. <b>REGULAR</b> <b>EXPRESSION</b> <b>TABLES</b> This section describes how the table lookups change when @@ -191,32 +165,20 @@ VIRTUAL(5) VIRTUAL(5) <i>foo</i>. Patterns are applied in the order as specified in the - - - - 3 - - - - - -VIRTUAL(5) VIRTUAL(5) - - table, until a pattern is found that matches the search string. - Results are the same as with normal indexed file lookups, - with the additional feature that parenthesized substrings - from the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. + Results are the same as with indexed file lookups, with + the additional feature that parenthesized substrings from + the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on. <b>BUGS</b> - The table format does not understand quoting conventions. + The table format does not understand quoting conventions. <b>CONFIGURATION</b> <b>PARAMETERS</b> - The following <b>main.cf</b> parameters are especially relevant - to this topic. 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 topic. 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>virtual</b><i>_</i><b>maps</b> @@ -225,11 +187,11 @@ VIRTUAL(5) VIRTUAL(5) Other parameters of interest: <b>inet</b><i>_</i><b>interfaces</b> - The network interface addresses that this system + The network interface addresses that this system receives mail on. <b>mydestination</b> - List of domains that this mail system considers + List of domains that this mail system considers local. <b>myorigin</b> @@ -246,7 +208,7 @@ VIRTUAL(5) VIRTUAL(5) <a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables <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> @@ -255,12 +217,6 @@ VIRTUAL(5) VIRTUAL(5) P.O. Box 704 Yorktown Heights, NY 10598, USA - - - - - - 4 - + 1 </pre> </body> </html> diff --git a/gnu/dist/postfix/html/virtual.8.html b/gnu/dist/postfix/html/virtual.8.html new file mode 100644 index 00000000000..a3f3571b5d1 --- /dev/null +++ b/gnu/dist/postfix/html/virtual.8.html @@ -0,0 +1,228 @@ +<html> <head> </head> <body> <pre> + +VIRTUAL(8) VIRTUAL(8) + +<b>NAME</b> + virtual - Postfix virtual domain mail delivery agent + +<b>SYNOPSIS</b> + <b>virtual</b> [generic Postfix daemon options] + +<b>DESCRIPTION</b> + The <b>virtual</b> delivery agent is designed for virtual mail + hosting services. Originally based on the Postfix local + delivery agent, this agent looks up recipients with map + lookups of their full recipient address, instead of using + hard-coded unix password file lookups of the address local + part only. + + This delivery agent only delivers mail. Other features + such as mail forwarding, out-of-office notifications, + etc., must be configured via virtual maps or via similar + lookup mechanisms. + +<b>MAILBOX</b> <b>LOCATION</b> + The mailbox location is controlled by the <b>virtual</b><i>_</i><b>mail-</b> + <b>box</b><i>_</i><b>base</b> and <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>maps</b> configuration parameters + (see below). The <b>virtual</b><i>_</i><b>mailbox</b><i>_</i><b>maps</b> table is indexed by + the full recipient address. + + The mailbox pathname is constructed as follows: + + <b>$virtual</b><i>_</i><b>mailbox</b><i>_</i><b>base/$virtual</b><i>_</i><b>mailbox</b><i>_</i><b>maps(</b><i>recipient</i><b>)</b> + + where <i>recipient</i> is the full recipient address. + +<b>UNIX</b> <b>MAILBOX</b> <b>FORMAT</b> + When the mailbox location does not end in <b>/</b>, the message + is delivered in UNIX mailbox format. This format stores + multiple messages in one textfile. + + The <b>virtual</b> delivery agent prepends a "<b>From</b> <i>sender</i> + <i>time_stamp</i>" envelope header to each message, prepends a + <b>Delivered-To:</b> message header with the envelope recipient + address, prepends a <b>Return-Path:</b> message header with the + envelope sender address, prepends a > character to lines + beginning with "<b>From</b> ", and appends an empty line. + + The mailbox is locked for exclusive access while delivery + is in progress. In case of problems, an attempt is made to + truncate the mailbox to its original length. + +<b>QMAIL</b> <b>MAILDIR</b> <b>FORMAT</b> + When the mailbox location ends in <b>/</b>, the message is deliv- + ered in qmail <b>maildir</b> format. This format stores one mes- + sage per file. + + The <b>virtual</b> delivery agent daemon prepends a <b>Delivered-To:</b> + message header with the envelope recipient address and + prepends a <b>Return-Path:</b> message header with the envelope + sender address. + + By definition, <b>maildir</b> format does not require file lock- + ing during mail delivery or retrieval. + +<b>MAILBOX</b> <b>OWNERSHIP</b> + Mailbox ownership is controlled by the <b>virtual</b><i>_</i><b>uid</b><i>_</i><b>maps</b> + and <b>virtual</b><i>_</i><b>gid</b><i>_</i><b>maps</b> lookup tables, which are indexed with + the full recipient address. Each table provides a string + with the numerical user and group ID, respectively. + + The <b>virtual</b><i>_</i><b>minimum</b><i>_</i><b>uid</b> parameter imposes a lower bound on + numerical user ID values that may be specified in any <b>vir-</b> + <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, 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) + +<b>DIAGNOSTICS</b> + Mail bounces when the recipient has no mailbox or when the + 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 + 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- + 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 + 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> + 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 + 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 + 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 + 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 + 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 + 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 + 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 + access to the parent directory of the mailbox file. + + 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>-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- + 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. + + <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). + +<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 + 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 + 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 + file. Set to zero to disable the limit. + +<b>HISTORY</b> + 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 + to "|command" or to /file/name. + + 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 + Daniel Bernstein. + +<b>SEE</b> <b>ALSO</b> + <a href="bounce.8.html">bounce(8)</a> non-delivery status reports + syslogd(8) system logging + <a href="qmgr.8.html">qmgr(8)</a> queue manager + +<b>LICENSE</b> + The Secure Mailer license must be distributed with this + software. + +<b>AUTHOR(S)</b> + Wietse Venema + IBM T.J. Watson Research + P.O. Box 704 + Yorktown Heights, NY 10598, USA + + Andrew McNamara + andrewm@connect.com.au + connect.com.au Pty. Ltd. + Level 3, 213 Miller St + North Sydney 2060, NSW, Australia + + 1 + +</pre> </body> </html> diff --git a/gnu/dist/postfix/man/Makefile.in b/gnu/dist/postfix/man/Makefile.in index 21b58261c5b..f1461025a45 100644 --- a/gnu/dist/postfix/man/Makefile.in +++ b/gnu/dist/postfix/man/Makefile.in @@ -5,11 +5,11 @@ SHELL = /bin/sh DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \ man8/lmtp.8 man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 \ man8/showq.8 man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 \ - man8/spawn.8 man8/flush.8 # man8/nqmgr.8 man8/virtual.8 + man8/nqmgr.8 man8/spawn.8 man8/flush.8 man8/virtual.8 man8/qmqpd.8 COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \ man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \ man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \ - man1/postsuper.1 + man1/postqueue.1 man1/postsuper.1 CONFIG = man5/access.5 man5/aliases.5 man5/canonical.5 man5/relocated.5 \ man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5 @@ -65,6 +65,9 @@ man8/pipe.8: ../src/pipe/pipe.c man8/qmgr.8: ../src/qmgr/qmgr.c ../mantools/srctoman $? >$@ +man8/qmqpd.8: ../src/qmqpd/qmqpd.c + ../mantools/srctoman $? >$@ + man8/showq.8: ../src/showq/showq.c ../mantools/srctoman $? >$@ @@ -110,6 +113,9 @@ man1/postlog.1: ../src/postlog/postlog.c man1/postmap.1: ../src/postmap/postmap.c ../mantools/srctoman $? >$@ +man1/postqueue.1: ../src/postqueue/postqueue.c + ../mantools/srctoman $? >$@ + man1/postsuper.1: ../src/postsuper/postsuper.c ../mantools/srctoman $? >$@ diff --git a/gnu/dist/postfix/man/man1/postalias.1 b/gnu/dist/postfix/man/man1/postalias.1 index 5637bbef447..0917606ff6b 100644 --- a/gnu/dist/postfix/man/man1/postalias.1 +++ b/gnu/dist/postfix/man/man1/postalias.1 @@ -9,7 +9,7 @@ Postfix alias database maintenance .na .nf .fi -\fBpostalias\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR] +\fBpostalias\fR [\fB-Nfinrvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-d \fIkey\fR] [\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ... .SH DESCRIPTION @@ -35,7 +35,14 @@ Read the \fBmain.cf\fR configuration file in the named directory instead of the default configuration directory. .IP "\fB-d \fIkey\fR" Search the specified maps for \fIkey\fR and remove one entry per map. -The exit status is non-zero if the requested information was not found. +The exit status is zero when the requested information was found. + +If a key value of \fB-\fR is specified, the program reads key +values from the standard input stream. The exit status is zero +when at least one of the requested keys was found. +.IP \fB-f\fR +Do not fold the lookup key to lower case while creating or querying +a map. .IP \fB-i\fR Incremental mode. Read entries from standard input and do not truncate an existing database. By default, \fBpostalias\fR creates @@ -46,8 +53,13 @@ keys and values. By default, Postfix does whatever is the default for the host operating system. .IP "\fB-q \fIkey\fR" Search the specified maps for \fIkey\fR and print the first value -found on the standard output stream. The exit status is non-zero -if the requested information was not found. +found on the standard output stream. The exit status is zero +when the requested information was found. + +If a key value of \fB-\fR is specified, the program reads key +values from the standard input stream and prints one line of +\fIkey: value\fR output for each key that was found. The exit +status is zero when at least one of the requested keys was found. .IP \fB-r\fR When updating a table, do not warn about duplicate entries; silently replace them. @@ -89,11 +101,6 @@ flagged with a warning. \fBpostalias\fR terminates with zero exit status in case of success (including successful \fBpostmap -q\fR lookup) and terminates with non-zero exit status in case of failure. -.SH BUGS -.ad -.fi -The "delete key" support is limited to one delete operation -per command invocation. .SH ENVIRONMENT .na .nf diff --git a/gnu/dist/postfix/man/man1/postdrop.1 b/gnu/dist/postfix/man/man1/postdrop.1 index eb293df7615..1221049246a 100644 --- a/gnu/dist/postfix/man/man1/postdrop.1 +++ b/gnu/dist/postfix/man/man1/postdrop.1 @@ -4,25 +4,26 @@ .SH NAME postdrop \- -Postfix mail posting agent +Postfix mail posting utility .SH SYNOPSIS .na .nf -\fBpostdrop\fR [\fIoption ...\fR] +\fBpostdrop\fR [\fB-rv\fR] [\fB-c \fIconfig_dir\fR] .SH DESCRIPTION .ad .fi The \fBpostdrop\fR command creates a file in the \fBmaildrop\fR directory and copies its standard input to the file. -The command is designed to run with set-gid privileges, and with -group write permission to the \fBmaildrop\fR queue directory. - -The \fBpostdrop\fR command is automatically invoked by the -\fBsendmail\fR(1) mail posting agent when the \fBmaildrop\fR -queue directory is not world-writable. - Options: +.IP \fB-c \fIconfig_dir\fR +The \fBmain.cf\fR configuration file is in the named directory +instead of the default configuration directory. See also the +MAIL_CONFIG environment setting below. +.IP \fB-r\fR +Use a Postfix-internal protocol for reading the message from +standard input, and for reporting status information on standard +output. This is currently the only supported method. .IP \fB-v\fR Enable verbose logging for debugging purposes. Multiple \fB-v\fR options make the software increasingly verbose. @@ -31,8 +32,9 @@ options make the software increasingly verbose. .nf .ad .fi -This program is designed so that it can run with set-user (or -group) id privileges. +The command is designed to run with set-group ID privileges, so +that it can write to the \fBmaildrop\fR queue directory and so that +it can connect to Postfix daemon processes. .SH DIAGNOSTICS .ad .fi @@ -45,8 +47,16 @@ INT, QUIT or TERM signal, the queue file is deleted. .nf .ad .fi -The program deletes all environment information, because the C -library can't be trusted. +.IP MAIL_CONFIG +Directory with the \fBmain.cf\fR file. In order to avoid exploitation +of set-group ID privileges, it is not possible to specify arbitrary +directory names. + +A non-standard directory is allowed only if the name is listed in the +standard \fBmain.cf\fR file, in the \fBalternate_config_directories\fR +configuration parameter value. + +Only the super-user is allowed to specify arbitrary directory names. .SH FILES .na .nf diff --git a/gnu/dist/postfix/man/man1/postfix.1 b/gnu/dist/postfix/man/man1/postfix.1 index e3230a053c8..204cd7e2ace 100644 --- a/gnu/dist/postfix/man/man1/postfix.1 +++ b/gnu/dist/postfix/man/man1/postfix.1 @@ -14,11 +14,15 @@ Postfix control program .SH DESCRIPTION .ad .fi +This command is reserved for the super-user. To submit mail, +use the Postfix \fBsendmail\fR command. + The \fBpostfix\fR command controls the operation of the Postfix mail system: start or stop the \fBmaster\fR daemon, do a health -check, and other maintenance. The command sets up a standardized -environment and runs the \fBpostfix-script\fR shell script to -do the actual work. +check, and other maintenance. + +The \fBpostfix\fR command sets up a standardized environment and +runs the \fBpostfix-script\fR shell script to do the actual work. The following commands are implemented: .IP \fBcheck\fR @@ -71,27 +75,52 @@ Directory with Postfix configuration files. This is set when the -v command-line option is present. .IP \fBMAIL_DEBUG\fR This is set when the -D command-line option is present. -.PP -The following configuration parameters are made available -as process environment variables with the same names: +.SH CONFIGURATION PARAMETERS +.na +.nf +.ad +.fi +The following \fBmain.cf\fR configuration parameters are made +available as process environment variables with the same names: .IP \fBcommand_directory\fR -Directory with Postfix support commands (default: -\fB$program_directory\fR). +Directory with Postfix administrative commands. .IP \fBdaemon_directory\fR -Directory with Postfix daemon programs (default: -\fB$program_directory\fR). +Directory with Postfix daemon programs. .IP \fBconfig_directory\fR Directory with Postfix configuration files and with administrative shell scripts. .IP \fBqueue_directory\fR -The directory with the Postfix queue directory (and with some -files needed for programs running in a chrooted environment). +The directory with Postfix queue files, with local inter-process +communication endpoints, and with files needed for daemon programs +that run in the optional chrooted environment. .IP \fBmail_owner\fR -The owner of the Postfix queue and of most Postfix processes. +The owner of Postfix queue files and of most Postfix processes. +.IP \fBsetgid_group\fR +The group for mail submission and queue management commands. +.IP \fBsendmail_path +The full pathname for the Postfix sendmail command. +.IP \fBnewaliases_path +The full pathname for the Postfix newaliases command. +.IP \fBmailq_path +The full pathname for the Postfix mailq command. +.IP \fBmanpage_directory +The directory for the Postfix on-line manual pages. +.IP \fBsample_directory +The directory for the Postfix sample configuration files. +.IP \fBreadme_directory +The directory for the Postfix README files. +.SH Other configuration parameters +.ad +.fi +.IP \fBimport_environment\fR +List of names of environment parameters that can be imported +from non-Postfix processes. .SH FILES .na .nf $\fBconfig_directory/postfix-script\fR, administrative commands +$\fBconfig_directory/main.cf\fR, configuration parameters +$\fBconfig_directory/master.cf\fR, Postfix daemon processes .SH SEE ALSO .na .nf diff --git a/gnu/dist/postfix/man/man1/postmap.1 b/gnu/dist/postfix/man/man1/postmap.1 index bdcd3bf16e5..d5385d40761 100644 --- a/gnu/dist/postfix/man/man1/postmap.1 +++ b/gnu/dist/postfix/man/man1/postmap.1 @@ -9,8 +9,9 @@ Postfix lookup table management .na .nf .fi -\fBpostmap\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-d \fIkey\fR] -[\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ... +\fBpostmap\fR [\fB-Nfinrvw\fR] [\fB-c \fIconfig_dir\fR] +[\fB-d \fIkey\fR] [\fB-q \fIkey\fR] +[\fIfile_type\fR:]\fIfile_name\fR ... .SH DESCRIPTION .ad .fi @@ -21,6 +22,9 @@ file formats are expected to be compatible with: .ti +4 \fBmakemap \fIfile_type\fR \fIfile_name\fR < \fIfile_name\fR +If the result files do not exist they will be created with the +same group and other read permissions as the source file. + While the table update is in progress, signal delivery is postponed, and an exclusive, advisory, lock is placed on the entire table, in order to avoid surprises in spectator @@ -28,14 +32,16 @@ programs. The format of a lookup table input file is as follows: .IP \(bu -Blank lines are ignored. So are lines beginning with `#'. -.IP \(bu A table entry has the form .sp .ti +5 \fIkey\fR whitespace \fIvalue\fR .IP \(bu -A line that starts with whitespace continues the preceding line. +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP \(bu +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .PP The \fIkey\fR and \fIvalue\fR are processed as is, except that surrounding white space is stripped off. Unlike with Postfix alias @@ -53,7 +59,14 @@ Read the \fBmain.cf\fR configuration file in the named directory instead of the default configuration directory. .IP "\fB-d \fIkey\fR" Search the specified maps for \fIkey\fR and remove one entry per map. -The exit status is non-zero if the requested information was not found. +The exit status is zero when the requested information was found. + +If a key value of \fB-\fR is specified, the program reads key +values from the standard input stream. The exit status is zero +when at least one of the requested keys was found. +.IP \fB-f\fR +Do not fold the lookup key to lower case while creating or querying +a map. .IP \fB-i\fR Incremental mode. Read entries from standard input and do not truncate an existing database. By default, \fBpostmap\fR creates @@ -64,8 +77,13 @@ keys and values. By default, Postfix does whatever is the default for the host operating system. .IP "\fB-q \fIkey\fR" Search the specified maps for \fIkey\fR and print the first value -found on the standard output stream. The exit status is non-zero -if the requested information was not found. +found on the standard output stream. The exit status is zero +when the requested information was found. + +If a key value of \fB-\fR is specified, the program reads key +values from the standard input stream and prints one line of +\fIkey value\fR output for each key that was found. The exit +status is zero when at least one of the requested keys was found. .IP \fB-r\fR When updating a table, do not warn about duplicate entries; silently replace them. @@ -106,11 +124,6 @@ skipped and are flagged with a warning. \fBpostmap\fR terminates with zero exit status in case of success (including successful \fBpostmap -q\fR lookup) and terminates with non-zero exit status in case of failure. -.SH BUGS -.ad -.fi -The "delete key" support is limited to one delete operation -per command invocation. .SH ENVIRONMENT .na .nf diff --git a/gnu/dist/postfix/man/man1/postqueue.1 b/gnu/dist/postfix/man/man1/postqueue.1 new file mode 100644 index 00000000000..f6680034318 --- /dev/null +++ b/gnu/dist/postfix/man/man1/postqueue.1 @@ -0,0 +1,117 @@ +.TH POSTQUEUE 1 +.ad +.fi +.SH NAME +postqueue +\- +Postfix queue control +.SH SYNOPSIS +.na +.nf +\fBpostqueue\fR [\fB-c \fIconfig_dir\fR] \fB-f\fR +.br +\fBpostqueue\fR [\fB-c \fIconfig_dir\fR] \fB-p\fR +.br +\fBpostqueue\fR [\fB-c \fIconfig_dir\fR] \fB-s \fIsite\fR +.SH DESCRIPTION +.ad +.fi +The \fBpostqueue\fR program implements the Postfix user interface +for queue management. It implements all the operations that are +traditionally available via the \fBsendmail\fR(1) command. + +The following options are recognized: +.IP "\fB-c \fIconfig_dir\fR" +The \fBmain.cf\fR configuration file is in the named directory +instead of the default configuration directory. See also the +MAIL_CONFIG environment setting below. +.IP \fB-f\fR +Flush the queue: attempt to deliver all queued mail. + +This option implements the traditional \fBsendmail -q\fR command, +by contacting the Postfix \fBqmgr\fR(8) daemon. +.IP \fB-p\fR +Produce a traditional sendmail-style queue listing. + +This option implements the traditional \fBmailq\fR command, +by contacting the Postfix \fBshowq\fR(8) daemon. +.IP "\fB-s \fIsite\fR" +Schedule immediate delivery of all mail that is queued for the named +\fIsite\fR. The site must be eligible for the "fast flush" service. +See \fBflush\fR(8) for more information about the "fast flush" +service. + +This option implements the traditional \fBsendmail -qR\fIsite\fR +command, by contacting the Postfix \fBflush\fR(8) daemon. +.IP \fB-v\fR +Enable verbose logging for debugging purposes. Multiple \fB-v\fR +options make the software increasingly verbose. +.SH SECURITY +.na +.nf +.ad +.fi +This program is designed to run with set-group ID privileges, so +that it can connect to Postfix daemon processes. +.SH DIAGNOSTICS +.ad +.fi +Problems are logged to \fBsyslogd\fR(8) and to the standard error +stream. +.SH ENVIRONMENT +.na +.nf +.ad +.fi +.IP MAIL_CONFIG +Directory with the \fBmain.cf\fR file. + +In order to avoid exploitation of set-group ID privileges, it is not +possible to specify arbitrary directory names. + +A non-standard directory is allowed only if the name is listed in the +standard \fBmain.cf\fR file, in the \fBalternate_config_directories\fR +configuration parameter value. + +Only the super-user is allowed to specify arbitrary directory names. +.SH FILES +.na +.nf +/var/spool/postfix, mail queue +/etc/postfix, configuration files +.SH CONFIGURATION PARAMETERS +.na +.nf +.ad +.fi +.IP \fBimport_environment\fR +List of names of environment parameters that can be imported +from non-Postfix processes. +.IP \fBqueue_directory\fR +Top-level directory of the Postfix queue. This is also the root +directory of Postfix daemons that run chrooted. +.IP \fBfast_flush_domains\fR +List of domains that will receive "fast flush" service (default: all +domains that this system is willing to relay mail to). This list +specifies the domains that Postfix accepts in the SMTP \fBETRN\fR +request and in the \fBsendmail -qR\fR command. +.SH SEE ALSO +.na +.nf +sendmail(8) sendmail-compatible user interface +qmgr(8) queue manager +showq(8) list mail queue +flush(8) fast flush service +.SH LICENSE +.na +.nf +.ad +.fi +The Secure Mailer license must be distributed with this software. +.SH AUTHOR(S) +.na +.nf +Wietse Venema +IBM T.J. Watson Research +P.O. Box 704 +Yorktown Heights, NY 10598, USA diff --git a/gnu/dist/postfix/man/man1/postsuper.1 b/gnu/dist/postfix/man/man1/postsuper.1 index 07fada8e870..80fc638644a 100644 --- a/gnu/dist/postfix/man/man1/postsuper.1 +++ b/gnu/dist/postfix/man/man1/postsuper.1 @@ -4,35 +4,102 @@ .SH NAME postsuper \- -Postfix super intendent +Postfix superintendent .SH SYNOPSIS .na .nf .fi -\fBpostsuper\fR [\fB-p\fR] [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR] +\fBpostsuper\fR [\fB-psv\fR] [\fB-d \fIqueue_id\fR] +[\fB-r \fIqueue_id\fR] [\fIdirectory ...\fR] .SH DESCRIPTION .ad .fi -The \fBpostsuper\fR command does small maintenance jobs on the named -Postfix queue directories (default: all). -Directory names are relative to the Postfix top-level queue directory. +The \fBpostsuper\fR command does maintenance jobs on the Postfix +queue. Use of the command is restricted to the super-user. By default, \fBpostsuper\fR performs the operations requested with the -\fB-s\fR and \fB-p\fR command-line options. -\fBpostsuper\fR always tries to remove objects that are neither files -nor directories. Use of this command is restricted to the super-user. +\fB-s\fR and \fB-p\fR command-line options on all Postfix queue +directories - this includes the \fBincoming\fR, \fBactive\fR and +\fBdeferred\fR directories with mail files and the \fBbounce\fR, +\fBdefer\fR and \fBflush\fR directories with log files. Options: -.IP \fB-s\fR -Structure check. Move queue files that are in the wrong place -in the file system hierarchy and remove subdirectories that are -no longer needed. File rearrangements are necessary after a change -in the \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR -configuration parameters. It is highly recommended to run this -check once before Postfix startup. +.IP "\fB-d \fIqueue_id\fR" +Delete one message with the named queue ID from the named +mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +\fBdeferred\fR). +If a \fIqueue_id\fR of \fB-\fR is specified, the program reads +queue IDs from standard input. +.sp +Specify \fB-d ALL\fR to remove all messages; for example, specify +\fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue. +As a safety measure, the word \fBALL\fR must be specified in upper +case. +.sp +.ft B +Postfix queue IDs are reused. +There is a very small possibility that postsuper deletes the +wrong message file when it is executed while the Postfix mail +system is running. +.ft R +.sp +The scenario is as follows: +.RS +.IP 1) +The Postfix queue manager deletes the message that \fBpostsuper\fR +is supposed to delete, because Postfix is finished with the +message. +.IP 2) +New mail arrives, and the new message is given the same queue ID +as the message that \fBpostsuper\fR is supposed to delete. +The probability for reusing a deleted queue ID is about 1 in 2**15 +(the number of different microsecond values that the system clock +can distinguish within a second). +.IP 3) +\fBpostsuper\fR deletes the new message, instead of the old +message that it should have deleted. +.RE .IP \fB-p\fR -Purge stale files (files that are left over after system or -software crashes). +Purge old temporary files that are left over after system or +software crashes. +.IP "\fB-r \fIqueue_id\fR" +Requeue the message with the named queue ID from the named +mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +\fBdeferred\fR). +To requeue multiple messages, specify multiple \fB-r\fR +command-line options. +Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, +the program reads queue IDs from standard input. +.sp +Specify \fB-r ALL\fR to requeue all messages. As a safety +measure, the word \fBALL\fR must be specified in upper case. +.sp +A requeued message is moved to the \fBmaildrop\fR queue, from +where it is copied by the pickup daemon to a new file whose name +is guaranteed to match the new queue file inode number. The +new queue file is subjected again to mail address rewriting and +substitution. This is useful when rewriting rules or virtual +mappings have changed. +.sp +Postfix queue IDs are reused. +There is a very small possibility that \fBpostsuper\fR requeues +the wrong message file when it is executed while the Postfix mail +system is running, but no harm should be done. +.IP \fB-s\fR +Structure check and structure repair. It is highly recommended +to perform this operation once before Postfix startup. +.RS +.IP \(bu +Rename files whose name does not match the message file inode +number. This operation is necessary after restoring a mail queue +from a different machine, or from backup media. +.IP \(bu +Move queue files that are in the wrong place in the file system +hierarchy and remove subdirectories that are no longer needed. +File position rearrangements are necessary after a change in the +\fBhash_queue_names\fR and/or \fBhash_queue_depth\fR +configuration parameters. +.RE .IP \fB-v\fR Enable verbose logging for debugging purposes. Multiple \fB-v\fR options make the software increasingly verbose. @@ -41,6 +108,11 @@ options make the software increasingly verbose. .fi Problems are reported to the standard error stream and to \fBsyslogd\fR. + +\fBpostsuper\fR reports the number of messages deleted with \fB-d\fR, +the number of messages requeued with \fB-r\fR, and the number of +messages whose queue file name was fixed with \fB-s\fR. The report +is written to the standard error stream and to \fBsyslogd\fR. .SH CONFIGURATION PARAMETERS .na .nf diff --git a/gnu/dist/postfix/man/man1/sendmail.1 b/gnu/dist/postfix/man/man1/sendmail.1 index 51fee871504..87fcd219aa4 100644 --- a/gnu/dist/postfix/man/man1/sendmail.1 +++ b/gnu/dist/postfix/man/man1/sendmail.1 @@ -25,11 +25,9 @@ Sendmail command-line options are recognized but silently ignored. By default, \fBsendmail\fR reads a message from standard input until EOF or until it reads a line with only a \fB.\fR character, -and arranges for delivery. \fBsendmail\fR attempts to create -a queue file in the \fBmaildrop\fR directory. If that directory -is not world-writable, the message is piped through the -\fBpostdrop\fR(1) command, which is expected to execute with -suitable privileges. +and arranges for delivery. \fBsendmail\fR relies on the +\fBpostdrop\fR(1) command to create a queue file in the \fBmaildrop\fR +directory. Specific command aliases are provided for other common modes of operation: @@ -38,14 +36,15 @@ List the mail queue. Each entry shows the queue file ID, message size, arrival time, sender, and the recipients that still need to be delivered. If mail could not be delivered upon the last attempt, the reason for failure is shown. This mode of operation is implemented -by connecting to the \fBshowq\fR(8) daemon. +by executing the \fBpostqueue\fR(1) command. .IP \fBnewaliases\fR -Initialize the alias database. If no alias database type is -specified, the program uses the type specified in the -\fBdatabase_type\fR configuration parameter; if no input file -is specified, the program processes the file(s) specified with the -\fBalias_database\fR configuration parameter. This mode of operation -is implemented by running the \fBpostalias\fR(1) command. +Initialize the alias database. If no input file is specified (with +the \fB-oA\fR option, see below), the program processes the file(s) +specified with the \fBalias_database\fR configuration parameter. +If no alias database type is specified, the program uses the type +specified with the \fBdatabase_type\fR configuration parameter. +This mode of operation is implemented by running the \fBpostalias\fR(1) +command. .sp Note: it may take a minute or so before an alias database update becomes visible. Use the \fBpostfix reload\fR command to eliminate @@ -70,6 +69,9 @@ Gateway (relay) submission, as opposed to initial user submission. .IP \fB-I\fR Initialize alias database. See the \fBnewaliases\fR command above. +.IP "\fB-L \fIlabel\fR (ignored)" +The logging label. Use the \fBsyslog_name\fR configuration +parameter instead. .IP "\fB-N \fIdsn\fR (ignored)" Delivery status notification control. Currently, Postfix does not implement \fBDSN\fR. @@ -81,6 +83,20 @@ Log mailer traffic. Use the \fBdebug_peer_list\fR and \fBdebug_peer_level\fR configuration parameters instead. .IP "\fB-U\fR (ignored)" Initial user submission. +.IP \fB-V\fR +Variable Envelope Return Path. Given an envelope sender address +of the form \fIowner-listname\fR@\fIorigin\fR, each recipient +\fIuser\fR@\fIdomain\fR receives mail with a personalized envelope +sender address. +.sp +By default, the personalized envelope sender address is +\fIowner-listname\fB+\fIuser\fB=\fIdomain\fR@\fIorigin\fR. The default +\fB+\fR and \fB=\fR characters are configurable with the +\fBdefault_verp_delimiters\fR configuration parameter. +.IP \fB-V\fIxy\fR +As \fB-V\fR, but uses \fIx\fR and \fIy\fR as the VERP delimiter +characters, instead of the characters specified with the +\fBdefault_verp_delimiters\fR configuration parameter. .IP \fB-bd\fR Go into daemon mode. This mode of operation is implemented by executing the \fBpostfix start\fR command. @@ -132,17 +148,17 @@ Set the envelope sender address. This is the address where delivery problems are sent to, unless the message contains an \fBErrors-To:\fR message header. .IP \fB-q\fR -Attempt to deliver all queued mail. This is implemented by kicking the -\fBqmgr\fR(8) daemon. +Attempt to deliver all queued mail. This is implemented by +executing the \fBpostqueue\fR(1) command. .IP "\fB-q\fIinterval\fR (ignored)" The interval between queue runs. Use the \fBqueue_run_delay\fR configuration parameter instead. .IP \fB-qR\fIsite\fR Schedule immediate delivery of all mail that is queued for the named -\fIsite\fR. Depending on the destination, this uses "fast flush" -service, or it has the same effect as \fBsendmail -q\fR. -This is implemented by connecting to the local SMTP server. -See \fBsmtpd\fR(8) for more information about the "fast flush" +\fIsite\fR. This option accepts only \fIsite\fR names that are +eligible for the "fast flush" service, and is implemented by +executing the \fBpostqueue\fR(1) command. +See \fBflush\fR(8) for more information about the "fast flush" service. .IP \fB-qS\fIsite\fR This command is not implemented. Use the slower \fBsendmail -q\fR @@ -210,12 +226,14 @@ pattern in the \fBdebug_peer_list\fR parameter. List of domain or network patterns. When a remote host matches a pattern, increase the verbose logging level by the amount specified in the \fBdebug_peer_level\fR parameter. +.IP \fBdefault_verp_delimiters\fR +The VERP delimiter characters that are used when the \fB-V\fR +command line option is specified without delimiter characters. .IP \fBfast_flush_domains\fR List of domains that will receive "fast flush" service (default: all -domains that this system is willing to relay mail to). This greatly -improves the performance of the SMTP \fBETRN\fR request, and of the -\fBsendmail -qR\fR command. For domains not in the list, Postfix simply -attempts to deliver all queued mail. +domains that this system is willing to relay mail to). This list +specifies the domains that Postfix accepts in the SMTP \fBETRN\fR +request and in the \fBsendmail -qR\fR command. .IP \fBfork_attempts\fR Number of attempts to \fBfork\fR() a process before giving up. .IP \fBfork_delay\fR @@ -235,18 +253,19 @@ Top-level directory of the Postfix queue. This is also the root directory of Postfix daemons that run chrooted. .IP \fBqueue_run_delay\fR The time between successive scans of the deferred queue. +.IP \fBverp_delimiter_filter\fR +The characters that Postfix accepts as VERP delimiter characters. .SH SEE ALSO .na .nf pickup(8) mail pickup daemon postalias(1) maintain alias database -postdrop(1) privileged posting agent +postdrop(1) mail posting utility postfix(1) mail system control -postkick(1) kick a Postfix daemon +postqueue(1) mail queue control qmgr(8) queue manager -showq(8) list mail queue smtpd(8) SMTP server -flushd(8) fast flush service +flush(8) fast flush service syslogd(8) system logging .SH LICENSE .na diff --git a/gnu/dist/postfix/man/man5/access.5 b/gnu/dist/postfix/man/man5/access.5 index 6488c0b7911..60ee50d9b2b 100644 --- a/gnu/dist/postfix/man/man5/access.5 +++ b/gnu/dist/postfix/man/man5/access.5 @@ -13,8 +13,9 @@ format of Postfix access table .ad .fi The optional \fBaccess\fR table directs the Postfix SMTP server -to selectively reject or accept mail from or to specific hosts, -domains, networks, host addresses or mail addresses. +to selectively reject or accept mail. Access can be allowed or +denied for specific host names, domain names, networks, host +network addresses or mail addresses. Normally, the \fBaccess\fR table is specified as a text file that serves as input to the \fBpostmap\fR(1) command. @@ -35,29 +36,66 @@ the lookups are done in a slightly different way as described below. .ad .fi The format of the access table is as follows: -.IP "blanks and comments" -Blank lines are ignored, as are lines beginning with `#'. -.IP "leading whitespace" -Lines that begin with whitespace continue the previous line. .IP "\fIpattern action\fR" When \fIpattern\fR matches a mail address, domain or host address, perform the corresponding \fIaction\fR. -.SH PATTERNS +.IP "blank lines and comments" +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP "multi-line text" +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. +.SH EMAIL ADDRESS PATTERNS .na .nf .ad .fi With lookups from indexed files such as DB or DBM, or from networked -tables such as NIS, LDAP or SQL, patterns are tried in the order as -listed below: +tables such as NIS, LDAP or SQL, the following lookup patterns are +examined in the order as listed: .IP \fIuser\fR@\fIdomain\fR Matches the specified mail address. .IP \fIdomain.name\fR -Matches the \fIdomain.name\fR itself and any subdomain thereof, -either in hostnames or in mail addresses. Top-level domains will -never be matched. +Matches \fIdomain.name\fR as the domain part of an email address. +.sp +The pattern \fIdomain.name\fR also matches subdomains, but only +when the string \fBsmtpd_access_maps\fR is listed in the Postfix +\fBparent_domain_matches_subdomains\fR configuration setting. +Otherwise, specify \fI.domain.name\fR (note the initial dot) in +order to match subdomains. .IP \fIuser\fR@ Matches all mail addresses with the specified user part. +.PP +Note: lookup of the null sender address may not be possible with +all supported types of lookup table. A workaround is to specify +\fBsmtpd_null_access_lookup_key = <>\fR in the Postfix \fBmain.cf\fR +file, and to specify \fB<>\fR as the left-hand field in the access +table. +.SH ADDRESS EXTENSION +.na +.nf +.fi +.ad +When a mail address localpart contains the optional recipient delimiter +(e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIdomain\fR, +\fIuser+foo\fR@, and \fIuser\fR@. +.SH HOST NAME/ADDRESS PATTERNS +.na +.nf +.ad +.fi +With lookups from indexed files such as DB or DBM, or from networked +tables such as NIS, LDAP or SQL, the following lookup patterns are +examined in the order as listed: +.IP \fIdomain.name\fR +Matches \fIdomain.name\fR. +.sp +The pattern \fIdomain.name\fR also matches subdomains, but only +when the string \fBsmtpd_access_maps\fR is listed in the Postfix +\fBparent_domain_matches_subdomains\fR configuration setting. +Otherwise, specify \fI.domain.name\fR (note the initial dot) in +order to match subdomains. .IP \fInet.work.addr.ess\fR .IP \fInet.work.addr\fR .IP \fInet.work\fR @@ -94,13 +132,14 @@ Each pattern is a regular expression that is applied to the entire string being looked up. Depending on the application, that string is an entire client hostname, an entire client IP address, or an entire mail address. Thus, no parent domain or parent network search -is done, and \fIuser@domain\fR mail addresses are not broken up into -their \fIuser@\fR and \fIdomain\fR constituent parts. +is done, \fIuser@domain\fR mail addresses are not broken up into +their \fIuser@\fR and \fIdomain\fR constituent parts, nor is +\fIuser+foo\fR broken up into \fIuser\fR and \fIfoo\fR. Patterns are applied in the order as specified in the table, until a pattern is found that matches the search string. -Actions are the same as with normal indexed file lookups, with +Actions are the same as with indexed file lookups, with the additional feature that parenthesized substrings from the pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. .SH BUGS diff --git a/gnu/dist/postfix/man/man5/aliases.5 b/gnu/dist/postfix/man/man5/aliases.5 index 8eab116ac01..394ad11788d 100644 --- a/gnu/dist/postfix/man/man5/aliases.5 +++ b/gnu/dist/postfix/man/man5/aliases.5 @@ -40,9 +40,11 @@ An alias definition has the form .ti +5 \fIname\fR: \fIvalue1\fR, \fIvalue2\fR, \fI...\fR .IP \(bu -Lines that begin with whitespace continue the previous line. +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. .IP \(bu -Blank lines are ignored, as are lines beginning with `#'. +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .PP The \fIname\fR is a local address (no domain part). Use double quotes when the name contains any special characters diff --git a/gnu/dist/postfix/man/man5/canonical.5 b/gnu/dist/postfix/man/man5/canonical.5 index 8dfaf2933f0..42cf7965700 100644 --- a/gnu/dist/postfix/man/man5/canonical.5 +++ b/gnu/dist/postfix/man/man5/canonical.5 @@ -50,13 +50,15 @@ Use the \fBaliases\fR(5) map for that purpose. .ad .fi The format of the \fBcanonical\fR table is as follows: -.IP "blanks and comments" -Blank lines are ignored, as are lines beginning with `#'. -.IP "leading whitespace" -Lines that begin with whitespace continue the previous line. .IP "\fIpattern result\fR" When \fIpattern\fR matches a mail address, replace it by the corresponding \fIresult\fR. +.IP "blank lines and comments" +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP "multi-line text" +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .PP With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, patterns are tried in the order as @@ -86,13 +88,11 @@ In all the above forms, when \fIaddress\fR has the form .nf .fi .ad -When table lookup fails, and the address localpart contains the -optional recipient delimiter (e.g., \fIuser+foo\fR@\fIdomain\fR), the -search is repeated for the unextended address (e.g. -\fIuser\fR@\fIdomain\fR), and the unmatched extension is propagated -to the result of table lookup. The matching order is: -\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, -\fIuser+foo\fR, \fIuser\fR, and @\fIdomain\fR. +When a mail address localpart contains the optional recipient delimiter +(e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR, +\fIuser\fR, and @\fIdomain\fR. An unmatched address extension +(\fI+foo\fR) is propagated to the result of table lookup. .SH REGULAR EXPRESSION TABLES .na .nf @@ -111,7 +111,7 @@ nor is \fIuser+foo\fR broken up into \fIuser\fR and \fIfoo\fR. Patterns are applied in the order as specified in the table, until a pattern is found that matches the search string. -Results are the same as with normal indexed file lookups, with +Results are the same as with indexed file lookups, with the additional feature that parenthesized substrings from the pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. .SH BUGS @@ -139,6 +139,10 @@ addresses. Other parameters of interest: .IP \fBinet_interfaces\fR The network interface addresses that this system receives mail on. +.IP \fBmasquerade_classes\fR +List of address classes subject to masquerading: zero or more of +\fBenvelope_sender\fR, \fBenvelope_recipient\fR, \fBheader_sender\fR, +\fBheader_recipient\fR. .IP \fBmasquerade_domains\fR List of domains that hide their subdomain structure. .IP \fBmasquerade_exceptions\fR diff --git a/gnu/dist/postfix/man/man5/pcre_table.5 b/gnu/dist/postfix/man/man5/pcre_table.5 index 85244230543..598839ee0a3 100644 --- a/gnu/dist/postfix/man/man5/pcre_table.5 +++ b/gnu/dist/postfix/man/man5/pcre_table.5 @@ -21,14 +21,15 @@ To find out what types of lookup tables your Postfix system supports use the \fBpostconf -m\fR command. The general form of a PCRE table is: -.IP "blanks and comments" -Blank lines are ignored, as are lines beginning with `#'. -.IP "leading whitespace" -Lines that begin with whitespace continue the previous line. .IP "\fIpattern result\fR" When \fIpattern\fR matches a search string, use the corresponding -\fIresult\fR. A line that starts with white space continues the -preceding line. +\fIresult\fR. +.IP "blank lines and comments" +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP "multi-line text" +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .PP Each pattern is a perl-like regular expression. The expression delimiter can be any character, except whitespace or characters @@ -56,21 +57,26 @@ Substitution of substrings from the matched expression into the result string is possible using the conventional perl syntax ($1, $2, etc.). The macros in the result string may need to be written as ${n} or $(n) if they aren't followed by whitespace. -.SH EXAMPLES +.SH EXAMPLE SMTPD ACCESS MAP .na .nf # Protect your outgoing majordomo exploders -/^(?!owner-)(.*)-outgoing@(my\.domain)$/ 550 Use ${1}@${2} instead +/^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead # Bounce friend@whatever, except when whatever is our domain (you would # be better just bouncing all friend@ mail - this is just an example). -/^friend@(?!my\.domain).*$/ 550 Stick this in your pipe $0 +/^friend@(?!my\\.domain)/ 550 Stick this in your pipe $0 # A multi-line entry. The text is sent as one line. # -/^noddy@connect\.com\.au$/ +/^noddy@my\\.domain$/ \ 550 This user is a funny one. You really don't want to send mail to \ them as it only makes their head spin. +.SH EXAMPLE HEADER FILTER MAP +.na +.nf +/^Subject: make money fast/ REJECT +/^To: friend@public\\.com/ REJECT .SH SEE ALSO .na .nf diff --git a/gnu/dist/postfix/man/man5/regexp_table.5 b/gnu/dist/postfix/man/man5/regexp_table.5 index efea3ef73e5..b561a4b149a 100644 --- a/gnu/dist/postfix/man/man5/regexp_table.5 +++ b/gnu/dist/postfix/man/man5/regexp_table.5 @@ -21,14 +21,15 @@ To find out what types of lookup tables your Postfix system supports use the \fBpostconf -m\fR command. The general form of a Postfix regular expression table is: -.IP "blanks and comments" -Blank lines are ignored, as are lines beginning with `#'. -.IP "leading whitespace" -Lines that begin with whitespace continue the previous line. .IP "\fIpattern result\fR" When \fIpattern\fR matches a search string, use the corresponding -\fIresult\fR. A line that starts with white space continues the -preceding line. +\fIresult\fR. +.IP "blank lines and comments" +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP "multi-line text" +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .IP "\fIpattern1!pattern2 result\fR" Matches \fIpattern1\fR but not \fIpattern2\fR. .PP @@ -58,19 +59,25 @@ Substitution of substrings from the matched expression into the result string is possible using $1, $2, etc.. The macros in the result string may need to be written as ${n} or $(n) if they aren't followed by whitespace. -.SH EXAMPLES +.SH EXAMPLE SMTPD ACCESS MAP .na .nf # Disallow sender-specified routing. This is a must if you relay mail # for other domains. -/[%!@].*[%!@]/ 550 Sender-specified routing rejected +/[%!@].*[%!@]/ 550 Sender-specified routing rejected # Postmaster is OK, that way they can talk to us about how to fix # their problem. -/^postmaster@.*$/ OK +/^postmaster@/ OK # Protect your outgoing majordomo exploders -/^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead +/^(.*)-outgoing@(.*)$/!/^owner-/ 550 Use ${1}@${2} instead +.SH EXAMPLE HEADER FILTER MAP +.na +.nf +# These were once common in junk mail. +/^Subject: make money fast/ REJECT +/^To: friend@public\\.com/ REJECT .SH SEE ALSO .na .nf diff --git a/gnu/dist/postfix/man/man5/relocated.5 b/gnu/dist/postfix/man/man5/relocated.5 index 727a732f63d..ddb318fc6d0 100644 --- a/gnu/dist/postfix/man/man5/relocated.5 +++ b/gnu/dist/postfix/man/man5/relocated.5 @@ -37,16 +37,18 @@ Table lookups are case insensitive. .fi The format of the table is as follows: .IP \(bu -Blank lines are ignored, as are lines beginning with `#'. -.IP \(bu -Lines that begin with whitespace continue the previous line. -.IP \(bu An entry has one of the following form: .ti +5 \fIkey new_location\fR .br Where \fInew_location\fR specifies contact information such as an email address, or perhaps a street address or telephone number. +.IP \(bu +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP \(bu +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .PP With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, the \fIkey\fR field is one of the @@ -66,10 +68,10 @@ precedence. .nf .fi .ad -When the search fails, and the address localpart contains the -optional recipient delimiter (e.g., \fIuser+foo\fR@\fIdomain\fR), -the search is repeated for the unextended address (e.g. -\fIuser\fR@\fIdomain\fR). +When a mail address localpart contains the optional recipient delimiter +(e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR, +\fIuser\fR, and @\fIdomain\fR. .SH REGULAR EXPRESSION TABLES .na .nf @@ -88,7 +90,7 @@ nor is \fIuser+foo\fR broken up into \fIuser\fR and \fIfoo\fR. Patterns are applied in the order as specified in the table, until a pattern is found that matches the search string. -Results are the same as with normal indexed file lookups, with +Results are the same as with indexed file lookups, with the additional feature that parenthesized substrings from the pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. .SH BUGS diff --git a/gnu/dist/postfix/man/man5/transport.5 b/gnu/dist/postfix/man/man5/transport.5 index 386d763f37a..d292c2916a4 100644 --- a/gnu/dist/postfix/man/man5/transport.5 +++ b/gnu/dist/postfix/man/man5/transport.5 @@ -35,13 +35,15 @@ the lookups are done in a slightly different way as described below. .ad .fi The format of the transport table is as follows: -.IP "blanks and comments" -Blank lines are ignored, as are lines beginning with `#'. -.IP "leading whitespace" -Lines that begin with whitespace continue the previous line. .IP "\fIpattern result\fR" When \fIpattern\fR matches the domain, use the corresponding \fIresult\fR. +.IP "blank lines and comments" +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP "multi-line text" +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .PP With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, patterns are tried in the order as @@ -51,7 +53,10 @@ Mail for \fIdomain\fR is delivered through \fItransport\fR to \fInexthop\fR. .IP "\fI.domain transport\fR:\fInexthop\fR" Mail for any subdomain of \fIdomain\fR is delivered through -\fItransport\fR to \fInexthop\fR. +\fItransport\fR to \fInexthop\fR. This applies only when the +string \fBtransport_maps\fR is not listed in the +\fBparent_domain_matches_subdomains\fR configuration setting. +Otherwise, a domain name matches itself and its subdomains. .PP Note: transport map entries take precedence over domains specified in the \fBmydestination\fR parameter. If you use @@ -138,7 +143,7 @@ broken up into parent domains. Patterns are applied in the order as specified in the table, until a pattern is found that matches the search string. -Results are the same as with normal indexed file lookups, with +Results are the same as with indexed file lookups, with the additional feature that parenthesized substrings from the pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. .SH CONFIGURATION PARAMETERS @@ -150,6 +155,10 @@ The following \fBmain.cf\fR parameters are especially relevant to 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 +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 diff --git a/gnu/dist/postfix/man/man5/virtual.5 b/gnu/dist/postfix/man/man5/virtual.5 index ef75b179de6..4ddc5d42e68 100644 --- a/gnu/dist/postfix/man/man5/virtual.5 +++ b/gnu/dist/postfix/man/man5/virtual.5 @@ -106,7 +106,7 @@ mydestination = $myhostname localhost.$mydomain $mydomain The \fBmain.cf mydestination\fR entry is required for a Sendmail-style virtual domain. -Do not specify a \fIvirtual.domain whatever\fR virtual map entry +Do not specify a \fIvirtual.domain anything\fR virtual map entry for a Sendmail-style virtual domain. Such an entry is required only with a Postfix-style virtual domain. @@ -122,13 +122,15 @@ mail to the sender. .fi The format of the virtual table is as follows, mappings being tried in the order as listed in this manual page: -.IP "blanks and comments" -Blank lines are ignored, as are lines beginning with `#'. -.IP "leading whitespace" -Lines that begin with whitespace continue the previous line. .IP "\fIpattern result\fR" When \fIpattern\fR matches a mail address, replace it by the corresponding \fIresult\fR. +.IP "blank lines and comments" +Empty lines and whitespace-only lines are ignored, as +are lines whose first non-whitespace character is a `#'. +.IP "multi-line text" +A logical line starts with non-whitespace text. A line that +starts with whitespace continues a logical line. .PP With lookups from indexed files such as DB or DBM, or from networked tables such as NIS, LDAP or SQL, patterns are tried in the order as @@ -156,13 +158,11 @@ This works for the first address in the expansion only. .nf .fi .ad -When the search fails, and the address localpart contains the -optional recipient delimiter (e.g., \fIuser+foo\fR@\fIdomain\fR), -the search is repeated for the unextended address (e.g. -\fIuser\fR@\fIdomain\fR), and the unmatched address extension is -propagated to the result of expansion. The matching order is: -\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, -\fIuser+foo\fR, \fIuser\fR, and @\fIdomain\fR. +When a mail address localpart contains the optional recipient delimiter +(e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +\fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR, +\fIuser\fR, and @\fIdomain\fR. An unmatched address extension +(\fI+foo\fR) is propagated to the result of table lookup. .SH REGULAR EXPRESSION TABLES .na .nf @@ -181,7 +181,7 @@ nor is \fIuser+foo\fR broken up into \fIuser\fR and \fIfoo\fR. Patterns are applied in the order as specified in the table, until a pattern is found that matches the search string. -Results are the same as with normal indexed file lookups, with +Results are the same as with indexed file lookups, with the additional feature that parenthesized substrings from the pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. .SH BUGS diff --git a/gnu/dist/postfix/man/man8/cleanup.8 b/gnu/dist/postfix/man/man8/cleanup.8 index 2cbdb5a3ac5..ed01ee8b612 100644 --- a/gnu/dist/postfix/man/man8/cleanup.8 +++ b/gnu/dist/postfix/man/man8/cleanup.8 @@ -41,7 +41,7 @@ Optionally, masquerade envelope sender addresses and message header addresses (i.e. strip host or domain information below all domains listed in the \fBmasquerade_domains\fR parameter, except for user names listed in \fBmasquerade_exceptions\fR). -Address masquerading does not affect envelope recipients. +By default, address masquerading does not affect envelope recipients. .IP \(bu Optionally, expand envelope recipients according to information found in the \fBvirtual\fR(5) lookup tables. @@ -108,6 +108,10 @@ addresses. .IP \fBsender_canonical_maps\fR Address mapping lookup table for envelope and header sender addresses. +.IP \fBmasquerade_classes\fR +List of address classes subject to masquerading: zero or +more of \fBenvelope_sender\fR, \fBenvelope_recipient\fR, +\fBheader_sender\fR, \fBheader_recipient\fR. .IP \fBmasquerade_domains\fR List of domains that hide their subdomain structure. .IP \fBmasquerade_exceptions\fR @@ -121,6 +125,9 @@ Address mapping lookup table for envelope recipient addresses. Limit the number of envelope recipients that are remembered. .IP \fBheader_size_limit\fR Limit the amount of memory in bytes used to process a message header. +.IP \fBin_flow_delay\fR +Amount of time to pause before accepting a message, when the +message arrival rate exceeds the message delivery rate. .IP \fBextract_recipient_limit\fR Limit the amount of recipients extracted from message headers. .SH SEE ALSO diff --git a/gnu/dist/postfix/man/man8/flush.8 b/gnu/dist/postfix/man/man8/flush.8 index 57eb598cec1..4aa4eb46ac0 100644 --- a/gnu/dist/postfix/man/man8/flush.8 +++ b/gnu/dist/postfix/man/man8/flush.8 @@ -44,7 +44,7 @@ destination's logfile, and the logfile is truncated to zero length; if mail is undeliverable it will be added back to the logfile. .sp If the destination is not eligible for a fast flush logfile, -this request triggers delivery of all queued mail. +this request is rejected (see below for status codes). .IP \fBTRIGGER_REQ_WAKEUP\fR This wakeup request from the master is an alternative way to request \fBFLUSH_REQ_REFRESH\fR. @@ -72,6 +72,10 @@ The flush server rejected the request (bad request name, bad request parameter value). .IP \fBFLUSH_STAT_FAIL\fR The request failed. +.IP \fBFLUSH_STAT_DENY\fR +The request was denied because the destination domain is not +eligible for fast flush service, or because the fast flush +service is disabled. .SH SECURITY .na .nf @@ -122,6 +126,10 @@ a send request for the corresponding destination. .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 +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 diff --git a/gnu/dist/postfix/man/man8/lmtp.8 b/gnu/dist/postfix/man/man8/lmtp.8 index 0521d53e5b5..b00dc9d3569 100644 --- a/gnu/dist/postfix/man/man8/lmtp.8 +++ b/gnu/dist/postfix/man/man8/lmtp.8 @@ -60,6 +60,7 @@ RFC 1870 (Message Size Declaration) RFC 2033 (LMTP protocol) RFC 2197 (Pipelining) RFC 2554 (AUTH command) +RFC 2821 (SMTP protocol) .SH DIAGNOSTICS .ad .fi @@ -103,7 +104,7 @@ Do not wait for the server response after sending QUIT. The TCP port to be used when connecting to a LMTP server. Used as backup if the \fBlmtp\fR service is not found in \fBservices\fR(4). .SH "Authentication controls" -.IP \fBlmtp_enable_sasl_auth\fR +.IP \fBlmtp_sasl_auth_enable\fR Enable per-session authentication as per RFC 2554 (SASL). By default, Postfix is built without SASL support. .IP \fBlmtp_sasl_password_maps\fR diff --git a/gnu/dist/postfix/man/man8/local.8 b/gnu/dist/postfix/man/man8/local.8 index c0929a6acba..13c2b761de3 100644 --- a/gnu/dist/postfix/man/man8/local.8 +++ b/gnu/dist/postfix/man/man8/local.8 @@ -96,7 +96,8 @@ mail arrives for a recipient that is already listed in a The default per-user mailbox is a file in the UNIX mail spool directory (\fB/var/mail/\fIuser\fR or \fB/var/spool/mail/\fIuser\fR); the location can be specified with the \fBmail_spool_directory\fR -configuration parameter. +configuration parameter. Specify a name ending in \fB/\fR for +\fBqmail\fR-compatible \fBmaildir\fR delivery. Alternatively, the per-user mailbox can be a file in the user's home directory with a name specified via the \fBhome_mailbox\fR @@ -193,13 +194,16 @@ and appends no empty line. .nf .ad .fi +The delivery format depends on the destination filename syntax. +The default is to use UNIX-style mailbox format. Specify a name +ending in \fB/\fR for \fBqmail\fR-compatible \fBmaildir\fR delivery. + The \fBallow_mail_to_files\fR configuration parameter restricts delivery to external files. The default setting (\fBalias, forward\fR) forbids file destinations in \fB:include:\fR files. -Specify a pathname ending in \fB/\fR for \fBqmail\fR-compatible -\fBmaildir\fR delivery. -The \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR" +In the case of UNIX-style mailbox delivery, +the \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR" envelope header to each message, prepends an optional \fBDelivered-To:\fR header with the recipient envelope address, prepends a \fB>\fR @@ -331,10 +335,14 @@ The \fIaddress\fR is subjected to \fI$name\fR expansion. .IP \fBmail_spool_directory\fR Directory with UNIX-style mailboxes. The default pathname is system dependent. +Specify a path ending in \fB/\fR for maildir-style delivery. .IP \fBmailbox_command\fR External command to use for mailbox delivery. The command executes with the recipient privileges (exception: root). The string is subject to $name expansions. +.IP \fBmailbox_command_maps\fR +Lookup tables with per-recipient external commands to use for mailbox +delivery. Behavior is as with \fBmailbox_command\fR. .IP \fBmailbox_transport\fR Message transport to use for mailbox delivery to all local recipients, whether or not they are found in the UNIX passwd database. diff --git a/gnu/dist/postfix/man/man8/nqmgr.8 b/gnu/dist/postfix/man/man8/nqmgr.8 new file mode 100644 index 00000000000..4a36d1df5a6 --- /dev/null +++ b/gnu/dist/postfix/man/man8/nqmgr.8 @@ -0,0 +1,307 @@ +.TH NQMGR 8 +.ad +.fi +.SH NAME +nqmgr +\- +Postfix queue manager +.SH SYNOPSIS +.na +.nf +\fBnqmgr\fR [generic Postfix daemon options] +.SH DESCRIPTION +.ad +.fi +The \fBnqmgr\fR daemon awaits the arrival of incoming mail +and arranges for its delivery via Postfix delivery processes. +The actual mail routing strategy is delegated to the +\fBtrivial-rewrite\fR(8) daemon. +This program expects to be run from the \fBmaster\fR(8) process +manager. + +Mail addressed to the local \fBdouble-bounce\fR address is silently +discarded. This stops potential loops caused by undeliverable +bounce notifications. + +Mail addressed to a user listed in the optional \fBrelocated\fR +database is bounced with a "user has moved to \fInew_location\fR" +message. See \fBrelocated\fR(5) for a precise description. +.SH MAIL QUEUES +.na +.nf +.ad +.fi +The \fBnqmgr\fR daemon maintains the following queues: +.IP \fBincoming\fR +Inbound mail from the network, or mail picked up by the +local \fBpickup\fR agent from the \fBmaildrop\fR directory. +.IP \fBactive\fR +Messages that the queue manager has opened for delivery. Only +a limited number of messages is allowed to enter the \fBactive\fR +queue (leaky bucket strategy, for a fixed delivery rate). +.IP \fBdeferred\fR +Mail that could not be delivered upon the first attempt. The queue +manager implements exponential backoff by doubling the time between +delivery attempts. +.IP \fBcorrupt\fR +Unreadable or damaged queue files are moved here for inspection. +.SH DELIVERY STATUS REPORTS +.na +.nf +.ad +.fi +The \fBnqmgr\fR daemon keeps an eye on per-message delivery status +reports in the following directories. Each status report file has +the same name as the corresponding message file: +.IP \fBbounce\fR +Per-recipient status information about why mail is bounced. +These files are maintained by the \fBbounce\fR(8) daemon. +.IP \fBdefer\fR +Per-recipient status information about why mail is delayed. +These files are maintained by the \fBdefer\fR(8) daemon. +.PP +The \fBnqmgr\fR daemon is responsible for asking the +\fBbounce\fR(8) or \fBdefer\fR(8) daemons to send non-delivery +reports. +.SH STRATEGIES +.na +.nf +.ad +.fi +The queue manager implements a variety of strategies for +either opening queue files (input) or for message delivery (output). +.IP "\fBleaky bucket\fR" +This strategy limits the number of messages in the \fBactive\fR queue +and prevents the queue manager from running out of memory under +heavy load. +.IP \fBfairness\fR +When the \fBactive\fR queue has room, the queue manager takes one +message from the \fBincoming\fR queue and one from the \fBdeferred\fR +queue. This prevents a large mail backlog from blocking the delivery +of new mail. +.IP "\fBslow start\fR" +This strategy eliminates "thundering herd" problems by slowly +adjusting the number of parallel deliveries to the same destination. +.IP "\fBround robin\fR +The queue manager sorts delivery requests by destination. +Round-robin selection prevents one destination from dominating +deliveries to other destinations. +.IP "\fBexponential backoff\fR" +Mail that cannot be delivered upon the first attempt is deferred. +The time interval between delivery attempts is doubled after each +attempt. +.IP "\fBdestination status cache\fR" +The queue manager avoids unnecessary delivery attempts by +maintaining a short-term, in-memory list of unreachable destinations. +.IP "\fBpreemptive message scheduling\fR" +The queue manager attempts to minimize the average per-recipient delay +while still preserving the correct per-message delays, using +a sophisticated preemptive message scheduling. +.SH TRIGGERS +.na +.nf +.ad +.fi +On an idle system, the queue manager waits for the arrival of +trigger events, or it waits for a timer to go off. A trigger +is a one-byte message. +Depending on the message received, the queue manager performs +one of the following actions (the message is followed by the +symbolic constant used internally by the software): +.IP "\fBD (QMGR_REQ_SCAN_DEFERRED)\fR" +Start a deferred queue scan. If a deferred queue scan is already +in progress, that scan will be restarted as soon as it finishes. +.IP "\fBI (QMGR_REQ_SCAN_INCOMING)\fR" +Start an incoming queue scan. If an incoming queue scan is already +in progress, that scan will be restarted as soon as it finishes. +.IP "\fBA (QMGR_REQ_SCAN_ALL)\fR" +Ignore deferred queue file time stamps. The request affects +the next deferred queue scan. +.IP "\fBF (QMGR_REQ_FLUSH_DEAD)\fR" +Purge all information about dead transports and destinations. +.IP "\fBW (TRIGGER_REQ_WAKEUP)\fR" +Wakeup call, This is used by the master server to instantiate +servers that should not go away forever. The action is to start +an incoming queue scan. +.PP +The \fBnqmgr\fR daemon reads an entire buffer worth of triggers. +Multiple identical trigger requests are collapsed into one, and +trigger requests are sorted so that \fBA\fR and \fBF\fR precede +\fBD\fR and \fBI\fR. Thus, in order to force a deferred queue run, +one would request \fBA F D\fR; in order to notify the queue manager +of the arrival of new mail one would request \fBI\fR. +.SH STANDARDS +.na +.nf +.ad +.fi +None. The \fBnqmgr\fR daemon does not interact with the outside world. +.SH SECURITY +.na +.nf +.ad +.fi +The \fBnqmgr\fR daemon is not security sensitive. It reads +single-character messages from untrusted local users, and thus may +be susceptible to denial of service attacks. The \fBnqmgr\fR daemon +does not talk to the outside world, and it can be run at fixed low +privilege in a chrooted environment. +.SH DIAGNOSTICS +.ad +.fi +Problems and transactions are logged to the syslog daemon. +Corrupted message files are saved to the \fBcorrupt\fR queue +for further inspection. + +Depending on the setting of the \fBnotify_classes\fR parameter, +the postmaster is notified of bounces and of other trouble. +.SH BUGS +.ad +.fi +A single queue manager process has to compete for disk access with +multiple front-end processes such as \fBsmtpd\fR. A sudden burst of +inbound mail can negatively impact outbound delivery rates. +.SH CONFIGURATION PARAMETERS +.na +.nf +.ad +.fi +The following \fBmain.cf\fR parameters are especially relevant to +this program. See the Postfix \fBmain.cf\fR file for syntax details +and for default values. Use the \fBpostfix reload\fR command after +a configuration change. +.SH Miscellaneous +.ad +.fi +.IP \fBallow_min_user\fR +Do not bounce recipient addresses that begin with '-'. +.IP \fBrelocated_maps\fR +Tables with contact information for users, hosts or domains +that no longer exist. See \fBrelocated\fR(5). +.IP \fBqueue_directory\fR +Top-level directory of the Postfix queue. +.SH "Active queue controls" +.ad +.fi +In the text below, \fItransport\fR is the first field in a +\fBmaster.cf\fR entry. +.IP \fBqmgr_message_active_limit\fR +Limit the number of messages in the active queue. +.IP \fBqmgr_message_recipient_limit\fR +Limit the number of in-memory recipients. +.sp +This parameter also limits the size of the short-term, in-memory +destination cache. +.IP \fBqmgr_message_recipient_minimum\fR +Per message minimum of in-memory recipients. +.IP \fBdefault_recipient_limit\fR +Default limit on the number of in-memory recipients per transport. +.IP \fItransport\fB_recipient_limit\fR +Limit on the number of in-memory recipients, for the named +message \fItransport\fR. +.IP \fBdefault_extra_recipient_limit\fR +Default limit on the total number of per transport in-memory +recipients that the preempting messages can have. +.IP \fItransport\fB_extra_recipient_limit\fR +Limit on the number of in-memory recipients which all preempting +messages delivered by the transport \fItransport\fR can have. +.SH "Timing controls" +.ad +.fi +.IP \fBmin_backoff\fR +Minimal time in seconds between delivery attempts +of a deferred message. +.sp +This parameter also limits the time an unreachable destination +is kept in the short-term, in-memory destination status cache. +.IP \fBmax_backoff\fR +Maximal time in seconds between delivery attempts +of a deferred message. +.IP \fBmaximal_queue_lifetime\fR +Maximal time in days a message is queued +before it is sent back as undeliverable. +.IP \fBqueue_run_delay\fR +Time in seconds between deferred queue scans. Queue scans do +not overlap. +.IP \fBtransport_retry_time\fR +Time in seconds between attempts to contact a broken +delivery transport. +.SH "Concurrency controls" +.ad +.fi +.IP \fBinitial_destination_concurrency\fR +Initial per-destination concurrency level for parallel delivery +to the same destination. +.IP \fBdefault_destination_concurrency_limit\fR +Default limit on the number of parallel deliveries to the same +destination. +.IP \fItransport\fB_destination_concurrency_limit\fR +Limit on the number of parallel deliveries to the same destination, +for delivery via the named message \fItransport\fR. +.SH "Recipient controls" +.ad +.fi +.IP \fBdefault_destination_recipient_limit\fR +Default limit on the number of recipients per message transfer. +.IP \fItransport\fB_destination_recipient_limit\fR +Limit on the number of recipients per message transfer, for the +named message \fItransport\fR. +.SH "Message scheduling" +.ad +.fi +.IP "\fItransport\fB_delivery_slot_cost\fR (valid range: 0,2,3...) +This parameter basically controls how often a message +delivered by \fItransport\fR can be preempted by another +message. +An internal per-message/transport counter is incremented by one +for each \fItransport\fB_delivery_slot_cost\fR +deliveries handled by \fItransport\fR. This counter represents +the number of "available delivery slots" for use by other messages. +Current message can be preempted by another message when that +other message can be delivered using less \fItransport\fR agents +than the value of the "available delivery slots" counter. +.sp +Value equal to 0 disables the message preemption for \fItransport\fR. +.IP \fItransport\fB_minimum_delivery_slots\fR +Message preemption is not attempted at all whenever a message +that can't ever accumulate at least \fItransport\fB_minimum_delivery_slots\fR +available delivery slots is being delivered by \fItransport\fR. +.IP "\fItransport\fB_delivery_slot_discount\fR (valid range: 0..100)" +.IP \fItransport\fB_delivery_slot_loan\fR +These parameters speed up the moment when a message preemption can happen. +Instead of waiting until the full amount of delivery slots +required is available, the preemption can happen when +\fItransport\fB_delivery_slot_discount\fR percent of the required +amount plus \fItransport\fB_delivery_slot_loan\fR still remains to +be accumulated. Note that the full amount will still have to be +accumulated before another preemption can take place later. +.IP \fBdefault_delivery_slot_cost\fR +.IP \fBdefault_minimum_delivery_slots\fR +.IP \fBdefault_delivery_slot_discount\fR +.IP \fBdefault_delivery_slot_loan\fR +Default values for the transport specific parameters described above. +.SH SEE ALSO +.na +.nf +master(8), process manager +relocated(5), format of the "user has moved" table +syslogd(8) system logging +trivial-rewrite(8), address routing +.SH LICENSE +.na +.nf +.ad +.fi +The Secure Mailer license must be distributed with this software. +.SH AUTHOR(S) +.na +.nf +Wietse Venema +IBM T.J. Watson Research +P.O. Box 704 +Yorktown Heights, NY 10598, USA + +Scheduler enhancements: +Patrik Rak +Modra 6 +155 00, Prague, Czech Republic diff --git a/gnu/dist/postfix/man/man8/pickup.8 b/gnu/dist/postfix/man/man8/pickup.8 index 8dfa64b68ab..bcc1b43cdf2 100644 --- a/gnu/dist/postfix/man/man8/pickup.8 +++ b/gnu/dist/postfix/man/man8/pickup.8 @@ -13,8 +13,8 @@ Postfix local mail pickup .ad .fi The \fBpickup\fR daemon waits for hints that new mail has been -dropped into the world-writable \fBmaildrop\fR directory, and -feeds it into the \fBcleanup\fR(8) daemon. +dropped into the \fBmaildrop\fR directory, and feeds it into the +\fBcleanup\fR(8) daemon. Ill-formatted files are deleted without notifying the originator. This program expects to be run from the \fBmaster\fR(8) process manager. @@ -76,6 +76,7 @@ Top-level directory of the Postfix queue. .nf cleanup(8) message canonicalization master(8) process manager +sendmail(1), postdrop(8) mail posting agent syslogd(8) system logging .SH LICENSE .na diff --git a/gnu/dist/postfix/man/man8/pipe.8 b/gnu/dist/postfix/man/man8/pipe.8 index 0ab6673ef49..65e566e480c 100644 --- a/gnu/dist/postfix/man/man8/pipe.8 +++ b/gnu/dist/postfix/man/man8/pipe.8 @@ -17,6 +17,10 @@ manager to deliver messages to external commands. This program expects to be run from the \fBmaster\fR(8) process manager. +Message attributes such as sender address, recipient address and +next-hop host name can be specified as command-line macros that are +expanded before the external command is executed. + The \fBpipe\fR daemon updates queue files and marks recipients as finished, or it informs the queue manager that delivery should be tried again at a later time. Delivery problem reports are sent @@ -46,7 +50,7 @@ entry for the pipe-based delivery transport. .fi The external command attributes are given in the \fBmaster.cf\fR file at the end of a service definition. The syntax is as follows: -.IP "\fBflags=BFR.>\fR (optional)" +.IP "\fBflags=BFRhqu.>\fR (optional)" Optional message processing flags. By default, a message is copied unchanged. .RS @@ -61,6 +65,27 @@ This is expected by, for example, \fBUUCP\fR software. .IP \fBR\fR Prepend a \fBReturn-Path:\fR message header with the envelope sender address. +.IP \fBh\fR +Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR +host name to lower case. +This is recommended for delivery via \fBUUCP\fR. +.IP \fBq\fR +Quote white space and other special characters in the command-line +\fB$sender\fR and \fB$recipient\fR address localparts (text to the +left of the right-most \fB@\fR character), according to an 8-bit +transparent version of RFC 822. +This is recommended for delivery via \fBUUCP\fR or \fBBSMTP\fR. +.sp +The result is compatible with the address parsing of command-line +recipients by the Postfix \fBsendmail\fR mail submission command. +.sp +The \fBq\fR flag affects only entire addresses, not the partial +address information from the \fB$user\fR, \fB$extension\fR or +\fB$mailbox\fR command-line macros. +.IP \fBu\fR +Fold the command-line \fB$recipient\fR address localpart (text to +the left of the right-most \fB@\fR character) to lower case. +This is recommended for delivery via \fBUUCP\fR. .IP \fB.\fR Prepend \fB.\fR to lines starting with "\fB.\fR". This is needed by, for example, \fBBSMTP\fR software. @@ -101,6 +126,8 @@ For example, with an address \fIuser+foo@domain\fR the extension is .sp A command-line argument that contains \fB${\fBextension\fR}\fR expands into as many command-line arguments as there are recipients. +.sp +This information is modified by the \fBu\fR flag for case folding. .IP \fB${\fBmailbox\fR}\fR This macro expands to the complete local part of a recipient address. For example, with an address \fIuser+foo@domain\fR the mailbox is @@ -108,15 +135,24 @@ For example, with an address \fIuser+foo@domain\fR the mailbox is .sp A command-line argument that contains \fB${\fBmailbox\fR}\fR expands into as many command-line arguments as there are recipients. +.sp +This information is modified by the \fBu\fR flag for case folding. .IP \fB${\fBnexthop\fR}\fR This macro expands to the next-hop hostname. +.sp +This information is modified by the \fBh\fR flag for case folding. .IP \fB${\fBrecipient\fR}\fR This macro expands to the complete recipient address. .sp A command-line argument that contains \fB${\fBrecipient\fR}\fR expands into as many command-line arguments as there are recipients. +.sp +This information is modified by the \fBhqu\fR flags for quoting +and case folding. .IP \fB${\fBsender\fR}\fR This macro expands to the envelope sender address. +.sp +This information is modified by the \fBq\fR flag for quoting. .IP \fB${\fBsize\fR}\fR This macro expands to Postfix's idea of the message size, which is an approximation of the size of the message as delivered. @@ -127,6 +163,8 @@ part is \fIuser\fR. .sp A command-line argument that contains \fB${\fBuser\fR}\fR expands into as many command-line arguments as there are recipients. +.sp +This information is modified by the \fBu\fR flag for case folding. .RE .PP In addition to the form ${\fIname\fR}, the forms $\fIname\fR and diff --git a/gnu/dist/postfix/man/man8/qmqpd.8 b/gnu/dist/postfix/man/man8/qmqpd.8 new file mode 100644 index 00000000000..f2b0c31a45d --- /dev/null +++ b/gnu/dist/postfix/man/man8/qmqpd.8 @@ -0,0 +1,120 @@ +.TH QMQPD 8 +.ad +.fi +.SH NAME +qmqpd +\- +Postfix QMQP server +.SH SYNOPSIS +.na +.nf +\fBqmqpd\fR [generic Postfix daemon options] +.SH DESCRIPTION +.ad +.fi +The Postfix QMQP server receives one message per connection. +Each message is piped through the \fBcleanup\fR(8) +daemon, and is placed into the \fBincoming\fR queue as one +single queue file. The program expects to be run from the +\fBmaster\fR(8) process manager. + +The QMQP server implements one access policy: only explicitly +authorized client hosts are allowed to use the service. +.SH SECURITY +.na +.nf +.ad +.fi +The QMQP server is moderately security-sensitive. It talks to QMQP +clients and to DNS servers on the network. The QMQP server can be +run chrooted at fixed low privilege. +.SH DIAGNOSTICS +.ad +.fi +Problems and transactions are logged to \fBsyslogd\fR(8). +.SH BUGS +.ad +.fi +The QMQP protocol provides only one server reply per message +delivery. It is therefore not possible to reject individual +recipients. + +The QMQP protocol requires the server to receive the entire +message before replying. If a message is malformed, or if any +netstring component is longer than acceptable, Postfix replies +immediately and closes the connection. It is left up to the +client to handle the situation. +.SH CONFIGURATION PARAMETERS +.na +.nf +.ad +.fi +The following \fBmain.cf\fR parameters are especially relevant to +this program. See the Postfix \fBmain.cf\fR file for syntax details +and for default values. Use the \fBpostfix reload\fR command after +a configuration change. +.SH Miscellaneous +.ad +.fi +.IP \fBalways_bcc\fR +Address to send a copy of each message that enters the system. +.IP \fBdebug_peer_level\fR +Increment in verbose logging level when a remote host matches a +pattern in the \fBdebug_peer_list\fR parameter. +.IP \fBdebug_peer_list\fR +List of domain or network patterns. When a remote host matches +a pattern, increase the verbose logging level by the amount +specified in the \fBdebug_peer_level\fR parameter. +.IP \fBhopcount_limit\fR +Limit the number of \fBReceived:\fR message headers. +.IP \fBqmqpd_authorized_clients\fR +A list of domain or network patterns that specifies what +clients are allowed to use the service. +.IP \fBqmqpd_timeout\fR +Limit the time to send a server response and to receive a client +request. +.IP \fBsoft_bounce\fR +Change hard (D) reject responses into soft (Z) reject responses. +This can be useful for testing purposes. +.SH "Content inspection controls" +.IP \fBcontent_filter\fR +The name of a mail delivery transport that filters mail and that +either bounces mail or re-injects the result back into Postfix. +This parameter uses the same syntax as the right-hand side of +a Postfix transport table. +.SH "Resource controls" +.ad +.fi +.IP \fBline_length_limit\fR +Limit the amount of memory in bytes used for the handling of +partial input lines, and the length of sender and recipient +addresses that are received from client. +.IP \fBmessage_size_limit\fR +Limit the total size in bytes of a message, including on-disk +storage for sender and recipient address information. +.SH Tarpitting +.ad +.fi +.IP \fBqmqpd_error_sleep_time\fR +Time to wait in seconds before informing the client of +a problem. This slows down run-away errors. +.SH SEE ALSO +.na +.nf +http://cr.yp.to/proto/qmqp.html, QMQP protocol +cleanup(8) message canonicalization +master(8) process manager +syslogd(8) system logging +.SH LICENSE +.na +.nf +.ad +.fi +The Secure Mailer license must be distributed with this software. +.SH AUTHOR(S) +.na +.nf +Wietse Venema +IBM T.J. Watson Research +P.O. Box 704 +Yorktown Heights, NY 10598, USA diff --git a/gnu/dist/postfix/man/man8/smtp.8 b/gnu/dist/postfix/man/man8/smtp.8 index ac6b37604eb..c111772b1a9 100644 --- a/gnu/dist/postfix/man/man8/smtp.8 +++ b/gnu/dist/postfix/man/man8/smtp.8 @@ -51,6 +51,7 @@ RFC 1651 (SMTP service extensions) RFC 1870 (Message Size Declaration) RFC 2197 (Pipelining) RFC 2554 (AUTH command) +RFC 2821 (SMTP protocol) .SH DIAGNOSTICS .ad .fi @@ -110,14 +111,23 @@ postmaster with transcripts of SMTP sessions with protocol errors. Always send EHLO at the start of a connection. .IP \fBsmtp_never_send_ehlo\fR Never send EHLO at the start of a connection. +.IP \fBsmtp_bind_address\fR +Numerical source network address to bind to when making a connection. +.IP \fBsmtp_break_lines\fR +Break lines > \fB$line_length_limit\fR into multiple shorter lines. +Some SMTP servers misbehave on long lines. .IP \fBsmtp_skip_4xx_greeting\fR Skip servers that greet us with a 4xx status code. .IP \fBsmtp_skip_5xx_greeting\fR Skip servers that greet us with a 5xx status code. .IP \fBsmtp_skip_quit_response\fR Do not wait for the server response after sending QUIT. -.IP \fBsmtp_bind_address\fR -Numerical network address to bind to when making a connection. +.IP \fBsmtp_pix_workaround_delay_time\fR +The time to pause before sending .<CR><LF>, while working +around the CISCO PIX firewall <CR><LF>.<CR><LF> bug. +.IP \fBsmtp_pix_workaround_threshold_time\fR +The time a message must be queued before the CISCO PIX firewall +<CR><LF>.<CR><LF> bug workaround is turned on. .SH "Authentication controls" .IP \fBsmtp_enable_sasl_auth\fR Enable per-session authentication as per RFC 2554 (SASL). diff --git a/gnu/dist/postfix/man/man8/smtpd.8 b/gnu/dist/postfix/man/man8/smtpd.8 index 7b5a4ea6e91..73814bedab6 100644 --- a/gnu/dist/postfix/man/man8/smtpd.8 +++ b/gnu/dist/postfix/man/man8/smtpd.8 @@ -42,12 +42,13 @@ run chrooted at fixed low privilege. .nf RFC 821 (SMTP protocol) RFC 1123 (Host requirements) -RFC 1651 (SMTP service extensions) RFC 1652 (8bit-MIME transport) +RFC 1869 (SMTP service extensions) RFC 1854 (SMTP Pipelining) RFC 1870 (Message Size Declaration) RFC 1985 (ETRN command) RFC 2554 (AUTH command) +RFC 2821 (SMTP protocol) .SH DIAGNOSTICS .ad .fi @@ -69,12 +70,16 @@ a configuration change. .ad .fi .IP \fBstrict_rfc821_envelopes\fR -Disallow non-RFC 821 style addresses in envelopes. For example, -allow RFC822-style address forms with comments, like Sendmail does. +Disallow non-RFC 821 style addresses in SMTP commands. For example, +the RFC822-style address forms with comments that Sendmail allows. .IP \fBbroken_sasl_auth_clients\fR Support older Microsoft clients that mis-implement the AUTH protocol, and that expect an EHLO response of "250 AUTH=list" instead of "250 AUTH list". +.IP \fBsmtpd_noop_commands\fR +List of commands that are treated as NOOP (no operation) commands, +without any parameter syntax checking and without any state change. +This list overrides built-in command definitions. .SH "Content inspection controls" .IP \fBcontent_filter\fR The name of a mail delivery transport that filters mail and that @@ -102,6 +107,10 @@ dictionary attack. .IP \fBnoanonymous\fR Disallow anonymous logins. .RE +.IP \fBsmtpd_sender_login_maps\fR +Maps that specify the SASL login name that owns a MAIL FROM sender +address. Used by the \fBreject_sender_login_mismatch\fR sender +anti-spoofing restriction. .SH Miscellaneous .ad .fi @@ -117,6 +126,9 @@ pattern in the \fBdebug_peer_list\fR parameter. List of domain or network patterns. When a remote host matches a pattern, increase the verbose logging level by the amount specified in the \fBdebug_peer_level\fR parameter. +.IP \fBdefault_verp_delimiters\fR +The default VERP delimiter characters that are used when the +XVERP command is specified without explicit delimiters. .IP \fBerror_notice_recipient\fR Recipient of protocol/policy/resource/software error notices. .IP \fBhopcount_limit\fR @@ -147,6 +159,8 @@ request. .IP \fBsoft_bounce\fR Change hard (5xx) reject responses into soft (4xx) reject responses. This can be useful for testing purposes. +.IP \fBverp_delimiter_filter\fR +The characters that Postfix accepts as VERP delimiter characters. .SH "Resource controls" .ad .fi @@ -159,6 +173,9 @@ storage for envelope information. .IP \fBqueue_minfree\fR Minimal amount of free space in bytes in the queue file system for the SMTP server to accept any mail at all. +.IP \fBsmtpd_history_flush_threshold\fR +Flush the command history to postmaster after receipt of RSET etc. +only if the number of history lines exceeds the given threshold. .SH Tarpitting .ad .fi @@ -177,6 +194,10 @@ it is penalized with tarpit delays. .SH "UCE control restrictions" .ad .fi +.IP \fBparent_domain_matches_subdomains\fR +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 @@ -200,9 +221,15 @@ trusted backup MX hosts. Declares the name of zero or more parameters that contain a list of UCE restrictions. The names of these parameters can then be used instead of the restriction lists that they represent. +.IP \fBsmtpd_null_access_lookup_key\fR +The lookup key to be used in SMTPD access tables instead of the +null sender address. A null sender address cannot be looked up. .IP \fBmaps_rbl_domains\fR List of DNS domains that publish the addresses of blacklisted hosts. +.IP \fBpermit_mx_backup_networks\fR +Only domains whose primary MX hosts match the listed networks +are eligible for the \fBpermit_mx_backup\fR feature. .IP \fBrelay_domains\fR Restrict what domains or networks this mail system will relay mail from or to. diff --git a/gnu/dist/postfix/man/man8/trivial-rewrite.8 b/gnu/dist/postfix/man/man8/trivial-rewrite.8 index bf110a70261..3aa705f575e 100644 --- a/gnu/dist/postfix/man/man8/trivial-rewrite.8 +++ b/gnu/dist/postfix/man/man8/trivial-rewrite.8 @@ -108,6 +108,10 @@ The default transport is \fBsmtp\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 +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. diff --git a/gnu/dist/postfix/man/man8/virtual.8 b/gnu/dist/postfix/man/man8/virtual.8 new file mode 100644 index 00000000000..b76c1a75241 --- /dev/null +++ b/gnu/dist/postfix/man/man8/virtual.8 @@ -0,0 +1,236 @@ +.TH VIRTUAL 8 +.ad +.fi +.SH NAME +virtual +\- +Postfix virtual domain mail delivery agent +.SH SYNOPSIS +.na +.nf +\fBvirtual\fR [generic Postfix daemon options] +.SH DESCRIPTION +.ad +.fi +The \fBvirtual\fR delivery agent is designed for virtual mail +hosting services. Originally based on the Postfix local delivery +agent, this agent looks up recipients with map lookups of their +full recipient address, instead of using hard-coded unix password +file lookups of the address local part only. + +This delivery agent only delivers mail. Other features such as +mail forwarding, out-of-office notifications, etc., must be +configured via virtual maps or via similar lookup mechanisms. +.SH MAILBOX LOCATION +.na +.nf +.ad +.fi +The mailbox location is controlled by the \fBvirtual_mailbox_base\fR +and \fBvirtual_mailbox_maps\fR configuration parameters (see below). +The \fBvirtual_mailbox_maps\fR table is indexed by the full recipient +address. + +The mailbox pathname is constructed as follows: + +.ti +2 +\fB$virtual_mailbox_base/$virtual_mailbox_maps(\fIrecipient\fB)\fR + +where \fIrecipient\fR is the full recipient address. +.SH UNIX MAILBOX FORMAT +.na +.nf +.ad +.fi +When the mailbox location does not end in \fB/\fR, the message +is delivered in UNIX mailbox format. This format stores multiple +messages in one textfile. + +The \fBvirtual\fR delivery agent prepends a "\fBFrom \fIsender +time_stamp\fR" envelope header to each message, prepends a +\fBDelivered-To:\fR message header with the envelope recipient +address, prepends a \fBReturn-Path:\fR message header with the +envelope sender address, prepends a \fB>\fR character to lines +beginning with "\fBFrom \fR", and appends an empty line. + +The mailbox is locked for exclusive access while delivery is in +progress. In case of problems, an attempt is made to truncate the +mailbox to its original length. +.SH QMAIL MAILDIR FORMAT +.na +.nf +.ad +.fi +When the mailbox location ends in \fB/\fR, the message is delivered +in qmail \fBmaildir\fR format. This format stores one message per file. + +The \fBvirtual\fR delivery agent daemon prepends a \fBDelivered-To:\fR +message header with the envelope recipient address and prepends a +\fBReturn-Path:\fR message header with the envelope sender address. + +By definition, \fBmaildir\fR format does not require file locking +during mail delivery or retrieval. +.SH MAILBOX OWNERSHIP +.na +.nf +.ad +.fi +Mailbox ownership is controlled by the \fBvirtual_uid_maps\fR +and \fBvirtual_gid_maps\fR lookup tables, which are indexed +with the full recipient address. Each table provides +a string with the numerical user and group ID, respectively. + +The \fBvirtual_minimum_uid\fR parameter imposes a lower bound on +numerical user ID values that may be specified in any +\fBvirtual_owner_maps\fR or \fBvirtual_uid_maps\fR. +.SH SECURITY +.na +.nf +.ad +.fi +The virtual delivery agent is not security sensitive, provided +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 +RFC 822 (ARPA Internet Text Messages) +.SH DIAGNOSTICS +.ad +.fi +Mail bounces when the recipient has no mailbox or when the +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 \fBsyslogd\fR(8). +Corrupted message files are marked so that the queue +manager can move them to the \fBcorrupt\fR queue afterwards. + +Depending on the setting of the \fBnotify_classes\fR parameter, +the postmaster is notified of bounces and of other trouble. +.SH BUGS +.ad +.fi +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 maintaining +three tables, use an LDAP or MYSQL database. +.SH CONFIGURATION PARAMETERS +.na +.nf +.ad +.fi +The following \fBmain.cf\fR parameters are especially relevant to +this program. See the Postfix \fBmain.cf\fR file for syntax details +and for default values. Use the \fBpostfix reload\fR command after +a configuration change. +.SH Mailbox delivery +.ad +.fi +.IP \fBvirtual_mailbox_base\fR +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 +\fBvirtual_mailbox_maps\fR doesn't litter the filesystem with mailboxes. +While it could be set to "/", this setting isn't recommended. +.IP "\fBvirtual_mailbox_maps\fR (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 assumed to specify a UNIX-style mailbox file. + +Note that \fBvirtual_mailbox_base\fR is unconditionally prepended +to this path. +.IP \fBvirtual_minimum_uid\fR +Specifies a minimum uid that will be accepted as a return from +a \fBvirtual_owner_maps\fR or \fBvirtual_uid_maps\fR lookup. +Returned values less than this will be rejected, and the message +will be deferred. +.IP "\fBvirtual_uid_maps\fR (regexp maps disallowed)" +Recipients are looked up in these maps to determine the user ID to be +used when writing to the target mailbox. +.IP "\fBvirtual_gid_maps\fR (regexp maps disallowed)" +Recipients are looked up in these maps to determine the group ID to be +used when writing to the target mailbox. +.SH "Locking controls" +.ad +.fi +.IP \fBvirtual_mailbox_lock\fR +How to lock UNIX-style mailboxes: one or more of \fBflock\fR, +\fBfcntl\fR or \fBdotlock\fR. The \fBdotlock\fR method requires +that the recipient UID or GID has write access to the parent +directory of the mailbox file. + +This setting is ignored with \fBmaildir\fR style delivery, +because such deliveries are safe without explicit locks. + +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 +on a UNIX-style mailbox file. +.IP \fBdeliver_lock_delay\fR +Time (default: seconds) between successive attempts to acquire +an exclusive lock on a UNIX-style mailbox file. The actual delay +is slightly randomized. +.IP \fBstale_lock_time\fR +Limit the time after which a stale lockfile is removed (applicable +to UNIX-style mailboxes only). +.SH "Resource controls" +.ad +.fi +.IP \fBvirtual_destination_concurrency_limit\fR +Limit the number of parallel deliveries to the same domain +via the \fBvirtual\fR delivery agent. +The default limit is taken from the +\fBdefault_destination_concurrency_limit\fR parameter. +The limit is enforced by the Postfix queue manager. +.IP \fBvirtual_destination_recipient_limit\fR +Limit the number of recipients per message delivery +via the \fBvirtual\fR delivery agent. +The default limit is taken from the +\fBdefault_destination_recipient_limit\fR parameter. +The limit is enforced by the Postfix queue manager. +.IP \fBvirtual_mailbox_limit\fR +The maximal size in bytes of a mailbox or maildir file. +Set to zero to disable the limit. +.SH HISTORY +.na +.nf +.ad +.fi +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 to "|command" or to /file/name. + +The \fBDelivered-To:\fR header appears in the \fBqmail\fR system +by Daniel Bernstein. + +The \fBmaildir\fR structure appears in the \fBqmail\fR system +by Daniel Bernstein. +.SH SEE ALSO +.na +.nf +bounce(8) non-delivery status reports +syslogd(8) system logging +qmgr(8) queue manager +.SH LICENSE +.na +.nf +.ad +.fi +The Secure Mailer license must be distributed with this software. +.SH AUTHOR(S) +.na +.nf +Wietse Venema +IBM T.J. Watson Research +P.O. Box 704 +Yorktown Heights, NY 10598, USA + +Andrew McNamara +andrewm@connect.com.au +connect.com.au Pty. Ltd. +Level 3, 213 Miller St +North Sydney 2060, NSW, Australia diff --git a/gnu/dist/postfix/mantools/postlink b/gnu/dist/postfix/mantools/postlink index d9c57a9c150..f53c82d9cce 100755 --- a/gnu/dist/postfix/mantools/postlink +++ b/gnu/dist/postfix/mantools/postlink @@ -19,6 +19,7 @@ exec sed ' s/[<bB>]*pickup[</bB>]*(8)/<a href="pickup.8.html">&<\/a>/ s/[<bB>]*pipe[</bB>]*(8)/<a href="pipe.8.html">&<\/a>/ s/[<bB>]*qmgr[</bB>]*(8)/<a href="qmgr.8.html">&<\/a>/ + s/[<bB>]*qmqpd[</bB>]*(8)/<a href="qmqpd.8.html">&<\/a>/ s/[<bB>]*showq[</bB>]*(8)/<a href="showq.8.html">&<\/a>/ s/[<bB>]*smtp[</bB>]*(8)/<a href="smtp.8.html">&<\/a>/ s/[<bB>]*smtpd[</bB>]*(8)/<a href="smtpd.8.html">&<\/a>/ @@ -35,6 +36,8 @@ exec sed ' s/[<bB>]*postlock[</bB>]*(1)/<a href="postlock.1.html">&<\/a>/ s/[<bB>]*postlog[</bB>]*(1)/<a href="postlog.1.html">&<\/a>/ s/[<bB>]*postmap[</bB>]*(1)/<a href="postmap.1.html">&<\/a>/ + s/[<bB>]*postqueue[</bB>]*(1)/<a href="postqueue.1.html">&<\/a>/ + s/[<bB>]*postsuper[</bB>]*(1)/<a href="postsuper.1.html">&<\/a>/ s/[<bB>]*send[-</bB>]*\n*[ <bB>]*mail[</bB>]*(1)/<a href="sendmail.1.html">&<\/a>/ s/[<bB>]*access[</bB>]*(5)/<a href="access.5.html">&<\/a>/ s/[<bB>]*aliases[</bB>]*(5)/<a href="aliases.5.html">&<\/a>/ @@ -47,5 +50,6 @@ exec sed ' s/[<bB>]*virtual[</bB>]*(5)/<a href="virtual.5.html">&<\/a>/ s/[<bB>]*virtual[</bB>]*(8)/<a href="virtual.8.html">&<\/a>/ s/\(<a href="[^"]*">\)\([<bB>]*[a-z0-9-]*[-</bB>]*\)\(\n *\)\([<bB>]*[a-z0-9-]*[</bB>]*([0-9])\)\(<\/a>\)/\1\2\5\3\1\4\5/ + s/http:\/\/[^ ,]*/<a href="&">&<\/a>/ s/RFC *\([0-9]*\)/<a href="http:\/\/www.faqs.org\/rfcs\/rfc\1.html">&<\/a>/ ' "$@" diff --git a/gnu/dist/postfix/postfix-install b/gnu/dist/postfix/postfix-install new file mode 100644 index 00000000000..66bbd557169 --- /dev/null +++ b/gnu/dist/postfix/postfix-install @@ -0,0 +1,675 @@ +#!/bin/sh + +# To view the formatted manual page of this file, type: +# POSTFIXSOURCE/mantools/srctoman - postfix-install | nroff -man + +#++ +# NAME +# postfix-install 1 +# SUMMARY +# Postfix installation procedure +# SYNOPSIS +# sh postfix-install [options] [name=value] ... +# DESCRIPTION +# The postfix-install script is to be run from the top-level +# Postfix source directory. It implements the following operations: +# .IP o +# Install or upgrade Postfix from source code. This requires +# super-user privileges. +# .IP o +# Build a package that can be distributed to other systems, in order +# to install or upgrade Postfix elsewhere. This requires no super-user +# privileges. To complete the installation after unpacking the +# package, execute as super-user the post-install script in the Postfix +# configuration directory. +# .PP +# The postfix-install script is controlled by installation parameters. +# Specific parameters are described at the end of this document. +# +# By default, postfix-install asks the user for installation +# parameter settings. Most settings are stored in the installed +# main.cf file. Stored settings are used as site-specific defaults +# when the postfix-install script is run later. +# +# The names of Postfix files and directories, as well as their +# ownerships and permissions, are stored in the postfix-files file +# in the Postfix configuration directory. This information is used +# by the post-install script (also in the configuration directory) +# for creating missing queue directories when Postfix is started, +# and for setting correct ownership and permissions when Postfix +# is installed from a pre-built package or from source code. +# +# Arguments +# .IP -non-interactive +# Do not ask the user for parameter settings. Installation parameters +# are specified via one of the non-interactive methods described +# below. +# INSTALLATION PARAMETER INPUT METHODS +# .ad +# .fi +# Parameter settings can be specified through a variety of +# mechanisms. In order of decreasing precedence these are: +# .IP "interactive mode" +# By default, postfix-install will ask the user for installation +# parameter settings. These settings have the highest precedence. +# .IP "command line" +# Parameter settings can be given as name=value arguments on +# the postfix-install command line. +# .IP "process environment" +# Parameter settings can be given as name=value environment +# variables. Environment parameters can also be specified on the +# make(1) command line as "make install name=value ...". +# .IP "installed configuration files" +# If a parameter is not specified via the command line or via the +# process environment, postfix-install will attempt to extract its +# value from an already installed Postfix main.cf configuration file. +# .IP "built-in defaults" +# These settings have the lowest precedence. +# INSTALLATION PARAMETER DESCRIPTION +# .ad +# .fi +# The description of installation parameters and their built-in +# default settings is as follows: +# .IP install_root +# Prefix that is prepended to the pathnames of installed files. +# This is useful for creating a pre-built package for distribution to +# other systems. The built-in default is "/", the local root directory. +# This parameter setting is not recorded in the installed main.cf file. +# .IP tempdir +# Directory for scratch files while installing Postfix. +# You must have write permission in this directory. +# The built-in default directory name is the current directory. +# This parameter setting is not recorded in the installed main.cf file. +# .IP config_directory +# The destination directory for Postfix configuration files. +# The built-in default directory name is /etc/postfix. +# This parameter setting is not recorded in the installed main.cf file. +# .IP daemon_directory +# The destination directory for Postfix daemon programs. This directory +# should not be in the command search path of any users. +# The built-in default directory name is /usr/libexec/postfix. +# This parameter setting is recorded in the installed main.cf file. +# .IP command_directory +# The destination directory for Postfix administrative commands. This +# directory should be in the command search path of adminstrative users. +# The built-in default directory name is system dependent. +# This parameter setting is recorded in the installed main.cf file. +# .IP queue_directory +# The destination directory for Postfix queues. +# The built-in default directory name is /var/spool/postfix. +# This parameter setting is recorded in the installed main.cf file. +# .IP sendmail_path +# The full destination pathname for the Postfix sendmail command. +# This is the Sendmail-compatible mail posting interface. +# The built-in default pathname is system dependent. +# This parameter setting is recorded in the installed main.cf file. +# .IP newaliases_path +# The full destination pathname for the Postfix newaliases command. +# This is the Sendmail-compatible command to build alias databases +# for the Postfix local delivery agent. +# The built-in default pathname is system dependent. +# This parameter setting is recorded in the installed main.cf file. +# .IP mailq_path +# The full destination pathname for the Postfix mailq command. +# This is the Sendmail-compatible command to list the mail queue. +# The built-in default pathname is system dependent. +# This parameter setting is recorded in the installed main.cf file. +# .IP mail_owner +# The owner of the Postfix queue. Its numerical user ID and group ID +# must not be used by any other accounts on the system. +# The built-in default account name is postfix. +# This parameter setting is recorded in the installed main.cf file. +# .IP setgid_group +# The group for mail submission and for queue management commands. +# Its numerical group ID must not be used by any other accounts on the +# system, not even by the mail_owner account. +# The built-in default group name is postdrop. +# This parameter setting is recorded in the installed main.cf file. +# .IP manpage_directory +# The destination directory for the Postfix on-line manual pages. +# This parameter setting is recorded in the installed main.cf file. +# .IP sample_directory +# The destination directory for the Postfix sample configuration files. +# This parameter setting is recorded in the installed main.cf file. +# .IP readme_directory +# The destination directory for the Postfix README files. +# This parameter setting is recorded in the installed main.cf file. +# SEE ALSO +# post-install(1) post-installation procedure +# FILES +# $config_directory/main.cf, Postfix installation configuration. +# $config_directory/postfix-files, installation control file. +# $config_directory/install.cf, obsolete configuration file. +# 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 +#-- + +# Initialize. +# By now, shells must have functions. Ultrix users must use sh5 or lose. + +umask 022 +PATH=/bin:/usr/bin:/usr/sbin:/usr/etc:/sbin:/etc:/usr/contrib/bin:/usr/gnu/bin:/usr/ucb:/usr/bsd +SHELL=/bin/sh +IFS=" +" +BACKUP_IFS="$IFS" + +USAGE="Usage: $0 [name=value] [option] + -non-interactive Do not ask for installation parameters. + name=value Specify an installation parameter". + +# Process command-line options and parameter settings. Work around +# brain damaged shells. "IFS=value command" should not make the +# IFS=value setting permanent. But some broken standard allows it. + +for arg +do + case $arg in + *=*) IFS= eval $arg; IFS="$BACKUP_IFS";; +-non-int*) non_interactive=1;; + *) echo $0: Error: $USAGE 1>&2; exit 1;; + esac + shift +done + +# Sanity checks. + +test -z "$non_interactive" -a ! -t 0 && { + echo $0: Error: for non-interactive use, run: \"$0 -non-interactive\" 1>&2 + exit 1 +} + +test -x bin/postconf || { + echo $0: Error: no bin/postconf file. Did you forget to run \"make\"? 1>&2 + exit 1 +} + +# +# LINUX by default does not synchronously update directories - +# that's dangerous for mail. +# +if [ -f /usr/bin/chattr ] +then + CHATTR="/usr/bin/chattr +S" +else + CHATTR=echo +fi + +case `uname -s` in +HP-UX*) FMT=cat;; + *) FMT=fmt;; +esac + +# Disclaimer. + +test -z "$non_interactive" && cat <<EOF | ${FMT} + + Warning: if you use this script to install Postfix locally, + this script will replace existing sendmail or Postfix programs. + Make backups if you want to be able to recover. + + Before installing files, this script prompts you for some + definitions. Most definitions will be remembered, so you have + to specify them only once. All definitions should have a + reasonable default value. +EOF + +# The following shell functions replace files/symlinks while minimizing +# the time that a file does not exist, and avoid copying over files +# in order to not disturb running programs. That is certainly desirable +# when upgrading Postfix on a live machine. It also avoids surprises +# when building a Postfix package for distribution to other systems. + +compare_or_replace() { + mode=$1 + owner=$2 + group=$3 + src=$4 + dst=$5 + (cmp $src $dst >/dev/null 2>&1 && echo Skipping $dst...) || { + echo Updating $dst... + rm -f $tempdir/junk || exit 1 + cp $src $tempdir/junk || exit 1 + mv -f $tempdir/junk $dst || exit 1 + test -z "$owner" || chown $owner $dst || exit 1 + test -z "$group" || chgrp $group $dst || exit 1 + chmod $mode $dst || exit 1 + } +} + +compare_or_symlink() { + (cmp $1 $2 >/dev/null 2>&1 && echo Skipping $2...) || { + echo Updating $2... + rm -f $tempdir/junk || exit 1 + dest=`echo $1 | sed ' + s;^'$install_root';; + s;/\./;/;g + s;//*;/;g + s;^/;; + '` + link=`echo $2 | sed ' + s;^'$install_root';; + s;/\./;/;g + s;//*;/;g + s;^/;; + s;/[^/]*$;/; + s;[^/]*/;../;g + s;$;'$dest'; + '` + ln -s $link $tempdir/junk || exit 1 + mv -f $tempdir/junk $2 || { + echo $0: Error: your mv command is unable to rename symlinks. 1>&2 + echo If you run Linux, upgrade to GNU fileutils-4.0 or better, 1>&2 + echo or choose a tempdir that is in the same file system as $2. 1>&2 + exit 1 + } + } +} + +check_parent() { + for path + do + dir=`echo $path|sed -e 's/[/][/]*[^/]*$//' -e 's/^$/\//'` + test -d $dir || mkdir -p $dir || exit 1 + done +} + +# How to supress newlines in echo. + +case `echo -n` in +"") n=-n; c=;; + *) n=; c='\c';; +esac + +# Prompts. + +install_root_prompt="the prefix for installed file names. This is +useful if you are building ready-to-install packages for distribution +to other machines." + +tempdir_prompt="a directory for scratch files while installing +Postfix. You must have write permission in this directory." + +config_directory_prompt="the destination directory for installed +Postfix configuration files." + +daemon_directory_prompt="the destination directory for installed +Postfix daemon programs. This directory should not be in the +command search path of any users." + +command_directory_prompt="the destination directory for installed +Postfix administrative commands. This directory should be in the +command search path of adminstrative users." + +queue_directory_prompt="the destination directory for Postfix +queues." + +sendmail_path_prompt="the full destination pathname for the installed +Postfix sendmail command. This is the Sendmail-compatible mail +posting interface." + +newaliases_path_prompt="the full destination pathname for the +installed Postfix newaliases command. This is the Sendmail-compatible +command to build alias databases for the Postfix local delivery +agent." + +mailq_path_prompt="the full destination pathname for the installed +Postfix mailq command. This is the Sendmail-compatible mail queue +listing command." + +mail_owner_prompt="the owner of the Postfix queue. Specify an +account with numerical user ID and group ID values that are not +used by any other accounts on the system." + +setgid_group_prompt="the group for mail submission and for queue +management commands. Specify a group name with a numerical group +ID that is not shared with other accounts, not even with the Postfix +mail_owner account. You can no longer specify \"no\" here." + +manpage_directory_prompt="the destination directory for the Postfix on-line +manual pages. You can no longer specify \"no\" here." + +sample_directory_prompt="the destination directory for the Postfix +sample configuration files." + +readme_directory_prompt="the destination directory for the Postfix +README files. Specify \"no\" if you do not want to install these files." + +# Default settings, just to get started. + +: ${install_root=/} +: ${tempdir=`pwd`} +: ${config_directory=`bin/postconf -h -d config_directory`} + +# Find out the location of installed configuration files. + +test -z "$non_interactive" && for name in install_root tempdir config_directory +do + while : + do + echo + eval echo Please specify \$${name}_prompt | ${FMT} + eval echo \$n "$name: [\$$name]\ \$c" + read ans + case $ans in + "") break;; + *) case $ans in + /*) eval $name=$ans; break;; + *) echo; echo $0: Error: $name should be an absolute path name. 1>&2;; + esac;; + esac + done +done + +# In case some systems special-case pathnames beginning with //. + +case $install_root in +/) install_root= +esac + +CONFIG_DIRECTORY=$install_root$config_directory + +# If a parameter is not set via the command line or environment, +# try to use settings from installed configuration files. + +# Extract parameter settings from the obsolete install.cf file, as +# a transitional aid. + +grep setgid_group $CONFIG_DIRECTORY/main.cf >/dev/null 2>&1 || { + test -f $CONFIG_DIRECTORY/install.cf && { + for name in sendmail_path newaliases_path mailq_path setgid manpages + do + eval junk=\$$name + case "$junk" in + "") eval unset $name;; + esac + eval : \${$name="\`. $CONFIG_DIRECTORY/install.cf; echo \$$name\`"} \ + || exit 1 + done + : ${setgid_group=$setgid} + : ${manpage_directory=$manpages} + } +} + +# Extract parameter settings from the installed main.cf file. + +test -f $CONFIG_DIRECTORY/main.cf && { + for name in daemon_directory command_directory queue_directory mail_owner \ + setgid_group sendmail_path newaliases_path mailq_path manpage_directory \ + sample_directory readme_directory + do + eval junk=\$$name + case "$junk" in + "") eval unset $name;; + esac + eval : \${$name=\`bin/postconf -c $CONFIG_DIRECTORY -h $name\`} || + exit 1 + done +} + +# Use built-in defaults as the final source of parameter settings. + +for name in daemon_directory command_directory queue_directory mail_owner \ + setgid_group sendmail_path newaliases_path mailq_path manpage_directory \ + sample_directory readme_directory +do + eval junk=\$$name + case "$junk" in + "") eval unset $name;; + esac + eval : \${$name=\`bin/postconf -d -h $name\`} || exit 1 +done + +# Override settings manually. + +test -z "$non_interactive" && for name in daemon_directory command_directory \ + queue_directory sendmail_path newaliases_path mailq_path mail_owner \ + setgid_group manpage_directory sample_directory readme_directory +do + while : + do + echo + eval echo Please specify \$${name}_prompt | ${FMT} + eval echo \$n "$name: [\$$name]\ \$c" + read ans + case $ans in + "") break;; + *) eval $name=$ans; break;; + esac + done +done + +# Sanity checks + +case "$setgid_group" in + no) (echo $0: Error: the setgid_group parameter no longer accepts + echo \"no\" values. Try again with \"setgid_group=groupname\" on the + echo command line or execute \"make install\" and specify setgid_group + echo interactively.) | ${FMT} 1>&2 + exit 1;; +esac + +case "$manpage_directory" in + no) (echo $0: Error: the manpage_directory parameter no longer accepts + echo \"no\" values. Try again with \"manpage_directory=/path/name\" + echo on the command line or execute \"make install\" and specify + echo manpage_directory interactively.) | ${FMT} 1>&2 + exit 1;; +esac + +for path in "$readme_directory" +do + case "$path" in + /*) ;; + no) ;; + *) echo $0: Error: \"$path\" should be \"no\" or an absolute path name. 1>&2 + exit 1;; + esac +done + +for path in "$daemon_directory" "$command_directory" "$queue_directory" \ + "$sendmail_path" "$newaliases_path" "$mailq_path" "$manpage_directory" \ + "$sample_directory" +do + case "$path" in + /*) ;; + *) echo $0: Error: \"$path\" should be an absolute path name. 1>&2; exit 1;; + esac +done + +test -d $tempdir || mkdir -p $tempdir || exit 1 + +trap "rm -f $tempdir/junk" 0 1 2 3 15 + +( rm -f $tempdir/junk && touch $tempdir/junk ) || { + echo $0: Error: you have no write permission to $tempdir. 1>&2 + echo Specify an alternative directory for scratch files. 1>&2 + exit 1 +} + +test -z "$install_root" && { + + chown root $tempdir/junk >/dev/null 2>&1 || { + echo Error: you have no permission to change file ownership. 1>&2 + exit 1 + } + + chown "$mail_owner" $tempdir/junk >/dev/null 2>&1 || { + echo $0: Error: \"$mail_owner\" needs an entry in the passwd file. 1>&2 + echo Remember, \"$mail_owner\" needs a dedicated user and group id. 1>&2 + exit 1 + } + + chgrp "$setgid_group" $tempdir/junk >/dev/null 2>&1 || { + echo $0: Error: \"$setgid_group\" needs an entry in the group file. 1>&2 + echo Remember, \"$setgid_group\" needs a dedicated group id. 1>&2 + exit 1 + } + +} + +rm -f $tempdir/junk || exit 1 + +trap 0 1 2 3 15 + +# Avoid clumsiness. + +DAEMON_DIRECTORY=$install_root$daemon_directory +COMMAND_DIRECTORY=$install_root$command_directory +QUEUE_DIRECTORY=$install_root$queue_directory +SENDMAIL_PATH=$install_root$sendmail_path +NEWALIASES_PATH=$install_root$newaliases_path +MAILQ_PATH=$install_root$mailq_path +MANPAGE_DIRECTORY=$install_root$manpage_directory +SAMPLE_DIRECTORY=$install_root$sample_directory +README_DIRECTORY=$install_root$readme_directory + +# Avoid repeated tests for existence of these; default permissions suffice. + +test -d $DAEMON_DIRECTORY || mkdir -p $DAEMON_DIRECTORY || exit 1 +test -d $COMMAND_DIRECTORY || mkdir -p $COMMAND_DIRECTORY || exit 1 +test -d $COMMAND_DIRECTORY || mkdir -p $COMMAND_DIRECTORY || exit 1 +test -d $SAMPLE_DIRECTORY || mkdir -p $SAMPLE_DIRECTORY || exit 1 +test "$readme_directory" = "no" -o -d $README_DIRECTORY || + mkdir -p $README_DIRECTORY || exit 1 + +# Upgrade or first-time installation? + +if [ -f $CONFIG_DIRECTORY/main.cf ] +then + post_install_options="upgrade-source" +else + post_install_options="first-install" +fi + +# Install files, using information from the postfix-files file. + +exec < conf/postfix-files || exit 1 +while IFS=: read path type owner group mode flags junk +do + IFS="$BACKUP_IFS" + + # Skip comments. + + case $path in + [$]*) ;; + *) continue;; + esac + + # Skip over files that must be preserved. + + case $flags in + *p*) eval test -f $install_root$path && { + eval echo "Skipping $install_root$path..." + continue + };; + esac + + # If installing from source code, apply special permissions or ownership. + # If building a package, don't apply special permissions or ownership. + + case $install_root in + "") case $owner in + [$]*) eval owner=$owner;; + root) owner=;; + esac + case $group in + [$]*) eval group=$group;; + -) group=;; + esac;; + *) case $mode in + [1-7]755) mode=755;; + esac + owner= + group=;; + esac + + # Create directory. + + case $type in + d) eval path=$install_root$path + test "$path" = "${install_root}no" -o -d $path || { + mkdir -p $path || exit 1 + test -z "$owner" || chown $owner $path || exit 1 + test -z "$group" || chgrp $group $path || exit 1 + chmod $mode $path || exit 1 + $CHATTR $path >/dev/null 2>/dev/null + } + continue;; + [fl]) ;; + *) echo $0: Error: unknown type for $path in conf/postfix-files; exit 1;; + esac + + # Install or replace file. + + echo $path | (IFS=/ read prefix file; IFS="$BACKUP_IFS" + case $prefix in + '$daemon_directory') + compare_or_replace $mode "$owner" "$group" libexec/$file \ + $DAEMON_DIRECTORY/$file || exit 1;; + '$command_directory') + compare_or_replace $mode "$owner" "$group" bin/$file \ + $COMMAND_DIRECTORY/$file || exit 1;; + '$config_directory') + compare_or_replace $mode "$owner" "$group" conf/$file \ + $CONFIG_DIRECTORY/$file || exit 1;; + '$sendmail_path') + check_parent $SENDMAIL_PATH || exit 1 + compare_or_replace $mode "$owner" "$group" bin/sendmail \ + $SENDMAIL_PATH || exit 1;; + '$mailq_path') + check_parent $MAILQ_PATH || exit 1 + compare_or_symlink $SENDMAIL_PATH $MAILQ_PATH || exit 1;; + '$newaliases_path') + check_parent $NEWALIASES_PATH || exit 1 + compare_or_symlink $SENDMAIL_PATH $NEWALIASES_PATH || exit 1;; + '$manpage_directory') + check_parent $MANPAGE_DIRECTORY/$file || exit 1 + compare_or_replace $mode "$owner" "$group" man/$file \ + $MANPAGE_DIRECTORY/$file || exit 1;; + '$sample_directory') + compare_or_replace $mode "$owner" "$group" conf/$file \ + $SAMPLE_DIRECTORY/$file || exit 1;; + '$readme_directory') + test "$readme_directory" = "no" || + compare_or_replace $mode "$owner" "$group" README_FILES/$file \ + $README_DIRECTORY/$file || exit 1;; + *) echo $0: Error: unknown entry $path in conf/postfix-files; exit 1;; + esac) || exit 1 +done + +# Save the installation parameters to main.cf even when they haven't +# changed from their current default. Defaults can change between +# Postfix releases, and software should not suddenly be installed in +# the wrong place when Postfix is being upgraded. + +bin/postconf -c $CONFIG_DIRECTORY -e \ + "daemon_directory = $daemon_directory" \ + "command_directory = $command_directory" \ + "queue_directory = $queue_directory" \ + "mail_owner = $mail_owner" \ + "setgid_group = $setgid_group" \ + "sendmail_path = $sendmail_path" \ + "mailq_path = $mailq_path" \ + "newaliases_path = $newaliases_path" \ + "manpage_directory = $manpage_directory" \ + "sample_directory = $sample_directory" \ + "readme_directory = $readme_directory" \ +|| exit 1 + +# If Postfix is being installed locally from source code, do the +# post-install processing now. + +test -n "$install_root" || { + export daemon_directory command_directory queue_directory sendmail_path \ + newaliases_path mailq_path mail_owner setgid_group manpage_directory \ + sample_directory readme_directory + ${SHELL} conf/post-install $post_install_options || exit 1 +} diff --git a/gnu/dist/postfix/proto/Makefile.in b/gnu/dist/postfix/proto/Makefile.in index 02397426deb..fadc1467865 100644 --- a/gnu/dist/postfix/proto/Makefile.in +++ b/gnu/dist/postfix/proto/Makefile.in @@ -6,6 +6,8 @@ CONFIG = ../conf/access ../conf/aliases ../conf/canonical ../conf/relocated \ ../conf/transport ../conf/virtual ../conf/pcre_table \ ../conf/regexp_table +AWK = awk '{ print; if (NR == 1) print ".pl 9999" }' + update: $(CONFIG) Makefile: Makefile.in @@ -20,25 +22,25 @@ clobber: rm -f $(CONFIG) ../conf/access: access - srctoman - $? | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ + srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ ../conf/aliases: aliases0 aliases - (cat aliases0; srctoman - aliases | nroff -man | col -bx | uniq | sed 's/^/# /') >$@ + (cat aliases0; srctoman - aliases | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /') >$@ ../conf/canonical: canonical - srctoman - $? | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ + srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ ../conf/pcre_table: pcre_table - srctoman - $? | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ + srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ ../conf/regexp_table: regexp_table - srctoman - $? | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ + srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ ../conf/relocated: relocated - srctoman - $? | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ + srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ ../conf/transport: transport - srctoman - $? | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ + srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ ../conf/virtual: virtual - srctoman - $? | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ + srctoman - $? | $(AWK) | nroff -man | col -bx | uniq | sed 's/^/# /' >$@ diff --git a/gnu/dist/postfix/proto/access b/gnu/dist/postfix/proto/access index a319352cd56..5536b41d542 100644 --- a/gnu/dist/postfix/proto/access +++ b/gnu/dist/postfix/proto/access @@ -7,8 +7,9 @@ # \fBpostmap /etc/postfix/access\fR # DESCRIPTION # The optional \fBaccess\fR table directs the Postfix SMTP server -# to selectively reject or accept mail from or to specific hosts, -# domains, networks, host addresses or mail addresses. +# to selectively reject or accept mail. Access can be allowed or +# denied for specific host names, domain names, networks, host +# network addresses or mail addresses. # # Normally, the \fBaccess\fR table is specified as a text file # that serves as input to the \fBpostmap\fR(1) command. @@ -27,27 +28,60 @@ # .ad # .fi # The format of the access table is as follows: -# .IP "blanks and comments" -# Blank lines are ignored, as are lines beginning with `#'. -# .IP "leading whitespace" -# Lines that begin with whitespace continue the previous line. # .IP "\fIpattern action\fR" # When \fIpattern\fR matches a mail address, domain or host address, # perform the corresponding \fIaction\fR. -# PATTERNS +# .IP "blank lines and comments" +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. +# .IP "multi-line text" +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. +# EMAIL ADDRESS PATTERNS # .ad # .fi # With lookups from indexed files such as DB or DBM, or from networked -# tables such as NIS, LDAP or SQL, patterns are tried in the order as -# listed below: +# tables such as NIS, LDAP or SQL, the following lookup patterns are +# examined in the order as listed: # .IP \fIuser\fR@\fIdomain\fR # Matches the specified mail address. # .IP \fIdomain.name\fR -# Matches the \fIdomain.name\fR itself and any subdomain thereof, -# either in hostnames or in mail addresses. Top-level domains will -# never be matched. +# Matches \fIdomain.name\fR as the domain part of an email address. +# .sp +# The pattern \fIdomain.name\fR also matches subdomains, but only +# when the string \fBsmtpd_access_maps\fR is listed in the Postfix +# \fBparent_domain_matches_subdomains\fR configuration setting. +# Otherwise, specify \fI.domain.name\fR (note the initial dot) in +# order to match subdomains. # .IP \fIuser\fR@ # Matches all mail addresses with the specified user part. +# .PP +# Note: lookup of the null sender address may not be possible with +# all supported types of lookup table. A workaround is to specify +# \fBsmtpd_null_access_lookup_key = <>\fR in the Postfix \fBmain.cf\fR +# file, and to specify \fB<>\fR as the left-hand field in the access +# table. +# ADDRESS EXTENSION +# .fi +# .ad +# When a mail address localpart contains the optional recipient delimiter +# (e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +# \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIdomain\fR, +# \fIuser+foo\fR@, and \fIuser\fR@. +# HOST NAME/ADDRESS PATTERNS +# .ad +# .fi +# With lookups from indexed files such as DB or DBM, or from networked +# tables such as NIS, LDAP or SQL, the following lookup patterns are +# examined in the order as listed: +# .IP \fIdomain.name\fR +# Matches \fIdomain.name\fR. +# .sp +# The pattern \fIdomain.name\fR also matches subdomains, but only +# when the string \fBsmtpd_access_maps\fR is listed in the Postfix +# \fBparent_domain_matches_subdomains\fR configuration setting. +# Otherwise, specify \fI.domain.name\fR (note the initial dot) in +# order to match subdomains. # .IP \fInet.work.addr.ess\fR # .IP \fInet.work.addr\fR # .IP \fInet.work\fR @@ -80,13 +114,14 @@ # string being looked up. Depending on the application, that string # is an entire client hostname, an entire client IP address, or an # entire mail address. Thus, no parent domain or parent network search -# is done, and \fIuser@domain\fR mail addresses are not broken up into -# their \fIuser@\fR and \fIdomain\fR constituent parts. +# is done, \fIuser@domain\fR mail addresses are not broken up into +# their \fIuser@\fR and \fIdomain\fR constituent parts, nor is +# \fIuser+foo\fR broken up into \fIuser\fR and \fIfoo\fR. # # Patterns are applied in the order as specified in the table, until a # pattern is found that matches the search string. # -# Actions are the same as with normal indexed file lookups, with +# Actions are the same as with indexed file lookups, with # the additional feature that parenthesized substrings from the # pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. # BUGS diff --git a/gnu/dist/postfix/proto/aliases b/gnu/dist/postfix/proto/aliases index a8b4209589a..4a53b7987fc 100644 --- a/gnu/dist/postfix/proto/aliases +++ b/gnu/dist/postfix/proto/aliases @@ -34,9 +34,11 @@ # .ti +5 # \fIname\fR: \fIvalue1\fR, \fIvalue2\fR, \fI...\fR # .IP \(bu -# Lines that begin with whitespace continue the previous line. +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. # .IP \(bu -# Blank lines are ignored, as are lines beginning with `#'. +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. # .PP # The \fIname\fR is a local address (no domain part). # Use double quotes when the name contains any special characters diff --git a/gnu/dist/postfix/proto/aliases0 b/gnu/dist/postfix/proto/aliases0 index d6cf7666bbc..9fcd48f7a0a 100644 --- a/gnu/dist/postfix/proto/aliases0 +++ b/gnu/dist/postfix/proto/aliases0 @@ -1,4 +1,8 @@ # +# Sample aliases file. Install in the location as specified by the +# output from the command "postconf alias_maps". Typical path names +# are /etc/aliases or /etc/mail/aliases. +# # >>>>>>>>>> The program "newaliases" must be run after # >> NOTE >> this file is updated for any changes to # >>>>>>>>>> show through to Postfix. diff --git a/gnu/dist/postfix/proto/canonical b/gnu/dist/postfix/proto/canonical index 4eaf21f79ff..7cf0829a4e6 100644 --- a/gnu/dist/postfix/proto/canonical +++ b/gnu/dist/postfix/proto/canonical @@ -42,13 +42,15 @@ # .ad # .fi # The format of the \fBcanonical\fR table is as follows: -# .IP "blanks and comments" -# Blank lines are ignored, as are lines beginning with `#'. -# .IP "leading whitespace" -# Lines that begin with whitespace continue the previous line. # .IP "\fIpattern result\fR" # When \fIpattern\fR matches a mail address, replace it by the # corresponding \fIresult\fR. +# .IP "blank lines and comments" +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. +# .IP "multi-line text" +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. # .PP # With lookups from indexed files such as DB or DBM, or from networked # tables such as NIS, LDAP or SQL, patterns are tried in the order as @@ -76,13 +78,11 @@ # ADDRESS EXTENSION # .fi # .ad -# When table lookup fails, and the address localpart contains the -# optional recipient delimiter (e.g., \fIuser+foo\fR@\fIdomain\fR), the -# search is repeated for the unextended address (e.g. -# \fIuser\fR@\fIdomain\fR), and the unmatched extension is propagated -# to the result of table lookup. The matching order is: -# \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, -# \fIuser+foo\fR, \fIuser\fR, and @\fIdomain\fR. +# When a mail address localpart contains the optional recipient delimiter +# (e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +# \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR, +# \fIuser\fR, and @\fIdomain\fR. An unmatched address extension +# (\fI+foo\fR) is propagated to the result of table lookup. # REGULAR EXPRESSION TABLES # .ad # .fi @@ -99,7 +99,7 @@ # Patterns are applied in the order as specified in the table, until a # pattern is found that matches the search string. # -# Results are the same as with normal indexed file lookups, with +# Results are the same as with indexed file lookups, with # the additional feature that parenthesized substrings from the # pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. # BUGS @@ -123,6 +123,10 @@ # Other parameters of interest: # .IP \fBinet_interfaces\fR # The network interface addresses that this system receives mail on. +# .IP \fBmasquerade_classes\fR +# List of address classes subject to masquerading: zero or more of +# \fBenvelope_sender\fR, \fBenvelope_recipient\fR, \fBheader_sender\fR, +# \fBheader_recipient\fR. # .IP \fBmasquerade_domains\fR # List of domains that hide their subdomain structure. # .IP \fBmasquerade_exceptions\fR diff --git a/gnu/dist/postfix/proto/pcre_table b/gnu/dist/postfix/proto/pcre_table index 7f71dcc8e44..69c8488b285 100644 --- a/gnu/dist/postfix/proto/pcre_table +++ b/gnu/dist/postfix/proto/pcre_table @@ -15,14 +15,15 @@ # supports use the \fBpostconf -m\fR command. # # The general form of a PCRE table is: -# .IP "blanks and comments" -# Blank lines are ignored, as are lines beginning with `#'. -# .IP "leading whitespace" -# Lines that begin with whitespace continue the previous line. # .IP "\fIpattern result\fR" # When \fIpattern\fR matches a search string, use the corresponding -# \fIresult\fR. A line that starts with white space continues the -# preceding line. +# \fIresult\fR. +# .IP "blank lines and comments" +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. +# .IP "multi-line text" +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. # .PP # Each pattern is a perl-like regular expression. The expression # delimiter can be any character, except whitespace or characters @@ -50,19 +51,22 @@ # string is possible using the conventional perl syntax ($1, $2, etc.). # The macros in the result string may need to be written as ${n} # or $(n) if they aren't followed by whitespace. -# EXAMPLES +# EXAMPLE SMTPD ACCESS MAP # # Protect your outgoing majordomo exploders -# /^(?!owner-)(.*)-outgoing@(my\.domain)$/ 550 Use ${1}@${2} instead +# /^(?!owner-)(.*)-outgoing@/ 550 Use ${1}@${2} instead # # # Bounce friend@whatever, except when whatever is our domain (you would # # be better just bouncing all friend@ mail - this is just an example). -# /^friend@(?!my\.domain).*$/ 550 Stick this in your pipe $0 +# /^friend@(?!my\\.domain)/ 550 Stick this in your pipe $0 # # # A multi-line entry. The text is sent as one line. # # -# /^noddy@connect\.com\.au$/ +# /^noddy@my\\.domain$/ # \ 550 This user is a funny one. You really don't want to send mail to # \ them as it only makes their head spin. +# EXAMPLE HEADER FILTER MAP +# /^Subject: make money fast/ REJECT +# /^To: friend@public\\.com/ REJECT # SEE ALSO # regexp_table(5) format of POSIX regular expression tables # AUTHOR(S) diff --git a/gnu/dist/postfix/proto/regexp_table b/gnu/dist/postfix/proto/regexp_table index bf453940485..bd6cb7f724f 100644 --- a/gnu/dist/postfix/proto/regexp_table +++ b/gnu/dist/postfix/proto/regexp_table @@ -15,14 +15,15 @@ # supports use the \fBpostconf -m\fR command. # # The general form of a Postfix regular expression table is: -# .IP "blanks and comments" -# Blank lines are ignored, as are lines beginning with `#'. -# .IP "leading whitespace" -# Lines that begin with whitespace continue the previous line. # .IP "\fIpattern result\fR" # When \fIpattern\fR matches a search string, use the corresponding -# \fIresult\fR. A line that starts with white space continues the -# preceding line. +# \fIresult\fR. +# .IP "blank lines and comments" +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. +# .IP "multi-line text" +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. # .IP "\fIpattern1!pattern2 result\fR" # Matches \fIpattern1\fR but not \fIpattern2\fR. # .PP @@ -52,17 +53,21 @@ # string is possible using $1, $2, etc.. The macros in the result string # may need to be written as ${n} or $(n) if they aren't followed # by whitespace. -# EXAMPLES +# EXAMPLE SMTPD ACCESS MAP # # Disallow sender-specified routing. This is a must if you relay mail # # for other domains. -# /[%!@].*[%!@]/ 550 Sender-specified routing rejected +# /[%!@].*[%!@]/ 550 Sender-specified routing rejected # # # Postmaster is OK, that way they can talk to us about how to fix # # their problem. -# /^postmaster@.*$/ OK +# /^postmaster@/ OK # # # Protect your outgoing majordomo exploders -# /^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead +# /^(.*)-outgoing@(.*)$/!/^owner-/ 550 Use ${1}@${2} instead +# EXAMPLE HEADER FILTER MAP +# # These were once common in junk mail. +# /^Subject: make money fast/ REJECT +# /^To: friend@public\\.com/ REJECT # SEE ALSO # pcre_table(5) format of PCRE tables # AUTHOR(S) diff --git a/gnu/dist/postfix/proto/relocated b/gnu/dist/postfix/proto/relocated index 9a272b80cfd..ba1b00726c0 100644 --- a/gnu/dist/postfix/proto/relocated +++ b/gnu/dist/postfix/proto/relocated @@ -29,16 +29,18 @@ # .fi # The format of the table is as follows: # .IP \(bu -# Blank lines are ignored, as are lines beginning with `#'. -# .IP \(bu -# Lines that begin with whitespace continue the previous line. -# .IP \(bu # An entry has one of the following form: # .ti +5 # \fIkey new_location\fR # .br # Where \fInew_location\fR specifies contact information such as # an email address, or perhaps a street address or telephone number. +# .IP \(bu +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. +# .IP \(bu +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. # .PP # With lookups from indexed files such as DB or DBM, or from networked # tables such as NIS, LDAP or SQL, the \fIkey\fR field is one of the @@ -56,10 +58,10 @@ # ADDRESS EXTENSION # .fi # .ad -# When the search fails, and the address localpart contains the -# optional recipient delimiter (e.g., \fIuser+foo\fR@\fIdomain\fR), -# the search is repeated for the unextended address (e.g. -# \fIuser\fR@\fIdomain\fR). +# When a mail address localpart contains the optional recipient delimiter +# (e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +# \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR, +# \fIuser\fR, and @\fIdomain\fR. # REGULAR EXPRESSION TABLES # .ad # .fi @@ -76,7 +78,7 @@ # Patterns are applied in the order as specified in the table, until a # pattern is found that matches the search string. # -# Results are the same as with normal indexed file lookups, with +# Results are the same as with indexed file lookups, with # the additional feature that parenthesized substrings from the # pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. # BUGS diff --git a/gnu/dist/postfix/proto/transport b/gnu/dist/postfix/proto/transport index 70c1a584375..18559faa9c6 100644 --- a/gnu/dist/postfix/proto/transport +++ b/gnu/dist/postfix/proto/transport @@ -27,13 +27,15 @@ # .ad # .fi # The format of the transport table is as follows: -# .IP "blanks and comments" -# Blank lines are ignored, as are lines beginning with `#'. -# .IP "leading whitespace" -# Lines that begin with whitespace continue the previous line. # .IP "\fIpattern result\fR" # When \fIpattern\fR matches the domain, use the corresponding # \fIresult\fR. +# .IP "blank lines and comments" +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. +# .IP "multi-line text" +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. # .PP # With lookups from indexed files such as DB or DBM, or from networked # tables such as NIS, LDAP or SQL, patterns are tried in the order as @@ -43,7 +45,10 @@ # \fInexthop\fR. # .IP "\fI.domain transport\fR:\fInexthop\fR" # Mail for any subdomain of \fIdomain\fR is delivered through -# \fItransport\fR to \fInexthop\fR. +# \fItransport\fR to \fInexthop\fR. This applies only when the +# string \fBtransport_maps\fR is not listed in the +# \fBparent_domain_matches_subdomains\fR configuration setting. +# Otherwise, a domain name matches itself and its subdomains. # .PP # Note: transport map entries take precedence over domains # specified in the \fBmydestination\fR parameter. If you use @@ -126,7 +131,7 @@ # Patterns are applied in the order as specified in the table, until a # pattern is found that matches the search string. # -# Results are the same as with normal indexed file lookups, with +# Results are the same as with indexed file lookups, with # the additional feature that parenthesized substrings from the # pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. # CONFIGURATION PARAMETERS @@ -136,6 +141,10 @@ # 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 +# 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 diff --git a/gnu/dist/postfix/proto/virtual b/gnu/dist/postfix/proto/virtual index a42646c7eb1..214eb88826a 100644 --- a/gnu/dist/postfix/proto/virtual +++ b/gnu/dist/postfix/proto/virtual @@ -96,7 +96,7 @@ # The \fBmain.cf mydestination\fR entry is required for a Sendmail-style # virtual domain. # -# Do not specify a \fIvirtual.domain whatever\fR virtual map entry +# Do not specify a \fIvirtual.domain anything\fR virtual map entry # for a Sendmail-style virtual domain. # Such an entry is required only with a Postfix-style virtual domain. # @@ -110,13 +110,15 @@ # .fi # The format of the virtual table is as follows, mappings being # tried in the order as listed in this manual page: -# .IP "blanks and comments" -# Blank lines are ignored, as are lines beginning with `#'. -# .IP "leading whitespace" -# Lines that begin with whitespace continue the previous line. # .IP "\fIpattern result\fR" # When \fIpattern\fR matches a mail address, replace it by the # corresponding \fIresult\fR. +# .IP "blank lines and comments" +# Empty lines and whitespace-only lines are ignored, as +# are lines whose first non-whitespace character is a `#'. +# .IP "multi-line text" +# A logical line starts with non-whitespace text. A line that +# starts with whitespace continues a logical line. # .PP # With lookups from indexed files such as DB or DBM, or from networked # tables such as NIS, LDAP or SQL, patterns are tried in the order as @@ -142,13 +144,11 @@ # ADDRESS EXTENSION # .fi # .ad -# When the search fails, and the address localpart contains the -# optional recipient delimiter (e.g., \fIuser+foo\fR@\fIdomain\fR), -# the search is repeated for the unextended address (e.g. -# \fIuser\fR@\fIdomain\fR), and the unmatched address extension is -# propagated to the result of expansion. The matching order is: -# \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, -# \fIuser+foo\fR, \fIuser\fR, and @\fIdomain\fR. +# When a mail address localpart contains the optional recipient delimiter +# (e.g., \fIuser+foo\fR@\fIdomain\fR), the lookup order becomes: +# \fIuser+foo\fR@\fIdomain\fR, \fIuser\fR@\fIdomain\fR, \fIuser+foo\fR, +# \fIuser\fR, and @\fIdomain\fR. An unmatched address extension +# (\fI+foo\fR) is propagated to the result of table lookup. # REGULAR EXPRESSION TABLES # .ad # .fi @@ -165,7 +165,7 @@ # Patterns are applied in the order as specified in the table, until a # pattern is found that matches the search string. # -# Results are the same as with normal indexed file lookups, with +# Results are the same as with indexed file lookups, with # the additional feature that parenthesized substrings from the # pattern can be interpolated as \fB$1\fR, \fB$2\fR and so on. # BUGS diff --git a/gnu/dist/postfix/src/bounce/Makefile.in b/gnu/dist/postfix/src/bounce/Makefile.in index 4172afd76ce..66066c2330f 100644 --- a/gnu/dist/postfix/src/bounce/Makefile.in +++ b/gnu/dist/postfix/src/bounce/Makefile.in @@ -1,8 +1,8 @@ SHELL = /bin/sh SRCS = bounce.c bounce_append_service.c bounce_notify_service.c \ - bounce_cleanup.c bounce_notify_util.c + bounce_cleanup.c bounce_notify_util.c bounce_notify_verp.c OBJS = bounce.o bounce_append_service.o bounce_notify_service.o \ - bounce_cleanup.o bounce_notify_util.o + bounce_cleanup.o bounce_notify_util.o bounce_notify_verp.o HDRS = TESTSRC = WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ @@ -65,10 +65,12 @@ bounce.o: ../../include/vstream.h bounce.o: ../../include/stringops.h bounce.o: ../../include/mail_proto.h bounce.o: ../../include/iostuff.h +bounce.o: ../../include/attr.h bounce.o: ../../include/mail_queue.h bounce.o: ../../include/mail_params.h bounce.o: ../../include/mail_conf.h bounce.o: ../../include/bounce.h +bounce.o: ../../include/mail_addr.h bounce.o: ../../include/mail_server.h bounce.o: bounce_service.h bounce.o: ../../include/bounce_log.h @@ -133,3 +135,19 @@ bounce_notify_util.o: ../../include/name_mask.h bounce_notify_util.o: ../../include/bounce_log.h bounce_notify_util.o: ../../include/mail_date.h bounce_notify_util.o: bounce_service.h +bounce_notify_verp.o: bounce_notify_verp.c +bounce_notify_verp.o: ../../include/sys_defs.h +bounce_notify_verp.o: ../../include/msg.h +bounce_notify_verp.o: ../../include/vstream.h +bounce_notify_verp.o: ../../include/vbuf.h +bounce_notify_verp.o: ../../include/name_mask.h +bounce_notify_verp.o: ../../include/mail_params.h +bounce_notify_verp.o: ../../include/mail_queue.h +bounce_notify_verp.o: ../../include/vstring.h +bounce_notify_verp.o: ../../include/post_mail.h +bounce_notify_verp.o: ../../include/cleanup_user.h +bounce_notify_verp.o: ../../include/mail_addr.h +bounce_notify_verp.o: ../../include/mail_error.h +bounce_notify_verp.o: ../../include/verp_sender.h +bounce_notify_verp.o: bounce_service.h +bounce_notify_verp.o: ../../include/bounce_log.h diff --git a/gnu/dist/postfix/src/bounce/bounce.c b/gnu/dist/postfix/src/bounce/bounce.c index eeedb7b141b..3cb98cc0028 100644 --- a/gnu/dist/postfix/src/bounce/bounce.c +++ b/gnu/dist/postfix/src/bounce/bounce.c @@ -80,6 +80,11 @@ /* System library. */ #include <sys_defs.h> +#include <string.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif /* Utility library. */ @@ -95,6 +100,7 @@ #include <mail_params.h> #include <mail_conf.h> #include <bounce.h> +#include <mail_addr.h> /* Single-threaded server skeleton. */ @@ -122,6 +128,7 @@ static VSTRING *queue_id; static VSTRING *queue_name; static VSTRING *recipient; static VSTRING *sender; +static VSTRING *verp_delims; static VSTRING *why; #define STR vstring_str @@ -135,8 +142,12 @@ static int bounce_append_proto(char *service_name, VSTREAM *client) /* * Read the and validate the client request. */ - if (mail_command_read(client, "%d %s %s %s", - &flags, queue_id, recipient, why) != 4) { + if (mail_command_server(client, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient, + ATTR_TYPE_STR, MAIL_ATTR_WHY, why, + ATTR_TYPE_END) != 4) { msg_warn("malformed request"); return (-1); } @@ -171,8 +182,12 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush) /* * Read and validate the client request. */ - if (mail_command_read(client, "%d %s %s %s", - &flags, queue_name, queue_id, sender) != 4) { + if (mail_command_server(client, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_END) != 4) { msg_warn("malformed request"); return (-1); } @@ -202,6 +217,65 @@ static int bounce_notify_proto(char *service_name, VSTREAM *client, int flush) STR(queue_id), STR(sender), flush)); } +/* bounce_verp_proto - bounce_notify server protocol, VERP style */ + +static int bounce_verp_proto(char *service_name, VSTREAM *client, int flush) +{ + char *myname = "bounce_verp_proto"; + int flags; + + /* + * Read and validate the client request. + */ + if (mail_command_server(client, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp_delims, + ATTR_TYPE_END) != 5) { + msg_warn("malformed request"); + return (-1); + } + if (mail_queue_name_ok(STR(queue_name)) == 0) { + msg_warn("malformed queue name: %s", printable(STR(queue_name), '?')); + return (-1); + } + if (mail_queue_id_ok(STR(queue_id)) == 0) { + msg_warn("malformed queue id: %s", printable(STR(queue_id), '?')); + return (-1); + } + if (strlen(STR(verp_delims)) != 2) { + msg_warn("malformed verp delimiter string: %s", + printable(STR(verp_delims), '?')); + return (-1); + } + if (msg_verbose) + msg_info("%s: service=%s queue=%s id=%s sender=%s delim=%s", + myname, service_name, STR(queue_name), STR(queue_id), + STR(sender), STR(verp_delims)); + + /* + * On request by the client, set up a trap to delete the log file in case + * of errors. + */ + if (flags & BOUNCE_FLAG_CLEAN) + bounce_cleanup_register(service_name, STR(queue_id)); + + /* + * Execute the request. Fall back to traditional notification if a bounce + * was returned as undeliverable, because we don't want to VERPify those. + */ + if (!*STR(sender) || !strcasecmp(STR(sender), mail_addr_double_bounce())) { + msg_warn("request to send VERP-style notification of bounced mail"); + return (bounce_notify_service(service_name, STR(queue_name), + STR(queue_id), STR(sender), flush)); + } else + return (bounce_notify_verp(service_name, STR(queue_name), + STR(queue_id), STR(sender), + STR(verp_delims), flush)); +} + /* bounce_service - parse bounce command type and delegate */ static void bounce_service(VSTREAM *client, char *service_name, char **argv) @@ -225,9 +299,12 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv) #define REALLY_BOUNCE 1 #define JUST_WARN 0 - if (mail_scan(client, "%d", &command) != 1) { + if (attr_scan(client, ATTR_FLAG_STRICT | ATTR_FLAG_MORE, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, &command, 0) != 1) { msg_warn("malformed request"); status = -1; + } else if (command == BOUNCE_CMD_VERP) { + status = bounce_verp_proto(service_name, client, REALLY_BOUNCE); } else if (command == BOUNCE_CMD_FLUSH) { status = bounce_notify_proto(service_name, client, REALLY_BOUNCE); } else if (command == BOUNCE_CMD_WARN) { @@ -243,7 +320,9 @@ static void bounce_service(VSTREAM *client, char *service_name, char **argv) * When the request has completed, send the completion status to the * client. */ - mail_print(client, "%d", status); + attr_print(client, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status, + ATTR_TYPE_END); vstream_fflush(client); /* @@ -271,6 +350,7 @@ static void post_jail_init(char *unused_name, char **unused_argv) queue_name = vstring_alloc(10); recipient = vstring_alloc(10); sender = vstring_alloc(10); + verp_delims = vstring_alloc(10); why = vstring_alloc(10); } diff --git a/gnu/dist/postfix/src/bounce/bounce_notify_service.c b/gnu/dist/postfix/src/bounce/bounce_notify_service.c index 35e10a45cb9..284b6468ee5 100644 --- a/gnu/dist/postfix/src/bounce/bounce_notify_service.c +++ b/gnu/dist/postfix/src/bounce/bounce_notify_service.c @@ -138,8 +138,7 @@ int bounce_notify_service(char *service, char *queue_name, postmaster = flush ? var_2bounce_rcpt : var_delay_rcpt; if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), postmaster, - NULL_CLEANUP_FLAGS, - "BOUNCE")) != 0) { + NULL_CLEANUP_FLAGS)) != 0) { /* * Double bounce to Postmaster. This is the last opportunity @@ -163,8 +162,7 @@ int bounce_notify_service(char *service, char *queue_name, */ else { if ((bounce = post_mail_fopen_nowait(NULL_SENDER, recipient, - NULL_CLEANUP_FLAGS, - "BOUNCE")) != 0) { + NULL_CLEANUP_FLAGS)) != 0) { /* * Send the bounce message header, some boilerplate text that @@ -203,8 +201,7 @@ int bounce_notify_service(char *service, char *queue_name, postmaster = flush ? var_bounce_rcpt : var_delay_rcpt; if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), postmaster, - NULL_CLEANUP_FLAGS, - "BOUNCE")) != 0) { + NULL_CLEANUP_FLAGS)) != 0) { if (bounce_header(bounce, bounce_info, postmaster) == 0 && bounce_diagnostic_log(bounce, bounce_info) == 0 && bounce_header_dsn(bounce, bounce_info) == 0 diff --git a/gnu/dist/postfix/src/bounce/bounce_notify_util.c b/gnu/dist/postfix/src/bounce/bounce_notify_util.c index cc5e15f6bf0..f2dc04156d9 100644 --- a/gnu/dist/postfix/src/bounce/bounce_notify_util.c +++ b/gnu/dist/postfix/src/bounce/bounce_notify_util.c @@ -199,7 +199,7 @@ BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name, */ if ((bounce_info->log_handle = bounce_log_open(bounce_info->service, bounce_info->queue_id, - O_RDONLY, 0)) == 0 + O_RDWR, 0)) == 0 && errno != ENOENT) msg_fatal("open %s %s: %m", bounce_info->service, bounce_info->queue_id); @@ -222,14 +222,16 @@ BOUNCE_INFO *bounce_mail_init(const char *service, const char *queue_name, * corrupted just send whatever we can (remember this is a best effort, * it does not have to be perfect). */ - while ((rec_type = rec_get(bounce_info->orig_fp, - bounce_info->buf, 0)) > 0) { - if (rec_type == REC_TYPE_TIME && bounce_info->arrival_time == 0) { - if ((bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0) - bounce_info->arrival_time = 0; - } else if (rec_type == REC_TYPE_MESG) { - bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp); - break; + if (bounce_info->orig_fp != 0) { + while ((rec_type = rec_get(bounce_info->orig_fp, + bounce_info->buf, 0)) > 0) { + if (rec_type == REC_TYPE_TIME && bounce_info->arrival_time == 0) { + if ((bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0) + bounce_info->arrival_time = 0; + } else if (rec_type == REC_TYPE_MESG) { + bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp); + break; + } } } return (bounce_info); @@ -339,7 +341,7 @@ int bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info) "####################################################################"); post_mail_fputs(bounce, ""); post_mail_fprintf(bounce, - "Your message could not be delivered for %.1f hours.", + "Your message could not be delivered for %.1f hours.", var_delay_warn_time / 3600.0); post_mail_fprintf(bounce, "It will be retried until it is %.1f days old.", @@ -478,7 +480,7 @@ int bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info) #endif if (bounce_info->flush == 0) post_mail_fprintf(bounce, "Will-Retry-Until: %s", - mail_date(bounce_info->arrival_time + var_max_queue_time)); + mail_date(bounce_info->arrival_time + var_max_queue_time)); return (vstream_ferror(bounce)); } @@ -547,12 +549,16 @@ int bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info, if (var_bounce_limit == 0 || bounce_length < var_bounce_limit) { bounce_length += VSTRING_LEN(bounce_info->buf) + 2; status = (REC_PUT_BUF(bounce, rec_type, bounce_info->buf) != rec_type); - } + } else + break; } /* * Final MIME headers. These require -- at the end of the boundary * string. + * + * XXX This should be a separate bounce_terminate() entry so we can be + * assured that the terminator will always be sent. */ post_mail_fputs(bounce, ""); post_mail_fprintf(bounce, "--%s--", bounce_info->mime_boundary); diff --git a/gnu/dist/postfix/src/bounce/bounce_notify_verp.c b/gnu/dist/postfix/src/bounce/bounce_notify_verp.c new file mode 100644 index 00000000000..f1880bae00c --- /dev/null +++ b/gnu/dist/postfix/src/bounce/bounce_notify_verp.c @@ -0,0 +1,210 @@ +/*++ +/* NAME +/* bounce_notify_verp 3 +/* SUMMARY +/* send non-delivery report to sender, server side +/* SYNOPSIS +/* #include "bounce_service.h" +/* +/* int bounce_notify_verp(service, queue_name, queue_id, sender, +/* verp_delims, flush) +/* char *queue_name; +/* char *queue_id; +/* char *sender; +/* char *verp_delims; +/* int flush; +/* DESCRIPTION +/* This module implements the server side of the bounce_notify() +/* (send bounce message) request. If flush is zero, the logfile +/* is not removed, and a warning is sent instead of a bounce. +/* The bounce recipient address is encoded in VERP format. +/* This routine must be used for single bounces only. +/* +/* When a message bounces, a full copy is sent to the originator, +/* and an optional copy of the diagnostics with message headers is +/* sent to the postmaster. The result is non-zero when the operation +/* should be tried again. +/* +/* When a bounce is sent, the sender address is the empty +/* address. +/* DIAGNOSTICS +/* Fatal error: error opening existing file. Warnings: corrupt +/* message file. A corrupt message is saved to the "corrupt" +/* queue for further inspection. +/* SEE ALSO +/* bounce(3) basic bounce service client interface +/* 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 <fcntl.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <vstream.h> +#include <name_mask.h> + +/* Global library. */ + +#include <mail_params.h> +#include <mail_queue.h> +#include <post_mail.h> +#include <mail_addr.h> +#include <mail_error.h> +#include <verp_sender.h> + +/* Application-specific. */ + +#include "bounce_service.h" + +#define STR vstring_str + +/* bounce_notify_verp - send a bounce */ + +int bounce_notify_verp(char *service, char *queue_name, + char *queue_id, char *recipient, + char *verp_delims, int flush) +{ + char *myname = "bounce_notify_verp"; + BOUNCE_INFO *bounce_info; + int bounce_status = 0; + int postmaster_status; + VSTREAM *bounce; + int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, + var_notify_classes); + char *postmaster; + VSTRING *verp_buf = vstring_alloc(100); + + /* + * Sanity checks. We must be called only for undeliverable non-bounce + * messages. + */ + if (*recipient == 0) + msg_panic("%s: attempt to bounce a single bounce", myname); + if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) + msg_panic("%s: attempt to bounce a double bounce", myname); + + /* + * Initialize. Open queue file, bounce log, etc. + */ + bounce_info = bounce_mail_init(service, queue_name, queue_id, flush); + +#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ +#define NULL_CLEANUP_FLAGS 0 +#define BOUNCE_HEADERS 1 +#define BOUNCE_ALL 0 + + /* + * A non-bounce message was returned. Send a single bounce, one per + * recipient. + */ + while (bounce_log_read(bounce_info->log_handle) != 0) { + + /* + * Notify the originator. + */ + verp_sender(verp_buf, verp_delims, recipient, + bounce_info->log_handle->recipient); + if ((bounce = post_mail_fopen_nowait(NULL_SENDER, STR(verp_buf), + NULL_CLEANUP_FLAGS)) != 0) { + + /* + * Send the bounce message header, some boilerplate text that + * pretends that we are a polite mail system, the text with + * reason for the bounce, and a copy of the original message. + */ + if (bounce_header(bounce, bounce_info, STR(verp_buf)) == 0 + && bounce_boilerplate(bounce, bounce_info) == 0 + && bounce_recipient_log(bounce, bounce_info) == 0 + && bounce_header_dsn(bounce, bounce_info) == 0 + && bounce_recipient_dsn(bounce, bounce_info) == 0) + bounce_original(bounce, bounce_info, flush ? + BOUNCE_ALL : BOUNCE_HEADERS); + bounce_status = post_mail_fclose(bounce); + } else + bounce_status = 1; + + /* + * Stop at the first sign of trouble, instead of making the problem + * worse. + */ + if (bounce_status != 0) + break; + + /* + * Mark this recipient as done. + */ + bounce_log_delrcpt(bounce_info->log_handle); + + /* + * Optionally, send a postmaster notice. + * + * This postmaster notice is not critical, so if it fails don't + * retransmit the bounce that we just generated, just log a warning. + */ +#define WANT_IF_BOUNCE (flush == 1 && (notify_mask & MAIL_ERROR_BOUNCE)) +#define WANT_IF_DELAY (flush == 0 && (notify_mask & MAIL_ERROR_DELAY)) + + if (WANT_IF_BOUNCE || WANT_IF_DELAY) { + + /* + * Send the text with reason for the bounce, and the headers of + * the original message. Don't bother sending the boiler-plate + * text. This postmaster notice is not critical, so if it fails + * don't retransmit the bounce that we just generated, just log a + * warning. + */ + postmaster = flush ? var_bounce_rcpt : var_delay_rcpt; + if ((bounce = post_mail_fopen_nowait(mail_addr_double_bounce(), + postmaster, + NULL_CLEANUP_FLAGS)) != 0) { + if (bounce_header(bounce, bounce_info, postmaster) == 0 + && bounce_recipient_log(bounce, bounce_info) == 0 + && bounce_header_dsn(bounce, bounce_info) == 0 + && bounce_recipient_dsn(bounce, bounce_info) == 0) + bounce_original(bounce, bounce_info, BOUNCE_HEADERS); + postmaster_status = post_mail_fclose(bounce); + } else + postmaster_status = 1; + + if (postmaster_status) + msg_warn("postmaster notice failed while bouncing to %s", + recipient); + } + } + + /* + * Examine the completion status. Delete the bounce log file only when + * the bounce was posted successfully, and only if we are bouncing for + * real, not just warning. + */ + if (flush != 0 && bounce_status == 0 && mail_queue_remove(service, queue_id) + && errno != ENOENT) + msg_fatal("remove %s %s: %m", service, queue_id); + + /* + * Cleanup. + */ + bounce_mail_free(bounce_info); + vstring_free(verp_buf); + + return (bounce_status); +} diff --git a/gnu/dist/postfix/src/bounce/bounce_service.h b/gnu/dist/postfix/src/bounce/bounce_service.h index 369a3da0d08..858609b7970 100644 --- a/gnu/dist/postfix/src/bounce/bounce_service.h +++ b/gnu/dist/postfix/src/bounce/bounce_service.h @@ -29,6 +29,11 @@ extern int bounce_append_service(char *, char *, char *, char *); extern int bounce_notify_service(char *, char *, char *, char *, int); /* + * bounce_notify_verp.c + */ +extern int bounce_notify_verp(char *, char *, char *, char *, char *, int); + + /* * bounce_cleanup.c */ extern VSTRING *bounce_cleanup_path; @@ -51,7 +56,7 @@ typedef struct { VSTREAM *orig_fp; /* open queue file */ long orig_offs; /* start of content */ time_t arrival_time; /* time of arrival */ - BOUNCE_LOG *log_handle; /* open logfile */ + BOUNCE_LOG *log_handle; /* open logfile */ } BOUNCE_INFO; extern BOUNCE_INFO *bounce_mail_init(const char *, const char *, const char *, int); diff --git a/gnu/dist/postfix/src/cleanup/Makefile.in b/gnu/dist/postfix/src/cleanup/Makefile.in index dd13667a6fc..cec834caa00 100644 --- a/gnu/dist/postfix/src/cleanup/Makefile.in +++ b/gnu/dist/postfix/src/cleanup/Makefile.in @@ -72,6 +72,7 @@ cleanup.o: ../../include/mail_conf.h cleanup.o: ../../include/cleanup_user.h cleanup.o: ../../include/mail_proto.h cleanup.o: ../../include/iostuff.h +cleanup.o: ../../include/attr.h cleanup.o: ../../include/mail_params.h cleanup.o: ../../include/record.h cleanup.o: ../../include/rec_type.h @@ -93,6 +94,7 @@ cleanup_api.o: ../../include/mail_queue.h cleanup_api.o: ../../include/vstream.h cleanup_api.o: ../../include/mail_proto.h cleanup_api.o: ../../include/iostuff.h +cleanup_api.o: ../../include/attr.h cleanup_api.o: ../../include/bounce.h cleanup_api.o: ../../include/mail_params.h cleanup_api.o: ../../include/mail_stream.h @@ -120,6 +122,7 @@ cleanup_envelope.o: ../../include/mail_params.h cleanup_envelope.o: ../../include/ext_prop.h cleanup_envelope.o: ../../include/mail_addr.h cleanup_envelope.o: ../../include/canon_addr.h +cleanup_envelope.o: ../../include/verp_sender.h cleanup_envelope.o: cleanup.h cleanup_envelope.o: ../../include/argv.h cleanup_envelope.o: ../../include/maps.h @@ -152,6 +155,7 @@ cleanup_init.o: cleanup_init.c cleanup_init.o: ../../include/sys_defs.h cleanup_init.o: ../../include/msg.h cleanup_init.o: ../../include/iostuff.h +cleanup_init.o: ../../include/name_mask.h cleanup_init.o: ../../include/mail_addr.h cleanup_init.o: ../../include/mail_params.h cleanup_init.o: ../../include/ext_prop.h diff --git a/gnu/dist/postfix/src/cleanup/cleanup.c b/gnu/dist/postfix/src/cleanup/cleanup.c index 70476aa2ec2..74c80bcc635 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup.c +++ b/gnu/dist/postfix/src/cleanup/cleanup.c @@ -35,7 +35,7 @@ /* header addresses (i.e. strip host or domain information below /* all domains listed in the \fBmasquerade_domains\fR parameter, /* except for user names listed in \fBmasquerade_exceptions\fR). -/* Address masquerading does not affect envelope recipients. +/* By default, address masquerading does not affect envelope recipients. /* .IP \(bu /* Optionally, expand envelope recipients according to information /* found in the \fBvirtual\fR(5) lookup tables. @@ -94,6 +94,10 @@ /* .IP \fBsender_canonical_maps\fR /* Address mapping lookup table for envelope and header sender /* addresses. +/* .IP \fBmasquerade_classes\fR +/* List of address classes subject to masquerading: zero or +/* more of \fBenvelope_sender\fR, \fBenvelope_recipient\fR, +/* \fBheader_sender\fR, \fBheader_recipient\fR. /* .IP \fBmasquerade_domains\fR /* List of domains that hide their subdomain structure. /* .IP \fBmasquerade_exceptions\fR @@ -107,6 +111,9 @@ /* Limit the number of envelope recipients that are remembered. /* .IP \fBheader_size_limit\fR /* Limit the amount of memory in bytes used to process a message header. +/* .IP \fBin_flow_delay\fR +/* Amount of time to pause before accepting a message, when the +/* message arrival rate exceeds the message delivery rate. /* .IP \fBextract_recipient_limit\fR /* Limit the amount of recipients extracted from message headers. /* SEE ALSO @@ -184,8 +191,12 @@ static void cleanup_service(VSTREAM *src, char *unused_service, char **argv) * can't read the client processing options we can pretty much forget * about the whole operation. */ - mail_print(src, "%s", state->queue_id); - if (mail_scan(src, "%d", &flags) != 1) { + attr_print(src, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, state->queue_id, + ATTR_TYPE_END); + if (attr_scan(src, ATTR_FLAG_STRICT, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &flags, + ATTR_TYPE_END) != 1) { state->errs |= CLEANUP_STAT_BAD; flags = 0; } @@ -223,7 +234,12 @@ static void cleanup_service(VSTREAM *src, char *unused_service, char **argv) /* * Finish this message, and report the result status to the client. */ - mail_print(src, "%d", cleanup_close(state)); + attr_print(src, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, cleanup_flush(state), + ATTR_TYPE_STR, MAIL_ATTR_WHY, state->reason ? + state->reason : "", + ATTR_TYPE_END); + cleanup_free(state); /* * Cleanup. @@ -271,5 +287,6 @@ int main(int argc, char **argv) MAIL_SERVER_PRE_INIT, cleanup_pre_jail, MAIL_SERVER_POST_INIT, cleanup_post_jail, MAIL_SERVER_PRE_ACCEPT, pre_accept, + MAIL_SERVER_IN_FLOW_DELAY, 0); } diff --git a/gnu/dist/postfix/src/cleanup/cleanup.h b/gnu/dist/postfix/src/cleanup/cleanup.h index a1e56848c73..09d700ed18a 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup.h +++ b/gnu/dist/postfix/src/cleanup/cleanup.h @@ -59,6 +59,7 @@ typedef struct CLEANUP_STATE { off_t xtra_offset; /* start of extra segment */ int end_seen; /* REC_TYPE_END seen */ int rcpt_count; /* recipient count */ + char *reason; /* failure reason */ } CLEANUP_STATE; /* @@ -71,6 +72,15 @@ extern MAPS *cleanup_header_checks; extern MAPS *cleanup_body_checks; extern MAPS *cleanup_virtual_maps; extern ARGV *cleanup_masq_domains; +extern int cleanup_masq_flags; + + /* + * Address masquerading fine control. + */ +#define CLEANUP_MASQ_FLAG_ENV_FROM (1<<0) /* envelope sender */ +#define CLEANUP_MASQ_FLAG_ENV_RCPT (1<<1) /* envelope recipient */ +#define CLEANUP_MASQ_FLAG_HDR_FROM (1<<2) /* header sender */ +#define CLEANUP_MASQ_FLAG_HDR_RCPT (1<<3) /* header recipient */ /* * Restrictions on extension propagation. @@ -94,7 +104,8 @@ extern void cleanup_state_free(CLEANUP_STATE *); */ extern CLEANUP_STATE *cleanup_open(void); extern void cleanup_control(CLEANUP_STATE *, int); -extern int cleanup_close(CLEANUP_STATE *); +extern int cleanup_flush(CLEANUP_STATE *); +extern void cleanup_free(CLEANUP_STATE *); extern void cleanup_all(void); extern void cleanup_pre_jail(char *, char **); extern void cleanup_post_jail(char *, char **); diff --git a/gnu/dist/postfix/src/cleanup/cleanup_api.c b/gnu/dist/postfix/src/cleanup/cleanup_api.c index 0773d2cf81f..2da603b9109 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup_api.c +++ b/gnu/dist/postfix/src/cleanup/cleanup_api.c @@ -18,7 +18,10 @@ /* char *buf; /* int len; /* -/* int cleanup_close(state) +/* int cleanup_flush(state) +/* CLEANUP_STATE *state; +/* +/* int cleanup_free(state) /* CLEANUP_STATE *state; /* DESCRIPTION /* This module implements a callable interface to the cleanup service @@ -27,26 +30,39 @@ /* /* cleanup_open() creates a new queue file and performs other /* per-message initialization. The result is a handle that should be -/* given to the cleanup_control(), cleanup_record() and cleanup_close() -/* routines. The name of the queue file is in the queue_id result -/* structure member. +/* given to the cleanup_control(), cleanup_record(), cleanup_flush() +/* and cleanup_free() routines. The name of the queue file is in the +/* queue_id result structure member. /* /* cleanup_control() processes per-message flags specified by the caller. /* These flags control the handling of data errors, and must be set /* before processing the first message record. -/* +/* .IP CLEANUP_FLAG_BOUNCE +/* The cleanup server is responsible for returning undeliverable +/* mail (too many hops, message too large) to the sender. +/* .IP CLEANUP_FLAG_FILTER +/* Enable header/body filtering. This should be enabled only with mail +/* that enters Postfix, not with locally forwarded mail or with bounce +/* messages. +/* .IP CLEANUP_FLAG_EXTRACT +/* Extract recipients from message headers when no recipients are +/* provided in the message envelope records. +/* .PP /* CLEANUP_RECORD() is a macro that processes one message record, /* that copies the result to the queue file, and that maintains a /* little state machine. The last record in a valid message has type /* REC_TYPE_END. In order to find out if a message is corrupted, /* the caller is encouraged to test the CLEANUP_OUT_OK(state) macro. /* The result is false when further message processing is futile. -/* In that case, it is safe to call cleanup_close() immediately. +/* In that case, it is safe to call cleanup_flush() immediately. /* -/* cleanup_close() finishes a queue file. In case of any errors, +/* cleanup_flush() closes a queue file. In case of any errors, /* the file is removed. The result value is non-zero in case of -/* problems. Use cleanup_strerror() to translate the result into -/* human_readable text. +/* problems. In some cases a human-readable text can be found in +/* the state->reason member. In all other cases, use cleanup_strerror() +/* to translate the result into human-readable text. +/* +/* cleanup_free() destroys its argument. /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* SEE ALSO @@ -109,7 +125,7 @@ CLEANUP_STATE *cleanup_open(void) * that the runtime error handler can clean up in case of problems. */ state->handle = mail_stream_file(MAIL_QUEUE_INCOMING, - MAIL_CLASS_PUBLIC, MAIL_SERVICE_QUEUE); + MAIL_CLASS_PUBLIC, MAIL_SERVICE_QUEUE, 0); state->dst = state->handle->stream; cleanup_path = mystrdup(VSTREAM_PATH(state->dst)); state->queue_id = mystrdup(state->handle->id); @@ -148,25 +164,28 @@ void cleanup_control(CLEANUP_STATE *state, int flags) * definition. */ if ((state->flags = flags) & CLEANUP_FLAG_BOUNCE) { - state->err_mask = - (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE | CLEANUP_STAT_SIZE); + state->err_mask = CLEANUP_STAT_MASK_INCOMPLETE; } else { - state->err_mask = CLEANUP_STAT_LETHAL; + state->err_mask = ~CLEANUP_STAT_MASK_EXTRACT_RCPT; } } -/* cleanup_close - finish queue file */ +/* cleanup_flush - finish queue file */ -int cleanup_close(CLEANUP_STATE *state) +int cleanup_flush(CLEANUP_STATE *state) { char *junk; int status; /* - * See if there are any errors. For example, the message is incomplete, - * or it needs to be bounced for lack of recipients. We want to turn on - * the execute bits on a file only when we really want the queue manager - * to process it. + * Ignore recipient extraction alarms if (a) we did (not need to) extract + * recipients, or (b) we did not examine all queue file records. + */ + if (state->recip != 0 || CLEANUP_OUT_OK(state) == 0) + state->errs &= ~CLEANUP_STAT_MASK_EXTRACT_RCPT; + + /* + * Raise these errors only if we examined all queue file records. */ if (CLEANUP_OUT_OK(state)) { if (state->recip == 0) @@ -180,10 +199,11 @@ int cleanup_close(CLEANUP_STATE *state) * because we are about to tell the sender that it can throw away its * copy of the message. */ - if ((state->errs & CLEANUP_STAT_LETHAL) == 0) - state->errs |= mail_stream_finish(state->handle); - else + if (state->errs == 0) { + state->errs = mail_stream_finish(state->handle, (VSTRING *) 0); + } else { mail_stream_cleanup(state->handle); + } state->handle = 0; state->dst = 0; @@ -200,26 +220,19 @@ int cleanup_close(CLEANUP_STATE *state) * * Do not log the arrival of a message that will be bounced by the client. * - * XXX CLEANUP_STAT_LETHAL masks errors that are not directly fatal (e.g., - * header buffer overflow is normally allowed to happen), but that can - * indirectly become a problem (e.g., no recipients were extracted from - * message headers because we could not process all the message headers). - * However, cleanup_strerror() prioritizes errors so that it can report - * the cause (e.g., header buffer overflow), which is more useful. - * * XXX When bouncing, should log sender because qmgr won't be able to. */ #define CAN_BOUNCE() \ - ((state->errs & (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE)) == 0 \ + ((state->errs & CLEANUP_STAT_MASK_CANT_BOUNCE) == 0 \ && state->sender != 0 \ && (state->flags & CLEANUP_FLAG_BOUNCE) != 0) - if (state->errs & CLEANUP_STAT_LETHAL) { + if (state->errs != 0) { if (CAN_BOUNCE()) { if (bounce_append(BOUNCE_FLAG_CLEAN, state->queue_id, state->recip ? state->recip : "unknown", "cleanup", state->time, - "Message processing aborted: %s", + "%s", state->reason ? state->reason : cleanup_strerror(state->errs)) == 0 && bounce_flush(BOUNCE_FLAG_CLEAN, MAIL_QUEUE_INCOMING, state->queue_id, state->sender) == 0) { @@ -249,8 +262,14 @@ int cleanup_close(CLEANUP_STATE *state) * initializations at the beginning of cleanup_open(). */ if (msg_verbose) - msg_info("cleanup_close: status %d", state->errs); - status = state->errs & CLEANUP_STAT_LETHAL; - cleanup_state_free(state); + msg_info("cleanup_flush: status %d", state->errs); + status = state->errs; return (status); } + +/* cleanup_free - pay the last respects */ + +void cleanup_free(CLEANUP_STATE *state) +{ + cleanup_state_free(state); +} diff --git a/gnu/dist/postfix/src/cleanup/cleanup_envelope.c b/gnu/dist/postfix/src/cleanup/cleanup_envelope.c index 86758c146ad..f4fd30e75d0 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup_envelope.c +++ b/gnu/dist/postfix/src/cleanup/cleanup_envelope.c @@ -67,6 +67,7 @@ #include <ext_prop.h> #include <mail_addr.h> #include <canon_addr.h> +#include <verp_sender.h> /* Application-specific. */ @@ -148,7 +149,8 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf, if (cleanup_comm_canon_maps) cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, cleanup_ext_prop_mask & EXT_PROP_CANONICAL); - if (cleanup_masq_domains) + if (cleanup_masq_domains + && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_FROM)) cleanup_masquerade_internal(clean_addr, cleanup_masq_domains); CLEANUP_OUT_BUF(state, type, clean_addr); if (state->sender == 0) @@ -170,6 +172,9 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf, if (cleanup_comm_canon_maps) cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, cleanup_ext_prop_mask & EXT_PROP_CANONICAL); + if (cleanup_masq_domains + && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) + cleanup_masquerade_internal(clean_addr, cleanup_masq_domains); cleanup_out_recipient(state, STR(clean_addr)); if (state->recip == 0) state->recip = mystrdup(STR(clean_addr)); @@ -179,6 +184,18 @@ static void cleanup_envelope_process(CLEANUP_STATE *state, int type, char *buf, state->errs |= CLEANUP_STAT_BAD; return; } + } else if (type == REC_TYPE_VERP) { + if (state->sender == 0 || *state->sender == 0) { + state->errs |= CLEANUP_STAT_BAD; + return; + } + if (verp_delims_verify(buf) == 0) { + cleanup_out(state, type, buf, len); + } else { + msg_warn("%s: bad VERP delimiters: \"%s\"", state->queue_id, buf); + state->errs |= CLEANUP_STAT_BAD; + return; + } } else { cleanup_out(state, type, buf, len); } diff --git a/gnu/dist/postfix/src/cleanup/cleanup_extracted.c b/gnu/dist/postfix/src/cleanup/cleanup_extracted.c index 243404be1c4..b9721bd88e3 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup_extracted.c +++ b/gnu/dist/postfix/src/cleanup/cleanup_extracted.c @@ -123,6 +123,9 @@ static void cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf, if (cleanup_comm_canon_maps) cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, cleanup_ext_prop_mask & EXT_PROP_CANONICAL); + if (cleanup_masq_domains + && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) + cleanup_masquerade_internal(clean_addr, cleanup_masq_domains); cleanup_out_recipient(state, STR(clean_addr)); if (state->recip == 0) state->recip = mystrdup(STR(clean_addr)); @@ -150,8 +153,8 @@ static void cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf, if (rcpt->argc >= var_extra_rcpt_limit) { state->errs |= CLEANUP_STAT_ROVFL; } else { + clean_addr = vstring_alloc(100); if (*var_always_bcc && rcpt->argv[0]) { - clean_addr = vstring_alloc(100); cleanup_rewrite_internal(clean_addr, var_always_bcc); if (cleanup_rcpt_canon_maps) cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps, @@ -160,13 +163,26 @@ static void cleanup_extracted_process(CLEANUP_STATE *state, int type, char *buf, cleanup_map11_internal(state, clean_addr, cleanup_comm_canon_maps, cleanup_ext_prop_mask & EXT_PROP_CANONICAL); argv_add(rcpt, STR(clean_addr), (char *) 0); - vstring_free(clean_addr); } argv_terminate(rcpt); - for (cpp = rcpt->argv; CLEANUP_OUT_OK(state) && *cpp; cpp++) - cleanup_out_recipient(state, *cpp); + + /* + * Recipients extracted from message headers already have + * undergone recipient address rewriting (see cleanup_message.c), + * but still may need address masquerading. + */ + for (cpp = rcpt->argv; CLEANUP_OUT_OK(state) && *cpp; cpp++) { + if (cleanup_masq_domains + && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_ENV_RCPT)) { + vstring_strcpy(clean_addr, *cpp); + cleanup_masquerade_internal(clean_addr, cleanup_masq_domains); + cleanup_out_recipient(state, STR(clean_addr)); + } else + cleanup_out_recipient(state, *cpp); + } if (rcpt->argv[0]) state->recip = mystrdup(rcpt->argv[0]); + vstring_free(clean_addr); } } diff --git a/gnu/dist/postfix/src/cleanup/cleanup_init.c b/gnu/dist/postfix/src/cleanup/cleanup_init.c index 0cb5812c5bc..b3e7a0157e4 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup_init.c +++ b/gnu/dist/postfix/src/cleanup/cleanup_init.c @@ -69,6 +69,7 @@ #include <msg.h> #include <iostuff.h> +#include <name_mask.h> /* Global library. */ @@ -106,6 +107,7 @@ char *var_prop_extension; /* propagate unmatched extension */ char *var_always_bcc; /* big brother */ int var_extra_rcpt_limit; /* recipient extract limit */ char *var_rcpt_witheld; /* recipients not disclosed */ +char *var_masq_classes; /* what to masquerade */ CONFIG_INT_TABLE cleanup_int_table[] = { VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0, @@ -133,6 +135,7 @@ CONFIG_STR_TABLE cleanup_str_table[] = { VAR_PROP_EXTENSION, DEF_PROP_EXTENSION, &var_prop_extension, 0, 0, VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0, VAR_RCPT_WITHELD, DEF_RCPT_WITHELD, &var_rcpt_witheld, 1, 0, + VAR_MASQ_CLASSES, DEF_MASQ_CLASSES, &var_masq_classes, 0, 0, 0, }; @@ -146,6 +149,7 @@ MAPS *cleanup_header_checks; MAPS *cleanup_body_checks; MAPS *cleanup_virtual_maps; ARGV *cleanup_masq_domains; +int cleanup_masq_flags; /* * Address extension propagation restrictions. @@ -164,9 +168,17 @@ void cleanup_all(void) void cleanup_pre_jail(char *unused_name, char **unused_argv) { + static NAME_MASK masq_class_table[] = { + MASQ_CLASS_ENV_FROM, CLEANUP_MASQ_FLAG_ENV_FROM, + MASQ_CLASS_ENV_RCPT, CLEANUP_MASQ_FLAG_ENV_RCPT, + MASQ_CLASS_HDR_FROM, CLEANUP_MASQ_FLAG_HDR_FROM, + MASQ_CLASS_HDR_RCPT, CLEANUP_MASQ_FLAG_HDR_RCPT, + 0, + }; + if (*var_canonical_maps) cleanup_comm_canon_maps = - maps_create(VAR_CANONICAL_MAPS, var_canonical_maps, DICT_FLAG_LOCK); + maps_create(VAR_CANONICAL_MAPS, var_canonical_maps, DICT_FLAG_LOCK); if (*var_send_canon_maps) cleanup_send_canon_maps = maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps, @@ -186,6 +198,9 @@ void cleanup_pre_jail(char *unused_name, char **unused_argv) if (*var_body_checks) cleanup_body_checks = maps_create(VAR_BODY_CHECKS, var_body_checks, DICT_FLAG_LOCK); + if (*var_masq_classes) + cleanup_masq_flags = name_mask(VAR_MASQ_CLASSES, masq_class_table, + var_masq_classes); } /* cleanup_post_jail - initialize after entering the chroot jail */ diff --git a/gnu/dist/postfix/src/cleanup/cleanup_message.c b/gnu/dist/postfix/src/cleanup/cleanup_message.c index 99644203fb0..fca690451bc 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup_message.c +++ b/gnu/dist/postfix/src/cleanup/cleanup_message.c @@ -178,7 +178,8 @@ static void cleanup_rewrite_sender(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts) if (cleanup_comm_canon_maps) cleanup_map11_tree(state, *tpp, cleanup_comm_canon_maps, cleanup_ext_prop_mask & EXT_PROP_CANONICAL); - if (cleanup_masq_domains) + if (cleanup_masq_domains + && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_HDR_FROM)) cleanup_masquerade_tree(*tpp, cleanup_masq_domains); if (hdr_opts->type == HDR_FROM && state->from == 0) state->from = cleanup_extract_internal(state->header_buf, *tpp); @@ -228,6 +229,11 @@ static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts) if (cleanup_comm_canon_maps) cleanup_map11_tree(state, *tpp, cleanup_comm_canon_maps, cleanup_ext_prop_mask & EXT_PROP_CANONICAL); + + /* + * Extract envelope recipients after recipient address rewriting but + * before address masquerading. + */ if (state->recip == 0 && (hdr_opts->flags & HDR_OPT_EXTRACT) != 0) { rcpt = (hdr_opts->flags & HDR_OPT_RR) ? state->resent_recip : state->recipients; @@ -236,7 +242,8 @@ static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts) argv_add(rcpt, vstring_str(state->temp1), (char *) 0); } } - if (cleanup_masq_domains) + if (cleanup_masq_domains + && (cleanup_masq_flags & CLEANUP_MASQ_FLAG_HDR_RCPT)) cleanup_masquerade_tree(*tpp, cleanup_masq_domains); } vstring_sprintf(state->header_buf, "%s: ", hdr_opts->name); @@ -247,6 +254,33 @@ static void cleanup_rewrite_recip(CLEANUP_STATE *state, HEADER_OPTS *hdr_opts) cleanup_fold_header(state); } +/* cleanup_check_reject - parse and match header/body REJECT line */ + +static int cleanup_check_reject(CLEANUP_STATE *state, const char *value) +{ + const char *reason = value + strcspn(value, " \t"); + + /* + * See if they spelled REJECT right. + * + * XXX The reason should be set only if we have a more severe error than + * anything that was found before. This calls for a cleanup_set_error() + * routine that takes an error code and an optional text. + */ + if (strncasecmp(value, "REJECT", reason - value) == 0) { + if (state->reason == 0) { + while (*reason && ISSPACE(*reason)) + reason++; + state->reason = mystrdup(*reason ? reason : + cleanup_strerror(CLEANUP_STAT_CONT)); + } + state->errs |= CLEANUP_STAT_CONT; + return (1); + } else { + return (0); + } +} + /* cleanup_header - process one complete header line */ static void cleanup_header(CLEANUP_STATE *state) @@ -262,13 +296,17 @@ static void cleanup_header(CLEANUP_STATE *state) const char *value; if ((value = maps_find(cleanup_header_checks, header, 0)) != 0) { - if (strcasecmp(value, "REJECT") == 0) { - msg_info("%s: reject: header %.200s; from=<%s> to=<%s>", + if (cleanup_check_reject(state, value) != 0) { + msg_info("%s: reject: header %.200s; from=<%s> to=<%s>: %s", state->queue_id, header, state->sender, - state->recip ? state->recip : "unknown"); - state->errs |= CLEANUP_STAT_CONT; + state->recip ? state->recip : "unknown", + state->reason); } else if (strcasecmp(value, "IGNORE") == 0) { return; + } else if (strcasecmp(value, "WARN") == 0) { + msg_info("%s: warning: header %.200s; from=<%s> to=<%s>", + state->queue_id, header, state->sender, + state->recip ? state->recip : "unknown"); } } } @@ -287,6 +325,29 @@ static void cleanup_header(CLEANUP_STATE *state) * we should do with this header: delete, count, rewrite. Note that we * should examine headers even when they will be deleted from the output, * because the addresses in those headers might be needed elsewhere. + * + * XXX 2821: Return-path breakage. + * + * RFC 821 specifies: When the receiver-SMTP makes the "final delivery" of a + * message it inserts at the beginning of the mail data a return path + * line. The return path line preserves the information in the + * <reverse-path> from the MAIL command. Here, final delivery means the + * message leaves the SMTP world. Normally, this would mean it has been + * delivered to the destination user, but in some cases it may be further + * processed and transmitted by another mail system. + * + * And that is what Postfix implements. Delivery agents prepend + * Return-Path:. In order to avoid cluttering up the message with + * possibly inconsistent Return-Path: information (the sender can change + * as the result of mail forwarding or mailing list delivery), Postfix + * removes any existing Return-Path: headers. + * + * RFC 2821 Section 4.4 specifies: A message-originating SMTP system + * SHOULD NOT send a message that already contains a Return-path header. + * SMTP servers performing a relay function MUST NOT inspect the message + * data, and especially not to the extent needed to determine if + * Return-path headers are present. SMTP servers making final delivery + * MAY remove Return-path headers before adding their own. */ else { state->headers_seen |= (1 << hdr_opts->type); @@ -324,6 +385,11 @@ static void cleanup_missing_headers(CLEANUP_STATE *state) /* * Add a missing (Resent-)Message-Id: header. The message ID gives the * time in GMT units, plus the local queue ID. + * + * XXX Message-Id is not a required message header (RFC 822 and RFC 2822). + * + * XXX It is the queue ID non-inode bits that prevent messages from getting + * the same Message-Id within the same second. */ if ((state->headers_seen & (1 << (state->resent[0] ? HDR_RESENT_MESSAGE_ID : HDR_MESSAGE_ID))) == 0) { @@ -366,6 +432,29 @@ static void cleanup_missing_headers(CLEANUP_STATE *state) } /* + * XXX 2821: Appendix B: The return address in the MAIL command SHOULD, + * if possible, be derived from the system's identity for the submitting + * (local) user, and the "From:" header field otherwise. If there is a + * system identity available, it SHOULD also be copied to the Sender + * header field if it is different from the address in the From header + * field. (Any Sender field that was already there SHOULD be removed.) + * Similar wording appears in RFC 2822 section 3.6.2. + * + * Postfix presently does not insert a Sender: header if envelope and From: + * address differ. Older Postfix versions assumed that the envelope + * sender address specifies the system identity and inserted Sender: + * whenever envelope and From: differed. This was wrong with relayed + * mail, and was often not even desirable with original submissions. + * + * XXX 2822 Section 3.6.2, as well as RFC 822 Section 4.1: FROM headers can + * contain multiple addresses. If this is the case, then a Sender: header + * must be provided with a single address. + * + * Postfix does not count the number of addresses in a From: header + * (although doing so is trivial, once the address is parsed). + */ + + /* * Add a missing destination header. */ #define VISIBLE_RCPT ((1 << HDR_TO) | (1 << HDR_RESENT_TO) \ @@ -491,13 +580,17 @@ static void cleanup_message_body(CLEANUP_STATE *state, int type, char *buf, int const char *value; if ((value = maps_find(cleanup_body_checks, buf, 0)) != 0) { - if (strcasecmp(value, "REJECT") == 0) { - msg_info("%s: reject: body %.200s; from=<%s> to=<%s>", + if (cleanup_check_reject(state, value) != 0) { + msg_info("%s: reject: body %.200s; from=<%s> to=<%s>: %s", state->queue_id, buf, state->sender, - state->recip ? state->recip : "unknown"); - state->errs |= CLEANUP_STAT_CONT; + state->recip ? state->recip : "unknown", + state->reason); } else if (strcasecmp(value, "IGNORE") == 0) { return; + } else if (strcasecmp(value, "WARN") == 0) { + msg_info("%s: warning: body %.200s; from=<%s> to=<%s>", + state->queue_id, buf, state->sender, + state->recip ? state->recip : "unknown"); } } } diff --git a/gnu/dist/postfix/src/cleanup/cleanup_state.c b/gnu/dist/postfix/src/cleanup/cleanup_state.c index c7e5b74b6c2..2206d7a42ec 100644 --- a/gnu/dist/postfix/src/cleanup/cleanup_state.c +++ b/gnu/dist/postfix/src/cleanup/cleanup_state.c @@ -84,6 +84,7 @@ CLEANUP_STATE *cleanup_state_alloc(void) state->xtra_offset = -1; state->end_seen = 0; state->rcpt_count = 0; + state->reason = 0; return (state); } @@ -113,5 +114,7 @@ void cleanup_state_free(CLEANUP_STATE *state) if (state->queue_id) myfree(state->queue_id); been_here_free(state->dups); + if (state->reason) + myfree(state->reason); myfree((char *) state); } diff --git a/gnu/dist/postfix/src/dns/Makefile.in b/gnu/dist/postfix/src/dns/Makefile.in index e132be3db58..812c3fbc8e8 100644 --- a/gnu/dist/postfix/src/dns/Makefile.in +++ b/gnu/dist/postfix/src/dns/Makefile.in @@ -81,6 +81,7 @@ dns_rr.o: dns_rr.c dns_rr.o: ../../include/sys_defs.h dns_rr.o: ../../include/msg.h dns_rr.o: ../../include/mymalloc.h +dns_rr.o: ../../include/myrand.h dns_rr.o: dns.h dns_rr.o: ../../include/vstring.h dns_rr.o: ../../include/vbuf.h diff --git a/gnu/dist/postfix/src/dns/dns.h b/gnu/dist/postfix/src/dns/dns.h index 490a5ff3923..e08583d6e8d 100644 --- a/gnu/dist/postfix/src/dns/dns.h +++ b/gnu/dist/postfix/src/dns/dns.h @@ -105,6 +105,7 @@ extern void dns_rr_free(DNS_RR *); extern DNS_RR *dns_rr_copy(DNS_RR *); extern DNS_RR *dns_rr_append(DNS_RR *, DNS_RR *); extern DNS_RR *dns_rr_sort(DNS_RR *, int (*) (DNS_RR *, DNS_RR *)); +extern DNS_RR *dns_rr_shuffle(DNS_RR *); /* * dns_lookup.c diff --git a/gnu/dist/postfix/src/dns/dns_rr.c b/gnu/dist/postfix/src/dns/dns_rr.c index 39cbf192061..2dc8edd1b0c 100644 --- a/gnu/dist/postfix/src/dns/dns_rr.c +++ b/gnu/dist/postfix/src/dns/dns_rr.c @@ -26,6 +26,9 @@ /* DNS_RR *dns_rr_sort(list, compar) /* DNS_RR *list /* int (*compar)(DNS_RR *, DNS_RR *); +/* +/* DNS_RR *dns_rr_shuffle(list) +/* DNS_RR *list; /* DESCRIPTION /* The routines in this module maintain memory for DNS resource record /* information, and maintain lists of DNS resource records. @@ -49,6 +52,8 @@ /* dns_rr_sort() sorts a list of resource records into ascending /* order according to a user-specified criterion. The result is the /* sorted list. +/* +/* dns_rr_shuffle() randomly permutes a list of resource records. /* LICENSE /* .ad /* .fi @@ -70,6 +75,7 @@ #include <msg.h> #include <mymalloc.h> +#include <myrand.h> /* DNS library. */ @@ -193,3 +199,47 @@ DNS_RR *dns_rr_sort(DNS_RR *list, int (*compar) (DNS_RR *, DNS_RR *)) dns_rr_sort_user = saved_user; return (list); } + +/* dns_rr_shuffle - shuffle resource record list */ + +DNS_RR *dns_rr_shuffle(DNS_RR *list) +{ + DNS_RR **rr_array; + DNS_RR *rr; + int len; + int i; + int r; + + /* + * Build linear array with pointers to each list element. + */ + for (len = 0, rr = list; rr != 0; len++, rr = rr->next) + /* void */ ; + rr_array = (DNS_RR **) mymalloc(len * sizeof(*rr_array)); + for (len = 0, rr = list; rr != 0; len++, rr = rr->next) + rr_array[len] = rr; + + /* + * Shuffle resource records. + */ + for (i = 0; i < len; i++) { + r = myrand() % len; + rr = rr_array[i]; + rr_array[i] = rr_array[r]; + rr_array[r] = rr; + } + + /* + * Fix the links. + */ + for (i = 0; i < len - 1; i++) + rr_array[i]->next = rr_array[i + 1]; + rr_array[i]->next = 0; + list = rr_array[0]; + + /* + * Cleanup. + */ + myfree((char *) rr_array); + return (list); +} diff --git a/gnu/dist/postfix/src/flush/Makefile.in b/gnu/dist/postfix/src/flush/Makefile.in index 19b51de2809..835aea3787e 100644 --- a/gnu/dist/postfix/src/flush/Makefile.in +++ b/gnu/dist/postfix/src/flush/Makefile.in @@ -71,10 +71,14 @@ flush.o: ../../include/mail_params.h flush.o: ../../include/mail_queue.h flush.o: ../../include/mail_proto.h flush.o: ../../include/iostuff.h +flush.o: ../../include/attr.h flush.o: ../../include/mail_flush.h flush.o: ../../include/flush_clnt.h flush.o: ../../include/mail_conf.h 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 diff --git a/gnu/dist/postfix/src/flush/flush.c b/gnu/dist/postfix/src/flush/flush.c index c8c76c0d09a..828681ad24a 100644 --- a/gnu/dist/postfix/src/flush/flush.c +++ b/gnu/dist/postfix/src/flush/flush.c @@ -38,7 +38,7 @@ /* if mail is undeliverable it will be added back to the logfile. /* .sp /* If the destination is not eligible for a fast flush logfile, -/* this request triggers delivery of all queued mail. +/* this request is rejected (see below for status codes). /* .IP \fBTRIGGER_REQ_WAKEUP\fR /* This wakeup request from the master is an alternative way to /* request \fBFLUSH_REQ_REFRESH\fR. @@ -66,6 +66,10 @@ /* request parameter value). /* .IP \fBFLUSH_STAT_FAIL\fR /* The request failed. +/* .IP \fBFLUSH_STAT_DENY\fR +/* The request was denied because the destination domain is not +/* eligible for fast flush service, or because the fast flush +/* service is disabled. /* SECURITY /* .ad /* .fi @@ -106,6 +110,10 @@ /* .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 +/* 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 @@ -156,6 +164,7 @@ #include <mail_scan_dir.h> #include <maps.h> #include <domain_list.h> +#include <match_parent_style.h> /* Single server skeleton. */ @@ -243,10 +252,10 @@ static int flush_add_service(const char *site, const char *queue_id) msg_info("%s: site %s queue_id %s", myname, site, queue_id); /* - * If this site is not eligible for logging, just ignore the request. + * If this site is not eligible for logging, deny the request. */ if (flush_policy_ok(site) == 0) - return (FLUSH_STAT_OK); + return (FLUSH_STAT_DENY); /* * Map site to path and update log. @@ -319,10 +328,10 @@ static int flush_send_service(const char *site) msg_info("%s: site %s", myname, site); /* - * If this site is not eligible for logging, deliver all queued mail. + * If this site is not eligible for logging, deny the request. */ if (flush_policy_ok(site) == 0) - return (mail_flush_deferred()); + return (FLUSH_STAT_DENY); /* * Map site name to path name and flush the log. @@ -507,6 +516,51 @@ static int flush_refresh_service(int max_age) return (FLUSH_STAT_OK); } +/* flush_request_receive - receive request */ + +static int flush_request_receive(VSTREAM *client_stream, VSTRING *request) +{ + int count; + + /* + * Kluge: choose the protocol depending on the request size. + */ + if (read_wait(vstream_fileno(client_stream), var_ipc_timeout) < 0) { + msg_warn("timeout while waiting for data from %s", + VSTREAM_PATH(client_stream)); + return (-1); + } + if ((count = peekfd(vstream_fileno(client_stream))) < 0) { + msg_warn("cannot examine read buffer of %s: %m", + VSTREAM_PATH(client_stream)); + return (-1); + } + + /* + * Short request: master trigger. Use the string+null protocol. + */ + if (count <= 2) { + if (vstring_get_null(request, client_stream) == VSTREAM_EOF) { + msg_warn("end-of-input while reading request from %s: %m", + VSTREAM_PATH(client_stream)); + return (-1); + } + } + + /* + * Long request: real flush client. Use the attribute list protocol. + */ + else { + if (attr_scan(client_stream, + ATTR_FLAG_MORE | ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_REQ, request, + ATTR_TYPE_END) != 1) { + return (-1); + } + } + return (0); +} + /* flush_service - perform service for client */ static void flush_service(VSTREAM *client_stream, char *unused_service, @@ -536,31 +590,46 @@ static void flush_service(VSTREAM *client_stream, char *unused_service, * All connection-management stuff is handled by the common code in * single_server.c. */ - if (mail_scan(client_stream, "%s", request) == 1) { + if (flush_request_receive(client_stream, request) == 0) { if (STREQ(STR(request), FLUSH_REQ_ADD)) { site = vstring_alloc(10); queue_id = vstring_alloc(10); - if (mail_command_read(client_stream, "%s %s", site, queue_id) == 2 + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_SITE, site, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_END) == 2 && mail_queue_id_ok(STR(queue_id))) status = flush_add_service(lowercase(STR(site)), STR(queue_id)); - mail_print(client_stream, "%d", status); + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status, + ATTR_TYPE_END); } else if (STREQ(STR(request), FLUSH_REQ_SEND)) { site = vstring_alloc(10); - if (mail_command_read(client_stream, "%s", site) == 1) + if (attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_SITE, site, + ATTR_TYPE_END) == 1) status = flush_send_service(lowercase(STR(site))); - mail_print(client_stream, "%d", status); + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status, + ATTR_TYPE_END); } else if (STREQ(STR(request), FLUSH_REQ_REFRESH) || STREQ(STR(request), wakeup)) { - mail_print(client_stream, "%d", FLUSH_STAT_OK); + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, FLUSH_STAT_OK, + ATTR_TYPE_END); vstream_fflush(client_stream); (void) flush_refresh_service(var_fflush_refresh); } else if (STREQ(STR(request), FLUSH_REQ_PURGE)) { - mail_print(client_stream, "%d", FLUSH_STAT_OK); + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, FLUSH_STAT_OK, + ATTR_TYPE_END); vstream_fflush(client_stream); (void) flush_refresh_service(0); } } else - mail_print(client_stream, "%d", status); + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status, + ATTR_TYPE_END); vstring_free(request); if (site) vstring_free(site); @@ -572,7 +641,8 @@ static void flush_service(VSTREAM *client_stream, char *unused_service, 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 */ diff --git a/gnu/dist/postfix/src/global/abounce.c b/gnu/dist/postfix/src/global/abounce.c index bfda481d51d..5cacccf5e8c 100644 --- a/gnu/dist/postfix/src/global/abounce.c +++ b/gnu/dist/postfix/src/global/abounce.c @@ -14,6 +14,15 @@ /* void (*callback)(int status, char *context); /* char *context; /* +/* void abounce_flush_verp(flags, queue, id, sender, verp, callback, context) +/* int flags; +/* const char *queue; +/* const char *id; +/* const char *sender; +/* const char *verp; +/* void (*callback)(int status, char *context); +/* char *context; +/* /* void adefer_flush(flags, queue, id, sender, callback, context) /* int flags; /* const char *queue; @@ -22,6 +31,15 @@ /* void (*callback)(int status, char *context); /* char *context; /* +/* void adefer_flush_verp(flags, queue, id, sender, verp, callback, context) +/* int flags; +/* const char *queue; +/* const char *id; +/* const char *sender; +/* const char *verp; +/* void (*callback)(int status, char *context); +/* char *context; +/* /* void adefer_warn(flags, queue, id, sender, callback, context) /* int flags; /* const char *queue; @@ -38,10 +56,16 @@ /* the specified sender, including the bounce log that was /* built with bounce_append(). /* +/* abounce_flush_verp() is like abounce_flush() but sends +/* one VERP style notification per undeliverable recipient. +/* /* adefer_flush() bounces the specified message to /* the specified sender, including the defer log that was /* built with defer_append(). /* +/* adefer_flush_verp() is like adefer_flush() but sends +/* one VERP style notification per undeliverable recipient. +/* /* adefer_warn() sends a "mail is delayed" notification to /* the specified sender, including the defer log that was /* built with defer_append(). @@ -64,6 +88,8 @@ /* file has the same name as the original message file. /* .IP sender /* The sender envelope address. +/* .IP verp +/* VERP delimiter characters. /* .IP callback /* Name of a routine that receives the notification status as /* documented for bounce_flush() or defer_flush(). @@ -145,7 +171,69 @@ static void abounce_event(int unused_event, char *context) int status; event_disable_readwrite(vstream_fileno(ap->fp)); - abounce_done(ap, mail_scan(ap->fp, "%d", &status) == 1 ? status : -1); + abounce_done(ap, attr_scan(ap->fp, ATTR_FLAG_STRICT, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) == 1 ? status : -1); +} + +/* abounce_request_verp - suspend pseudo thread until server reply event */ + +static void abounce_request_verp(const char *class, const char *service, + int command, int flags, + const char *queue, const char *id, + const char *sender, const char *verp, + ABOUNCE_FN callback, + char *context) +{ + ABOUNCE *ap; + + /* + * Save pseudo thread state. Connect to the server. Send the request and + * suspend the pseudo thread until the server replies (or dies). + */ + ap = (ABOUNCE *) mymalloc(sizeof(*ap)); + ap->command = command; + ap->flags = flags; + ap->id = mystrdup(id); + ap->callback = callback; + ap->context = context; + ap->fp = mail_connect_wait(class, service); + + if (attr_print(ap->fp, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp, + ATTR_TYPE_END) == 0 + && vstream_fflush(ap->fp) == 0) { + event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap); + } else { + abounce_done(ap, -1); + } +} + +/* abounce_flush_verp - asynchronous bounce flush */ + +void abounce_flush_verp(int flags, const char *queue, const char *id, + const char *sender, const char *verp, + ABOUNCE_FN callback, char *context) +{ + abounce_request_verp(MAIL_CLASS_PRIVATE, MAIL_SERVICE_BOUNCE, + BOUNCE_CMD_VERP, flags, queue, id, sender, verp, + callback, context); +} + +/* adefer_flush_verp - asynchronous defer flush */ + +void adefer_flush_verp(int flags, const char *queue, const char *id, + const char *sender, const char *verp, + ABOUNCE_FN callback, char *context) +{ + abounce_request_verp(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER, + BOUNCE_CMD_VERP, flags, queue, id, sender, verp, + callback, context); } /* abounce_request - suspend pseudo thread until server reply event */ @@ -171,8 +259,13 @@ static void abounce_request(const char *class, const char *service, ap->context = context; ap->fp = mail_connect_wait(class, service); - if (mail_print(ap->fp, "%d %d %s %s %s %s", command, - flags, queue, id, sender, MAIL_EOF) == 0 + if (attr_print(ap->fp, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_END) == 0 && vstream_fflush(ap->fp) == 0) { event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap); } else { diff --git a/gnu/dist/postfix/src/global/abounce.h b/gnu/dist/postfix/src/global/abounce.h index 8932248751c..69542383a5b 100644 --- a/gnu/dist/postfix/src/global/abounce.h +++ b/gnu/dist/postfix/src/global/abounce.h @@ -25,6 +25,9 @@ extern void abounce_flush(int, const char *, const char *, const char *, ABOUNCE extern void adefer_flush(int, const char *, const char *, const char *, ABOUNCE_FN, char *); extern void adefer_warn(int, const char *, const char *, const char *, ABOUNCE_FN, char *); +extern void abounce_flush_verp(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *); +extern void adefer_flush_verp(int, const char *, const char *, const char *, const char *, ABOUNCE_FN, char *); + /* LICENSE /* .ad /* .fi diff --git a/gnu/dist/postfix/src/global/bounce.c b/gnu/dist/postfix/src/global/bounce.c index 75b07298d87..805d4c78710 100644 --- a/gnu/dist/postfix/src/global/bounce.c +++ b/gnu/dist/postfix/src/global/bounce.c @@ -142,10 +142,14 @@ int vbounce_append(int flags, const char *id, const char *recipient, why = vstring_alloc(100); delay = time((time_t *) 0) - entry; vstring_vsprintf(why, fmt, ap); - if (mail_command_write(MAIL_CLASS_PRIVATE, var_soft_bounce ? - MAIL_SERVICE_DEFER : MAIL_SERVICE_BOUNCE, - "%d %d %s %s %s", BOUNCE_CMD_APPEND, - flags, id, recipient, vstring_str(why)) == 0) { + if (mail_command_client(MAIL_CLASS_PRIVATE, var_soft_bounce ? + MAIL_SERVICE_DEFER : MAIL_SERVICE_BOUNCE, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient, + ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why), + ATTR_TYPE_END) == 0) { msg_info("%s: to=<%s>, relay=%s, delay=%d, status=%s (%s)", id, recipient, relay, delay, var_soft_bounce ? "deferred" : "bounced", vstring_str(why)); @@ -172,9 +176,13 @@ int bounce_flush(int flags, const char *queue, const char *id, */ if (var_soft_bounce) return (-1); - if (mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_BOUNCE, - "%d %d %s %s %s", BOUNCE_CMD_FLUSH, - flags, queue, id, sender) == 0) { + if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_BOUNCE, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_END) == 0) { return (0); } else if ((flags & BOUNCE_FLAG_CLEAN) == 0) { msg_info("%s: status=deferred (bounce failed)", id); diff --git a/gnu/dist/postfix/src/global/bounce.h b/gnu/dist/postfix/src/global/bounce.h index 43ebc6040bb..018b91a4fe6 100644 --- a/gnu/dist/postfix/src/global/bounce.h +++ b/gnu/dist/postfix/src/global/bounce.h @@ -40,8 +40,8 @@ extern int vbounce_recip(int, const char *, const char *, const char *, */ #define BOUNCE_CMD_APPEND 0 /* append log */ #define BOUNCE_CMD_FLUSH 1 /* send log */ -#define BOUNCE_CMD_WARN 2 /* send warning bounce, don't delete - * log */ +#define BOUNCE_CMD_WARN 2 /* send warning, don't delete log */ +#define BOUNCE_CMD_VERP 3 /* send log, verp style */ /* * Flags. diff --git a/gnu/dist/postfix/src/global/bounce_log.c b/gnu/dist/postfix/src/global/bounce_log.c index 566ad48783b..f0f84153207 100644 --- a/gnu/dist/postfix/src/global/bounce_log.c +++ b/gnu/dist/postfix/src/global/bounce_log.c @@ -24,6 +24,9 @@ /* BOUNCE_LOG *bounce_log_read(bp) /* BOUNCE_LOG *bp; /* +/* BOUNCE_LOG *bounce_log_delrcpt(bp) +/* BOUNCE_LOG *bp; +/* /* void bounce_log_rewind(bp) /* BOUNCE_LOG *bp; /* @@ -31,8 +34,7 @@ /* BOUNCE_LOG *bp; /* DESCRIPTION /* This module implements a bounce/defer logfile API. Information -/* is sanitized for control and non-ASCII characters. Currently, -/* only the reading end is implemented. +/* is sanitized for control and non-ASCII characters. /* /* bounce_log_open() opens the named bounce or defer logfile /* and returns a handle that must be used for further access. @@ -47,6 +49,9 @@ /* bounce_log_read() returns a null pointer when no recipient was read, /* otherwise it returns its argument. /* +/* bounce_log_delrcpt() marks the last accessed recipient record as +/* "deleted". This requires that the logfile is opened for update. +/* /* bounce_log_rewind() is a helper that seeks to the first recipient /* in an open bounce or defer logfile (skipping over recipients that /* are marked as done). The result is 0 in case of success, -1 in case @@ -92,6 +97,7 @@ #include <sys_defs.h> #include <string.h> #include <ctype.h> +#include <unistd.h> /* Utility library. */ @@ -133,6 +139,7 @@ BOUNCE_LOG *bounce_log_open(const char *queue_name, const char *queue_id, bp->fp = fp; bp->buf = vstring_alloc(100); bp->status = STREQ(queue_name, MAIL_QUEUE_DEFER) ? "4.0.0" : "5.0.0"; + bp->offset = 0; return (bp); } } @@ -145,7 +152,8 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) char *text; char *cp; - while (vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF) { + while ((bp->offset = vstream_ftell(bp->fp)), + (vstring_get_nonl(bp->buf, bp->fp) != VSTREAM_EOF)) { if (STR(bp->buf)[0] == 0) continue; @@ -156,6 +164,12 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) cp = printable(STR(bp->buf), '?'); /* + * Skip over deleted recipients. + */ + if (*cp == BOUNCE_LOG_STAT_DELETED) + continue; + + /* * Find the recipient address. */ if (*cp != '<') { @@ -185,6 +199,21 @@ BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *bp) return (0); } +/* bounce_log_delrcpt - mark recipient record as deleted */ + +BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *bp) +{ + long current_offset; + + current_offset = vstream_ftell(bp->fp); + if (vstream_fseek(bp->fp, bp->offset, SEEK_SET) < 0) + msg_fatal("bounce logfile %s seek error: %m", VSTREAM_PATH(bp->fp)); + VSTREAM_PUTC(BOUNCE_LOG_STAT_DELETED, bp->fp); + if (vstream_fseek(bp->fp, current_offset, SEEK_SET) < 0) + msg_fatal("bounce logfile %s seek error: %m", VSTREAM_PATH(bp->fp)); + return (bp); +} + /* bounce_log_close - close bounce reader stream */ int bounce_log_close(BOUNCE_LOG *bp) diff --git a/gnu/dist/postfix/src/global/bounce_log.h b/gnu/dist/postfix/src/global/bounce_log.h index 7b949e95175..0f91c6f8d68 100644 --- a/gnu/dist/postfix/src/global/bounce_log.h +++ b/gnu/dist/postfix/src/global/bounce_log.h @@ -28,14 +28,18 @@ typedef struct { const char *recipient; /* final recipient */ const char *status; /* recipient status */ const char *text; /* why undeliverable */ + long offset; /* start of current record */ } BOUNCE_LOG; extern BOUNCE_LOG *bounce_log_open(const char *, const char *, int, int); extern BOUNCE_LOG *bounce_log_read(BOUNCE_LOG *); +extern BOUNCE_LOG *bounce_log_delrcpt(BOUNCE_LOG *); extern int bounce_log_close(BOUNCE_LOG *); #define bounce_log_rewind(bp) vstream_fseek((bp)->fp, 0L, SEEK_SET) +#define BOUNCE_LOG_STAT_DELETED 'D' /* deleted record */ + /* LICENSE /* .ad /* .fi diff --git a/gnu/dist/postfix/src/global/cleanup_user.h b/gnu/dist/postfix/src/global/cleanup_user.h index 8dff9102277..c60565d6229 100644 --- a/gnu/dist/postfix/src/global/cleanup_user.h +++ b/gnu/dist/postfix/src/global/cleanup_user.h @@ -34,7 +34,23 @@ #define CLEANUP_STAT_HOVFL (1<<7) /* Header overflow */ #define CLEANUP_STAT_ROVFL (1<<8) /* Recipient overflow */ -#define CLEANUP_STAT_LETHAL ~(CLEANUP_STAT_HOVFL|CLEANUP_STAT_ROVFL) + /* + * These are set when we can't bounce even if we were asked to. + */ +#define CLEANUP_STAT_MASK_CANT_BOUNCE \ + (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE) + + /* + * These are set when we can't examine every record of a message. + */ +#define CLEANUP_STAT_MASK_INCOMPLETE \ + (CLEANUP_STAT_BAD | CLEANUP_STAT_WRITE | CLEANUP_STAT_SIZE) + + /* + * These are relevant for extracting recipients from headers. + */ +#define CLEANUP_STAT_MASK_EXTRACT_RCPT \ + (CLEANUP_STAT_HOVFL | CLEANUP_STAT_ROVFL | CLEANUP_STAT_RCPT) extern const char *cleanup_strerror(unsigned); diff --git a/gnu/dist/postfix/src/global/debug_peer.c b/gnu/dist/postfix/src/global/debug_peer.c index 29170bad58f..c7096c97321 100644 --- a/gnu/dist/postfix/src/global/debug_peer.c +++ b/gnu/dist/postfix/src/global/debug_peer.c @@ -69,6 +69,7 @@ #include <mail_params.h> #include <namadr_list.h> #include <debug_peer.h> +#include <match_parent_style.h> /* Application-specific. */ @@ -97,7 +98,9 @@ void debug_peer_init(void) * 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 */ diff --git a/gnu/dist/postfix/src/global/defer.c b/gnu/dist/postfix/src/global/defer.c index 59cde38fa41..40130cfe37d 100644 --- a/gnu/dist/postfix/src/global/defer.c +++ b/gnu/dist/postfix/src/global/defer.c @@ -145,9 +145,13 @@ int vdefer_append(int flags, const char *id, const char *recipient, const char *rcpt_domain; vstring_vsprintf(why, fmt, ap); - if (mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER, - "%d %d %s %s %s", BOUNCE_CMD_APPEND, - flags, id, recipient, vstring_str(why)) != 0) + if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_APPEND, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient, + ATTR_TYPE_STR, MAIL_ATTR_WHY, vstring_str(why), + ATTR_TYPE_END) != 0) msg_warn("%s: defer service failure", id); msg_info("%s: to=<%s>, relay=%s, delay=%d, status=deferred (%s)", id, recipient, relay, delay, vstring_str(why)); @@ -158,8 +162,14 @@ int vdefer_append(int flags, const char *id, const char *recipient, * bounce/defer daemon? Well, doing it here is more robust. */ if ((rcpt_domain = strrchr(recipient, '@')) != 0 && *++rcpt_domain != 0) - if (flush_add(rcpt_domain, id) != FLUSH_STAT_OK) + switch (flush_add(rcpt_domain, id)) { + case FLUSH_STAT_OK: + case FLUSH_STAT_DENY: + break; + default: msg_warn("unable to talk to fast flush service"); + break; + } return (-1); } @@ -169,9 +179,13 @@ int vdefer_append(int flags, const char *id, const char *recipient, int defer_flush(int flags, const char *queue, const char *id, const char *sender) { - if (mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER, - "%d %d %s %s %s", BOUNCE_CMD_FLUSH, - flags, queue, id, sender) == 0) { + if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_FLUSH, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_END) == 0) { return (0); } else { return (-1); @@ -184,9 +198,13 @@ int defer_flush(int flags, const char *queue, const char *id, int defer_warn(int flags, const char *queue, const char *id, const char *sender) { - if (mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER, - "%d %d %s %s %s", BOUNCE_CMD_WARN, - flags, queue, id, sender) == 0) { + if (mail_command_client(MAIL_CLASS_PRIVATE, MAIL_SERVICE_DEFER, + ATTR_TYPE_NUM, MAIL_ATTR_NREQ, BOUNCE_CMD_WARN, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender, + ATTR_TYPE_END) == 0) { return (0); } else { return (-1); diff --git a/gnu/dist/postfix/src/global/deliver_pass.c b/gnu/dist/postfix/src/global/deliver_pass.c index 2deec8c3c2a..f428d551ebf 100644 --- a/gnu/dist/postfix/src/global/deliver_pass.c +++ b/gnu/dist/postfix/src/global/deliver_pass.c @@ -77,7 +77,9 @@ static int deliver_pass_initial_reply(VSTREAM *stream) { int stat; - if (mail_scan(stream, "%d", &stat) != 1) { + if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat, + ATTR_TYPE_END) != 1) { msg_warn("%s: malformed response", VSTREAM_PATH(stream)); stat = -1; } @@ -91,14 +93,21 @@ static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request, { int stat; - mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld %ld %s %s", - request->flags, - request->queue_name, request->queue_id, - request->data_offset, request->data_size, - nexthop, request->sender, - request->errors_to, request->return_receipt, - request->arrival_time, - offs, addr, "0"); + attr_print(stream, ATTR_FLAG_NONE, + 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_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_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); if (vstream_fflush(stream)) { msg_warn("%s: bad write: %m", VSTREAM_PATH(stream)); @@ -115,7 +124,10 @@ static int deliver_pass_final_reply(VSTREAM *stream, VSTRING *reason) { int stat; - if (mail_scan(stream, "%s %d", reason, &stat) != 2) { + if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_WHY, reason, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat, + ATTR_TYPE_END) != 2) { msg_warn("%s: malformed response", VSTREAM_PATH(stream)); stat = -1; } diff --git a/gnu/dist/postfix/src/global/deliver_request.c b/gnu/dist/postfix/src/global/deliver_request.c index 63c20c4fee4..35c83e78061 100644 --- a/gnu/dist/postfix/src/global/deliver_request.c +++ b/gnu/dist/postfix/src/global/deliver_request.c @@ -67,7 +67,7 @@ /* Warnings: bad data sent by the client. Fatal errors: out of /* memory, queue file open errors. /* SEE ALSO -/* mail_scan(3) low-level intra-mail input routines +/* attr_scan(3) low-level intra-mail input routines /* LICENSE /* .ad /* .fi @@ -85,6 +85,7 @@ #include <sys/stat.h> #include <string.h> #include <unistd.h> +#include <errno.h> /* Utility library. */ @@ -117,7 +118,9 @@ static int deliver_request_initial(VSTREAM *stream) */ if (msg_verbose) msg_info("deliver_request_initial: send initial status"); - mail_print(stream, "%d", 0); + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, 0, + ATTR_TYPE_END); if ((err = vstream_fflush(stream)) != 0) if (msg_verbose) msg_warn("send initial status: %m"); @@ -137,7 +140,10 @@ static int deliver_request_final(VSTREAM *stream, char *reason, int status) reason = ""; if (msg_verbose) msg_info("deliver_request_final: send: \"%s\" %d", reason, status); - mail_print(stream, "%s %d", reason, status); + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_WHY, reason, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status, + ATTR_TYPE_END); if ((err = vstream_fflush(stream)) != 0) if (msg_verbose) msg_warn("send final status: %m"); @@ -186,11 +192,18 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) * Extract the queue file name, data offset, and sender address. Abort * the conversation when they send bad information. */ - if (mail_scan(stream, "%d %s %s %ld %ld %s %s %s %s %ld", - &request->flags, - queue_name, queue_id, &request->data_offset, - &request->data_size, nexthop, address, - errors_to, return_receipt, &request->arrival_time) != 10) + if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE, + 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_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_LONG, MAIL_ATTR_TIME, &request->arrival_time, + ATTR_TYPE_END) != 10) return (-1); if (mail_open_ok(vstring_str(queue_name), vstring_str(queue_id), &st, &path) == 0) @@ -204,14 +217,19 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) request->return_receipt = mystrdup(vstring_str(return_receipt)); /* - * Extract the recipient offset and address list. + * Extract the recipient offset and address list. Skip over any + * attributes from the sender that we do not understand. */ for (;;) { - if (mail_scan(stream, "%ld", &offset) != 1) + if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT, + ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &offset, + ATTR_TYPE_END) != 1) return (-1); if (offset == 0) break; - if (mail_scan(stream, "%s", address) != 1) + if (attr_scan(stream, ATTR_FLAG_MORE | ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_RECIP, address, + ATTR_TYPE_END) != 1) return (-1); recipient_list_add(&request->rcpt_list, offset, vstring_str(address)); } @@ -230,8 +248,12 @@ static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) request->fp = mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0); - if (request->fp == 0) - msg_fatal("open %s %s: %m", request->queue_name, request->queue_id); + if (request->fp == 0) { + if (errno != ENOENT) + msg_fatal("open %s %s: %m", request->queue_name, request->queue_id); + msg_warn("open %s %s: %m", request->queue_name, request->queue_id); + return (-1); + } if (msg_verbose) msg_info("%s: file %s", myname, VSTREAM_PATH(request->fp)); if (myflock(vstream_fileno(request->fp), INTERNAL_LOCK, DELIVER_LOCK_MODE) < 0) @@ -309,9 +331,11 @@ DELIVER_REQUEST *deliver_request_read(VSTREAM *stream) /* * Allocate and read the queue manager's delivery request. */ +#define XXX_DEFER_STATUS -1 + request = deliver_request_alloc(); if (deliver_request_get(stream, request) < 0) { - deliver_request_free(request); + deliver_request_done(stream, request, XXX_DEFER_STATUS); request = 0; } return (request); diff --git a/gnu/dist/postfix/src/global/deliver_request.h b/gnu/dist/postfix/src/global/deliver_request.h index 2406085ff1e..45c2055234c 100644 --- a/gnu/dist/postfix/src/global/deliver_request.h +++ b/gnu/dist/postfix/src/global/deliver_request.h @@ -45,6 +45,17 @@ typedef struct DELIVER_REQUEST { #define DEL_REQ_FLAG_SUCCESS (1<<0) /* delete successful recipients */ #define DEL_REQ_FLAG_BOUNCE (1<<1) /* unimplemented */ + /* + * Delivery status. Note that there are only FINAL and DEFER. This is + * because delivery status information can be lost when a delivery agent or + * queue manager process terminates prematurely. The only distinctions we + * can rely on are "final delivery completed" and "everything else". In the + * absence of a definitive statement the queue manager will always have to + * be prepared for all possibilities. + */ +#define DEL_STAT_FINAL 0 /* delivered or bounced */ +#define DEL_STAT_DEFER (-1) /* not delivered or bounced */ + typedef struct VSTREAM _deliver_vstream_; extern DELIVER_REQUEST *deliver_request_read(_deliver_vstream_ *); extern int deliver_request_done(_deliver_vstream_ *, DELIVER_REQUEST *, int); diff --git a/gnu/dist/postfix/src/global/domain_list.c b/gnu/dist/postfix/src/global/domain_list.c index 1322642d0f9..d4ea536b29f 100644 --- a/gnu/dist/postfix/src/global/domain_list.c +++ b/gnu/dist/postfix/src/global/domain_list.c @@ -6,7 +6,8 @@ /* 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) @@ -16,6 +17,8 @@ /* 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. /* @@ -30,9 +33,17 @@ /* 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. @@ -62,33 +73,11 @@ /* 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> @@ -120,7 +109,7 @@ main(int argc, char **argv) } 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"); diff --git a/gnu/dist/postfix/src/global/domain_list.h b/gnu/dist/postfix/src/global/domain_list.h index b36f516b444..23f60c78950 100644 --- a/gnu/dist/postfix/src/global/domain_list.h +++ b/gnu/dist/postfix/src/global/domain_list.h @@ -12,13 +12,19 @@ /* .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 diff --git a/gnu/dist/postfix/src/global/file_id.c b/gnu/dist/postfix/src/global/file_id.c index ad4ce57987f..e130087db24 100644 --- a/gnu/dist/postfix/src/global/file_id.c +++ b/gnu/dist/postfix/src/global/file_id.c @@ -65,7 +65,7 @@ const char *get_file_id(int fd) result = vstring_alloc(1); if (fstat(fd, &st) < 0) msg_fatal("fstat: %m"); - vstring_sprintf(result, "%X", (int) st.st_ino); + vstring_sprintf(result, "%lX", (long) st.st_ino); return (vstring_str(result)); } diff --git a/gnu/dist/postfix/src/global/flush_clnt.c b/gnu/dist/postfix/src/global/flush_clnt.c index 6de4b426de8..8f35b6c5bbf 100644 --- a/gnu/dist/postfix/src/global/flush_clnt.c +++ b/gnu/dist/postfix/src/global/flush_clnt.c @@ -46,6 +46,9 @@ /* .IP MAIL_FLUSH_BAD /* The "fast flush" server rejected the request (invalid request /* parameter). +/* .IP MAIL_FLUSH_DENY +/* The specified domain is not eligible for "fast flush" service, +/* or the "fast flush" service is disabled. /* SEE ALSO /* flush(8) Postfix fast flush cache manager /* LICENSE @@ -95,10 +98,11 @@ int flush_purge(void) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = FLUSH_STAT_OK; + status = FLUSH_STAT_DENY; else - status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, - "%s", FLUSH_REQ_PURGE); + status = mail_command_client(MAIL_CLASS_PUBLIC, MAIL_SERVICE_FLUSH, + ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_PURGE, + ATTR_TYPE_END); if (msg_verbose) msg_info("%s: status %d", myname, status); @@ -120,10 +124,11 @@ int flush_refresh(void) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = FLUSH_STAT_OK; + status = FLUSH_STAT_DENY; else - status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, - "%s", FLUSH_REQ_REFRESH); + status = mail_command_client(MAIL_CLASS_PUBLIC, MAIL_SERVICE_FLUSH, + ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_REFRESH, + ATTR_TYPE_END); if (msg_verbose) msg_info("%s: status %d", myname, status); @@ -145,10 +150,12 @@ int flush_send(const char *site) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = mail_flush_deferred(); + status = FLUSH_STAT_DENY; else - status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, - "%s %s", FLUSH_REQ_SEND, site); + status = mail_command_client(MAIL_CLASS_PUBLIC, MAIL_SERVICE_FLUSH, + ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_SEND, + ATTR_TYPE_STR, MAIL_ATTR_SITE, site, + ATTR_TYPE_END); if (msg_verbose) msg_info("%s: site %s status %d", myname, site, status); @@ -170,10 +177,13 @@ int flush_add(const char *site, const char *queue_id) * Don't bother the server if the service is turned off. */ if (*var_fflush_domains == 0) - status = FLUSH_STAT_OK; + status = FLUSH_STAT_DENY; else - status = mail_command_write(MAIL_CLASS_PRIVATE, MAIL_SERVICE_FLUSH, - "%s %s %s", FLUSH_REQ_ADD, site, queue_id); + status = mail_command_client(MAIL_CLASS_PUBLIC, MAIL_SERVICE_FLUSH, + ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_ADD, + ATTR_TYPE_STR, MAIL_ATTR_SITE, site, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_END); if (msg_verbose) msg_info("%s: site %s id %s status %d", myname, site, queue_id, diff --git a/gnu/dist/postfix/src/global/flush_clnt.h b/gnu/dist/postfix/src/global/flush_clnt.h index 47a88558a53..ee82a984cb4 100644 --- a/gnu/dist/postfix/src/global/flush_clnt.h +++ b/gnu/dist/postfix/src/global/flush_clnt.h @@ -33,6 +33,7 @@ extern int flush_purge(void); #define FLUSH_STAT_FAIL -1 /* request failed */ #define FLUSH_STAT_OK 0 /* request executed */ #define FLUSH_STAT_BAD 3 /* invalid parameter */ +#define FLUSH_STAT_DENY 4 /* request denied */ /* LICENSE diff --git a/gnu/dist/postfix/src/global/is_header.c b/gnu/dist/postfix/src/global/is_header.c index 0cd3e93c2d5..5ed88fadd6e 100644 --- a/gnu/dist/postfix/src/global/is_header.c +++ b/gnu/dist/postfix/src/global/is_header.c @@ -41,6 +41,13 @@ int is_header(const char *str) const char *cp; int c; + /* + * XXX RFC 2822 Section 4.5.2, Obsolete header fields: whitespace may + * appear between header label and ":" (see: RFC 822, Section 3.4.2.). + * + * The code below allows no such whitespace. This has never been a problem, + * and therefore we're not inclined to add code for it. + */ for (cp = str; (c = *(unsigned char *) cp) != 0; cp++) { if (c == ':') return (cp > str); diff --git a/gnu/dist/postfix/src/global/mail_command_client.c b/gnu/dist/postfix/src/global/mail_command_client.c new file mode 100644 index 00000000000..fc1c56c9efe --- /dev/null +++ b/gnu/dist/postfix/src/global/mail_command_client.c @@ -0,0 +1,82 @@ +/*++ +/* NAME +/* mail_command_client 3 +/* SUMMARY +/* single-command client +/* SYNOPSIS +/* #include <mail_proto.h> +/* +/* int mail_command_client(class, name, type, attr, ...) +/* const char *class; +/* const char *name; +/* int type; +/* const char *attr; +/* DESCRIPTION +/* This module implements a client interface for single-command +/* clients: a client that sends a single command and expects +/* a single completion status code. +/* +/* Arguments: +/* .IP class +/* Service type: MAIL_CLASS_PUBLIC or MAIL_CLASS_PRIVATE +/* .IP name +/* Service name (master.cf). +/* .IP "type, attr, ..." +/* Attribute information as defined in attr_print(3). +/* DIAGNOSTICS +/* The result is -1 if the request could not be sent, otherwise +/* the result is the status reported by the server. +/* Warnings: problems connecting to the requested service. +/* Fatal: out of memory. +/* SEE ALSO +/* attr_print(3), send attributes over byte stream +/* mail_command_server(3), server interface +/* mail_proto(3h), client-server protocol +/* 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 <stdlib.h> /* 44BSD stdarg.h uses abort() */ +#include <stdarg.h> + +/* Utility library. */ + +#include <vstream.h> + +/* Global library. */ + +#include <mail_proto.h> + +/* mail_command_client - single-command transaction with completion status */ + +int mail_command_client(const char *class, const char *name,...) +{ + va_list ap; + VSTREAM *stream; + int status; + + /* + * Talk a little protocol with the specified service. + */ + if ((stream = mail_connect(class, name, BLOCKING)) == 0) + return (-1); + va_start(ap, name); + status = attr_vprint(stream, ATTR_FLAG_NONE, ap); + va_end(ap); + if (status != 0 + || attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, 0) != 1) + status = -1; + (void) vstream_fclose(stream); + return (status); +} diff --git a/gnu/dist/postfix/src/global/mail_command_server.c b/gnu/dist/postfix/src/global/mail_command_server.c new file mode 100644 index 00000000000..9565b55fb4c --- /dev/null +++ b/gnu/dist/postfix/src/global/mail_command_server.c @@ -0,0 +1,67 @@ +/*++ +/* NAME +/* mail_command_server 3 +/* SUMMARY +/* single-command server +/* SYNOPSIS +/* #include <mail_proto.h> +/* +/* int mail_command_server(stream, type, name, ...) +/* VSTREAM *stream; +/* int type; +/* const char *name; +/* DESCRIPTION +/* This module implements the server interface for single-command +/* requests: a clients sends a single command and expects a single +/* completion status code. +/* +/* Arguments: +/* .IP stream +/* Server endpoint. +/* .IP "type, name, ..." +/* Attribute list as defined in attr_scan(3). +/* DIAGNOSTICS +/* Fatal: out of memory. +/* SEE ALSO +/* attr_scan(3) +/* mail_command_client(3) client interface +/* mail_proto(3h), client-server protocol +#include <mail_proto.h> +/* 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 <stdlib.h> /* 44BSD stdarg.h uses abort() */ +#include <stdarg.h> +#include <string.h> + +/* Utility library. */ + +#include <vstream.h> + +/* Global library. */ + +#include "mail_proto.h" + +/* mail_command_server - read single-command request */ + +int mail_command_server(VSTREAM *stream,...) +{ + va_list ap; + int count; + + va_start(ap, stream); + count = attr_vscan(stream, ATTR_FLAG_MISSING, ap); + va_end(ap); + return (count); +} diff --git a/gnu/dist/postfix/src/global/mail_conf.c b/gnu/dist/postfix/src/global/mail_conf.c index 2af13f29c55..df25bed6974 100644 --- a/gnu/dist/postfix/src/global/mail_conf.c +++ b/gnu/dist/postfix/src/global/mail_conf.c @@ -73,7 +73,9 @@ /* System library. */ #include <sys_defs.h> +#include <unistd.h> #include <stdlib.h> +#include <string.h> /* Utility library. */ @@ -84,12 +86,55 @@ #include <dict.h> #include <safe.h> #include <stringops.h> +#include <readlline.h> /* Global library. */ #include "mail_params.h" #include "mail_conf.h" +/* mail_conf_checkdir - authorize non-default directory */ + +static void mail_conf_checkdir(const char *config_dir) +{ + VSTRING *buf; + VSTREAM *fp; + char *path; + char *name; + char *value; + char *cp; + int found = 0; + + /* + * If running set-[ug]id, require that a non-default configuration + * directory name is blessed as a bona fide configuration directory in + * the default main.cf file. + */ + path = concatenate(DEF_CONFIG_DIR, "/", "main.cf", (char *) 0); + if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) + msg_fatal("open file %s: %m", path); + + buf = vstring_alloc(1); + while (found == 0 && readlline(buf, fp, (int *) 0)) { + if (split_nameval(vstring_str(buf), &name, &value) == 0 + && strcmp(name, VAR_CONFIG_DIRS) == 0) { + while (found == 0 && (cp = mystrtok(&value, ", \t\r\n")) != 0) + if (strcmp(cp, config_dir) == 0) + found = 1; + } + } + if (vstream_fclose(fp)) + msg_fatal("read file %s: %m", path); + vstring_free(buf); + + if (found == 0) { + msg_error("untrusted configuration directory name: %s", config_dir); + msg_fatal("specify \"%s = %s\" in %s", + VAR_CONFIG_DIRS, config_dir, path); + } + myfree(path); +} + /* mail_conf_read - read global configuration file */ void mail_conf_read(void) @@ -114,9 +159,19 @@ void mail_conf_suck(void) dict_unknown_allowed = 1; if (var_config_dir) myfree(var_config_dir); - var_config_dir = mystrdup((config_dir = safe_getenv(CONF_ENV_PATH)) != 0 ? - config_dir : DEF_CONFIG_DIR); /* XXX */ + if ((config_dir = getenv(CONF_ENV_PATH)) == 0) + config_dir = DEF_CONFIG_DIR; + var_config_dir = mystrdup(config_dir); set_mail_conf_str(VAR_CONFIG_DIR, var_config_dir); + + /* + * If the configuration directory name comes from a different trust + * domain, require that it is listed in the default main.cf file. + */ + if (strcmp(var_config_dir, DEF_CONFIG_DIR) != 0 /* non-default */ + && safe_getenv(CONF_ENV_PATH) == 0 /* non-default */ + && geteuid() != 0) /* untrusted */ + mail_conf_checkdir(var_config_dir); path = concatenate(var_config_dir, "/", "main.cf", (char *) 0); dict_load_file(CONFIG_DICT, path); myfree(path); diff --git a/gnu/dist/postfix/src/global/mail_conf.h b/gnu/dist/postfix/src/global/mail_conf.h index ffa1341d7ca..25406e8da14 100644 --- a/gnu/dist/postfix/src/global/mail_conf.h +++ b/gnu/dist/postfix/src/global/mail_conf.h @@ -21,7 +21,8 @@ */ #define CONF_ENV_PATH "MAIL_CONFIG" /* config database */ #define CONF_ENV_VERB "MAIL_VERBOSE" /* verbose mode on */ -#define CONF_ENV_DEBUG "MAIL_DEBUG" /* verbose mode on */ +#define CONF_ENV_DEBUG "MAIL_DEBUG" /* live debugging */ +#define CONF_ENV_LOGTAG "MAIL_LOGTAG" /* instance name */ /* * External representation for booleans. diff --git a/gnu/dist/postfix/src/global/mail_connect.c b/gnu/dist/postfix/src/global/mail_connect.c index cd486f9bc40..a8ef96d1364 100644 --- a/gnu/dist/postfix/src/global/mail_connect.c +++ b/gnu/dist/postfix/src/global/mail_connect.c @@ -66,6 +66,7 @@ #include <connect.h> #include <mymalloc.h> #include <iostuff.h> +#include <stringops.h> /* Global library. */ @@ -79,6 +80,7 @@ VSTREAM *mail_connect(const char *class, const char *name, int block_mode) char *path; VSTREAM *stream; int fd; + char *sock_name; path = mail_pathname(class, name); if ((fd = LOCAL_CONNECT(path, block_mode, 0)) < 0) { @@ -90,9 +92,11 @@ VSTREAM *mail_connect(const char *class, const char *name, int block_mode) msg_info("connect to subsystem %s", path); stream = vstream_fdopen(fd, O_RDWR); timed_ipc_setup(stream); + sock_name = concatenate(path, " socket", (char *) 0); vstream_control(stream, - VSTREAM_CTL_PATH, path, + VSTREAM_CTL_PATH, sock_name, VSTREAM_CTL_END); + myfree(sock_name); } myfree(path); return (stream); diff --git a/gnu/dist/postfix/src/global/mail_copy.c b/gnu/dist/postfix/src/global/mail_copy.c index e08d301f56e..c2d328981ca 100644 --- a/gnu/dist/postfix/src/global/mail_copy.c +++ b/gnu/dist/postfix/src/global/mail_copy.c @@ -62,6 +62,14 @@ /* DIAGNOSTICS /* A non-zero result means the operation failed. Warnings: corrupt /* message file. A corrupt message is marked as corrupt. +/* +/* The result is the bit-wise OR of zero or more of the following: +/* .IP MAIL_COPY_STAT_CORRUPT +/* The queue file is marked as corrupt. +/* .IP MAIL_COPY_STAT_READ +/* A read error was detected; errno specifies the nature of the problem. +/* .IP MAIL_COPY_STAT_WRITE +/* A write error was detected; errno specifies the nature of the problem. /* SEE ALSO /* mark_corrupt(3), mark queue file as corrupted. /* LICENSE @@ -81,6 +89,7 @@ #include <string.h> #include <unistd.h> #include <time.h> +#include <errno.h> /* Utility library. */ @@ -98,8 +107,9 @@ #include "rec_type.h" #include "mail_queue.h" #include "mail_addr.h" -#include "mail_copy.h" #include "mark_corrupt.h" +#include "mail_params.h" +#include "mail_copy.h" /* mail_copy - copy message with extreme prejudice */ @@ -183,6 +193,8 @@ int mail_copy(const char *sender, const char *delivered, prev_type = type; } if (vstream_ferror(dst) == 0) { + if (var_fault_inj_code == 1) + type = 0; if (type != REC_TYPE_XTRA) corrupt_error = mark_corrupt(src); if (prev_type != REC_TYPE_NORM) @@ -208,9 +220,17 @@ int mail_copy(const char *sender, const char *delivered, if ((flags & MAIL_COPY_TOFILE) != 0) write_error |= fsync(vstream_fileno(dst)); #endif + if (var_fault_inj_code == 2) { + read_error = 1; + errno = ENOENT; + } + if (var_fault_inj_code == 3) { + write_error = 1; + errno = ENOENT; + } #ifndef NO_TRUNCATE if ((flags & MAIL_COPY_TOFILE) != 0) - if (read_error || write_error) + if (corrupt_error || read_error || write_error) ftruncate(vstream_fileno(dst), (off_t) orig_length); #endif write_error |= vstream_fclose(dst); @@ -218,5 +238,7 @@ int mail_copy(const char *sender, const char *delivered, vstring_sprintf(why, "error reading message: %m"); if (why && write_error) vstring_sprintf(why, "error writing message: %m"); - return (corrupt_error || read_error || write_error); + return ((corrupt_error ? MAIL_COPY_STAT_CORRUPT : 0) + | (read_error ? MAIL_COPY_STAT_READ : 0) + | (write_error ? MAIL_COPY_STAT_WRITE : 0)); } diff --git a/gnu/dist/postfix/src/global/mail_copy.h b/gnu/dist/postfix/src/global/mail_copy.h index 2d8c6ae39f1..efa1957c5c0 100644 --- a/gnu/dist/postfix/src/global/mail_copy.h +++ b/gnu/dist/postfix/src/global/mail_copy.h @@ -35,6 +35,11 @@ extern int mail_copy(const char *, const char *, VSTREAM *, VSTREAM *, MAIL_COPY_RETURN_PATH | MAIL_COPY_BLANK) #define MAIL_COPY_NONE 0 /* all turned off */ +#define MAIL_COPY_STAT_OK 0 +#define MAIL_COPY_STAT_CORRUPT (1<<0) +#define MAIL_COPY_STAT_READ (1<<1) +#define MAIL_COPY_STAT_WRITE (1<<2) + /* LICENSE /* .ad /* .fi diff --git a/gnu/dist/postfix/src/global/mail_params.c b/gnu/dist/postfix/src/global/mail_params.c index ed04630aad6..bf134b11a0e 100644 --- a/gnu/dist/postfix/src/global/mail_params.c +++ b/gnu/dist/postfix/src/global/mail_params.c @@ -14,9 +14,12 @@ /* char *var_transit_origin; /* char *var_transit_dest; /* char *var_mail_name; +/* char *var_syslog_name; /* char *var_mail_owner; /* uid_t var_owner_uid; /* gid_t var_owner_gid; +/* char *var_sgid_group; +/* gid_t var_sgid_gid; /* char *var_default_privs; /* uid_t var_default_uid; /* gid_t var_default_gid; @@ -39,6 +42,7 @@ /* int var_line_limit; /* char *var_alias_db_map; /* int var_message_limit; +/* char *var_mail_release; /* char *var_mail_version; /* int var_ipc_idle_limit; /* char *var_db_type; @@ -61,9 +65,17 @@ /* char *var_fflush_domains; /* char *var_def_transport; /* char *var_mynetworks_style; +/* char *var_verp_delims; +/* char *var_verp_filter; +/* char *var_par_dom_match; +/* char *var_config_dirs; /* /* char *var_import_environ; /* char *var_export_environ; +/* char *var_debug_peer_list; +/* int var_debug_peer_level; +/* int var_in_flow_delay; +/* int var_fault_inj_code; /* /* void mail_params_init() /* DESCRIPTION @@ -92,8 +104,10 @@ #include <sys_defs.h> #include <unistd.h> +#include <stdlib.h> #include <string.h> #include <pwd.h> +#include <grp.h> #include <time.h> #ifdef STRCASECMP_IN_STRINGS_H @@ -107,6 +121,7 @@ #include <get_hostname.h> #include <valid_hostname.h> #include <stringops.h> +#include <safe.h> /* Global library. */ @@ -114,6 +129,7 @@ #include "mail_conf.h" #include "mail_version.h" #include "mail_proto.h" +#include "verp_sender.h" #include "mail_params.h" /* @@ -127,9 +143,12 @@ char *var_relayhost; char *var_transit_origin; char *var_transit_dest; char *var_mail_name; +char *var_syslog_name; char *var_mail_owner; uid_t var_owner_uid; gid_t var_owner_gid; +char *var_sgid_group; +gid_t var_sgid_gid; char *var_default_privs; uid_t var_default_uid; gid_t var_default_gid; @@ -152,6 +171,7 @@ char *var_double_bounce_sender; int var_line_limit; char *var_alias_db_map; int var_message_limit; +char *var_mail_release; char *var_mail_version; int var_ipc_idle_limit; char *var_db_type; @@ -174,9 +194,19 @@ char *var_relay_domains; char *var_fflush_domains; char *var_def_transport; char *var_mynetworks_style; +char *var_verp_delims; +char *var_verp_filter; +int var_in_flow_delay; +char *var_par_dom_match; +char *var_config_dirs; char *var_import_environ; char *var_export_environ; +char *var_debug_peer_list; +int var_debug_peer_level; +int var_fault_inj_code; + +#define MAIN_CONF_FILE "main.cf" /* check_myhostname - lookup hostname and validate */ @@ -199,9 +229,11 @@ static const char *check_myhostname(void) name = get_hostname(); if ((dot = strchr(name, '.')) == 0) { if ((domain = mail_conf_lookup_eval(VAR_MYDOMAIN)) == 0) - msg_fatal("My hostname %s is not a fully qualified name - set %s or %s in %s/main.cf", - name, VAR_MYHOSTNAME, VAR_MYDOMAIN, var_config_dir); - name = concatenate(name, ".", domain, (char *) 0); + msg_warn("My hostname %s is not a fully qualified name - set %s or %s in %s/%s", + name, VAR_MYHOSTNAME, VAR_MYDOMAIN, + var_config_dir, MAIN_CONF_FILE); + else + name = concatenate(name, ".", domain, (char *) 0); } return (name); } @@ -228,13 +260,16 @@ static void check_default_privs(void) struct passwd *pwd; if ((pwd = getpwnam(var_default_privs)) == 0) - msg_fatal("unknown %s configuration parameter value: %s", + msg_fatal("file %s/%s: parameter %s: unknown user name value: %s", + var_config_dir, MAIN_CONF_FILE, VAR_DEFAULT_PRIVS, var_default_privs); if ((var_default_uid = pwd->pw_uid) == 0) - msg_fatal("%s: %s: privileged user is not allowed", + msg_fatal("file %s/%s: parameter %s: user %s has privileged user ID", + var_config_dir, MAIN_CONF_FILE, VAR_DEFAULT_PRIVS, var_default_privs); if ((var_default_gid = pwd->pw_gid) == 0) - msg_fatal("%s: %s: privileged group is not allowed", + msg_fatal("file %s/%s: parameter %s: user %s has privileged group ID", + var_config_dir, MAIN_CONF_FILE, VAR_DEFAULT_PRIVS, var_default_privs); } @@ -245,14 +280,91 @@ static void check_mail_owner(void) struct passwd *pwd; if ((pwd = getpwnam(var_mail_owner)) == 0) - msg_fatal("unknown %s configuration parameter value: %s", + msg_fatal("file %s/%s: parameter %s: unknown user name value: %s", + var_config_dir, MAIN_CONF_FILE, VAR_MAIL_OWNER, var_mail_owner); if ((var_owner_uid = pwd->pw_uid) == 0) - msg_fatal("%s: %s: privileged user is not allowed", + msg_fatal("file %s/%s: parameter %s: user %s has privileged user ID", + var_config_dir, MAIN_CONF_FILE, VAR_MAIL_OWNER, var_mail_owner); if ((var_owner_gid = pwd->pw_gid) == 0) - msg_fatal("%s: %s: privileged group is not allowed", - VAR_DEFAULT_PRIVS, var_mail_owner); + msg_fatal("file %s/%s: parameter %s: user %s has privileged group ID", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, var_mail_owner); + + /* + * This detects only some forms of sharing. Enumerating the entire + * password file name space could be expensive. The purpose of this code + * is to discourage user ID sharing by developers and package + * maintainers. + */ + if ((pwd = getpwuid(var_owner_uid)) != 0 + && strcmp(pwd->pw_name, var_mail_owner) != 0) + msg_fatal("file %s/%s: parameter %s: user %s has same user ID as %s", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, var_mail_owner, pwd->pw_name); +} + +/* check_sgid_group - lookup setgid group attributes and validate */ + +static void check_sgid_group(void) +{ + struct group *grp; + + if ((grp = getgrnam(var_sgid_group)) == 0) + msg_fatal("file %s/%s: parameter %s: unknown group name: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_SGID_GROUP, var_sgid_group); + if ((var_sgid_gid = grp->gr_gid) == 0) + msg_fatal("file %s/%s: parameter %s: group %s has privileged group ID", + var_config_dir, MAIN_CONF_FILE, + VAR_SGID_GROUP, var_sgid_group); + + /* + * This detects only some forms of sharing. Enumerating the entire group + * file name space could be expensive. The purpose of this code is to + * discourage group ID sharing by developers and package maintainers. + */ + if ((grp = getgrgid(var_sgid_gid)) != 0 + && strcmp(grp->gr_name, var_sgid_group) != 0) + msg_fatal("file %s/%s: parameter %s: group %s has same group ID as %s", + var_config_dir, MAIN_CONF_FILE, + VAR_SGID_GROUP, var_sgid_group, grp->gr_name); +} + +/* check_overlap - disallow UID or GID sharing */ + +static void check_overlap(void) +{ + if (strcmp(var_default_privs, var_mail_owner) == 0) + msg_fatal("file %s/%s: parameters %s and %s specify the same user %s", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_MAIL_OWNER, + var_default_privs); + if (var_default_uid == var_owner_uid) + msg_fatal("file %s/%s: parameters %s and %s: users %s and %s have the same user ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_MAIL_OWNER, + var_default_privs, var_mail_owner, + (long) var_owner_uid); + if (var_default_gid == var_owner_gid) + msg_fatal("file %s/%s: parameters %s and %s: users %s and %s have the same group ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_MAIL_OWNER, + var_default_privs, var_mail_owner, + (long) var_owner_gid); + if (var_default_gid == var_sgid_gid) + msg_fatal("file %s/%s: parameters %s and %s: user %s and group %s have the same group ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_DEFAULT_PRIVS, VAR_SGID_GROUP, + var_default_privs, var_sgid_group, + (long) var_sgid_gid); + if (var_owner_gid == var_sgid_gid) + msg_fatal("file %s/%s: parameters %s and %s: user %s and group %s have the same group ID: %ld", + var_config_dir, MAIN_CONF_FILE, + VAR_MAIL_OWNER, VAR_SGID_GROUP, + var_mail_owner, var_sgid_group, + (long) var_sgid_gid); } /* mail_params_init - configure built-in parameters */ @@ -270,7 +382,9 @@ void mail_params_init() }; static CONFIG_STR_TABLE other_str_defaults[] = { VAR_MAIL_NAME, DEF_MAIL_NAME, &var_mail_name, 1, 0, + VAR_SYSLOG_NAME, DEF_SYSLOG_NAME, &var_syslog_name, 1, 0, VAR_MAIL_OWNER, DEF_MAIL_OWNER, &var_mail_owner, 1, 0, + VAR_SGID_GROUP, DEF_SGID_GROUP, &var_sgid_group, 1, 0, VAR_MYDEST, DEF_MYDEST, &var_mydest, 0, 0, VAR_MYORIGIN, DEF_MYORIGIN, &var_myorigin, 1, 0, VAR_RELAYHOST, DEF_RELAYHOST, &var_relayhost, 0, 0, @@ -283,6 +397,7 @@ void mail_params_init() VAR_DOUBLE_BOUNCE, DEF_DOUBLE_BOUNCE, &var_double_bounce_sender, 1, 0, VAR_DEFAULT_PRIVS, DEF_DEFAULT_PRIVS, &var_default_privs, 1, 0, VAR_ALIAS_DB_MAP, DEF_ALIAS_DB_MAP, &var_alias_db_map, 0, 0, + VAR_MAIL_RELEASE, DEF_MAIL_RELEASE, &var_mail_release, 1, 0, VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0, VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0, VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0, @@ -293,6 +408,11 @@ void mail_params_init() VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0, VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 0, 0, VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0, + 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, + VAR_CONFIG_DIRS, DEF_CONFIG_DIRS, &var_config_dirs, 0, 0, 0, }; static CONFIG_STR_FN_TABLE function_str_defaults_2[] = { @@ -307,6 +427,8 @@ void mail_params_init() VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0, VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0, VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0, + VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0, + VAR_FAULT_INJ_CODE, DEF_FAULT_INJ_CODE, &var_fault_inj_code, 0, 0, 0, }; static CONFIG_TIME_TABLE time_defaults[] = { @@ -318,6 +440,7 @@ void mail_params_init() VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0, VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0, VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0, + VAR_IN_FLOW_DELAY, DEF_IN_FLOW_DELAY, &var_in_flow_delay, 0, 10, 0, }; static CONFIG_BOOL_TABLE bool_defaults[] = { @@ -326,6 +449,7 @@ void mail_params_init() VAR_OWNREQ_SPECIAL, DEF_OWNREQ_SPECIAL, &var_ownreq_special, 0, }; + const char *cp; /* * Extract syslog_facility early, so that from here on all errors are @@ -334,7 +458,8 @@ void mail_params_init() get_mail_conf_str_table(first_str_defaults); if (!msg_syslog_facility(var_syslog_facility)) - msg_fatal("unknown %s configuration parameter value: %s", + msg_fatal("file %s/%s: parameter %s: unrecognized value: %s", + var_config_dir, MAIN_CONF_FILE, VAR_SYSLOG_FACILITY, var_syslog_facility); /* @@ -343,10 +468,14 @@ void mail_params_init() * the domain. */ get_mail_conf_str_fn_table(function_str_defaults); - if (!valid_hostname(var_myhostname, DO_GRIPE) - || !valid_hostname(var_mydomain, DO_GRIPE)) - msg_fatal("main.cf configuration error: bad %s or %s parameter value", - VAR_MYHOSTNAME, VAR_MYDOMAIN); + if (!valid_hostname(var_myhostname, DO_GRIPE)) + msg_fatal("file %s/%s: parameter %s: bad parameter value: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_MYHOSTNAME, var_myhostname); + if (!valid_hostname(var_mydomain, DO_GRIPE)) + msg_fatal("file %s/%s: parameter %s: bad parameter value: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_MYDOMAIN, var_mydomain); /* * Variables that are needed by almost every program. @@ -357,6 +486,8 @@ void mail_params_init() get_mail_conf_time_table(time_defaults); check_default_privs(); check_mail_owner(); + check_sgid_group(); + check_overlap(); /* * Variables whose defaults are determined at runtime, after other @@ -377,8 +508,25 @@ void mail_params_init() time(&var_starttime); /* + * Export the syslog name so children can inherit and use it before they + * have initialized. + */ + if ((cp = safe_getenv(CONF_ENV_LOGTAG)) == 0 + || strcmp(cp, var_syslog_name) != 0) + if (setenv(CONF_ENV_LOGTAG, var_syslog_name, 1) < 0) + msg_fatal("setenv %s %s: %m", CONF_ENV_LOGTAG, var_syslog_name); + + /* * I have seen this happen just too often. */ if (strcasecmp(var_myhostname, var_relayhost) == 0) msg_fatal("myhostname == relayhost"); + + /* + * One more sanity check. + */ + if ((cp = verp_delims_verify(var_verp_delims)) != 0) + msg_fatal("file %s/%s: parameters %s and %s: %s", + var_config_dir, MAIN_CONF_FILE, + VAR_VERP_DELIMS, VAR_VERP_FILTER, cp); } diff --git a/gnu/dist/postfix/src/global/mail_params.h b/gnu/dist/postfix/src/global/mail_params.h index 294fd1fc5fd..4009dbdc2b5 100644 --- a/gnu/dist/postfix/src/global/mail_params.h +++ b/gnu/dist/postfix/src/global/mail_params.h @@ -49,6 +49,11 @@ extern char *var_mail_owner; extern uid_t var_owner_uid; extern gid_t var_owner_gid; +#define VAR_SGID_GROUP "setgid_group" +#define DEF_SGID_GROUP "postdrop" +extern char *var_sgid_group; +extern gid_t var_sgid_gid; + #define VAR_DEFAULT_PRIVS "default_privs" #define DEF_DEFAULT_PRIVS "nobody" extern char *var_default_privs; @@ -124,6 +129,17 @@ extern char *var_masq_domains; #define DEF_MASQ_EXCEPTIONS "" extern char *var_masq_exceptions; +#define MASQ_CLASS_ENV_FROM "envelope_sender" +#define MASQ_CLASS_ENV_RCPT "envelope_recipient" +#define MASQ_CLASS_HDR_FROM "header_sender" +#define MASQ_CLASS_HDR_RCPT "header_recipient" + +#define VAR_MASQ_CLASSES "masquerade_classes" +#define DEF_MASQ_CLASSES MASQ_CLASS_ENV_FROM ", " \ + MASQ_CLASS_HDR_FROM ", " \ + MASQ_CLASS_HDR_RCPT +extern char *var_masq_classes; + /* * Intranet versus internet. */ @@ -158,13 +174,13 @@ extern char *var_queue_dir; #define VAR_DAEMON_DIR "daemon_directory" #ifndef DEF_DAEMON_DIR -#define DEF_DAEMON_DIR "$program_directory" +#define DEF_DAEMON_DIR "/usr/libexec/postfix" #endif extern char *var_daemon_dir; #define VAR_COMMAND_DIR "command_directory" #ifndef DEF_COMMAND_DIR -#define DEF_COMMAND_DIR "$program_directory" +#define DEF_COMMAND_DIR "/usr/sbin" #endif extern char *var_command_dir; @@ -191,6 +207,10 @@ extern time_t var_starttime; #endif extern char *var_config_dir; +#define VAR_CONFIG_DIRS "alternate_config_directories" +#define DEF_CONFIG_DIRS "" +extern char *var_config_dirs; + /* * Preferred type of indexed files. The DEF_DB_TYPE macro value is system * dependent. It is defined in <sys_defs.h>. @@ -224,6 +244,10 @@ extern char *var_always_bcc; /* * What to put in the To: header when no recipients were disclosed. + * + * XXX 2822: When no recipient headers remain, a system should insert a Bcc: + * header without additional information. That is not so great given that + * MTAs routinely strip Bcc: headers from message headers. */ #define VAR_RCPT_WITHELD "undisclosed_recipients_header" #define DEF_RCPT_WITHELD "To: undisclosed-recipients:;" @@ -358,6 +382,10 @@ extern char *var_home_mailbox; #define DEF_MAILBOX_COMMAND "" extern char *var_mailbox_command; +#define VAR_MAILBOX_CMD_MAPS "mailbox_command_maps" +#define DEF_MAILBOX_CMD_MAPS "" +extern char *var_mailbox_cmd_maps; + #define VAR_MAILBOX_TRANSP "mailbox_transport" #define DEF_MAILBOX_TRANSP "" extern char *var_mailbox_transport; @@ -634,6 +662,9 @@ extern int var_hash_queue_depth; * determines how many recipient addresses the SMTP client sends along with * each message. Unfortunately, some mailers misbehave and disconnect (smap) * when given more recipients than they are willing to handle. + * + * XXX 2821: A mail system is supposed to use EHLO instead of HELO, and to fall + * back to HELO if EHLO is not supported. */ #define VAR_BESTMX_TRANSP "best_mx_transport" #define DEF_BESTMX_TRANSP "" @@ -688,7 +719,11 @@ extern bool var_ign_mx_lookup_err; extern bool var_skip_quit_resp; #define VAR_SMTP_ALWAYS_EHLO "smtp_always_send_ehlo" +#ifdef RFC821_SYNTAX #define DEF_SMTP_ALWAYS_EHLO 0 +#else +#define DEF_SMTP_ALWAYS_EHLO 1 +#endif extern bool var_smtp_always_ehlo; #define VAR_SMTP_NEVER_EHLO "smtp_never_send_ehlo" @@ -699,6 +734,22 @@ extern bool var_smtp_never_ehlo; #define DEF_SMTP_BIND_ADDR "" extern char *var_smtp_bind_addr; +#define VAR_SMTP_RAND_ADDR "smtp_randomize_addresses" +#define DEF_SMTP_RAND_ADDR 1 +extern bool var_smtp_rand_addr; + +#define VAR_SMTP_BREAK_LINES "smtp_break_lines" +#define DEF_SMTP_BREAK_LINES 1 +extern bool var_smtp_break_lines; + +#define VAR_SMTP_PIX_THRESH "smtp_pix_workaround_threshold_time" +#define DEF_SMTP_PIX_THRESH "500s" +extern int var_smtp_pix_thresh; + +#define VAR_SMTP_PIX_DELAY "smtp_pix_workaround_delay_time" +#define DEF_SMTP_PIX_DELAY "10s" +extern int var_smtp_pix_delay; + /* * SMTP server. The soft error limit determines how many errors an SMTP * client may make before we start to slow down; the hard error limit @@ -729,9 +780,17 @@ extern int var_smtpd_hard_erlim; extern int var_smtpd_err_sleep; #define VAR_SMTPD_JUNK_CMD "smtpd_junk_command_limit" -#define DEF_SMTPD_JUNK_CMD 1000 +#define DEF_SMTPD_JUNK_CMD 100 extern int var_smtpd_junk_cmd_limit; +#define VAR_SMTPD_HIST_THRSH "smtpd_history_flush_threshold" +#define DEF_SMTPD_HIST_THRSH 100 +extern int var_smtpd_hist_thrsh; + +#define VAR_SMTPD_NOOP_CMDS "smtpd_noop_commands" +#define DEF_SMTPD_NOOP_CMDS "" +extern char *var_smtpd_noop_cmds; + /* * SASL authentication support, SMTP server side. */ @@ -747,6 +806,12 @@ extern char *var_smtpd_sasl_opts; #define DEF_SMTPD_SASL_REALM "$myhostname" extern char *var_smtpd_sasl_realm; +#define VAR_SMTPD_SND_AUTH_MAPS "smtpd_sender_login_maps" +#define DEF_SMTPD_SND_AUTH_MAPS "" +extern char *var_smtpd_snd_auth_maps; + +#define REJECT_SENDER_LOGIN_MISMATCH "reject_sender_login_mismatch" + /* * SASL authentication support, SMTP client side. */ @@ -1092,6 +1157,10 @@ extern int var_relay_code; #define PERMIT_MX_BACKUP "permit_mx_backup" +#define VAR_PERM_MX_NETWORKS "permit_mx_backup_networks" +#define DEF_PERM_MX_NETWORKS "" +extern char *var_perm_mx_networks; + #define VAR_ACCESS_MAP_CODE "access_map_reject_code" #define DEF_ACCESS_MAP_CODE 554 extern int var_access_map_code; @@ -1102,13 +1171,15 @@ extern int var_access_map_code; #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 extern int var_maps_rbl_code; #define VAR_MAPS_RBL_DOMAINS "maps_rbl_domains" -#define DEF_MAPS_RBL_DOMAINS "blackholes.mail-abuse.org" +#define DEF_MAPS_RBL_DOMAINS "" extern char *var_maps_rbl_domains; #define VAR_SMTPD_DELAY_REJECT "smtpd_delay_reject" @@ -1117,6 +1188,10 @@ extern int var_smtpd_delay_reject; #define REJECT_UNAUTH_PIPE "reject_unauth_pipelining" +#define VAR_SMTPD_NULL_KEY "smtpd_null_access_lookup_key" +#define DEF_SMTPD_NULL_KEY "" +extern char *var_smtpd_null_key; + /* * Heuristic to reject most unknown recipients at the SMTP port. */ @@ -1192,7 +1267,7 @@ extern int var_fflush_refresh; * and what Postfix exports to the external world. */ #define VAR_IMPORT_ENVIRON "import_environment" -#define DEF_IMPORT_ENVIRON "MAIL_CONFIG MAIL_DEBUG TZ XAUTHORITY DISPLAY" +#define DEF_IMPORT_ENVIRON "MAIL_CONFIG MAIL_DEBUG MAIL_LOGTAG TZ XAUTHORITY DISPLAY" extern char *var_import_environ; #define VAR_EXPORT_ENVIRON "export_environment" @@ -1230,6 +1305,112 @@ extern int var_virt_mailbox_limit; #define DEF_VIRT_MAILBOX_LOCK "fcntl" extern char *var_virt_mailbox_lock; + /* + * Distinct logging tag for multiple Postfix instances. + */ +#define VAR_SYSLOG_NAME "syslog_name" +#define DEF_SYSLOG_NAME "postfix" +extern char *var_syslog_name; + + /* + * QMQPD + */ +#define VAR_QMQPD_CLIENTS "qmqpd_authorized_clients" +#define DEF_QMQPD_CLIENTS "" +extern char *var_qmqpd_clients; + +#define VAR_QMTPD_TMOUT "qmqpd_timeout" +#define DEF_QMTPD_TMOUT "300s" +extern int var_qmqpd_timeout; + +#define VAR_QMTPD_ERR_SLEEP "qmqpd_error_delay" +#define DEF_QMTPD_ERR_SLEEP "5s" +extern int var_qmqpd_err_sleep; + + /* + * VERP, more DJB intellectual cross-pollination. However, we prefer + as + * the default recipient delimiter. + */ +#define VAR_VERP_DELIMS "default_verp_delimiters" +#define DEF_VERP_DELIMS "+=" +extern char *var_verp_delims; + +#define VAR_VERP_FILTER "verp_delimiter_filter" +#define DEF_VERP_FILTER "-=+" +extern char *var_verp_filter; + +#define VAR_VERP_BOUNCE_OFF "disable_verp_bounces" +#define DEF_VERP_BOUNCE_OFF 0 +extern bool var_verp_bounce_off; + + /* + * Inbound mail flow control. This allows for a stiffer coupling between + * receiving mail and sending mail. A sending process produces one token for + * each message that it takes from the incoming queue; a receiving process + * consumes one token for each message that it adds to the incoming queue. + * When no token is available (Postfix receives more mail than it is able to + * deliver) a receiving process pauses for $in_flow_delay seconds so that + * the sending processes get a chance to access the disk. + */ +#define VAR_IN_FLOW_DELAY "in_flow_delay" +#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" + + /* + * Run-time fault injection. + */ +#define VAR_FAULT_INJ_CODE "fault_injection_code" +#define DEF_FAULT_INJ_CODE 0 +extern int var_fault_inj_code; + + /* + * Install/upgrade information. + */ +#define VAR_SENDMAIL_PATH "sendmail_path" +#ifndef DEF_SENDMAIL_PATH +#define DEF_SENDMAIL_PATH "/usr/sbin/sendmail" +#endif + +#define VAR_MAILQ_PATH "mailq_path" +#ifndef DEF_MAILQ_PATH +#define DEF_MAILQ_PATH "/usr/bin/mailq" +#endif + +#define VAR_NEWALIAS_PATH "newaliases_path" +#ifndef DEF_NEWALIAS_PATH +#define DEF_NEWALIAS_PATH "/usr/bin/newaliases" +#endif + +#define VAR_MANPAGE_DIR "manpage_directory" +#ifndef DEF_MANPAGE_DIR +#define DEF_MANPAGE_DIR "/usr/local/man" +#endif + +#define VAR_SAMPLE_DIR "sample_directory" +#ifndef DEF_SAMPLE_DIR +#define DEF_SAMPLE_DIR DEF_CONFIG_DIR +#endif + +#define VAR_README_DIR "readme_directory" +#ifndef DEF_README_DIR +#define DEF_README_DIR "no" +#endif + /* LICENSE /* .ad /* .fi diff --git a/gnu/dist/postfix/src/global/mail_proto.h b/gnu/dist/postfix/src/global/mail_proto.h index 78b76c864ec..adadcda60c9 100644 --- a/gnu/dist/postfix/src/global/mail_proto.h +++ b/gnu/dist/postfix/src/global/mail_proto.h @@ -21,6 +21,7 @@ */ #include <vstream.h> #include <iostuff.h> +#include <attr.h> /* * Names of services: these are the names if INET ports, UNIX-domain sockets @@ -50,12 +51,6 @@ #define MAIL_CLASS_PRIVATE "private" /* - * When sending across a list of objects, this is how we signal the list - * end. - */ -#define MAIL_EOF "@" - - /* * Generic triggers. */ #define TRIGGER_REQ_WAKEUP 'W' /* wakeup */ @@ -71,28 +66,37 @@ /* * Functional interface. */ -#define MAIL_SCAN_MORE 0 -#define MAIL_SCAN_DONE 1 -#define MAIL_SCAN_ERROR -1 - -typedef int (*MAIL_SCAN_FN) (const char *, char *); -typedef void (*MAIL_PRINT_FN) (VSTREAM *, const char *); extern VSTREAM *mail_connect(const char *, const char *, int); extern VSTREAM *mail_connect_wait(const char *, const char *); -extern int mail_scan(VSTREAM *, const char *,...); -extern void mail_scan_register(int, const char *, MAIL_SCAN_FN); -extern void mail_print_register(int, const char *, MAIL_PRINT_FN); -extern int PRINTFLIKE(2, 3) mail_print(VSTREAM *, const char *,...); -extern int PRINTFLIKE(3, 4) mail_command_write(const char *, const char *, const char *,...); -extern int mail_command_read(VSTREAM *, char *,...); +extern int mail_command_client(const char *, const char *,...); +extern int mail_command_server(VSTREAM *,...); extern int mail_trigger(const char *, const char *, const char *, int); extern char *mail_pathname(const char *, const char *); /* - * Stuff that needs <stdarg.h> + * Attribute names. */ -extern int mail_vprint(VSTREAM *, const char *, va_list); -extern int mail_vscan(VSTREAM *, const char *, va_list); +#define MAIL_ATTR_REQ "request" +#define MAIL_ATTR_NREQ "nrequest" +#define MAIL_ATTR_STATUS "status" + +#define MAIL_ATTR_FLAGS "flags" +#define MAIL_ATTR_QUEUE "queue_name" +#define MAIL_ATTR_QUEUEID "queue_id" +#define MAIL_ATTR_SENDER "sender" +#define MAIL_ATTR_RECIP "recipient" +#define MAIL_ATTR_WHY "reason" +#define MAIL_ATTR_VERPDL "verp_delimiters" +#define MAIL_ATTR_SITE "site" +#define MAIL_ATTR_OFFSET "offset" +#define MAIL_ATTR_SIZE "size" +#define MAIL_ATTR_ERRTO "errors-to" +#define MAIL_ATTR_RRCPT "return-receipt" +#define MAIL_ATTR_TIME "time" +#define MAIL_ATTR_RULE "rule" +#define MAIL_ATTR_ADDR "address" +#define MAIL_ATTR_TRANSPORT "transport" +#define MAIL_ATTR_NEXTHOP "nexthop" /* LICENSE /* .ad diff --git a/gnu/dist/postfix/src/global/mail_queue.c b/gnu/dist/postfix/src/global/mail_queue.c index 5fc18640ec3..54916c8b59f 100644 --- a/gnu/dist/postfix/src/global/mail_queue.c +++ b/gnu/dist/postfix/src/global/mail_queue.c @@ -76,7 +76,7 @@ /* mail_queue_rename() renames a queue file. A non-zero result /* means the operation failed. /* -/* mail_queue_remove() renames the named queue file. A non-zero result +/* mail_queue_remove() removes the named queue file. A non-zero result /* means the operation failed. /* /* mail_queue_name_ok() validates a mail queue name and returns @@ -378,9 +378,23 @@ VSTREAM *mail_queue_enter(const char *queue_name, int mode) file_id = get_file_id(fd); GETTIMEOFDAY(&tv); + /* + * XXX Some systems seem to have clocks that correlate with process + * scheduling or something. Unfortunately, we cannot add random + * quantities to the time, because the non-inode part of a queue ID must + * not repeat within the same second. The queue ID is the sole thing that + * prevents multiple messages from getting the same Message-ID value. + */ for (count = 0;; count++) { vstring_sprintf(id_buf, "%05X%s", (int) tv.tv_usec, file_id); mail_queue_path(path_buf, queue_name, STR(id_buf)); +#if 0 + if (access(STR(path_buf), X_OK) == 0) { /* collision. */ + if ((int) ++tv.tv_usec < 0) + tv.tv_usec = 0; + continue; + } +#endif if (sane_rename(STR(temp_path), STR(path_buf)) == 0) /* success */ break; if (errno == EPERM || errno == EISDIR) {/* collision. weird. */ diff --git a/gnu/dist/postfix/src/global/mail_stream.c b/gnu/dist/postfix/src/global/mail_stream.c index e30537dfff6..74a8ada8c0a 100644 --- a/gnu/dist/postfix/src/global/mail_stream.c +++ b/gnu/dist/postfix/src/global/mail_stream.c @@ -14,10 +14,11 @@ /* .in -4 /* } MAIL_STREAM; /* -/* MAIL_STREAM *mail_stream_file(queue, class, service) +/* MAIL_STREAM *mail_stream_file(queue, class, service, mode) /* const char *queue; /* const char *class; /* const char *service; +/* int mode; /* /* MAIL_STREAM *mail_stream_service(class, service) /* const char *class; @@ -29,8 +30,9 @@ /* void mail_stream_cleanup(info) /* MAIL_STREAM *info; /* -/* int mail_stream_finish(info) +/* int mail_stream_finish(info, why) /* MAIL_STREAM *info; +/* VSTRING *why; /* DESCRIPTION /* This module provides a generic interface to Postfix queue file /* format messages to file, to Postfix server, or to external command. @@ -41,7 +43,8 @@ /* /* mail_stream_file() opens a mail stream to a newly-created file and /* arranges for trigger delivery at finish time. This call never fails. -/* But it may take forever. +/* But it may take forever. The mode argument specifies additional +/* file permissions that will be OR-ed in. /* /* mail_stream_command() opens a mail stream to external command, /* and receives queue ID information from the command. The result @@ -62,6 +65,7 @@ /* any of the mail_stream_xxx() routines, and destroys the argument. /* The result is any of the status codes defined in <cleanup_user.h>. /* It is up to the caller to remove incomplete file objects. +/* The why argument can be a null pointer. /* LICENSE /* .ad /* .fi @@ -78,6 +82,7 @@ #include <sys_defs.h> #include <sys/stat.h> #include <unistd.h> +#include <errno.h> /* Utility library. */ @@ -116,22 +121,30 @@ void mail_stream_cleanup(MAIL_STREAM * info) /* mail_stream_finish_file - finish file mail stream */ -static int mail_stream_finish_file(MAIL_STREAM * info) +static int mail_stream_finish_file(MAIL_STREAM * info, VSTRING *unused_why) { int status = 0; static char wakeup[] = {TRIGGER_REQ_WAKEUP}; /* * Make sure the message makes it to file. Set the execute bit when no - * write error was detected. + * write error was detected. Some people believe that this code has a + * problem if the system crashes before fsync() returns; fchmod() could + * take effect before all the data blocks are written. Wietse claims that + * this is not a problem. Postfix rejects incomplete queue files, even + * when the +x attribute is set. Every Postfix queue file record has a + * type code and a length field. Files with truncated records are + * rejected, as are files with unknown type codes. Every Postfix queue + * file must end with an explicit END record. Postfix queue files without + * END record are discarded. */ if (vstream_fflush(info->stream) - || fchmod(vstream_fileno(info->stream), 0700) + || fchmod(vstream_fileno(info->stream), 0700 | info->mode) #ifdef HAS_FSYNC || fsync(vstream_fileno(info->stream)) #endif ) - status = CLEANUP_STAT_WRITE; + status = (errno == EFBIG ? CLEANUP_STAT_SIZE : CLEANUP_STAT_WRITE); /* * Close the queue file and mark it as closed. Be prepared for @@ -142,7 +155,7 @@ static int mail_stream_finish_file(MAIL_STREAM * info) * reasons. */ if (info->close(info->stream)) - status = CLEANUP_STAT_WRITE; + status = (errno == EFBIG ? CLEANUP_STAT_SIZE : CLEANUP_STAT_WRITE); info->stream = 0; /* @@ -161,14 +174,20 @@ static int mail_stream_finish_file(MAIL_STREAM * info) /* mail_stream_finish_ipc - finish IPC mail stream */ -static int mail_stream_finish_ipc(MAIL_STREAM * info) +static int mail_stream_finish_ipc(MAIL_STREAM * info, VSTRING *why) { int status = CLEANUP_STAT_WRITE; /* * Receive the peer's completion status. */ - if (mail_scan(info->stream, "%d", &status) != 1) + if ((why && attr_scan(info->stream, ATTR_FLAG_STRICT, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_STR, MAIL_ATTR_WHY, why, + ATTR_TYPE_END) != 2) + || (!why && attr_scan(info->stream, ATTR_FLAG_MISSING, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1)) status = CLEANUP_STAT_WRITE; /* @@ -180,20 +199,20 @@ static int mail_stream_finish_ipc(MAIL_STREAM * info) /* mail_stream_finish - finish action */ -int mail_stream_finish(MAIL_STREAM * info) +int mail_stream_finish(MAIL_STREAM * info, VSTRING *why) { - return (info->finish(info)); + return (info->finish(info, why)); } /* mail_stream_file - destination is file */ MAIL_STREAM *mail_stream_file(const char *queue, const char *class, - const char *service) + const char *service, int mode) { MAIL_STREAM *info; VSTREAM *stream; - stream = mail_queue_enter(queue, 0600); + stream = mail_queue_enter(queue, 0600 | mode); if (msg_verbose) msg_info("open %s", VSTREAM_PATH(stream)); @@ -204,6 +223,7 @@ MAIL_STREAM *mail_stream_file(const char *queue, const char *class, info->id = mystrdup(basename(VSTREAM_PATH(stream))); info->class = mystrdup(class); info->service = mystrdup(service); + info->mode = mode; return (info); } @@ -218,7 +238,8 @@ MAIL_STREAM *mail_stream_service(const char *class, const char *name) id_buf = vstring_alloc(10); stream = mail_connect_wait(class, name); - if (mail_scan(stream, "%s", id_buf) != 1) { + if (attr_scan(stream, ATTR_FLAG_MISSING, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id_buf, 0) != 1) { vstream_fclose(stream); return (0); } else { @@ -263,8 +284,12 @@ MAIL_STREAM *mail_stream_command(const char *command) sleep(10); } argv_free(export_env); + vstream_control(stream, + VSTREAM_CTL_PATH, command, + VSTREAM_CTL_END); - if (mail_scan(stream, "%s", id_buf) != 1) { + if (attr_scan(stream, ATTR_FLAG_MISSING, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id_buf, 0) != 1) { vstream_pclose(stream); return (0); } else { diff --git a/gnu/dist/postfix/src/global/mail_stream.h b/gnu/dist/postfix/src/global/mail_stream.h index 3ae6c624ac8..c9fbfd97a78 100644 --- a/gnu/dist/postfix/src/global/mail_stream.h +++ b/gnu/dist/postfix/src/global/mail_stream.h @@ -22,7 +22,7 @@ */ typedef struct MAIL_STREAM MAIL_STREAM; -typedef int (*MAIL_STREAM_FINISH_FN) (MAIL_STREAM *); +typedef int (*MAIL_STREAM_FINISH_FN) (MAIL_STREAM *, VSTRING *); typedef int (*MAIL_STREAM_CLOSE_FN) (VSTREAM *); struct MAIL_STREAM { @@ -32,13 +32,14 @@ struct MAIL_STREAM { MAIL_STREAM_CLOSE_FN close; /* close stream */ char *class; /* trigger class */ char *service; /* trigger service */ + int mode; /* additional permissions */ }; -extern MAIL_STREAM *mail_stream_file(const char *, const char *, const char *); +extern MAIL_STREAM *mail_stream_file(const char *, const char *, const char *, int); extern MAIL_STREAM *mail_stream_service(const char *, const char *); extern MAIL_STREAM *mail_stream_command(const char *); extern void mail_stream_cleanup(MAIL_STREAM *); -extern int mail_stream_finish(MAIL_STREAM *); +extern int mail_stream_finish(MAIL_STREAM *, VSTRING *); /* LICENSE diff --git a/gnu/dist/postfix/src/global/mail_task.c b/gnu/dist/postfix/src/global/mail_task.c index 0500754565c..2c06f9edaa3 100644 --- a/gnu/dist/postfix/src/global/mail_task.c +++ b/gnu/dist/postfix/src/global/mail_task.c @@ -12,7 +12,8 @@ /* mail_task() enforces consistent naming of mailer processes. /* It strips pathname information from the process name, and /* prepends the name of the mail system so that logfile entries -/* are easier to recognize. +/* are easier to recognize. The mail system name is specified +/* with the "syslog_name" configuration parameter. /* /* The result is volatile. Make a copy of the result if it is /* to be used for any appreciable amount of time. @@ -35,25 +36,28 @@ /* Utility library. */ #include <vstring.h> +#include <safe.h> /* Global library. */ #include "mail_params.h" +#include "mail_conf.h" #include "mail_task.h" -#define MAIL_TASK_FORMAT "postfix/%s" - /* mail_task - clean up and decorate the process name */ const char *mail_task(const char *argv0) { static VSTRING *canon_name; const char *slash; + const char *tag; if (canon_name == 0) canon_name = vstring_alloc(10); if ((slash = strrchr(argv0, '/')) != 0) argv0 = slash + 1; - vstring_sprintf(canon_name, MAIL_TASK_FORMAT, argv0); + if ((tag = safe_getenv(CONF_ENV_LOGTAG)) == 0) + tag = DEF_SYSLOG_NAME; + vstring_sprintf(canon_name, "%s/%s", tag, argv0); return (vstring_str(canon_name)); } diff --git a/gnu/dist/postfix/src/global/mail_trigger.c b/gnu/dist/postfix/src/global/mail_trigger.c index 4d4d61c3f8b..457f19d6b8f 100644 --- a/gnu/dist/postfix/src/global/mail_trigger.c +++ b/gnu/dist/postfix/src/global/mail_trigger.c @@ -79,7 +79,7 @@ int mail_trigger(const char *class, const char *service, */ path = mail_pathname(class, service); if ((status = stat(path, &st)) < 0) { - /* void */ ; + msg_warn("unable to look up %s: %m", path); } else if (S_ISFIFO(st.st_mode)) { status = fifo_trigger(path, req_buf, req_len, var_trigger_timeout); if (status < 0 && S_ISSOCK(st.st_mode)) diff --git a/gnu/dist/postfix/src/global/mail_version.h b/gnu/dist/postfix/src/global/mail_version.h index fe062b14530..c5c930804ee 100644 --- a/gnu/dist/postfix/src/global/mail_version.h +++ b/gnu/dist/postfix/src/global/mail_version.h @@ -12,12 +12,29 @@ /* .nf /* - * Version of this program. + * Version of this program. Official versions are called a.b.c, and + * snapshots are called a.b.c-yyyymmdd, where a=major release number, + * b=minor release number, c=patchlevel, and yyyymmdd is the release date: + * yyyy=year, mm=month, dd=day. + * + * Patches change the patchlevel and the release date. Snapshots change the + * release date only, unless they include the same bugfix as a patch release. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Postfix-20010228-pl08" +#ifdef SNAPSHOT +#define DEF_MAIL_VERSION "1.1.2-$mail_release_date" +#else +#define DEF_MAIL_VERSION "1.1.2" +#endif extern char *var_mail_version; + /* + * Release date. + */ +#define VAR_MAIL_RELEASE "mail_release_date" +#define DEF_MAIL_RELEASE "20020125" +extern char *var_mail_release; + /* LICENSE /* .ad /* .fi diff --git a/gnu/dist/postfix/src/global/mark_corrupt.c b/gnu/dist/postfix/src/global/mark_corrupt.c index 994492ef1c3..bcffef8dd5c 100644 --- a/gnu/dist/postfix/src/global/mark_corrupt.c +++ b/gnu/dist/postfix/src/global/mark_corrupt.c @@ -27,15 +27,19 @@ #include <sys_defs.h> #include <sys/stat.h> +#include <unistd.h> /* Utility library. */ #include <msg.h> #include <vstream.h> +#include <set_eugid.h> /* Global library. */ #include <mail_queue.h> +#include <mail_params.h> +#include <deliver_request.h> #include <mark_corrupt.h> /* mark_corrupt - mark queue file as corrupt */ @@ -43,6 +47,16 @@ int mark_corrupt(VSTREAM *src) { char *myname = "mark_corrupt"; + uid_t saved_uid; + gid_t saved_gid; + + /* + * If not running as the mail system, change privileges first. + */ + if ((saved_uid = geteuid()) != var_owner_uid) { + saved_gid = getegid(); + set_eugid(var_owner_uid, var_owner_gid); + } /* * For now, the result value is -1; this may become a bit mask, or @@ -52,5 +66,12 @@ int mark_corrupt(VSTREAM *src) msg_warn("corrupted queue file: %s", VSTREAM_PATH(src)); if (fchmod(vstream_fileno(src), MAIL_QUEUE_STAT_CORRUPT)) msg_fatal("%s: fchmod %s: %m", myname, VSTREAM_PATH(src)); - return (-1); + + /* + * Restore privileges. + */ + if (saved_uid != var_owner_uid) + set_eugid(saved_uid, saved_gid); + + return (DEL_STAT_DEFER); } diff --git a/gnu/dist/postfix/src/global/match_parent_style.c b/gnu/dist/postfix/src/global/match_parent_style.c new file mode 100644 index 00000000000..a914f616fbe --- /dev/null +++ b/gnu/dist/postfix/src/global/match_parent_style.c @@ -0,0 +1,72 @@ +/*++ +/* 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); +} diff --git a/gnu/dist/postfix/src/global/match_parent_style.h b/gnu/dist/postfix/src/global/match_parent_style.h new file mode 100644 index 00000000000..7b51eddf70a --- /dev/null +++ b/gnu/dist/postfix/src/global/match_parent_style.h @@ -0,0 +1,35 @@ +#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 diff --git a/gnu/dist/postfix/src/global/namadr_list.c b/gnu/dist/postfix/src/global/namadr_list.c index 0e6b1bba730..c5169d87e59 100644 --- a/gnu/dist/postfix/src/global/namadr_list.c +++ b/gnu/dist/postfix/src/global/namadr_list.c @@ -6,7 +6,8 @@ /* 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) @@ -17,6 +18,8 @@ /* 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. /* @@ -35,9 +38,18 @@ /* 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. @@ -67,33 +79,11 @@ /* 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> @@ -126,7 +116,7 @@ main(int argc, char **argv) } 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, diff --git a/gnu/dist/postfix/src/global/namadr_list.h b/gnu/dist/postfix/src/global/namadr_list.h index 186cd66c1b7..9bf90d7684d 100644 --- a/gnu/dist/postfix/src/global/namadr_list.h +++ b/gnu/dist/postfix/src/global/namadr_list.h @@ -7,18 +7,25 @@ /* 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 diff --git a/gnu/dist/postfix/src/global/off_cvt.c b/gnu/dist/postfix/src/global/off_cvt.c index 95a689f14e1..756b63c8c60 100644 --- a/gnu/dist/postfix/src/global/off_cvt.c +++ b/gnu/dist/postfix/src/global/off_cvt.c @@ -27,10 +27,6 @@ /* Buffer for storage of the result of conversion to string. /* .IP offset /* Non-negative off_t value to be converted to string. -/* BUGS -/* The string to number conversion routine has no reliable way to -/* detect an overflow error, so the result may be much smaller -/* than the number specified in the input. /* DIAGNOSTICS /* Panic: negative offset /* LICENSE @@ -70,19 +66,28 @@ off_t off_cvt_string(const char *str) { int ch; off_t result; + off_t res2; + off_t res4; + off_t res8; + off_t res10; /* - * We're not doing this often, so simplicity has precedence over - * performance. XXX Need a portable way to correctly detect overflow. - * Bear in mind that an off_t is not necessarily a long integer, so using - * raw bit patterns is not going to be a portable solution. + * Multiplication by numbers > 2 can overflow without producing a smaller + * result mod 2^N (where N is the number of bits in the result type). + * (Victor Duchovni, Morgan Stanley). */ for (result = 0; (ch = *(unsigned char *) str) != 0; str++) { if (!ISDIGIT(ch)) return (-1); - result *= 10; - result += ch - '0'; - if (result < 0) + if ((res2 = result + result) < result) + return (-1); + if ((res4 = res2 + res2) < res2) + return (-1); + if ((res8 = res4 + res4) < res4) + return (-1); + if ((res10 = res8 + res2) < res8) + return (-1); + if ((result = res10 + ch - '0') < res10) return (-1); } return (result); @@ -101,7 +106,7 @@ VSTRING *off_cvt_number(VSTRING *buf, off_t offset) * Sanity checks */ if (offset < 0) - msg_panic("off_cvt_number: negative offset %s", + msg_panic("off_cvt_number: negative offset -%s", STR(off_cvt_number(buf, -offset))); /* diff --git a/gnu/dist/postfix/src/global/pipe_command.c b/gnu/dist/postfix/src/global/pipe_command.c index 8c9615a6fd4..11f68b32544 100644 --- a/gnu/dist/postfix/src/global/pipe_command.c +++ b/gnu/dist/postfix/src/global/pipe_command.c @@ -33,11 +33,11 @@ /* or when it appears to be a shell built-in command, otherwise /* the command is executed without invoking a shell. /* One of PIPE_CMD_COMMAND or PIPE_CMD_ARGV must be specified. +/* See also the PIPE_CMD_SHELL attribute below. /* .IP "PIPE_CMD_ARGV (char **)" /* The command is specified as an argument vector. This vector is /* passed without further inspection to the \fIexecvp\fR() routine. /* One of PIPE_CMD_COMMAND or PIPE_CMD_ARGV must be specified. -/* See also the PIPE_CMD_SHELL attribute below. /* .IP "PIPE_CMD_ENV (char **)" /* Additional environment information, in the form of a null-terminated /* list of name, value, name, value, ... elements. By default only the @@ -88,8 +88,11 @@ /* The command indicated that the message was not acceptable, /* or the command did not finish within the time limit. /* The reason is given via the \fIwhy\fR argument. +/* .IP PIPE_STAT_CORRUPT +/* The queue file is corrupted. /* SEE ALSO /* mail_copy(3) deliver to any. +/* mark_corrupt(3) mark queue file as corrupt. /* sys_exits(3) sendmail-compatible exit status codes. /* LICENSE /* .ad @@ -509,6 +512,8 @@ int pipe_command(VSTREAM *src, VSTRING *why,...) log_len ? ". Command output: " : "", log_buf); return (PIPE_STAT_BOUNCE); } + } else if (write_status & MAIL_COPY_STAT_CORRUPT) { + return (PIPE_STAT_CORRUPT); } else if (write_status && errno != EPIPE) { vstring_sprintf(why, "Command failed: %m: \"%s\"", args.command); return (PIPE_STAT_DEFER); diff --git a/gnu/dist/postfix/src/global/pipe_command.h b/gnu/dist/postfix/src/global/pipe_command.h index cf8d5989220..1750ccc7bd3 100644 --- a/gnu/dist/postfix/src/global/pipe_command.h +++ b/gnu/dist/postfix/src/global/pipe_command.h @@ -45,6 +45,7 @@ #define PIPE_STAT_OK 0 /* success */ #define PIPE_STAT_DEFER 1 /* try again */ #define PIPE_STAT_BOUNCE 2 /* failed */ +#define PIPE_STAT_CORRUPT 3 /* corrupted file */ extern int pipe_command(VSTREAM *, VSTRING *,...); diff --git a/gnu/dist/postfix/src/global/post_mail.c b/gnu/dist/postfix/src/global/post_mail.c index c3673243f5c..7c2fb0def1e 100644 --- a/gnu/dist/postfix/src/global/post_mail.c +++ b/gnu/dist/postfix/src/global/post_mail.c @@ -6,17 +6,15 @@ /* SYNOPSIS /* #include <post_mail.h> /* -/* VSTREAM *post_mail_fopen(sender, recipient, flags, via) +/* VSTREAM *post_mail_fopen(sender, recipient, flags) /* const char *sender; /* const char *recipient; /* int flags; -/* const char *via; /* -/* VSTREAM *post_mail_fopen_nowait(sender, recipient, flags, via) +/* VSTREAM *post_mail_fopen_nowait(sender, recipient, flags) /* const char *sender; /* const char *recipient; /* int flags; -/* const char *via; /* /* int post_mail_fprintf(stream, format, ...) /* VSTREAM *stream; @@ -132,7 +130,7 @@ /* post_mail_init - initial negotiations */ static void post_mail_init(VSTREAM *stream, const char *sender, - const char *recipient, int flags, const char *via) + const char *recipient, int flags) { VSTRING *id = vstring_alloc(100); long now = time((time_t *) 0); @@ -141,8 +139,12 @@ static void post_mail_init(VSTREAM *stream, const char *sender, /* * Negotiate with the cleanup service. Give up if we can't agree. */ - if (mail_scan(stream, "%s", id) != 1 - || mail_print(stream, "%d", flags) != 0) + if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id, + ATTR_TYPE_END) != 1 + || attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_END) != 0) msg_fatal("unable to contact the %s service", MAIL_SERVICE_CLEANUP); /* @@ -158,8 +160,8 @@ static void post_mail_init(VSTREAM *stream, const char *sender, * Do the Received: and Date: header lines. This allows us to shave a few * cycles by using the expensive date conversion result for both. */ - post_mail_fprintf(stream, "Received: by %s (%s) via %s", - var_myhostname, var_mail_name, via); + post_mail_fprintf(stream, "Received: by %s (%s)", + var_myhostname, var_mail_name); post_mail_fprintf(stream, "\tid %s; %s", vstring_str(id), date); post_mail_fprintf(stream, "Date: %s", date); vstring_free(id); @@ -167,26 +169,25 @@ static void post_mail_init(VSTREAM *stream, const char *sender, /* post_mail_fopen - prepare for posting a message */ -VSTREAM *post_mail_fopen(const char *sender, const char *recipient, - int flags, const char *via) +VSTREAM *post_mail_fopen(const char *sender, const char *recipient, int flags) { VSTREAM *stream; - stream = mail_connect_wait(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP); - post_mail_init(stream, sender, recipient, flags, via); + stream = mail_connect_wait(MAIL_CLASS_PUBLIC, MAIL_SERVICE_CLEANUP); + post_mail_init(stream, sender, recipient, flags); return (stream); } /* post_mail_fopen_nowait - prepare for posting a message */ VSTREAM *post_mail_fopen_nowait(const char *sender, const char *recipient, - int flags, const char *via) + int flags) { VSTREAM *stream; - if ((stream = mail_connect(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP, + if ((stream = mail_connect(MAIL_CLASS_PUBLIC, MAIL_SERVICE_CLEANUP, BLOCKING)) != 0) - post_mail_init(stream, sender, recipient, flags, via); + post_mail_init(stream, sender, recipient, flags); return (stream); } @@ -235,7 +236,10 @@ int post_mail_fclose(VSTREAM *cleanup) } else { rec_fputs(cleanup, REC_TYPE_XTRA, ""); rec_fputs(cleanup, REC_TYPE_END, ""); - if (vstream_fflush(cleanup) || mail_scan(cleanup, "%d", &status) != 1) + if (vstream_fflush(cleanup) + || attr_scan(cleanup, ATTR_FLAG_MISSING, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1) status = CLEANUP_STAT_WRITE; } (void) vstream_fclose(cleanup); diff --git a/gnu/dist/postfix/src/global/post_mail.h b/gnu/dist/postfix/src/global/post_mail.h index 8fa5a80bf3b..264afc77bff 100644 --- a/gnu/dist/postfix/src/global/post_mail.h +++ b/gnu/dist/postfix/src/global/post_mail.h @@ -24,9 +24,8 @@ /* * External interface. */ -extern VSTREAM *post_mail_fopen(const char *, const char *, int, const char *); -extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, - int, const char *); +extern VSTREAM *post_mail_fopen(const char *, const char *, int); +extern VSTREAM *post_mail_fopen_nowait(const char *, const char *, int); extern int PRINTFLIKE(2, 3) post_mail_fprintf(VSTREAM *, const char *,...); extern int post_mail_fputs(VSTREAM *, const char *); extern int post_mail_buffer(VSTREAM *, const char *, int); diff --git a/gnu/dist/postfix/src/global/qmqp_proto.h b/gnu/dist/postfix/src/global/qmqp_proto.h new file mode 100644 index 00000000000..8ad9e2aadaf --- /dev/null +++ b/gnu/dist/postfix/src/global/qmqp_proto.h @@ -0,0 +1,27 @@ +/*++ +/* NAME +/* qmqpd 3h +/* SUMMARY +/* QMQP protocol +/* SYNOPSIS +/* include <qmqpd_proto.h> +/* DESCRIPTION +/* .nf + + /* + * QMQP protocol status codes. + */ +#define QMQP_STAT_OK 'K' /* success */ +#define QMQP_STAT_RETRY 'Z' /* recoverable error */ +#define QMQP_STAT_HARD 'D' /* unrecoverable error */ + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ diff --git a/gnu/dist/postfix/src/global/rec_type.c b/gnu/dist/postfix/src/global/rec_type.c index c86a461aa14..d1e630b3709 100644 --- a/gnu/dist/postfix/src/global/rec_type.c +++ b/gnu/dist/postfix/src/global/rec_type.c @@ -48,7 +48,9 @@ REC_TYPE_NAME rec_type_names[] = { REC_TYPE_FROM, "sender", REC_TYPE_DONE, "done", REC_TYPE_RCPT, "recipient", + REC_TYPE_ORCP, "original recipient", REC_TYPE_WARN, "warning_message_time", + REC_TYPE_ATTR, "named attribute", REC_TYPE_MESG, "message_content", REC_TYPE_CONT, "unterminated", REC_TYPE_NORM, "normal_data", @@ -56,6 +58,7 @@ REC_TYPE_NAME rec_type_names[] = { REC_TYPE_RRTO, "return_receipt", REC_TYPE_ERTO, "errors_to", REC_TYPE_PRIO, "priority", + REC_TYPE_VERP, "verp_delimiters", REC_TYPE_END, "message_end", 0, 0, }; diff --git a/gnu/dist/postfix/src/global/rec_type.h b/gnu/dist/postfix/src/global/rec_type.h index 4412ee37da4..f1caaa466fe 100644 --- a/gnu/dist/postfix/src/global/rec_type.h +++ b/gnu/dist/postfix/src/global/rec_type.h @@ -33,7 +33,9 @@ #define REC_TYPE_FROM 'S' /* sender, required */ #define REC_TYPE_DONE 'D' /* delivered recipient, optional */ #define REC_TYPE_RCPT 'R' /* todo recipient, optional */ +#define REC_TYPE_ORCP 'O' /* original recipient, optional */ #define REC_TYPE_WARN 'W' /* warning message time */ +#define REC_TYPE_ATTR 'A' /* named attribute for extensions */ #define REC_TYPE_MESG 'M' /* start message records */ @@ -45,6 +47,7 @@ #define REC_TYPE_RRTO 'r' /* return-receipt, from headers */ #define REC_TYPE_ERTO 'e' /* errors-to, from headers */ #define REC_TYPE_PRIO 'P' /* priority */ +#define REC_TYPE_VERP 'V' /* VERP delimiters */ #define REC_TYPE_END 'E' /* terminator, required */ @@ -53,9 +56,9 @@ * record groups. The first member in each set is the record type that * indicates the end of that record group. */ -#define REC_TYPE_ENVELOPE "MCTFILSDRW" +#define REC_TYPE_ENVELOPE "MCTFILSDROWVA" #define REC_TYPE_CONTENT "XLN" -#define REC_TYPE_EXTRACT "EDRPre" +#define REC_TYPE_EXTRACT "EDROPre" /* NOT A */ #define REC_TYPE_NOEXTRACT "E" /* diff --git a/gnu/dist/postfix/src/global/recdump.c b/gnu/dist/postfix/src/global/recdump.c index a02d1755e5d..74ff7ea02e0 100644 --- a/gnu/dist/postfix/src/global/recdump.c +++ b/gnu/dist/postfix/src/global/recdump.c @@ -44,7 +44,8 @@ int main(int unused_argc, char **argv) msg_vstream_init(argv[0], VSTREAM_OUT); while (offset = vstream_ftell(VSTREAM_IN), - (type = rec_get(VSTREAM_IN, buf, 0)) > 0) { + ((type = rec_get(VSTREAM_IN, buf, 0)) != REC_TYPE_EOF + && type != REC_TYPE_ERROR)) { vstream_fprintf(VSTREAM_OUT, "%15s|%4ld|%3d|%s\n", rec_type_name(type), offset, VSTRING_LEN(buf), vstring_str(buf)); diff --git a/gnu/dist/postfix/src/global/resolve_clnt.c b/gnu/dist/postfix/src/global/resolve_clnt.c index ff27504a627..56382876541 100644 --- a/gnu/dist/postfix/src/global/resolve_clnt.c +++ b/gnu/dist/postfix/src/global/resolve_clnt.c @@ -156,13 +156,20 @@ void resolve_clnt_query(const char *addr, RESOLVE_REPLY *reply) for (;;) { stream = clnt_stream_access(rewrite_clnt_stream); - if (mail_print(stream, "%s %s", RESOLVE_ADDR, addr) + if (attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_REQ, RESOLVE_ADDR, + ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr, + ATTR_TYPE_END) || vstream_fflush(stream)) { if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("%s: bad write: %m", myname); - } else if (mail_scan(stream, "%s %s %s %d", - reply->transport, reply->nexthop, - reply->recipient, &reply->flags) != 4) { + } else if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_TRANSPORT, reply->transport, + ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, reply->nexthop, + + ATTR_TYPE_STR, MAIL_ATTR_RECIP, reply->recipient, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, &reply->flags, + ATTR_TYPE_END) != 4) { if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("%s: bad read: %m", myname); } else { diff --git a/gnu/dist/postfix/src/global/rewrite_clnt.c b/gnu/dist/postfix/src/global/rewrite_clnt.c index ba9049ad3b6..886dc4922eb 100644 --- a/gnu/dist/postfix/src/global/rewrite_clnt.c +++ b/gnu/dist/postfix/src/global/rewrite_clnt.c @@ -123,11 +123,17 @@ VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result) for (;;) { stream = clnt_stream_access(rewrite_clnt_stream); - if (mail_print(stream, "%s %s %s", REWRITE_ADDR, rule, addr), + if (attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_REQ, REWRITE_ADDR, + ATTR_TYPE_STR, MAIL_ATTR_RULE, rule, + ATTR_TYPE_STR, MAIL_ATTR_ADDR, addr, + ATTR_TYPE_END), vstream_fflush(stream)) { if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("%s: bad write: %m", myname); - } else if (mail_scan(stream, "%s", result) != 1) { + } else if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_ADDR, result, + ATTR_TYPE_END) != 1) { if (msg_verbose || (errno != EPIPE && errno != ENOENT)) msg_warn("%s: bad read: %m", myname); } else { diff --git a/gnu/dist/postfix/src/global/smtp_stream.c b/gnu/dist/postfix/src/global/smtp_stream.c index 606ffb65fc0..751e92aa6ae 100644 --- a/gnu/dist/postfix/src/global/smtp_stream.c +++ b/gnu/dist/postfix/src/global/smtp_stream.c @@ -200,6 +200,9 @@ int smtp_get(VSTRING *vp, VSTREAM *stream, int bound) * Allow for partial long lines (we will read the remainder later) and * allow for lines ending in bare LF. The idea is to be liberal in what * we accept, strict in what we send. + * + * XXX 2821: Section 4.1.1.4 says that an SMTP server must not recognize + * bare LF as record terminator. */ smtp_timeout_reset(stream); last_char = (bound == 0 ? vstring_get(vp, stream) : @@ -224,11 +227,13 @@ int smtp_get(VSTRING *vp, VSTREAM *stream, int bound) /* * Strip off the record terminator: either CRLF or just bare LF. + * + * XXX RFC 2821 disallows sending bare CR everywhere. We remove bare CR + * if received before CRLF, and leave it alone otherwise. */ case '\n': - if (VSTRING_LEN(vp) > 1 && vstring_end(vp)[-2] == '\r') - vstring_truncate(vp, VSTRING_LEN(vp) - 2); - else + vstring_truncate(vp, VSTRING_LEN(vp) - 1); + while (VSTRING_LEN(vp) > 0 && vstring_end(vp)[-1] == '\r') vstring_truncate(vp, VSTRING_LEN(vp) - 1); VSTRING_TERMINATE(vp); diff --git a/gnu/dist/postfix/src/global/string_list.c b/gnu/dist/postfix/src/global/string_list.c index bcb457e77a7..522ff26a1df 100644 --- a/gnu/dist/postfix/src/global/string_list.c +++ b/gnu/dist/postfix/src/global/string_list.c @@ -6,7 +6,8 @@ /* 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) @@ -16,6 +17,8 @@ /* 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 @@ -28,8 +31,8 @@ /* 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. @@ -58,33 +61,11 @@ /* 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> @@ -117,7 +98,7 @@ main(int argc, char **argv) } 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"); diff --git a/gnu/dist/postfix/src/global/string_list.h b/gnu/dist/postfix/src/global/string_list.h index 946ecf1d296..daa9541d2f5 100644 --- a/gnu/dist/postfix/src/global/string_list.h +++ b/gnu/dist/postfix/src/global/string_list.h @@ -12,13 +12,19 @@ /* .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 diff --git a/gnu/dist/postfix/src/global/tok822.h b/gnu/dist/postfix/src/global/tok822.h index c0dd10f5c58..316dfb19821 100644 --- a/gnu/dist/postfix/src/global/tok822.h +++ b/gnu/dist/postfix/src/global/tok822.h @@ -45,8 +45,7 @@ typedef struct TOK822 { #define TOK822_DOMLIT 259 /* stuff between [] not nesting */ #define TOK822_ADDR 260 /* actually a token group */ #define TOK822_STARTGRP 261 /* start of named group */ -#define TOK822_COMMENT_TEXT 262 /* comment text */ -#define TOK822_MAXTOK 262 +#define TOK822_MAXTOK 261 /* * tok822_node.c diff --git a/gnu/dist/postfix/src/global/tok822_node.c b/gnu/dist/postfix/src/global/tok822_node.c index 797deb3424e..d39bf15b94f 100644 --- a/gnu/dist/postfix/src/global/tok822_node.c +++ b/gnu/dist/postfix/src/global/tok822_node.c @@ -57,7 +57,7 @@ TOK822 *tok822_alloc(int type, const char *strval) TOK822 *tp; #define CONTAINER_TOKEN(x) \ - ((x) == TOK822_ADDR || (x) == TOK822_COMMENT || (x) == TOK822_STARTGRP) + ((x) == TOK822_ADDR || (x) == TOK822_STARTGRP) tp = (TOK822 *) mymalloc(sizeof(*tp)); tp->type = type; diff --git a/gnu/dist/postfix/src/global/tok822_parse.ref b/gnu/dist/postfix/src/global/tok822_parse.ref index dc35bff57b7..169957ac40e 100644 --- a/gnu/dist/postfix/src/global/tok822_parse.ref +++ b/gnu/dist/postfix/src/global/tok822_parse.ref @@ -86,8 +86,7 @@ Parse tree: OP "," address atom "venema" - comment - text ""wietse " + comment "("wietse )" OP "," address quoted string ")" @@ -135,11 +134,7 @@ Parse tree: OP "." atom "org" OP ")" - comment - text " " - comment - text ""wietse " - text " venema"" + comment "( ("wietse ) venema")" Internalized: wietse venema@porcupine.org) ( ("wietse ) venema") @@ -272,9 +267,8 @@ Parse tree: atom "wietse" OP "@" atom "foo" - comment - text "wietse - venema" + comment "(wietse + venema)" Internalized: wietse@foo (wietse diff --git a/gnu/dist/postfix/src/global/verp_sender.c b/gnu/dist/postfix/src/global/verp_sender.c new file mode 100644 index 00000000000..b7c0f806e06 --- /dev/null +++ b/gnu/dist/postfix/src/global/verp_sender.c @@ -0,0 +1,106 @@ +/*++ +/* NAME +/* verp_sender 3 +/* SUMMARY +/* quote local part of mailbox +/* SYNOPSIS +/* #include <verp_sender.h> +/* +/* VSTRING *verp_sender(dst, delims, sender, recipient) +/* VSTRING *dst; +/* const char *delims; +/* const char *sender; +/* const char *recipient; +/* +/* const char *verp_delims_verify(delims) +/* const char *delims; +/* DESCRIPTION +/* verp_sender() encodes the recipient address in the sender +/* address, using the specified delimiters. For example, +/* with delims +=, sender \fIprefix@origin\fR, and +/* recipient \fIuser@domain\fR the result is +/* \fIprefix+user=domain@origin\fR. +/* +/* verp_delims_verify() determines if the specified VERP delimiters +/* have reasonable values. What is reasonable is configured with +/* the verp_delimiter_filter configuration parameter. The result +/* is null in case of success, a description of the problem in +/* case of error. +/* +/* Arguments: +/* .IP dst +/* The result. The buffer is null terminated. +/* .IP delims +/* VERP formatting characters. +/* .IP sender +/* Sender envelope address. +/* .IP recipient +/* Recipient envelope address. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <string.h> + +/* Utility library. */ + +#include <vstring.h> + +/* Global library. */ + +#include <mail_params.h> +#include <verp_sender.h> + +/* verp_sender - encode recipient into envelope sender address */ + +VSTRING *verp_sender(VSTRING *buf, const char *delimiters, + const char *sender, const char *recipient) +{ + int send_local_len; + int rcpt_local_len; + const char *cp; + + /* + * Change prefix@origin into prefix+user=domain@origin. + */ + send_local_len = ((cp = strrchr(sender, '@')) ? + cp - sender : strlen(sender)); + rcpt_local_len = ((cp = strrchr(recipient, '@')) ? + cp - recipient : strlen(recipient)); + vstring_strncpy(buf, sender, send_local_len); + VSTRING_ADDCH(buf, delimiters[0] & 0xff); + vstring_strncat(buf, recipient, rcpt_local_len); + if (recipient[rcpt_local_len] && recipient[rcpt_local_len + 1]) { + VSTRING_ADDCH(buf, delimiters[1] & 0xff); + vstring_strcat(buf, recipient + rcpt_local_len + 1); + } + if (sender[send_local_len] && sender[send_local_len + 1]) { + VSTRING_ADDCH(buf, '@'); + vstring_strcat(buf, sender + send_local_len + 1); + } + VSTRING_TERMINATE(buf); + return (buf); +} + +/* verp_delims_verify - sanitize VERP delimiters */ + +const char *verp_delims_verify(const char *delims) +{ + if (strlen(delims) != 2) + return ("bad VERP delimiter character count"); + if (strchr(var_verp_filter, delims[0]) == 0) + return ("bad first VERP delimiter character"); + if (strchr(var_verp_filter, delims[1]) == 0) + return ("bad second VERP delimiter character"); + return (0); +} diff --git a/gnu/dist/postfix/src/global/verp_sender.h b/gnu/dist/postfix/src/global/verp_sender.h new file mode 100644 index 00000000000..61641ac8a14 --- /dev/null +++ b/gnu/dist/postfix/src/global/verp_sender.h @@ -0,0 +1,36 @@ +#ifndef _VERP_SENDER_H_INCLUDED_ +#define _VERP_SENDER_H_INCLUDED_ + +/*++ +/* NAME +/* verp_sender 3h +/* SUMMARY +/* encode recipient into sender, VERP style +/* SYNOPSIS +/* #include "verp_sender.h" +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include <vstring.h> + + /* + * External interface. + */ +extern VSTRING *verp_sender(VSTRING *, const char *, const char *, const char *); +extern const char *verp_delims_verify(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 diff --git a/gnu/dist/postfix/src/lmtp/Makefile.in b/gnu/dist/postfix/src/lmtp/Makefile.in index 9821cf6af48..cb8f5637fd9 100644 --- a/gnu/dist/postfix/src/lmtp/Makefile.in +++ b/gnu/dist/postfix/src/lmtp/Makefile.in @@ -132,6 +132,7 @@ lmtp_connect.o: ../../include/timed_connect.h lmtp_connect.o: ../../include/stringops.h lmtp_connect.o: ../../include/mail_params.h lmtp_connect.o: ../../include/mail_proto.h +lmtp_connect.o: ../../include/attr.h lmtp_connect.o: ../../include/dns.h lmtp_connect.o: lmtp.h lmtp_connect.o: ../../include/argv.h @@ -175,6 +176,8 @@ lmtp_sasl_glue.o: ../../include/split_at.h 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 diff --git a/gnu/dist/postfix/src/lmtp/lmtp.c b/gnu/dist/postfix/src/lmtp/lmtp.c index 8a1560c5350..17a5e9c598d 100644 --- a/gnu/dist/postfix/src/lmtp/lmtp.c +++ b/gnu/dist/postfix/src/lmtp/lmtp.c @@ -50,6 +50,7 @@ /* RFC 2033 (LMTP protocol) /* RFC 2197 (Pipelining) /* RFC 2554 (AUTH command) +/* RFC 2821 (SMTP protocol) /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* Corrupted message files are marked so that the queue manager can @@ -87,7 +88,7 @@ /* The TCP port to be used when connecting to a LMTP server. Used as /* backup if the \fBlmtp\fR service is not found in \fBservices\fR(4). /* .SH "Authentication controls" -/* .IP \fBlmtp_enable_sasl_auth\fR +/* .IP \fBlmtp_sasl_auth_enable\fR /* Enable per-session authentication as per RFC 2554 (SASL). /* By default, Postfix is built without SASL support. /* .IP \fBlmtp_sasl_password_maps\fR @@ -226,8 +227,6 @@ #include <string.h> #include <fcntl.h> #include <dict.h> -#include <pwd.h> -#include <grp.h> /* Utility library. */ @@ -269,8 +268,6 @@ int var_lmtp_data0_tmout; int var_lmtp_data1_tmout; int var_lmtp_data2_tmout; int var_lmtp_quit_tmout; -char *var_debug_peer_list; -int var_debug_peer_level; int var_lmtp_cache_conn; int var_lmtp_skip_quit_resp; char *var_notify_classes; @@ -512,7 +509,6 @@ static void pre_accept(char *unused_name, char **unused_argv) int main(int argc, char **argv) { static CONFIG_STR_TABLE str_table[] = { - VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0, VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0, VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0, VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0, @@ -521,7 +517,6 @@ int main(int argc, char **argv) }; static CONFIG_INT_TABLE int_table[] = { VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0, - VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0, 0, }; static CONFIG_TIME_TABLE time_table[] = { diff --git a/gnu/dist/postfix/src/lmtp/lmtp.h b/gnu/dist/postfix/src/lmtp/lmtp.h index 9574b648ac0..419cb38d5b0 100644 --- a/gnu/dist/postfix/src/lmtp/lmtp.h +++ b/gnu/dist/postfix/src/lmtp/lmtp.h @@ -61,7 +61,7 @@ typedef struct LMTP_STATE { #define LMTP_FEATURE_8BITMIME (1<<1) #define LMTP_FEATURE_PIPELINING (1<<2) #define LMTP_FEATURE_SIZE (1<<3) -#define SMTP_FEATURE_AUTH (1<<5) +#define LMTP_FEATURE_AUTH (1<<5) /* * lmtp.c diff --git a/gnu/dist/postfix/src/lmtp/lmtp_chat.c b/gnu/dist/postfix/src/lmtp/lmtp_chat.c index 19b37cc03c4..40f5947165a 100644 --- a/gnu/dist/postfix/src/lmtp/lmtp_chat.c +++ b/gnu/dist/postfix/src/lmtp/lmtp_chat.c @@ -268,7 +268,7 @@ void lmtp_chat_notify(LMTP_STATE *state) notice = post_mail_fopen_nowait(mail_addr_double_bounce(), var_error_rcpt, - NULL_CLEANUP_FLAGS, "NOTICE"); + NULL_CLEANUP_FLAGS); if (notice == 0) { msg_warn("postmaster notify: %m"); return; diff --git a/gnu/dist/postfix/src/lmtp/lmtp_proto.c b/gnu/dist/postfix/src/lmtp/lmtp_proto.c index 1c970dad728..7cf98f77cc6 100644 --- a/gnu/dist/postfix/src/lmtp/lmtp_proto.c +++ b/gnu/dist/postfix/src/lmtp/lmtp_proto.c @@ -218,7 +218,7 @@ int lmtp_lhlo(LMTP_STATE *state) lines = resp->str; (void) mystrtok(&lines, "\n"); while ((words = mystrtok(&lines, "\n")) != 0) { - if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) { + if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) { if (strcasecmp(word, "8BITMIME") == 0) state->features |= LMTP_FEATURE_8BITMIME; else if (strcasecmp(word, "PIPELINING") == 0) @@ -235,7 +235,7 @@ int lmtp_lhlo(LMTP_STATE *state) msg_info("server features: 0x%x", state->features); #ifdef USE_SASL_AUTH - if (var_lmtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH)) + if (var_lmtp_sasl_enable && (state->features & LMTP_FEATURE_AUTH)) return (lmtp_sasl_helo_login(state)); #endif @@ -489,9 +489,19 @@ static int lmtp_loop(LMTP_STATE *state, int send_state, int recv_state) * rejected, ignore RCPT TO responses: all recipients are * dead already. When all recipients are rejected the * receiver may apply a course correction. + * + * XXX 2821: Section 4.5.3.1 says that a 552 RCPT TO reply + * must be treated as if the server replied with 452. + * However, this causes "too much mail data" to be + * treated as a recoverable error, which is wrong. I'll + * stick with RFC 821. */ case LMTP_STATE_RCPT: if (!mail_from_rejected) { +#ifdef notdef + if (resp->code == 552) + resp->code = 452; +#endif rcpt = request->rcpt_list.info + recv_rcpt; if (resp->code / 100 == 2) { if (survivors == 0) diff --git a/gnu/dist/postfix/src/lmtp/lmtp_sasl_proto.c b/gnu/dist/postfix/src/lmtp/lmtp_sasl_proto.c index 8eaeafd1489..b8c280c019c 100644 --- a/gnu/dist/postfix/src/lmtp/lmtp_sasl_proto.c +++ b/gnu/dist/postfix/src/lmtp/lmtp_sasl_proto.c @@ -14,14 +14,14 @@ /* LMTP_STATE *state; /* DESCRIPTION /* This module contains random chunks of code that implement -/* the SMTP protocol interface for SASL negotiation. The goal +/* the LMTP protocol interface for SASL negotiation. The goal /* is to reduce clutter in the main LMTP client source code. /* /* lmtp_sasl_helo_auth() processes the AUTH option in the -/* SMTP server's EHLO response. +/* LMTP server's LHLO response. /* /* lmtp_sasl_helo_login() authenticates the LMTP client to the -/* SMTP server, using the authentication mechanism information +/* LMTP server, using the authentication mechanism information /* given by the server. The result is a Postfix delivery status /* code in case of trouble. /* @@ -52,6 +52,10 @@ /* System library. */ #include <sys_defs.h> +#include <string.h> +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif /* Utility library. */ @@ -79,15 +83,17 @@ void lmtp_sasl_helo_auth(LMTP_STATE *state, const char *words) * then pretend that the server doesn't support SASL authentication. */ if (state->sasl_mechanism_list) { + if (strcasecmp(state->sasl_mechanism_list, words) == 0) + return; myfree(state->sasl_mechanism_list); msg_warn("%s offered AUTH option multiple times", state->session->namaddr); state->sasl_mechanism_list = 0; - state->features &= ~SMTP_FEATURE_AUTH; + state->features &= ~LMTP_FEATURE_AUTH; } if (strlen(words) > 0) { state->sasl_mechanism_list = mystrdup(words); - state->features |= SMTP_FEATURE_AUTH; + state->features |= LMTP_FEATURE_AUTH; } else { msg_warn("%s offered null AUTH mechanism list", state->session->namaddr); diff --git a/gnu/dist/postfix/src/local/Makefile.in b/gnu/dist/postfix/src/local/Makefile.in index ff36cf9bf65..fc6a4ae2d76 100644 --- a/gnu/dist/postfix/src/local/Makefile.in +++ b/gnu/dist/postfix/src/local/Makefile.in @@ -213,6 +213,7 @@ forward.o: ../../include/vstring_vstream.h forward.o: ../../include/iostuff.h forward.o: ../../include/stringops.h forward.o: ../../include/mail_proto.h +forward.o: ../../include/attr.h forward.o: ../../include/cleanup_user.h forward.o: ../../include/sent.h forward.o: ../../include/record.h @@ -334,13 +335,16 @@ mailbox.o: ../../include/deliver_request.h mailbox.o: ../../include/recipient_list.h mailbox.o: ../../include/mail_proto.h mailbox.o: ../../include/iostuff.h +mailbox.o: ../../include/attr.h mailbox.o: ../../include/mbox_open.h mailbox.o: ../../include/safe_open.h +mailbox.o: ../../include/maps.h +mailbox.o: ../../include/dict.h +mailbox.o: ../../include/argv.h mailbox.o: local.h mailbox.o: ../../include/tok822.h mailbox.o: ../../include/resolve_clnt.h mailbox.o: ../../include/mbox_conf.h -mailbox.o: ../../include/argv.h mailbox.o: biff_notify.h maildir.o: maildir.c maildir.o: ../../include/sys_defs.h @@ -403,6 +407,7 @@ resolve.o: ../../include/htable.h resolve.o: ../../include/mail_proto.h resolve.o: ../../include/vstream.h resolve.o: ../../include/iostuff.h +resolve.o: ../../include/attr.h resolve.o: ../../include/resolve_clnt.h resolve.o: ../../include/rewrite_clnt.h resolve.o: ../../include/tok822.h @@ -446,6 +451,7 @@ unknown.o: ../../include/mail_params.h unknown.o: ../../include/mail_proto.h unknown.o: ../../include/vstream.h unknown.o: ../../include/iostuff.h +unknown.o: ../../include/attr.h unknown.o: ../../include/bounce.h unknown.o: local.h unknown.o: ../../include/htable.h diff --git a/gnu/dist/postfix/src/local/alias.c b/gnu/dist/postfix/src/local/alias.c index 69e0b4e7991..fe1eb46fd7d 100644 --- a/gnu/dist/postfix/src/local/alias.c +++ b/gnu/dist/postfix/src/local/alias.c @@ -135,7 +135,8 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, struct mypasswd *alias_pwd; VSTRING *canon_owner; DICT *dict; - const char *owner_rhs; /* owner alias, RHS */ + const char *owner_rhs; /* owner alias, RHS */ + int alias_count; /* * Make verbose logging easier to understand. @@ -171,7 +172,7 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, if (state.level > 100) { msg_warn("possible alias database loop for %s", name); *statusp = bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), - "possible alias database loop for %s", name); + "possible alias database loop for %s", name); return (YES); } state.msg_attr.exp_from = name; @@ -271,11 +272,19 @@ int deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr, /* * Deliver. */ + alias_count = 0; *statusp = (dict_errno ? defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), "alias database unavailable") : - deliver_token_string(state, usr_attr, expansion, (int *) 0)); + deliver_token_string(state, usr_attr, expansion, &alias_count)); +#if 0 + if (var_ownreq_special + && strncmp("owner-", state.msg_attr.sender, 6) != 0 + && alias_count > 10) + msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias", + name, name); +#endif myfree(expansion); if (owner) myfree(owner); diff --git a/gnu/dist/postfix/src/local/command.c b/gnu/dist/postfix/src/local/command.c index 23fffdf2ff3..8a86ac63a05 100644 --- a/gnu/dist/postfix/src/local/command.c +++ b/gnu/dist/postfix/src/local/command.c @@ -9,7 +9,7 @@ /* int deliver_command(state, usr_attr, command) /* LOCAL_STATE state; /* USER_ATTR exp_attr; -/* char *command; +/* const char *command; /* DESCRIPTION /* deliver_command() runs a command with a message as standard /* input. A limited amount of standard output and standard error @@ -79,7 +79,7 @@ /* deliver_command - deliver to shell command */ -int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command) +int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, const char *command) { char *myname = "deliver_command"; VSTRING *why; @@ -107,16 +107,6 @@ int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command) return (0); /* - * DELIVERY POLICY - * - * Do we permit mail to shell commands? Allow delivery via mailbox_command. - */ - if (command != var_mailbox_command - && (local_cmd_deliver_mask & state.msg_attr.exp_type) == 0) - return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), - "mail to command is restricted")); - - /* * DELIVERY RIGHTS * * Choose a default uid and gid when none have been selected (i.e. values @@ -205,6 +195,9 @@ int deliver_command(LOCAL_STATE state, USER_ATTR usr_attr, char *command) BOUNCE_ATTR(state.msg_attr), "%s", vstring_str(why)); break; + case PIPE_STAT_CORRUPT: + deliver_status = DEL_STAT_DEFER; + break; default: msg_panic("%s: bad status %d", myname, cmd_status); /* NOTREACHED */ diff --git a/gnu/dist/postfix/src/local/file.c b/gnu/dist/postfix/src/local/file.c index e3a530ba8a1..96663d3c41e 100644 --- a/gnu/dist/postfix/src/local/file.c +++ b/gnu/dist/postfix/src/local/file.c @@ -86,7 +86,8 @@ int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path) struct stat st; MBOX *mp; VSTRING *why; - int status = -1; + int mail_copy_status = MAIL_COPY_STAT_WRITE; + int deliver_status; int copy_flags; /* @@ -157,10 +158,10 @@ int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path) vstring_sprintf(why, "destination file is executable"); errno = 0; } else { - status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, - S_ISREG(st.st_mode) ? copy_flags : - (copy_flags & ~MAIL_COPY_TOFILE), - "\n", why); + mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, + S_ISREG(st.st_mode) ? copy_flags : + (copy_flags & ~MAIL_COPY_TOFILE), + "\n", why); } mbox_release(mp); } @@ -169,19 +170,21 @@ int deliver_file(LOCAL_STATE state, USER_ATTR usr_attr, char *path) /* * As the mail system, bounce, defer delivery, or report success. */ - if (status != 0) { - status = (errno == EAGAIN || errno == ENOSPC ? - defer_append : bounce_append) + if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { + deliver_status = DEL_STAT_DEFER; + } else if (mail_copy_status != 0) { + deliver_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", path, STR(why)); } else { - sent(SENT_ATTR(state.msg_attr), "%s", path); + deliver_status = sent(SENT_ATTR(state.msg_attr), "%s", path); } /* * Clean up. */ vstring_free(why); - return (status); + return (deliver_status); } diff --git a/gnu/dist/postfix/src/local/forward.c b/gnu/dist/postfix/src/local/forward.c index 91f239348d6..5efbf181341 100644 --- a/gnu/dist/postfix/src/local/forward.c +++ b/gnu/dist/postfix/src/local/forward.c @@ -120,12 +120,18 @@ static FORWARD_INFO *forward_open(char *sender) * Contact the cleanup service and save the new mail queue id. Request * that the cleanup service bounces bad messages to the sender so that we * can avoid the trouble of bounce management. + * + * In case you wonder what kind of bounces, examples are "too many hops", + * "message too large", perhaps some others. The reason not to bounce + * ourselves is that we don't really know who the recipients are. */ - cleanup = mail_connect(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP, BLOCKING); + cleanup = mail_connect(MAIL_CLASS_PUBLIC, MAIL_SERVICE_CLEANUP, BLOCKING); if (cleanup == 0) return (0); close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC); - if (mail_scan(cleanup, "%s", buffer) != 1) { + if (attr_scan(cleanup, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, buffer, + ATTR_TYPE_END) != 1) { vstream_fclose(cleanup); return (0); } @@ -133,7 +139,9 @@ static FORWARD_INFO *forward_open(char *sender) info->cleanup = cleanup; info->queue_id = mystrdup(vstring_str(buffer)); info->posting_time = time((time_t *) 0); - mail_print(cleanup, "%d", CLEANUP_FLAG_BOUNCE); + attr_print(cleanup, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, CLEANUP_FLAG_BOUNCE, + ATTR_TYPE_END); /* * Send initial message envelope information. For bounces, set the @@ -233,7 +241,9 @@ static int forward_send(FORWARD_INFO *info, DELIVER_ATTR attr, char *delivered) */ if (status == 0) if (vstream_fflush(info->cleanup) - || mail_scan(info->cleanup, "%d", &status) != 1) + || attr_scan(info->cleanup, ATTR_FLAG_MISSING, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1) status = 1; /* diff --git a/gnu/dist/postfix/src/local/local.c b/gnu/dist/postfix/src/local/local.c index 931b2c98f3d..dc13ca16677 100644 --- a/gnu/dist/postfix/src/local/local.c +++ b/gnu/dist/postfix/src/local/local.c @@ -84,7 +84,8 @@ /* The default per-user mailbox is a file in the UNIX mail spool /* directory (\fB/var/mail/\fIuser\fR or \fB/var/spool/mail/\fIuser\fR); /* the location can be specified with the \fBmail_spool_directory\fR -/* configuration parameter. +/* configuration parameter. Specify a name ending in \fB/\fR for +/* \fBqmail\fR-compatible \fBmaildir\fR delivery. /* /* Alternatively, the per-user mailbox can be a file in the user's home /* directory with a name specified via the \fBhome_mailbox\fR @@ -177,13 +178,16 @@ /* EXTERNAL FILE DELIVERY /* .ad /* .fi +/* The delivery format depends on the destination filename syntax. +/* The default is to use UNIX-style mailbox format. Specify a name +/* ending in \fB/\fR for \fBqmail\fR-compatible \fBmaildir\fR delivery. +/* /* The \fBallow_mail_to_files\fR configuration parameter restricts /* delivery to external files. The default setting (\fBalias, /* forward\fR) forbids file destinations in \fB:include:\fR files. -/* Specify a pathname ending in \fB/\fR for \fBqmail\fR-compatible -/* \fBmaildir\fR delivery. /* -/* The \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR" +/* In the case of UNIX-style mailbox delivery, +/* the \fBlocal\fR daemon prepends a "\fBFrom \fIsender time_stamp\fR" /* envelope header to each message, prepends an /* optional \fBDelivered-To:\fR /* header with the recipient envelope address, prepends a \fB>\fR @@ -303,10 +307,14 @@ /* .IP \fBmail_spool_directory\fR /* Directory with UNIX-style mailboxes. The default pathname is system /* dependent. +/* Specify a path ending in \fB/\fR for maildir-style delivery. /* .IP \fBmailbox_command\fR /* External command to use for mailbox delivery. The command executes /* with the recipient privileges (exception: root). The string is subject /* to $name expansions. +/* .IP \fBmailbox_command_maps\fR +/* Lookup tables with per-recipient external commands to use for mailbox +/* delivery. Behavior is as with \fBmailbox_command\fR. /* .IP \fBmailbox_transport\fR /* Message transport to use for mailbox delivery to all local /* recipients, whether or not they are found in the UNIX passwd database. @@ -446,6 +454,7 @@ int var_dup_filter_limit; int var_command_maxtime; char *var_home_mailbox; char *var_mailbox_command; +char *var_mailbox_cmd_maps; char *var_rcpt_fdelim; char *var_local_cmd_shell; char *var_luser_relay; @@ -695,6 +704,7 @@ int main(int argc, char **argv) static CONFIG_RAW_TABLE raw_table[] = { VAR_FORWARD_PATH, DEF_FORWARD_PATH, &var_forward_path, 0, 0, VAR_MAILBOX_COMMAND, DEF_MAILBOX_COMMAND, &var_mailbox_command, 0, 0, + VAR_MAILBOX_CMD_MAPS, DEF_MAILBOX_CMD_MAPS, &var_mailbox_cmd_maps, 0, 0, VAR_LUSER_RELAY, DEF_LUSER_RELAY, &var_luser_relay, 0, 0, 0, }; diff --git a/gnu/dist/postfix/src/local/local.h b/gnu/dist/postfix/src/local/local.h index 4843179e0d5..302ea541973 100644 --- a/gnu/dist/postfix/src/local/local.h +++ b/gnu/dist/postfix/src/local/local.h @@ -152,7 +152,7 @@ extern int deliver_resolve_addr(LOCAL_STATE, USER_ATTR, char *); * "leaf" nodes of the delivery graph. */ extern int deliver_mailbox(LOCAL_STATE, USER_ATTR, int *); -extern int deliver_command(LOCAL_STATE, USER_ATTR, char *); +extern int deliver_command(LOCAL_STATE, USER_ATTR, const char *); extern int deliver_file(LOCAL_STATE, USER_ATTR, char *); extern int deliver_indirect(LOCAL_STATE); extern int deliver_maildir(LOCAL_STATE, USER_ATTR, char *); diff --git a/gnu/dist/postfix/src/local/mailbox.c b/gnu/dist/postfix/src/local/mailbox.c index 854590c111a..45d24d8d234 100644 --- a/gnu/dist/postfix/src/local/mailbox.c +++ b/gnu/dist/postfix/src/local/mailbox.c @@ -72,6 +72,7 @@ #include <mail_params.h> #include <deliver_pass.h> #include <mbox_open.h> +#include <maps.h> #ifndef EDQUOT #define EDQUOT EFBIG @@ -94,7 +95,8 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) char *mailbox; VSTRING *why; MBOX *mp; - int status; + int mail_copy_status; + int deliver_status; int copy_flags; VSTRING *biff; long end; @@ -118,7 +120,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); state.msg_attr.delivered = state.msg_attr.recipient; - status = -1; + mail_copy_status = MAIL_COPY_STAT_WRITE; why = vstring_alloc(100); if (*var_home_mailbox) { spool_dir = 0; @@ -189,8 +191,8 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) errno = 0; } else { end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END); - status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, - copy_flags, "\n", why); + mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, + copy_flags, "\n", why); } if (spool_uid != usr_attr.uid || spool_gid != usr_attr.gid) set_eugid(spool_uid, spool_gid); @@ -201,14 +203,16 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) /* * As the mail system, bounce, defer delivery, or report success. */ - if (status != 0) { - status = (errno == EAGAIN || errno == ENOSPC ? - defer_append : bounce_append) + if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { + deliver_status = DEL_STAT_DEFER; + } else if (mail_copy_status != 0) { + deliver_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", mailbox, state.msg_attr.user, vstring_str(why)); } else { - sent(SENT_ATTR(state.msg_attr), "mailbox"); + deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox"); if (var_biff) { biff = vstring_alloc(100); vstring_sprintf(biff, "%s@%ld", usr_attr.logname, (long) end); @@ -222,7 +226,7 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) */ myfree(mailbox); vstring_free(why); - return (status); + return (deliver_status); } /* deliver_mailbox - deliver to recipient mailbox */ @@ -233,6 +237,8 @@ int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp) int status; struct mypasswd *mbox_pwd; char *path; + static MAPS *cmd_maps; + const char *map_command; /* * Make verbose logging easier to understand. @@ -276,16 +282,29 @@ int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp) SET_USER_ATTR(usr_attr, mbox_pwd, state.level); /* - * Deliver to mailbox or to external command. + * Deliver to mailbox, maildir or to external command. */ #define LAST_CHAR(s) (s[strlen(s) - 1]) - if (*var_mailbox_command) + 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) == '/') { + } else if (*var_home_mailbox && LAST_CHAR(var_home_mailbox) == '/') { path = concatenate(usr_attr.home, "/", var_home_mailbox, (char *) 0); status = deliver_maildir(state, usr_attr, path); myfree(path); + } else if (*var_mail_spool_dir && LAST_CHAR(var_mail_spool_dir) == '/') { + path = concatenate(var_mail_spool_dir, state.msg_attr.user, + "/", (char *) 0); + status = deliver_maildir(state, usr_attr, path); + myfree(path); } else status = deliver_mailbox_file(state, usr_attr); diff --git a/gnu/dist/postfix/src/local/maildir.c b/gnu/dist/postfix/src/local/maildir.c index e9bd0de85c7..b2ccef3cea5 100644 --- a/gnu/dist/postfix/src/local/maildir.c +++ b/gnu/dist/postfix/src/local/maildir.c @@ -80,7 +80,8 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path) VSTRING *why; VSTRING *buf; VSTREAM *dst; - int status; + int mail_copy_status; + int deliver_status; int copy_flags; static int count; @@ -98,7 +99,7 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path) if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); state.msg_attr.delivered = state.msg_attr.recipient; - status = -1; + mail_copy_status = MAIL_COPY_STAT_WRITE; buf = vstring_alloc(100); why = vstring_alloc(100); @@ -137,14 +138,14 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path) || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) { vstring_sprintf(why, "create %s: %m", tmpfile); } else { - if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why) == 0) { + if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), + dst, copy_flags, "\n", why)) == 0) { if (sane_link(tmpfile, newfile) < 0 && (errno != ENOENT || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0 || sane_link(tmpfile, newfile) < 0)) { vstring_sprintf(why, "link to %s: %m", newfile); - } else { - status = 0; + mail_copy_status = MAIL_COPY_STAT_WRITE; } } if (unlink(tmpfile) < 0) @@ -152,12 +153,19 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path) } set_eugid(var_owner_uid, var_owner_gid); - if (status) - status = (errno == ENOSPC ? defer_append : bounce_append) + /* + * As the mail system, bounce or defer delivery. + */ + if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { + deliver_status = DEL_STAT_DEFER; + } else if (mail_copy_status != 0) { + deliver_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 - status = sent(SENT_ATTR(state.msg_attr), "maildir"); + } else { + deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir"); + } vstring_free(buf); vstring_free(why); myfree(newdir); @@ -165,5 +173,5 @@ int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr, char *path) myfree(curdir); myfree(tmpfile); myfree(newfile); - return (status); + return (deliver_status); } diff --git a/gnu/dist/postfix/src/local/token.c b/gnu/dist/postfix/src/local/token.c index 28803fe4c6c..c427eb7042c 100644 --- a/gnu/dist/postfix/src/local/token.c +++ b/gnu/dist/postfix/src/local/token.c @@ -148,7 +148,12 @@ int deliver_token(LOCAL_STATE state, USER_ATTR usr_attr, TOK822 *addr) } else if (*STR(addr_buf) == '~') { status = deliver_token_home(state, usr_attr, STR(addr_buf)); } else if (*STR(addr_buf) == '|') { - status = deliver_command(state, usr_attr, STR(addr_buf) + 1); + if ((local_cmd_deliver_mask & state.msg_attr.exp_type) == 0) + status = bounce_append(BOUNCE_FLAG_KEEP, + BOUNCE_ATTR(state.msg_attr), + "mail to command is restricted"); + else + status = deliver_command(state, usr_attr, STR(addr_buf) + 1); } else if (strncasecmp(STR(addr_buf), include, sizeof(include) - 1) == 0) { path = STR(addr_buf) + sizeof(include) - 1; status = deliver_include(state, usr_attr, path); diff --git a/gnu/dist/postfix/src/master/Makefile.in b/gnu/dist/postfix/src/master/Makefile.in index 47f3369af07..cbb2894bf3f 100644 --- a/gnu/dist/postfix/src/master/Makefile.in +++ b/gnu/dist/postfix/src/master/Makefile.in @@ -2,12 +2,13 @@ SHELL = /bin/sh SRCS = master.c master_conf.c master_ent.c master_sig.c master_avail.c \ master_spawn.c master_service.c master_status.o master_listen.c \ master_proto.c single_server.c multi_server.c master_vars.c \ - master_wakeup.c + master_wakeup.c master_flow.c mail_flow.c OBJS = master.o master_conf.o master_ent.o master_sig.o master_avail.o \ master_spawn.o master_service.o master_status.o master_listen.o \ - master_vars.o master_wakeup.o -LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o -HDRS = mail_server.h master_proto.h + master_vars.o master_wakeup.o master_flow.o +LIB_OBJ = single_server.o multi_server.o trigger_server.o master_proto.o \ + mail_flow.o +HDRS = mail_server.h master_proto.h mail_flow.h INT_HDR = master.h WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ @@ -78,6 +79,12 @@ depend: $(MAKES) @$(EXPORT) make -f Makefile.in Makefile 1>&2 # do not edit below this line - it is generated by 'make depend' +mail_flow.o: mail_flow.c +mail_flow.o: ../../include/sys_defs.h +mail_flow.o: ../../include/msg.h +mail_flow.o: ../../include/iostuff.h +mail_flow.o: mail_flow.h +mail_flow.o: master_proto.h master.o: master.c master.o: ../../include/sys_defs.h master.o: ../../include/events.h @@ -93,6 +100,7 @@ master.o: ../../include/myflock.h master.o: ../../include/watchdog.h master.o: ../../include/clean_env.h master.o: ../../include/argv.h +master.o: ../../include/safe.h master.o: ../../include/mail_params.h master.o: ../../include/debug_process.h master.o: ../../include/mail_task.h @@ -125,10 +133,17 @@ master_ent.o: ../../include/inet_util.h master_ent.o: ../../include/inet_addr_host.h master_ent.o: ../../include/mail_proto.h master_ent.o: ../../include/iostuff.h +master_ent.o: ../../include/attr.h master_ent.o: ../../include/mail_params.h master_ent.o: ../../include/own_inet_addr.h master_ent.o: master_proto.h master_ent.o: master.h +master_flow.o: master_flow.c +master_flow.o: ../../include/sys_defs.h +master_flow.o: ../../include/msg.h +master_flow.o: ../../include/iostuff.h +master_flow.o: master.h +master_flow.o: master_proto.h master_listen.o: master_listen.c master_listen.o: ../../include/sys_defs.h master_listen.o: ../../include/msg.h @@ -140,6 +155,7 @@ master_listen.o: ../../include/vstring.h master_listen.o: ../../include/vbuf.h master_listen.o: ../../include/inet_addr_list.h master_listen.o: ../../include/set_eugid.h +master_listen.o: ../../include/set_ugid.h master_listen.o: ../../include/mail_params.h master_listen.o: master.h master_proto.o: master_proto.c @@ -188,10 +204,14 @@ master_wakeup.o: ../../include/sys_defs.h master_wakeup.o: ../../include/msg.h master_wakeup.o: ../../include/trigger.h master_wakeup.o: ../../include/events.h +master_wakeup.o: ../../include/set_eugid.h +master_wakeup.o: ../../include/set_ugid.h master_wakeup.o: ../../include/mail_proto.h master_wakeup.o: ../../include/vstream.h master_wakeup.o: ../../include/vbuf.h master_wakeup.o: ../../include/iostuff.h +master_wakeup.o: ../../include/attr.h +master_wakeup.o: ../../include/mail_params.h master_wakeup.o: mail_server.h master_wakeup.o: master.h multi_server.o: multi_server.c @@ -219,6 +239,7 @@ multi_server.o: ../../include/mail_params.h multi_server.o: ../../include/mail_conf.h multi_server.o: ../../include/timed_ipc.h multi_server.o: ../../include/resolve_local.h +multi_server.o: mail_flow.h multi_server.o: master_proto.h multi_server.o: mail_server.h single_server.o: single_server.c @@ -246,6 +267,7 @@ single_server.o: ../../include/debug_process.h single_server.o: ../../include/mail_conf.h single_server.o: ../../include/timed_ipc.h single_server.o: ../../include/resolve_local.h +single_server.o: mail_flow.h single_server.o: master_proto.h single_server.o: mail_server.h trigger_server.o: trigger_server.c @@ -272,5 +294,6 @@ trigger_server.o: ../../include/mail_task.h trigger_server.o: ../../include/debug_process.h trigger_server.o: ../../include/mail_conf.h trigger_server.o: ../../include/resolve_local.h +trigger_server.o: mail_flow.h trigger_server.o: master_proto.h trigger_server.o: mail_server.h diff --git a/gnu/dist/postfix/src/master/mail_flow.c b/gnu/dist/postfix/src/master/mail_flow.c new file mode 100644 index 00000000000..efb59885409 --- /dev/null +++ b/gnu/dist/postfix/src/master/mail_flow.c @@ -0,0 +1,140 @@ +/*++ +/* NAME +/* mail_flow 3 +/* SUMMARY +/* global mail flow control +/* SYNOPSIS +/* #include <mail_flow.h> +/* +/* int mail_flow_get(count) +/* int count; +/* +/* void mail_flow_put(count) +/* int count; +/* +/* int mail_flow_count() +/* DESCRIPTION +/* This module implements a simple flow control mechanism that +/* is based on tokens that are consumed by mail receiving processes +/* and that are produced by mail sending processes. +/* +/* mail_flow_get() attempts to read specified number of tokens. The +/* result is > 0 for success, < 0 for failure. In the latter case, +/* the process is expected to slow down a little. +/* +/* mail_flow_put() produces the specified number of tokens. The +/* token producing process is expected to produce new tokens +/* whenever it falls idle and no more tokens are available. +/* +/* mail_flow_count() returns the number of available tokens. +/* BUGS +/* The producer needs to wake up periodically to ensure that +/* tokens are not lost due to leakage. +/* 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/stat.h> +#include <unistd.h> +#include <stdlib.h> + +/* Utility library. */ + +#include <msg.h> +#include <iostuff.h> + +/* Global library. */ + +#include <mail_flow.h> + +/* Master library. */ + +#include <master_proto.h> + +#define BUFFER_SIZE 1024 + +/* mail_flow_get - read N tokens */ + +int mail_flow_get(int len) +{ + char *myname = "mail_flow_get"; + char buf[BUFFER_SIZE]; + struct stat st; + int count; + int n = 0; + + /* + * Sanity check. + */ + if (len <= 0) + msg_panic("%s: bad length %d", myname, len); + + /* + * Silence some wild claims. + */ + if (fstat(MASTER_FLOW_WRITE, &st) < 0) + msg_fatal("fstat flow pipe write descriptor: %m"); + + /* + * Read and discard N bytes. XXX AIX read() can return 0 when an open + * pipe is empty. + */ + for (count = len; count > 0; count -= n) + if ((n = read(MASTER_FLOW_READ, buf, count > BUFFER_SIZE ? + BUFFER_SIZE : count)) <= 0) + return (-1); + if (msg_verbose) + msg_info("%s: %d %d", myname, len, len - count); + return (len - count); +} + +/* mail_flow_put - put N tokens */ + +int mail_flow_put(int len) +{ + char *myname = "mail_flow_put"; + char buf[BUFFER_SIZE]; + int count; + int n = 0; + + /* + * Sanity check. + */ + if (len <= 0) + msg_panic("%s: bad length %d", myname, len); + + /* + * Write or discard N bytes. + */ + memset(buf, 0, len > BUFFER_SIZE ? BUFFER_SIZE : len); + + for (count = len; count > 0; count -= n) + if ((n = write(MASTER_FLOW_WRITE, buf, count > BUFFER_SIZE ? + BUFFER_SIZE : count)) < 0) + return (-1); + if (msg_verbose) + msg_info("%s: %d %d", myname, len, len - count); + return (len - count); +} + +/* mail_flow_count - return number of available tokens */ + +int mail_flow_count(void) +{ + char *myname = "mail_flow_count"; + int count; + + if ((count = peekfd(MASTER_FLOW_READ)) < 0) + msg_warn("%s: %m", myname); + return (count); +} diff --git a/gnu/dist/postfix/src/master/mail_flow.h b/gnu/dist/postfix/src/master/mail_flow.h new file mode 100644 index 00000000000..9e058598f5d --- /dev/null +++ b/gnu/dist/postfix/src/master/mail_flow.h @@ -0,0 +1,32 @@ +#ifndef _MAIL_FLOW_H_INCLUDED_ +#define _MAIL_FLOW_H_INCLUDED_ + +/*++ +/* NAME +/* mail_flow 3h +/* SUMMARY +/* global mail flow control +/* SYNOPSIS +/* #include <mail_flow.h> +/* DESCRIPTION +/* .nf + + /* + * Functional interface. + */ +extern int mail_flow_get(int); +extern int mail_flow_put(int); +extern int mail_flow_count(void); + +/* 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 diff --git a/gnu/dist/postfix/src/master/mail_server.h b/gnu/dist/postfix/src/master/mail_server.h index d03313b1ead..47b8cfeeed2 100644 --- a/gnu/dist/postfix/src/master/mail_server.h +++ b/gnu/dist/postfix/src/master/mail_server.h @@ -28,6 +28,8 @@ #define MAIL_SERVER_EXIT 13 #define MAIL_SERVER_PRE_ACCEPT 14 +#define MAIL_SERVER_IN_FLOW_DELAY 20 + typedef void (*MAIL_SERVER_INIT_FN) (char *, char **); typedef int (*MAIL_SERVER_LOOP_FN) (char *, char **); typedef void (*MAIL_SERVER_EXIT_FN) (char *, char **); diff --git a/gnu/dist/postfix/src/master/master.c b/gnu/dist/postfix/src/master/master.c index 4299424f1ce..337ba7931b5 100644 --- a/gnu/dist/postfix/src/master/master.c +++ b/gnu/dist/postfix/src/master/master.c @@ -154,6 +154,7 @@ #include <watchdog.h> #include <clean_env.h> #include <argv.h> +#include <safe.h> /* Global library. */ @@ -241,6 +242,16 @@ int main(int argc, char **argv) msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY); /* + * The mail system must be run by the superuser so it can revoke + * privileges for selected operations. That's right - it takes privileges + * to toss privileges. + */ + if (getuid() != 0) + msg_fatal("the master command is reserved for the superuser"); + if (unsafe() != 0) + msg_fatal("the master command must not run as a set-uid process"); + + /* * If started from a terminal, get rid of any tty association. This also * means that all errors and warnings must go to the syslog daemon. */ @@ -256,8 +267,11 @@ int main(int argc, char **argv) * when a service listens on many ports. In order to do this right we * must change the master-child interface so that descriptors do not need * to have fixed numbers. + * + * In a child we need two descriptors for the flow control pipe, one for + * child->master status updates and at least one for listening. */ - for (n = 0; n < 3; n++) { + for (n = 0; n < 5; n++) { if (close_on_exec(dup(0), CLOSE_ON_EXEC) < 0) msg_fatal("dup(0): %m"); } @@ -349,6 +363,7 @@ int main(int argc, char **argv) */ master_config(); master_sigsetup(); + master_flow_init(); msg_info("daemon started"); /* diff --git a/gnu/dist/postfix/src/master/master_flow.c b/gnu/dist/postfix/src/master/master_flow.c new file mode 100644 index 00000000000..ed9b492d22b --- /dev/null +++ b/gnu/dist/postfix/src/master/master_flow.c @@ -0,0 +1,33 @@ +/* System library. */ + +#include <sys_defs.h> +#include <unistd.h> +#include <stdlib.h> + +/* Utility library. */ + +#include <msg.h> +#include <iostuff.h> + +/* Application-specific. */ + +#include <master.h> +#include <master_proto.h> + +int master_flow_pipe[2]; + +/* master_flow_init - initialize the flow control channel */ + +void master_flow_init(void) +{ + char *myname = "master_flow_init"; + + if (pipe(master_flow_pipe) < 0) + msg_fatal("%s: pipe: %m", myname); + + non_blocking(master_flow_pipe[0], NON_BLOCKING); + non_blocking(master_flow_pipe[1], NON_BLOCKING); + + close_on_exec(master_flow_pipe[0], CLOSE_ON_EXEC); + close_on_exec(master_flow_pipe[1], CLOSE_ON_EXEC); +} diff --git a/gnu/dist/postfix/src/master/master_proto.h b/gnu/dist/postfix/src/master/master_proto.h index 2929ed46375..36c30f8d5bb 100644 --- a/gnu/dist/postfix/src/master/master_proto.h +++ b/gnu/dist/postfix/src/master/master_proto.h @@ -32,6 +32,14 @@ typedef struct MASTER_STATUS { extern int master_notify(int, int); /* encapsulate status msg */ /* + * File descriptors inherited from the master process. The flow control pipe + * is read by receive processes and is written to by send processes. If + * receive processes get too far ahead they will pause for a brief moment. + */ +#define MASTER_FLOW_READ 3 +#define MASTER_FLOW_WRITE 4 + + /* * File descriptors inherited from the master process. All processes that * provide a given service share the same status file descriptor, and listen * on the same service socket(s). The kernel decides what process gets the @@ -41,8 +49,8 @@ extern int master_notify(int, int); /* encapsulate status msg */ * actually the lowest-numbered descriptor of a sequence of descriptors to * listen on. */ -#define MASTER_STATUS_FD 3 /* shared channel to parent */ -#define MASTER_LISTEN_FD 4 /* accept connections here */ +#define MASTER_STATUS_FD 5 /* shared channel to parent */ +#define MASTER_LISTEN_FD 6 /* accept connections here */ /* LICENSE /* .ad diff --git a/gnu/dist/postfix/src/master/master_spawn.c b/gnu/dist/postfix/src/master/master_spawn.c index 75dcfafbeec..2eaf7bf96b3 100644 --- a/gnu/dist/postfix/src/master/master_spawn.c +++ b/gnu/dist/postfix/src/master/master_spawn.c @@ -175,6 +175,23 @@ void master_spawn(MASTER_SERV *serv) case 0: msg_cleanup((void (*) (void)) 0); /* disable exit handler */ closelog(); /* avoid filedes leak */ + + if (master_flow_pipe[0] <= MASTER_FLOW_READ) + msg_fatal("%s: flow pipe read descriptor <= %d", + myname, MASTER_FLOW_READ); + if (DUP2(master_flow_pipe[0], MASTER_FLOW_READ) < 0) + msg_fatal("%s: dup2: %m", myname); + if (close(master_flow_pipe[0]) < 0) + msg_fatal("close %d: %m", master_flow_pipe[0]); + + if (master_flow_pipe[1] <= MASTER_FLOW_WRITE) + msg_fatal("%s: flow pipe read descriptor <= %d", + myname, MASTER_FLOW_WRITE); + if (DUP2(master_flow_pipe[1], MASTER_FLOW_WRITE) < 0) + msg_fatal("%s: dup2: %m", myname); + if (close(master_flow_pipe[1]) < 0) + msg_fatal("close %d: %m", master_flow_pipe[1]); + close(serv->status_fd[0]); /* status channel */ if (serv->status_fd[1] <= MASTER_STATUS_FD) msg_fatal("%s: status file descriptor collision", myname); diff --git a/gnu/dist/postfix/src/master/master_wakeup.c b/gnu/dist/postfix/src/master/master_wakeup.c index 16cc7be5bcc..d3052e688ff 100644 --- a/gnu/dist/postfix/src/master/master_wakeup.c +++ b/gnu/dist/postfix/src/master/master_wakeup.c @@ -58,10 +58,13 @@ #include <msg.h> #include <trigger.h> #include <events.h> +#include <set_eugid.h> +#include <set_ugid.h> /* Global library. */ #include <mail_proto.h> /* triggers */ +#include <mail_params.h> /* Application-specific. */ @@ -101,8 +104,30 @@ static void master_wakeup_timer_event(int unused_event, char *context) case MASTER_SERV_TYPE_UNIX: status = LOCAL_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY); break; + + /* + * If someone compromises the postfix account then this must not + * overwrite files outside the chroot jail. Countermeasures: + * + * - Limit the damage by accessing the FIFO as postfix not root. + * + * - Have fifo_trigger() call safe_open() so we won't follow + * arbitrary hard/symlinks to files in/outside the chroot jail. + * + * - All non-chroot postfix-related files must be root owned (or + * postfix check complains). + * + * - The postfix user and group ID must not be shared with other + * applications (says the INSTALL documentation). + * + * Result of a discussion with Michael Tokarev, who received his + * insights from Solar Designer, who tested Postfix with a kernel + * module that is paranoid about open() calls. + */ case MASTER_SERV_TYPE_FIFO: + set_eugid(var_owner_uid, var_owner_gid); status = fifo_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY); + set_ugid(getuid(), getgid()); break; default: msg_panic("%s: unknown service type: %d", myname, serv->type); diff --git a/gnu/dist/postfix/src/master/multi_server.c b/gnu/dist/postfix/src/master/multi_server.c index c9df296f4f9..602db54c71a 100644 --- a/gnu/dist/postfix/src/master/multi_server.c +++ b/gnu/dist/postfix/src/master/multi_server.c @@ -95,6 +95,9 @@ /* Function to be executed prior to accepting a new connection. /* .sp /* Only the last instance of this parameter type is remembered. +/* .IP "MAIL_SERVER_IN_FLOW_DELAY (none)" +/* Pause $in_flow_delay seconds when no "mail flow control token" +/* is available. A token is consumed for each connection request. /* .PP /* multi_server_disconnect() should be called by the application /* when a client disconnects. @@ -168,6 +171,7 @@ #include <mail_conf.h> #include <timed_ipc.h> #include <resolve_local.h> +#include <mail_flow.h> /* Process manager. */ @@ -190,6 +194,7 @@ static void (*multi_server_accept) (int, char *); static void (*multi_server_onexit) (char *, char **); static void (*multi_server_pre_accept) (char *, char **); static VSTREAM *multi_server_lock; +static int multi_server_in_flow_delay; /* multi_server_exit - normal termination */ @@ -253,11 +258,21 @@ static void multi_server_execute(int unused_event, char *context) event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit); } +/* multi_server_enable_read - enable read events */ + +static void multi_server_enable_read(int unused_event, char *context) +{ + VSTREAM *stream = (VSTREAM *) context; + + event_enable_read(vstream_fileno(stream), multi_server_execute, (char *) stream); +} + /* multi_server_wakeup - wake up application */ static void multi_server_wakeup(int fd) { VSTREAM *stream; + char *tmp; if (msg_verbose) msg_info("connection established fd %d", fd); @@ -265,8 +280,15 @@ static void multi_server_wakeup(int fd) close_on_exec(fd, CLOSE_ON_EXEC); client_count++; stream = vstream_fdopen(fd, O_RDWR); + tmp = concatenate(multi_server_name, " socket", (char *) 0); + vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END); + myfree(tmp); timed_ipc_setup(stream); - event_enable_read(fd, multi_server_execute, (char *) stream); + if (multi_server_in_flow_delay && mail_flow_get(1) < 0) + event_request_timer(multi_server_enable_read, (char *) stream, + var_in_flow_delay); + else + multi_server_enable_read(0, (char *) stream); } /* multi_server_accept_local - accept client connection request */ @@ -498,6 +520,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) case MAIL_SERVER_PRE_ACCEPT: multi_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); break; + case MAIL_SERVER_IN_FLOW_DELAY: + multi_server_in_flow_delay = 1; + break; default: msg_panic("%s: unknown argument type: %d", myname, key); } @@ -611,6 +636,8 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) } event_enable_read(MASTER_STATUS_FD, multi_server_abort, (char *) 0); close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC); + close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC); + close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC); watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0); /* diff --git a/gnu/dist/postfix/src/master/single_server.c b/gnu/dist/postfix/src/master/single_server.c index 9c6920a7d73..d110e40102c 100644 --- a/gnu/dist/postfix/src/master/single_server.c +++ b/gnu/dist/postfix/src/master/single_server.c @@ -92,6 +92,9 @@ /* Function to be executed prior to accepting a new connection. /* .sp /* Only the last instance of this parameter type is remembered. +/* .IP "MAIL_SERVER_IN_FLOW_DELAY (none)" +/* Pause $in_flow_delay seconds when no "mail flow control token" +/* is available. A token is consumed for each connection request. /* .PP /* The var_use_limit variable limits the number of clients that /* a server can service before it commits suicide. @@ -162,6 +165,7 @@ #include <mail_conf.h> #include <timed_ipc.h> #include <resolve_local.h> +#include <mail_flow.h> /* Process manager. */ @@ -183,6 +187,7 @@ static void (*single_server_accept) (int, char *); static void (*single_server_onexit) (char *, char **); static void (*single_server_pre_accept) (char *, char **); static VSTREAM *single_server_lock; +static int single_server_in_flow_delay; /* single_server_exit - normal termination */ @@ -216,6 +221,7 @@ static void single_server_timeout(int unused_event, char *unused_context) static void single_server_wakeup(int fd) { VSTREAM *stream; + char *tmp; /* * If the accept() succeeds, be sure to disable non-blocking I/O, because @@ -228,9 +234,14 @@ static void single_server_wakeup(int fd) non_blocking(fd, BLOCKING); close_on_exec(fd, CLOSE_ON_EXEC); stream = vstream_fdopen(fd, O_RDWR); + tmp = concatenate(single_server_name, " socket", (char *) 0); + vstream_control(stream, VSTREAM_CTL_PATH, tmp, VSTREAM_CTL_END); + myfree(tmp); timed_ipc_setup(stream); if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0) single_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT); + if (single_server_in_flow_delay && mail_flow_get(1) < 0) + doze(var_in_flow_delay * 1000000); single_server_service(stream, single_server_name, single_server_argv); (void) vstream_fclose(stream); if (master_notify(var_pid, MASTER_STAT_AVAIL) < 0) @@ -469,6 +480,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) case MAIL_SERVER_PRE_ACCEPT: single_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); break; + case MAIL_SERVER_IN_FLOW_DELAY: + single_server_in_flow_delay = 1; + break; default: msg_panic("%s: unknown argument type: %d", myname, key); } @@ -582,6 +596,8 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) } event_enable_read(MASTER_STATUS_FD, single_server_abort, (char *) 0); close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC); + close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC); + close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC); watchdog = watchdog_create(var_daemon_timeout, (WATCHDOG_FN) 0, (char *) 0); /* diff --git a/gnu/dist/postfix/src/master/trigger_server.c b/gnu/dist/postfix/src/master/trigger_server.c index 7edd05ff6d6..c84b8a8b519 100644 --- a/gnu/dist/postfix/src/master/trigger_server.c +++ b/gnu/dist/postfix/src/master/trigger_server.c @@ -99,6 +99,9 @@ /* Function to be executed prior to accepting a new request. /* .sp /* Only the last instance of this parameter type is remembered. +/* .IP "MAIL_SERVER_IN_FLOW_DELAY (none)" +/* Pause $in_flow_delay seconds when no "mail flow control token" +/* is available. A token is consumed for each connection request. /* .PP /* The var_use_limit variable limits the number of clients that /* a server can service before it commits suicide. @@ -169,6 +172,7 @@ #include <debug_process.h> #include <mail_conf.h> #include <resolve_local.h> +#include <mail_flow.h> /* Process manager. */ @@ -190,6 +194,7 @@ static void (*trigger_server_accept) (int, char *); static void (*trigger_server_onexit) (char *, char **); static void (*trigger_server_pre_accept) (char *, char **); static VSTREAM *trigger_server_lock; +static int trigger_server_in_flow_delay; /* trigger_server_exit - normal termination */ @@ -230,6 +235,8 @@ static void trigger_server_wakeup(int fd) */ if (master_notify(var_pid, MASTER_STAT_TAKEN) < 0) trigger_server_abort(EVENT_NULL_TYPE, EVENT_NULL_CONTEXT); + if (trigger_server_in_flow_delay && mail_flow_get(1) < 0) + doze(var_in_flow_delay * 1000000); if ((len = read(fd, buf, sizeof(buf))) >= 0) trigger_server_service(buf, len, trigger_server_name, trigger_server_argv); @@ -469,6 +476,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. case MAIL_SERVER_PRE_ACCEPT: trigger_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); break; + case MAIL_SERVER_IN_FLOW_DELAY: + trigger_server_in_flow_delay = 1; + break; default: msg_panic("%s: unknown argument type: %d", myname, key); } @@ -593,6 +603,8 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. } event_enable_read(MASTER_STATUS_FD, trigger_server_abort, (char *) 0); close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC); + close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC); + close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC); watchdog = watchdog_create(1000, (WATCHDOG_FN) 0, (char *) 0); /* diff --git a/gnu/dist/postfix/src/nqmgr/.printfck b/gnu/dist/postfix/src/nqmgr/.printfck new file mode 100644 index 00000000000..66016ed453c --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/.printfck @@ -0,0 +1,25 @@ +been_here_xt 2 0 +bounce_append 5 0 +cleanup_out_format 1 0 +defer_append 5 0 +mail_command 1 0 +mail_print 1 0 +msg_error 0 0 +msg_fatal 0 0 +msg_info 0 0 +msg_panic 0 0 +msg_warn 0 0 +opened 4 0 +post_mail_fprintf 1 0 +qmgr_message_bounce 2 0 +rec_fprintf 2 0 +sent 4 0 +smtp_cmd 1 0 +smtp_mesg_fail 2 0 +smtp_printf 1 0 +smtp_rcpt_fail 3 0 +smtp_site_fail 2 0 +udp_syslog 1 0 +vstream_fprintf 1 0 +vstream_printf 0 0 +vstring_sprintf 1 0 diff --git a/gnu/dist/postfix/src/nqmgr/Makefile.in b/gnu/dist/postfix/src/nqmgr/Makefile.in new file mode 100644 index 00000000000..7396348c878 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/Makefile.in @@ -0,0 +1,296 @@ +SHELL = /bin/sh +SRCS = qmgr.c qmgr_active.c qmgr_transport.c qmgr_queue.c qmgr_entry.c \ + qmgr_message.c qmgr_deliver.c qmgr_move.c qmgr_rcpt_list.c \ + qmgr_job.c qmgr_peer.c \ + qmgr_defer.c qmgr_enable.c qmgr_scan.c qmgr_bounce.c +OBJS = qmgr.o qmgr_active.o qmgr_transport.o qmgr_queue.o qmgr_entry.o \ + qmgr_message.o qmgr_deliver.o qmgr_move.o qmgr_rcpt_list.o \ + qmgr_job.o qmgr_peer.o \ + qmgr_defer.o qmgr_enable.o qmgr_scan.o qmgr_bounce.o +HDRS = qmgr.h +TESTSRC = +WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ + -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ + -Wunused +DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) +CFLAGS = $(DEBUG) $(OPT) $(DEFS) +TESTPROG= +PROG = qmgr +INC_DIR = ../../include +LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a + +.c.o:; $(CC) $(CFLAGS) -c $*.c + +$(PROG): $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) + +Makefile: Makefile.in + (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@ + +test: $(TESTPROG) + +update: ../../libexec/n$(PROG) + +../../libexec/n$(PROG): $(PROG) + cp $(PROG) ../../libexec/n$(PROG) + +printfck: $(OBJS) $(PROG) + rm -rf printfck + mkdir printfck + cp *.h printfck + sed '1,/^# do not edit/!d' Makefile >printfck/Makefile + set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done + cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o` + +lint: + lint $(DEFS) $(SRCS) $(LINTFIX) + +clean: + rm -f *.o *core $(PROG) $(TESTPROG) junk + rm -rf printfck + +tidy: clean + +depend: $(MAKES) + (sed '1,/^# do not edit/!d' Makefile.in; \ + set -e; for i in [a-z][a-z0-9]*.c; do \ + $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ + -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \ + done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in + @$(EXPORT) make -f Makefile.in Makefile 1>&2 + +# do not edit below this line - it is generated by 'make depend' +qmgr.o: qmgr.c +qmgr.o: ../../include/sys_defs.h +qmgr.o: ../../include/msg.h +qmgr.o: ../../include/events.h +qmgr.o: ../../include/vstream.h +qmgr.o: ../../include/vbuf.h +qmgr.o: ../../include/dict.h +qmgr.o: ../../include/argv.h +qmgr.o: ../../include/mail_queue.h +qmgr.o: ../../include/vstring.h +qmgr.o: ../../include/recipient_list.h +qmgr.o: ../../include/mail_conf.h +qmgr.o: ../../include/mail_params.h +qmgr.o: ../../include/mail_proto.h +qmgr.o: ../../include/iostuff.h +qmgr.o: ../../include/attr.h +qmgr.o: ../../include/mail_flow.h +qmgr.o: ../../include/master_proto.h +qmgr.o: ../../include/mail_server.h +qmgr.o: qmgr.h +qmgr.o: ../../include/scan_dir.h +qmgr.o: ../../include/maps.h +qmgr_active.o: qmgr_active.c +qmgr_active.o: ../../include/sys_defs.h +qmgr_active.o: ../../include/msg.h +qmgr_active.o: ../../include/events.h +qmgr_active.o: ../../include/mymalloc.h +qmgr_active.o: ../../include/vstream.h +qmgr_active.o: ../../include/vbuf.h +qmgr_active.o: ../../include/mail_params.h +qmgr_active.o: ../../include/mail_open_ok.h +qmgr_active.o: ../../include/mail_queue.h +qmgr_active.o: ../../include/vstring.h +qmgr_active.o: ../../include/recipient_list.h +qmgr_active.o: ../../include/bounce.h +qmgr_active.o: ../../include/defer.h +qmgr_active.o: ../../include/abounce.h +qmgr_active.o: ../../include/rec_type.h +qmgr_active.o: qmgr.h +qmgr_active.o: ../../include/scan_dir.h +qmgr_active.o: ../../include/maps.h +qmgr_active.o: ../../include/dict.h +qmgr_active.o: ../../include/argv.h +qmgr_bounce.o: qmgr_bounce.c +qmgr_bounce.o: ../../include/sys_defs.h +qmgr_bounce.o: ../../include/bounce.h +qmgr_bounce.o: ../../include/deliver_completed.h +qmgr_bounce.o: ../../include/vstream.h +qmgr_bounce.o: ../../include/vbuf.h +qmgr_bounce.o: qmgr.h +qmgr_bounce.o: ../../include/scan_dir.h +qmgr_bounce.o: ../../include/maps.h +qmgr_bounce.o: ../../include/dict.h +qmgr_bounce.o: ../../include/argv.h +qmgr_defer.o: qmgr_defer.c +qmgr_defer.o: ../../include/sys_defs.h +qmgr_defer.o: ../../include/msg.h +qmgr_defer.o: ../../include/vstream.h +qmgr_defer.o: ../../include/vbuf.h +qmgr_defer.o: ../../include/defer.h +qmgr_defer.o: ../../include/bounce.h +qmgr_defer.o: qmgr.h +qmgr_defer.o: ../../include/scan_dir.h +qmgr_defer.o: ../../include/maps.h +qmgr_defer.o: ../../include/dict.h +qmgr_defer.o: ../../include/argv.h +qmgr_deliver.o: qmgr_deliver.c +qmgr_deliver.o: ../../include/sys_defs.h +qmgr_deliver.o: ../../include/msg.h +qmgr_deliver.o: ../../include/vstring.h +qmgr_deliver.o: ../../include/vbuf.h +qmgr_deliver.o: ../../include/vstream.h +qmgr_deliver.o: ../../include/vstring_vstream.h +qmgr_deliver.o: ../../include/events.h +qmgr_deliver.o: ../../include/iostuff.h +qmgr_deliver.o: ../../include/mail_queue.h +qmgr_deliver.o: ../../include/mail_proto.h +qmgr_deliver.o: ../../include/attr.h +qmgr_deliver.o: ../../include/recipient_list.h +qmgr_deliver.o: ../../include/mail_params.h +qmgr_deliver.o: ../../include/deliver_request.h +qmgr_deliver.o: ../../include/verp_sender.h +qmgr_deliver.o: qmgr.h +qmgr_deliver.o: ../../include/scan_dir.h +qmgr_deliver.o: ../../include/maps.h +qmgr_deliver.o: ../../include/dict.h +qmgr_deliver.o: ../../include/argv.h +qmgr_enable.o: qmgr_enable.c +qmgr_enable.o: ../../include/sys_defs.h +qmgr_enable.o: ../../include/msg.h +qmgr_enable.o: ../../include/vstream.h +qmgr_enable.o: ../../include/vbuf.h +qmgr_enable.o: qmgr.h +qmgr_enable.o: ../../include/scan_dir.h +qmgr_enable.o: ../../include/maps.h +qmgr_enable.o: ../../include/dict.h +qmgr_enable.o: ../../include/argv.h +qmgr_entry.o: qmgr_entry.c +qmgr_entry.o: ../../include/sys_defs.h +qmgr_entry.o: ../../include/msg.h +qmgr_entry.o: ../../include/mymalloc.h +qmgr_entry.o: ../../include/events.h +qmgr_entry.o: ../../include/vstream.h +qmgr_entry.o: ../../include/vbuf.h +qmgr_entry.o: ../../include/mail_params.h +qmgr_entry.o: qmgr.h +qmgr_entry.o: ../../include/scan_dir.h +qmgr_entry.o: ../../include/maps.h +qmgr_entry.o: ../../include/dict.h +qmgr_entry.o: ../../include/argv.h +qmgr_job.o: qmgr_job.c +qmgr_job.o: ../../include/sys_defs.h +qmgr_job.o: ../../include/msg.h +qmgr_job.o: ../../include/htable.h +qmgr_job.o: ../../include/mymalloc.h +qmgr_job.o: ../../include/sane_time.h +qmgr_job.o: qmgr.h +qmgr_job.o: ../../include/vstream.h +qmgr_job.o: ../../include/vbuf.h +qmgr_job.o: ../../include/scan_dir.h +qmgr_job.o: ../../include/maps.h +qmgr_job.o: ../../include/dict.h +qmgr_job.o: ../../include/argv.h +qmgr_message.o: qmgr_message.c +qmgr_message.o: ../../include/sys_defs.h +qmgr_message.o: ../../include/msg.h +qmgr_message.o: ../../include/mymalloc.h +qmgr_message.o: ../../include/vstring.h +qmgr_message.o: ../../include/vbuf.h +qmgr_message.o: ../../include/vstream.h +qmgr_message.o: ../../include/split_at.h +qmgr_message.o: ../../include/valid_hostname.h +qmgr_message.o: ../../include/argv.h +qmgr_message.o: ../../include/stringops.h +qmgr_message.o: ../../include/myflock.h +qmgr_message.o: ../../include/sane_time.h +qmgr_message.o: ../../include/dict.h +qmgr_message.o: ../../include/mail_queue.h +qmgr_message.o: ../../include/mail_params.h +qmgr_message.o: ../../include/canon_addr.h +qmgr_message.o: ../../include/record.h +qmgr_message.o: ../../include/rec_type.h +qmgr_message.o: ../../include/sent.h +qmgr_message.o: ../../include/deliver_completed.h +qmgr_message.o: ../../include/mail_addr_find.h +qmgr_message.o: ../../include/maps.h +qmgr_message.o: ../../include/opened.h +qmgr_message.o: ../../include/resolve_local.h +qmgr_message.o: ../../include/verp_sender.h +qmgr_message.o: ../../include/resolve_clnt.h +qmgr_message.o: qmgr.h +qmgr_message.o: ../../include/scan_dir.h +qmgr_move.o: qmgr_move.c +qmgr_move.o: ../../include/sys_defs.h +qmgr_move.o: ../../include/msg.h +qmgr_move.o: ../../include/scan_dir.h +qmgr_move.o: ../../include/recipient_list.h +qmgr_move.o: ../../include/mail_queue.h +qmgr_move.o: ../../include/vstring.h +qmgr_move.o: ../../include/vbuf.h +qmgr_move.o: ../../include/vstream.h +qmgr_move.o: ../../include/mail_scan_dir.h +qmgr_move.o: qmgr.h +qmgr_move.o: ../../include/maps.h +qmgr_move.o: ../../include/dict.h +qmgr_move.o: ../../include/argv.h +qmgr_peer.o: qmgr_peer.c +qmgr_peer.o: ../../include/sys_defs.h +qmgr_peer.o: ../../include/msg.h +qmgr_peer.o: ../../include/htable.h +qmgr_peer.o: ../../include/mymalloc.h +qmgr_peer.o: qmgr.h +qmgr_peer.o: ../../include/vstream.h +qmgr_peer.o: ../../include/vbuf.h +qmgr_peer.o: ../../include/scan_dir.h +qmgr_peer.o: ../../include/maps.h +qmgr_peer.o: ../../include/dict.h +qmgr_peer.o: ../../include/argv.h +qmgr_queue.o: qmgr_queue.c +qmgr_queue.o: ../../include/sys_defs.h +qmgr_queue.o: ../../include/msg.h +qmgr_queue.o: ../../include/mymalloc.h +qmgr_queue.o: ../../include/events.h +qmgr_queue.o: ../../include/htable.h +qmgr_queue.o: ../../include/mail_params.h +qmgr_queue.o: ../../include/recipient_list.h +qmgr_queue.o: qmgr.h +qmgr_queue.o: ../../include/vstream.h +qmgr_queue.o: ../../include/vbuf.h +qmgr_queue.o: ../../include/scan_dir.h +qmgr_queue.o: ../../include/maps.h +qmgr_queue.o: ../../include/dict.h +qmgr_queue.o: ../../include/argv.h +qmgr_rcpt_list.o: qmgr_rcpt_list.c +qmgr_rcpt_list.o: ../../include/sys_defs.h +qmgr_rcpt_list.o: ../../include/mymalloc.h +qmgr_rcpt_list.o: qmgr.h +qmgr_rcpt_list.o: ../../include/vstream.h +qmgr_rcpt_list.o: ../../include/vbuf.h +qmgr_rcpt_list.o: ../../include/scan_dir.h +qmgr_rcpt_list.o: ../../include/maps.h +qmgr_rcpt_list.o: ../../include/dict.h +qmgr_rcpt_list.o: ../../include/argv.h +qmgr_scan.o: qmgr_scan.c +qmgr_scan.o: ../../include/sys_defs.h +qmgr_scan.o: ../../include/msg.h +qmgr_scan.o: ../../include/mymalloc.h +qmgr_scan.o: ../../include/scan_dir.h +qmgr_scan.o: ../../include/mail_scan_dir.h +qmgr_scan.o: qmgr.h +qmgr_scan.o: ../../include/vstream.h +qmgr_scan.o: ../../include/vbuf.h +qmgr_scan.o: ../../include/maps.h +qmgr_scan.o: ../../include/dict.h +qmgr_scan.o: ../../include/argv.h +qmgr_transport.o: qmgr_transport.c +qmgr_transport.o: ../../include/sys_defs.h +qmgr_transport.o: ../../include/msg.h +qmgr_transport.o: ../../include/htable.h +qmgr_transport.o: ../../include/events.h +qmgr_transport.o: ../../include/mymalloc.h +qmgr_transport.o: ../../include/vstream.h +qmgr_transport.o: ../../include/vbuf.h +qmgr_transport.o: ../../include/iostuff.h +qmgr_transport.o: ../../include/mail_proto.h +qmgr_transport.o: ../../include/attr.h +qmgr_transport.o: ../../include/recipient_list.h +qmgr_transport.o: ../../include/mail_conf.h +qmgr_transport.o: ../../include/mail_params.h +qmgr_transport.o: qmgr.h +qmgr_transport.o: ../../include/scan_dir.h +qmgr_transport.o: ../../include/maps.h +qmgr_transport.o: ../../include/dict.h +qmgr_transport.o: ../../include/argv.h diff --git a/gnu/dist/postfix/src/nqmgr/qmgr.c b/gnu/dist/postfix/src/nqmgr/qmgr.c new file mode 100644 index 00000000000..e259e47aa06 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr.c @@ -0,0 +1,582 @@ +/*++ +/* NAME +/* qmgr 8 +/* SUMMARY +/* Postfix queue manager +/* SYNOPSIS +/* \fBqmgr\fR [generic Postfix daemon options] +/* DESCRIPTION +/* The \fBqmgr\fR daemon awaits the arrival of incoming mail +/* and arranges for its delivery via Postfix delivery processes. +/* The actual mail routing strategy is delegated to the +/* \fBtrivial-rewrite\fR(8) daemon. +/* This program expects to be run from the \fBmaster\fR(8) process +/* manager. +/* +/* Mail addressed to the local \fBdouble-bounce\fR address is silently +/* discarded. This stops potential loops caused by undeliverable +/* bounce notifications. +/* +/* Mail addressed to a user listed in the optional \fBrelocated\fR +/* database is bounced with a "user has moved to \fInew_location\fR" +/* message. See \fBrelocated\fR(5) for a precise description. +/* MAIL QUEUES +/* .ad +/* .fi +/* The \fBqmgr\fR daemon maintains the following queues: +/* .IP \fBincoming\fR +/* Inbound mail from the network, or mail picked up by the +/* local \fBpickup\fR agent from the \fBmaildrop\fR directory. +/* .IP \fBactive\fR +/* Messages that the queue manager has opened for delivery. Only +/* a limited number of messages is allowed to enter the \fBactive\fR +/* queue (leaky bucket strategy, for a fixed delivery rate). +/* .IP \fBdeferred\fR +/* Mail that could not be delivered upon the first attempt. The queue +/* manager implements exponential backoff by doubling the time between +/* delivery attempts. +/* .IP \fBcorrupt\fR +/* Unreadable or damaged queue files are moved here for inspection. +/* DELIVERY STATUS REPORTS +/* .ad +/* .fi +/* The \fBqmgr\fR daemon keeps an eye on per-message delivery status +/* reports in the following directories. Each status report file has +/* the same name as the corresponding message file: +/* .IP \fBbounce\fR +/* Per-recipient status information about why mail is bounced. +/* These files are maintained by the \fBbounce\fR(8) daemon. +/* .IP \fBdefer\fR +/* Per-recipient status information about why mail is delayed. +/* These files are maintained by the \fBdefer\fR(8) daemon. +/* .PP +/* The \fBqmgr\fR daemon is responsible for asking the +/* \fBbounce\fR(8) or \fBdefer\fR(8) daemons to send non-delivery +/* reports. +/* STRATEGIES +/* .ad +/* .fi +/* The queue manager implements a variety of strategies for +/* either opening queue files (input) or for message delivery (output). +/* .IP "\fBleaky bucket\fR" +/* This strategy limits the number of messages in the \fBactive\fR queue +/* and prevents the queue manager from running out of memory under +/* heavy load. +/* .IP \fBfairness\fR +/* When the \fBactive\fR queue has room, the queue manager takes one +/* message from the \fBincoming\fR queue and one from the \fBdeferred\fR +/* queue. This prevents a large mail backlog from blocking the delivery +/* of new mail. +/* .IP "\fBslow start\fR" +/* This strategy eliminates "thundering herd" problems by slowly +/* adjusting the number of parallel deliveries to the same destination. +/* .IP "\fBround robin\fR +/* The queue manager sorts delivery requests by destination. +/* Round-robin selection prevents one destination from dominating +/* deliveries to other destinations. +/* .IP "\fBexponential backoff\fR" +/* Mail that cannot be delivered upon the first attempt is deferred. +/* The time interval between delivery attempts is doubled after each +/* attempt. +/* .IP "\fBdestination status cache\fR" +/* The queue manager avoids unnecessary delivery attempts by +/* maintaining a short-term, in-memory list of unreachable destinations. +/* .IP "\fBpreemptive message scheduling\fR" +/* The queue manager attempts to minimize the average per-recipient delay +/* while still preserving the correct per-message delays, using +/* a sophisticated preemptive message scheduling. +/* TRIGGERS +/* .ad +/* .fi +/* On an idle system, the queue manager waits for the arrival of +/* trigger events, or it waits for a timer to go off. A trigger +/* is a one-byte message. +/* Depending on the message received, the queue manager performs +/* one of the following actions (the message is followed by the +/* symbolic constant used internally by the software): +/* .IP "\fBD (QMGR_REQ_SCAN_DEFERRED)\fR" +/* Start a deferred queue scan. If a deferred queue scan is already +/* in progress, that scan will be restarted as soon as it finishes. +/* .IP "\fBI (QMGR_REQ_SCAN_INCOMING)\fR" +/* Start an incoming queue scan. If an incoming queue scan is already +/* in progress, that scan will be restarted as soon as it finishes. +/* .IP "\fBA (QMGR_REQ_SCAN_ALL)\fR" +/* Ignore deferred queue file time stamps. The request affects +/* the next deferred queue scan. +/* .IP "\fBF (QMGR_REQ_FLUSH_DEAD)\fR" +/* Purge all information about dead transports and destinations. +/* .IP "\fBW (TRIGGER_REQ_WAKEUP)\fR" +/* Wakeup call, This is used by the master server to instantiate +/* servers that should not go away forever. The action is to start +/* an incoming queue scan. +/* .PP +/* The \fBqmgr\fR daemon reads an entire buffer worth of triggers. +/* Multiple identical trigger requests are collapsed into one, and +/* trigger requests are sorted so that \fBA\fR and \fBF\fR precede +/* \fBD\fR and \fBI\fR. Thus, in order to force a deferred queue run, +/* one would request \fBA F D\fR; in order to notify the queue manager +/* of the arrival of new mail one would request \fBI\fR. +/* STANDARDS +/* .ad +/* .fi +/* None. The \fBqmgr\fR daemon does not interact with the outside world. +/* SECURITY +/* .ad +/* .fi +/* The \fBqmgr\fR daemon is not security sensitive. It reads +/* single-character messages from untrusted local users, and thus may +/* be susceptible to denial of service attacks. The \fBqmgr\fR daemon +/* does not talk to the outside world, and it can be run at fixed low +/* privilege in a chrooted environment. +/* DIAGNOSTICS +/* Problems and transactions are logged to the syslog daemon. +/* Corrupted message files are saved to the \fBcorrupt\fR queue +/* for further inspection. +/* +/* Depending on the setting of the \fBnotify_classes\fR parameter, +/* the postmaster is notified of bounces and of other trouble. +/* BUGS +/* A single queue manager process has to compete for disk access with +/* multiple front-end processes such as \fBsmtpd\fR. A sudden burst of +/* inbound mail can negatively impact outbound delivery rates. +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* The following \fBmain.cf\fR parameters are especially relevant to +/* this program. See the Postfix \fBmain.cf\fR file for syntax details +/* and for default values. Use the \fBpostfix reload\fR command after +/* a configuration change. +/* .SH Miscellaneous +/* .ad +/* .fi +/* .IP \fBallow_min_user\fR +/* Do not bounce recipient addresses that begin with '-'. +/* .IP \fBrelocated_maps\fR +/* Tables with contact information for users, hosts or domains +/* that no longer exist. See \fBrelocated\fR(5). +/* .IP \fBqueue_directory\fR +/* Top-level directory of the Postfix queue. +/* .SH "Active queue controls" +/* .ad +/* .fi +/* In the text below, \fItransport\fR is the first field in a +/* \fBmaster.cf\fR entry. +/* .IP \fBqmgr_message_active_limit\fR +/* Limit the number of messages in the active queue. +/* .IP \fBqmgr_message_recipient_limit\fR +/* Limit the number of in-memory recipients. +/* .sp +/* This parameter also limits the size of the short-term, in-memory +/* destination cache. +/* .IP \fBqmgr_message_recipient_minimum\fR +/* Per message minimum of in-memory recipients. +/* .IP \fBdefault_recipient_limit\fR +/* Default limit on the number of in-memory recipients per transport. +/* .IP \fItransport\fB_recipient_limit\fR +/* Limit on the number of in-memory recipients, for the named +/* message \fItransport\fR. +/* .IP \fBdefault_extra_recipient_limit\fR +/* Default limit on the total number of per transport in-memory +/* recipients that the preempting messages can have. +/* .IP \fItransport\fB_extra_recipient_limit\fR +/* Limit on the number of in-memory recipients which all preempting +/* messages delivered by the transport \fItransport\fR can have. +/* .SH "Timing controls" +/* .ad +/* .fi +/* .IP \fBmin_backoff\fR +/* Minimal time in seconds between delivery attempts +/* of a deferred message. +/* .sp +/* This parameter also limits the time an unreachable destination +/* is kept in the short-term, in-memory destination status cache. +/* .IP \fBmax_backoff\fR +/* Maximal time in seconds between delivery attempts +/* of a deferred message. +/* .IP \fBmaximal_queue_lifetime\fR +/* Maximal time in days a message is queued +/* before it is sent back as undeliverable. +/* .IP \fBqueue_run_delay\fR +/* Time in seconds between deferred queue scans. Queue scans do +/* not overlap. +/* .IP \fBtransport_retry_time\fR +/* Time in seconds between attempts to contact a broken +/* delivery transport. +/* .SH "Concurrency controls" +/* .ad +/* .fi +/* .IP \fBinitial_destination_concurrency\fR +/* Initial per-destination concurrency level for parallel delivery +/* to the same destination. +/* .IP \fBdefault_destination_concurrency_limit\fR +/* Default limit on the number of parallel deliveries to the same +/* destination. +/* .IP \fItransport\fB_destination_concurrency_limit\fR +/* Limit on the number of parallel deliveries to the same destination, +/* for delivery via the named message \fItransport\fR. +/* .SH "Recipient controls" +/* .ad +/* .fi +/* .IP \fBdefault_destination_recipient_limit\fR +/* Default limit on the number of recipients per message transfer. +/* .IP \fItransport\fB_destination_recipient_limit\fR +/* Limit on the number of recipients per message transfer, for the +/* named message \fItransport\fR. +/* .SH "Message scheduling" +/* .ad +/* .fi +/* .IP "\fItransport\fB_delivery_slot_cost\fR (valid range: 0,2,3...) +/* This parameter basically controls how often a message +/* delivered by \fItransport\fR can be preempted by another +/* message. +/* An internal per-message/transport counter is incremented by one +/* for each \fItransport\fB_delivery_slot_cost\fR +/* deliveries handled by \fItransport\fR. This counter represents +/* the number of "available delivery slots" for use by other messages. +/* Current message can be preempted by another message when that +/* other message can be delivered using less \fItransport\fR agents +/* than the value of the "available delivery slots" counter. +/* .sp +/* Value equal to 0 disables the message preemption for \fItransport\fR. +/* .IP \fItransport\fB_minimum_delivery_slots\fR +/* Message preemption is not attempted at all whenever a message +/* that can't ever accumulate at least \fItransport\fB_minimum_delivery_slots\fR +/* available delivery slots is being delivered by \fItransport\fR. +/* .IP "\fItransport\fB_delivery_slot_discount\fR (valid range: 0..100)" +/* .IP \fItransport\fB_delivery_slot_loan\fR +/* These parameters speed up the moment when a message preemption can happen. +/* Instead of waiting until the full amount of delivery slots +/* required is available, the preemption can happen when +/* \fItransport\fB_delivery_slot_discount\fR percent of the required +/* amount plus \fItransport\fB_delivery_slot_loan\fR still remains to +/* be accumulated. Note that the full amount will still have to be +/* accumulated before another preemption can take place later. +/* .IP \fBdefault_delivery_slot_cost\fR +/* .IP \fBdefault_minimum_delivery_slots\fR +/* .IP \fBdefault_delivery_slot_discount\fR +/* .IP \fBdefault_delivery_slot_loan\fR +/* Default values for the transport specific parameters described above. +/* SEE ALSO +/* master(8), process manager +/* relocated(5), format of the "user has moved" table +/* syslogd(8) system logging +/* trivial-rewrite(8), address routing +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> + +/* Utility library. */ + +#include <msg.h> +#include <events.h> +#include <vstream.h> +#include <dict.h> + +/* Global library. */ + +#include <mail_queue.h> +#include <recipient_list.h> +#include <mail_conf.h> +#include <mail_params.h> +#include <mail_proto.h> /* QMGR_SCAN constants */ +#include <mail_flow.h> + +/* Master process interface */ + +#include <master_proto.h> +#include <mail_server.h> + +/* Application-specific. */ + +#include "qmgr.h" + + /* + * Tunables. + */ +int var_queue_run_delay; +int var_min_backoff_time; +int var_max_backoff_time; +int var_max_queue_time; +int var_qmgr_active_limit; +int var_qmgr_rcpt_limit; +int var_qmgr_msg_rcpt_limit; +int var_xport_rcpt_limit; +int var_stack_rcpt_limit; +int var_delivery_slot_cost; +int var_delivery_slot_loan; +int var_delivery_slot_discount; +int var_min_delivery_slots; +int var_init_dest_concurrency; +int var_transport_retry_time; +int var_dest_con_limit; +int var_dest_rcpt_limit; +char *var_relocated_maps; +char *var_virtual_maps; +char *var_defer_xports; +bool var_allow_min_user; +int var_local_con_lim; +int var_local_rcpt_lim; +int var_proc_limit; +bool var_verp_bounce_off; + +static QMGR_SCAN *qmgr_incoming; +static QMGR_SCAN *qmgr_deferred; + +MAPS *qmgr_relocated; +MAPS *qmgr_virtual; + +/* qmgr_deferred_run_event - queue manager heartbeat */ + +static void qmgr_deferred_run_event(int unused_event, char *dummy) +{ + + /* + * This routine runs when it is time for another deferred queue scan. + * Make sure this routine gets called again in the future. + */ + qmgr_scan_request(qmgr_deferred, QMGR_SCAN_START); + event_request_timer(qmgr_deferred_run_event, dummy, var_queue_run_delay); +} + +/* qmgr_trigger_event - respond to external trigger(s) */ + +static void qmgr_trigger_event(char *buf, int len, + char *unused_service, char **argv) +{ + int incoming_flag = 0; + int deferred_flag = 0; + int i; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + msg_fatal("unexpected command-line argument: %s", argv[0]); + + /* + * Collapse identical requests that have arrived since we looked last + * time. There is no client feedback so there is no need to process each + * request in order. And as long as we don't have conflicting requests we + * are free to sort them into the most suitable order. + */ + for (i = 0; i < len; i++) { + if (msg_verbose) + msg_info("request: %d (%c)", + buf[i], ISALNUM(buf[i]) ? buf[i] : '?'); + switch (buf[i]) { + case TRIGGER_REQ_WAKEUP: + case QMGR_REQ_SCAN_INCOMING: + incoming_flag |= QMGR_SCAN_START; + break; + case QMGR_REQ_SCAN_DEFERRED: + deferred_flag |= QMGR_SCAN_START; + break; + case QMGR_REQ_FLUSH_DEAD: + deferred_flag |= QMGR_FLUSH_DEAD; + incoming_flag |= QMGR_FLUSH_DEAD; + break; + case QMGR_REQ_SCAN_ALL: + deferred_flag |= QMGR_SCAN_ALL; + incoming_flag |= QMGR_SCAN_ALL; + break; + default: + if (msg_verbose) + msg_info("request ignored"); + break; + } + } + + /* + * Process each request type at most once. Modifiers take effect upon the + * next queue run. If no queue run is in progress, and a queue scan is + * requested, the request takes effect immediately. + */ + if (incoming_flag != 0) + qmgr_scan_request(qmgr_incoming, incoming_flag); + if (deferred_flag != 0) + qmgr_scan_request(qmgr_deferred, deferred_flag); +} + +/* qmgr_loop - queue manager main loop */ + +static int qmgr_loop(char *unused_name, char **unused_argv) +{ + char *in_path = 0; + char *df_path = 0; + int token_count; + int in_feed = 0; + + /* + * This routine runs as part of the event handling loop, after the event + * manager has delivered a timer or I/O event (including the completion + * of a connection to a delivery process), or after it has waited for a + * specified amount of time. The result value of qmgr_loop() specifies + * how long the event manager should wait for the next event. + */ +#define DONT_WAIT 0 +#define WAIT_FOR_EVENT (-1) + + /* + * Attempt to drain the active queue by allocating a suitable delivery + * process and by delivering mail via it. Delivery process allocation and + * mail delivery are asynchronous. + */ + qmgr_active_drain(); + + /* + * Let some new blood into the active queue when the queue size is + * smaller than some configurable limit. When the system is under heavy + * load, favor new mail over old mail. + */ + if (qmgr_message_count < var_qmgr_active_limit) + if ((in_path = qmgr_scan_next(qmgr_incoming)) != 0) + in_feed = qmgr_active_feed(qmgr_incoming, in_path); + if (qmgr_message_count < var_qmgr_active_limit) + if ((df_path = qmgr_scan_next(qmgr_deferred)) != 0) + qmgr_active_feed(qmgr_deferred, df_path); + + /* + * Global flow control. If enabled, slow down receiving processes that + * get ahead of the queue manager, but don't block them completely. + */ + if (var_in_flow_delay > 0) { + token_count = mail_flow_count(); + if (token_count < var_proc_limit) { + if (in_feed != 0) + mail_flow_put(1); + else if (qmgr_incoming->handle == 0) + mail_flow_put(var_proc_limit - token_count); + } else if (token_count > var_proc_limit) { + mail_flow_get(token_count - var_proc_limit); + } + } + if (in_path || df_path) + return (DONT_WAIT); + return (WAIT_FOR_EVENT); +} + +/* pre_accept - see if tables have changed */ + +static void pre_accept(char *unused_name, char **unused_argv) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + +/* qmgr_pre_init - pre-jail initialization */ + +static void qmgr_pre_init(char *unused_name, char **unused_argv) +{ + if (*var_relocated_maps) + qmgr_relocated = maps_create("relocated", var_relocated_maps, + DICT_FLAG_LOCK); + if (*var_virtual_maps) + qmgr_virtual = maps_create("virtual", var_virtual_maps, + DICT_FLAG_LOCK); +} + +/* qmgr_post_init - post-jail initialization */ + +static void qmgr_post_init(char *unused_name, char **unused_argv) +{ + + /* + * This routine runs after the skeleton code has entered the chroot jail. + * Prevent automatic process suicide after a limited number of client + * requests or after a limited amount of idle time. Move any left-over + * entries from the active queue to the incoming queue, and give them a + * time stamp into the future, in order to allow ongoing deliveries to + * finish first. Start scanning the incoming and deferred queues. + * Left-over active queue entries are moved to the incoming queue because + * the incoming queue has priority; moving left-overs to the deferred + * queue could cause anomalous delays when "postfix reload/start" are + * issued often. + */ + var_use_limit = 0; + var_idle_limit = 0; + qmgr_move(MAIL_QUEUE_ACTIVE, MAIL_QUEUE_INCOMING, event_time()); + qmgr_incoming = qmgr_scan_create(MAIL_QUEUE_INCOMING); + qmgr_deferred = qmgr_scan_create(MAIL_QUEUE_DEFERRED); + qmgr_scan_request(qmgr_incoming, QMGR_SCAN_START); + qmgr_deferred_run_event(0, (char *) 0); +} + +/* main - the main program */ + +int main(int argc, char **argv) +{ + static CONFIG_STR_TABLE str_table[] = { + VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0, + VAR_VIRTUAL_MAPS, DEF_VIRTUAL_MAPS, &var_virtual_maps, 0, 0, + VAR_DEFER_XPORTS, DEF_DEFER_XPORTS, &var_defer_xports, 0, 0, + 0, + }; + static CONFIG_TIME_TABLE time_table[] = { + VAR_QUEUE_RUN_DELAY, DEF_QUEUE_RUN_DELAY, &var_queue_run_delay, 1, 0, + VAR_MIN_BACKOFF_TIME, DEF_MIN_BACKOFF_TIME, &var_min_backoff_time, 1, 0, + VAR_MAX_BACKOFF_TIME, DEF_MAX_BACKOFF_TIME, &var_max_backoff_time, 1, 0, + VAR_MAX_QUEUE_TIME, DEF_MAX_QUEUE_TIME, &var_max_queue_time, 1, 8640000, + VAR_XPORT_RETRY_TIME, DEF_XPORT_RETRY_TIME, &var_transport_retry_time, 1, 0, + 0, + }; + static CONFIG_INT_TABLE int_table[] = { + VAR_QMGR_ACT_LIMIT, DEF_QMGR_ACT_LIMIT, &var_qmgr_active_limit, 1, 0, + VAR_QMGR_RCPT_LIMIT, DEF_QMGR_RCPT_LIMIT, &var_qmgr_rcpt_limit, 1, 0, + VAR_QMGR_MSG_RCPT_LIMIT, DEF_QMGR_MSG_RCPT_LIMIT, &var_qmgr_msg_rcpt_limit, 1, 0, + VAR_XPORT_RCPT_LIMIT, DEF_XPORT_RCPT_LIMIT, &var_xport_rcpt_limit, 0, 0, + VAR_STACK_RCPT_LIMIT, DEF_STACK_RCPT_LIMIT, &var_stack_rcpt_limit, 0, 0, + VAR_DELIVERY_SLOT_COST, DEF_DELIVERY_SLOT_COST, &var_delivery_slot_cost, 0, 0, + VAR_DELIVERY_SLOT_LOAN, DEF_DELIVERY_SLOT_LOAN, &var_delivery_slot_loan, 0, 0, + VAR_DELIVERY_SLOT_DISCOUNT, DEF_DELIVERY_SLOT_DISCOUNT, &var_delivery_slot_discount, 0, 100, + VAR_MIN_DELIVERY_SLOTS, DEF_MIN_DELIVERY_SLOTS, &var_min_delivery_slots, 0, 0, + VAR_INIT_DEST_CON, DEF_INIT_DEST_CON, &var_init_dest_concurrency, 1, 0, + VAR_DEST_CON_LIMIT, DEF_DEST_CON_LIMIT, &var_dest_con_limit, 0, 0, + VAR_DEST_RCPT_LIMIT, DEF_DEST_RCPT_LIMIT, &var_dest_rcpt_limit, 0, 0, + VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0, + VAR_LOCAL_CON_LIMIT, DEF_LOCAL_CON_LIMIT, &var_local_con_lim, 0, 0, + VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0, + 0, + }; + static CONFIG_BOOL_TABLE bool_table[] = { + VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user, + VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off, + 0, + }; + + /* + * Use the trigger service skeleton, because no-one else should be + * monitoring our service port while this process runs, and because we do + * not talk back to the client. + */ + trigger_server_main(argc, argv, qmgr_trigger_event, + MAIL_SERVER_INT_TABLE, int_table, + MAIL_SERVER_STR_TABLE, str_table, + MAIL_SERVER_BOOL_TABLE, bool_table, + MAIL_SERVER_TIME_TABLE, time_table, + MAIL_SERVER_PRE_INIT, qmgr_pre_init, + MAIL_SERVER_POST_INIT, qmgr_post_init, + MAIL_SERVER_LOOP, qmgr_loop, + MAIL_SERVER_PRE_ACCEPT, pre_accept, + 0); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr.h b/gnu/dist/postfix/src/nqmgr/qmgr.h new file mode 100644 index 00000000000..8749c35605c --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr.h @@ -0,0 +1,431 @@ +/*++ +/* NAME +/* qmgr 3h +/* SUMMARY +/* queue manager data structures +/* SYNOPSIS +/* #include "qmgr.h" +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include <vstream.h> +#include <scan_dir.h> + + /* + * Global library. + */ +#include <maps.h> + + /* + * The queue manager is built around lots of mutually-referring structures. + * These typedefs save some typing. + */ +typedef struct QMGR_TRANSPORT QMGR_TRANSPORT; +typedef struct QMGR_QUEUE QMGR_QUEUE; +typedef struct QMGR_ENTRY QMGR_ENTRY; +typedef struct QMGR_MESSAGE QMGR_MESSAGE; +typedef struct QMGR_JOB QMGR_JOB; +typedef struct QMGR_PEER QMGR_PEER; +typedef struct QMGR_TRANSPORT_LIST QMGR_TRANSPORT_LIST; +typedef struct QMGR_QUEUE_LIST QMGR_QUEUE_LIST; +typedef struct QMGR_ENTRY_LIST QMGR_ENTRY_LIST; +typedef struct QMGR_JOB_LIST QMGR_JOB_LIST; +typedef struct QMGR_PEER_LIST QMGR_PEER_LIST; +typedef struct QMGR_RCPT QMGR_RCPT; +typedef struct QMGR_RCPT_LIST QMGR_RCPT_LIST; +typedef struct QMGR_SCAN QMGR_SCAN; + + /* + * Hairy macros to update doubly-linked lists. + */ +#define QMGR_LIST_ROTATE(head, object, peers) { \ + head.next->peers.prev = head.prev; \ + head.prev->peers.next = head.next; \ + head.next = object->peers.next; \ + head.next->peers.prev = 0; \ + head.prev = object; \ + object->peers.next = 0; \ +} + +#define QMGR_LIST_UNLINK(head, type, object, peers) { \ + type next = object->peers.next; \ + type prev = object->peers.prev; \ + if (prev) prev->peers.next = next; \ + else head.next = next; \ + if (next) next->peers.prev = prev; \ + else head.prev = prev; \ + object->peers.next = object->peers.prev = 0; \ +} + +#define QMGR_LIST_LINK(head, pred, object, succ, peers) { \ + object->peers.prev = pred; \ + object->peers.next = succ; \ + if (pred) pred->peers.next = object; \ + else head.next = object; \ + if (succ) succ->peers.prev = object; \ + else head.prev = object; \ +} + +#define QMGR_LIST_PREPEND(head, object, peers) { \ + object->peers.next = head.next; \ + object->peers.prev = 0; \ + if (head.next) { \ + head.next->peers.prev = object; \ + } else { \ + head.prev = object; \ + } \ + head.next = object; \ +} + +#define QMGR_LIST_APPEND(head, object, peers) { \ + object->peers.prev = head.prev; \ + object->peers.next = 0; \ + if (head.prev) { \ + head.prev->peers.next = object; \ + } else { \ + head.next = object; \ + } \ + head.prev = object; \ +} + +#define QMGR_LIST_INIT(head) { \ + head.prev = 0; \ + head.next = 0; \ +} + + /* + * Transports are looked up by name (when we have resolved a message), or + * round-robin wise (when we want to distribute resources fairly). + */ +struct QMGR_TRANSPORT_LIST { + QMGR_TRANSPORT *next; + QMGR_TRANSPORT *prev; +}; + +extern struct HTABLE *qmgr_transport_byname; /* transport by name */ +extern QMGR_TRANSPORT_LIST qmgr_transport_list; /* transports, round robin */ + + /* + * Each transport (local, smtp-out, bounce) can have one queue per next hop + * name. Queues are looked up by next hop name (when we have resolved a + * message destination), or round-robin wise (when we want to deliver + * messages fairly). + */ +struct QMGR_QUEUE_LIST { + QMGR_QUEUE *next; + QMGR_QUEUE *prev; +}; + +struct QMGR_JOB_LIST { + QMGR_JOB *next; + QMGR_JOB *prev; +}; + +struct QMGR_TRANSPORT { + int flags; /* blocked, etc. */ + char *name; /* transport name */ + int dest_concurrency_limit; /* concurrency per domain */ + int init_dest_concurrency; /* init. per-domain concurrency */ + int recipient_limit; /* recipients per transaction */ + int rcpt_per_stack; /* extra slots reserved for jobs put + * on the job stack */ + int rcpt_unused; /* available in-core recipient slots */ + int slot_cost; /* cost of new preemption slot (# of + * selected entries) */ + int slot_loan; /* preemption boost offset and */ + int slot_loan_factor; /* factor, see qmgr_job_preempt() */ + int min_slots; /* when preemption can take effect at + * all */ + struct HTABLE *queue_byname; /* queues indexed by domain */ + QMGR_QUEUE_LIST queue_list; /* queues, round robin order */ + struct HTABLE *job_byname; /* jobs indexed by queue id */ + QMGR_JOB_LIST job_list; /* list of message jobs (1 per + * message) ordered by scheduler */ + QMGR_JOB_LIST job_bytime; /* jobs ordered by time since queued */ + QMGR_JOB *job_current; /* keeps track of the current job */ + QMGR_JOB *job_next_unread; /* next job with unread recipients */ + QMGR_JOB *candidate_cache; /* cached result from + * qmgr_job_candidate() */ + QMGR_JOB *candidate_cache_current; /* current job tied to the candidate */ + time_t candidate_cache_time; /* when candidate_cache was last + * updated */ + int blocker_tag; /* for marking blocker jobs */ + QMGR_TRANSPORT_LIST peers; /* linkage */ + char *reason; /* why unavailable */ +}; + +#define QMGR_TRANSPORT_STAT_DEAD (1<<1) +#define QMGR_TRANSPORT_STAT_BUSY (1<<2) + +typedef void (*QMGR_TRANSPORT_ALLOC_NOTIFY) (QMGR_TRANSPORT *, VSTREAM *); +extern QMGR_TRANSPORT *qmgr_transport_select(void); +extern void qmgr_transport_alloc(QMGR_TRANSPORT *, QMGR_TRANSPORT_ALLOC_NOTIFY); +extern void qmgr_transport_throttle(QMGR_TRANSPORT *, const char *); +extern void qmgr_transport_unthrottle(QMGR_TRANSPORT *); +extern QMGR_TRANSPORT *qmgr_transport_create(const char *); +extern QMGR_TRANSPORT *qmgr_transport_find(const char *); + + /* + * Each next hop (e.g., a domain name) has its own queue of pending message + * transactions. The "todo" queue contains messages that are to be delivered + * to this next hop. When a message is elected for transmission, it is moved + * from the "todo" queue to the "busy" queue. Messages are taken from the + * "todo" queue in round-robin order. + */ +struct QMGR_ENTRY_LIST { + QMGR_ENTRY *next; + QMGR_ENTRY *prev; +}; + +struct QMGR_QUEUE { + char *name; /* domain name */ + int todo_refcount; /* queue entries (todo list) */ + int busy_refcount; /* queue entries (busy list) */ + int window; /* slow open algorithm */ + QMGR_TRANSPORT *transport; /* transport linkage */ + QMGR_ENTRY_LIST todo; /* todo queue entries */ + QMGR_ENTRY_LIST busy; /* messages on the wire */ + QMGR_QUEUE_LIST peers; /* neighbor queues */ + char *reason; /* why unavailable */ + int blocker_tag; /* tagged if blocks job list */ +}; + +#define QMGR_QUEUE_TODO 1 /* waiting for service */ +#define QMGR_QUEUE_BUSY 2 /* recipients on the wire */ + +extern int qmgr_queue_count; + +extern QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *, const char *); +extern void qmgr_queue_done(QMGR_QUEUE *); +extern void qmgr_queue_throttle(QMGR_QUEUE *, const char *); +extern void qmgr_queue_unthrottle(QMGR_QUEUE *); +extern QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *, const char *); + + /* + * Structure for a recipient list. Initially, it just contains recipient + * addresses and file offsets. After the address resolver has done its work, + * each recipient is accompanied by a reference to a specific queues (which + * implies a specific transport). This is an extended version of similar + * information maintained by the recipient_list(3) module. + */ +struct QMGR_RCPT { + long offset; /* REC_TYPE_RCPT byte */ + char *address; /* complete address */ + QMGR_QUEUE *queue; /* resolved queue */ +}; + +struct QMGR_RCPT_LIST { + QMGR_RCPT *info; + int len; + int avail; +}; + +extern void qmgr_rcpt_list_init(QMGR_RCPT_LIST *); +extern void qmgr_rcpt_list_add(QMGR_RCPT_LIST *, long, const char *); +extern void qmgr_rcpt_list_free(QMGR_RCPT_LIST *); + + /* + * Structure of one next-hop queue entry. In order to save some copying + * effort we allow multiple recipients per transaction. + */ +struct QMGR_ENTRY { + VSTREAM *stream; /* delivery process */ + QMGR_MESSAGE *message; /* message info */ + QMGR_RCPT_LIST rcpt_list; /* as many as it takes */ + QMGR_QUEUE *queue; /* parent linkage */ + QMGR_PEER *peer; /* parent linkage */ + QMGR_ENTRY_LIST queue_peers; /* per queue neighbor entries */ + QMGR_ENTRY_LIST peer_peers; /* per peer neighbor entries */ +}; + +extern QMGR_ENTRY *qmgr_entry_select(QMGR_PEER *); +extern void qmgr_entry_unselect(QMGR_ENTRY *); +extern void qmgr_entry_done(QMGR_ENTRY *, int); +extern QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *, QMGR_MESSAGE *); + + /* + * All common in-core information about a message is kept here. When all + * recipients have been tried the message file is linked to the "deferred" + * queue (some hosts not reachable), to the "bounce" queue (some recipients + * were rejected), and is then removed from the "active" queue. + */ +struct QMGR_MESSAGE { + int flags; /* delivery problems */ + int qflags; /* queuing flags */ + VSTREAM *fp; /* open queue file or null */ + int refcount; /* queue entries */ + int single_rcpt; /* send one rcpt at a time */ + long arrival_time; /* time when queued */ + time_t queued_time; /* time when moved to the active + * queue */ + long warn_offset; /* warning bounce flag offset */ + time_t warn_time; /* time next warning to be sent */ + long data_offset; /* data seek offset */ + char *queue_name; /* queue name */ + char *queue_id; /* queue file */ + char *sender; /* complete address */ + char *verp_delims; /* VERP delimiters */ + char *errors_to; /* error report address */ + char *return_receipt; /* confirm receipt address */ + char *filter_xport; /* filtering transport */ + char *inspect_xport; /* inspecting transport */ + long data_size; /* message content size */ + long rcpt_offset; /* more recipients here */ + long unread_offset; /* more unread recipients here */ + QMGR_RCPT_LIST rcpt_list; /* complete addresses */ + int rcpt_count; /* used recipient slots */ + int rcpt_limit; /* maximum read in-core */ + int rcpt_unread; /* # of recipients left in queue file */ + QMGR_JOB_LIST job_list; /* jobs delivering this message (1 + * per transport) */ +}; + +#define QMGR_MESSAGE_LOCKED ((QMGR_MESSAGE *) 1) + +extern int qmgr_message_count; +extern int qmgr_recipient_count; +extern MAPS *qmgr_relocated; +extern MAPS *qmgr_virtual; + +extern void qmgr_message_free(QMGR_MESSAGE *); +extern void qmgr_message_update_warn(QMGR_MESSAGE *); +extern QMGR_MESSAGE *qmgr_message_alloc(const char *, const char *, int); +extern QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *); + + /* + * Sometimes it's required to access the transport queues and entries on per + * message basis. That's what the QMGR_JOB structure is for - it groups all + * per message information within each transport using a list of QMGR_PEER + * structures. These structures in turn correspond with per message + * QMGR_QUEUE structure and list all per message QMGR_ENTRY structures. + */ +struct QMGR_PEER_LIST { + QMGR_PEER *next; + QMGR_PEER *prev; +}; + +struct QMGR_JOB { + QMGR_MESSAGE *message; /* message delivered by this job */ + QMGR_TRANSPORT *transport; /* transport this job belongs to */ + QMGR_JOB_LIST message_peers; /* per message neighbor linkage */ + QMGR_JOB_LIST transport_peers; /* per transport neighbor linkage */ + QMGR_JOB_LIST time_peers; /* by time neighbor linkage */ + QMGR_JOB *stack_parent; /* stack parent */ + QMGR_JOB_LIST stack_children; /* all stack children */ + QMGR_JOB_LIST stack_siblings; /* stack children linkage */ + int stack_level; /* job stack nesting level (-1 means + * it's not on the lists at all) */ + int blocker_tag; /* tagged if blocks the job list */ + struct HTABLE *peer_byname; /* message job peers, indexed by + * domain */ + QMGR_PEER_LIST peer_list; /* list of message job peers */ + int slots_used; /* slots used during preemption */ + int slots_available; /* slots available for preemption (in + * multiples of slot_cost) */ + int selected_entries; /* # of entries selected for delivery + * so far */ + int read_entries; /* # of entries read in-core so far */ + int rcpt_count; /* used recipient slots */ + int rcpt_limit; /* available recipient slots */ +}; + +struct QMGR_PEER { + QMGR_JOB *job; /* job handling this peer */ + QMGR_QUEUE *queue; /* queue corresponding with this peer */ + int refcount; /* peer entries */ + QMGR_ENTRY_LIST entry_list; /* todo message entries queued for + * this peer */ + QMGR_PEER_LIST peers; /* neighbor linkage */ +}; + +extern QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *); +extern QMGR_PEER *qmgr_peer_select(QMGR_JOB *); + +extern QMGR_JOB *qmgr_job_obtain(QMGR_MESSAGE *, QMGR_TRANSPORT *); +extern void qmgr_job_free(QMGR_JOB *); +extern void qmgr_job_move_limits(QMGR_JOB *); + +extern QMGR_PEER *qmgr_peer_create(QMGR_JOB *, QMGR_QUEUE *); +extern QMGR_PEER *qmgr_peer_find(QMGR_JOB *, QMGR_QUEUE *); +extern void qmgr_peer_free(QMGR_PEER *); + + /* + * qmgr_defer.c + */ +extern void qmgr_defer_transport(QMGR_TRANSPORT *, const char *); +extern void qmgr_defer_todo(QMGR_QUEUE *, const char *); +extern void qmgr_defer_recipient(QMGR_MESSAGE *, const char *, const char *); + + /* + * qmgr_bounce.c + */ +extern void PRINTFLIKE(3, 4) qmgr_bounce_recipient(QMGR_MESSAGE *, QMGR_RCPT *, const char *,...); + + /* + * qmgr_deliver.c + */ +extern int qmgr_deliver_concurrency; +extern void qmgr_deliver(QMGR_TRANSPORT *, VSTREAM *); + + /* + * qmgr_active.c + */ +extern int qmgr_active_feed(QMGR_SCAN *, const char *); +extern void qmgr_active_drain(void); +extern void qmgr_active_done(QMGR_MESSAGE *); + + /* + * qmgr_move.c + */ +extern void qmgr_move(const char *, const char *, time_t); + + /* + * qmgr_enable.c + */ +extern void qmgr_enable_all(void); +extern void qmgr_enable_transport(QMGR_TRANSPORT *); +extern void qmgr_enable_queue(QMGR_QUEUE *); + + /* + * Queue scan context. + */ +struct QMGR_SCAN { + char *queue; /* queue name */ + int flags; /* private, this run */ + int nflags; /* private, next run */ + struct SCAN_DIR *handle; /* scan */ +}; + + /* + * Flags that control queue scans or destination selection. These are + * similar to the QMGR_REQ_XXX request codes. + */ +#define QMGR_SCAN_START (1<<0) /* start now/restart when done */ +#define QMGR_SCAN_ALL (1<<1) /* all queue file time stamps */ +#define QMGR_FLUSH_DEAD (1<<2) /* all sites, all transports */ + + /* + * qmgr_scan.c + */ +extern QMGR_SCAN *qmgr_scan_create(const char *); +extern void qmgr_scan_request(QMGR_SCAN *, int); +extern char *qmgr_scan_next(QMGR_SCAN *); + +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_active.c b/gnu/dist/postfix/src/nqmgr/qmgr_active.c new file mode 100644 index 00000000000..722d810739c --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_active.c @@ -0,0 +1,500 @@ +/*++ +/* NAME +/* qmgr_active 3 +/* SUMMARY +/* active queue management +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* void qmgr_active_feed(scan_info, queue_id) +/* QMGR_SCAN *scan_info; +/* const char *queue_id; +/* +/* void qmgr_active_drain() +/* +/* int qmgr_active_done(message) +/* QMGR_MESSAGE *message; +/* DESCRIPTION +/* These functions maintain the active message queue: the set +/* of messages that the queue manager is actually working on. +/* The active queue is limited in size. Messages are drained +/* from the active queue by allocating a delivery process and +/* by delivering mail via that process. Messages leak into the +/* active queue only when the active queue is small enough. +/* Damaged message files are saved to the "corrupt" directory. +/* +/* qmgr_active_feed() inserts the named message file into +/* the active queue. Message files with the wrong name or +/* with other wrong properties are skipped but not removed. +/* The following queue flags are recognized, other flags being +/* ignored: +/* .IP QMGR_SCAN_ALL +/* Examine all queue files. Normally, deferred queue files with +/* future time stamps are ignored, and incoming queue files with +/* future time stamps are frowned upon. +/* .PP +/* qmgr_active_drain() allocates one delivery process. +/* Process allocation is asynchronous. Once the delivery +/* process is available, an attempt is made to deliver +/* a message via it. Message delivery is asynchronous, too. +/* +/* qmgr_active_done() deals with a message after delivery +/* has been tried for all in-core recipients. If the message +/* was bounced, a bounce message is sent to the sender, or +/* to the Errors-To: address if one was specified. +/* If there are more on-file recipients, a new batch of +/* in-core recipients is read from the queue file. Otherwise, +/* if a delivery agent marked the queue file as corrupt, +/* the queue file is moved to the "corrupt" queue (surprise); +/* if at least one delivery failed, the message is moved +/* to the deferred queue. The time stamps of a deferred queue +/* file are set to the nearest wakeup time of its recipient +/* sites (if delivery failed due to a problem with a next-hop +/* host), are set into the future by the amount of time the +/* message was queued (per-message exponential backoff), or are set +/* into the future by a minimal backoff time, whichever is more. +/* The minimal_backoff_time parameter specifies the minimal +/* amount of time between delivery attempts; maximal_backoff_time +/* specifies an upper limit. +/* DIAGNOSTICS +/* Fatal: queue file access failures, out of memory. +/* Panic: interface violations, internal consistency errors. +/* Warnings: corrupt message file. A corrupt message is saved +/* to the "corrupt" queue for further inspection. +/* 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/stat.h> +#include <dirent.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <utime.h> +#include <errno.h> + +#ifndef S_IRWXU /* What? no POSIX system? */ +#define S_IRWXU 0700 +#endif + +/* Utility library. */ + +#include <msg.h> +#include <events.h> +#include <mymalloc.h> +#include <vstream.h> + +/* Global library. */ + +#include <mail_params.h> +#include <mail_open_ok.h> +#include <mail_queue.h> +#include <recipient_list.h> +#include <bounce.h> +#include <defer.h> +#include <abounce.h> +#include <rec_type.h> + +/* Application-specific. */ + +#include "qmgr.h" + + /* + * A bunch of call-back routines. + */ +static void qmgr_active_done_2_bounce_flush(int, char *); +static void qmgr_active_done_2_generic(QMGR_MESSAGE *); +static void qmgr_active_done_3_defer_flush(int, char *); +static void qmgr_active_done_3_defer_warn(int, char *); +static void qmgr_active_done_3_generic(QMGR_MESSAGE *); + +/* qmgr_active_corrupt - move corrupted file out of the way */ + +static void qmgr_active_corrupt(const char *queue_id) +{ + char *myname = "qmgr_active_corrupt"; + + if (mail_queue_rename(queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT)) { + if (errno != ENOENT) + msg_fatal("%s: save corrupt file queue %s id %s: %m", + myname, MAIL_QUEUE_ACTIVE, queue_id); + msg_warn("%s: save corrupt file queue %s id %s: %m", + myname, MAIL_QUEUE_ACTIVE, queue_id); + } else { + msg_warn("saving corrupt file \"%s\" from queue \"%s\" to queue \"%s\"", + queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT); + } +} + +/* qmgr_active_defer - defer queue file */ + +static void qmgr_active_defer(const char *queue_name, const char *queue_id, + const char *dest_queue, int delay) +{ + char *myname = "qmgr_active_defer"; + const char *path; + struct utimbuf tbuf; + + if (msg_verbose) + msg_info("wakeup %s after %ld secs", queue_id, (long) delay); + + tbuf.actime = tbuf.modtime = event_time() + delay; + path = mail_queue_path((VSTRING *) 0, queue_name, queue_id); + if (utime(path, &tbuf) < 0 && errno != ENOENT) + msg_fatal("%s: update %s time stamps: %m", myname, path); + if (mail_queue_rename(queue_id, queue_name, dest_queue)) { + if (errno != ENOENT) + msg_fatal("%s: rename %s from %s to %s: %m", myname, + queue_id, queue_name, dest_queue); + msg_warn("%s: rename %s from %s to %s: %m", myname, + queue_id, queue_name, dest_queue); + } else if (msg_verbose) { + msg_info("%s: defer %s", myname, queue_id); + } +} + +/* qmgr_active_feed - feed one message into active queue */ + +int qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) +{ + char *myname = "qmgr_active_feed"; + QMGR_MESSAGE *message; + struct stat st; + const char *path; + + if (strcmp(scan_info->queue, MAIL_QUEUE_ACTIVE) == 0) + msg_panic("%s: bad queue %s", myname, scan_info->queue); + if (msg_verbose) + msg_info("%s: queue %s", myname, scan_info->queue); + + /* + * Make sure this is something we are willing to open. + */ + if (mail_open_ok(scan_info->queue, queue_id, &st, &path) == MAIL_OPEN_NO) + return (0); + + if (msg_verbose) + msg_info("%s: %s", myname, path); + + /* + * Skip files that have time stamps into the future. They need to cool + * down. Incoming and deferred files can have future time stamps. + */ + if ((scan_info->flags & QMGR_SCAN_ALL) == 0 + && st.st_mtime > time((time_t *) 0) + 1) { + if (msg_verbose) + msg_info("%s: skip %s (%ld seconds)", myname, queue_id, + (long) (st.st_mtime - event_time())); + return (0); + } + + /* + * Move the message to the active queue. File access errors are fatal. + */ + if (mail_queue_rename(queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE)) { + if (errno != ENOENT) + msg_fatal("%s: %s: rename from %s to %s: %m", myname, + queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE); + msg_warn("%s: %s: rename from %s to %s: %m", myname, + queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE); + return (0); + } + + /* + * Extract envelope information: sender and recipients. At this point, + * mail addresses have been processed by the cleanup service so they + * should be in canonical form. Generate requests to deliver this + * message. + * + * Throwing away queue files seems bad, especially when they made it this + * far into the mail system. Therefore we save bad files to a separate + * directory for further inspection. + * + * After queue manager restart it is possible that a queue file is still + * being delivered. In that case (the file is locked), defer delivery by + * a minimal amount of time. + */ + if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id, + scan_info->flags)) == 0) { + qmgr_active_corrupt(queue_id); + return (0); + } else if (message == QMGR_MESSAGE_LOCKED) { + qmgr_active_defer(MAIL_QUEUE_ACTIVE, queue_id, MAIL_QUEUE_INCOMING, 60); + return (0); + } else { + + /* + * Special case if all recipients were already delivered. Send any + * bounces and clean up. + */ + if (message->refcount == 0) + qmgr_active_done(message); + return (1); + } +} + +/* qmgr_active_done - dispose of message after recipients have been tried */ + +void qmgr_active_done(QMGR_MESSAGE *message) +{ + char *myname = "qmgr_active_done"; + struct stat st; + + if (msg_verbose) + msg_info("%s: %s", myname, message->queue_id); + + /* + * During a previous iteration, an attempt to bounce this message may + * have failed, so there may still be a bounce log lying around. XXX By + * groping around in the bounce queue, we're trespassing on the bounce + * service's territory. But doing so is more robust than depending on the + * bounce daemon to do the lookup for us, and for us to do the deleting + * after we have received a successful status from the bounce service. + * The bounce queue directory blocks are most likely in memory anyway. If + * these lookups become a performance problem we will have to build an + * in-core cache into the bounce daemon. + * + * Don't bounce when the bounce log is empty. The bounce process obviously + * failed, and the delivery agent will have requested that the message be + * deferred. + * + * Bounces are sent asynchronously to avoid stalling while the cleanup + * daemon waits for the qmgr to accept the "new mail" trigger. + */ + if (stat(mail_queue_path((VSTRING *) 0, MAIL_QUEUE_BOUNCE, message->queue_id), &st) == 0) { + if (st.st_size == 0) { + if (mail_queue_remove(MAIL_QUEUE_BOUNCE, message->queue_id)) + msg_fatal("remove %s %s: %m", + MAIL_QUEUE_BOUNCE, message->queue_id); + } else { + if (msg_verbose) + msg_info("%s: bounce %s", myname, message->queue_id); + if (message->verp_delims == 0 || var_verp_bounce_off) + abounce_flush(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + qmgr_active_done_2_bounce_flush, + (char *) message); + else + abounce_flush_verp(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + message->verp_delims, + qmgr_active_done_2_bounce_flush, + (char *) message); + return; + } + } + + /* + * Asynchronous processing does not reach this point. + */ + qmgr_active_done_2_generic(message); +} + +/* qmgr_active_done_2_bounce_flush - process abounce_flush() status */ + +static void qmgr_active_done_2_bounce_flush(int status, char *context) +{ + QMGR_MESSAGE *message = (QMGR_MESSAGE *) context; + + /* + * Process abounce_flush() status and continue processing. + */ + message->flags |= status; + qmgr_active_done_2_generic(message); +} + +/* qmgr_active_done_2_generic - continue processing */ + +static void qmgr_active_done_2_generic(QMGR_MESSAGE *message) +{ + char *myname = "qmgr_active_done_2_generic"; + const char *path; + struct stat st; + + /* + * A delivery agent marks a queue file as corrupt by changing its + * attributes, and by pretending that delivery was deferred. + */ + if (message->flags + && mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path) == MAIL_OPEN_NO) { + qmgr_active_corrupt(message->queue_id); + qmgr_message_free(message); + return; + } + + /* + * If we did not read all recipients from this file, go read some more, + * but remember whether some recipients have to be tried again. + * + * Throwing away queue files seems bad, especially when they made it this + * far into the mail system. Therefore we save bad files to a separate + * directory for further inspection by a human being. + */ + if (message->rcpt_offset > 0) { + if (qmgr_message_realloc(message) == 0) { + qmgr_active_corrupt(message->queue_id); + qmgr_message_free(message); + } else { + if (message->refcount == 0) + qmgr_active_done(message); /* recurse for consistency */ + } + return; + } + + /* + * If we get to this point we have tried all recipients for this message. + * If the message is too old, try to bounce it. + * + * Bounces are sent asynchronously to avoid stalling while the cleanup + * daemon waits for the qmgr to accept the "new mail" trigger. + */ + if (message->flags) { + if (event_time() > message->arrival_time + var_max_queue_time) { + msg_info("%s: from=<%s>, status=expired, returned to sender", + message->queue_id, message->sender); + if (message->verp_delims == 0 || var_verp_bounce_off) + adefer_flush(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + qmgr_active_done_3_defer_flush, + (char *) message); + else + adefer_flush_verp(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + message->verp_delims, + qmgr_active_done_3_defer_flush, + (char *) message); + return; + } else if (message->warn_time > 0 + && event_time() > message->warn_time) { + if (msg_verbose) + msg_info("%s: sending defer warning for %s", myname, message->queue_id); + adefer_warn(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + qmgr_active_done_3_defer_warn, + (char *) message); + return; + } + } + + /* + * Asynchronous processing does not reach this point. + */ + qmgr_active_done_3_generic(message); +} + +/* qmgr_active_done_3_defer_warn - continue after adefer_warn() completion */ + +static void qmgr_active_done_3_defer_warn(int status, char *context) +{ + QMGR_MESSAGE *message = (QMGR_MESSAGE *) context; + + /* + * Process adefer_warn() completion status and continue processing. + */ + if (status == 0) + qmgr_message_update_warn(message); + qmgr_active_done_3_generic(message); +} + +/* qmgr_active_done_3_defer_flush - continue after adefer_flush() completion */ + +static void qmgr_active_done_3_defer_flush(int status, char *context) +{ + QMGR_MESSAGE *message = (QMGR_MESSAGE *) context; + + /* + * Process adefer_flush() status and continue processing. + */ + message->flags = status; + qmgr_active_done_3_generic(message); +} + +/* qmgr_active_done_3_generic - continue processing */ + +static void qmgr_active_done_3_generic(QMGR_MESSAGE *message) +{ + char *myname = "qmgr_active_done_3_generic"; + int delay; + + /* + * Some recipients need to be tried again. Move the queue file time + * stamps into the future by the amount of time that the message is + * delayed, and move the message to the deferred queue. Impose minimal + * and maximal backoff times. + * + * Since we look at actual time in queue, not time since last delivery + * attempt, backoff times will be distributed. However, we can still see + * spikes in delivery activity because the interval between deferred + * queue scans is finite. + */ + if (message->flags) { + if (message->arrival_time > 0) { + delay = event_time() - message->arrival_time; + if (delay > var_max_backoff_time) + delay = var_max_backoff_time; + if (delay < var_min_backoff_time) + delay = var_min_backoff_time; + } else { + delay = var_min_backoff_time; + } + qmgr_active_defer(message->queue_name, message->queue_id, + MAIL_QUEUE_DEFERRED, delay); + } + + /* + * All recipients done. Remove the queue file. + */ + else { + if (mail_queue_remove(message->queue_name, message->queue_id)) { + if (errno != ENOENT) + msg_fatal("%s: remove %s from %s: %m", myname, + message->queue_id, message->queue_name); + msg_warn("%s: remove %s from %s: %m", myname, + message->queue_id, message->queue_name); + } else if (msg_verbose) { + msg_info("%s: remove %s", myname, message->queue_id); + } + } + + /* + * Finally, delete the in-core message structure. + */ + qmgr_message_free(message); +} + +/* qmgr_active_drain - drain active queue by allocating a delivery process */ + +void qmgr_active_drain(void) +{ + QMGR_TRANSPORT *transport; + + /* + * Allocate one delivery process for every transport with pending mail. + * The process allocation completes asynchronously. + */ + while ((transport = qmgr_transport_select()) != 0) { + if (msg_verbose) + msg_info("qmgr_active_drain: allocate %s", transport->name); + qmgr_transport_alloc(transport, qmgr_deliver); + } +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_bounce.c b/gnu/dist/postfix/src/nqmgr/qmgr_bounce.c new file mode 100644 index 00000000000..e8f01405f4d --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_bounce.c @@ -0,0 +1,79 @@ +/*++ +/* NAME +/* qmgr_bounce +/* SUMMARY +/* deal with mail that will not be delivered +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* QMGR_QUEUE *qmgr_bounce_recipient(message, recipient, format, ...) +/* QMGR_MESSAGE *message; +/* QMGR_RCPT *recipient; +/* const char *format; +/* DESCRIPTION +/* qmgr_bounce_recipient() produces a bounce log record. +/* Once the bounce record is written successfully, the recipient +/* is marked as done. When the bounce record cannot be written, +/* the message structure is updated to reflect that the mail is +/* deferred. +/* +/* Arguments: +/* .IP message +/* Open queue file with the message being bounced. +/* .IP recipient +/* The recipient that will not be delivered. +/* .IP format +/* Free-format text that describes why delivery will not happen. +/* DIAGNOSTICS +/* Panic: consistency check failure. Fatal: out of memory. +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <stdarg.h> + +/* Utility library. */ + +/* Global library. */ + +#include <bounce.h> +#include <deliver_completed.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_bounce_recipient - bounce one message recipient */ + +void qmgr_bounce_recipient(QMGR_MESSAGE *message, QMGR_RCPT *recipient, + const char *format,...) +{ + va_list ap; + int status; + + va_start(ap, format); + status = vbounce_append(BOUNCE_FLAG_KEEP, message->queue_id, + recipient->address, "none", + message->arrival_time, format, ap); + va_end(ap); + + if (status == 0) + deliver_completed(message->fp, recipient->offset); + else + message->flags |= status; +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_defer.c b/gnu/dist/postfix/src/nqmgr/qmgr_defer.c new file mode 100644 index 00000000000..72d30aac927 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_defer.c @@ -0,0 +1,164 @@ +/*++ +/* NAME +/* qmgr_defer +/* SUMMARY +/* deal with mail that must be delivered later +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* void qmgr_defer_recipient(message, address, reason) +/* QMGR_MESSAGE *message; +/* const char *address; +/* const char *reason; +/* +/* void qmgr_defer_todo(queue, reason) +/* QMGR_QUEUE *queue; +/* const char *reason; +/* +/* QMGR_QUEUE *qmgr_defer_transport(transport, reason) +/* QMGR_TRANSPORT *transport; +/* const char *reason; +/* DESCRIPTION +/* qmgr_defer_recipient() defers delivery of the named message to +/* the named recipient. It updates the message structure and writes +/* a log entry. +/* +/* qmgr_defer_todo() iterates over all "todo" deliveries queued for +/* the named site, and calls qmgr_defer_recipient() for each recipient +/* found. Side effects caused by qmgr_entry_done(), qmgr_queue_done(), +/* and by qmgr_active_done(): in-core queue entries will disappear, +/* in-core queues may disappear, in-core and on-disk messages may +/* disappear, bounces may be sent, new in-core queues, queue entries +/* and recipients may appear. +/* +/* qmgr_defer_transport() calls qmgr_defer_todo() for each queue +/* that depends on the named transport. See there for side effects. +/* +/* Arguments: +/* .IP recipient +/* A recipient address; used for logging purposes, and for updating +/* the message-specific \fIdefer\fR log. +/* .IP queue +/* Specifies a queue with delivery requests for a specific next-hop +/* host (or local user). +/* .IP transport +/* Specifies a message delivery transport. +/* .IP reason +/* Free-format text that describes why delivery is deferred; this +/* used for logging purposes, and for updating the message-specific +/* \fIdefer\fR log. +/* BUGS +/* The side effects of calling this routine are quite dramatic. +/* DIAGNOSTICS +/* Panic: consistency check failure. Fatal: out of memory. +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstream.h> + +/* Global library. */ + +#include <defer.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_defer_transport - defer todo entries for named transport */ + +void qmgr_defer_transport(QMGR_TRANSPORT *transport, const char *reason) +{ + char *myname = "qmgr_defer_transport"; + QMGR_QUEUE *queue; + QMGR_QUEUE *next; + + /* + * Sanity checks. + */ + if (reason == 0) + msg_panic("%s: null reason", myname); + if (msg_verbose) + msg_info("defer transport %s: %s", transport->name, reason); + + /* + * Proceed carefully. Queues may disappear as a side effect. + */ + for (queue = transport->queue_list.next; queue; queue = next) { + next = queue->peers.next; + qmgr_defer_todo(queue, reason); + } +} + +/* qmgr_defer_todo - defer all todo queue entries for specific site */ + +void qmgr_defer_todo(QMGR_QUEUE *queue, const char *reason) +{ + char *myname = "qmgr_defer_todo"; + QMGR_ENTRY *entry; + QMGR_ENTRY *next; + QMGR_MESSAGE *message; + QMGR_RCPT *recipient; + int nrcpt; + + /* + * Sanity checks. + */ + if (reason == 0) + msg_panic("%s: null reason", myname); + if (msg_verbose) + msg_info("defer site %s: %s", queue->name, reason); + + /* + * Proceed carefully. Queue entries will disappear as a side effect. + */ + for (entry = queue->todo.next; entry != 0; entry = next) { + next = entry->queue_peers.next; + message = entry->message; + for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) { + recipient = entry->rcpt_list.info + nrcpt; + qmgr_defer_recipient(message, recipient->address, reason); + } + qmgr_entry_done(entry, QMGR_QUEUE_TODO); + } +} + +/* qmgr_defer_recipient - defer delivery of specific recipient */ + +void qmgr_defer_recipient(QMGR_MESSAGE *message, const char *address, + const char *reason) +{ + char *myname = "qmgr_defer_recipient"; + + /* + * Sanity checks. + */ + if (reason == 0) + msg_panic("%s: reason 0", myname); + + /* + * Update the message structure and log the message disposition. + */ + message->flags |= defer_append(BOUNCE_FLAG_KEEP, message->queue_id, + address, "none", message->arrival_time, + "%s", reason); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_deliver.c b/gnu/dist/postfix/src/nqmgr/qmgr_deliver.c new file mode 100644 index 00000000000..394b267d6a9 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_deliver.c @@ -0,0 +1,349 @@ +/*++ +/* NAME +/* qmgr_deliver 3 +/* SUMMARY +/* deliver one per-site queue entry to that site +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* int qmgr_deliver_concurrency; +/* +/* int qmgr_deliver(transport, fp) +/* QMGR_TRANSPORT *transport; +/* VSTREAM *fp; +/* DESCRIPTION +/* This module implements the client side of the `queue manager +/* to delivery agent' protocol. The queue manager uses +/* asynchronous I/O so that it can drive multiple delivery +/* agents in parallel. Depending on the outcome of a delivery +/* attempt, the status of messages, queues and transports is +/* updated. +/* +/* qmgr_deliver_concurrency is a global counter that says how +/* many delivery processes are in use. This can be used, for +/* example, to control the size of the `active' message queue. +/* +/* qmgr_deliver() executes when a delivery process announces its +/* availability for the named transport. It arranges for delivery +/* of a suitable queue entry. The \fIfp\fR argument specifies a +/* stream that is connected to the delivery process. Upon completion +/* of delivery (successful or not), the stream is closed, so that the +/* delivery process is released. +/* DIAGNOSTICS +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <time.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <vstream.h> +#include <vstring_vstream.h> +#include <events.h> +#include <iostuff.h> + +/* Global library. */ + +#include <mail_queue.h> +#include <mail_proto.h> +#include <recipient_list.h> +#include <mail_params.h> +#include <deliver_request.h> +#include <verp_sender.h> + +/* Application-specific. */ + +#include "qmgr.h" + +int qmgr_deliver_concurrency; + + /* + * Message delivery status codes. + */ +#define DELIVER_STAT_OK 0 /* all recipients delivered */ +#define DELIVER_STAT_DEFER 1 /* try some recipients later */ +#define DELIVER_STAT_CRASH 2 /* mailer internal problem */ + +/* qmgr_deliver_initial_reply - retrieve initial delivery process response */ + +static int qmgr_deliver_initial_reply(VSTREAM *stream) +{ + int stat; + + if (peekfd(vstream_fileno(stream)) < 0) { + msg_warn("%s: premature disconnect", VSTREAM_PATH(stream)); + return (DELIVER_STAT_CRASH); + } else if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat, + ATTR_TYPE_END) != 1) { + msg_warn("%s: malformed response", VSTREAM_PATH(stream)); + return (DELIVER_STAT_CRASH); + } else { + return (stat ? DELIVER_STAT_DEFER : 0); + } +} + +/* qmgr_deliver_final_reply - retrieve final delivery process response */ + +static int qmgr_deliver_final_reply(VSTREAM *stream, VSTRING *reason) +{ + int stat; + + if (peekfd(vstream_fileno(stream)) < 0) { + msg_warn("%s: premature disconnect", VSTREAM_PATH(stream)); + return (DELIVER_STAT_CRASH); + } else if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_WHY, reason, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat, + ATTR_TYPE_END) != 2) { + msg_warn("%s: malformed response", VSTREAM_PATH(stream)); + return (DELIVER_STAT_CRASH); + } else { + return (stat ? DELIVER_STAT_DEFER : 0); + } +} + +/* qmgr_deliver_send_request - send delivery request to delivery process */ + +static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) +{ + QMGR_RCPT_LIST list = entry->rcpt_list; + QMGR_RCPT *recipient; + QMGR_MESSAGE *message = entry->message; + char *cp; + VSTRING *sender_buf = 0; + char *sender; + int flags; + char *nexthop; + + /* + * If variable envelope return path is requested, change prefix+@origin + * into prefix+user=domain@origin. Note that with VERP there is only one + * recipient per delivery. + */ + if (message->verp_delims == 0) { + sender = message->sender; + } else { + sender_buf = vstring_alloc(100); + verp_sender(sender_buf, message->verp_delims, + message->sender, list.info->address); + sender = vstring_str(sender_buf); + } + + /* + * With mail transports that accept only one recipient per delivery, the + * queue name is user@nexthop, so that we can implement per-recipient + * concurrency limits. However, the delivery agent protocol expects + * nexthop only, so we must strip off the recipient local part. + */ + flags = message->inspect_xport ? + DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT; + nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? + cp + 1 : entry->queue->name; + attr_print(stream, ATTR_FLAG_MORE, + 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_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_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_LONG, MAIL_ATTR_OFFSET, recipient->offset, + ATTR_TYPE_STR, MAIL_ATTR_RECIP, recipient->address, + ATTR_TYPE_END); + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0, + ATTR_TYPE_END); + if (vstream_fflush(stream) != 0) { + msg_warn("write to process (%s): %m", entry->queue->transport->name); + return (-1); + } else { + if (msg_verbose) + msg_info("qmgr_deliver: site `%s'", entry->queue->name); + return (0); + } +} + +/* qmgr_deliver_abort - transport response watchdog */ + +static void qmgr_deliver_abort(int unused_event, char *context) +{ + QMGR_ENTRY *entry = (QMGR_ENTRY *) context; + QMGR_QUEUE *queue = entry->queue; + QMGR_TRANSPORT *transport = queue->transport; + QMGR_MESSAGE *message = entry->message; + + msg_fatal("%s: timeout receiving delivery status from transport: %s", + message->queue_id, transport->name); +} + +/* qmgr_deliver_update - process delivery status report */ + +static void qmgr_deliver_update(int unused_event, char *context) +{ + QMGR_ENTRY *entry = (QMGR_ENTRY *) context; + QMGR_QUEUE *queue = entry->queue; + QMGR_TRANSPORT *transport = queue->transport; + QMGR_MESSAGE *message = entry->message; + VSTRING *reason = vstring_alloc(1); + int status; + + /* + * The message transport has responded. Stop the watchdog timer. + */ + event_cancel_timer(qmgr_deliver_abort, context); + + /* + * Retrieve the delivery agent status report. The numerical status code + * indicates if delivery should be tried again. The reason text is sent + * only when a site should be avoided for a while, so that the queue + * manager can log why it does not even try to schedule delivery to the + * affected recipients. + */ + status = qmgr_deliver_final_reply(entry->stream, reason); + + /* + * The mail delivery process failed for some reason (although delivery + * may have been successful). Back off with this transport type for a + * while. Dispose of queue entries for this transport that await + * selection (the todo lists). Stay away from queue entries that have + * been selected (the busy lists), or we would have dangling pointers. + * The queue itself won't go away before we dispose of the current queue + * entry. + */ + if (status == DELIVER_STAT_CRASH) { + message->flags |= DELIVER_STAT_DEFER; + qmgr_transport_throttle(transport, "unknown mail transport error"); + msg_warn("transport %s failure -- see a previous warning/fatal/panic logfile record for the problem description", + transport->name); + qmgr_defer_transport(transport, transport->reason); + } + + /* + * This message must be tried again. + * + * If we have a problem talking to this site, back off with this site for a + * while; dispose of queue entries for this site that await selection + * (the todo list); stay away from queue entries that have been selected + * (the busy list), or we would have dangling pointers. The queue itself + * won't go away before we dispose of the current queue entry. + */ + if (status == DELIVER_STAT_DEFER) { + message->flags |= DELIVER_STAT_DEFER; + if (VSTRING_LEN(reason)) { + qmgr_queue_throttle(queue, vstring_str(reason)); + if (queue->window == 0) + qmgr_defer_todo(queue, queue->reason); + } + } + + /* + * No problems detected. Mark the transport and queue as alive. The queue + * itself won't go away before we dispose of the current queue entry. + */ + if (status == 0) { + qmgr_transport_unthrottle(transport); + qmgr_queue_unthrottle(queue); + } + + /* + * Release the delivery process, and give some other queue entry a chance + * to be delivered. When all recipients for a message have been tried, + * decide what to do next with this message: defer, bounce, delete. + */ + event_disable_readwrite(vstream_fileno(entry->stream)); + if (vstream_fclose(entry->stream) != 0) + msg_warn("qmgr_deliver_update: close delivery stream: %m"); + entry->stream = 0; + qmgr_deliver_concurrency--; + qmgr_entry_done(entry, QMGR_QUEUE_BUSY); + vstring_free(reason); +} + +/* qmgr_deliver - deliver one per-site queue entry */ + +void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream) +{ + QMGR_ENTRY *entry; + + /* + * Find out if this delivery process is really available. Once elected, + * the delivery process is supposed to express its happiness. If there is + * a problem, wipe the pending deliveries for this transport. This + * routine runs in response to an external event, so it does not run + * while some other queue manipulation is happening. + */ + if (qmgr_deliver_initial_reply(stream) != 0) { + qmgr_transport_throttle(transport, "mail transport unavailable"); + qmgr_defer_transport(transport, transport->reason); + (void) vstream_fclose(stream); + return; + } + + /* + * Find a suitable queue entry. Things may have changed since this + * transport was allocated. If no suitable entry is found, + * unceremoniously disconnect from the delivery process. The delivery + * agent request reading routine is prepared for the queue manager to + * change its mind for no apparent reason. + */ + if ((entry = qmgr_job_entry_select(transport)) == 0) { + (void) vstream_fclose(stream); + return; + } + + /* + * Send the queue file info and recipient info to the delivery process. + * If there is a problem, wipe the pending deliveries for this transport. + * This routine runs in response to an external event, so it does not run + * while some other queue manipulation is happening. + */ + if (qmgr_deliver_send_request(entry, stream) < 0) { + qmgr_entry_unselect(entry); + qmgr_transport_throttle(transport, "mail transport unavailable"); + qmgr_defer_transport(transport, transport->reason); + /* warning: entry may be a dangling pointer here */ + (void) vstream_fclose(stream); + return; + } + + /* + * If we get this far, go wait for the delivery status report. + */ + qmgr_deliver_concurrency++; + entry->stream = stream; + event_enable_read(vstream_fileno(stream), + qmgr_deliver_update, (char *) entry); + + /* + * Guard against broken systems. + */ + event_request_timer(qmgr_deliver_abort, (char *) entry, var_daemon_timeout); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_enable.c b/gnu/dist/postfix/src/nqmgr/qmgr_enable.c new file mode 100644 index 00000000000..5f0c3841b91 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_enable.c @@ -0,0 +1,107 @@ +/*++ +/* NAME +/* qmgr_enable +/* SUMMARY +/* enable dead transports or sites +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* void qmgr_enable_queue(queue) +/* QMGR_QUEUE *queue; +/* +/* QMGR_QUEUE *qmgr_enable_transport(transport) +/* QMGR_TRANSPORT *transport; +/* +/* void qmgr_enable_all(void) +/* DESCRIPTION +/* This module purges dead in-core state information, effectively +/* re-enabling delivery. +/* +/* qmgr_enable_queue() enables deliveries to the named dead site. +/* Empty queues are destroyed. The existed solely to indicate that +/* a site is dead. +/* +/* qmgr_enable_transport() enables deliveries via the specified +/* transport, and calls qmgr_enable_queue() for each destination +/* on that transport. Empty queues are destroyed. +/* +/* qmgr_enable_all() enables all transports and queues. +/* See above for the side effects caused by doing this. +/* BUGS +/* The side effects of calling this module can be quite dramatic. +/* DIAGNOSTICS +/* Panic: consistency check failure. Fatal: out of memory. +/* 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. */ + +#include <msg.h> +#include <vstream.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_enable_all - enable transports and queues */ + +void qmgr_enable_all(void) +{ + QMGR_TRANSPORT *xport; + + if (msg_verbose) + msg_info("qmgr_enable_all"); + + /* + * The number of transports does not change as a side effect, so this can + * be a straightforward loop. + */ + for (xport = qmgr_transport_list.next; xport; xport = xport->peers.next) + qmgr_enable_transport(xport); +} + +/* qmgr_enable_transport - defer todo entries for named transport */ + +void qmgr_enable_transport(QMGR_TRANSPORT *transport) +{ + QMGR_QUEUE *queue; + QMGR_QUEUE *next; + + /* + * Proceed carefully. Queues may disappear as a side effect. + */ + if (transport->flags & QMGR_TRANSPORT_STAT_DEAD) { + if (msg_verbose) + msg_info("enable transport %s", transport->name); + qmgr_transport_unthrottle(transport); + } + for (queue = transport->queue_list.next; queue; queue = next) { + next = queue->peers.next; + qmgr_enable_queue(queue); + } +} + +/* qmgr_enable_queue - enable and possibly delete queue */ + +void qmgr_enable_queue(QMGR_QUEUE *queue) +{ + if (queue->window == 0) { + if (msg_verbose) + msg_info("enable site %s/%s", queue->transport->name, queue->name); + qmgr_queue_unthrottle(queue); + } + if (queue->todo.next == 0 && queue->busy.next == 0) + qmgr_queue_done(queue); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_entry.c b/gnu/dist/postfix/src/nqmgr/qmgr_entry.c new file mode 100644 index 00000000000..64cec0b28f8 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_entry.c @@ -0,0 +1,268 @@ +/*++ +/* NAME +/* qmgr_entry 3 +/* SUMMARY +/* per-site queue entries +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* QMGR_ENTRY *qmgr_entry_create(peer, message) +/* QMGR_PEER *peer; +/* QMGR_MESSAGE *message; +/* +/* void qmgr_entry_done(entry, which) +/* QMGR_ENTRY *entry; +/* int which; +/* +/* QMGR_ENTRY *qmgr_entry_select(queue) +/* QMGR_QUEUE *queue; +/* +/* void qmgr_entry_unselect(queue, entry) +/* QMGR_QUEUE *queue; +/* QMGR_ENTRY *entry; +/* DESCRIPTION +/* These routines add/delete/manipulate per-site message +/* delivery requests. +/* +/* qmgr_entry_create() creates an entry for the named peer and message, +/* and appends the entry to the peer's list and its queue's todo list. +/* Filling in and cleaning up the recipients is the responsibility +/* of the caller. +/* +/* qmgr_entry_done() discards a per-site queue entry. The +/* \fIwhich\fR argument is either QMGR_QUEUE_BUSY for an entry +/* of the site's `busy' list (i.e. queue entries that have been +/* selected for actual delivery), or QMGR_QUEUE_TODO for an entry +/* of the site's `todo' list (i.e. queue entries awaiting selection +/* for actual delivery). +/* +/* qmgr_entry_done() discards its peer structure when the peer +/* is not referenced anymore. +/* +/* qmgr_entry_done() triggers cleanup of the per-site queue when +/* the site has no pending deliveries, and the site is either +/* alive, or the site is dead and the number of in-core queues +/* exceeds a configurable limit (see qmgr_queue_done()). +/* +/* qmgr_entry_done() triggers special action when the last in-core +/* queue entry for a message is done with: either read more +/* recipients from the queue file, delete the queue file, or move +/* the queue file to the deferred queue; send bounce reports to the +/* message originator (see qmgr_active_done()). +/* +/* qmgr_entry_select() selects first entry from the named +/* per-site queue's `todo' list for actual delivery. The entry is +/* moved to the queue's `busy' list: the list of messages being +/* delivered. The entry is also removed from its peer list. +/* +/* qmgr_entry_unselect() takes the named entry off the named +/* per-site queue's `busy' list and moves it to the queue's +/* `todo' list. The entry is also appended to its peer list again. +/* DIAGNOSTICS +/* Panic: interface violations, internal inconsistencies. +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <stdlib.h> +#include <time.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <events.h> +#include <vstream.h> + +/* Global library. */ + +#include <mail_params.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_entry_select - select queue entry for delivery */ + +QMGR_ENTRY *qmgr_entry_select(QMGR_PEER *peer) +{ + QMGR_ENTRY *entry; + QMGR_QUEUE *queue; + + if ((entry = peer->entry_list.next) != 0) { + queue = entry->queue; + QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry, queue_peers); + queue->todo_refcount--; + QMGR_LIST_APPEND(queue->busy, entry, queue_peers); + queue->busy_refcount++; + QMGR_LIST_UNLINK(peer->entry_list, QMGR_ENTRY *, entry, peer_peers); + peer->job->selected_entries++; + } + return (entry); +} + +/* qmgr_entry_unselect - unselect queue entry for delivery */ + +void qmgr_entry_unselect(QMGR_ENTRY *entry) +{ + QMGR_PEER *peer = entry->peer; + QMGR_QUEUE *queue = entry->queue; + + QMGR_LIST_UNLINK(queue->busy, QMGR_ENTRY *, entry, queue_peers); + queue->busy_refcount--; + QMGR_LIST_APPEND(queue->todo, entry, queue_peers); + queue->todo_refcount++; + QMGR_LIST_APPEND(peer->entry_list, entry, peer_peers); + peer->job->selected_entries--; +} + +/* qmgr_entry_done - dispose of queue entry */ + +void qmgr_entry_done(QMGR_ENTRY *entry, int which) +{ + QMGR_QUEUE *queue = entry->queue; + QMGR_MESSAGE *message = entry->message; + QMGR_PEER *peer = entry->peer; + QMGR_JOB *sponsor, + *job = peer->job; + QMGR_TRANSPORT *transport = job->transport; + + /* + * Take this entry off the in-core queue. + */ + if (entry->stream != 0) + msg_panic("qmgr_entry_done: file is open"); + if (which == QMGR_QUEUE_BUSY) { + QMGR_LIST_UNLINK(queue->busy, QMGR_ENTRY *, entry, queue_peers); + queue->busy_refcount--; + } else if (which == QMGR_QUEUE_TODO) { + QMGR_LIST_UNLINK(peer->entry_list, QMGR_ENTRY *, entry, peer_peers); + job->selected_entries++; + QMGR_LIST_UNLINK(queue->todo, QMGR_ENTRY *, entry, queue_peers); + queue->todo_refcount--; + } else { + msg_panic("qmgr_entry_done: bad queue spec: %d", which); + } + + /* + * Decrease the in-core recipient counts and free the recipient list and + * the structure itself. + */ + job->rcpt_count -= entry->rcpt_list.len; + message->rcpt_count -= entry->rcpt_list.len; + qmgr_recipient_count -= entry->rcpt_list.len; + qmgr_rcpt_list_free(&entry->rcpt_list); + myfree((char *) entry); + + /* + * Make sure that the transport of any retired or finishing job that + * donated recipient slots to this message gets them back first. Then, if + * possible, pass the remaining unused recipient slots to the next job on + * the job list. + */ + for (sponsor = message->job_list.next; sponsor; sponsor = sponsor->message_peers.next) { + if (sponsor->rcpt_count >= sponsor->rcpt_limit || sponsor == job) + continue; + if (sponsor->stack_level < 0 || message->rcpt_offset == 0) + qmgr_job_move_limits(sponsor); + } + if (message->rcpt_offset == 0) { + qmgr_job_move_limits(job); + } + + /* + * If the queue was blocking some of the jobs on the job list, check if + * the concurrency limit has lifted. If there are still some pending + * deliveries, give it a try and unmark all transport blockers at once. + * The qmgr_job_entry_select() will do the rest. In either case make sure + * the queue is not marked as a blocker anymore, with extra handling of + * queues which were declared dead. + * + * Note that changing the blocker status also affects the candidate cache. + * Most of the cases would be automatically recognized by the current job + * change, but we play safe and reset the cache explicitly below. + * + * Keeping the transport blocker tag odd is an easy way to make sure the tag + * never matches jobs that are not explicitly marked as blockers. + */ + if (queue->blocker_tag == transport->blocker_tag) { + if (queue->window > queue->busy_refcount && queue->todo.next != 0) { + transport->blocker_tag += 2; + transport->job_current = transport->job_list.next; + transport->candidate_cache_current = 0; + } + if (queue->window > queue->busy_refcount || queue->window == 0) + queue->blocker_tag = 0; + } + + /* + * When there are no more entries for this peer, discard the peer + * structure. + */ + peer->refcount--; + if (peer->refcount == 0) + qmgr_peer_free(peer); + + /* + * When the in-core queue for this site is empty and when this site is + * not dead, discard the in-core queue. When this site is dead, but the + * number of in-core queues exceeds some threshold, get rid of this + * in-core queue anyway, in order to avoid running out of memory. + */ + if (queue->todo.next == 0 && queue->busy.next == 0) { + if (queue->window == 0 && qmgr_queue_count > 2 * var_qmgr_rcpt_limit) + qmgr_queue_unthrottle(queue); + if (queue->window > 0) + qmgr_queue_done(queue); + } + + /* + * Update the in-core message reference count. When the in-core message + * structure has no more references, dispose of the message. + */ + message->refcount--; + if (message->refcount == 0) + qmgr_active_done(message); +} + +/* qmgr_entry_create - create queue todo entry */ + +QMGR_ENTRY *qmgr_entry_create(QMGR_PEER *peer, QMGR_MESSAGE *message) +{ + QMGR_ENTRY *entry; + QMGR_QUEUE *queue = peer->queue; + + /* + * Sanity check. + */ + if (queue->window == 0) + msg_panic("qmgr_entry_create: dead queue: %s", queue->name); + + entry = (QMGR_ENTRY *) mymalloc(sizeof(QMGR_ENTRY)); + entry->stream = 0; + entry->message = message; + qmgr_rcpt_list_init(&entry->rcpt_list); + message->refcount++; + entry->peer = peer; + QMGR_LIST_APPEND(peer->entry_list, entry, peer_peers); + peer->refcount++; + entry->queue = queue; + QMGR_LIST_APPEND(queue->todo, entry, queue_peers); + queue->todo_refcount++; + return (entry); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_job.c b/gnu/dist/postfix/src/nqmgr/qmgr_job.c new file mode 100644 index 00000000000..094838b77e2 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_job.c @@ -0,0 +1,912 @@ +/*++ +/* NAME +/* qmgr_job 3 +/* SUMMARY +/* per-transport jobs +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* QMGR_JOB *qmgr_job_obtain(message, transport) +/* QMGR_MESSAGE *message; +/* QMGR_TRANSPORT *transport; +/* +/* void qmgr_job_free(job) +/* QMGR_JOB *job; +/* +/* void qmgr_job_move_limits(job) +/* QMGR_JOB *job; +/* +/* QMGR_ENTRY *qmgr_job_entry_select(transport) +/* QMGR_TRANSPORT *transport; +/* DESCRIPTION +/* These routines add/delete/manipulate per-transport jobs. +/* Each job corresponds to a specific transport and message. +/* Each job has a peer list containing all pending delivery +/* requests for that message. +/* +/* qmgr_job_obtain() finds an existing job for named message and +/* transport combination. New empty job is created if no existing can +/* be found. In either case, the job is prepared for assignement of +/* (more) message recipients. +/* +/* qmgr_job_free() disposes of a per-transport job after all +/* its entries have been taken care of. It is an error to dispose +/* of a job that is still in use. +/* +/* qmgr_job_entry_select() attempts to find the next entry suitable +/* for delivery. The job preempting algorithm is also exercised. +/* If necessary, an attempt to read more recipients into core is made. +/* This can result in creation of more job, queue and entry structures. +/* +/* qmgr_job_move_limits() takes care of proper distribution of the +/* per-transport recipients limit among the per-transport jobs. +/* Should be called whenever a job's recipient slot becomes available. +/* DIAGNOSTICS +/* Panic: consistency check failure. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Patrik Rak +/* patrik@raxoft.cz +/*--*/ + +/* System library. */ + +#include <sys_defs.h> + +/* Utility library. */ + +#include <msg.h> +#include <htable.h> +#include <mymalloc.h> +#include <sane_time.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* Forward declarations */ + +static void qmgr_job_pop(QMGR_JOB *); + +/* Helper macros */ + +#define HAS_ENTRIES(job) ((job)->selected_entries < (job)->read_entries) + +/* + * The MIN_ENTRIES macro may underestimate a lot but we can't use message->rcpt_unread + * because we don't know if all those unread recipients go to our transport yet. + */ + +#define MIN_ENTRIES(job) ((job)->read_entries) +#define MAX_ENTRIES(job) ((job)->read_entries + (job)->message->rcpt_unread) + +#define RESET_CANDIDATE_CACHE(transport) ((transport)->candidate_cache_current = 0) + +#define IS_BLOCKER(job,transport) ((job)->blocker_tag == (transport)->blocker_tag) + +/* qmgr_job_create - create and initialize message job structure */ + +static QMGR_JOB *qmgr_job_create(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport) +{ + QMGR_JOB *job; + + job = (QMGR_JOB *) mymalloc(sizeof(QMGR_JOB)); + job->message = message; + QMGR_LIST_APPEND(message->job_list, job, message_peers); + htable_enter(transport->job_byname, message->queue_id, (char *) job); + job->transport = transport; + QMGR_LIST_INIT(job->transport_peers); + QMGR_LIST_INIT(job->time_peers); + job->stack_parent = 0; + QMGR_LIST_INIT(job->stack_children); + QMGR_LIST_INIT(job->stack_siblings); + job->stack_level = -1; + job->blocker_tag = 0; + job->peer_byname = htable_create(0); + QMGR_LIST_INIT(job->peer_list); + job->slots_used = 0; + job->slots_available = 0; + job->selected_entries = 0; + job->read_entries = 0; + job->rcpt_count = 0; + job->rcpt_limit = 0; + return (job); +} + +/* qmgr_job_link - append the job to the job lists based on the time it was queued */ + +static void qmgr_job_link(QMGR_JOB *job) +{ + QMGR_TRANSPORT *transport = job->transport; + QMGR_MESSAGE *message = job->message; + QMGR_JOB *prev, + *next, + *list_prev, + *list_next, + *unread, + *current; + int delay; + + /* + * Sanity checks. + */ + if (job->stack_level >= 0) + msg_panic("qmgr_job_link: already on the job lists (%d)", job->stack_level); + + /* + * Traverse the time list and the scheduler list from the end and stop + * when we found job older than the one beeing linked. + * + * During the traversals keep track if we have come accross either the + * current job or the first unread job on the job list. If this is the + * case, these pointers will be adjusted below as required. + * + * Although both lists are exactly the same when only jobs on the stack + * level zero are considered, it's easier to traverse them separately. + * Otherwise it's impossible to keep track of the current job pointer + * effectively. + * + * This may look inefficient but under normal operation it is expected that + * the loops will stop right away, resulting in normal list appends + * below. However, this code is necessary for reviving retired jobs and + * for jobs which are created long after the first chunk of recipients + * was read in-core (either of these can happen only for multi-transport + * messages). + */ + current = transport->job_current; + for (next = 0, prev = transport->job_list.prev; prev; + next = prev, prev = prev->transport_peers.prev) { + if (prev->stack_parent == 0) { + delay = message->queued_time - prev->message->queued_time; + if (delay >= 0) + break; + } + if (current == prev) + current = 0; + } + list_prev = prev; + list_next = next; + + unread = transport->job_next_unread; + for (next = 0, prev = transport->job_bytime.prev; prev; + next = prev, prev = prev->time_peers.prev) { + delay = message->queued_time - prev->message->queued_time; + if (delay >= 0) + break; + if (unread == prev) + unread = 0; + } + + /* + * Link the job into the proper place on the job lists and mark it so we + * know it has been linked. + */ + job->stack_level = 0; + QMGR_LIST_LINK(transport->job_list, list_prev, job, list_next, transport_peers); + QMGR_LIST_LINK(transport->job_bytime, prev, job, next, time_peers); + + /* + * Update the current job pointer if necessary. + */ + if (current == 0) + transport->job_current = job; + + /* + * Update the pointer to the first unread job on the job list and steal + * the unused recipient slots from the old one. + */ + if (unread == 0) { + unread = transport->job_next_unread; + transport->job_next_unread = job; + if (unread != 0) + qmgr_job_move_limits(unread); + } + + /* + * Get as much recipient slots as possible. The excess will be returned + * to the transport pool as soon as the exact amount required is known + * (which is usually after all recipients have been read in core). + */ + if (transport->rcpt_unused > 0) { + job->rcpt_limit += transport->rcpt_unused; + message->rcpt_limit += transport->rcpt_unused; + transport->rcpt_unused = 0; + } +} + +/* qmgr_job_find - lookup job associated with named message and transport */ + +static QMGR_JOB *qmgr_job_find(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport) +{ + + /* + * Instead of traversing the message job list, we use single per + * transport hash table. This is better (at least with respect to memory + * usage) than having single hash table (usually almost empty) for each + * message. + */ + return ((QMGR_JOB *) htable_find(transport->job_byname, message->queue_id)); +} + +/* qmgr_job_obtain - find/create the appropriate job and make it ready for new recipients */ + +QMGR_JOB *qmgr_job_obtain(QMGR_MESSAGE *message, QMGR_TRANSPORT *transport) +{ + QMGR_JOB *job; + + /* + * Try finding an existing job, reviving it if it was already retired. + * Create a new job for this transport/message combination otherwise. In + * either case, the job ends linked on the job lists. + */ + if ((job = qmgr_job_find(message, transport)) == 0) + job = qmgr_job_create(message, transport); + if (job->stack_level < 0) + qmgr_job_link(job); + + /* + * Reset the candidate cache because of the new expected recipients. Make + * sure the job is not marked as a blocker for the same reason. Note that + * this can result in having a non-blocker followed by more blockers. + * Consequently, we can't just update the current job pointer, we have to + * reset it. Fortunately qmgr_job_entry_select() will easily deal with + * this and will lookup the real current job for us. + */ + RESET_CANDIDATE_CACHE(transport); + if (IS_BLOCKER(job, transport)) { + job->blocker_tag = 0; + transport->job_current = transport->job_list.next; + } + return (job); +} + +/* qmgr_job_move_limits - move unused recipient slots to the next unread job */ + +void qmgr_job_move_limits(QMGR_JOB *job) +{ + QMGR_TRANSPORT *transport = job->transport; + QMGR_MESSAGE *message = job->message; + QMGR_JOB *next = transport->job_next_unread; + int rcpt_unused, + msg_rcpt_unused; + + /* + * Find next unread job on the job list if necessary. Cache it for later. + * This makes the amortized efficiency of this routine O(1) per job. Note + * that we use the time list whose ordering doesn't change over time. + */ + if (job == next) { + for (next = next->time_peers.next; next; next = next->time_peers.next) + if (next->message->rcpt_offset != 0) + break; + transport->job_next_unread = next; + } + + /* + * Calculate the number of available unused slots. + */ + rcpt_unused = job->rcpt_limit - job->rcpt_count; + msg_rcpt_unused = message->rcpt_limit - message->rcpt_count; + if (msg_rcpt_unused < rcpt_unused) + rcpt_unused = msg_rcpt_unused; + + /* + * Transfer the unused recipient slots back to the transport pool and to + * the next not-fully-read job. Job's message limits are adjusted + * accordingly. Note that the transport pool can be negative if we used + * some of the rcpt_per_stack slots. + */ + if (rcpt_unused > 0) { + job->rcpt_limit -= rcpt_unused; + message->rcpt_limit -= rcpt_unused; + transport->rcpt_unused += rcpt_unused; + if (next != 0 && (rcpt_unused = transport->rcpt_unused) > 0) { + next->rcpt_limit += rcpt_unused; + next->message->rcpt_limit += rcpt_unused; + transport->rcpt_unused = 0; + } + } +} + +/* qmgr_job_parent_gone - take care of orphaned stack children */ + +static void qmgr_job_parent_gone(QMGR_JOB *job, QMGR_JOB *parent) +{ + QMGR_JOB *child; + + while ((child = job->stack_children.next) != 0) { + QMGR_LIST_UNLINK(job->stack_children, QMGR_JOB *, child, stack_siblings); + if (parent != 0) + QMGR_LIST_APPEND(parent->stack_children, child, stack_siblings); + child->stack_parent = parent; + } +} + +/* qmgr_job_unlink - unlink the job from the job lists */ + +static void qmgr_job_unlink(QMGR_JOB *job) +{ + char *myname = "qmgr_job_unlink"; + QMGR_TRANSPORT *transport = job->transport; + + /* + * Sanity checks. + */ + if (job->stack_level != 0) + msg_panic("%s: non-zero stack level (%d)", myname, job->stack_level); + if (job->stack_parent != 0) + msg_panic("%s: parent present", myname); + if (job->stack_siblings.next != 0) + msg_panic("%s: siblings present", myname); + + /* + * Make sure that children of job on zero stack level are informed that + * their parent is gone too. + */ + qmgr_job_parent_gone(job, 0); + + /* + * Update the current job pointer if necessary. + */ + if (transport->job_current == job) + transport->job_current = job->transport_peers.next; + + /* + * Invalidate the candidate selection cache if necessary. + */ + if (job == transport->candidate_cache + || job == transport->candidate_cache_current) + RESET_CANDIDATE_CACHE(transport); + + /* + * Remove the job from the job lists and mark it as unlinked. + */ + QMGR_LIST_UNLINK(transport->job_list, QMGR_JOB *, job, transport_peers); + QMGR_LIST_UNLINK(transport->job_bytime, QMGR_JOB *, job, time_peers); + job->stack_level = -1; +} + +/* qmgr_job_retire - remove the job from the job lists while waiting for recipients to deliver */ + +static void qmgr_job_retire(QMGR_JOB *job) +{ + if (msg_verbose) + msg_info("qmgr_job_retire: %s", job->message->queue_id); + + /* + * Pop the job from the job stack if necessary. + */ + if (job->stack_level > 0) + qmgr_job_pop(job); + + /* + * Make sure this job is not cached as the next unread job for this + * transport. The qmgr_entry_done() will make sure that the slots donated + * by this job are moved back to the transport pool as soon as possible. + */ + qmgr_job_move_limits(job); + + /* + * Remove the job from the job lists. Note that it remains on the message + * job list, though, and that it can be revived by using + * qmgr_job_obtain(). Also note that the available slot counter is left + * intact. + */ + qmgr_job_unlink(job); +} + +/* qmgr_job_free - release the job structure */ + +void qmgr_job_free(QMGR_JOB *job) +{ + char *myname = "qmgr_job_free"; + QMGR_MESSAGE *message = job->message; + QMGR_TRANSPORT *transport = job->transport; + + if (msg_verbose) + msg_info("%s: %s %s", myname, message->queue_id, transport->name); + + /* + * Sanity checks. + */ + if (job->rcpt_count) + msg_panic("%s: non-zero recipient count (%d)", myname, job->rcpt_count); + + /* + * Pop the job from the job stack if necessary. + */ + if (job->stack_level > 0) + qmgr_job_pop(job); + + /* + * Return any remaining recipient slots back to the recipient slots pool. + */ + qmgr_job_move_limits(job); + if (job->rcpt_limit) + msg_panic("%s: recipient slots leak (%d)", myname, job->rcpt_limit); + + /* + * Unlink and discard the structure. Check if the job is still linked on + * the job lists or if it was already retired before unlinking it. + */ + if (job->stack_level >= 0) + qmgr_job_unlink(job); + QMGR_LIST_UNLINK(message->job_list, QMGR_JOB *, job, message_peers); + htable_delete(transport->job_byname, message->queue_id, (void (*) (char *)) 0); + htable_free(job->peer_byname, (void (*) (char *)) 0); + myfree((char *) job); +} + +/* qmgr_job_count_slots - maintain the delivery slot counters */ + +static void qmgr_job_count_slots(QMGR_JOB *job) +{ + + /* + * Count the number of delivery slots used during the delivery of the + * selected job. Also count the number of delivery slots available for + * its preemption. + * + * Despite its trivial look, this is one of the key parts of the theory + * behind this preempting scheduler. + */ + job->slots_available++; + job->slots_used++; + + /* + * If the selected job is not the original current job, reset the + * candidate cache because the change above have slightly increased the + * chance of this job becoming a candidate next time. + * + * Don't expect that the change of the current jobs this turn will render + * the candidate cache invalid the next turn - it can happen that the + * next turn the original current job will be selected again and the + * cache would be considered valid in such case. + */ + if (job != job->transport->candidate_cache_current) + RESET_CANDIDATE_CACHE(job->transport); +} + +/* qmgr_job_candidate - find best job candidate for preempting given job */ + +static QMGR_JOB *qmgr_job_candidate(QMGR_JOB *current) +{ + QMGR_TRANSPORT *transport = current->transport; + QMGR_JOB *job, + *best_job = 0; + double score, + best_score = 0.0; + int max_slots, + max_needed_entries, + max_total_entries; + int delay; + time_t now = sane_time(); + + /* + * Fetch the result directly from the cache if the cache is still valid. + * + * Note that we cache negative results too, so the cache must be invalidated + * by resetting the cached current job pointer, not the candidate pointer + * itself. + * + * In case the cache is valid and contains no candidate, we can ignore the + * time change, as it affects only which candidate is the best, not if + * one exists. However, this feature requires that we no longer relax the + * cache resetting rules, depending on the automatic cache timeout. + */ + if (transport->candidate_cache_current == current + && (transport->candidate_cache_time == now + || transport->candidate_cache == 0)) + return (transport->candidate_cache); + + /* + * Estimate the minimum amount of delivery slots that can ever be + * accumulated for the given job. All jobs that won't fit into these + * slots are excluded from the candidate selection. + */ + max_slots = (MIN_ENTRIES(current) - current->selected_entries + + current->slots_available) / transport->slot_cost; + + /* + * Select the candidate with best time_since_queued/total_recipients + * score. In addition to jobs which don't meet the max_slots limit, skip + * also jobs which don't have any selectable entries at the moment. + * + * Instead of traversing the whole job list we traverse it just from the + * current job forward. This has several advantages. First, we skip some + * of the blocker jobs and the current job itself right away. But the + * really important advantage is that we are sure that we don't consider + * any jobs that are already stack children of the current job. Thanks to + * this we can easily include all encountered jobs which are leaf + * children of some of the preempting stacks as valid candidates. All we + * need to do is to make sure we do not include any of the stack parents. + * And, because the leaf children are not ordered by the time since + * queued, we have to exclude them from the early loop end test. + * + * However, don't bother searching if we can't find anything suitable + * anyway. + */ + if (max_slots > 0) { + for (job = current->transport_peers.next; job; job = job->transport_peers.next) { + if (job->stack_children.next != 0 || IS_BLOCKER(job, transport)) + continue; + max_total_entries = MAX_ENTRIES(job); + max_needed_entries = max_total_entries - job->selected_entries; + delay = now - job->message->queued_time + 1; + if (max_needed_entries > 0 && max_needed_entries <= max_slots) { + score = (double) delay / max_total_entries; + if (score > best_score) { + best_score = score; + best_job = job; + } + } + + /* + * Stop early if the best score is as good as it can get. + */ + if (delay <= best_score && job->stack_level == 0) + break; + } + } + + /* + * Cache the result for later use. + */ + transport->candidate_cache = best_job; + transport->candidate_cache_current = current; + transport->candidate_cache_time = now; + + return (best_job); +} + +/* qmgr_job_preempt - preempt large message with smaller one */ + +static QMGR_JOB *qmgr_job_preempt(QMGR_JOB *current) +{ + char *myname = "qmgr_job_preempt"; + QMGR_TRANSPORT *transport = current->transport; + QMGR_JOB *job, + *prev; + int expected_slots; + int rcpt_slots; + + /* + * Suppress preempting completely if the current job is not big enough to + * accumulate even the mimimal number of slots required. + * + * Also, don't look for better job candidate if there are no available slots + * yet (the count can get negative due to the slot loans below). + */ + if (current->slots_available <= 0 + || MAX_ENTRIES(current) < transport->min_slots * transport->slot_cost) + return (current); + + /* + * Find best candidate for preempting the current job. + * + * Note that the function also takes care that the candidate fits within the + * number of delivery slots which the current job is still able to + * accumulate. + */ + if ((job = qmgr_job_candidate(current)) == 0) + return (current); + + /* + * Sanity checks. + */ + if (job == current) + msg_panic("%s: attempt to preempt itself", myname); + if (job->stack_children.next != 0) + msg_panic("%s: already on the job stack (%d)", myname, job->stack_level); + if (job->stack_level < 0) + msg_panic("%s: not on the job list (%d)", myname, job->stack_level); + + /* + * Check if there is enough available delivery slots accumulated to + * preempt the current job. + * + * The slot loaning scheme improves the average message response time. Note + * that the loan only allows the preemption happen earlier, though. It + * doesn't affect how many slots have to be "paid" - in either case the + * full number of slots required has to be accumulated later before the + * current job can be preempted again. + */ + expected_slots = MAX_ENTRIES(job) - job->selected_entries; + if (current->slots_available / transport->slot_cost + transport->slot_loan + < expected_slots * transport->slot_loan_factor / 100.0) + return (current); + + /* + * Preempt the current job. + * + * This involves placing the selected candidate in front of the current job + * on the job list and updating the stack parent/child/sibling pointers + * appropriately. But first we need to make sure that the candidate is + * taken from its previous job stack which it might be top of. + */ + if (job->stack_level > 0) + qmgr_job_pop(job); + QMGR_LIST_UNLINK(transport->job_list, QMGR_JOB *, job, transport_peers); + prev = current->transport_peers.prev; + QMGR_LIST_LINK(transport->job_list, prev, job, current, transport_peers); + job->stack_parent = current; + QMGR_LIST_APPEND(current->stack_children, job, stack_siblings); + job->stack_level = current->stack_level + 1; + + /* + * Update the current job pointer and explicitly reset the candidate + * cache. + */ + transport->job_current = job; + RESET_CANDIDATE_CACHE(transport); + + /* + * Since the single job can be preempted by several jobs at the same + * time, we have to adjust the available slot count now to prevent using + * the same slots multiple times. To do that we subtract the number of + * slots the preempting job will supposedly use. This number will be + * corrected later when that job is popped from the stack to reflect the + * number of slots really used. + * + * As long as we don't need to keep track of how many slots were really + * used, we can (ab)use the slots_used counter for counting the + * difference between the real and expected amounts instead of the + * absolute amount. + */ + current->slots_available -= expected_slots * transport->slot_cost; + job->slots_used = -expected_slots; + + /* + * Add part of extra recipient slots reserved for preempting jobs to the + * new current job if necessary. + * + * Note that transport->rcpt_unused is within <-rcpt_per_stack,0> in such + * case. + */ + if (job->message->rcpt_offset != 0) { + rcpt_slots = (transport->rcpt_per_stack + transport->rcpt_unused + 1) / 2; + job->rcpt_limit += rcpt_slots; + job->message->rcpt_limit += rcpt_slots; + transport->rcpt_unused -= rcpt_slots; + } + if (msg_verbose) + msg_info("%s: %s by %s, level %d", myname, current->message->queue_id, + job->message->queue_id, job->stack_level); + + return (job); +} + +/* qmgr_job_pop - remove the job from its job preemption stack */ + +static void qmgr_job_pop(QMGR_JOB *job) +{ + char *myname = "qmgr_job_pop"; + QMGR_TRANSPORT *transport = job->transport; + QMGR_JOB *parent; + + if (msg_verbose) + msg_info("%s: %s", myname, job->message->queue_id); + + /* + * Sanity checks. + */ + if (job->stack_level <= 0) + msg_panic("%s: not on the job stack (%d)", myname, job->stack_level); + + /* + * Adjust the number of delivery slots available to preempt job's parent. + * + * Note that we intentionally do not adjust slots_used of the parent. Doing + * so would decrease the maximum per message inflation factor if the + * preemption appeared near the end of parent delivery. + * + * For the same reason we do not adjust parent's slots_available if the + * parent is not the original parent that was preempted by this job + * (i.e., the original parent job has already completed). + * + * This is another key part of the theory behind this preempting scheduler. + */ + if ((parent = job->stack_parent) != 0 + && job->stack_level == parent->stack_level + 1) + parent->slots_available -= job->slots_used * transport->slot_cost; + + /* + * Remove the job from its parent's children list. + */ + if (parent != 0) { + QMGR_LIST_UNLINK(parent->stack_children, QMGR_JOB *, job, stack_siblings); + job->stack_parent = 0; + } + + /* + * If there is a parent, let it adopt all those orphaned children. + * Otherwise at least notify the children that their parent is gone. + */ + qmgr_job_parent_gone(job, parent); + + /* + * Put the job back to stack level zero. + */ + job->stack_level = 0; + + /* + * Explicitely reset the candidate cache. It's not worth trying to skip + * this under some complicated conditions - in most cases the popped job + * is the current job so we would have to reset it anyway. + */ + RESET_CANDIDATE_CACHE(transport); + + /* + * Here we leave the remaining work involving the proper placement on the + * job list to the caller. The most important reason for this is that it + * allows us not to look up where exactly to place the job. + * + * The caller is also made responsible for invalidating the current job + * cache if necessary. + */ +#if 0 + QMGR_LIST_UNLINK(transport->job_list, QMGR_JOB *, job, transport_peers); + QMGR_LIST_LINK(transport->job_list, some_prev, job, some_next, transport_peers); + + if (transport->job_current == job) + transport->job_current = job->transport_peers.next; +#endif +} + +/* qmgr_job_peer_select - select next peer suitable for delivery */ + +static QMGR_PEER *qmgr_job_peer_select(QMGR_JOB *job) +{ + QMGR_PEER *peer; + QMGR_MESSAGE *message = job->message; + + if (HAS_ENTRIES(job) && (peer = qmgr_peer_select(job)) != 0) + return (peer); + + /* + * Try reading in more recipients. Note that we do not try to read them + * as soon as possible as that would decrease the chance of per-site + * recipient grouping. We waited until reading more is really necessary. + * + * XXX Workaround for logic mismatch. The message->refcount test needs + * explanation. If the refcount is zero, it means that qmgr_active_done() + * is beeing completed asynchronously. In such case, we can't read in + * more recipients as bad things would happen after qmgr_active_done() + * continues processing. Note that this results in the given job beeing + * stalled for some time, but fortunately this particular situation is so + * rare that it is not critical. Still we seek for better solution. + */ + if (message->rcpt_offset != 0 + && message->rcpt_limit > message->rcpt_count + && message->refcount > 0) { + qmgr_message_realloc(message); + if (HAS_ENTRIES(job)) + return (qmgr_peer_select(job)); + } + return (0); +} + +/* qmgr_job_entry_select - select next entry suitable for delivery */ + +QMGR_ENTRY *qmgr_job_entry_select(QMGR_TRANSPORT *transport) +{ + QMGR_JOB *job, + *next; + QMGR_PEER *peer; + QMGR_ENTRY *entry; + + /* + * Get the current job if there is one. + */ + if ((job = transport->job_current) == 0) + return (0); + + /* + * Exercise the preempting algorithm if enabled. + * + * The slot_cost equal to 1 causes the algorithm to degenerate and is + * therefore disabled too. + */ + if (transport->slot_cost >= 2) + job = qmgr_job_preempt(job); + + /* + * Select next entry suitable for delivery. In case the current job can't + * provide one because of the per-destination concurrency limits, we mark + * it as a "blocker" job and continue with the next job on the job list. + * + * Note that the loop also takes care of getting the "stall" jobs (job with + * no entries currently available) out of the way if necessary. Stall + * jobs can appear in case of multi-transport messages whose recipients + * don't fit in-core at once. Some jobs created by such message may have + * only few recipients and would stay on the job list until all other + * jobs of that message are delivered, blocking precious recipient slots + * available to this transport. Or it can happen that the job has some + * more entries but suddenly they all get deferred. Whatever the reason, + * we retire such jobs below if we happen to come across some. + */ + for ( /* empty */ ; job; job = next) { + next = job->transport_peers.next; + + /* + * Don't bother if the job is known to have no available entries + * because of the per-destination concurrency limits. + */ + if (IS_BLOCKER(job, transport)) + continue; + + if ((peer = qmgr_job_peer_select(job)) != 0) { + + /* + * We have found a suitable peer. Select one of its entries and + * adjust the delivery slot counters. + */ + entry = qmgr_entry_select(peer); + qmgr_job_count_slots(job); + + /* + * Remember the current job for the next time so we don't have to + * crawl over all those blockers again. They will be reconsidered + * when the concurrency limit permits. + */ + transport->job_current = job; + + /* + * In case we selected the very last job entry, remove the job + * from the job lists right now. + * + * This action uses the assumption that once the job entry has been + * selected, it can be unselected only before the message ifself + * is deferred. Thus the job with all entries selected can't + * re-appear with more entries available for selection again + * (without reading in more entries from the queue file, which in + * turn invokes qmgr_job_obtain() which re-links the job back on + * the lists if necessary). + * + * Note that qmgr_job_move_limits() transfers the recipients slots + * correctly even if the job is unlinked from the job list thanks + * to the job_next_unread caching. + */ + if (!HAS_ENTRIES(job) && job->message->rcpt_offset == 0) + qmgr_job_retire(job); + + /* + * Finally. Hand back the fruit of our tedious effort. + */ + return (entry); + } else if (HAS_ENTRIES(job)) { + + /* + * The job can't be selected due the concurrency limits. Mark it + * together with its queues so we know they are blocking the job + * list and they get the appropriate treatment. In particular, + * all blockers will be reconsidered when one of the problematic + * queues will accept more deliveries. And the job itself will be + * reconsidered if it is assigned some more entries. + */ + job->blocker_tag = transport->blocker_tag; + for (peer = job->peer_list.next; peer; peer = peer->peers.next) + if (peer->entry_list.next != 0) + peer->queue->blocker_tag = transport->blocker_tag; + } else { + + /* + * The job is "stalled". Retire it until it either gets freed or + * gets more entries later. + */ + qmgr_job_retire(job); + } + } + + /* + * We have not found any entry we could use for delivery. Well, things + * must have changed since this transport was selected for asynchronous + * allocation. Never mind. Clear the current job pointer and reluctantly + * report back that we have failed in our task. + */ + transport->job_current = 0; + return (0); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_message.c b/gnu/dist/postfix/src/nqmgr/qmgr_message.c new file mode 100644 index 00000000000..f83f7e0d105 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_message.c @@ -0,0 +1,1025 @@ +/*++ +/* NAME +/* qmgr_message 3 +/* SUMMARY +/* in-core message structures +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* int qmgr_message_count; +/* int qmgr_recipient_count; +/* +/* QMGR_MESSAGE *qmgr_message_alloc(class, name, qflags) +/* const char *class; +/* const char *name; +/* int qflags; +/* +/* QMGR_MESSAGE *qmgr_message_realloc(message) +/* QMGR_MESSAGE *message; +/* +/* void qmgr_message_free(message) +/* QMGR_MESSAGE *message; +/* +/* void qmgr_message_update_warn(message) +/* QMGR_MESSAGE *message; +/* DESCRIPTION +/* This module performs en-gross operations on queue messages. +/* +/* qmgr_message_count is a global counter for the total number +/* of in-core message structures (i.e. the total size of the +/* `active' message queue). +/* +/* qmgr_recipient_count is a global counter for the total number +/* of in-core recipient structures (i.e. the sum of all recipients +/* in all in-core message structures). +/* +/* qmgr_message_alloc() creates an in-core message structure +/* with sender and recipient information taken from the named queue +/* file. A null result means the queue file could not be read or +/* that the queue file contained incorrect information. A result +/* QMGR_MESSAGE_LOCKED means delivery must be deferred. The number +/* of recipients read from a queue file is limited by the global +/* var_qmgr_rcpt_limit configuration parameter. When the limit +/* is reached, the \fIrcpt_offset\fR structure member is set to +/* the position where the read was terminated. Recipients are +/* run through the resolver, and are assigned to destination +/* queues. Recipients that cannot be assigned are deferred or +/* bounced. Mail that has bounced twice is silently absorbed. +/* +/* qmgr_message_realloc() resumes reading recipients from the queue +/* file, and updates the recipient list and \fIrcpt_offset\fR message +/* structure members. A null result means that the file could not be +/* read or that the file contained incorrect information. Recipient +/* limit imposed this time is based on the position of the message +/* job(s) on corresponding transport job list(s). It's considered +/* an error to call this when the recipient slots can't be allocated. +/* +/* qmgr_message_free() destroys an in-core message structure and makes +/* the resources available for reuse. It is an error to destroy +/* a message structure that is still referenced by queue entry structures. +/* +/* qmgr_message_update_warn() takes a closed message, opens it, updates +/* the warning field, and closes it again. +/* DIAGNOSTICS +/* Warnings: malformed message file. Fatal errors: out of memory. +/* SEE ALSO +/* envelope(3) message envelope parser +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <stdio.h> /* sscanf() */ +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <vstring.h> +#include <vstream.h> +#include <split_at.h> +#include <valid_hostname.h> +#include <argv.h> +#include <stringops.h> +#include <myflock.h> +#include <sane_time.h> + +/* Global library. */ + +#include <dict.h> +#include <mail_queue.h> +#include <mail_params.h> +#include <canon_addr.h> +#include <record.h> +#include <rec_type.h> +#include <sent.h> +#include <deliver_completed.h> +#include <mail_addr_find.h> +#include <opened.h> +#include <resolve_local.h> +#include <verp_sender.h> + +/* Client stubs. */ + +#include <resolve_clnt.h> + +/* Application-specific. */ + +#include "qmgr.h" + +int qmgr_message_count; +int qmgr_recipient_count; + +/* qmgr_message_create - create in-core message structure */ + +static QMGR_MESSAGE *qmgr_message_create(const char *queue_name, + const char *queue_id, int qflags) +{ + QMGR_MESSAGE *message; + + message = (QMGR_MESSAGE *) mymalloc(sizeof(QMGR_MESSAGE)); + qmgr_message_count++; + message->flags = 0; + message->qflags = qflags; + message->fp = 0; + message->refcount = 0; + message->single_rcpt = 0; + message->arrival_time = 0; + message->queued_time = sane_time(); + message->data_offset = 0; + message->queue_id = mystrdup(queue_id); + message->queue_name = mystrdup(queue_name); + message->sender = 0; + message->errors_to = 0; + message->return_receipt = 0; + message->filter_xport = 0; + message->inspect_xport = 0; + message->data_size = 0; + message->warn_offset = 0; + message->warn_time = 0; + message->rcpt_offset = 0; + message->verp_delims = 0; + message->unread_offset = 0; + qmgr_rcpt_list_init(&message->rcpt_list); + message->rcpt_count = 0; + message->rcpt_limit = var_qmgr_msg_rcpt_limit; + message->rcpt_unread = 0; + QMGR_LIST_INIT(message->job_list); + return (message); +} + +/* qmgr_message_close - close queue file */ + +static void qmgr_message_close(QMGR_MESSAGE *message) +{ + vstream_fclose(message->fp); + message->fp = 0; +} + +/* qmgr_message_open - open queue file */ + +static int qmgr_message_open(QMGR_MESSAGE *message) +{ + + /* + * Sanity check. + */ + if (message->fp) + msg_panic("%s: queue file is open", message->queue_id); + + /* + * Open this queue file. Skip files that we cannot open. Back off when + * the system appears to be running out of resources. + */ + if ((message->fp = mail_queue_open(message->queue_name, + message->queue_id, + O_RDWR, 0)) == 0) { + if (errno != ENOENT) + msg_fatal("open %s %s: %m", message->queue_name, message->queue_id); + msg_warn("open %s %s: %m", message->queue_name, message->queue_id); + return (-1); + } + return (0); +} + +/* qmgr_message_oldstyle_scan - extract required information from an old style queue file */ + +static void qmgr_message_oldstyle_scan(QMGR_MESSAGE *message) +{ + VSTRING *buf; + long orig_offset, + curr_offset, + extra_offset; + int rec_type; + char *start; + + /* + * Initialize. No early returns or we have a memory leak. + */ + buf = vstring_alloc(100); + if ((orig_offset = vstream_ftell(message->fp)) < 0) + msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp)); + + /* + * Rewind to the very beginning to make sure we see all records. + */ + if (vstream_fseek(message->fp, 0, SEEK_SET) < 0) + msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); + + /* + * Scan through the old style queue file. Count the total number of + * recipients and find the data/extra sections offsets. Note that the new + * queue files require that data_size equals extra_offset - data_offset, + * so we set data_size to this as well and ignore the size record itself + * completely. + */ + message->rcpt_unread = 0; + do { + if ((curr_offset = vstream_ftell(message->fp)) < 0) + msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp)); + rec_type = rec_get(message->fp, buf, 0); + start = vstring_str(buf); + if (rec_type == REC_TYPE_DONE || rec_type == REC_TYPE_RCPT) { + message->rcpt_unread++; + } else if (rec_type == REC_TYPE_MESG) { + if ((message->data_offset = vstream_ftell(message->fp)) < 0) + msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp)); + if ((extra_offset = atol(start)) <= curr_offset) + msg_fatal("bad extra offset %s file %s", + start, VSTREAM_PATH(message->fp)); + if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0) + msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); + message->data_size = extra_offset - message->data_offset; + } + } while (rec_type > 0 && rec_type != REC_TYPE_END); + + /* + * Clean up. + */ + if (vstream_fseek(message->fp, orig_offset, SEEK_SET) < 0) + msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); + vstring_free(buf); + + /* + * Sanity checks. Verify that all required information was found, + * including the queue file end marker. + */ + if (message->data_offset == 0 || rec_type != REC_TYPE_END) + msg_fatal("%s: envelope records out of order", message->queue_id); +} + +/* qmgr_message_read - read envelope records */ + +static int qmgr_message_read(QMGR_MESSAGE *message) +{ + VSTRING *buf; + long extra_offset; + int rec_type; + long curr_offset; + long save_offset = message->rcpt_offset; /* save a flag */ + char *start; + int recipient_limit; + + /* + * Initialize. No early returns or we have a memory leak. + */ + buf = vstring_alloc(100); + + /* + * If we re-open this file, skip over on-file recipient records that we + * already looked at, and refill the in-core recipient address list. + * + * For the first time, the message recipient limit is calculated from the + * global recipient limit. This is to avoid reading little recipients + * when the active queue is near empty. When the queue becomes full, only + * the necessary amount is read in core. Such priming is necessary + * because there are no message jobs yet. + * + * For the next time, the recipient limit is based solely on the message + * jobs' positions in the job lists and/or job stacks. + */ + if (message->rcpt_offset) { + if (message->rcpt_list.len) + msg_panic("%s: recipient list not empty on recipient reload", message->queue_id); + if (vstream_fseek(message->fp, message->rcpt_offset, SEEK_SET) < 0) + msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); + message->rcpt_offset = 0; + recipient_limit = message->rcpt_limit - message->rcpt_count; + } else { + recipient_limit = var_qmgr_rcpt_limit - qmgr_recipient_count; + if (recipient_limit < message->rcpt_limit) + recipient_limit = message->rcpt_limit; + } + if (recipient_limit <= 0) + msg_panic("%s: no recipient slots available", message->queue_id); + + /* + * Read envelope records. XXX Rely on the front-end programs to enforce + * record size limits. Read up to recipient_limit recipients from the + * queue file, to protect against memory exhaustion. Recipient records + * may appear before or after the message content, so we keep reading + * from the queue file until we have enough recipients (rcpt_offset != 0) + * and until we know where the message content starts (data_offset != 0). + * + * Note that the total recipient count record is accurate only for fresh + * queue files. After some of the recipients are marked as done and the + * queue file is deferred, it can be used as upper bound estimate only. + * Fortunately, this poses no major problem on the scheduling algorithm, + * as the only impact is that the already deferred messages are not + * chosen by qmgr_job_candidate() as often as they could. + */ + do { + if ((curr_offset = vstream_ftell(message->fp)) < 0) + msg_fatal("vstream_ftell %s: %m", VSTREAM_PATH(message->fp)); + if (curr_offset == message->data_offset && curr_offset > 0) { + extra_offset = curr_offset + message->data_size; + if (extra_offset <= curr_offset) + msg_fatal("bad extra offset %ld file %s", + extra_offset, VSTREAM_PATH(message->fp)); + if (vstream_fseek(message->fp, extra_offset, SEEK_SET) < 0) + msg_fatal("seek file %s: %m", VSTREAM_PATH(message->fp)); + curr_offset = extra_offset; + } + rec_type = rec_get(message->fp, buf, 0); + start = vstring_str(buf); + if (rec_type == REC_TYPE_SIZE) { + if (message->data_size == 0) { + switch (sscanf(start, "%ld %ld %d", &message->data_size, + &message->data_offset, &message->rcpt_unread)) { + case 1: + + /* + * Gather data_size, data_offset and rcpt_unread values + * from the old style queue file. + */ + qmgr_message_oldstyle_scan(message); + break; + case 3: + + /* + * No extra work for new style queue files. + */ + break; + default: + msg_fatal("%s: weird size record", message->queue_id); + break; + } + } + } else if (rec_type == REC_TYPE_TIME) { + if (message->arrival_time == 0) + message->arrival_time = atol(start); + } else if (rec_type == REC_TYPE_FILT) { + if (message->filter_xport == 0) + message->filter_xport = mystrdup(start); + } else if (rec_type == REC_TYPE_INSP) { + if (message->inspect_xport == 0) + message->inspect_xport = mystrdup(start); + } else if (rec_type == REC_TYPE_FROM) { + if (message->sender == 0) { + message->sender = mystrdup(start); + opened(message->queue_id, message->sender, + message->data_size, message->rcpt_unread, + "queue %s", message->queue_name); + } + } else if (rec_type == REC_TYPE_DONE) { + if (curr_offset > message->unread_offset) { + message->unread_offset = curr_offset; + message->rcpt_unread--; + } + } else if (rec_type == REC_TYPE_RCPT) { + if (message->rcpt_list.len < recipient_limit) { + message->rcpt_unread--; + qmgr_rcpt_list_add(&message->rcpt_list, curr_offset, start); + if (message->rcpt_list.len >= recipient_limit) { + if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0) + msg_fatal("vstream_ftell %s: %m", + VSTREAM_PATH(message->fp)); + if (message->data_offset != 0 + && message->errors_to != 0 + && message->return_receipt != 0) + break; + } + } + } else if (rec_type == REC_TYPE_ERTO) { + if (message->errors_to == 0) { + message->errors_to = mystrdup(start); + if (message->data_offset != 0 + && message->rcpt_offset != 0 + && message->return_receipt != 0) + break; + } + } else if (rec_type == REC_TYPE_RRTO) { + if (message->return_receipt == 0) { + message->return_receipt = mystrdup(start); + if (message->data_offset != 0 + && message->rcpt_offset != 0 + && message->errors_to != 0) + break; + } + } else if (rec_type == REC_TYPE_WARN) { + if (message->warn_offset == 0) { + message->warn_offset = curr_offset; + message->warn_time = atol(start); + } + } else if (rec_type == REC_TYPE_VERP) { + if (message->verp_delims == 0) { + if (verp_delims_verify(start) != 0) { + msg_warn("%s: bad VERP record content: \"%s\"", + message->queue_id, start); + } else { + message->single_rcpt = 1; + message->verp_delims = mystrdup(start); + } + } + } + } while (rec_type > 0 && rec_type != REC_TYPE_END); + + /* + * Avoid clumsiness elsewhere in the program. When sending data across an + * IPC channel, sending an empty string is more convenient than sending a + * null pointer. + */ + if (message->errors_to == 0) + message->errors_to = mystrdup(""); + if (message->return_receipt == 0) + message->return_receipt = mystrdup(""); + + /* + * Clean up. + */ + vstring_free(buf); + + /* + * Sanity checks. Verify that all required information was found, + * including the queue file end marker. + */ + if (message->rcpt_unread < 0 + || (message->rcpt_offset == 0 && message->rcpt_unread != 0)) { + msg_warn("%s: rcpt count mismatch (%d)", + message->queue_id, message->rcpt_unread); + message->rcpt_unread = 0; + } + if (message->arrival_time == 0 + || message->sender == 0 + || message->data_offset == 0 + || (message->rcpt_offset == 0 && rec_type != REC_TYPE_END)) { + msg_warn("%s: envelope records out of order", message->queue_id); + message->rcpt_offset = save_offset; /* restore flag */ + message->rcpt_unread += message->rcpt_list.len; + qmgr_rcpt_list_free(&message->rcpt_list); + qmgr_rcpt_list_init(&message->rcpt_list); + return (-1); + } else { + return (0); + } +} + +/* qmgr_message_update_warn - update the time of next delay warning */ + +void qmgr_message_update_warn(QMGR_MESSAGE *message) +{ + + /* + * XXX eventually this should let us schedule multiple warnings, right + * now it just allows for one. + */ + if (qmgr_message_open(message) + || vstream_fseek(message->fp, message->warn_offset, SEEK_SET) < 0 + || rec_fprintf(message->fp, REC_TYPE_WARN, REC_TYPE_WARN_FORMAT, 0L) < 0 + || vstream_fflush(message->fp)) + msg_fatal("update queue file %s: %m", VSTREAM_PATH(message->fp)); + qmgr_message_close(message); +} + +/* qmgr_message_sort_compare - compare recipient information */ + +static int qmgr_message_sort_compare(const void *p1, const void *p2) +{ + QMGR_RCPT *rcpt1 = (QMGR_RCPT *) p1; + QMGR_RCPT *rcpt2 = (QMGR_RCPT *) p2; + QMGR_QUEUE *queue1; + QMGR_QUEUE *queue2; + char *at1; + char *at2; + int result; + + /* + * Compare most significant to least significant recipient attributes. + */ + if ((queue1 = rcpt1->queue) != 0 && (queue2 = rcpt2->queue) != 0) { + + /* + * Compare message transport. + */ + if ((result = strcmp(queue1->transport->name, + queue2->transport->name)) != 0) + return (result); + + /* + * Compare (already lowercased) next-hop hostname. + */ + if ((result = strcmp(queue1->name, queue2->name)) != 0) + return (result); + } + + /* + * Compare recipient domain. + */ + if ((at1 = strrchr(rcpt1->address, '@')) != 0 + && (at2 = strrchr(rcpt2->address, '@')) != 0 + && (result = strcasecmp(at1, at2)) != 0) + return (result); + + /* + * Compare recipient address. + */ + return (strcmp(rcpt1->address, rcpt2->address)); +} + +/* qmgr_message_sort - sort message recipient addresses by domain */ + +static void qmgr_message_sort(QMGR_MESSAGE *message) +{ + qsort((char *) message->rcpt_list.info, message->rcpt_list.len, + sizeof(message->rcpt_list.info[0]), qmgr_message_sort_compare); + if (msg_verbose) { + QMGR_RCPT_LIST list = message->rcpt_list; + QMGR_RCPT *rcpt; + + msg_info("start sorted recipient list"); + for (rcpt = list.info; rcpt < list.info + list.len; rcpt++) + msg_info("qmgr_message_sort: %s", rcpt->address); + msg_info("end sorted recipient list"); + } +} + +/* qmgr_message_resolve - resolve recipients */ + +static void qmgr_message_resolve(QMGR_MESSAGE *message) +{ + static ARGV *defer_xport_argv; + QMGR_RCPT_LIST list = message->rcpt_list; + QMGR_RCPT *recipient; + QMGR_TRANSPORT *transport = 0; + QMGR_QUEUE *queue = 0; + RESOLVE_REPLY reply; + const char *newloc; + char *at; + char **cpp; + char *domain; + const char *junk; + char *nexthop; + int len; + +#define STREQ(x,y) (strcmp(x,y) == 0) +#define STR vstring_str +#define LEN VSTRING_LEN +#define UPDATE(ptr,new) { myfree(ptr); ptr = mystrdup(new); } + + resolve_clnt_init(&reply); + for (recipient = list.info; recipient < list.info + list.len; recipient++) { + + /* + * This may be a bit late in the game, but it is the most convenient + * place to scrutinize the destination address syntax. We have a + * complete queue file, so bouncing is easy. That luxury is not + * available to the cleanup service. The main issue is that we want + * to have this test in one place, instead of having to do this in + * every front-ent program. + */ + if ((at = strrchr(recipient->address, '@')) != 0 + && (at + 1)[strspn(at + 1, "[]0123456789.")] != 0 + && valid_hostname(at + 1, DONT_GRIPE) == 0) { + qmgr_bounce_recipient(message, recipient, + "bad host/domain syntax: \"%s\"", at + 1); + continue; + } + + /* + * Resolve the destination to (transport, nexthop, address). The + * result address may differ from the one specified by the sender. + */ + resolve_clnt_query(recipient->address, &reply); + if (message->filter_xport) { + vstring_strcpy(reply.transport, message->filter_xport); + if ((nexthop = split_at(STR(reply.transport), ':')) == 0 + || *nexthop == 0) + nexthop = var_myhostname; + vstring_strcpy(reply.nexthop, nexthop); + } else { + if (!STREQ(recipient->address, STR(reply.recipient))) + UPDATE(recipient->address, STR(reply.recipient)); + } + + /* + * XXX The nexthop destination is also used as lookup key for the + * per-destination queue. Fold the nexthop to lower case so that we + * don't have multiple queues for the same site. + */ + lowercase(STR(reply.nexthop)); + + /* + * Bounce recipients that have moved. We do it here instead of in the + * local delivery agent. The benefit is that we can bounce mail for + * virtual addresses, not just local addresses only, and that there + * is no need to run a local delivery agent just for the sake of + * relocation notices. The downside is that this table has no effect + * on local alias expansion results, so that mail will have to make + * almost an entire iteration through the mail system. + */ +#define IGNORE_ADDR_EXTENSION ((char **) 0) + + if (qmgr_relocated != 0) { + if ((newloc = mail_addr_find(qmgr_relocated, recipient->address, + IGNORE_ADDR_EXTENSION)) != 0) { + qmgr_bounce_recipient(message, recipient, + "user has moved to %s", newloc); + continue; + } else if (dict_errno != 0) { + qmgr_defer_recipient(message, recipient->address, + "relocated map lookup failure"); + continue; + } + } + + /* + * Bounce mail to non-existent users in virtual domains. + */ + if (qmgr_virtual != 0 + && (at = strrchr(recipient->address, '@')) != 0 + && !resolve_local(at + 1)) { + domain = lowercase(mystrdup(at + 1)); + junk = maps_find(qmgr_virtual, domain, 0); + myfree(domain); + if (junk) { + qmgr_bounce_recipient(message, recipient, + "unknown user: \"%s\"", recipient->address); + continue; + } + } + + /* + * Bounce recipient addresses that start with `-'. External commands + * may misinterpret such addresses as command-line options. + * + * In theory I could say people should always carefully set up their + * master.cf pipe mailer entries with `--' before the first + * non-option argument, but mistakes will happen regardless. + * + * Therefore the protection is put in place here, in the queue manager, + * where it cannot be bypassed. + */ + if (var_allow_min_user == 0 && recipient->address[0] == '-') { + qmgr_bounce_recipient(message, recipient, + "invalid recipient syntax: \"%s\"", + recipient->address); + continue; + } + + /* + * Queues are identified by the transport name and by the next-hop + * hostname. When the delivery agent accepts only one recipient per + * delivery, give each recipient its own queue, so that deliveries to + * different recipients of the same message can happen in parallel. + * This also has the benefit that one bad recipient cannot interfere + * with deliveries to other recipients. XXX Should split the address + * on the recipient delimiter if one is defined, but doing a proper + * job requires knowledge of local aliases. Yuck! I don't want to + * duplicate delivery-agent specific knowledge in the queue manager. + * XXX The nexthop field is overloaded to serve as destination and as + * queue name. Should have separate fields for queue name and for + * destination. + */ + at = strrchr(STR(reply.recipient), '@'); + len = (at ? (at - STR(reply.recipient)) : strlen(STR(reply.recipient))); + + /* + * Look up or instantiate the proper transport. We're working a + * little ahead, doing queue management stuff that used to be done + * way down. + */ + if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) { + if ((transport = qmgr_transport_find(STR(reply.transport))) == 0) + transport = qmgr_transport_create(STR(reply.transport)); + queue = 0; + } + if (transport->recipient_limit == 1) { + VSTRING_SPACE(reply.nexthop, len + 1); + memmove(STR(reply.nexthop) + len + 1, STR(reply.nexthop), + LEN(reply.nexthop) + 1); + memcpy(STR(reply.nexthop), STR(reply.recipient), len); + STR(reply.nexthop)[len] = '@'; + lowercase(STR(reply.nexthop)); + } + + /* + * Discard mail to the local double bounce address here, so this + * system can run without a local delivery agent. They'd still have + * to configure something for mail directed to the local postmaster, + * though, but that is an RFC requirement anyway. + */ + if (at == 0 || resolve_local(at + 1)) { + if (strncasecmp(STR(reply.recipient), var_double_bounce_sender, + len) == 0 + && !var_double_bounce_sender[len]) { + sent(message->queue_id, recipient->address, + "none", message->arrival_time, "discarded"); + deliver_completed(message->fp, recipient->offset); + msg_warn("%s: undeliverable postmaster notification discarded", + message->queue_id); + continue; + } + } + + /* + * Optionally defer deliveries over specific transports, unless the + * restriction is lifted temporarily. + */ + if (*var_defer_xports && (message->qflags & QMGR_FLUSH_DEAD) == 0) { + if (defer_xport_argv == 0) + defer_xport_argv = argv_split(var_defer_xports, " \t\r\n,"); + for (cpp = defer_xport_argv->argv; *cpp; cpp++) + if (strcmp(*cpp, STR(reply.transport)) == 0) + break; + if (*cpp) { + qmgr_defer_recipient(message, recipient->address, + "deferred transport"); + continue; + } + } + + /* + * XXX Gross hack alert. We want to group recipients by transport and + * by next-hop hostname, in order to minimize the number of network + * transactions. However, it would be wasteful to have an in-memory + * resolver reply structure for each in-core recipient. Instead, we + * bind each recipient to an in-core queue instance which is needed + * anyway. That gives all information needed for recipient grouping. + */ +#if 0 + + /* + * Look up or instantiate the proper transport. + */ + if (transport == 0 || !STREQ(transport->name, STR(reply.transport))) { + if ((transport = qmgr_transport_find(STR(reply.transport))) == 0) + transport = qmgr_transport_create(STR(reply.transport)); + queue = 0; + } +#endif + + /* + * This transport is dead. Defer delivery to this recipient. + */ + if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) { + qmgr_defer_recipient(message, recipient->address, transport->reason); + continue; + } + + /* + * This transport is alive. Find or instantiate a queue for this + * recipient. + */ + if (queue == 0 || !STREQ(queue->name, STR(reply.nexthop))) { + if ((queue = qmgr_queue_find(transport, STR(reply.nexthop))) == 0) + queue = qmgr_queue_create(transport, STR(reply.nexthop)); + } + + /* + * This queue is dead. Defer delivery to this recipient. + */ + if (queue->window == 0) { + qmgr_defer_recipient(message, recipient->address, queue->reason); + continue; + } + + /* + * This queue is alive. Bind this recipient to this queue instance. + */ + recipient->queue = queue; + } + resolve_clnt_free(&reply); +} + +/* qmgr_message_assign - assign recipients to specific delivery requests */ + +static void qmgr_message_assign(QMGR_MESSAGE *message) +{ + QMGR_RCPT_LIST list = message->rcpt_list; + QMGR_RCPT *recipient; + QMGR_ENTRY *entry = 0; + QMGR_QUEUE *queue; + QMGR_JOB *job = 0; + QMGR_PEER *peer = 0; + + /* + * Try to bundle as many recipients in a delivery request as we can. When + * the recipient resolves to the same site and transport as the previous + * recipient, do not create a new queue entry, just move that recipient + * to the recipient list of the existing queue entry. All this provided + * that we do not exceed the transport-specific limit on the number of + * recipients per transaction. Skip recipients with a dead transport or + * destination. + */ +#define LIMIT_OK(limit, count) ((limit) == 0 || ((count) < (limit))) + + for (recipient = list.info; recipient < list.info + list.len; recipient++) { + if ((queue = recipient->queue) != 0) { + if (message->single_rcpt || entry == 0 || entry->queue != queue + || !LIMIT_OK(queue->transport->recipient_limit, + entry->rcpt_list.len)) { + + /* + * Lookup or instantiate the message job if necessary. + */ + if (job == 0 || queue->transport != job->transport) { + job = qmgr_job_obtain(message, queue->transport); + peer = 0; + } + + /* + * Lookup or instantiate job peer if necessary. + */ + if (peer == 0 || queue != peer->queue) { + if ((peer = qmgr_peer_find(job, queue)) == 0) + peer = qmgr_peer_create(job, queue); + } + + /* + * Create new peer entry. + */ + entry = qmgr_entry_create(peer, message); + job->read_entries++; + } + + /* + * Add the recipient to the current entry and increase all those + * recipient counters accordingly. + */ + qmgr_rcpt_list_add(&entry->rcpt_list, recipient->offset, recipient->address); + job->rcpt_count++; + message->rcpt_count++; + qmgr_recipient_count++; + } + } + + /* + * Release the message recipient list and reinitialize it for the next + * time. + */ + qmgr_rcpt_list_free(&message->rcpt_list); + qmgr_rcpt_list_init(&message->rcpt_list); + + /* + * Note that even if qmgr_job_obtain() reset the job candidate cache of + * all transports to which we assigned new recipients, this message may + * have other jobs which we didn't touch at all this time. But the number + * of unread recipients affecting the candidate selection might have + * changed considerably, so we must invalidate the caches if it might be + * of some use. + */ + for (job = message->job_list.next; job; job = job->message_peers.next) + if (job->selected_entries < job->read_entries + && job->blocker_tag != job->transport->blocker_tag) + job->transport->candidate_cache_current = 0; +} + +/* qmgr_message_move_limits - recycle unused recipient slots */ + +static void qmgr_message_move_limits(QMGR_MESSAGE *message) +{ + QMGR_JOB *job; + + for (job = message->job_list.next; job; job = job->message_peers.next) + qmgr_job_move_limits(job); +} + +/* qmgr_message_free - release memory for in-core message structure */ + +void qmgr_message_free(QMGR_MESSAGE *message) +{ + QMGR_JOB *job; + + if (message->refcount != 0) + msg_panic("qmgr_message_free: reference len: %d", message->refcount); + if (message->fp) + msg_panic("qmgr_message_free: queue file is open"); + while ((job = message->job_list.next) != 0) + qmgr_job_free(job); + myfree(message->queue_id); + myfree(message->queue_name); + if (message->sender) + myfree(message->sender); + if (message->verp_delims) + myfree(message->verp_delims); + if (message->errors_to) + myfree(message->errors_to); + if (message->return_receipt) + myfree(message->return_receipt); + if (message->filter_xport) + myfree(message->filter_xport); + if (message->inspect_xport) + myfree(message->inspect_xport); + qmgr_rcpt_list_free(&message->rcpt_list); + qmgr_message_count--; + myfree((char *) message); +} + +/* qmgr_message_alloc - create in-core message structure */ + +QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id, + int qflags) +{ + char *myname = "qmgr_message_alloc"; + QMGR_MESSAGE *message; + + if (msg_verbose) + msg_info("%s: %s %s", myname, queue_name, queue_id); + + /* + * Create an in-core message structure. + */ + message = qmgr_message_create(queue_name, queue_id, qflags); + + /* + * Extract message envelope information: time of arrival, sender address, + * recipient addresses. Skip files with malformed envelope information. + */ +#define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT) + + if (qmgr_message_open(message) < 0) { + qmgr_message_free(message); + return (0); + } + if (myflock(vstream_fileno(message->fp), INTERNAL_LOCK, QMGR_LOCK_MODE) < 0) { + msg_info("%s: skipped, still being delivered", queue_id); + qmgr_message_close(message); + qmgr_message_free(message); + return (QMGR_MESSAGE_LOCKED); + } + if (qmgr_message_read(message) < 0) { + qmgr_message_close(message); + qmgr_message_free(message); + return (0); + } else { + + /* + * Reset the defer log. This code should not be here, but we must + * reset the defer log *after* acquiring the exclusive lock on the + * queue file and *before* resolving new recipients. Since all those + * operations are encapsulated so nicely by this routine, the defer + * log reset has to be done here as well. + */ + if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT) + msg_fatal("%s: %s: remove %s %s: %m", myname, + queue_id, MAIL_QUEUE_DEFER, queue_id); + qmgr_message_sort(message); + qmgr_message_resolve(message); + qmgr_message_sort(message); + qmgr_message_assign(message); + qmgr_message_close(message); + if (message->rcpt_offset == 0) + qmgr_message_move_limits(message); + return (message); + } +} + +/* qmgr_message_realloc - refresh in-core message structure */ + +QMGR_MESSAGE *qmgr_message_realloc(QMGR_MESSAGE *message) +{ + char *myname = "qmgr_message_realloc"; + + /* + * Sanity checks. + */ + if (message->rcpt_offset <= 0) + msg_panic("%s: invalid offset: %ld", myname, message->rcpt_offset); + if (msg_verbose) + msg_info("%s: %s %s offset %ld", myname, message->queue_name, + message->queue_id, message->rcpt_offset); + + /* + * Extract recipient addresses. Skip files with malformed envelope + * information. + */ + if (qmgr_message_open(message) < 0) + return (0); + if (qmgr_message_read(message) < 0) { + qmgr_message_close(message); + return (0); + } else { + qmgr_message_sort(message); + qmgr_message_resolve(message); + qmgr_message_sort(message); + qmgr_message_assign(message); + qmgr_message_close(message); + if (message->rcpt_offset == 0) + qmgr_message_move_limits(message); + return (message); + } +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_move.c b/gnu/dist/postfix/src/nqmgr/qmgr_move.c new file mode 100644 index 00000000000..a4e55f0585f --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_move.c @@ -0,0 +1,104 @@ +/*++ +/* NAME +/* qmgr_move 3 +/* SUMMARY +/* move queue entries to another queue +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* void qmgr_move(from, to, time_stamp) +/* const char *from; +/* const char *to; +/* time_t time_stamp; +/* DESCRIPTION +/* The \fBqmgr_move\fR routine scans the \fIfrom\fR queue for entries +/* with valid queue names and moves them to the \fIto\fR queue. +/* If \fItime_stamp\fR is non-zero, the queue file time stamps are +/* set to the specified value. +/* Entries with invalid names are left alone. No attempt is made to +/* look for other badness such as multiple links or weird file types. +/* These issues are dealt with when a queue file is actually opened. +/* 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/stat.h> +#include <string.h> +#include <utime.h> +#include <errno.h> + +/* Utility library. */ + +#include <msg.h> +#include <scan_dir.h> +#include <recipient_list.h> + +/* Global library. */ + +#include <mail_queue.h> +#include <mail_scan_dir.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_move - move queue entries to another queue, leave bad files alone */ + +void qmgr_move(const char *src_queue, const char *dst_queue, + time_t time_stamp) +{ + char *myname = "qmgr_move"; + SCAN_DIR *queue_dir; + char *queue_id; + struct utimbuf tbuf; + const char *path; + + if (strcmp(src_queue, dst_queue) == 0) + msg_panic("%s: source queue %s is destination", myname, src_queue); + if (msg_verbose) + msg_info("start move queue %s -> %s", src_queue, dst_queue); + + queue_dir = scan_dir_open(src_queue); + while ((queue_id = mail_scan_dir_next(queue_dir)) != 0) { + if (mail_queue_id_ok(queue_id)) { + if (time_stamp > 0) { + tbuf.actime = tbuf.modtime = time_stamp; + path = mail_queue_path((VSTRING *) 0, src_queue, queue_id); + if (utime(path, &tbuf) < 0) { + if (errno != ENOENT) + msg_fatal("%s: update %s time stamps: %m", myname, path); + msg_warn("%s: update %s time stamps: %m", myname, path); + continue; + } + } + if (mail_queue_rename(queue_id, src_queue, dst_queue)) { + if (errno != ENOENT) + msg_fatal("%s: rename %s from %s to %s: %m", + myname, queue_id, src_queue, dst_queue); + msg_warn("%s: rename %s from %s to %s: %m", + myname, queue_id, src_queue, dst_queue); + continue; + } + if (msg_verbose) + msg_info("%s: moved %s from %s to %s", + myname, queue_id, src_queue, dst_queue); + } else { + msg_warn("%s: ignored: queue %s id %s", + myname, src_queue, queue_id); + } + } + scan_dir_close(queue_dir); + + if (msg_verbose) + msg_info("end move queue %s -> %s", src_queue, dst_queue); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_peer.c b/gnu/dist/postfix/src/nqmgr/qmgr_peer.c new file mode 100644 index 00000000000..9b61e64e521 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_peer.c @@ -0,0 +1,136 @@ +/*++ +/* NAME +/* qmgr_peer 3 +/* SUMMARY +/* per-job peers +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* QMGR_PEER *qmgr_peer_create(job, queue) +/* QMGR_JOB *job; +/* QMGR_QUEUE *queue; +/* +/* QMGR_PEER *qmgr_peer_find(job, queue) +/* QMGR_JOB *job; +/* QMGR_QUEUE *queue; +/* +/* void qmgr_peer_free(peer) +/* QMGR_PEER *peer; +/* +/* QMGR_PEER *qmgr_peer_select(job) +/* QMGR_JOB *job; +/* +/* DESCRIPTION +/* These routines add/delete/manipulate per-job peers. +/* Each queue corresponds to a specific job and destination. +/* It is similar to per-transport queue structure, but groups +/* only the entries of the given job. +/* +/* qmgr_peer_create() creates an empty peer structure for the named +/* job and destination. It is an error to call this function +/* if a peer for given combination already exists. +/* +/* qmgr_peer_find() looks up the peer for the named destination +/* for the named job. A null result means that the peer +/* was not found. +/* +/* qmgr_peer_free() disposes of a per-job peer after all +/* its entries have been taken care of. It is an error to dispose +/* of a peer still in use. +/* +/* qmgr_peer_select() attempts to find a peer of named job that +/* has messages pending delivery. This routine implements +/* round-robin search among job's peers. +/* DIAGNOSTICS +/* Panic: consistency check failure. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Patrik Rak +/* patrik@raxoft.cz +/*--*/ + +/* System library. */ + +#include <sys_defs.h> + +/* Utility library. */ + +#include <msg.h> +#include <htable.h> +#include <mymalloc.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_peer_create - create and initialize message peer structure */ + +QMGR_PEER *qmgr_peer_create(QMGR_JOB *job, QMGR_QUEUE *queue) +{ + QMGR_PEER *peer; + + peer = (QMGR_PEER *) mymalloc(sizeof(QMGR_PEER)); + peer->queue = queue; + peer->job = job; + QMGR_LIST_APPEND(job->peer_list, peer, peers); + htable_enter(job->peer_byname, queue->name, (char *) peer); + peer->refcount = 0; + QMGR_LIST_INIT(peer->entry_list); + return (peer); +} + +/* qmgr_peer_free - release peer structure */ + +void qmgr_peer_free(QMGR_PEER *peer) +{ + char *myname = "qmgr_peer_free"; + QMGR_JOB *job = peer->job; + QMGR_QUEUE *queue = peer->queue; + + /* + * Sanity checks. It is an error to delete a referenced peer structure. + */ + if (peer->refcount != 0) + msg_panic("%s: refcount: %d", myname, peer->refcount); + if (peer->entry_list.next != 0) + msg_panic("%s: entry list not empty: %s", myname, queue->name); + + QMGR_LIST_UNLINK(job->peer_list, QMGR_PEER *, peer, peers); + htable_delete(job->peer_byname, queue->name, (void (*) (char *)) 0); + myfree((char *) peer); +} + +/* qmgr_peer_find - lookup peer associated with given job and queue */ + +QMGR_PEER *qmgr_peer_find(QMGR_JOB *job, QMGR_QUEUE *queue) +{ + return ((QMGR_PEER *) htable_find(job->peer_byname, queue->name)); +} + +/* qmgr_peer_select - select next peer suitable for delivery within given job */ + +QMGR_PEER *qmgr_peer_select(QMGR_JOB *job) +{ + QMGR_PEER *peer; + QMGR_QUEUE *queue; + + /* + * If we find a suitable site, rotate the list to enforce round-robin + * selection. See similar selection code in qmgr_transport_select(). + */ + for (peer = job->peer_list.next; peer; peer = peer->peers.next) { + queue = peer->queue; + if (queue->window > queue->busy_refcount && peer->entry_list.next != 0) { + QMGR_LIST_ROTATE(job->peer_list, peer, peers); + if (msg_verbose) + msg_info("qmgr_peer_select: %s %s %s (%d of %d)", + job->message->queue_id, queue->transport->name, queue->name, + queue->busy_refcount + 1, queue->window); + return (peer); + } + } + return (0); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_queue.c b/gnu/dist/postfix/src/nqmgr/qmgr_queue.c new file mode 100644 index 00000000000..d4aced58e23 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_queue.c @@ -0,0 +1,251 @@ +/*++ +/* NAME +/* qmgr_queue 3 +/* SUMMARY +/* per-destination queues +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* int qmgr_queue_count; +/* +/* QMGR_QUEUE *qmgr_queue_create(transport, site) +/* QMGR_TRANSPORT *transport; +/* const char *site; +/* +/* void qmgr_queue_done(queue) +/* QMGR_QUEUE *queue; +/* +/* QMGR_QUEUE *qmgr_queue_find(transport, site) +/* QMGR_TRANSPORT *transport; +/* const char *site; +/* +/* void qmgr_queue_throttle(queue, reason) +/* QMGR_QUEUE *queue; +/* const char *reason; +/* +/* void qmgr_queue_unthrottle(queue) +/* QMGR_QUEUE *queue; +/* DESCRIPTION +/* These routines add/delete/manipulate per-destination queues. +/* Each queue corresponds to a specific transport and destination. +/* Each queue has a `todo' list of delivery requests for that +/* destination, and a `busy' list of delivery requests in progress. +/* +/* qmgr_queue_count is a global counter for the total number +/* of in-core queue structures. +/* +/* qmgr_queue_create() creates an empty queue for the named +/* transport and destination. The queue is given an initial +/* concurrency limit as specified with the +/* \fIinitial_destination_concurrency\fR configuration parameter, +/* provided that it does not exceed the transport-specific +/* concurrency limit. +/* +/* qmgr_queue_done() disposes of a per-destination queue after all +/* its entries have been taken care of. It is an error to dispose +/* of a dead queue. +/* +/* qmgr_queue_find() looks up the queue for the named destination +/* for the named transport. A null result means that the queue +/* was not found. +/* +/* qmgr_queue_throttle() handles a delivery error, and decrements the +/* concurrency limit for the destination. When the concurrency limit +/* for a destination becomes zero, qmgr_queue_throttle() starts a timer +/* to re-enable delivery to the destination after a configurable delay. +/* +/* qmgr_queue_unthrottle() undoes qmgr_queue_throttle()'s effects. +/* The concurrency limit for the destination is incremented, +/* provided that it does not exceed the destination concurrency +/* limit specified for the transport. This routine implements +/* "slow open" mode, and eliminates the "thundering herd" problem. +/* DIAGNOSTICS +/* Panic: consistency check failure. +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <time.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <events.h> +#include <htable.h> + +/* Global library. */ + +#include <mail_params.h> +#include <recipient_list.h> + +/* Application-specific. */ + +#include "qmgr.h" + +int qmgr_queue_count; + +/* qmgr_queue_unthrottle_wrapper - in case (char *) != (struct *) */ + +static void qmgr_queue_unthrottle_wrapper(int unused_event, char *context) +{ + QMGR_QUEUE *queue = (QMGR_QUEUE *) context; + + /* + * This routine runs when a wakeup timer goes off; it does not run in the + * context of some queue manipulation. Therefore, it is safe to discard + * this in-core queue when it is empty and when this site is not dead. + */ + qmgr_queue_unthrottle(queue); + if (queue->window > 0 && queue->todo.next == 0 && queue->busy.next == 0) + qmgr_queue_done(queue); +} + +/* qmgr_queue_unthrottle - give this destination another chance */ + +void qmgr_queue_unthrottle(QMGR_QUEUE *queue) +{ + char *myname = "qmgr_queue_unthrottle"; + QMGR_TRANSPORT *transport = queue->transport; + + if (msg_verbose) + msg_info("%s: queue %s", myname, queue->name); + + /* + * Special case when this site was dead. + */ + if (queue->window == 0) { + event_cancel_timer(qmgr_queue_unthrottle_wrapper, (char *) queue); + if (queue->reason == 0) + msg_panic("%s: queue %s: window 0 reason 0", myname, queue->name); + myfree(queue->reason); + queue->reason = 0; + queue->window = transport->init_dest_concurrency; + return; + } + + /* + * Increase the destination's concurrency limit until we reach the + * transport's concurrency limit. Allow for a margin the size of the + * initial destination concurrency, so that we're not too gentle. + */ + if (transport->dest_concurrency_limit == 0 + || transport->dest_concurrency_limit > queue->window) + if (queue->window < queue->busy_refcount + transport->init_dest_concurrency) + queue->window++; +} + +/* qmgr_queue_throttle - handle destination delivery failure */ + +void qmgr_queue_throttle(QMGR_QUEUE *queue, const char *reason) +{ + char *myname = "qmgr_queue_throttle"; + + /* + * Sanity checks. + */ + if (queue->reason) + msg_panic("%s: queue %s: spurious reason %s", + myname, queue->name, queue->reason); + if (msg_verbose) + msg_info("%s: queue %s: %s", myname, queue->name, reason); + + /* + * Decrease the destination's concurrency limit until we reach zero, at + * which point the destination is declared dead. Decrease the concurrency + * limit by one, instead of using actual concurrency - 1, to avoid + * declaring a host dead after just one single delivery failure. + */ + if (queue->window > 0) + queue->window--; + + /* + * Special case for a site that just was declared dead. + */ + if (queue->window == 0) { + queue->reason = mystrdup(reason); + event_request_timer(qmgr_queue_unthrottle_wrapper, + (char *) queue, var_min_backoff_time); + } +} + +/* qmgr_queue_done - delete in-core queue for site */ + +void qmgr_queue_done(QMGR_QUEUE *queue) +{ + char *myname = "qmgr_queue_done"; + QMGR_TRANSPORT *transport = queue->transport; + + /* + * Sanity checks. It is an error to delete an in-core queue with pending + * messages or timers. + */ + if (queue->busy_refcount != 0 || queue->todo_refcount != 0) + msg_panic("%s: refcount: %d", myname, + queue->busy_refcount + queue->todo_refcount); + if (queue->todo.next || queue->busy.next) + msg_panic("%s: queue not empty: %s", myname, queue->name); + if (queue->window <= 0) + msg_panic("%s: window %d", myname, queue->window); + if (queue->reason) + msg_panic("%s: queue %s: spurious reason %s", + myname, queue->name, queue->reason); + + /* + * Clean up this in-core queue. + */ + QMGR_LIST_UNLINK(transport->queue_list, QMGR_QUEUE *, queue, peers); + htable_delete(transport->queue_byname, queue->name, (void (*) (char *)) 0); + myfree(queue->name); + qmgr_queue_count--; + myfree((char *) queue); +} + +/* qmgr_queue_create - create in-core queue for site */ + +QMGR_QUEUE *qmgr_queue_create(QMGR_TRANSPORT *transport, const char *site) +{ + QMGR_QUEUE *queue; + + /* + * If possible, choose an initial concurrency of > 1 so that one bad + * message or one bad network won't slow us down unnecessarily. + */ + + queue = (QMGR_QUEUE *) mymalloc(sizeof(QMGR_QUEUE)); + qmgr_queue_count++; + queue->name = mystrdup(site); + queue->todo_refcount = 0; + queue->busy_refcount = 0; + queue->transport = transport; + queue->window = transport->init_dest_concurrency; + QMGR_LIST_INIT(queue->todo); + QMGR_LIST_INIT(queue->busy); + queue->reason = 0; + queue->blocker_tag = 0; + QMGR_LIST_APPEND(transport->queue_list, queue, peers); + htable_enter(transport->queue_byname, site, (char *) queue); + return (queue); +} + +/* qmgr_queue_find - find in-core queue for site */ + +QMGR_QUEUE *qmgr_queue_find(QMGR_TRANSPORT *transport, const char *site) +{ + return ((QMGR_QUEUE *) htable_find(transport->queue_byname, site)); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_rcpt_list.c b/gnu/dist/postfix/src/nqmgr/qmgr_rcpt_list.c new file mode 100644 index 00000000000..2bb292e016e --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_rcpt_list.c @@ -0,0 +1,96 @@ +/*++ +/* NAME +/* qmgr_rcpt_list 3 +/* SUMMARY +/* in-core recipient structures +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* void qmgr_rcpt_list_init(list) +/* QMGR_RCPT_LIST *list; +/* +/* void qmgr_rcpt_list_add(list, offset, recipient) +/* QMGR_RCPT_LIST *list; +/* long offset; +/* const char *recipient; +/* +/* void qmgr_rcpt_list_free(list) +/* QMGR_RCPT_LIST *list; +/* DESCRIPTION +/* This module maintains lists of queue manager recipient structures. +/* These structures are extended versions of the structures maintained +/* by the recipient_list(3) module. The extension is that the queue +/* manager version of a recipient can have a reference to a queue +/* structure. +/* +/* qmgr_rcpt_list_init() creates an empty recipient structure list. +/* The list argument is initialized such that it can be given to +/* qmgr_rcpt_list_add() and qmgr_rcpt_list_free(). +/* +/* qmgr_rcpt_list_add() adds a recipient to the specified list. +/* The recipient name is copied. +/* +/* qmgr_rcpt_list_free() releases memory for the specified list +/* of recipient structures. +/* SEE ALSO +/* qmgr_rcpt_list(3h) data structure +/* recipient_list(3) same code, different data structure. +/* DIAGNOSTICS +/* Fatal errors: memory allocation. +/* 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. */ + +#include <mymalloc.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_rcpt_list_init - initialize */ + +void qmgr_rcpt_list_init(QMGR_RCPT_LIST *list) +{ + list->avail = 1; + list->len = 0; + list->info = (QMGR_RCPT *) mymalloc(sizeof(QMGR_RCPT)); +} + +/* qmgr_rcpt_list_add - add rcpt to list */ + +void qmgr_rcpt_list_add(QMGR_RCPT_LIST *list, long offset, const char *rcpt) +{ + if (list->len >= list->avail) { + list->avail *= 2; + list->info = (QMGR_RCPT *) + myrealloc((char *) list->info, list->avail * sizeof(QMGR_RCPT)); + } + list->info[list->len].address = mystrdup(rcpt); + list->info[list->len].offset = offset; + list->info[list->len].queue = 0; + list->len++; +} + +/* qmgr_rcpt_list_free - release memory for in-core recipient structure */ + +void qmgr_rcpt_list_free(QMGR_RCPT_LIST *list) +{ + QMGR_RCPT *rcpt; + + for (rcpt = list->info; rcpt < list->info + list->len; rcpt++) + myfree(rcpt->address); + myfree((char *) list->info); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_scan.c b/gnu/dist/postfix/src/nqmgr/qmgr_scan.c new file mode 100644 index 00000000000..e0d9fc079ab --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_scan.c @@ -0,0 +1,159 @@ +/*++ +/* NAME +/* qmgr_scan 3 +/* SUMMARY +/* queue scanning +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* QMGR_SCAN *qmgr_scan_create(queue_name) +/* const char *queue_name; +/* +/* char *qmgr_scan_next(scan_info) +/* QMGR_SCAN *scan_info; +/* +/* void qmgr_scan_request(scan_info, flags) +/* QMGR_SCAN *scan_info; +/* int flags; +/* DESCRIPTION +/* This module implements queue scans. A queue scan always runs +/* to completion, so that all files get a fair chance. The caller +/* can request that a queue scan be restarted once it completes. +/* +/* qmgr_scan_create() creates a context for scanning the named queue, +/* but does not start a queue scan. +/* +/* qmgr_scan_next() returns the base name of the next queue file. +/* A null pointer means that no file was found. qmgr_scan_next() +/* automagically restarts a queue scan when a scan request had +/* arrived while the scan was in progress. +/* +/* qmgr_scan_request() records a request for the next queue scan. The +/* flags argument is the bit-wise OR of zero or more of the following, +/* unrecognized flags being ignored: +/* .IP QMGR_FLUSH_DEAD +/* Forget state information about dead hosts or transports. This +/* request takes effect upon the next queue scan. +/* .IP QMGR_SCAN_ALL +/* Ignore queue file time stamps. +/* This flag is passed on to the qmgr_active_feed() routine. +/* .IP QMGR_SCAN_START +/* Start a queue scan when none is in progress, or restart the +/* current scan upon completion. +/* DIAGNOSTICS +/* Fatal: out of memory. +/* Panic: interface violations, internal consistency errors. +/* 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. */ + +#include <msg.h> +#include <mymalloc.h> +#include <scan_dir.h> + +/* Global library. */ + +#include <mail_scan_dir.h> + +/* Application-specific. */ + +#include "qmgr.h" + +/* qmgr_scan_start - start queue scan */ + +static void qmgr_scan_start(QMGR_SCAN *scan_info) +{ + char *myname = "qmgr_scan_start"; + + /* + * Sanity check. + */ + if (scan_info->handle) + msg_panic("%s: %s queue scan in progress", + myname, scan_info->queue); + + /* + * Give the poor tester a clue. + */ + if (msg_verbose) + msg_info("%s: %sstart %s queue scan", + myname, + scan_info->nflags & QMGR_SCAN_START ? "re" : "", + scan_info->queue); + + /* + * Optionally forget all dead host information. + */ + if (scan_info->nflags & QMGR_FLUSH_DEAD) + qmgr_enable_all(); + + /* + * Start or restart the scan. + */ + scan_info->flags = scan_info->nflags; + scan_info->nflags = 0; + scan_info->handle = scan_dir_open(scan_info->queue); +} + +/* qmgr_scan_request - request for future scan */ + +void qmgr_scan_request(QMGR_SCAN *scan_info, int flags) +{ + + /* + * If a scan is in progress, just record the request. + */ + scan_info->nflags |= flags; + if (scan_info->handle == 0 && (flags & QMGR_SCAN_START) != 0) { + scan_info->nflags &= ~QMGR_SCAN_START; + qmgr_scan_start(scan_info); + } +} + +/* qmgr_scan_next - look for next queue file */ + +char *qmgr_scan_next(QMGR_SCAN *scan_info) +{ + char *path = 0; + + /* + * Restart the scan if we reach the end and a queue scan request has + * arrived in the mean time. + */ + if (scan_info->handle && (path = mail_scan_dir_next(scan_info->handle)) == 0) { + scan_info->handle = scan_dir_close(scan_info->handle); + if (msg_verbose && (scan_info->nflags & QMGR_SCAN_START) == 0) + msg_info("done %s queue scan", scan_info->queue); + } + if (!scan_info->handle && (scan_info->nflags & QMGR_SCAN_START)) { + qmgr_scan_start(scan_info); + path = mail_scan_dir_next(scan_info->handle); + } + return (path); +} + +/* qmgr_scan_create - create queue scan context */ + +QMGR_SCAN *qmgr_scan_create(const char *queue) +{ + QMGR_SCAN *scan_info; + + scan_info = (QMGR_SCAN *) mymalloc(sizeof(*scan_info)); + scan_info->queue = mystrdup(queue); + scan_info->flags = scan_info->nflags = 0; + scan_info->handle = 0; + return (scan_info); +} diff --git a/gnu/dist/postfix/src/nqmgr/qmgr_transport.c b/gnu/dist/postfix/src/nqmgr/qmgr_transport.c new file mode 100644 index 00000000000..204880962b3 --- /dev/null +++ b/gnu/dist/postfix/src/nqmgr/qmgr_transport.c @@ -0,0 +1,381 @@ +/*++ +/* NAME +/* qmgr_transport 3 +/* SUMMARY +/* per-transport data structures +/* SYNOPSIS +/* #include "qmgr.h" +/* +/* QMGR_TRANSPORT *qmgr_transport_create(name) +/* const char *name; +/* +/* QMGR_TRANSPORT *qmgr_transport_find(name) +/* const char *name; +/* +/* QMGR_TRANSPORT *qmgr_transport_select() +/* +/* void qmgr_transport_alloc(transport, notify) +/* QMGR_TRANSPORT *transport; +/* void (*notify)(QMGR_TRANSPORT *transport, VSTREAM *fp); +/* +/* void qmgr_transport_throttle(transport, reason) +/* QMGR_TRANSPORT *transport; +/* const char *reason; +/* +/* void qmgr_transport_unthrottle(transport) +/* QMGR_TRANSPORT *transport; +/* DESCRIPTION +/* This module organizes the world by message transport type. +/* Each transport can have zero or more destination queues +/* associated with it. +/* +/* qmgr_transport_create() instantiates a data structure for the +/* named transport type. +/* +/* qmgr_transport_find() looks up an existing message transport +/* data structure. +/* +/* qmgr_transport_select() attempts to find a transport that +/* has messages pending delivery. This routine implements +/* round-robin search among transports. +/* +/* qmgr_transport_alloc() allocates a delivery process for the +/* specified transport type. Allocation is performed asynchronously. +/* When a process becomes available, the application callback routine +/* is invoked with as arguments the transport and a stream that +/* is connected to a delivery process. It is an error to call +/* qmgr_transport_alloc() while delivery process allocation for +/* the same transport is in progress. +/* +/* qmgr_transport_throttle blocks further allocation of delivery +/* processes for the named transport. Attempts to throttle a +/* throttled transport are ignored. +/* +/* qmgr_transport_unthrottle() undoes qmgr_transport_throttle(). +/* Attempts to unthrottle a non-throttled transport are ignored. +/* DIAGNOSTICS +/* Panic: consistency check failure. Fatal: out of memory. +/* 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 +/* +/* Scheduler enhancements: +/* Patrik Rak +/* Modra 6 +/* 155 00, Prague, Czech Republic +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <unistd.h> + +/* Utility library. */ + +#include <msg.h> +#include <htable.h> +#include <events.h> +#include <mymalloc.h> +#include <vstream.h> +#include <iostuff.h> + +/* Global library. */ + +#include <mail_proto.h> +#include <recipient_list.h> +#include <mail_conf.h> +#include <mail_params.h> + +/* Application-specific. */ + +#include "qmgr.h" + +HTABLE *qmgr_transport_byname; /* transport by name */ +QMGR_TRANSPORT_LIST qmgr_transport_list;/* transports, round robin */ + + /* + * A local structure to remember a delivery process allocation request. + */ +typedef struct QMGR_TRANSPORT_ALLOC QMGR_TRANSPORT_ALLOC; + +struct QMGR_TRANSPORT_ALLOC { + QMGR_TRANSPORT *transport; /* transport context */ + VSTREAM *stream; /* delivery service stream */ + QMGR_TRANSPORT_ALLOC_NOTIFY notify; /* application call-back routine */ +}; + +/* qmgr_transport_unthrottle_wrapper - in case (char *) != (struct *) */ + +static void qmgr_transport_unthrottle_wrapper(int unused_event, char *context) +{ + qmgr_transport_unthrottle((QMGR_TRANSPORT *) context); +} + +/* qmgr_transport_unthrottle - open the throttle */ + +void qmgr_transport_unthrottle(QMGR_TRANSPORT *transport) +{ + char *myname = "qmgr_transport_unthrottle"; + + /* + * This routine runs after expiration of the timer set by + * qmgr_transport_throttle(), or whenever a delivery transport has been + * used without malfunction. In either case, we enable delivery again if + * the transport was blocked, otherwise the request is ignored. + */ + if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) { + if (msg_verbose) + msg_info("%s: transport %s", myname, transport->name); + transport->flags &= ~QMGR_TRANSPORT_STAT_DEAD; + if (transport->reason == 0) + msg_panic("%s: transport %s: null reason", myname, transport->name); + myfree(transport->reason); + transport->reason = 0; + event_cancel_timer(qmgr_transport_unthrottle_wrapper, + (char *) transport); + } +} + +/* qmgr_transport_throttle - disable delivery process allocation */ + +void qmgr_transport_throttle(QMGR_TRANSPORT *transport, const char *reason) +{ + char *myname = "qmgr_transport_throttle"; + + /* + * We are unable to connect to a deliver process for this type of message + * transport. Instead of hosing the system by retrying in a tight loop, + * back off and disable this transport type for a while. + */ + if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) == 0) { + if (msg_verbose) + msg_info("%s: transport %s: reason: %s", + myname, transport->name, reason); + transport->flags |= QMGR_TRANSPORT_STAT_DEAD; + if (transport->reason) + msg_panic("%s: transport %s: spurious reason: %s", + myname, transport->name, transport->reason); + transport->reason = mystrdup(reason); + event_request_timer(qmgr_transport_unthrottle_wrapper, + (char *) transport, var_transport_retry_time); + } +} + +/* qmgr_transport_abort - transport connect watchdog */ + +static void qmgr_transport_abort(int unused_event, char *context) +{ + QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context; + + msg_fatal("timeout connecting to transport: %s", alloc->transport->name); +} + +/* qmgr_transport_event - delivery process availability notice */ + +static void qmgr_transport_event(int unused_event, char *context) +{ + QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context; + + /* + * This routine notifies the application when the request given to + * qmgr_transport_alloc() completes. + */ + if (msg_verbose) + msg_info("transport_event: %s", alloc->transport->name); + + /* + * Connection request completed. Stop the watchdog timer. + */ + event_cancel_timer(qmgr_transport_abort, context); + + /* + * Disable further read events that end up calling this function. + */ + event_disable_readwrite(vstream_fileno(alloc->stream)); + alloc->transport->flags &= ~QMGR_TRANSPORT_STAT_BUSY; + + /* + * Notify the requestor. + */ + alloc->notify(alloc->transport, alloc->stream); + myfree((char *) alloc); +} + +#ifdef UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT + +/* qmgr_transport_connect - handle connection request completion */ + +static void qmgr_transport_connect(int unused_event, char *context) +{ + QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context; + + /* + * This code is necessary for some versions of LINUX, where connect(2) + * blocks until the application performs an accept(2). Reportedly, the + * same can happen on Solaris 2.5.1. + */ + event_disable_readwrite(vstream_fileno(alloc->stream)); + non_blocking(vstream_fileno(alloc->stream), BLOCKING); + event_enable_read(vstream_fileno(alloc->stream), + qmgr_transport_event, (char *) alloc); +} + +#endif + +/* qmgr_transport_select - select transport for allocation */ + +QMGR_TRANSPORT *qmgr_transport_select(void) +{ + QMGR_TRANSPORT *xport; + QMGR_QUEUE *queue; + + /* + * If we find a suitable transport, rotate the list of transports to + * effectuate round-robin selection. See similar selection code in + * qmgr_peer_select(). + */ +#define STAY_AWAY (QMGR_TRANSPORT_STAT_BUSY | QMGR_TRANSPORT_STAT_DEAD) + + for (xport = qmgr_transport_list.next; xport; xport = xport->peers.next) { + if (xport->flags & STAY_AWAY) + continue; + for (queue = xport->queue_list.next; queue; queue = queue->peers.next) { + if (queue->window > queue->busy_refcount && queue->todo.next != 0) { + QMGR_LIST_ROTATE(qmgr_transport_list, xport, peers); + if (msg_verbose) + msg_info("qmgr_transport_select: %s", xport->name); + return (xport); + } + } + } + return (0); +} + +/* qmgr_transport_alloc - allocate delivery process */ + +void qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOTIFY notify) +{ + QMGR_TRANSPORT_ALLOC *alloc; + VSTREAM *stream; + + /* + * Sanity checks. + */ + if (transport->flags & QMGR_TRANSPORT_STAT_DEAD) + msg_panic("qmgr_transport: dead transport: %s", transport->name); + if (transport->flags & QMGR_TRANSPORT_STAT_BUSY) + msg_panic("qmgr_transport: nested allocation: %s", transport->name); + + /* + * Connect to the well-known port for this delivery service, and wake up + * when a process announces its availability. In the mean time, block out + * other delivery process allocation attempts for this transport. In case + * of problems, back off. Do not hose the system when it is in trouble + * already. + */ +#ifdef UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT +#define BLOCK_MODE NON_BLOCKING +#define ENABLE_EVENTS event_enable_write +#define EVENT_HANDLER qmgr_transport_connect +#else +#define BLOCK_MODE BLOCKING +#define ENABLE_EVENTS event_enable_read +#define EVENT_HANDLER qmgr_transport_event +#endif + + if ((stream = mail_connect(MAIL_CLASS_PRIVATE, transport->name, BLOCK_MODE)) == 0) { + msg_warn("connect to transport %s: %m", transport->name); + qmgr_transport_throttle(transport, "transport is unavailable"); + return; + } + alloc = (QMGR_TRANSPORT_ALLOC *) mymalloc(sizeof(*alloc)); + alloc->stream = stream; + alloc->transport = transport; + alloc->notify = notify; + transport->flags |= QMGR_TRANSPORT_STAT_BUSY; + ENABLE_EVENTS(vstream_fileno(alloc->stream), EVENT_HANDLER, (char *) alloc); + + /* + * Guard against broken systems. + */ + event_request_timer(qmgr_transport_abort, (char *) alloc, + var_daemon_timeout); +} + +/* qmgr_transport_create - create transport instance */ + +QMGR_TRANSPORT *qmgr_transport_create(const char *name) +{ + QMGR_TRANSPORT *transport; + + if (htable_find(qmgr_transport_byname, name) != 0) + msg_panic("qmgr_transport_create: transport exists: %s", name); + transport = (QMGR_TRANSPORT *) mymalloc(sizeof(QMGR_TRANSPORT)); + transport->flags = 0; + transport->name = mystrdup(name); + + /* + * Use global configuration settings or transport-specific settings. + */ + transport->dest_concurrency_limit = + get_mail_conf_int2(name, _DEST_CON_LIMIT, + var_dest_con_limit, 0, 0); + transport->recipient_limit = + get_mail_conf_int2(name, _DEST_RCPT_LIMIT, + var_dest_rcpt_limit, 0, 0); + + if (transport->dest_concurrency_limit == 0 + || transport->dest_concurrency_limit >= var_init_dest_concurrency) + transport->init_dest_concurrency = var_init_dest_concurrency; + else + transport->init_dest_concurrency = transport->dest_concurrency_limit; + + transport->slot_cost = get_mail_conf_int2(name, _DELIVERY_SLOT_COST, + var_delivery_slot_cost, 0, 0); + transport->slot_loan = get_mail_conf_int2(name, _DELIVERY_SLOT_LOAN, + var_delivery_slot_loan, 0, 0); + transport->slot_loan_factor = + 100 - get_mail_conf_int2(name, _DELIVERY_SLOT_DISCOUNT, + var_delivery_slot_discount, 0, 100); + transport->min_slots = get_mail_conf_int2(name, _MIN_DELIVERY_SLOTS, + var_min_delivery_slots, 0, 0); + transport->rcpt_unused = get_mail_conf_int2(name, _XPORT_RCPT_LIMIT, + var_xport_rcpt_limit, 0, 0); + transport->rcpt_per_stack = get_mail_conf_int2(name, _STACK_RCPT_LIMIT, + var_stack_rcpt_limit, 0, 0); + + transport->queue_byname = htable_create(0); + QMGR_LIST_INIT(transport->queue_list); + transport->job_byname = htable_create(0); + QMGR_LIST_INIT(transport->job_list); + QMGR_LIST_INIT(transport->job_bytime); + transport->job_current = 0; + transport->job_next_unread = 0; + transport->candidate_cache = 0; + transport->candidate_cache_current = 0; + transport->candidate_cache_time = (time_t) 0; + transport->blocker_tag = 1; + transport->reason = 0; + if (qmgr_transport_byname == 0) + qmgr_transport_byname = htable_create(10); + htable_enter(qmgr_transport_byname, name, (char *) transport); + QMGR_LIST_PREPEND(qmgr_transport_list, transport, peers); + if (msg_verbose) + msg_info("qmgr_transport_create: %s concurrency %d recipients %d", + transport->name, transport->dest_concurrency_limit, + transport->recipient_limit); + return (transport); +} + +/* qmgr_transport_find - find transport instance */ + +QMGR_TRANSPORT *qmgr_transport_find(const char *name) +{ + return ((QMGR_TRANSPORT *) htable_find(qmgr_transport_byname, name)); +} diff --git a/gnu/dist/postfix/src/pickup/Makefile.in b/gnu/dist/postfix/src/pickup/Makefile.in index 19f5688fc74..a9006d5edd3 100644 --- a/gnu/dist/postfix/src/pickup/Makefile.in +++ b/gnu/dist/postfix/src/pickup/Makefile.in @@ -60,13 +60,14 @@ pickup.o: ../../include/scan_dir.h pickup.o: ../../include/vstring.h pickup.o: ../../include/vbuf.h pickup.o: ../../include/vstream.h -pickup.o: ../../include/open_as.h -pickup.o: ../../include/set_eugid.h +pickup.o: ../../include/set_ugid.h +pickup.o: ../../include/safe_open.h pickup.o: ../../include/mail_queue.h pickup.o: ../../include/mail_open_ok.h pickup.o: ../../include/mymalloc.h pickup.o: ../../include/mail_proto.h pickup.o: ../../include/iostuff.h +pickup.o: ../../include/attr.h pickup.o: ../../include/cleanup_user.h pickup.o: ../../include/mail_date.h pickup.o: ../../include/mail_params.h diff --git a/gnu/dist/postfix/src/pickup/pickup.c b/gnu/dist/postfix/src/pickup/pickup.c index 38d798e39cc..994a6328f58 100644 --- a/gnu/dist/postfix/src/pickup/pickup.c +++ b/gnu/dist/postfix/src/pickup/pickup.c @@ -7,8 +7,8 @@ /* \fBpickup\fR [generic Postfix daemon options] /* DESCRIPTION /* The \fBpickup\fR daemon waits for hints that new mail has been -/* dropped into the world-writable \fBmaildrop\fR directory, and -/* feeds it into the \fBcleanup\fR(8) daemon. +/* dropped into the \fBmaildrop\fR directory, and feeds it into the +/* \fBcleanup\fR(8) daemon. /* Ill-formatted files are deleted without notifying the originator. /* This program expects to be run from the \fBmaster\fR(8) process /* manager. @@ -58,6 +58,7 @@ /* SEE ALSO /* cleanup(8) message canonicalization /* master(8) process manager +/* sendmail(1), postdrop(8) mail posting agent /* syslogd(8) system logging /* LICENSE /* .ad @@ -89,8 +90,8 @@ #include <scan_dir.h> #include <vstring.h> #include <vstream.h> -#include <open_as.h> -#include <set_eugid.h> +#include <set_ugid.h> +#include <safe_open.h> /* Global library. */ @@ -295,7 +296,9 @@ static int pickup_copy(VSTREAM *qfile, VSTREAM *cleanup, * bounce, the cleanup service can report only soft errors here. */ rec_fputs(cleanup, REC_TYPE_END, ""); - if (mail_scan(cleanup, "%d", &status) != 1) + if (attr_scan(cleanup, ATTR_FLAG_MISSING, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status, + ATTR_TYPE_END) != 1) return (cleanup_service_error(info, CLEANUP_STAT_WRITE)); /* @@ -315,8 +318,7 @@ static int pickup_copy(VSTREAM *qfile, VSTREAM *cleanup, static int pickup_file(PICKUP_INFO *info) { - struct stat st; - VSTRING *buf; + VSTRING *buf = vstring_alloc(100); int status; VSTREAM *qfile; VSTREAM *cleanup; @@ -329,29 +331,16 @@ static int pickup_file(PICKUP_INFO *info) * Perhaps we should save "bad" files elsewhere for further inspection. * XXX How can we delete a file when open() fails with ENOENT? */ - fd = open_as(info->path, O_RDONLY | O_NONBLOCK, 0, - info->st.st_uid, info->st.st_gid); - if (fd < 0) { + qfile = safe_open(info->path, O_RDONLY | O_NONBLOCK, 0, + (struct stat *) 0, -1, -1, buf); + if (qfile == 0) { if (errno != ENOENT) - msg_fatal("open input file %s: %m", info->path); - msg_warn("open input file %s: %m", info->path); - return (REMOVE_MESSAGE_FILE); + msg_warn("open input file %s: %s", info->path, vstring_str(buf)); + vstring_free(buf); + return (errno == EACCES ? KEEP_MESSAGE_FILE : REMOVE_MESSAGE_FILE); } /* - * Like safe_open(pat, O_RDONLY, 0), but without any link count checks. - */ - if (fstat(fd, &st) < 0) - msg_fatal("fstat: %m"); - if (st.st_dev != info->st.st_dev - || st.st_ino != info->st.st_ino - || st.st_mode != info->st.st_mode) { - msg_warn("%s: uid %ld: file has changed", info->path, (long) st.st_uid); - return (REMOVE_MESSAGE_FILE); - } - qfile = vstream_fdopen(fd, O_RDONLY); - - /* * Contact the cleanup service and read the queue ID that it has * allocated. In case of trouble, request that the cleanup service * bounces its copy of the message. because the original input file is @@ -363,10 +352,13 @@ static int pickup_file(PICKUP_INFO *info) */ #define PICKUP_CLEANUP_FLAGS (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_FILTER) - buf = vstring_alloc(100); - cleanup = mail_connect_wait(MAIL_CLASS_PRIVATE, MAIL_SERVICE_CLEANUP); - if (mail_scan(cleanup, "%s", buf) != 1 - || mail_print(cleanup, "%d", PICKUP_CLEANUP_FLAGS) != 0) { + cleanup = mail_connect_wait(MAIL_CLASS_PUBLIC, MAIL_SERVICE_CLEANUP); + if (attr_scan(cleanup, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, buf, + ATTR_TYPE_END) != 1 + || attr_print(cleanup, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, PICKUP_CLEANUP_FLAGS, + ATTR_TYPE_END) != 0) { status = KEEP_MESSAGE_FILE; } else { info->id = mystrdup(vstring_str(buf)); @@ -445,11 +437,16 @@ static void pickup_service(char *unused_buf, int unused_len, } while (file_count); } -/* drop_privileges - drop privileges most of the time */ +/* drop_privileges - drop privileges */ static void drop_privileges(char *unused_name, char **unused_argv) { - set_eugid(var_owner_uid, var_owner_gid); + + /* + * In case master.cf was not updated for unprivileged service. + */ + if (getuid() != var_owner_uid) + set_ugid(var_owner_uid, var_owner_gid); } /* main - pass control to the multi-threaded server skeleton */ diff --git a/gnu/dist/postfix/src/pipe/Makefile.in b/gnu/dist/postfix/src/pipe/Makefile.in index 8575f30fbd4..c46d22ca03d 100644 --- a/gnu/dist/postfix/src/pipe/Makefile.in +++ b/gnu/dist/postfix/src/pipe/Makefile.in @@ -82,4 +82,5 @@ pipe.o: ../../include/mail_addr.h pipe.o: ../../include/canon_addr.h pipe.o: ../../include/split_addr.h pipe.o: ../../include/off_cvt.h +pipe.o: ../../include/quote_822_local.h pipe.o: ../../include/mail_server.h diff --git a/gnu/dist/postfix/src/pipe/pipe.c b/gnu/dist/postfix/src/pipe/pipe.c index 2b1552c60c1..9794c697cfc 100644 --- a/gnu/dist/postfix/src/pipe/pipe.c +++ b/gnu/dist/postfix/src/pipe/pipe.c @@ -11,6 +11,10 @@ /* This program expects to be run from the \fBmaster\fR(8) process /* manager. /* +/* Message attributes such as sender address, recipient address and +/* next-hop host name can be specified as command-line macros that are +/* expanded before the external command is executed. +/* /* The \fBpipe\fR daemon updates queue files and marks recipients /* as finished, or it informs the queue manager that delivery should /* be tried again at a later time. Delivery problem reports are sent @@ -23,10 +27,10 @@ /* fax machines, and so on. /* /* To prevent Postfix from sending multiple recipients per delivery -/* request, specify +/* request, specify /* /* .ti +4 -/* \fItransport\fB_destination_recipient_limit = 1\fR +/* \fItransport\fB_destination_recipient_limit = 1\fR /* /* in the Postfix \fBmain.cf\fR file, where \fItransport\fR /* is the name in the first column of the Postfix \fBmaster.cf\fR @@ -36,7 +40,7 @@ /* .fi /* The external command attributes are given in the \fBmaster.cf\fR /* file at the end of a service definition. The syntax is as follows: -/* .IP "\fBflags=BFR.>\fR (optional)" +/* .IP "\fBflags=BFRhqu.>\fR (optional)" /* Optional message processing flags. By default, a message is /* copied unchanged. /* .RS @@ -51,6 +55,27 @@ /* .IP \fBR\fR /* Prepend a \fBReturn-Path:\fR message header with the envelope sender /* address. +/* .IP \fBh\fR +/* Fold the command-line \fB$recipient\fR domain name and \fB$nexthop\fR +/* host name to lower case. +/* This is recommended for delivery via \fBUUCP\fR. +/* .IP \fBq\fR +/* Quote white space and other special characters in the command-line +/* \fB$sender\fR and \fB$recipient\fR address localparts (text to the +/* left of the right-most \fB@\fR character), according to an 8-bit +/* transparent version of RFC 822. +/* This is recommended for delivery via \fBUUCP\fR or \fBBSMTP\fR. +/* .sp +/* The result is compatible with the address parsing of command-line +/* recipients by the Postfix \fBsendmail\fR mail submission command. +/* .sp +/* The \fBq\fR flag affects only entire addresses, not the partial +/* address information from the \fB$user\fR, \fB$extension\fR or +/* \fB$mailbox\fR command-line macros. +/* .IP \fBu\fR +/* Fold the command-line \fB$recipient\fR address localpart (text to +/* the left of the right-most \fB@\fR character) to lower case. +/* This is recommended for delivery via \fBUUCP\fR. /* .IP \fB.\fR /* Prepend \fB.\fR to lines starting with "\fB.\fR". This is needed /* by, for example, \fBBSMTP\fR software. @@ -91,6 +116,8 @@ /* .sp /* A command-line argument that contains \fB${\fBextension\fR}\fR expands /* into as many command-line arguments as there are recipients. +/* .sp +/* This information is modified by the \fBu\fR flag for case folding. /* .IP \fB${\fBmailbox\fR}\fR /* This macro expands to the complete local part of a recipient address. /* For example, with an address \fIuser+foo@domain\fR the mailbox is @@ -98,15 +125,24 @@ /* .sp /* A command-line argument that contains \fB${\fBmailbox\fR}\fR /* expands into as many command-line arguments as there are recipients. +/* .sp +/* This information is modified by the \fBu\fR flag for case folding. /* .IP \fB${\fBnexthop\fR}\fR /* This macro expands to the next-hop hostname. +/* .sp +/* This information is modified by the \fBh\fR flag for case folding. /* .IP \fB${\fBrecipient\fR}\fR /* This macro expands to the complete recipient address. /* .sp /* A command-line argument that contains \fB${\fBrecipient\fR}\fR /* expands into as many command-line arguments as there are recipients. +/* .sp +/* This information is modified by the \fBhqu\fR flags for quoting +/* and case folding. /* .IP \fB${\fBsender\fR}\fR /* This macro expands to the envelope sender address. +/* .sp +/* This information is modified by the \fBq\fR flag for quoting. /* .IP \fB${\fBsize\fR}\fR /* This macro expands to Postfix's idea of the message size, which /* is an approximation of the size of the message as delivered. @@ -117,6 +153,8 @@ /* .sp /* A command-line argument that contains \fB${\fBuser\fR}\fR expands /* into as many command-line arguments as there are recipients. +/* .sp +/* This information is modified by the \fBu\fR flag for case folding. /* .RE /* .PP /* In addition to the form ${\fIname\fR}, the forms $\fIname\fR and @@ -195,6 +233,7 @@ #include <pwd.h> #include <grp.h> #include <fcntl.h> +#include <ctype.h> #ifdef STRCASECMP_IN_STRINGS_H #include <strings.h> @@ -231,6 +270,7 @@ #include <canon_addr.h> #include <split_addr.h> #include <off_cvt.h> +#include <quote_822_local.h> /* Single server skeleton. */ @@ -262,6 +302,16 @@ #define PIPE_FLAG_SIZE (1<<4) /* + * Additional flags. These are colocated with mail_copy() flags. Allow some + * space for extension of the mail_copy() interface. + */ +#define PIPE_OPT_FOLD_USER (1<<16) +#define PIPE_OPT_FOLD_HOST (1<<17) +#define PIPE_OPT_QUOTE_LOCAL (1<<18) + +#define PIPE_OPT_FOLD_FLAGS (PIPE_OPT_FOLD_USER | PIPE_OPT_FOLD_HOST) + + /* * Tunable parameters. Values are taken from the config file, after * prepending the service name to _name, and so on. */ @@ -291,6 +341,11 @@ typedef struct { off_t size_limit; /* max size in bytes we will accept */ } PIPE_ATTR; + /* + * Silly little macros. + */ +#define STR vstring_str + /* parse_callback - callback for mac_parse() */ static int parse_callback(int type, VSTRING *buf, char *context) @@ -313,9 +368,44 @@ static int parse_callback(int type, VSTRING *buf, char *context) return (0); } +/* morph_recipient - morph a recipient address */ + +static void morph_recipient(VSTRING *buf, const char *address, int flags) +{ + char *cp; + + /* + * Quote the recipient address as appropriate. + */ + if (flags & PIPE_OPT_QUOTE_LOCAL) + quote_822_local(buf, address); + else + vstring_strcpy(buf, address); + + /* + * Fold the recipient address as appropriate. + */ + switch (flags & PIPE_OPT_FOLD_FLAGS) { + case PIPE_OPT_FOLD_HOST: + if ((cp = strrchr(STR(buf), '@')) != 0) + lowercase(cp + 1); + break; + case PIPE_OPT_FOLD_USER: + if ((cp = strrchr(STR(buf), '@')) != 0) { + *cp = 0; + lowercase(STR(buf)); + *cp = '@'; + break; + } + case PIPE_OPT_FOLD_USER | PIPE_OPT_FOLD_HOST: + lowercase(STR(buf)); + break; + } +} + /* expand_argv - expand macros in the argument vector */ -static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list) +static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list, int flags) { VSTRING *buf = vstring_alloc(100); ARGV *result; @@ -338,7 +428,6 @@ static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list) * would screw up mail addresses that contain $ characters. */ #define NO 0 -#define STR vstring_str result = argv_alloc(1); for (cpp = argv; *cpp; cpp++) { @@ -353,8 +442,8 @@ static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list) * This argument contains $recipient. */ if (expand_flag & PIPE_FLAG_RCPT) { - dict_update(PIPE_DICT_TABLE, PIPE_DICT_RCPT, - rcpt_list->info[i].address); + morph_recipient(buf, rcpt_list->info[i].address, flags); + dict_update(PIPE_DICT_TABLE, PIPE_DICT_RCPT, STR(buf)); } /* @@ -370,7 +459,8 @@ static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list) * expansions of this specific command-line argument. */ if (expand_flag & PIPE_FLAG_USER) { - vstring_strcpy(buf, rcpt_list->info[i].address); + morph_recipient(buf, rcpt_list->info[i].address, + flags & PIPE_OPT_FOLD_FLAGS); if (split_at_right(STR(buf), '@') == 0) msg_warn("no @ in recipient address: %s", rcpt_list->info[i].address); @@ -378,7 +468,6 @@ static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list) split_addr(STR(buf), *var_rcpt_delim); if (*STR(buf) == 0) continue; - lowercase(STR(buf)); dict_update(PIPE_DICT_TABLE, PIPE_DICT_USER, STR(buf)); } @@ -388,15 +477,14 @@ static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list) * delimiter and the rightmost @. The extension may be blank. */ if (expand_flag & PIPE_FLAG_EXTENSION) { - vstring_strcpy(buf, rcpt_list->info[i].address); + morph_recipient(buf, rcpt_list->info[i].address, + flags & PIPE_OPT_FOLD_FLAGS); if (split_at_right(STR(buf), '@') == 0) msg_warn("no @ in recipient address: %s", rcpt_list->info[i].address); if (*var_rcpt_delim == 0 || (ext = split_addr(STR(buf), *var_rcpt_delim)) == 0) ext = ""; /* insert null arg */ - else - lowercase(ext); dict_update(PIPE_DICT_TABLE, PIPE_DICT_EXTENSION, ext); } @@ -405,11 +493,11 @@ static ARGV *expand_argv(char **argv, RECIPIENT_LIST *rcpt_list) * anything to the left of the rightmost @. */ if (expand_flag & PIPE_FLAG_MAILBOX) { - vstring_strcpy(buf, rcpt_list->info[i].address); + morph_recipient(buf, rcpt_list->info[i].address, + flags & PIPE_OPT_FOLD_FLAGS); if (split_at_right(STR(buf), '@') == 0) msg_warn("no @ in recipient address: %s", rcpt_list->info[i].address); - lowercase(STR(buf)); dict_update(PIPE_DICT_TABLE, PIPE_DICT_MAILBOX, STR(buf)); } @@ -492,6 +580,15 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv) case 'R': attr->flags |= MAIL_COPY_RETURN_PATH; break; + case 'h': + attr->flags |= PIPE_OPT_FOLD_HOST; + break; + case 'q': + attr->flags |= PIPE_OPT_QUOTE_LOCAL; + break; + case 'u': + attr->flags |= PIPE_OPT_FOLD_USER; + break; default: msg_fatal("unknown flag: %c (ignored)", *cp); break; @@ -620,6 +717,9 @@ static int eval_command_status(int command_status, char *service, service, request->arrival_time, "%s", why); } break; + case PIPE_STAT_CORRUPT: + result |= DEL_STAT_DEFER; + break; default: msg_panic("eval_command_status: bad status %d", command_status); /* NOTREACHED */ @@ -704,13 +804,22 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv) if (vstream_fseek(request->fp, request->data_offset, SEEK_SET) < 0) msg_fatal("seek queue file %s: %m", VSTREAM_PATH(request->fp)); - dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, request->sender); - dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop); buf = vstring_alloc(10); + if (attr.flags & PIPE_OPT_QUOTE_LOCAL) { + quote_822_local(buf, request->sender); + dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, STR(buf)); + } else + dict_update(PIPE_DICT_TABLE, PIPE_DICT_SENDER, request->sender); + if (attr.flags & PIPE_OPT_FOLD_HOST) { + vstring_strcpy(buf, request->nexthop); + lowercase(STR(buf)); + dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, STR(buf)); + } else + dict_update(PIPE_DICT_TABLE, PIPE_DICT_NEXTHOP, request->nexthop); vstring_sprintf(buf, "%ld", (long) request->data_size); dict_update(PIPE_DICT_TABLE, PIPE_DICT_SIZE, STR(buf)); vstring_free(buf); - expanded_argv = expand_argv(attr.command, rcpt_list); + expanded_argv = expand_argv(attr.command, rcpt_list, attr.flags); export_env = argv_split(var_export_environ, ", \t\r\n"); command_status = pipe_command(request->fp, why, diff --git a/gnu/dist/postfix/src/postalias/Makefile.in b/gnu/dist/postfix/src/postalias/Makefile.in index 1fbc2a67d54..b18759656dd 100644 --- a/gnu/dist/postfix/src/postalias/Makefile.in +++ b/gnu/dist/postfix/src/postalias/Makefile.in @@ -21,10 +21,36 @@ $(PROG): $(OBJS) $(LIBS) Makefile: Makefile.in (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@ -test: $(TESTPROG) - update: ../../bin/$(PROG) +test: test1 test2 + +test1: $(PROG) map.in map-abc1.ref map-ghi1.ref map-ABC1.ref + ./$(PROG) map.in + for key in abc ghi; \ + do \ + ./$(PROG) -q $${key} map.in | diff map-$${key}1.ref -; \ + done + ./$(PROG) -f map.in + for key in ABC; \ + do \ + ./$(PROG) -fq $${key} map.in | diff map-$${key}1.ref -; \ + done + rm -f map.in.db + +test2: $(PROG) map.in map-abc2.ref map-ghi2.ref map-ABC2.ref + ./$(PROG) map.in + for key in abc ghi; \ + do \ + echo $${key} | ./$(PROG) -q - map.in | diff map-$${key}2.ref -; \ + done + ./$(PROG) -f map.in + for key in ABC; \ + do \ + echo $${key} | ./$(PROG) -fq - map.in | diff map-$${key}2.ref -; \ + done + rm -f map.in.db + ../../bin/$(PROG): $(PROG) cp $(PROG) ../../bin @@ -65,6 +91,7 @@ postalias.o: ../../include/readlline.h postalias.o: ../../include/stringops.h postalias.o: ../../include/split_at.h postalias.o: ../../include/get_hostname.h +postalias.o: ../../include/vstring_vstream.h postalias.o: ../../include/tok822.h postalias.o: ../../include/resolve_clnt.h postalias.o: ../../include/mail_conf.h diff --git a/gnu/dist/postfix/src/postalias/map-ABC1.ref b/gnu/dist/postfix/src/postalias/map-ABC1.ref new file mode 100644 index 00000000000..142195f36ae --- /dev/null +++ b/gnu/dist/postfix/src/postalias/map-ABC1.ref @@ -0,0 +1 @@ +DEF diff --git a/gnu/dist/postfix/src/postalias/map-ABC2.ref b/gnu/dist/postfix/src/postalias/map-ABC2.ref new file mode 100644 index 00000000000..929916bcb4d --- /dev/null +++ b/gnu/dist/postfix/src/postalias/map-ABC2.ref @@ -0,0 +1 @@ +ABC: DEF diff --git a/gnu/dist/postfix/src/postalias/map-abc1.ref b/gnu/dist/postfix/src/postalias/map-abc1.ref new file mode 100644 index 00000000000..142195f36ae --- /dev/null +++ b/gnu/dist/postfix/src/postalias/map-abc1.ref @@ -0,0 +1 @@ +DEF diff --git a/gnu/dist/postfix/src/postalias/map-abc2.ref b/gnu/dist/postfix/src/postalias/map-abc2.ref new file mode 100644 index 00000000000..dfbdab6f18e --- /dev/null +++ b/gnu/dist/postfix/src/postalias/map-abc2.ref @@ -0,0 +1 @@ +abc: DEF diff --git a/gnu/dist/postfix/src/postalias/map-ghi1.ref b/gnu/dist/postfix/src/postalias/map-ghi1.ref new file mode 100644 index 00000000000..7beb1db20dc --- /dev/null +++ b/gnu/dist/postfix/src/postalias/map-ghi1.ref @@ -0,0 +1 @@ +jkl diff --git a/gnu/dist/postfix/src/postalias/map-ghi2.ref b/gnu/dist/postfix/src/postalias/map-ghi2.ref new file mode 100644 index 00000000000..e2ca310ca9d --- /dev/null +++ b/gnu/dist/postfix/src/postalias/map-ghi2.ref @@ -0,0 +1 @@ +ghi: jkl diff --git a/gnu/dist/postfix/src/postalias/map.in b/gnu/dist/postfix/src/postalias/map.in new file mode 100644 index 00000000000..203fa0cd34a --- /dev/null +++ b/gnu/dist/postfix/src/postalias/map.in @@ -0,0 +1,2 @@ +ABC: DEF +ghi: jkl diff --git a/gnu/dist/postfix/src/postalias/postalias.c b/gnu/dist/postfix/src/postalias/postalias.c index 0fe46f910f5..6daf0fff6d4 100644 --- a/gnu/dist/postfix/src/postalias/postalias.c +++ b/gnu/dist/postfix/src/postalias/postalias.c @@ -5,7 +5,7 @@ /* Postfix alias database maintenance /* SYNOPSIS /* .fi -/* \fBpostalias\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR] +/* \fBpostalias\fR [\fB-Nfinrvw\fR] [\fB-c \fIconfig_dir\fR] /* [\fB-d \fIkey\fR] [\fB-q \fIkey\fR] /* [\fIfile_type\fR:]\fIfile_name\fR ... /* DESCRIPTION @@ -29,7 +29,14 @@ /* instead of the default configuration directory. /* .IP "\fB-d \fIkey\fR" /* Search the specified maps for \fIkey\fR and remove one entry per map. -/* The exit status is non-zero if the requested information was not found. +/* The exit status is zero when the requested information was found. +/* +/* If a key value of \fB-\fR is specified, the program reads key +/* values from the standard input stream. The exit status is zero +/* when at least one of the requested keys was found. +/* .IP \fB-f\fR +/* Do not fold the lookup key to lower case while creating or querying +/* a map. /* .IP \fB-i\fR /* Incremental mode. Read entries from standard input and do not /* truncate an existing database. By default, \fBpostalias\fR creates @@ -40,8 +47,13 @@ /* the host operating system. /* .IP "\fB-q \fIkey\fR" /* Search the specified maps for \fIkey\fR and print the first value -/* found on the standard output stream. The exit status is non-zero -/* if the requested information was not found. +/* found on the standard output stream. The exit status is zero +/* when the requested information was found. +/* +/* If a key value of \fB-\fR is specified, the program reads key +/* values from the standard input stream and prints one line of +/* \fIkey: value\fR output for each key that was found. The exit +/* status is zero when at least one of the requested keys was found. /* .IP \fB-r\fR /* When updating a table, do not warn about duplicate entries; silently /* replace them. @@ -81,9 +93,6 @@ /* \fBpostalias\fR terminates with zero exit status in case of success /* (including successful \fBpostmap -q\fR lookup) and terminates /* with non-zero exit status in case of failure. -/* BUGS -/* The "delete key" support is limited to one delete operation -/* per command invocation. /* ENVIRONMENT /* .ad /* .fi @@ -137,6 +146,7 @@ #include <stringops.h> #include <split_at.h> #include <get_hostname.h> +#include <vstring_vstream.h> /* Global library. */ @@ -188,23 +198,7 @@ static void postalias(char *map_type, char *path_name, * Add records to the database. */ lineno = 0; - while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) { - - /* - * Skip comments. - */ - if (*STR(line_buffer) == '#') - continue; - - /* - * Weird stuff. Normally, a line that begins with whitespace is a - * continuation of the previous line. - */ - if (ISSPACE(*STR(line_buffer))) { - msg_warn("%s, line %d: malformed line", - VSTREAM_PATH(source_fp), lineno); - continue; - } + while (readlline(line_buffer, source_fp, &lineno)) { /* * Tokenize the input, so that we do the right thing when a quoted @@ -263,7 +257,8 @@ static void postalias(char *map_type, char *path_name, /* * Store the value under a case-insensitive key. */ - lowercase(STR(key_buffer)); + if (dict_flags & DICT_FLAG_FOLD_KEY) + lowercase(STR(key_buffer)); mkmap_append(mkmap, STR(key_buffer), STR(value_buffer)); } @@ -306,6 +301,65 @@ static void postalias(char *map_type, char *path_name, vstream_fclose(source_fp); } +/* postalias_queries - apply multiple requests from stdin */ + +static int postalias_queries(VSTREAM *in, char **maps, const int map_count, + const int dict_flags) +{ + int found = 0; + VSTRING *keybuf = vstring_alloc(100); + DICT **dicts; + const char *map_name; + const char *value; + int n; + + /* + * Sanity check. + */ + if (map_count <= 0) + msg_panic("postalias_queries: bad map count"); + + /* + * Prepare to open maps lazily. + */ + dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); + for (n = 0; n < map_count; n++) + dicts[n] = 0; + + /* + * Perform all queries. Open maps on the fly, to avoid opening unecessary + * maps. + */ + while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { + if (dict_flags & DICT_FLAG_FOLD_KEY) + lowercase(STR(keybuf)); + for (n = 0; n < map_count; n++) { + if (dicts[n] == 0) + dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ? + dict_open3(maps[n], map_name, O_RDONLY, DICT_FLAG_LOCK) : + dict_open3(var_db_type, maps[n], O_RDONLY, DICT_FLAG_LOCK)); + if ((value = dict_get(dicts[n], STR(keybuf))) != 0) { + vstream_printf("%s: %s\n", STR(keybuf), value); + found = 1; + break; + } + } + } + if (found) + vstream_fflush(VSTREAM_OUT); + + /* + * Cleanup. + */ + for (n = 0; n < map_count; n++) + if (dicts[n]) + dict_close(dicts[n]); + myfree((char *) dicts); + vstring_free(keybuf); + + return (found); +} + /* postalias_query - query a map and print the result to stdout */ static int postalias_query(const char *map_type, const char *map_name, @@ -323,6 +377,50 @@ static int postalias_query(const char *map_type, const char *map_name, return (value != 0); } +/* postalias_deletes - apply multiple requests from stdin */ + +static int postalias_deletes(VSTREAM *in, char **maps, const int map_count) +{ + int found = 0; + VSTRING *keybuf = vstring_alloc(100); + DICT **dicts; + const char *map_name; + int n; + + /* + * Sanity check. + */ + if (map_count <= 0) + msg_panic("postalias_deletes: bad map count"); + + /* + * Open maps ahead of time. + */ + dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); + for (n = 0; n < map_count; n++) + dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ? + dict_open3(maps[n], map_name, O_RDWR, DICT_FLAG_LOCK) : + dict_open3(var_db_type, maps[n], O_RDWR, DICT_FLAG_LOCK)); + + /* + * Perform all requests. + */ + while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) + for (n = 0; n < map_count; n++) + found |= (dict_del(dicts[n], STR(keybuf)) == 0); + + /* + * Cleanup. + */ + for (n = 0; n < map_count; n++) + if (dicts[n]) + dict_close(dicts[n]); + myfree((char *) dicts); + vstring_free(keybuf); + + return (found); +} + /* postalias_delete - delete a key value pair from a map */ static int postalias_delete(const char *map_type, const char *map_name, @@ -331,10 +429,6 @@ static int postalias_delete(const char *map_type, const char *map_name, DICT *dict; int status; - /* - * XXX This must be generalized to multi-key (read from stdin) and - * multi-map (given on command line) updates. - */ dict = dict_open3(map_type, map_name, O_RDWR, DICT_FLAG_LOCK); status = dict_del(dict, key); dict_close(dict); @@ -345,7 +439,7 @@ static int postalias_delete(const char *map_type, const char *map_name, static NORETURN usage(char *myname) { - msg_fatal("usage: %s [-Ninrvw] [-c config_dir] [-d key] [-q key] [map_type:]file...", + msg_fatal("usage: %s [-Nfinrvw] [-c config_dir] [-d key] [-q key] [map_type:]file...", myname); } @@ -357,7 +451,7 @@ int main(int argc, char **argv) char *slash; struct stat st; int open_flags = O_RDWR | O_CREAT | O_TRUNC; - int dict_flags = DICT_FLAG_DUP_WARN; + int dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_KEY; char *query = 0; char *delkey = 0; int found; @@ -395,7 +489,7 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((ch = GETOPT(argc, argv, "Nc:d:inq:rvw")) > 0) { + while ((ch = GETOPT(argc, argv, "Nc:d:finq:rvw")) > 0) { switch (ch) { default: usage(argv[0]); @@ -413,6 +507,9 @@ int main(int argc, char **argv) msg_fatal("specify only one of -q or -d"); delkey = optarg; break; + case 'f': + dict_flags &= ~DICT_FLAG_FOLD_KEY; + break; case 'i': open_flags &= ~O_TRUNC; break; @@ -447,6 +544,8 @@ int main(int argc, char **argv) if (delkey) { /* remove entry */ if (optind + 1 > argc) usage(argv[0]); + if (strcmp(delkey, "-") == 0) + exit(postalias_deletes(VSTREAM_IN, argv + optind, argc - optind) == 0); found = 0; while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { @@ -460,6 +559,11 @@ int main(int argc, char **argv) } else if (query) { /* query map(s) */ if (optind + 1 > argc) usage(argv[0]); + if (strcmp(query, "-") == 0) + exit(postalias_queries(VSTREAM_IN, argv + optind, argc - optind, + dict_flags) == 0); + if (dict_flags & DICT_FLAG_FOLD_KEY) + lowercase(query); while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { found = postalias_query(argv[optind], path_name, query); diff --git a/gnu/dist/postfix/src/postconf/Makefile.in b/gnu/dist/postfix/src/postconf/Makefile.in index 1cf46772319..35434d4b751 100644 --- a/gnu/dist/postfix/src/postconf/Makefile.in +++ b/gnu/dist/postfix/src/postconf/Makefile.in @@ -23,7 +23,10 @@ $(PROG): $(OBJS) $(LIBS) ../../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 $?) >$@ @@ -35,7 +38,7 @@ update: ../../bin/$(PROG) $(SAMPLES) ../../bin/$(PROG): $(PROG) cp $(PROG) ../../bin -$(MAKES): $(INC_DIR)/mail_params.h +$(MAKES): $(INC_DIR)/mail_params.h ../global/mail_params.c $(AWK) -f extract.awk ../*/*.c printfck: $(OBJS) $(PROG) @@ -79,12 +82,13 @@ postconf.o: ../../include/argv.h postconf.o: ../../include/safe.h postconf.o: ../../include/mymalloc.h postconf.o: ../../include/split_at.h -postconf.o: ../../include/readlline.h +postconf.o: ../../include/vstring_vstream.h postconf.o: ../../include/myflock.h postconf.o: ../../include/mynetworks.h postconf.o: ../../include/mail_conf.h postconf.o: ../../include/mail_proto.h postconf.o: ../../include/iostuff.h +postconf.o: ../../include/attr.h postconf.o: ../../include/mail_version.h postconf.o: ../../include/mail_params.h postconf.o: ../../include/mail_addr.h @@ -95,9 +99,11 @@ postconf.o: int_vars.h postconf.o: str_vars.h postconf.o: raw_vars.h postconf.o: smtp_vars.h +postconf.o: install_vars.h postconf.o: time_table.h postconf.o: bool_table.h postconf.o: int_table.h postconf.o: str_table.h postconf.o: smtp_table.h +postconf.o: install_table.h postconf.o: raw_table.h diff --git a/gnu/dist/postfix/src/postconf/install_table.h b/gnu/dist/postfix/src/postconf/install_table.h new file mode 100644 index 00000000000..a7dff6f3f18 --- /dev/null +++ b/gnu/dist/postfix/src/postconf/install_table.h @@ -0,0 +1 @@ + VAR_CONFIG_DIR, DEF_CONFIG_DIR, &var_config_dir, 1, 0, diff --git a/gnu/dist/postfix/src/postconf/install_vars.h b/gnu/dist/postfix/src/postconf/install_vars.h new file mode 100644 index 00000000000..c54581ee8ee --- /dev/null +++ b/gnu/dist/postfix/src/postconf/install_vars.h @@ -0,0 +1 @@ +char *var_config_dir; diff --git a/gnu/dist/postfix/src/postconf/postconf.c b/gnu/dist/postfix/src/postconf/postconf.c index da7d5625edd..ffcc7fbd86c 100644 --- a/gnu/dist/postfix/src/postconf/postconf.c +++ b/gnu/dist/postfix/src/postconf/postconf.c @@ -84,7 +84,7 @@ #include <mymalloc.h> #include <argv.h> #include <split_at.h> -#include <readlline.h> +#include <vstring_vstream.h> #include <myflock.h> /* Global library. */ @@ -131,6 +131,7 @@ DICT *text_table; * Manually extracted. */ #include "smtp_vars.h" +#include "install_vars.h" /* * Lookup tables generated by scanning actual C source files. @@ -153,6 +154,7 @@ static CONFIG_INT_TABLE int_table[] = { static CONFIG_STR_TABLE str_table[] = { #include "str_table.h" #include "smtp_table.h" /* XXX */ +#include "install_table.h" 0, }; @@ -225,7 +227,7 @@ static void get_myhostname(void) { const char *name; - if ((name = dict_lookup(CONFIG_DICT, VAR_MYHOSTNAME)) == 0) + if ((name = mail_conf_lookup_eval(VAR_MYHOSTNAME)) == 0) name = check_myhostname(); var_myhostname = mystrdup(name); } @@ -255,13 +257,13 @@ static const char *check_mynetworks(void) if (var_inet_interfaces == 0) { if ((mode & SHOW_DEFS) - || !(junk = mail_conf_lookup(VAR_INET_INTERFACES))) + || !(junk = mail_conf_lookup_eval(VAR_INET_INTERFACES))) junk = DEF_INET_INTERFACES; var_inet_interfaces = mystrdup(junk); } if (var_mynetworks_style == 0) { if ((mode & SHOW_DEFS) - || !(junk = mail_conf_lookup(VAR_MYNETWORKS_STYLE))) + || !(junk = mail_conf_lookup_eval(VAR_MYNETWORKS_STYLE))) junk = DEF_MYNETWORKS_STYLE; var_mynetworks_style = mystrdup(junk); } @@ -280,9 +282,9 @@ static void edit_parameters(int argc, char **argv) VSTRING *buf = vstring_alloc(100); VSTRING *key = vstring_alloc(10); char *cp; - char *value; + char *edit_key; + char *edit_val; HTABLE *table; - int first = 1; struct cvalue { char *value; int found; @@ -290,21 +292,26 @@ static void edit_parameters(int argc, char **argv) struct cvalue *cvalue; HTABLE_INFO **ht_info; HTABLE_INFO **ht; + int interesting; + const char *err; /* * Store command-line parameters for quick lookup. */ table = htable_create(argc); while ((cp = *argv++) != 0) { - if ((value = split_at(cp, '=')) == 0 - || *(cp += strspn(cp, " \t\r\n")) == 0) - msg_fatal("edit requires \"key = value\" arguments"); - while (*value && ISSPACE(*value)) - value++; + if (strchr(cp, '\n') != 0) + msg_fatal("edit accepts no multi-line input"); + while (ISSPACE(*cp)) + cp++; + if (*cp == '#') + msg_fatal("edit accepts no comment input"); + if ((err = split_nameval(cp, &edit_key, &edit_val)) != 0) + msg_fatal("%s: \"%s\"", err, cp); cvalue = (struct cvalue *) mymalloc(sizeof(*cvalue)); - cvalue->value = value; + cvalue->value = edit_val; cvalue->found = 0; - htable_enter(table, mystrtok(&cp, " \t\r\n"), (char *) cvalue); + htable_enter(table, edit_key, (char *) cvalue); } /* @@ -342,26 +349,30 @@ static void edit_parameters(int argc, char **argv) */ #define STR(x) vstring_str(x) - while (readlline(buf, src, (int *) 0, READLL_KEEPNL)) { - cp = STR(buf); - if (first) { - first = 0; - if (ISSPACE(*cp)) - msg_fatal("%s: file starts with whitespace", path); - } - if (*cp == '#') { + interesting = 0; + while (vstring_get(buf, src) != VSTREAM_EOF) { + for (cp = STR(buf); ISSPACE(*cp) /* including newline */ ; cp++) + /* void */ ; + /* Copy comment, all-whitespace, or empty line. */ + if (*cp == '#' || *cp == 0) { vstream_fputs(STR(buf), dst); - continue; } - cp += strspn(cp, " \t\r\n"); - vstring_strncpy(key, cp, strcspn(cp, " \t\r\n=")); - cvalue = (struct cvalue *) htable_find(table, STR(key)); - if (cvalue == 0) { - vstream_fputs(STR(buf), dst); - } else { - if (cvalue->found++ == 1) - msg_warn("%s: multiple entries for key %s", path, STR(key)); - vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value); + /* Copy or skip continued text. */ + else if (cp > STR(buf)) { + if (interesting == 0) + vstream_fputs(STR(buf), dst); + } + /* Copy or replace start of logical line. */ + else { + vstring_strncpy(key, cp, strcspn(cp, " \t\r\n=")); + cvalue = (struct cvalue *) htable_find(table, STR(key)); + if ((interesting = !!cvalue) != 0) { + if (cvalue->found++ == 1) + msg_warn("%s: multiple entries for \"%s\"", path, STR(key)); + vstream_fprintf(dst, "%s = %s\n", STR(key), cvalue->value); + } else { + vstream_fputs(STR(buf), dst); + } } } diff --git a/gnu/dist/postfix/src/postdrop/Makefile.in b/gnu/dist/postfix/src/postdrop/Makefile.in index 2d893c3ac61..a58a1b581ce 100644 --- a/gnu/dist/postfix/src/postdrop/Makefile.in +++ b/gnu/dist/postfix/src/postdrop/Makefile.in @@ -63,8 +63,9 @@ postdrop.o: ../../include/vstring.h postdrop.o: ../../include/msg_vstream.h postdrop.o: ../../include/msg_syslog.h postdrop.o: ../../include/argv.h -postdrop.o: ../../include/mail_proto.h postdrop.o: ../../include/iostuff.h +postdrop.o: ../../include/mail_proto.h +postdrop.o: ../../include/attr.h postdrop.o: ../../include/mail_queue.h postdrop.o: ../../include/mail_params.h postdrop.o: ../../include/mail_conf.h diff --git a/gnu/dist/postfix/src/postdrop/postdrop.c b/gnu/dist/postfix/src/postdrop/postdrop.c index 4a8c16d3c48..dacd70fdee5 100644 --- a/gnu/dist/postfix/src/postdrop/postdrop.c +++ b/gnu/dist/postfix/src/postdrop/postdrop.c @@ -2,29 +2,31 @@ /* NAME /* postdrop 1 /* SUMMARY -/* Postfix mail posting agent +/* Postfix mail posting utility /* SYNOPSIS -/* \fBpostdrop\fR [\fIoption ...\fR] +/* \fBpostdrop\fR [\fB-rv\fR] [\fB-c \fIconfig_dir\fR] /* DESCRIPTION /* The \fBpostdrop\fR command creates a file in the \fBmaildrop\fR /* directory and copies its standard input to the file. /* -/* The command is designed to run with set-gid privileges, and with -/* group write permission to the \fBmaildrop\fR queue directory. -/* -/* The \fBpostdrop\fR command is automatically invoked by the -/* \fBsendmail\fR(1) mail posting agent when the \fBmaildrop\fR -/* queue directory is not world-writable. -/* /* Options: +/* .IP \fB-c \fIconfig_dir\fR +/* The \fBmain.cf\fR configuration file is in the named directory +/* instead of the default configuration directory. See also the +/* MAIL_CONFIG environment setting below. +/* .IP \fB-r\fR +/* Use a Postfix-internal protocol for reading the message from +/* standard input, and for reporting status information on standard +/* output. This is currently the only supported method. /* .IP \fB-v\fR /* Enable verbose logging for debugging purposes. Multiple \fB-v\fR /* options make the software increasingly verbose. /* SECURITY /* .ad /* .fi -/* This program is designed so that it can run with set-user (or -/* group) id privileges. +/* The command is designed to run with set-group ID privileges, so +/* that it can write to the \fBmaildrop\fR queue directory and so that +/* it can connect to Postfix daemon processes. /* DIAGNOSTICS /* Fatal errors: malformed input, I/O error, out of memory. Problems /* are logged to \fBsyslogd\fR(8) and to the standard error stream. @@ -33,8 +35,16 @@ /* ENVIRONMENT /* .ad /* .fi -/* The program deletes all environment information, because the C -/* library can't be trusted. +/* .IP MAIL_CONFIG +/* Directory with the \fBmain.cf\fR file. In order to avoid exploitation +/* of set-group ID privileges, it is not possible to specify arbitrary +/* directory names. +/* +/* A non-standard directory is allowed only if the name is listed in the +/* standard \fBmain.cf\fR file, in the \fBalternate_config_directories\fR +/* configuration parameter value. +/* +/* Only the super-user is allowed to specify arbitrary directory names. /* FILES /* /var/spool/postfix, mail queue /* /etc/postfix, configuration files @@ -75,6 +85,7 @@ #include <stdlib.h> #include <signal.h> #include <syslog.h> +#include <errno.h> /* Utility library. */ @@ -85,6 +96,7 @@ #include <msg_vstream.h> #include <msg_syslog.h> #include <argv.h> +#include <iostuff.h> /* Global library. */ @@ -104,10 +116,14 @@ /* * WARNING WARNING WARNING * - * This software is designed to run set-gid on systems that cannot afford a - * world-writable spool directory. In order to make this restriction work, - * this software should not run any external commands, nor should it take - * any configuration information from the user. + * This software is designed to run set-gid. In order to avoid exploitation of + * privilege, this software should not run any external commands, nor should + * it take any information from the user unless that information can be + * properly sanitized. To get an idea of how much information a process can + * inherit from a potentially hostile user, examine all the members of the + * process structure (typically, in /usr/include/sys/proc.h): the current + * directory, open files, timers, signals, environment, command line, umask, + * and so on. */ /* @@ -137,8 +153,17 @@ static void postdrop_cleanup(void) static void postdrop_sig(int sig) { - postdrop_cleanup(); - exit(sig); + + /* + * Assume atomic signal() updates, even when emulated with sigaction(). + */ + if (signal(SIGHUP, SIG_IGN) != SIG_IGN + && signal(SIGINT, SIG_IGN) != SIG_IGN + && signal(SIGQUIT, SIG_IGN) != SIG_IGN + && signal(SIGTERM, SIG_IGN) != SIG_IGN) { + postdrop_cleanup(); + exit(sig); + } } /* main - the main program */ @@ -183,6 +208,28 @@ int main(int argc, char **argv) set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); /* + * Parse JCL. This program is set-gid and must sanitize all command-line + * arguments. The configuration directory argument is validated by the + * mail configuration read routine. Don't do complex things until we have + * completed initializations. + */ + while ((c = GETOPT(argc, argv, "c:rv")) > 0) { + switch (c) { + case 'c': + if (setenv(CONF_ENV_PATH, optarg, 1) < 0) + msg_fatal("out of memory"); + break; + case 'r': /* forward compatibility */ + break; + case 'v': + msg_verbose++; + break; + default: + msg_fatal("usage: %s [-c config_dir] [-v]", argv[0]); + } + } + + /* * Read the global configuration file and extract configuration * information. Some claim that the user should supply the working * directory instead. That might be OK, given that this command needs @@ -194,6 +241,13 @@ int main(int argc, char **argv) mail_conf_read(); /* + * Stop run-away process accidents by limiting the queue file size. This + * is not a defense against DOS attack. + */ + if (var_message_limit > 0 && get_file_limit() > var_message_limit) + set_file_limit((off_t) var_message_limit); + + /* * Strip the environment so we don't have to trust the C library. */ import_env = argv_split(var_import_environ, ", \t\r\n"); @@ -210,6 +264,7 @@ int main(int argc, char **argv) * clean up incomplete output. */ signal(SIGPIPE, SIG_IGN); + signal(SIGXFSZ, SIG_IGN); signal(SIGHUP, postdrop_sig); signal(SIGINT, postdrop_sig); @@ -217,18 +272,7 @@ int main(int argc, char **argv) signal(SIGTERM, postdrop_sig); msg_cleanup(postdrop_cleanup); - /* - * Parse JCL. - */ - while ((c = GETOPT(argc, argv, "v")) > 0) { - switch (c) { - case 'v': - msg_verbose++; - break; - default: - msg_fatal("usage: %s [-v]", argv[0]); - } - } + /* End of initializations. */ /* * Create queue file. mail_stream_file() never fails. Send the queue ID @@ -236,8 +280,10 @@ int main(int argc, char **argv) * clean up in case of a fatal error or an interrupt. */ dst = mail_stream_file(MAIL_QUEUE_MAILDROP, MAIL_CLASS_PUBLIC, - MAIL_SERVICE_PICKUP); - mail_print(VSTREAM_OUT, "%s", dst->id); + MAIL_SERVICE_PICKUP, 0444); + attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, dst->id, + ATTR_TYPE_END); vstream_fflush(VSTREAM_OUT); postdrop_path = mystrdup(VSTREAM_PATH(dst->stream)); @@ -248,6 +294,9 @@ int main(int argc, char **argv) * file descriptor to the cleanup daemon. These are by no means all * sanity checks - the cleanup service and queue manager services will * reject messages that lack required information. + * + * If something goes wrong, slurp up the input before responding to the + * client, otherwise the client will give up after detecting SIGPIPE. */ vstream_control(VSTREAM_IN, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END); buf = vstring_alloc(100); @@ -273,8 +322,12 @@ int main(int argc, char **argv) msg_fatal("uid=%ld: unexpected record type: %d", (long) uid, rec_type); if (rec_type == **expected) expected++; - if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) - msg_fatal("uid=%ld: queue file write error", (long) uid); + if (REC_PUT_BUF(dst->stream, rec_type, buf) < 0) { + while ((rec_type = rec_get(VSTREAM_IN, buf, var_line_limit)) > 0 + && rec_type != REC_TYPE_END) + /* void */ ; + break; + } if (rec_type == REC_TYPE_END) break; } @@ -283,8 +336,10 @@ int main(int argc, char **argv) /* * Finish the file. */ - if ((status = mail_stream_finish(dst)) != 0) - msg_fatal("uid=%ld: %s", (long) uid, cleanup_strerror(status)); + if ((status = mail_stream_finish(dst, (VSTRING *) 0)) != 0) { + postdrop_cleanup(); + msg_warn("uid=%ld: %m", (long) uid); + } /* * Disable deletion on fatal error before reporting success, so the file @@ -298,7 +353,10 @@ int main(int argc, char **argv) /* * Send the completion status to the caller and terminate. */ - mail_print(VSTREAM_OUT, "%d", status); + attr_print(VSTREAM_OUT, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, status, + ATTR_TYPE_STR, MAIL_ATTR_WHY, "", + ATTR_TYPE_END); vstream_fflush(VSTREAM_OUT); exit(status); } diff --git a/gnu/dist/postfix/src/postfix/Makefile.in b/gnu/dist/postfix/src/postfix/Makefile.in index 3b651dbecc3..45e05f7f978 100644 --- a/gnu/dist/postfix/src/postfix/Makefile.in +++ b/gnu/dist/postfix/src/postfix/Makefile.in @@ -66,5 +66,8 @@ postfix.o: ../../include/msg_vstream.h postfix.o: ../../include/msg_syslog.h postfix.o: ../../include/stringops.h postfix.o: ../../include/vstring.h +postfix.o: ../../include/clean_env.h +postfix.o: ../../include/argv.h +postfix.o: ../../include/safe.h postfix.o: ../../include/mail_conf.h postfix.o: ../../include/mail_params.h diff --git a/gnu/dist/postfix/src/postfix/postfix.c b/gnu/dist/postfix/src/postfix/postfix.c index 466118504bb..2db1dc24fb1 100644 --- a/gnu/dist/postfix/src/postfix/postfix.c +++ b/gnu/dist/postfix/src/postfix/postfix.c @@ -8,11 +8,15 @@ /* \fBpostfix\fR [\fB-c \fIconfig_dir\fR] [\fB-D\fR] [\fB-v\fR] /* \fIcommand\fR /* DESCRIPTION +/* This command is reserved for the super-user. To submit mail, +/* use the Postfix \fBsendmail\fR command. +/* /* The \fBpostfix\fR command controls the operation of the Postfix /* mail system: start or stop the \fBmaster\fR daemon, do a health -/* check, and other maintenance. The command sets up a standardized -/* environment and runs the \fBpostfix-script\fR shell script to -/* do the actual work. +/* check, and other maintenance. +/* +/* The \fBpostfix\fR command sets up a standardized environment and +/* runs the \fBpostfix-script\fR shell script to do the actual work. /* /* The following commands are implemented: /* .IP \fBcheck\fR @@ -63,25 +67,48 @@ /* This is set when the -v command-line option is present. /* .IP \fBMAIL_DEBUG\fR /* This is set when the -D command-line option is present. -/* .PP -/* The following configuration parameters are made available -/* as process environment variables with the same names: +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* The following \fBmain.cf\fR configuration parameters are made +/* available as process environment variables with the same names: /* .IP \fBcommand_directory\fR -/* Directory with Postfix support commands (default: -/* \fB$program_directory\fR). +/* Directory with Postfix administrative commands. /* .IP \fBdaemon_directory\fR -/* Directory with Postfix daemon programs (default: -/* \fB$program_directory\fR). +/* Directory with Postfix daemon programs. /* .IP \fBconfig_directory\fR /* Directory with Postfix configuration files and with administrative /* shell scripts. /* .IP \fBqueue_directory\fR -/* The directory with the Postfix queue directory (and with some -/* files needed for programs running in a chrooted environment). +/* The directory with Postfix queue files, with local inter-process +/* communication endpoints, and with files needed for daemon programs +/* that run in the optional chrooted environment. /* .IP \fBmail_owner\fR -/* The owner of the Postfix queue and of most Postfix processes. +/* The owner of Postfix queue files and of most Postfix processes. +/* .IP \fBsetgid_group\fR +/* The group for mail submission and queue management commands. +/* .IP \fBsendmail_path +/* The full pathname for the Postfix sendmail command. +/* .IP \fBnewaliases_path +/* The full pathname for the Postfix newaliases command. +/* .IP \fBmailq_path +/* The full pathname for the Postfix mailq command. +/* .IP \fBmanpage_directory +/* The directory for the Postfix on-line manual pages. +/* .IP \fBsample_directory +/* The directory for the Postfix sample configuration files. +/* .IP \fBreadme_directory +/* The directory for the Postfix README files. +/* .SH Other configuration parameters +/* .ad +/* .fi +/* .IP \fBimport_environment\fR +/* List of names of environment parameters that can be imported +/* from non-Postfix processes. /* FILES /* $\fBconfig_directory/postfix-script\fR, administrative commands +/* $\fBconfig_directory/main.cf\fR, configuration parameters +/* $\fBconfig_directory/master.cf\fR, Postfix daemon processes /* SEE ALSO /* master(8) Postfix master program /* LICENSE @@ -115,12 +142,24 @@ #include <msg_vstream.h> #include <msg_syslog.h> #include <stringops.h> +#include <clean_env.h> +#include <argv.h> +#include <safe.h> /* Global library. */ #include <mail_conf.h> #include <mail_params.h> +/* Additional installation parameters. */ + +static char *var_sendmail_path; +static char *var_mailq_path; +static char *var_newalias_path; +static char *var_manpage_dir; +static char *var_sample_dir; +static char *var_readme_dir; + /* check_setenv - setenv() with extreme prejudice */ static void check_setenv(char *name, char *value) @@ -137,9 +176,18 @@ int main(int argc, char **argv) char *script; struct stat st; char *slash; - int uid; int fd; int ch; + ARGV *import_env; + static CONFIG_STR_TABLE str_table[] = { + VAR_SENDMAIL_PATH, DEF_SENDMAIL_PATH, &var_sendmail_path, 1, 0, + VAR_MAILQ_PATH, DEF_MAILQ_PATH, &var_mailq_path, 1, 0, + VAR_NEWALIAS_PATH, DEF_NEWALIAS_PATH, &var_newalias_path, 1, 0, + VAR_MANPAGE_DIR, DEF_MANPAGE_DIR, &var_manpage_dir, 1, 0, + VAR_SAMPLE_DIR, DEF_SAMPLE_DIR, &var_sample_dir, 1, 0, + VAR_README_DIR, DEF_README_DIR, &var_readme_dir, 1, 0, + 0, + }; /* * Be consistent with file permissions. @@ -172,10 +220,12 @@ int main(int argc, char **argv) * privileges for selected operations. That's right - it takes privileges * to toss privileges. */ - if ((uid = getuid()) != 0) { + if (getuid() != 0) { msg_error("to submit mail, use the Postfix sendmail command"); msg_fatal("the postfix command is reserved for the superuser"); } + if (unsafe() != 0) + msg_fatal("the postfix command must not run as a set-uid process"); /* * Parse switches. @@ -206,6 +256,17 @@ int main(int argc, char **argv) * scripts. */ mail_conf_read(); + get_mail_conf_str_table(str_table); + + /* + * Environment import filter, to enforce consistent behavior whether this + * command is started by hand, or at system boot time. This is necessary + * because some shell scripts use environment settings to override + * main.cf settings. + */ + import_env = argv_split(var_import_environ, ", \t\r\n"); + clean_env(import_env->argv); + argv_free(import_env); check_setenv("PATH", ROOT_PATH); /* sys_defs.h */ check_setenv(CONF_ENV_PATH, var_config_dir);/* mail_conf.h */ @@ -214,7 +275,18 @@ int main(int argc, char **argv) check_setenv(VAR_DAEMON_DIR, var_daemon_dir); /* main.cf */ check_setenv(VAR_QUEUE_DIR, var_queue_dir); /* main.cf */ check_setenv(VAR_CONFIG_DIR, var_config_dir); /* main.cf */ + + /* + * Do we want to keep adding things here as shell scripts evolve? + */ check_setenv(VAR_MAIL_OWNER, var_mail_owner); /* main.cf */ + check_setenv(VAR_SGID_GROUP, var_sgid_group); /* main.cf */ + check_setenv(VAR_SENDMAIL_PATH, var_sendmail_path); /* main.cf */ + check_setenv(VAR_MAILQ_PATH, var_mailq_path); /* main.cf */ + check_setenv(VAR_NEWALIAS_PATH, var_newalias_path); /* main.cf */ + check_setenv(VAR_MANPAGE_DIR, var_manpage_dir); /* main.cf */ + check_setenv(VAR_SAMPLE_DIR, var_sample_dir); /* main.cf */ + check_setenv(VAR_README_DIR, var_readme_dir); /* main.cf */ /* * Make sure these directories exist. Run the maintenance scripts with as diff --git a/gnu/dist/postfix/src/postkick/Makefile.in b/gnu/dist/postfix/src/postkick/Makefile.in index b34c9673614..d4cf100f460 100644 --- a/gnu/dist/postfix/src/postkick/Makefile.in +++ b/gnu/dist/postfix/src/postkick/Makefile.in @@ -61,7 +61,9 @@ postkick.o: ../../include/vstream.h postkick.o: ../../include/vbuf.h postkick.o: ../../include/msg_vstream.h postkick.o: ../../include/safe.h +postkick.o: ../../include/events.h postkick.o: ../../include/mail_proto.h postkick.o: ../../include/iostuff.h +postkick.o: ../../include/attr.h postkick.o: ../../include/mail_params.h postkick.o: ../../include/mail_conf.h diff --git a/gnu/dist/postfix/src/postkick/postkick.c b/gnu/dist/postfix/src/postkick/postkick.c index c756c14ae49..a4066a96aca 100644 --- a/gnu/dist/postfix/src/postkick/postkick.c +++ b/gnu/dist/postfix/src/postkick/postkick.c @@ -80,6 +80,7 @@ #include <vstream.h> #include <msg_vstream.h> #include <safe.h> +#include <events.h> /* Global library. */ @@ -164,6 +165,7 @@ int main(int argc, char **argv) class, service); exit(1); } else { + event_drain(); exit(0); } } diff --git a/gnu/dist/postfix/src/postmap/Makefile.in b/gnu/dist/postfix/src/postmap/Makefile.in index b2d64c2bf1d..a96270e30f8 100644 --- a/gnu/dist/postfix/src/postmap/Makefile.in +++ b/gnu/dist/postfix/src/postmap/Makefile.in @@ -21,13 +21,39 @@ $(PROG): $(OBJS) $(LIBS) Makefile: Makefile.in (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@ -test: $(TESTPROG) - update: ../../bin/$(PROG) ../../bin/$(PROG): $(PROG) cp $(PROG) ../../bin +test: test1 test2 + +test1: $(PROG) map.in map-abc1.ref map-ghi1.ref map-ABC1.ref + ./$(PROG) map.in + for key in abc ghi; \ + do \ + ./$(PROG) -q $${key} map.in | diff map-$${key}1.ref -; \ + done + ./$(PROG) -f map.in + for key in ABC; \ + do \ + ./$(PROG) -fq $${key} map.in | diff map-$${key}1.ref -; \ + done + rm -f map.in.db + +test2: $(PROG) map.in map-abc2.ref map-ghi2.ref map-ABC2.ref + ./$(PROG) map.in + for key in abc ghi; \ + do \ + echo $${key} | ./$(PROG) -q - map.in | diff map-$${key}2.ref -; \ + done + ./$(PROG) -f map.in + for key in ABC; \ + do \ + echo $${key} | ./$(PROG) -fq - map.in | diff map-$${key}2.ref -; \ + done + rm -f map.in.db + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck @@ -39,7 +65,7 @@ lint: lint $(DEFS) $(SRCS) $(LINTFIX) clean: - rm -f *.o *core $(PROG) $(TESTPROG) junk + rm -f *.o *core $(PROG) $(TESTPROG) junk map.in.db rm -rf printfck tidy: clean @@ -64,6 +90,7 @@ postmap.o: ../../include/msg_vstream.h postmap.o: ../../include/readlline.h postmap.o: ../../include/stringops.h postmap.o: ../../include/split_at.h +postmap.o: ../../include/vstring_vstream.h postmap.o: ../../include/mail_conf.h postmap.o: ../../include/mail_params.h postmap.o: ../../include/mkmap.h diff --git a/gnu/dist/postfix/src/postmap/map-ABC1.ref b/gnu/dist/postfix/src/postmap/map-ABC1.ref new file mode 100644 index 00000000000..142195f36ae --- /dev/null +++ b/gnu/dist/postfix/src/postmap/map-ABC1.ref @@ -0,0 +1 @@ +DEF diff --git a/gnu/dist/postfix/src/postmap/map-ABC2.ref b/gnu/dist/postfix/src/postmap/map-ABC2.ref new file mode 100644 index 00000000000..cc3ea4e3c40 --- /dev/null +++ b/gnu/dist/postfix/src/postmap/map-ABC2.ref @@ -0,0 +1 @@ +ABC DEF diff --git a/gnu/dist/postfix/src/postmap/map-abc1.ref b/gnu/dist/postfix/src/postmap/map-abc1.ref new file mode 100644 index 00000000000..142195f36ae --- /dev/null +++ b/gnu/dist/postfix/src/postmap/map-abc1.ref @@ -0,0 +1 @@ +DEF diff --git a/gnu/dist/postfix/src/postmap/map-abc2.ref b/gnu/dist/postfix/src/postmap/map-abc2.ref new file mode 100644 index 00000000000..2ee5fab43d9 --- /dev/null +++ b/gnu/dist/postfix/src/postmap/map-abc2.ref @@ -0,0 +1 @@ +abc DEF diff --git a/gnu/dist/postfix/src/postmap/map-ghi1.ref b/gnu/dist/postfix/src/postmap/map-ghi1.ref new file mode 100644 index 00000000000..7beb1db20dc --- /dev/null +++ b/gnu/dist/postfix/src/postmap/map-ghi1.ref @@ -0,0 +1 @@ +jkl diff --git a/gnu/dist/postfix/src/postmap/map-ghi2.ref b/gnu/dist/postfix/src/postmap/map-ghi2.ref new file mode 100644 index 00000000000..5926a187ff9 --- /dev/null +++ b/gnu/dist/postfix/src/postmap/map-ghi2.ref @@ -0,0 +1 @@ +ghi jkl diff --git a/gnu/dist/postfix/src/postmap/map.in b/gnu/dist/postfix/src/postmap/map.in new file mode 100644 index 00000000000..f1805549ec2 --- /dev/null +++ b/gnu/dist/postfix/src/postmap/map.in @@ -0,0 +1,2 @@ +ABC DEF +ghi jkl diff --git a/gnu/dist/postfix/src/postmap/postmap.c b/gnu/dist/postfix/src/postmap/postmap.c index f82edfb1443..40579938e7a 100644 --- a/gnu/dist/postfix/src/postmap/postmap.c +++ b/gnu/dist/postfix/src/postmap/postmap.c @@ -5,8 +5,9 @@ /* Postfix lookup table management /* SYNOPSIS /* .fi -/* \fBpostmap\fR [\fB-Ninrvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-d \fIkey\fR] -/* [\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ... +/* \fBpostmap\fR [\fB-Nfinrvw\fR] [\fB-c \fIconfig_dir\fR] +/* [\fB-d \fIkey\fR] [\fB-q \fIkey\fR] +/* [\fIfile_type\fR:]\fIfile_name\fR ... /* DESCRIPTION /* The \fBpostmap\fR command creates or queries one or more Postfix /* lookup tables, or updates an existing one. The input and output @@ -15,6 +16,9 @@ /* .ti +4 /* \fBmakemap \fIfile_type\fR \fIfile_name\fR < \fIfile_name\fR /* +/* If the result files do not exist they will be created with the +/* same group and other read permissions as the source file. +/* /* While the table update is in progress, signal delivery is /* postponed, and an exclusive, advisory, lock is placed on the /* entire table, in order to avoid surprises in spectator @@ -22,14 +26,16 @@ /* /* The format of a lookup table input file is as follows: /* .IP \(bu -/* Blank lines are ignored. So are lines beginning with `#'. -/* .IP \(bu /* A table entry has the form /* .sp /* .ti +5 /* \fIkey\fR whitespace \fIvalue\fR /* .IP \(bu -/* A line that starts with whitespace continues the preceding line. +/* Empty lines and whitespace-only lines are ignored, as +/* are lines whose first non-whitespace character is a `#'. +/* .IP \(bu +/* A logical line starts with non-whitespace text. A line that +/* starts with whitespace continues a logical line. /* .PP /* The \fIkey\fR and \fIvalue\fR are processed as is, except that /* surrounding white space is stripped off. Unlike with Postfix alias @@ -47,7 +53,14 @@ /* instead of the default configuration directory. /* .IP "\fB-d \fIkey\fR" /* Search the specified maps for \fIkey\fR and remove one entry per map. -/* The exit status is non-zero if the requested information was not found. +/* The exit status is zero when the requested information was found. +/* +/* If a key value of \fB-\fR is specified, the program reads key +/* values from the standard input stream. The exit status is zero +/* when at least one of the requested keys was found. +/* .IP \fB-f\fR +/* Do not fold the lookup key to lower case while creating or querying +/* a map. /* .IP \fB-i\fR /* Incremental mode. Read entries from standard input and do not /* truncate an existing database. By default, \fBpostmap\fR creates @@ -58,8 +71,13 @@ /* the host operating system. /* .IP "\fB-q \fIkey\fR" /* Search the specified maps for \fIkey\fR and print the first value -/* found on the standard output stream. The exit status is non-zero -/* if the requested information was not found. +/* found on the standard output stream. The exit status is zero +/* when the requested information was found. +/* +/* If a key value of \fB-\fR is specified, the program reads key +/* values from the standard input stream and prints one line of +/* \fIkey value\fR output for each key that was found. The exit +/* status is zero when at least one of the requested keys was found. /* .IP \fB-r\fR /* When updating a table, do not warn about duplicate entries; silently /* replace them. @@ -98,9 +116,6 @@ /* \fBpostmap\fR terminates with zero exit status in case of success /* (including successful \fBpostmap -q\fR lookup) and terminates /* with non-zero exit status in case of failure. -/* BUGS -/* The "delete key" support is limited to one delete operation -/* per command invocation. /* ENVIRONMENT /* .ad /* .fi @@ -146,6 +161,7 @@ #include <readlline.h> #include <stringops.h> #include <split_at.h> +#include <vstring_vstream.h> /* Global library. */ @@ -168,6 +184,8 @@ static void postmap(char *map_type, char *path_name, int lineno; char *key; char *value; + struct stat st; + mode_t saved_mask; /* * Initialize. @@ -179,6 +197,14 @@ static void postmap(char *map_type, char *path_name, } else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) { msg_fatal("open %s: %m", path_name); } + if (fstat(vstream_fileno(source_fp), &st) < 0) + msg_fatal("fstat %s: %m", path_name); + + /* + * Turn off group/other read permissions as indicated in the source file. + */ + if (S_ISREG(st.st_mode)) + saved_mask = umask(022 | (~st.st_mode & 077)); /* * Open the database, optionally create it when it does not exist, @@ -188,39 +214,31 @@ static void postmap(char *map_type, char *path_name, mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags); /* + * And restore the umask, in case it matters. + */ + if (S_ISREG(st.st_mode)) + umask(saved_mask); + + /* * Add records to the database. */ lineno = 0; - while (readlline(line_buffer, source_fp, &lineno, READLL_STRIPNL)) { - - /* - * Skip comments. - */ - if (*STR(line_buffer) == '#') - continue; + while (readlline(line_buffer, source_fp, &lineno)) { /* * Split on the first whitespace character, then trim leading and * trailing whitespace from key and value. */ key = STR(line_buffer); - value = STR(line_buffer) + strcspn(STR(line_buffer), " \t\r\n"); + value = key + strcspn(key, " \t\r\n"); if (*value) *value++ = 0; - while (ISSPACE(*key)) - key++; while (ISSPACE(*value)) value++; trimblanks(key, 0)[0] = 0; trimblanks(value, 0)[0] = 0; /* - * Skip empty lines, or lines with whitespace characters only. - */ - if (*key == 0 && *value == 0) - continue; - - /* * Enforce the "key whitespace value" format. Disallow missing keys * or missing values. */ @@ -236,7 +254,8 @@ static void postmap(char *map_type, char *path_name, /* * Store the value under a case-insensitive key. */ - lowercase(key); + if (dict_flags & DICT_FLAG_FOLD_KEY) + lowercase(key); mkmap_append(mkmap, key, value); } @@ -253,6 +272,65 @@ static void postmap(char *map_type, char *path_name, vstream_fclose(source_fp); } +/* postmap_queries - apply multiple requests from stdin */ + +static int postmap_queries(VSTREAM *in, char **maps, const int map_count, + const int dict_flags) +{ + int found = 0; + VSTRING *keybuf = vstring_alloc(100); + DICT **dicts; + const char *map_name; + const char *value; + int n; + + /* + * Sanity check. + */ + if (map_count <= 0) + msg_panic("postmap_queries: bad map count"); + + /* + * Prepare to open maps lazily. + */ + dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); + for (n = 0; n < map_count; n++) + dicts[n] = 0; + + /* + * Perform all queries. Open maps on the fly, to avoid opening unecessary + * maps. + */ + while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) { + if (dict_flags & DICT_FLAG_FOLD_KEY) + lowercase(STR(keybuf)); + for (n = 0; n < map_count; n++) { + if (dicts[n] == 0) + dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ? + dict_open3(maps[n], map_name, O_RDONLY, DICT_FLAG_LOCK) : + dict_open3(var_db_type, maps[n], O_RDONLY, DICT_FLAG_LOCK)); + if ((value = dict_get(dicts[n], STR(keybuf))) != 0) { + vstream_printf("%s %s\n", STR(keybuf), value); + found = 1; + break; + } + } + } + if (found) + vstream_fflush(VSTREAM_OUT); + + /* + * Cleanup. + */ + for (n = 0; n < map_count; n++) + if (dicts[n]) + dict_close(dicts[n]); + myfree((char *) dicts); + vstring_free(keybuf); + + return (found); +} + /* postmap_query - query a map and print the result to stdout */ static int postmap_query(const char *map_type, const char *map_name, @@ -270,6 +348,50 @@ static int postmap_query(const char *map_type, const char *map_name, return (value != 0); } +/* postmap_deletes - apply multiple requests from stdin */ + +static int postmap_deletes(VSTREAM *in, char **maps, const int map_count) +{ + int found = 0; + VSTRING *keybuf = vstring_alloc(100); + DICT **dicts; + const char *map_name; + int n; + + /* + * Sanity check. + */ + if (map_count <= 0) + msg_panic("postmap_deletes: bad map count"); + + /* + * Open maps ahead of time. + */ + dicts = (DICT **) mymalloc(sizeof(*dicts) * map_count); + for (n = 0; n < map_count; n++) + dicts[n] = ((map_name = split_at(maps[n], ':')) != 0 ? + dict_open3(maps[n], map_name, O_RDWR, DICT_FLAG_LOCK) : + dict_open3(var_db_type, maps[n], O_RDWR, DICT_FLAG_LOCK)); + + /* + * Perform all requests. + */ + while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) + for (n = 0; n < map_count; n++) + found |= (dict_del(dicts[n], STR(keybuf)) == 0); + + /* + * Cleanup. + */ + for (n = 0; n < map_count; n++) + if (dicts[n]) + dict_close(dicts[n]); + myfree((char *) dicts); + vstring_free(keybuf); + + return (found); +} + /* postmap_delete - delete a (key, value) pair from a map */ static int postmap_delete(const char *map_type, const char *map_name, @@ -278,10 +400,6 @@ static int postmap_delete(const char *map_type, const char *map_name, DICT *dict; int status; - /* - * XXX This must be generalized to multi-key (read from stdin) and - * multi-map (given on command line) updates. - */ dict = dict_open3(map_type, map_name, O_RDWR, DICT_FLAG_LOCK); status = dict_del(dict, key); dict_close(dict); @@ -292,7 +410,7 @@ static int postmap_delete(const char *map_type, const char *map_name, static NORETURN usage(char *myname) { - msg_fatal("usage: %s [-Ninrvw] [-c config_dir] [-d key] [-q key] [map_type:]file...", + msg_fatal("usage: %s [-Nfinrvw] [-c config_dir] [-d key] [-q key] [map_type:]file...", myname); } @@ -304,7 +422,7 @@ int main(int argc, char **argv) char *slash; struct stat st; int open_flags = O_RDWR | O_CREAT | O_TRUNC; - int dict_flags = DICT_FLAG_DUP_WARN; + int dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_KEY; char *query = 0; char *delkey = 0; int found; @@ -342,7 +460,7 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((ch = GETOPT(argc, argv, "Nc:d:inq:rvw")) > 0) { + while ((ch = GETOPT(argc, argv, "Nc:d:finq:rvw")) > 0) { switch (ch) { default: usage(argv[0]); @@ -360,6 +478,9 @@ int main(int argc, char **argv) msg_fatal("specify only one of -q or -d"); delkey = optarg; break; + case 'f': + dict_flags &= ~DICT_FLAG_FOLD_KEY; + break; case 'i': open_flags &= ~O_TRUNC; break; @@ -394,6 +515,8 @@ int main(int argc, char **argv) if (delkey) { /* remove entry */ if (optind + 1 > argc) usage(argv[0]); + if (strcmp(delkey, "-") == 0) + exit(postmap_deletes(VSTREAM_IN, argv + optind, argc - optind) == 0); found = 0; while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { @@ -407,6 +530,11 @@ int main(int argc, char **argv) } else if (query) { /* query map(s) */ if (optind + 1 > argc) usage(argv[0]); + if (strcmp(query, "-") == 0) + exit(postmap_queries(VSTREAM_IN, argv + optind, argc - optind, + dict_flags) == 0); + if (dict_flags & DICT_FLAG_FOLD_KEY) + lowercase(query); while (optind < argc) { if ((path_name = split_at(argv[optind], ':')) != 0) { found = postmap_query(argv[optind], path_name, query); diff --git a/gnu/dist/postfix/src/postqueue/Makefile.in b/gnu/dist/postfix/src/postqueue/Makefile.in new file mode 100644 index 00000000000..f9470cc9a47 --- /dev/null +++ b/gnu/dist/postfix/src/postqueue/Makefile.in @@ -0,0 +1,80 @@ +SHELL = /bin/sh +SRCS = postqueue.c +OBJS = postqueue.o +HDRS = +TESTSRC = +WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ + -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ + -Wunused +DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) +CFLAGS = $(DEBUG) $(OPT) $(DEFS) +TESTPROG= +PROG = postqueue +INC_DIR = ../../include +LIBS = ../../lib/libglobal.a ../../lib/libutil.a + +.c.o:; $(CC) $(CFLAGS) -c $*.c + +$(PROG): $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) + +Makefile: Makefile.in + (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@ + +test: $(TESTPROG) + +update: ../../bin/$(PROG) + +../../bin/$(PROG): $(PROG) + cp $(PROG) ../../bin + +printfck: $(OBJS) $(PROG) + rm -rf printfck + mkdir printfck + sed '1,/^# do not edit/!d' Makefile >printfck/Makefile + set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done + cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o` + +lint: + lint $(DEFS) $(SRCS) $(LINTFIX) + +clean: + rm -f *.o *core $(PROG) $(TESTPROG) junk + rm -rf printfck + +tidy: clean + +depend: $(MAKES) + (sed '1,/^# do not edit/!d' Makefile.in; \ + set -e; for i in [a-z][a-z0-9]*.c; do \ + $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ + -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \ + done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in + @$(EXPORT) make -f Makefile.in Makefile 1>&2 + +# do not edit below this line - it is generated by 'make depend' +postqueue.o: postqueue.c +postqueue.o: ../../include/sys_defs.h +postqueue.o: ../../include/msg.h +postqueue.o: ../../include/mymalloc.h +postqueue.o: ../../include/clean_env.h +postqueue.o: ../../include/vstream.h +postqueue.o: ../../include/vbuf.h +postqueue.o: ../../include/msg_vstream.h +postqueue.o: ../../include/msg_syslog.h +postqueue.o: ../../include/argv.h +postqueue.o: ../../include/safe.h +postqueue.o: ../../include/connect.h +postqueue.o: ../../include/iostuff.h +postqueue.o: ../../include/valid_hostname.h +postqueue.o: ../../include/mail_proto.h +postqueue.o: ../../include/attr.h +postqueue.o: ../../include/mail_params.h +postqueue.o: ../../include/mail_conf.h +postqueue.o: ../../include/mail_task.h +postqueue.o: ../../include/debug_process.h +postqueue.o: ../../include/mail_run.h +postqueue.o: ../../include/mail_flush.h +postqueue.o: ../../include/flush_clnt.h +postqueue.o: ../../include/smtp_stream.h +postqueue.o: ../../include/vstring.h diff --git a/gnu/dist/postfix/src/postqueue/postqueue.c b/gnu/dist/postfix/src/postqueue/postqueue.c new file mode 100644 index 00000000000..7fba3c61d5b --- /dev/null +++ b/gnu/dist/postfix/src/postqueue/postqueue.c @@ -0,0 +1,396 @@ +/*++ +/* NAME +/* postqueue 1 +/* SUMMARY +/* Postfix queue control +/* SYNOPSIS +/* \fBpostqueue\fR [\fB-c \fIconfig_dir\fR] \fB-f\fR +/* .br +/* \fBpostqueue\fR [\fB-c \fIconfig_dir\fR] \fB-p\fR +/* .br +/* \fBpostqueue\fR [\fB-c \fIconfig_dir\fR] \fB-s \fIsite\fR +/* DESCRIPTION +/* The \fBpostqueue\fR program implements the Postfix user interface +/* for queue management. It implements all the operations that are +/* traditionally available via the \fBsendmail\fR(1) command. +/* +/* The following options are recognized: +/* .IP "\fB-c \fIconfig_dir\fR" +/* The \fBmain.cf\fR configuration file is in the named directory +/* instead of the default configuration directory. See also the +/* MAIL_CONFIG environment setting below. +/* .IP \fB-f\fR +/* Flush the queue: attempt to deliver all queued mail. +/* +/* This option implements the traditional \fBsendmail -q\fR command, +/* by contacting the Postfix \fBqmgr\fR(8) daemon. +/* .IP \fB-p\fR +/* Produce a traditional sendmail-style queue listing. +/* +/* This option implements the traditional \fBmailq\fR command, +/* by contacting the Postfix \fBshowq\fR(8) daemon. +/* .IP "\fB-s \fIsite\fR" +/* Schedule immediate delivery of all mail that is queued for the named +/* \fIsite\fR. The site must be eligible for the "fast flush" service. +/* See \fBflush\fR(8) for more information about the "fast flush" +/* service. +/* +/* This option implements the traditional \fBsendmail -qR\fIsite\fR +/* command, by contacting the Postfix \fBflush\fR(8) daemon. +/* .IP \fB-v\fR +/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR +/* options make the software increasingly verbose. +/* SECURITY +/* .ad +/* .fi +/* This program is designed to run with set-group ID privileges, so +/* that it can connect to Postfix daemon processes. +/* DIAGNOSTICS +/* Problems are logged to \fBsyslogd\fR(8) and to the standard error +/* stream. +/* ENVIRONMENT +/* .ad +/* .fi +/* .IP MAIL_CONFIG +/* Directory with the \fBmain.cf\fR file. +/* +/* In order to avoid exploitation of set-group ID privileges, it is not +/* possible to specify arbitrary directory names. +/* +/* A non-standard directory is allowed only if the name is listed in the +/* standard \fBmain.cf\fR file, in the \fBalternate_config_directories\fR +/* configuration parameter value. +/* +/* Only the super-user is allowed to specify arbitrary directory names. +/* FILES +/* /var/spool/postfix, mail queue +/* /etc/postfix, configuration files +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* .IP \fBimport_environment\fR +/* List of names of environment parameters that can be imported +/* from non-Postfix processes. +/* .IP \fBqueue_directory\fR +/* Top-level directory of the Postfix queue. This is also the root +/* directory of Postfix daemons that run chrooted. +/* .IP \fBfast_flush_domains\fR +/* List of domains that will receive "fast flush" service (default: all +/* domains that this system is willing to relay mail to). This list +/* specifies the domains that Postfix accepts in the SMTP \fBETRN\fR +/* request and in the \fBsendmail -qR\fR command. +/* SEE ALSO +/* sendmail(8) sendmail-compatible user interface +/* qmgr(8) queue manager +/* showq(8) list mail queue +/* flush(8) fast flush service +/* 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/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <sysexits.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <clean_env.h> +#include <vstream.h> +#include <msg_vstream.h> +#include <msg_syslog.h> +#include <argv.h> +#include <safe.h> +#include <connect.h> +#include <valid_hostname.h> + +/* Global library. */ + +#include <mail_proto.h> +#include <mail_params.h> +#include <mail_conf.h> +#include <mail_task.h> +#include <debug_process.h> +#include <mail_run.h> +#include <mail_flush.h> +#include <flush_clnt.h> +#include <smtp_stream.h> + +/* Application-specific. */ + + /* + * WARNING WARNING WARNING + * + * This software is designed to run set-gid. In order to avoid exploitation of + * privilege, this software should not run any external commands, nor should + * it take any information from the user, unless that information can be + * properly sanitized. To get an idea of how much information a process can + * inherit from a potentially hostile user, examine all the members of the + * process structure (typically, in /usr/include/sys/proc.h): the current + * directory, open files, timers, signals, environment, command line, umask, + * and so on. + */ + + /* + * Modes of operation. + */ +#define PQ_MODE_DEFAULT 0 /* noop */ +#define PQ_MODE_MAILQ_LIST 1 /* list mail queue */ +#define PQ_MODE_FLUSH_QUEUE 2 /* flush queue */ +#define PQ_MODE_FLUSH_SITE 3 /* flush site */ + + /* + * Silly little macros (SLMs). + */ +#define STR vstring_str + +/* show_queue - show queue status */ + +static void show_queue(void) +{ + char buf[VSTREAM_BUFSIZE]; + VSTREAM *showq; + int n; + + /* + * Connect to the show queue service. Terminate silently when piping into + * a program that terminates early. + */ + if ((showq = mail_connect(MAIL_CLASS_PUBLIC, MAIL_SERVICE_SHOWQ, BLOCKING)) != 0) { + while ((n = vstream_fread(showq, buf, sizeof(buf))) > 0) + if (vstream_fwrite(VSTREAM_OUT, buf, n) != n + || vstream_fflush(VSTREAM_OUT) != 0) + msg_fatal("write error: %m"); + + if (vstream_fclose(showq)) + msg_warn("close: %m"); + } + + /* + * When the mail system is down, the superuser can still access the queue + * directly. Just run the showq program in stand-alone mode. + */ + else if (geteuid() == 0) { + ARGV *argv; + int stat; + + msg_warn("Mail system is down -- accessing queue directly"); + argv = argv_alloc(6); + argv_add(argv, MAIL_SERVICE_SHOWQ, "-u", "-S", (char *) 0); + for (n = 0; n < msg_verbose; n++) + argv_add(argv, "-v", (char *) 0); + argv_terminate(argv); + stat = mail_run_foreground(var_daemon_dir, argv->argv); + argv_free(argv); + } + + /* + * When the mail system is down, unprivileged users are stuck, because by + * design the mail system contains no set_uid programs. The only way for + * an unprivileged user to cross protection boundaries is to talk to the + * showq daemon. + */ + else { + msg_fatal_status(EX_UNAVAILABLE, + "Queue report unavailable - mail system is down"); + } +} + +/* flush_queue - force delivery */ + +static void flush_queue(void) +{ + + /* + * Trigger the flush queue service. + */ + if (mail_flush_deferred() < 0) + msg_fatal_status(EX_UNAVAILABLE, + "Cannot flush mail queue - mail system is down"); +} + +/* flush_site - flush mail for site */ + +static void flush_site(const char *site) +{ + int status; + + switch (status = flush_send(site)) { + case FLUSH_STAT_OK: + exit(0); + case FLUSH_STAT_BAD: + msg_fatal_status(EX_USAGE, "Invalid request: \"%s\"", site); + case FLUSH_STAT_FAIL: + msg_fatal_status(EX_UNAVAILABLE, + "Cannot flush mail queue - mail system is down"); + case FLUSH_STAT_DENY: + msg_fatal_status(EX_UNAVAILABLE, + "Flush service is not configured for destination \"%s\"", + site); + default: + msg_fatal_status(EX_SOFTWARE, + "Unknown flush server reply status %d", status); + } +} + +/* usage - scream and die */ + +static NORETURN usage(void) +{ + msg_fatal_status(EX_USAGE, "usage: specify one of -f, -p, or -s"); +} + +/* main - the main program */ + +int main(int argc, char **argv) +{ + struct stat st; + char *slash; + int c; + int fd; + int mode = PQ_MODE_DEFAULT; + char *site_to_flush = 0; + ARGV *import_env; + char *last; + + /* + * Be consistent with file permissions. + */ + umask(022); + + /* + * To minimize confusion, make sure that the standard file descriptors + * are open before opening anything else. XXX Work around for 44BSD where + * fstat can return EBADF on an open file descriptor. + */ + for (fd = 0; fd < 3; fd++) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) + msg_fatal_status(EX_UNAVAILABLE, "open /dev/null: %m"); + + /* + * Initialize. Set up logging, read the global configuration file and + * extract configuration information. Set up signal handlers so that we + * can clean up incomplete output. + */ + if ((slash = strrchr(argv[0], '/')) != 0) + argv[0] = slash + 1; + msg_vstream_init(argv[0], VSTREAM_ERR); + msg_syslog_init(mail_task("postqueue"), LOG_PID, LOG_FACILITY); + set_mail_conf_str(VAR_PROCNAME, var_procname = mystrdup(argv[0])); + + /* + * Parse JCL. This program is set-gid and must sanitize all command-line + * parameters. The configuration directory argument is validated by the + * mail configuration read routine. Don't do complex things until we have + * completed initializations. + */ + while ((c = GETOPT(argc, argv, "c:fps:v")) > 0) { + switch (c) { + case 'c': /* non-default configuration */ + if (setenv(CONF_ENV_PATH, optarg, 1) < 0) + msg_fatal_status(EX_UNAVAILABLE, "out of memory"); + break; + case 'f': /* flush queue */ + if (mode != PQ_MODE_DEFAULT) + usage(); + mode = PQ_MODE_FLUSH_QUEUE; + break; + case 'p': /* traditional mailq */ + if (mode != PQ_MODE_DEFAULT) + usage(); + mode = PQ_MODE_MAILQ_LIST; + break; + break; + case 's': /* flush site */ + if (mode != PQ_MODE_DEFAULT) + usage(); + mode = PQ_MODE_FLUSH_SITE; + site_to_flush = optarg; + break; + case 'v': + msg_verbose++; + break; + default: + usage(); + } + } + + /* + * Further initialization... + */ + mail_conf_read(); + + /* + * Strip the environment so we don't have to trust the C library. + */ + import_env = argv_split(var_import_environ, ", \t\r\n"); + clean_env(import_env->argv); + argv_free(import_env); + + if (chdir(var_queue_dir)) + msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir); + + signal(SIGPIPE, SIG_IGN); + + /* End of initializations. */ + + /* + * Further input validation. + */ + if (site_to_flush != 0) { + if (*site_to_flush == '[' + && *(last = site_to_flush + strlen(site_to_flush) - 1) == ']') { + *last = 0; + if (!valid_hostaddr(site_to_flush + 1, DONT_GRIPE)) + site_to_flush = 0; + *last = ']'; + } else { + if (!valid_hostname(site_to_flush, DONT_GRIPE) + && !valid_hostaddr(site_to_flush, DONT_GRIPE)) + site_to_flush = 0; + } + if (site_to_flush == 0) + msg_fatal_status(EX_USAGE, + "Cannot flush mail queue - invalid destination: \"%.100s%s\"", + optarg, strlen(optarg) > 100 ? "..." : ""); + } + + /* + * Start processing. + */ + switch (mode) { + default: + msg_panic("unknown operation mode: %d", mode); + /* NOTREACHED */ + case PQ_MODE_MAILQ_LIST: + show_queue(); + exit(0); + break; + case PQ_MODE_FLUSH_SITE: + flush_site(site_to_flush); + exit(0); + break; + case PQ_MODE_FLUSH_QUEUE: + flush_queue(); + exit(0); + break; + case PQ_MODE_DEFAULT: + usage(); + /* NOTREACHED */ + } +} diff --git a/gnu/dist/postfix/src/postsuper/Makefile.in b/gnu/dist/postfix/src/postsuper/Makefile.in index 3ff67a4d3df..4afa39a5434 100644 --- a/gnu/dist/postfix/src/postsuper/Makefile.in +++ b/gnu/dist/postfix/src/postsuper/Makefile.in @@ -66,7 +66,10 @@ postsuper.o: ../../include/vstring.h postsuper.o: ../../include/safe.h postsuper.o: ../../include/set_ugid.h postsuper.o: ../../include/argv.h +postsuper.o: ../../include/vstring_vstream.h +postsuper.o: ../../include/sane_fsops.h postsuper.o: ../../include/mail_task.h postsuper.o: ../../include/mail_conf.h postsuper.o: ../../include/mail_params.h postsuper.o: ../../include/mail_queue.h +postsuper.o: ../../include/mail_open_ok.h diff --git a/gnu/dist/postfix/src/postsuper/postsuper.c b/gnu/dist/postfix/src/postsuper/postsuper.c index b762d0849c7..660cf9ca718 100644 --- a/gnu/dist/postfix/src/postsuper/postsuper.c +++ b/gnu/dist/postfix/src/postsuper/postsuper.c @@ -2,37 +2,109 @@ /* NAME /* postsuper 1 /* SUMMARY -/* Postfix super intendent +/* Postfix superintendent /* SYNOPSIS /* .fi -/* \fBpostsuper\fR [\fB-p\fR] [\fB-s\fR] [\fB-v\fR] [\fIdirectory ...\fR] +/* \fBpostsuper\fR [\fB-psv\fR] [\fB-d \fIqueue_id\fR] +/* [\fB-r \fIqueue_id\fR] [\fIdirectory ...\fR] /* DESCRIPTION -/* The \fBpostsuper\fR command does small maintenance jobs on the named -/* Postfix queue directories (default: all). -/* Directory names are relative to the Postfix top-level queue directory. +/* The \fBpostsuper\fR command does maintenance jobs on the Postfix +/* queue. Use of the command is restricted to the super-user. /* /* By default, \fBpostsuper\fR performs the operations requested with the -/* \fB-s\fR and \fB-p\fR command-line options. -/* \fBpostsuper\fR always tries to remove objects that are neither files -/* nor directories. Use of this command is restricted to the super-user. +/* \fB-s\fR and \fB-p\fR command-line options on all Postfix queue +/* directories - this includes the \fBincoming\fR, \fBactive\fR and +/* \fBdeferred\fR directories with mail files and the \fBbounce\fR, +/* \fBdefer\fR and \fBflush\fR directories with log files. /* /* Options: -/* .IP \fB-s\fR -/* Structure check. Move queue files that are in the wrong place -/* in the file system hierarchy and remove subdirectories that are -/* no longer needed. File rearrangements are necessary after a change -/* in the \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR -/* configuration parameters. It is highly recommended to run this -/* check once before Postfix startup. +/* .IP "\fB-d \fIqueue_id\fR" +/* Delete one message with the named queue ID from the named +/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +/* \fBdeferred\fR). +/* If a \fIqueue_id\fR of \fB-\fR is specified, the program reads +/* queue IDs from standard input. +/* .sp +/* Specify \fB-d ALL\fR to remove all messages; for example, specify +/* \fB-d ALL deferred\fR to delete mail in the \fBdeferred\fR queue. +/* As a safety measure, the word \fBALL\fR must be specified in upper +/* case. +/* .sp +/* .ft B +/* Postfix queue IDs are reused. +/* There is a very small possibility that postsuper deletes the +/* wrong message file when it is executed while the Postfix mail +/* system is running. +/* .ft R +/* .sp +/* The scenario is as follows: +/* .RS +/* .IP 1) +/* The Postfix queue manager deletes the message that \fBpostsuper\fR +/* is supposed to delete, because Postfix is finished with the +/* message. +/* .IP 2) +/* New mail arrives, and the new message is given the same queue ID +/* as the message that \fBpostsuper\fR is supposed to delete. +/* The probability for reusing a deleted queue ID is about 1 in 2**15 +/* (the number of different microsecond values that the system clock +/* can distinguish within a second). +/* .IP 3) +/* \fBpostsuper\fR deletes the new message, instead of the old +/* message that it should have deleted. +/* .RE /* .IP \fB-p\fR -/* Purge stale files (files that are left over after system or -/* software crashes). +/* Purge old temporary files that are left over after system or +/* software crashes. +/* .IP "\fB-r \fIqueue_id\fR" +/* Requeue the message with the named queue ID from the named +/* mail queue(s) (default: \fBincoming\fR, \fBactive\fR and +/* \fBdeferred\fR). +/* To requeue multiple messages, specify multiple \fB-r\fR +/* command-line options. +/* Alternatively, if a \fIqueue_id\fR of \fB-\fR is specified, +/* the program reads queue IDs from standard input. +/* .sp +/* Specify \fB-r ALL\fR to requeue all messages. As a safety +/* measure, the word \fBALL\fR must be specified in upper case. +/* .sp +/* A requeued message is moved to the \fBmaildrop\fR queue, from +/* where it is copied by the pickup daemon to a new file whose name +/* is guaranteed to match the new queue file inode number. The +/* new queue file is subjected again to mail address rewriting and +/* substitution. This is useful when rewriting rules or virtual +/* mappings have changed. +/* .sp +/* Postfix queue IDs are reused. +/* There is a very small possibility that \fBpostsuper\fR requeues +/* the wrong message file when it is executed while the Postfix mail +/* system is running, but no harm should be done. +/* .IP \fB-s\fR +/* Structure check and structure repair. It is highly recommended +/* to perform this operation once before Postfix startup. +/* .RS +/* .IP \(bu +/* Rename files whose name does not match the message file inode +/* number. This operation is necessary after restoring a mail queue +/* from a different machine, or from backup media. +/* .IP \(bu +/* Move queue files that are in the wrong place in the file system +/* hierarchy and remove subdirectories that are no longer needed. +/* File position rearrangements are necessary after a change in the +/* \fBhash_queue_names\fR and/or \fBhash_queue_depth\fR +/* configuration parameters. +/* .RE /* .IP \fB-v\fR /* Enable verbose logging for debugging purposes. Multiple \fB-v\fR /* options make the software increasingly verbose. /* DIAGNOSTICS /* Problems are reported to the standard error stream and to /* \fBsyslogd\fR. +/* +/* \fBpostsuper\fR reports the number of messages deleted with \fB-d\fR, +/* the number of messages requeued with \fB-r\fR, and the number of +/* messages whose queue file name was fixed with \fB-s\fR. The report +/* is written to the standard error stream and to \fBsyslogd\fR. /* CONFIGURATION PARAMETERS /* .ad /* .fi @@ -62,6 +134,7 @@ #include <stdlib.h> #include <errno.h> #include <string.h> +#include <signal.h> #include <stdio.h> /* remove() */ /* Utility library. */ @@ -76,6 +149,8 @@ #include <safe.h> #include <set_ugid.h> #include <argv.h> +#include <vstring_vstream.h> +#include <sane_fsops.h> /* Global library. */ @@ -83,6 +158,7 @@ #include <mail_conf.h> #include <mail_params.h> #include <mail_queue.h> +#include <mail_open_ok.h> /* Application-specific. */ @@ -91,6 +167,10 @@ #define ACTION_STRUCT (1<<0) /* fix file organization */ #define ACTION_PURGE (1<<1) /* purge old temp files */ +#define ACTION_DELETE_ONE (1<<2) /* delete named queue file(s) */ +#define ACTION_DELETE_ALL (1<<3) /* delete all queue file(s) */ +#define ACTION_REQUEUE_ONE (1<<4) /* requeue named queue file(s) */ +#define ACTION_REQUEUE_ALL (1<<5) /* requeue all queue file(s) */ #define ACTION_DEFAULT (ACTION_STRUCT | ACTION_PURGE) @@ -121,21 +201,276 @@ static struct queue_info queue_info[] = { 0, }; -/* super - check queue file location and clean up */ + /* + * Directories with per-message meta files. + */ +const char *log_queue_names[] = { + MAIL_QUEUE_BOUNCE, + MAIL_QUEUE_DEFER, + 0, +}; + + /* + * Cruft that we append to a file name when a queue ID is named after the + * message file inode number. This cruft must not pass mail_queue_id_ok() so + * that the queue manager will ignore it, should people be so unwise as to + * run this operation on a live mail system. + */ +#define SUFFIX "#FIX" +#define SUFFIX_LEN 4 + + /* + * Grr. These counters are global, because C only has clumsy ways to return + * multiple results from a function. + */ +static int message_requeued = 0; /* requeued messages */ +static int message_deleted = 0; /* deleted messages */ +static int inode_fixed = 0; /* queue id matched to inode number */ +static int inode_mismatch = 0; /* queue id inode mismatch */ +static int position_mismatch = 0; /* file position mismatch */ + + /* + * Silly little macros. These translate arcane expressions into something + * more at a conceptual level. + */ +#define MESSAGE_QUEUE(qp) ((qp)->perms == MAIL_QUEUE_STAT_READY) +#define READY_MESSAGE(st) (((st).st_mode & S_IRWXU) == MAIL_QUEUE_STAT_READY) + +/* find_queue_info - look up expected permissions field by queue name */ + +static struct queue_info *find_queue_info(const char *queue_name) +{ + struct queue_info *qp; + + for (qp = queue_info; qp->name; qp++) + if (strcmp(queue_name, qp->name) == 0) + return (qp); + msg_fatal("invalid directory name: %s", queue_name); +} + +/* postremove - remove file with extreme prejudice */ + +static int postremove(const char *path) +{ + int ret; + + if ((ret = remove(path)) < 0) { + if (errno != ENOENT) + msg_fatal("remove file %s: %m", path); + } else { + if (msg_verbose) + msg_info("removed file %s", path); + } + return (ret); +} + +/* postrename - rename file with extreme prejudice */ + +static int postrename(const char *old, const char *new) +{ + int ret; + + if ((ret = sane_rename(old, new)) < 0) { + if (errno != ENOENT + || mail_queue_mkdirs(new) < 0 + || sane_rename(old, new) < 0) + if (errno != ENOENT) + msg_fatal("rename file %s as %s: %m", old, new); + } else { + if (msg_verbose) + msg_info("renamed file %s as %s", old, new); + } + return (ret); +} + +/* postrmdir - remove directory with extreme prejudice */ + +static int postrmdir(const char *path) +{ + int ret; + + if ((ret = rmdir(path)) < 0) { + if (errno != ENOENT) + msg_fatal("remove directory %s: %m", path); + } else { + if (msg_verbose) + msg_info("remove directory %s", path); + } + return (ret); +} + +/* delete_one - delete one message instance and all its associated files */ + +static int delete_one(const char **queue_names, const char *queue_id) +{ + struct stat st; + const char **msg_qpp; + const char **log_qpp; + const char *msg_path; + VSTRING *log_path_buf; + int found; + int tries; + + /* + * Sanity check. No early returns beyond this point. + */ + if (!mail_queue_id_ok(queue_id)) { + msg_warn("invalid mail queue id: %s", queue_id); + return (0); + } + log_path_buf = vstring_alloc(100); + + /* + * Skip meta file directories. Delete defer or bounce logfiles before + * deleting the corresponding message file, and only if the message file + * exists. This minimizes but does not eliminate a race condition with + * queue ID reuse which results in deleting the wrong files. + */ + for (found = 0, tries = 0; found == 0 && tries < 2; tries++) { + for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) { + if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp))) + continue; + if (mail_open_ok(*msg_qpp, queue_id, &st, &msg_path) != MAIL_OPEN_YES) + continue; + for (log_qpp = log_queue_names; *log_qpp != 0; log_qpp++) + postremove(mail_queue_path(log_path_buf, *log_qpp, queue_id)); + if (postremove(msg_path) == 0) { + found = 1; + msg_info("%s: removed", queue_id); + break; + } /* else: maybe lost a race */ + } + } + vstring_free(log_path_buf); + return (found); +} + +/* requeue_one - requeue one message instance and delete its logfiles */ + +static int requeue_one(const char **queue_names, const char *queue_id) +{ + struct stat st; + const char **msg_qpp; + const char *old_path; + VSTRING *new_path_buf; + int found; + int tries; + + /* + * Sanity check. No early returns beyond this point. + */ + if (!mail_queue_id_ok(queue_id)) { + msg_warn("invalid mail queue id: %s", queue_id); + return (0); + } + new_path_buf = vstring_alloc(100); + + /* + * Skip meta file directories. Like the mass requeue operation, we not + * delete defer or bounce logfiles, to avoid losing a race where the + * queue manager decides to bounce mail after all recipients have been + * tried. + */ + for (found = 0, tries = 0; found == 0 && tries < 2; tries++) { + for (msg_qpp = queue_names; *msg_qpp != 0; msg_qpp++) { + if (strcmp(*msg_qpp, MAIL_QUEUE_MAILDROP) == 0) + continue; + if (!MESSAGE_QUEUE(find_queue_info(*msg_qpp))) + continue; + if (mail_open_ok(*msg_qpp, queue_id, &st, &old_path) != MAIL_OPEN_YES) + continue; + (void) mail_queue_path(new_path_buf, MAIL_QUEUE_MAILDROP, queue_id); + if (postrename(old_path, STR(new_path_buf)) == 0) { + msg_info("%s: requeued", queue_id); + found = 1; + break; + } /* else: maybe lost a race */ + } + } + vstring_free(new_path_buf); + return (found); +} + +/* operate_stream - operate on queue IDs given on stream */ + +static int operate_stream(VSTREAM *fp, + int (*operator) (const char **, const char *), + const char **queues) +{ + VSTRING *buf = vstring_alloc(20); + int found = 0; + + while (vstring_get_nonl(buf, fp) != VSTREAM_EOF) + found += operator(queues, STR(buf)); + + vstring_free(buf); + return (found); +} + +/* fix_queue_id - make message queue ID match inode number */ + +static int fix_queue_id(const char *actual_path, const char *actual_queue, + const char *actual_id, ino_t inum) +{ + VSTRING *old_path = vstring_alloc(10); + VSTRING *new_path = vstring_alloc(10); + VSTRING *new_id = vstring_alloc(10); + const char **log_qpp; + int ret; + + /* + * Create the new queue ID from the existing time digits and from the new + * inode number. Since we are renaming multiple files, the new name must + * be deterministic so that we can recover even when the renaming + * operation is interrupted in the middle. + */ + vstring_sprintf(new_id, "%.5s%lX", actual_id, (unsigned long) inum); + + /* + * Rename logfiles before renaming the message file, so that we can + * recover when a previous attempt was interrupted. + */ + for (log_qpp = log_queue_names; *log_qpp; log_qpp++) { + mail_queue_path(old_path, *log_qpp, actual_id); + mail_queue_path(new_path, *log_qpp, STR(new_id)); + vstring_strcat(new_path, SUFFIX); + postrename(STR(old_path), STR(new_path)); + } + + /* + * Rename the message file last, so that we know that we are done with + * this message and with all its logfiles. + */ + mail_queue_path(new_path, actual_queue, STR(new_id)); + vstring_strcat(new_path, SUFFIX); + ret = postrename(actual_path, STR(new_path)); + + /* + * Clean up. + */ + vstring_free(old_path); + vstring_free(new_path); + vstring_free(new_id); + + return (ret); +} + +/* super - check queue structure, clean up, do wild-card operations */ -static void super(char **queues, int action) +static void super(const char **queues, int action) { ARGV *hash_queue_names = argv_split(var_hash_queue_names, " \t\r\n,"); VSTRING *actual_path = vstring_alloc(10); VSTRING *wanted_path = vstring_alloc(10); struct stat st; - char *queue_name; + const char *queue_name; SCAN_DIR *info; char *path; int actual_depth; int wanted_depth; char **cpp; struct queue_info *qp; + unsigned long inum; /* * Make sure every file is in the right place, clean out stale files, and @@ -151,12 +486,7 @@ static void super(char **queues, int action) * file permissions to look for, and whether or not it is desirable * to step into subdirectories. */ - for (qp = queue_info; /* void */ ; qp++) { - if (qp->name == 0) - msg_fatal("unknown queue name: %s", queue_name); - if (strcmp(qp->name, queue_name) == 0) - break; - } + qp = find_queue_info(queue_name); for (cpp = hash_queue_names->argv; /* void */ ; cpp++) { if (*cpp == 0) { wanted_depth = 0; @@ -189,12 +519,8 @@ static void super(char **queues, int action) if ((path = scan_dir_next(info)) == 0) { if (actual_depth == 0) break; - if (actual_depth > wanted_depth) { - if (rmdir(scan_dir_path(info)) < 0 && errno != ENOENT) - msg_warn("remove %s: %m", scan_dir_path(info)); - else if (msg_verbose) - msg_info("remove %s", scan_dir_path(info)); - } + if (actual_depth > wanted_depth) + postrmdir(scan_dir_path(info)); scan_dir_pop(info); actual_depth--; continue; @@ -212,66 +538,175 @@ static void super(char **queues, int action) } /* - * See if this is a stale file or some non-file object. Be - * careful not to delete bounce or defer logs just because they - * are more than a couple days old. + * From here on we need to keep track of operations that + * invalidate or revalidate the actual_path and path variables, + * otherwise we can hit the wrong files. */ vstring_sprintf(actual_path, "%s/%s", scan_dir_path(info), path); if (stat(STR(actual_path), &st) < 0) continue; + + /* + * Remove alien directories. If maildrop is world writable, then + * we cannot abort just because we cannot remove someone's + * directory. + */ if (S_ISDIR(st.st_mode)) { - if (rmdir(STR(actual_path)) < 0 && errno != ENOENT) - msg_warn("remove subdirectory %s: %m", STR(actual_path)); - else if (msg_verbose) - msg_info("remove subdirectory %s", STR(actual_path)); + if (rmdir(STR(actual_path)) < 0) { + if (errno != ENOENT) + msg_warn("remove subdirectory %s: %m", STR(actual_path)); + } else { + if (msg_verbose) + msg_info("remove subdirectory %s", STR(actual_path)); + } + /* No further work on this object is possible. */ + continue; + } + + /* + * Mass deletion. We count the deletion of mail that this system + * has taken responsibility for. XXX This option does not use the + * mail_queue(3) API, so that it can be run on a queue that does + * not have files in the "right" place. It would be terribly + * inefficient to first have to rename files into place before + * deleting them. + */ + if (action & ACTION_DELETE_ALL) { + if (postremove(STR(actual_path)) == 0) + if (MESSAGE_QUEUE(qp) && READY_MESSAGE(st)) + message_deleted++; + /* No further work on this object is possible. */ continue; } + + /* + * Remove non-file objects and old temporary files. Be careful + * not to delete bounce or defer logs just because they are more + * than a couple days old. + */ if (!S_ISREG(st.st_mode) - || ((action & ACTION_PURGE) != 0 && - (st.st_mode & S_IRWXU) != qp->perms + || ((action & ACTION_PURGE) != 0 + && MESSAGE_QUEUE(qp) + && !READY_MESSAGE(st) && time((time_t *) 0) > st.st_mtime + MAX_TEMP_AGE)) { - if (remove(STR(actual_path)) < 0 && errno != ENOENT) - msg_warn("remove %s: %m", STR(actual_path)); - else if (msg_verbose) - msg_info("remove %s", STR(actual_path)); + (void) postremove(STR(actual_path)); + /* No further work on this object is possible. */ continue; } /* + * Skip temporary message files that aren't old enough. + */ + if (MESSAGE_QUEUE(qp) && !READY_MESSAGE(st)) + /* No further work on this object is possible. */ + continue; + + /* + * Fix queueid#FIX names that were left from a previous pass over + * the queue where message queue file names were matched to their + * inode number. This requires that the file is already in the + * proper directory so that we only have to strip the suffix. + * Make sure that the name minus suffix is well formed and that + * the name matches the file inode number. + */ + if (strcmp(path + (strlen(path) - SUFFIX_LEN), SUFFIX) == 0) { + path[strlen(path) - SUFFIX_LEN] = 0; /* XXX */ + if (!mail_queue_id_ok(path)) { + msg_warn("bogus file name: %s", STR(actual_path)); + continue; + } + if (MESSAGE_QUEUE(qp)) { + if (sscanf(path + 5, "%lx", &inum) != 1) { + msg_warn("bogus file name: %s", STR(actual_path)); + continue; + } + if (inum != (unsigned long) st.st_ino) { + msg_warn("name/inode mismatch: %s", STR(actual_path)); + continue; + } + } + vstring_strncpy(wanted_path, STR(actual_path), + strlen(STR(actual_path)) - SUFFIX_LEN); + if (postrename(STR(actual_path), STR(wanted_path)) < 0) { + /* No further work on this object is possible. */ + continue; + } else { + if (MESSAGE_QUEUE(qp)) + inode_fixed++; + vstring_strcpy(actual_path, STR(wanted_path)); + /* At this point, path and actual_path are revalidated. */ + } + } + + /* * Skip over files with illegal names. The library routines * refuse to operate on them. */ - if (mail_queue_id_ok(path) == 0) + if (!mail_queue_id_ok(path)) { + msg_warn("bogus file name: %s", STR(actual_path)); continue; + } /* - * Skip temporary files that aren't old enough. + * Mass requeuing. The pickup daemon will copy requeued mail to a + * new queue file, so that address rewriting is applied again. + * XXX This option does not use the mail_queue(3) API, so that it + * can be run on a queue that does not have the files in the + * "right" place. It would be terribly inefficient to first have + * to rename files into place before requeuing them. Like the + * requeue_one() routine, this code does not touch logfiles. */ - if (qp->perms == MAIL_QUEUE_STAT_READY - && (st.st_mode & S_IRWXU) != qp->perms) + if ((action & ACTION_REQUEUE_ALL) + && MESSAGE_QUEUE(qp) + && strcmp(queue_name, MAIL_QUEUE_MAILDROP) != 0) { + (void) mail_queue_path(wanted_path, MAIL_QUEUE_MAILDROP, path); + if (postrename(STR(actual_path), STR(wanted_path)) == 0) + message_requeued++; + /* At this point, path and actual_path are invalidated. */ continue; + } + + /* + * See if the file name matches the file inode number. Skip meta + * file directories. This option requires that meta files be put + * into their proper place before queue files, so that we can + * rename queue files and meta files at the same time. Mis-named + * files are renamed to newqueueid#FIX on the first pass, and + * upon the second pass the #FIX is stripped off the name. Of + * course we have to be prepared that the program is interrupted + * before it completes, so any left-over newqueueid#FIX files + * have to be handled properly. XXX This option does not use the + * mail_queue(3) API for message queue files, so that it can be + * run on a queue that does not have message queue files in the + * "right" place. It would be terribly inefficient to first have + * to rename files into place before fixing the file names. + */ + if ((action & ACTION_STRUCT) != 0 && MESSAGE_QUEUE(qp)) { + if (sscanf(path + 5, "%lx", &inum) != 1) { + msg_warn("bogus file name: %s", STR(actual_path)); + continue; + } + if (inum != (unsigned long) st.st_ino) { + inode_mismatch++; /* before we fix */ + fix_queue_id(STR(actual_path), queue_name, path, st.st_ino); + /* At this point, path and actual_path are invalidated. */ + continue; + } + } /* * See if this file sits in the right place in the file system * hierarchy. Its place may be wrong after a change to the - * hash_queue_{names,depth} parameter settings. The implied - * mkdir() operation is the main reason for this command to run - * with postfix privilege. The mail_queue_mkdirs() routine could - * be fixed to use the "right" privilege, but it is a good idea - * to do everything with the postfix owner privileges regardless, - * in order to limit the amount of damage that we can do. + * hash_queue_{names,depth} parameter settings. */ - (void) mail_queue_path(wanted_path, queue_name, path); - if (strcmp(STR(actual_path), STR(wanted_path)) != 0) { - if (rename(STR(actual_path), STR(wanted_path)) < 0) - if (errno != ENOENT - || mail_queue_mkdirs(STR(wanted_path)) < 0 - || rename(STR(actual_path), STR(wanted_path)) < 0) - msg_fatal("rename %s to %s: %m", STR(actual_path), - STR(wanted_path)); - if (msg_verbose) - msg_info("rename %s to %s", STR(actual_path), - STR(wanted_path)); + if (action & ACTION_STRUCT) { + (void) mail_queue_path(wanted_path, queue_name, path); + if (strcmp(STR(actual_path), STR(wanted_path)) != 0) { + position_mismatch++; /* before we fix */ + (void) postrename(STR(actual_path), STR(wanted_path)); + /* At this point, path and actual_path are invalidated. */ + continue; + } } } scan_dir_close(info); @@ -285,26 +720,43 @@ static void super(char **queues, int action) argv_free(hash_queue_names); } +/* fatal_exit - print warning if queue fix is incomplete */ + +static void fatal_exit(void) +{ + if (inode_mismatch > 0 || inode_fixed > 0 || position_mismatch > 0) + msg_fatal("OPERATION INCOMPLETE -- RERUN COMMAND TO FIX THE QUEUE FIRST"); +} + +/* interrupted - signal handler */ + +static void interrupted(int unused_sig) +{ + fatal_exit(); +} + int main(int argc, char **argv) { int fd; struct stat st; char *slash; - int debug_me = 0; int action = 0; - char **queues; + const char **queues; int c; + ARGV *requeue_names = 0; + ARGV *delete_names = 0; + char **cpp; /* * Defaults. */ static char *default_queues[] = { + MAIL_QUEUE_DEFER, /* before message directories */ + MAIL_QUEUE_BOUNCE, /* before message directories */ MAIL_QUEUE_MAILDROP, MAIL_QUEUE_INCOMING, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_DEFERRED, - MAIL_QUEUE_DEFER, - MAIL_QUEUE_BOUNCE, MAIL_QUEUE_FLUSH, 0, }; @@ -331,8 +783,6 @@ int main(int argc, char **argv) */ if (safe_getenv(CONF_ENV_VERB)) msg_verbose = 1; - if (safe_getenv(CONF_ENV_DEBUG)) - debug_me = 1; /* * Initialize. Set up logging, read the global configuration file and @@ -349,6 +799,17 @@ int main(int argc, char **argv) msg_fatal("chdir %s: %m", var_queue_dir); /* + * Be sure to log a warning if we do not finish structural repair. Maybe + * we should have an fsck-style "clean" flag so Postfix will not start + * with a broken queue. + */ + signal(SIGHUP, interrupted); + signal(SIGINT, interrupted); + signal(SIGQUIT, interrupted); + signal(SIGTERM, interrupted); + msg_cleanup(fatal_exit); + + /* * All file/directory updates must be done as the mail system owner. This * is because Postfix daemons manipulate the queue with those same * privileges, so directories must be created with the right ownership. @@ -359,22 +820,38 @@ int main(int argc, char **argv) * a non-root user limits the damage to the already compromised mail * owner. */ + if (getuid()) + msg_fatal("use of this command is reserved for the super-user"); set_ugid(var_owner_uid, var_owner_gid); /* * Parse JCL. */ - while ((c = GETOPT(argc, argv, "spv")) > 0) { + while ((c = GETOPT(argc, argv, "d:pr:sv")) > 0) { switch (c) { default: - msg_fatal("usage: %s [-s (fix structure)] [-p (purge stale files)]", + msg_fatal("usage: %s [-d queue_id (delete)] [-p (purge temporary files)] [-r queue_id (requeue)] [-s (structure fix)]", argv[0]); - case 's': - action |= ACTION_STRUCT; + case 'd': + if (delete_names == 0) + delete_names = argv_alloc(1); + argv_add(delete_names, optarg, (char *) 0); + action |= (strcmp(optarg, "ALL") == 0 ? + ACTION_DELETE_ALL : ACTION_DELETE_ONE); break; case 'p': action |= ACTION_PURGE; break; + case 'r': + if (requeue_names == 0) + requeue_names = argv_alloc(1); + argv_add(requeue_names, optarg, (char *) 0); + action |= (strcmp(optarg, "ALL") == 0 ? + ACTION_REQUEUE_ALL : ACTION_REQUEUE_ONE); + break; + case 's': + action |= ACTION_STRUCT; + break; case 'v': msg_verbose++; break; @@ -384,15 +861,100 @@ int main(int argc, char **argv) /* * Execute the explicitly specified (or default) action, on the * explicitly specified (or default) queues. + * + * XXX Work around gcc const brain damage. */ if (action == 0) action = ACTION_DEFAULT; if (argv[optind] == 0) - queues = default_queues; + queues = (const char **) default_queues; else - queues = argv + optind; + queues = (const char **) argv + optind; + +#define ACTIONS_BY_QUEUE_ID (ACTION_DELETE_ONE | ACTION_REQUEUE_ONE) + + /* + * Basic queue maintenance, as well as mass deletion, mass requeuing, and + * mass name-to-inode fixing. This ensures that queue files are in the + * right place before the file-by-name operations are done. + */ + if (action & ~ACTIONS_BY_QUEUE_ID) + super(queues, action & ~ACTIONS_BY_QUEUE_ID); - super(queues, action); + /* + * If any file names needed changing to match the message file inode + * number, those files were named newqeueid#FIX. We need a second pass to + * strip the suffix from the new queue ID. + */ + if (inode_mismatch > 0) + super(queues, 0); + + /* + * Delete queue files by name. This must not be done when queue file + * names have changed names as a result of inode number mismatches, + * because we could be deleting the wrong message. + */ + if (action & ACTION_DELETE_ONE) { + if (inode_mismatch > 0 || inode_fixed > 0) { + msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS"); + msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND"); + } + argv_terminate(delete_names); + for (cpp = delete_names->argv; *cpp; cpp++) { + if (strcmp(*cpp, "ALL") == 0) + continue; + if (strcmp(*cpp, "-") == 0) + message_deleted += + operate_stream(VSTREAM_IN, delete_one, queues); + else + message_deleted += delete_one(queues, *cpp); + } + } + + /* + * Requeue queue files by name. This must not be done when queue file + * names have changed names as a result of inode number mismatches, + * because we could be requeuing the wrong message. + */ + if (action & ACTION_REQUEUE_ONE) { + if (inode_mismatch > 0 || inode_fixed > 0) { + msg_error("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS"); + msg_fatal("CHECK YOUR QUEUE IDS AND RE-ISSUE THE COMMAND"); + } + argv_terminate(requeue_names); + for (cpp = requeue_names->argv; *cpp; cpp++) { + if (strcmp(*cpp, "ALL") == 0) + continue; + if (strcmp(*cpp, "-") == 0) + message_requeued += + operate_stream(VSTREAM_IN, requeue_one, queues); + else + message_requeued += requeue_one(queues, *cpp); + } + } + + /* + * Report. + */ + if (message_requeued > 0) + msg_info("Requeued: %d message%s", message_requeued, + message_requeued > 1 ? "s" : ""); + if (message_deleted > 0) + msg_info("Deleted: %d message%s", message_deleted, + message_deleted > 1 ? "s" : ""); + if (inode_fixed > 0) + msg_info("Renamed to match inode number: %d message%s", inode_fixed, + inode_fixed > 1 ? "s" : ""); + if (inode_mismatch > 0 || inode_fixed > 0) + msg_warn("QUEUE FILE NAMES WERE CHANGED TO MATCH INODE NUMBERS"); + + /* + * Clean up. + */ + if (requeue_names) + argv_free(requeue_names); + if (delete_names) + argv_free(delete_names); exit(0); } diff --git a/gnu/dist/postfix/src/qmgr/Makefile.in b/gnu/dist/postfix/src/qmgr/Makefile.in index c37f1d78fd0..19f24d7e67e 100644 --- a/gnu/dist/postfix/src/qmgr/Makefile.in +++ b/gnu/dist/postfix/src/qmgr/Makefile.in @@ -73,6 +73,8 @@ qmgr.o: ../../include/mail_conf.h qmgr.o: ../../include/mail_params.h qmgr.o: ../../include/mail_proto.h qmgr.o: ../../include/iostuff.h +qmgr.o: ../../include/attr.h +qmgr.o: ../../include/mail_flow.h qmgr.o: ../../include/master_proto.h qmgr.o: ../../include/mail_server.h qmgr.o: qmgr.h @@ -133,9 +135,11 @@ qmgr_deliver.o: ../../include/events.h qmgr_deliver.o: ../../include/iostuff.h qmgr_deliver.o: ../../include/mail_queue.h qmgr_deliver.o: ../../include/mail_proto.h +qmgr_deliver.o: ../../include/attr.h qmgr_deliver.o: ../../include/recipient_list.h qmgr_deliver.o: ../../include/mail_params.h qmgr_deliver.o: ../../include/deliver_request.h +qmgr_deliver.o: ../../include/verp_sender.h qmgr_deliver.o: qmgr.h qmgr_deliver.o: ../../include/scan_dir.h qmgr_deliver.o: ../../include/maps.h @@ -188,6 +192,7 @@ qmgr_message.o: ../../include/mail_addr_find.h qmgr_message.o: ../../include/maps.h qmgr_message.o: ../../include/opened.h qmgr_message.o: ../../include/resolve_local.h +qmgr_message.o: ../../include/verp_sender.h qmgr_message.o: ../../include/resolve_clnt.h qmgr_message.o: qmgr.h qmgr_message.o: ../../include/scan_dir.h @@ -252,6 +257,7 @@ qmgr_transport.o: ../../include/vstream.h qmgr_transport.o: ../../include/vbuf.h qmgr_transport.o: ../../include/iostuff.h qmgr_transport.o: ../../include/mail_proto.h +qmgr_transport.o: ../../include/attr.h qmgr_transport.o: ../../include/recipient_list.h qmgr_transport.o: ../../include/mail_conf.h qmgr_transport.o: ../../include/mail_params.h diff --git a/gnu/dist/postfix/src/qmgr/qmgr.c b/gnu/dist/postfix/src/qmgr/qmgr.c index 7513aa368e9..146b2646933 100644 --- a/gnu/dist/postfix/src/qmgr/qmgr.c +++ b/gnu/dist/postfix/src/qmgr/qmgr.c @@ -262,6 +262,7 @@ #include <mail_conf.h> #include <mail_params.h> #include <mail_proto.h> /* QMGR_SCAN constants */ +#include <mail_flow.h> /* Master process interface */ @@ -293,6 +294,8 @@ int var_qmgr_fudge; int var_qmgr_hog; int var_local_rcpt_lim; /* XXX */ int var_local_con_lim; /* XXX */ +int var_proc_limit; +bool var_verp_bounce_off; static QMGR_SCAN *qmgr_incoming; static QMGR_SCAN *qmgr_deferred; @@ -378,6 +381,8 @@ static int qmgr_loop(char *unused_name, char **unused_argv) { char *in_path = 0; char *df_path = 0; + int token_count; + int in_feed = 0; /* * This routine runs as part of the event handling loop, after the event @@ -405,11 +410,27 @@ static int qmgr_loop(char *unused_name, char **unused_argv) if (qmgr_message_count < var_qmgr_active_limit && qmgr_recipient_count < var_qmgr_rcpt_limit) if ((in_path = qmgr_scan_next(qmgr_incoming)) != 0) - qmgr_active_feed(qmgr_incoming, in_path); + in_feed = qmgr_active_feed(qmgr_incoming, in_path); if (qmgr_message_count < var_qmgr_active_limit && qmgr_recipient_count < var_qmgr_rcpt_limit) if ((df_path = qmgr_scan_next(qmgr_deferred)) != 0) qmgr_active_feed(qmgr_deferred, df_path); + + /* + * Global flow control. If enabled, slow down receiving processes that + * get ahead of the queue manager, but don't block them completely. + */ + if (var_in_flow_delay > 0) { + token_count = mail_flow_count(); + if (token_count < var_proc_limit) { + if (in_feed != 0) + mail_flow_put(1); + else if (qmgr_incoming->handle == 0) + mail_flow_put(var_proc_limit - token_count); + } else if (token_count > var_proc_limit) { + mail_flow_get(token_count - var_proc_limit); + } + } if (in_path || df_path) return (DONT_WAIT); return (WAIT_FOR_EVENT); @@ -491,10 +512,12 @@ int main(int argc, char **argv) VAR_QMGR_HOG, DEF_QMGR_HOG, &var_qmgr_hog, 10, 100, VAR_LOCAL_RCPT_LIMIT, DEF_LOCAL_RCPT_LIMIT, &var_local_rcpt_lim, 0, 0, VAR_LOCAL_CON_LIMIT, DEF_LOCAL_CON_LIMIT, &var_local_con_lim, 0, 0, + VAR_PROC_LIMIT, DEF_PROC_LIMIT, &var_proc_limit, 1, 0, 0, }; static CONFIG_BOOL_TABLE bool_table[] = { VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user, + VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off, 0, }; diff --git a/gnu/dist/postfix/src/qmgr/qmgr.h b/gnu/dist/postfix/src/qmgr/qmgr.h index 45ceac8e99b..9839c07c209 100644 --- a/gnu/dist/postfix/src/qmgr/qmgr.h +++ b/gnu/dist/postfix/src/qmgr/qmgr.h @@ -227,6 +227,7 @@ struct QMGR_MESSAGE { char *queue_name; /* queue name */ char *queue_id; /* queue file */ char *sender; /* complete address */ + char *verp_delims; /* VERP delimiters */ char *errors_to; /* error report address */ char *return_receipt; /* confirm receipt address */ char *filter_xport; /* filtering transport */ @@ -269,7 +270,7 @@ extern void qmgr_deliver(QMGR_TRANSPORT *, VSTREAM *); /* * qmgr_active.c */ -extern void qmgr_active_feed(QMGR_SCAN *, const char *); +extern int qmgr_active_feed(QMGR_SCAN *, const char *); extern void qmgr_active_drain(void); extern void qmgr_active_done(QMGR_MESSAGE *); diff --git a/gnu/dist/postfix/src/qmgr/qmgr_active.c b/gnu/dist/postfix/src/qmgr/qmgr_active.c index 404c4eda986..722d810739c 100644 --- a/gnu/dist/postfix/src/qmgr/qmgr_active.c +++ b/gnu/dist/postfix/src/qmgr/qmgr_active.c @@ -131,7 +131,8 @@ static void qmgr_active_corrupt(const char *queue_id) msg_warn("%s: save corrupt file queue %s id %s: %m", myname, MAIL_QUEUE_ACTIVE, queue_id); } else { - msg_warn("corrupt file queue %s id %s", MAIL_QUEUE_ACTIVE, queue_id); + msg_warn("saving corrupt file \"%s\" from queue \"%s\" to queue \"%s\"", + queue_id, MAIL_QUEUE_ACTIVE, MAIL_QUEUE_CORRUPT); } } @@ -164,7 +165,7 @@ static void qmgr_active_defer(const char *queue_name, const char *queue_id, /* qmgr_active_feed - feed one message into active queue */ -void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) +int qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) { char *myname = "qmgr_active_feed"; QMGR_MESSAGE *message; @@ -180,7 +181,7 @@ void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) * Make sure this is something we are willing to open. */ if (mail_open_ok(scan_info->queue, queue_id, &st, &path) == MAIL_OPEN_NO) - return; + return (0); if (msg_verbose) msg_info("%s: %s", myname, path); @@ -194,7 +195,7 @@ void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) if (msg_verbose) msg_info("%s: skip %s (%ld seconds)", myname, queue_id, (long) (st.st_mtime - event_time())); - return; + return (0); } /* @@ -206,7 +207,7 @@ void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE); msg_warn("%s: %s: rename from %s to %s: %m", myname, queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE); - return; + return (0); } /* @@ -226,8 +227,10 @@ void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id, scan_info->flags)) == 0) { qmgr_active_corrupt(queue_id); + return (0); } else if (message == QMGR_MESSAGE_LOCKED) { qmgr_active_defer(MAIL_QUEUE_ACTIVE, queue_id, MAIL_QUEUE_INCOMING, 60); + return (0); } else { /* @@ -236,6 +239,7 @@ void qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) */ if (message->refcount == 0) qmgr_active_done(message); + return (1); } } @@ -275,12 +279,21 @@ void qmgr_active_done(QMGR_MESSAGE *message) } else { if (msg_verbose) msg_info("%s: bounce %s", myname, message->queue_id); - abounce_flush(BOUNCE_FLAG_KEEP, - message->queue_name, - message->queue_id, - message->errors_to, - qmgr_active_done_2_bounce_flush, - (char *) message); + if (message->verp_delims == 0 || var_verp_bounce_off) + abounce_flush(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + qmgr_active_done_2_bounce_flush, + (char *) message); + else + abounce_flush_verp(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + message->verp_delims, + qmgr_active_done_2_bounce_flush, + (char *) message); return; } } @@ -317,7 +330,7 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message) * attributes, and by pretending that delivery was deferred. */ if (message->flags - && !mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path)) { + && mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path) == MAIL_OPEN_NO) { qmgr_active_corrupt(message->queue_id); qmgr_message_free(message); return; @@ -351,14 +364,23 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message) */ if (message->flags) { if (event_time() > message->arrival_time + var_max_queue_time) { - if (msg_verbose) - msg_info("%s: too old, bouncing %s", myname, message->queue_id); - adefer_flush(BOUNCE_FLAG_KEEP, - message->queue_name, - message->queue_id, - message->errors_to, - qmgr_active_done_3_defer_flush, - (char *) message); + msg_info("%s: from=<%s>, status=expired, returned to sender", + message->queue_id, message->sender); + if (message->verp_delims == 0 || var_verp_bounce_off) + adefer_flush(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + qmgr_active_done_3_defer_flush, + (char *) message); + else + adefer_flush_verp(BOUNCE_FLAG_KEEP, + message->queue_name, + message->queue_id, + message->errors_to, + message->verp_delims, + qmgr_active_done_3_defer_flush, + (char *) message); return; } else if (message->warn_time > 0 && event_time() > message->warn_time) { diff --git a/gnu/dist/postfix/src/qmgr/qmgr_deliver.c b/gnu/dist/postfix/src/qmgr/qmgr_deliver.c index 1a605dd1f05..45c0a6cdde0 100644 --- a/gnu/dist/postfix/src/qmgr/qmgr_deliver.c +++ b/gnu/dist/postfix/src/qmgr/qmgr_deliver.c @@ -63,6 +63,7 @@ #include <recipient_list.h> #include <mail_params.h> #include <deliver_request.h> +#include <verp_sender.h> /* Application-specific. */ @@ -86,7 +87,9 @@ static int qmgr_deliver_initial_reply(VSTREAM *stream) if (peekfd(vstream_fileno(stream)) < 0) { msg_warn("%s: premature disconnect", VSTREAM_PATH(stream)); return (DELIVER_STAT_CRASH); - } else if (mail_scan(stream, "%d", &stat) != 1) { + } else if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat, + ATTR_TYPE_END) != 1) { msg_warn("%s: malformed response", VSTREAM_PATH(stream)); return (DELIVER_STAT_CRASH); } else { @@ -103,7 +106,10 @@ static int qmgr_deliver_final_reply(VSTREAM *stream, VSTRING *reason) if (peekfd(vstream_fileno(stream)) < 0) { msg_warn("%s: premature disconnect", VSTREAM_PATH(stream)); return (DELIVER_STAT_CRASH); - } else if (mail_scan(stream, "%s %d", reason, &stat) != 2) { + } else if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_WHY, reason, + ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &stat, + ATTR_TYPE_END) != 2) { msg_warn("%s: malformed response", VSTREAM_PATH(stream)); return (DELIVER_STAT_CRASH); } else { @@ -119,6 +125,24 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) QMGR_RCPT *recipient; QMGR_MESSAGE *message = entry->message; char *cp; + VSTRING *sender_buf = 0; + char *sender; + int flags; + char *nexthop; + + /* + * If variable envelope return path is requested, change prefix+@origin + * into prefix+user=domain@origin. Note that with VERP there is only one + * recipient per delivery. + */ + if (message->verp_delims == 0) { + sender = message->sender; + } else { + sender_buf = vstring_alloc(100); + verp_sender(sender_buf, message->verp_delims, + message->sender, list.info->address); + sender = vstring_str(sender_buf); + } /* * With mail transports that accept only one recipient per delivery, the @@ -126,17 +150,32 @@ static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream) * concurrency limits. However, the delivery agent protocol expects * nexthop only, so we must strip off the recipient local part. */ - mail_print(stream, "%d %s %s %ld %ld %s %s %s %s %ld", - message->inspect_xport ? DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT, - message->queue_name, message->queue_id, - message->data_offset, message->data_size, - (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? cp + 1 : - entry->queue->name, message->sender, - message->errors_to, message->return_receipt, - message->arrival_time); + flags = message->inspect_xport ? + DEL_REQ_FLAG_BOUNCE : DEL_REQ_FLAG_DEFLT; + nexthop = (cp = strrchr(entry->queue->name, '@')) != 0 && cp[1] ? + cp + 1 : entry->queue->name; + attr_print(stream, ATTR_FLAG_MORE, + 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_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_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++) - mail_print(stream, "%ld %s", recipient->offset, recipient->address); - mail_print(stream, "%s", "0"); + attr_print(stream, ATTR_FLAG_MORE, + 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, + ATTR_TYPE_NUM, MAIL_ATTR_OFFSET, 0, + ATTR_TYPE_END); if (vstream_fflush(stream) != 0) { msg_warn("write to process (%s): %m", entry->queue->transport->name); return (-1); @@ -197,6 +236,8 @@ static void qmgr_deliver_update(int unused_event, char *context) if (status == DELIVER_STAT_CRASH) { message->flags |= DELIVER_STAT_DEFER; qmgr_transport_throttle(transport, "unknown mail transport error"); + msg_warn("transport %s failure -- see a previous warning/fatal/panic logfile record for the problem description", + transport->name); qmgr_defer_transport(transport, transport->reason); } diff --git a/gnu/dist/postfix/src/qmgr/qmgr_move.c b/gnu/dist/postfix/src/qmgr/qmgr_move.c index 7f86197ec01..a4e55f0585f 100644 --- a/gnu/dist/postfix/src/qmgr/qmgr_move.c +++ b/gnu/dist/postfix/src/qmgr/qmgr_move.c @@ -35,6 +35,7 @@ #include <sys/stat.h> #include <string.h> #include <utime.h> +#include <errno.h> /* Utility library. */ @@ -73,12 +74,21 @@ void qmgr_move(const char *src_queue, const char *dst_queue, if (time_stamp > 0) { tbuf.actime = tbuf.modtime = time_stamp; path = mail_queue_path((VSTRING *) 0, src_queue, queue_id); - if (utime(path, &tbuf) < 0) - msg_fatal("%s: update %s time stamps: %m", myname, path); + if (utime(path, &tbuf) < 0) { + if (errno != ENOENT) + msg_fatal("%s: update %s time stamps: %m", myname, path); + msg_warn("%s: update %s time stamps: %m", myname, path); + continue; + } + } + if (mail_queue_rename(queue_id, src_queue, dst_queue)) { + if (errno != ENOENT) + msg_fatal("%s: rename %s from %s to %s: %m", + myname, queue_id, src_queue, dst_queue); + msg_warn("%s: rename %s from %s to %s: %m", + myname, queue_id, src_queue, dst_queue); + continue; } - if (mail_queue_rename(queue_id, src_queue, dst_queue)) - msg_fatal("%s: rename %s from %s to %s: %m", - myname, queue_id, src_queue, dst_queue); if (msg_verbose) msg_info("%s: moved %s from %s to %s", myname, queue_id, src_queue, dst_queue); diff --git a/gnu/dist/postfix/src/qmqpd/.printfck b/gnu/dist/postfix/src/qmqpd/.printfck new file mode 100644 index 00000000000..66016ed453c --- /dev/null +++ b/gnu/dist/postfix/src/qmqpd/.printfck @@ -0,0 +1,25 @@ +been_here_xt 2 0 +bounce_append 5 0 +cleanup_out_format 1 0 +defer_append 5 0 +mail_command 1 0 +mail_print 1 0 +msg_error 0 0 +msg_fatal 0 0 +msg_info 0 0 +msg_panic 0 0 +msg_warn 0 0 +opened 4 0 +post_mail_fprintf 1 0 +qmgr_message_bounce 2 0 +rec_fprintf 2 0 +sent 4 0 +smtp_cmd 1 0 +smtp_mesg_fail 2 0 +smtp_printf 1 0 +smtp_rcpt_fail 3 0 +smtp_site_fail 2 0 +udp_syslog 1 0 +vstream_fprintf 1 0 +vstream_printf 0 0 +vstring_sprintf 1 0 diff --git a/gnu/dist/postfix/src/qmqpd/Makefile.in b/gnu/dist/postfix/src/qmqpd/Makefile.in new file mode 100644 index 00000000000..5e923c5b071 --- /dev/null +++ b/gnu/dist/postfix/src/qmqpd/Makefile.in @@ -0,0 +1,117 @@ +SHELL = /bin/sh +SRCS = qmqpd.c qmqpd_state.c qmqpd_peer.c +OBJS = qmqpd.o qmqpd_state.o qmqpd_peer.o +HDRS = +TESTSRC = +WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ + -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ + -Wunused +DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) +CFLAGS = $(DEBUG) $(OPT) $(DEFS) +TESTPROG= qmqpd_token qmqpd_check +PROG = qmqpd +INC_DIR = ../../include +LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libdns.a ../../lib/libutil.a + +.c.o:; $(CC) $(CFLAGS) -c $*.c + +$(PROG): $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) + +Makefile: Makefile.in + (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs && cat $?) >$@ + +test: $(TESTPROG) + +update: ../../libexec/$(PROG) + +../../libexec/$(PROG): $(PROG) + cp $(PROG) ../../libexec + +SMTPD_CHECK_OBJ = qmqpd_state.o qmqpd_peer.o + +qmqpd_token: qmqpd_token.c $(LIBS) + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS) + +qmqpd_check: qmqpd_check.c $(SMTPD_CHECK_OBJ) $(LIBS) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ qmqpd_check.c $(SMTPD_CHECK_OBJ) \ + $(LIBS) $(SYSLIBS) + mv junk $@.o + +printfck: $(OBJS) $(PROG) + rm -rf printfck + mkdir printfck + cp *.h printfck + sed '1,/^# do not edit/!d' Makefile >printfck/Makefile + set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done + cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o` + +lint: + lint $(DEFS) $(SRCS) $(LINTFIX) + +clean: + rm -f *.o *core $(PROG) $(TESTPROG) junk *.db *.out *.tmp + rm -rf printfck + +tidy: clean + +depend: $(MAKES) + (sed '1,/^# do not edit/!d' Makefile.in; \ + set -e; for i in [a-z][a-z0-9]*.c; do \ + $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ + -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \ + done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in + @$(EXPORT) make -f Makefile.in Makefile 1>&2 + +tests: + +# do not edit below this line - it is generated by 'make depend' +qmqpd.o: qmqpd.c +qmqpd.o: ../../include/sys_defs.h +qmqpd.o: ../../include/msg.h +qmqpd.o: ../../include/mymalloc.h +qmqpd.o: ../../include/vstring.h +qmqpd.o: ../../include/vbuf.h +qmqpd.o: ../../include/vstream.h +qmqpd.o: ../../include/netstring.h +qmqpd.o: ../../include/dict.h +qmqpd.o: ../../include/argv.h +qmqpd.o: ../../include/mail_params.h +qmqpd.o: ../../include/record.h +qmqpd.o: ../../include/rec_type.h +qmqpd.o: ../../include/mail_proto.h +qmqpd.o: ../../include/iostuff.h +qmqpd.o: ../../include/attr.h +qmqpd.o: ../../include/cleanup_user.h +qmqpd.o: ../../include/mail_date.h +qmqpd.o: ../../include/mail_conf.h +qmqpd.o: ../../include/debug_peer.h +qmqpd.o: ../../include/mail_stream.h +qmqpd.o: ../../include/namadr_list.h +qmqpd.o: ../../include/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 +qmqpd_peer.o: ../../include/sys_defs.h +qmqpd_peer.o: ../../include/msg.h +qmqpd_peer.o: ../../include/mymalloc.h +qmqpd_peer.o: ../../include/valid_hostname.h +qmqpd_peer.o: ../../include/stringops.h +qmqpd_peer.o: ../../include/vstring.h +qmqpd_peer.o: ../../include/vbuf.h +qmqpd_peer.o: qmqpd.h +qmqpd_peer.o: ../../include/vstream.h +qmqpd_peer.o: ../../include/mail_stream.h +qmqpd_state.o: qmqpd_state.c +qmqpd_state.o: ../../include/sys_defs.h +qmqpd_state.o: ../../include/mymalloc.h +qmqpd_state.o: ../../include/vstream.h +qmqpd_state.o: ../../include/vbuf.h +qmqpd_state.o: ../../include/vstring.h +qmqpd_state.o: ../../include/mail_stream.h +qmqpd_state.o: ../../include/cleanup_user.h +qmqpd_state.o: qmqpd.h diff --git a/gnu/dist/postfix/src/qmqpd/qmqpd.c b/gnu/dist/postfix/src/qmqpd/qmqpd.c new file mode 100644 index 00000000000..442e41433e0 --- /dev/null +++ b/gnu/dist/postfix/src/qmqpd/qmqpd.c @@ -0,0 +1,677 @@ +/*++ +/* NAME +/* qmqpd 8 +/* SUMMARY +/* Postfix QMQP server +/* SYNOPSIS +/* \fBqmqpd\fR [generic Postfix daemon options] +/* DESCRIPTION +/* The Postfix QMQP server receives one message per connection. +/* Each message is piped through the \fBcleanup\fR(8) +/* daemon, and is placed into the \fBincoming\fR queue as one +/* single queue file. The program expects to be run from the +/* \fBmaster\fR(8) process manager. +/* +/* The QMQP server implements one access policy: only explicitly +/* authorized client hosts are allowed to use the service. +/* SECURITY +/* .ad +/* .fi +/* The QMQP server is moderately security-sensitive. It talks to QMQP +/* clients and to DNS servers on the network. The QMQP server can be +/* run chrooted at fixed low privilege. +/* DIAGNOSTICS +/* Problems and transactions are logged to \fBsyslogd\fR(8). +/* BUGS +/* The QMQP protocol provides only one server reply per message +/* delivery. It is therefore not possible to reject individual +/* recipients. +/* +/* The QMQP protocol requires the server to receive the entire +/* message before replying. If a message is malformed, or if any +/* netstring component is longer than acceptable, Postfix replies +/* immediately and closes the connection. It is left up to the +/* client to handle the situation. +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* The following \fBmain.cf\fR parameters are especially relevant to +/* this program. See the Postfix \fBmain.cf\fR file for syntax details +/* and for default values. Use the \fBpostfix reload\fR command after +/* a configuration change. +/* .SH Miscellaneous +/* .ad +/* .fi +/* .IP \fBalways_bcc\fR +/* Address to send a copy of each message that enters the system. +/* .IP \fBdebug_peer_level\fR +/* Increment in verbose logging level when a remote host matches a +/* pattern in the \fBdebug_peer_list\fR parameter. +/* .IP \fBdebug_peer_list\fR +/* List of domain or network patterns. When a remote host matches +/* a pattern, increase the verbose logging level by the amount +/* specified in the \fBdebug_peer_level\fR parameter. +/* .IP \fBhopcount_limit\fR +/* Limit the number of \fBReceived:\fR message headers. +/* .IP \fBqmqpd_authorized_clients\fR +/* A list of domain or network patterns that specifies what +/* clients are allowed to use the service. +/* .IP \fBqmqpd_timeout\fR +/* Limit the time to send a server response and to receive a client +/* request. +/* .IP \fBsoft_bounce\fR +/* Change hard (D) reject responses into soft (Z) reject responses. +/* This can be useful for testing purposes. +/* .SH "Content inspection controls" +/* .IP \fBcontent_filter\fR +/* The name of a mail delivery transport that filters mail and that +/* either bounces mail or re-injects the result back into Postfix. +/* This parameter uses the same syntax as the right-hand side of +/* a Postfix transport table. +/* .SH "Resource controls" +/* .ad +/* .fi +/* .IP \fBline_length_limit\fR +/* Limit the amount of memory in bytes used for the handling of +/* partial input lines, and the length of sender and recipient +/* addresses that are received from client. +/* .IP \fBmessage_size_limit\fR +/* Limit the total size in bytes of a message, including on-disk +/* storage for sender and recipient address information. +/* .SH Tarpitting +/* .ad +/* .fi +/* .IP \fBqmqpd_error_sleep_time\fR +/* Time to wait in seconds before informing the client of +/* a problem. This slows down run-away errors. +/* SEE ALSO +/* http://cr.yp.to/proto/qmqp.html, QMQP protocol +/* cleanup(8) message canonicalization +/* master(8) process manager +/* syslogd(8) system logging +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include <stdarg.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <vstring.h> +#include <vstream.h> +#include <netstring.h> +#include <dict.h> + +/* Global library. */ + +#include <mail_params.h> +#include <record.h> +#include <rec_type.h> +#include <mail_proto.h> +#include <cleanup_user.h> +#include <mail_date.h> +#include <mail_conf.h> +#include <debug_peer.h> +#include <mail_stream.h> +#include <namadr_list.h> +#include <quote_822_local.h> +#include <match_parent_style.h> + +/* Single-threaded server skeleton. */ + +#include <mail_server.h> + +/* Application-specific */ + +#include <qmqpd.h> + + /* + * Tunable parameters. Make sure that there is some bound on the length of a + * netstring, so that the mail system stays in control even when a malicious + * client sends netstrings of unreasonable length. The recipient count limit + * is enforced by the message size limit. + */ +int var_qmqpd_timeout; +int var_qmqpd_err_sleep; +char *var_always_bcc; +char *var_filter_xport; +char *var_qmqpd_clients; + + /* + * Silly little macros. + */ +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +#define DO_LOG 1 +#define DONT_LOG 0 + + /* + * Access control. This service should be exposed only to explicitly + * authorized clients. There is no default authorization. + */ +static NAMADR_LIST *qmqpd_clients; + +/* qmqpd_open_file - open a queue file */ + +static void qmqpd_open_file(QMQPD_STATE *state) +{ + + /* + * Connect to the cleanup server. Log client name/address with queue ID. + */ + state->dest = mail_stream_service(MAIL_CLASS_PUBLIC, MAIL_SERVICE_CLEANUP); + if (state->dest == 0 + || attr_print(state->dest->stream, ATTR_FLAG_NONE, + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, CLEANUP_FLAG_FILTER, + ATTR_TYPE_END) != 0) + msg_fatal("unable to connect to the %s %s service", + MAIL_CLASS_PUBLIC, MAIL_SERVICE_CLEANUP); + state->cleanup = state->dest->stream; + state->queue_id = mystrdup(state->dest->id); + msg_info("%s: client=%s", state->queue_id, state->namaddr); + + /* + * Record the time of arrival. Optionally, enable content filtering (not + * bloody likely, but present for the sake of consistency with all other + * Postfix points of entrance). + */ + rec_fprintf(state->cleanup, REC_TYPE_TIME, "%ld", state->time); + if (*var_filter_xport) + rec_fprintf(state->cleanup, REC_TYPE_FILT, "%s", var_filter_xport); +} + +/* qmqpd_read_content - receive message content */ + +static void qmqpd_read_content(QMQPD_STATE *state) +{ + state->where = "receiving message content"; + netstring_get(state->client, state->message, var_message_limit); +} + +/* qmqpd_copy_sender - copy envelope sender */ + +static void qmqpd_copy_sender(QMQPD_STATE *state) +{ + char *end_prefix; + char *end_origin; + int verp_requested; + + /* + * If the sender address looks like prefix-@origin-@[], then request + * variable envelope return path delivery, with an envelope sender + * address of prefix@origin, and with VERP delimiters of - and =. This + * way, the recipients will see envelope sender addresses that look like: + * prefix-user=domain@origin. + */ + state->where = "receiving sender address"; + netstring_get(state->client, state->buf, var_line_limit); + VSTRING_TERMINATE(state->buf); + verp_requested = ((end_prefix = strstr(STR(state->buf), "-@")) != 0 + && (end_origin = strstr(end_prefix + 2, "-@")) != 0 + && strncmp(end_origin + 2, "[]", 2) == 0 + && vstring_end(state->buf) == end_origin + 4); + if (verp_requested) { + memcpy(end_prefix, end_prefix + 1, end_origin - end_prefix - 1); + vstring_truncate(state->buf, end_origin - STR(state->buf) - 1); + } + if (state->err == CLEANUP_STAT_OK + && REC_PUT_BUF(state->cleanup, REC_TYPE_FROM, state->buf) < 0) + state->err = CLEANUP_STAT_WRITE; + if (verp_requested) + if (state->err == CLEANUP_STAT_OK + && rec_put(state->cleanup, REC_TYPE_VERP, "-=", 2) < 0) + state->err = CLEANUP_STAT_WRITE; + state->sender = mystrndup(STR(state->buf), LEN(state->buf)); +} + +/* qmqpd_copy_recipients - copy message recipients */ + +static void qmqpd_copy_recipients(QMQPD_STATE *state) +{ + int ch; + + /* + * Remember the first recipient. We are done when we read the over-all + * netstring terminator. + * + * XXX This approach violates abstractions, but it is a heck of a lot more + * convenient than counting the over-all byte count down to zero, like + * qmail does. + */ + state->where = "receiving recipient address"; + while ((ch = VSTREAM_GETC(state->client)) != ',') { + vstream_ungetc(state->client, ch); + netstring_get(state->client, state->buf, var_line_limit); + if (state->err == CLEANUP_STAT_OK + && REC_PUT_BUF(state->cleanup, REC_TYPE_RCPT, state->buf) < 0) + state->err = CLEANUP_STAT_WRITE; + state->rcpt_count++; + if (state->recipient == 0) + state->recipient = mystrndup(STR(state->buf), LEN(state->buf)); + } + + /* + * Append the optional recipient who is copied on all mail. + */ + if (*var_always_bcc) + rec_fputs(state->cleanup, REC_TYPE_RCPT, var_always_bcc); +} + +/* qmqpd_next_line - get line from buffer, return last char, newline, or -1 */ + +static int qmqpd_next_line(VSTRING *message, char **start, int *len, + char **next) +{ + char *beyond = STR(message) + LEN(message); + char *enough = *next + var_line_limit; + char *cp; + + /* + * Stop at newline or at some limit. Don't look beyond the end of the + * buffer. + */ +#define UCHARPTR(x) ((unsigned char *) (x)) + + for (cp = *start = *next; /* void */ ; cp++) { + if (cp >= beyond) + return ((*len = (*next = cp) - *start) > 0 ? UCHARPTR(cp)[-1] : -1); + if (*cp == '\n') + return ((*len = cp - *start), (*next = cp + 1), '\n'); + if (cp >= enough) + return ((*len = cp - *start), (*next = cp), UCHARPTR(cp)[-1]); + } +} + +/* qmqpd_write_content - write the message content segment */ + +static void qmqpd_write_content(QMQPD_STATE *state) +{ + char *start; + char *next; + int len; + int rec_type; + int first = 1; + int ch; + + /* + * Start the message content segment. Prepend our own Received: header to + * the message content. List the recipient only when a message has one + * recipient. Otherwise, don't list the recipient to avoid revealing Bcc: + * recipients that are supposed to be invisible. + */ + rec_fputs(state->cleanup, REC_TYPE_MESG, ""); + rec_fprintf(state->cleanup, REC_TYPE_NORM, "Received: from %s (%s [%s])", + state->name, state->name, state->addr); + if (state->rcpt_count == 1 && state->recipient) { + rec_fprintf(state->cleanup, REC_TYPE_NORM, + "\tby %s (%s) with %s id %s", + var_myhostname, var_mail_name, + state->protocol, state->queue_id); + quote_822_local(state->buf, state->recipient); + rec_fprintf(state->cleanup, REC_TYPE_NORM, + "\tfor <%s>; %s", STR(state->buf), mail_date(state->time)); + } else { + rec_fprintf(state->cleanup, REC_TYPE_NORM, + "\tby %s (%s) with %s", + var_myhostname, var_mail_name, state->protocol); + rec_fprintf(state->cleanup, REC_TYPE_NORM, + "\tid %s; %s", state->queue_id, mail_date(state->time)); + } +#ifdef RECEIVED_ENVELOPE_FROM + quote_822_local(state->buf, state->sender); + rec_fprintf(state->cleanup, REC_TYPE_NORM, + "\t(envelope-from <%s>)", STR(state->buf)); +#endif + + /* + * Write the message content. + * + * XXX Force an empty record when the queue file content begins with + * whitespace, so that it won't be considered as being part of our own + * Received: header. What an ugly Kluge. + * + * XXX Deal with UNIX-style From_ lines at the start of message content just + * in case. + */ + for (next = STR(state->message); /* void */ ; /* void */ ) { + if ((ch = qmqpd_next_line(state->message, &start, &len, &next)) < 0) + break; + if (ch == '\n') + rec_type = REC_TYPE_NORM; + else + rec_type = REC_TYPE_CONT; + if (first) { + if (strncmp(start + strspn(start, ">"), "From ", 5) == 0) { + rec_fprintf(state->cleanup, rec_type, + "Mailbox-Line: %*s", len, start); + continue; + } + first = 0; + if (len > 0 && ISSPACE(start[0])) + rec_put(state->cleanup, REC_TYPE_NORM, "", 0); + } + if (rec_put(state->cleanup, rec_type, start, len) < 0) { + state->err = CLEANUP_STAT_WRITE; + return; + } + } +} + +/* qmqpd_close_file - close queue file */ + +static void qmqpd_close_file(QMQPD_STATE *state) +{ + + /* + * Send the end-of-segment markers. + */ + if (state->err == CLEANUP_STAT_OK) + if (rec_fputs(state->cleanup, REC_TYPE_XTRA, "") < 0 + || rec_fputs(state->cleanup, REC_TYPE_END, "") < 0 + || vstream_fflush(state->cleanup)) + state->err = CLEANUP_STAT_WRITE; + + /* + * Finish the queue file or finish the cleanup conversation. + */ + if (state->err == 0) + state->err = mail_stream_finish(state->dest, state->why_rejected); + else + mail_stream_cleanup(state->dest); + state->dest = 0; +} + +/* qmqpd_reply - send status to client and optionally log message */ + +static void qmqpd_reply(QMQPD_STATE *state, int log_message, + int status_code, const char *fmt,...) +{ + va_list ap; + + /* + * Optionally change hard errors into retryable ones. Send the reply and + * optionally log it. Always insert a delay before reporting a problem. + * This slows down software run-away conditions. + */ + if (status_code == QMQPD_STAT_HARD && var_soft_bounce) + status_code = QMQPD_STAT_RETRY; + VSTRING_RESET(state->buf); + VSTRING_ADDCH(state->buf, status_code); + va_start(ap, fmt); + vstring_vsprintf_append(state->buf, fmt, ap); + va_end(ap); + NETSTRING_PUT_BUF(state->client, state->buf); + if (log_message) + (status_code == QMQPD_STAT_OK ? msg_info : msg_warn) ("%s: %s: %s", + state->queue_id, state->namaddr, STR(state->buf) + 1); + if (status_code != QMQPD_STAT_OK) + sleep(var_qmqpd_err_sleep); + netstring_fflush(state->client); +} + +/* qmqpd_send_status - send mail transaction completion status */ + +static void qmqpd_send_status(QMQPD_STATE *state) +{ + + /* + * One message may suffer from multiple errors, so complain only about + * the most severe error. + * + * See also: smtpd.c + */ + state->where = "sending completion status"; + + if (state->err == CLEANUP_STAT_OK) { + qmqpd_reply(state, DONT_LOG, QMQPD_STAT_OK, + "Ok: queued as %s", state->queue_id); + } else if ((state->err & CLEANUP_STAT_BAD) != 0) { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, + "Error: internal error %d", state->err); + } else if ((state->err & CLEANUP_STAT_SIZE) != 0) { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, + "Error: message too large"); + } else if ((state->err & CLEANUP_STAT_HOPS) != 0) { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, + "Error: too many hops"); + } else if ((state->err & CLEANUP_STAT_CONT) != 0) { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, + "Error: %s", STR(state->why_rejected)); + } else if ((state->err & CLEANUP_STAT_WRITE) != 0) { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, + "Error: queue file write error"); + } else if ((state->err & CLEANUP_STAT_RCPT) != 0) { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_HARD, + "Error: no recipients specified"); + } else { + qmqpd_reply(state, DO_LOG, QMQPD_STAT_RETRY, + "Error: internal error %d", state->err); + } +} + +/* qmqpd_receive - receive QMQP message+sender+recipients */ + +static void qmqpd_receive(QMQPD_STATE *state) +{ + + /* + * Open a queue file. This must be first so that we can simplify the + * error logging and always include the queue ID information. + */ + qmqpd_open_file(state); + + /* + * Read and ignore the over-all netstring length indicator. + */ + state->where = "receiving QMQP packet header"; + (void) netstring_get_length(state->client); + + /* + * XXX Read the message content into memory, because Postfix expects to + * store the sender before storing the message content. Fixing that + * requires changes to pickup, cleanup, qmgr, and perhaps elsewhere, so + * that will have to happen later when I have more time. However, QMQP is + * used for mailing list distribution, so the bulk of the volume is + * expected to be not message content but recipients, and recipients are + * not accumulated in memory. + */ + qmqpd_read_content(state); + + /* + * Read and write the envelope sender. + */ + qmqpd_copy_sender(state); + + /* + * Read and write the envelope recipients, including the optional big + * brother recipient. + */ + qmqpd_copy_recipients(state); + + /* + * Start the message content segment, prepend our own Received: header, + * and write the message content. + */ + qmqpd_write_content(state); + + /* + * Close the queue file. + */ + qmqpd_close_file(state); + + /* + * Report the completion status to the client. + */ + qmqpd_send_status(state); +} + +/* qmqpd_proto - speak the QMQP "protocol" */ + +static void qmqpd_proto(QMQPD_STATE *state) +{ + int status; + + netstring_setup(state->client, var_qmqpd_timeout); + + switch (status = vstream_setjmp(state->client)) { + + default: + msg_panic("qmqpd_proto: unknown status %d", status); + + case NETSTRING_ERR_EOF: + state->reason = "lost connection"; + break; + + case NETSTRING_ERR_TIME: + state->reason = "read/write timeout"; + break; + + case NETSTRING_ERR_FORMAT: + state->reason = "netstring format error"; + if (vstream_setjmp(state->client) == 0) + if (state->reason && state->where) + qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s", + state->reason, state->where); + break; + + case NETSTRING_ERR_SIZE: + state->reason = "netstring length exceeds storage limit"; + if (vstream_setjmp(state->client) == 0) + if (state->reason && state->where) + qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, "%s while %s", + state->reason, state->where); + break; + + case 0: + qmqpd_receive(state); + break; + } + + /* + * Log abnormal session termination. Indicate the last recognized state + * before things went wrong. + */ + if (state->reason && state->where) + msg_info("%s: %s: %s while %s", + state->queue_id, state->namaddr, state->reason, state->where); +} + +/* qmqpd_service - service one client */ + +static void qmqpd_service(VSTREAM *stream, char *unused_service, char **argv) +{ + QMQPD_STATE *state; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + msg_fatal("unexpected command-line argument: %s", argv[0]); + + /* + * This routine runs when a client has connected to our network port. + * Look up and sanitize the peer name and initialize some connection- + * specific state. + */ + state = qmqpd_state_alloc(stream); + + /* + * See if we need to turn on verbose logging for this client. + */ + debug_peer_check(state->name, state->addr); + + /* + * See if we want to talk to this client at all. In all cases, log the + * connection event. + */ + if (namadr_list_match(qmqpd_clients, state->name, state->addr) == 0) { + msg_info("refused connect from %s", state->namaddr); + qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD, + "Error: %s is not authorized to use this service", + state->namaddr); + } + + /* + * Provide the QMQP service. + */ + else { + msg_info("connect from %s", state->namaddr); + qmqpd_proto(state); + msg_info("disconnect from %s", state->namaddr); + } + + /* + * After the client has gone away, clean up whatever we have set up at + * connection time. + */ + debug_peer_restore(); + qmqpd_state_free(state); +} + +/* pre_accept - see if tables have changed */ + +static void pre_accept(char *unused_name, char **unused_argv) +{ + if (dict_changed()) { + msg_info("lookup table has changed -- exiting"); + exit(0); + } +} + +/* pre_jail_init - pre-jail initialization */ + +static void pre_jail_init(char *unused_name, char **unused_argv) +{ + debug_peer_init(); + qmqpd_clients = + namadr_list_init(match_parent_style(VAR_QMQPD_CLIENTS), + var_qmqpd_clients); +} + +/* main - the main program */ + +int main(int argc, char **argv) +{ + static CONFIG_TIME_TABLE time_table[] = { + VAR_QMTPD_TMOUT, DEF_QMTPD_TMOUT, &var_qmqpd_timeout, 1, 0, + VAR_QMTPD_ERR_SLEEP, DEF_QMTPD_ERR_SLEEP, &var_qmqpd_err_sleep, 0, 0, + 0, + }; + static CONFIG_STR_TABLE str_table[] = { + VAR_ALWAYS_BCC, DEF_ALWAYS_BCC, &var_always_bcc, 0, 0, + VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0, + VAR_QMQPD_CLIENTS, DEF_QMQPD_CLIENTS, &var_qmqpd_clients, 0, 0, + 0, + }; + + /* + * Pass control to the single-threaded service skeleton. + */ + single_server_main(argc, argv, qmqpd_service, + MAIL_SERVER_TIME_TABLE, time_table, + MAIL_SERVER_STR_TABLE, str_table, + MAIL_SERVER_PRE_INIT, pre_jail_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, + 0); +} diff --git a/gnu/dist/postfix/src/qmqpd/qmqpd.h b/gnu/dist/postfix/src/qmqpd/qmqpd.h new file mode 100644 index 00000000000..aaacb424254 --- /dev/null +++ b/gnu/dist/postfix/src/qmqpd/qmqpd.h @@ -0,0 +1,79 @@ +/*++ +/* NAME +/* qmqpd 3h +/* SUMMARY +/* Postfix QMQP server +/* SYNOPSIS +/* include "qmqpd.h" +/* DESCRIPTION +/* .nf + + /* + * System library. + */ +#include <time.h> + + /* + * Utility library. + */ +#include <vstream.h> +#include <vstring.h> + + /* + * Global library. + */ +#include <mail_stream.h> + + /* + * Per-session state. + */ +typedef struct { + int err; /* error flags */ + VSTREAM *client; /* client connection */ + VSTRING *message; /* message buffer */ + VSTRING *buf; /* line buffer */ + time_t time; /* start of session */ + char *name; /* client name */ + char *addr; /* client IP address */ + char *namaddr; /* name[addr] */ + char *queue_id; /* queue file ID */ + VSTREAM *cleanup; /* cleanup server */ + MAIL_STREAM *dest; /* cleanup server */ + int rcpt_count; /* recipient count */ + char *reason; /* exception name */ + char *sender; /* sender address */ + char *recipient; /* recipient address */ + char *protocol; /* protocol name */ + char *where; /* protocol state */ + VSTRING *why_rejected; /* REJECT reason */ +} QMQPD_STATE; + + /* + * QMQP protocol status codes. + */ +#define QMQPD_STAT_OK 'K' +#define QMQPD_STAT_RETRY 'Z' +#define QMQPD_STAT_HARD 'D' + + /* + * qmqpd_state.c + */ +QMQPD_STATE *qmqpd_state_alloc(VSTREAM *); +void qmqpd_state_free(QMQPD_STATE *); + + /* + * qmqpd_peer.c + */ +void qmqpd_peer_init(QMQPD_STATE *); +void qmqpd_peer_reset(QMQPD_STATE *); + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ diff --git a/gnu/dist/postfix/src/qmqpd/qmqpd_peer.c b/gnu/dist/postfix/src/qmqpd/qmqpd_peer.c new file mode 100644 index 00000000000..9f0e9f2f5dd --- /dev/null +++ b/gnu/dist/postfix/src/qmqpd/qmqpd_peer.c @@ -0,0 +1,183 @@ +/*++ +/* NAME +/* qmqpd_peer 3 +/* SUMMARY +/* look up peer name/address information +/* SYNOPSIS +/* #include "qmqpd.h" +/* +/* void qmqpd_peer_init(state) +/* QMQPD_STATE *state; +/* +/* void qmqpd_peer_reset(state) +/* QMQPD_STATE *state; +/* DESCRIPTION +/* The qmqpd_peer_init() routine attempts to produce a printable +/* version of the peer name and address of the specified socket. +/* Where information is unavailable, the name and/or address +/* are set to "unknown". +/* +/* qmqpd_peer_init() updates the following fields: +/* .IP name +/* The client hostname. An unknown name is represented by the +/* string "unknown". +/* .IP addr +/* Printable representation of the client address. +/* .IP namaddr +/* String of the form: "name[addr]". +/* .PP +/* qmqpd_peer_reset() releases memory allocate by qmqpd_peer_init(). +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdio.h> /* strerror() */ +#include <errno.h> +#include <netdb.h> +#include <string.h> + + /* + * Older systems don't have h_errno. Even modern systems don't have + * hstrerror(). + */ +#ifdef NO_HERRNO + +static int h_errno = TRY_AGAIN; + +#define HSTRERROR(err) "Host not found" + +#else + +#define HSTRERROR(err) (\ + err == TRY_AGAIN ? "Host not found, try again" : \ + err == HOST_NOT_FOUND ? "Host not found" : \ + err == NO_DATA ? "Host name has no address" : \ + err == NO_RECOVERY ? "Name server failure" : \ + strerror(errno) \ + ) +#endif + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <valid_hostname.h> +#include <stringops.h> + +/* Global library. */ + + +/* Application-specific. */ + +#include "qmqpd.h" + +/* qmqpd_peer_init - initialize peer information */ + +void qmqpd_peer_init(QMQPD_STATE *state) +{ + struct sockaddr_in sin; + SOCKADDR_SIZE len = sizeof(sin); + struct hostent *hp; + int i; + + /* + * Look up the peer address information. + */ + if (getpeername(vstream_fileno(state->client), + (struct sockaddr *) & sin, &len) >= 0) { + errno = 0; + } + + /* + * If peer went away, give up. + */ + if (errno == ECONNRESET || errno == ECONNABORTED) { + state->name = mystrdup("unknown"); + state->addr = mystrdup("unknown"); + } + + /* + * Look up and "verify" the client hostname. + */ + else if (errno == 0 && sin.sin_family == AF_INET) { + state->addr = mystrdup(inet_ntoa(sin.sin_addr)); + hp = gethostbyaddr((char *) &(sin.sin_addr), + sizeof(sin.sin_addr), AF_INET); + if (hp == 0) { + state->name = mystrdup("unknown"); + } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { + state->name = mystrdup("unknown"); + } else { + state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ + + /* + * Reject the hostname if it does not list the peer address. + */ +#define REJECT_PEER_NAME(state) { \ + myfree(state->name); \ + state->name = mystrdup("unknown"); \ + } + + hp = gethostbyname(state->name); /* clobbers hp->name!! */ + if (hp == 0) { + msg_warn("%s: hostname %s verification failed: %s", + state->addr, state->name, HSTRERROR(h_errno)); + REJECT_PEER_NAME(state); + } else if (hp->h_length != sizeof(sin.sin_addr)) { + msg_warn("%s: hostname %s verification failed: bad address size %d", + state->addr, state->name, hp->h_length); + REJECT_PEER_NAME(state); + } else { + for (i = 0; /* void */ ; i++) { + if (hp->h_addr_list[i] == 0) { + msg_warn("%s: address not listed for hostname %s", + state->addr, state->name); + REJECT_PEER_NAME(state); + break; + } + if (memcmp(hp->h_addr_list[i], + (char *) &sin.sin_addr, + sizeof(sin.sin_addr)) == 0) + break; /* keep peer name */ + } + } + } + } + + /* + * If it's not Internet, assume the client is local, and avoid using the + * naming service because that can hang when the machine is disconnected. + */ + else { + state->name = mystrdup("localhost"); + state->addr = mystrdup("127.0.0.1"); /* XXX bogus. */ + } + + /* + * Do the name[addr] formatting for pretty reports. + */ + state->namaddr = + concatenate(state->name, "[", state->addr, "]", (char *) 0); +} + +/* qmqpd_peer_reset - destroy peer information */ + +void qmqpd_peer_reset(QMQPD_STATE *state) +{ + myfree(state->name); + myfree(state->addr); + myfree(state->namaddr); +} diff --git a/gnu/dist/postfix/src/qmqpd/qmqpd_state.c b/gnu/dist/postfix/src/qmqpd/qmqpd_state.c new file mode 100644 index 00000000000..8e5b46c9c4e --- /dev/null +++ b/gnu/dist/postfix/src/qmqpd/qmqpd_state.c @@ -0,0 +1,98 @@ +/*++ +/* NAME +/* qmqpd_state 3 +/* SUMMARY +/* Postfix QMQP server +/* SYNOPSIS +/* #include "qmqpd.h" +/* +/* QMQPD_STATE *qmqpd_state_alloc(stream) +/* VSTREAM *stream; +/* +/* void qmqpd_state_free(state) +/* QMQPD_STATE *state; +/* DESCRIPTION +/* qmqpd_state_alloc() creates and initializes session context. +/* +/* qmqpd_state_free() destroys session context. +/* +/* Arguments: +/* .IP stream +/* Stream connected to peer. The stream is not copied. +/* DIAGNOSTICS +/* All errors are fatal. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <time.h> + +/* Utility library. */ + +#include <mymalloc.h> +#include <vstream.h> +#include <vstring.h> + +/* Global library. */ + +#include <mail_stream.h> +#include <cleanup_user.h> + +/* Application-specific. */ + +#include <qmqpd.h> + +/* qmqpd_state_alloc - allocate and initialize session state */ + +QMQPD_STATE *qmqpd_state_alloc(VSTREAM *stream) +{ + QMQPD_STATE *state; + + state = (QMQPD_STATE *) mymalloc(sizeof(*state)); + state->err = CLEANUP_STAT_OK; + state->client = stream; + state->message = vstring_alloc(1000); + state->buf = vstring_alloc(100); + state->time = time((time_t *) 0); + qmqpd_peer_init(state); + state->queue_id = 0; + state->cleanup = 0; + state->dest = 0; + state->rcpt_count = 0; + state->reason = 0; + state->sender = 0; + state->recipient = 0; + state->protocol = "QMQP"; + state->where = "initializing client connection"; + state->why_rejected = vstring_alloc(10); + return (state); +} + +/* qmqpd_state_free - destroy session state */ + +void qmqpd_state_free(QMQPD_STATE *state) +{ + vstring_free(state->message); + vstring_free(state->buf); + qmqpd_peer_reset(state); + if (state->queue_id) + myfree(state->queue_id); + if (state->dest) + mail_stream_cleanup(state->dest); + if (state->sender) + myfree(state->sender); + if (state->recipient) + myfree(state->recipient); + vstring_free(state->why_rejected); + myfree((char *) state); +} diff --git a/gnu/dist/postfix/src/sendmail/Makefile.in b/gnu/dist/postfix/src/sendmail/Makefile.in index 0f9f5a4786c..e037edf1fd3 100644 --- a/gnu/dist/postfix/src/sendmail/Makefile.in +++ b/gnu/dist/postfix/src/sendmail/Makefile.in @@ -73,6 +73,7 @@ sendmail.o: ../../include/set_ugid.h sendmail.o: ../../include/connect.h sendmail.o: ../../include/mail_queue.h sendmail.o: ../../include/mail_proto.h +sendmail.o: ../../include/attr.h sendmail.o: ../../include/mail_params.h sendmail.o: ../../include/record.h sendmail.o: ../../include/rec_type.h @@ -86,4 +87,4 @@ sendmail.o: ../../include/tok822.h sendmail.o: ../../include/resolve_clnt.h sendmail.o: ../../include/mail_flush.h sendmail.o: ../../include/mail_stream.h -sendmail.o: ../../include/smtp_stream.h +sendmail.o: ../../include/verp_sender.h diff --git a/gnu/dist/postfix/src/sendmail/sendmail.c b/gnu/dist/postfix/src/sendmail/sendmail.c index a3daf6422a7..54cb2443f2d 100644 --- a/gnu/dist/postfix/src/sendmail/sendmail.c +++ b/gnu/dist/postfix/src/sendmail/sendmail.c @@ -19,11 +19,9 @@ /* /* By default, \fBsendmail\fR reads a message from standard input /* until EOF or until it reads a line with only a \fB.\fR character, -/* and arranges for delivery. \fBsendmail\fR attempts to create -/* a queue file in the \fBmaildrop\fR directory. If that directory -/* is not world-writable, the message is piped through the -/* \fBpostdrop\fR(1) command, which is expected to execute with -/* suitable privileges. +/* and arranges for delivery. \fBsendmail\fR relies on the +/* \fBpostdrop\fR(1) command to create a queue file in the \fBmaildrop\fR +/* directory. /* /* Specific command aliases are provided for other common modes of /* operation: @@ -32,7 +30,7 @@ /* size, arrival time, sender, and the recipients that still need to /* be delivered. If mail could not be delivered upon the last attempt, /* the reason for failure is shown. This mode of operation is implemented -/* by connecting to the \fBshowq\fR(8) daemon. +/* by executing the \fBpostqueue\fR(1) command. /* .IP \fBnewaliases\fR /* Initialize the alias database. If no input file is specified (with /* the \fB-oA\fR option, see below), the program processes the file(s) @@ -65,6 +63,9 @@ /* .IP \fB-I\fR /* Initialize alias database. See the \fBnewaliases\fR /* command above. +/* .IP "\fB-L \fIlabel\fR (ignored)" +/* The logging label. Use the \fBsyslog_name\fR configuration +/* parameter instead. /* .IP "\fB-N \fIdsn\fR (ignored)" /* Delivery status notification control. Currently, Postfix does /* not implement \fBDSN\fR. @@ -76,6 +77,20 @@ /* \fBdebug_peer_level\fR configuration parameters instead. /* .IP "\fB-U\fR (ignored)" /* Initial user submission. +/* .IP \fB-V\fR +/* Variable Envelope Return Path. Given an envelope sender address +/* of the form \fIowner-listname\fR@\fIorigin\fR, each recipient +/* \fIuser\fR@\fIdomain\fR receives mail with a personalized envelope +/* sender address. +/* .sp +/* By default, the personalized envelope sender address is +/* \fIowner-listname\fB+\fIuser\fB=\fIdomain\fR@\fIorigin\fR. The default +/* \fB+\fR and \fB=\fR characters are configurable with the +/* \fBdefault_verp_delimiters\fR configuration parameter. +/* .IP \fB-V\fIxy\fR +/* As \fB-V\fR, but uses \fIx\fR and \fIy\fR as the VERP delimiter +/* characters, instead of the characters specified with the +/* \fBdefault_verp_delimiters\fR configuration parameter. /* .IP \fB-bd\fR /* Go into daemon mode. This mode of operation is implemented by /* executing the \fBpostfix start\fR command. @@ -127,17 +142,17 @@ /* delivery problems are sent to, unless the message contains an /* \fBErrors-To:\fR message header. /* .IP \fB-q\fR -/* Attempt to deliver all queued mail. This is implemented by kicking the -/* \fBqmgr\fR(8) daemon. +/* Attempt to deliver all queued mail. This is implemented by +/* executing the \fBpostqueue\fR(1) command. /* .IP "\fB-q\fIinterval\fR (ignored)" /* The interval between queue runs. Use the \fBqueue_run_delay\fR /* configuration parameter instead. /* .IP \fB-qR\fIsite\fR /* Schedule immediate delivery of all mail that is queued for the named -/* \fIsite\fR. Depending on the destination, this uses "fast flush" -/* service, or it has the same effect as \fBsendmail -q\fR. -/* This is implemented by connecting to the local SMTP server. -/* See \fBsmtpd\fR(8) for more information about the "fast flush" +/* \fIsite\fR. This option accepts only \fIsite\fR names that are +/* eligible for the "fast flush" service, and is implemented by +/* executing the \fBpostqueue\fR(1) command. +/* See \fBflush\fR(8) for more information about the "fast flush" /* service. /* .IP \fB-qS\fIsite\fR /* This command is not implemented. Use the slower \fBsendmail -q\fR @@ -195,12 +210,14 @@ /* List of domain or network patterns. When a remote host matches /* a pattern, increase the verbose logging level by the amount /* specified in the \fBdebug_peer_level\fR parameter. +/* .IP \fBdefault_verp_delimiters\fR +/* The VERP delimiter characters that are used when the \fB-V\fR +/* command line option is specified without delimiter characters. /* .IP \fBfast_flush_domains\fR /* List of domains that will receive "fast flush" service (default: all -/* domains that this system is willing to relay mail to). This greatly -/* improves the performance of the SMTP \fBETRN\fR request, and of the -/* \fBsendmail -qR\fR command. For domains not in the list, Postfix simply -/* attempts to deliver all queued mail. +/* domains that this system is willing to relay mail to). This list +/* specifies the domains that Postfix accepts in the SMTP \fBETRN\fR +/* request and in the \fBsendmail -qR\fR command. /* .IP \fBfork_attempts\fR /* Number of attempts to \fBfork\fR() a process before giving up. /* .IP \fBfork_delay\fR @@ -220,16 +237,17 @@ /* directory of Postfix daemons that run chrooted. /* .IP \fBqueue_run_delay\fR /* The time between successive scans of the deferred queue. +/* .IP \fBverp_delimiter_filter\fR +/* The characters that Postfix accepts as VERP delimiter characters. /* SEE ALSO /* pickup(8) mail pickup daemon /* postalias(1) maintain alias database -/* postdrop(1) privileged posting agent +/* postdrop(1) mail posting utility /* postfix(1) mail system control -/* postkick(1) kick a Postfix daemon +/* postqueue(1) mail queue control /* qmgr(8) queue manager -/* showq(8) list mail queue /* smtpd(8) SMTP server -/* flushd(8) fast flush service +/* flush(8) fast flush service /* syslogd(8) system logging /* LICENSE /* .ad @@ -257,6 +275,7 @@ #include <errno.h> #include <ctype.h> #include <stdarg.h> +#include <sysexits.h> /* Utility library. */ @@ -291,7 +310,7 @@ #include <tok822.h> #include <mail_flush.h> #include <mail_stream.h> -#include <smtp_stream.h> +#include <verp_sender.h> /* Application-specific. */ @@ -306,13 +325,6 @@ #define SM_MODE_FLUSHQ 6 /* user (stand-alone) mode */ /* - * Queue file name. Global, so that the cleanup routine can find it when - * called by the run-time error handler. - */ -static char *sendmail_path; -static void sendmail_cleanup(void); - - /* * Flag parade. */ #define SM_FLAG_AEOF (1<<0) /* archaic EOF */ @@ -320,6 +332,11 @@ static void sendmail_cleanup(void); #define SM_FLAG_DEFAULT (SM_FLAG_AEOF) /* + * VERP support. + */ +char *verp_delims; + + /* * Silly little macros (SLMs). */ #define STR vstring_str @@ -345,7 +362,6 @@ static void enqueue(const int flags, const char *sender, const char *full_name, char *postdrop_command; uid_t uid = getuid(); int status; - struct stat st; int naddr; /* @@ -370,31 +386,21 @@ static void enqueue(const int flags, const char *sender, const char *full_name, msg_warn("-f option specified malformed sender: %s", sender); } else { if ((sender = username()) == 0) - msg_fatal("unable to find out your login name"); + msg_fatal_status(EX_OSERR, "unable to find out your login name"); saved_sender = mystrdup(sender); } /* - * Open the queue file. Save the queue file name, so the run-time error - * handler can clean up in case of errors. - * - * If the queue is not world-writable, let the postdrop command open the - * queue file. + * Let the postdrop command open the queue file for us, and sanity check + * the content. XXX Make postdrop a manifest constant. */ - if (stat(MAIL_QUEUE_MAILDROP, &st) < 0) - msg_fatal("No maildrop directory %s: %m", MAIL_QUEUE_MAILDROP); - if (st.st_mode & S_IWOTH) { - handle = mail_stream_file(MAIL_QUEUE_MAILDROP, - MAIL_CLASS_PUBLIC, MAIL_SERVICE_PICKUP); - sendmail_path = mystrdup(VSTREAM_PATH(handle->stream)); - } else { - postdrop_command = concatenate(var_command_dir, "/postdrop", + errno = 0; + postdrop_command = concatenate(var_command_dir, "/postdrop -r", msg_verbose ? " -v" : (char *) 0, (char *) 0); - if ((handle = mail_stream_command(postdrop_command)) == 0) - msg_fatal("%s(%ld): unable to execute %s", - saved_sender, (long) uid, postdrop_command); - myfree(postdrop_command); - } + if ((handle = mail_stream_command(postdrop_command)) == 0) + msg_fatal_status(EX_UNAVAILABLE, "%s(%ld): unable to execute %s: %m", + saved_sender, (long) uid, postdrop_command); + myfree(postdrop_command); dst = handle->stream; /* @@ -414,6 +420,10 @@ static void enqueue(const int flags, const char *sender, const char *full_name, if (full_name || (full_name = fullname()) != 0) rec_fputs(dst, REC_TYPE_FULL, full_name); rec_fputs(dst, REC_TYPE_FROM, saved_sender); + if (verp_delims && *saved_sender == 0) + msg_fatal("-V option requires non-null sender address"); + if (verp_delims) + rec_fputs(dst, REC_TYPE_VERP, verp_delims); if (recipients) { for (cpp = recipients; *cpp != 0; cpp++) { tree = tok822_parse(*cpp); @@ -421,8 +431,9 @@ static void enqueue(const int flags, const char *sender, const char *full_name, if (tp->type == TOK822_ADDR) { tok822_internalize(buf, tp->head, TOK822_STR_DEFL); if (REC_PUT_BUF(dst, REC_TYPE_RCPT, buf) < 0) - msg_fatal("%s(%ld): error writing queue file: %m", - saved_sender, (long) uid); + msg_fatal_status(EX_TEMPFAIL, + "%s(%ld): error writing queue file: %m", + saved_sender, (long) uid); } } tok822_free_tree(tree); @@ -463,8 +474,9 @@ static void enqueue(const int flags, const char *sender, const char *full_name, if ((flags & SM_FLAG_AEOF) && VSTRING_LEN(buf) == 1 && *STR(buf) == '.') break; if (REC_PUT_BUF(dst, type, buf) < 0) - msg_fatal("%s(%ld): error writing queue file: %m", - saved_sender, (long) uid); + msg_fatal_status(EX_TEMPFAIL, + "%s(%ld): error writing queue file: %m", + saved_sender, (long) uid); } /* @@ -485,15 +497,13 @@ static void enqueue(const int flags, const char *sender, const char *full_name, * handler from removing the file. */ if (vstream_ferror(VSTREAM_IN)) - msg_fatal("%s(%ld): error reading input: %m", - saved_sender, (long) uid); - if ((status = mail_stream_finish(handle)) != 0) - msg_fatal("%s(%ld): %s", saved_sender, - (long) uid, cleanup_strerror(status)); - if (sendmail_path) { - myfree(sendmail_path); - sendmail_path = 0; - } + msg_fatal_status(EX_DATAERR, "%s(%ld): error reading input: %m", + saved_sender, (long) uid); + if ((status = mail_stream_finish(handle, (VSTRING *) 0)) != 0) + msg_fatal_status((status & CLEANUP_STAT_BAD) ? EX_SOFTWARE : + (status & CLEANUP_STAT_WRITE) ? EX_TEMPFAIL : + EX_UNAVAILABLE, "%s(%ld): %s", saved_sender, + (long) uid, cleanup_strerror(status)); /* * Cleanup. Not really necessary as we're about to exit, but good for @@ -503,168 +513,6 @@ static void enqueue(const int flags, const char *sender, const char *full_name, myfree(saved_sender); } -/* show_queue - show queue status */ - -static void show_queue(void) -{ - char buf[VSTREAM_BUFSIZE]; - VSTREAM *showq; - int n; - - /* - * Connect to the show queue service. Terminate silently when piping into - * a program that terminates early. - */ - signal(SIGPIPE, SIG_DFL); - if ((showq = mail_connect(MAIL_CLASS_PUBLIC, MAIL_SERVICE_SHOWQ, BLOCKING)) != 0) { - while ((n = vstream_fread(showq, buf, sizeof(buf))) > 0) - if (vstream_fwrite(VSTREAM_OUT, buf, n) != n - || vstream_fflush(VSTREAM_OUT) != 0) - msg_fatal("write error: %m"); - - if (vstream_fclose(showq)) - msg_warn("close: %m"); - } - - /* - * When the mail system is down, the superuser can still access the queue - * directly. Just run the showq program in stand-alone mode. - */ - else if (geteuid() == 0) { - ARGV *argv; - int stat; - - msg_warn("Mail system is down -- accessing queue directly"); - argv = argv_alloc(6); - argv_add(argv, MAIL_SERVICE_SHOWQ, "-c", "-u", "-S", (char *) 0); - for (n = 0; n < msg_verbose; n++) - argv_add(argv, "-v", (char *) 0); - argv_terminate(argv); - stat = mail_run_foreground(var_daemon_dir, argv->argv); - argv_free(argv); - } - - /* - * When the mail system is down, unprivileged users are stuck, because by - * design the mail system contains no set_uid programs. The only way for - * an unprivileged user to cross protection boundaries is to talk to the - * showq daemon. - */ - else { - msg_fatal("Queue report unavailable - mail system is down"); - } -} - -/* flush_queue - force delivery */ - -static void flush_queue(void) -{ - - /* - * Trigger the flush queue service. - */ - if (mail_flush_deferred() < 0) - msg_warn("Cannot flush mail queue - mail system is down"); -} - -/* chat - send command and examine reply */ - -static void chat(VSTREAM *fp, VSTRING *buf, const char *fmt,...) -{ - va_list ap; - - smtp_get(buf, fp, var_line_limit); - if (STR(buf)[0] != '2') - msg_fatal("server rejected request: %s", STR(buf)); - - if (msg_verbose) - msg_info("<<< %s", STR(buf)); - - if (msg_verbose) { - va_start(ap, fmt); - vstring_vsprintf(buf, fmt, ap); - va_end(ap); - msg_info(">>> %s", STR(buf)); - } - va_start(ap, fmt); - smtp_vprintf(fp, fmt, ap); - va_end(ap); -} - -/* flush_site - flush mail for site */ - -static void flush_site(const char *site) -{ - VSTRING *buf = vstring_alloc(10); - VSTREAM *fp; - int sock; - int status; - - /* - * Make connection to the local SMTP server. Translate "connection - * refused" into something less misleading. - */ - vstring_sprintf(buf, "%s:smtp", var_myhostname); - if ((sock = inet_connect(STR(buf), BLOCKING, 10)) < 0) { - if (errno == ECONNREFUSED) - msg_fatal("mail service at %s is down", var_myhostname); - msg_fatal("connect to mail service at %s: %m", var_myhostname); - } - fp = vstream_fdopen(sock, O_RDWR); - - /* - * Prepare for trouble. - */ - vstream_control(fp, VSTREAM_CTL_EXCEPT, VSTREAM_CTL_END); - status = vstream_setjmp(fp); - if (status != 0) { - switch (status) { - case SMTP_ERR_EOF: - msg_fatal("server at %s aborted connection", var_myhostname); - case SMTP_ERR_TIME: - msg_fatal("timeout while talking to server at %s", var_myhostname); - } - } - smtp_timeout_setup(fp, 60); - - /* - * Chat with the SMTP server. - */ - chat(fp, buf, "helo %s", var_myhostname); - chat(fp, buf, "etrn %s", site); - chat(fp, buf, "quit"); - - vstream_fclose(fp); - vstring_free(buf); -} - -/* sendmail_cleanup - callback for the runtime error handler */ - -static void sendmail_cleanup(void) -{ - - /* - * We're possibly running from a signal handler, so we should not be - * doing complicated things such as memory of buffer management, but if - * for some reason we can't cleanup it is even worse to just die quietly. - */ - if (sendmail_path) { - if (remove(sendmail_path)) - msg_warn("sendmail_cleanup: remove %s: %m", sendmail_path); - else if (msg_verbose) - msg_info("remove %s", sendmail_path); - sendmail_path = 0; - } -} - -/* sendmail_sig - catch signal and clean up */ - -static void sendmail_sig(int sig) -{ - sendmail_cleanup(); - exit(sig); -} - /* main - the main program */ int main(int argc, char **argv) @@ -697,7 +545,7 @@ int main(int argc, char **argv) for (fd = 0; fd < 3; fd++) if (fstat(fd, &st) == -1 && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) - msg_fatal("open /dev/null: %m"); + msg_fatal_status(EX_UNAVAILABLE, "open /dev/null: %m"); /* * The CDE desktop calendar manager leaks a parent file descriptor into @@ -745,15 +593,16 @@ int main(int argc, char **argv) */ mail_conf_read(); if (chdir(var_queue_dir)) - msg_fatal("chdir %s: %m", var_queue_dir); + msg_fatal_status(EX_UNAVAILABLE, "chdir %s: %m", var_queue_dir); - signal(SIGPIPE, SIG_IGN); + /* + * Stop run-away process accidents by limiting the queue file size. This + * is not a defense against DOS attack. + */ + if (var_message_limit > 0 && get_file_limit() > var_message_limit) + set_file_limit((off_t) var_message_limit); - signal(SIGHUP, sendmail_sig); - signal(SIGINT, sendmail_sig); - signal(SIGQUIT, sendmail_sig); - signal(SIGTERM, sendmail_sig); - msg_cleanup(sendmail_cleanup); + signal(SIGPIPE, SIG_IGN); /* * Optionally start the debugger on ourself. This must be done after @@ -794,7 +643,12 @@ int main(int argc, char **argv) optind++; continue; } - if ((c = GETOPT(argc, argv, "B:C:F:GIN:R:UX:b:ce:f:h:imno:p:r:q:tvx")) <= 0) + if (strcmp(argv[OPTIND], "-V") == 0) { + verp_delims = var_verp_delims; + optind++; + continue; + } + if ((c = GETOPT(argc, argv, "B:C:F:GIL:N:R:UV:X:b:ce:f:h:imno:p:r:q:tvx")) <= 0) break; switch (c) { default: @@ -802,25 +656,23 @@ int main(int argc, char **argv) msg_info("-%c option ignored", c); break; case 'n': - msg_fatal("-%c option not supported", c); - case 'B': /* body type */ - break; + msg_fatal_status(EX_USAGE, "-%c option not supported", c); case 'F': /* full name */ full_name = optarg; break; - case 'G': /* gateway submission */ - break; case 'I': /* newaliases */ mode = SM_MODE_NEWALIAS; break; - case 'N': /* DSN */ - break; - case 'R': /* DSN */ + case 'V': /* VERP */ + if (verp_delims_verify(optarg) != 0) + msg_fatal_status(EX_USAGE, "-V requires two characters from %s", + var_verp_filter); + verp_delims = optarg; break; case 'b': switch (*optarg) { default: - msg_fatal("unsupported: -%c%c", c, *optarg); + msg_fatal_status(EX_USAGE, "unsupported: -%c%c", c, *optarg); case 'd': /* daemon mode */ if (mode == SM_MODE_FLUSHQ) msg_warn("ignoring -q option in daemon mode"); @@ -854,7 +706,7 @@ int main(int argc, char **argv) break; case 'A': if (optarg[1] == 0) - msg_fatal("-oA requires pathname"); + msg_fatal_status(EX_USAGE, "-oA requires pathname"); myfree(var_alias_db_map); var_alias_db_map = mystrdup(optarg + 1); set_mail_conf_str(VAR_ALIAS_DB_MAP, var_alias_db_map); @@ -881,8 +733,11 @@ int main(int argc, char **argv) } } else if (optarg[0] == 'R') { site_to_flush = optarg + 1; + if (*site_to_flush == 0) + msg_fatal("specify: -qRsitename"); } else { - msg_fatal("-q%c is not implemented", optarg[0]); + msg_fatal_status(EX_USAGE, "-q%c is not implemented", + optarg[0]); } break; case 't': @@ -892,7 +747,7 @@ int main(int argc, char **argv) msg_verbose++; break; case '?': - msg_fatal("usage: %s [options]", argv[0]); + msg_fatal_status(EX_USAGE, "usage: %s [options]", argv[0]); } } @@ -909,29 +764,47 @@ int main(int argc, char **argv) msg_fatal("cannot handle command-line recipients with -t"); /* - * Start processing. Some modes are implemented internally (enqueue - * message), or as network clients (show queue, flush queue); everything - * else is delegated to external commands. + * Start processing. Everything is delegated to external commands. */ switch (mode) { default: msg_panic("unknown operation mode: %d", mode); /* NOTREACHED */ case SM_MODE_ENQUEUE: - if (site_to_flush) - flush_site(site_to_flush); - else + if (site_to_flush == 0) { enqueue(flags, sender, full_name, argv + OPTIND); - exit(0); + exit(0); + } + if (argv[OPTIND]) + msg_fatal("flush site requires no recipient"); + ext_argv = argv_alloc(2); + argv_add(ext_argv, "postqueue", "-s", site_to_flush, (char *) 0); + for (n = 0; n < msg_verbose; n++) + argv_add(ext_argv, "-v", (char *) 0); + argv_terminate(ext_argv); + mail_run_replace(var_command_dir, ext_argv->argv); + /* NOTREACHED */ break; case SM_MODE_MAILQ: - show_queue(); - exit(0); - break; + if (argv[OPTIND]) + msg_fatal("display queue mode requires no recipient"); + ext_argv = argv_alloc(2); + argv_add(ext_argv, "postqueue", "-p", (char *) 0); + for (n = 0; n < msg_verbose; n++) + argv_add(ext_argv, "-v", (char *) 0); + argv_terminate(ext_argv); + mail_run_replace(var_command_dir, ext_argv->argv); + /* NOTREACHED */ case SM_MODE_FLUSHQ: - flush_queue(); - exit(0); - break; + if (argv[OPTIND]) + msg_fatal("flush queue mode requires no recipient"); + ext_argv = argv_alloc(2); + argv_add(ext_argv, "postqueue", "-f", (char *) 0); + for (n = 0; n < msg_verbose; n++) + argv_add(ext_argv, "-v", (char *) 0); + argv_terminate(ext_argv); + mail_run_replace(var_command_dir, ext_argv->argv); + /* NOTREACHED */ case SM_MODE_DAEMON: if (argv[OPTIND]) msg_fatal("daemon mode requires no recipient"); @@ -955,6 +828,7 @@ int main(int argc, char **argv) for (n = 0; n < msg_verbose; n++) argv_add(ext_argv, "-v", (char *) 0); argv_split_append(ext_argv, var_alias_db_map, ", \t\r\n"); + argv_terminate(ext_argv); mail_run_replace(var_command_dir, ext_argv->argv); /* NOTREACHED */ case SM_MODE_USER: diff --git a/gnu/dist/postfix/src/showq/Makefile.in b/gnu/dist/postfix/src/showq/Makefile.in index 23d15c420d5..5c714ef1145 100644 --- a/gnu/dist/postfix/src/showq/Makefile.in +++ b/gnu/dist/postfix/src/showq/Makefile.in @@ -68,6 +68,7 @@ showq.o: ../../include/mail_queue.h showq.o: ../../include/mail_open_ok.h showq.o: ../../include/mail_proto.h showq.o: ../../include/iostuff.h +showq.o: ../../include/attr.h showq.o: ../../include/mail_date.h showq.o: ../../include/mail_params.h showq.o: ../../include/mail_scan_dir.h diff --git a/gnu/dist/postfix/src/showq/showq.c b/gnu/dist/postfix/src/showq/showq.c index 55cab747a91..97147adeae8 100644 --- a/gnu/dist/postfix/src/showq/showq.c +++ b/gnu/dist/postfix/src/showq/showq.c @@ -92,6 +92,7 @@ int var_dup_filter_limit; #define STRING_FORMAT "%-10s %8s %-20s %s\n" #define DATA_FORMAT "%-10s%c%8ld %20.20s %s\n" +#define DROP_FORMAT "%-10s%c%8ld %20.20s (maildrop queue, sender UID %u)\n" static void showq_reasons(VSTREAM *, BOUNCE_LOG *, HTABLE *); @@ -106,6 +107,7 @@ static void showq_report(VSTREAM *client, char *queue, char *id, BOUNCE_LOG *logfile; HTABLE *dup_filter = 0; char status = (strcmp(queue, MAIL_QUEUE_ACTIVE) == 0 ? '*' : ' '); + long offset; while (!vstream_ferror(client) && (rec_type = rec_get(qfile, buf, 0)) > 0) { start = vstring_str(buf); @@ -114,7 +116,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id, arrival_time = atol(start); break; case REC_TYPE_SIZE: - msg_size = atol(start); + if ((msg_size = atol(start)) <= 0) + msg_size = size; break; case REC_TYPE_FROM: if (*start == 0) @@ -132,7 +135,8 @@ static void showq_report(VSTREAM *client, char *queue, char *id, "", "", "", printable(start, '?')); break; case REC_TYPE_MESG: - if (vstream_fseek(qfile, atol(start), SEEK_SET) < 0) + if ((offset = atol(start)) > 0 + && vstream_fseek(qfile, offset, SEEK_SET) < 0) msg_fatal("seek file %s: %m", VSTREAM_PATH(qfile)); break; case REC_TYPE_END: @@ -203,7 +207,6 @@ static void showq_reasons(VSTREAM *client, BOUNCE_LOG *bp, HTABLE *dup_filter) static void showq_service(VSTREAM *client, char *unused_service, char **argv) { - char **queue; VSTREAM *qfile; const char *path; int status; @@ -211,11 +214,17 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv) int file_count; unsigned long queue_size = 0; struct stat st; - char *queue_names[] = { /* XXX configurable */ - MAIL_QUEUE_INCOMING, - MAIL_QUEUE_ACTIVE, - MAIL_QUEUE_DEFERRED, - /* No maildrop until we can disable recursive scans. */ + struct queue_info { + char *name; /* queue name */ + char *(*scan_next) (SCAN_DIR *); /* flat or recursive */ + }; + struct queue_info *qp; + + static struct queue_info queue_info[] = { + MAIL_QUEUE_MAILDROP, scan_dir_next, + MAIL_QUEUE_INCOMING, mail_scan_dir_next, + MAIL_QUEUE_ACTIVE, mail_scan_dir_next, + MAIL_QUEUE_DEFERRED, mail_scan_dir_next, 0, }; @@ -231,11 +240,11 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv) * mis-configured, and force backoff by raising a fatal error. */ file_count = 0; - for (queue = queue_names; *queue != 0; queue++) { - SCAN_DIR *scan = scan_dir_open(*queue); + for (qp = queue_info; qp->name != 0; qp++) { + SCAN_DIR *scan = scan_dir_open(qp->name); char *saved_id = 0; - while ((id = mail_scan_dir_next(scan)) != 0) { + while ((id = qp->scan_next(scan)) != 0) { /* * XXX I have seen showq loop on the same queue id. That would be @@ -244,13 +253,13 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv) */ if (saved_id) { if (strcmp(saved_id, id) == 0) { - msg_warn("readdir loop on queue %s id %s", *queue, id); + msg_warn("readdir loop on queue %s id %s", qp->name, id); break; } myfree(saved_id); } saved_id = mystrdup(id); - status = mail_open_ok(*queue, id, &st, &path); + status = mail_open_ok(qp->name, id, &st, &path); if (status == MAIL_OPEN_YES) { if (file_count == 0) vstream_fprintf(client, STRING_FORMAT, @@ -259,19 +268,19 @@ static void showq_service(VSTREAM *client, char *unused_service, char **argv) "-Sender/Recipient-------"); else vstream_fprintf(client, "\n"); - if ((qfile = mail_queue_open(*queue, id, O_RDONLY, 0)) != 0) { + if ((qfile = mail_queue_open(qp->name, id, O_RDONLY, 0)) != 0) { queue_size += st.st_size; - showq_report(client, *queue, id, qfile, (long) st.st_size); + showq_report(client, qp->name, id, qfile, (long) st.st_size); if (vstream_fclose(qfile)) - msg_warn("close file %s %s: %m", *queue, id); - } else if (strcmp(*queue, MAIL_QUEUE_MAILDROP) == 0) { + msg_warn("close file %s %s: %m", qp->name, id); + } else if (strcmp(qp->name, MAIL_QUEUE_MAILDROP) == 0) { queue_size += st.st_size; - vstream_fprintf(client, DATA_FORMAT, id, ' ', + vstream_fprintf(client, DROP_FORMAT, id, ' ', (long) st.st_size, asctime(localtime(&st.st_mtime)), - "(to be determined)"); + (unsigned) st.st_uid); } else if (errno != ENOENT) - msg_fatal("open %s %s: %m", *queue, id); + msg_fatal("open %s %s: %m", qp->name, id); file_count++; vstream_fflush(client); } diff --git a/gnu/dist/postfix/src/smtp/Makefile.in b/gnu/dist/postfix/src/smtp/Makefile.in index ed46099b665..035cd5acab4 100644 --- a/gnu/dist/postfix/src/smtp/Makefile.in +++ b/gnu/dist/postfix/src/smtp/Makefile.in @@ -80,6 +80,7 @@ smtp.o: ../../include/mail_error.h smtp.o: ../../include/deliver_pass.h smtp.o: ../../include/mail_proto.h smtp.o: ../../include/iostuff.h +smtp.o: ../../include/attr.h smtp.o: ../../include/mail_server.h smtp.o: smtp.h smtp.o: smtp_sasl.h @@ -91,6 +92,7 @@ smtp_addr.o: ../../include/vbuf.h smtp_addr.o: ../../include/mymalloc.h smtp_addr.o: ../../include/inet_addr_list.h smtp_addr.o: ../../include/stringops.h +smtp_addr.o: ../../include/myrand.h smtp_addr.o: ../../include/mail_params.h smtp_addr.o: ../../include/own_inet_addr.h smtp_addr.o: ../../include/dns.h @@ -149,6 +151,7 @@ smtp_proto.o: ../../include/vstream.h 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 @@ -177,6 +180,8 @@ smtp_sasl_glue.o: ../../include/split_at.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 diff --git a/gnu/dist/postfix/src/smtp/smtp.c b/gnu/dist/postfix/src/smtp/smtp.c index 477e33b7197..9c61d89dbba 100644 --- a/gnu/dist/postfix/src/smtp/smtp.c +++ b/gnu/dist/postfix/src/smtp/smtp.c @@ -41,6 +41,7 @@ /* RFC 1870 (Message Size Declaration) /* RFC 2197 (Pipelining) /* RFC 2554 (AUTH command) +/* RFC 2821 (SMTP protocol) /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* Corrupted message files are marked so that the queue manager can @@ -94,14 +95,23 @@ /* Always send EHLO at the start of a connection. /* .IP \fBsmtp_never_send_ehlo\fR /* Never send EHLO at the start of a connection. +/* .IP \fBsmtp_bind_address\fR +/* Numerical source network address to bind to when making a connection. +/* .IP \fBsmtp_break_lines\fR +/* Break lines > \fB$line_length_limit\fR into multiple shorter lines. +/* Some SMTP servers misbehave on long lines. /* .IP \fBsmtp_skip_4xx_greeting\fR /* Skip servers that greet us with a 4xx status code. /* .IP \fBsmtp_skip_5xx_greeting\fR /* Skip servers that greet us with a 5xx status code. /* .IP \fBsmtp_skip_quit_response\fR /* Do not wait for the server response after sending QUIT. -/* .IP \fBsmtp_bind_address\fR -/* Numerical network address to bind to when making a connection. +/* .IP \fBsmtp_pix_workaround_delay_time\fR +/* The time to pause before sending .<CR><LF>, while working +/* around the CISCO PIX firewall <CR><LF>.<CR><LF> bug. +/* .IP \fBsmtp_pix_workaround_threshold_time\fR +/* The time a message must be queued before the CISCO PIX firewall +/* <CR><LF>.<CR><LF> bug workaround is turned on. /* .SH "Authentication controls" /* .IP \fBsmtp_enable_sasl_auth\fR /* Enable per-session authentication as per RFC 2554 (SASL). @@ -234,8 +244,6 @@ int var_smtp_data1_tmout; int var_smtp_data2_tmout; int var_smtp_quit_tmout; char *var_inet_interfaces; -char *var_debug_peer_list; -int var_debug_peer_level; char *var_notify_classes; int var_smtp_skip_4xx_greeting; int var_smtp_skip_5xx_greeting; @@ -250,6 +258,10 @@ char *var_smtp_sasl_opts; char *var_smtp_sasl_passwd; bool var_smtp_sasl_enable; char *var_smtp_bind_addr; +bool var_smtp_rand_addr; +bool var_smtp_break_lines; +int var_smtp_pix_thresh; +int var_smtp_pix_delay; /* * Global variables. smtp_errno is set by the address lookup routines and by @@ -394,7 +406,6 @@ static void pre_exit(void) int main(int argc, char **argv) { static CONFIG_STR_TABLE str_table[] = { - VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0, VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0, VAR_FALLBACK_RELAY, DEF_FALLBACK_RELAY, &var_fallback_relay, 0, 0, VAR_BESTMX_TRANSP, DEF_BESTMX_TRANSP, &var_bestmx_transp, 0, 0, @@ -413,10 +424,11 @@ int main(int argc, char **argv) VAR_SMTP_DATA1_TMOUT, DEF_SMTP_DATA1_TMOUT, &var_smtp_data1_tmout, 1, 0, VAR_SMTP_DATA2_TMOUT, DEF_SMTP_DATA2_TMOUT, &var_smtp_data2_tmout, 1, 0, VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0, + VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0, + VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0, 0, }; static CONFIG_INT_TABLE int_table[] = { - VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0, 0, }; static CONFIG_BOOL_TABLE bool_table[] = { @@ -427,6 +439,8 @@ int main(int argc, char **argv) VAR_SMTP_ALWAYS_EHLO, DEF_SMTP_ALWAYS_EHLO, &var_smtp_always_ehlo, VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo, VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable, + VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr, + VAR_SMTP_BREAK_LINES, DEF_SMTP_BREAK_LINES, &var_smtp_break_lines, 0, }; diff --git a/gnu/dist/postfix/src/smtp/smtp.h b/gnu/dist/postfix/src/smtp/smtp.h index 8c6dd5b0636..81990e8a2f5 100644 --- a/gnu/dist/postfix/src/smtp/smtp.h +++ b/gnu/dist/postfix/src/smtp/smtp.h @@ -52,6 +52,7 @@ typedef struct SMTP_STATE { VSTRING *sasl_decoded; /* decoding buffer */ sasl_callback_t *sasl_callbacks; /* stateful callbacks */ #endif + off_t size_limit; /* server limit or unknown */ } SMTP_STATE; #define SMTP_FEATURE_ESMTP (1<<0) @@ -60,6 +61,7 @@ typedef struct SMTP_STATE { #define SMTP_FEATURE_SIZE (1<<3) #define SMTP_FEATURE_STARTTLS (1<<4) #define SMTP_FEATURE_AUTH (1<<5) +#define SMTP_FEATURE_MAYBEPIX (1<<6) /* PIX smtp fixup mode */ /* * smtp.c diff --git a/gnu/dist/postfix/src/smtp/smtp_chat.c b/gnu/dist/postfix/src/smtp/smtp_chat.c index 62c0de64f3f..d33a90e4e04 100644 --- a/gnu/dist/postfix/src/smtp/smtp_chat.c +++ b/gnu/dist/postfix/src/smtp/smtp_chat.c @@ -252,7 +252,7 @@ void smtp_chat_notify(SMTP_STATE *state) notice = post_mail_fopen_nowait(mail_addr_double_bounce(), var_error_rcpt, - NULL_CLEANUP_FLAGS, "NOTICE"); + NULL_CLEANUP_FLAGS); if (notice == 0) { msg_warn("postmaster notify: %m"); return; diff --git a/gnu/dist/postfix/src/smtp/smtp_proto.c b/gnu/dist/postfix/src/smtp/smtp_proto.c index a7871312379..04e0db3fcde 100644 --- a/gnu/dist/postfix/src/smtp/smtp_proto.c +++ b/gnu/dist/postfix/src/smtp/smtp_proto.c @@ -82,6 +82,7 @@ #include <vstring_vstream.h> #include <stringops.h> #include <mymalloc.h> +#include <iostuff.h> /* Global library. */ @@ -174,6 +175,14 @@ int smtp_helo(SMTP_STATE *state) session->namaddr, translit(resp->str, "\n", " "))); /* + * XXX Some PIX firewall versions require flush before ".<CR><LF>" so it + * 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) + state->features |= SMTP_FEATURE_MAYBEPIX; + + /* * See if we are talking to ourself. This should not be possible with the * way we implement DNS lookups. However, people are known to sometimes * screw up the naming service. And, mailer loops are still possible when @@ -188,9 +197,9 @@ int smtp_helo(SMTP_STATE *state) } 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; /* @@ -217,21 +226,30 @@ int smtp_helo(SMTP_STATE *state) * overflow detection, ignore the message size limit advertised by the * SMTP server. Otherwise, we might do the wrong thing when the server * advertises a really huge message size limit. + * + * XXX Allow for "code (SP|-) ehlo-keyword (SP|=) ehlo-param...", because + * MicroSoft implemented AUTH based on an old draft. */ lines = resp->str; while ((words = mystrtok(&lines, "\n")) != 0) { - if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) { + if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) { if (strcasecmp(word, "8BITMIME") == 0) state->features |= SMTP_FEATURE_8BITMIME; else if (strcasecmp(word, "PIPELINING") == 0) state->features |= SMTP_FEATURE_PIPELINING; - else if (strcasecmp(word, "SIZE") == 0) + else if (strcasecmp(word, "SIZE") == 0) { state->features |= SMTP_FEATURE_SIZE; + if ((word = mystrtok(&words, " \t")) != 0) { + if (!alldig(word)) + msg_warn("bad size limit \"%s\" in EHLO reply from %s", + word, session->namaddr); + else + state->size_limit = off_cvt_string(word); + } + } #ifdef USE_SASL_AUTH else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0) smtp_sasl_helo_auth(state, words); - else if (var_smtp_sasl_enable && strncasecmp(word, "AUTH=", 5) == 0) - smtp_sasl_helo_auth(state, word + 5); #endif else if (strcasecmp(word, var_myhostname) == 0) { msg_warn("host %s replied to HELO/EHLO with my own hostname %s", @@ -243,7 +261,8 @@ int smtp_helo(SMTP_STATE *state) } } if (msg_verbose) - msg_info("server features: 0x%x", state->features); + msg_info("server features: 0x%x size %.0f", + state->features, (double) state->size_limit); #ifdef USE_SASL_AUTH if (var_smtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH)) @@ -302,6 +321,19 @@ int smtp_xfer(SMTP_STATE *state) (recv_state <= SMTP_STATE_DOT) /* + * See if we should even try to send this message at all. This code sits + * here rather than in the EHLO processing code, because of future SMTP + * connection caching. + */ + if (state->size_limit > 0 && state->size_limit < request->data_size) { + smtp_mesg_fail(state, 552, + "message size %lu exceeds size limit %.0f of server %s", + request->data_size, (double) state->size_limit, + session->namaddr); + RETURN(0); + } + + /* * We use SMTP command pipelining if the server said it supported it. * Since we use blocking I/O, RFC 2197 says that we should inspect the * TCP window size and not send more than this amount of information. @@ -487,9 +519,19 @@ int smtp_xfer(SMTP_STATE *state) * rejected, ignore RCPT TO responses: all recipients are * dead already. When all recipients are rejected the * receiver may apply a course correction. + * + * XXX 2821: Section 4.5.3.1 says that a 552 RCPT TO reply + * must be treated as if the server replied with 452. + * However, this causes "too much mail data" to be + * treated as a recoverable error, which is wrong. I'll + * stick with RFC 821. */ case SMTP_STATE_RCPT: if (!mail_from_rejected) { +#ifdef notdef + if (resp->code == 552) + resp->code = 452; +#endif if (resp->code / 100 == 2) { ++nrcpt; } else { @@ -623,6 +665,8 @@ int smtp_xfer(SMTP_STATE *state) if (prev_type != REC_TYPE_CONT) if (vstring_str(state->scratch)[0] == '.') smtp_fputc('.', session->stream); + if (var_smtp_break_lines) + rec_type = REC_TYPE_NORM; if (rec_type == REC_TYPE_CONT) smtp_fwrite(vstring_str(state->scratch), VSTRING_LEN(state->scratch), @@ -636,6 +680,14 @@ int smtp_xfer(SMTP_STATE *state) if (prev_type == REC_TYPE_CONT) /* missing newline at end */ smtp_fputs("", 0, session->stream); + if ((state->features & SMTP_FEATURE_MAYBEPIX) != 0 + && request->arrival_time < vstream_ftime(session->stream) + - var_smtp_pix_thresh) { + msg_info("%s: enabling PIX <CRLF>.<CRLF> workaround for %s", + request->queue_id, session->namaddr); + vstream_fflush(session->stream);/* hurts performance */ + sleep(var_smtp_pix_delay); /* not to mention this */ + } if (vstream_ferror(state->src)) msg_fatal("queue file read error"); if (rec_type != REC_TYPE_XTRA) diff --git a/gnu/dist/postfix/src/smtp/smtp_sasl_glue.c b/gnu/dist/postfix/src/smtp/smtp_sasl_glue.c index 6336e2e5e48..0a4e28fe313 100644 --- a/gnu/dist/postfix/src/smtp/smtp_sasl_glue.c +++ b/gnu/dist/postfix/src/smtp/smtp_sasl_glue.c @@ -139,11 +139,11 @@ static int smtp_sasl_log(void *unused_context, int priority, switch (priority) { case SASL_LOG_ERR: case SASL_LOG_WARNING: - msg_warn("%s", message); + msg_warn("SASL authentication problem: %s", message); break; case SASL_LOG_INFO: if (msg_verbose) - msg_info("%s", message); + msg_info("SASL authentication info: %s", message); break; } return (SASL_OK); diff --git a/gnu/dist/postfix/src/smtp/smtp_sasl_proto.c b/gnu/dist/postfix/src/smtp/smtp_sasl_proto.c index f3818236520..97c2592c02e 100644 --- a/gnu/dist/postfix/src/smtp/smtp_sasl_proto.c +++ b/gnu/dist/postfix/src/smtp/smtp_sasl_proto.c @@ -52,6 +52,10 @@ /* System library. */ #include <sys_defs.h> +#include <string.h> +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif /* Utility library. */ @@ -79,6 +83,8 @@ void smtp_sasl_helo_auth(SMTP_STATE *state, const char *words) * then pretend that the server doesn't support SASL authentication. */ if (state->sasl_mechanism_list) { + if (strcasecmp(state->sasl_mechanism_list, words) == 0) + return; myfree(state->sasl_mechanism_list); msg_warn("%s offered AUTH option multiple times", state->session->namaddr); diff --git a/gnu/dist/postfix/src/smtp/smtp_state.c b/gnu/dist/postfix/src/smtp/smtp_state.c index 790bdfa6bca..2c4cad35c49 100644 --- a/gnu/dist/postfix/src/smtp/smtp_state.c +++ b/gnu/dist/postfix/src/smtp/smtp_state.c @@ -68,6 +68,7 @@ SMTP_STATE *smtp_state_alloc(void) #ifdef USE_SASL_AUTH smtp_sasl_connect(state); #endif + state->size_limit = 0; return (state); } diff --git a/gnu/dist/postfix/src/smtpd/Makefile.in b/gnu/dist/postfix/src/smtpd/Makefile.in index aebfcaeac19..8668041980e 100644 --- a/gnu/dist/postfix/src/smtpd/Makefile.in +++ b/gnu/dist/postfix/src/smtpd/Makefile.in @@ -70,19 +70,19 @@ depend: $(MAKES) tests: smtpd_check_test smtpd_check_test2 smtpd_acl_test smtpd_token_test smtpd_check_test: smtpd_check smtpd_check.in smtpd_check.ref - ../postmap/postmap smtpd_check_access + ../postmap/postmap hash:smtpd_check_access ./smtpd_check <smtpd_check.in >smtpd_check.tmp 2>&1 diff smtpd_check.ref smtpd_check.tmp rm -f smtpd_check.tmp smtpd_check_access.* smtpd_check_test2: smtpd_check smtpd_check.in2 smtpd_check.ref2 - ../postmap/postmap smtpd_check_access + ../postmap/postmap hash:smtpd_check_access ./smtpd_check <smtpd_check.in2 >smtpd_check.tmp 2>&1 diff smtpd_check.ref2 smtpd_check.tmp rm -f smtpd_check.tmp smtpd_check_access.* smtpd_acl_test: smtpd_check smtpd_acl.in smtpd_acl.ref - ../postmap/postmap smtpd_check_access + ../postmap/postmap hash:smtpd_check_access ./smtpd_check <smtpd_acl.in >smtpd_check.tmp 2>&1 diff smtpd_acl.ref smtpd_check.tmp rm -f smtpd_check.tmp smtpd_check_access.* @@ -113,6 +113,7 @@ smtpd.o: ../../include/record.h smtpd.o: ../../include/rec_type.h smtpd.o: ../../include/mail_proto.h smtpd.o: ../../include/iostuff.h +smtpd.o: ../../include/attr.h smtpd.o: ../../include/cleanup_user.h smtpd.o: ../../include/mail_date.h smtpd.o: ../../include/mail_conf.h @@ -125,6 +126,10 @@ smtpd.o: ../../include/mail_stream.h smtpd.o: ../../include/mail_queue.h smtpd.o: ../../include/tok822.h smtpd.o: ../../include/resolve_clnt.h +smtpd.o: ../../include/verp_sender.h +smtpd.o: ../../include/string_list.h +smtpd.o: ../../include/match_list.h +smtpd.o: ../../include/match_ops.h smtpd.o: ../../include/mail_server.h smtpd.o: smtpd_token.h smtpd.o: smtpd.h @@ -147,6 +152,7 @@ smtpd_chat.o: ../../include/record.h smtpd_chat.o: ../../include/rec_type.h smtpd_chat.o: ../../include/mail_proto.h smtpd_chat.o: ../../include/iostuff.h +smtpd_chat.o: ../../include/attr.h smtpd_chat.o: ../../include/mail_params.h smtpd_chat.o: ../../include/mail_addr.h smtpd_chat.o: ../../include/post_mail.h @@ -173,6 +179,8 @@ smtpd_check.o: ../../include/htable.h 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 @@ -184,6 +192,8 @@ smtpd_check.o: ../../include/own_inet_addr.h smtpd_check.o: ../../include/mail_conf.h smtpd_check.o: ../../include/maps.h smtpd_check.o: ../../include/mail_addr_find.h +smtpd_check.o: ../../include/match_parent_style.h +smtpd_check.o: ../../include/split_addr.h smtpd_check.o: smtpd.h smtpd_check.o: ../../include/mail_stream.h smtpd_check.o: smtpd_sasl_glue.h @@ -205,6 +215,8 @@ smtpd_sasl_glue.o: ../../include/sys_defs.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 @@ -225,6 +237,7 @@ smtpd_sasl_proto.o: ../../include/mail_proto.h smtpd_sasl_proto.o: ../../include/vstream.h smtpd_sasl_proto.o: ../../include/vbuf.h smtpd_sasl_proto.o: ../../include/iostuff.h +smtpd_sasl_proto.o: ../../include/attr.h smtpd_sasl_proto.o: ../../include/mail_error.h smtpd_sasl_proto.o: ../../include/name_mask.h smtpd_sasl_proto.o: smtpd.h diff --git a/gnu/dist/postfix/src/smtpd/smtpd.h b/gnu/dist/postfix/src/smtpd/smtpd.h index 29fb3d2d743..20386ad73fc 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd.h +++ b/gnu/dist/postfix/src/smtpd/smtpd.h @@ -76,6 +76,7 @@ typedef struct SMTPD_STATE { VSTRING *sasl_encoded; VSTRING *sasl_decoded; #endif + int warn_if_reject; } SMTPD_STATE; extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *); diff --git a/gnu/dist/postfix/src/smtpd/smtpd_acl.in b/gnu/dist/postfix/src/smtpd/smtpd_acl.in index e633c48d561..99955409f73 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_acl.in +++ b/gnu/dist/postfix/src/smtpd/smtpd_acl.in @@ -4,6 +4,7 @@ smtpd_delay_reject 0 mynetworks 127.0.0.0/8,168.100.189.0/28 relay_domains porcupine.org +smtpd_null_access_lookup_key <> # # Test check_domain_access() # @@ -105,3 +106,7 @@ rcpt ok@ok.domain rcpt anyone@ok.domain # Expect: OK rcpt bad-sender@ok.domain +# +# check_sender_access specific +# +mail <> diff --git a/gnu/dist/postfix/src/smtpd/smtpd_acl.ref b/gnu/dist/postfix/src/smtpd/smtpd_acl.ref index 34e35186627..294891fd0c4 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_acl.ref +++ b/gnu/dist/postfix/src/smtpd/smtpd_acl.ref @@ -7,6 +7,8 @@ OK OK >>> relay_domains porcupine.org OK +>>> smtpd_null_access_lookup_key <> +OK >>> # >>> # Test check_domain_access() >>> # @@ -162,3 +164,9 @@ OK >>> # Expect: OK >>> rcpt bad-sender@ok.domain OK +>>> # +>>> # check_sender_access specific +>>> # +>>> mail <> +./smtpd_check: reject: MAIL from bar.duno.com[44.33.44.33]: 550 <>: Sender address rejected: Go away postmaster; from=<> +550 <>: Sender address rejected: Go away postmaster diff --git a/gnu/dist/postfix/src/smtpd/smtpd_chat.c b/gnu/dist/postfix/src/smtpd/smtpd_chat.c index 2d1f8772672..b9be60015cd 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_chat.c +++ b/gnu/dist/postfix/src/smtpd/smtpd_chat.c @@ -107,6 +107,9 @@ static void smtp_chat_append(SMTPD_STATE *state, char *direction) { char *line; + if (state->notify_mask == 0) + return; + if (state->history == 0) state->history = argv_alloc(10); line = concatenate(direction, STR(state->buffer), (char *) 0); @@ -207,7 +210,7 @@ void smtpd_chat_notify(SMTPD_STATE *state) notice = post_mail_fopen_nowait(mail_addr_double_bounce(), var_error_rcpt, - NULL_CLEANUP_FLAGS, "NOTICE"); + NULL_CLEANUP_FLAGS); if (notice == 0) { msg_warn("postmaster notify: %m"); return; @@ -227,7 +230,5 @@ void smtpd_chat_notify(SMTPD_STATE *state) post_mail_fputs(notice, ""); if (state->reason) post_mail_fprintf(notice, "Session aborted, reason: %s", state->reason); - else - post_mail_fputs(notice, "No message was collected successfully."); (void) post_mail_fclose(notice); } diff --git a/gnu/dist/postfix/src/smtpd/smtpd_check.in b/gnu/dist/postfix/src/smtpd/smtpd_check.in index f7c3cdd709d..44f969ce9c6 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_check.in +++ b/gnu/dist/postfix/src/smtpd/smtpd_check.in @@ -6,6 +6,7 @@ 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. # diff --git a/gnu/dist/postfix/src/smtpd/smtpd_check.in2 b/gnu/dist/postfix/src/smtpd/smtpd_check.in2 index 0eaf8c02b9e..2b9000267b4 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_check.in2 +++ b/gnu/dist/postfix/src/smtpd/smtpd_check.in2 @@ -6,6 +6,7 @@ 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. # diff --git a/gnu/dist/postfix/src/smtpd/smtpd_check.ref b/gnu/dist/postfix/src/smtpd/smtpd_check.ref index b63c3f70545..121c9e32a5d 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_check.ref +++ b/gnu/dist/postfix/src/smtpd/smtpd_check.ref @@ -9,6 +9,8 @@ OK OK >>> relay_domains porcupine.org OK +>>> maps_rbl_domains blackholes.mail-abuse.org +OK >>> # >>> # Test the client restrictions. >>> # diff --git a/gnu/dist/postfix/src/smtpd/smtpd_check.ref2 b/gnu/dist/postfix/src/smtpd/smtpd_check.ref2 index c8d014f6000..2bd38266375 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_check.ref2 +++ b/gnu/dist/postfix/src/smtpd/smtpd_check.ref2 @@ -9,6 +9,8 @@ OK OK >>> relay_domains porcupine.org OK +>>> maps_rbl_domains blackholes.mail-abuse.org +OK >>> # >>> # Test the client restrictions. >>> # diff --git a/gnu/dist/postfix/src/smtpd/smtpd_check_access b/gnu/dist/postfix/src/smtpd/smtpd_check_access index afb5487c965..b9cf1761fa0 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_check_access +++ b/gnu/dist/postfix/src/smtpd/smtpd_check_access @@ -29,3 +29,4 @@ reject.domain REJECT reject@ok.domain REJECT ok@ok.domain OK ok.domain OK +<> 550 Go away postmaster diff --git a/gnu/dist/postfix/src/smtpd/smtpd_sasl_glue.c b/gnu/dist/postfix/src/smtpd/smtpd_sasl_glue.c index caa3ec04fb1..716b7873dd3 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_sasl_glue.c +++ b/gnu/dist/postfix/src/smtpd/smtpd_sasl_glue.c @@ -118,11 +118,11 @@ static int smtpd_sasl_log(void *unused_context, int priority, switch (priority) { case SASL_LOG_ERR: case SASL_LOG_WARNING: - msg_warn("%s", message); + msg_warn("SASL authentication problem: %s", message); break; case SASL_LOG_INFO: if (msg_verbose) - msg_info("%s", message); + msg_info("SASL authentication info: %s", message); break; } return SASL_OK; diff --git a/gnu/dist/postfix/src/smtpd/smtpd_state.c b/gnu/dist/postfix/src/smtpd/smtpd_state.c index ca492963487..6e7236543e9 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_state.c +++ b/gnu/dist/postfix/src/smtpd/smtpd_state.c @@ -91,6 +91,7 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream) 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)) diff --git a/gnu/dist/postfix/src/smtpd/smtpd_token.c b/gnu/dist/postfix/src/smtpd/smtpd_token.c index 09d64cd01e5..66bc6bc9c38 100644 --- a/gnu/dist/postfix/src/smtpd/smtpd_token.c +++ b/gnu/dist/postfix/src/smtpd/smtpd_token.c @@ -196,7 +196,7 @@ int smtpd_token(char *cp, SMTPD_TOKEN **argvp) #include <vstream.h> #include <vstring_vstream.h> -main(int unused_argc, char **unused_argv) +int main(int unused_argc, char **unused_argv) { VSTRING *vp = vstring_alloc(10); int tok_argc; diff --git a/gnu/dist/postfix/src/smtpstone/Makefile.in b/gnu/dist/postfix/src/smtpstone/Makefile.in index 5cf7920e0e6..454a44c1343 100644 --- a/gnu/dist/postfix/src/smtpstone/Makefile.in +++ b/gnu/dist/postfix/src/smtpstone/Makefile.in @@ -1,6 +1,6 @@ SHELL = /bin/sh -SRCS = smtp-source.c smtp-sink.c -OBJS = smtp-source.o smtp-sink.o +SRCS = smtp-source.c smtp-sink.c qmqp-source.c qmqp-sink.c +OBJS = smtp-source.o smtp-sink.o qmqp-source.o qmqp-sink.o HDRS = TESTSRC = WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ @@ -10,7 +10,7 @@ DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) TESTPROG= INC_DIR = ../../include -PROG = smtp-source smtp-sink +PROG = smtp-source smtp-sink qmqp-source qmqp-sink LIBS = ../../lib/libglobal.a ../../lib/libutil.a .c.o:; $(CC) $(CFLAGS) -c $*.c @@ -26,9 +26,15 @@ smtp-sink: smtp-sink.o $(LIBS) smtp-source: smtp-source.o $(LIBS) $(CC) $(CFLAGS) -o $@ smtp-source.o $(LIBS) $(SYSLIBS) +qmqp-sink: qmqp-sink.o $(LIBS) + $(CC) $(CFLAGS) -o $@ qmqp-sink.o $(LIBS) $(SYSLIBS) + +qmqp-source: qmqp-source.o $(LIBS) + $(CC) $(CFLAGS) -o $@ qmqp-source.o $(LIBS) $(SYSLIBS) + test: $(TESTPROG) -update: ../../bin/smtp-source ../../bin/smtp-sink +update: ../../bin/smtp-source ../../bin/smtp-sink ../../bin/qmqp-source ../../bin/smtp-source: smtp-source cp $? $@ @@ -36,6 +42,12 @@ update: ../../bin/smtp-source ../../bin/smtp-sink ../../bin/smtp-sink: smtp-sink cp $? $@ +../../bin/qmqp-source: qmqp-source + cp $? $@ + +../../bin/qmqp-sink: qmqp-sink + cp $? $@ + printfck: $(OBJS) $(PROG) rm -rf printfck mkdir printfck @@ -61,6 +73,36 @@ depend: $(MAKES) @$(EXPORT) make -f Makefile.in Makefile 1>&2 # do not edit below this line - it is generated by 'make depend' +qmqp-sink.o: qmqp-sink.c +qmqp-sink.o: ../../include/sys_defs.h +qmqp-sink.o: ../../include/msg.h +qmqp-sink.o: ../../include/vstring.h +qmqp-sink.o: ../../include/vbuf.h +qmqp-sink.o: ../../include/vstream.h +qmqp-sink.o: ../../include/listen.h +qmqp-sink.o: ../../include/iostuff.h +qmqp-sink.o: ../../include/events.h +qmqp-sink.o: ../../include/mymalloc.h +qmqp-sink.o: ../../include/msg_vstream.h +qmqp-sink.o: ../../include/netstring.h +qmqp-sink.o: ../../include/qmqp_proto.h +qmqp-source.o: qmqp-source.c +qmqp-source.o: ../../include/sys_defs.h +qmqp-source.o: ../../include/msg.h +qmqp-source.o: ../../include/msg_vstream.h +qmqp-source.o: ../../include/vstream.h +qmqp-source.o: ../../include/vbuf.h +qmqp-source.o: ../../include/vstring.h +qmqp-source.o: ../../include/get_hostname.h +qmqp-source.o: ../../include/split_at.h +qmqp-source.o: ../../include/connect.h +qmqp-source.o: ../../include/iostuff.h +qmqp-source.o: ../../include/mymalloc.h +qmqp-source.o: ../../include/events.h +qmqp-source.o: ../../include/find_inet.h +qmqp-source.o: ../../include/netstring.h +qmqp-source.o: ../../include/mail_date.h +qmqp-source.o: ../../include/qmqp_proto.h smtp-sink.o: smtp-sink.c smtp-sink.o: ../../include/sys_defs.h smtp-sink.o: ../../include/msg.h diff --git a/gnu/dist/postfix/src/smtpstone/qmqp-sink.c b/gnu/dist/postfix/src/smtpstone/qmqp-sink.c new file mode 100644 index 00000000000..1c696b8991b --- /dev/null +++ b/gnu/dist/postfix/src/smtpstone/qmqp-sink.c @@ -0,0 +1,287 @@ +/*++ +/* NAME +/* qmqp-sink 8 +/* SUMMARY +/* multi-threaded QMQP test server +/* SYNOPSIS +/* .fi +/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR] +/* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR +/* +/* \fBqmqp-sink\fR [\fB-cv\fR] [\fB-x \fItime\fR] +/* \fBunix:\fR\fIpathname\fR \fIbacklog\fR +/* DESCRIPTION +/* \fIqmqp-sink\fR listens on the named host (or address) and port. +/* It receives messages from the network and throws them away. +/* The purpose is to measure QMQP client performance, not protocol +/* compliance. +/* Connections can be accepted on IPV4 endpoints or UNIX-domain sockets. +/* IPV4 is the default. +/* This program is the complement of the \fIqmqp-source\fR program. +/* .IP \fB-c\fR +/* Display a running counter that is updated whenever a delivery +/* is completed. +/* .IP \fB-v\fR +/* Increase verbosity. Specify \fB-v -v\fR to see some of the QMQP +/* conversation. +/* .IP "\fB-x \fItime\fR +/* Terminate after \fItime\fR seconds. This is to facilitate memory +/* leak testing. +/* SEE ALSO +/* qmqp-source, QMQP test message generator +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> + +#ifdef STRCASECMP_IN_STRINGS_H +#include <strings.h> +#endif + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <vstream.h> +#include <listen.h> +#include <events.h> +#include <mymalloc.h> +#include <iostuff.h> +#include <msg_vstream.h> +#include <netstring.h> + +/* Global library. */ + +#include <qmqp_proto.h> + +/* Application-specific. */ + +typedef struct { + VSTREAM *stream; /* client connection */ + int count; /* bytes to go */ +} SINK_STATE; + +static int var_tmout; +static VSTRING *buffer; +static void disconnect(SINK_STATE *); +static int count; +static int counter; + +/* send_reply - finish conversation */ + +static void send_reply(SINK_STATE *state) +{ + vstring_sprintf(buffer, "%cOk", QMQP_STAT_OK); + NETSTRING_PUT_BUF(state->stream, buffer); + netstring_fflush(state->stream); + if (count) { + counter++; + vstream_printf("%d\r", counter); + vstream_fflush(VSTREAM_OUT); + } + disconnect(state); +} + +/* read_data - read over-all netstring data */ + +static void read_data(int unused_event, char *context) +{ + SINK_STATE *state = (SINK_STATE *) context; + int fd = vstream_fileno(state->stream); + int count; + + /* + * Refill the VSTREAM buffer, if necessary. + */ + if (VSTREAM_GETC(state->stream) == VSTREAM_EOF) + netstring_except(state->stream, vstream_ftimeout(state->stream) ? + NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); + state->count--; + + /* + * Flush the VSTREAM buffer. As documented, vstream_fseek() discards + * unread input. + */ + if ((count = vstream_peek(state->stream)) > 0) { + state->count -= count; + if (state->count <= 0) { + send_reply(state); + return; + } + vstream_fseek(state->stream, 0L, 0); + } + + /* + * Do not block while waiting for the arrival of more data. + */ + event_disable_readwrite(fd); + event_enable_read(fd, read_data, context); +} + +/* read_length - read over-all netstring length */ + +static void read_length(int event, char *context) +{ + SINK_STATE *state = (SINK_STATE *) context; + + switch (vstream_setjmp(state->stream)) { + + default: + msg_panic("unknown error reading input"); + + case NETSTRING_ERR_TIME: + msg_panic("attempt to read non-readable socket"); + /* NOTREACHED */ + + case NETSTRING_ERR_EOF: + msg_warn("lost connection"); + disconnect(state); + return; + + case NETSTRING_ERR_FORMAT: + msg_warn("netstring format error"); + disconnect(state); + return; + + case NETSTRING_ERR_SIZE: + msg_warn("netstring size error"); + disconnect(state); + return; + + /* + * Include the netstring terminator in the read byte count. This + * violates abstractions. + */ + case 0: + state->count = netstring_get_length(state->stream) + 1; + read_data(event, context); + return; + } +} + +/* disconnect - handle disconnection events */ + +static void disconnect(SINK_STATE *state) +{ + event_disable_readwrite(vstream_fileno(state->stream)); + vstream_fclose(state->stream); + myfree((char *) state); +} + +/* connect_event - handle connection events */ + +static void connect_event(int unused_event, char *context) +{ + int sock = CAST_CHAR_PTR_TO_INT(context); + struct sockaddr sa; + SOCKADDR_SIZE len = sizeof(sa); + SINK_STATE *state; + int fd; + + if ((fd = accept(sock, &sa, &len)) >= 0) { + if (msg_verbose) + msg_info("connect (%s)", +#ifdef AF_LOCAL + sa.sa_family == AF_LOCAL ? "AF_LOCAL" : +#else + sa.sa_family == AF_UNIX ? "AF_UNIX" : +#endif + sa.sa_family == AF_INET ? "AF_INET" : +#ifdef AF_INET6 + sa.sa_family == AF_INET6 ? "AF_INET6" : +#endif + "unknown protocol family"); + non_blocking(fd, NON_BLOCKING); + state = (SINK_STATE *) mymalloc(sizeof(*state)); + state->stream = vstream_fdopen(fd, O_RDWR); + netstring_setup(state->stream, var_tmout); + event_enable_read(fd, read_length, (char *) state); + } +} + +/* terminate - voluntary exit */ + +static void terminate(int unused_event, char *unused_context) +{ + exit(0); +} + +/* usage - explain */ + +static void usage(char *myname) +{ + msg_fatal("usage: %s [-cv] [-x time] [host]:port backlog", myname); +} + +int main(int argc, char **argv) +{ + int sock; + int backlog; + int ch; + int ttl; + + /* + * Initialize diagnostics. + */ + msg_vstream_init(argv[0], VSTREAM_ERR); + + /* + * Parse JCL. + */ + while ((ch = GETOPT(argc, argv, "cvx:")) > 0) { + switch (ch) { + case 'c': + count++; + break; + case 'v': + msg_verbose++; + break; + case 'x': + if ((ttl = atoi(optarg)) <= 0) + usage(argv[0]); + event_request_timer(terminate, (char *) 0, ttl); + break; + default: + usage(argv[0]); + } + } + if (argc - optind != 2) + usage(argv[0]); + if ((backlog = atoi(argv[optind + 1])) <= 0) + usage(argv[0]); + + /* + * Initialize. + */ + buffer = vstring_alloc(1024); + if (strncmp(argv[optind], "unix:", 5) == 0) { + sock = unix_listen(argv[optind] + 5, backlog, BLOCKING); + } else { + if (strncmp(argv[optind], "inet:", 5) == 0) + argv[optind] += 5; + sock = inet_listen(argv[optind], backlog, BLOCKING); + } + + /* + * Start the event handler. + */ + event_enable_read(sock, connect_event, CAST_INT_TO_CHAR_PTR(sock)); + for (;;) + event_loop(-1); +} diff --git a/gnu/dist/postfix/src/smtpstone/qmqp-source.c b/gnu/dist/postfix/src/smtpstone/qmqp-source.c new file mode 100644 index 00000000000..66fd33854e3 --- /dev/null +++ b/gnu/dist/postfix/src/smtpstone/qmqp-source.c @@ -0,0 +1,593 @@ +/*++ +/* NAME +/* qmqp-source 8 +/* SUMMARY +/* multi-threaded QMQP test generator +/* SYNOPSIS +/* .fi +/* \fBqmqp-source\fR [\fIoptions\fR] [\fBinet:\fR]\fIhost\fR[:\fIport\fR] +/* +/* \fBqmqp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR +/* DESCRIPTION +/* qmqp-source connects to the named host and TCP port (default 628) +/* and sends one or more messages to it, either sequentially +/* or in parallel. The program speaks the QMQP protocol. +/* Connections can be made to UNIX-domain and IPV4 servers. +/* IPV4 is the default. +/* +/* Options: +/* .IP -c +/* Display a running counter that is incremented each time +/* a delivery completes. +/* .IP "-C count" +/* When a host sends RESET instead of SYN|ACK, try \fIcount\fR times +/* before giving up. The default count is 1. Specify a larger count in +/* order to work around a problem with TCP/IP stacks that send RESET +/* when the listen queue is full. +/* .IP "-f from" +/* Use the specified sender address (default: <foo@myhostname>). +/* .IP "-l length" +/* Send \fIlength\fR bytes as message payload. The length +/* includes the message headers. +/* .IP "-m message_count" +/* Send the specified number of messages (default: 1). +/* .IP "-r recipient_count" +/* Send the specified number of recipients per transaction (default: 1). +/* Recipient names are generated by prepending a number to the +/* recipient address. +/* .IP "-s session_count" +/* Run the specified number of QMQP sessions in parallel (default: 1). +/* .IP "-t to" +/* Use the specified recipient address (default: <foo@myhostname>). +/* .IP "-R interval" +/* Wait for a random period of time 0 <= n <= interval between messages. +/* Suspending one thread does not affect other delivery threads. +/* .IP "-w interval" +/* Wait a fixed time between messages. +/* Suspending one thread does not affect other delivery threads. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <netinet/in.h> +#include <sys/un.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <msg_vstream.h> +#include <vstring.h> +#include <vstream.h> +#include <get_hostname.h> +#include <split_at.h> +#include <connect.h> +#include <mymalloc.h> +#include <events.h> +#include <find_inet.h> +#include <iostuff.h> +#include <netstring.h> + +/* Global library. */ + +#include <mail_date.h> +#include <qmqp_proto.h> + +/* Application-specific. */ + + /* + * Per-session data structure with state. + * + * This software can maintain multiple parallel connections to the same QMQP + * server. However, it makes no more than one connection request at a time + * to avoid overwhelming the server with SYN packets and having to back off. + * Back-off would screw up the benchmark. Pending connection requests are + * kept in a linear list. + */ +typedef struct SESSION { + int xfer_count; /* # of xfers in session */ + int rcpt_done; /* # of recipients done */ + int rcpt_count; /* # of recipients to go */ + VSTREAM *stream; /* open connection */ + int connect_count; /* # of connect()s to retry */ + struct SESSION *next; /* connect() queue linkage */ +} SESSION; + +static SESSION *last_session; /* connect() queue tail */ + +static VSTRING *buffer; +static int var_line_limit = 10240; +static int var_timeout = 300; +static const char *var_myhostname; +static int session_count; +static int message_count = 1; +static struct sockaddr_in sin; + +#undef sun +static struct sockaddr_un sun; +static struct sockaddr *sa; +static int sa_length; +static int recipients = 1; +static char *defaddr; +static char *recipient; +static char *sender; +static int message_length = 1024; +static int count = 0; +static int counter = 0; +static int connect_count = 1; +static int random_delay = 0; +static int fixed_delay = 0; +static const char *mydate; +static int mypid; + +static void enqueue_connect(SESSION *); +static void start_connect(SESSION *); +static void connect_done(int, char *); + +static void send_data(SESSION *); +static void receive_reply(int, char *); + +static VSTRING *message_buffer; +static VSTRING *sender_buffer; +static VSTRING *recipient_buffer; + +/* Silly little macros. */ + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +/* random_interval - generate a random value in 0 .. (small) interval */ + +static int random_interval(int interval) +{ + return (rand() % (interval + 1)); +} + +/* socket_error - look up and reset the last socket error */ + +static int socket_error(int sock) +{ + int error; + SOCKOPT_SIZE error_len; + + /* + * Some Solaris 2 versions have getsockopt() itself return the error, + * instead of returning it via the parameter list. + */ + error = 0; + error_len = sizeof(error); + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &error, &error_len) < 0) + return (-1); + if (error) { + errno = error; + return (-1); + } + + /* + * No problems. + */ + return (0); +} + +/* exception_text - translate exceptions from the netstring module */ + +static char *exception_text(int except) +{ + ; + + switch (except) { + case NETSTRING_ERR_EOF: + return ("lost connection"); + case NETSTRING_ERR_TIME: + return ("timeout"); + case NETSTRING_ERR_FORMAT: + return ("netstring format error"); + case NETSTRING_ERR_SIZE: + return ("netstring size exceeds limit"); + default: + msg_panic("exception_text: unknown exception %d", except); + } + /* NOTREACHED */ +} + +/* startup - connect to server but do not wait */ + +static void startup(SESSION *session) +{ + if (message_count-- <= 0) { + myfree((char *) session); + session_count--; + return; + } + enqueue_connect(session); +} + +/* start_event - invoke startup from timer context */ + +static void start_event(int unused_event, char *context) +{ + SESSION *session = (SESSION *) context; + + startup(session); +} + +/* start_another - start another session */ + +static void start_another(SESSION *session) +{ + if (random_delay > 0) { + event_request_timer(start_event, (char *) session, + random_interval(random_delay)); + } else if (fixed_delay > 0) { + event_request_timer(start_event, (char *) session, fixed_delay); + } else { + startup(session); + } +} + +/* enqueue_connect - queue a connection request */ + +static void enqueue_connect(SESSION *session) +{ + session->next = 0; + if (last_session == 0) { + last_session = session; + start_connect(session); + } else { + last_session->next = session; + last_session = session; + } +} + +/* dequeue_connect - connection request completed */ + +static void dequeue_connect(SESSION *session) +{ + if (session == last_session) { + if (session->next != 0) + msg_panic("dequeue_connect: queue ends after last"); + last_session = 0; + } else { + if (session->next == 0) + msg_panic("dequeue_connect: queue ends before last"); + start_connect(session->next); + } +} + +/* fail_connect - handle failed startup */ + +static void fail_connect(SESSION *session) +{ + if (session->connect_count-- == 1) + msg_fatal("connect: %m"); + msg_warn("connect: %m"); + event_disable_readwrite(vstream_fileno(session->stream)); + vstream_fclose(session->stream); + session->stream = 0; +#ifdef MISSING_USLEEP + doze(10); +#else + usleep(10); +#endif + start_connect(session); +} + +/* start_connect - start TCP handshake */ + +static void start_connect(SESSION *session) +{ + int fd; + + /* + * Some systems don't set the socket error when connect() fails early + * (loopback) so we must deal with the error immediately, rather than + * retrieving it later with getsockopt(). We can't use MSG_PEEK to + * distinguish between server disconnect and connection refused. + */ + if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) + msg_fatal("socket: %m"); + (void) non_blocking(fd, NON_BLOCKING); + session->stream = vstream_fdopen(fd, O_RDWR); + event_enable_write(fd, connect_done, (char *) session); + netstring_setup(session->stream, var_timeout); + if (connect(fd, sa, sa_length) < 0 && errno != EINPROGRESS) + fail_connect(session); +} + +/* connect_done - send message sender info */ + +static void connect_done(int unused_event, char *context) +{ + SESSION *session = (SESSION *) context; + int fd = vstream_fileno(session->stream); + + /* + * Try again after some delay when the connection failed, in case they + * run a Mickey Mouse protocol stack. + */ + if (socket_error(fd) < 0) { + fail_connect(session); + } else { + dequeue_connect(session); + non_blocking(fd, BLOCKING); + event_disable_readwrite(fd); + send_data(session); + } +} + +/* send_data - send message+sender+recipients */ + +static void send_data(SESSION *session) +{ + int fd = vstream_fileno(session->stream); + int except; + + /* + * Prepare for disaster. + */ + if ((except = vstream_setjmp(session->stream)) != 0) + msg_fatal("%s while sending message", exception_text(except)); + + /* + * Send the message content, by wrapping three netstrings into an + * over-all netstring. + * + * XXX This should be done more carefully to avoid blocking when sending + * large messages over slow networks. + */ + netstring_put_multi(session->stream, + STR(message_buffer), LEN(message_buffer), + STR(sender_buffer), LEN(sender_buffer), + STR(recipient_buffer), LEN(recipient_buffer), + 0); + netstring_fflush(session->stream); + + /* + * Wake me up when the server replies or when something bad happens. + */ + event_enable_read(fd, receive_reply, (char *) session); +} + +/* receive_reply - read server reply */ + +static void receive_reply(int unused_event, char *context) +{ + SESSION *session = (SESSION *) context; + int except; + + /* + * Prepare for disaster. + */ + if ((except = vstream_setjmp(session->stream)) != 0) + msg_fatal("%s while receiving server reply", exception_text(except)); + + /* + * Receive and process the server reply. + */ + netstring_get(session->stream, buffer, var_line_limit); + if (msg_verbose) + vstream_printf("<< %.*s\n", LEN(buffer), STR(buffer)); + if (STR(buffer)[0] != QMQP_STAT_OK) + msg_fatal("%s error: %.*s", + STR(buffer)[0] == QMQP_STAT_RETRY ? "recoverable" : + STR(buffer)[0] == QMQP_STAT_HARD ? "unrecoverable" : + "unknown", LEN(buffer) - 1, STR(buffer) + 1); + + /* + * Update the optional running counter. + */ + if (count) { + counter++; + vstream_printf("%d\r", counter); + vstream_fflush(VSTREAM_OUT); + } + + /* + * Finish this session. QMQP sends only one message per session. + */ + event_disable_readwrite(vstream_fileno(session->stream)); + vstream_fclose(session->stream); + session->stream = 0; + start_another(session); +} + +/* usage - explain */ + +static void usage(char *myname) +{ + msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -f from -t to -R delay -v -w delay host[:port]", myname); +} + +/* main - parse JCL and start the machine */ + +int main(int argc, char **argv) +{ + SESSION *session; + char *host; + char *port; + char *path; + int path_len; + int sessions = 1; + int ch; + int n; + int i; + + signal(SIGPIPE, SIG_IGN); + msg_vstream_init(argv[0], VSTREAM_ERR); + + /* + * Parse JCL. + */ + while ((ch = GETOPT(argc, argv, "cC:f:l:m:r:R:s:t:vw:")) > 0) { + switch (ch) { + case 'c': + count++; + break; + case 'C': + if ((connect_count = atoi(optarg)) <= 0) + usage(argv[0]); + break; + case 'f': + sender = optarg; + break; + case 'l': + if ((message_length = atoi(optarg)) <= 0) + usage(argv[0]); + break; + case 'm': + if ((message_count = atoi(optarg)) <= 0) + usage(argv[0]); + break; + case 'r': + if ((recipients = atoi(optarg)) <= 0) + usage(argv[0]); + break; + case 'R': + if (fixed_delay > 0 || (random_delay = atoi(optarg)) <= 0) + usage(argv[0]); + break; + case 's': + if ((sessions = atoi(optarg)) <= 0) + usage(argv[0]); + break; + case 't': + recipient = optarg; + break; + case 'v': + msg_verbose++; + break; + case 'w': + if (random_delay > 0 || (fixed_delay = atoi(optarg)) <= 0) + usage(argv[0]); + break; + default: + usage(argv[0]); + } + } + if (argc - optind != 1) + usage(argv[0]); + + if (random_delay > 0) + srand(getpid()); + + /* + * Translate endpoint address to internal form. + */ + if (strncmp(argv[optind], "unix:", 5) == 0) { + path = argv[optind] + 5; + path_len = strlen(path); + if (path_len >= (int) sizeof(sun.sun_path)) + msg_fatal("unix-domain name too long: %s", path); + memset((char *) &sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; +#ifdef HAS_SUN_LEN + sun.sun_len = path_len + 1; +#endif + memcpy(sun.sun_path, path, path_len); + sa = (struct sockaddr *) & sun; + sa_length = sizeof(sun); + } else { + if (strncmp(argv[optind], "inet:", 5) == 0) + argv[optind] += 5; + if ((port = split_at(host = argv[optind], ':')) == 0 || *port == 0) + port = "628"; + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = find_inet_addr(host); + sin.sin_port = find_inet_port(port, "tcp"); + sa = (struct sockaddr *) & sin; + sa_length = sizeof(sin); + } + + /* + * Allocate space for temporary buffer. + */ + buffer = vstring_alloc(100); + + /* + * Make sure we have sender and recipient addresses. + */ + var_myhostname = get_hostname(); + if (sender == 0 || recipient == 0) { + vstring_sprintf(buffer, "foo@%s", var_myhostname); + defaddr = mystrdup(vstring_str(buffer)); + if (sender == 0) + sender = defaddr; + if (recipient == 0) + recipient = defaddr; + } + + /* + * Prepare some results that may be used multiple times: the message + * content netstring, the sender netstring, and the recipient netstrings. + */ + mydate = mail_date(time((time_t *) 0)); + mypid = getpid(); + + message_buffer = vstring_alloc(message_length + 200); + vstring_sprintf(buffer, + "From: <%s>\nTo: <%s>\nDate: %s\nMessage-Id: <%d@%s>\n\n", + sender, recipient, mydate, mypid, var_myhostname); + for (n = 1; LEN(buffer) < message_length; n++) { + for (i = 0; i < n && i < 79; i++) + VSTRING_ADDCH(buffer, 'X'); + VSTRING_ADDCH(buffer, '\n'); + } + STR(buffer)[message_length - 1] = '\n'; + netstring_memcpy(message_buffer, STR(buffer), message_length); + + n = strlen(sender); + sender_buffer = vstring_alloc(n); + netstring_memcpy(sender_buffer, sender, n); + + if (recipients == 1) { + n = strlen(recipient); + recipient_buffer = vstring_alloc(n); + netstring_memcpy(recipient_buffer, recipient, n); + } else { + recipient_buffer = vstring_alloc(100); + for (n = 0; n < recipients; n++) { + vstring_sprintf(buffer, "%d%s", n, recipient); + netstring_memcat(recipient_buffer, STR(buffer), LEN(buffer)); + } + } + + /* + * Start sessions. + */ + while (sessions-- > 0) { + session = (SESSION *) mymalloc(sizeof(*session)); + session->stream = 0; + session->xfer_count = 0; + session->connect_count = connect_count; + session->next = 0; + session_count++; + startup(session); + } + for (;;) { + event_loop(-1); + if (session_count <= 0 && message_count <= 0) { + if (count) { + VSTREAM_PUTC('\n', VSTREAM_OUT); + vstream_fflush(VSTREAM_OUT); + } + exit(0); + } + } +} diff --git a/gnu/dist/postfix/src/smtpstone/smtp-sink.c b/gnu/dist/postfix/src/smtpstone/smtp-sink.c index 81aab916b36..24a5e278492 100644 --- a/gnu/dist/postfix/src/smtpstone/smtp-sink.c +++ b/gnu/dist/postfix/src/smtpstone/smtp-sink.c @@ -5,11 +5,10 @@ /* multi-threaded SMTP/LMTP test server /* SYNOPSIS /* .fi -/* \fBsmtp-sink\fR [\fB-cLpv\fR] [\fB-w \fIdelay\fR] -/* [\fBinet:\fR][\fIhost\fR]:\fIport\fR \fIbacklog\fR +/* \fBsmtp-sink\fR [\fIoptions\fR] [\fBinet:\fR][\fIhost\fR]:\fIport\fR +/* \fIbacklog\fR /* -/* \fBsmtp-sink\fR [\fB-cLpv\fR] [\fB-w \fIdelay\fR] -/* \fBunix:\fR\fIpathname\fR \fIbacklog\fR +/* \fBsmtp-sink\fR [\fIoptions\fR] \fBunix:\fR\fIpathname\fR \fIbacklog\fR /* DESCRIPTION /* \fIsmtp-sink\fR listens on the named host (or address) and port. /* It takes SMTP messages from the network and throws them away. @@ -18,17 +17,33 @@ /* Connections can be accepted on IPV4 endpoints or UNIX-domain sockets. /* IPV4 is the default. /* This program is the complement of the \fIsmtp-source\fR program. -/* .IP -c +/* +/* Arguments: +/* .IP \fB-c\fR /* Display a running counter that is updated whenever an SMTP /* QUIT command is executed. -/* .IP -L +/* .IP \fB-L\fR /* Speak LMTP rather than SMTP. -/* .IP -p +/* .IP "\fB-n \fIcount\fR" +/* Terminate after \fIcount\fR sessions. This is for testing purposes. +/* .IP \fB-p\fR /* Disable ESMTP command pipelining. -/* .IP -v +/* .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 "-w delay" +/* .IP "\fB-w \fIdelay\fR" /* Wait \fIdelay\fR seconds before responding to a DATA command. +/* .IP [\fBinet:\fR][\fIhost\fR]:\fIport\fR +/* Listen on network interface \fIhost\fR (default: any interface) +/* TCP port \fIport\fR. Both \fIhost\fR and \fIport\fR may be +/* specified in numeric or symbolic form. +/* .IP \fBunix:\fR\fIpathname\fR +/* Listen on the UNIX-domain socket at \fIpathname\fR. +/* .IP \fIbacklog\fR +/* The maximum length the queue of pending connections, +/* as defined by the listen(2) call. /* SEE ALSO /* smtp-source, SMTP/LMTP test message generator /* LICENSE @@ -77,6 +92,7 @@ typedef struct SINK_STATE { VSTREAM *stream; + VSTRING *buffer; int data_state; int (*read) (struct SINK_STATE *); int rcpts; @@ -90,17 +106,18 @@ typedef struct SINK_STATE { #define ST_CR_LF_DOT_CR_LF 5 static int var_tmout; -static int var_max_line_length; +static int var_max_line_length = 2048; static char *var_myhostname; -static VSTRING *buffer; static int command_read(SINK_STATE *); static int data_read(SINK_STATE *); static void disconnect(SINK_STATE *); static int count; static int counter; +static int max_count; static int disable_pipelining; static int fixed_delay; static int enable_lmtp; +static int pretend_pix; /* ehlo_response - respond to EHLO command */ @@ -197,11 +214,10 @@ static int data_read(SINK_STATE *state) struct data_trans *dp; /* - * We must avoid blocking I/O, so get out of here as soon as both the - * VSTREAM and kernel read buffers dry up. + * A read may result in EOF, but is never supposed to time out - a time + * out means that we were trying to read when no data was available. */ - while (vstream_peek(state->stream) > 0 - || peekfd(vstream_fileno(state->stream)) > 0) { + for (;;) { if ((ch = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) return (-1); for (dp = data_trans; dp->state != state->data_state; dp++) @@ -224,8 +240,17 @@ static int data_read(SINK_STATE *state) msg_info("."); dot_response(state); state->read = command_read; + state->data_state = ST_ANY; break; } + + /* + * We must avoid blocking I/O, so get out of here as soon as both the + * VSTREAM and kernel read buffers dry up. + */ + if (vstream_peek(state->stream) <= 0 + && peekfd(vstream_fileno(state->stream)) <= 0) + return (0); } return (0); } @@ -258,9 +283,74 @@ static int command_read(SINK_STATE *state) { char *command; SINK_COMMAND *cmdp; + int ch; + struct cmd_trans { + int state; + int want; + int next_state; + }; + static struct cmd_trans cmd_trans[] = { + ST_ANY, '\r', ST_CR, + ST_CR, '\n', ST_CR_LF, + }; + struct cmd_trans *cp; - smtp_get(buffer, state->stream, var_max_line_length); - if ((command = strtok(vstring_str(buffer), " \t")) == 0) { + /* + * A read may result in EOF, but is never supposed to time out - a time + * out means that we were trying to read when no data was available. + */ + for (;;) { + if ((ch = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) + return (-1); + + /* + * Sanity check. We don't want to store infinitely long commands. + */ + if (VSTRING_LEN(state->buffer) >= var_max_line_length) { + msg_warn("command line too long"); + return (-1); + } + VSTRING_ADDCH(state->buffer, ch); + + /* + * Try to match the current character desired by the state machine. + * If that fails, try to restart the machine with a match for its + * first state. + */ + for (cp = cmd_trans; cp->state != state->data_state; cp++) + /* void */ ; + if (ch == cp->want) + state->data_state = cp->next_state; + else if (ch == cmd_trans[0].want) + state->data_state = cmd_trans[0].next_state; + else + state->data_state = ST_ANY; + if (state->data_state == ST_CR_LF) + break; + + /* + * We must avoid blocking I/O, so get out of here as soon as both the + * VSTREAM and kernel read buffers dry up. + */ + if (vstream_peek(state->stream) <= 0 + && peekfd(vstream_fileno(state->stream)) <= 0) + return (0); + } + + /* + * Properly terminate the result, and reset the buffer write pointer for + * reading the next command. This is ugly, but not as ugly as trying to + * deal with all the early returns below. + */ + vstring_truncate(state->buffer, VSTRING_LEN(state->buffer) - 2); + VSTRING_TERMINATE(state->buffer); + state->data_state = ST_ANY; + VSTRING_RESET(state->buffer); + + /* + * Got a complete command line. Parse it. + */ + if ((command = strtok(vstring_str(state->buffer), " \t")) == 0) { smtp_printf(state->stream, "500 Error: unknown command"); return (0); } @@ -321,7 +411,10 @@ static void disconnect(SINK_STATE *state) { event_disable_readwrite(vstream_fileno(state->stream)); vstream_fclose(state->stream); + vstring_free(state->buffer); myfree((char *) state); + if (max_count > 0 && counter >= max_count) + exit(0); } /* connect_event - handle connection events */ @@ -350,9 +443,13 @@ static void connect_event(int unused_event, char *context) non_blocking(fd, NON_BLOCKING); state = (SINK_STATE *) mymalloc(sizeof(*state)); state->stream = vstream_fdopen(fd, O_RDWR); + state->buffer = vstring_alloc(1024); state->read = command_read; - state->data_state = 0; + 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); } @@ -362,7 +459,7 @@ static void connect_event(int unused_event, char *context) static void usage(char *myname) { - msg_fatal("usage: %s [-cLpv] [host]:port backlog", myname); + msg_fatal("usage: %s [-cLpPv] [-n count] [-w delay] [host]:port backlog", myname); } int main(int argc, char **argv) @@ -379,7 +476,7 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((ch = GETOPT(argc, argv, "cLpvw:")) > 0) { + while ((ch = GETOPT(argc, argv, "cLn:pPvw:")) > 0) { switch (ch) { case 'c': count++; @@ -387,9 +484,15 @@ int main(int argc, char **argv) case 'L': enable_lmtp = 1; break; + case 'n': + max_count = atoi(optarg); + break; case 'p': disable_pipelining = 1; break; + case 'P': + pretend_pix=1; + break; case 'v': msg_verbose++; break; @@ -409,7 +512,6 @@ int main(int argc, char **argv) /* * Initialize. */ - buffer = vstring_alloc(1024); var_myhostname = "smtp-sink"; if (strncmp(argv[optind], "unix:", 5) == 0) { sock = unix_listen(argv[optind] + 5, backlog, BLOCKING); diff --git a/gnu/dist/postfix/src/smtpstone/smtp-source.c b/gnu/dist/postfix/src/smtpstone/smtp-source.c index 6ab916429bd..d05caae779a 100644 --- a/gnu/dist/postfix/src/smtpstone/smtp-source.c +++ b/gnu/dist/postfix/src/smtpstone/smtp-source.c @@ -9,48 +9,59 @@ /* /* \fBsmtp-source\fR [\fIoptions\fR] \fBunix:\fIpathname\fR /* DESCRIPTION -/* smtp-source connects to the named host and port (default 25) -/* and sends one or more little messages to it, either sequentially +/* smtp-source connects to the named \fIhost\fR and TCP \fIport\fR +/* (default: port 25) +/* and sends one or more messages to it, either sequentially /* or in parallel. The program speaks either SMTP (default) or /* LMTP. Connections can be made to UNIX-domain and IPV4 servers. /* IPV4 is the default. /* -/* Options: -/* .IP -c +/* Arguments: +/* .IP \fB-c\fR /* Display a running counter that is incremented each time /* an SMTP DATA command completes. -/* .IP "-C count" +/* .IP "\fB-C \fIcount\fR" /* When a host sends RESET instead of SYN|ACK, try \fIcount\fR times /* before giving up. The default count is 1. Specify a larger count in /* order to work around a problem with TCP/IP stacks that send RESET /* when the listen queue is full. -/* .IP -d +/* .IP \fB-d\fR /* Don't disconnect after sending a message; send the next /* message over the same connection. -/* .IP "-f from" +/* .IP "\fB-f \fIfrom\fR" /* Use the specified sender address (default: <foo@myhostname>). -/* .IP -o +/* .IP \fB-o\fR /* Old mode: don't send HELO, and don't send message headers. -/* .IP "-l length" -/* Send \fIlength\fR bytes as message payload. -/* .IP -L +/* .IP "\fB-l \fIlength\fR" +/* Send \fIlength\fR bytes as message payload. The length does not +/* include message headers. +/* .IP \fB-L\fR /* Speak LMTP rather than SMTP. -/* .IP "-m message_count" +/* .IP "\fB-m \fImessage_count\fR" /* Send the specified number of messages (default: 1). -/* .IP "-r recipient_count" +/* .IP "\fB-r \fIrecipient_count\fR" /* Send the specified number of recipients per transaction (default: 1). /* Recipient names are generated by prepending a number to the -/* recipient address. The default is one recipient per transaction. -/* .IP "-s session_count" +/* recipient address. +/* .IP "\fB-s \fIsession_count\fR" /* Run the specified number of SMTP sessions in parallel (default: 1). -/* .IP "-t to" +/* .IP "\fB-S \fIsubject\fR" +/* Send mail with the named subject line (default: none). +/* .IP "\fB-t \fIto\fR" /* Use the specified recipient address (default: <foo@myhostname>). -/* .IP "-R interval" +/* .IP "\fB-R \fIinterval\fR" /* Wait for a random period of time 0 <= n <= interval between messages. /* Suspending one thread does not affect other delivery threads. -/* .IP "-w interval" +/* .IP "\fB-w \fIinterval\fR" /* Wait a fixed time between messages. /* Suspending one thread does not affect other delivery threads. +/* .IP [\fBinet:\fR]\fIhost\fR[:\fIport\fR] +/* Connect via TCP to \fIhost\fR port \fIport\fR. The default +/* port is \fBsmtp\fR. +/* .IP \fBunix:\fIpathname\fR +/* Connect to the UNIX-domain socket at \fIpathname\fR. +/* BUGS +/* No SMTP command pipelining support. /* LICENSE /* .ad /* .fi @@ -156,6 +167,7 @@ static int connect_count = 1; static int random_delay = 0; static int fixed_delay = 0; static int talk_lmtp = 0; +static char *subject = 0; static void enqueue_connect(SESSION *); static void start_connect(SESSION *); @@ -644,6 +656,8 @@ static void data_done(int unused_event, char *context) smtp_printf(session->stream, "Date: %s", mydate); smtp_printf(session->stream, "Message-Id: <%04x.%04x.%04x@%s>", mypid, vstream_fileno(session->stream), message_count, var_myhostname); + if (subject) + smtp_printf(session->stream, "Subject: %s", subject); smtp_fputs("", 0, session->stream); } @@ -738,7 +752,7 @@ static void quit_done(int unused_event, char *context) static void usage(char *myname) { - msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -d -f from -o -t to -R delay -v -w delay host[:port]", myname); + msg_fatal("usage: %s -s sess -l msglen -m msgs -c -C count -d -f from -o -t to -r rcptcount -R delay -v -w delay host[:port]", myname); } /* main - parse JCL and start the machine */ @@ -760,7 +774,7 @@ int main(int argc, char **argv) /* * Parse JCL. */ - while ((ch = GETOPT(argc, argv, "cC:df:l:Lm:or:R:s:t:vw:")) > 0) { + while ((ch = GETOPT(argc, argv, "cC:df:l:Lm:or:R:s:S:t:vw:")) > 0) { switch (ch) { case 'c': count++; @@ -781,6 +795,7 @@ int main(int argc, char **argv) message_data = mymalloc(message_length); memset(message_data, 'X', message_length); for (i = 80; i < message_length; i += 80) { + message_data[i - 80] = "0123456789"[(i / 80) % 10]; message_data[i - 2] = '\r'; message_data[i - 1] = '\n'; } @@ -808,6 +823,9 @@ int main(int argc, char **argv) if ((sessions = atoi(optarg)) <= 0) usage(argv[0]); break; + case 'S': + subject = optarg; + break; case 't': recipient = optarg; break; @@ -847,7 +865,7 @@ int main(int argc, char **argv) } else { if (strncmp(argv[optind], "inet:", 5) == 0) argv[optind] += 5; - if ((port = split_at(host = argv[optind], ':')) == 0) + if ((port = split_at(host = argv[optind], ':')) == 0 || *port == 0) port = "smtp"; memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_INET; diff --git a/gnu/dist/postfix/src/trivial-rewrite/Makefile.in b/gnu/dist/postfix/src/trivial-rewrite/Makefile.in index 1065ce0cfea..7f33c4c376f 100644 --- a/gnu/dist/postfix/src/trivial-rewrite/Makefile.in +++ b/gnu/dist/postfix/src/trivial-rewrite/Makefile.in @@ -70,6 +70,7 @@ resolve.o: ../../include/split_at.h resolve.o: ../../include/mail_params.h resolve.o: ../../include/mail_proto.h resolve.o: ../../include/iostuff.h +resolve.o: ../../include/attr.h resolve.o: ../../include/mail_addr.h resolve.o: ../../include/rewrite_clnt.h resolve.o: ../../include/resolve_local.h @@ -90,6 +91,7 @@ rewrite.o: ../../include/split_at.h rewrite.o: ../../include/mail_params.h rewrite.o: ../../include/mail_proto.h rewrite.o: ../../include/iostuff.h +rewrite.o: ../../include/attr.h rewrite.o: ../../include/resolve_local.h rewrite.o: ../../include/tok822.h rewrite.o: ../../include/resolve_clnt.h @@ -108,6 +110,8 @@ transport.o: ../../include/vstream.h transport.o: ../../include/argv.h transport.o: ../../include/mail_params.h transport.o: ../../include/maps.h +transport.o: ../../include/match_parent_style.h +transport.o: ../../include/match_ops.h transport.o: transport.h trivial-rewrite.o: trivial-rewrite.c trivial-rewrite.o: ../../include/sys_defs.h @@ -123,6 +127,7 @@ trivial-rewrite.o: ../../include/argv.h trivial-rewrite.o: ../../include/mail_params.h trivial-rewrite.o: ../../include/mail_proto.h trivial-rewrite.o: ../../include/iostuff.h +trivial-rewrite.o: ../../include/attr.h trivial-rewrite.o: ../../include/resolve_local.h trivial-rewrite.o: ../../include/mail_conf.h trivial-rewrite.o: ../../include/resolve_clnt.h diff --git a/gnu/dist/postfix/src/trivial-rewrite/resolve.c b/gnu/dist/postfix/src/trivial-rewrite/resolve.c index bd99fa61ae3..ba446301934 100644 --- a/gnu/dist/postfix/src/trivial-rewrite/resolve.c +++ b/gnu/dist/postfix/src/trivial-rewrite/resolve.c @@ -257,7 +257,9 @@ int resolve_proto(VSTREAM *stream) { int flags; - if (mail_scan(stream, "%s", query) != 1) + if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_ADDR, query, + ATTR_TYPE_END) != 1) return (-1); resolve_addr(STR(query), channel, nexthop, nextrcpt, &flags); @@ -266,8 +268,12 @@ int resolve_proto(VSTREAM *stream) msg_info("%s -> (`%s' `%s' `%s' `%d')", STR(query), STR(channel), STR(nexthop), STR(nextrcpt), flags); - mail_print(stream, "%s %s %s %d", - STR(channel), STR(nexthop), STR(nextrcpt), flags); + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_TRANSPORT, STR(channel), + ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, STR(nexthop), + ATTR_TYPE_STR, MAIL_ATTR_RECIP, STR(nextrcpt), + ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_END); if (vstream_fflush(stream) != 0) { msg_warn("write resolver reply: %m"); diff --git a/gnu/dist/postfix/src/trivial-rewrite/rewrite.c b/gnu/dist/postfix/src/trivial-rewrite/rewrite.c index 80ab11c252b..e1ae59cf751 100644 --- a/gnu/dist/postfix/src/trivial-rewrite/rewrite.c +++ b/gnu/dist/postfix/src/trivial-rewrite/rewrite.c @@ -203,7 +203,10 @@ void rewrite_addr(char *ruleset, char *addr, VSTRING *result) int rewrite_proto(VSTREAM *stream) { - if (mail_scan(stream, "%s %s", ruleset, address) != 2) + if (attr_scan(stream, ATTR_FLAG_STRICT, + ATTR_TYPE_STR, MAIL_ATTR_RULE, ruleset, + ATTR_TYPE_STR, MAIL_ATTR_ADDR, address, + ATTR_TYPE_END) != 2) return (-1); rewrite_addr(vstring_str(ruleset), vstring_str(address), result); @@ -212,7 +215,9 @@ int rewrite_proto(VSTREAM *stream) msg_info("`%s' `%s' -> `%s'", vstring_str(ruleset), vstring_str(address), vstring_str(result)); - mail_print(stream, "%s", vstring_str(result)); + attr_print(stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_ADDR, vstring_str(result), + ATTR_TYPE_END); if (vstream_fflush(stream) != 0) { msg_warn("write rewrite reply: %m"); diff --git a/gnu/dist/postfix/src/trivial-rewrite/transport.c b/gnu/dist/postfix/src/trivial-rewrite/transport.c index baf55f69963..379e2395f0a 100644 --- a/gnu/dist/postfix/src/trivial-rewrite/transport.c +++ b/gnu/dist/postfix/src/trivial-rewrite/transport.c @@ -62,12 +62,14 @@ #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 */ @@ -77,6 +79,7 @@ void transport_init(void) 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 */ @@ -85,6 +88,7 @@ int transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop) { char *low_domain = lowercase(mystrdup(domain)); const char *name; + const char *next; const char *value; const char *host; char *saved_value; @@ -113,7 +117,7 @@ int transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop) * 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) @@ -132,6 +136,10 @@ int transport_lookup(const char *domain, VSTRING *channel, VSTRING *nexthop) } 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); diff --git a/gnu/dist/postfix/src/trivial-rewrite/trivial-rewrite.c b/gnu/dist/postfix/src/trivial-rewrite/trivial-rewrite.c index 61624ada5e4..71dc8b2f1dd 100644 --- a/gnu/dist/postfix/src/trivial-rewrite/trivial-rewrite.c +++ b/gnu/dist/postfix/src/trivial-rewrite/trivial-rewrite.c @@ -80,7 +80,7 @@ /* .fi /* .IP \fBlocal_transport\fR /* Where to deliver mail for destinations that match $\fBmydestination\fR -/* or $\fBinet_interfaces\fR. +/* or $\fBinet_interfaces\fR. /* The default transport is \fBlocal\fR. /* .sp /* Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5) @@ -92,6 +92,10 @@ /* .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 +/* 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. @@ -181,7 +185,9 @@ static void rewrite_service(VSTREAM *stream, char *unused_service, char **argv) * dedicated to address rewriting. All connection-management stuff is * handled by the common code in multi_server.c. */ - if (mail_scan(stream, "%s", command) == 1) { + if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE, + ATTR_TYPE_STR, MAIL_ATTR_REQ, command, + ATTR_TYPE_END) == 1) { if (strcmp(vstring_str(command), REWRITE_ADDR) == 0) { status = rewrite_proto(stream); } else if (strcmp(vstring_str(command), RESOLVE_ADDR) == 0) { diff --git a/gnu/dist/postfix/src/util/alldig.c b/gnu/dist/postfix/src/util/alldig.c new file mode 100644 index 00000000000..c4815f68c67 --- /dev/null +++ b/gnu/dist/postfix/src/util/alldig.c @@ -0,0 +1,48 @@ +/*++ +/* NAME +/* alldig 3 +/* SUMMARY +/* predicate if string is all numerical +/* SYNOPSIS +/* #include <stringops.h> +/* +/* int alldig(string) +/* const char *string; +/* DESCRIPTION +/* alldig() determines if its argument is an all-numerical string. +/* SEE ALSO +/* An alldig() routine appears in Brian W. Kernighan, P.J. Plauger: +/* "Software Tools", Addison-Wesley 1976. +/* 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 <ctype.h> + +/* Utility library. */ + +#include <stringops.h> + +/* alldig - return true if string is all digits */ + +int alldig(const char *string) +{ + const char *cp; + + if (*string == 0) + return (0); + for (cp = string; *cp != 0; cp++) + if (!ISDIGIT(*cp)) + return (0); + return (1); +} diff --git a/gnu/dist/postfix/src/util/attr.h b/gnu/dist/postfix/src/util/attr.h index e81381ed337..c656dadf8e1 100644 --- a/gnu/dist/postfix/src/util/attr.h +++ b/gnu/dist/postfix/src/util/attr.h @@ -5,19 +5,80 @@ /* NAME /* attr 3h /* SUMMARY -/* attribute list manager +/* attribute list manipulations /* SYNOPSIS -/* #include <attr.h> -/* DESCRIPTION -/* .nf +/* #include "attr.h" + DESCRIPTION + .nf /* - * External interface. + * System library. */ -extern void attr_enter(HTABLE *, const char *, const char *); -extern void attr_free(HTABLE *); +#include <stdarg.h> -#define attr_find(table, name) htable_find((table), (name)) + /* + * Utility library. + */ +#include <vstream.h> + + /* + * Attribute types. See attr_scan(3) for documentation. + */ +#define ATTR_TYPE_END 0 /* end of data */ +#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_NONE 0 +#define ATTR_FLAG_MISSING (1<<0) /* Flag missing attribute */ +#define ATTR_FLAG_EXTRA (1<<1) /* Flag spurious attribute */ +#define ATTR_FLAG_MORE (1<<2) /* Don't skip or terminate */ + +#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_print0.c. + */ +extern int attr_print0(VSTREAM *, int,...); +extern int attr_vprint0(VSTREAM *, int, va_list); + + /* + * attr_scan0.c. + */ +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 + * routines. + */ +#ifdef TEST +#define ATTR_NAME_NUM "number" +#define ATTR_NAME_STR "string" +#define ATTR_NAME_LONG "long_number" +#endif /* LICENSE /* .ad diff --git a/gnu/dist/postfix/src/util/attr_print0.c b/gnu/dist/postfix/src/util/attr_print0.c new file mode 100644 index 00000000000..c39b72104da --- /dev/null +++ b/gnu/dist/postfix/src/util/attr_print0.c @@ -0,0 +1,209 @@ +/*++ +/* 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> +#include <string.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 diff --git a/gnu/dist/postfix/src/util/attr_print64.c b/gnu/dist/postfix/src/util/attr_print64.c new file mode 100644 index 00000000000..1fc37d7b346 --- /dev/null +++ b/gnu/dist/postfix/src/util/attr_print64.c @@ -0,0 +1,253 @@ +/*++ +/* NAME +/* attr_print64 3 +/* SUMMARY +/* send attributes over byte stream +/* SYNOPSIS +/* #include <attr.h> +/* +/* int attr_print64(fp, flags, type, name, ...) +/* VSTREAM fp; +/* int flags; +/* int type; +/* char *name; +/* +/* int attr_vprint64(fp, flags, ap) +/* VSTREAM fp; +/* int flags; +/* va_list ap; +/* DESCRIPTION +/* 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_scan64(). The stream +/* is not flushed. +/* +/* 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_print64() argument list. This routine satisfies the formatting +/* rules as outlined in attr_scan64(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_print64() 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_scan64(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> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <vstream.h> +#include <htable.h> +#include <base64_code.h> +#include <attr.h> + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +/* attr_print64_str - encode and send attribute information */ + +static void attr_print64_str(VSTREAM *fp, const char *str, int len) +{ + static VSTRING *base64_buf; + + if (base64_buf == 0) + base64_buf = vstring_alloc(10); + + base64_encode(base64_buf, str, len); + vstream_fputs(STR(base64_buf), fp); +} + +static void attr_print64_num(VSTREAM *fp, unsigned num) +{ + static VSTRING *plain; + + if (plain == 0) + plain = vstring_alloc(10); + + vstring_sprintf(plain, "%u", num); + attr_print64_str(fp, STR(plain), LEN(plain)); +} + +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_vprint64(VSTREAM *fp, int flags, va_list ap) +{ + 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; + + /* + * 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 *); + attr_print64_str(fp, attr_name, strlen(attr_name)); + int_val = va_arg(ap, int); + VSTREAM_PUTC(':', fp); + 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_print64_str(fp, attr_name, strlen(attr_name)); + str_val = va_arg(ap, char *); + VSTREAM_PUTC(':', fp); + 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_print64_str(fp, ht[0]->key, strlen(ht[0]->key)); + VSTREAM_PUTC(':', fp); + 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); + if (ht[1] != 0) + VSTREAM_PUTC('\n', fp); + } + myfree((char *) ht_info_list); + break; + default: + msg_panic("%s: unknown type code: %d", myname, attr_type); + } + VSTREAM_PUTC('\n', fp); + } + if ((flags & ATTR_FLAG_MORE) == 0) + VSTREAM_PUTC('\n', fp); + return (vstream_ferror(fp)); +} + +int attr_print64(VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vprint64(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan64 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_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"); + + htable_free(table, myfree); + return (0); +} + +#endif diff --git a/gnu/dist/postfix/src/util/attr_scan.ref b/gnu/dist/postfix/src/util/attr_scan.ref new file mode 100644 index 00000000000..cd06a27d82d --- /dev/null +++ b/gnu/dist/postfix/src/util/attr_scan.ref @@ -0,0 +1,36 @@ +./attr_print: send attr number = 4711 +./attr_print: send attr string = whoopee +./attr_print: send attr name foo-name value foo-value +./attr_print: send attr name bar-name value bar-value +./attr_print: send attr number = 4711 +./attr_print: send attr string = whoopee +./attr_scan: unknown_stream: wanted attribute: number +./attr_scan: input attribute name: number +./attr_scan: input attribute value: 4711 +./attr_scan: unknown_stream: wanted attribute: string +./attr_scan: input attribute name: string +./attr_scan: input attribute value: whoopee +./attr_scan: unknown_stream: wanted attribute: (any attribute name or list terminator) +./attr_scan: input attribute name: foo-name +./attr_scan: input attribute value: foo-value +./attr_scan: unknown_stream: wanted attribute: (any attribute name or list terminator) +./attr_scan: input attribute name: bar-name +./attr_scan: input attribute value: bar-value +./attr_scan: unknown_stream: wanted attribute: (any attribute name or list terminator) +./attr_scan: input attribute name: (end) +./attr_scan: unknown_stream: wanted attribute: number +./attr_scan: input attribute name: number +./attr_scan: input attribute value: 4711 +./attr_scan: unknown_stream: wanted attribute: string +./attr_scan: input attribute name: string +./attr_scan: input attribute value: whoopee +./attr_scan: unknown_stream: wanted attribute: (list terminator) +./attr_scan: input attribute name: (end) +number 4711 +string whoopee +(hash) foo-name foo-value +(hash) bar-name bar-value +number 4711 +string whoopee +(hash) foo-name foo-value +(hash) bar-name bar-value diff --git a/gnu/dist/postfix/src/util/attr_scan0.c b/gnu/dist/postfix/src/util/attr_scan0.c new file mode 100644 index 00000000000..ea4cf880886 --- /dev/null +++ b/gnu/dist/postfix/src/util/attr_scan0.c @@ -0,0 +1,441 @@ +/*++ +/* 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 <string.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 diff --git a/gnu/dist/postfix/src/util/attr_scan0.ref b/gnu/dist/postfix/src/util/attr_scan0.ref new file mode 100644 index 00000000000..105382fd1ef --- /dev/null +++ b/gnu/dist/postfix/src/util/attr_scan0.ref @@ -0,0 +1,46 @@ +./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 diff --git a/gnu/dist/postfix/src/util/attr_scan64.c b/gnu/dist/postfix/src/util/attr_scan64.c new file mode 100644 index 00000000000..d8631ef1cac --- /dev/null +++ b/gnu/dist/postfix/src/util/attr_scan64.c @@ -0,0 +1,506 @@ +/*++ +/* NAME +/* attr_scan64 3 +/* SUMMARY +/* recover attributes from byte stream +/* SYNOPSIS +/* #include <attr.h> +/* +/* int attr_scan64(fp, flags, type, name, ...) +/* VSTREAM fp; +/* int flags; +/* int type; +/* char *name; +/* +/* int attr_vscan64(fp, flags, ap) +/* VSTREAM fp; +/* int flags; +/* va_list ap; +/* DESCRIPTION +/* 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_print64(). +/* +/* 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 +/* for zero or more instances of the specified item, and where +/* (item1 | item2) stands for choice: +/* +/* .in +5 +/* attr-list :== simple-attr* newline +/* .br +/* simple-attr :== attr-name colon attr-value newline +/* .br +/* attr-name :== any base64 encoded string +/* .br +/* attr-value :== any base64 encoded string +/* .br +/* colon :== the ASCII colon character +/* .br +/* newline :== the ASCII newline character +/* .in +/* +/* All attribute names and attribute values are sent as base64-encoded +/* strings. Each base64 encoding must be no longer than 2*var_line_limit +/* 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_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 +/* 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_scan64() operations from the +/* same 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 +/* 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_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 +/* as the number of entries stored into the table). +/* +/* Panic: interface violation. All system call errors are fatal. +/* SEE ALSO +/* attr_print64(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 <string.h> +#include <stdio.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <vstream.h> +#include <vstring.h> +#include <htable.h> +#include <base64_code.h> +#include <attr.h> + +/* Application specific. */ + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +/* attr_scan64_string - pull a string from the input stream */ + +static int attr_scan64_string(VSTREAM *fp, VSTRING *plain_buf, const char *context) +{ + static VSTRING *base64_buf = 0; + extern int var_line_limit; /* XXX */ + int limit = var_line_limit * 2; + int ch; + + if (base64_buf == 0) + base64_buf = vstring_alloc(10); + + VSTRING_RESET(base64_buf); + while ((ch = VSTREAM_GETC(fp)) != ':' && ch != '\n') { + if (ch == VSTREAM_EOF) { + msg_warn("premature end-of-input from %s while reading %s", + VSTREAM_PATH(fp), context); + return (-1); + } + VSTRING_ADDCH(base64_buf, ch); +#if 0 + if (LEN(base64_buf) > limit) { + msg_warn("string length > %d characters from %s while reading %s", + limit, VSTREAM_PATH(fp), context); + return (-1); + } +#endif + } + VSTRING_TERMINATE(base64_buf); + if (base64_decode(plain_buf, STR(base64_buf), LEN(base64_buf)) == 0) { + msg_warn("malformed base64 data from %s: %.100s", + VSTREAM_PATH(fp), STR(base64_buf)); + return (-1); + } + if (msg_verbose) + msg_info("%s: %s", context, *STR(plain_buf) ? STR(plain_buf) : "(end)"); + return (ch); +} + +/* attr_scan64_number - pull a number from the input stream */ + +static int attr_scan64_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf, + const char *context) +{ + char junk = 0; + int ch; + + 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", + VSTREAM_PATH(fp), context, STR(str_buf)); + return (-1); + } + return (ch); +} + +/* attr_scan64_long_number - pull a number from the input stream */ + +static int attr_scan64_long_number(VSTREAM *fp, unsigned long *ptr, + VSTRING *str_buf, + const char *context) +{ + 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; + 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_scan64_string(fp, name_buf, + "input attribute name")) == VSTREAM_EOF) + return (-1); + if (ch == '\n' && 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. + */ + while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n') + /* void */ ; + } + + /* + * Do the requested conversion. If the target attribute is a + * non-array type, disallow sending a multi-valued attribute, and + * disallow sending no value. If the target attribute is an array + * type, allow the sender to send a zero-element array (i.e. no value + * at all). XXX Need to impose a bound on the number of array + * elements. + */ + switch (wanted_type) { + case ATTR_TYPE_NUM: + if (ch != ':') { + msg_warn("missing value for number attribute %s from %s", + STR(name_buf), VSTREAM_PATH(fp)); + return (-1); + } + number = va_arg(ap, unsigned int *); + 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", + STR(name_buf), VSTREAM_PATH(fp)); + return (-1); + } + break; + case ATTR_TYPE_STR: + if (ch != ':') { + msg_warn("missing value for string attribute %s from %s", + STR(name_buf), VSTREAM_PATH(fp)); + return (-1); + } + string = va_arg(ap, VSTRING *); + 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); + } + break; + case ATTR_TYPE_HASH: + if (ch != ':') { + msg_warn("missing value for string attribute %s from %s", + STR(name_buf), VSTREAM_PATH(fp)); + return (-1); + } + 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", + STR(name_buf), VSTREAM_PATH(fp)); + 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_scan64 - read attribute list from stream */ + +int attr_scan64(VSTREAM *fp, int flags,...) +{ + va_list ap; + int ret; + + va_start(ap, flags); + ret = attr_vscan64(fp, flags, ap); + va_end(ap); + return (ret); +} + +#ifdef TEST + + /* + * Proof of concept test program. Mirror image of the attr_scan64 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_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++) + 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_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++) + 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 diff --git a/gnu/dist/postfix/src/util/attr_scan64.ref b/gnu/dist/postfix/src/util/attr_scan64.ref new file mode 100644 index 00000000000..1b3a01581cf --- /dev/null +++ b/gnu/dist/postfix/src/util/attr_scan64.ref @@ -0,0 +1,46 @@ +./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 diff --git a/gnu/dist/postfix/src/util/base64_code.c b/gnu/dist/postfix/src/util/base64_code.c new file mode 100644 index 00000000000..21210e6053d --- /dev/null +++ b/gnu/dist/postfix/src/util/base64_code.c @@ -0,0 +1,201 @@ +/*++ +/* NAME +/* base64_code 3 +/* SUMMARY +/* encode/decode data, base 64 style +/* SYNOPSIS +/* #include <base64_code.h> +/* +/* VSTRING *base64_encode(result, in, len) +/* VSTRING *result; +/* const char *in; +/* int len; +/* +/* VSTRING *base64_decode(result, in, len) +/* VSTRING *result; +/* const char *in; +/* int len; +/* DESCRIPTION +/* base64_encode() takes a block of len bytes and encodes it as one +/* null-terminated string. The result value is the result argument. +/* +/* base64_decode() performs the opposite transformation. The result +/* value is the result argument. The result is null terminated, whether +/* or not that makes sense. +/* DIAGNOSTICS +/* base64_decode () returns a null pointer when the input contains +/* characters not in the base 64 alphabet. +/* 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 <ctype.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <vstring.h> +#include <base64_code.h> + +/* Application-specific. */ + +static unsigned char to_b64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +#define UNSIG_CHAR_PTR(x) ((unsigned char *)(x)) + +/* base64_encode - raw data to encoded */ + +VSTRING *base64_encode(VSTRING *result, const char *in, int len) +{ + const unsigned char *cp; + int count; + + /* + * Encode 3 -> 4. + */ + VSTRING_RESET(result); + for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 3, cp += 3) { + VSTRING_ADDCH(result, to_b64[cp[0] >> 2]); + if (count > 1) { + VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4 | cp[1] >> 4]); + if (count > 2) { + VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2 | cp[2] >> 6]); + VSTRING_ADDCH(result, to_b64[cp[2] & 0x3f]); + } else { + VSTRING_ADDCH(result, to_b64[(cp[1] & 0xf) << 2]); + VSTRING_ADDCH(result, '='); + break; + } + } else { + VSTRING_ADDCH(result, to_b64[(cp[0] & 0x3) << 4]); + VSTRING_ADDCH(result, '='); + VSTRING_ADDCH(result, '='); + break; + } + } + VSTRING_TERMINATE(result); + return (result); +} + +/* base64_decode - encoded data to raw */ + +VSTRING *base64_decode(VSTRING *result, const char *in, int len) +{ + static unsigned char *un_b64 = 0; + const unsigned char *cp; + int count; + int ch0; + int ch1; + int ch2; + int ch3; + +#define CHARS_PER_BYTE 256 +#define INVALID 0xff + + /* + * Sanity check. + */ + if (len % 4) + return (0); + + /* + * Once: initialize the decoding lookup table on the fly. + */ + if (un_b64 == 0) { + un_b64 = (unsigned char *) mymalloc(CHARS_PER_BYTE); + memset(un_b64, INVALID, CHARS_PER_BYTE); + for (cp = to_b64; cp < to_b64 + sizeof(to_b64); cp++) + un_b64[*cp] = cp - to_b64; + } + + /* + * Decode 4 -> 3. + */ + VSTRING_RESET(result); + for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 4) { + if ((ch0 = un_b64[*cp++]) == INVALID + || (ch1 = un_b64[*cp++]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch0 << 2 | ch1 >> 4); + if ((ch2 = *cp++) == '=') + break; + if ((ch2 = un_b64[ch2]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch1 << 4 | ch2 >> 2); + if ((ch3 = *cp++) == '=') + break; + if ((ch3 = un_b64[ch3]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch2 << 6 | ch3); + } + VSTRING_TERMINATE(result); + return (result); +} + +#ifdef TEST + + /* + * Proof-of-concept test program: convert to base 64 and back. + */ + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +int main(int unused_argc, char **unused_argv) +{ + VSTRING *b1 = vstring_alloc(1); + VSTRING *b2 = vstring_alloc(1); + char *test = "this is a test"; + +#define DECODE(b,x,l) { \ + if (base64_decode((b),(x),(l)) == 0) \ + msg_panic("bad base64: %s", (x)); \ + } +#define VERIFY(b,t) { \ + if (strcmp((b), (t)) != 0) \ + msg_panic("bad test: %s", (b)); \ + } + + base64_encode(b1, test, strlen(test)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + base64_encode(b1, test, strlen(test)); + base64_encode(b2, STR(b1), LEN(b1)); + base64_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + base64_encode(b1, test, strlen(test)); + base64_encode(b2, STR(b1), LEN(b1)); + base64_encode(b1, STR(b2), LEN(b2)); + base64_encode(b2, STR(b1), LEN(b1)); + base64_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), test); + + vstring_free(b1); + vstring_free(b2); + return (0); +} + +#endif diff --git a/gnu/dist/postfix/src/util/base64_code.h b/gnu/dist/postfix/src/util/base64_code.h new file mode 100644 index 00000000000..d018947e1c1 --- /dev/null +++ b/gnu/dist/postfix/src/util/base64_code.h @@ -0,0 +1,36 @@ +#ifndef _BASE64_CODE_H_INCLUDED_ +#define _BASE64_CODE_H_INCLUDED_ + +/*++ +/* NAME +/* base64_code 3h +/* SUMMARY +/* encode/decode data, base 64 style +/* SYNOPSIS +/* #include <base64_code.h> +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include <vstring.h> + + /* + * External interface. + */ +extern VSTRING *base64_encode(VSTRING *, const char *, int); +extern VSTRING *base64_decode(VSTRING *, const char *, int); + +/* 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 diff --git a/gnu/dist/postfix/src/util/cache.in b/gnu/dist/postfix/src/util/cache.in new file mode 100644 index 00000000000..89974bd2c66 --- /dev/null +++ b/gnu/dist/postfix/src/util/cache.in @@ -0,0 +1,26 @@ +a +1 +b +2 +c +3 +d +4 +e +5 +f +6 +f +e +d +c +b +a +1 +b +c +d +e +f +6 +f diff --git a/gnu/dist/postfix/src/util/dict.c b/gnu/dist/postfix/src/util/dict.c index 7d07d3be0be..5fd30887983 100644 --- a/gnu/dist/postfix/src/util/dict.c +++ b/gnu/dist/postfix/src/util/dict.c @@ -182,6 +182,7 @@ #include "vstring.h" #include "readlline.h" #include "mac_parse.h" +#include "stringops.h" #include "dict.h" #include "dict_ht.h" @@ -372,43 +373,18 @@ void dict_load_file(const char *dict_name, const char *path) void dict_load_fp(const char *dict_name, VSTREAM *fp) { VSTRING *buf; - char *start; char *member; char *val; - char *cp; - char *ep; int lineno; - - /* - * Ugly macros to make complex expressions less unreadable. - */ -#define SKIP(start, var, cond) \ - for (var = start; *var && (cond); var++); - -#define TRIM(s) { \ - char *p; \ - for (p = (s) + strlen(s); p > (s) && ISSPACE(p[-1]); p--); \ - *p = 0; \ - } + const char *err; buf = vstring_alloc(100); lineno = 0; - while (readlline(buf, fp, &lineno, READLL_STRIPNL)) { - start = STR(buf); - SKIP(start, member, ISSPACE(*member)); /* find member begin */ - if (*member == 0 || *member == '#') - continue; /* comment or blank line */ - SKIP(member, ep, !ISSPACE(*ep) && *ep != '='); /* find member end */ - SKIP(ep, cp, ISSPACE(*cp)); /* skip blanks before '=' */ - if (*cp && *cp != '=') /* need '=' or end of string */ - msg_fatal("%s, line %d: whitespace in attribute name: \"%s\"", - VSTREAM_PATH(fp), lineno, member); - if (*cp) - cp++; /* skip over '=' */ - *ep = 0; /* terminate member name */ - SKIP(cp, val, ISSPACE(*val)); /* skip leading blanks */ - TRIM(val); /* trim trailing blanks */ + while (readlline(buf, fp, &lineno)) { + if ((err = split_nameval(STR(buf), &member, &val)) != 0) + msg_fatal("%s, line %d: %s: \"%s\"", + VSTREAM_PATH(fp), lineno, err, STR(buf)); dict_update(dict_name, member, val); } vstring_free(buf); diff --git a/gnu/dist/postfix/src/util/dict.h b/gnu/dist/postfix/src/util/dict.h index 5a669aa096d..1d9d8c4a129 100644 --- a/gnu/dist/postfix/src/util/dict.h +++ b/gnu/dist/postfix/src/util/dict.h @@ -55,6 +55,7 @@ extern DICT *dict_debug(DICT *); #define DICT_FLAG_DUP_REPLACE (1<<7) /* if file, replace dups */ #define DICT_FLAG_SYNC_UPDATE (1<<8) /* if file, sync updates */ #define DICT_FLAG_DEBUG (1<<9) /* log access */ +#define DICT_FLAG_FOLD_KEY (1<<10) /* lowercase the lookup key */ extern int dict_unknown_allowed; extern int dict_errno; diff --git a/gnu/dist/postfix/src/util/dict_db.c b/gnu/dist/postfix/src/util/dict_db.c index 69518e10f8a..423244a3a7f 100644 --- a/gnu/dist/postfix/src/util/dict_db.c +++ b/gnu/dist/postfix/src/util/dict_db.c @@ -437,6 +437,23 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags, #endif + /* + * Mismatches between #include file and library are a common cause for + * trouble. + */ +#if DB_VERSION_MAJOR > 1 + int major_version; + int minor_version; + int patch_version; + + (void) db_version(&major_version, &minor_version, &patch_version); + if (major_version != DB_VERSION_MAJOR) + msg_fatal("incorrect version of Berkeley DB: " + "compiled against %d.%d.%d, linked against %d.%d.%d", + DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, + major_version, minor_version, patch_version); +#endif + db_path = concatenate(path, ".db", (char *) 0); /* diff --git a/gnu/dist/postfix/src/util/dict_ldap.c b/gnu/dist/postfix/src/util/dict_ldap.c index ebbfe8f9003..2cf8936c43e 100644 --- a/gnu/dist/postfix/src/util/dict_ldap.c +++ b/gnu/dist/postfix/src/util/dict_ldap.c @@ -62,6 +62,9 @@ /* The cache size in bytes. Does nothing if the cache is off, of course. /* .IP \fIldapsource_\fRdereference /* How to handle LDAP aliases. See ldap.h or ldap_open(3) man page. +/* .IP \fIldapsource_\fRdebuglevel +/* Debug level. See 'loglevel' option in slapd.conf(5) man page. +/* Currently only in openldap libraries (and derivatives). /* SEE ALSO /* dict(3) generic dictionary manager /* AUTHOR(S) @@ -77,6 +80,9 @@ /* John Hensley /* john@sunislelodge.com /* +/* LaMont Jones +/* lamont@hp.com +/* /*--*/ /* System library. */ @@ -94,6 +100,14 @@ #include <ldap.h> #include <string.h> +/* Handle differences between LDAP SDK's constant definitions */ +#ifndef LDAP_CONST +#define LDAP_CONST const +#endif +#ifndef LDAP_OPT_SUCCESS +#define LDAP_OPT_SUCCESS 0 +#endif + /* Utility library. */ #include "match_list.h" @@ -131,6 +145,7 @@ typedef struct { long cache_expiry; long cache_size; int dereference; + int debuglevel; LDAP *ld; } DICT_LDAP; @@ -139,6 +154,13 @@ typedef struct { */ static jmp_buf env; +static void dict_ldap_logprint(LDAP_CONST char *data) +{ + char *myname = "dict_ldap_debug"; + + msg_info("%s: %s", myname, data); +} + static void dict_ldap_timeout(int unused_sig) { longjmp(env, 1); @@ -153,6 +175,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) #ifdef LDAP_API_FEATURE_X_MEMCACHE LDAPMemCache *dircache; + #endif #ifdef LDAP_OPT_NETWORK_TIMEOUT @@ -170,14 +193,16 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) dict_ldap->ld = ldap_init(dict_ldap->server_host, (int) dict_ldap->server_port); if (dict_ldap->ld == NULL) { - msg_warn("%s: Unable to int LDAP server %s", + msg_warn("%s: Unable to init LDAP server %s", myname, dict_ldap->server_host); dict_errno = DICT_ERR_RETRY; return (-1); } mytimeval.tv_sec = dict_ldap->timeout; mytimeval.tv_usec = 0; - ldap_set_option(dict_ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, &mytimeval); + if (ldap_set_option(dict_ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, &mytimeval) != + LDAP_OPT_SUCCESS) + msg_warn("%s: Unable to set network timeout.", myname); #else if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) { msg_warn("%s: Error setting signal handler for open timeout: %m", @@ -212,11 +237,24 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) * Mattice for this, and to Hery Rakotoarisoa for the v3 update. */ #if (LDAP_API_VERSION >= 2000) - ldap_set_option(dict_ldap->ld, LDAP_OPT_DEREF, &(dict_ldap->dereference)); + if (ldap_set_option(dict_ldap->ld, LDAP_OPT_DEREF, + &(dict_ldap->dereference)) != LDAP_OPT_SUCCESS) + msg_warn("%s: Unable to set dereference option.", myname); #else dict_ldap->ld->ld_deref = dict_ldap->dereference; #endif +#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN) + if (dict_ldap->debuglevel > 0 && + ber_set_option(NULL, LBER_OPT_LOG_PRINT_FN, + (LDAP_CONST *) dict_ldap_logprint) != LBER_OPT_SUCCESS) + msg_warn("%s: Unable to set ber logprint function.", myname); + if (ldap_set_option(dict_ldap->ld, LDAP_OPT_DEBUG_LEVEL, + &(dict_ldap->debuglevel)) != LDAP_OPT_SUCCESS) + msg_warn("%s: Unable to set LDAP debug level.", myname); +#endif + + /* * If this server requires a bind, do so. Thanks to Sam Tardieu for * noticing that the original bind call was broken. @@ -267,7 +305,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap) } else { if (msg_verbose) msg_info("%s: Caching enabled for %s", - myname, dict_ldap->ldapsource); + myname, dict_ldap->ldapsource); } } #else @@ -342,7 +380,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res, if (strcasecmp(dict_ldap->result_attributes->argv[i], attr) == 0) { if (msg_verbose) - msg_info("%s: search returned %d value(s) for requested result attribute %s", myname, i, attr); + msg_info("%s: search returned %ld value(s) for requested result attribute %s", myname, i, attr); break; } } @@ -374,21 +412,23 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage * res, 0, &tv, &resloop); } switch (rc) { - case LDAP_SUCCESS: - dict_ldap_get_values(dict_ldap, resloop, result); - break; - case LDAP_NO_SUCH_OBJECT: - /* Go ahead and treat this as though the DN existed - * and just didn't have any result attributes. - */ - msg_warn("%s: DN %s not found, skipping ", myname, - vals[i]); - break; - default: - msg_warn("%s: search error %d: %s ", myname, rc, + case LDAP_SUCCESS: + dict_ldap_get_values(dict_ldap, resloop, result); + break; + case LDAP_NO_SUCH_OBJECT: + + /* + * Go ahead and treat this as though the DN existed + * and just didn't have any result attributes. + */ + msg_warn("%s: DN %s not found, skipping ", myname, + vals[i]); + break; + default: + msg_warn("%s: search error %d: %s ", myname, rc, ldap_err2string(rc)); - dict_errno = DICT_ERR_RETRY; - break; + dict_errno = DICT_ERR_RETRY; + break; } if (resloop != 0) @@ -428,11 +468,12 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) * load on the LDAP server. */ if (dict_ldap->domain) { - const char *p=strrchr(name,'@'); + const char *p = strrchr(name, '@'); + if (p != 0) - p=p+1; + p = p + 1; else - p=name; + p = name; if (match_list_match(dict_ldap->domain, p) == 0) { if (msg_verbose) msg_info("%s: domain of %s not found in domain list", myname, @@ -454,7 +495,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) if (dict_ldap->ld == NULL) { if (msg_verbose) msg_info - ("%s: No existing connection for ldapsource %s, reopening", + ("%s: No existing connection for LDAP source %s, reopening", myname, dict_ldap->ldapsource); dict_ldap_connect(dict_ldap); @@ -465,7 +506,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) if (dict_errno) return (0); } else if (msg_verbose) - msg_info("%s: Using existing connection for ldapsource %s", + msg_info("%s: Using existing connection for LDAP source %s", myname, dict_ldap->ldapsource); @@ -540,31 +581,32 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) /* * Make sure it's %[sud] and not something else. For backward - * compatibilty, treat anything other than %u or %d as %s, with - * a warning. + * compatibilty, treat anything other than %u or %d as %s, with a + * warning. */ if (*(sub) == '%') { - char *u=vstring_str(escaped_name); - char *p=strchr(u,'@'); - switch (*(sub+1)) { - case 'd': - if (p) - vstring_strcat(filter_buf, p+1); - break; - case 'u': - if (p) - vstring_strncat(filter_buf, u, p-u); - else - vstring_strcat(filter_buf, u); - break; - default: - msg_warn - ("%s: Invalid lookup substitution format '%%%c'!", - myname, *(sub + 1)); - /* fall through */ - case 's': + char *u = vstring_str(escaped_name); + char *p = strchr(u, '@'); + + switch (*(sub + 1)) { + case 'd': + if (p) + vstring_strcat(filter_buf, p + 1); + break; + case 'u': + if (p) + vstring_strncat(filter_buf, u, p - u); + else vstring_strcat(filter_buf, u); - break; + break; + default: + msg_warn + ("%s: Invalid lookup substitution format '%%%c'!", + myname, *(sub + 1)); + /* fall through */ + case 's': + vstring_strcat(filter_buf, u); + break; } sub++; } else @@ -580,11 +622,35 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) msg_info("%s: Searching with filter %s", myname, vstring_str(filter_buf)); - if ((rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base, - dict_ldap->scope, - vstring_str(filter_buf), - dict_ldap->result_attributes->argv, - 0, &tv, &res)) == LDAP_SUCCESS) { + rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base, + dict_ldap->scope, + vstring_str(filter_buf), + dict_ldap->result_attributes->argv, + 0, &tv, &res); + + if (rc == LDAP_SERVER_DOWN) { + if (msg_verbose) + msg_info("%s: Lost connection for LDAP source %s, reopening", + myname, dict_ldap->ldapsource); + + ldap_unbind(dict_ldap->ld); + dict_ldap->ld = NULL; + dict_ldap_connect(dict_ldap); + + /* + * if dict_ldap_connect() set dict_errno, abort. + */ + if (dict_errno) + return (0); + + rc = ldap_search_st(dict_ldap->ld, dict_ldap->search_base, + dict_ldap->scope, + vstring_str(filter_buf), + dict_ldap->result_attributes->argv, + 0, &tv, &res); + + } + if (rc == LDAP_SUCCESS) { /* * Search worked; extract the requested result_attribute. @@ -598,7 +664,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) */ #if (LDAP_API_VERSION >= 2000) - ldap_get_option(dict_ldap->ld, LDAP_OPT_ERROR_NUMBER, &rc); + if (ldap_get_option(dict_ldap->ld, LDAP_OPT_ERROR_NUMBER, &rc) != + LDAP_OPT_SUCCESS) + msg_warn("%s: Unable to get last error number.", myname); if (rc != LDAP_SUCCESS && rc != LDAP_DECODING_ERROR) msg_warn("%s: Had some trouble with entries returned by search: %s", myname, ldap_err2string(rc)); #else @@ -641,7 +709,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name) ldap_msgfree(res); if (filter_buf != 0) vstring_free(filter_buf); - if (escaped_name != 0) + if (escaped_name != 0) vstring_free(escaped_name); /* @@ -759,7 +827,12 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) mystrdup((char *) get_mail_conf_str(vstring_str(config_param), "", 0, 0)); if (*domainlist) { +#ifdef MATCH_FLAG_NONE + dict_ldap->domain = match_list_init(MATCH_FLAG_NONE, + domainlist, 1, match_string); +#else dict_ldap->domain = match_list_init(domainlist, 1, match_string); +#endif if (dict_ldap->domain == NULL) msg_warn("%s: domain match list creation using \"%s\" failed, will continue without it", myname, domainlist); if (msg_verbose) @@ -892,6 +965,18 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) msg_info("%s: %s is %d", myname, vstring_str(config_param), dict_ldap->dereference); + /* + * Debug level. + */ +#if defined(LDAP_OPT_DEBUG_LEVEL) && defined(LBER_OPT_LOG_PRINT_FN) + vstring_sprintf(config_param, "%s_debuglevel", ldapsource); + dict_ldap->debuglevel = get_mail_conf_int(vstring_str(config_param), 0, 0, + 0); + if (msg_verbose) + msg_info("%s: %s is %d", myname, vstring_str(config_param), + dict_ldap->debuglevel); +#endif + dict_ldap_connect(dict_ldap); /* @@ -908,7 +993,7 @@ DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags) /* * Otherwise, we're all set. Return the new dict_ldap structure. */ - return (DICT_DEBUG(&dict_ldap->dict)); + return (DICT_DEBUG (&dict_ldap->dict)); } #endif diff --git a/gnu/dist/postfix/src/util/dict_mysql.c b/gnu/dist/postfix/src/util/dict_mysql.c index 28fc7015639..f778e928d08 100644 --- a/gnu/dist/postfix/src/util/dict_mysql.c +++ b/gnu/dist/postfix/src/util/dict_mysql.c @@ -274,14 +274,14 @@ static MYSQL_RES *plmysql_query(PLMYSQL *PLDB, if (res == 0 && host->stat == STATACTIVE) { if (!(mysql_query(host->db, query))) { if ((res = mysql_store_result(host->db)) == 0) { - msg_warn("%s", mysql_error(host->db)); + msg_warn("mysql query failed: %s", mysql_error(host->db)); plmysql_down_host(host); } else { if (msg_verbose) msg_info("dict_mysql: successful query from host %s", host->hostname); } } else { - msg_warn("%s", mysql_error(host->db)); + msg_warn("mysql query failed: %s", mysql_error(host->db)); plmysql_down_host(host); } } @@ -323,7 +323,8 @@ static void plmysql_connect_single(HOST *host, char *dbname, char *username, cha host->hostname); host->stat = STATACTIVE; } else { - msg_warn("%s", mysql_error(host->db)); + msg_warn("connect to mysql server %s: %s", + host->hostname, mysql_error(host->db)); plmysql_down_host(host); } if (hostname) @@ -366,7 +367,7 @@ DICT *dict_mysql_open(const char *name, int unused_open_flags, int dict_flags) if (dict_mysql->pldb == NULL) msg_fatal("couldn't intialize pldb!\n"); dict_register(name, (DICT *) dict_mysql); - return (DICT_DEBUG(&dict_mysql->dict)); + return (DICT_DEBUG (&dict_mysql->dict)); } /* mysqlname_parse - parse mysql configuration file */ diff --git a/gnu/dist/postfix/src/util/dict_open.c b/gnu/dist/postfix/src/util/dict_open.c index 2c15ac897ef..52a5dddc14b 100644 --- a/gnu/dist/postfix/src/util/dict_open.c +++ b/gnu/dist/postfix/src/util/dict_open.c @@ -81,6 +81,8 @@ /* .IP DICT_FLAG_SYNC_UPDATE /* With file-based maps, flush I/O buffers to file after each update. /* Thus feature is not supported with some file-based dictionaries. +/* .IP DICT_FLAG_FOLD_KEY +/* Fold the lookup key to lower case. /* .PP /* The dictionary types are as follows: /* .IP environ @@ -166,6 +168,7 @@ #include <dict_mysql.h> #include <dict_pcre.h> #include <dict_regexp.h> +#include <dict_static.h> #include <stringops.h> #include <split_at.h> #include <htable.h> @@ -212,6 +215,7 @@ static DICT_OPEN_INFO dict_open_info[] = { #ifdef HAS_POSIX_REGEXP DICT_TYPE_REGEXP, dict_regexp_open, #endif + DICT_TYPE_STATIC, dict_static_open, 0, }; @@ -339,6 +343,7 @@ static NORETURN usage(char *myname) int main(int argc, char **argv) { VSTRING *keybuf = vstring_alloc(1); + VSTRING *inbuf = vstring_alloc(1); DICT *dict; char *dict_name; int open_flags; @@ -374,13 +379,16 @@ int main(int argc, char **argv) dict_name = argv[optind]; dict = dict_open(dict_name, open_flags, DICT_FLAG_LOCK); dict_register(dict_name, dict); - while (vstring_fgets_nonl(keybuf, VSTREAM_IN)) { - bufp = vstring_str(keybuf); - if ((cmd = mystrtok(&bufp, " ")) == 0) + while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) { + bufp = vstring_str(inbuf); + if ((cmd = mystrtok(&bufp, " ")) == 0 || *bufp == 0) { + vstream_printf("usage: del key|get key|put key=value\n"); + vstream_fflush(VSTREAM_OUT); continue; + } if (dict_changed()) msg_warn("dictionary has changed"); - key = mystrtok(&bufp, " ="); + key = vstring_str(unescape(keybuf, mystrtok(&bufp, " ="))); value = mystrtok(&bufp, " ="); if (strcmp(cmd, "del") == 0 && key && !value) { if (dict_del(dict, key)) @@ -404,6 +412,7 @@ int main(int argc, char **argv) vstream_fflush(VSTREAM_OUT); } vstring_free(keybuf); + vstring_free(inbuf); dict_close(dict); return (0); } diff --git a/gnu/dist/postfix/src/util/dict_pcre.c b/gnu/dist/postfix/src/util/dict_pcre.c index 6d3c6f52393..1cc0f19f946 100644 --- a/gnu/dist/postfix/src/util/dict_pcre.c +++ b/gnu/dist/postfix/src/util/dict_pcre.c @@ -257,13 +257,7 @@ DICT *dict_pcre_open(const char *map, int unused_flags, int dict_flags) if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) { msg_fatal("open %s: %m", map); } - while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) { - - if (*vstring_str(line_buffer) == '#') /* Skip comments */ - continue; - - if (*vstring_str(line_buffer) == 0) /* Skip blank lines */ - continue; + while (readlline(line_buffer, map_fp, &lineno)) { p = vstring_str(line_buffer); trimblanks(p, 0)[0] = 0; /* Trim space at end */ diff --git a/gnu/dist/postfix/src/util/dict_regexp.c b/gnu/dist/postfix/src/util/dict_regexp.c index 1debbe96ff2..732208ca67d 100644 --- a/gnu/dist/postfix/src/util/dict_regexp.c +++ b/gnu/dist/postfix/src/util/dict_regexp.c @@ -356,15 +356,9 @@ DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags) if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) { msg_fatal("open %s: %m", map); } - while (readlline(line_buffer, map_fp, &lineno, READLL_STRIPNL)) { + while (readlline(line_buffer, map_fp, &lineno)) { p = vstring_str(line_buffer); - if (*p == '#') /* Skip comments */ - continue; - - if (*p == 0) /* Skip blank lines */ - continue; - trimblanks(p, 0)[0] = 0; /* Trim space at end */ rule = dict_regexp_parseline(lineno, p, &nsub, map_fp); diff --git a/gnu/dist/postfix/src/util/dict_static.c b/gnu/dist/postfix/src/util/dict_static.c new file mode 100644 index 00000000000..1b06a89aba4 --- /dev/null +++ b/gnu/dist/postfix/src/util/dict_static.c @@ -0,0 +1,72 @@ +/*++ +/* NAME +/* dict_static 3 +/* SUMMARY +/* dictionary manager interface to static variables +/* SYNOPSIS +/* #include <dict_static.h> +/* +/* DICT *dict_static_open(name, dummy, dict_flags) +/* const char *name; +/* int dummy; +/* int dict_flags; +/* DESCRIPTION +/* dict_static_open() implements a dummy dictionary that returns +/* as lookup result the dictionary name, regardless of the lookup +/* key value. +/* +/* The \fIdummy\fR argument is ignored. +/* SEE ALSO +/* dict(3) generic dictionary manager +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* jeffm +/* ghostgun.com +/*--*/ + +/* System library. */ + +#include "sys_defs.h" +#include <stdio.h> /* sprintf() prototype */ +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +/* Utility library. */ + +#include "mymalloc.h" +#include "msg.h" +#include "dict.h" +#include "dict_static.h" + +/* dict_static_lookup - access static value*/ + +static const char *dict_static_lookup(DICT *dict, const char *name) +{ + dict_errno = 0; + + return (dict->name); +} + +/* dict_static_close - close static dictionary */ + +static void dict_static_close(DICT *dict) +{ + dict_free(dict); +} + +/* dict_static_open - make association with static variable */ + +DICT *dict_static_open(const char *name, int unused_flags, int dict_flags) +{ + DICT *dict; + + dict = dict_alloc(DICT_TYPE_STATIC, name, sizeof(*dict)); + dict->lookup = dict_static_lookup; + dict->close = dict_static_close; + dict->flags = dict_flags | DICT_FLAG_FIXED; + return (DICT_DEBUG (dict)); +} diff --git a/gnu/dist/postfix/src/util/dict_static.h b/gnu/dist/postfix/src/util/dict_static.h new file mode 100644 index 00000000000..d4ad1cc11d3 --- /dev/null +++ b/gnu/dist/postfix/src/util/dict_static.h @@ -0,0 +1,35 @@ +#ifndef _DICT_STATIC_H_INCLUDED_ +#define _DICT_STATIC_H_INCLUDED_ + +/*++ +/* NAME +/* dict_static 3h +/* SUMMARY +/* dictionary manager interface to static settings +/* SYNOPSIS +/* #include <dict_static.h> +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include <dict.h> + + /* + * External interface. + */ +#define DICT_TYPE_STATIC "static" + +extern DICT *dict_static_open(const char *, int, int); + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* jeffm +/* ghostgun.com +/*--*/ + +#endif diff --git a/gnu/dist/postfix/src/util/dir_forest.c b/gnu/dist/postfix/src/util/dir_forest.c index 289cd122e10..929f937c730 100644 --- a/gnu/dist/postfix/src/util/dir_forest.c +++ b/gnu/dist/postfix/src/util/dir_forest.c @@ -104,7 +104,7 @@ char *dir_forest(VSTRING *buf, const char *path, int depth) } VSTRING_TERMINATE(buf); - if (msg_verbose) + if (msg_verbose > 1) msg_info("%s: %s -> %s", myname, path, vstring_str(buf)); return (vstring_str(buf)); } diff --git a/gnu/dist/postfix/src/util/events.c b/gnu/dist/postfix/src/util/events.c index c07504a26d6..99e1269565c 100644 --- a/gnu/dist/postfix/src/util/events.c +++ b/gnu/dist/postfix/src/util/events.c @@ -32,6 +32,8 @@ /* /* void event_disable_readwrite(fd) /* int fd; +/* +/* void event_drain() /* DESCRIPTION /* This module delivers I/O and timer events. /* Multiple I/O streams and timers can be monitored simultaneously. @@ -98,6 +100,10 @@ /* event_disable_readwrite() disables further I/O events on the specified /* I/O channel. The application is allowed to cancel non-existing /* I/O event requests. +/* +/* event_drain() repeatedly calls event_loop() until no more timer +/* events or I/O events are pending. This routine must not be called +/* from an event_whatever() callback routine. /* DIAGNOSTICS /* Panics: interface violations. Fatal errors: out of memory, /* system call failure. Warnings: the number of available @@ -242,6 +248,21 @@ time_t event_time(void) return (event_present); } +/* event_drain - loop until all pending events are done */ + +void event_drain(void) +{ + fd_set zero_mask; + + if (EVENT_INIT_NEEDED()) + return; + + FD_ZERO(&zero_mask); + while (event_timer_head.pred != event_timer_head.succ + || memcmp(&zero_mask, &event_xmask, sizeof(zero_mask)) != 0) + event_loop(-1); +} + /* event_enable_read - enable read events */ void event_enable_read(int fd, EVENT_NOTIFY_RDWR callback, char *context) diff --git a/gnu/dist/postfix/src/util/events.h b/gnu/dist/postfix/src/util/events.h index bc39b4787c4..d7235093b21 100644 --- a/gnu/dist/postfix/src/util/events.h +++ b/gnu/dist/postfix/src/util/events.h @@ -29,6 +29,7 @@ extern void event_disable_readwrite(int); extern time_t event_request_timer(EVENT_NOTIFY_TIME, char *, int); extern int event_cancel_timer(EVENT_NOTIFY_TIME, char *); extern void event_loop(int); +extern void event_drain(void); /* * Event codes. diff --git a/gnu/dist/postfix/src/util/fifo_trigger.c b/gnu/dist/postfix/src/util/fifo_trigger.c index b2801143610..841011a1bfc 100644 --- a/gnu/dist/postfix/src/util/fifo_trigger.c +++ b/gnu/dist/postfix/src/util/fifo_trigger.c @@ -13,7 +13,8 @@ /* int timeout; /* DESCRIPTION /* fifo_trigger() wakes up the named fifo server by writing -/* the contents of the specified buffer to the fifo. +/* the contents of the specified buffer to the fifo. There is +/* no guarantee that the written data will actually be received. /* /* Arguments: /* .IP service @@ -26,7 +27,7 @@ /* Deadline in seconds. Specify a value <= 0 to disable /* the time limit. /* DIAGNOSTICS -/* The result is zero in case of success, -1 in case of problems. +/* The result is zero when the fifo could be opened, -1 otherwise. /* BUGS /* LICENSE /* .ad @@ -49,25 +50,37 @@ #include <msg.h> #include <iostuff.h> +#include <safe_open.h> #include <trigger.h> /* fifo_trigger - wakeup fifo server */ int fifo_trigger(const char *service, const char *buf, int len, int timeout) { + static VSTRING *why; char *myname = "fifo_trigger"; + VSTREAM *fp; int fd; + if (why == 0) + why = vstring_alloc(1); + /* * Write the request to the service fifo. According to POSIX, the open * shall always return immediately, and shall return an error when no * process is reading from the FIFO. + * + * Use safe_open() so that we don't follow symlinks, and so that we don't + * open files with multiple hard links. We're not (yet) going to bother + * the caller with safe_open() specific quirks such as the why argument. */ - if ((fd = open(service, O_WRONLY | O_NONBLOCK, 0)) < 0) { + if ((fp = safe_open(service, O_WRONLY | O_NONBLOCK, 0, + (struct stat *) 0, -1, -1, why)) == 0) { if (msg_verbose) - msg_info("%s: open %s: %m", myname, service); + msg_info("%s: open %s: %s", myname, service, vstring_str(why)); return (-1); } + fd = vstream_fileno(fp); /* * Write the request... @@ -80,7 +93,7 @@ int fifo_trigger(const char *service, const char *buf, int len, int timeout) /* * Disconnect. */ - if (close(fd)) + if (vstream_fclose(fp)) if (msg_verbose) msg_warn("%s: close %s: %m", myname, service); return (0); diff --git a/gnu/dist/postfix/src/util/inet_trigger.c b/gnu/dist/postfix/src/util/inet_trigger.c index e92c2d8dbfb..dddbcb62aac 100644 --- a/gnu/dist/postfix/src/util/inet_trigger.c +++ b/gnu/dist/postfix/src/util/inet_trigger.c @@ -16,6 +16,10 @@ /* a brief connection to it and by writing the contents of the /* named buffer. /* +/* The connection is closed by a background thread. Some kernels +/* cannot handle client-side disconnect before the server has +/* received the message. +/* /* Arguments: /* .IP service /* Name of the communication endpoint. @@ -45,6 +49,7 @@ /* System library. */ #include <sys_defs.h> +#include <sys/socket.h> #include <unistd.h> #include <string.h> @@ -53,13 +58,42 @@ #include <msg.h> #include <connect.h> #include <iostuff.h> +#include <mymalloc.h> +#include <events.h> #include <trigger.h> +struct inet_trigger { + int fd; + char *service; +}; + +/* inet_trigger_event - disconnect from peer */ + +static void inet_trigger_event(int event, char *context) +{ + struct inet_trigger *ip = (struct inet_trigger *) context; + static char *myname = "inet_trigger_event"; + + /* + * Disconnect. + */ + if (event == EVENT_TIME) + msg_warn("%s: read timeout for service %s", myname, ip->service); + event_disable_readwrite(ip->fd); + event_cancel_timer(inet_trigger_event, context); + if (close(ip->fd) < 0) + msg_warn("%s: close %s: %m", myname, ip->service); + myfree(ip->service); + myfree((char *) ip); +} + + /* inet_trigger - wakeup INET-domain server */ int inet_trigger(const char *service, const char *buf, int len, int timeout) { char *myname = "inet_trigger"; + struct inet_trigger *ip; int fd; if (msg_verbose > 1) @@ -73,19 +107,24 @@ int inet_trigger(const char *service, const char *buf, int len, int timeout) 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); /* * Write the request... */ - if (write_buf(fd, buf, len, timeout) < 0) + if (write_buf(fd, buf, len, timeout) < 0 + || write_buf(fd, "", 1, timeout) < 0) if (msg_verbose) msg_warn("%s: write to %s: %m", myname, service); /* - * Disconnect. + * Wakeup when the peer disconnects, or when we lose patience. */ - if (close(fd) < 0) - if (msg_verbose) - msg_warn("%s: close %s: %m", myname, service); + if (timeout > 0) + event_request_timer(inet_trigger_event, (char *) ip, timeout + 100); + event_enable_read(fd, inet_trigger_event, (char *) ip); return (0); } diff --git a/gnu/dist/postfix/src/util/intv.c b/gnu/dist/postfix/src/util/intv.c new file mode 100644 index 00000000000..1d117fe0209 --- /dev/null +++ b/gnu/dist/postfix/src/util/intv.c @@ -0,0 +1,114 @@ +/*++ +/* NAME +/* intv 3 +/* SUMMARY +/* integer array utilities +/* SYNOPSIS +/* #include <intv.h> +/* +/* INTV *intv_alloc(len) +/* int len; +/* +/* INTV *intv_free(intvp) +/* INTV *intvp; +/* +/* void intv_add(intvp, count, arg, ...) +/* INTV *intvp; +/* int count; +/* int *arg; +/* DESCRIPTION +/* The functions in this module manipulate arrays of integers. +/* An INTV structure contains the following members: +/* .IP len +/* The actual length of the \fIintv\fR array. +/* .IP intc +/* The number of \fIintv\fR elements used. +/* .IP intv +/* An array of integer values. +/* .PP +/* intv_alloc() returns an empty integer array of the requested +/* length. The result is ready for use by intv_add(). +/* +/* intv_add() copies zero or more integers and adds them to the +/* specified integer array. +/* +/* intv_free() releases storage for an integer array, and conveniently +/* returns a null pointer. +/* SEE ALSO +/* msg(3) diagnostics interface +/* DIAGNOSTICS +/* Fatal errors: memory allocation problem. +/* 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 libraries. */ + +#include <sys_defs.h> +#include <stdlib.h> /* 44BSD stdarg.h uses abort() */ +#include <stdarg.h> + +/* Application-specific. */ + +#include "mymalloc.h" +#include "msg.h" +#include "intv.h" + +/* intv_free - destroy integer array */ + +INTV *intv_free(INTV *intvp) +{ + myfree((char *) intvp->intv); + myfree((char *) intvp); + return (0); +} + +/* intv_alloc - initialize integer array */ + +INTV *intv_alloc(int len) +{ + INTV *intvp; + + /* + * Sanity check. + */ + if (len < 1) + msg_panic("intv_alloc: bad array length %d", len); + + /* + * Initialize. + */ + intvp = (INTV *) mymalloc(sizeof(*intvp)); + intvp->len = len; + intvp->intv = (int *) mymalloc(intvp->len * sizeof(intvp->intv[0])); + intvp->intc = 0; + return (intvp); +} + +/* intv_add - add integer to vector */ + +void intv_add(INTV *intvp, int count,...) +{ + va_list ap; + + /* + * Make sure that always intvp->intc < intvp->len. + */ + va_start(ap, count); + while (count-- > 0) { + if (intvp->intc >= intvp->len) { + intvp->len *= 2; + intvp->intv = (int *) myrealloc((char *) intvp->intv, + intvp->len * sizeof(int)); + } + intvp->intv[intvp->intc++] = va_arg(ap, int); + } + va_end(ap); +} diff --git a/gnu/dist/postfix/src/util/intv.h b/gnu/dist/postfix/src/util/intv.h new file mode 100644 index 00000000000..d84c5b4b191 --- /dev/null +++ b/gnu/dist/postfix/src/util/intv.h @@ -0,0 +1,38 @@ +#ifndef _INTV_H_INCLUDED_ +#define _INTV_H_INCLUDED_ + +/*++ +/* NAME +/* intv 3h +/* SUMMARY +/* string array utilities +/* SYNOPSIS +/* #include "intv.h" + DESCRIPTION + .nf + + /* + * External interface. + */ +typedef struct INTV { + int len; /* number of array elements */ + int intc; /* array elements in use */ + int *intv; /* integer array */ +} INTV; + +extern INTV *intv_alloc(int); +extern void intv_add(INTV *, int,...); +extern INTV *intv_free(INTV *); + +/* 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 diff --git a/gnu/dist/postfix/src/util/make_dirs.c b/gnu/dist/postfix/src/util/make_dirs.c index b3efcddbf60..ad1b451de70 100644 --- a/gnu/dist/postfix/src/util/make_dirs.c +++ b/gnu/dist/postfix/src/util/make_dirs.c @@ -54,6 +54,7 @@ int make_dirs(const char *path, int perms) int saved_ch; struct stat st; int ret; + mode_t saved_mode = 0; /* * Initialize. Make a copy of the path that we can safely clobber. @@ -78,14 +79,31 @@ int make_dirs(const char *path, int perms) ret = -1; break; } + saved_mode = st.st_mode; } else { if (errno != ENOENT) break; + + /* + * Create a new directory. Unfortunately, mkdir(2) has no + * equivalent of open(2)'s O_CREAT|O_EXCL safety net, so we must + * require that the parent directory is not world writable. + * Detecting a lost race condition after the fact is not + * sufficient, as an attacker could repeat the attack and add one + * directory level at a time. + */ + if (saved_mode & S_IWOTH) { + msg_warn("refusing to mkdir %s: parent directory is writable by everyone", + saved_path); + errno = EPERM; + ret = -1; + break; + } if ((ret = mkdir(saved_path, perms)) < 0) { if (errno != EEXIST) break; /* Race condition? */ - if ((ret = stat(saved_path, &st)) < 0) + if ((ret = stat(saved_path, &st)) < 0) break; if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; diff --git a/gnu/dist/postfix/src/util/match_list.h b/gnu/dist/postfix/src/util/match_list.h index aba88b8f694..910ae713bf2 100644 --- a/gnu/dist/postfix/src/util/match_list.h +++ b/gnu/dist/postfix/src/util/match_list.h @@ -15,9 +15,9 @@ * 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 *); diff --git a/gnu/dist/postfix/src/util/match_ops.h b/gnu/dist/postfix/src/util/match_ops.h index a938c04fb34..e147f7b50dd 100644 --- a/gnu/dist/postfix/src/util/match_ops.h +++ b/gnu/dist/postfix/src/util/match_ops.h @@ -13,9 +13,13 @@ /* 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 diff --git a/gnu/dist/postfix/src/util/msg.c b/gnu/dist/postfix/src/util/msg.c index 08379a90b86..683359b2b37 100644 --- a/gnu/dist/postfix/src/util/msg.c +++ b/gnu/dist/postfix/src/util/msg.c @@ -20,6 +20,10 @@ /* NORETURN msg_fatal(format, ...) /* const char *format; /* +/* NORETURN msg_fatal_status(status, format, ...) +/* int status; +/* const char *format; +/* /* NORETURN msg_panic(format, ...) /* const char *format; /* @@ -48,11 +52,14 @@ /* msg_fatal() reports an unrecoverable error and terminates the program /* with a non-zero exit status. /* +/* msg_fatal_status() reports an unrecoverable error and terminates the +/* program with the specified exit status. +/* /* msg_panic() reports an internal inconsistency, terminates the /* program immediately (i.e. without calling the optional user-specified /* cleanup routine), and forces a core dump when possible. /* -/* msg_cleanup() specifies a function that msg_fatal() should +/* msg_cleanup() specifies a function that msg_fatal[_status]() should /* invoke before terminating the program, and returns the /* current function pointer. Specify a null argument to disable /* this feature. @@ -163,6 +170,23 @@ NORETURN msg_fatal(const char *fmt,...) exit(1); } +/* msg_fatal_status - report error and terminate gracefully */ + +NORETURN msg_fatal_status(int status, const char *fmt,...) +{ + va_list ap; + + if (msg_exiting++ == 0) { + va_start(ap, fmt); + msg_vprintf(MSG_FATAL, fmt, ap); + va_end(ap); + if (msg_cleanup_fn) + msg_cleanup_fn(); + } + sleep(1); + exit(status); +} + /* msg_panic - report error and dump core */ NORETURN msg_panic(const char *fmt,...) diff --git a/gnu/dist/postfix/src/util/msg.h b/gnu/dist/postfix/src/util/msg.h index fae8a2327c9..42198a2a71b 100644 --- a/gnu/dist/postfix/src/util/msg.h +++ b/gnu/dist/postfix/src/util/msg.h @@ -22,6 +22,7 @@ extern void PRINTFLIKE(1, 2) msg_info(const char *,...); extern void PRINTFLIKE(1, 2) msg_warn(const char *,...); extern void PRINTFLIKE(1, 2) msg_error(const char *,...); extern NORETURN PRINTFLIKE(1, 2) msg_fatal(const char *,...); +extern NORETURN PRINTFLIKE(2, 3) msg_fatal_status(int, const char *,...); extern NORETURN PRINTFLIKE(1, 2) msg_panic(const char *,...); extern int msg_error_limit(int); diff --git a/gnu/dist/postfix/src/util/mymalloc.c b/gnu/dist/postfix/src/util/mymalloc.c index e20531c0605..61014a800e0 100644 --- a/gnu/dist/postfix/src/util/mymalloc.c +++ b/gnu/dist/postfix/src/util/mymalloc.c @@ -90,7 +90,10 @@ typedef struct MBLOCK { int signature; /* set when block is active */ int length; /* user requested length */ - char payload[1]; /* actually a bunch of bytes */ + union { + ALIGN_TYPE align; + char payload[1]; /* actually a bunch of bytes */ + } u; } MBLOCK; #define SIGNATURE 0xdead @@ -99,7 +102,7 @@ typedef struct MBLOCK { #define CHECK_IN_PTR(ptr, real_ptr, len, fname) { \ if (ptr == 0) \ msg_panic("%s: null pointer input", fname); \ - real_ptr = (MBLOCK *) (ptr - offsetof(MBLOCK, payload[0])); \ + real_ptr = (MBLOCK *) (ptr - offsetof(MBLOCK, u.payload[0])); \ if (real_ptr->signature != SIGNATURE) \ msg_panic("%s: corrupt or unallocated memory block", fname); \ real_ptr->signature = 0; \ @@ -110,10 +113,10 @@ typedef struct MBLOCK { #define CHECK_OUT_PTR(ptr, real_ptr, len) { \ real_ptr->signature = SIGNATURE; \ real_ptr->length = len; \ - ptr = real_ptr->payload; \ + ptr = real_ptr->u.payload; \ } -#define SPACE_FOR(len) (offsetof(MBLOCK, payload[0]) + len) +#define SPACE_FOR(len) (offsetof(MBLOCK, u.payload[0]) + len) /* mymalloc - allocate memory or bust */ @@ -165,6 +168,8 @@ void myfree(char *ptr) char *mystrdup(const char *str) { + if (str == 0) + msg_panic("mystrdup: null pointer argument"); return (strcpy(mymalloc(strlen(str) + 1), str)); } @@ -173,10 +178,12 @@ char *mystrdup(const char *str) char *mystrndup(const char *str, int len) { char *result; - int slen; + char *cp; - if ((slen = strlen(str)) < len) - len = slen; + if (str == 0) + msg_panic("mystrndup: null pointer argument"); + if ((cp = memchr(str, 0, len)) != 0) + len = cp - str; result = memcpy(mymalloc(len + 1), str, len); result[len] = 0; return (result); @@ -186,5 +193,7 @@ char *mystrndup(const char *str, int len) char *mymemdup(const char *ptr, int len) { + if (ptr == 0) + msg_panic("mymemdup: null pointer argument"); return (memcpy(mymalloc(len), ptr, len)); } diff --git a/gnu/dist/postfix/src/util/myrand.c b/gnu/dist/postfix/src/util/myrand.c new file mode 100644 index 00000000000..39fcbfd9e47 --- /dev/null +++ b/gnu/dist/postfix/src/util/myrand.c @@ -0,0 +1,63 @@ +/*++ +/* NAME +/* myrand 3 +/* SUMMARY +/* rand wrapper +/* SYNOPSIS +/* #include <myrand.h> +/* +/* void mysrand(seed) +/* int seed; +/* +/* int myrand() +/* DESCRIPTION +/* This module implements a wrapper for the portable, pseudo-random +/* number generator. The wrapper adds automatic initialization. +/* +/* mysrand() performs initialization. This call may be skipped. +/* +/* myrand() returns a pseudo-random number in the range [0, RAND_MAX]. +/* If mysrand() was not called, it is invoked with the process ID +/* ex-or-ed with the time of day in seconds. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* WARNING +/* Do not use this code for generating unpredictable numbers. +/* 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 <stdlib.h> +#include <unistd.h> +#include <time.h> + +/* Utility library. */ + +#include <myrand.h> + +static int myrand_initdone = 0; + +/* mysrand - initialize */ + +void mysrand(int seed) +{ + srand(seed); + myrand_initdone = 1; +} + +/* myrand - pseudo-random number */ + +int myrand(void) +{ + if (myrand_initdone == 0) + mysrand(getpid() ^ time((time_t *) 0)); + return (rand()); +} diff --git a/gnu/dist/postfix/src/util/myrand.h b/gnu/dist/postfix/src/util/myrand.h new file mode 100644 index 00000000000..49c5abb8433 --- /dev/null +++ b/gnu/dist/postfix/src/util/myrand.h @@ -0,0 +1,31 @@ +#ifndef _MYRAND_H_INCLUDED_ +#define _MYRAND_H_INCLUDED_ + +/*++ +/* NAME +/* myrand 3h +/* SUMMARY +/* rand wrapper +/* SYNOPSIS +/* #include <myrand.h> +/* DESCRIPTION +/* .nf + + /* + * External interface. + */ +extern void mysrand(int); +extern int myrand(void); + +/* 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 diff --git a/gnu/dist/postfix/src/util/netstring.c b/gnu/dist/postfix/src/util/netstring.c new file mode 100644 index 00000000000..3f3e73112ad --- /dev/null +++ b/gnu/dist/postfix/src/util/netstring.c @@ -0,0 +1,351 @@ +/*++ +/* NAME +/* netstring 3 +/* SUMMARY +/* netstring stream I/O support +/* SYNOPSIS +/* #include <netstring.h> +/* +/* void netstring_setup(stream, timeout) +/* VSTREAM *stream; +/* int timeout; +/* +/* void netstring_except(stream, exception) +/* VSTREAM *stream; +/* int exception; +/* +/* VSTRING *netstring_get(stream, buf, limit) +/* VSTREAM *stream; +/* VSTRING *buf; +/* int limit; +/* +/* void netstring_put(stream, data, len) +/* VSTREAM *stream; +/* const char *data; +/* int len; +/* +/* void netstring_put_multi(stream, data, len, data, len, ..., 0) +/* VSTREAM *stream; +/* const char *data; +/* int len; +/* +/* void NETSTRING_PUT_BUF(stream, buf) +/* VSTREAM *stream; +/* VSTRING *buf; +/* +/* void netstring_fflush(stream) +/* VSTREAM *stream; +/* +/* VSTRING *netstring_memcpy(buf, data, len) +/* VSTRING *buf; +/* const char *data; +/* int len; +/* +/* VSTRING *netstring_memcat(buf, data, len) +/* VSTRING *buf; +/* const char *src; +/* int len; +/* AUXILIARY ROUTINES +/* int netstring_get_length(stream) +/* VSTREAM *stream; +/* +/* VSTRING *netstring_get_data(stream, buf, len) +/* VSTREAM *stream; +/* VSTRING *buf; +/* int len; +/* +/* void netstring_get_terminator(stream) +/* VSTREAM *stream; +/* DESCRIPTION +/* This module reads and writes netstrings with error detection: +/* timeouts, unexpected end-of-file, or format errors. Netstring +/* is a data format designed by Daniel Bernstein. +/* +/* netstring_setup() arranges for a time limit on the netstring +/* read and write operations described below. +/* This routine alters the behavior of streams as follows: +/* .IP \(bu +/* The read/write timeout is set to the specified value. +/* .IP \(bu +/* The stream is configured to enable exception handling. +/* .PP +/* netstring_except() raises the specified exception on the +/* named stream. See the DIAGNOSTICS section below. +/* +/* netstring_get() reads a netstring from the specified stream +/* and extracts its content. The limit specifies a maximal size. +/* Specify zero to disable the size limit. The result is not null +/* terminated. The result value is the buf argument. +/* +/* netstring_put() encapsulates the specified string as a netstring +/* and sends the result to the specified stream. +/* The stream output buffer is not flushed. +/* +/* netstring_put_multi() encapsulates the content of multiple strings +/* as one netstring and sends the result to the specified stream. The +/* argument list must be terminated with a null data pointer. +/* The stream output buffer is not flushed. +/* +/* NETSTRING_PUT_BUF() is a macro that provides a VSTRING-based +/* wrapper for the netstring_put() routine. +/* +/* netstring_fflush() flushes the output buffer of the specified +/* stream and handles any errors. +/* +/* netstring_memcpy() encapsulates the specified data as a netstring +/* and copies the result over the specified buffer. The result +/* value is the buffer. +/* +/* netstring_memcat() encapsulates the specified data as a netstring +/* and appends the result to the specified buffer. The result +/* value is the buffer. +/* +/* The following routines provide low-level access to a netstring +/* stream. +/* +/* netstring_get_length() reads a length field from the specified +/* stream, and absorbs the netstring length field terminator. +/* +/* netstring_get_data() reads the specified number of bytes from the +/* specified stream into the specified buffer, and absorbs the +/* netstring terminator. The result value is the buf argument. +/* +/* netstring_get_terminator() reads the netstring terminator from +/* the specified stream. +/* DIAGNOSTICS +/* .fi +/* .ad +/* In case of error, a vstream_longjmp() call is performed to the +/* context specified with vstream_setjmp(). +/* Error codes passed along with vstream_longjmp() are: +/* .IP NETSTRING_ERR_EOF +/* An I/O error happened, or the peer has disconnected unexpectedly. +/* .IP NETSTRING_ERR_TIME +/* The time limit specified to netstring_setup() was exceeded. +/* .IP NETSTRING_ERR_FORMAT +/* The input contains an unexpected character value. +/* .IP NETSTRING_ERR_SIZE +/* The input is larger than acceptable. +/* BUGS +/* The timeout deadline affects all I/O on the named stream, not +/* just the I/O done on behalf of this module. +/* +/* The timeout deadline overwrites any previously set up state on +/* the named stream. +/* +/* netstrings are not null terminated, which makes printing them +/* a bit awkward. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* SEE ALSO +/* http://cr.yp.to/proto/netstrings.txt, netstring definition +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <stdarg.h> +#include <ctype.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstream.h> +#include <vstring.h> +#include <netstring.h> + +/* Application-specific. */ + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +/* netstring_setup - initialize netstring stream */ + +void netstring_setup(VSTREAM *stream, int timeout) +{ + vstream_control(stream, + VSTREAM_CTL_TIMEOUT, timeout, + VSTREAM_CTL_EXCEPT, + VSTREAM_CTL_END); +} + +/* netstring_except - process netstring stream exception */ + +void netstring_except(VSTREAM *stream, int exception) +{ + vstream_longjmp(stream, exception); +} + +/* netstring_get_length - read netstring length + terminator */ + +int netstring_get_length(VSTREAM *stream) +{ + char *myname = "netstring_get_length"; + int len = 0; + int ch; + + for (;;) { + switch (ch = VSTREAM_GETC(stream)) { + case VSTREAM_EOF: + netstring_except(stream, vstream_ftimeout(stream) ? + NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); + case ':': + if (msg_verbose > 1) + msg_info("%s: read netstring length %d", myname, len); + return (len); + default: + if (!ISDIGIT(ch)) + netstring_except(stream, NETSTRING_ERR_FORMAT); + len = len * 10 + ch - '0'; + break; + } + } +} + +/* netstring_get_data - read netstring payload + terminator */ + +VSTRING *netstring_get_data(VSTREAM *stream, VSTRING *buf, int len) +{ + char *myname = "netstring_get_data"; + + /* + * Allocate buffer space. + */ + VSTRING_RESET(buf); + VSTRING_SPACE(buf, len); + + /* + * Read the payload and absorb the terminator. + */ + if (vstream_fread(stream, STR(buf), len) != len) + netstring_except(stream, vstream_ftimeout(stream) ? + NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); + if (msg_verbose > 1) + msg_info("%s: read netstring data %.*s", + myname, len < 30 ? len : 30, STR(buf)); + netstring_get_terminator(stream); + + /* + * Position the buffer. + */ + VSTRING_AT_OFFSET(buf, len); + return (buf); +} + +/* netstring_get_terminator - absorb netstring terminator */ + +void netstring_get_terminator(VSTREAM *stream) +{ + if (VSTREAM_GETC(stream) != ',') + netstring_except(stream, NETSTRING_ERR_FORMAT); +} + +/* netstring_get - read string from netstring stream */ + +VSTRING *netstring_get(VSTREAM *stream, VSTRING *buf, int limit) +{ + int len; + + len = netstring_get_length(stream); + if (limit && len > limit) + netstring_except(stream, NETSTRING_ERR_SIZE); + netstring_get_data(stream, buf, len); + return (buf); +} + +/* netstring_put - send string as netstring */ + +void netstring_put(VSTREAM *stream, const char *data, int len) +{ + char *myname = "netstring_put"; + + if (msg_verbose > 1) + msg_info("%s: write netstring len %d data %.*s", + myname, len, len < 30 ? len : 30, data); + vstream_fprintf(stream, "%d:", len); + vstream_fwrite(stream, data, len); + VSTREAM_PUTC(',', stream); +} + +/* netstring_put_multi - send multiple strings as one netstring */ + +void netstring_put_multi(VSTREAM *stream,...) +{ + char *myname = "netstring_put_multi"; + int total; + char *data; + int data_len; + va_list ap; + + /* + * Figure out the total result size. + */ + va_start(ap, stream); + for (total = 0; (data = va_arg(ap, char *)) != 0; total += data_len) + if ((data_len = va_arg(ap, int)) < 0) + msg_panic("netstring_put_multi: bad data length %d", data_len); + va_end(ap); + + /* + * Debugging support. + */ + if (msg_verbose > 1) { + va_start(ap, stream); + data = va_arg(ap, char *); + data_len = va_arg(ap, int); + msg_info("%s: write netstring len %d data %.*s", + myname, total, data_len < 30 ? data_len : 30, data); + va_end(ap); + } + + /* + * Send the length, content and terminator. + */ + vstream_fprintf(stream, "%d:", total); + va_start(ap, stream); + while ((data = va_arg(ap, char *)) != 0) { + data_len = va_arg(ap, int); + if (data_len > 0) + if (vstream_fwrite(stream, data, data_len) != data_len) + netstring_except(stream, vstream_ftimeout(stream) ? + NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); + va_end(ap); + } + vstream_fwrite(stream, ",", 1); +} + +/* netstring_fflush - flush netstring stream */ + +void netstring_fflush(VSTREAM *stream) +{ + if (vstream_fflush(stream) == VSTREAM_EOF) + netstring_except(stream, vstream_ftimeout(stream) ? + NETSTRING_ERR_TIME : NETSTRING_ERR_EOF); +} + +/* netstring_memcpy - copy data as in-memory netstring */ + +VSTRING *netstring_memcpy(VSTRING *buf, const char *src, int len) +{ + vstring_sprintf(buf, "%d:", len); + vstring_memcat(buf, src, len); + VSTRING_ADDCH(buf, ','); + return (buf); +} + +/* netstring_memcat - append data as in-memory netstring */ + +VSTRING *netstring_memcat(VSTRING *buf, const char *src, int len) +{ + vstring_sprintf_append(buf, "%d:", len); + vstring_memcat(buf, src, len); + VSTRING_ADDCH(buf, ','); + return (buf); +} diff --git a/gnu/dist/postfix/src/util/netstring.h b/gnu/dist/postfix/src/util/netstring.h new file mode 100644 index 00000000000..6b82d90e4e8 --- /dev/null +++ b/gnu/dist/postfix/src/util/netstring.h @@ -0,0 +1,54 @@ +#ifndef _NETSTRING_H_INCLUDED_ +#define _NETSTRING_H_INCLUDED_ + +/*++ +/* NAME +/* netstring 3h +/* SUMMARY +/* netstring stream I/O support +/* SYNOPSIS +/* #include <netstring.h> +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include <vstring.h> +#include <vstream.h> + + /* + * External interface. + */ +#define NETSTRING_ERR_EOF 1 /* unexpected disconnect */ +#define NETSTRING_ERR_TIME 2 /* time out */ +#define NETSTRING_ERR_FORMAT 3 /* format error */ +#define NETSTRING_ERR_SIZE 4 /* netstring too large */ + +extern void netstring_except(VSTREAM *, int); +extern void netstring_setup(VSTREAM *, int); +extern int netstring_get_length(VSTREAM *); +extern VSTRING *netstring_get_data(VSTREAM *, VSTRING *, int); +extern void netstring_get_terminator(VSTREAM *); +extern VSTRING *netstring_get(VSTREAM *, VSTRING *, int); +extern void netstring_put(VSTREAM *, const char *, int); +extern void netstring_put_multi(VSTREAM *,...); +extern void netstring_fflush(VSTREAM *); +extern VSTRING *netstring_memcpy(VSTRING *, const char *, int); +extern VSTRING *netstring_memcat(VSTRING *, const char *, int); + +#define NETSTRING_PUT_BUF(str, buf) \ + netstring_put((str), vstring_str(buf), VSTRING_LEN(buf)) + +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/*--*/ + +#endif diff --git a/gnu/dist/postfix/src/util/rand_sleep.c b/gnu/dist/postfix/src/util/rand_sleep.c index d119f074f57..33ffecb51c4 100644 --- a/gnu/dist/postfix/src/util/rand_sleep.c +++ b/gnu/dist/postfix/src/util/rand_sleep.c @@ -45,6 +45,7 @@ /* Utility library. */ #include <msg.h> +#include <myrand.h> #include <iostuff.h> /* rand_sleep - block for random time */ @@ -52,7 +53,6 @@ void rand_sleep(unsigned delay, unsigned variation) { char *myname = "rand_sleep"; - static pid_t my_pid; unsigned usec; /* @@ -66,9 +66,7 @@ void rand_sleep(unsigned delay, unsigned variation) /* * Use the semi-crappy random number generator. */ - if (my_pid == 0) - srand((my_pid = getpid()) ^ time((time_t *) 0)); - usec = (delay - variation / 2) + variation * (double) rand() / RAND_MAX; + usec = (delay - variation / 2) + variation * (double) myrand() / RAND_MAX; doze(usec); } diff --git a/gnu/dist/postfix/src/util/readlline.c b/gnu/dist/postfix/src/util/readlline.c index 314d6962bf0..9be31eab109 100644 --- a/gnu/dist/postfix/src/util/readlline.c +++ b/gnu/dist/postfix/src/util/readlline.c @@ -6,30 +6,37 @@ /* SYNOPSIS /* #include <readlline.h> /* -/* VSTRING *readlline(buf, fp, lineno, stripnl) +/* VSTRING *readlline(buf, fp, lineno) /* VSTRING *buf; /* VSTREAM *fp; /* int *lineno; -/* int stripnl; /* DESCRIPTION /* readlline() reads one logical line from the named stream. -/* A line that starts with whitespace is a continuation of -/* the previous line. When the stripnl argument is non-zero, -/* the newline between continued lines -/* is deleted from the input. The result value is the input -/* buffer argument or a null pointer when no input is found. +/* .IP "blank lines and comments" +/* Empty lines and whitespace-only lines are ignored, as +/* are lines whose first non-whitespace character is a `#'. +/* .IP "multi-line text" +/* A logical line starts with non-whitespace text. A line that +/* starts with whitespace continues a logical line. +/* .PP +/* The result value is the input buffer argument or a null pointer +/* when no input is found. /* /* Arguments: /* .IP buf -/* A variable-length buffer for input. +/* A variable-length buffer for input. The result is null terminated. /* .IP fp /* Handle to an open stream. /* .IP lineno /* A null pointer, or a pointer to an integer that is incremented -/* after reading a newline. -/* .IP stripnl -/* Non-zero to strip newlines. readlline.h provides the symbolic -/* constants READLL_STRIPNL and READLL_KEEPNL for convenience. +/* after reading a newline character. +/* .RE +/* DIAGNOSTICS +/* Warning: a continuation line that does not continue preceding text. +/* The invalid input is ignored, to avoid complicating caller code. +/* SECURITY +/* readlline() imposes no logical line length limit therefore it +/* should be used for reading trusted information only. /* LICENSE /* .ad /* .fi @@ -44,40 +51,73 @@ /* System library. */ #include <sys_defs.h> +#include <ctype.h> /* Utility library. */ +#include "msg.h" #include "vstream.h" #include "vstring.h" #include "readlline.h" +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) +#define END(x) vstring_end(x) + /* readlline - read one logical line */ -VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno, int stripnl) +VSTRING *readlline(VSTRING *buf, VSTREAM *fp, int *lineno) { int ch; int next; + int start; + char *cp; + + VSTRING_RESET(buf); /* - * Lines that start with whitespace continue the preceding line. + * Ignore comment lines, all whitespace lines, and empty lines. Terminate + * at EOF or at the beginning of the next logical line. */ - VSTRING_RESET(buf); - while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF) { - if (ch == '\n') { - if (stripnl == 0) - VSTRING_ADDCH(buf, ch); - if (lineno) - *lineno += 1; - if ((next = VSTREAM_GETC(fp)) == ' ' || next == '\t') { - ch = next; - } else { - if (next != VSTREAM_EOF) - vstream_ungetc(fp, next); + for (;;) { + /* Read one line, possibly not newline terminated. */ + start = LEN(buf); + while ((ch = VSTREAM_GETC(fp)) != VSTREAM_EOF && ch != '\n') + VSTRING_ADDCH(buf, ch); + if (ch == '\n' && lineno != 0) + *lineno += 1; + /* Ignore comment line, all whitespace line, or empty line. */ + for (cp = STR(buf) + start; cp < END(buf) && ISSPACE(*cp); cp++) + /* void */ ; + if (cp == END(buf) || *cp == '#') + vstring_truncate(buf, start); + /* Terminate at EOF or at the beginning of the next logical line. */ + if (ch == VSTREAM_EOF) + break; + if (LEN(buf) > 0) { + if ((next = VSTREAM_GETC(fp)) != VSTREAM_EOF) + vstream_ungetc(fp, next); + if (next != '#' && !ISSPACE(next)) break; - } } - VSTRING_ADDCH(buf, ch); } + + /* + * Invalid input: continuing text without preceding text. Allowing this + * would complicate "postconf -e", which implements its own multi-line + * parsing routine. Do not abort, just warn, so that critical programs + * like postmap do not leave behind a truncated table. + */ + if (LEN(buf) > 0 && ISSPACE(*STR(buf))) { + msg_warn("%s: logical line must not start with whitespace: \"%.30s%s\"", + VSTREAM_PATH(fp), STR(buf), + LEN(buf) > 30 ? "..." : ""); + return (readlline(buf, fp, lineno)); + } + + /* + * Done. + */ VSTRING_TERMINATE(buf); - return (VSTRING_LEN(buf) || ch == '\n' ? buf : 0); + return (LEN(buf) > 0 ? buf : 0); } diff --git a/gnu/dist/postfix/src/util/readlline.h b/gnu/dist/postfix/src/util/readlline.h index 00658433cc2..8a8bd548711 100644 --- a/gnu/dist/postfix/src/util/readlline.h +++ b/gnu/dist/postfix/src/util/readlline.h @@ -20,10 +20,7 @@ /* * External interface. */ -extern VSTRING *readlline(VSTRING *, VSTREAM *, int *, int); - -#define READLL_STRIPNL 1 -#define READLL_KEEPNL 0 +extern VSTRING *readlline(VSTRING *, VSTREAM *, int *); /* LICENSE /* .ad diff --git a/gnu/dist/postfix/src/util/safe_open.c b/gnu/dist/postfix/src/util/safe_open.c index e1e88f8b475..d20c9404c1a 100644 --- a/gnu/dist/postfix/src/util/safe_open.c +++ b/gnu/dist/postfix/src/util/safe_open.c @@ -41,8 +41,9 @@ /* Panic: interface violations. /* /* A null result means there was a problem. The nature of the -/* problem is returned via the \fIwhy\fR buffer; some errors -/* cannot be reported via \fIerrno\fR. +/* problem is returned via the \fIwhy\fR buffer; when an error +/* cannot be reported via \fIerrno\fR, the generic value EPERM +/* (operation not permitted) is used instead. /* HISTORY /* .fi /* .ad @@ -54,7 +55,7 @@ /* be fooled by delaying the open() until the inode found with /* lstat() has been re-used for a sensitive file (article /* <20000103212443.A5807@monad.swb.de> posted to bugtraq on -/* Jan 3, 2000). This can be a concern for a set-uid process +/* Jan 3, 2000). This can be a concern for a set-ugid process /* that runs under the control of a user and that can be /* manipulated with start/stop signals. /* LICENSE @@ -113,8 +114,10 @@ static VSTREAM *safe_open_exist(const char *path, int flags, } else if (fstat_st->st_nlink != 1) { vstring_sprintf(why, "file has %d hard links", (int) fstat_st->st_nlink); + errno = EPERM; } else if (S_ISDIR(fstat_st->st_mode)) { vstring_sprintf(why, "file is a directory"); + errno = EISDIR; } /* @@ -135,10 +138,12 @@ static VSTREAM *safe_open_exist(const char *path, int flags, */ else if (lstat(path, &lstat_st) < 0) { vstring_sprintf(why, "file status changed unexpectedly: %m"); + errno = EPERM; } else if (S_ISLNK(lstat_st.st_mode)) { if (lstat_st.st_uid == 0) return (fp); vstring_sprintf(why, "file is a symbolic link"); + errno = EPERM; } else if (fstat_st->st_dev != lstat_st.st_dev || fstat_st->st_ino != lstat_st.st_ino #ifdef HAS_ST_GEN @@ -147,6 +152,7 @@ static VSTREAM *safe_open_exist(const char *path, int flags, || fstat_st->st_nlink != lstat_st.st_nlink || fstat_st->st_mode != lstat_st.st_mode) { vstring_sprintf(why, "file status changed unexpectedly"); + errno = EPERM; } /* @@ -158,9 +164,7 @@ static VSTREAM *safe_open_exist(const char *path, int flags, /* * End up here in case of fstat()/lstat() problems or inconsistencies. - * Reset errno to reduce confusion. */ - errno = 0; vstream_fclose(fp); return (0); } @@ -190,7 +194,7 @@ static VSTREAM *safe_open_create(const char *path, int flags, int mode, if (CHANGE_OWNER(user, group) && fchown(vstream_fileno(fp), user, group) < 0) { - vstring_sprintf(why, "cannot change file ownership: %m"); + msg_warn("%s: cannot change file ownership: %m", path); } /* diff --git a/gnu/dist/postfix/src/util/sane_accept.c b/gnu/dist/postfix/src/util/sane_accept.c index d9d8464d0ad..9ae9f6e3f49 100644 --- a/gnu/dist/postfix/src/util/sane_accept.c +++ b/gnu/dist/postfix/src/util/sane_accept.c @@ -36,6 +36,7 @@ /* Utility library. */ +#include "msg.h" #include "sane_accept.h" /* sane_accept - sanitize accept() error returns */ @@ -55,6 +56,10 @@ int sane_accept(int sock, struct sockaddr * sa, SOCKADDR_SIZE *len) EWOULDBLOCK, 0, }; + static int accept_warn_errors[] = { + ECONNABORTED, + 0, + }; int count; int err; int fd; @@ -68,6 +73,13 @@ int sane_accept(int sock, struct sockaddr * sa, SOCKADDR_SIZE *len) * XXX LINUX < 2.1 accept() wakes up before the three-way handshake is * complete, so it can fail with ECONNRESET and other "false alarm" * indications. + * + * XXX FreeBSD 4.2-STABLE accept() returns ECONNABORTED when a UNIX-domain + * client has disconnected in the mean time. The data that was sent with + * connect() write() close() is lost, even though the write() and close() + * reported successful completion. This was fixed shortly before FreeBSD + * 4.3. However, other systems may make that same mistake again, so we're + * adding a special warning. */ if ((fd = accept(sock, sa, len)) < 0) { for (count = 0; (err = accept_ok_errors[count]) != 0; count++) { @@ -76,6 +88,13 @@ int sane_accept(int sock, struct sockaddr * sa, SOCKADDR_SIZE *len) break; } } + for (count = 0; (err = accept_warn_errors[count]) != 0; count++) { + if (errno == err) { + msg_warn("accept: %m"); + errno = EAGAIN; + break; + } + } } return (fd); } diff --git a/gnu/dist/postfix/src/util/split_nameval.c b/gnu/dist/postfix/src/util/split_nameval.c new file mode 100644 index 00000000000..f3e519bad1e --- /dev/null +++ b/gnu/dist/postfix/src/util/split_nameval.c @@ -0,0 +1,94 @@ +/*++ +/* NAME +/* split_nameval 3 +/* SUMMARY +/* name-value splitter +/* SYNOPSIS +/* #include <split_nameval.h> +/* +/* const char *split_nameval(buf, name, value) +/* char *buf; +/* char **name; +/* char **value; +/* DESCRIPTION +/* split_nameval() takes a logical line from readlline() and expects +/* text of the form "name = value" or "name =". The buffer +/* argument is broken up into name and value substrings. +/* +/* Arguments: +/* .IP buf +/* Result from readlline() or equivalent. The buffer is modified. +/* .IP name +/* Upon successful completion, this is set to the name +/* substring. +/* .IP value +/* Upon successful completion, this is set to the value +/* substring. +/* FEATURES +/* SEE ALSO +/* dict(3) mid-level dictionary routines +/* BUGS +/* DIAGNOSTICS +/* Fatal errors: out of memory. +/* +/* The result is a null pointer in case of success, a string +/* describing the error otherwise: missing '=' after attribute +/* name; missing attribute name. +/* 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 libraries. */ + +#include "sys_defs.h" +#include <ctype.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <stringops.h> + +/* split_nameval - split text into name and value */ + +const char *split_nameval(char *buf, char **name, char **value) +{ + char *np; /* name substring */ + char *vp; /* value substring */ + char *cp; + char *ep; + + /* + * Ugly macros to make complex expressions less unreadable. + */ +#define SKIP(start, var, cond) \ + for (var = start; *var && (cond); var++); + +#define TRIM(s) { \ + char *p; \ + for (p = (s) + strlen(s); p > (s) && ISSPACE(p[-1]); p--); \ + *p = 0; \ + } + + SKIP(buf, np, ISSPACE(*np)); /* find name begin */ + if (*np == 0) + return ("missing attribute name"); + SKIP(np, ep, !ISSPACE(*ep) && *ep != '='); /* find name end */ + SKIP(ep, cp, ISSPACE(*cp)); /* skip blanks before '=' */ + if (*cp != '=') /* need '=' */ + return ("missing '=' after attribute name"); + *ep = 0; /* terminate name */ + cp++; /* skip over '=' */ + SKIP(cp, vp, ISSPACE(*vp)); /* skip leading blanks */ + TRIM(vp); /* trim trailing blanks */ + *name = np; + *value = vp; + return (0); +} diff --git a/gnu/dist/postfix/src/util/stream_trigger.c b/gnu/dist/postfix/src/util/stream_trigger.c index 585f392bf6e..9cb57e5135e 100644 --- a/gnu/dist/postfix/src/util/stream_trigger.c +++ b/gnu/dist/postfix/src/util/stream_trigger.c @@ -15,6 +15,10 @@ /* stream_trigger() wakes up the named stream server by making /* a brief connection to it and writing the named buffer. /* +/* The connection is closed by a background thread. Some kernels +/* cannot handle client-side disconnect before the server has +/* received the message. +/* /* Arguments: /* .IP service /* Name of the communication endpoint. @@ -51,13 +55,41 @@ #include <msg.h> #include <connect.h> #include <iostuff.h> +#include <mymalloc.h> +#include <events.h> #include <trigger.h> +struct stream_trigger { + int fd; + char *service; +}; + +/* stream_trigger_event - disconnect from peer */ + +static void stream_trigger_event(int event, char *context) +{ + struct stream_trigger *sp = (struct stream_trigger *) context; + static char *myname = "stream_trigger_event"; + + /* + * Disconnect. + */ + if (event == EVENT_TIME) + msg_warn("%s: read timeout for service %s", myname, sp->service); + event_disable_readwrite(sp->fd); + event_cancel_timer(stream_trigger_event, context); + if (close(sp->fd) < 0) + msg_warn("%s: close %s: %m", myname, sp->service); + myfree(sp->service); + myfree((char *) sp); +} + /* stream_trigger - wakeup stream server */ int stream_trigger(const char *service, const char *buf, int len, int timeout) { char *myname = "stream_trigger"; + struct stream_trigger *sp; int fd; if (msg_verbose > 1) @@ -71,19 +103,28 @@ int stream_trigger(const char *service, const char *buf, int len, int timeou msg_warn("%s: connect to %s: %m", myname, service); return (-1); } + close_on_exec(fd, CLOSE_ON_EXEC); + + /* + * Stash away context. + */ + sp = (struct stream_trigger *) mymalloc(sizeof(*sp)); + sp->fd = fd; + sp->service = mystrdup(service); /* * Write the request... */ - if (write_buf(fd, buf, len, timeout) < 0) + if (write_buf(fd, buf, len, timeout) < 0 + || write_buf(fd, "", 1, timeout) < 0) if (msg_verbose) msg_warn("%s: write to %s: %m", myname, service); /* - * Disconnect. + * Wakeup when the peer disconnects, or when we lose patience. */ - if (close(fd) < 0) - if (msg_verbose) - msg_warn("%s: close %s: %m", myname, service); + if (timeout > 0) + event_request_timer(stream_trigger_event, (char *) sp, timeout + 100); + event_enable_read(fd, stream_trigger_event, (char *) sp); return (0); } diff --git a/gnu/dist/postfix/src/util/stringops.h b/gnu/dist/postfix/src/util/stringops.h index 1310d4cb062..0cd80c797d1 100644 --- a/gnu/dist/postfix/src/util/stringops.h +++ b/gnu/dist/postfix/src/util/stringops.h @@ -30,6 +30,8 @@ extern char *translit(char *, const char *, const char *); extern char *basename(const char *); #endif extern VSTRING *unescape(VSTRING *, const char *); +extern int alldig(const char *); +extern const char *split_nameval(char *, char **, char **); /* LICENSE /* .ad diff --git a/gnu/dist/postfix/src/util/unix_trigger.c b/gnu/dist/postfix/src/util/unix_trigger.c index d0f03d6c78f..6a3b1916073 100644 --- a/gnu/dist/postfix/src/util/unix_trigger.c +++ b/gnu/dist/postfix/src/util/unix_trigger.c @@ -15,6 +15,10 @@ /* unix_trigger() wakes up the named UNIX-domain server by making /* a brief connection to it and writing the named buffer. /* +/* The connection is closed by a background thread. Some kernels +/* cannot handle client-side disconnect before the server has +/* received the message. +/* /* Arguments: /* .IP service /* Name of the communication endpoint. @@ -43,6 +47,7 @@ /* System library. */ #include <sys_defs.h> +#include <sys/socket.h> #include <unistd.h> #include <string.h> @@ -51,13 +56,41 @@ #include <msg.h> #include <connect.h> #include <iostuff.h> +#include <mymalloc.h> +#include <events.h> #include <trigger.h> +struct unix_trigger { + int fd; + char *service; +}; + +/* unix_trigger_event - disconnect from peer */ + +static void unix_trigger_event(int event, char *context) +{ + struct unix_trigger *up = (struct unix_trigger *) context; + static char *myname = "unix_trigger_event"; + + /* + * Disconnect. + */ + if (event == EVENT_TIME) + msg_warn("%s: read timeout for service %s", myname, up->service); + event_disable_readwrite(up->fd); + event_cancel_timer(unix_trigger_event, context); + if (close(up->fd) < 0) + msg_warn("%s: close %s: %m", myname, up->service); + myfree(up->service); + myfree((char *) up); +} + /* unix_trigger - wakeup UNIX-domain server */ int unix_trigger(const char *service, const char *buf, int len, int timeout) { char *myname = "unix_trigger"; + struct unix_trigger *up; int fd; if (msg_verbose > 1) @@ -71,19 +104,28 @@ int unix_trigger(const char *service, const char *buf, int len, int timeout) msg_warn("%s: connect to %s: %m", myname, service); return (-1); } + close_on_exec(fd, CLOSE_ON_EXEC); + + /* + * Stash away context. + */ + up = (struct unix_trigger *) mymalloc(sizeof(*up)); + up->fd = fd; + up->service = mystrdup(service); /* * Write the request... */ - if (write_buf(fd, buf, len, timeout) < 0) + if (write_buf(fd, buf, len, timeout) < 0 + || write_buf(fd, "", 1, timeout) < 0) if (msg_verbose) msg_warn("%s: write to %s: %m", myname, service); /* - * Disconnect. + * Wakeup when the peer disconnects, or when we lose patience. */ - if (close(fd) < 0) - if (msg_verbose) - msg_warn("%s: close %s: %m", myname, service); + if (timeout > 0) + event_request_timer(unix_trigger_event, (char *) up, timeout + 100); + event_enable_read(fd, unix_trigger_event, (char *) up); return (0); } diff --git a/gnu/dist/postfix/src/util/vstream.c b/gnu/dist/postfix/src/util/vstream.c index e2ec94ddcf7..22c59440ca7 100644 --- a/gnu/dist/postfix/src/util/vstream.c +++ b/gnu/dist/postfix/src/util/vstream.c @@ -72,6 +72,9 @@ /* int vstream_fileno(stream) /* VSTREAM *stream; /* +/* void *vstream_context(stream) +/* VSTREAM *stream; +/* /* int vstream_ferror(stream) /* VSTREAM *stream; /* @@ -97,7 +100,7 @@ /* int vstream_setjmp(stream) /* VSTREAM *stream; /* -/* void longjmp(stream, val) +/* void vstream_longjmp(stream, val) /* VSTREAM *stream; /* int val; /* @@ -175,11 +178,11 @@ /* /* VSTREAM_PUTCHAR(c) is an alias for VSTREAM_PUTC(c, VSTREAM_OUT). /* -/* vstream_unget() pushes back a character onto the specified stream +/* vstream_ungetc() pushes back a character onto the specified stream /* and returns the character, or VSTREAM_EOF in case of problems. /* It is an error to push back before reading (or immediately after /* changing the stream offset via vstream_fseek()). Upon successful -/* return, vstream_unget() clears the end-of-file stream flag. +/* return, vstream_ungetc() clears the end-of-file stream flag. /* /* vstream_fputs() appends the given null-terminated string to the /* specified buffered stream. The result is 0 in case of success, @@ -250,6 +253,9 @@ /* a buffered stream. With streams that have separate read/write /* file descriptors, the result is the current descriptor. /* +/* vstream_context() returns the application context that is passed on to +/* the application-specified read/write routines. +/* /* VSTREAM_PATH() is an unsafe macro that returns the name stored /* with vstream_fopen() or with vstream_control(). The macro is /* unsafe because it evaluates some arguments more than once. diff --git a/gnu/dist/postfix/src/util/vstream.h b/gnu/dist/postfix/src/util/vstream.h index f38259b2701..3ec6382956b 100644 --- a/gnu/dist/postfix/src/util/vstream.h +++ b/gnu/dist/postfix/src/util/vstream.h @@ -90,6 +90,7 @@ extern VSTREAM *vstream_fdopen(int, int); #define VSTREAM_GETCHAR() VSTREAM_GETC(VSTREAM_IN) #define vstream_fileno(vp) ((vp)->fd) +#define vstream_context(vp) ((vp)->context) #define vstream_ferror(vp) vbuf_error(&(vp)->buf) #define vstream_feof(vp) vbuf_eof(&(vp)->buf) #define vstream_ftimeout(vp) vbuf_timeout(&(vp)->buf) diff --git a/gnu/dist/postfix/src/util/vstring.c b/gnu/dist/postfix/src/util/vstring.c index 356b114b2b8..0f3e33b5e40 100644 --- a/gnu/dist/postfix/src/util/vstring.c +++ b/gnu/dist/postfix/src/util/vstring.c @@ -67,6 +67,16 @@ /* const char *src; /* int len; /* +/* VSTRING *vstring_memcpy(vp, src, len) +/* VSTRING *vp; +/* const char *src; +/* int len; +/* +/* VSTRING *vstring_memcat(vp, src, len) +/* VSTRING *vp; +/* const char *src; +/* int len; +/* /* VSTRING *vstring_sprintf(vp, format, ...) /* VSTRING *vp; /* const char *format; @@ -101,14 +111,15 @@ /* of at least "len" bytes. The minimal length is 1. The result /* is a null-terminated string of length zero. /* -/* vstring_ctl() gives control over memory management policy. +/* vstring_ctl() gives additional control over vstring behavior. /* The function takes a VSTRING pointer and a list of zero -/* or more (name,value) pairs. The expected valye type of the -/* value depends on the specified name. The name codes are: +/* or more (name,value) pairs. The expected value type +/* depends on the specified name. The value name codes are: /* .IP "VSTRING_CTL_MAXLEN (int)" /* Specifies a hard upper limit on a string's length. When the /* length would be exceeded, the program simulates a memory /* allocation problem (i.e. it terminates through msg_fatal()). +/* This fuctionality is currently unimplemented. /* .IP "VSTRING_CTL_END (no value)" /* Specifies the end of the argument list. Forgetting to terminate /* the argument list may cause the program to crash. @@ -174,6 +185,14 @@ /* vstring_strncat() copies at most \fIlen\fR characters. Otherwise it is /* identical to vstring_strcat(). /* +/* vstring_memcpy() copies \fIlen\fR bytes to a variable-length string. +/* \fIsrc\fP provides the data to be copied; \fIvp\fP is the +/* target and result value. The result is not null-terminated. +/* +/* vstring_memcat() appends \fIlen\fR bytes to a variable-length string. +/* \fIsrc\fP provides the data to be copied; \fIvp\fP is the +/* target and result value. The result is not null-terminated. +/* /* vstring_sprintf() produces a formatted string according to its /* \fIformat\fR argument. See vstring_vsprintf() for details. /* @@ -392,6 +411,29 @@ VSTRING *vstring_strncat(VSTRING *vp, const char *src, int len) return (vp); } +/* vstring_memcpy - copy buffer of limited length */ + +VSTRING *vstring_memcpy(VSTRING *vp, const char *src, int len) +{ + VSTRING_RESET(vp); + + VSTRING_SPACE(vp, len); + memcpy(vstring_str(vp), src, len); + VSTRING_AT_OFFSET(vp, len); + return (vp); +} + +/* vstring_memcat - append buffer of limited length */ + +VSTRING *vstring_memcat(VSTRING *vp, const char *src, int len) +{ + VSTRING_SPACE(vp, len); + memcpy(vstring_end(vp), src, len); + len += VSTRING_LEN(vp); + VSTRING_AT_OFFSET(vp, len); + return (vp); +} + /* vstring_export - VSTRING to bare string */ char *vstring_export(VSTRING *vp) diff --git a/gnu/dist/postfix/src/util/vstring.h b/gnu/dist/postfix/src/util/vstring.h index 6ae8947e784..b1b81bb8acd 100644 --- a/gnu/dist/postfix/src/util/vstring.h +++ b/gnu/dist/postfix/src/util/vstring.h @@ -38,6 +38,8 @@ extern VSTRING *vstring_strcpy(VSTRING *, const char *); extern VSTRING *vstring_strncpy(VSTRING *, const char *, int); extern VSTRING *vstring_strcat(VSTRING *, const char *); extern VSTRING *vstring_strncat(VSTRING *, const char *, int); +extern VSTRING *vstring_memcpy(VSTRING *, const char *, int); +extern VSTRING *vstring_memcat(VSTRING *, const char *, int); extern VSTRING *PRINTFLIKE(2, 3) vstring_sprintf(VSTRING *, const char *,...); extern VSTRING *PRINTFLIKE(2, 3) vstring_sprintf_append(VSTRING *, const char *,...); extern char *vstring_export(VSTRING *); diff --git a/gnu/dist/postfix/src/util/vstring_vstream.c b/gnu/dist/postfix/src/util/vstring_vstream.c index 078d255e1ac..2f644bf1dc7 100644 --- a/gnu/dist/postfix/src/util/vstring_vstream.c +++ b/gnu/dist/postfix/src/util/vstring_vstream.c @@ -27,6 +27,11 @@ /* 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 @@ -41,7 +46,7 @@ /* 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 @@ -154,6 +159,22 @@ int vstring_get_nonl_bound(VSTRING *vp, VSTREAM *fp, int bound) 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 /* diff --git a/gnu/dist/postfix/src/util/vstring_vstream.h b/gnu/dist/postfix/src/util/vstring_vstream.h index 897167ca640..68bd8106db0 100644 --- a/gnu/dist/postfix/src/util/vstring_vstream.h +++ b/gnu/dist/postfix/src/util/vstring_vstream.h @@ -24,6 +24,7 @@ extern int vstring_get_nonl(VSTRING *, VSTREAM *); 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() diff --git a/gnu/dist/postfix/src/virtual/.printfck b/gnu/dist/postfix/src/virtual/.printfck new file mode 100644 index 00000000000..66016ed453c --- /dev/null +++ b/gnu/dist/postfix/src/virtual/.printfck @@ -0,0 +1,25 @@ +been_here_xt 2 0 +bounce_append 5 0 +cleanup_out_format 1 0 +defer_append 5 0 +mail_command 1 0 +mail_print 1 0 +msg_error 0 0 +msg_fatal 0 0 +msg_info 0 0 +msg_panic 0 0 +msg_warn 0 0 +opened 4 0 +post_mail_fprintf 1 0 +qmgr_message_bounce 2 0 +rec_fprintf 2 0 +sent 4 0 +smtp_cmd 1 0 +smtp_mesg_fail 2 0 +smtp_printf 1 0 +smtp_rcpt_fail 3 0 +smtp_site_fail 2 0 +udp_syslog 1 0 +vstream_fprintf 1 0 +vstream_printf 0 0 +vstring_sprintf 1 0 diff --git a/gnu/dist/postfix/src/virtual/Makefile.in b/gnu/dist/postfix/src/virtual/Makefile.in new file mode 100644 index 00000000000..8bf523ed3f8 --- /dev/null +++ b/gnu/dist/postfix/src/virtual/Makefile.in @@ -0,0 +1,166 @@ +SHELL = /bin/sh +SRCS = virtual.c mailbox.c recipient.c deliver_attr.c maildir.c unknown.c +OBJS = virtual.o mailbox.o recipient.o deliver_attr.o maildir.o unknown.o +HDRS = virtual.h +TESTSRC = +WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ + -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ + -Wunused +DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) -I.. +CFLAGS = $(DEBUG) $(OPT) $(DEFS) +PROG = virtual +TESTPROG= +INC_DIR = ../../include +LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a $(AUXLIBS) + +.c.o:; $(CC) $(CFLAGS) -c $*.c + +$(PROG): $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) + +Makefile: Makefile.in + (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs; cat $?) >$@ + +test: $(TESTPROG) + +update: ../../libexec/$(PROG) + +../../libexec/$(PROG): $(PROG) + cp $(PROG) ../../libexec + +printfck: $(OBJS) $(PROG) + rm -rf printfck + mkdir printfck + cp *.h printfck + sed '1,/^# do not edit/!d' Makefile >printfck/Makefile + set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done + cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o` + +lint: + lint $(DEFS) $(SRCS) $(LINTFIX) + +clean: + rm -f *.o *core $(PROG) $(TESTPROG) junk + rm -rf printfck + +tidy: clean + +depend: $(MAKES) + (sed '1,/^# do not edit/!d' Makefile.in; \ + set -e; for i in [a-z][a-z0-9]*.c; do \ + $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ + -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \ + done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in + @make -f Makefile.in Makefile + +# do not edit below this line - it is generated by 'make depend' +deliver_attr.o: deliver_attr.c +deliver_attr.o: ../../include/sys_defs.h +deliver_attr.o: ../../include/msg.h +deliver_attr.o: ../../include/vstream.h +deliver_attr.o: ../../include/vbuf.h +deliver_attr.o: virtual.h +deliver_attr.o: ../../include/vstring.h +deliver_attr.o: ../../include/deliver_request.h +deliver_attr.o: ../../include/recipient_list.h +deliver_attr.o: ../../include/maps.h +deliver_attr.o: ../../include/dict.h +deliver_attr.o: ../../include/argv.h +deliver_attr.o: ../../include/mbox_conf.h +mailbox.o: mailbox.c +mailbox.o: ../../include/sys_defs.h +mailbox.o: ../../include/msg.h +mailbox.o: ../../include/vstring.h +mailbox.o: ../../include/vbuf.h +mailbox.o: ../../include/vstream.h +mailbox.o: ../../include/mymalloc.h +mailbox.o: ../../include/stringops.h +mailbox.o: ../../include/set_eugid.h +mailbox.o: ../../include/mail_copy.h +mailbox.o: ../../include/mbox_open.h +mailbox.o: ../../include/safe_open.h +mailbox.o: ../../include/defer.h +mailbox.o: ../../include/bounce.h +mailbox.o: ../../include/sent.h +mailbox.o: ../../include/mail_params.h +mailbox.o: virtual.h +mailbox.o: ../../include/deliver_request.h +mailbox.o: ../../include/recipient_list.h +mailbox.o: ../../include/maps.h +mailbox.o: ../../include/dict.h +mailbox.o: ../../include/argv.h +mailbox.o: ../../include/mbox_conf.h +maildir.o: maildir.c +maildir.o: ../../include/sys_defs.h +maildir.o: ../../include/msg.h +maildir.o: ../../include/mymalloc.h +maildir.o: ../../include/stringops.h +maildir.o: ../../include/vstring.h +maildir.o: ../../include/vbuf.h +maildir.o: ../../include/vstream.h +maildir.o: ../../include/make_dirs.h +maildir.o: ../../include/set_eugid.h +maildir.o: ../../include/get_hostname.h +maildir.o: ../../include/sane_fsops.h +maildir.o: ../../include/mail_copy.h +maildir.o: ../../include/bounce.h +maildir.o: ../../include/defer.h +maildir.o: ../../include/sent.h +maildir.o: ../../include/mail_params.h +maildir.o: virtual.h +maildir.o: ../../include/deliver_request.h +maildir.o: ../../include/recipient_list.h +maildir.o: ../../include/maps.h +maildir.o: ../../include/dict.h +maildir.o: ../../include/argv.h +maildir.o: ../../include/mbox_conf.h +recipient.o: recipient.c +recipient.o: ../../include/sys_defs.h +recipient.o: ../../include/msg.h +recipient.o: ../../include/mymalloc.h +recipient.o: ../../include/stringops.h +recipient.o: ../../include/vstring.h +recipient.o: ../../include/vbuf.h +recipient.o: ../../include/bounce.h +recipient.o: virtual.h +recipient.o: ../../include/vstream.h +recipient.o: ../../include/deliver_request.h +recipient.o: ../../include/recipient_list.h +recipient.o: ../../include/maps.h +recipient.o: ../../include/dict.h +recipient.o: ../../include/argv.h +recipient.o: ../../include/mbox_conf.h +unknown.o: unknown.c +unknown.o: ../../include/sys_defs.h +unknown.o: ../../include/msg.h +unknown.o: ../../include/bounce.h +unknown.o: virtual.h +unknown.o: ../../include/vstream.h +unknown.o: ../../include/vbuf.h +unknown.o: ../../include/vstring.h +unknown.o: ../../include/deliver_request.h +unknown.o: ../../include/recipient_list.h +unknown.o: ../../include/maps.h +unknown.o: ../../include/dict.h +unknown.o: ../../include/argv.h +unknown.o: ../../include/mbox_conf.h +virtual.o: virtual.c +virtual.o: ../../include/sys_defs.h +virtual.o: ../../include/msg.h +virtual.o: ../../include/vstring.h +virtual.o: ../../include/vbuf.h +virtual.o: ../../include/vstream.h +virtual.o: ../../include/iostuff.h +virtual.o: ../../include/set_eugid.h +virtual.o: ../../include/dict.h +virtual.o: ../../include/argv.h +virtual.o: ../../include/mail_queue.h +virtual.o: ../../include/recipient_list.h +virtual.o: ../../include/deliver_request.h +virtual.o: ../../include/deliver_completed.h +virtual.o: ../../include/mail_params.h +virtual.o: ../../include/mail_conf.h +virtual.o: ../../include/mail_server.h +virtual.o: virtual.h +virtual.o: ../../include/maps.h +virtual.o: ../../include/mbox_conf.h diff --git a/gnu/dist/postfix/src/virtual/deliver_attr.c b/gnu/dist/postfix/src/virtual/deliver_attr.c new file mode 100644 index 00000000000..63b15580fcf --- /dev/null +++ b/gnu/dist/postfix/src/virtual/deliver_attr.c @@ -0,0 +1,74 @@ +/*++ +/* NAME +/* deliver_attr 3 +/* SUMMARY +/* initialize message delivery attributes +/* SYNOPSIS +/* #include "virtual.h" +/* +/* void deliver_attr_init(attrp) +/* DELIVER_ATTR *attrp; +/* +/* void deliver_attr_dump(attrp) +/* DELIVER_ATTR *attrp; +/* DESCRIPTION +/* deliver_attr_init() initializes a structure with message delivery +/* attributes to a known initial state (all zeros). +/* +/* deliver_attr_dump() logs the contents of the given attribute list. +/* 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. */ + +#include <msg.h> +#include <vstream.h> + +/* Application-specific. */ + +#include "virtual.h" + +/* deliver_attr_init - set message delivery attributes to all-zero state */ + +void deliver_attr_init(DELIVER_ATTR *attrp) +{ + attrp->level = 0; + attrp->fp = 0; + attrp->queue_name = 0; + attrp->queue_id = 0; + attrp->offset = 0; + attrp->sender = 0; + attrp->recipient = 0; + attrp->user = 0; + attrp->delivered = 0; + attrp->relay = 0; +} + +/* deliver_attr_dump - log message delivery attributes */ + +void deliver_attr_dump(DELIVER_ATTR *attrp) +{ + msg_info("level: %d", attrp->level); + msg_info("path: %s", VSTREAM_PATH(attrp->fp)); + msg_info("fp: 0x%lx", (long) attrp->fp); + msg_info("queue_name: %s", attrp->queue_name ? attrp->queue_name : "null"); + msg_info("queue_id: %s", attrp->queue_id ? attrp->queue_id : "null"); + msg_info("offset: %ld", attrp->offset); + msg_info("sender: %s", attrp->sender ? attrp->sender : "null"); + msg_info("recipient: %s", attrp->recipient ? attrp->recipient : "null"); + msg_info("user: %s", attrp->user ? attrp->user : "null"); + msg_info("delivered: %s", attrp->delivered ? attrp->delivered : "null"); + msg_info("relay: %s", attrp->relay ? attrp->relay : "null"); +} diff --git a/gnu/dist/postfix/src/virtual/mailbox.c b/gnu/dist/postfix/src/virtual/mailbox.c new file mode 100644 index 00000000000..21782404b62 --- /dev/null +++ b/gnu/dist/postfix/src/virtual/mailbox.c @@ -0,0 +1,246 @@ +/*++ +/* NAME +/* mailbox 3 +/* SUMMARY +/* mailbox delivery +/* SYNOPSIS +/* #include "virtual.h" +/* +/* int deliver_mailbox(state, usr_attr, statusp) +/* LOCAL_STATE state; +/* USER_ATTR usr_attr; +/* int *statusp; +/* DESCRIPTION +/* deliver_mailbox() delivers to UNIX-style mailbox or to maildir. +/* +/* A zero result means that the named user was not found. +/* +/* Arguments: +/* .IP state +/* The attributes that specify the message, recipient and more. +/* .IP usr_attr +/* Attributes describing user rights and mailbox location. +/* .IP statusp +/* Delivery status: see below. +/* DIAGNOSTICS +/* The message delivery status is non-zero when delivery should be tried +/* again. +/* 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/stat.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <vstream.h> +#include <mymalloc.h> +#include <stringops.h> +#include <set_eugid.h> + +/* Global library. */ + +#include <mail_copy.h> +#include <mbox_open.h> +#include <defer.h> +#include <sent.h> +#include <mail_params.h> + +#ifndef EDQUOT +#define EDQUOT EFBIG +#endif + +/* Application-specific. */ + +#include "virtual.h" + +#define YES 1 +#define NO 0 + +/* deliver_mailbox_file - deliver to recipient mailbox */ + +static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr) +{ + char *myname = "deliver_mailbox_file"; + VSTRING *why; + MBOX *mp; + int mail_copy_status; + int deliver_status; + int copy_flags; + long end; + struct stat st; + + /* + * Make verbose logging easier to understand. + */ + state.level++; + if (msg_verbose) + MSG_LOG_STATE(myname, state); + + /* + * Initialize. Assume the operation will fail. Set the delivered + * attribute to reflect the final recipient. + */ + if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) + msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); + state.msg_attr.delivered = state.msg_attr.recipient; + mail_copy_status = MAIL_COPY_STAT_WRITE; + why = vstring_alloc(100); + + /* + * Lock the mailbox and open/create the mailbox file. + * + * Write the file as the recipient, so that file quota work. + */ + copy_flags = MAIL_COPY_MBOX; + + set_eugid(usr_attr.uid, usr_attr.gid); + mp = mbox_open(usr_attr.mailbox, O_APPEND | O_WRONLY | O_CREAT, + S_IRUSR | S_IWUSR, &st, -1, -1, + virtual_mbox_lock_mask, why); + if (mp != 0) { + if (S_ISREG(st.st_mode) == 0) { + vstream_fclose(mp->fp); + vstring_sprintf(why, "destination is not a regular file"); + errno = 0; + } else { + end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END); + mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp, + copy_flags, "\n", why); + } + mbox_release(mp); + } + set_eugid(var_owner_uid, var_owner_gid); + + /* + * As the mail system, bounce, defer delivery, or report success. + */ + if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { + deliver_status = DEL_STAT_DEFER; + } else if (mail_copy_status != 0) { + deliver_status = (errno == EDQUOT || errno == EFBIG ? + bounce_append : defer_append) + (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "mailbox %s: %s", usr_attr.mailbox, vstring_str(why)); + } else { + deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox"); + } + vstring_free(why); + return (deliver_status); +} + +/* deliver_mailbox - deliver to recipient mailbox */ + +int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp) +{ + char *myname = "deliver_mailbox"; + const char *mailbox_res; + const char *uid_res; + const char *gid_res; + long n; + + /* + * Make verbose logging easier to understand. + */ + state.level++; + if (msg_verbose) + MSG_LOG_STATE(myname, state); + + /* + * Sanity check. + */ + if (*var_virt_mailbox_base != '/') + msg_fatal("do not specify relative pathname: %s = %s", + VAR_VIRT_MAILBOX_BASE, var_virt_mailbox_base); + + /* + * Look up the mailbox location. Bounce if not found, defer in case of + * trouble. + */ + mailbox_res = maps_find(virtual_mailbox_maps, state.msg_attr.user, + DICT_FLAG_FIXED); + if (mailbox_res == 0) { + if (dict_errno == 0) + return (NO); + + *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "%s: lookup %s: %m", + virtual_mailbox_maps->title, state.msg_attr.user); + return (YES); + } + usr_attr.mailbox = concatenate(var_virt_mailbox_base, "/", + mailbox_res, (char *) 0); + +#define RETURN(res) { myfree(usr_attr.mailbox); return (res); } + + /* + * Look up the mailbox owner rights. Defer in case of trouble. + */ + if ((uid_res = maps_find(virtual_uid_maps, state.msg_attr.user, + DICT_FLAG_FIXED)) == 0) { + *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "recipient %s: uid not found in %s", + state.msg_attr.user, virtual_uid_maps->title); + RETURN(YES); + } + if ((n = atol(uid_res)) < var_virt_minimum_uid) { + *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "recipient %s: bad uid %s in %s", + state.msg_attr.user, uid_res, virtual_uid_maps->title); + RETURN(YES); + } + usr_attr.uid = (uid_t) n; + + /* + * Look up the mailbox group rights. Defer in case of trouble. + */ + if ((gid_res = maps_find(virtual_gid_maps, state.msg_attr.user, + DICT_FLAG_FIXED)) == 0) { + *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "recipient %s: gid not found in %s", + state.msg_attr.user, virtual_gid_maps->title); + RETURN(YES); + } + if ((n = atol(gid_res)) <= 0) { + *statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "recipient %s: bad gid %s in %s", + state.msg_attr.user, gid_res, virtual_gid_maps->title); + RETURN(YES); + } + usr_attr.gid = (gid_t) n; + + if (msg_verbose) + msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u", + myname, state.level, usr_attr.mailbox, + (unsigned) usr_attr.uid, (unsigned) usr_attr.gid); + + /* + * Deliver to mailbox or to external command. + */ +#define LAST_CHAR(s) (s[strlen(s) - 1]) + + if (LAST_CHAR(usr_attr.mailbox) == '/') + *statusp = deliver_maildir(state, usr_attr); + else + *statusp = deliver_mailbox_file(state, usr_attr); + + /* + * Cleanup. + */ + RETURN(YES); +} diff --git a/gnu/dist/postfix/src/virtual/maildir.c b/gnu/dist/postfix/src/virtual/maildir.c new file mode 100644 index 00000000000..2db4130020a --- /dev/null +++ b/gnu/dist/postfix/src/virtual/maildir.c @@ -0,0 +1,176 @@ +/*++ +/* NAME +/* maildir 3 +/* SUMMARY +/* delivery to maildir +/* SYNOPSIS +/* #include "virtual.h" +/* +/* int deliver_maildir(state, usr_attr) +/* LOCAL_STATE state; +/* USER_ATTR usr_attr; +/* DESCRIPTION +/* deliver_maildir() delivers a message to a qmail-style maildir. +/* +/* Arguments: +/* .IP state +/* The attributes that specify the message, recipient and more. +/* .IP usr_attr +/* Attributes describing user rights and environment information. +/* DIAGNOSTICS +/* deliver_maildir() always succeeds or it bounces the message. +/* SEE ALSO +/* bounce(3) +/* 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 <errno.h> + +#ifndef EDQUOT +#define EDQUOT EFBIG +#endif + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <stringops.h> +#include <vstream.h> +#include <vstring.h> +#include <make_dirs.h> +#include <set_eugid.h> +#include <get_hostname.h> +#include <sane_fsops.h> + +/* Global library. */ + +#include <mail_copy.h> +#include <bounce.h> +#include <defer.h> +#include <sent.h> +#include <mail_params.h> + +/* Application-specific. */ + +#include "virtual.h" + +/* deliver_maildir - delivery to maildir-style mailbox */ + +int deliver_maildir(LOCAL_STATE state, USER_ATTR usr_attr) +{ + char *myname = "deliver_maildir"; + char *newdir; + char *tmpdir; + char *curdir; + char *tmpfile; + char *newfile; + VSTRING *why; + VSTRING *buf; + VSTREAM *dst; + int mail_copy_status; + int deliver_status; + int copy_flags; + static int count; + + /* + * Make verbose logging easier to understand. + */ + state.level++; + if (msg_verbose) + MSG_LOG_STATE(myname, state); + + /* + * Initialize. Assume the operation will fail. Set the delivered + * attribute to reflect the final recipient. + */ + if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0) + msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp)); + state.msg_attr.delivered = state.msg_attr.recipient; + mail_copy_status = MAIL_COPY_STAT_WRITE; + buf = vstring_alloc(100); + why = vstring_alloc(100); + + copy_flags = MAIL_COPY_TOFILE | MAIL_COPY_RETURN_PATH | MAIL_COPY_DELIVERED; + + newdir = concatenate(usr_attr.mailbox, "new/", (char *) 0); + tmpdir = concatenate(usr_attr.mailbox, "tmp/", (char *) 0); + curdir = concatenate(usr_attr.mailbox, "cur/", (char *) 0); + + /* + * Create and write the file as the recipient, so that file quota work. + * Create any missing directories on the fly. The file name is chosen + * according to ftp://koobera.math.uic.edu/www/proto/maildir.html: + * + * "A unique name has three pieces, separated by dots. On the left is the + * result of time(). On the right is the result of gethostname(). In the + * middle is something that doesn't repeat within one second on a single + * host. I fork a new process for each delivery, so I just use the + * process ID. If you're delivering several messages from one process, + * use starttime.pid_count.host, where starttime is the time that your + * process started, and count is the number of messages you've + * delivered." + */ +#define STR vstring_str + + set_eugid(usr_attr.uid, usr_attr.gid); + vstring_sprintf(buf, "%ld.%d_%d.%s", (long) var_starttime, + var_pid, count++, get_hostname()); + tmpfile = concatenate(tmpdir, STR(buf), (char *) 0); + newfile = concatenate(newdir, STR(buf), (char *) 0); + if ((dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0 + && (errno != ENOENT + || make_dirs(tmpdir, 0700) < 0 + || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) { + vstring_sprintf(why, "create %s: %m", tmpfile); + } else { + if ((mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), + dst, copy_flags, "\n", why)) == 0) { + if (sane_link(tmpfile, newfile) < 0 + && (errno != ENOENT + || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0 + || sane_link(tmpfile, newfile) < 0)) { + vstring_sprintf(why, "link to %s: %m", newfile); + mail_copy_status = MAIL_COPY_STAT_WRITE; + } + } + if (unlink(tmpfile) < 0) + msg_warn("remove %s: %m", tmpfile); + } + set_eugid(var_owner_uid, var_owner_gid); + + /* + * The maildir location is controlled by the mail administrator. If + * delivery fails, try again later. We would just bounce when the maildir + * location possibly under user control. + */ + if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) { + deliver_status = DEL_STAT_DEFER; + } else if (mail_copy_status != 0) { + deliver_status = (errno == EDQUOT || errno == EFBIG ? + bounce_append : defer_append) + (BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "maildir delivery failed: %s", vstring_str(why)); + + } else { + deliver_status = sent(SENT_ATTR(state.msg_attr), "maildir"); + } + vstring_free(buf); + vstring_free(why); + myfree(newdir); + myfree(tmpdir); + myfree(curdir); + myfree(tmpfile); + myfree(newfile); + return (deliver_status); +} diff --git a/gnu/dist/postfix/src/virtual/recipient.c b/gnu/dist/postfix/src/virtual/recipient.c new file mode 100644 index 00000000000..725108f5be7 --- /dev/null +++ b/gnu/dist/postfix/src/virtual/recipient.c @@ -0,0 +1,93 @@ +/*++ +/* NAME +/* recipient 3 +/* SUMMARY +/* deliver to one local recipient +/* SYNOPSIS +/* #include "virtual.h" +/* +/* int deliver_recipient(state, usr_attr) +/* LOCAL_STATE state; +/* USER_ATTR *usr_attr; +/* DESCRIPTION +/* deliver_recipient() delivers a message to a local recipient. +/* +/* Arguments: +/* .IP state +/* The attributes that specify the message, sender, and more. +/* .IP usr_attr +/* Attributes describing user rights and mailbox location. +/* DIAGNOSTICS +/* deliver_recipient() returns non-zero when delivery should be +/* tried again. +/* SEE ALSO +/* mailbox(3) delivery to UNIX-style mailbox +/* maildir(3) delivery to qmail-style maildir +/* 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. */ + +#include <msg.h> +#include <mymalloc.h> +#include <stringops.h> + +/* Global library. */ + +#include <bounce.h> + +/* Application-specific. */ + +#include "virtual.h" + +/* deliver_recipient - deliver one local recipient */ + +int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr) +{ + char *myname = "deliver_recipient"; + int rcpt_stat; + + /* + * Make verbose logging easier to understand. + */ + state.level++; + if (msg_verbose) + MSG_LOG_STATE(myname, state); + + /* + * Set up the recipient-specific attributes. The recipient's lookup + * handle is the full address. + */ + if (state.msg_attr.delivered == 0) + state.msg_attr.delivered = state.msg_attr.recipient; + state.msg_attr.user = mystrdup(state.msg_attr.recipient); + lowercase(state.msg_attr.user); + + /* + * Deliver + */ + if (msg_verbose) + deliver_attr_dump(&state.msg_attr); + + if (deliver_mailbox(state, usr_attr, &rcpt_stat) == 0) + rcpt_stat = deliver_unknown(state); + + /* + * Cleanup. + */ + myfree(state.msg_attr.user); + + return (rcpt_stat); +} diff --git a/gnu/dist/postfix/src/virtual/unknown.c b/gnu/dist/postfix/src/virtual/unknown.c new file mode 100644 index 00000000000..8989046e0d1 --- /dev/null +++ b/gnu/dist/postfix/src/virtual/unknown.c @@ -0,0 +1,64 @@ +/*++ +/* NAME +/* unknown 3 +/* SUMMARY +/* delivery of unknown recipients +/* SYNOPSIS +/* #include "virtual.h" +/* +/* int deliver_unknown(state) +/* LOCAL_STATE state; +/* DESCRIPTION +/* deliver_unknown() delivers a message for unknown recipients. +/* .PP +/* Arguments: +/* .IP state +/* Message delivery attributes (sender, recipient etc.). +/* .IP usr_attr +/* Attributes describing user rights and mailbox location. +/* DIAGNOSTICS +/* The result status is non-zero when delivery should be tried again. +/* 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. */ + +#include <msg.h> + +/* Global library. */ + +#include <bounce.h> + +/* Application-specific. */ + +#include "virtual.h" + +/* deliver_unknown - delivery for unknown recipients */ + +int deliver_unknown(LOCAL_STATE state) +{ + char *myname = "deliver_unknown"; + + /* + * Make verbose logging easier to understand. + */ + state.level++; + if (msg_verbose) + MSG_LOG_STATE(myname, state); + + return (bounce_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr), + "unknown user: \"%s\"", state.msg_attr.user)); + +} diff --git a/gnu/dist/postfix/src/virtual/virtual.c b/gnu/dist/postfix/src/virtual/virtual.c new file mode 100644 index 00000000000..7968dcc2856 --- /dev/null +++ b/gnu/dist/postfix/src/virtual/virtual.c @@ -0,0 +1,414 @@ +/*++ +/* NAME +/* virtual 8 +/* SUMMARY +/* Postfix virtual domain mail delivery agent +/* SYNOPSIS +/* \fBvirtual\fR [generic Postfix daemon options] +/* DESCRIPTION +/* The \fBvirtual\fR delivery agent is designed for virtual mail +/* hosting services. Originally based on the Postfix local delivery +/* agent, this agent looks up recipients with map lookups of their +/* full recipient address, instead of using hard-coded unix password +/* file lookups of the address local part only. +/* +/* This delivery agent only delivers mail. Other features such as +/* mail forwarding, out-of-office notifications, etc., must be +/* configured via virtual maps or via similar lookup mechanisms. +/* MAILBOX LOCATION +/* .ad +/* .fi +/* The mailbox location is controlled by the \fBvirtual_mailbox_base\fR +/* and \fBvirtual_mailbox_maps\fR configuration parameters (see below). +/* The \fBvirtual_mailbox_maps\fR table is indexed by the full recipient +/* address. +/* +/* The mailbox pathname is constructed as follows: +/* +/* .ti +2 +/* \fB$virtual_mailbox_base/$virtual_mailbox_maps(\fIrecipient\fB)\fR +/* +/* where \fIrecipient\fR is the full recipient address. +/* UNIX MAILBOX FORMAT +/* .ad +/* .fi +/* When the mailbox location does not end in \fB/\fR, the message +/* is delivered in UNIX mailbox format. This format stores multiple +/* messages in one textfile. +/* +/* The \fBvirtual\fR delivery agent prepends a "\fBFrom \fIsender +/* time_stamp\fR" envelope header to each message, prepends a +/* \fBDelivered-To:\fR message header with the envelope recipient +/* address, prepends a \fBReturn-Path:\fR message header with the +/* envelope sender address, prepends a \fB>\fR character to lines +/* beginning with "\fBFrom \fR", and appends an empty line. +/* +/* The mailbox is locked for exclusive access while delivery is in +/* progress. In case of problems, an attempt is made to truncate the +/* mailbox to its original length. +/* QMAIL MAILDIR FORMAT +/* .ad +/* .fi +/* When the mailbox location ends in \fB/\fR, the message is delivered +/* in qmail \fBmaildir\fR format. This format stores one message per file. +/* +/* The \fBvirtual\fR delivery agent daemon prepends a \fBDelivered-To:\fR +/* message header with the envelope recipient address and prepends a +/* \fBReturn-Path:\fR message header with the envelope sender address. +/* +/* By definition, \fBmaildir\fR format does not require file locking +/* during mail delivery or retrieval. +/* MAILBOX OWNERSHIP +/* .ad +/* .fi +/* Mailbox ownership is controlled by the \fBvirtual_uid_maps\fR +/* and \fBvirtual_gid_maps\fR lookup tables, which are indexed +/* with the full recipient address. Each table provides +/* a string with the numerical user and group ID, respectively. +/* +/* The \fBvirtual_minimum_uid\fR parameter imposes a lower bound on +/* 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 user/group ID information are +/* adequately protected. This program is not designed to run chrooted. +/* STANDARDS +/* RFC 822 (ARPA Internet Text Messages) +/* DIAGNOSTICS +/* Mail bounces when the recipient has no mailbox or when the +/* 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 \fBsyslogd\fR(8). +/* Corrupted message files are marked so that the queue +/* manager can move them to the \fBcorrupt\fR queue afterwards. +/* +/* Depending on the setting of the \fBnotify_classes\fR parameter, +/* the postmaster is notified of bounces and of other trouble. +/* BUGS +/* 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 maintaining +/* three tables, use an LDAP or MYSQL database. +/* CONFIGURATION PARAMETERS +/* .ad +/* .fi +/* The following \fBmain.cf\fR parameters are especially relevant to +/* this program. See the Postfix \fBmain.cf\fR file for syntax details +/* and for default values. Use the \fBpostfix reload\fR command after +/* a configuration change. +/* .SH Mailbox delivery +/* .ad +/* .fi +/* .IP \fBvirtual_mailbox_base\fR +/* 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 +/* \fBvirtual_mailbox_maps\fR doesn't litter the filesystem with mailboxes. +/* While it could be set to "/", this setting isn't recommended. +/* .IP "\fBvirtual_mailbox_maps\fR (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 assumed to specify a UNIX-style mailbox file. +/* +/* Note that \fBvirtual_mailbox_base\fR is unconditionally prepended +/* to this path. +/* .IP \fBvirtual_minimum_uid\fR +/* Specifies a minimum uid that will be accepted as a return from +/* a \fBvirtual_owner_maps\fR or \fBvirtual_uid_maps\fR lookup. +/* Returned values less than this will be rejected, and the message +/* will be deferred. +/* .IP "\fBvirtual_uid_maps\fR (regexp maps disallowed)" +/* Recipients are looked up in these maps to determine the user ID to be +/* used when writing to the target mailbox. +/* .IP "\fBvirtual_gid_maps\fR (regexp maps disallowed)" +/* Recipients are looked up in these maps to determine the group ID to be +/* used when writing to the target mailbox. +/* .SH "Locking controls" +/* .ad +/* .fi +/* .IP \fBvirtual_mailbox_lock\fR +/* How to lock UNIX-style mailboxes: one or more of \fBflock\fR, +/* \fBfcntl\fR or \fBdotlock\fR. The \fBdotlock\fR method requires +/* that the recipient UID or GID has write access to the parent +/* directory of the mailbox file. +/* +/* This setting is ignored with \fBmaildir\fR style delivery, +/* because such deliveries are safe without explicit locks. +/* +/* 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 +/* on a UNIX-style mailbox file. +/* .IP \fBdeliver_lock_delay\fR +/* Time (default: seconds) between successive attempts to acquire +/* an exclusive lock on a UNIX-style mailbox file. The actual delay +/* is slightly randomized. +/* .IP \fBstale_lock_time\fR +/* Limit the time after which a stale lockfile is removed (applicable +/* to UNIX-style mailboxes only). +/* .SH "Resource controls" +/* .ad +/* .fi +/* .IP \fBvirtual_destination_concurrency_limit\fR +/* Limit the number of parallel deliveries to the same domain +/* via the \fBvirtual\fR delivery agent. +/* The default limit is taken from the +/* \fBdefault_destination_concurrency_limit\fR parameter. +/* The limit is enforced by the Postfix queue manager. +/* .IP \fBvirtual_destination_recipient_limit\fR +/* Limit the number of recipients per message delivery +/* via the \fBvirtual\fR delivery agent. +/* The default limit is taken from the +/* \fBdefault_destination_recipient_limit\fR parameter. +/* The limit is enforced by the Postfix queue manager. +/* .IP \fBvirtual_mailbox_limit\fR +/* The maximal size in bytes of a mailbox or maildir file. +/* Set to zero to disable the limit. +/* HISTORY +/* .ad +/* .fi +/* 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 to "|command" or to /file/name. +/* +/* The \fBDelivered-To:\fR header appears in the \fBqmail\fR system +/* by Daniel Bernstein. +/* +/* The \fBmaildir\fR structure appears in the \fBqmail\fR system +/* by Daniel Bernstein. +/* SEE ALSO +/* bounce(8) non-delivery status reports +/* syslogd(8) system logging +/* qmgr(8) queue manager +/* 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 +/* +/* Andrew McNamara +/* andrewm@connect.com.au +/* connect.com.au Pty. Ltd. +/* Level 3, 213 Miller St +/* North Sydney 2060, NSW, Australia +/*--*/ + +/* System library. */ + +#include <sys_defs.h> +#include <stdlib.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <vstream.h> +#include <iostuff.h> +#include <set_eugid.h> +#include <dict.h> + +/* Global library. */ + +#include <mail_queue.h> +#include <recipient_list.h> +#include <deliver_request.h> +#include <deliver_completed.h> +#include <mail_params.h> +#include <mail_conf.h> +#include <mail_params.h> + +/* Single server skeleton. */ + +#include <mail_server.h> + +/* Application-specific. */ + +#include "virtual.h" + + /* + * Tunable parameters. + */ +char *var_virt_mailbox_maps; +char *var_virt_uid_maps; +char *var_virt_gid_maps; +int var_virt_minimum_uid; +char *var_virt_mailbox_base; +char *var_virt_mailbox_lock; +int var_virt_mailbox_limit; + + /* + * Mappings. + */ +MAPS *virtual_mailbox_maps; +MAPS *virtual_uid_maps; +MAPS *virtual_gid_maps; + + /* + * Bit masks. + */ +int virtual_mbox_lock_mask; + +/* local_deliver - deliver message with extreme prejudice */ + +static int local_deliver(DELIVER_REQUEST *rqst, char *service) +{ + char *myname = "local_deliver"; + RECIPIENT *rcpt_end = rqst->rcpt_list.info + rqst->rcpt_list.len; + RECIPIENT *rcpt; + int rcpt_stat; + int msg_stat; + LOCAL_STATE state; + USER_ATTR usr_attr; + + if (msg_verbose) + msg_info("local_deliver: %s from %s", rqst->queue_id, rqst->sender); + + /* + * Initialize the delivery attributes that are not recipient specific. + */ + state.level = 0; + deliver_attr_init(&state.msg_attr); + state.msg_attr.queue_name = rqst->queue_name; + state.msg_attr.queue_id = rqst->queue_id; + state.msg_attr.fp = rqst->fp; + state.msg_attr.offset = rqst->data_offset; + state.msg_attr.sender = rqst->sender; + state.msg_attr.relay = service; + state.msg_attr.arrival_time = rqst->arrival_time; + RESET_USER_ATTR(usr_attr, state.level); + state.request = rqst; + + /* + * Iterate over each recipient named in the delivery request. When the + * mail delivery status for a given recipient is definite (i.e. bounced + * or delivered), update the message queue file and cross off the + * recipient. Update the per-message delivery status. + */ + for (msg_stat = 0, rcpt = rqst->rcpt_list.info; rcpt < rcpt_end; rcpt++) { + state.msg_attr.recipient = rcpt->address; + rcpt_stat = deliver_recipient(state, usr_attr); + if (rcpt_stat == 0) + deliver_completed(state.msg_attr.fp, rcpt->offset); + msg_stat |= rcpt_stat; + } + + return (msg_stat); +} + +/* local_service - perform service for client */ + +static void local_service(VSTREAM *stream, char *service, char **argv) +{ + DELIVER_REQUEST *request; + int status; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (argv[0]) + msg_fatal("unexpected command-line argument: %s", argv[0]); + + /* + * This routine runs whenever a client connects to the UNIX-domain socket + * that is dedicated to local mail delivery service. What we see below is + * a little protocol to (1) tell the client that we are ready, (2) read a + * delivery request from the client, and (3) report the completion status + * of that request. + */ + if ((request = deliver_request_read(stream)) != 0) { + status = local_deliver(request, service); + deliver_request_done(stream, request, status); + } +} + +/* pre_accept - see if tables have changed */ + +static void pre_accept(char *unused_name, char **unused_argv) +{ + if (dict_changed()) { + msg_info("table has changed -- exiting"); + exit(0); + } +} + +/* post_init - post-jail initialization */ + +static void post_init(char *unused_name, char **unused_argv) +{ + + /* + * Drop privileges most of the time. + */ + set_eugid(var_owner_uid, var_owner_gid); + + virtual_mailbox_maps = + maps_create(VAR_VIRT_MAILBOX_MAPS, var_virt_mailbox_maps, + DICT_FLAG_LOCK); + + virtual_uid_maps = + maps_create(VAR_VIRT_UID_MAPS, var_virt_uid_maps, DICT_FLAG_LOCK); + + virtual_gid_maps = + maps_create(VAR_VIRT_GID_MAPS, var_virt_gid_maps, DICT_FLAG_LOCK); + + virtual_mbox_lock_mask = mbox_lock_mask(var_virt_mailbox_lock); +} + +/* pre_init - pre-jail initialization */ + +static void pre_init(char *unused_name, char **unused_argv) +{ + + /* + * Reset the file size limit from the message size limit to the mailbox + * size limit. + * + * We can't have mailbox size limit smaller than the message size limit, + * because that prohibits the delivery agent from updating the queue + * file. + */ + if (var_virt_mailbox_limit) { + if (var_virt_mailbox_limit < var_message_limit) + msg_fatal("main.cf configuration error: %s is smaller than %s", + VAR_VIRT_MAILBOX_LIMIT, VAR_MESSAGE_LIMIT); + set_file_limit(var_virt_mailbox_limit); + } +} + +/* main - pass control to the single-threaded skeleton */ + +int main(int argc, char **argv) +{ + static CONFIG_INT_TABLE int_table[] = { + VAR_VIRT_MINUID, DEF_VIRT_MINUID, &var_virt_minimum_uid, 1, 0, + VAR_VIRT_MAILBOX_LIMIT, DEF_VIRT_MAILBOX_LIMIT, &var_virt_mailbox_limit, 0, 0, + 0, + }; + static CONFIG_STR_TABLE str_table[] = { + VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0, + VAR_VIRT_UID_MAPS, DEF_VIRT_UID_MAPS, &var_virt_uid_maps, 0, 0, + VAR_VIRT_GID_MAPS, DEF_VIRT_GID_MAPS, &var_virt_gid_maps, 0, 0, + VAR_VIRT_MAILBOX_BASE, DEF_VIRT_MAILBOX_BASE, &var_virt_mailbox_base, 0, 0, + VAR_VIRT_MAILBOX_LOCK, DEF_VIRT_MAILBOX_LOCK, &var_virt_mailbox_lock, 1, 0, + 0, + }; + + single_server_main(argc, argv, local_service, + MAIL_SERVER_INT_TABLE, int_table, + MAIL_SERVER_STR_TABLE, str_table, + MAIL_SERVER_PRE_INIT, pre_init, + MAIL_SERVER_POST_INIT, post_init, + MAIL_SERVER_PRE_ACCEPT, pre_accept, + 0); +} diff --git a/gnu/dist/postfix/src/virtual/virtual.h b/gnu/dist/postfix/src/virtual/virtual.h new file mode 100644 index 00000000000..1443bc8d04f --- /dev/null +++ b/gnu/dist/postfix/src/virtual/virtual.h @@ -0,0 +1,134 @@ +/*++ +/* NAME +/* virtual 3h +/* SUMMARY +/* virtual mail delivery +/* SYNOPSIS +/* #include "virtual.h" +/* DESCRIPTION +/* .nf + + /* + * System library. + */ +#include <unistd.h> + + /* + * Utility library. + */ +#include <vstream.h> +#include <vstring.h> + + /* + * Global library. + */ +#include <deliver_request.h> +#include <maps.h> +#include <mbox_conf.h> + + /* + * Mappings. + */ +extern MAPS *virtual_mailbox_maps; +extern MAPS *virtual_uid_maps; +extern MAPS *virtual_gid_maps; + + /* + * User attributes: these control the privileges for delivery to external + * commands, external files, or mailboxes, and the initial environment of + * external commands. + */ +typedef struct USER_ATTR { + uid_t uid; /* file/command access */ + gid_t gid; /* file/command access */ + char *mailbox; /* mailbox file or directory */ +} USER_ATTR; + + /* + * Critical macros. Not for obscurity, but to ensure consistency. + */ +#define RESET_USER_ATTR(usr_attr, level) { \ + usr_attr.uid = 0; usr_attr.gid = 0; usr_attr.mailbox = 0; \ + if (msg_verbose) \ + msg_info("%s[%d]: reset user_attr", myname, level); \ + } + + /* + * The delivery attributes are inherited from files, from aliases, and from + * whatnot. Some of the information is changed on the fly. DELIVER_ATTR + * structres are therefore passed by value, so there is no need to undo + * changes. + */ +typedef struct DELIVER_ATTR { + int level; /* recursion level */ + VSTREAM *fp; /* open queue file */ + char *queue_name; /* mail queue id */ + char *queue_id; /* mail queue id */ + long offset; /* data offset */ + char *sender; /* taken from envelope */ + char *recipient; /* taken from resolver */ + char *user; /* recipient lookup handle */ + char *delivered; /* for loop detection */ + char *relay; /* relay host */ + long arrival_time; /* arrival time */ +} DELIVER_ATTR; + +extern void deliver_attr_init(DELIVER_ATTR *); +extern void deliver_attr_dump(DELIVER_ATTR *); + +#define FEATURE_NODELIVERED (1<<0) /* no delivered-to */ + + /* + * Rather than schlepping around dozens of arguments, here is one that has + * all. Well, almost. The user attributes are just a bit too sensitive, so + * they are passed around separately. + */ +typedef struct LOCAL_STATE { + int level; /* nesting level, for logging */ + DELIVER_ATTR msg_attr; /* message attributes */ + DELIVER_REQUEST *request; /* as from queue manager */ +} LOCAL_STATE; + + /* + * Bundle up some often-user attributes. + */ +#define BOUNCE_ATTR(attr) attr.queue_id, attr.recipient, attr.relay, \ + attr.arrival_time +#define SENT_ATTR(attr) attr.queue_id, attr.recipient, attr.relay, \ + attr.arrival_time +#define COPY_ATTR(attr) attr.sender, attr.delivered, attr.fp + +#define MSG_LOG_STATE(m, p) \ + msg_info("%s[%d]: recip %s deliver %s", m, \ + p.level, \ + p.msg_attr.recipient ? p.msg_attr.recipient : "", \ + p.msg_attr.delivered ? p.msg_attr.delivered : "") + + /* + * "inner" nodes of the delivery graph. + */ +extern int deliver_recipient(LOCAL_STATE, USER_ATTR); + + /* + * "leaf" nodes of the delivery graph. + */ +extern int deliver_mailbox(LOCAL_STATE, USER_ATTR, int *); +extern int deliver_file(LOCAL_STATE, USER_ATTR, char *); +extern int deliver_maildir(LOCAL_STATE, USER_ATTR); +extern int deliver_unknown(LOCAL_STATE); + + /* + * Mailbox lock protocol. + */ +extern int virtual_mbox_lock_mask; + +/* 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 +/*--*/ |
