From: Wietse Venema Date: Mon, 7 Jan 2008 05:00:00 +0000 (-0500) Subject: postfix-2.5-20080107 X-Git-Tag: v2.5.0-RC1~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=938ae95e64d0665743357de9376466a07c7bb3bf;p=thirdparty%2Fpostfix.git postfix-2.5-20080107 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index d30cc7994..b0787657c 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -14083,3 +14083,23 @@ Apologies for any names omitted. Bugfix: the Milter client did not replace the Postfix-specific form for unknown host names by the Sendmail-specific form. File: milter/milter8.c. + + Cleanup: when a cleanup milter reports a problem don't log + generic "4.3.0 Sevice unavailable", but log the text for + the actual error. File: cleanup/cleanup_milter.c. + +20080104 + + Workaround: minor change to the Dovecot AUTH request to + prevent dovecot-auth memory wastage. Timo Sirainen. File: + xsasl/xsasl_dovecot_server.c. + +20070807 + + Feature (experimental release only): new "pass" service + type (in addition to "inet", "unix" and "fifo"). The "pass" + service type supports front-end daemons that accept all + inbound connections and that permit only well-behaved clients + to talk to the MTA. This service type had been sitting in + the master daemon for years but was disabled by default. + Files: util/upass_connect.c, util/upass_trigger.c. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index c953a33dd..cc1d9e95d 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -11,6 +11,16 @@ instead, a new snapshot is released. The mail_release_date configuration parameter (format: yyyymmdd) specifies the release date of a stable release or snapshot release. +Major changes with Postfix snapshot 20080107 +============================================ + +New "pass" service type in master.cf. Written years ago, this +allows a front-end daemon to accept all connections from the network, +and forward only those from well-behaved clients to Postfix. Since +this uses file descriptor passing, it imposes no overhead once a +connection is handed over to Postfix. This is available in the +experimental release only. See master(5) for a few details. + Incompatibility with Postfix snapshot 20071224 ============================================== diff --git a/postfix/WISHLIST b/postfix/WISHLIST index 3302948b5..179fbcba1 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -1,9 +1,6 @@ Wish list: - Milter client: send [ipaddress] instead of "unknown". - - The cleanup server should report "file too large" milter - errors as permanent errors. + Consolidate duplicated code in {inet,unix,upass}_trigger.c. In the SMTP client, handle 421 replies in smtp_loop() by having the input function raise a flag after detecting 421 diff --git a/postfix/html/master.5.html b/postfix/html/master.5.html index a527cc44f..68fe8dc19 100644 --- a/postfix/html/master.5.html +++ b/postfix/html/master.5.html @@ -109,44 +109,57 @@ MASTER(5) MASTER(5) trolled with the queue_directory configura- tion parameter in main.cf). + pass The service listens on a UNIX-domain socket, + receives one open connection (file descrip- + tor passing) per connection request, and is + accessible to local clients only. + + This feature is not part of the stable Post- + fix release. + + The service name is a pathname relative to + the Postfix queue directory (pathname con- + trolled with the queue_directory configura- + tion parameter in main.cf). + Private (default: y) - Whether or not access is restricted to the mail - system. Internet (type inet) services can't be + Whether or not access is restricted to the mail + system. Internet (type inet) services can't be private. Unprivileged (default: y) Whether the service runs with root privileges or as - the owner of the Postfix system (the owner name is + the owner of the Postfix system (the owner name is controlled by the mail_owner configuration variable in the main.cf file). - The local(8), pipe(8), spawn(8), and virtual(8) + The local(8), pipe(8), spawn(8), and virtual(8) daemons require privileges. Chroot (default: y) - Whether or not the service runs chrooted to the + Whether or not the service runs chrooted to the mail queue directory (pathname is controlled by the - queue_directory configuration variable in the + queue_directory configuration variable in the main.cf file). Chroot should not be used with the local(8), - pipe(8), spawn(8), and virtual(8) daemons. - Although the proxymap(8) server can run chrooted, + pipe(8), spawn(8), and virtual(8) daemons. + Although the proxymap(8) server can run chrooted, doing so defeats most of the purpose of having that service in the first place. The files in the examples/chroot-setup subdirectory of the Postfix source archive show set up a Postfix - chroot environment on a variety of systems. See - also BASIC_CONFIGURATION_README for issues related + chroot environment on a variety of systems. See + also BASIC_CONFIGURATION_README for issues related to running daemons chrooted. Wake up time (default: 0) - Automatically wake up the named service after the - specified number of seconds. The wake up is imple- - mented by connecting to the service and sending a - wake up request. A ? at the end of the wake-up - time field requests that no wake up events be sent + Automatically wake up the named service after the + specified number of seconds. The wake up is imple- + mented by connecting to the service and sending a + wake up request. A ? at the end of the wake-up + time field requests that no wake up events be sent before the first time a service is used. Specify 0 for no automatic wake up. @@ -154,59 +167,59 @@ MASTER(5) MASTER(5) a wake up timer. Process limit (default: $default_process_limit) - The maximum number of processes that may execute + The maximum number of processes that may execute this service simultaneously. Specify 0 for no process count limit. NOTE: Some Postfix services must be configured as a - single-process service (for example, qmgr(8)) and - some services must be configured with no process + single-process service (for example, qmgr(8)) and + some services must be configured with no process limit (for example, cleanup(8)). These limits must not be changed. Command name + arguments - The command to be executed. Characters that are - special to the shell such as ">" or "|" have no - special meaning here, and quotes cannot be used to + The command to be executed. Characters that are + special to the shell such as ">" or "|" have no + special meaning here, and quotes cannot be used to protect arguments containing whitespace. - The command name is relative to the Postfix daemon + The command name is relative to the Postfix daemon directory (pathname is controlled by the dae- mon_directory configuration variable). - The command argument syntax for specific commands - is specified in the respective daemon manual page. + The command argument syntax for specific commands + is specified in the respective daemon manual page. - The following command-line options have the same + The following command-line options have the same effect for all daemon programs: - -D Run the daemon under control by the command + -D Run the daemon under control by the command specified with the debugger_command variable in the main.cf configuration file. See DEBUG_README for hints and tips. -o name=value Override the named main.cf configuration - parameter. The parameter value can refer to + parameter. The parameter value can refer to other parameters as $name etc., just like in main.cf. See postconf(5) for syntax. NOTE 1: do not specify whitespace around the - "=". In parameter values, either avoid + "=". In parameter values, either avoid whitespace altogether, use commas instead of - spaces, or consider overrides like "-o - name=$override_parameter" with $over- + spaces, or consider overrides like "-o + name=$override_parameter" with $over- ride_parameter set in main.cf. - NOTE 2: Over-zealous use of parameter over- - rides makes the Postfix configuration hard - to understand and maintain. At a certain - point, it might be easier to configure mul- - tiple instances of Postfix, instead of con- + NOTE 2: Over-zealous use of parameter over- + rides makes the Postfix configuration hard + to understand and maintain. At a certain + point, it might be easier to configure mul- + tiple instances of Postfix, instead of con- figuring multiple personalities via mas- ter.cf. - -v Increase the verbose logging level. Specify + -v Increase the verbose logging level. Specify multiple -v options to make a Postfix daemon process increasingly verbose. @@ -219,7 +232,7 @@ MASTER(5) MASTER(5) DEBUG_README, Postfix debugging LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/man/man5/master.5 b/postfix/man/man5/master.5 index 7be2b2e8c..2a787a23a 100644 --- a/postfix/man/man5/master.5 +++ b/postfix/man/man5/master.5 @@ -98,6 +98,16 @@ streams sockets. The service listens on a FIFO (named pipe) and is accessible for local clients only. +The service name is a pathname relative to the Postfix +queue directory (pathname controlled with the \fBqueue_directory\fR +configuration parameter in main.cf). +.IP \fBpass\fR +The service listens on a UNIX-domain socket, receives one +open connection (file descriptor passing) per connection +request, and is accessible to local clients only. + +This feature is not part of the stable Postfix release. + The service name is a pathname relative to the Postfix queue directory (pathname controlled with the \fBqueue_directory\fR configuration parameter in main.cf). diff --git a/postfix/proto/master b/postfix/proto/master index 5ee1c8079..11f407933 100644 --- a/postfix/proto/master +++ b/postfix/proto/master @@ -95,6 +95,16 @@ # The service name is a pathname relative to the Postfix # queue directory (pathname controlled with the \fBqueue_directory\fR # configuration parameter in main.cf). +# .IP \fBpass\fR +# The service listens on a UNIX-domain socket, receives one +# open connection (file descriptor passing) per connection +# request, and is accessible to local clients only. +# +# This feature is not part of the stable Postfix release. +# +# The service name is a pathname relative to the Postfix +# queue directory (pathname controlled with the \fBqueue_directory\fR +# configuration parameter in main.cf). # .RE # .IP "\fBPrivate (default: y)\fR" # Whether or not access is restricted to the mail system. diff --git a/postfix/src/cleanup/cleanup.h b/postfix/src/cleanup/cleanup.h index d73058a8c..500d31f5c 100644 --- a/postfix/src/cleanup/cleanup.h +++ b/postfix/src/cleanup/cleanup.h @@ -104,6 +104,7 @@ typedef struct CLEANUP_STATE { const char *client_port; /* real or ersatz client */ VSTRING *milter_ext_from; /* externalized sender */ VSTRING *milter_ext_rcpt; /* externalized recipient */ + VSTRING *milter_err_text; /* milter call-back reply */ /* * Support for Milter body replacement requests. diff --git a/postfix/src/cleanup/cleanup_milter.c b/postfix/src/cleanup/cleanup_milter.c index 9a060326b..ed1adb8ff 100644 --- a/postfix/src/cleanup/cleanup_milter.c +++ b/postfix/src/cleanup/cleanup_milter.c @@ -234,6 +234,7 @@ static void cleanup_milter_set_error(CLEANUP_STATE *state, int err) static const char *cleanup_milter_error(CLEANUP_STATE *state, int err) { const char *myname = "cleanup_milter_error"; + CLEANUP_STAT_DETAIL *dp; /* * For consistency with error reporting within the milter infrastructure, @@ -251,7 +252,11 @@ static const char *cleanup_milter_error(CLEANUP_STATE *state, int err) cleanup_milter_set_error(state, err); else if (CLEANUP_OUT_OK(state)) msg_panic("%s: missing errno to error flag mapping", myname); - return ("451 4.3.0 Server internal error"); + if (state->milter_err_text == 0) + state->milter_err_text = vstring_alloc(50); + dp = cleanup_stat_detail(state->errs); + return (STR(vstring_sprintf(state->milter_err_text, + "%d %s %s", dp->smtp, dp->dsn, dp->text))); } /* cleanup_add_header - append message header */ diff --git a/postfix/src/cleanup/cleanup_state.c b/postfix/src/cleanup/cleanup_state.c index a69f9f7aa..9e584a660 100644 --- a/postfix/src/cleanup/cleanup_state.c +++ b/postfix/src/cleanup/cleanup_state.c @@ -117,6 +117,7 @@ CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src) state->client_port = 0; state->milter_ext_from = 0; state->milter_ext_rcpt = 0; + state->milter_err_text = 0; state->free_regions = state->body_regions = state->curr_body_region = 0; return (state); } @@ -168,6 +169,8 @@ void cleanup_state_free(CLEANUP_STATE *state) vstring_free(state->milter_ext_from); if (state->milter_ext_rcpt) vstring_free(state->milter_ext_rcpt); + if (state->milter_err_text) + vstring_free(state->milter_err_text); cleanup_region_done(state); myfree((char *) state); } diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 89a103c26..1d9229222 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20071229" +#define MAIL_RELEASE_DATE "20080107" #define MAIL_VERSION_NUMBER "2.5" #ifdef SNAPSHOT diff --git a/postfix/src/master/master.h b/postfix/src/master/master.h index 0ed354d28..f1dcdda4f 100644 --- a/postfix/src/master/master.h +++ b/postfix/src/master/master.h @@ -33,9 +33,6 @@ typedef struct MASTER_SERV { int wakeup_time; /* wakeup interval */ int *listen_fd; /* incoming requests */ int listen_fd_count; /* nr of descriptors */ -#ifdef MASTER_SERV_TYPE_PASS - struct PASS_INFO *pass_info; /* descriptor passing state */ -#endif union { struct { char *port; /* inet listen port */ @@ -78,7 +75,9 @@ typedef struct MASTER_SERV { #define MASTER_SERV_TYPE_UNIX 1 /* AF_UNIX domain socket */ #define MASTER_SERV_TYPE_INET 2 /* AF_INET domain socket */ #define MASTER_SERV_TYPE_FIFO 3 /* fifo (named pipe) */ -/*#define MASTER_SERV_TYPE_PASS 4 /* AF_UNIX domain socket */ +#ifdef SNAPSHOT /* see also master_proto.h */ +#define MASTER_SERV_TYPE_PASS 4 /* AF_UNIX domain socket */ +#endif /* * Default process management policy values. This is only the bare minimum. diff --git a/postfix/src/master/master_listen.c b/postfix/src/master/master_listen.c index 984b5dc05..50b972177 100644 --- a/postfix/src/master/master_listen.c +++ b/postfix/src/master/master_listen.c @@ -136,8 +136,7 @@ void master_listen_init(MASTER_SERV *serv) set_eugid(var_owner_uid, var_owner_gid); serv->listen_fd[0] = PASS_LISTEN(serv->name, serv->max_proc > var_proc_limit ? - serv->max_proc : var_proc_limit, NON_BLOCKING, - &(serv->pass_info)); + serv->max_proc : var_proc_limit, NON_BLOCKING); close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC); set_ugid(getuid(), getgid()); break; @@ -161,10 +160,6 @@ void master_listen_cleanup(MASTER_SERV *serv) * listener. The 4.4BSD shutdown(2) man page promises an ENOTCONN error * when shutdown(2) is applied to a socket that is not connected. */ -#ifdef MASTER_SERV_TYPE_PASS - if (serv->type == MASTER_SERV_TYPE_PASS) - PASS_SHUTDOWN(&(serv->pass_info)); -#endif for (n = 0; n < serv->listen_fd_count; n++) { if (close(serv->listen_fd[n]) < 0) msg_warn("%s: close listener socket %d: %m", diff --git a/postfix/src/master/master_proto.h b/postfix/src/master/master_proto.h index ca6fe0b24..a017b5a26 100644 --- a/postfix/src/master/master_proto.h +++ b/postfix/src/master/master_proto.h @@ -15,7 +15,9 @@ #define MASTER_XPORT_NAME_UNIX "unix" /* local IPC */ #define MASTER_XPORT_NAME_FIFO "fifo" /* local IPC */ #define MASTER_XPORT_NAME_INET "inet" /* non-local IPC */ -/*#define MASTER_XPORT_NAME_PASS "pass" /* local IPC */ +#ifdef SNAPSHOT /* see also master.h */ +#define MASTER_XPORT_NAME_PASS "pass" /* local IPC */ +#endif /* * Format of a status message sent by a child process to the process diff --git a/postfix/src/master/master_wakeup.c b/postfix/src/master/master_wakeup.c index 8a431001f..306514ede 100644 --- a/postfix/src/master/master_wakeup.c +++ b/postfix/src/master/master_wakeup.c @@ -106,8 +106,7 @@ static void master_wakeup_timer_event(int unused_event, char *context) break; #ifdef MASTER_SERV_TYPE_PASS case MASTER_SERV_TYPE_PASS: - /* Can't send data to a service that expects descriptors. */ - status = 0; + status = PASS_TRIGGER(serv->name, &wakeup, sizeof(wakeup), BRIEFLY); break; #endif diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 5e8a6c47e..475bcf749 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -30,7 +30,8 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \ username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \ vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \ write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \ - allascii.c load_file.c killme_after.c vstream_tweak.c + allascii.c load_file.c killme_after.c vstream_tweak.c upass_connect.c \ + upass_listen.c upass_trigger.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ @@ -62,7 +63,8 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \ vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \ write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \ - allascii.o load_file.o killme_after.o vstream_tweak.o + allascii.o load_file.o killme_after.o vstream_tweak.o upass_connect.o \ + upass_listen.o upass_trigger.o HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ @@ -1550,12 +1552,30 @@ unix_trigger.o: unix_trigger.c unsafe.o: safe.h unsafe.o: sys_defs.h unsafe.o: unsafe.c +upass_connect.o: connect.h +upass_connect.o: events.h +upass_connect.o: iostuff.h +upass_connect.o: msg.h +upass_connect.o: mymalloc.h +upass_connect.o: sane_connect.h +upass_connect.o: sane_socketpair.h +upass_connect.o: sys_defs.h +upass_connect.o: timed_connect.h +upass_connect.o: upass_connect.c upass_listen.o: iostuff.h upass_listen.o: listen.h upass_listen.o: msg.h upass_listen.o: sane_accept.h upass_listen.o: sys_defs.h upass_listen.o: upass_listen.c +upass_trigger.o: connect.h +upass_trigger.o: events.h +upass_trigger.o: iostuff.h +upass_trigger.o: msg.h +upass_trigger.o: mymalloc.h +upass_trigger.o: sys_defs.h +upass_trigger.o: trigger.h +upass_trigger.o: upass_trigger.c uppercase.o: stringops.h uppercase.o: sys_defs.h uppercase.o: uppercase.c diff --git a/postfix/src/util/connect.h b/postfix/src/util/connect.h index 080b99c06..40987dc72 100644 --- a/postfix/src/util/connect.h +++ b/postfix/src/util/connect.h @@ -22,6 +22,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); +extern int upass_connect(const char *, int, int); /* LICENSE /* .ad diff --git a/postfix/src/util/listen.h b/postfix/src/util/listen.h index f7e70db4c..8a9041547 100644 --- a/postfix/src/util/listen.h +++ b/postfix/src/util/listen.h @@ -24,7 +24,7 @@ extern int inet_listen(const char *, int, int); extern int fifo_listen(const char *, int, int); extern int stream_listen(const char *, int, int); -#define upass_listen(path, mode, log) fifo_listen((path), (mode), (log)) +#define upass_listen(path, mode, log) unix_listen((path), (mode), (log)) extern int inet_accept(int); extern int unix_accept(int); diff --git a/postfix/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index af3b1fd17..a43098de3 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -1301,6 +1301,12 @@ extern int inet_pton(int, const char *, void *); #define LOCAL_RECV_FD unix_recv_fd #endif +#ifndef PASS_LISTEN +#define PASS_LISTEN upass_listen +#define PASS_ACCEPT upass_accept +#define PASS_TRIGGER upass_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/src/util/trigger.h b/postfix/src/util/trigger.h index 1f1548229..bd3e45d4f 100644 --- a/postfix/src/util/trigger.h +++ b/postfix/src/util/trigger.h @@ -18,6 +18,7 @@ extern int unix_trigger(const char *, const char *, ssize_t, int); extern int inet_trigger(const char *, const char *, ssize_t, int); extern int fifo_trigger(const char *, const char *, ssize_t, int); extern int stream_trigger(const char *, const char *, ssize_t, int); +extern int upass_trigger(const char *, const char *, ssize_t, int); /* LICENSE /* .ad diff --git a/postfix/src/util/unix_connect.c b/postfix/src/util/unix_connect.c index 402befb90..68de86d32 100644 --- a/postfix/src/util/unix_connect.c +++ b/postfix/src/util/unix_connect.c @@ -79,7 +79,7 @@ int unix_connect(const char *addr, int block_mode, int timeout) * Create a client socket. */ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) - msg_fatal("socket: %m"); + return (-1); /* * Timed connect. diff --git a/postfix/src/util/upass_connect.c b/postfix/src/util/upass_connect.c new file mode 100644 index 000000000..4efd837a9 --- /dev/null +++ b/postfix/src/util/upass_connect.c @@ -0,0 +1,141 @@ +/*++ +/* NAME +/* upass_connect 3 +/* SUMMARY +/* connect to UNIX-domain file descriptor listener +/* SYNOPSIS +/* #include +/* +/* int upass_connect(addr, block_mode, timeout) +/* const char *addr; +/* int block_mode; +/* int timeout; +/* DESCRIPTION +/* upass_connect() connects to a file descriptor listener in +/* the UNIX domain at the specified address, sends one half +/* of a socketpair to the listener, and returns the other half +/* to the caller. +/* +/* The file descriptor transporting connection is closed by +/* a background thread. Some kernels might otherwise discard +/* the descriptor before the server has received it. +/* +/* Arguments: +/* .IP addr +/* Null-terminated string with connection destination. +/* .IP block_mode +/* Either NON_BLOCKING for a non-blocking socket, or BLOCKING for +/* blocking mode. This setting has no effect on the connection +/* establishment process. +/* .IP timeout +/* Bounds the number of seconds that the operation may take. Specify +/* a value <= 0 to disable the time limit. +/* 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 interfaces. */ + +#include +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include +#include +#include + + /* + * Workaround for hostile kernels that don't support graceful shutdown. + */ +struct upass_connect { + int fd; + char *service; +}; + +/* upass_connect_event - disconnect from peer */ + +static void upass_connect_event(int event, char *context) +{ + struct upass_connect *up = (struct upass_connect *) context; + static const char *myname = "upass_connect_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(upass_connect_event, context); + if (close(up->fd) < 0) + msg_warn("%s: close %s: %m", myname, up->service); + myfree(up->service); + myfree((char *) up); +} + +/* upass_connect - connect to UNIX-domain file descriptor listener */ + +int upass_connect(const char *addr, int block_mode, int timeout) +{ + struct upass_connect *up; + int pair[2]; + int sock; + + /* + * Connect. + */ + if ((sock = unix_connect(addr, BLOCKING, timeout)) < 0) + return (-1); + + /* + * Send one socket pair half to the server. + */ +#define OUR_HALF 0 +#define THEIR_HALF 1 + + if (sane_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { + close(sock); + return (-1); + } + if (unix_send_fd(sock, pair[THEIR_HALF]) < 0) { + close(pair[THEIR_HALF]); + close(pair[OUR_HALF]); + close(sock); + return (-1); + } + close(pair[THEIR_HALF]); + + /* + * Return the other socket pair half to the caller. Don't close the + * control socket just yet, but wait until the receiver closes it first. + * Otherwise, some hostile kernel might discard the socket that we just + * sent. + */ + up = (struct upass_connect *) mymalloc(sizeof(*up)); + up->fd = sock; + up->service = mystrdup(addr); + if (timeout > 0) + event_request_timer(upass_connect_event, (char *) up, timeout + 100); + event_enable_read(sock, upass_connect_event, (char *) up); + non_blocking(pair[OUR_HALF], block_mode); + return (pair[OUR_HALF]); +} diff --git a/postfix/src/util/upass_trigger.c b/postfix/src/util/upass_trigger.c new file mode 100644 index 000000000..2532f2bf3 --- /dev/null +++ b/postfix/src/util/upass_trigger.c @@ -0,0 +1,131 @@ +/*++ +/* NAME +/* upass_trigger 3 +/* SUMMARY +/* wakeup UNIX-domain file descriptor listener +/* SYNOPSIS +/* #include +/* +/* int upass_trigger(service, buf, len, timeout) +/* const char *service; +/* const char *buf; +/* ssize_t len; +/* int timeout; +/* DESCRIPTION +/* upass_trigger() wakes up the named UNIX-domain server by sending +/* 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. +/* .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 +/* upass_connect(3), UNIX-domain 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 +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include + +struct upass_trigger { + int fd; + char *service; +}; + +/* upass_trigger_event - disconnect from peer */ + +static void upass_trigger_event(int event, char *context) +{ + struct upass_trigger *up = (struct upass_trigger *) context; + static const char *myname = "upass_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(upass_trigger_event, context); + if (close(up->fd) < 0) + msg_warn("%s: close %s: %m", myname, up->service); + myfree(up->service); + myfree((char *) up); +} + +/* upass_trigger - wakeup UNIX-domain server */ + +int upass_trigger(const char *service, const char *buf, ssize_t len, int timeout) +{ + const char *myname = "upass_trigger"; + struct upass_trigger *up; + int fd; + + if (msg_verbose > 1) + msg_info("%s: service %s", myname, service); + + /* + * Connect... + */ + if ((fd = upass_connect(service, BLOCKING, timeout)) < 0) { + if (msg_verbose) + msg_warn("%s: connect to %s: %m", myname, service); + return (-1); + } + close_on_exec(fd, CLOSE_ON_EXEC); + + /* + * Stash away context. + */ + up = (struct upass_trigger *) mymalloc(sizeof(*up)); + up->fd = fd; + up->service = mystrdup(service); + + /* + * Write the request... + */ + 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); + + /* + * Wakeup when the peer disconnects, or when we lose patience. + */ + if (timeout > 0) + event_request_timer(upass_trigger_event, (char *) up, timeout + 100); + event_enable_read(fd, upass_trigger_event, (char *) up); + return (0); +} diff --git a/postfix/src/xsasl/xsasl_dovecot_server.c b/postfix/src/xsasl/xsasl_dovecot_server.c index fa59fa722..2e382f24a 100644 --- a/postfix/src/xsasl/xsasl_dovecot_server.c +++ b/postfix/src/xsasl/xsasl_dovecot_server.c @@ -579,7 +579,7 @@ int xsasl_dovecot_server_first(XSASL_SERVER *xp, const char *sasl_method, /* send the request */ server->last_request_id = ++server->impl->request_id_counter; vstream_fprintf(server->impl->sasl_stream, - "AUTH\t%u\t%s\tservice=%s", + "AUTH\t%u\t%s\tservice=%s\tnologin", server->last_request_id, sasl_method, server->service); if (init_response) {