~ubuntu-branches/ubuntu/trusty/postfix/trusty

« back to all changes in this revision

Viewing changes to src/smtp/smtp_session.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones, LaMont Jones, localization folks
  • Date: 2014-02-11 07:44:30 UTC
  • mfrom: (58.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20140211074430-kwkoxdz0fbajn0fj
Tags: 2.11.0-1
[LaMont Jones]

* New upstream release: 2.11.0

[localization folks]

* l10n: Updated German translations.  Closes: #734893 (Helge Kreutzmann)

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
/* SYNOPSIS
7
7
/*      #include "smtp.h"
8
8
/*
9
 
/*      SMTP_SESSION *smtp_session_alloc(stream, dest, host, addr,
10
 
/*                                      port, start, flags)
11
 
/*      VSTREAM *stream;
12
 
/*      char    *dest;
13
 
/*      char    *host;
14
 
/*      char    *addr;
15
 
/*      unsigned port;
 
9
/*      SMTP_SESSION *smtp_session_alloc(stream, iter, start, flags)
 
10
/*      VSTREAM *stream;
 
11
/*      SMTP_ITERATOR *iter;
16
12
/*      time_t  start;
17
13
/*      int     flags;
18
14
/*
24
20
/*      VSTRING *dest_prop;
25
21
/*      VSTRING *endp_prop;
26
22
/*
27
 
/*      SMTP_SESSION *smtp_session_activate(fd, dest_prop, endp_prop)
 
23
/*      SMTP_SESSION *smtp_session_activate(fd, iter, dest_prop, endp_prop)
28
24
/*      int     fd;
 
25
/*      SMTP_ITERATOR *iter;
29
26
/*      VSTRING *dest_prop;
30
27
/*      VSTRING *endp_prop;
31
28
/* DESCRIPTION
33
30
/*      and initializes it with the given stream and destination, host name
34
31
/*      and address information.  The host name and address strings are
35
32
/*      copied. The port is in network byte order.
36
 
/*      When TLS is enabled, smtp_session_alloc() looks up the
37
 
/*      per-site TLS policies for TLS enforcement and certificate
38
 
/*      verification.  The resulting policy is stored into the
39
 
/*      SMTP_SESSION object.
40
33
/*
41
34
/*      smtp_session_free() destroys an SMTP_SESSION structure and its
42
35
/*      members, making memory available for reuse. It will handle the
47
40
/*      it can be cached. The SMTP_SESSION structure is destroyed.
48
41
/*
49
42
/*      smtp_session_activate() inflates a flattened SMTP session
50
 
/*      so that it can be used. The input is modified.
 
43
/*      so that it can be used. The input property arguments are
 
44
/*      modified.
51
45
/*
52
46
/*      Arguments:
53
47
/* .IP stream
54
48
/*      A full-duplex stream.
55
 
/* .IP dest
56
 
/*      The unmodified next-hop or fall-back destination including
57
 
/*      the optional [] and including the optional port or service.
58
 
/* .IP host
59
 
/*      The name of the host that we are connected to.
60
 
/* .IP addr
61
 
/*      The address of the host that we are connected to.
62
 
/* .IP port
63
 
/*      The remote port, network byte order.
 
49
/* .IP iter
 
50
/*      The literal next-hop or fall-back destination including
 
51
/*      the optional [] and including the :port or :service;
 
52
/*      the name of the remote host;
 
53
/*      the printable address of the remote host;
 
54
/*      the remote port in network byte order.
64
55
/* .IP start
65
56
/*      The time when this connection was opened.
66
57
/* .IP flags
74
65
/*      SMTP_MISC_FLAG_CONN_MASK corresponds with both _LOAD and _STORE.
75
66
/* .IP dest_prop
76
67
/*      Destination specific session properties: the server is the
77
 
/*      best MX host for the current logical destination.
 
68
/*      best MX host for the current logical destination, the dest,
 
69
/*      host, and addr properties. When dest_prop is non-empty, it
 
70
/*      overrides the iterator dest, host, and addr properties.  It
 
71
/*      is the caller's responsibility to save the current nexthop
 
72
/*      with SMTP_ITER_SAVE_DEST() and to restore it afterwards
 
73
/*      with SMTP_ITER_RESTORE_DEST() before trying alternatives.
78
74
/* .IP endp_prop
79
75
/*      Endpoint specific session properties: all the features
80
76
/*      advertised by the remote server.
88
84
/*      P.O. Box 704
89
85
/*      Yorktown Heights, NY 10598, USA
90
86
/*
91
 
/*      TLS support originally by:
92
 
/*      Lutz Jaenicke
93
 
/*      BTU Cottbus
94
 
/*      Allgemeine Elektrotechnik
95
 
/*      Universitaetsplatz 3-4
96
 
/*      D-03044 Cottbus, Germany
 
87
/*      Viktor Dukhovni
97
88
/*--*/
98
89
 
99
90
/* System library. */
114
105
#include <vstring.h>
115
106
#include <vstream.h>
116
107
#include <stringops.h>
117
 
#include <valid_hostname.h>
118
 
#include <name_code.h>
119
108
 
120
109
/* Global library. */
121
110
 
122
111
#include <mime_state.h>
123
112
#include <debug_peer.h>
124
113
#include <mail_params.h>
125
 
#include <maps.h>
126
 
#include <smtp_stream.h>
127
114
 
128
115
/* Application-specific. */
129
116
 
130
117
#include "smtp.h"
131
118
#include "smtp_sasl.h"
132
119
 
133
 
#ifdef USE_TLS
134
 
 
135
 
static MAPS *tls_policy;                /* lookup table(s) */
136
 
static MAPS *tls_per_site;              /* lookup table(s) */
137
 
 
138
 
/* smtp_tls_list_init - initialize per-site policy lists */
139
 
 
140
 
void    smtp_tls_list_init(void)
141
 
{
142
 
    if (*var_smtp_tls_policy) {
143
 
        tls_policy = maps_create(VAR_SMTP_TLS_POLICY, var_smtp_tls_policy,
144
 
                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
145
 
        if (*var_smtp_tls_per_site)
146
 
            msg_warn("%s ignored when %s is not empty.",
147
 
                     VAR_SMTP_TLS_PER_SITE, VAR_SMTP_TLS_POLICY);
148
 
        return;
149
 
    }
150
 
    if (*var_smtp_tls_per_site) {
151
 
        tls_per_site = maps_create(VAR_SMTP_TLS_PER_SITE, var_smtp_tls_per_site,
152
 
                                   DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
153
 
    }
154
 
}
155
 
 
156
 
/* policy_name - printable tls policy level */
157
 
 
158
 
static const char *policy_name(int tls_level)
159
 
{
160
 
    const char *name = str_tls_level(tls_level);
161
 
 
162
 
    if (name == 0)
163
 
        name = "unknown";
164
 
    return name;
165
 
}
166
 
 
167
 
/* tls_site_lookup - look up per-site TLS security level */
168
 
 
169
 
static void tls_site_lookup(int *site_level, const char *site_name,
170
 
                                    const char *site_class)
171
 
{
172
 
    const char *lookup;
173
 
 
174
 
    /*
175
 
     * Look up a non-default policy. In case of multiple lookup results, the
176
 
     * precedence order is a permutation of the TLS enforcement level order:
177
 
     * VERIFY, ENCRYPT, NONE, MAY, NOTFOUND. I.e. we override MAY with a more
178
 
     * specific policy including NONE, otherwise we choose the stronger
179
 
     * enforcement level.
180
 
     */
181
 
    if ((lookup = maps_find(tls_per_site, site_name, 0)) != 0) {
182
 
        if (!strcasecmp(lookup, "NONE")) {
183
 
            /* NONE overrides MAY or NOTFOUND. */
184
 
            if (*site_level <= TLS_LEV_MAY)
185
 
                *site_level = TLS_LEV_NONE;
186
 
        } else if (!strcasecmp(lookup, "MAY")) {
187
 
            /* MAY overrides NOTFOUND but not NONE. */
188
 
            if (*site_level < TLS_LEV_NONE)
189
 
                *site_level = TLS_LEV_MAY;
190
 
        } else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) {
191
 
            if (*site_level < TLS_LEV_ENCRYPT)
192
 
                *site_level = TLS_LEV_ENCRYPT;
193
 
        } else if (!strcasecmp(lookup, "MUST")) {
194
 
            if (*site_level < TLS_LEV_VERIFY)
195
 
                *site_level = TLS_LEV_VERIFY;
196
 
        } else {
197
 
            msg_warn("Table %s: ignoring unknown TLS policy '%s' for %s %s",
198
 
                     var_smtp_tls_per_site, lookup, site_class, site_name);
199
 
        }
200
 
    } else if (tls_per_site->error) {
201
 
        msg_fatal("%s lookup error for %s", tls_per_site->title, site_name);
202
 
    }
203
 
}
204
 
 
205
 
/* tls_policy_lookup_one - look up destination TLS policy */
206
 
 
207
 
static int tls_policy_lookup_one(SMTP_SESSION *session, int *site_level,
208
 
                                         const char *site_name,
209
 
                                         const char *site_class)
210
 
{
211
 
    const char *lookup;
212
 
    char   *policy;
213
 
    char   *saved_policy;
214
 
    char   *tok;
215
 
    const char *err;
216
 
    char   *name;
217
 
    char   *val;
218
 
    static VSTRING *cbuf;
219
 
 
220
 
#undef FREE_RETURN
221
 
#define FREE_RETURN(x) do { myfree(saved_policy); return (x); } while (0)
222
 
 
223
 
    if ((lookup = maps_find(tls_policy, site_name, 0)) == 0) {
224
 
        if (tls_policy->error) {
225
 
            msg_fatal("%s: %s lookup error for %s",
226
 
                      session->state->request->queue_id,
227
 
                      tls_policy->title, site_name);
228
 
            /* XXX session->stream has no longjmp context yet. */
229
 
        }
230
 
        return (0);
231
 
    }
232
 
    if (cbuf == 0)
233
 
        cbuf = vstring_alloc(10);
234
 
 
235
 
#define WHERE \
236
 
    vstring_str(vstring_sprintf(cbuf, "TLS policy table, %s \"%s\"", \
237
 
                site_class, site_name))
238
 
 
239
 
    saved_policy = policy = mystrdup(lookup);
240
 
 
241
 
    if ((tok = mystrtok(&policy, "\t\n\r ,")) == 0) {
242
 
        msg_warn("%s: invalid empty policy", WHERE);
243
 
        *site_level = TLS_LEV_INVALID;
244
 
        FREE_RETURN(1);                         /* No further lookups */
245
 
    }
246
 
    *site_level = tls_level_lookup(tok);
247
 
    if (*site_level == TLS_LEV_INVALID) {
248
 
        /* tls_level_lookup() logs no warning. */
249
 
        msg_warn("%s: invalid security level \"%s\"", WHERE, tok);
250
 
        FREE_RETURN(1);                         /* No further lookups */
251
 
    }
252
 
 
253
 
    /*
254
 
     * Warn about ignored attributes when TLS is disabled.
255
 
     */
256
 
    if (*site_level < TLS_LEV_MAY) {
257
 
        while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0)
258
 
            msg_warn("%s: ignoring attribute \"%s\" with TLS disabled",
259
 
                     WHERE, tok);
260
 
        FREE_RETURN(1);
261
 
    }
262
 
 
263
 
    /*
264
 
     * Errors in attributes may have security consequences, don't ignore
265
 
     * errors that can degrade security.
266
 
     */
267
 
    while ((tok = mystrtok(&policy, "\t\n\r ,")) != 0) {
268
 
        if ((err = split_nameval(tok, &name, &val)) != 0) {
269
 
            *site_level = TLS_LEV_INVALID;
270
 
            msg_warn("%s: malformed attribute/value pair \"%s\": %s",
271
 
                     WHERE, tok, err);
272
 
            break;
273
 
        }
274
 
        /* Only one instance per policy. */
275
 
        if (!strcasecmp(name, "ciphers")) {
276
 
            if (*val == 0) {
277
 
                msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
278
 
                *site_level = TLS_LEV_INVALID;
279
 
                break;
280
 
            }
281
 
            if (session->tls_grade) {
282
 
                msg_warn("%s: attribute \"%s\" is specified multiple times",
283
 
                         WHERE, name);
284
 
                *site_level = TLS_LEV_INVALID;
285
 
                break;
286
 
            }
287
 
            session->tls_grade = mystrdup(val);
288
 
            continue;
289
 
        }
290
 
        /* Only one instance per policy. */
291
 
        if (!strcasecmp(name, "protocols")) {
292
 
            if (session->tls_protocols) {
293
 
                msg_warn("%s: attribute \"%s\" is specified multiple times",
294
 
                         WHERE, name);
295
 
                *site_level = TLS_LEV_INVALID;
296
 
                break;
297
 
            }
298
 
            session->tls_protocols = mystrdup(val);
299
 
            continue;
300
 
        }
301
 
        /* Multiple instance(s) per policy. */
302
 
        if (!strcasecmp(name, "match")) {
303
 
            char   *delim = *site_level == TLS_LEV_FPRINT ? "|" : ":";
304
 
 
305
 
            if (*site_level <= TLS_LEV_ENCRYPT) {
306
 
                msg_warn("%s: attribute \"%s\" invalid at security level \"%s\"",
307
 
                         WHERE, name, policy_name(*site_level));
308
 
                *site_level = TLS_LEV_INVALID;
309
 
                break;
310
 
            }
311
 
            if (*val == 0) {
312
 
                msg_warn("%s: attribute \"%s\" has empty value", WHERE, name);
313
 
                *site_level = TLS_LEV_INVALID;
314
 
                break;
315
 
            }
316
 
            if (session->tls_matchargv == 0)
317
 
                session->tls_matchargv = argv_split(val, delim);
318
 
            else
319
 
                argv_split_append(session->tls_matchargv, val, delim);
320
 
            continue;
321
 
        }
322
 
        /* Only one instance per policy. */
323
 
        if (!strcasecmp(name, "exclude")) {
324
 
            if (session->tls_exclusions) {
325
 
                msg_warn("%s: attribute \"%s\" is specified multiple times",
326
 
                         WHERE, name);
327
 
                *site_level = TLS_LEV_INVALID;
328
 
                break;
329
 
            }
330
 
            session->tls_exclusions = vstring_strcpy(vstring_alloc(10), val);
331
 
            continue;
332
 
        } else {
333
 
            msg_warn("%s: invalid attribute name: \"%s\"", WHERE, name);
334
 
            *site_level = TLS_LEV_INVALID;
335
 
            break;
336
 
        }
337
 
    }
338
 
    FREE_RETURN(1);
339
 
}
340
 
 
341
 
/* tls_policy_lookup - look up destination TLS policy */
342
 
 
343
 
static void tls_policy_lookup(SMTP_SESSION *session, int *site_level,
344
 
                                      const char *site_name,
345
 
                                      const char *site_class)
346
 
{
347
 
 
348
 
    /*
349
 
     * Only one lookup with [nexthop]:port, [nexthop] or nexthop:port These
350
 
     * are never the domain part of localpart@domain, rather they are
351
 
     * explicit nexthops from transport:nexthop, and match only the
352
 
     * corresponding policy. Parent domain matching (below) applies only to
353
 
     * sub-domains of the recipient domain.
354
 
     */
355
 
    if (!valid_hostname(site_name, DONT_GRIPE)) {
356
 
        tls_policy_lookup_one(session, site_level, site_name, site_class);
357
 
        return;
358
 
    }
359
 
 
360
 
    /*
361
 
     * XXX For clarity consider using ``do { .. } while'', instead of using
362
 
     * ``while { .. }'' with loop control at the bottom.
363
 
     */
364
 
    while (1) {
365
 
        /* Try the given domain */
366
 
        if (tls_policy_lookup_one(session, site_level, site_name, site_class))
367
 
            return;
368
 
        /* Re-try with parent domain */
369
 
        if ((site_name = strchr(site_name + 1, '.')) == 0)
370
 
            return;
371
 
    }
372
 
}
373
 
 
374
 
/* set_cipher_grade - Set cipher grade and exclusions */
375
 
 
376
 
static void set_cipher_grade(SMTP_SESSION *session)
377
 
{
378
 
    const char *mand_exclude = "";
379
 
    const char *also_exclude = "";
380
 
 
381
 
    /*
382
 
     * Use main.cf cipher level if no per-destination value specified. With
383
 
     * mandatory encryption at least encrypt, and with mandatory verification
384
 
     * at least authenticate!
385
 
     */
386
 
    switch (session->tls_level) {
387
 
    case TLS_LEV_INVALID:
388
 
    case TLS_LEV_NONE:
389
 
        return;
390
 
 
391
 
    case TLS_LEV_MAY:
392
 
        if (session->tls_grade == 0)
393
 
            session->tls_grade = mystrdup(var_smtp_tls_ciph);
394
 
        break;
395
 
 
396
 
    case TLS_LEV_ENCRYPT:
397
 
        if (session->tls_grade == 0)
398
 
            session->tls_grade = mystrdup(var_smtp_tls_mand_ciph);
399
 
        mand_exclude = var_smtp_tls_mand_excl;
400
 
        also_exclude = "eNULL";
401
 
        break;
402
 
 
403
 
    case TLS_LEV_FPRINT:
404
 
    case TLS_LEV_VERIFY:
405
 
    case TLS_LEV_SECURE:
406
 
        if (session->tls_grade == 0)
407
 
            session->tls_grade = mystrdup(var_smtp_tls_mand_ciph);
408
 
        mand_exclude = var_smtp_tls_mand_excl;
409
 
        also_exclude = "aNULL";
410
 
        break;
411
 
    }
412
 
 
413
 
#define ADD_EXCLUDE(vstr, str) \
414
 
    do { \
415
 
        if (*(str)) \
416
 
            vstring_sprintf_append((vstr), "%s%s", \
417
 
                                   VSTRING_LEN(vstr) ? " " : "", (str)); \
418
 
    } while (0)
419
 
 
420
 
    /*
421
 
     * The "exclude" policy table attribute overrides main.cf exclusion
422
 
     * lists.
423
 
     */
424
 
    if (session->tls_exclusions == 0) {
425
 
        session->tls_exclusions = vstring_alloc(10);
426
 
        ADD_EXCLUDE(session->tls_exclusions, var_smtp_tls_excl_ciph);
427
 
        ADD_EXCLUDE(session->tls_exclusions, mand_exclude);
428
 
    }
429
 
    ADD_EXCLUDE(session->tls_exclusions, also_exclude);
430
 
}
431
 
 
432
 
/* session_tls_init - session TLS parameters */
433
 
 
434
 
static void session_tls_init(SMTP_SESSION *session, const char *dest,
435
 
                                     const char *host, int flags)
436
 
{
437
 
    const char *myname = "session_tls_init";
438
 
    int     global_level;
439
 
    int     site_level;
440
 
 
441
 
    /*
442
 
     * Initialize all TLS related session properties.
443
 
     */
444
 
    session->tls_context = 0;
445
 
    session->tls_nexthop = 0;
446
 
    session->tls_level = TLS_LEV_NONE;
447
 
    session->tls_retry_plain = 0;
448
 
    session->tls_protocols = 0;
449
 
    session->tls_grade = 0;
450
 
    session->tls_exclusions = 0;
451
 
    session->tls_matchargv = 0;
452
 
 
453
 
    /*
454
 
     * Compute the global TLS policy. This is the default policy level when
455
 
     * no per-site policy exists. It also is used to override a wild-card
456
 
     * per-site policy.
457
 
     */
458
 
    if (*var_smtp_tls_level) {
459
 
        /* Require that var_smtp_tls_level is sanitized upon startup. */
460
 
        global_level = tls_level_lookup(var_smtp_tls_level);
461
 
        if (global_level == TLS_LEV_INVALID)
462
 
            msg_panic("%s: invalid TLS security level: \"%s\"",
463
 
                      myname, var_smtp_tls_level);
464
 
    } else if (var_smtp_enforce_tls) {
465
 
        global_level = var_smtp_tls_enforce_peername ?
466
 
            TLS_LEV_VERIFY : TLS_LEV_ENCRYPT;
467
 
    } else {
468
 
        global_level = var_smtp_use_tls ?
469
 
            TLS_LEV_MAY : TLS_LEV_NONE;
470
 
    }
471
 
    if (msg_verbose)
472
 
        msg_info("%s TLS level: %s", "global", policy_name(global_level));
473
 
 
474
 
    /*
475
 
     * Compute the per-site TLS enforcement level. For compatibility with the
476
 
     * original TLS patch, this algorithm is gives equal precedence to host
477
 
     * and next-hop policies.
478
 
     */
479
 
    site_level = TLS_LEV_NOTFOUND;
480
 
 
481
 
    if (tls_policy) {
482
 
        tls_policy_lookup(session, &site_level, dest, "next-hop destination");
483
 
    } else if (tls_per_site) {
484
 
        tls_site_lookup(&site_level, dest, "next-hop destination");
485
 
        if (strcasecmp(dest, host) != 0)
486
 
            tls_site_lookup(&site_level, host, "server hostname");
487
 
        if (msg_verbose)
488
 
            msg_info("%s TLS level: %s", "site", policy_name(site_level));
489
 
 
490
 
        /*
491
 
         * Override a wild-card per-site policy with a more specific global
492
 
         * policy.
493
 
         * 
494
 
         * With the original TLS patch, 1) a per-site ENCRYPT could not override
495
 
         * a global VERIFY, and 2) a combined per-site (NONE+MAY) policy
496
 
         * produced inconsistent results: it changed a global VERIFY into
497
 
         * NONE, while producing MAY with all weaker global policy settings.
498
 
         * 
499
 
         * With the current implementation, a combined per-site (NONE+MAY)
500
 
         * consistently overrides global policy with NONE, and global policy
501
 
         * can override only a per-site MAY wildcard. That is, specific
502
 
         * policies consistently override wildcard policies, and
503
 
         * (non-wildcard) per-site policies consistently override global
504
 
         * policies.
505
 
         */
506
 
        if (site_level == TLS_LEV_MAY && global_level > TLS_LEV_MAY)
507
 
            site_level = global_level;
508
 
    }
509
 
    if (site_level == TLS_LEV_NOTFOUND)
510
 
        session->tls_level = global_level;
511
 
    else
512
 
        session->tls_level = site_level;
513
 
 
514
 
    /*
515
 
     * Use main.cf protocols setting if not set in per-destination table.
516
 
     */
517
 
    if (session->tls_level > TLS_LEV_NONE && session->tls_protocols == 0)
518
 
        session->tls_protocols =
519
 
            mystrdup((session->tls_level == TLS_LEV_MAY) ?
520
 
                     var_smtp_tls_proto : var_smtp_tls_mand_proto);
521
 
 
522
 
    /*
523
 
     * Compute cipher grade (if set in per-destination table, else
524
 
     * set_cipher() uses main.cf settings) and security level dependent
525
 
     * cipher exclusion list.
526
 
     */
527
 
    set_cipher_grade(session);
528
 
 
529
 
    /*
530
 
     * Use main.cf cert_match setting if not set in per-destination table.
531
 
     */
532
 
    if (session->tls_matchargv == 0) {
533
 
        switch (session->tls_level) {
534
 
        case TLS_LEV_INVALID:
535
 
        case TLS_LEV_NONE:
536
 
        case TLS_LEV_MAY:
537
 
        case TLS_LEV_ENCRYPT:
538
 
            break;
539
 
        case TLS_LEV_FPRINT:
540
 
            session->tls_matchargv =
541
 
                argv_split(var_smtp_tls_fpt_cmatch, "\t\n\r, |");
542
 
            break;
543
 
        case TLS_LEV_VERIFY:
544
 
            session->tls_matchargv =
545
 
                argv_split(var_smtp_tls_vfy_cmatch, "\t\n\r, :");
546
 
            break;
547
 
        case TLS_LEV_SECURE:
548
 
            session->tls_matchargv =
549
 
                argv_split(var_smtp_tls_sec_cmatch, "\t\n\r, :");
550
 
            break;
551
 
        default:
552
 
            msg_panic("unexpected TLS security level: %d",
553
 
                      session->tls_level);
554
 
        }
555
 
    }
556
 
    if (msg_verbose && (tls_policy || tls_per_site))
557
 
        msg_info("%s TLS level: %s", "effective",
558
 
                 policy_name(session->tls_level));
559
 
}
560
 
 
561
 
#endif
562
 
 
563
120
/* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */
564
121
 
565
 
SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, const char *dest,
566
 
                                         const char *host, const char *addr,
567
 
                                         unsigned port, time_t start,
568
 
                                         int flags)
 
