~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002110912

« back to all changes in this revision

Viewing changes to src/imap-login/client-authenticate.c

  • Committer: Bazaar Package Importer
  • Author(s): CHuck Short, Chuck Short
  • Date: 2009-11-06 00:47:29 UTC
  • mfrom: (4.1.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091106004729-i39n7v9e7d4h51f6
Tags: 1:1.2.6-1ubuntu1
* Merge from debian testing, remaining changes:
  Add new binary pkg dovecot-postfix that integrates postfix and dovecot
  automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restrictions
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
   + debian/dovecot-postfix.dirs: create backup directory for postfix's configuration
   + restart postfix and dovecot.
   + debian/dovecot-postfix.postrm:
     - remove all dovecot related configuration from postfix.
     - restart postfix and dovecot.
   + debian/dovecot-common.init:
     - check if /etc/dovecot/dovecot-postfix.conf exists and use it
       as the configuration file if so.
   + debian/patches/warning-ubuntu-postfix.dpatch
     - add warning about dovecot-postfix.conf in dovecot default 
       configuration file
   + debian/patches/dovecot-postfix.conf.diff:
     - Ubuntu server custom changes to the default dovecot configuration for
       better interfation with postfix
     - enable sieve plugin
   + debian/patches/dovecot-postfix.conf.diff:
     + Ubuntu server custom changes to the default dovecot configuration for
       better integration with postfix:
       - enable imap, pop3, imaps, pop3s and managesieve by default.
       - enable dovecot LDA (deliver).
       - enable SASL auth socket in postfix private directory.
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules:
       + install profile
     - debian/control:
       + Suggest ufw
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). LP: #254721
   + debian/control:
     - Update Vcs-* headers.
   + debian/rules:
     - Create emtpy stamp.h.in files in dovecot-sieve/ and dovecot-managesieve/
       if they're not there since empty files are not included in the diff.gz 
       file.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
   + Dropped:
     - debian/patches/security-CVE-2009-3235: Applied upstream.
     - debian/patches/fix-pop3-assertion.dpatch: Applied upstream.
     - dovecot-sieve and dovecot-managesieve: Use the debian patches instead.

  [Chuck Short]
  - Updated dovecot-sieve to 0.1.13.
  - Updated dovecot-managesieve to 0.11.9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
#include "safe-memset.h"
10
10
#include "str.h"
11
11
#include "str-sanitize.h"
 
12
#include "imap-resp-code.h"
12
13
#include "imap-parser.h"
13
14
#include "auth-client.h"
14
15
#include "client.h"
17
18
 
18
19
#include <stdlib.h>
19
20
 
 
21
#define AUTH_FAILURE_DELAY_INCREASE_MSECS 5000
 
22
 
20
23
#define IMAP_SERVICE_NAME "imap"
21
24
 
22
25
const char *client_authenticate_get_capabilities(bool secured)
52
55
                return;
53
56
 
54
57
        if (client->skip_line) {
55
 
                if (i_stream_next_line(client->input) == NULL)
 
58
                if (i_stream_next_line(client->common.input) == NULL)
56
59
                        return;
57
60
 
58
61
                client->skip_line = FALSE;
59
62
        }
60
63
 
61
64
        /* @UNSAFE */
62
 
        line = i_stream_next_line(client->input);
 
65
        line = i_stream_next_line(client->common.input);
63
66
        if (line == NULL)
64
67
                return;
65
68
 
66
 
        if (strcmp(line, "*") == 0) {
67
 
                sasl_server_auth_client_error(&client->common,
68
 
                                              "Authentication aborted");
69
 
        } else {
 
69
        if (strcmp(line, "*") == 0)
 
70
                sasl_server_auth_abort(&client->common);
 
71
        else {
 
72
                client_set_auth_waiting(client);
70
73
                auth_client_request_continue(client->common.auth_request, line);
71
74
                io_remove(&client->io);
72
75
 
75
78
        }
76
79
}
77
80
 
78
 
static void client_auth_failed(struct imap_client *client)
 
81
static void client_authfail_delay_timeout(struct imap_client *client)
79
82
{
80
 
        if (client->auth_initializing)
81
 
                return;
 
83
        timeout_remove(&client->to_authfail_delay);
82
84
 
83
85
        /* get back to normal client input. */
84
 
        if (client->io != NULL)
85
 
                io_remove(&client->io);
86
 
        client->io = io_add(client->common.fd, IO_READ,
87
 
                            client_input, client);
 
86
        i_assert(client->io == NULL);
 
87
        client->io = io_add(client->common.fd, IO_READ, client_input, client);
88
88
        client_input(client);
89
89
}
90
90
 
 
91
void client_auth_failed(struct imap_client *client, bool nodelay)
 
