~ubuntu-branches/ubuntu/dapper/postfix/dapper-security

« back to all changes in this revision

Viewing changes to src/smtp/smtp_proto.c

  • Committer: Bazaar Package Importer
  • Author(s): LaMont Jones
  • Date: 2005-02-27 09:33:07 UTC
  • Revision ID: james.westby@ubuntu.com-20050227093307-cn789t27ibnlh6tf
Tags: upstream-2.1.5
ImportĀ upstreamĀ versionĀ 2.1.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*++
 
2
/* NAME
 
3
/*      smtp_proto 3
 
4
/* SUMMARY
 
5
/*      client SMTP protocol
 
6
/* SYNOPSIS
 
7
/*      #include "smtp.h"
 
8
/*
 
9
/*      int     smtp_helo(state)
 
10
/*      SMTP_STATE *state;
 
11
/*
 
12
/*      int     smtp_xfer(state)
 
13
/*      SMTP_STATE *state;
 
14
/* DESCRIPTION
 
15
/*      This module implements the client side of the SMTP protocol.
 
16
/*
 
17
/*      smtp_helo() performs the initial handshake with the SMTP server.
 
18
/*
 
19
/*      smtp_xfer() sends message envelope information followed by the
 
20
/*      message data, and finishes the SMTP conversation. These operations
 
21
/*      are combined in one function, in order to implement SMTP pipelining.
 
22
/*      Recipients are marked as "done" in the mail queue file when
 
23
/*      bounced or delivered. The message delivery status is updated
 
24
/*      accordingly.
 
25
/* DIAGNOSTICS
 
26
/*      smtp_helo() and smtp_xfer() return 0 in case of success, -1 in case
 
27
/*      of failure. For smtp_xfer(), success means the ability to perform
 
28
/*      an SMTP conversation, not necessarily the ability to deliver mail.
 
29
/*
 
30
/*      Warnings: corrupt message file. A corrupt message is marked
 
31
/*      as "corrupt" by changing its queue file permissions.
 
32
/* BUGS
 
33
/*      Some SMTP servers will abort when the number of recipients
 
34
/*      for one message exceeds their capacity. This behavior violates
 
35
/*      the SMTP protocol.
 
36
/*      The only way around this is to limit the number of recipients
 
37
/*      per transaction to an artificially-low value.
 
38
/* SEE ALSO
 
39
/*      smtp(3h) internal data structures
 
40
/*      smtp_chat(3) query/reply SMTP support
 
41
/*      smtp_trouble(3) error handlers
 
42
/* LICENSE
 
43
/* .ad
 
44
/* .fi
 
45
/*      The Secure Mailer license must be distributed with this software.
 
46
/* AUTHOR(S)
 
47
/*      Wietse Venema
 
48
/*      IBM T.J. Watson Research
 
49
/*      P.O. Box 704
 
50
/*      Yorktown Heights, NY 10598, USA
 
51
/*
 
52
/*      Pipelining code in cooperation with:
 
53
/*      Jon Ribbens
 
54
/*      Oaktree Internet Solutions Ltd.,
 
55
/*      Internet House,
 
56
/*      Canal Basin,
 
57
/*      Coventry,
 
58
/*      CV1 4LY, United Kingdom.
 
59
/*
 
60
/*--*/
 
61
 
 
62
/* System library. */
 
63
 
 
64
#include <sys_defs.h>
 
65
#include <sys/stat.h>
 
66
#include <sys/socket.h>                 /* shutdown(2) */
 
67
#include <string.h>
 
68
#include <unistd.h>
 
69
#include <stdlib.h>                     /* 44BSD stdarg.h uses abort() */
 
70
#include <stdarg.h>
 
71
#include <time.h>
 
72
 
 
73
#ifdef STRCASECMP_IN_STRINGS_H
 
74
#include <strings.h>
 
75
#endif
 
76
 
 
77
/* Utility library. */
 
78
 
 
79
#include <msg.h>
 
80
#include <vstring.h>
 
81
#include <vstream.h>
 
82
#include <vstring_vstream.h>
 
83
#include <stringops.h>
 
84
#include <mymalloc.h>
 
85
#include <iostuff.h>
 
86
#include <split_at.h>
 
87
#include <name_code.h>
 
88
 
 
89
/* Global library. */
 
90
 
 
91
#include <mail_params.h>
 
92
#include <smtp_stream.h>
 
93
#include <mail_queue.h>
 
94
#include <recipient_list.h>
 
95
#include <deliver_request.h>
 
96
#include <defer.h>
 
97
#include <bounce.h>
 
98
#include <record.h>
 
99
#include <rec_type.h>
 
100
#include <off_cvt.h>
 
101
#include <mark_corrupt.h>
 
102
#include <quote_821_local.h>
 
103
#include <mail_proto.h>
 
104
#include <mime_state.h>
 
105
 
 
106
/* Application-specific. */
 
107
 
 
108
#include "smtp.h"
 
109
#include "smtp_sasl.h"
 
110
 
 
111
 /*
 
112
  * Sender and receiver state. A session does not necessarily go through a
 
113
  * linear progression, but states are guaranteed to not jump backwards.
 
114
  * Normal sessions go from MAIL->RCPT->DATA->DOT->QUIT->LAST. The states
 
115
  * MAIL, RCPT, and DATA may also be followed by ABORT->QUIT->LAST.
 
116
  * 
 
117
  * By default, the receiver skips the QUIT response. Some SMTP servers
 
118
  * disconnect after responding to ".", and some SMTP servers wait before
 
119
  * responding to QUIT.
 
120
  * 
 
121
  * Client states that are associated with sending mail (up to and including
 
122
  * SMTP_STATE_DOT) must have smaller numerical values than the non-sending
 
123
  * states (SMTP_STATE_ABORT .. SMTP_STATE_LAST).
 
124
  */
 
125
#define SMTP_STATE_XFORWARD_NAME_ADDR 0
 
126
#define SMTP_STATE_XFORWARD_PROTO_HELO 1
 
127
#define SMTP_STATE_MAIL         2
 
