summaryrefslogtreecommitdiffstats
path: root/src/smtp/smtp_sasl_proto.c
blob: 30ae9eca6bf8957323e837da78b6211d0b8d61e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*++
/* NAME
/*	smtp_sasl_proto 3
/* SUMMARY
/*	Postfix SASL interface for SMTP client
/* SYNOPSIS
/*	#include smtp_sasl.h
/*
/*	void	smtp_sasl_helo_auth(state, words)
/*	SMTP_STATE *state;
/*	const char *words;
/*
/*	int	smtp_sasl_helo_login(state)
/*	SMTP_STATE *state;
/* DESCRIPTION
/*	This module contains random chunks of code that implement
/*	the SMTP protocol interface for SASL negotiation. The goal
/*	is to reduce clutter in the main SMTP client source code.
/*
/*	smtp_sasl_helo_auth() processes the AUTH option in the
/*	SMTP server's EHLO response.
/*
/*	smtp_sasl_helo_login() authenticates the SMTP client to the
/*	SMTP 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
/*
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, 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>
#include <stringops.h>

/* Global library. */

#include <mail_params.h>
#include <sasl_mech_filter.h>

/* Application-specific. */

#include "smtp.h"
#include "smtp_sasl.h"

#ifdef USE_SASL_AUTH

/* smtp_sasl_helo_auth - handle AUTH option in EHLO reply */

void    smtp_sasl_helo_auth(SMTP_SESSION *session, const char *words)
{
    const char *mech_list = sasl_mech_filter(smtp_sasl_mechs, words);
    char   *junk;

    /*
     * XXX If the server offers no compatible authentication mechanisms, then
     * pretend that the server doesn't support SASL authentication.
     * 
     * XXX If the server offers multiple different lists, concatenate them. Let
     * the SASL library worry about duplicates.
     */
    if (session->sasl_mechanism_list) {
	if (strcasecmp(session->sasl_mechanism_list, mech_list) != 0
	    && strlen(mech_list) > 0
	    && strlen(session->sasl_mechanism_list) < var_line_limit) {
	    junk = concatenate(session->sasl_mechanism_list, " ", mech_list,
			       (char *) 0);
	    myfree(session->sasl_mechanism_list);
	    session->sasl_mechanism_list = junk;
	}
	return;
    }
    if (strlen(mech_list) > 0) {
	session->sasl_mechanism_list = mystrdup(mech_list);
    } else {
	msg_warn(*words ? "%s offered no supported AUTH mechanisms: '%s'" :
		 "%s offered null AUTH mechanism list%s",
		 session->namaddrport, words);
    }
    session->features |= SMTP_FEATURE_AUTH;
}

/* smtp_sasl_helo_login - perform SASL login */

int     smtp_sasl_helo_login(SMTP_STATE *state)
{
    SMTP_SESSION *session = state->session;
    DSN_BUF *why = state->why;
    int     ret;

    /*
     * Skip authentication when no authentication info exists for this
     * server, so that we talk to each other like strangers.
     */
    if (smtp_sasl_passwd_lookup(session) == 0) {
	session->features &= ~SMTP_FEATURE_AUTH;
	return 0;
    }

    /*
     * Otherwise, if authentication information exists, assume that
     * authentication is required, and assume that an authentication error is
     * recoverable from the message delivery point of view. An authentication
     * error is unrecoverable from a session point of view - the session will
     * not be reused.
     */
    ret = 0;
    if (session->sasl_mechanism_list == 0) {
	dsb_simple(why, "4.7.0", "SASL authentication failed: "
		   "server %s offered no compatible authentication mechanisms for this type of connection security",
		   session->namaddr);
	ret = smtp_sess_fail(state);
	/* Session reuse is disabled. */
    } else {
#ifndef USE_TLS
	smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_OPTS), var_smtp_sasl_opts);
#else
	if (session->tls_context == 0)
	    smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_OPTS),
			    var_smtp_sasl_opts);
	else if (TLS_CERT_IS_MATCHED(session->tls_context))
	    smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_TLSV_OPTS),
			    var_smtp_sasl_tlsv_opts);
	else
	    smtp_sasl_start(session, VAR_LMTP_SMTP(SASL_TLS_OPTS),
			    var_smtp_sasl_tls_opts);
#endif
	if (smtp_sasl_authenticate(session, why) <= 0) {
	    ret = smtp_sess_fail(state);
	    /* Session reuse is disabled. */
	}
    }
    return (ret);
}

#endif