Not used by postfix 2.3.0. Removed due to conflict with postconf awk script.

This commit is contained in:
rpaulo 2006-07-19 01:56:30 +00:00
parent ba10c8855d
commit 404ed95661
14 changed files with 0 additions and 4134 deletions

View File

@ -1,256 +0,0 @@
SHELL = /bin/sh
SRCS = lmtp.c lmtp_connect.c lmtp_proto.c lmtp_chat.c lmtp_session.c \
lmtp_addr.c lmtp_trouble.c lmtp_state.c lmtp_sasl_glue.c \
lmtp_sasl_proto.c
OBJS = lmtp.o lmtp_connect.o lmtp_proto.o lmtp_chat.o lmtp_session.o \
lmtp_addr.o lmtp_trouble.o lmtp_state.o lmtp_sasl_glue.o \
lmtp_sasl_proto.o
HDRS = lmtp.h
TESTSRC =
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
TESTPROG=
PROG = lmtp
INC_DIR = ../../include
LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libdns.a ../../lib/libutil.a
.c.o:; $(CC) $(CFLAGS) -c $*.c
$(PROG): $(OBJS) $(LIBS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
$(OBJS): ../../conf/makedefs.out
Makefile: Makefile.in
(cat ../../conf/makedefs.out $?) >$@
test: $(TESTPROG)
tests: test
update: ../../libexec/$(PROG)
../../libexec/$(PROG): $(PROG)
cp $(PROG) ../../libexec
printfck: $(OBJS) $(PROG)
rm -rf printfck
mkdir printfck
cp *.h printfck
sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o`
lint:
lint $(DEFS) $(SRCS) $(LINTFIX)
clean:
rm -f *.o *core $(PROG) $(TESTPROG) junk
rm -rf printfck
tidy: clean
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
$(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
-e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
@$(EXPORT) make -f Makefile.in Makefile 1>&2
# do not edit below this line - it is generated by 'make depend'
lmtp.o: lmtp.c
lmtp.o: ../../include/sys_defs.h
lmtp.o: ../../include/dict.h
lmtp.o: ../../include/vstream.h
lmtp.o: ../../include/vbuf.h
lmtp.o: ../../include/argv.h
lmtp.o: ../../include/msg.h
lmtp.o: ../../include/mymalloc.h
lmtp.o: ../../include/name_mask.h
lmtp.o: ../../include/split_at.h
lmtp.o: ../../include/deliver_request.h
lmtp.o: ../../include/vstring.h
lmtp.o: ../../include/recipient_list.h
lmtp.o: ../../include/mail_queue.h
lmtp.o: ../../include/mail_params.h
lmtp.o: ../../include/mail_conf.h
lmtp.o: ../../include/debug_peer.h
lmtp.o: ../../include/mail_error.h
lmtp.o: ../../include/flush_clnt.h
lmtp.o: ../../include/mail_server.h
lmtp.o: lmtp.h
lmtp.o: lmtp_sasl.h
lmtp_addr.o: lmtp_addr.c
lmtp_addr.o: ../../include/sys_defs.h
lmtp_addr.o: ../../include/msg.h
lmtp_addr.o: ../../include/vstring.h
lmtp_addr.o: ../../include/vbuf.h
lmtp_addr.o: ../../include/mymalloc.h
lmtp_addr.o: ../../include/inet_addr_list.h
lmtp_addr.o: ../../include/myaddrinfo.h
lmtp_addr.o: ../../include/stringops.h
lmtp_addr.o: ../../include/sock_addr.h
lmtp_addr.o: ../../include/inet_proto.h
lmtp_addr.o: ../../include/mail_params.h
lmtp_addr.o: ../../include/own_inet_addr.h
lmtp_addr.o: ../../include/dns.h
lmtp_addr.o: lmtp.h
lmtp_addr.o: ../../include/vstream.h
lmtp_addr.o: ../../include/argv.h
lmtp_addr.o: ../../include/deliver_request.h
lmtp_addr.o: ../../include/recipient_list.h
lmtp_addr.o: lmtp_addr.h
lmtp_chat.o: lmtp_chat.c
lmtp_chat.o: ../../include/sys_defs.h
lmtp_chat.o: ../../include/msg.h
lmtp_chat.o: ../../include/vstring.h
lmtp_chat.o: ../../include/vbuf.h
lmtp_chat.o: ../../include/vstream.h
lmtp_chat.o: ../../include/argv.h
lmtp_chat.o: ../../include/stringops.h
lmtp_chat.o: ../../include/line_wrap.h
lmtp_chat.o: ../../include/mymalloc.h
lmtp_chat.o: ../../include/recipient_list.h
lmtp_chat.o: ../../include/deliver_request.h
lmtp_chat.o: ../../include/smtp_stream.h
lmtp_chat.o: ../../include/mail_params.h
lmtp_chat.o: ../../include/mail_addr.h
lmtp_chat.o: ../../include/post_mail.h
lmtp_chat.o: ../../include/cleanup_user.h
lmtp_chat.o: ../../include/mail_error.h
lmtp_chat.o: ../../include/name_mask.h
lmtp_chat.o: lmtp.h
lmtp_connect.o: lmtp_connect.c
lmtp_connect.o: ../../include/sys_defs.h
lmtp_connect.o: ../../include/msg.h
lmtp_connect.o: ../../include/vstream.h
lmtp_connect.o: ../../include/vbuf.h
lmtp_connect.o: ../../include/vstring.h
lmtp_connect.o: ../../include/split_at.h
lmtp_connect.o: ../../include/mymalloc.h
lmtp_connect.o: ../../include/iostuff.h
lmtp_connect.o: ../../include/timed_connect.h
lmtp_connect.o: ../../include/stringops.h
lmtp_connect.o: ../../include/host_port.h
lmtp_connect.o: ../../include/sane_connect.h
lmtp_connect.o: ../../include/inet_addr_list.h
lmtp_connect.o: ../../include/myaddrinfo.h
lmtp_connect.o: ../../include/sock_addr.h
lmtp_connect.o: ../../include/mail_params.h
lmtp_connect.o: ../../include/mail_proto.h
lmtp_connect.o: ../../include/attr.h
lmtp_connect.o: ../../include/own_inet_addr.h
lmtp_connect.o: ../../include/dns.h
lmtp_connect.o: lmtp.h
lmtp_connect.o: ../../include/argv.h
lmtp_connect.o: ../../include/deliver_request.h
lmtp_connect.o: ../../include/recipient_list.h
lmtp_connect.o: lmtp_addr.h
lmtp_proto.o: lmtp_proto.c
lmtp_proto.o: ../../include/sys_defs.h
lmtp_proto.o: ../../include/msg.h
lmtp_proto.o: ../../include/vstring.h
lmtp_proto.o: ../../include/vbuf.h
lmtp_proto.o: ../../include/vstream.h
lmtp_proto.o: ../../include/vstring_vstream.h
lmtp_proto.o: ../../include/stringops.h
lmtp_proto.o: ../../include/mymalloc.h
lmtp_proto.o: ../../include/name_code.h
lmtp_proto.o: ../../include/mail_params.h
lmtp_proto.o: ../../include/smtp_stream.h
lmtp_proto.o: ../../include/mail_queue.h
lmtp_proto.o: ../../include/recipient_list.h
lmtp_proto.o: ../../include/deliver_request.h
lmtp_proto.o: ../../include/deliver_completed.h
lmtp_proto.o: ../../include/defer.h
lmtp_proto.o: ../../include/bounce.h
lmtp_proto.o: ../../include/sent.h
lmtp_proto.o: ../../include/record.h
lmtp_proto.o: ../../include/rec_type.h
lmtp_proto.o: ../../include/off_cvt.h
lmtp_proto.o: ../../include/mark_corrupt.h
lmtp_proto.o: ../../include/quote_821_local.h
lmtp_proto.o: ../../include/quote_flags.h
lmtp_proto.o: ../../include/mail_proto.h
lmtp_proto.o: ../../include/iostuff.h
lmtp_proto.o: ../../include/attr.h
lmtp_proto.o: lmtp.h
lmtp_proto.o: ../../include/argv.h
lmtp_proto.o: lmtp_sasl.h
lmtp_sasl_glue.o: lmtp_sasl_glue.c
lmtp_sasl_glue.o: ../../include/sys_defs.h
lmtp_sasl_glue.o: ../../include/msg.h
lmtp_sasl_glue.o: ../../include/mymalloc.h
lmtp_sasl_glue.o: ../../include/stringops.h
lmtp_sasl_glue.o: ../../include/vstring.h
lmtp_sasl_glue.o: ../../include/vbuf.h
lmtp_sasl_glue.o: ../../include/split_at.h
lmtp_sasl_glue.o: ../../include/name_mask.h
lmtp_sasl_glue.o: ../../include/mail_params.h
lmtp_sasl_glue.o: ../../include/string_list.h
lmtp_sasl_glue.o: ../../include/match_list.h
lmtp_sasl_glue.o: ../../include/match_ops.h
lmtp_sasl_glue.o: ../../include/maps.h
lmtp_sasl_glue.o: ../../include/dict.h
lmtp_sasl_glue.o: ../../include/vstream.h
lmtp_sasl_glue.o: ../../include/argv.h
lmtp_sasl_glue.o: lmtp.h
lmtp_sasl_glue.o: ../../include/deliver_request.h
lmtp_sasl_glue.o: ../../include/recipient_list.h
lmtp_sasl_glue.o: lmtp_sasl.h
lmtp_sasl_proto.o: lmtp_sasl_proto.c
lmtp_sasl_proto.o: ../../include/sys_defs.h
lmtp_sasl_proto.o: ../../include/msg.h
lmtp_sasl_proto.o: ../../include/mymalloc.h
lmtp_sasl_proto.o: ../../include/mail_params.h
lmtp_sasl_proto.o: lmtp.h
lmtp_sasl_proto.o: ../../include/vstream.h
lmtp_sasl_proto.o: ../../include/vbuf.h
lmtp_sasl_proto.o: ../../include/vstring.h
lmtp_sasl_proto.o: ../../include/argv.h
lmtp_sasl_proto.o: ../../include/deliver_request.h
lmtp_sasl_proto.o: ../../include/recipient_list.h
lmtp_sasl_proto.o: lmtp_sasl.h
lmtp_session.o: lmtp_session.c
lmtp_session.o: ../../include/sys_defs.h
lmtp_session.o: ../../include/mymalloc.h
lmtp_session.o: ../../include/vstream.h
lmtp_session.o: ../../include/vbuf.h
lmtp_session.o: ../../include/stringops.h
lmtp_session.o: ../../include/vstring.h
lmtp_session.o: ../../include/debug_peer.h
lmtp_session.o: lmtp.h
lmtp_session.o: ../../include/argv.h
lmtp_session.o: ../../include/deliver_request.h
lmtp_session.o: ../../include/recipient_list.h
lmtp_state.o: lmtp_state.c
lmtp_state.o: ../../include/sys_defs.h
lmtp_state.o: ../../include/mymalloc.h
lmtp_state.o: ../../include/vstring.h
lmtp_state.o: ../../include/vbuf.h
lmtp_state.o: ../../include/vstream.h
lmtp_state.o: ../../include/mail_conf.h
lmtp_state.o: lmtp.h
lmtp_state.o: ../../include/argv.h
lmtp_state.o: ../../include/deliver_request.h
lmtp_state.o: ../../include/recipient_list.h
lmtp_state.o: lmtp_sasl.h
lmtp_trouble.o: lmtp_trouble.c
lmtp_trouble.o: ../../include/sys_defs.h
lmtp_trouble.o: ../../include/msg.h
lmtp_trouble.o: ../../include/vstring.h
lmtp_trouble.o: ../../include/vbuf.h
lmtp_trouble.o: ../../include/stringops.h
lmtp_trouble.o: ../../include/mymalloc.h
lmtp_trouble.o: ../../include/smtp_stream.h
lmtp_trouble.o: ../../include/vstream.h
lmtp_trouble.o: ../../include/deliver_request.h
lmtp_trouble.o: ../../include/recipient_list.h
lmtp_trouble.o: ../../include/deliver_completed.h
lmtp_trouble.o: ../../include/bounce.h
lmtp_trouble.o: ../../include/defer.h
lmtp_trouble.o: ../../include/mail_error.h
lmtp_trouble.o: ../../include/name_mask.h
lmtp_trouble.o: lmtp.h
lmtp_trouble.o: ../../include/argv.h

View File

@ -1,598 +0,0 @@
/* $NetBSD: lmtp.c,v 1.1.1.10 2006/01/05 02:12:49 rpaulo Exp $ */
/*++
/* NAME
/* lmtp 8
/* SUMMARY
/* Postfix local delivery via LMTP
/* SYNOPSIS
/* \fBlmtp\fR [generic Postfix daemon options]
/* DESCRIPTION
/* The LMTP client processes message delivery requests from
/* the queue manager. Each request specifies a queue file, a sender
/* address, a domain or host to deliver to, and recipient information.
/* This program expects to be run from the \fBmaster\fR(8) process
/* manager.
/*
/* The LMTP client updates the queue file and marks recipients
/* as finished, or it informs the queue manager that delivery should
/* be tried again at a later time. Delivery status reports are sent
/* to the \fBbounce\fR(8), \fBdefer\fR(8) or \fBtrace\fR(8) daemon as
/* appropriate.
/*
/* The LMTP client connects to the destination specified in the message
/* delivery request. The destination, usually specified in the Postfix
/* \fBtransport\fR(5) table, has the form:
/* .IP \fBunix\fR:\fIpathname\fR
/* Connect to the local UNIX-domain server that is bound to the specified
/* \fIpathname\fR. If the process runs chrooted, an absolute pathname
/* is interpreted relative to the changed root directory.
/* .IP "\fBinet\fR:\fIhost\fR, \fBinet\fB:\fIhost\fR:\fIport\fR (symbolic host)"
/* .IP "\fBinet\fR:[\fIaddr\fR], \fBinet\fR:[\fIaddr\fR]:\fIport\fR (numeric host)"
/* Connect to the specified IPV4 TCP port on the specified local or
/* remote host. If no port is specified, connect to the port defined as
/* \fBlmtp\fR in \fBservices\fR(4).
/* If no such service is found, the \fBlmtp_tcp_port\fR configuration
/* parameter (default value of 24) will be used.
/*
/* The LMTP client does not perform MX (mail exchanger) lookups since
/* those are defined only for mail delivery via SMTP.
/* .PP
/* If neither \fBunix:\fR nor \fBinet:\fR are specified, \fBinet:\fR
/* is assumed.
/* SECURITY
/* .ad
/* .fi
/* The LMTP client is moderately security-sensitive. It talks to LMTP
/* servers and to DNS servers on the network. The LMTP client can be
/* run chrooted at fixed low privilege.
/* STANDARDS
/* RFC 821 (SMTP protocol)
/* RFC 1651 (SMTP service extensions)
/* RFC 1652 (8bit-MIME transport)
/* RFC 1870 (Message Size Declaration)
/* RFC 2033 (LMTP protocol)
/* RFC 2554 (AUTH command)
/* RFC 2821 (SMTP protocol)
/* RFC 2920 (SMTP Pipelining)
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8).
/* Corrupted message files are marked so that the queue manager can
/* move them to the \fBcorrupt\fR queue for further inspection.
/*
/* Depending on the setting of the \fBnotify_classes\fR parameter,
/* the postmaster is notified of bounces, protocol problems, and of
/* other trouble.
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
/* Changes to \fBmain.cf\fR are picked up automatically, as \fBlmtp\fR(8)
/* processes run for only a limited amount of time. Use the command
/* "\fBpostfix reload\fR" to speed up a change.
/*
/* The text below provides only a parameter summary. See
/* \fBpostconf\fR(5) for more details including examples.
/* COMPATIBILITY CONTROLS
/* .ad
/* .fi
/* .IP "\fBlmtp_skip_quit_response (no)\fR"
/* Wait for the response to the LMTP QUIT command.
/* TROUBLE SHOOTING CONTROLS
/* .ad
/* .fi
/* .IP "\fBdebug_peer_level (2)\fR"
/* The increment in verbose logging level when a remote client or
/* server matches a pattern in the debug_peer_list parameter.
/* .IP "\fBdebug_peer_list (empty)\fR"
/* Optional list of remote client or server hostname or network
/* address patterns that cause the verbose logging level to increase
/* by the amount specified in $debug_peer_level.
/* .IP "\fBerror_notice_recipient (postmaster)\fR"
/* The recipient of postmaster notifications about mail delivery
/* problems that are caused by policy, resource, software or protocol
/* errors.
/* .IP "\fBnotify_classes (resource, software)\fR"
/* The list of error classes that are reported to the postmaster.
/* EXTERNAL CONTENT INSPECTION CONTROLS
/* .ad
/* .fi
/* Available in Postfix version 2.1 and later:
/* .IP "\fBlmtp_send_xforward_command (no)\fR"
/* Send an XFORWARD command to the LMTP server when the LMTP LHLO
/* server response announces XFORWARD support.
/* SASL AUTHENTICATION CONTROLS
/* .ad
/* .fi
/* .IP "\fBlmtp_sasl_auth_enable (no)\fR"
/* Enable SASL authentication in the Postfix LMTP client.
/* .IP "\fBlmtp_sasl_password_maps (empty)\fR"
/* Optional LMTP client lookup tables with one username:password entry
/* per host or domain.
/* .IP "\fBlmtp_sasl_security_options (noplaintext, noanonymous)\fR"
/* What authentication mechanisms the Postfix LMTP client is allowed
/* to use.
/* RESOURCE AND RATE CONTROLS
/* .ad
/* .fi
/* In the text below, \fItransport\fR is the name
/* of the service as specified in the \fBmaster.cf\fR file.
/* .IP "\fBlmtp_cache_connection (yes)\fR"
/* Keep Postfix LMTP client connections open for up to $max_idle
/* seconds.
/* .IP "\fItransport_\fBdestination_concurrency_limit ($default_destination_concurrency_limit)\fR"
/* Limit the number of parallel deliveries to the same destination
/* via this mail delivery transport.
/* .IP "\fItransport_\fBdestination_recipient_limit ($default_destination_recipient_limit)\fR"
/* Limit the number of recipients per message delivery via this mail
/* delivery transport.
/*
/* This parameter becomes significant if the LMTP client is used
/* for local delivery. Some LMTP servers can optimize delivery of
/* the same message to multiple recipients. The default limit for
/* local mail delivery is 1.
/*
/* Setting this parameter to 0 will lead to an unbounded number of
/* recipients per delivery. However, this could be risky since it may
/* make the machine vulnerable to running out of resources if messages
/* are encountered with an inordinate number of recipients. Exercise
/* care when setting this parameter.
/* .IP "\fBlmtp_connect_timeout (0s)\fR"
/* The LMTP client time limit for completing a TCP connection, or
/* zero (use the operating system built-in time limit).
/* .IP "\fBlmtp_lhlo_timeout (300s)\fR"
/* The LMTP client time limit for receiving the LMTP greeting
/* banner.
/* .IP "\fBlmtp_xforward_timeout (300s)\fR"
/* The LMTP client time limit for sending the XFORWARD command, and
/* for receiving the server response.
/* .IP "\fBlmtp_mail_timeout (300s)\fR"
/* The LMTP client time limit for sending the MAIL FROM command, and
/* for receiving the server response.
/* .IP "\fBlmtp_rcpt_timeout (300s)\fR"
/* The LMTP client time limit for sending the RCPT TO command, and
/* for receiving the server response.
/* .IP "\fBlmtp_data_init_timeout (120s)\fR"
/* The LMTP client time limit for sending the LMTP DATA command, and
/* for receiving the server response.
/* .IP "\fBlmtp_data_xfer_timeout (180s)\fR"
/* The LMTP client time limit for sending the LMTP message content.
/* .IP "\fBlmtp_data_done_timeout (600s)\fR"
/* The LMTP client time limit for sending the LMTP ".", and for
/* receiving the server response.
/* .IP "\fBlmtp_rset_timeout (20s)\fR"
/* The LMTP client time limit for sending the RSET command, and
/* for receiving the server response.
/* .IP "\fBlmtp_quit_timeout (300s)\fR"
/* The LMTP client time limit for sending the QUIT command, and for
/* receiving the server response.
/* MISCELLANEOUS CONTROLS
/* .ad
/* .fi
/* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
/* The default location of the Postfix main.cf and master.cf
/* configuration files.
/* .IP "\fBdaemon_timeout (18000s)\fR"
/* How much time a Postfix daemon process may take to handle a
/* request before it is terminated by a built-in watchdog timer.
/* .IP "\fBdisable_dns_lookups (no)\fR"
/* Disable DNS lookups in the Postfix SMTP and LMTP clients.
/* .IP "\fBipc_timeout (3600s)\fR"
/* The time limit for sending or receiving information over an internal
/* communication channel.
/* .IP "\fBlmtp_tcp_port (24)\fR"
/* The default TCP port that the Postfix LMTP client connects to.
/* .IP "\fBmax_idle (100s)\fR"
/* The maximum amount of time that an idle Postfix daemon process
/* waits for the next service request before exiting.
/* .IP "\fBmax_use (100)\fR"
/* The maximal number of connection requests before a Postfix daemon
/* process terminates.
/* .IP "\fBprocess_id (read-only)\fR"
/* The process ID of a Postfix command or daemon process.
/* .IP "\fBprocess_name (read-only)\fR"
/* The process name of a Postfix command or daemon process.
/* .IP "\fBqueue_directory (see 'postconf -d' output)\fR"
/* The location of the Postfix top-level queue directory.
/* .IP "\fBsyslog_facility (mail)\fR"
/* The syslog facility of Postfix logging.
/* .IP "\fBsyslog_name (postfix)\fR"
/* The mail system name that is prepended to the process name in syslog
/* records, so that "smtpd" becomes, for example, "postfix/smtpd".
/* SEE ALSO
/* bounce(8), delivery status reports
/* qmgr(8), queue manager
/* postconf(5), configuration parameters
/* master(5), generic daemon options
/* services(4), Internet services and aliases
/* master(8), process manager
/* syslogd(8), system logging
/* README FILES
/* .ad
/* .fi
/* Use "\fBpostconf readme_directory\fR" or
/* "\fBpostconf html_directory\fR" to locate this information.
/* .na
/* .nf
/* LMTP_README, Postfix LMTP client howto
/* VIRTUAL_README, virtual delivery agent howto
/* 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
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <dict.h>
/* Utility library. */
#include <msg.h>
#include <argv.h>
#include <mymalloc.h>
#include <name_mask.h>
#include <split_at.h>
/* Global library. */
#include <deliver_request.h>
#include <mail_queue.h>
#include <mail_params.h>
#include <mail_conf.h>
#include <debug_peer.h>
#include <mail_error.h>
#include <flush_clnt.h>
/* Single server skeleton. */
#include <mail_server.h>
/* Application-specific. */
#include "lmtp.h"
#include "lmtp_sasl.h"
/*
* Tunable parameters. These have compiled-in defaults that can be overruled
* by settings in the global Postfix configuration file.
*/
int var_lmtp_tcp_port;
int var_lmtp_conn_tmout;
int var_lmtp_rset_tmout;
int var_lmtp_lhlo_tmout;
int var_lmtp_xfwd_tmout;
int var_lmtp_mail_tmout;
int var_lmtp_rcpt_tmout;
int var_lmtp_data0_tmout;
int var_lmtp_data1_tmout;
int var_lmtp_data2_tmout;
int var_lmtp_quit_tmout;
int var_lmtp_cache_conn;
int var_lmtp_skip_quit_resp;
char *var_notify_classes;
char *var_error_rcpt;
char *var_lmtp_sasl_opts;
char *var_lmtp_sasl_passwd;
bool var_lmtp_sasl_enable;
bool var_lmtp_send_xforward;
/*
* Global variables.
*
* lmtp_errno is set by the address lookup routines and by the connection
* management routines.
*
* state is global for the connection caching to work.
*/
int lmtp_errno;
static LMTP_STATE *state = 0;
/* deliver_message - deliver message with extreme prejudice */
static int deliver_message(DELIVER_REQUEST *request, char **unused_argv)
{
char *myname = "deliver_message";
VSTRING *why;
int result;
if (msg_verbose)
msg_info("%s: from %s", myname, request->sender);
/*
* Sanity checks.
*/
if (request->rcpt_list.len <= 0)
msg_fatal("%s: recipient count: %d", myname, request->rcpt_list.len);
/*
* Initialize. Bundle all information about the delivery request, so that
* we can produce understandable diagnostics when something goes wrong
* many levels below. The alternative would be to make everything global.
*
* Note: `state' was made global (to this file) so that we can cache
* connections and so that we can close a cached connection via the
* MAIL_SERVER_EXIT function (cleanup). The alloc for `state' is
* performed in the MAIL_SERVER_POST_INIT function (post_init).
*
*/
why = vstring_alloc(100);
state->request = request;
state->src = request->fp;
/*
* See if we can reuse an existing connection.
*/
if (state->session != 0) {
/*
* Disconnect if we're going to a different destination. Discard
* transcript and status information for sending QUIT.
*
* XXX Should transform nexthop into canonical form (unix:/path or
* inet:host:port) before doing connection cache lookup. See also the
* connection cache updating code in lmtp_connect.c.
*/
if (strcasecmp(state->session->dest, request->nexthop) != 0) {
lmtp_quit(state);
lmtp_chat_reset(state);
state->session = lmtp_session_free(state->session);
#ifdef USE_SASL_AUTH
if (var_lmtp_sasl_enable)
lmtp_sasl_cleanup(state);
#endif
}
/*
* Disconnect if RSET can't be sent over an existing connection.
* Discard transcript and status information for sending RSET.
*/
else if (lmtp_rset(state) != 0
|| (state->features & LMTP_FEATURE_RSET_REJECTED) != 0) {
lmtp_chat_reset(state);
state->session = lmtp_session_free(state->session);
#ifdef USE_SASL_AUTH
if (var_lmtp_sasl_enable)
lmtp_sasl_cleanup(state);
#endif
}
/*
* Ready to go with another load. The reuse counter is logged for
* statistical analysis purposes. Given the Postfix architecture,
* connection cacheing makes sense only for dedicated transports.
* Logging the reuse count can help to convince people.
*/
else {
++state->reuse;
if (msg_verbose)
msg_info("%s: reusing (count %d) session with: %s",
myname, state->reuse, state->session->host);
}
}
/*
* See if we need to establish an LMTP connection.
*/
if (state->session == 0) {
/*
* Bounce or defer the recipients if no connection can be made.
*/
if ((state->session = lmtp_connect(request->nexthop, why)) == 0) {
lmtp_site_fail(state, lmtp_errno == LMTP_RETRY ? 450 : 550,
"%s", vstring_str(why));
}
/*
* Bounce or defer the recipients if the LMTP handshake fails.
*/
else if (lmtp_lhlo(state) != 0) {
state->session = lmtp_session_free(state->session);
#ifdef USE_SASL_AUTH
if (var_lmtp_sasl_enable)
lmtp_sasl_cleanup(state);
#endif
}
/*
* Congratulations. We just established a new LMTP connection.
*/
else
state->reuse = 0;
}
/*
* If a session exists, deliver this message to all requested recipients.
*/
if (state->session != 0)
lmtp_xfer(state);
/*
* Optionally, notify the postmaster of problems with establishing a
* session or with delivering mail.
*/
if (state->history != 0
&& (state->error_mask & name_mask(VAR_NOTIFY_CLASSES, mail_error_masks,
var_notify_classes)))
lmtp_chat_notify(state);
/*
* Disconnect if we're not caching connections. The pipelined protocol
* state machine knows if it should have sent a QUIT command. Do not
* cache a broken connection.
*/
if (state->session != 0
&& (!var_lmtp_cache_conn
|| vstream_ferror(state->session->stream)
|| vstream_feof(state->session->stream)))
state->session = lmtp_session_free(state->session);
/*
* Clean up.
*/
vstring_free(why);
result = state->status;
lmtp_chat_reset(state);
/*
* XXX State persists until idle timeout, but these fields will be
* dangling pointers. Nuke them.
*/
state->request = 0;
state->src = 0;
return (result);
}
/* lmtp_service - perform service for client */
static void lmtp_service(VSTREAM *client_stream, char *unused_service, char **argv)
{
DELIVER_REQUEST *request;
int status;
/*
* Sanity check. This service takes no command-line arguments.
*/
if (argv[0])
msg_fatal("unexpected command-line argument: %s", argv[0]);
/*
* This routine runs whenever a client connects to the UNIX-domain socket
* dedicated to remote LMTP delivery service. What we see below is a
* little protocol to (1) tell the queue manager that we are ready, (2)
* read a request from the queue manager, and (3) report the completion
* status of that request. All connection-management stuff is handled by
* the common code in single_server.c.
*/
if ((request = deliver_request_read(client_stream)) != 0) {
status = deliver_message(request, argv);
deliver_request_done(client_stream, request, status);
}
}
/* post_init - post-jail initialization */
static void post_init(char *unused_name, char **unused_argv)
{
state = lmtp_state_alloc();
}
/* pre_init - pre-jail initialization */
static void pre_init(char *unused_name, char **unused_argv)
{
debug_peer_init();
if (var_lmtp_sasl_enable)
#ifdef USE_SASL_AUTH
lmtp_sasl_initialize();
#else
msg_warn("%s is true, but SASL support is not compiled in",
VAR_LMTP_SASL_ENABLE);
#endif
/*
* flush client.
*/
flush_init();
}
/* cleanup - close any open connections, etc. */
static void cleanup(void)
{
if (state->session != 0) {
lmtp_quit(state);
lmtp_chat_reset(state);
state->session = lmtp_session_free(state->session);
if (msg_verbose)
msg_info("cleanup: just closed down session");
}
lmtp_state_free(state);
#ifdef USE_SASL_AUTH
if (var_lmtp_sasl_enable)
sasl_done();
#endif
}
/* pre_accept - see if tables have changed */
static void pre_accept(char *unused_name, char **unused_argv)
{
const char *table;
if ((table = dict_changed_name()) != 0) {
msg_info("table %s has changed -- restarting", table);
cleanup();
exit(0);
}
}
/* main - pass control to the single-threaded skeleton */
int main(int argc, char **argv)
{
static CONFIG_STR_TABLE str_table[] = {
VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0,
VAR_LMTP_SASL_OPTS, DEF_LMTP_SASL_OPTS, &var_lmtp_sasl_opts, 0, 0,
0,
};
static CONFIG_INT_TABLE int_table[] = {
VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
0,
};
static CONFIG_TIME_TABLE time_table[] = {
VAR_LMTP_CONN_TMOUT, DEF_LMTP_CONN_TMOUT, &var_lmtp_conn_tmout, 0, 0,
VAR_LMTP_RSET_TMOUT, DEF_LMTP_RSET_TMOUT, &var_lmtp_rset_tmout, 1, 0,
VAR_LMTP_LHLO_TMOUT, DEF_LMTP_LHLO_TMOUT, &var_lmtp_lhlo_tmout, 1, 0,
VAR_LMTP_XFWD_TMOUT, DEF_LMTP_XFWD_TMOUT, &var_lmtp_xfwd_tmout, 1, 0,
VAR_LMTP_MAIL_TMOUT, DEF_LMTP_MAIL_TMOUT, &var_lmtp_mail_tmout, 1, 0,
VAR_LMTP_RCPT_TMOUT, DEF_LMTP_RCPT_TMOUT, &var_lmtp_rcpt_tmout, 1, 0,
VAR_LMTP_DATA0_TMOUT, DEF_LMTP_DATA0_TMOUT, &var_lmtp_data0_tmout, 1, 0,
VAR_LMTP_DATA1_TMOUT, DEF_LMTP_DATA1_TMOUT, &var_lmtp_data1_tmout, 1, 0,
VAR_LMTP_DATA2_TMOUT, DEF_LMTP_DATA2_TMOUT, &var_lmtp_data2_tmout, 1, 0,
VAR_LMTP_QUIT_TMOUT, DEF_LMTP_QUIT_TMOUT, &var_lmtp_quit_tmout, 1, 0,
0,
};
static CONFIG_BOOL_TABLE bool_table[] = {
VAR_LMTP_CACHE_CONN, DEF_LMTP_CACHE_CONN, &var_lmtp_cache_conn,
VAR_LMTP_SKIP_QUIT_RESP, DEF_LMTP_SKIP_QUIT_RESP, &var_lmtp_skip_quit_resp,
VAR_LMTP_SASL_ENABLE, DEF_LMTP_SASL_ENABLE, &var_lmtp_sasl_enable,
VAR_LMTP_SEND_XFORWARD, DEF_LMTP_SEND_XFORWARD, &var_lmtp_send_xforward,
0,
};
single_server_main(argc, argv, lmtp_service,
MAIL_SERVER_INT_TABLE, int_table,
MAIL_SERVER_STR_TABLE, str_table,
MAIL_SERVER_BOOL_TABLE, bool_table,
MAIL_SERVER_TIME_TABLE, time_table,
MAIL_SERVER_PRE_INIT, pre_init,
MAIL_SERVER_POST_INIT, post_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
MAIL_SERVER_EXIT, cleanup,
0);
}

View File

@ -1,162 +0,0 @@
/* $NetBSD: lmtp.h,v 1.1.1.7 2006/01/05 02:12:51 rpaulo Exp $ */
/*++
/* NAME
/* lmtp 3h
/* SUMMARY
/* lmtp client program
/* SYNOPSIS
/* #include "lmtp.h"
/* DESCRIPTION
/* .nf
/*
* SASL library.
*/
#ifdef USE_SASL_AUTH
#include <sasl.h>
#include <saslutil.h>
#endif
/*
* Utility library.
*/
#include <vstream.h>
#include <vstring.h>
#include <argv.h>
/*
* Global library.
*/
#include <deliver_request.h>
/*
* State information associated with each LMTP delivery. We're bundling the
* state so that we can give meaningful diagnostics in case of problems.
*/
typedef struct LMTP_STATE {
VSTREAM *src; /* queue file stream */
DELIVER_REQUEST *request; /* envelope info, offsets */
struct LMTP_SESSION *session; /* network connection */
VSTRING *buffer; /* I/O buffer */
VSTRING *scratch; /* scratch buffer */
VSTRING *scratch2; /* scratch buffer */
int status; /* delivery status */
int features; /* server features */
ARGV *history; /* transaction log */
int error_mask; /* error classes */
#ifdef USE_SASL_AUTH
char *sasl_mechanism_list; /* server mechanism list */
char *sasl_username; /* client username */
char *sasl_passwd; /* client password */
sasl_conn_t *sasl_conn; /* SASL internal state */
VSTRING *sasl_encoded; /* encoding buffer */
VSTRING *sasl_decoded; /* decoding buffer */
sasl_callback_t *sasl_callbacks; /* stateful callbacks */
#endif
int sndbufsize; /* total window size */
int reuse; /* connection being reused */
} LMTP_STATE;
#define LMTP_FEATURE_ESMTP (1<<0)
#define LMTP_FEATURE_8BITMIME (1<<1)
#define LMTP_FEATURE_PIPELINING (1<<2)
#define LMTP_FEATURE_SIZE (1<<3)
#define LMTP_FEATURE_AUTH (1<<5)
#define LMTP_FEATURE_XFORWARD_NAME (1<<6)
#define LMTP_FEATURE_XFORWARD_ADDR (1<<7)
#define LMTP_FEATURE_XFORWARD_PROTO (1<<8)
#define LMTP_FEATURE_XFORWARD_HELO (1<<9)
#define LMTP_FEATURE_XFORWARD_DOMAIN (1<<10)
#define LMTP_FEATURE_RSET_REJECTED (1<<11)
/*
* lmtp.c
*/
extern int lmtp_errno; /* XXX can we get rid of this? */
/*
* lmtp_session.c
*/
typedef struct LMTP_SESSION {
VSTREAM *stream; /* network connection */
char *host; /* mail exchanger, name */
char *addr; /* mail exchanger, address */
char *namaddr; /* mail exchanger, for logging */
char *dest; /* remote endpoint name */
} LMTP_SESSION;
extern LMTP_SESSION *lmtp_session_alloc(VSTREAM *, const char *, const char *, const char *);
extern LMTP_SESSION *lmtp_session_free(LMTP_SESSION *);
/*
* lmtp_connect.c
*/
extern LMTP_SESSION *lmtp_connect(const char *, VSTRING *);
/*
* lmtp_proto.c
*/
extern int lmtp_lhlo(LMTP_STATE *);
extern int lmtp_xfer(LMTP_STATE *);
extern int lmtp_quit(LMTP_STATE *);
extern int lmtp_rset(LMTP_STATE *);
/*
* lmtp_chat.c
*/
typedef struct LMTP_RESP { /* server response */
int code; /* status */
char *str; /* text */
VSTRING *buf; /* origin of text */
} LMTP_RESP;
extern void PRINTFLIKE(2, 3) lmtp_chat_cmd(LMTP_STATE *, char *,...);
extern LMTP_RESP *lmtp_chat_resp(LMTP_STATE *);
extern void lmtp_chat_reset(LMTP_STATE *);
extern void lmtp_chat_notify(LMTP_STATE *);
/*
* lmtp_trouble.c
*/
extern int PRINTFLIKE(3, 4) lmtp_conn_fail(LMTP_STATE *, int, char *,...);
extern int PRINTFLIKE(3, 4) lmtp_site_fail(LMTP_STATE *, int, char *,...);
extern int PRINTFLIKE(3, 4) lmtp_mesg_fail(LMTP_STATE *, int, char *,...);
extern void PRINTFLIKE(4, 5) lmtp_rcpt_fail(LMTP_STATE *, int, RECIPIENT *, char *,...);
extern int lmtp_stream_except(LMTP_STATE *, int, char *);
/*
* lmtp_state.c
*/
extern LMTP_STATE *lmtp_state_alloc(void);
extern void lmtp_state_free(LMTP_STATE *);
/*
* Status codes. Errors must have negative codes so that they do not
* interfere with useful counts of work done.
*/
#define LMTP_OK 0 /* so far, so good */
#define LMTP_RETRY (-1) /* transient error */
#define LMTP_FAIL (-2) /* hard error */
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/

View File

@ -1,214 +0,0 @@
/* $NetBSD: lmtp_addr.c,v 1.1.1.4 2006/02/25 22:09:20 rpaulo Exp $ */
/*++
/* NAME
/* lmtp_addr 3
/* SUMMARY
/* LMTP server address lookup
/* SYNOPSIS
/* #include "lmtp_addr.h"
/*
/* DNS_RR *lmtp_host_addr(name, why)
/* char *name;
/* VSTRING *why;
/* DESCRIPTION
/* This module implements Internet address lookups. By default,
/* lookups are done via the Internet domain name service (DNS).
/* A reasonable number of CNAME indirections is permitted.
/*
/* lmtp_host_addr() looks up all addresses listed for the named
/* host. The host can be specified as a numerical Internet network
/* address, or as a symbolic host name.
/*
/* Fortunately, we don't have to worry about MX records because
/* those are for SMTP servers, not LMTP servers.
/*
/* Results from lmtp_host_addr() are destroyed by dns_rr_free(),
/* including null lists.
/* DIAGNOSTICS
/* This routine either returns a DNS_RR pointer, or return a null
/* pointer and sets the \fIlmtp_errno\fR global variable accordingly:
/* .IP LMTP_RETRY
/* The request failed due to a soft error, and should be retried later.
/* .IP LMTP_FAIL
/* The request attempt failed due to a hard error.
/* .PP
/* In addition, a textual description of the problem is made available
/* via the \fIwhy\fR argument.
/* 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
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netdb.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <mymalloc.h>
#include <inet_addr_list.h>
#include <stringops.h>
#include <myaddrinfo.h>
#include <sock_addr.h>
#include <inet_proto.h>
/* Global library. */
#include <mail_params.h>
#include <own_inet_addr.h>
/* DNS library. */
#include <dns.h>
/* Application-specific. */
#include "lmtp.h"
#include "lmtp_addr.h"
/* lmtp_print_addr - print address list */
static void lmtp_print_addr(char *what, DNS_RR *addr_list)
{
DNS_RR *addr;
MAI_HOSTADDR_STR hostaddr;
msg_info("begin %s address list", what);
for (addr = addr_list; addr; addr = addr->next) {
if (dns_rr_to_pa(addr, &hostaddr) == 0) {
msg_warn("skipping record type %s: %m", dns_strtype(addr->type));
} else {
msg_info("pref %4d host %s/%s",
addr->pref, addr->rname,
hostaddr.buf);
}
}
msg_info("end %s address list", what);
}
/* lmtp_addr_one - address lookup for one host name */
static DNS_RR *lmtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
{
char *myname = "lmtp_addr_one";
DNS_RR *addr = 0;
DNS_RR *rr;
int aierr;
struct addrinfo *res0;
struct addrinfo *res;
INET_PROTO_INFO *proto_info = inet_proto_info();
int found;
if (msg_verbose)
msg_info("%s: host %s", myname, host);
/*
* Interpret a numerical name as an address.
*/
if (hostaddr_to_sockaddr(host, (char *) 0, 0, &res0) == 0
&& strchr((char *) proto_info->sa_family_list, res0->ai_family) != 0) {
if ((addr = dns_sa_to_rr(host, pref, res0->ai_addr)) == 0)
msg_fatal("host %s: conversion error for address family %d: %m",
host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
addr_list = dns_rr_append(addr_list, addr);
freeaddrinfo(res0);
return (addr_list);
}
/*
* Use native name service when DNS is disabled.
*/
#define RETRY_AI_ERROR(e) \
((e) == EAI_AGAIN || (e) == EAI_MEMORY || (e) == EAI_SYSTEM)
if (var_disable_dns) {
if ((aierr = hostname_to_sockaddr(host, (char *) 0, 0, &res0)) != 0) {
vstring_sprintf(why, "%s: %s", host, MAI_STRERROR(aierr));
lmtp_errno = (RETRY_AI_ERROR(aierr) ? LMTP_RETRY : LMTP_FAIL);
} else {
for (found = 0, res = res0; res != 0; res = res->ai_next) {
if (strchr((char *) proto_info->sa_family_list, res->ai_family) == 0) {
msg_info("skipping address family %d for host %s",
res->ai_family, host);
continue;
}
found++;
if ((addr = dns_sa_to_rr(host, pref, res->ai_addr)) == 0)
msg_fatal("host %s: conversion error for address family %d: %m",
host, ((struct sockaddr *) (res0->ai_addr))->sa_family);
addr_list = dns_rr_append(addr_list, addr);
}
freeaddrinfo(res0);
if (found == 0) {
vstring_sprintf(why, "%s: host not found", host);
lmtp_errno = LMTP_FAIL;
}
return (addr_list);
}
}
/*
* Append the addresses for this host to the address list.
*/
switch (dns_lookup_v(host, RES_DEFNAMES, &addr, (VSTRING *) 0, why,
DNS_REQ_FLAG_ALL, proto_info->dns_atype_list)) {
case DNS_OK:
for (rr = addr; rr; rr = rr->next)
rr->pref = pref;
addr_list = dns_rr_append(addr_list, addr);
break;
default:
lmtp_errno = LMTP_RETRY;
break;
case DNS_NOTFOUND:
case DNS_FAIL:
lmtp_errno = LMTP_FAIL;
break;
}
return (addr_list);
}
/* lmtp_host_addr - direct host lookup */
DNS_RR *lmtp_host_addr(char *host, VSTRING *why)
{
DNS_RR *addr_list;
/*
* If the host is specified by numerical address, just convert the
* address to internal form. Otherwise, the host is specified by name.
*/
#define PREF0 0
addr_list = lmtp_addr_one((DNS_RR *) 0, host, PREF0, why);
if (msg_verbose)
lmtp_print_addr(host, addr_list);
return (addr_list);
}

View File

@ -1,43 +0,0 @@
/* $NetBSD: lmtp_addr.h,v 1.1.1.2 2004/05/31 00:24:36 heas Exp $ */
/*++
/* NAME
/* lmtp_addr 3h
/* SUMMARY
/* LMTP server address lookup
/* SYNOPSIS
/* #include "lmtp_addr.h"
/* DESCRIPTION
/* .nf
/*
* DNS library.
*/
#include <dns.h>
/*
* Internal interfaces.
*/
extern DNS_RR *lmtp_host_addr(char *, VSTRING *);
/* 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
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/

View File

@ -1,312 +0,0 @@
/* $NetBSD: lmtp_chat.c,v 1.1.1.6 2005/12/01 21:44:20 rpaulo Exp $ */
/*++
/* NAME
/* lmtp_chat 3
/* SUMMARY
/* LMTP client request/response support
/* SYNOPSIS
/* #include "lmtp.h"
/*
/* typedef struct {
/* .in +4
/* int code;
/* char *str;
/* VSTRING *buf;
/* .in -4
/* } LMTP_RESP;
/*
/* void lmtp_chat_cmd(state, format, ...)
/* LMTP_STATE *state;
/* char *format;
/*
/* LMTP_RESP *lmtp_chat_resp(state)
/* LMTP_STATE *state;
/*
/* void lmtp_chat_notify(state)
/* LMTP_STATE *state;
/*
/* void lmtp_chat_reset(state)
/* LMTP_STATE *state;
/* DESCRIPTION
/* This module implements LMTP client support for request/reply
/* conversations, and maintains a limited LMTP transaction log.
/*
/* lmtp_chat_cmd() formats a command and sends it to an LMTP server.
/* Optionally, the command is logged.
/*
/* lmtp_chat_resp() read one LMTP server response. It separates the
/* numerical status code from the text, and concatenates multi-line
/* responses to one string, using a newline as separator.
/* Optionally, the server response is logged.
/*
/* lmtp_chat_notify() sends a copy of the LMTP transaction log
/* to the postmaster for review. The postmaster notice is sent only
/* when delivery is possible immediately. It is an error to call
/* lmtp_chat_notify() when no LMTP transaction log exists.
/*
/* lmtp_chat_reset() resets the transaction log. This is
/* typically done at the beginning or end of an LMTP session,
/* or within a session to discard non-error information.
/* In addition, lmtp_chat_reset() resets the per-session error
/* status bits and flags.
/* DIAGNOSTICS
/* Fatal errors: memory allocation problem, server response exceeds
/* configurable limit.
/* All other exceptions are handled by long jumps (see smtp_stream(3)).
/* SEE ALSO
/* smtp_stream(3) LMTP session I/O support
/* msg(3) generic logging interface
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
#include <stdarg.h>
#include <ctype.h>
#include <stdlib.h>
#include <setjmp.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <argv.h>
#include <stringops.h>
#include <line_wrap.h>
#include <mymalloc.h>
/* Global library. */
#include <recipient_list.h>
#include <deliver_request.h>
#include <smtp_stream.h>
#include <mail_params.h>
#include <mail_addr.h>
#include <post_mail.h>
#include <mail_error.h>
/* Application-specific. */
#include "lmtp.h"
#define STR(x) ((char *) vstring_str(x))
#define LEN VSTRING_LEN
/* lmtp_chat_reset - reset LMTP transaction log */
void lmtp_chat_reset(LMTP_STATE *state)
{
if (state->history) {
argv_free(state->history);
state->history = 0;
}
/* What's status without history? */
state->status = 0;
state->error_mask = 0;
}
/* lmtp_chat_append - append record to LMTP transaction log */
static void lmtp_chat_append(LMTP_STATE *state, char *direction, char *data)
{
char *line;
if (state->history == 0)
state->history = argv_alloc(10);
line = concatenate(direction, data, (char *) 0);
argv_add(state->history, line, (char *) 0);
myfree(line);
}
/* lmtp_chat_cmd - send an LMTP command */
void lmtp_chat_cmd(LMTP_STATE *state, char *fmt,...)
{
LMTP_SESSION *session = state->session;
va_list ap;
/*
* Format the command, and update the transaction log.
*/
va_start(ap, fmt);
vstring_vsprintf(state->buffer, fmt, ap);
va_end(ap);
lmtp_chat_append(state, "Out: ", STR(state->buffer));
/*
* Optionally log the command first, so we can see in the log what the
* program is trying to do.
*/
if (msg_verbose)
msg_info("> %s: %s", session->namaddr, STR(state->buffer));
/*
* Send the command to the LMTP server.
*/
smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
}
/* lmtp_chat_resp - read and process LMTP server response */
LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
{
LMTP_SESSION *session = state->session;
static LMTP_RESP rdata;
char *cp;
int last_char;
int three_digs = 0;
/*
* Initialize the response data buffer.
*/
if (rdata.buf == 0)
rdata.buf = vstring_alloc(100);
/*
* Censor out non-printable characters in server responses. Concatenate
* multi-line server responses. Separate the status code from the text.
* Leave further parsing up to the application.
*/
VSTRING_RESET(rdata.buf);
for (;;) {
last_char = smtp_get(state->buffer, session->stream, var_line_limit);
printable(STR(state->buffer), '?');
if (last_char != '\n')
msg_warn("%s: response longer than %d: %.30s...",
session->namaddr, var_line_limit, STR(state->buffer));
if (msg_verbose)
msg_info("< %s: %s", session->namaddr, STR(state->buffer));
/*
* Defend against a denial of service attack by limiting the amount
* of multi-line text that we are willing to store.
*/
if (LEN(rdata.buf) < var_line_limit) {
if (VSTRING_LEN(rdata.buf))
VSTRING_ADDCH(rdata.buf, '\n');
vstring_strcat(rdata.buf, STR(state->buffer));
lmtp_chat_append(state, "In: ", STR(state->buffer));
}
/*
* Parse into code and text. Ignore unrecognized garbage. This means
* that any character except space (or end of line) will have the
* same effect as the '-' line continuation character.
*/
for (cp = STR(state->buffer); *cp && ISDIGIT(*cp); cp++)
/* void */ ;
if ((three_digs = (cp - STR(state->buffer) == 3)) != 0) {
if (*cp == '-')
continue;
if (*cp == ' ' || *cp == 0)
break;
}
/*
* XXX Do not ignore garbage when ESMTP command pipelining is turned
* on. After sending ".<CR><LF>QUIT<CR><LF>", Postfix might recognize
* the server's 2XX QUIT reply as a 2XX END-OF-DATA reply after
* garbage, causing mail to be lost. Instead, make a long jump so
* that all recipients of multi-recipient mail get consistent
* treatment.
*/
state->error_mask |= MAIL_ERROR_PROTOCOL;
if (state->features & LMTP_FEATURE_PIPELINING) {
msg_warn("non-LMTP response from %s: %.100s",
session->namaddr, STR(state->buffer));
vstream_longjmp(session->stream, SMTP_ERR_PROTO);
}
}
if (three_digs != 0)
rdata.code = atoi(STR(state->buffer));
else
rdata.code = 0;
VSTRING_TERMINATE(rdata.buf);
rdata.str = STR(rdata.buf);
return (&rdata);
}
/* print_line - line_wrap callback */
static void print_line(const char *str, int len, int indent, char *context)
{
VSTREAM *notice = (VSTREAM *) context;
post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
}
/* lmtp_chat_notify - notify postmaster */
void lmtp_chat_notify(LMTP_STATE *state)
{
char *myname = "lmtp_chat_notify";
LMTP_SESSION *session = state->session;
VSTREAM *notice;
char **cpp;
/*
* Sanity checks.
*/
if (state->history == 0)
msg_panic("%s: no conversation history", myname);
if (msg_verbose)
msg_info("%s: notify postmaster", myname);
/*
* Construct a message for the postmaster, explaining what this is all
* about. This is junk mail: don't send it when the mail posting service
* is unavailable, and use the double bounce sender address, to prevent
* mail bounce wars. Always prepend one space to message content that we
* generate from untrusted data.
*/
#define NULL_TRACE_FLAGS 0
#define LENGTH 78
#define INDENT 4
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
var_error_rcpt,
CLEANUP_FLAG_MASK_INTERNAL,
NULL_TRACE_FLAGS);
if (notice == 0) {
msg_warn("postmaster notify: %m");
return;
}
post_mail_fprintf(notice, "From: %s (Mail Delivery System)",
mail_addr_mail_daemon());
post_mail_fprintf(notice, "To: %s (Postmaster)", var_error_rcpt);
post_mail_fprintf(notice, "Subject: %s LMTP client: errors from %s",
var_mail_name, session->namaddr);
post_mail_fputs(notice, "");
post_mail_fprintf(notice, "Unexpected response from %s.", session->namaddr);
post_mail_fputs(notice, "");
post_mail_fputs(notice, "Transcript of session follows.");
post_mail_fputs(notice, "");
argv_terminate(state->history);
for (cpp = state->history->argv; *cpp; cpp++)
line_wrap(printable(*cpp, '?'), LENGTH, INDENT, print_line,
(char *) notice);
(void) post_mail_fclose(notice);
}

View File

@ -1,374 +0,0 @@
/* $NetBSD: lmtp_connect.c,v 1.1.1.7 2006/02/25 22:09:21 rpaulo Exp $ */
/*++
/* NAME
/* lmtp_connect 3
/* SUMMARY
/* connect to LMTP server
/* SYNOPSIS
/* #include "lmtp.h"
/*
/* LMTP_SESSION *lmtp_connect(destination, why)
/* char *destination;
/* VSTRING *why;
/* DESCRIPTION
/* This module implements LMTP connection management.
/*
/* lmtp_connect() attempts to establish an LMTP session.
/*
/* The destination is one of the following:
/* .IP unix:address
/* Connect to a UNIX-domain service. The destination is a pathname.
/* Beware: UNIX-domain sockets are flakey on Solaris, at last up to
/* and including Solaris 7.0.
/* .IP inet:address
/* Connect to an IPV4 service.
/* The destination is either a host name or a numeric address.
/* Symbolic or numeric service port information may be appended,
/* separated by a colon (":").
/*
/* Numerical address information should always be quoted with `[]'.
/* .PP
/* When no transport is specified, "inet" is assumed.
/* DIAGNOSTICS
/* This routine either returns an LMTP_SESSION pointer, or
/* returns a null pointer and set the \fIlmtp_errno\fR
/* global variable accordingly:
/* .IP LMTP_RETRY
/* The connection attempt failed, but should be retried later.
/* .IP LMTP_FAIL
/* The connection attempt failed.
/* .PP
/* In addition, a textual description of the error is made available
/* via the \fIwhy\fR argument.
/* SEE ALSO
/* lmtp_proto(3) LMTP client protocol
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */
#include <msg.h>
#include <vstream.h>
#include <vstring.h>
#include <split_at.h>
#include <mymalloc.h>
#include <iostuff.h>
#include <timed_connect.h>
#include <stringops.h>
#include <host_port.h>
#include <sane_connect.h>
#include <inet_addr_list.h>
#include <myaddrinfo.h>
#include <sock_addr.h>
/* Global library. */
#include <mail_params.h>
#include <mail_proto.h>
#include <own_inet_addr.h>
/* DNS library. */
#include <dns.h>
/* Application-specific. */
#include "lmtp.h"
#include "lmtp_addr.h"
/*
* Forward declaration.
*/
static LMTP_SESSION *lmtp_connect_sock(int, struct sockaddr *, int,
const char *, const char *,
const char *, VSTRING *);
/* lmtp_connect_unix - connect to UNIX-domain address */
static LMTP_SESSION *lmtp_connect_unix(const char *addr,
const char *destination, VSTRING *why)
{
#undef sun
char *myname = "lmtp_connect_unix";
struct sockaddr_un sun;
int len = strlen(addr);
int sock;
/*
* Sanity checks.
*/
if (len >= (int) sizeof(sun.sun_path)) {
msg_warn("unix-domain name too long: %s", addr);
lmtp_errno = LMTP_RETRY;
return (0);
}
/*
* Initialize.
*/
memset((char *) &sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
#ifdef HAS_SUN_LEN
sun.sun_len = len + 1;
#endif
memcpy(sun.sun_path, addr, len + 1);
/*
* Create a client socket.
*/
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
msg_fatal("%s: socket: %m", myname);
/*
* Connect to the LMTP server.
*/
if (msg_verbose)
msg_info("%s: trying: %s...", myname, addr);
return (lmtp_connect_sock(sock, (struct sockaddr *) & sun, sizeof(sun),
addr, addr, destination, why));
}
/* lmtp_connect_addr - connect to explicit address */
static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port,
const char *destination, VSTRING *why)
{
char *myname = "lmtp_connect_addr";
struct sockaddr_storage ss;
struct sockaddr *sa = SOCK_ADDR_PTR(&ss);
SOCKADDR_SIZE salen = sizeof(ss);
MAI_HOSTADDR_STR hostaddr;
int sock;
/*
* Sanity checks.
*/
if (dns_rr_to_sa(addr, port, sa, &salen) != 0) {
msg_warn("%s: skip address type %s: %m",
myname, dns_strtype(addr->type));
lmtp_errno = LMTP_RETRY;
return (0);
}
/*
* Initialize.
*/
if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
msg_fatal("%s: socket: %m", myname);
/*
* Connect to the LMTP server.
*/
SOCKADDR_TO_HOSTADDR(sa, salen, &hostaddr, (MAI_SERVPORT_STR *) 0, 0);
if (msg_verbose)
msg_info("%s: trying: %s[%s] port %d...",
myname, addr->rname, hostaddr.buf, ntohs(port));
return (lmtp_connect_sock(sock, sa, salen,
addr->rname, hostaddr.buf, destination, why));
}
/* lmtp_connect_sock - connect a socket over some transport */
static LMTP_SESSION *lmtp_connect_sock(int sock, struct sockaddr * sa, int len,
const char *name, const char *addr,
const char *destination, VSTRING *why)
{
int conn_stat;
int saved_errno;
VSTREAM *stream;
int ch;
if (var_lmtp_conn_tmout > 0) {
non_blocking(sock, NON_BLOCKING);
conn_stat = timed_connect(sock, sa, len, var_lmtp_conn_tmout);
saved_errno = errno;
non_blocking(sock, BLOCKING);
errno = saved_errno;
} else {
conn_stat = sane_connect(sock, sa, len);
}
if (conn_stat < 0) {
vstring_sprintf(why, "connect to %s[%s]: %m",
name, addr);
lmtp_errno = LMTP_RETRY;
close(sock);
return (0);
}
/*
* Skip this host if it takes no action within some time limit.
*/
if (read_wait(sock, var_lmtp_lhlo_tmout) < 0) {
vstring_sprintf(why, "connect to %s[%s]: read timeout",
name, addr);
lmtp_errno = LMTP_RETRY;
close(sock);
return (0);
}
/*
* Skip this host if it disconnects without talking to us.
*/
stream = vstream_fdopen(sock, O_RDWR);
if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
vstring_sprintf(why, "connect to %s[%s]: server dropped connection without sending the initial greeting",
name, addr);
lmtp_errno = LMTP_RETRY;
vstream_fclose(stream);
return (0);
}
vstream_ungetc(stream, ch);
/*
* Skip this host if it sends a 4xx or 5xx greeting.
*/
if (ch == '4' || ch == '5') {
vstring_sprintf(why, "connect to %s[%s]: server refused mail service",
name, addr);
lmtp_errno = LMTP_RETRY;
vstream_fclose(stream);
return (0);
}
return (lmtp_session_alloc(stream, name, addr, destination));
}
/* lmtp_connect_host - direct connection to host */
static LMTP_SESSION *lmtp_connect_host(char *host, unsigned port,
const char *destination, VSTRING *why)
{
LMTP_SESSION *session = 0;
DNS_RR *addr_list;
DNS_RR *addr;
/*
* Try each address in the specified order until we find one that works.
* The addresses belong to the same A record, so we have no information
* on what address is "best".
*/
addr_list = lmtp_host_addr(host, why);
for (addr = addr_list; addr; addr = addr->next) {
if ((session = lmtp_connect_addr(addr, port, destination, why)) != 0) {
break;
}
}
dns_rr_free(addr_list);
return (session);
}
/* lmtp_parse_destination - parse destination */
static char *lmtp_parse_destination(const char *destination, char *def_service,
char **hostp, unsigned *portp)
{
char *myname = "lmtp_parse_destination";
char *buf = mystrdup(destination);
char *service;
struct servent *sp;
char *protocol = "tcp"; /* XXX configurable? */
unsigned port;
const char *err;
if (msg_verbose)
msg_info("%s: %s %s", myname, destination, def_service);
/*
* Parse the host/port information. We're working with a copy of the
* destination argument so the parsing can be destructive.
*/
if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
msg_fatal("%s in LMTP server description: %s", err, destination);
/*
* Convert service to port number, network byte order. Since most folks
* aren't going to have lmtp defined as a service, use a default value
* instead of just blowing up.
*/
if (alldig(service)) {
if ((port = atoi(service)) >= 65536)
msg_fatal("bad numeric port in destination: %s", destination);
*portp = htons(port);
} else if ((sp = getservbyname(service, protocol)) != 0)
*portp = sp->s_port;
else
*portp = htons(var_lmtp_tcp_port);
return (buf);
}
/* lmtp_connect - establish LMTP connection */
LMTP_SESSION *lmtp_connect(const char *destination, VSTRING *why)
{
char *myname = "lmtp_connect";
LMTP_SESSION *session;
char *dest_buf;
char *host;
unsigned port;
char *def_service = "lmtp"; /* XXX configurable? */
/*
* Connect to the LMTP server.
*
* XXX Ad-hoc transport parsing and connection management. Some or all
* should be moved away to a reusable library routine so that every
* program benefits from it.
*
* XXX Should transform destination into canonical form (unix:/path or
* inet:host:port before entering it into the connection cache. See also
* the connection cache lookup code in lmtp.c.
*/
if (strncmp(destination, "unix:", 5) == 0)
return (lmtp_connect_unix(destination + 5, destination, why));
if (strncmp(destination, "inet:", 5) == 0)
dest_buf = lmtp_parse_destination(destination + 5, def_service,
&host, &port);
else
dest_buf = lmtp_parse_destination(destination, def_service,
&host, &port);
if (msg_verbose)
msg_info("%s: connecting to %s port %d", myname, host, ntohs(port));
session = lmtp_connect_host(host, port, destination, why);
myfree(dest_buf);
return (session);
}