92
{
 
93
        unsigned int delay_msecs;
 
94
 
 
95
        client->common.auth_command_tag = NULL;
 
96
 
 
97
        if (client->auth_initializing)
 
98
                return;
 
99
 
 
100
        if (client->io != NULL)
 
101
                io_remove(&client->io);
 
102
        if (nodelay) {
 
103
                client->io = io_add(client->common.fd, IO_READ,
 
104
                                    client_input, client);
 
105
                client_input(client);
 
106
                return;
 
107
        }
 
108
 
 
109
        /* increase the timeout after each unsuccessful attempt, but don't
 
110
           increase it so high that the idle timeout would be triggered */
 
111
        delay_msecs = client->common.auth_attempts *
 
112
                AUTH_FAILURE_DELAY_INCREASE_MSECS;
 
113
        if (delay_msecs > CLIENT_LOGIN_IDLE_TIMEOUT_MSECS)
 
114
                delay_msecs = CLIENT_LOGIN_IDLE_TIMEOUT_MSECS - 1000;
 
115
 
 
116
        i_assert(client->to_authfail_delay == NULL);
 
117
        client->to_authfail_delay =
 
118
                timeout_add(delay_msecs, client_authfail_delay_timeout, client);
 
119
}
 
120
 
91
121
static bool client_handle_args(struct imap_client *client,
92
 
                               const char *const *args, bool success)
 
122
                               const char *const *args, bool success,
 
123
                               bool *nodelay_r)