128
#define SMTP_STATE_RCPT         3
 
129
#define SMTP_STATE_DATA         4
 
130
#define SMTP_STATE_DOT          5
 
131
#define SMTP_STATE_ABORT        6
 
132
#define SMTP_STATE_QUIT         7
 
133
#define SMTP_STATE_LAST         8
 
134
 
 
135
int    *xfer_timeouts[SMTP_STATE_LAST] = {
 
136
    &var_smtp_xfwd_tmout,               /* name/addr */
 
137
    &var_smtp_xfwd_tmout,               /* helo/proto */
 
138
    &var_smtp_mail_tmout,
 
139
    &var_smtp_rcpt_tmout,
 
140
    &var_smtp_data0_tmout,
 
141
    &var_smtp_data2_tmout,
 
142
    &var_smtp_rset_tmout,
 
143
    &var_smtp_quit_tmout,
 
144
};
 
145
 
 
146
char   *xfer_states[SMTP_STATE_LAST] = {
 
147
    "sending XFORWARD name/address",
 
148
    "sending XFORWARD protocol/helo_name",
 
149
    "sending MAIL FROM",
 
150
    "sending RCPT TO",
 
151
    "sending DATA command",
 
152
    "sending end of data -- message may be sent more than once",
 
153
    "sending final RSET",
 
154
    "sending QUIT",
 
155
};
 
156
 
 
157
char   *xfer_request[SMTP_STATE_LAST] = {
 
158
    "XFORWARD name/address command",
 
159
    "XFORWARD helo/protocol command",
 
160
    "MAIL FROM command",
 
161
    "RCPT TO command",
 
162
    "DATA command",
 
163
    "end of DATA command",
 
164
    "final RSET command",
 
165
    "QUIT command",
 
166
};
 
167
 
 
168
/* smtp_helo - perform initial handshake with SMTP server */
 
169
 
 
170
int     smtp_helo(SMTP_STATE *state, int misc_flags)
 
171
{
 
172
    SMTP_SESSION *session = state->session;
 
173
    DELIVER_REQUEST *request = state->request;
 
174
    SMTP_RESP *resp;
 
175
    int     except;
 
176
    char   *lines;
 
177
    char   *words;
 
178
    char   *word;
 
179
    int     n;
 
180
    static NAME_CODE xforward_features[] = {
 
181
        XFORWARD_NAME, SMTP_FEATURE_XFORWARD_NAME,
 
182
        XFORWARD_ADDR, SMTP_FEATURE_XFORWARD_ADDR,
 
183
        XFORWARD_PROTO, SMTP_FEATURE_XFORWARD_PROTO,
 
184
        XFORWARD_HELO, SMTP_FEATURE_XFORWARD_HELO,
 
185
        0, 0,
 
186
    };
 
187
 
 
188
    /*
 
189
     * Prepare for disaster.
 
190
     */
 
191
    smtp_timeout_setup(state->session->stream, var_smtp_helo_tmout);
 
192
    if ((except = vstream_setjmp(state->session->stream)) != 0)
 
193
        return (smtp_stream_except(state, except,
 
194
                                   "receiving the initial SMTP greeting"));
 
195
 
 
196
    /*
 
197
     * Read and parse the server's SMTP greeting banner.
 
198
     */
 
199
    switch ((resp = smtp_chat_resp(state))->code / 100) {
 
200
    case 2:
 
201
        break;
 
202
    case 5:
 
203
        if (var_smtp_skip_5xx_greeting)
 
204
            resp->code = 400;
 
205
    default:
 
206
        return (smtp_site_fail(state, resp->code,
 
207
                               "host %s refused to talk to me: %s",
 
208
                               session->namaddr,
 
209
                               translit(resp->str, "\n", " ")));
 
210
    }
 
211
 
 
212
    /*
 
213
     * XXX Some PIX firewall versions require flush before ".<CR><LF>" so it
 
214
     * does not span a packet boundary. This hurts performance so it is not
 
215
     * on by default.
 
216
     */
 
217
    if (resp->str[strspn(resp->str, "20 *\t\n")] == 0)
 
218
        state->features |= SMTP_FEATURE_MAYBEPIX;
 
219
 
 
220
    /*
 
221
     * See if we are talking to ourself. This should not be possible with the
 
222
     * way we implement DNS lookups. However, people are known to sometimes
 
223
     * screw up the naming service. And, mailer loops are still possible when
 
224
     * our own mailer routing tables are mis-configured.
 
225
     */
 
226
    words = resp->str;
 
227
    (void) mystrtok(&words, "- \t\n");
 
228
    for (n = 0; (word = mystrtok(&words, " \t\n")) != 0; n++) {
 
229
        if (n == 0 && strcasecmp(word, var_myhostname) == 0) {
 
230
            if (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT)
 
231
                msg_warn("host %s greeted me with my own hostname %s",
 
232
                         session->namaddr, var_myhostname);
 
233
        } else if (strcasecmp(word, "ESMTP") == 0)
 
234
            state->features |= SMTP_FEATURE_ESMTP;
 
235
    }
 
236
    if (var_smtp_always_ehlo && (state->features & SMTP_FEATURE_MAYBEPIX) == 0)
 
237
        state->features |= SMTP_FEATURE_ESMTP;
 
238
    if (var_smtp_never_ehlo || (state->features & SMTP_FEATURE_MAYBEPIX) != 0)
 
239
        state->features &= ~SMTP_FEATURE_ESMTP;
 
240
 
 
241
    /*
 
242
     * Return the compliment. Fall back to SMTP if our ESMTP recognition
 
243
     * heuristic failed.
 
244
     */
 
245
    if (state->features & SMTP_FEATURE_ESMTP) {
 
246
        smtp_chat_cmd(state, "EHLO %s", var_smtp_helo_name);
 
247
        if ((resp = smtp_chat_resp(state))->code / 100 != 2)
 
248
            state->features &= ~SMTP_FEATURE_ESMTP;
 
249
    }
 
250
    if ((state->features & SMTP_FEATURE_ESMTP) == 0) {
 
251
        smtp_chat_cmd(state, "HELO %s", var_smtp_helo_name);
 
252
        if ((resp = smtp_chat_resp(state))->code / 100 != 2)
 
253
            return (smtp_site_fail(state, resp->code,
 
254
                                   "host %s refused to talk to me: %s",
 
255
                                   session->namaddr,
 
256
                                   translit(resp->str, "\n", " ")));
 
257
        return (0);
 
258
    }
 
259
 
 
260
    /*
 
261
     * Pick up some useful features offered by the SMTP server. XXX Until we
 
262
     * have a portable routine to convert from string to off_t with proper
 
263
     * overflow detection, ignore the message size limit advertised by the
 
264
     * SMTP server. Otherwise, we might do the wrong thing when the server
 
265
     * advertises a really huge message size limit.
 
266
     * 
 
267
     * XXX Allow for "code (SP|-) ehlo-keyword (SP|=) ehlo-param...", because
 
268
     * MicroSoft implemented AUTH based on an old draft.
 
269
     */
 
270
    lines = resp->str;
 
271
    while ((words = mystrtok(&lines, "\n")) != 0) {
 
272
        if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) {
 
273
            if (strcasecmp(word, "8BITMIME") == 0)
 
274
                state->features |= SMTP_FEATURE_8BITMIME;
 
275
            else if (strcasecmp(word, "PIPELINING") == 0)
 
276
                state->features |= SMTP_FEATURE_PIPELINING;
 
277
            else if (strcasecmp(word, "XFORWARD") == 0)
 
278
                while ((word = mystrtok(&words, " \t")) != 0)
 
279
                    state->features |= name_code(xforward_features,
 
280
                                                 NAME_CODE_FLAG_NONE, word);
 
281
            else if (strcasecmp(word, "SIZE") == 0) {
 
282
                state->features |= SMTP_FEATURE_SIZE;
 
283
                if ((word = mystrtok(&words, " \t")) != 0) {
 
284
                    if (!alldig(word))
 
285
                        msg_warn("bad size limit \"%s\" in EHLO reply from %s",
 
286
                                 word, session->namaddr);
 
287
                    else
 
288
                        state->size_limit = off_cvt_string(word);
 
289
                }
 
290
            }
 
291
#ifdef USE_SASL_AUTH
 
292
            else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
 
293
                smtp_sasl_helo_auth(state, words);
 
294
#endif
 
295
            else if (strcasecmp(word, var_myhostname) == 0) {
 
296
                if (misc_flags & SMTP_MISC_FLAG_LOOP_DETECT) {
 
297
                    msg_warn("host %s replied to HELO/EHLO with my own hostname %s",
 
298
                             session->namaddr, var_myhostname);
 
299
                    return (smtp_site_fail(state, session->best ? 550 : 450,
 
300
                                         "mail for %s loops back to myself",
 
301
                                           request->nexthop));
 
302
                }
 
303
            }
 
304
        }
 
305
    }
 
