Not used by postfix 2.3.0. Removed due to conflict with postconf awk script.
This commit is contained in:
parent
ba10c8855d
commit
404ed95661
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
/*--*/
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
/*--*/
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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
|
||||
/*--*/
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue