~ubuntu-branches/ubuntu/wily/dovecot/wily

« back to all changes in this revision

Viewing changes to dovecot-managesieve/src/managesieve-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:
1
 
/* Copyright (c) 2002-2009 Dovecot Sieve authors, see the included COPYING file
2
 
 */
3
 
 
4
 
#include "common.h"
5
 
#include "base64.h"
6
 
#include "buffer.h"
7
 
#include "ioloop.h"
8
 
#include "istream.h"
9
 
#include "ostream.h"
10
 
#include "safe-memset.h"
11
 
#include "str.h"
12
 
#include "str-sanitize.h"
13
 
 
14
 
#include "managesieve-parser.h"
15
 
#include "managesieve-quote.h"
16
 
#include "auth-client.h"
17
 
#include "client.h"
18
 
#include "client-authenticate.h"
19
 
#include "managesieve-proxy.h"
20
 
 
21
 
#include <unistd.h>
22
 
#include <stdlib.h>
23
 
 
24
 
#define MANAGESIEVE_SERVICE_NAME "managesieve"
25
 
 
26
 
/* FIXME: The use of the ANONYMOUS mechanism is currently denied 
27
 
 */
28
 
static bool _sasl_mechanism_acceptable
29
 
        (const struct auth_mech_desc *mech, bool secured) {
30
 
 
31
 
        /* a) transport is secured
32
 
           b) auth mechanism isn't plaintext
33
 
       c) we allow insecure authentication
34
 
         */
35
 
 
36
 
        if ((mech->flags & MECH_SEC_PRIVATE) == 0 &&
37
 
                (mech->flags & MECH_SEC_ANONYMOUS) == 0 &&
38
 
                (secured || !disable_plaintext_auth ||
39
 
                (mech->flags & MECH_SEC_PLAINTEXT) == 0)) {
40
 
                return 1;     
41
 
        }  
42
 
 
43
 
        return 0;
44
 
}
45
 
 
46
 
const char *client_authenticate_get_capabilities(bool secured)
47
 
{
48
 
        const struct auth_mech_desc *mech;
49
 
        unsigned int i, count;
50
 
        string_t *str;
51
 
 
52
 
        str = t_str_new(128);
53
 
        mech = auth_client_get_available_mechs(auth_client, &count);
54
 
 
55
 
        if ( count > 0 ) {
56
 
                if ( _sasl_mechanism_acceptable(&(mech[0]), secured) ) {
57
 
                        str_append(str, mech[0].name);
58
 
                }
59
 
     
60
 
                for (i = 1; i < count; i++) {
61
 
                        if ( _sasl_mechanism_acceptable(&(mech[i]), secured) ) {
62
 
                                str_append_c(str, ' ');
63
 
                                str_append(str, mech[i].name);
64
 
                        }
65
 
                }
66
 
        }
67
 
 
68
 
        return str_c(str);
69
 
}
70
 
 
71
 
static void client_auth_input(struct managesieve_client *client)
72
 
{
73
 
        struct managesieve_arg *args;
74
 
        const char *msg;
75
 
        char *line;
76
 
        bool fatal;
77
 
 
78
 
        if (client->destroyed)
79
 
                return;
80
 
 
81
 
        if (!client_read(client))
82
 
                return;
83
 
 
84
 
        if (client->skip_line) {
85
 
                if (i_stream_next_line(client->input) == NULL)
86
 
                        return;
87
 
 
88
 
                client->skip_line = FALSE;
89
 
        }
90
 
 
91
 
        switch (managesieve_parser_read_args(client->parser, 0, 0, &args)) {
92
 
        case -1:
93
 
                /* error */
94
 
                msg = managesieve_parser_get_error(client->parser, &fatal);
95
 
                if (fatal) {
96
 
                        /* FIXME: What to do? */
97
 
                }
98
 
          
99
 
                sasl_server_auth_client_error(&client->common, msg);
100
 
                return;
101
 
        case -2:
102
 
                /* not enough data */
103
 
                return;
104
 
        }
105
 
 
106
 
        if (args[0].type != MANAGESIEVE_ARG_STRING || 
107
 
                args[1].type != MANAGESIEVE_ARG_EOL) {
108
 
                sasl_server_auth_client_error(&client->common, "Invalid AUTHENTICATE client response.");
109
 
                return;
110
 
        }
111
 
 
112
 
        line = MANAGESIEVE_ARG_STR(&args[0]);
113
 
 
114
 
    auth_client_request_continue(client->common.auth_request, line);
115
 
        io_remove(&client->io);
116
 
 
117
 
        /* clear sensitive data */
118
 
        safe_memset(line, 0, strlen(line));
119
 
}
120
 
 
121
 
static void client_auth_failed(struct managesieve_client *client)
122
 
