~james-page/ubuntu/raring/dovecot/autopkgtest

« back to all changes in this revision

Viewing changes to pigeonhole/src/managesieve/cmd-putscript.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2012-06-11 11:11:54 UTC
  • mfrom: (1.15.2) (4.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120611111154-678cwbdj6ktgsv1h
Tags: 1:2.1.7-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/{control,rules}: enable PIE hardening.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + d/control: Added Pre-Depends: dpkg (>= 1.15.6) to dovecot-dbg to support
    xz compression in Ubuntu.
  + d/control: Demote dovecot-common Recommends: to Suggests: to prevent
    install of extra packages on upgrade.
  + d/patches/dovecot-drac.patch: Updated with version for dovecot >= 2.0.0.
  + d/control: Drop B-D on systemd.
* Dropped changes:
  + d/patches/fix-racey-restart.patch: part of 2.1.x, no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
#include "managesieve-parser.h"
21
21
 
22
22
#include "managesieve-common.h"
 
23
#include "managesieve-client.h"
23
24
#include "managesieve-commands.h"
24
25
#include "managesieve-quota.h"
25
26
 
33
34
        struct istream *input;
34
35
 
35
36
        const char *scriptname;
36
 
        uoff_t script_size;     
 
37
        uoff_t script_size, max_script_size;
37
38
 
38
39
        struct managesieve_parser *save_parser;
39
40
        struct sieve_save_context *save_ctx;
102
103
        o_stream_set_flush_callback(ctx->client->output,
103
104
                                    client_output, ctx->client);
104
105
 
105
 
        if (ctx->input != NULL)
106
 
                i_stream_unref(&ctx->input);
107
 
 
108
106
        if (ctx->save_ctx != NULL)
109
107
        {
110
108
                ctx->client->input_skip_line = TRUE;
121
119
        (void)i_stream_get_data(ctx->input, &size);
122
120
        i_stream_skip(ctx->input, size);
123
121
 
124
 
        if ( cmd->client->input->closed ||
 
122
        if ( cmd->client->input->closed || ctx->input->eof ||
125
123
                ctx->input->v_offset == ctx->script_size ) {
126
124
                cmd_putscript_finish(ctx);
127
125
                return TRUE;
129
127
        return FALSE;
130
128
}
131
129
 
132
 
static bool cmd_putscript_cancel(struct cmd_putscript_context *ctx, bool nonsync)
 
130
static bool cmd_putscript_cancel(struct cmd_putscript_context *ctx, bool skip)
133
131
{
134
132
        ctx->client->input_skip_line = TRUE;
135
133
 
136
 
        if (!nonsync) { /* Rediculous for managesieve */
 
134
        if ( !skip ) {
137
135
                cmd_putscript_finish(ctx);
138
136
                return TRUE;
139
137
        }
140
138
 
141
139
        /* we have to read the nonsynced literal so we don't treat the uploaded script
142
140
           as commands. */
143
 
        ctx->input = i_stream_create_limit(ctx->client->input, ctx->script_size);
144
 
 
145
141
        ctx->client->command_pending = TRUE;
146
142
        ctx->cmd->func = cmd_putscript_continue_cancel;
147
143
        ctx->cmd->context = ctx;
152
148
{
153
149
        struct client *client = cmd->client;
154
150
        struct cmd_putscript_context *ctx = cmd->context;
155
 
        struct managesieve_arg *args;
 
151
        const struct managesieve_arg *args;
156
152
        int ret;
157
153
        
158
154
        /* if error occurs, the CRLF is already read. */
159
155
        client->input_skip_line = FALSE;
160
156
        
161
157
        /* <script literal> */
162
 
        ret = managesieve_parser_read_args(ctx->save_parser, 0,
163
 
          MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE, &args);
 
158
        ret = managesieve_parser_read_args(ctx->save_parser, 0, 0, &args);
164
159
        if (ret == -1 || client->output->closed) {
165
160
                if (ctx->storage != NULL)
166
161
                        client_send_command_error(cmd, NULL);
172
167
                return FALSE;
173
168
        }
174
169
 
175
 
        if (args[0].type == MANAGESIEVE_ARG_EOL) {
 
170
        if ( MANAGESIEVE_ARG_IS_EOL(&args[0]) ) {
176
171
                struct sieve_script *script;
177
 
 
178
 
                /* Last (and only) script */
179
172
                bool success = TRUE;
180
173
 
181
174
                /* Eat away the trailing CRLF */
191
184
                        return TRUE;
192
185
                }
193
186
 
 
187
                /* If quoted string, the size was not known until now */
 
188
                if ( ctx->script_size == 0 ) {
 
189
                        /* Check quota; max size is already checked */
 
190
                        if ( ctx->scriptname != NULL && !managesieve_quota_check_all
 
191
                                        (client, ctx->scriptname, ctx->script_size) ) {
 
192
                                cmd_putscript_finish(ctx);                              
 
193
                                return TRUE;
 
194
                        }
 
195
                }
 
196
 
194
197
                /* Try to compile script */
195
198
                T_BEGIN {
196
199
                        struct sieve_error_handler *ehandler;
 
200
                        enum sieve_compile_flags cpflags = 
 
201
                                SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_UPLOADED;
197
202
                        struct sieve_binary *sbin;
198
203
                        string_t *errors;
199
204
 
 
205
                        /* Mark this as an activation when we are replacing the active script */
 
206
                        if ( sieve_storage_save_will_activate(ctx->save_ctx) ) {
 
207
                                cpflags |= SIEVE_COMPILE_FLAG_ACTIVATED;
 
208
                        }
 
209
 
200
210
                        /* Prepare error handler */
201
211
                        errors = str_new(default_pool, 1024);
202
212
                        ehandler = sieve_strbuf_ehandler_create(client->svinst, errors, TRUE, 
203
213
                                client->set->managesieve_max_compile_errors);
204
214
 
205
215
                        /* Compile */
206
 
                        if ( (sbin=sieve_compile_script(script, ehandler, NULL)) == NULL ) {
 
216
                        if ( (sbin=sieve_compile_script
 
217
                                (script, ehandler, cpflags, NULL)) == NULL ) {
207
218
                                client_send_no(client, str_c(errors));
208
219
                                success = FALSE;
209
220
                        } else {
252
263
{
253
264
        struct client *client = cmd->client;
254
265
        struct cmd_putscript_context *ctx = cmd->context;
255
 
        struct managesieve_arg *args;
256
 
        bool nonsync = FALSE;
 
266
        const struct managesieve_arg *args;
257
267
        int ret;
258
268
 
259
269
        /* if error occurs, the CRLF is already read. */
261
271
 
262
272
        /* <script literal> */
263
273
        ret = managesieve_parser_read_args(ctx->save_parser, 0,
264
 
                                    MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE, &args);
 
274
                                    MANAGESIEVE_PARSE_FLAG_STRING_STREAM, &args);
265
275
        if (ret == -1 || client->output->closed) {
266
276
                cmd_putscript_finish(ctx);
267
277
                client_send_command_error(cmd, "Invalid arguments.");
273
283
                return FALSE;
274
284
        }
275
285
 
276
 
        if (args->type != MANAGESIEVE_ARG_STRING) {
277
 
                /* Validate the script argument */
278
 
                if (args->type != MANAGESIEVE_ARG_LITERAL_SIZE ) {
279
 
                        client_send_command_error(cmd, "Invalid arguments.");
280
 
                        return cmd_putscript_cancel(ctx, FALSE);
 
286
        /* Validate the script argument */
 
287
        if ( !managesieve_arg_get_string_stream(args,&ctx->input) ) {
 
288
                client_send_command_error(cmd, "Invalid arguments.");
 
289
                return cmd_putscript_cancel(ctx, FALSE);
 
290
        }
 
291
 
 
292
        if ( i_stream_get_size(ctx->input, FALSE, &ctx->script_size) > 0 ) {
 
293
                if ( ctx->script_size == 0 ) {
 
294
                        /* no script content, abort */
 
295
                        if ( ctx->scriptname != NULL ) 
 
296
                                client_send_no(client, "PUTSCRIPT aborted (empty script).");
 
297
                        else
 
298
                                client_send_no(client, "CHECKSCRIPT aborted (empty script).");
 
299
 
 
300
                        cmd_putscript_finish(ctx);      
 
301
                        return TRUE;
 
302
 
 
303
                /* Check quota */
 
304
                } else if ( ctx->scriptname == NULL ) {
 
305
                        if ( !managesieve_quota_check_validsize(client, ctx->script_size) )
 
306
                                return cmd_putscript_cancel(ctx, TRUE);
 
307
                } else {
 
308
                        if ( !managesieve_quota_check_all
 
309
                                (client, ctx->scriptname, ctx->script_size) )
 
310
                                return cmd_putscript_cancel(ctx, TRUE);
281
311
                }
282
 
 
283
 
                ctx->script_size = MANAGESIEVE_ARG_LITERAL_SIZE(args);
284
 
                nonsync = TRUE;
 
312
                
285
313
        } else {
286
 
                /* FIXME: allow quoted strings */
287
 
                client_send_no(client, 
288
 
                        "This MANAGESIEVE implementation currently does not allow "
289
 
                        "quoted strings to be used for script contents.");
290
 
                return cmd_putscript_cancel(ctx, FALSE);                
291
 
        }
292
 
 
293
 
        if ( ctx->script_size == 0 ) {
294
 
                /* no script content, abort */
295
 
                if ( ctx->scriptname != NULL ) 
296
 
                        client_send_no(client, "PUTSCRIPT aborted (empty script).");
297
 
                else
298
 
                        client_send_no(client, "CHECKSCRIPT aborted (empty script).");
299
 
 
300
 
                cmd_putscript_finish(ctx);      
301
 
                return TRUE;    
 
314
                ctx->max_script_size = managesieve_quota_max_script_size(client);               
302
315
        }
303
316
 
304
317
        /* save the script */
305
 
        ctx->input = i_stream_create_limit(client->input, ctx->script_size);
306
318
        ctx->save_ctx = sieve_storage_save_init
307
319
                (ctx->storage, ctx->scriptname, ctx->input);
308
320
 
309
321
        if ( ctx->save_ctx == NULL ) {
310
322
                /* save initialization failed */
311
323
                client_send_storage_error(client, ctx->storage);
312
 
                return cmd_putscript_cancel(ctx, nonsync);
313
 
        }
314
 
 
315
 
        /* Check quota */
316
 
        if ( ctx->scriptname == NULL ) {
317
 
                if ( !managesieve_quota_check_validsize(client, ctx->script_size) )
318
 
                        return cmd_putscript_cancel(ctx, nonsync);
319
 
        } else {
320
 
                if ( !managesieve_quota_check_all
321
 
                        (client, ctx->scriptname, ctx->script_size) )
322
 
                        return cmd_putscript_cancel(ctx, nonsync);
 
324
                return cmd_putscript_cancel(ctx, TRUE);
323
325
        }
324
326
 
325
327
        /* after literal comes CRLF, if we fail make sure we eat it away */
335
337
        struct client *client = cmd->client;
336
338
        struct cmd_putscript_context *ctx = cmd->context;
337
339
        size_t size;
338
 
        bool failed;
339
340
        int ret;
340
341
 
341
342
        if (ctx->save_ctx != NULL) {
342
 
                while (ctx->input->v_offset != ctx->script_size) {
343
 
                        ret = i_stream_read(ctx->input);
 
343
                while (ctx->script_size == 0 || ctx->input->v_offset != ctx->script_size) {
 
344
                        if ( ctx->max_script_size > 0 &&
 
345
                                ctx->input->v_offset > ctx->max_script_size ) {
 
346
                                (void)managesieve_quota_check_validsize(client, ctx->input->v_offset);
 
347
                                cmd_putscript_finish(ctx);
 
348
                                return TRUE;
 
349
                        }
 
350
 
 
351
                        ret = i_stream_read(ctx->input);        
344
352
                        if (sieve_storage_save_continue(ctx->save_ctx) < 0) {
345
353
                                /* we still have to finish reading the script
346
354
                                  from client */
359
367
        }
360
368
 
361
369
        if (ctx->input->eof || client->input->closed) {
362
 
                bool all_written = ctx->input->v_offset == ctx->script_size;
 
370
                bool failed = FALSE;
 
371
                bool all_written = FALSE;
 
372
 
 
373
                if ( ctx->script_size == 0 ) {
 
374
                        if ( ctx->input->stream_errno == EPROTO ) {
 
375
                                bool fatal;
 
376
                                const char *parse_error;
 
377
 
 
378
                                parse_error = managesieve_parser_get_error(ctx->save_parser, &fatal);
 
379
                                if ( parse_error != NULL) {
 
380
                                        client_send_command_error(cmd, parse_error);
 
381
                                        client->input_skip_line = TRUE;
 
382
                                        failed = TRUE;
 
383
                                }
 
384
                        }                       
 
385
                        all_written = ( ctx->input->eof && ctx->input->stream_errno == 0 );
 
386
 
 
387
                } else {
 
388
                        all_written = ( ctx->input->v_offset == ctx->script_size );
 
389
                }
363
390
 
364
391
                /* finished */
365
 
                i_stream_unref(&ctx->input);
366
392
                ctx->input = NULL;
367
393
 
368
 
                if (ctx->save_ctx == NULL) {
369
 
                        /* failed above */
370
 
                        client_send_storage_error(client, ctx->storage);
371
 
                        failed = TRUE;
372
 
                } else if (!all_written) {
373
 
                        /* client disconnected before it finished sending the
374
 
                           whole script. */
375
 
                        failed = TRUE;
376
 
                        sieve_storage_save_cancel(&ctx->save_ctx);
377
 
                        client_disconnect(client, "EOF while appending in PUTSCRIPT/CHECKSCRIPT");
378
 
                } else if (sieve_storage_save_finish(ctx->save_ctx) < 0) {
379
 
                        failed = TRUE;
380
 
                        client_send_storage_error(client, ctx->storage);
381
 
                } else {
382
 
                        failed = client->input->closed;
 
394
                if ( !failed ) {
 
395
                        if (ctx->save_ctx == NULL) {
 
396
                                /* failed above */
 
397
                                client_send_storage_error(client, ctx->storage);
 
398
                                failed = TRUE;
 
399
                        } else if (!all_written) {
 
400
                                /* client disconnected before it finished sending the
 
401
                                         whole script. */
 
402
                                failed = TRUE;
 
403
                                sieve_storage_save_cancel(&ctx->save_ctx);
 
404
                                client_disconnect
 
405
                                        (client, "EOF while appending in PUTSCRIPT/CHECKSCRIPT");
 
406
                        } else if (sieve_storage_save_finish(ctx->save_ctx) < 0) {
 
407
                                failed = TRUE;
 
408
                                client_send_storage_error(client, ctx->storage);
 
409
                        } else {
 
410
                                failed = client->input->closed;
 
411
                        }
383
412
                }
384
413
 
385
414
                if (failed) {
417
446
           finished */
418
447
        o_stream_unset_flush_callback(client->output);
419
448
 
420
 
        ctx->save_parser = managesieve_parser_create(client->input, client->output,
421
 
                                              client->set->managesieve_max_line_length);
 
449
        ctx->save_parser = managesieve_parser_create
 
450
                (client->input, client->set->managesieve_max_line_length);
422
451
 
423
452
        cmd->func = cmd_putscript_continue_parsing;
424
453
        cmd->context = ctx;