View File

@ -1,890 +0,0 @@
/* $NetBSD: lmtp_proto.c,v 1.1.1.11 2006/01/05 02:12:56 rpaulo Exp $ */
/*++
/* NAME
/* lmtp_proto 3
/* SUMMARY
/* client LMTP protocol
/* SYNOPSIS
/* #include "lmtp.h"
/*
/* int lmtp_lhlo(state)
/* LMTP_STATE *state;
/*
/* int lmtp_xfer(state)
/* LMTP_STATE *state;
/*
/* int lmtp_rset(state)
/* LMTP_STATE *state;
/*
/* int lmtp_quit(state)
/* LMTP_STATE *state;
/* DESCRIPTION
/* This module implements the client side of the LMTP protocol.
/*
/* lmtp_lhlo() performs the initial handshake with the LMTP server.
/*
/* lmtp_xfer() sends message envelope information followed by the
/* message data and sends QUIT when connection cacheing is disabled.
/* These operations are combined in one function, in order to implement
/* LMTP pipelining.
/* Recipients are marked as "done" in the mail queue file when
/* bounced or delivered. The message delivery status is updated
/* accordingly.
/*
/* lmtp_rset() sends a lone RSET command and waits for the response.
/* In case of a negative reply it sets the CANT_RSET_THIS_SESSION flag.
/*
/* lmtp_quit() sends a lone QUIT command and waits for the response
/* only if waiting for QUIT replies is enabled.
/* DIAGNOSTICS
/* lmtp_lhlo(), lmtp_xfer(), lmtp_rset() and lmtp_quit() return 0 in
/* case of success, -1 in case of failure. For lmtp_xfer(), lmtp_rset()
/* and lmtp_quit(), success means the ability to perform an LMTP
/* conversation, not necessarily OK replies from the server.
/*
/* Warnings: corrupt message file. A corrupt message is marked
/* as "corrupt" by changing its queue file permissions.
/* SEE ALSO
/* lmtp(3h) internal data structures
/* lmtp_chat(3) query/reply LMTP support
/* lmtp_trouble(3) error handlers
/* 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
/*
/* Pipelining code in cooperation with:
/* Jon Ribbens
/* Oaktree Internet Solutions Ltd.,
/* Internet House,
/* Canal Basin,
/* Coventry,
/* CV1 4LY, United Kingdom.
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <sys/stat.h>
#include <sys/socket.h> /* shutdown(2) */
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
#include <stdarg.h>
#include <time.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <stringops.h>
#include <mymalloc.h>
#include <name_code.h>
/* Global library. */
#include <mail_params.h>
#include <smtp_stream.h>
#include <mail_queue.h>
#include <recipient_list.h>
#include <deliver_request.h>
#include <deliver_completed.h>
#include <defer.h>
#include <bounce.h>
#include <sent.h>
#include <record.h>
#include <rec_type.h>
#include <off_cvt.h>
#include <mark_corrupt.h>
#include <quote_821_local.h>
#include <mail_proto.h>
/* Application-specific. */
#include "lmtp.h"
#include "lmtp_sasl.h"
/*
* Sender and receiver state. A session does not necessarily go through a
* linear progression, but states are guaranteed to not jump backwards.
* Normal sessions go from MAIL->RCPT->DATA->DOT->QUIT->LAST. The states
* MAIL, RCPT, and DATA may also be followed by ABORT->QUIT->LAST.
*
* When connection cacheing is turned on, the transition diagram changes as
* follows. Before sending mail over an existing connection, the client
* sends a lone RSET command to find out if the connection still works. The
* client sends QUIT only when closing a connection. The respective state
* transitions are RSET->LAST and QUIT->LAST.
*
* For the sake of code reuse, the non-pipelined RSET command is sent by the
* same code that implements command pipelining, so that we can borrow from
* the existing code for exception handling and error reporting.
*
* Client states that are associated with sending mail (up to and including
* LMTP_STATE_DOT) must have smaller numerical values than the non-sending
* states (LMTP_STATE_ABORT .. LMTP_STATE_LAST).
*/
#define LMTP_STATE_XFORWARD_NAME_ADDR 0
#define LMTP_STATE_XFORWARD_PROTO_HELO 1
#define LMTP_STATE_MAIL 2
#define LMTP_STATE_RCPT 3
#define LMTP_STATE_DATA 4
#define LMTP_STATE_DOT 5
#define LMTP_STATE_ABORT 6
#define LMTP_STATE_RSET 7
#define LMTP_STATE_QUIT 8
#define LMTP_STATE_LAST 9
int *xfer_timeouts[LMTP_STATE_LAST] = {
&var_lmtp_xfwd_tmout, /* name/addr */
&var_lmtp_xfwd_tmout, /* helo/proto */
&var_lmtp_mail_tmout,
&var_lmtp_rcpt_tmout,
&var_lmtp_data0_tmout,
&var_lmtp_data2_tmout,
&var_lmtp_rset_tmout, /* abort */
&var_lmtp_rset_tmout, /* rset */
&var_lmtp_quit_tmout,
};
char *xfer_states[LMTP_STATE_LAST] = {
"sending XFORWARD name/address",
"sending XFORWARD protocol/helo_name",
"sending MAIL FROM",
"sending RCPT TO",
"sending DATA command",
"sending end of data -- message may be sent more than once",
"sending RSET", /* abort */
"sending RSET", /* rset */
"sending QUIT",
};
char *xfer_request[LMTP_STATE_LAST] = {
"XFORWARD name/address command",
"XFORWARD helo/protocol command",
"MAIL FROM command",
"RCPT TO command",
"DATA command",
"end of DATA command",
"RSET command", /* abort */
"RSET command", /* rset */
"QUIT command",
};
static int lmtp_send_proto_helo;
/* lmtp_lhlo - perform initial handshake with LMTP server */
int lmtp_lhlo(LMTP_STATE *state)
{
LMTP_SESSION *session = state->session;
LMTP_RESP *resp;
int except;
char *lines;
char *words;
char *word;
static NAME_CODE xforward_features[] = {
XFORWARD_NAME, LMTP_FEATURE_XFORWARD_NAME,
XFORWARD_ADDR, LMTP_FEATURE_XFORWARD_ADDR,
XFORWARD_PROTO, LMTP_FEATURE_XFORWARD_PROTO,
XFORWARD_HELO, LMTP_FEATURE_XFORWARD_HELO,
XFORWARD_DOMAIN, LMTP_FEATURE_XFORWARD_DOMAIN,
0, 0,
};
/*
* Prepare for disaster.
*/
smtp_timeout_setup(state->session->stream, var_lmtp_lhlo_tmout);
if ((except = vstream_setjmp(state->session->stream)) != 0)
return (lmtp_stream_except(state, except, "sending LHLO"));
/*
* Read and parse the server's LMTP greeting banner.
*/
if (((resp = lmtp_chat_resp(state))->code / 100) != 2)
return (lmtp_site_fail(state, resp->code,
"host %s refused to talk to me: %s",
session->namaddr, translit(resp->str, "\n", " ")));
/*
* Return the compliment.
*/
lmtp_chat_cmd(state, "LHLO %s", var_myhostname);
if ((resp = lmtp_chat_resp(state))->code / 100 != 2)
return (lmtp_site_fail(state, resp->code,
"host %s refused to talk to me: %s",
session->namaddr,
translit(resp->str, "\n", " ")));
/*
* Pick up some useful features offered by the LMTP server. XXX Until we
* have a portable routine to convert from string to off_t with proper
* overflow detection, ignore the message size limit advertised by the
* LMTP server. Otherwise, we might do the wrong thing when the server
* advertises a really huge message size limit.
*/
state->features = 0;
lines = resp->str;
(void) mystrtok(&lines, "\n");
while ((words = mystrtok(&lines, "\n")) != 0) {
if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) {
if (strcasecmp(word, "8BITMIME") == 0)
state->features |= LMTP_FEATURE_8BITMIME;
else if (strcasecmp(word, "PIPELINING") == 0)
state->features |= LMTP_FEATURE_PIPELINING;
else if (strcasecmp(word, "XFORWARD") == 0)
while ((word = mystrtok(&words, " \t")) != 0)
state->features |= name_code(xforward_features,
NAME_CODE_FLAG_NONE, word);
else if (strcasecmp(word, "SIZE") == 0)
state->features |= LMTP_FEATURE_SIZE;
#ifdef USE_SASL_AUTH
else if (var_lmtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
lmtp_sasl_helo_auth(state, words);
#endif
}
}
if (msg_verbose)
msg_info("server features: 0x%x", state->features);
/*
* We use LMTP command pipelining if the server said it supported it.
* Since we use blocking I/O, RFC 2197 says that we should inspect the
* TCP window size and not send more than this amount of information.
* Unfortunately this information is not available using the sockets
* interface. However, we *can* get the TCP send buffer size on the local
* TCP/IP stack. We should be able to fill this buffer without being
* blocked, and then the kernel will effectively do non-blocking I/O for
* us by automatically writing out the contents of its send buffer while
* we are reading in the responses. In addition to TCP buffering we have
* to be aware of application-level buffering by the vstream module,
* which is limited to a couple kbytes.
*
* XXX Apparently, the getsockopt() call causes trouble with UNIX-domain
* sockets. Don't worry about command pipelining for local connections,
* because they benefit little from pipelining.
*/
if (state->features & LMTP_FEATURE_PIPELINING) {
state->sndbufsize = 4 * 1024;
if (msg_verbose)
msg_info("Using LMTP PIPELINING, send buffer size is %d",
state->sndbufsize);
} else
state->sndbufsize = 0;
#ifdef USE_SASL_AUTH
if (var_lmtp_sasl_enable && (state->features & LMTP_FEATURE_AUTH))
return (lmtp_sasl_helo_login(state));
#endif
return (0);
}
/* lmtp_loop - the LMTP state machine */
static int lmtp_loop(LMTP_STATE *state, NOCLOBBER int send_state,
NOCLOBBER int recv_state)
{
char *myname = "lmtp_loop";
DELIVER_REQUEST *request = state->request;
LMTP_SESSION *session = state->session;
LMTP_RESP *resp;
RECIPIENT *rcpt;
VSTRING *next_command = vstring_alloc(100);
int *NOCLOBBER survivors = 0;
NOCLOBBER int next_state;
NOCLOBBER int next_rcpt;
NOCLOBBER int send_rcpt;
NOCLOBBER int recv_rcpt;
NOCLOBBER int nrcpt;
int except;
int rec_type;
NOCLOBBER int prev_type = 0;
NOCLOBBER int sndbuffree;
NOCLOBBER int mail_from_rejected;
NOCLOBBER int recv_dot;
/*
* Macros for readability. XXX Aren't LMTP addresses supposed to be case
* insensitive?
*/
#define REWRITE_ADDRESS(dst, src) do { \
if (*(src)) { \
quote_821_local(dst, src); \
} else { \
vstring_strcpy(dst, src); \
} \
} while (0)
#define RETURN(x) do { \
vstring_free(next_command); \
if (survivors) \
myfree((char *) survivors); \
return (x); \
} while (0)
#define SENDER_IS_AHEAD \
(recv_state < send_state || recv_rcpt != send_rcpt)
#define SENDER_IN_WAIT_STATE \
(send_state == LMTP_STATE_DOT || send_state == LMTP_STATE_LAST)
#define SENDING_MAIL \
(recv_state <= LMTP_STATE_DOT)
#define CANT_RSET_THIS_SESSION \
(state->features |= LMTP_FEATURE_RSET_REJECTED)
/*
* Pipelining support requires two loops: one loop for sending and one
* for receiving. Each loop has its own independent state. Most of the
* time the sender can run ahead of the receiver by as much as the TCP
* send buffer permits. There are only two places where the sender must
* wait for status information from the receiver: once after sending DATA
* and once after sending QUIT.
*
* The sender state advances until the TCP send buffer would overflow, or
* until the sender needs status information from the receiver. At that
* point the receiver starts processing responses. Once the receiver has
* caught up with the sender, the sender resumes sending commands. If the
* receiver detects a serious problem (MAIL FROM rejected, all RCPT TO
* commands rejected, DATA rejected) it forces the sender to abort the
* LMTP dialog with RSET.
*/
nrcpt = 0;
next_rcpt = send_rcpt = recv_rcpt = recv_dot = 0;
mail_from_rejected = 0;
sndbuffree = state->sndbufsize;
while (recv_state != LMTP_STATE_LAST) {
/*
* Build the next command.
*/
switch (send_state) {
/*
* Sanity check.
*/
default:
msg_panic("%s: bad sender state %d", myname, send_state);
/*
* Build the XFORWARD command. With properly sanitized
* information, the command length stays within the 512 byte
* command line length limit.
*/
case LMTP_STATE_XFORWARD_NAME_ADDR:
vstring_strcpy(next_command, XFORWARD_CMD);
if (state->features & LMTP_FEATURE_XFORWARD_NAME)
vstring_sprintf_append(next_command, " %s=%s",
XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
request->client_name : XFORWARD_UNAVAILABLE);
if (state->features & LMTP_FEATURE_XFORWARD_ADDR)
vstring_sprintf_append(next_command, " %s=%s",
XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
request->client_addr : XFORWARD_UNAVAILABLE);
if (lmtp_send_proto_helo)
next_state = LMTP_STATE_XFORWARD_PROTO_HELO;
else
next_state = LMTP_STATE_MAIL;
break;
case LMTP_STATE_XFORWARD_PROTO_HELO:
vstring_strcpy(next_command, XFORWARD_CMD);
if (state->features & LMTP_FEATURE_XFORWARD_PROTO)
vstring_sprintf_append(next_command, " %s=%s",
XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
request->client_proto : XFORWARD_UNAVAILABLE);
if (state->features & LMTP_FEATURE_XFORWARD_HELO)
vstring_sprintf_append(next_command, " %s=%s",
XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
request->client_helo : XFORWARD_UNAVAILABLE);
if (state->features & LMTP_FEATURE_XFORWARD_DOMAIN)
vstring_sprintf_append(next_command, " %s=%s", XFORWARD_DOMAIN,
DEL_REQ_ATTR_AVAIL(request->rewrite_context) == 0 ?
XFORWARD_UNAVAILABLE :
strcmp(request->rewrite_context, MAIL_ATTR_RWR_LOCAL) ?
XFORWARD_DOM_REMOTE : XFORWARD_DOM_LOCAL);
next_state = LMTP_STATE_MAIL;
break;
/*
* Build the MAIL FROM command.
*/
case LMTP_STATE_MAIL:
REWRITE_ADDRESS(state->scratch, request->sender);
vstring_sprintf(next_command, "MAIL FROM:<%s>",
vstring_str(state->scratch));
if (state->features & LMTP_FEATURE_SIZE) /* RFC 1652 */
vstring_sprintf_append(next_command, " SIZE=%lu",
request->data_size);
if (state->features & LMTP_FEATURE_8BITMIME) {
if (strcmp(request->encoding, MAIL_ATTR_ENC_8BIT) == 0)
vstring_strcat(next_command, " BODY=8BITMIME");
else if (strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) == 0)
vstring_strcat(next_command, " BODY=7BIT");
else if (strcmp(request->encoding, MAIL_ATTR_ENC_NONE) != 0)
msg_warn("%s: unknown content encoding: %s",
request->queue_id, request->encoding);
}
/*
* We authenticate the local MTA only, but not the sender.
*/
#ifdef USE_SASL_AUTH
if (var_lmtp_sasl_enable
&& (state->features & LMTP_FEATURE_AUTH)
&& state->sasl_passwd)
vstring_strcat(next_command, " AUTH=<>");
#endif
next_state = LMTP_STATE_RCPT;
break;
/*
* Build one RCPT TO command before we have seen the MAIL FROM
* response.
*/
case LMTP_STATE_RCPT:
rcpt = request->rcpt_list.info + send_rcpt;
REWRITE_ADDRESS(state->scratch, rcpt->address);
vstring_sprintf(next_command, "RCPT TO:<%s>",
vstring_str(state->scratch));
if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
LMTP_STATE_RSET : LMTP_STATE_DATA;
break;
/*
* Build the DATA command before we have seen all the RCPT TO
* responses.
*/
case LMTP_STATE_DATA:
vstring_strcpy(next_command, "DATA");
next_state = LMTP_STATE_DOT;
break;
/*
* Build the "." command before we have seen the DATA response.
*/
case LMTP_STATE_DOT:
vstring_strcpy(next_command, ".");
next_state = var_lmtp_cache_conn ?
LMTP_STATE_LAST : LMTP_STATE_QUIT;
break;
/*
* Can't happen. The LMTP_STATE_ABORT sender state is entered by
* the receiver and is left before the bottom of the main loop.
*/
case LMTP_STATE_ABORT:
msg_panic("%s: sender abort state", myname);
/*
* Build the RSET command. This is used between pipelined
* deliveries, and to abort a trace-only delivery request.
*/
case LMTP_STATE_RSET:
vstring_strcpy(next_command, "RSET");
next_state = LMTP_STATE_LAST;
break;
/*
* Build the QUIT command.
*/
case LMTP_STATE_QUIT:
vstring_strcpy(next_command, "QUIT");
next_state = LMTP_STATE_LAST;
break;
/*
* The final sender state has no action associated with it.
*/
case LMTP_STATE_LAST:
VSTRING_RESET(next_command);
break;
}
VSTRING_TERMINATE(next_command);
/*
* Process responses until the receiver has caught up. Vstreams
* automatically flush buffered output when reading new data.
*
* Flush unsent output if command pipelining is off or if no I/O
* happened for a while. This limits the accumulation of client-side
* delays in pipelined sessions.
*/
if (SENDER_IN_WAIT_STATE
|| (SENDER_IS_AHEAD
&& (VSTRING_LEN(next_command) + 2 > sndbuffree
|| time((time_t *) 0) - vstream_ftime(session->stream) > 10))) {
while (SENDER_IS_AHEAD) {
/*
* Sanity check.
*/
if (recv_state < LMTP_STATE_XFORWARD_NAME_ADDR
|| recv_state > LMTP_STATE_QUIT)
msg_panic("%s: bad receiver state %d (sender state %d)",
myname, recv_state, send_state);
/*
* Receive the next server response. Use the proper timeout,
* and log the proper client state in case of trouble.
*/
smtp_timeout_setup(state->session->stream,
*xfer_timeouts[recv_state]);
if ((except = vstream_setjmp(state->session->stream)) != 0)
RETURN(SENDING_MAIL ? lmtp_stream_except(state, except,
xfer_states[recv_state]) : -1);
resp = lmtp_chat_resp(state);
/*
* Process the response.
*/
switch (recv_state) {
/*
* Process the XFORWARD response.
*/
case LMTP_STATE_XFORWARD_NAME_ADDR:
if (resp->code / 100 != 2)
msg_warn("host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_XFORWARD_NAME_ADDR]);
if (lmtp_send_proto_helo)
recv_state = LMTP_STATE_XFORWARD_PROTO_HELO;
else
recv_state = LMTP_STATE_MAIL;
break;
case LMTP_STATE_XFORWARD_PROTO_HELO:
if (resp->code / 100 != 2)
msg_warn("host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_XFORWARD_PROTO_HELO]);
recv_state = LMTP_STATE_MAIL;
break;
/*
* Process the MAIL FROM response. When the server
* rejects the sender, set the mail_from_rejected flag so
* that the receiver may apply a course correction.
*/
case LMTP_STATE_MAIL:
if (resp->code / 100 != 2) {
lmtp_mesg_fail(state, resp->code,
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_MAIL]);
mail_from_rejected = 1;
}
recv_state = LMTP_STATE_RCPT;
break;
/*
* Process one RCPT TO response. If MAIL FROM was
* rejected, ignore RCPT TO responses: all recipients are
* dead already. When all recipients are rejected the
* receiver may apply a course correction.
*
* XXX 2821: Section 4.5.3.1 says that a 552 RCPT TO reply
* must be treated as if the server replied with 452.
* However, this causes "too much mail data" to be
* treated as a recoverable error, which is wrong. I'll
* stick with RFC 821.
*/
case LMTP_STATE_RCPT:
if (!mail_from_rejected) {
#ifdef notdef
if (resp->code == 552)
resp->code = 452;
#endif
rcpt = request->rcpt_list.info + recv_rcpt;
if (resp->code / 100 == 2) {
if (survivors == 0)
survivors = (int *)
mymalloc(request->rcpt_list.len
* sizeof(int));
survivors[nrcpt++] = recv_rcpt;
/* If trace-only, mark the recipient done. */
if (DEL_REQ_TRACE_ONLY(request->flags)
&& sent(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, rcpt->orig_addr,
rcpt->address, rcpt->offset,
session->namaddr, request->arrival_time,
"%s",
translit(resp->str, "\n", " ")) == 0) {
if (request->flags & DEL_REQ_FLAG_SUCCESS)
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0; /* in case deferred */
}
} else {
lmtp_rcpt_fail(state, resp->code, rcpt,
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_RCPT]);
rcpt->offset = 0; /* in case deferred */
}
}
/* If trace-only, send RSET instead of DATA. */
if (++recv_rcpt == request->rcpt_list.len)
recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
LMTP_STATE_ABORT : LMTP_STATE_DATA;
break;
/*
* Process the DATA response. When the server rejects
* DATA, set nrcpt to a negative value so that the
* receiver can apply a course correction.
*/
case LMTP_STATE_DATA:
if (resp->code / 100 != 3) {
if (nrcpt > 0)
lmtp_mesg_fail(state, resp->code,
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_DATA]);
nrcpt = -1;
}
recv_state = LMTP_STATE_DOT;
break;
/*
* Process the end of message response. Ignore the
* response when no recipient was accepted: all
* recipients are dead already, and the next receiver
* state is LMTP_STATE_LAST regardless. Otherwise, if the
* message transfer fails, bounce all remaining
* recipients, else cross off the recipients that were
* delivered.
*/
case LMTP_STATE_DOT:
if (nrcpt > 0) {
rcpt = request->rcpt_list.info + survivors[recv_dot];
if (resp->code / 100 == 2) {
if (rcpt->offset) {
if (sent(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id, rcpt->orig_addr,
rcpt->address, rcpt->offset,
session->namaddr,
request->arrival_time,
"%s", resp->str) == 0) {
if (request->flags & DEL_REQ_FLAG_SUCCESS)
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
}
}
} else {
lmtp_rcpt_fail(state, resp->code, rcpt,
"host %s said: %s (in reply to %s)",
session->namaddr,
translit(resp->str, "\n", " "),
xfer_request[LMTP_STATE_DOT]);
rcpt->offset = 0; /* in case deferred */
}
}
/*
* We get one response per valid RCPT TO:
*/
if (msg_verbose)
msg_info("%s: recv_dot = %d", myname, recv_dot);
if (++recv_dot >= nrcpt) {
if (msg_verbose)
msg_info("%s: finished . command", myname);
recv_state = var_lmtp_skip_quit_resp || var_lmtp_cache_conn ?
LMTP_STATE_LAST : LMTP_STATE_QUIT;
}
break;
/*
* Ignore the RSET response.
*/
case LMTP_STATE_ABORT:
recv_state = var_lmtp_skip_quit_resp || var_lmtp_cache_conn ?
LMTP_STATE_LAST : LMTP_STATE_QUIT;
break;
/*
* Ignore the RSET response.
*/
case LMTP_STATE_RSET:
if (resp->code / 100 != 2)
CANT_RSET_THIS_SESSION;
recv_state = LMTP_STATE_LAST;
break;
/*
* Ignore the QUIT response.
*/
case LMTP_STATE_QUIT:
recv_state = LMTP_STATE_LAST;
break;
}
}
/*
* At this point, the sender and receiver are fully synchronized,
* so that the entire TCP send buffer becomes available again.
*/
sndbuffree = state->sndbufsize;
/*
* We know the server response to every command that was sent.
* Apply a course correction if necessary: the sender wants to
* send RCPT TO but MAIL FROM was rejected; the sender wants to
* send DATA but all recipients were rejected; the sender wants
* to deliver the message but DATA was rejected.
*/
if ((send_state == LMTP_STATE_RCPT && mail_from_rejected)
|| (send_state == LMTP_STATE_DATA && nrcpt == 0)
|| (send_state == LMTP_STATE_DOT && nrcpt < 0)) {
send_state = recv_state = LMTP_STATE_ABORT;
send_rcpt = recv_rcpt = 0;
vstring_strcpy(next_command, "RSET");
next_state = var_lmtp_cache_conn ?
LMTP_STATE_LAST : LMTP_STATE_QUIT;
next_rcpt = 0;
}
}
/*
* Make the next sender state the current sender state.
*/
if (send_state == LMTP_STATE_LAST)
continue;
/*
* Special case if the server accepted the DATA command. If the
* server accepted at least one recipient send the entire message.
* Otherwise, just send "." as per RFC 2197.
*/
if (send_state == LMTP_STATE_DOT && nrcpt > 0) {
smtp_timeout_setup(state->session->stream,
var_lmtp_data1_tmout);
if ((except = vstream_setjmp(state->session->stream)) != 0)
RETURN(lmtp_stream_except(state, except,
"sending message body"));
if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
msg_fatal("seek queue file: %m");
while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
break;
if (prev_type != REC_TYPE_CONT)
if (vstring_str(state->scratch)[0] == '.')
smtp_fputc('.', session->stream);
if (rec_type == REC_TYPE_CONT)
smtp_fwrite(vstring_str(state->scratch),
VSTRING_LEN(state->scratch),
session->stream);
else
smtp_fputs(vstring_str(state->scratch),
VSTRING_LEN(state->scratch),
session->stream);
prev_type = rec_type;
}
if (prev_type == REC_TYPE_CONT) /* missing newline at end */
smtp_fputs("", 0, session->stream);
if (vstream_ferror(state->src))
msg_fatal("queue file read error");
if (rec_type != REC_TYPE_XTRA) {
msg_warn("%s: bad record type: %d in message content",
request->queue_id, rec_type);
RETURN(mark_corrupt(state->src));
}
}
/*
* Copy the next command to the buffer and update the sender state.
*/
if (sndbuffree > 0)
sndbuffree -= VSTRING_LEN(next_command) + 2;
lmtp_chat_cmd(state, "%s", vstring_str(next_command));
send_state = next_state;
send_rcpt = next_rcpt;
}
RETURN(0);
}
/* lmtp_xfer - send a batch of envelope information and the message data */
int lmtp_xfer(LMTP_STATE *state)
{
DELIVER_REQUEST *request = state->request;
int start;
int send_name_addr;
/*
* Use the XFORWARD command to forward client attributes only when a
* minimal amount of information is available.
*/
send_name_addr =
var_lmtp_send_xforward
&& (((state->features & LMTP_FEATURE_XFORWARD_NAME)
&& DEL_REQ_ATTR_AVAIL(request->client_name))
|| ((state->features & LMTP_FEATURE_XFORWARD_ADDR)
&& DEL_REQ_ATTR_AVAIL(request->client_addr)));
lmtp_send_proto_helo =
var_lmtp_send_xforward
&& (((state->features & LMTP_FEATURE_XFORWARD_PROTO)
&& DEL_REQ_ATTR_AVAIL(request->client_proto))
|| ((state->features & LMTP_FEATURE_XFORWARD_HELO)
&& DEL_REQ_ATTR_AVAIL(request->client_helo)));
if (send_name_addr)
start = LMTP_STATE_XFORWARD_NAME_ADDR;
else if (lmtp_send_proto_helo)
start = LMTP_STATE_XFORWARD_PROTO_HELO;
else
start = LMTP_STATE_MAIL;
return (lmtp_loop(state, start, start));
}
/* lmtp_rset - send a lone RSET command and wait for response */
int lmtp_rset(LMTP_STATE *state)
{
return (lmtp_loop(state, LMTP_STATE_RSET, LMTP_STATE_RSET));
}
/* lmtp_quit - send a lone QUIT command */
int lmtp_quit(LMTP_STATE *state)
{
return (lmtp_loop(state, LMTP_STATE_QUIT, var_lmtp_skip_quit_resp ?
LMTP_STATE_LAST : LMTP_STATE_QUIT));
}

