diff --git a/postfix/HISTORY b/postfix/HISTORY index 136a2c58c..f6750e5d3 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -2371,6 +2371,40 @@ Apologies for any names omitted. Bugfix: \username was broken. Frank Dziuba was the first to notice. +19990321 + + Workaround: from now on, Postfix on Solaris uses stream + pipes instead of UNIX-domain sockets. Despite workarounds, + the latter were causing more trouble than anything else on + all systems combined. + +19990322 + + Portability: the makedefs would mis-identify IRIX 6.5.x as + IRIX 5.x. Fix by Brian Truelsen of Maersk Mc-Kinney Moller + Institute for Production Technology, Denmark. + + Feature: reject_unknown_recipient_domain restriction for + recipient addresses. For the sake of symmetry, we now also + have reject_unknown_sender_domain. This means the old + reject_unknown_address restriction is being phased out. + Suggested by Rask Ingemann Lambertsen [XXX affiliation to + be determined]. + + Feature: unknown sender/recipient domain restrictions now + distinguish between soft errors (always: 450) and hard + errors (configurable with the unknown_address_reject_code + parameter, default: 450; use 550 at your own risk). + + Feature: no HELO junk mail restrictions means that no syntax + check will be done on HELO/EHLO hostname arguments. + + Bugfix: the initial Solaris workaround for UNIX-domain + sockets could cause the queue manager to block if Postfix + ran into a delivery agent process limit. After another code + rewrite that problem is eliminated. Thanks to Chris + Cappuccio, Empire Net, for assistance with testing. + Future: Planned: must be able to list the same hash table in diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index 712ed3c0c..2a484bf80 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -1,5 +1,15 @@ -Incompatible changes with postfix-alpha-19990317: -================================================= +Major changes with snapshot-19990322: +===================================== + +- The UNIX-domain socket workaround for Solaris was fixed +after one day of review. More testing is welcome. + +- reject_unknown_{sender,recipient}_domain restrictions that +distinguish between hard (always 450) and soft (configurable, +default 450) lookup errors. + +Incompatible changes with postfix-19990317: +=========================================== - You MUST install the new version of /etc/postfix/postfix-script. @@ -7,8 +17,8 @@ Incompatible changes with postfix-alpha-19990317: MUST specify the R flag in order to generate a Return-Path: message header (as needed by, for example, cyrus). -Major changes since postfix-beta-19990122-pl01: -=============================================== +Major changes with postfix-19990317: +==================================== A detailed record of changes is given in the HISTORY file. diff --git a/postfix/global/mail_params.h b/postfix/global/mail_params.h index 420267830..b18de0e08 100644 --- a/postfix/global/mail_params.h +++ b/postfix/global/mail_params.h @@ -704,6 +704,8 @@ extern int var_unk_name_code; #define DEF_NON_FQDN_CODE 504 extern int var_non_fqdn_code; +#define REJECT_UNKNOWN_SENDDOM "reject_unknown_sender_domain" +#define REJECT_UNKNOWN_RCPTDOM "reject_unknown_recipient_domain" #define REJECT_UNKNOWN_ADDRESS "reject_unknown_address" #define VAR_UNK_ADDR_CODE "unknown_address_reject_code" #define DEF_UNK_ADDR_CODE 450 diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index 028e1e36b..5164dfe05 100644 --- a/postfix/global/mail_version.h +++ b/postfix/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-19990321" +#define DEF_MAIL_VERSION "Snapshot-19990322" extern char *var_mail_version; /* LICENSE diff --git a/postfix/html/uce.html b/postfix/html/uce.html index 86c81d8ed..8a93bbf86 100644 --- a/postfix/html/uce.html +++ b/postfix/html/uce.html @@ -353,7 +353,7 @@ network address.
Example: -
smtpd_sender_restrictions = reject_unknown_address +
smtpd_sender_restrictions = reject_unknown_sender_domain

@@ -361,12 +361,13 @@ network address.