{
123
 
    /* get back to normal client input. */
124
 
    if (client->io != NULL)
125
 
        io_remove(&client->io);
126
 
    client->io = io_add(client->common.fd, IO_READ,
127
 
                client_input, client);
128
 
}
129
 
 
130
 
static bool client_handle_args(struct managesieve_client *client,
131
 
                               const char *const *args, bool success)
132
 
{
133
 
        const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
134
 
        string_t *resp_code;
135
 
        unsigned int port = 2000;
136
 
        bool proxy = FALSE, temp = FALSE, nologin = !success, proxy_self;
137
 
 
138
 
        for (; *args != NULL; args++) {
139
 
                if (strcmp(*args, "nologin") == 0)
140
 
                        nologin = TRUE;
141
 
                else if (strcmp(*args, "proxy") == 0)
142
 
                        proxy = TRUE;
143
 
                else if (strcmp(*args, "temp") == 0)
144
 
                        temp = TRUE;
145
 
                else if (strncmp(*args, "reason=", 7) == 0)
146
 
                        reason = *args + 7;
147
 
                else if (strncmp(*args, "host=", 5) == 0)
148
 
                        host = *args + 5;
149
 
                else if (strncmp(*args, "port=", 5) == 0)
150
 
                        port = atoi(*args + 5);
151
 
                else if (strncmp(*args, "destuser=", 9) == 0)
152
 
                        destuser = *args + 9;
153
 
                else if (strncmp(*args, "pass=", 5) == 0)
154
 
                        pass = *args + 5;
155
 
        }
156
 
 
157
 
        if (destuser == NULL)
158
 
                destuser = client->common.virtual_user;
159
 
 
160
 
         proxy_self = proxy &&
161
 
        login_proxy_is_ourself(&client->common, host, port, destuser);  
162
 
        if (proxy && !proxy_self) {
163
 
                /* we want to proxy the connection to another server.
164
 
                don't do this unless authentication succeeded. with
165
 
                master user proxying we can get FAIL with proxy still set.
166
 
 
167
 
                proxy host=.. [port=..] [destuser=..] pass=.. */
168
 
 
169
 
                if (!success)
170
 
                        return FALSE;
171
 
                if (managesieve_proxy_new(client, host, port, destuser, pass) < 0)
172
 
                        client_destroy_internal_failure(client);
173
 
                return TRUE;
174
 
        }
175
 
 
176
 
        if (!proxy && host != NULL) {
177
 
                /* MANAGESIEVE referral
178
 
 
179
 
                   [nologin] referral host=.. [port=..] [destuser=..]
180
 
                   [reason=..]
181
 
 
182
 
                   NO (REFERRAL sieve://user;AUTH=mech@host:port/) Can't login.
183
 
                   OK (...) Logged in, but you should use this server instead.
184
 
                   .. [REFERRAL ..] (Reason from auth server)
185
 
                */
186
 
                resp_code = t_str_new(128);
187
 
                str_printfa(resp_code, "REFERRAL sieve://%s;AUTH=%s@%s",
188
 
                            destuser, client->common.auth_mech_name, host);
189
 
                if (port != 2000)
190
 
                        str_printfa(resp_code, ":%u", port);
191
 
 
192
 
                if (reason == NULL) {
193
 
                        if (nologin)
194
 
                                reason = "Try this server instead.";
195
 
                        else 
196
 
                                reason = "Logged in, but you should use "
197
 
                                        "this server instead.";
198
 
                }
199
 
 
200
 
                if (!nologin) {
201
 
                        client_send_okresp(client, str_c(resp_code), reason);
202
 
                        client_destroy(client, "Login with referral");
203
 
                        return TRUE;
204
 
                }
205
 
                client_send_noresp(client, str_c(resp_code), reason);
206
 
        } else if (nologin || proxy_self) {
207
 
                /* Authentication went ok, but for some reason user isn't
208
 
                   allowed to log in. Shouldn't probably happen. */
209
 
                if (proxy_self) {
210
 
                        client_syslog(&client->common,
211
 
                                "Proxying loops to itself");
212
 
        }
213
 
 
214
 
                if (reason != NULL)
215
 
                        client_send_no(client, reason);
216
 
                else if (temp)
217
 
                        client_send_no(client, AUTH_TEMP_FAILED_MSG);           
218
 
                else
219
 
                        client_send_no(client, AUTH_FAILED_MSG);
220
 
        } else {
221
 
                /* normal login/failure */
222
 
                return FALSE;
223
 
        }
224
 
 
225
 
        i_assert(nologin || proxy_self);
226
 
 
227
 
        managesieve_parser_reset(client->parser);
228
 
 
229
 
        if (!client->destroyed) 
230
 
                client_auth_failed(client);
231
 
        return TRUE;
232
 
}
233
 
 
234
 
static void sasl_callback(struct client *_client, enum sasl_server_reply reply,
235
 
                          const char *data, const char *const *args)
