~ubuntu-branches/ubuntu/saucy/postfix/saucy

« back to all changes in this revision

Viewing changes to src/postscreen/postscreen_starttls.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2011-02-22 11:20:43 UTC
  • mfrom: (1.1.27 upstream)
  • Revision ID: james.westby@ubuntu.com-20110222112043-c34ht219w3ybrilr
Tags: 2.8.0-2
* a little more lintian cleanup
* Fix missing format strings in smtp-sink.c

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      postscreen_starttls 3
 
4
/* SUMMARY
 
5
/*      postscreen TLS proxy support
 
6
/* SYNOPSIS
 
7
/*      #include <postscreen.h>
 
8
/*
 
9
/*      int     psc_starttls_open(state, resume_event)
 
10
/*      PSC_STATE *state;
 
11
/*      void    (*resume_event)(int unused_event, char *context);
 
12
/* DESCRIPTION
 
13
/*      This module inserts the tlsproxy(8) proxy between the
 
14
/*      postscreen(8) server and the remote SMTP client. The entire
 
15
/*      process happens in the background, including notification
 
16
/*      of completion to the remote SMTP client and to the calling
 
17
/*      application.
 
18
/*
 
19
/*      Before calling psc_starttls_open() the caller must turn off
 
20
/*      all pending timer and I/O event requests on the SMTP client
 
21
/*      stream.
 
22
/*
 
23
/*      psc_starttls_open() starts the first transaction in the
 
24
/*      tlsproxy(8) hand-off protocol, and sets up event handlers
 
25
/*      for the successive protocol stages.
 
26
/*
 
27
/*      Upon completion, the event handlers call resume_event()
 
28
/*      which must reset the SMTP helo/sender/etc. state when the
 
29
/*      PSC_STATE_FLAG_USING_TLS is set, and set up timer and read
 
30
/*      event requests to receive the next SMTP command.
 
31
/* LICENSE
 
32
/* .ad
 
33
/* .fi
 
34
/*      The Secure Mailer license must be distributed with this software.
 
35
/* AUTHOR(S)
 
36
/*      Wietse Venema
 
37
/*      IBM T.J. Watson Research
 
38
/*      P.O. Box 704
 
39
/*      Yorktown Heights, NY 10598, USA
 
40
/*--*/
 
41
 
 
42
/* System library. */
 
43
 
 
44
#include <sys_defs.h>
 
45
 
 
46
/* Utility library. */
 
47
 
 
48
#include <msg.h>
 
49
#include <mymalloc.h>
 
50
#include <connect.h>
 
51
#include <stringops.h>                  /* concatenate() */
 
52
#include <vstring.h>
 
53
 
 
54
/* Global library. */
 
55
 
 
56
#include <mail_params.h>
 
57
#include <mail_proto.h>
 
58
 
 
59
/* TLS library. */
 
60
 
 
61
#include <tls_proxy.h>
 
62
 
 
63
/* Application-specific. */
 
64
 
 
65
#include <postscreen.h>
 
66
 
 
67
 /*
 
68
  * For now, this code is built into the postscreen(8) daemon. In the future
 
69
  * it may be abstracted into a reusable library module for use by other
 
70
  * event-driven programs (perhaps smtp-source and smtp-sink).
 
71
  */
 
72
 
 
73
 /*
 
74
  * Transient state for the portscreen(8)-to-tlsproxy(8) hand-off protocol.
 
75
  */
 
76
typedef struct {
 
77
    VSTREAM *tlsproxy_stream;           /* hand-off negotiation */
 
78
    EVENT_NOTIFY_FN resume_event;       /* call-back handler */
 
79
    PSC_STATE *smtp_state;              /* SMTP session state */
 
80
} PSC_STARTTLS;
 
81
 
 
82
#define TLSPROXY_INIT_TIMEOUT           10
 
83
 
 
84
static char *psc_tlsp_service = 0;
 
85
 
 
86
/* psc_starttls_finish - complete negotiation with TLS proxy */
 
87
 
 
88
static void psc_starttls_finish(int event, char *context)
 