93
124
{
94
125
        const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
 
126
        const char *master_user = NULL;
 
127
        const char *key, *value, *p;
 
128
        enum login_proxy_ssl_flags ssl_flags = 0;
95
129
        string_t *reply;
96
130
        unsigned int port = 143;
97
 
        bool proxy = FALSE, temp = FALSE, nologin = !success, proxy_self;
 
131
        unsigned int proxy_timeout_msecs = 0;
 
132
        bool proxy = FALSE, temp = FALSE, nologin = !success;
 
133
        bool authz_failure = FALSE;
98
134
 
 
135
        *nodelay_r = FALSE;
99
136
        for (; *args != NULL; args++) {
100
 
                if (strcmp(*args, "nologin") == 0)
 
137
                p = strchr(*args, '=');
 
138
                if (p == NULL) {
 
139
                        key = *args;
 
140
                        value = "";
 
141
                } else {
 
142
                        key = t_strdup_until(*args, p);
 
143
                        value = p + 1;
 
144
                }
 
145
                if (strcmp(key, "nologin") == 0)
101
146
                        nologin = TRUE;
102
 
                else if (strcmp(*args, "proxy") == 0)
 
147
                else if (strcmp(key, "nodelay") == 0)
 
148
                        *nodelay_r = TRUE;
 
149
                else if (strcmp(key, "proxy") == 0)
103
150
                        proxy = TRUE;
104
 
                else if (strcmp(*args, "temp") == 0)
 
151
                else if (strcmp(key, "temp") == 0)
105
152
                        temp = TRUE;
106
 
                else if (strncmp(*args, "reason=", 7) == 0)
107
 
                        reason = *args + 7;
108
 
                else if (strncmp(*args, "host=", 5) == 0)
109
 
                        host = *args + 5;
110
 
                else if (strncmp(*args, "port=", 5) == 0)
111
 
                        port = atoi(*args + 5);
112
 
                else if (strncmp(*args, "destuser=", 9) == 0)
113
 
                        destuser = *args + 9;
114
 
                else if (strncmp(*args, "pass=", 5) == 0)
115
 
                        pass = *args + 5;
116
 
                else if (strncmp(*args, "user=", 5) == 0) {
 
153
                else if (strcmp(key, "authz") == 0)
 
154
                        authz_failure = TRUE;
 
155
                else if (strcmp(key, "reason") == 0)
 
156
                        reason = value;
 
157
                else if (strcmp(key, "host") == 0)
 
158
                        host = value;
 
159
                else if (strcmp(key, "port") == 0)
 
160
                        port = atoi(value);
 
161
                else if (strcmp(key, "destuser") == 0)
 
162
                        destuser = value;
 
163
                else if (strcmp(key, "pass") == 0)
 
164
                        pass = value;
 
165
                else if (strcmp(key, "proxy_timeout") == 0)
 
166
                        proxy_timeout_msecs = 1000*atoi(value);
 
167
                else if (strcmp(key, "master") == 0)
 
168
                        master_user = value;
 
169
                else if (strcmp(key, "ssl") == 0) {
 
170
                        if (strcmp(value, "yes") == 0)
 
171
                                ssl_flags |= PROXY_SSL_FLAG_YES;
 
172
                        else if (strcmp(value, "any-cert") == 0) {
 
173
                                ssl_flags |= PROXY_SSL_FLAG_YES |
 
174
                                        PROXY_SSL_FLAG_ANY_CERT;
 
175
                        }
 
176
                } else if (strcmp(key, "starttls") == 0) {
 
177
                        ssl_flags |= PROXY_SSL_FLAG_STARTTLS;
 
178
                } else if (strcmp(key, "user") == 0) {
117
179
                        /* already handled in login-common */
118
180
                } else if (auth_debug) {
119
 
                        i_info("Ignoring unknown passdb extra field: %s",
120
 
                               *args);
 
181
                        i_info("Ignoring unknown passdb extra field: %s", key);
121
182
                }
122
183
        }
123
184
 
124
185
        if (destuser == NULL)
125
186
                destuser = client->common.virtual_user;
126
187
 
127
 
        proxy_self = proxy &&
128
 
                login_proxy_is_ourself(&client->common, host, port, destuser);
129
 
        if (proxy && !proxy_self) {
 
188
        if (proxy) {
130
189
                /* we want to proxy the connection to another server.
131
190
                   don't do this unless authentication succeeded. with
132
191
                   master user proxying we can get FAIL with proxy still set.
134
193
                   proxy host=.. [port=..] [destuser=..] pass=.. */
135
194
                if (!success)
136
195
                        return FALSE;
137
 
                if (imap_proxy_new(client, host, port, destuser, pass) < 0)
138
 
                        client_destroy_internal_failure(client);
 
196
                if (imap_proxy_new(client, host, port, destuser, master_user,
 
197
                                   pass, ssl_flags, proxy_timeout_msecs) < 0)
 
198
                        client_auth_failed(client, TRUE);
139
199
                return TRUE;
140
200
        }
141
201
 
142
 
        if (!proxy && host != NULL) {
 
202
        if (host != NULL) {
143
203
                /* IMAP referral
144
204
 
145
205
                   [nologin] referral host=.. [port=..] [destuser=..]
169
229
                        client_destroy_success(client, "Login with referral");
170
230
                        return TRUE;
171
231
                }
172
 
        } else if (nologin || proxy_self) {
 
232
        } else if (nologin) {
173
233
                /* Authentication went ok, but for some reason user isn't
174
234
                   allowed to log in. Shouldn't probably happen. */
175
 
                if (proxy_self) {
176
 
                        client_syslog(&client->common,
177
 
                                      "Proxying loops to itself");
178
 
                }
179
 
 
180
235
                reply = t_str_new(128);
181
236
                if (reason != NULL)
182
 
                        str_printfa(reply, "NO %s", reason);
183
 
                else if (temp || proxy_self)
184
 
                        str_append(reply, "NO "AUTH_TEMP_FAILED_MSG);
185
 
                else
186
 
                        str_append(reply, "NO "AUTH_FAILED_MSG);
 
237
                        str_printfa(reply, "NO [ALERT] %s", reason);
 
238
                else if (temp) {
 
239
                        str_append(reply, "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "
 
240
                                   AUTH_TEMP_FAILED_MSG);
 
241
                } else if (authz_failure) {
 
242
                        str_append(reply, "NO "IMAP_AUTHZ_FAILED_MSG);
 
243
                } else {
 
244
                        str_append(reply, "NO "IMAP_AUTH_FAILED_MSG);
 
245
                }
187
246
                client_send_tagline(client, str_c(reply));
188
247
        } else {
189
248
                /* normal login/failure */
190
249
                return FALSE;
191
250
        }
192
251
 
193
 
        i_assert(nologin || proxy_self);
 
252
        i_assert(nologin);
194
253
 
195
254
        if (!client->destroyed)
196
 
                client_auth_failed(client);
 
255
                client_auth_failed(client, *nodelay_r);
197
256
        return TRUE;
198
257
}
199
258
 
204
263
        struct const_iovec iov[3];
205
264
        const char *msg;
206
265
        size_t data_len;
 
266
        bool nodelay;
207
267
 
208
268
        i_assert(!client->destroyed ||
209
 
                 reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
 
269
                 reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
210
270
                 reply == SASL_SERVER_REPLY_MASTER_FAILED);
211
271
 
212
272
        switch (reply) {
214
274
                if (client->to_auth_waiting != NULL)
215
275
                        timeout_remove(&client->to_auth_waiting);
216
276
                if (args != NULL) {
217
 
                        if (client_handle_args(client, args, TRUE))
 
277
                        if (client_handle_args(client, args, TRUE, &nodelay))
218
278
                                break;
219
279
                }
220
 
 
221
 
                client_send_tagline(client, "OK Logged in.");
222
280
                client_destroy_success(client, "Login");
223
281
                break;
224
282
        case SASL_SERVER_REPLY_AUTH_FAILED:
225
 
        case SASL_SERVER_REPLY_CLIENT_ERROR:
 
283
        case SASL_SERVER_REPLY_AUTH_ABORTED:
226
284
                if (client->to_auth_waiting != NULL)
227
285
                        timeout_remove(&client->to_auth_waiting);
228
286
                if (args != NULL) {
229
 
                        if (client_handle_args(client, args, FALSE))
 
287
                        if (client_handle_args(client, args, FALSE, &nodelay))
230
288
                                break;
231
289
                }
232
290
 
233
 
                msg = reply == SASL_SERVER_REPLY_AUTH_FAILED ? "NO " : "BAD ";
234
 
                msg = t_strconcat(msg, data != NULL ? data : AUTH_FAILED_MSG,
235
 
                                  NULL);
 
291
                if (reply == SASL_SERVER_REPLY_AUTH_ABORTED)
 
292
                        msg = "BAD Authentication aborted by client.";
 
293
                else if (data == NULL)
 
294
                        msg = "NO "IMAP_AUTH_FAILED_MSG;
 
295
                else
 
296
                        msg = t_strconcat("NO [ALERT] ", data, NULL);
236
297
                client_send_tagline(client, msg);
237
298
 
238
299
                if (!client->destroyed)
239
 
                        client_auth_failed(client);
 
300
                        client_auth_failed(client, nodelay);
240
301
                break;
241
302
        case SASL_SERVER_REPLY_MASTER_FAILED:
242
303
                if (data == NULL)
262
323
                   to call client_destroy() in here. */
263
324
                (void)o_stream_sendv(client->output, iov, 3);
264
325
 
 
326
                if (client->to_auth_waiting != NULL)
 
327
                        timeout_remove(&client->to_auth_waiting);
 
328
 
265
329
                i_assert(client->io == NULL);
266
330
                client->io = io_add(client->common.fd, IO_READ,
267
331
                                    client_auth_input, client);
275
339
static int client_auth_begin(struct imap_client *client, const char *mech_name,
276
340
                             const char *init_resp)
277
341
{
 
342
        client->common.auth_command_tag = client->cmd_tag;
 
343
 
278
344
        client_ref(client);
279
345
        client->auth_initializing = TRUE;
280
346
        sasl_server_auth_begin(&client->common, IMAP_SERVICE_NAME, mech_name,
305
371
                init_resp = IMAP_ARG_STR(&args[1]);
306
372
        }
307
373
 
 
374
        if (!client->common.secured && ssl_required) {
 
375
                if (verbose_auth) {
 
376
                        client_syslog(&client->common, "Login failed: "
 
377
                                      "SSL required for authentication");
 
378
                }
 
379
                client->common.auth_attempts++;
 
380
                client_send_tagline(client,
 
381
                        "NO ["IMAP_RESP_CODE_PRIVACYREQUIRED"] "
 
382
                        "Authentication not allowed until SSL/TLS is enabled.");
 
383
                return 1;
 
384
        }
 
385
 
308
386
        mech_name = IMAP_ARG_STR(&args[0]);
309
387
        if (*mech_name == '\0')
310
388
                return -1;
338
416
                        "* BAD [ALERT] Plaintext authentication not allowed "
339
417
                        "without SSL/TLS, but your client did it anyway. "
340
418
                        "If anyone was listening, the password was exposed.");
341
 
                client_send_tagline(client, "NO "AUTH_PLAINTEXT_DISABLED_MSG);
 
419
                client_send_tagline(client, "NO ["IMAP_RESP_CODE_CLIENTBUG"] "
 
420
                                    AUTH_PLAINTEXT_DISABLED_MSG);
342
421
                return 1;
343
422
        }
344
423