306
    if (msg_verbose)
 
307
        msg_info("server features: 0x%x size %.0f",
 
308
                 state->features, (double) state->size_limit);
 
309
 
 
310
#ifdef USE_SASL_AUTH
 
311
    if (var_smtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH))
 
312
        return (smtp_sasl_helo_login(state));
 
313
#endif
 
314
 
 
315
    return (0);
 
316
}
 
317
 
 
318
/* smtp_text_out - output one header/body record */
 
319
 
 
320
static void smtp_text_out(void *context, int rec_type,
 
321
                                  const char *text, int len,
 
322
                                  off_t unused_offset)
 
323
{
 
324
    SMTP_STATE *state = (SMTP_STATE *) context;
 
325
    SMTP_SESSION *session = state->session;
 
326
    int     data_left;
 
327
    const char *data_start;
 
328
 
 
329
    /*
 
330
     * Deal with an impedance mismatch between Postfix queue files (record
 
331
     * length <= $message_line_length_limit) and SMTP (DATA record length <=
 
332
     * $smtp_line_length_limit). The code below does a little too much work
 
333
     * when the SMTP line length limit is disabled, but it avoids code
 
334
     * duplication, and thus, it avoids testing and maintenance problems.
 
335
     */
 
336
    data_left = len;
 
337
    data_start = text;
 
338
    do {
 
339
        if (state->space_left == var_smtp_line_limit
 
340
            && data_left > 0 && *data_start == '.')
 
341
            smtp_fputc('.', session->stream);
 
342
        if (var_smtp_line_limit > 0 && data_left >= state->space_left) {
 
343
            smtp_fputs(data_start, state->space_left, session->stream);
 
344
            data_start += state->space_left;
 
345
            data_left -= state->space_left;
 
346
            state->space_left = var_smtp_line_limit;
 
347
            if (data_left > 0 || rec_type == REC_TYPE_CONT) {
 
348
                smtp_fputc(' ', session->stream);
 
349
                state->space_left -= 1;
 
350
            }
 
351
        } else {
 
352
            if (rec_type == REC_TYPE_CONT) {
 
353
                smtp_fwrite(data_start, data_left, session->stream);
 
354
                state->space_left -= data_left;
 
355
            } else {
 
356
                smtp_fputs(data_start, data_left, session->stream);
 
357
                state->space_left = var_smtp_line_limit;
 
358
            }
 
359
            break;
 
360
        }
 
361
    } while (data_left > 0);
 
362
}
 
363
 
 
364
/* smtp_header_out - output one message header */
 
365
 
 
366
static void smtp_header_out(void *context, int unused_header_class,
 
367
                                    HEADER_OPTS *unused_info, VSTRING *buf,
 
368
                                    off_t offset)
 
369
{
 
370
    char   *start = vstring_str(buf);
 
371
    char   *line;
 
372
    char   *next_line;
 
373
 
 
374
    for (line = start; line; line = next_line) {
 
375
        next_line = split_at(line, '\n');
 
376
        smtp_text_out(context, REC_TYPE_NORM, line, next_line ?
 
377
                      next_line - line - 1 : strlen(line), offset);
 
378
    }
 
379
}
 