122
SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, SMTP_ITERATOR *iter,
 
123
                                         time_t start, int flags)
569
124
{
570
125
    SMTP_SESSION *session;
 
126
    const char *host = STR(iter->host);
 
127
    const char *addr = STR(iter->addr);
 
128
    unsigned port = iter->port;
571
129
 
572
130
    session = (SMTP_SESSION *) mymalloc(sizeof(*session));
573
131
    session->stream = stream;
574
 
    session->dest = mystrdup(dest);
575
 
    session->host = mystrdup(host);
576
 
    session->addr = mystrdup(addr);
 
132
    session->iterator = iter;
577
133
    session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
578
134
    session->helo = 0;
579
135
    session->port = port;
607
163
    smtp_sasl_connect(session);
608
164
#endif
609
165
 
610
 
    /*
611
 
     * Need to pass the session as a parameter when the new-style per-nexthop
612
 
     * policies can specify not only security level thresholds, but also how
613
 
     * security levels are defined.
614
 
     */
615
166
#ifdef USE_TLS
616
 
    session_tls_init(session, dest, host, flags);
 
167
    session->tls_context = 0;
 
168
    session->tls_retry_plain = 0;
 
169
    session->tls_nexthop = 0;
 
170
    session->tls = 0;                           /* TEMPORARY */
617
171
#endif
618
172
    session->state = 0;
619
173
    debug_peer_check(host, addr);
631
185
            tls_client_stop(smtp_tls_ctx, session->stream,
632
186
                          var_smtp_starttls_tmout, 0, session->tls_context);
633
187
    }
