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

« back to all changes in this revision

Viewing changes to dovecot-managesieve/src/managesieve-login/managesieve-proxy.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 <string.h>
5
 
#include "common.h"
6
 
#include "ioloop.h"
7
 
#include "istream.h"
8
 
#include "ostream.h"
9
 
#include "str.h"
10
 
#include "str-sanitize.h"
11
 
#include "safe-memset.h"
12
 
#include "buffer.h"
13
 
#include "base64.h"
14
 
#include "client.h"
15
 
#include "managesieve-quote.h"
16
 
#include "managesieve-proxy.h"
17
 
#include "managesieve-parser.h"
18
 
 
19
 
static int proxy_input_line(struct managesieve_client *client,
20
 
                            struct ostream *output, const char *line)
21
 
{
22
 
        string_t *str;
23
 
        const char *msg;
24
 
 
25
 
        i_assert(!client->destroyed);
26
 
 
27
 
        if (!client->proxy_login_sent) {
28
 
                string_t *plain_login, *base64;
29
 
                struct istream *input;
30
 
                struct managesieve_parser *parser;
31
 
                struct managesieve_arg *args;
32
 
                int ret;
33
 
                bool fatal = FALSE, greeting_recvd = FALSE;
34
 
 
35
 
                /* Server will send greeting which is actually a capability 
36
 
                 * response. Output from a faulty server should not be accepted,
37
 
                 * so the response is parsed and verified.
38
 
                 */
39
 
 
40
 
                /* Build an input stream for the managesieve parser 
41
 
                 *  FIXME: It would be nice if the line-wise parsing could be
42
 
                 *    substituded by something similar to the command line interpreter.
43
 
                 *    However, the current login_proxy structure does not make streams
44
 
                 *    known until inside proxy_input handler.
45
 
                 */
46
 
                line = t_strconcat(line, "\r\n", NULL);
47
 
                input = i_stream_create_from_data(line, strlen(line));
48
 
                parser = managesieve_parser_create(input, NULL, MAX_MANAGESIEVE_LINE);
49
 
                managesieve_parser_reset(parser);
50
 
 
51
 
            /* Parse input 
52
 
                 *  FIXME: Theoretically the OK response could include a 
53
 
                 *   response code which could be rejected by the parser. 
54
 
                 */ 
55
 
                (void)i_stream_read(input);
56
 
                ret = managesieve_parser_read_args(parser, 2, 0, &args);
57
 
                
58
 
                if ( ret >= 1 ) {
59
 
                        if ( args[0].type == MANAGESIEVE_ARG_ATOM &&
60
 
                        strncasecmp(MANAGESIEVE_ARG_STR(&(args[0])), "OK", 2) == 0 ) {
61
 
 
62
 
                                /* Received OK response; greeting is finished */
63
 
                                greeting_recvd = TRUE;
64
 
 
65
 
                } else if ( args[0].type == MANAGESIEVE_ARG_STRING ) {
66
 
                        if ( strncasecmp(MANAGESIEVE_ARG_STR(&(args[0])), "SASL", 4) == 0 ) {
67
 
                                        /* Check whether the server supports the SASL mechanism 
68
 
                                 * we are going to use (currently only PLAIN supported). 
69
 
                                         */
70
 
                                        if ( ret == 2 && args[1].type == MANAGESIEVE_ARG_STRING ) {
71
 
                                                char *p = MANAGESIEVE_ARG_STR(&(args[1]));
72
 
                                                int mech_found = FALSE;
73
 
                                                                
74
 
                                                while ( p != NULL ) {
75
 
                                                        if ( strncasecmp(p, "PLAIN", 5) == 0 ) {
76
 
                                                                mech_found = TRUE;
77
 
                                                                break;
78
 
                                        }
79
 
 
80
 
                                                        p = strchr(p, ' ');
81
 
                                                        if ( p != NULL ) p++;
82
 
                                                }        
83
 
 
84
 
                                                if ( !mech_found ) {
85
 
                                                        client_syslog(&client->common, "proxy: "
86
 
                                                        "Server does not support required PLAIN SASL mechanism.");
87
 
 
88
 
                                                        fatal = TRUE;
89
 
                                                }       
90
 
                                        }
91
 
                                }       
92
 
                        } else {
93
 
                                /* Do not accept faulty server */
94
 
                        client_syslog(&client->common, t_strdup_printf("proxy: "
95
 
                                "Remote returned with invalid capability/greeting line: %s",
96
 
                                str_sanitize(line,160)));
97
 
 
98
 
                                fatal = TRUE;
99
 
                        }
100
 
 
101
 
        } else if ( ret == -2 ) {
102
 
                        /* Parser needs more data (not possible on mem stream) */
103
 
                        i_unreached();
104
 
 
105
 
        } else if ( ret < 0 ) {
106
 
                        const char *error_str = managesieve_parser_get_error(parser, &fatal);
107
 
                        error_str = (error_str != NULL ? error_str : "unknown (bug)" );
108
 
        
109
 
                        /* Do not accept faulty server */
110
 
                        client_syslog(&client->common, t_strdup_printf("proxy: "
111
 
                                "Protocol parse error(%d) in capability/greeting line: %s (line='%s')",
112
 
                                ret, error_str, line));
113
 
        
114
 
                        fatal = TRUE;
115
 
                }
116
 
 
117
 
                /* Cleanup parser */
118
 
        managesieve_parser_destroy(&parser);
119
 
            i_stream_destroy(&input);
120
 
 
121
 
                /* Time to exit if greeting was not accepted */
122
 
                if ( fatal ) {                  
123
 
                        client_destroy_internal_failure(client);
124
 
        
125
 
                        return -1;
126
 
                }
127
 
 
128
 
                /* Wait until greeting is received completely */
129
 
                if ( !greeting_recvd ) return 0;
130
 
 
131
 
                /* Send AUTHENTICATE "PLAIN" command 
132
 
         *  FIXME: Currently there seems to be no SASL client implementation,
133
 
                 *    so only implement the trivial PLAIN method 
134
 
                 *    - Stephan
135
 
             */
136
 
                t_push();
137
 
        
138
 
                /*   Base64-encode the credentials 
139
 
                 *         [authorization ID \0 authentication ID \0 pass]
140
 
             */
141
 
                plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
142
 
                buffer_append_c(plain_login, '\0');
143
 
                buffer_append(plain_login, client->proxy_user, strlen(client->proxy_user));
144
 
                buffer_append_c(plain_login, '\0');
145
 
                buffer_append(plain_login, client->proxy_password, strlen(client->proxy_password));
146
 
 
147
 
                base64 = buffer_create_dynamic(pool_datastack_create(),
148
 
                        MAX_BASE64_ENCODED_SIZE(plain_login->used));
149
 
                base64_encode(plain_login->data, plain_login->used, base64);
150
 
 
151
 
                /*   Send command */
152
 
                str = t_str_new(128);
153
 
                str_append(str, "AUTHENTICATE \"PLAIN\" ");
154
 
                managesieve_quote_append_string(str, str_c(base64),  FALSE);
155
 
                str_append(str, "\r\n");
156
 
                (void)o_stream_send(output, str_data(str), str_len(str));
157
 
                
158
 
                /*   Cleanup */
159
 
                t_pop();
160
 
 
161
 
                /* Cleanup sensitive data */
162
 
                safe_memset(client->proxy_password, 0,
163
 
                           strlen(client->proxy_password));
164
 
                i_free(client->proxy_password);
165
 
                client->proxy_password = NULL;
166
 
                client->proxy_login_sent = TRUE;
167
 
 
168
 
                return 0;
169
 
 
170
 
        } else { 
171
 
                if (strncasecmp(line, "OK ", 3) == 0) {
172
 
                        /* Login successful. Send this line to client. */
173
 
                        o_stream_cork(client->output);
174
 
                        (void)o_stream_send_str(client->output, line);
175
 
                        (void)o_stream_send(client->output, "\r\n", 2);
176
 
                        o_stream_uncork(client->output);
177
 
 
178
 
                        msg = t_strdup_printf("proxy(%s): started proxying to %s:%u",
179
 
                                      client->common.virtual_user,
180
 
                                      login_proxy_get_host(client->proxy),
181
 
                                      login_proxy_get_port(client->proxy));
182
 
 
183
 
                        (void)client_skip_line(client);
184
 
                        login_proxy_detach(client->proxy, client->input,
185
 
                                   client->output);
186
 
 
187
 
                        client->proxy = NULL;
188
 
                        client->input = NULL;
189
 
                        client->output = NULL;
190
 
                        client->common.fd = -1;
191
 
                        client_destroy(client, msg);
192
 
 
193
 
                } else {
194
 
                        /* Login failed. Send our own failure reply so client can't
195
 
                         * figure out if user exists or not just by looking at the
196
 
                         * reply string.
197
 
                         */
198
 
                        client_send_no(client, AUTH_FAILED_MSG);
199
 
 
200
 
                        /* allow client input again */
201
 
                        i_assert(client->io == NULL);
202
 
                        client->io = io_add(client->common.fd, IO_READ,
203
 
                                    client_input, client);
204
 
 
205
 
                        login_proxy_free(client->proxy);
206
 
                        client->proxy = NULL;
207
 
 
208
 
                        i_free(client->proxy_user);
209
 
                        client->proxy_user = NULL;
210
 
                }
211
 
 
212
 
                return -1;
213
 
        }
214
 
 
215
 
        i_unreached();
216
 
        return -1;
217
 
}
218
 
 
219
 