380
 
 
381
/* smtp_xfer - send a batch of envelope information and the message data */
 
382
 
 
383
int     smtp_xfer(SMTP_STATE *state)
 
384
{
 
385
    char   *myname = "smtp_xfer";
 
386
    DELIVER_REQUEST *request = state->request;
 
387
    SMTP_SESSION *session = state->session;
 
388
    SMTP_RESP *resp;
 
389
    RECIPIENT *rcpt;
 
390
    VSTRING *next_command = vstring_alloc(100);
 
391
    NOCLOBBER int next_state;
 
392
    NOCLOBBER int next_rcpt;
 
393
    NOCLOBBER int send_state;
 
394
    NOCLOBBER int recv_state;
 
395
    NOCLOBBER int send_rcpt;
 
396
    NOCLOBBER int recv_rcpt;
 
397
    NOCLOBBER int nrcpt;
 
398
    int     except;
 
399
    int     rec_type;
 
400
    NOCLOBBER int prev_type = 0;
 
401
    int     sndbufsize = 0;
 
402
    NOCLOBBER int sndbuffree;
 
403
    SOCKOPT_SIZE optlen = sizeof(sndbufsize);
 
404
    NOCLOBBER int mail_from_rejected;
 
405
    NOCLOBBER int downgrading;
 
406
    int     mime_errs;
 
407
    int     send_name_addr;
 
408
    NOCLOBBER int send_proto_helo;
 
409
 
 
410
    /*
 
411
     * Macros for readability.
 
412
     */
 
413
#define REWRITE_ADDRESS(dst, mid, src) do { \
 
414
        if (*(src) && var_smtp_quote_821_env) { \
 
415
            quote_821_local(mid, src); \
 
416
            smtp_unalias_addr(dst, vstring_str(mid)); \
 
417
        } else { \
 
418
            vstring_strcpy(dst, src); \
 
419
        } \
 
420
    } while (0)
 
421
 
 
422
#define QUOTE_ADDRESS(dst, src) do { \
 
423
        if (*(src) && var_smtp_quote_821_env) { \
 
424
            quote_821_local(dst, src); \
 
425
        } else { \
 
426
            vstring_strcpy(dst, src); \
 
427
        } \
 
428
    } while (0)
 
429
 
 
430
#define RETURN(x) do { \
 
431
        vstring_free(next_command); \
 
432
        if (state->mime_state) \
 
433
            state->mime_state = mime_state_free(state->mime_state); \
 
434
        return (x); \
 
435
    } while (0)
 
436
 
 
437
#define SENDER_IS_AHEAD \
 
438
        (recv_state < send_state || recv_rcpt != send_rcpt)
 
439
 
 
440
#define SENDER_IN_WAIT_STATE \
 
441
        (send_state == SMTP_STATE_DOT || send_state == SMTP_STATE_LAST)
 
442
 
 
443
#define SENDING_MAIL \
 
444
        (recv_state <= SMTP_STATE_DOT)
 
445
 
 
446
    /*
 
447
     * Sanity check. Recipients should be unmarked at this point.
 
448
     */
 
449
    if (SMTP_RCPT_LEFT(state) <= 0)
 
450
        msg_panic("smtp_xfer: bad recipient count: %d",
 
451
                  SMTP_RCPT_LEFT(state));
 
452
    if (SMTP_RCPT_ISMARKED(request->rcpt_list.info))
 
453
        msg_panic("smtp_xfer: bad recipient status: %d",
 
454
                  request->rcpt_list.info->status);
 
455
 
 
456
    /*
 
457
     * See if we should even try to send this message at all. This code sits
 
458
     * here rather than in the EHLO processing code, because of future SMTP
 
459
     * connection caching.
 
460
     */
 
461
    if (state->size_limit > 0 && state->size_limit < request->data_size) {
 
462
        smtp_mesg_fail(state, 552,
 
463
                    "message size %lu exceeds size limit %.0f of server %s",
 
464
                       request->data_size, (double) state->size_limit,
 
465
                       session->namaddr);
 
466
        RETURN(0);
 
467
    }
 
468
 
 
469
    /*
 
470
     * We use SMTP command pipelining if the server said it supported it.
 
471
     * Since we use blocking I/O, RFC 2197 says that we should inspect the
 
472
     * TCP window size and not send more than this amount of information.
 
473
     * Unfortunately this information is not available using the sockets
 
474
     * interface. However, we *can* get the TCP send buffer size on the local
 
475
     * TCP/IP stack. We should be able to fill this buffer without being
 
476
     * blocked, and then the kernel will effectively do non-blocking I/O for
 
477
     * us by automatically writing out the contents of its send buffer while
 
478
     * we are reading in the responses. In addition to TCP buffering we have
 
479
     * to be aware of application-level buffering by the vstream module,
 
480
     * which is limited to a couple kbytes.
 
481
     */
 
482
    if (state->features & SMTP_FEATURE_PIPELINING) {
 
483
        if (getsockopt(vstream_fileno(state->session->stream), SOL_SOCKET,
 
484
                       SO_SNDBUF, (char *) &sndbufsize, &optlen) < 0)
 
485
            msg_fatal("%s: getsockopt: %m", myname);
 
486
        if (sndbufsize > VSTREAM_BUFSIZE)
 
487
            sndbufsize = VSTREAM_BUFSIZE;
 
488
        if (sndbufsize == 0) {
 
489
            sndbufsize = VSTREAM_BUFSIZE;
 
490
            if (setsockopt(vstream_fileno(state->session->stream), SOL_SOCKET,
 
491
                           SO_SNDBUF, (char *) &sndbufsize, optlen) < 0)
 
492
                msg_fatal("%s: setsockopt: %m", myname);
 
493
        }
 
494
        if (msg_verbose)
 
495
            msg_info("Using ESMTP PIPELINING, TCP send buffer size is %d",
 
496
                     sndbufsize);
 
497
    } else {
 
498
        sndbufsize = 0;
 
499
    }
 
500
    sndbuffree = sndbufsize;
 