89
{
 
90
    const char *myname = "psc_starttls_finish";
 
91
    PSC_STARTTLS *starttls_state = (PSC_STARTTLS *) context;
 
92
    PSC_STATE *smtp_state = starttls_state->smtp_state;
 
93
    VSTREAM *tlsproxy_stream = starttls_state->tlsproxy_stream;
 
94
    int     status;
 
95
 
 
96
    if (msg_verbose)
 
97
        msg_info("%s: send client handle on proxy socket %d"
 
98
                 " for smtp socket %d from [%s]:%s flags=%s",
 
99
                 myname, vstream_fileno(tlsproxy_stream),
 
100
                 vstream_fileno(smtp_state->smtp_client_stream),
 
101
                 smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
 
102
                 psc_print_state_flags(smtp_state->flags, myname));
 
103
 
 
104
    /*
 
105
     * We leave read-event notification enabled on the postscreen to TLS
 
106
     * proxy stream, to avoid two kqueue/epoll/etc. system calls: one here,
 
107
     * and one when resuming the dummy SMTP engine.
 
108
     */
 
109
    if (event != EVENT_TIME)
 
110
        event_cancel_timer(psc_starttls_finish, (char *) starttls_state);
 
111
 
 
112
    /*
 
113
     * Receive the "TLS is available" indication.
 
114
     * 
 
115
     * This may seem out of order, but we must have a read transaction between
 
116
     * sending the request attributes and sending the SMTP client file
 
117
     * descriptor. We can't assume UNIX-domain socket semantics here.
 
118
     */
 
119
    if (event != EVENT_READ
 
120
        || attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT,
 
121
                     ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status,
 
122
                     ATTR_TYPE_END) != 1 || status == 0) {
 
123
 
 
124
        /*
 
125
         * The TLS proxy reports that the TLS engine is not available (due to
 
126
         * configuration error, or other causes).
 
127
         */
 
128
        event_disable_readwrite(vstream_fileno(tlsproxy_stream));
 
129
        vstream_fclose(tlsproxy_stream);
 
130
        PSC_SEND_REPLY(smtp_state,
 
131
                    "454 4.7.0 TLS not available due to local problem\r\n");
 
132
    }
 
133
 
 
134
    /*
 
135
     * Send the remote SMTP client file descriptor.
 
136
     */
 
137
    else if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream),
 
138
                      vstream_fileno(smtp_state->smtp_client_stream)) < 0) {
 
139
 
 
140
        /*
 
141
         * Some error: drop the TLS proxy stream.
 
142
         */
 
143
        msg_warn("%s sending file handle to %s service",
 
144
                 event == EVENT_TIME ? "timeout" : "problem",
 
145
                 psc_tlsp_service);
 
146
        event_disable_readwrite(vstream_fileno(tlsproxy_stream));
 
147
        vstream_fclose(tlsproxy_stream);
 
148
        PSC_SEND_REPLY(smtp_state,
 
149
                    "454 4.7.0 TLS not available due to local problem\r\n");
 
150
    }
 
151
 
 
152
    /*
 
153
     * After we send the plaintext 220 greeting, the client-side TLS engine
 
154
     * is supposed to talk first, then the server-side TLS engine. However,
 
155
     * postscreen(8) will not participate in that conversation.
 
156
     */
 
157
    else {
 
158
        PSC_SEND_REPLY(smtp_state, "220 2.0.0 Ready to start TLS\r\n");
 
159
 
 
160
        /*
 
161
         * Replace our SMTP client stream by the TLS proxy stream.  Once the
 
162
         * TLS handshake is done, the TLS proxy will deliver plaintext SMTP
 
163
         * commands to postscreen(8).
 
164
         * 
 
165
         * Swap the file descriptors from under the VSTREAM so that we don't
 
166
         * have to worry about loss of user-configurable VSTREAM attributes.
 
167
         */
 
168
        vstream_fpurge(smtp_state->smtp_client_stream, VSTREAM_PURGE_BOTH);
 
169
        vstream_control(smtp_state->smtp_client_stream,
 
170
                        VSTREAM_CTL_SWAP_FD, tlsproxy_stream,
 
171
                        VSTREAM_CTL_END);
 
172
        vstream_fclose(tlsproxy_stream);        /* direct-to-client stream! */
 
173
        smtp_state->flags |= PSC_STATE_FLAG_USING_TLS;
 
174
    }
 
175
 
 
176
    /*
 
177
     * Resume the postscreen(8) dummy SMTP engine and clean up.
 
178
     */
 