634
 
    if (session->tls_protocols)
635
 
        myfree(session->tls_protocols);
636
 
    if (session->tls_grade)
637
 
        myfree(session->tls_grade);
638
 
    if (session->tls_exclusions)
639
 
        vstring_free(session->tls_exclusions);
640
 
    if (session->tls_matchargv)
641
 
        argv_free(session->tls_matchargv);
642
188
#endif
643
189
    if (session->stream)
644
190
        vstream_fclose(session->stream);
645
 
    myfree(session->dest);
646
 
    myfree(session->host);
647
 
    myfree(session->addr);
648
191
    myfree(session->namaddr);
649
192
    myfree(session->namaddrport);
650
193
    if (session->helo)
672
215
int     smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop,
673
216
                                       VSTRING *endp_prop)
674
217
{
 
218
    SMTP_ITERATOR *iter = session->iterator;
675
219
    int     fd;
676
220
 
677
221
    /*
683
227
     * XXX It would be nice to have a VSTRING to VSTREAM adapter so that we can
684
228
     * serialize the properties with attr_print() instead of using ad-hoc,
685
229
     * non-reusable, code and hard-coded format strings.
 
230
     * 
 
231
     * TODO: save SASL username and password information so that we can
 
232
     * correctly save a reused authenticated connection.
 
233
     * 
686
234
     */
687
 
    vstring_sprintf(dest_prop, "%u",
 
235
    vstring_sprintf(dest_prop, "%s\n%s\n%s\n%u",
 
236
                    STR(iter->dest), STR(iter->host), STR(iter->addr),
688
237
                    session->features & SMTP_FEATURE_DESTINATION_MASK);
689
238
 
690
239
    /*
703
252
     * XXX Be sure to use unsigned types in the format string. Sign characters
704
253
     * would be rejected by the alldig() test on the reading end.
705
254
     */
706
 
    vstring_sprintf(endp_prop, "%u\n%s\n%s\n%s\n%u\n%u\n%lu",
 
255
    vstring_sprintf(endp_prop, "%u\n%u\n%lu",
707
256
                    session->reuse_count,
708
 
                    session->dest, session->host,
709
 
                    session->addr, session->port,
710
257
                    session->features & SMTP_FEATURE_ENDPOINT_MASK,
711
258
                    (long) session->expire_time);
712
259
 
732
279
 
733
280
/* smtp_session_activate - re-activate a passivated SMTP_SESSION object */
734
281
 
735
 
SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop,
 
282
SMTP_SESSION *smtp_session_activate(int fd, SMTP_ITERATOR *iter,
 
283
                                            VSTRING *dest_prop,
736
284
                                            VSTRING *endp_prop)
737
285
{
738
286
    const char *myname = "smtp_session_activate";
743
291
    const char *dest;
744
292
    const char *host;
745
293
    const char *addr;
746
 
    unsigned port;
747
294
    unsigned features;                  /* server features */
748
295
    time_t  expire_time;                /* session re-use expiration time */
749
296
    unsigned reuse_count;               /* # times reused */
762
309
        return (0);
763
310
    }
764
311
    reuse_count = atoi(prop);
765
 
    if ((dest = mystrtok(&endp_props, "\n")) == 0) {
766
 
        msg_warn("%s: missing cached session destination property", myname);
767
 
        return (0);
768
 
    }
769
 
    if ((host = mystrtok(&endp_props, "\n")) == 0) {
770
 
        msg_warn("%s: missing cached session hostname property", myname);
771
 
        return (0);
772
 
    }
773
 
    if ((addr = mystrtok(&endp_props, "\n")) == 0) {
774
 
        msg_warn("%s: missing cached session address property", myname);
775
 
        return (0);
776
 
    }
777
 
    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
778
 
        msg_warn("%s: bad cached session port property", myname);
779
 
        return (0);
780
 
    }
781
 
    port = atoi(prop);
782
 
 
783
312
    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
784
313
        msg_warn("%s: bad cached session features property", myname);
785
314
        return (0);
786
315
    }
787
316
    features = atoi(prop);
788
 
 
789
317
    if ((prop = mystrtok(&endp_props, "\n")) == 0 || !alldig(prop)) {
790
318
        msg_warn("%s: bad cached session expiration time property", myname);
791
319
        return (0);
796
324
    expire_time = strtoul(prop, 0, 10);
797
325
#endif
798
326
 
 
327
    /*
 
328
     * Clobber the iterator's current nexthop, host and address fields with
 
329
     * cached-connection information. This is done when a session is looked
 
330
     * up by request nexthop instead of address and port. It is the caller's
 
331
     * responsibility to save and restore the request nexthop with
 
332
     * SMTP_ITER_SAVE_DEST() and SMTP_ITER_RESTORE_DEST().
 
333
     * 
 
334
     * TODO: Eliminate the duplication between SMTP_ITERATOR and SMTP_SESSION.
 
335
     * 
 
336
     * TODO: restore SASL username and password information so that we can
 
337
     * correctly save a reused authenticated connection.
 
338
     */
799
339
    if (dest_prop && VSTRING_LEN(dest_prop)) {
800
340
        dest_props = STR(dest_prop);
 
341
        if ((dest = mystrtok(&dest_props, "\n")) == 0) {
 
342
            msg_warn("%s: missing cached session destination property", myname);
 
343
            return (0);
 
344
        }
 
345
        if ((host = mystrtok(&dest_props, "\n")) == 0) {
 
346
            msg_warn("%s: missing cached session hostname property", myname);
 
347
            return (0);
 
348
        }
 
349
        if ((addr = mystrtok(&dest_props, "\n")) == 0) {
 
350
            msg_warn("%s: missing cached session address property", myname);
 
351
            return (0);
 
352
        }
801
353
        if ((prop = mystrtok(&dest_props, "\n")) == 0 || !alldig(prop)) {
802
354
            msg_warn("%s: bad cached destination features property", myname);
803
355
            return (0);
804
356
        }
805
357
        features |= atoi(prop);
 
358
        SMTP_ITER_CLOBBER(iter, dest, host, addr);
806
359
    }
807
360
 
808
361
    /*
810
363
     */
811
364
#define NO_FLAGS        0
812
365
 
813
 
    session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), dest, host,
814
 
                                 addr, port, (time_t) 0, NO_FLAGS);
 
366
    session = smtp_session_alloc(vstream_fdopen(fd, O_RDWR), iter,
 
367
                                 (time_t) 0, NO_FLAGS);
815
368
    session->features = (features | SMTP_FEATURE_FROM_CACHE);
816
369
    CACHE_THIS_SESSION_UNTIL(expire_time);
817
370
    session->reuse_count = ++reuse_count;
819
372
    if (msg_verbose)
820
373
        msg_info("%s: dest=%s host=%s addr=%s port=%u features=0x%x, "
821
374
                 "ttl=%ld, reuse=%d",
822
 
                 myname, dest, host, addr, ntohs(port), features,
823
 
                 (long) (expire_time - time((time_t *) 0)), reuse_count);
 
375
                 myname, STR(iter->dest), STR(iter->host),
 
376
                 STR(iter->addr), ntohs(iter->port), features,
 
377
                 (long) (expire_time - time((time_t *) 0)),
 
378
                 reuse_count);
824
379
 
825
380
    /*
826
381
     * Re-activate the SASL attributes.