501
 
 
502
    /*
 
503
     * Pipelining support requires two loops: one loop for sending and one
 
504
     * for receiving. Each loop has its own independent state. Most of the
 
505
     * time the sender can run ahead of the receiver by as much as the TCP
 
506
     * send buffer permits. There are only two places where the sender must
 
507
     * wait for status information from the receiver: once after sending DATA
 
508
     * and once after sending QUIT.
 
509
     * 
 
510
     * The sender state advances until the TCP send buffer would overflow, or
 
511
     * until the sender needs status information from the receiver. At that
 
512
     * point the receiver starts processing responses. Once the receiver has
 
513
     * caught up with the sender, the sender resumes sending commands. If the
 
514
     * receiver detects a serious problem (MAIL FROM rejected, all RCPT TO
 
515
     * commands rejected, DATA rejected) it forces the sender to abort the
 
516
     * SMTP dialog with RSET and QUIT.
 
517
     * 
 
518
     * Use the XFORWARD command to forward client attributes only when a minimal
 
519
     * amount of information is available.
 
520
     */
 
521
    nrcpt = 0;
 
522
    send_name_addr =
 
523
        var_smtp_send_xforward
 
524
        && (((state->features & SMTP_FEATURE_XFORWARD_NAME)
 
525
             && DEL_REQ_ATTR_AVAIL(request->client_name))
 
526
            || ((state->features & SMTP_FEATURE_XFORWARD_ADDR)
 
527
                && DEL_REQ_ATTR_AVAIL(request->client_addr)));
 
528
    send_proto_helo =
 
529
        var_smtp_send_xforward
 
530
        && (((state->features & SMTP_FEATURE_XFORWARD_PROTO)
 
531
             && DEL_REQ_ATTR_AVAIL(request->client_proto))
 
532
            || ((state->features & SMTP_FEATURE_XFORWARD_HELO)
 
533
                && DEL_REQ_ATTR_AVAIL(request->client_helo)));
 
534
    if (send_name_addr)
 
535
        recv_state = send_state = SMTP_STATE_XFORWARD_NAME_ADDR;
 
536
    else if (send_proto_helo)
 
537
        recv_state = send_state = SMTP_STATE_XFORWARD_PROTO_HELO;
 
538
    else
 
539
        recv_state = send_state = SMTP_STATE_MAIL;
 
540
    next_rcpt = send_rcpt = recv_rcpt = 0;
 
541
    mail_from_rejected = 0;
 
542
 
 
543
    while (recv_state != SMTP_STATE_LAST) {
 
544
 
 
545
        /*
 
546
         * Build the next command.
 
547
         */
 
548
        switch (send_state) {
 
549
 
 
550
            /*
 
551
             * Sanity check.
 
552
             */
 
553
        default:
 
554
            msg_panic("%s: bad sender state %d", myname, send_state);
 
555
 
 
556
            /*
 
557
             * Build the XFORWARD command. With properly sanitized
 
558
             * information, the command length stays within the 512 byte
 
559
             * command line length limit.
 
560
             */
 
561
        case SMTP_STATE_XFORWARD_NAME_ADDR:
 
562
            vstring_strcpy(next_command, XFORWARD_CMD);
 
563
            if (state->features & SMTP_FEATURE_XFORWARD_NAME)
 
564
                vstring_sprintf_append(next_command, " %s=%s",
 
565
                   XFORWARD_NAME, DEL_REQ_ATTR_AVAIL(request->client_name) ?
 
566
                               request->client_name : XFORWARD_UNAVAILABLE);
 
567
            if (state->features & SMTP_FEATURE_XFORWARD_ADDR)
 
568
                vstring_sprintf_append(next_command, " %s=%s",
 
569
                   XFORWARD_ADDR, DEL_REQ_ATTR_AVAIL(request->client_addr) ?
 
570
                               request->client_addr : XFORWARD_UNAVAILABLE);
 
571
            if (send_proto_helo)
 
572
                next_state = SMTP_STATE_XFORWARD_PROTO_HELO;
 
573
            else
 
574
                next_state = SMTP_STATE_MAIL;
 
575
            break;
 
576
 
 
577
        case SMTP_STATE_XFORWARD_PROTO_HELO:
 
578
            vstring_strcpy(next_command, XFORWARD_CMD);
 
579
            if (state->features & SMTP_FEATURE_XFORWARD_PROTO)
 
580
                vstring_sprintf_append(next_command, " %s=%s",
 
581
                 XFORWARD_PROTO, DEL_REQ_ATTR_AVAIL(request->client_proto) ?
 
582
                              request->client_proto : XFORWARD_UNAVAILABLE);
 
583
            if (state->features & SMTP_FEATURE_XFORWARD_HELO)
 
584
                vstring_sprintf_append(next_command, " %s=%s",
 
585
                   XFORWARD_HELO, DEL_REQ_ATTR_AVAIL(request->client_helo) ?
 
586
                               request->client_helo : XFORWARD_UNAVAILABLE);
 
587
            next_state = SMTP_STATE_MAIL;
 
588
            break;
 
589
 
 
590
            /*
 
591
             * Build the MAIL FROM command.
 
592
             */
 
593
        case SMTP_STATE_MAIL:
 
594
            QUOTE_ADDRESS(state->scratch, request->sender);
 
595
            vstring_sprintf(next_command, "MAIL FROM:<%s>",
 
596
                            vstring_str(state->scratch));
 
597
            if (state->features & SMTP_FEATURE_SIZE)    /* RFC 1870 */
 
598
                vstring_sprintf_append(next_command, " SIZE=%lu",
 
599
                                       request->data_size);
 
600
            if (state->features & SMTP_FEATURE_8BITMIME) {      /* RFC 1652 */
 
601
                if (strcmp(request->encoding, MAIL_ATTR_ENC_8BIT) == 0)
 
602
                    vstring_strcat(next_command, " BODY=8BITMIME");
 
603
                else if (strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) == 0)
 
604
                    vstring_strcat(next_command, " BODY=7BIT");
 
605
                else if (strcmp(request->encoding, MAIL_ATTR_ENC_NONE) != 0)
 
606
                    msg_warn("%s: unknown content encoding: %s",
 
607
                             request->queue_id, request->encoding);
 
608
            }
 
609
 
 
610
            /*
 
611
             * We authenticate the local MTA only, but not the sender.
 
612
             */
 
613
#ifdef USE_SASL_AUTH
 
614
            if (var_smtp_sasl_enable
 
615
                && (state->features & SMTP_FEATURE_AUTH)
 
616
                && state->sasl_passwd)
 
617
                vstring_strcat(next_command, " AUTH=<>");
 
618
#endif
 
619
            next_state = SMTP_STATE_RCPT;
 
620
            break;
 
621
 
 
622
            /*
 
623
             * Build one RCPT TO command before we have seen the MAIL FROM
 
624
             * response.
 
625
             */
 
626
        case SMTP_STATE_RCPT:
 
627
            rcpt = request->rcpt_list.info + send_rcpt;
 
628
            QUOTE_ADDRESS(state->scratch, rcpt->address);
 
629
            vstring_sprintf(next_command, "RCPT TO:<%s>",
 
630
                            vstring_str(state->scratch));
 
631
            if ((next_rcpt = send_rcpt + 1) == SMTP_RCPT_LEFT(state))
 
632
                next_state = DEL_REQ_TRACE_ONLY(request->flags) ?
 
633
                    SMTP_STATE_ABORT : SMTP_STATE_DATA;
 
634
            break;
 
635
 
 
636
            /*
 
637
             * Build the DATA command before we have seen all the RCPT TO
 
638
             * responses.
 
639
             */
 
640
        case SMTP_STATE_DATA:
 
641
            vstring_strcpy(next_command, "DATA");
 
642
            next_state = SMTP_STATE_DOT;
 
643
            break;
 
644
 
 
645
            /*
 
646
             * Build the "." command before we have seen the DATA response.
 
647
             */
 
648
        case SMTP_STATE_DOT:
 
649
            vstring_strcpy(next_command, ".");
 
650
            next_state = SMTP_STATE_QUIT;
 
651
            break;
 
652
 
 
653
            /*
 
654
             * The SMTP_STATE_ABORT sender state is entered by sender when it
 
655
             * has verified all recipients; or it is entered the receiver
 
656
             * when all recipients are rejected and is then left before the
 
657
             * bottom of the main loop.
 
658
             */
 
659
        case SMTP_STATE_ABORT:
 
660
            vstring_strcpy(next_command, "RSET");
 
661
            next_state = SMTP_STATE_QUIT;
 
662
            break;
 
663
 
 
664
            /*
 
665
             * Build the QUIT command before we have seen the "." or RSET
 
666
             * response.
 
667
             */
 
668
        case SMTP_STATE_QUIT:
 
669
            vstring_strcpy(next_command, "QUIT");
 
670
            next_state = SMTP_STATE_LAST;
 
671
            break;
 
672
 
 
673
            /*
 
674
             * The final sender state has no action associated with it.
 
675
             */
 
676
        case SMTP_STATE_LAST:
 
677
            VSTRING_RESET(next_command);
 
678
            break;
 
679
        }
 