- + -
reject_unknown_address
Reject the request when -the sender mail address has no DNS A or MX record. The +
reject_unknown_sender_domain
Reject the request +when the sender mail address has no DNS A or MX record. The unknown_address_reject_code parameter specifies the response -code for rejected requests (default: 450). +code for rejected requests (default: 450). The response +is always 450 in case of a temporary DNS error.

@@ -506,6 +507,16 @@ for rejected requests (default: 550).

+ + +

reject_unknown_recipient_domain
Reject the request +when the recipient mail address has no DNS A or MX record. The +unknown_address_reject_code parameter specifies the response +code for rejected requests (default: 450). The response +is always 450 in case of a temporary DNS error. + +

+

reject_non_fqdn_recipient
Reject the request when @@ -515,7 +526,7 @@ response code to rejected requests (default: 504).

-

reject_unknown_address +
reject_unknown_sender_domain
reject_non_fqdn_sender diff --git a/postfix/makedefs b/postfix/makedefs index 61274aebf..49512a2ee 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -137,12 +137,12 @@ case "$SYSTEM.$RELEASE" in CCARGS="$CCARGS -DPATH_DB_H=''" fi ;; - IRIX*.5*) SYSTYPE=IRIX5 + IRIX*.5.*) SYSTYPE=IRIX5 # Use the native compiler by default : ${CC=cc} RANLIB=echo ;; - IRIX*.6*) SYSTYPE=IRIX6 + IRIX*.6.*) SYSTYPE=IRIX6 # Use the native compiler by default, and allow nested comments. : ${CC="cc -woff 1009,1116,1412"} RANLIB=echo diff --git a/postfix/master/multi_server.c b/postfix/master/multi_server.c index 4fcad413c..3ec04e42a 100644 --- a/postfix/master/multi_server.c +++ b/postfix/master/multi_server.c @@ -133,10 +133,8 @@ #include #include #include -#ifndef NO_SELECT_COLLISION #include #include -#endif #include /* Global library. */ @@ -167,12 +165,8 @@ static char *multi_server_name; static char **multi_server_argv; static void (*multi_server_accept) (int, char *); static void (*multi_server_onexit) (void); - -#ifndef NO_SELECT_COLLISION static VSTREAM *multi_server_lock; -#endif - /* multi_server_exit - normal termination */ static NORETURN multi_server_exit(void) @@ -231,11 +225,9 @@ static void multi_server_execute(int unused_event, char *context) { VSTREAM *stream = (VSTREAM *) context; -#ifndef NO_SELECT_COLLISION if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0) msg_fatal("select unlock: %m"); -#endif /* * Do not bother the application when the client disconnected. @@ -290,11 +282,9 @@ static void multi_server_accept_local(int unused_event, char *context) time_left = event_cancel_timer(multi_server_timeout, (char *) 0); fd = LOCAL_ACCEPT(listen_fd); -#ifndef NO_SELECT_COLLISION if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0) msg_fatal("select unlock: %m"); -#endif if (fd < 0) { if (errno != EAGAIN) msg_fatal("accept connection: %m"); @@ -331,11 +321,9 @@ static void multi_server_accept_inet(int unused_event, char *context) time_left = event_cancel_timer(multi_server_timeout, (char *) 0); fd = inet_accept(listen_fd); -#ifndef NO_SELECT_COLLISION if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0) msg_fatal("select unlock: %m"); -#endif if (fd < 0) { if (errno != EAGAIN) msg_fatal("accept connection: %m"); @@ -366,12 +354,8 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) MAIL_SERVER_LOOP_FN loop = 0; int key; char *transport = 0; - -#ifndef NO_SELECT_COLLISION char *lock_path; VSTRING *why; - -#endif int alone = 0; /* @@ -519,7 +503,6 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) * Illustrated volume 2 page 532. We avoid select() collisions with an * external lock file. */ -#ifndef NO_SELECT_COLLISION if (stream == 0 && !alone) { lock_path = concatenate(DEF_PID_DIR, "/", transport, ".", service_name, (char *) 0); @@ -531,7 +514,6 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) myfree(lock_path); vstring_free(why); } -#endif /* * Run pre-jail initialization. @@ -587,11 +569,9 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC); while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) { delay = loop ? loop() : -1; -#ifndef NO_SELECT_COLLISION if (multi_server_lock != 0 && myflock(vstream_fileno(multi_server_lock), MYFLOCK_EXCLUSIVE) < 0) msg_fatal("select lock: %m"); -#endif event_loop(delay); } multi_server_exit(); diff --git a/postfix/master/single_server.c b/postfix/master/single_server.c index eca04871d..cee0426bb 100644 --- a/postfix/master/single_server.c +++ b/postfix/master/single_server.c @@ -124,10 +124,8 @@ #include #include #include -#ifndef NO_SELECT_COLLISION #include #include -#endif #include /* Global library. */ @@ -157,12 +155,8 @@ static char *single_server_name; static char **single_server_argv; static void (*single_server_accept) (int, char *); static void (*single_server_onexit) (void); - -#ifndef NO_SELECT_COLLISION static VSTREAM *single_server_lock; -#endif - /* single_server_exit - normal termination */ static NORETURN single_server_exit(void) @@ -258,11 +252,9 @@ static void single_server_accept_local(int unused_event, char *context) time_left = event_cancel_timer(single_server_timeout, (char *) 0); fd = LOCAL_ACCEPT(listen_fd); -#ifndef NO_SELECT_COLLISION if (single_server_lock != 0 && myflock(vstream_fileno(single_server_lock), MYFLOCK_NONE) < 0) msg_fatal("select unlock: %m"); -#endif if (fd < 0) { if (errno != EAGAIN) msg_fatal("accept connection: %m"); @@ -297,11 +289,9 @@ static void single_server_accept_inet(int unused_event, char *context) time_left = event_cancel_timer(single_server_timeout, (char *) 0); fd = inet_accept(listen_fd); -#ifndef NO_SELECT_COLLISION if (single_server_lock != 0 && myflock(vstream_fileno(single_server_lock), MYFLOCK_NONE) < 0) msg_fatal("select unlock: %m"); -#endif if (fd < 0) { if (errno != EAGAIN) msg_fatal("accept connection: %m"); @@ -332,12 +322,8 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) MAIL_SERVER_LOOP_FN loop = 0; int key; char *transport = 0; - -#ifndef NO_SELECT_COLLISION char *lock_path; VSTRING *why; - -#endif int alone = 0; /* @@ -485,7 +471,6 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) * Illustrated volume 2 page 532. We avoid select() collisions with an * external lock file. */ -#ifndef NO_SELECT_COLLISION if (stream == 0 && !alone) { lock_path = concatenate(DEF_PID_DIR, "/", transport, ".", service_name, (char *) 0); @@ -497,7 +482,6 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) myfree(lock_path); vstring_free(why); } -#endif /* * Run pre-jail initialization. @@ -553,11 +537,9 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC); while (var_use_limit == 0 || use_count < var_use_limit) { delay = loop ? loop() : -1; -#ifndef NO_SELECT_COLLISION if (single_server_lock != 0 && myflock(vstream_fileno(single_server_lock), MYFLOCK_EXCLUSIVE) < 0) msg_fatal("select lock: %m"); -#endif event_loop(delay); } single_server_exit(); diff --git a/postfix/master/trigger_server.c b/postfix/master/trigger_server.c index 261a9dabc..245780c70 100644 --- a/postfix/master/trigger_server.c +++ b/postfix/master/trigger_server.c @@ -132,10 +132,8 @@ #include #include #include -#ifndef NO_SELECT_COLLISION #include #include -#endif #include /* Global library. */ @@ -164,12 +162,8 @@ static char *trigger_server_name; static char **trigger_server_argv; static void (*trigger_server_accept) (int, char *); static void (*trigger_server_onexit) (void); - -#ifndef NO_SELECT_COLLISION static VSTREAM *trigger_server_lock; -#endif - /* trigger_server_exit - normal termination */ static NORETURN trigger_server_exit(void) @@ -239,11 +233,9 @@ static void trigger_server_accept_fifo(int unused_event, char *context) char *myname = "trigger_server_accept_fifo"; int listen_fd = (int) context; -#ifndef NO_SELECT_COLLISION if (trigger_server_lock != 0 && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0) msg_fatal("select unlock: %m"); -#endif if (msg_verbose) msg_info("%s: trigger arrived", myname); @@ -291,11 +283,9 @@ static void trigger_server_accept_local(int unused_event, char *context) time_left = event_cancel_timer(trigger_server_timeout, (char *) 0); fd = LOCAL_ACCEPT(listen_fd); -#ifndef NO_SELECT_COLLISION if (trigger_server_lock != 0 && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_NONE) < 0) msg_fatal("select unlock: %m"); -#endif if (fd < 0) { if (errno != EAGAIN) msg_fatal("accept connection: %m"); @@ -333,12 +323,8 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. char buf[TRIGGER_BUF_SIZE]; int len; char *transport = 0; - -#ifndef NO_SELECT_COLLISION char *lock_path; VSTRING *why; - -#endif int alone = 0; /* @@ -500,7 +486,6 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. * Illustrated volume 2 page 532. We avoid select() collisions with an * external lock file. */ -#ifndef NO_SELECT_COLLISION if (stream == 0 && !alone) { lock_path = concatenate(DEF_PID_DIR, "/", transport, ".", service_name, (char *) 0); @@ -512,7 +497,6 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. myfree(lock_path); vstring_free(why); } -#endif /* * Run pre-jail initialization. @@ -565,11 +549,9 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC); while (var_use_limit == 0 || use_count < var_use_limit) { delay = loop ? loop() : -1; -#ifndef NO_SELECT_COLLISION if (trigger_server_lock != 0 && myflock(vstream_fileno(trigger_server_lock), MYFLOCK_EXCLUSIVE) < 0) msg_fatal("select lock: %m"); -#endif event_loop(delay); } trigger_server_exit(); diff --git a/postfix/smtpd/smtpd.c b/postfix/smtpd/smtpd.c index 5f57eced0..e3689662d 100644 --- a/postfix/smtpd/smtpd.c +++ b/postfix/smtpd/smtpd.c @@ -280,13 +280,26 @@ char *var_always_bcc; */ char *smtpd_path; +/* collapse_args - put arguments together again */ + +static void collapse_args(int argc, SMTPD_TOKEN *argv) +{ + int i; + + for (i = 2; i < argc; i++) { + vstring_strcat(argv[1].vstrval, " "); + vstring_strcat(argv[1].vstrval, argv[i].strval); + } + argv[1].strval = vstring_str(argv[1].vstrval); +} + /* helo_cmd - process HELO command */ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) { char *err; - if (argc != 2) { + if (argc < 2) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 Syntax: HELO hostname"); return (-1); @@ -296,6 +309,7 @@ static int helo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "503 Duplicate HELO/EHLO"); return (-1); } + collapse_args(argc, argv); if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_helo(state, argv[1].strval)) != 0) { smtpd_chat_reply(state, "%s", err); @@ -313,7 +327,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) { char *err; - if (argc != 2) { + if (argc < 2) { state->error_mask |= MAIL_ERROR_PROTOCOL; smtpd_chat_reply(state, "501 Syntax: EHLO hostname"); return (-1); @@ -323,6 +337,7 @@ static int ehlo_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "503 Error: duplicate HELO/EHLO"); return (-1); } + collapse_args(argc, argv); if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_helo(state, argv[1].strval)) != 0) { smtpd_chat_reply(state, "%s", err); @@ -758,9 +773,7 @@ static int noop_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) { - VSTRING *buf; char *err = 0; - int i; /* * The SMTP standard (RFC 821) disallows unquoted special characters in @@ -772,18 +785,9 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "501 Syntax: VRFY address"); return (-1); } - - /* - * Yuck. All input is tokenized. Now put it back together again. - */ - buf = vstring_alloc(100); - for (i = 1; i < argc; i++) { - vstring_strcat(buf, " "); - vstring_strcat(buf, argv[i].strval); - } + collapse_args(argc, argv); if (SMTPD_STAND_ALONE(state) == 0) - err = smtpd_check_rcpt(state, vstring_str(buf)); - vstring_free(buf); + err = smtpd_check_rcpt(state, argv[1].strval); /* * End untokenize. diff --git a/postfix/smtpd/smtpd_check.c b/postfix/smtpd/smtpd_check.c index c59fe1e92..6c1b2f916 100644 --- a/postfix/smtpd/smtpd_check.c +++ b/postfix/smtpd/smtpd_check.c @@ -108,11 +108,16 @@ /* Reject the request when the HELO/EHLO hostname has no A or MX record. /* The \fIunknown_hostname_reject_code\fR configuration /* parameter specifies the reject status code (default: 450). -/* .IP reject_unknown_address +/* .IP reject_unknown_sender_domain /* Reject the request when the resolved sender address has no /* DNS A or MX record. /* The \fIunknown_address_reject_code\fR configuration parameter /* specifies the reject status code (default: 450). +/* .IP reject_unknown_recipient_domain +/* Reject the request when the resolved recipient address has no +/* DNS A or MX record. +/* The \fIunknown_address_reject_code\fR configuration parameter +/* specifies the reject status code (default: 450). /* .IP check_relay_domains /* Allow the request when either the client hostname or the resolved /* recipient domain matches the \fIrelay_domains\fR configuration @@ -577,7 +582,8 @@ static int reject_unknown_mailhost(SMTPD_STATE *state, char *name) if (dns_status != DNS_OK) return (smtpd_check_reject(state, MAIL_ERROR_POLICY, "%d <%s>: Domain not found", - var_unk_addr_code, name)); + dns_status == DNS_NOTFOUND ? + var_unk_addr_code : 450, name)); return (SMTPD_CHECK_DUNNO); } @@ -1197,6 +1203,10 @@ static int generic_checks(SMTPD_STATE *state, char *name, *status = reject_unknown_address(state, state->sender); return (1); } + if (strcasecmp(name, REJECT_UNKNOWN_SENDDOM) == 0) { + *status = reject_unknown_address(state, state->sender); + return (1); + } if (strcasecmp(name, REJECT_NON_FQDN_SENDER) == 0) { if (*state->sender) *status = reject_non_fqdn_address(state, state->sender); @@ -1336,6 +1346,8 @@ char *smtpd_check_rcpt(SMTPD_STATE *state, char *recipient) status = permit_mx_backup(state, recipient); } else if (strcasecmp(name, CHECK_RELAY_DOMAINS) == 0) { status = check_relay_domains(state, recipient); + } else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) { + status = reject_unknown_address(state, recipient); } else if (strcasecmp(name, REJECT_NON_FQDN_RCPT) == 0) { status = reject_non_fqdn_address(state, recipient); } else if (generic_checks(state, name, &cpp, &status, recipient) == 0) { diff --git a/postfix/smtpd/smtpd_check.in2 b/postfix/smtpd/smtpd_check.in2 index 467251307..f779a6e91 100644 --- a/postfix/smtpd/smtpd_check.in2 +++ b/postfix/smtpd/smtpd_check.in2 @@ -83,3 +83,13 @@ mail foo@friend.bad.domain client_restrictions reject_maps_rbl client spike.porcupine.org 168.100.189.2 client foo 127.0.0.2 +# +# unknown sender/recipient domain +# +unknown_address_reject_code 550 +recipient_restrictions reject_unknown_recipient_domain,reject_unknown_sender_domain +mail wietse@porcupine.org +rcpt wietse@porcupine.org +rcpt wietse@no.recipient.domain +mail wietse@no.sender.domain +rcpt wietse@porcupine.org diff --git a/postfix/smtpd/smtpd_check.ref2 b/postfix/smtpd/smtpd_check.ref2 index 78b1f2bda..8009cdb2e 100644 --- a/postfix/smtpd/smtpd_check.ref2 +++ b/postfix/smtpd/smtpd_check.ref2 @@ -172,3 +172,22 @@ OK >>> client foo 127.0.0.2 ./smtpd_check: reject: CONNECT from foo[127.0.0.2]: 550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com 550 Service unavailable; [127.0.0.2] blocked using rbl.maps.vix.com +>>> # +>>> # unknown sender/recipient domain +>>> # +>>> unknown_address_reject_code 550 +OK +>>> recipient_restrictions reject_unknown_recipient_domain,reject_unknown_sender_domain +OK +>>> mail wietse@porcupine.org +OK +>>> rcpt wietse@porcupine.org +OK +>>> rcpt wietse@no.recipient.domain +./smtpd_check: reject: RCPT from foo[127.0.0.2]: 550 : Domain not found +550 : Domain not found +>>> mail wietse@no.sender.domain +OK +>>> rcpt wietse@porcupine.org +./smtpd_check: reject: RCPT from foo[127.0.0.2]: 550 : Domain not found +550 : Domain not found diff --git a/postfix/util/Makefile.in b/postfix/util/Makefile.in index 0c332472c..b9e7a1268 100644 --- a/postfix/util/Makefile.in +++ b/postfix/util/Makefile.in @@ -55,7 +55,8 @@ HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \ vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \ dict_unix.h dict_pcre.h -TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c +TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ + stream_test.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ -Wunused @@ -68,7 +69,7 @@ TESTPROG= dict_open events exec_command fifo_open fifo_rdonly_bug \ fifo_rdwr_bug fifo_trigger fsspace fullname inet_addr_host \ inet_addr_local mac_parse make_dirs msg_syslog \ mystrtok peer_name sigdelay translit valid_hostname vstream_popen \ - vstring vstring_vstream doze select_bug + vstring vstring_vstream doze select_bug stream_test LIB_DIR = ../lib INC_DIR = ../include @@ -237,6 +238,9 @@ depend: $(MAKES) done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in @make Makefile +stream_test: stream_test.c $(LIB) + $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS) + tests: valid_hostname_test valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref @@ -664,15 +668,6 @@ select_bug.o: msg.h select_bug.o: vstream.h select_bug.o: vbuf.h select_bug.o: msg_vstream.h -sendfd_test.o: sendfd_test.c -sendfd_test.o: sys_defs.h -sendfd_test.o: sendfd_test.c -sendfd_test.o: iostuff.h -sendfd_test.o: msg.h -sendfd_test.o: msg_vstream.h -sendfd_test.o: vstream.h -sendfd_test.o: vbuf.h -sendfd_test.o: listen.h set_eugid.o: set_eugid.c set_eugid.o: sys_defs.h set_eugid.o: msg.h @@ -707,6 +702,16 @@ stream_listen.o: sys_defs.h stream_listen.o: msg.h stream_listen.o: listen.h stream_listen.o: iostuff.h +stream_test.o: stream_test.c +stream_test.o: sys_defs.h +stream_test.o: stream_test.c +stream_test.o: iostuff.h +stream_test.o: msg.h +stream_test.o: msg_vstream.h +stream_test.o: vstream.h +stream_test.o: vbuf.h +stream_test.o: listen.h +stream_test.o: connect.h stream_trigger.o: stream_trigger.c stream_trigger.o: sys_defs.h stream_trigger.o: msg.h diff --git a/postfix/util/sendfd_test b/postfix/util/sendfd_test deleted file mode 100755 index 20900647e..000000000 Binary files a/postfix/util/sendfd_test and /dev/null differ diff --git a/postfix/util/stream_connect.c b/postfix/util/stream_connect.c index f15dea51b..be270c93d 100644 --- a/postfix/util/stream_connect.c +++ b/postfix/util/stream_connect.c @@ -41,10 +41,16 @@ /* System library. */ #include + +#ifdef STREAM_CONNECTIONS + #include #include #include #include +#include + +#endif /* Utility library. */ @@ -57,46 +63,41 @@ int stream_connect(const char *path, int block_mode, int unused_timeout) { #ifdef STREAM_CONNECTIONS char *myname = "stream_connect"; - struct stat st; - int fd; - int flags; + int pair[2]; + int fifo; /* * The requested file system object must exist, otherwise we can't reach * the server. */ - if (block_mode == NON_BLOCKING) - flags = O_RDWR | O_NONBLOCK; - else - flags = O_RDWR; - if ((fd = open(path, flags, 0)) < 0) + if ((fifo = open(path, O_WRONLY | O_NONBLOCK, 0)) < 0) return (-1); /* - * XXX Horror. If the open() result is a regular file, no server was - * listening. In this case we simulate what would have happened with - * UNIX-domain sockets. + * Create a pipe, and send one pipe end to the server. */ - if (fstat(fd, &st) < 0) - msg_fatal("%s: fstat: %m", myname); - if (S_ISREG(st.st_mode)) { - close(fd); - errno = ECONNREFUSED; - return (-1); - } + if (pipe(pair) < 0) + msg_fatal("%s: pipe: %m", myname); + if (ioctl(fifo, I_SENDFD, pair[1]) < 0) + msg_fatal("%s: send file descriptor: %m", myname); + close(pair[1]); /* * This is for {unix,inet}_connect() compatibility. */ if (block_mode == NON_BLOCKING) - non_blocking(fd, NON_BLOCKING); + non_blocking(pair[0], NON_BLOCKING); /* - * No trouble detected, so far. + * Cleanup. */ - return (fd); + close(fifo); + + /* + * Keep the other end of the pipe. + */ + return (pair[0]); #else msg_fatal("stream connections are not implemented"); #endif } - diff --git a/postfix/util/stream_listen.c b/postfix/util/stream_listen.c index 0c71c8451..dbbe1a095 100644 --- a/postfix/util/stream_listen.c +++ b/postfix/util/stream_listen.c @@ -29,16 +29,13 @@ /* .IP backlog /* This argument exists for compatibility and is ignored. /* .IP block_mode -/* This argument exists for compatibility and is ignored. -/* blocking mode. +/* Either NON_BLOCKING or BLOCKING. This does not affect the +/* mode of accepted connections. /* .IP fd /* File descriptor returned by stream_listen(). /* DIAGNOSTICS /* Fatal errors: stream_listen() aborts upon any system call failure. /* stream_accept() leaves all error handling up to the caller. -/* BUGS -/* This implementation leaks one file descriptor. This is fixed when -/* endpoints become objects rather than file descriptors. /* LICENSE /* .ad /* .fi @@ -71,46 +68,15 @@ /* stream_listen - create stream listener */ -int stream_listen(const char *path, int unused_backlog, -int unused_block_mode) +int stream_listen(const char *path, int unused_backlog, int block_mode) { #ifdef STREAM_CONNECTIONS - char *myname = "stream_listen"; - static int pair[2]; - int fd; /* - * Initialize: create the specified endpoint with the right permissions. + * We can't specify a listen backlog, however, sending file descriptors + * across a FIFO gives us a backlog buffer of 460 on Solaris 2.4/SPARC. */ -#define PERMS 0666 - if (unlink(path) && errno != ENOENT) - msg_fatal("%s: remove %s: %m", myname, path); - if ((fd = open(path, PERMS, O_CREAT | O_TRUNC | O_WRONLY)) < 0) - msg_fatal("%s: create file %s: %m", myname, path); - if (fchmod(fd, PERMS) < 0) - msg_fatal("%s: chmod 0%o: %m", myname, PERMS); - if (close(fd) < 0) - msg_fatal("%s: close file %s: %m", myname, path); - - /* - * Associate one pipe end with the file just created. See: Richard - * Stevens, Advanced Programming in the UNIX Environment Ch. 15.5.1 - * - * On Solaris 2.4/SPARC, this gives us a "listen queue" of some 460 - * connections. - */ - if (pipe(pair) < 0) - msg_fatal("%s: create pipe: %m", myname); - if (ioctl(pair[1], I_PUSH, "connld") < 0) - msg_fatal("%s: push connld module: %m", myname); - if (fattach(pair[1], path) < 0) - msg_fatal("%s: fattach %s: %m", myname, path); - - /* - * Return one end, and leak the other. This will be fixed when all - * endpoints are objects instead of bare file descriptors. - */ - return (pair[0]); + return (fifo_listen(path, 0666, block_mode)); #else msg_fatal("stream connections are not implemented"); #endif @@ -131,6 +97,6 @@ int stream_accept(int fd) return (-1); return (fdinfo.fd); #else - msg_fatal("stream connections are not implemented"); + msg_fatal("stream connections are not implemented"); #endif } diff --git a/postfix/util/sendfd_test.c b/postfix/util/stream_test.c similarity index 64% rename from postfix/util/sendfd_test.c rename to postfix/util/stream_test.c index d7b148142..1d51f31f4 100644 --- a/postfix/util/sendfd_test.c +++ b/postfix/util/stream_test.c @@ -9,6 +9,7 @@ #include "msg.h" #include "msg_vstream.h" #include "listen.h" +#include "connect.h" #define FIFO "/tmp/test-fifo" @@ -33,9 +34,9 @@ static NORETURN usage(void) main(int argc, char **argv) { - struct strrecvfd fdinfo; int server_fd; int client_fd; + int fd; int print_fstats = 0; int count = 1; int ch; @@ -63,43 +64,39 @@ main(int argc, char **argv) break; } } - server_fd = fifo_listen(FIFO, 0600, NON_BLOCKING); + server_fd = stream_listen(FIFO, 0, 0); if (readable(server_fd)) msg_fatal("server fd is readable after create"); /* * Connect in client. */ - if ((client_fd = open(FIFO, O_RDWR, NON_BLOCKING)) < 0) - msg_fatal("open %s as client: %m", FIFO); - if (readable(server_fd)) - msg_warn("server fd is readable after client open"); - if (print_fstats) - print_fstat(0); - if (ioctl(client_fd, I_RECVFD, &fdinfo) < 0) - msg_fatal("receive fd: %m"); for (i = 0; i < count; i++) { - msg_info("send attempt %d", i); - while (!writable(client_fd)) - msg_info("wait for client fd to become writable"); - if (ioctl(client_fd, I_SENDFD, 0) < 0) - msg_fatal("send fd to server: %m"); + msg_info("connect attempt %d", i); + if ((client_fd = stream_connect(FIFO, 0, 0)) < 0) + msg_fatal("open %s as client: %m", FIFO); + if (readable(server_fd)) + msg_info("server fd is readable after client open"); + if (close(client_fd) < 0) + msg_fatal("close client fd: %m"); } - if (close(client_fd) < 0) - msg_fatal("close client fd: %m"); /* * Accept in server. */ for (i = 0; i < count; i++) { msg_info("receive attempt %d", i); - while (!readable(server_fd)) - msg_info("wait for server fd to become writable"); - if (ioctl(server_fd, I_RECVFD, &fdinfo) < 0) + if (!readable(server_fd)) { + msg_info("wait for server fd to become readable"); + read_wait(server_fd, -1); + } + if ((fd = stream_accept(server_fd)) < 0) msg_fatal("receive fd: %m"); if (print_fstats) - print_fstat(fdinfo.fd); - if (close(fdinfo.fd) < 0) + print_fstat(fd); + if (close(fd) < 0) msg_fatal("close received fd: %m"); } + if (close(server_fd) < 0) + msg_fatal("close server fd"); }