diff --git a/postfix/HISTORY b/postfix/HISTORY index befee96dd..136a2c58c 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -2346,6 +2346,31 @@ Apologies for any names omitted. recipients to a master.cf entry called "cyrus", allowing you to have both UNIX and non-UNIX mailboxes side by side. +19990319 + + Workaround: on 4.4 BSD derivatives, fstat() can return + EBADF on an open file descriptor. Now, that was a surprise. + This caused std{out,err} from cron commands to not be + delivered. + + Bugfix: "local -v" stopped working. + + Workaround: more watchdog timers for postfix-unfriendly + systems. By now every Postfix daemon has one. Call it life + insurance. + + Robustness: increased the maximal time to receive or deliver + mail from $ipc_timeout (default: 3600 seconds) to the more + generous $daemon_timeout (default: 18000 seconds). We don't + want false alarms. + + Portability: IRIX 5.2 does not have usleep(). + +19990320 + + Bugfix: \username was broken. Frank Dziuba was the first + to notice. + Future: Planned: must be able to list the same hash table in diff --git a/postfix/PCRE_README b/postfix/PCRE_README index d407d5ef9..1c743b7ca 100644 --- a/postfix/PCRE_README +++ b/postfix/PCRE_README @@ -22,6 +22,8 @@ and add the path to the PCRE library to AUXLIBS, for example: make -f Makefile.init makefiles 'CCARGS=-DHAS_PCRE -I../../pcre-2.04' \ 'AUXLIBS=../../pcre-2.04/libpcre.a' +[note: earlier pcre versions have problems -- Wietse] + One possible use is to add a line to main.cf: smtpd_recipient_restrictions = pcre:/opt/postfix/etc/smtprecipient diff --git a/postfix/global/Makefile.in b/postfix/global/Makefile.in index 2eb474973..34b2be57d 100644 --- a/postfix/global/Makefile.in +++ b/postfix/global/Makefile.in @@ -577,6 +577,7 @@ mail_trigger.o: mail_params.h mail_trigger.o: mail_proto.h mail_trigger.o: ../include/vstream.h mail_trigger.o: ../include/vbuf.h +mail_version.o: mail_version.c maps.o: maps.c maps.o: ../include/sys_defs.h maps.o: ../include/argv.h diff --git a/postfix/global/mail_connect.c b/postfix/global/mail_connect.c index 8b9223a5a..3de429326 100644 --- a/postfix/global/mail_connect.c +++ b/postfix/global/mail_connect.c @@ -81,7 +81,7 @@ VSTREAM *mail_connect(const char *class, const char *name, int block_mode) int fd; path = mail_pathname(class, name); - if ((fd = unix_connect(path, block_mode, 0)) < 0) { + if ((fd = LOCAL_CONNECT(path, block_mode, 0)) < 0) { if (msg_verbose) msg_info("connect to subsystem %s: %m", path); stream = 0; diff --git a/postfix/global/mail_params.c b/postfix/global/mail_params.c index 0191de98b..7acf5e677 100644 --- a/postfix/global/mail_params.c +++ b/postfix/global/mail_params.c @@ -55,10 +55,7 @@ /* int var_soft_bounce; /* time_t var_starttime; /* int var_ownreq_special; -/* -/* char *var_ldap_server_host; -/* char *var_ldap_search_base; -/* int var_ldap_timeout; +/* int var_daemon_timeout; /* /* void mail_params_init() /* DESCRIPTION @@ -160,14 +157,7 @@ int var_disable_dns; int var_soft_bounce; time_t var_starttime; int var_ownreq_special; - -#ifdef HAS_LDAP - -char *var_ldap_server_host; -char *var_ldap_search_base; -int var_ldap_timeout; - -#endif +int var_daemon_timeout; /* check_myhostname - lookup hostname and validate */ @@ -259,10 +249,6 @@ void mail_params_init() 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, -#ifdef HAS_LDAP - VAR_LDAP_SERVER, DEF_LDAP_SERVER, &var_ldap_server_host, 0, 0, - VAR_LDAP_SEARCH, DEF_LDAP_SEARCH, &var_ldap_search_base, 0, 0, -#endif VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1, 0, }; @@ -279,15 +265,13 @@ void mail_params_init() VAR_MESSAGE_LIMIT, DEF_MESSAGE_LIMIT, &var_message_limit, 0, 0, VAR_IPC_IDLE, DEF_IPC_IDLE, &var_ipc_idle_limit, 1, 0, VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0, -#ifdef HAS_LDAP - VAR_LDAP_TIMEOUT, DEF_LDAP_TIMEOUT, &var_ldap_timeout, 1, 0, -#endif VAR_TRIGGER_TIMEOUT, DEF_TRIGGER_TIMEOUT, &var_trigger_timeout, 1, 0, VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0, VAR_FORK_DELAY, DEF_FORK_DELAY, &var_fork_delay, 1, 0, VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0, 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, 0, }; static CONFIG_BOOL_TABLE bool_defaults[] = { diff --git a/postfix/global/mail_params.h b/postfix/global/mail_params.h index 61978087a..420267830 100644 --- a/postfix/global/mail_params.h +++ b/postfix/global/mail_params.h @@ -234,21 +234,6 @@ extern bool var_append_dot_mydomain; #define DEF_PERCENT_HACK 1 extern bool var_percent_hack; - /* - * LDAP lookups. Preliminary code, interface subject to change. - */ -#define VAR_LDAP_SERVER "ldap_server_host" -#define DEF_LDAP_SERVER "" -extern char *var_ldap_server; - -#define VAR_LDAP_SEARCH "ldap_search_base" -#define DEF_LDAP_SEARCH "" -extern char *var_ldap_search; - -#define VAR_LDAP_TIMEOUT "ldap_lookup_timeout" -#define DEF_LDAP_TIMEOUT 10 -extern int var_ldap_timeout; - /* * Local delivery: alias databases. */ @@ -623,6 +608,14 @@ extern int var_flock_delay; #define DEF_FLOCK_STALE 500 extern int var_flock_stale; + /* + * How long a daemon command may take to receive or deliver a message etc. + * before we assume it is wegded (should never happen). + */ +#define VAR_DAEMON_TIMEOUT "daemon_timeout" +#define DEF_DAEMON_TIMEOUT 18000 +extern int var_daemon_timeout; + /* * How long an intra-mail command may take before we assume the mail system * is in deadlock (should never happen). diff --git a/postfix/global/mail_trigger.c b/postfix/global/mail_trigger.c index 66710b145..4d4d61c3f 100644 --- a/postfix/global/mail_trigger.c +++ b/postfix/global/mail_trigger.c @@ -83,9 +83,9 @@ int mail_trigger(const char *class, const char *service, } 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)) - status = unix_trigger(path, req_buf, req_len, var_trigger_timeout); + status = LOCAL_TRIGGER(path, req_buf, req_len, var_trigger_timeout); } else if (S_ISSOCK(st.st_mode)) { - status = unix_trigger(path, req_buf, req_len, var_trigger_timeout); + status = LOCAL_TRIGGER(path, req_buf, req_len, var_trigger_timeout); } else { msg_warn("%s is not a socket or a fifo", path); status = -1; diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index fb32eac87..028e1e36b 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 "Beta-19990317" +#define DEF_MAIL_VERSION "Snapshot-19990321" extern char *var_mail_version; /* LICENSE diff --git a/postfix/local/Makefile.in b/postfix/local/Makefile.in index 487b63d30..a1436e0ca 100644 --- a/postfix/local/Makefile.in +++ b/postfix/local/Makefile.in @@ -81,6 +81,8 @@ alias.o: local.h alias.o: ../include/been_here.h alias.o: ../include/tok822.h alias.o: ../include/resolve_clnt.h +alias.o: ../include/deliver_request.h +alias.o: ../include/recipient_list.h biff_notify.o: biff_notify.c biff_notify.o: ../include/sys_defs.h biff_notify.o: ../include/msg.h @@ -103,6 +105,8 @@ command.o: ../include/mail_copy.h command.o: local.h command.o: ../include/tok822.h command.o: ../include/resolve_clnt.h +command.o: ../include/deliver_request.h +command.o: ../include/recipient_list.h deliver_attr.o: deliver_attr.c deliver_attr.o: ../include/sys_defs.h deliver_attr.o: ../include/msg.h @@ -114,6 +118,8 @@ deliver_attr.o: ../include/vstring.h deliver_attr.o: ../include/been_here.h deliver_attr.o: ../include/tok822.h deliver_attr.o: ../include/resolve_clnt.h +deliver_attr.o: ../include/deliver_request.h +deliver_attr.o: ../include/recipient_list.h delivered.o: delivered.c delivered.o: ../include/sys_defs.h delivered.o: ../include/msg.h @@ -132,6 +138,8 @@ delivered.o: local.h delivered.o: ../include/been_here.h delivered.o: ../include/tok822.h delivered.o: ../include/resolve_clnt.h +delivered.o: ../include/deliver_request.h +delivered.o: ../include/recipient_list.h dotforward.o: dotforward.c dotforward.o: ../include/sys_defs.h dotforward.o: ../include/msg.h @@ -151,6 +159,8 @@ dotforward.o: ../include/mail_params.h dotforward.o: local.h dotforward.o: ../include/tok822.h dotforward.o: ../include/resolve_clnt.h +dotforward.o: ../include/deliver_request.h +dotforward.o: ../include/recipient_list.h feature.o: feature.c feature.o: ../include/sys_defs.h feature.o: ../include/msg.h @@ -165,6 +175,8 @@ feature.o: ../include/vstring.h feature.o: ../include/been_here.h feature.o: ../include/tok822.h feature.o: ../include/resolve_clnt.h +feature.o: ../include/deliver_request.h +feature.o: ../include/recipient_list.h file.o: file.c file.o: ../include/sys_defs.h file.o: ../include/msg.h @@ -183,6 +195,8 @@ file.o: ../include/mail_params.h file.o: local.h file.o: ../include/tok822.h file.o: ../include/resolve_clnt.h +file.o: ../include/deliver_request.h +file.o: ../include/recipient_list.h forward.o: forward.c forward.o: ../include/sys_defs.h forward.o: ../include/msg.h @@ -208,6 +222,8 @@ forward.o: local.h forward.o: ../include/been_here.h forward.o: ../include/tok822.h forward.o: ../include/resolve_clnt.h +forward.o: ../include/deliver_request.h +forward.o: ../include/recipient_list.h include.o: include.c include.o: ../include/sys_defs.h include.o: ../include/msg.h @@ -227,6 +243,8 @@ include.o: local.h include.o: ../include/vstring.h include.o: ../include/tok822.h include.o: ../include/resolve_clnt.h +include.o: ../include/deliver_request.h +include.o: ../include/recipient_list.h indirect.o: indirect.c indirect.o: ../include/sys_defs.h indirect.o: ../include/msg.h @@ -241,6 +259,8 @@ indirect.o: ../include/vbuf.h indirect.o: ../include/vstring.h indirect.o: ../include/tok822.h indirect.o: ../include/resolve_clnt.h +indirect.o: ../include/deliver_request.h +indirect.o: ../include/recipient_list.h local.o: local.c local.o: ../include/sys_defs.h local.o: ../include/msg.h @@ -283,9 +303,13 @@ mailbox.o: ../include/sent.h mailbox.o: ../include/mypwd.h mailbox.o: ../include/been_here.h mailbox.o: ../include/mail_params.h +mailbox.o: ../include/mail_proto.h +mailbox.o: ../include/iostuff.h mailbox.o: local.h mailbox.o: ../include/tok822.h mailbox.o: ../include/resolve_clnt.h +mailbox.o: ../include/deliver_request.h +mailbox.o: ../include/recipient_list.h mailbox.o: biff_notify.h maildir.o: maildir.c maildir.o: ../include/sys_defs.h @@ -307,6 +331,8 @@ maildir.o: ../include/htable.h maildir.o: ../include/been_here.h maildir.o: ../include/tok822.h maildir.o: ../include/resolve_clnt.h +maildir.o: ../include/deliver_request.h +maildir.o: ../include/recipient_list.h recipient.o: recipient.c recipient.o: ../include/sys_defs.h recipient.o: ../include/msg.h @@ -325,6 +351,8 @@ recipient.o: ../include/vstring.h recipient.o: ../include/been_here.h recipient.o: ../include/tok822.h recipient.o: ../include/resolve_clnt.h +recipient.o: ../include/deliver_request.h +recipient.o: ../include/recipient_list.h resolve.o: resolve.c resolve.o: ../include/sys_defs.h resolve.o: ../include/msg.h @@ -340,6 +368,8 @@ resolve.o: ../include/tok822.h resolve.o: ../include/mail_params.h resolve.o: local.h resolve.o: ../include/been_here.h +resolve.o: ../include/deliver_request.h +resolve.o: ../include/recipient_list.h token.o: token.c token.o: ../include/sys_defs.h token.o: ../include/msg.h @@ -355,6 +385,8 @@ token.o: ../include/resolve_clnt.h token.o: ../include/mail_params.h token.o: local.h token.o: ../include/been_here.h +token.o: ../include/deliver_request.h +token.o: ../include/recipient_list.h unknown.o: unknown.c unknown.o: ../include/sys_defs.h unknown.o: ../include/msg.h @@ -362,11 +394,15 @@ unknown.o: ../include/stringops.h unknown.o: ../include/mymalloc.h unknown.o: ../include/been_here.h unknown.o: ../include/mail_params.h +unknown.o: ../include/mail_proto.h +unknown.o: ../include/vstream.h +unknown.o: ../include/vbuf.h +unknown.o: ../include/iostuff.h unknown.o: ../include/bounce.h unknown.o: local.h unknown.o: ../include/htable.h -unknown.o: ../include/vstream.h -unknown.o: ../include/vbuf.h unknown.o: ../include/vstring.h unknown.o: ../include/tok822.h unknown.o: ../include/resolve_clnt.h +unknown.o: ../include/deliver_request.h +unknown.o: ../include/recipient_list.h diff --git a/postfix/local/local.h b/postfix/local/local.h index ee4a88488..3461d0bdc 100644 --- a/postfix/local/local.h +++ b/postfix/local/local.h @@ -126,7 +126,9 @@ typedef struct LOCAL_STATE { #define MSG_LOG_STATE(m, s) \ msg_info("%s[%d]: local %s recip %s exten %s deliver %s", m, \ - s.level, s.msg_attr.local, s.msg_attr.recipient, \ + s.level, \ + s.msg_attr.local ? s.msg_attr.local : "" , \ + s.msg_attr.recipient ? s.msg_attr.recipient : "", \ s.msg_attr.extension ? s.msg_attr.extension : "", \ s.msg_attr.delivered ? s.msg_attr.delivered : "") diff --git a/postfix/local/recipient.c b/postfix/local/recipient.c index 8456b72fd..17271b28b 100644 --- a/postfix/local/recipient.c +++ b/postfix/local/recipient.c @@ -105,7 +105,7 @@ static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr) * \user is special: it means don't do any alias or forward expansion. */ if (state.msg_attr.recipient[0] == '\\') { - state.msg_attr.recipient++; + state.msg_attr.recipient++, state.msg_attr.local++; if (*var_rcpt_delim) state.msg_attr.extension = split_addr(state.msg_attr.local, *var_rcpt_delim); diff --git a/postfix/master/Makefile.in b/postfix/master/Makefile.in index dcf254d15..f66a542ea 100644 --- a/postfix/master/Makefile.in +++ b/postfix/master/Makefile.in @@ -225,6 +225,7 @@ single_server.o: ../include/stringops.h single_server.o: ../include/sane_accept.h single_server.o: ../include/myflock.h single_server.o: ../include/safe_open.h +single_server.o: ../include/listen.h single_server.o: ../include/mail_params.h single_server.o: ../include/mail_task.h single_server.o: ../include/debug_process.h @@ -249,6 +250,7 @@ trigger_server.o: ../include/stringops.h trigger_server.o: ../include/sane_accept.h trigger_server.o: ../include/myflock.h trigger_server.o: ../include/safe_open.h +trigger_server.o: ../include/listen.h trigger_server.o: ../include/mail_params.h trigger_server.o: ../include/mail_task.h trigger_server.o: ../include/debug_process.h diff --git a/postfix/master/master.c b/postfix/master/master.c index 2f78b3d1c..2343e3ae5 100644 --- a/postfix/master/master.c +++ b/postfix/master/master.c @@ -152,6 +152,19 @@ #include "master.h" +/* master_watchdog - something got stuck */ + +static NORETURN master_watchdog(int unused_sig) +{ + + /* + * This runs as a signal handler. We should not do anything that could + * involve memory managent, but exiting without explanation would be + * worse. + */ + msg_fatal("watchdog timer"); +} + int main(int argc, char **argv) { static VSTREAM *lock_fp; @@ -316,7 +329,9 @@ int main(int argc, char **argv) * multiple things at the same time, it really is all a single thread, so * that there are no concurrency conflicts within the master process. */ + signal(SIGALRM, master_watchdog); for (;;) { + alarm(1000); /* same as trigger servers */ event_loop(-1); if (master_gotsighup) { msg_info("reload configuration"); diff --git a/postfix/master/master_listen.c b/postfix/master/master_listen.c index 14b8ed5f4..d7020ac42 100644 --- a/postfix/master/master_listen.c +++ b/postfix/master/master_listen.c @@ -80,13 +80,13 @@ void master_listen_init(MASTER_SERV *serv) switch (serv->type) { /* - * UNIX-domain listener endpoints always come as singlets. + * UNIX-domain or stream listener endpoints always come as singlets. */ case MASTER_SERV_TYPE_UNIX: set_eugid(var_owner_uid, var_owner_gid); serv->listen_fd[0] = - unix_listen(serv->name, serv->max_proc > var_proc_limit ? - serv->max_proc : var_proc_limit, NON_BLOCKING); + LOCAL_LISTEN(serv->name, serv->max_proc > var_proc_limit ? + serv->max_proc : var_proc_limit, NON_BLOCKING); close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC); set_eugid(getuid(), getgid()); break; diff --git a/postfix/master/master_wakeup.c b/postfix/master/master_wakeup.c index 7070d84d6..c0f9edf7c 100644 --- a/postfix/master/master_wakeup.c +++ b/postfix/master/master_wakeup.c @@ -99,7 +99,7 @@ static void master_wakeup_timer_event(int unused_event, char *context) status = inet_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY); break; case MASTER_SERV_TYPE_UNIX: - status = unix_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY); + status = LOCAL_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY); break; case MASTER_SERV_TYPE_FIFO: status = fifo_trigger(serv->name, &wakeup, sizeof(wakeup), BRIEFLY); diff --git a/postfix/master/multi_server.c b/postfix/master/multi_server.c index a3d04b48e..4fcad413c 100644 --- a/postfix/master/multi_server.c +++ b/postfix/master/multi_server.c @@ -137,6 +137,7 @@ #include #include #endif +#include /* Global library. */ @@ -164,6 +165,7 @@ static int use_count; static void (*multi_server_service) (VSTREAM *, char *, char **); 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 @@ -180,6 +182,19 @@ static NORETURN multi_server_exit(void) exit(0); } +/* multi_server_watchdog - something got stuck */ + +static NORETURN multi_server_watchdog(int unused_sig) +{ + + /* + * This runs as a signal handler. We should not do anything that could + * involve memory managent, but exiting without explanation would be + * worse. + */ + msg_fatal("watchdog timer"); +} + /* multi_server_abort - terminate after abnormal master exit */ static void multi_server_abort(int unused_event, char *unused_context) @@ -234,20 +249,35 @@ static void multi_server_execute(int unused_event, char *context) event_request_timer(multi_server_timeout, (char *) 0, var_idle_limit); } -/* multi_server_accept - accept client connection request */ +/* multi_server_wakeup - wake up application */ -static void multi_server_accept(int unused_event, char *context) +static void multi_server_wakeup(int fd) +{ + VSTREAM *stream; + + if (msg_verbose) + msg_info("connection established fd %d", fd); + non_blocking(fd, BLOCKING); + close_on_exec(fd, CLOSE_ON_EXEC); + client_count++; + stream = vstream_fdopen(fd, O_RDWR); + timed_ipc_setup(stream); + event_enable_read(fd, multi_server_execute, (char *) stream); +} + +/* multi_server_accept_local - accept client connection request */ + +static void multi_server_accept_local(int unused_event, char *context) { int listen_fd = (int) context; int time_left = -1; int fd; - VSTREAM *stream; -#ifndef NO_SELECT_COLLISION - if (multi_server_lock != 0 - && myflock(vstream_fileno(multi_server_lock), MYFLOCK_NONE) < 0) - msg_fatal("select unlock: %m"); -#endif + /* + * Some buggy systems cause Postfix to lock up. + */ + signal(SIGALRM, multi_server_watchdog); + alarm(var_daemon_timeout); /* * Be prepared for accept() to fail because some other process already @@ -258,21 +288,62 @@ static void multi_server_accept(int unused_event, char *context) */ if (client_count == 0 && var_idle_limit > 0) time_left = event_cancel_timer(multi_server_timeout, (char *) 0); - if ((fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) < 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"); if (time_left >= 0) event_request_timer(multi_server_timeout, (char *) 0, time_left); return; } - if (msg_verbose) - msg_info("connection established fd %d", fd); - non_blocking(fd, BLOCKING); - close_on_exec(fd, CLOSE_ON_EXEC); - client_count++; - stream = vstream_fdopen(fd, O_RDWR); - timed_ipc_setup(stream); - event_enable_read(fd, multi_server_execute, (char *) stream); + multi_server_wakeup(fd); +} + +/* multi_server_accept_inet - accept client connection request */ + +static void multi_server_accept_inet(int unused_event, char *context) +{ + int listen_fd = (int) context; + int time_left = -1; + int fd; + VSTREAM *stream; + + /* + * Some buggy systems cause Postfix to lock up. + */ + signal(SIGALRM, multi_server_watchdog); + alarm(var_daemon_timeout); + + /* + * Be prepared for accept() to fail because some other process already + * got the connection (the number of processes competing for clients is + * kept small, so this is not a "thundering herd" problem). If the + * accept() succeeds, be sure to disable non-blocking I/O, in order to + * minimize confusion. + */ + if (client_count == 0 && var_idle_limit > 0) + 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"); + if (time_left >= 0) + event_request_timer(multi_server_timeout, (char *) 0, time_left); + return; + } + multi_server_wakeup(fd); } /* multi_server_main - the real main program */ @@ -428,8 +499,11 @@ NORETURN multi_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) if (stream == 0) { if (transport == 0) msg_fatal("no transport type specified"); - if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0 - && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0) + if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0) + multi_server_accept = multi_server_accept_inet; + else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0) + multi_server_accept = multi_server_accept_local; + else msg_fatal("unsupported transport type: %s", transport); } diff --git a/postfix/master/single_server.c b/postfix/master/single_server.c index 4976ae02c..eca04871d 100644 --- a/postfix/master/single_server.c +++ b/postfix/master/single_server.c @@ -128,6 +128,7 @@ #include #include #endif +#include /* Global library. */ @@ -154,6 +155,7 @@ static int use_count; static void (*single_server_service) (VSTREAM *, char *, char **); 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 @@ -170,6 +172,19 @@ static NORETURN single_server_exit(void) exit(0); } +/* single_server_watchdog - something got stuck */ + +static NORETURN single_server_watchdog(int unused_sig) +{ + + /* + * This runs as a signal handler. We should not do anything that could + * involve memory managent, but exiting without explanation would be + * worse. + */ + msg_fatal("watchdog timer"); +} + /* single_server_abort - terminate after abnormal master exit */ static void single_server_abort(int unused_event, char *unused_context) @@ -188,37 +203,11 @@ static void single_server_timeout(int unused_event, char *unused_context) single_server_exit(); } -/* single_server_accept - accept client connection request */ +/* single_server_wakeup - wake up application */ -static void single_server_accept(int unused_event, char *context) +static void single_server_wakeup(int fd) { - int listen_fd = (int) context; VSTREAM *stream; - int time_left = -1; - int 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 - - /* - * Be prepared for accept() to fail because some other process already - * got the connection. We use select() + accept(), instead of simply - * blocking in accept(), because we must be able to detect that the - * master process has gone away unexpectedly. - */ - if (var_idle_limit > 0) - time_left = event_cancel_timer(single_server_timeout, (char *) 0); - - if ((fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) < 0) { - if (errno != EAGAIN) - msg_fatal("accept connection: %m"); - if (time_left >= 0) - event_request_timer(single_server_timeout, (char *) 0, time_left); - return; - } /* * If the accept() succeeds, be sure to disable non-blocking I/O, because @@ -245,6 +234,84 @@ static void single_server_accept(int unused_event, char *context) event_request_timer(single_server_timeout, (char *) 0, var_idle_limit); } +/* single_server_accept_local - accept client connection request */ + +static void single_server_accept_local(int unused_event, char *context) +{ + int listen_fd = (int) context; + int time_left = -1; + int fd; + + /* + * Some buggy systems cause Postfix to lock up. + */ + signal(SIGALRM, single_server_watchdog); + alarm(var_daemon_timeout); + + /* + * Be prepared for accept() to fail because some other process already + * got the connection. We use select() + accept(), instead of simply + * blocking in accept(), because we must be able to detect that the + * master process has gone away unexpectedly. + */ + if (var_idle_limit > 0) + 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"); + if (time_left >= 0) + event_request_timer(single_server_timeout, (char *) 0, time_left); + return; + } + single_server_wakeup(fd); +} + +/* single_server_accept_inet - accept client connection request */ + +static void single_server_accept_inet(int unused_event, char *context) +{ + int listen_fd = (int) context; + int time_left = -1; + int fd; + + /* + * Some buggy systems cause Postfix to lock up. + */ + signal(SIGALRM, single_server_watchdog); + alarm(var_daemon_timeout); + + /* + * Be prepared for accept() to fail because some other process already + * got the connection. We use select() + accept(), instead of simply + * blocking in accept(), because we must be able to detect that the + * master process has gone away unexpectedly. + */ + if (var_idle_limit > 0) + 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"); + if (time_left >= 0) + event_request_timer(single_server_timeout, (char *) 0, time_left); + return; + } + single_server_wakeup(fd); +} + /* single_server_main - the real main program */ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) @@ -398,8 +465,11 @@ NORETURN single_server_main(int argc, char **argv, SINGLE_SERVER_FN service,...) if (stream == 0) { if (transport == 0) msg_fatal("no transport type specified"); - if (strcasecmp(transport, MASTER_XPORT_NAME_INET) != 0 - && strcasecmp(transport, MASTER_XPORT_NAME_UNIX) != 0) + if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0) + single_server_accept = single_server_accept_inet; + else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0) + single_server_accept = single_server_accept_local; + else msg_fatal("unsupported transport type: %s", transport); } diff --git a/postfix/master/trigger_server.c b/postfix/master/trigger_server.c index 651adac31..261a9dabc 100644 --- a/postfix/master/trigger_server.c +++ b/postfix/master/trigger_server.c @@ -136,6 +136,7 @@ #include #include #endif +#include /* Global library. */ @@ -231,7 +232,7 @@ static void trigger_server_wakeup(int fd) use_count++; } -/* trigger_server_accept_fifo - accept socket client request */ +/* trigger_server_accept_fifo - accept fifo client request */ static void trigger_server_accept_fifo(int unused_event, char *context) { @@ -260,20 +261,15 @@ static void trigger_server_accept_fifo(int unused_event, char *context) trigger_server_wakeup(listen_fd); } -/* trigger_server_accept_socket - accept socket client request */ +/* trigger_server_accept_local - accept socket client request */ -static void trigger_server_accept_socket(int unused_event, char *context) +static void trigger_server_accept_local(int unused_event, char *context) { - char *myname = "trigger_server_accept_socket"; + char *myname = "trigger_server_accept_local"; int listen_fd = (int) context; int time_left = 0; int 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 (msg_verbose) msg_info("%s: trigger arrived", myname); @@ -281,6 +277,7 @@ static void trigger_server_accept_socket(int unused_event, char *context) /* * Some buggy systems cause Postfix to lock up. */ + signal(SIGALRM, trigger_server_watchdog); alarm(1000); /* @@ -292,7 +289,14 @@ static void trigger_server_accept_socket(int unused_event, char *context) */ if (var_idle_limit > 0) time_left = event_cancel_timer(trigger_server_timeout, (char *) 0); - if ((fd = sane_accept(listen_fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)) < 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"); if (time_left >= 0) @@ -469,14 +473,15 @@ NORETURN trigger_server_main(int argc, char **argv, TRIGGER_SERVER_FN service,.. * problems, witness the workarounds in the fifo_listen() routine. * Therefore we support both FIFOs and UNIX-domain sockets, so that the * user can choose whatever works best. + * + * Well, I give up. Solaris UNIX-domain sockets still don't work properly, + * so it will have to limp along with a streams-specific alternative. */ if (stream == 0) { if (transport == 0) msg_fatal("no transport type specified"); - if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0) - trigger_server_accept = trigger_server_accept_socket; if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0) - trigger_server_accept = trigger_server_accept_socket; + trigger_server_accept = trigger_server_accept_local; else if (strcasecmp(transport, MASTER_XPORT_NAME_FIFO) == 0) trigger_server_accept = trigger_server_accept_fifo; else diff --git a/postfix/pickup/Makefile.in b/postfix/pickup/Makefile.in index fcb0c1c7b..1edbf8c3b 100644 --- a/postfix/pickup/Makefile.in +++ b/postfix/pickup/Makefile.in @@ -53,7 +53,6 @@ depend: $(MAKES) @make -f Makefile.in Makefile # do not edit below this line - it is generated by 'make depend' -cleanup_extra.o: cleanup_extra.c pickup.o: pickup.c pickup.o: ../include/sys_defs.h pickup.o: ../include/msg.h diff --git a/postfix/postalias/postalias.c b/postfix/postalias/postalias.c index 83c28cfb3..7c3e6a9d4 100644 --- a/postfix/postalias/postalias.c +++ b/postfix/postalias/postalias.c @@ -282,10 +282,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postcat/postcat.c b/postfix/postcat/postcat.c index 0f77e5421..c86e3f622 100644 --- a/postfix/postcat/postcat.c +++ b/postfix/postcat/postcat.c @@ -146,10 +146,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postconf/postconf.c b/postfix/postconf/postconf.c index cbf755dc7..9cee72ab8 100644 --- a/postfix/postconf/postconf.c +++ b/postfix/postconf/postconf.c @@ -450,10 +450,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postdrop/postdrop.c b/postfix/postdrop/postdrop.c index d2267db61..3dffaf04d 100644 --- a/postfix/postdrop/postdrop.c +++ b/postfix/postdrop/postdrop.c @@ -161,10 +161,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postfix/postfix.c b/postfix/postfix/postfix.c index a6e469bf0..d88f6e4d8 100644 --- a/postfix/postfix/postfix.c +++ b/postfix/postfix/postfix.c @@ -147,10 +147,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postkick/postkick.c b/postfix/postkick/postkick.c index f6ad75a54..044a08390 100644 --- a/postfix/postkick/postkick.c +++ b/postfix/postkick/postkick.c @@ -104,10 +104,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postlock/postlock.c b/postfix/postlock/postlock.c index c90879119..558f8f780 100644 --- a/postfix/postlock/postlock.c +++ b/postfix/postlock/postlock.c @@ -5,7 +5,7 @@ /* lock mail folder and execute command /* SYNOPSIS /* .fi -/* \fBpostlock\fR [\fB-c \fIconfig_dir\fB] [\fB-v\fR] +/* \fBpostlock\fR [\fB-c \fIconfig_dir\fB] [\fB-v\fR] /* \fIfile command...\fR /* DESCRIPTION /* The \fBpostlock\fR command locks \fIfile\fR for exclusive @@ -14,17 +14,17 @@ /* /* Options: /* .IP "\fB-c \fIconfig_dir\fR" -/* Read configuration information from \fBmain.cf\fR in the named +/* Read configuration information from \fBmain.cf\fR in the named /* configuration directory. /* .IP \fB-v\fR -/* Enable verbose mode for debugging purposes. Multiple \fB-v\fR +/* Enable verbose mode for debugging purposes. Multiple \fB-v\fR /* options make the software increasingly verbose. /* .PP /* Arguments: /* .IP \fIfile\fR /* A mailbox file. The user should have read/write permission. /* .IP \fIcommand...\fR -/* The command to execute while \fIfile\fR is locked for exclusive +/* The command to execute while \fIfile\fR is locked for exclusive /* access. The command is executed directly, i.e. without /* interpretation by a shell command interpreter. /* DIAGNOSTICS @@ -50,7 +50,7 @@ /* and for default values. /* .SH "Locking controls" /* .ad -/* .fi +/* .fi /* .IP \fBdeliver_lock_attempts\fR /* Limit the number of attempts to acquire an exclusive lock. /* .IP \fBdeliver_lock_delay\fR @@ -137,10 +137,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postlog/postlog.c b/postfix/postlog/postlog.c index 2ae1551f7..ece9daf50 100644 --- a/postfix/postlog/postlog.c +++ b/postfix/postlog/postlog.c @@ -29,7 +29,7 @@ /* Specifies the logging tag, that is, the identifying name that /* appears at the beginning of each logging record. /* .IP \fB-v\fR -/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR +/* Enable verbose logging for debugging purposes. Multiple \fB-v\fR /* options make the software increasingly verbose. /* SEE ALSO /* syslogd(8) syslog daemon. @@ -151,10 +151,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postmap/postmap.c b/postfix/postmap/postmap.c index 1ace8e16b..9cd698ebc 100644 --- a/postfix/postmap/postmap.c +++ b/postfix/postmap/postmap.c @@ -247,10 +247,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/postsuper/postsuper.c b/postfix/postsuper/postsuper.c index 5d575cee1..9ebd498cd 100644 --- a/postfix/postsuper/postsuper.c +++ b/postfix/postsuper/postsuper.c @@ -297,10 +297,12 @@ main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/qmgr/qmgr_deliver.c b/postfix/qmgr/qmgr_deliver.c index 8aefffceb..1ff2f350e 100644 --- a/postfix/qmgr/qmgr_deliver.c +++ b/postfix/qmgr/qmgr_deliver.c @@ -290,5 +290,5 @@ void qmgr_deliver(QMGR_TRANSPORT *transport, VSTREAM *stream) /* * Guard against broken systems. */ - event_request_timer(qmgr_deliver_abort, (char *) entry, var_ipc_timeout); + event_request_timer(qmgr_deliver_abort, (char *) entry, var_daemon_timeout); } diff --git a/postfix/qmgr/qmgr_transport.c b/postfix/qmgr/qmgr_transport.c index cf3a0d6c8..fcaa95c39 100644 --- a/postfix/qmgr/qmgr_transport.c +++ b/postfix/qmgr/qmgr_transport.c @@ -299,7 +299,8 @@ void qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOT /* * Guard against broken systems. */ - event_request_timer(qmgr_transport_abort, (char *) alloc, var_ipc_timeout); + event_request_timer(qmgr_transport_abort, (char *) alloc, + var_daemon_timeout); } /* qmgr_transport_create - create transport instance */ diff --git a/postfix/sendmail/sendmail.c b/postfix/sendmail/sendmail.c index 6c1535aae..33736e36f 100644 --- a/postfix/sendmail/sendmail.c +++ b/postfix/sendmail/sendmail.c @@ -564,10 +564,12 @@ int main(int argc, char **argv) /* * To minimize confusion, make sure that the standard file descriptors - * are open before opening anything else. + * 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 && open("/dev/null", 2) != fd) + if (fstat(fd, &st) == -1 + && (close(fd), open("/dev/null", O_RDWR, 0)) != fd) msg_fatal("open /dev/null: %m"); /* diff --git a/postfix/smtpstone/Makefile.in b/postfix/smtpstone/Makefile.in index c7e8eb6af..d96d09920 100644 --- a/postfix/smtpstone/Makefile.in +++ b/postfix/smtpstone/Makefile.in @@ -78,9 +78,10 @@ smtp-sink.o: ../include/smtp_stream.h smtp-source.o: smtp-source.c smtp-source.o: ../include/sys_defs.h smtp-source.o: ../include/msg.h -smtp-source.o: ../include/vstring.h -smtp-source.o: ../include/vbuf.h +smtp-source.o: ../include/msg_vstream.h smtp-source.o: ../include/vstream.h +smtp-source.o: ../include/vbuf.h +smtp-source.o: ../include/vstring.h smtp-source.o: ../include/vstring_vstream.h smtp-source.o: ../include/get_hostname.h smtp-source.o: ../include/split_at.h diff --git a/postfix/util/Makefile.in b/postfix/util/Makefile.in index 04c65102e..0c332472c 100644 --- a/postfix/util/Makefile.in +++ b/postfix/util/Makefile.in @@ -18,7 +18,8 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \ translit.c trimblanks.c unix_connect.c unix_listen.c unix_trigger.c \ unsafe.c username.c valid_hostname.c vbuf.c vbuf_print.c \ vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \ - write_buf.c write_wait.c dict_unix.c dict_pcre.c + write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \ + stream_connect.c stream_trigger.c OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \ dict_env.o dict_ht.o dict_ldap.o dict_ni.o dict_nis.o \ @@ -38,7 +39,8 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ translit.o trimblanks.o unix_connect.o unix_listen.o unix_trigger.o \ unsafe.o username.o valid_hostname.o vbuf.o vbuf_print.o \ vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \ - write_buf.o write_wait.o dict_unix.o dict_pcre.o + write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \ + stream_connect.o stream_trigger.o HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_ni.h dict_nis.h \ dict_nisplus.h dir_forest.h events.h exec_command.h find_inet.h \ @@ -478,6 +480,7 @@ inet_listen.o: find_inet.h inet_listen.o: inet_util.h inet_listen.o: iostuff.h inet_listen.o: listen.h +inet_listen.o: sane_accept.h inet_trigger.o: inet_trigger.c inet_trigger.o: sys_defs.h inet_trigger.o: msg.h @@ -661,6 +664,15 @@ 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 @@ -685,6 +697,22 @@ stat_as.o: sys_defs.h stat_as.o: msg.h stat_as.o: set_eugid.h stat_as.o: stat_as.h +stream_connect.o: stream_connect.c +stream_connect.o: sys_defs.h +stream_connect.o: msg.h +stream_connect.o: connect.h +stream_connect.o: iostuff.h +stream_listen.o: stream_listen.c +stream_listen.o: sys_defs.h +stream_listen.o: msg.h +stream_listen.o: listen.h +stream_listen.o: iostuff.h +stream_trigger.o: stream_trigger.c +stream_trigger.o: sys_defs.h +stream_trigger.o: msg.h +stream_trigger.o: connect.h +stream_trigger.o: iostuff.h +stream_trigger.o: trigger.h sys_compat.o: sys_compat.c sys_compat.o: sys_defs.h timed_connect.o: timed_connect.c @@ -714,6 +742,7 @@ unix_listen.o: sys_defs.h unix_listen.o: msg.h unix_listen.o: iostuff.h unix_listen.o: listen.h +unix_listen.o: sane_accept.h unix_trigger.o: unix_trigger.c unix_trigger.o: sys_defs.h unix_trigger.o: msg.h diff --git a/postfix/util/connect.h b/postfix/util/connect.h index 5fc5e0413..080b99c06 100644 --- a/postfix/util/connect.h +++ b/postfix/util/connect.h @@ -21,6 +21,7 @@ */ extern int unix_connect(const char *, int, int); extern int inet_connect(const char *, int, int); +extern int stream_connect(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/inet_listen.c b/postfix/util/inet_listen.c index 81e3d2a12..91347c95a 100644 --- a/postfix/util/inet_listen.c +++ b/postfix/util/inet_listen.c @@ -10,11 +10,16 @@ /* const char *addr; /* int backlog; /* int block_mode; +/* +/* int inet_accept(fd) +/* int fd; /* DESCRIPTION /* The \fBinet_listen\fR routine starts a listener in the INET domain /* on the specified address, with the specified backlog, and returns /* the resulting file descriptor. /* +/* inet_accept() accepts a connection and sanitizes error results. +/* /* Arguments: /* .IP addr /* The communication endpoint to listen on. The syntax is "host:port". @@ -25,8 +30,11 @@ /* .IP block_mode /* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for /* blocking mode. +/* .IP fd +/* File descriptor returned by inet_listen(). /* DIAGNOSTICS -/* Fatal errors: all errors are fatal. +/* Fatal errors: inet_listen() aborts upon any system call failure. +/* inet_accept() leaves all error handling up to the caller. /* LICENSE /* .ad /* .fi @@ -59,6 +67,7 @@ #include "inet_util.h" #include "iostuff.h" #include "listen.h" +#include "sane_accept.h" /* Application-specific stuff. */ @@ -102,3 +111,10 @@ int inet_listen(const char *addr, int backlog, int block_mode) msg_fatal("listen: %m"); return (sock); } + +/* inet_accept - accept connection */ + +int inet_accept(int fd) +{ + return (sane_accept(fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)); +} diff --git a/postfix/util/listen.h b/postfix/util/listen.h index 7cd873e0d..81c5389c0 100644 --- a/postfix/util/listen.h +++ b/postfix/util/listen.h @@ -22,6 +22,11 @@ extern int unix_listen(const char *, int, int); extern int inet_listen(const char *, int, int); extern int fifo_listen(const char *, int, int); +extern int stream_listen(const char *, int, int); + +extern int inet_accept(int); +extern int unix_accept(int); +extern int stream_accept(int); /* LICENSE /* .ad diff --git a/postfix/util/sane_accept.c b/postfix/util/sane_accept.c index b1e2a5309..d9d8464d0 100644 --- a/postfix/util/sane_accept.c +++ b/postfix/util/sane_accept.c @@ -9,7 +9,7 @@ /* int sane_accept(sock, buf, len) /* int sock; /* struct sockaddr *buf; -/* int len; +/* SOCKADDR_SIZE *len; /* DESCRIPTION /* sane_accept() implements the accept(2) socket call, and maps /* known harmless error results to EAGAIN. diff --git a/postfix/util/sendfd_test b/postfix/util/sendfd_test new file mode 100755 index 000000000..20900647e Binary files /dev/null and b/postfix/util/sendfd_test differ diff --git a/postfix/util/sendfd_test.c b/postfix/util/sendfd_test.c new file mode 100644 index 000000000..d7b148142 --- /dev/null +++ b/postfix/util/sendfd_test.c @@ -0,0 +1,105 @@ +#include "sys_defs.h" +#include +#include +#include +#include +#include +#include "iostuff.h" + +#include "msg.h" +#include "msg_vstream.h" +#include "listen.h" + +#define FIFO "/tmp/test-fifo" + +static const char *progname; + +static print_fstat(int fd) +{ + struct stat st; + + if (fstat(fd, &st) < 0) + msg_fatal("fstat: %m"); + vstream_printf("fd %d\n", fd); + vstream_printf("dev %d\n", st.st_dev); + vstream_printf("ino %d\n", st.st_ino); + vstream_fflush(VSTREAM_OUT); +} + +static NORETURN usage(void) +{ + msg_fatal("usage: %s [-p] [-n count] [-v]", progname); +} + +main(int argc, char **argv) +{ + struct strrecvfd fdinfo; + int server_fd; + int client_fd; + int print_fstats = 0; + int count = 1; + int ch; + int i; + + progname = argv[0]; + msg_vstream_init(argv[0], VSTREAM_ERR); + + /* + * Parse JCL. + */ + while ((ch = GETOPT(argc, argv, "pn:v")) > 0) { + switch (ch) { + default: + usage(); + case 'p': + print_fstats = 1; + break; + case 'n': + if ((count = atoi(optarg)) < 1) + usage(); + break; + case 'v': + msg_verbose++; + break; + } + } + server_fd = fifo_listen(FIFO, 0600, NON_BLOCKING); + 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"); + } + 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) + msg_fatal("receive fd: %m"); + if (print_fstats) + print_fstat(fdinfo.fd); + if (close(fdinfo.fd) < 0) + msg_fatal("close received fd: %m"); + } +} diff --git a/postfix/util/stream_connect.c b/postfix/util/stream_connect.c new file mode 100644 index 000000000..f15dea51b --- /dev/null +++ b/postfix/util/stream_connect.c @@ -0,0 +1,102 @@ +/*++ +/* NAME +/* stream_connect 3 +/* SUMMARY +/* connect to stream listener +/* SYNOPSIS +/* #include +/* +/* int stream_connect(path, block_mode, timeout) +/* const char *path; +/* int block_mode; +/* int timeout; +/* DESCRIPTION +/* stream_connect() connects to a stream listener for the specified +/* pathname, and returns the resulting file descriptor. +/* +/* Arguments: +/* .IP path +/* Null-terminated string with listener endpoint name. +/* .IP block_mode +/* Either NON_BLOCKING for a non-blocking stream, or BLOCKING for +/* blocking mode. However, a stream connection succeeds or fails +/* immediately. +/* .IP timeout +/* This argument is ignored; it is present for compatibility with +/* other interfaces. Stream connections succeed or fail immediately. +/* DIAGNOSTICS +/* The result is -1 in case the connection could not be made. +/* Fatal errors: other system call failures. +/* 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 +#include +#include +#include +#include + +/* Utility library. */ + +#include +#include + +/* stream_connect - connect to stream listener */ + +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; + + /* + * 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) + 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. + */ + if (fstat(fd, &st) < 0) + msg_fatal("%s: fstat: %m", myname); + if (S_ISREG(st.st_mode)) { + close(fd); + errno = ECONNREFUSED; + return (-1); + } + + /* + * This is for {unix,inet}_connect() compatibility. + */ + if (block_mode == NON_BLOCKING) + non_blocking(fd, NON_BLOCKING); + + /* + * No trouble detected, so far. + */ + return (fd); +#else + msg_fatal("stream connections are not implemented"); +#endif +} + diff --git a/postfix/util/stream_listen.c b/postfix/util/stream_listen.c new file mode 100644 index 000000000..0c71c8451 --- /dev/null +++ b/postfix/util/stream_listen.c @@ -0,0 +1,136 @@ +/*++ +/* NAME +/* stream_listen 3 +/* SUMMARY +/* start stream listener +/* SYNOPSIS +/* #include +/* +/* int stream_listen(path, backlog, block_mode) +/* const char *path; +/* int backlog; +/* int block_mode; +/* +/* int stream_accept(fd) +/* int fd; +/* DESCRIPTION +/* This module implements a substitute local IPC for systems that do +/* not have properly-working UNIX-domain sockets. +/* +/* stream_listen() creates a listener endpoint with the specified +/* permissions, and returns a file descriptor to be used for accepting +/* connections. +/* +/* stream_accept() accepts a connection. +/* +/* Arguments: +/* .IP path +/* Null-terminated string with connection destination. +/* .IP backlog +/* This argument exists for compatibility and is ignored. +/* .IP block_mode +/* This argument exists for compatibility and is ignored. +/* blocking mode. +/* .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 +/* 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 interfaces. */ + +#include + +#ifdef STREAM_CONNECTIONS + +#include +#include +#include +#include +#include + +#endif + +/* Utility library. */ + +#include "msg.h" +#include "listen.h" + +/* stream_listen - create stream listener */ + +int stream_listen(const char *path, int unused_backlog, +int unused_block_mode) +{ +#ifdef STREAM_CONNECTIONS + char *myname = "stream_listen"; + static int pair[2]; + int fd; + + /* + * Initialize: create the specified endpoint with the right permissions. + */ +#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]); +#else + msg_fatal("stream connections are not implemented"); +#endif +} + +/* stream_accept - accept stream connection */ + +int stream_accept(int fd) +{ +#ifdef STREAM_CONNECTIONS + struct strrecvfd fdinfo; + + /* + * This will return EAGAIN on a non-blocking stream when someone else + * snatched the connection from us. + */ + if (ioctl(fd, I_RECVFD, &fdinfo) < 0) + return (-1); + return (fdinfo.fd); +#else + msg_fatal("stream connections are not implemented"); +#endif +} diff --git a/postfix/util/stream_trigger.c b/postfix/util/stream_trigger.c new file mode 100644 index 000000000..585f392bf --- /dev/null +++ b/postfix/util/stream_trigger.c @@ -0,0 +1,89 @@ +/*++ +/* NAME +/* stream_trigger 3 +/* SUMMARY +/* wakeup stream server +/* SYNOPSIS +/* #include +/* +/* int stream_trigger(service, buf, len, timeout) +/* const char *service; +/* const char *buf; +/* int len; +/* int timeout; +/* DESCRIPTION +/* stream_trigger() wakes up the named stream server by making +/* a brief connection to it and writing the named buffer. +/* +/* Arguments: +/* .IP service +/* Name of the communication endpoint. +/* .IP buf +/* Address of data to be written. +/* .IP len +/* Amount of data to be written. +/* .IP timeout +/* 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. +/* SEE ALSO +/* stream_connect(3), stream client +/* 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 +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include + +/* stream_trigger - wakeup stream server */ + +int stream_trigger(const char *service, const char *buf, int len, int timeout) +{ + char *myname = "stream_trigger"; + int fd; + + if (msg_verbose > 1) + msg_info("%s: service %s", myname, service); + + /* + * Connect... + */ + if ((fd = stream_connect(service, BLOCKING, timeout)) < 0) { + if (msg_verbose) + msg_warn("%s: connect to %s: %m", myname, service); + return (-1); + } + + /* + * Write the request... + */ + if (write_buf(fd, buf, len, timeout) < 0) + if (msg_verbose) + msg_warn("%s: write to %s: %m", myname, service); + + /* + * Disconnect. + */ + if (close(fd) < 0) + if (msg_verbose) + msg_warn("%s: close %s: %m", myname, service); + return (0); +} diff --git a/postfix/util/sys_defs.h b/postfix/util/sys_defs.h index 21b0e0151..1dc87ee8f 100644 --- a/postfix/util/sys_defs.h +++ b/postfix/util/sys_defs.h @@ -151,7 +151,11 @@ extern int opterr; #define DBM_NO_TRAILING_NULL #define USE_STATVFS #define STATVFS_IN_SYS_STATVFS_H -#define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT /* Solaris 2.5.1, reportedly */ +#define STREAM_CONNECTIONS /* connld module */ +#define LOCAL_LISTEN stream_listen +#define LOCAL_ACCEPT stream_accept +#define LOCAL_CONNECT stream_connect +#define LOCAL_TRIGGER stream_trigger #endif #ifdef UW7 /* UnixWare 7 */ @@ -261,6 +265,10 @@ extern int initgroups(const char *, int); #define STATVFS_IN_SYS_STATVFS_H #endif +#if defined(IRIX5) +#define usleep doze +#endif + #ifdef LINUX2 #define SUPPORTED #include @@ -503,6 +511,13 @@ extern int opterr; #define SOCKOPT_SIZE int #endif +#ifndef LOCAL_LISTEN +#define LOCAL_LISTEN unix_listen +#define LOCAL_ACCEPT unix_accept +#define LOCAL_CONNECT unix_connect +#define LOCAL_TRIGGER unix_trigger +#endif + #if !defined (HAVE_SYS_NDIR_H) && !defined (HAVE_SYS_DIR_H) \ && !defined (HAVE_NDIR_H) #define HAVE_DIRENT_H diff --git a/postfix/util/trigger.h b/postfix/util/trigger.h index 1f266a747..ffcf63c52 100644 --- a/postfix/util/trigger.h +++ b/postfix/util/trigger.h @@ -17,6 +17,7 @@ extern int unix_trigger(const char *, const char *, int, int); extern int inet_trigger(const char *, const char *, int, int); extern int fifo_trigger(const char *, const char *, int, int); +extern int stream_trigger(const char *, const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/util/unix_listen.c b/postfix/util/unix_listen.c index 9c00710f2..36d3d1066 100644 --- a/postfix/util/unix_listen.c +++ b/postfix/util/unix_listen.c @@ -10,11 +10,16 @@ /* const char *addr; /* int backlog; /* int block_mode; +/* +/* int unix_accept(fd) +/* int fd; /* DESCRIPTION /* The \fBunix_listen\fR() routine starts a listener in the UNIX domain /* on the specified address, with the specified backlog, and returns /* the resulting file descriptor. /* +/* unix_accept() accepts a connection and sanitizes error results. +/* /* Arguments: /* .IP addr /* Null-terminated string with connection destination. @@ -23,8 +28,11 @@ /* .IP block_mode /* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for /* blocking mode. +/* .IP fd +/* File descriptor returned by unix_listen(). /* DIAGNOSTICS -/* Fatal errors: all errors are fatal. +/* Fatal errors: unix_listen() aborts upon any system call failure. +/* unix_accept() leaves all error handling up to the caller. /* LICENSE /* .ad /* .fi @@ -50,6 +58,7 @@ #include "msg.h" #include "iostuff.h" #include "listen.h" +#include "sane_accept.h" /* unix_listen - create UNIX-domain listener */ @@ -93,3 +102,10 @@ int unix_listen(const char *addr, int backlog, int block_mode) msg_fatal("listen: %m"); return (sock); } + +/* unix_accept - accept connection */ + +int unix_accept(int fd) +{ + return (sane_accept(fd, (struct sockaddr *) 0, (SOCKADDR_SIZE *) 0)); +} diff --git a/postfix/util/writable.c b/postfix/util/writable.c index 3e1da8c86..53af93cbb 100644 --- a/postfix/util/writable.c +++ b/postfix/util/writable.c @@ -77,7 +77,7 @@ int writable(int fd) switch (select(fd + 1, (fd_set *) 0, &write_fds, &except_fds, &tv)) { case -1: if (errno != EINTR) - msg_fatal("select"); + msg_fatal("select: %m"); continue; default: return (FD_ISSET(fd, &write_fds));