680
        VSTRING_TERMINATE(next_command);
 
681
 
 
682
        /*
 
683
         * Process responses until the receiver has caught up. Vstreams
 
684
         * automatically flush buffered output when reading new data.
 
685
         * 
 
686
         * Flush unsent output if command pipelining is off or if no I/O
 
687
         * happened for a while. This limits the accumulation of client-side
 
688
         * delays in pipelined sessions.
 
689
         */
 
690
        if (SENDER_IN_WAIT_STATE
 
691
            || (SENDER_IS_AHEAD
 
692
                && (VSTRING_LEN(next_command) + 2 > sndbuffree
 
693
            || time((time_t *) 0) - vstream_ftime(session->stream) > 10))) {
 
694
            while (SENDER_IS_AHEAD) {
 
695
 
 
696
                /*
 
697
                 * Sanity check.
 
698
                 */
 
699
                if (recv_state < SMTP_STATE_XFORWARD_NAME_ADDR
 
700
                    || recv_state > SMTP_STATE_QUIT)
 
701
                    msg_panic("%s: bad receiver state %d (sender state %d)",
 
702
                              myname, recv_state, send_state);
 
703
 
 
704
                /*
 
705
                 * Receive the next server response. Use the proper timeout,
 
706
                 * and log the proper client state in case of trouble.
 
707
                 */
 
708
                smtp_timeout_setup(state->session->stream,
 
709
                                   *xfer_timeouts[recv_state]);
 
710
                if ((except = vstream_setjmp(state->session->stream)) != 0)
 
711
                    RETURN(SENDING_MAIL ? smtp_stream_except(state, except,
 
712
                                             xfer_states[recv_state]) : -1);
 
713
                resp = smtp_chat_resp(state);
 
714
 
 
715
                /*
 
716
                 * Process the response.
 
717
                 */
 
718
                switch (recv_state) {
 
719
 
 
720
                    /*
 
721
                     * Process the XFORWARD response.
 
722
                     */
 
723
                case SMTP_STATE_XFORWARD_NAME_ADDR:
 
724
                    if (resp->code / 100 != 2)
 
725
                        msg_warn("host %s said: %s (in reply to %s)",
 
726
                                 session->namaddr,
 
727
                                 translit(resp->str, "\n", " "),
 
728
                               xfer_request[SMTP_STATE_XFORWARD_NAME_ADDR]);
 
729
                    if (send_proto_helo)
 
730
                        recv_state = SMTP_STATE_XFORWARD_PROTO_HELO;
 
731
                    else
 
732
                        recv_state = SMTP_STATE_MAIL;
 
733
                    break;
 
734
 
 
735
                case SMTP_STATE_XFORWARD_PROTO_HELO:
 
736
                    if (resp->code / 100 != 2)
 
737
                        msg_warn("host %s said: %s (in reply to %s)",
 
738
                                 session->namaddr,
 
739
                                 translit(resp->str, "\n", " "),
 
740
                              xfer_request[SMTP_STATE_XFORWARD_PROTO_HELO]);
 
741
                    recv_state = SMTP_STATE_MAIL;
 
742
                    break;
 
743
 
 
744
                    /*
 
745
                     * Process the MAIL FROM response. When the server
 
746
                     * rejects the sender, set the mail_from_rejected flag so
 
747
                     * that the receiver may apply a course correction.
 
748
                     */
 
749
                case SMTP_STATE_MAIL:
 
750
                    if (resp->code / 100 != 2) {
 
751
                        smtp_mesg_fail(state, resp->code,
 
752
                                       "host %s said: %s (in reply to %s)",
 
753
                                       session->namaddr,
 
754
                                       translit(resp->str, "\n", " "),
 
755
                                       xfer_request[SMTP_STATE_MAIL]);
 
756
                        mail_from_rejected = 1;
 
757
                    }
 
758
                    recv_state = SMTP_STATE_RCPT;
 
759
                    break;
 
760
 
 
761
                    /*
 
762
                     * Process one RCPT TO response. If MAIL FROM was
 
763
                     * rejected, ignore RCPT TO responses: all recipients are
 
764
                     * dead already. When all recipients are rejected the
 
765
                     * receiver may apply a course correction.
 
766
                     * 
 
767
                     * XXX 2821: Section 4.5.3.1 says that a 552 RCPT TO reply
 
768
                     * must be treated as if the server replied with 452.
 
769
                     * However, this causes "too much mail data" to be
 
770
                     * treated as a recoverable error, which is wrong. I'll
 
771
                     * stick with RFC 821.
 
772
                     */
 
773
                case SMTP_STATE_RCPT:
 
774
                    if (!mail_from_rejected) {
 
775
#ifdef notdef
 
776
                        if (resp->code == 552)
 
777
                            resp->code = 452;
 
778
#endif
 
779
                        rcpt = request->rcpt_list.info + recv_rcpt;
 
780
                        if (resp->code / 100 == 2) {
 
781
                            ++nrcpt;
 
782
                            /* If trace-only, mark the recipient done. */
 
783
                            if (DEL_REQ_TRACE_ONLY(request->flags))
 
784
                                smtp_rcpt_done(state, resp->str, rcpt);
 
785
                        } else {
 
786
                            smtp_rcpt_fail(state, resp->code, rcpt,
 
787
                                        "host %s said: %s (in reply to %s)",
 
788
                                           session->namaddr,
 
789
                                           translit(resp->str, "\n", " "),
 
790
                                           xfer_request[SMTP_STATE_RCPT]);
 
791
                        }
 
792
                    }
 
793
                    /* If trace-only, send RSET instead of DATA. */
 
794
                    if (++recv_rcpt == SMTP_RCPT_LEFT(state))
 
795
                        recv_state = DEL_REQ_TRACE_ONLY(request->flags) ?
 
796
                            SMTP_STATE_ABORT : SMTP_STATE_DATA;
 
797
                    break;
 
798
 
 
799
                    /*
 
800
                     * Process the DATA response. When the server rejects
 
801
                     * DATA, set nrcpt to a negative value so that the
 
802
                     * receiver can apply a course correction.
 
803
                     */
 
804
                case SMTP_STATE_DATA:
 
805
                    if (resp->code / 100 != 3) {
 
806
                        if (nrcpt > 0)
 
807
                            smtp_mesg_fail(state, resp->code,
 
808
                                        "host %s said: %s (in reply to %s)",
 
809
                                           session->namaddr,
 
810
                                           translit(resp->str, "\n", " "),
 
811
                                           xfer_request[SMTP_STATE_DATA]);
 
812
                        nrcpt = -1;
 
813
                    }
 
814
                    recv_state = SMTP_STATE_DOT;
 
815
                    break;
 
816
 
 
817
                    /*
 
818
                     * Process the end of message response. Ignore the
 
819
                     * response when no recipient was accepted: all
 
820
                     * recipients are dead already, and the next receiver
 
821
                     * state is SMTP_STATE_QUIT regardless. Otherwise, if the
 
822
                     * message transfer fails, bounce all remaining
 
823
                     * recipients, else cross off the recipients that were
 
824
                     * delivered.
 
825
                     */
 
826
                case SMTP_STATE_DOT:
 
827
                    if (nrcpt > 0) {
 
828
                        if (resp->code / 100 != 2) {
 
829
                            smtp_mesg_fail(state, resp->code,
 
830
                                        "host %s said: %s (in reply to %s)",
 
831
                                           session->namaddr,
 
832
                                           translit(resp->str, "\n", " "),
 
833
                                           xfer_request[SMTP_STATE_DOT]);
 
834
                        } else {
 
835
                            for (nrcpt = 0; nrcpt < recv_rcpt; nrcpt++) {
 
836
                                rcpt = request->rcpt_list.info + nrcpt;
 
837
                                if (!SMTP_RCPT_ISMARKED(rcpt))
 
838
                                    smtp_rcpt_done(state, resp->str, rcpt);
 
839
                            }
 
840
                        }
 
841
                    }
 
842
                    recv_state = (var_skip_quit_resp ?
 
843
                                  SMTP_STATE_LAST : SMTP_STATE_QUIT);
 
844
                    break;
 
845
 
 
846
                    /*
 
847
                     * Ignore the RSET response.
 
848
                     */
 
849
                case SMTP_STATE_ABORT:
 
850
                    recv_state = (var_skip_quit_resp ?
 
851
                                  SMTP_STATE_LAST : SMTP_STATE_QUIT);
 
852
                    break;
 
853
 
 
854
                    /*
 
855
                     * Ignore the QUIT response.
 
856
                     */
 
857
                case SMTP_STATE_QUIT:
 
858
                    recv_state = SMTP_STATE_LAST;
 
859
                    break;
 
860
                }
 
861
            }
 
862
 
 
863
            /*
 
864
             * At this point, the sender and receiver are fully synchronized,
 
865
             * so that the entire TCP send buffer becomes available again.
 
866
             */
 
867
            sndbuffree = sndbufsize;
 
868
 
 
869
            /*
 
870
             * We know the server response to every command that was sent.
 
871
             * Apply a course correction if necessary: the sender wants to
 
872
             * send RCPT TO but MAIL FROM was rejected; the sender wants to
 
873
             * send DATA but all recipients were rejected; the sender wants
 
874
             * to deliver the message but DATA was rejected.
 
875
             */
 
876
            if ((send_state == SMTP_STATE_RCPT && mail_from_rejected)
 
877
                || (send_state == SMTP_STATE_DATA && nrcpt == 0)
 
878
                || (send_state == SMTP_STATE_DOT && nrcpt < 0)) {
 
879
                send_state = recv_state = SMTP_STATE_ABORT;
 
880
                send_rcpt = recv_rcpt = 0;
 
881
                vstring_strcpy(next_command, "RSET");
 
882
                next_state = SMTP_STATE_QUIT;
 
883
                next_rcpt = 0;
 
884
            }
 
885
        }
 