static void proxy_input(struct istream *input, struct ostream *output,
220
 
                        void *context)
221
 
{
222
 
        struct managesieve_client *client = context;
223
 
        const char *line;
224
 
 
225
 
        if (input == NULL) {
226
 
                if (client->io != NULL) {
227
 
                        /* remote authentication failed, we're just
228
 
                           freeing the proxy */
229
 
                        return;
230
 
                }
231
 
 
232
 
                if (client->destroyed) {
233
 
                        /* we came here from client_destroy() */
234
 
                        return;
235
 
                }
236
 
 
237
 
                /* failed for some reason, probably server disconnected */
238
 
                client_send_byeresp(client, "TRYLATER", "Temporary login failure.");
239
 
                client_destroy(client, NULL);
240
 
                return;
241
 
        }
242
 
 
243
 
        i_assert(!client->destroyed);
244
 
 
245
 
        switch (i_stream_read(input)) {
246
 
        case -2:
247
 
                /* buffer full */
248
 
                client_syslog(&client->common, "proxy: Remote input buffer full");
249
 
                client_destroy_internal_failure(client);
250
 
                return;
251
 
        case -1:
252
 
                /* disconnected */
253
 
                client_destroy(client, "Proxy: Remote disconnected");
254
 
                return;
255
 
        }
256
 
 
257
 
        while ((line = i_stream_next_line(input)) != NULL) {
258
 
                if (proxy_input_line(client, output, line) < 0)
259
 
                        break;
260
 
        }
261
 
}
262
 
 
263
 
int managesieve_proxy_new(struct managesieve_client *client, const char *host,
264
 
                   unsigned int port, const char *user, const char *password)
265
 
{
266
 
        i_assert(user != NULL);
267
 
        i_assert(!client->destroyed);
268
 
 
269
 
        if (password == NULL) {
270
 
                client_syslog(&client->common, "proxy: password not given");
271
 
                return -1;
272
 
        }
273
 
 
274
 
        i_assert(client->refcount > 1);
275
 
        connection_queue_add(1);
276
 
 
277
 
        if (client->destroyed) {
278
 
                /* connection_queue_add() decided that we were the oldest
279
 
                   connection and killed us. */
280
 
                return -1;
281
 
        }
282
 
 
283
 
        client->proxy = login_proxy_new(&client->common, host, port,
284
 
                                        proxy_input, client);
285
 
        if (client->proxy == NULL)
286
 
                return -1;
287
 
 
288
 
        client->proxy_login_sent = FALSE;
289
 
        client->proxy_user = i_strdup(user);
290
 
        client->proxy_password = i_strdup(password);
291
 
 
292
 
        /* disable input until authentication is finished */
293
 
        if (client->io != NULL)
294
 
                io_remove(&client->io);
295
 
 
296
 
        return 0;
297
 
}