179
    starttls_state->resume_event(event, (char *) smtp_state);
 
180
    myfree((char *) starttls_state);
 
181
}
 
182
 
 
183
/* psc_starttls_open - open negotiations with TLS proxy */
 
184
 
 
185
void    psc_starttls_open(PSC_STATE *smtp_state, EVENT_NOTIFY_FN resume_event)
 
186
{
 
187
    const char *myname = "psc_starttls_open";
 
188
    PSC_STARTTLS *starttls_state;
 
189
    VSTREAM *tlsproxy_stream;
 
190
    int     fd;
 
191
    static VSTRING *remote_endpt = 0;
 
192
 
 
193
    if (psc_tlsp_service == 0) {
 
194
        psc_tlsp_service = concatenate(MAIL_CLASS_PRIVATE "/",
 
195
                                       var_tlsproxy_service, (char *) 0);
 
196
        remote_endpt = vstring_alloc(20);
 
197
    }
 
198
 
 
199
    /*
 
200
     * Connect to the tlsproxy(8) daemon. We report all errors
 
201
     * asynchronously, to avoid having to maintain multiple delivery paths.
 
202
     */
 
203
    if ((fd = LOCAL_CONNECT(psc_tlsp_service, NON_BLOCKING, 1)) < 0) {
 
204
        msg_warn("connect to %s service: %m", psc_tlsp_service);
 
205
        PSC_SEND_REPLY(smtp_state,
 
206
                    "454 4.7.0 TLS not available due to local problem\r\n");
 
207
        event_request_timer(resume_event, (char *) smtp_state, 0);
 
208
        return;
 
209
    }
 
210
    if (msg_verbose)
 
211
        msg_info("%s: send client name/address on proxy socket %d"
 
212
                 " for smtp socket %d from [%s]:%s flags=%s",
 
213
                 myname, fd, vstream_fileno(smtp_state->smtp_client_stream),
 
214
                 smtp_state->smtp_client_addr, smtp_state->smtp_client_port,
 
215
                 psc_print_state_flags(smtp_state->flags, myname));
 
216
 
 
217
    /*
 
218
     * Initial handshake. Send the data attributes now, and send the client
 
219
     * file descriptor in a later transaction. We report all errors
 
220
     * asynchronously, to avoid having to maintain multiple delivery paths.
 
221
     * 
 
222
     * XXX The formatted endpoint should be a state member. Then, we can
 
223
     * simplify all the format strings throughout the program.
 
224
     */
 
225
    tlsproxy_stream = vstream_fdopen(fd, O_RDWR);
 
226
    vstring_sprintf(remote_endpt, "[%s]:%s", smtp_state->smtp_client_addr,
 
227
                    smtp_state->smtp_client_port);
 
228
    attr_print(tlsproxy_stream, ATTR_FLAG_NONE,
 
229
               ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt),
 
230
               ATTR_TYPE_INT, MAIL_ATTR_FLAGS, TLS_PROXY_FLAG_ROLE_SERVER,
 
231
               ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, psc_normal_cmd_time_limit,
 
232
               ATTR_TYPE_END);
 
233
    if (vstream_fflush(tlsproxy_stream) != 0) {
 
234
        msg_warn("error sending request to %s service: %m", psc_tlsp_service);
 
235
        vstream_fclose(tlsproxy_stream);
 
236
        PSC_SEND_REPLY(smtp_state,
 
237
                    "454 4.7.0 TLS not available due to local problem\r\n");
 
238
        event_request_timer(resume_event, (char *) smtp_state, 0);
 
239
        return;
 
240
    }
 
241
 
 
242
    /*
 
243
     * Set up a read event for the next phase of the TLS proxy handshake.
 
244
     */
 
245
    starttls_state = (PSC_STARTTLS *) mymalloc(sizeof(*starttls_state));
 
246
    starttls_state->tlsproxy_stream = tlsproxy_stream;
 
247
    starttls_state->resume_event = resume_event;
 
248
    starttls_state->smtp_state = smtp_state;
 
249
    PSC_READ_EVENT_REQUEST(vstream_fileno(tlsproxy_stream), psc_starttls_finish,
 
250
                           (char *) starttls_state, TLSPROXY_INIT_TIMEOUT);
 
251
}