886
 
 
887
        /*
 
888
         * Make the next sender state the current sender state.
 
889
         */
 
890
        if (send_state == SMTP_STATE_LAST)
 
891
            continue;
 
892
 
 
893
        /*
 
894
         * Special case if the server accepted the DATA command. If the
 
895
         * server accepted at least one recipient send the entire message.
 
896
         * Otherwise, just send "." as per RFC 2197.
 
897
         * 
 
898
         * XXX If there is a hard MIME error while downgrading to 7-bit mail,
 
899
         * disconnect ungracefully, because there is no other way to cancel a
 
900
         * transaction in progress.
 
901
         */
 
902
        if (send_state == SMTP_STATE_DOT && nrcpt > 0) {
 
903
            downgrading =
 
904
                (var_disable_mime_oconv == 0
 
905
                 && (state->features & SMTP_FEATURE_8BITMIME) == 0
 
906
                 && strcmp(request->encoding, MAIL_ATTR_ENC_7BIT) != 0);
 
907
            if (downgrading)
 
908
                state->mime_state = mime_state_alloc(MIME_OPT_DOWNGRADE
 
909
                                                  | MIME_OPT_REPORT_NESTING,
 
910
                                                     smtp_header_out,
 
911
                                                     (MIME_STATE_ANY_END) 0,
 
912
                                                     smtp_text_out,
 
913
                                                     (MIME_STATE_ANY_END) 0,
 
914
                                                   (MIME_STATE_ERR_PRINT) 0,
 
915
                                                     (void *) state);
 
916
            state->space_left = var_smtp_line_limit;
 
917
            smtp_timeout_setup(state->session->stream,
 
918
                               var_smtp_data1_tmout);
 
919
            if ((except = vstream_setjmp(state->session->stream)) != 0)
 
920
                RETURN(smtp_stream_except(state, except,
 
921
                                          "sending message body"));
 
922
 
 
923
            if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
 
924
                msg_fatal("seek queue file: %m");
 
925
 
 
926
            while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
 
927
                if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
 
928
                    break;
 
929
                if (downgrading == 0) {
 
930
                    smtp_text_out((void *) state, rec_type,
 
931
                                  vstring_str(state->scratch),
 
932
                                  VSTRING_LEN(state->scratch),
 
933
                                  (off_t) 0);
 
934
                } else {
 
935
                    mime_errs =
 
936
                        mime_state_update(state->mime_state, rec_type,
 
937
                                          vstring_str(state->scratch),
 
938
                                          VSTRING_LEN(state->scratch));
 
939
                    if (mime_errs) {
 
940
                        smtp_mesg_fail(state, 554,
 
941
                                       "MIME 7-bit conversion failed: %s",
 
942
                                       mime_state_error(mime_errs));
 
943
                        RETURN(0);
 
944
                    }
 
945
                }
 
946
                prev_type = rec_type;
 
947
            }
 