View File

@ -1,41 +0,0 @@
/* $NetBSD: lmtp_sasl.h,v 1.1.1.3 2004/05/31 00:24:36 heas Exp $ */
/*++
/* NAME
/* lmtp_sasl 3h
/* SUMMARY
/* Postfix SASL interface for LMTP client
/* SYNOPSIS
/* #include "lmtp_sasl.h"
/* DESCRIPTION
/* .nf
/*
* SASL protocol functions
*/
extern void lmtp_sasl_initialize(void);
extern void lmtp_sasl_connect(LMTP_STATE *);
extern int lmtp_sasl_passwd_lookup(LMTP_STATE *);
extern void lmtp_sasl_start(LMTP_STATE *, const char *, const char *);
extern int lmtp_sasl_authenticate(LMTP_STATE *, VSTRING *);
extern void lmtp_sasl_cleanup(LMTP_STATE *);
extern void lmtp_sasl_helo_auth(LMTP_STATE *, const char *);
extern int lmtp_sasl_helo_login(LMTP_STATE *);
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Initial implementation by:
/* Till Franke
/* SuSE Rhein/Main AG
/* 65760 Eschborn, Germany
/*
/* Adopted by:
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/

View File

@ -1,578 +0,0 @@
/* $NetBSD: lmtp_sasl_glue.c,v 1.1.1.6 2005/08/18 21:07:21 rpaulo Exp $ */
/*++
/* NAME
/* lmtp_sasl 3
/* SUMMARY
/* Postfix SASL interface for LMTP client
/* SYNOPSIS
/* #include lmtp_sasl.h
/*
/* void lmtp_sasl_initialize()
/*
/* void lmtp_sasl_connect(state)
/* LMTP_STATE *state;
/*
/* void lmtp_sasl_start(state, sasl_opts_name, sasl_opts_val)
/* LMTP_STATE *state;
/*
/* int lmtp_sasl_passwd_lookup(state)
/* LMTP_STATE *state;
/*
/* int lmtp_sasl_authenticate(state, why)
/* LMTP_STATE *state;
/* VSTRING *why;
/*
/* void lmtp_sasl_cleanup(state)
/* LMTP_STATE *state;
/* DESCRIPTION
/* lmtp_sasl_initialize() initializes the SASL library. This
/* routine must be called once at process startup, before any
/* chroot operations.
/*
/* lmtp_sasl_connect() performs per-session initialization. This
/* routine must be called once at the start of each connection.
/*
/* lmtp_sasl_start() performs per-session initialization. This
/* routine must be called once per session before doing any SASL
/* authentication. The sasl_opts_name and sasl_opts_val parameters are
/* the postfix configuration parameters setting the security
/* policy of the SASL authentication.
/*
/* lmtp_sasl_passwd_lookup() looks up the username/password
/* for the current LMTP server. The result is zero in case
/* of failure.
/*
/* lmtp_sasl_authenticate() implements the SASL authentication
/* dialog. The result is < 0 in case of protocol failure, zero in
/* case of unsuccessful authentication, > 0 in case of success.
/* The why argument is updated with a reason for failure.
/* This routine must be called only when lmtp_sasl_passwd_lookup()
/* suceeds.
/*
/* lmtp_sasl_cleanup() cleans up. It must be called at the
/* end of every LMTP session that uses SASL authentication.
/* This routine is a noop for non-SASL sessions.
/*
/* Arguments:
/* .IP state
/* Session context.
/* .IP mech_list
/* String of SASL mechanisms (separated by blanks)
/* DIAGNOSTICS
/* All errors are fatal.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Original author:
/* Till Franke
/* SuSE Rhein/Main AG
/* 65760 Eschborn, Germany
/*
/* Adopted by:
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/*
* System library.
*/
#include <sys_defs.h>
#include <stdlib.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/*
* Utility library
*/
#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
#include <split_at.h>
#include <name_mask.h>
/*
* Global library
*/
#include <mail_params.h>
#include <string_list.h>
#include <maps.h>
/*
* Application-specific
*/
#include "lmtp.h"
#include "lmtp_sasl.h"
#ifdef USE_SASL_AUTH
/*
* Authentication security options.
*/
static NAME_MASK lmtp_sasl_sec_mask[] = {
"noplaintext", SASL_SEC_NOPLAINTEXT,
"noactive", SASL_SEC_NOACTIVE,
"nodictionary", SASL_SEC_NODICTIONARY,
"noanonymous", SASL_SEC_NOANONYMOUS,
#if SASL_VERSION_MAJOR >= 2
"mutual_auth", SASL_SEC_MUTUAL_AUTH,
#endif
0,
};
/*
* Silly little macros.
*/
#define STR(x) vstring_str(x)
/*
* Macros to handle API differences between SASLv1 and SASLv2. Specifics:
*
* The SASL_LOG_* constants were renamed in SASLv2.
*
* SASLv2's sasl_client_new takes two new parameters to specify local and
* remote IP addresses for auth mechs that use them.
*
* SASLv2's sasl_client_start function no longer takes the secret parameter.
*
* SASLv2's sasl_decode64 function takes an extra parameter for the length of
* the output buffer.
*
* The other major change is that SASLv2 now takes more responsibility for
* deallocating memory that it allocates internally. Thus, some of the
* function parameters are now 'const', to make sure we don't try to free
* them too. This is dealt with in the code later on.
*/
#if SASL_VERSION_MAJOR < 2
/* SASL version 1.x */
#define SASL_LOG_WARN SASL_LOG_WARNING
#define SASL_LOG_NOTE SASL_LOG_INFO
#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
sasl_client_new(srv, fqdn, prompt, secflags, pconn)
#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
sasl_client_start(conn, mechlst, secret, prompt, clout, cllen, mech)
#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
sasl_decode64(in, inlen, out, outlen)
#endif
#if SASL_VERSION_MAJOR >= 2
/* SASL version > 2.x */
#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
sasl_client_new(srv, fqdn, lport, rport, prompt, secflags, pconn)
#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
sasl_client_start(conn, mechlst, prompt, clout, cllen, mech)
#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
sasl_decode64(in, inlen, out, outmaxlen, outlen)
#endif
/*
* Per-host login/password information.
*/
static MAPS *lmtp_sasl_passwd_map;
/* lmtp_sasl_log - logging call-back routine */
static int lmtp_sasl_log(void *unused_context, int priority,
const char *message)
{
switch (priority) {
case SASL_LOG_ERR: /* unusual errors */
case SASL_LOG_WARN: /* non-fatal warnings */
msg_warn("SASL authentication problem: %s", message);
break;
case SASL_LOG_NOTE: /* other info */
if (msg_verbose)
msg_info("SASL authentication info: %s", message);
break;
#if SASL_VERSION_MAJOR >= 2
case SASL_LOG_FAIL: /* authentication failures */
msg_warn("SASL authentication failure: %s", message);
#endif
}
return (SASL_OK);
}
/* lmtp_sasl_get_user - username lookup call-back routine */
static int lmtp_sasl_get_user(void *context, int unused_id, const char **result,
unsigned *len)
{
char *myname = "lmtp_sasl_get_user";
LMTP_STATE *state = (LMTP_STATE *) context;
if (msg_verbose)
msg_info("%s: %s", myname, state->sasl_username);
/*
* Sanity check.
*/
if (state->sasl_passwd == 0)
msg_panic("%s: no username looked up", myname);
*result = state->sasl_username;
if (len)
*len = strlen(state->sasl_username);
return (SASL_OK);
}
/* lmtp_sasl_get_passwd - password lookup call-back routine */
static int lmtp_sasl_get_passwd(sasl_conn_t *conn, void *context,
int id, sasl_secret_t **psecret)
{
char *myname = "lmtp_sasl_get_passwd";
LMTP_STATE *state = (LMTP_STATE *) context;
int len;
if (msg_verbose)
msg_info("%s: %s", myname, state->sasl_passwd);
/*
* Sanity check.
*/
if (!conn || !psecret || id != SASL_CB_PASS)
return (SASL_BADPARAM);
if (state->sasl_passwd == 0)
msg_panic("%s: no password looked up", myname);
/*
* Convert the password into a counted string.
*/
len = strlen(state->sasl_passwd);
if ((*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len)) == 0)
return (SASL_NOMEM);
(*psecret)->len = len;
memcpy((*psecret)->data, state->sasl_passwd, len + 1);
return (SASL_OK);
}
/* lmtp_sasl_passwd_lookup - password lookup routine */
int lmtp_sasl_passwd_lookup(LMTP_STATE *state)
{
char *myname = "lmtp_sasl_passwd_lookup";
const char *value;
char *passwd;
/*
* Sanity check.
*/
if (lmtp_sasl_passwd_map == 0)
msg_panic("%s: passwd map not initialized", myname);
/*
* Look up the per-server password information. Try the hostname first,
* then try the destination.
*/
if ((value = maps_find(lmtp_sasl_passwd_map, state->session->host, 0)) != 0
|| (value = maps_find(lmtp_sasl_passwd_map, state->request->nexthop, 0)) != 0) {
state->sasl_username = mystrdup(value);
passwd = split_at(state->sasl_username, ':');
state->sasl_passwd = mystrdup(passwd ? passwd : "");
if (msg_verbose)
msg_info("%s: host `%s' user `%s' pass `%s'",
myname, state->session->host,
state->sasl_username, state->sasl_passwd);
return (1);
} else {
if (msg_verbose)
msg_info("%s: host `%s' no auth info found",
myname, state->session->host);
return (0);
}
}
/* lmtp_sasl_initialize - per-process initialization (pre jail) */
void lmtp_sasl_initialize(void)
{
/*
* Global callbacks. These have no per-session context.
*/
static sasl_callback_t callbacks[] = {
{SASL_CB_LOG, &lmtp_sasl_log, 0},
{SASL_CB_LIST_END, 0, 0}
};
/*
* Sanity check.
*/
if (lmtp_sasl_passwd_map)
msg_panic("lmtp_sasl_initialize: repeated call");
if (*var_lmtp_sasl_passwd == 0)
msg_fatal("specify a password table via the `%s' configuration parameter",
VAR_LMTP_SASL_PASSWD);
/*
* Open the per-host password table and initialize the SASL library. Use
* shared locks for reading, just in case someone updates the table.
*/
lmtp_sasl_passwd_map = maps_create("lmtp_sasl_passwd",
var_lmtp_sasl_passwd, DICT_FLAG_LOCK);
if (sasl_client_init(callbacks) != SASL_OK)
msg_fatal("SASL library initialization");
}
/* lmtp_sasl_connect - per-session client initialization */
void lmtp_sasl_connect(LMTP_STATE *state)
{
state->sasl_mechanism_list = 0;
state->sasl_username = 0;
state->sasl_passwd = 0;
state->sasl_conn = 0;
state->sasl_encoded = 0;
state->sasl_decoded = 0;
state->sasl_callbacks = 0;
}
/* lmtp_sasl_start - per-session SASL initialization */
void lmtp_sasl_start(LMTP_STATE *state, const char *sasl_opts_name,
const char *sasl_opts_val)
{
static sasl_callback_t callbacks[] = {
{SASL_CB_USER, &lmtp_sasl_get_user, 0},
{SASL_CB_AUTHNAME, &lmtp_sasl_get_user, 0},
{SASL_CB_PASS, &lmtp_sasl_get_passwd, 0},
{SASL_CB_LIST_END, 0, 0}
};
sasl_callback_t *cp;
sasl_security_properties_t sec_props;
if (msg_verbose)
msg_info("starting new SASL client");
/*
* Per-session initialization. Provide each session with its own callback
* context.
*/
#define NULL_SECFLAGS 0
state->sasl_callbacks = (sasl_callback_t *) mymalloc(sizeof(callbacks));
memcpy((char *) state->sasl_callbacks, callbacks, sizeof(callbacks));
for (cp = state->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
cp->context = (void *) state;
#define NULL_SERVER_ADDR ((char *) 0)
#define NULL_CLIENT_ADDR ((char *) 0)
if (SASL_CLIENT_NEW("lmtp", state->session->host,
NULL_CLIENT_ADDR, NULL_SERVER_ADDR,
state->sasl_callbacks, NULL_SECFLAGS,
(sasl_conn_t **) &state->sasl_conn) != SASL_OK)
msg_fatal("per-session SASL client initialization");
/*
* Per-session security properties. XXX This routine is not sufficiently
* documented. What is the purpose of all this?
*/
memset(&sec_props, 0L, sizeof(sec_props));
sec_props.min_ssf = 0;
sec_props.max_ssf = 0; /* don't allow real SASL
* security layer */
sec_props.security_flags = name_mask(sasl_opts_name, lmtp_sasl_sec_mask,
sasl_opts_val);
sec_props.maxbufsize = 0;
sec_props.property_names = 0;
sec_props.property_values = 0;
if (sasl_setprop(state->sasl_conn, SASL_SEC_PROPS,
&sec_props) != SASL_OK)
msg_fatal("set per-session SASL security properties");
/*
* We use long-lived conversion buffers rather than local variables in
* order to avoid memory leaks in case of read/write timeout or I/O
* error.
*/
state->sasl_encoded = vstring_alloc(10);
state->sasl_decoded = vstring_alloc(10);
}
/* lmtp_sasl_authenticate - run authentication protocol */
int lmtp_sasl_authenticate(LMTP_STATE *state, VSTRING *why)
{
char *myname = "lmtp_sasl_authenticate";
unsigned enc_length;
unsigned enc_length_out;
#if SASL_VERSION_MAJOR >= 2
const char *clientout;
#else
char *clientout;
#endif
unsigned clientoutlen;
unsigned serverinlen;
LMTP_RESP *resp;
const char *mechanism;
int result;
char *line;
#define NO_SASL_SECRET 0
#define NO_SASL_INTERACTION 0
#define NO_SASL_LANGLIST ((const char *) 0)
#define NO_SASL_OUTLANG ((const char **) 0)
if (msg_verbose)
msg_info("%s: %s: SASL mechanisms %s",
myname, state->session->namaddr, state->sasl_mechanism_list);
/*
* Start the client side authentication protocol.
*/
result = SASL_CLIENT_START((sasl_conn_t *) state->sasl_conn,
state->sasl_mechanism_list,
NO_SASL_SECRET, NO_SASL_INTERACTION,
&clientout, &clientoutlen, &mechanism);
if (result != SASL_OK && result != SASL_CONTINUE) {
vstring_sprintf(why, "cannot SASL authenticate to server %s: %s",
state->session->namaddr,
sasl_errstring(result, NO_SASL_LANGLIST,
NO_SASL_OUTLANG));
return (-1);
}
/*
* Send the AUTH command and the optional initial client response.
* sasl_encode64() produces four bytes for each complete or incomplete
* triple of input bytes. Allocate an extra byte for string termination.
*/
#define ENCODE64_LENGTH(n) ((((n) + 2) / 3) * 4)
if (clientoutlen > 0) {
if (msg_verbose)
msg_info("%s: %s: uncoded initial reply: %.*s",
myname, state->session->namaddr,
(int) clientoutlen, clientout);
enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
VSTRING_SPACE(state->sasl_encoded, enc_length);
if (sasl_encode64(clientout, clientoutlen,
STR(state->sasl_encoded), enc_length,
&enc_length_out) != SASL_OK)
msg_panic("%s: sasl_encode64 botch", myname);
#if SASL_VERSION_MAJOR < 2
/* SASL version 1 doesn't free memory that it allocates. */
free(clientout);
#endif
lmtp_chat_cmd(state, "AUTH %s %s", mechanism, STR(state->sasl_encoded));
} else {
lmtp_chat_cmd(state, "AUTH %s", mechanism);
}
/*
* Step through the authentication protocol until the server tells us
* that we are done.
*/
while ((resp = lmtp_chat_resp(state))->code / 100 == 3) {
/*
* Process a server challenge.
*/
line = resp->str;
(void) mystrtok(&line, "- \t\n"); /* skip over result code */
serverinlen = strlen(line);
VSTRING_SPACE(state->sasl_decoded, serverinlen);
if (SASL_DECODE64(line, serverinlen, STR(state->sasl_decoded),
serverinlen, &enc_length) != SASL_OK) {
vstring_sprintf(why, "malformed SASL challenge from server %s",
state->session->namaddr);
return (-1);
}
if (msg_verbose)
msg_info("%s: %s: decoded challenge: %.*s",
myname, state->session->namaddr,
(int) enc_length, STR(state->sasl_decoded));
result = sasl_client_step((sasl_conn_t *) state->sasl_conn,
STR(state->sasl_decoded), enc_length,
NO_SASL_INTERACTION, &clientout, &clientoutlen);
if (result != SASL_OK && result != SASL_CONTINUE)
msg_warn("SASL authentication failed to server %s: %s",
state->session->namaddr,
sasl_errstring(result, NO_SASL_LANGLIST,
NO_SASL_OUTLANG));
/*
* Send a client response.
*/
if (clientoutlen > 0) {
if (msg_verbose)
msg_info("%s: %s: uncoded client response %.*s",
myname, state->session->namaddr,
(int) clientoutlen, clientout);
enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
VSTRING_SPACE(state->sasl_encoded, enc_length);
if (sasl_encode64(clientout, clientoutlen,
STR(state->sasl_encoded), enc_length,
&enc_length_out) != SASL_OK)
msg_panic("%s: sasl_encode64 botch", myname);
#if SASL_VERSION_MAJOR < 2
/* SASL version 1 doesn't free memory that it allocates. */
free(clientout);
#endif
} else {
vstring_strcat(state->sasl_encoded, "");
}
lmtp_chat_cmd(state, "%s", STR(state->sasl_encoded));
}
/*
* We completed the authentication protocol.
*/
if (resp->code / 100 != 2) {
vstring_sprintf(why, "SASL authentication failed; server %s said: %s",
state->session->namaddr, resp->str);
return (0);
}
return (1);
}
/* lmtp_sasl_cleanup - per-session cleanup */
void lmtp_sasl_cleanup(LMTP_STATE *state)
{
if (state->sasl_username) {
myfree(state->sasl_username);
state->sasl_username = 0;
}
if (state->sasl_passwd) {
myfree(state->sasl_passwd);
state->sasl_passwd = 0;
}
if (state->sasl_mechanism_list) {
/* allocated in lmtp_sasl_helo_auth */
myfree(state->sasl_mechanism_list);
state->sasl_mechanism_list = 0;
}
if (state->sasl_conn) {
if (msg_verbose)
msg_info("disposing SASL state information");
sasl_dispose(&state->sasl_conn);
}
if (state->sasl_callbacks) {
myfree((char *) state->sasl_callbacks);
state->sasl_callbacks = 0;
}
if (state->sasl_encoded) {
vstring_free(state->sasl_encoded);
state->sasl_encoded = 0;
}
if (state->sasl_decoded) {
vstring_free(state->sasl_decoded);
state->sasl_decoded = 0;
}
}
#endif

View File

@ -1,128 +0,0 @@
/* $NetBSD: lmtp_sasl_proto.c,v 1.1.1.4 2004/05/31 00:24:36 heas Exp $ */
/*++
/* NAME
/* lmtp_sasl_proto 3
/* SUMMARY
/* Postfix SASL interface for LMTP client
/* SYNOPSIS
/* #include lmtp_sasl.h
/*
/* void lmtp_sasl_helo_auth(state, words)
/* LMTP_STATE *state;
/* const char *words;
/*
/* int lmtp_sasl_helo_login(state)
/* LMTP_STATE *state;
/* DESCRIPTION
/* This module contains random chunks of code that implement
/* the LMTP protocol interface for SASL negotiation. The goal
/* is to reduce clutter in the main LMTP client source code.
/*
/* lmtp_sasl_helo_auth() processes the AUTH option in the
/* LMTP server's LHLO response.
/*
/* lmtp_sasl_helo_login() authenticates the LMTP client to the
/* LMTP server, using the authentication mechanism information
/* given by the server. The result is a Postfix delivery status
/* code in case of trouble.
/*
/* Arguments:
/* .IP state
/* Session context.
/* .IP words
/* List of SASL authentication mechanisms (separated by blanks)
/* DIAGNOSTICS
/* All errors are fatal.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Original author:
/* Till Franke
/* SuSE Rhein/Main AG
/* 65760 Eschborn, Germany
/*
/* Adopted by:
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <string.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
/* Global library. */
#include <mail_params.h>
/* Application-specific. */
#include "lmtp.h"
#include "lmtp_sasl.h"
#ifdef USE_SASL_AUTH
/* lmtp_sasl_helo_auth - handle AUTH option in EHLO reply */
void lmtp_sasl_helo_auth(LMTP_STATE *state, const char *words)
{
/*
* XXX If the server offers a null list of authentication mechanisms,
* then pretend that the server doesn't support SASL authentication.
*/
if (state->sasl_mechanism_list) {
if (strcasecmp(state->sasl_mechanism_list, words) == 0)
return;
myfree(state->sasl_mechanism_list);
msg_warn("%s offered AUTH option multiple times",
state->session->namaddr);
state->sasl_mechanism_list = 0;
state->features &= ~LMTP_FEATURE_AUTH;
}
if (strlen(words) > 0) {
state->sasl_mechanism_list = mystrdup(words);
state->features |= LMTP_FEATURE_AUTH;
} else {
msg_warn("%s offered null AUTH mechanism list",
state->session->namaddr);
}
}
/* lmtp_sasl_helo_login - perform SASL login */
int lmtp_sasl_helo_login(LMTP_STATE *state)
{
VSTRING *why = vstring_alloc(10);
int ret = 0;
/*
* Skip authentication when no authentication info exists for this
* server, so that we talk to each other like strangers. Otherwise, if
* authentication information exists, assume that authentication is
* required, and assume that an authentication error is recoverable.
*/
if (lmtp_sasl_passwd_lookup(state) != 0) {
lmtp_sasl_start(state, VAR_LMTP_SASL_OPTS, var_lmtp_sasl_opts);
if (lmtp_sasl_authenticate(state, why) <= 0)
ret = lmtp_site_fail(state, 450, "Authentication failed: %s",
vstring_str(why));
}
vstring_free(why);
return (ret);
}
#endif

View File

@ -1,108 +0,0 @@
/* $NetBSD: lmtp_session.c,v 1.1.1.2 2004/05/31 00:24:36 heas Exp $ */
/*++
/* NAME
/* lmtp_session 3
/* SUMMARY
/* LMTP_SESSION structure management
/* SYNOPSIS
/* #include "lmtp.h"
/*
/* LMTP_SESSION *lmtp_session_alloc(stream, host, addr, dest, type)
/* VSTREAM *stream;
/* const char *host;
/* const char *addr;
/* const char *dest;
/* int type;
/*
/* LMTP_SESSION *lmtp_session_free(session)
/* LMTP_SESSION *session;
/* DESCRIPTION
/* This module maintains information about connections, including
/* per-peer debugging.
/*
/* lmtp_session_alloc() allocates memory for an LMTP_SESSION structure
/* and initializes it with the given stream and host name and address
/* information. The host name and address strings are copied.
/* The type argument specifies the transport type. The dest argument
/* specifies a string-valued name for the remote endpoint.
/* If the peer name or address matches the debug-peer_list configuration
/* parameter, the debugging level is incremented by the amount specified
/* in the debug_peer_level parameter.
/*
/* lmtp_session_free() destroys an LMTP_SESSION structure and its
/* members, making memory available for reuse. The result value is
/* convenient null pointer. The debugging level is restored to the
/* value prior to the lmtp_session_alloc() call.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* SEE ALSO
/* debug_peer(3), increase logging for selected peers
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <mymalloc.h>
#include <vstream.h>
#include <stringops.h>
/* Global library. */
#include <debug_peer.h>
/* Application-specific. */
#include "lmtp.h"
/* lmtp_session_alloc - allocate and initialize LMTP_SESSION structure */
LMTP_SESSION *lmtp_session_alloc(VSTREAM *stream, const char *host,
const char *addr, const char *dest)
{
LMTP_SESSION *session;
session = (LMTP_SESSION *) mymalloc(sizeof(*session));
session->stream = stream;
session->host = mystrdup(host);
session->addr = mystrdup(addr);
session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
session->dest = mystrdup(dest);
debug_peer_check(host, addr);
return (session);
}
/* lmtp_session_free - destroy LMTP_SESSION structure and contents */
LMTP_SESSION *lmtp_session_free(LMTP_SESSION *session)
{
debug_peer_restore();
vstream_fclose(session->stream);
myfree(session->host);
myfree(session->addr);
myfree(session->namaddr);
myfree(session->dest);
myfree((char *) session);
return (0);
}

View File

@ -1,100 +0,0 @@
/* $NetBSD: lmtp_state.c,v 1.1.1.3 2004/05/31 00:24:36 heas Exp $ */
/*++
/* NAME
/* lmtp_state 8
/* SUMMARY
/* initialize/cleanup shared state
/* SYNOPSIS
/* #include "lmtp.h"
/*
/* LMTP_STATE *lmtp_state_alloc()
/*
/* void lmtp_state_free(state)
/* LMTP_STATE *state;
/* DESCRIPTION
/* lmtp_state_init() initializes the shared state, and allocates
/* memory for buffers etc.
/*
/* lmtp_cleanup() destroys memory allocated by lmtp_state_init().
/* STANDARDS
/* DIAGNOSTICS
/* BUGS
/* SEE ALSO
/* 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
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
/* Utility library. */
#include <mymalloc.h>
#include <vstring.h>
#include <vstream.h>
/* Global library. */
#include <mail_conf.h>
/* Application-specific. */
#include "lmtp.h"
#include "lmtp_sasl.h"
/* lmtp_state_alloc - initialize */
LMTP_STATE *lmtp_state_alloc(void)
{
LMTP_STATE *state = (LMTP_STATE *) mymalloc(sizeof(*state));
state->src = 0;
state->request = 0;
state->session = 0;
state->buffer = vstring_alloc(100);
state->scratch = vstring_alloc(100);
state->scratch2 = vstring_alloc(100);
state->status = 0;
state->features = 0;
state->history = 0;
state->error_mask = 0;
#ifdef USE_SASL_AUTH
lmtp_sasl_connect(state);
#endif
state->sndbufsize = 0;
state->reuse = 0;
return (state);
}
/* lmtp_state_free - destroy state */
void lmtp_state_free(LMTP_STATE *state)
{
vstring_free(state->buffer);
vstring_free(state->scratch);
vstring_free(state->scratch2);
#ifdef USE_SASL_AUTH
lmtp_sasl_cleanup(state);
#endif
myfree((char *) state);
}

View File

@ -1,330 +0,0 @@
/* $NetBSD: lmtp_trouble.c,v 1.1.1.6 2005/12/01 21:44:26 rpaulo Exp $ */
/*++
/* NAME
/* lmtp_trouble 3
/* SUMMARY
/* error handler policies
/* SYNOPSIS
/* #include "lmtp.h"
/*
/* int lmtp_site_fail(state, code, format, ...)
/* LMTP_STATE *state;
/* int code;
/* char *format;
/*
/* int lmtp_mesg_fail(state, code, format, ...)
/* LMTP_STATE *state;
/* int code;
/* char *format;
/*
/* void lmtp_rcpt_fail(state, code, recipient, format, ...)
/* LMTP_STATE *state;
/* int code;
/* RECIPIENT *recipient;
/* char *format;
/*
/* int lmtp_stream_except(state, exception, description)
/* LMTP_STATE *state;
/* int exception;
/* char *description;
/* DESCRIPTION
/* This module handles all non-fatal errors that can happen while
/* attempting to deliver mail via LMTP, and implements the policy
/* of how to deal with the error. Depending on the nature of
/* the problem, delivery of a single message is deferred, delivery
/* of all messages to the same domain is deferred, or one or more
/* recipients are given up as non-deliverable and a bounce log is
/* updated.
/*
/* In addition, when an unexpected response code is seen such
/* as 3xx where only 4xx or 5xx are expected, or any error code
/* that suggests a syntax error or something similar, the
/* protocol error flag is set so that the postmaster receives
/* a transcript of the session. No notification is generated for
/* what appear to be configuration errors - very likely, they
/* would suffer the same problem and just cause more trouble.
/*
/* lmtp_site_fail() handles the case where the program fails to
/* complete the initial LMTP handshake: the server is not reachable,
/* is not running, does not want talk to us, or we talk to ourselves.
/* The \fIcode\fR gives an error status code; the \fIformat\fR
/* argument gives a textual description. The policy is: soft
/* error: defer delivery of all messages to this domain; hard
/* error: bounce all recipients of this message.
/* The result is non-zero.
/*
/* lmtp_mesg_fail() handles the case where the lmtp server
/* does not accept the sender address or the message data.
/* The policy is: soft errors: defer delivery of this message;
/* hard error: bounce all recipients of this message.
/* The result is non-zero.
/*
/* lmtp_rcpt_fail() handles the case where a recipient is not
/* accepted by the server for reasons other than that the server
/* recipient limit is reached. The policy is: soft error: defer
/* delivery to this recipient; hard error: bounce this recipient.
/*
/* lmtp_stream_except() handles the exceptions generated by
/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
/* The \fIexception\fR argument specifies the type of problem.
/* The \fIdescription\fR argument describes at what stage of
/* the LMTP dialog the problem happened. The policy is to defer
/* delivery of all messages to the same domain. The result is non-zero.
/* DIAGNOSTICS
/* Panic: unknown exception code.
/* SEE ALSO
/* lmtp_proto(3) lmtp high-level protocol
/* smtp_stream(3) lmtp low-level protocol
/* defer(3) basic message defer interface
/* bounce(3) basic message bounce interface
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Alterations for LMTP by:
/* Philip A. Prindeville
/* Mirapoint, Inc.
/* USA.
/*
/* Additional work on LMTP by:
/* Amos Gouaux
/* University of Texas at Dallas
/* P.O. Box 830688, MC34
/* Richardson, TX 75083, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
#include <stdarg.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <stringops.h>
#include <mymalloc.h>
/* Global library. */
#include <smtp_stream.h>
#include <deliver_request.h>
#include <deliver_completed.h>
#include <bounce.h>
#include <defer.h>
#include <mail_error.h>
/* Application-specific. */
#include "lmtp.h"
#define LMTP_SOFT(code) (((code) / 100) == 4)
#define LMTP_HARD(code) (((code) / 100) == 5)
/* lmtp_check_code - check response code */
static void lmtp_check_code(LMTP_STATE *state, int code)
{
/*
* The intention of this stuff is to alert the postmaster when the local
* Postfix LMTP client screws up, protocol wise. RFC 821 says that x0z
* replies "refer to syntax errors, syntactically correct commands that
* don't fit any functional category, and unimplemented or superfluous
* commands". Unfortunately, this also triggers postmaster notices when
* remote servers screw up, protocol wise. This is becoming a common
* problem now that response codes are configured manually as part of
* anti-UCE systems, by people who aren't aware of RFC details.
*/
if ((!LMTP_SOFT(code) && !LMTP_HARD(code))
|| code == 555 /* RFC 1869, section 6.1. */
|| (code >= 500 && code < 510))
state->error_mask |= MAIL_ERROR_PROTOCOL;
}
/* lmtp_site_fail - defer site or bounce recipients */
int lmtp_site_fail(LMTP_STATE *state, int code, char *format,...)
{
DELIVER_REQUEST *request = state->request;
LMTP_SESSION *session = state->session;
RECIPIENT *rcpt;
int status;
int nrcpt;
int soft_error = LMTP_SOFT(code);
va_list ap;
VSTRING *why = vstring_alloc(100);
/*
* Initialize.
*/
va_start(ap, format);
vstring_vsprintf(why, format, ap);
va_end(ap);
/*
* If this is a soft error, postpone further deliveries to this domain.
* Otherwise, generate a bounce record for each recipient.
*/
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
status = (soft_error ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
rcpt->orig_addr, rcpt->address, rcpt->offset,
session ? session->namaddr : "none",
request->arrival_time, "%s", vstring_str(why));
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
}
state->status |= status;
}
if (soft_error && request->hop_status == 0)
request->hop_status = mystrdup(vstring_str(why));
/*
* Cleanup.
*/
vstring_free(why);
return (-1);
}
/* lmtp_mesg_fail - defer message or bounce all recipients */
int lmtp_mesg_fail(LMTP_STATE *state, int code, char *format,...)
{
DELIVER_REQUEST *request = state->request;
LMTP_SESSION *session = state->session;
RECIPIENT *rcpt;
int status;
int nrcpt;
va_list ap;
VSTRING *why = vstring_alloc(100);
/*
* Initialize.
*/
va_start(ap, format);
vstring_vsprintf(why, format, ap);
va_end(ap);
/*
* If this is a soft error, postpone delivery of this message. Otherwise,
* generate a bounce record for each recipient.
*/
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
status = (LMTP_SOFT(code) ? defer_append : bounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
rcpt->orig_addr, rcpt->address, rcpt->offset,
session->namaddr, request->arrival_time,
"%s", vstring_str(why));
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
}
state->status |= status;
}
lmtp_check_code(state, code);
/*
* Cleanup.
*/
vstring_free(why);
return (-1);
}
/* lmtp_rcpt_fail - defer or bounce recipient */
void lmtp_rcpt_fail(LMTP_STATE *state, int code, RECIPIENT *rcpt,
char *format,...)
{
DELIVER_REQUEST *request = state->request;
LMTP_SESSION *session = state->session;
int status;
va_list ap;
/*
* If this is a soft error, postpone delivery to this recipient.
* Otherwise, generate a bounce record for this recipient.
*/
va_start(ap, format);
status = (LMTP_SOFT(code) ? vdefer_append : vbounce_append)
(DEL_REQ_TRACE_FLAGS(request->flags), request->queue_id,
rcpt->orig_addr, rcpt->address, rcpt->offset,
session->namaddr, request->arrival_time, format, ap);
va_end(ap);
if (status == 0) {
deliver_completed(state->src, rcpt->offset);
rcpt->offset = 0;
}
lmtp_check_code(state, code);
state->status |= status;
}
/* lmtp_stream_except - defer domain after I/O problem */
int lmtp_stream_except(LMTP_STATE *state, int code, char *description)
{
DELIVER_REQUEST *request = state->request;
LMTP_SESSION *session = state->session;
RECIPIENT *rcpt;
int nrcpt;
VSTRING *why = vstring_alloc(100);
/*
* Initialize.
*/
switch (code) {
default:
msg_panic("lmtp_stream_except: unknown exception %d", code);
case SMTP_ERR_EOF:
vstring_sprintf(why, "lost connection with %s while %s",
session->namaddr, description);
break;
case SMTP_ERR_TIME:
vstring_sprintf(why, "conversation with %s timed out while %s",
session->namaddr, description);
break;
case SMTP_ERR_PROTO:
vstring_sprintf(why, "remote protocol error in reply from %s while %s",
session->namaddr, description);
break;
}
/*
* At this point, the status of individual recipients remains unresolved.
* All we know is that we should stay away from this host for a while.
*/
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
rcpt = request->rcpt_list.info + nrcpt;
if (rcpt->offset == 0)
continue;
state->status |= defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
request->queue_id,
rcpt->orig_addr, rcpt->address,
rcpt->offset, session->namaddr,
request->arrival_time,
"%s", vstring_str(why));
}
if (request->hop_status == 0)
request->hop_status = mystrdup(vstring_str(why));
/*
* Cleanup.
*/
vstring_free(why);
return (-1);
}