236
 
{
237
 
        struct managesieve_client *client = (struct managesieve_client *)_client;
238
 
        string_t *str;
239
 
 
240
 
        i_assert(!client->destroyed ||
241
 
                reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
242
 
                reply == SASL_SERVER_REPLY_MASTER_FAILED);
243
 
 
244
 
        client->skip_line = TRUE;
245
 
 
246
 
        switch (reply) {
247
 
        case SASL_SERVER_REPLY_SUCCESS:
248
 
                if ( client->to_auth_waiting != NULL )
249
 
                        timeout_remove(&client->to_auth_waiting);
250
 
                if (args != NULL) {
251
 
                        if (client_handle_args(client, args, TRUE))
252
 
                                break;
253
 
                }
254
 
 
255
 
                client_destroy(client, "Login");
256
 
                break;
257
 
        case SASL_SERVER_REPLY_AUTH_FAILED:
258
 
        case SASL_SERVER_REPLY_CLIENT_ERROR:
259
 
                if ( client->to_auth_waiting != NULL )
260
 
                        timeout_remove(&client->to_auth_waiting);
261
 
                if (args != NULL) {
262
 
                        if (client_handle_args(client, args, FALSE))
263
 
                                break;
264
 
                }
265
 
 
266
 
                client_send_no(client, data != NULL ? data : AUTH_FAILED_MSG);
267
 
 
268
 
                managesieve_parser_reset(client->parser);
269
 
 
270
 
                if (!client->destroyed) 
271
 
                        client_auth_failed(client);
272
 
                break;
273
 
        case SASL_SERVER_REPLY_MASTER_FAILED:
274
 
                if (data == NULL)
275
 
                        client_destroy_internal_failure(client);
276
 
                else {
277
 
                        client_send_no(client, data);
278
 
                        client_destroy(client, data);
279
 
                }
280
 
                break;
281
 
        case SASL_SERVER_REPLY_CONTINUE:
282
 
                t_push();
283
 
                str = t_str_new(256);
284
 
                managesieve_quote_append_string(str, data, TRUE);
285
 
                str_append(str, "\r\n");
286
 
                                
287
 
                /* don't check return value here. it gets tricky if we try
288
 
                   to call client_destroy() in here. */
289
 
                (void)o_stream_send(client->output, str_c(str), str_len(str));
290
 
                t_pop();
291
 
 
292
 
                managesieve_parser_reset(client->parser);
293
 
 
294
 
                i_assert(client->io == NULL);
295
 
        client->io = io_add(client->common.fd, IO_READ,
296
 
                    client_auth_input, client);
297
 
        client_auth_input(client);
298
 
                
299
 
                return;
300
 
        }
301
 
 
302
 
        client_unref(client);
303
 
}
304
 
 
305
 
int cmd_authenticate(struct managesieve_client *client, struct managesieve_arg *args)
306
 
{
307
 
        const char *mech_name, *init_resp = NULL;
308
 
 
309
 
        /* one mandatory argument: authentication mechanism name */
310
 
        if (args[0].type != MANAGESIEVE_ARG_STRING)
311
 
                return -1;
312
 
        if (args[1].type != MANAGESIEVE_ARG_EOL) {
313
 
                /* optional SASL initial response */
314
 
                if (args[1].type != MANAGESIEVE_ARG_STRING ||
315
 
                    args[2].type != MANAGESIEVE_ARG_EOL)
316
 
                        return -1;
317
 
                init_resp = MANAGESIEVE_ARG_STR(&args[1]);
318
 
        }
319
 
 
320
 
        mech_name = MANAGESIEVE_ARG_STR(&args[0]);
321
 
        if (*mech_name == '\0') 
322
 
                return -1;
323
 
 
324
 
        /* FIXME: This refuses the ANONYMOUS mechanism. 
325
 
         *   This can be removed once anonymous login is implemented according to the 
326
 
         *   draft RFC. - Stephan
327
 
         */
328
 
        if ( strncasecmp(mech_name, "ANONYMOUS", 9) == 0 ) {
329
 
                client_send_no(client, "ANONYMOUS mechanism is not implemented.");              
330
 
                return 0;
331
 
        }
332
 
 
333
 
    client_ref(client);
334
 
    sasl_server_auth_begin(&client->common, MANAGESIEVE_SERVICE_NAME, mech_name,
335
 
                   init_resp, sasl_callback);
336
 
    if (!client->common.authenticating)
337
 
        return 1;
338
 
 
339
 
    /* don't handle input until we get the initial auth reply */
340
 
    if (client->io != NULL)
341
 
        io_remove(&client->io);
342
 
    client_set_auth_waiting(client);
343
 
 
344
 
        managesieve_parser_reset(client->parser);
345
 
 
346
 
        return 0;
347
 
}
348