948
 
 
949
            if (state->mime_state) {
 
950
 
 
951
                /*
 
952
                 * The cleanup server normally ends MIME content with a
 
953
                 * normal text record. The following code is needed to flush
 
954
                 * an internal buffer when someone submits 8-bit mail not
 
955
                 * ending in newline via /usr/sbin/sendmail while MIME input
 
956
                 * processing is turned off, and MIME 8bit->7bit conversion
 
957
                 * is requested upon delivery.
 
958
                 */
 
959
                mime_errs =
 
960
                    mime_state_update(state->mime_state, rec_type, "", 0);
 
961
                if (mime_errs) {
 
962
                    smtp_mesg_fail(state, 554,
 
963
                                   "MIME 7-bit conversion failed: %s",
 
964
                                   mime_state_error(mime_errs));
 
965
                    RETURN(0);
 
966
                }
 
967
            } else if (prev_type == REC_TYPE_CONT)      /* missing newline */
 
968
                smtp_fputs("", 0, session->stream);
 
969
            if ((state->features & SMTP_FEATURE_MAYBEPIX) != 0
 
970
                && request->arrival_time < vstream_ftime(session->stream)
 
971
                - var_smtp_pix_thresh) {
 
972
                msg_info("%s: enabling PIX <CRLF>.<CRLF> workaround for %s",
 
973
                         request->queue_id, session->namaddr);
 
974
                vstream_fflush(session->stream);/* hurts performance */
 
975
                sleep(var_smtp_pix_delay);      /* not to mention this */
 
976
            }
 
977
            if (vstream_ferror(state->src))
 
978
                msg_fatal("queue file read error");
 
979
            if (rec_type != REC_TYPE_XTRA)
 
980
                RETURN(mark_corrupt(state->src));
 
981
        }
 
982
 
 
983
        /*
 
984
         * Copy the next command to the buffer and update the sender state.
 
985
         */
 
986
        if (sndbuffree > 0)
 
987
            sndbuffree -= VSTRING_LEN(next_command) + 2;
 
988
        smtp_chat_cmd(state, "%s", vstring_str(next_command));
 
989
        send_state = next_state;
 
990
        send_rcpt = next_rcpt;
 
991
    }
 
992
    RETURN(0);
 
993
}