~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002101901

« back to all changes in this revision

Viewing changes to libsieve/src/lib-sieve/plugins/include/ext-include-common.c

  • Committer: Chuck Short
  • Date: 2010-01-21 20:21:25 UTC
  • mfrom: (4.1.11 squeeze)
  • Revision ID: zulcss@ubuntu.com-20100121202125-pme73o491kfwj5nc
* 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 restriction
    - 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 config
    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.
    - 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.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
* New upstream release.
* debian/patches/gold-fix.patch: Removed. Fixed upstream.
* Moved libexec to lib corrections in dovecot-managesieve.patch and
  dovecot-managesieve-dist.patch to dovecot-example.patch
* debian/patches/dovecot-mboxlocking.patch: Regenerated to avoid FTBFS
  when quilt isn't installed.
* debian/patches/quota-mountpoint.patch: Removed. Not needed anymore.
* debian/patches/dovecot-quota.patch: Removed. Quotas aren't properly
  enabled unless mail_plugins = quota imap_quota.
* debian/patches/gold-fix.patch: Fixed configure script to build even
  with binutils-gold or --no-add-needed linker flag (Closes: #554306)
* debian/dovecot-common.init: fixed LSB headers. Thanks to Pascal Volk.
  (Closes: #558040)
* debian/changelog: added CVE references to previous changelog entry.
* debian/rules: checked up the build system. It's not fragile anymore.
  (Closes: 493803)
* debian/dovecot-common.postinst: Now invoking dpkg-reconfigure
  on dovecot-common is enough to generate new certificates
  if the previous ones were removed. (Closes: #545582)
* debian/rules: No longer install convert-tool in /usr/bin.
  It isn't an user utility and it should stay in /usr/lib/dovecot
  like all other similar tool.
* New upstream release. (Closes: #557601)
* [SECURITY] Fixes local information disclosure and denial of service.
  (see: http://www.dovecot.org/list/dovecot-news/2009-November/000143.html
  and CVE-2009-3897)
* Added myself to uploaders.
* Switched to the new source format "3.0 (quilt)":
  - removed dpatch from build-depends
  - removed debian/README.source because now we use only standard
    dpkg features
  - regenerated all patches
* Prepared to switch to multi-origin source:
  - recreated dovecot-libsieve.patch and dovecot-managesieve-dist.patch
    starting from the upstream tarball
  - removed all autotools related build-depends and build-conflict
  - renamed dovecot-libsieve and dovecot-managesieve directories
    to libsieve and managesieve.
* debian/rules: Moved the configuration of libsieve and managesieve from
  the build phase to the configuration phase
* Added dovecot-dbg package  with debugging symbols.  Thanks Stephan Bosch.
  (Closes: #554710)
* Fixed some stray libexec'isms in the default configuration.
* New upstream release.
* debian/dovecot-common.init:
  - use $CONF when starting the daemon. (Closes: #549944)
  - always output start/stop messages. (Closes: #523810)

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 "lib.h"
 
5
#include "array.h"
 
6
#include "str-sanitize.h"
 
7
#include "home-expand.h"
 
8
 
 
9
#include "sieve-common.h"
 
10
#include "sieve-error.h"
 
11
#include "sieve-script.h"
 
12
#include "sieve-ast.h"
 
13
#include "sieve-binary.h"
 
14
#include "sieve-commands.h"
 
15
#include "sieve-generator.h"
 
16
#include "sieve-interpreter.h"
 
17
 
 
18
#include "ext-include-common.h"
 
19
#include "ext-include-limits.h"
 
20
#include "ext-include-binary.h"
 
21
#include "ext-include-variables.h"
 
22
 
 
23
#include <stdlib.h>
 
24
 
 
25
/*
 
26
 * Forward declarations
 
27
 */
 
28
 
 
29
/* Generator context */
 
30
 
 
31
struct ext_include_generator_context {
 
32
        unsigned int nesting_level;
 
33
        struct sieve_script *script;
 
34
        struct ext_include_generator_context *parent;
 
35
};
 
36
 
 
37
static inline struct ext_include_generator_context *
 
38
        ext_include_get_generator_context
 
39
        (struct sieve_generator *gentr);
 
40
 
 
41
/* Interpreter context */
 
42
 
 
43
struct ext_include_interpreter_global {
 
44
        ARRAY_DEFINE(included_scripts, struct sieve_script *);
 
45
 
 
46
        struct sieve_variable_storage *variables;
 
47
};
 
48
 
 
49
struct ext_include_interpreter_context {
 
50
        struct ext_include_interpreter_context *parent;
 
51
        struct ext_include_interpreter_global *global;
 
52
 
 
53
        struct sieve_interpreter *interp;
 
54
        pool_t pool;
 
55
 
 
56
        unsigned int nesting_level;
 
57
 
 
58
        struct sieve_script *script;
 
59
        const struct ext_include_script_info *script_info;
 
60
        
 
61
        const struct ext_include_script_info *include;
 
62
        bool returned;
 
63
};
 
64
 
 
65
/* 
 
66
 * Script access 
 
67
 */
 
68
 
 
69
const char *ext_include_get_script_directory
 
70
(enum ext_include_script_location location, const char *script_name)
 
71
{
 
72
        const char *home, *sieve_dir;
 
73
 
 
74
        switch ( location ) {
 
75
        case EXT_INCLUDE_LOCATION_PERSONAL:
 
76
                sieve_dir = getenv("SIEVE_DIR");
 
77
                home = getenv("HOME");
 
78
 
 
79
                if (sieve_dir == NULL) {
 
80
                        if ( home == NULL )     {               
 
81
                                sieve_sys_error(
 
82
                                        "include: sieve_dir and home not set for :personal script include "     
 
83
                                        "(wanted script '%s')", str_sanitize(script_name, 80));
 
84
                                return NULL;
 
85
                        }
 
86
 
 
87
                        sieve_dir = "~/sieve"; 
 
88
                }
 
89
 
 
90
                if ( home != NULL )
 
91
                        sieve_dir = home_expand_tilde(sieve_dir, home); 
 
92
 
 
93
                break;
 
94
        case EXT_INCLUDE_LOCATION_GLOBAL:
 
95
                sieve_dir = getenv("SIEVE_GLOBAL_DIR");
 
96
 
 
97
                if (sieve_dir == NULL) {
 
98
                        sieve_sys_error(
 
99
                                "include: sieve_global_dir not set for :global script include " 
 
100
                                "(wanted script '%s')", str_sanitize(script_name, 80));
 
101
                        return NULL;
 
102
                }
 
103
 
 
104
                break;
 
105
        default:
 
106
                return NULL;
 
107
        }
 
108
 
 
109
 
 
110
        return sieve_dir;
 
111
}
 
112
 
 
113
/*
 
114
 * AST context management
 
115
 */
 
116
 
 
117
static void ext_include_ast_free
 
118
(struct sieve_ast *ast ATTR_UNUSED, void *context)
 
119
{
 
120
        struct ext_include_ast_context *actx = 
 
121
                (struct ext_include_ast_context *) context;
 
122
        struct sieve_script **scripts;
 
123
        unsigned int count, i;
 
124
 
 
125
        /* Unreference included scripts */
 
126
        scripts = array_get_modifiable(&actx->included_scripts, &count);
 
127
        for ( i = 0; i < count; i++ ) {
 
128
                sieve_script_unref(&scripts[i]);
 
129
        }       
 
130
 
 
131
        /* Unreference variable scopes */
 
132
        if ( actx->global_vars != NULL )
 
133
                sieve_variable_scope_unref(&actx->global_vars);
 
134
}
 
135
 
 
136
static const struct sieve_ast_extension include_ast_extension = {
 
137
        &include_extension,
 
138
        ext_include_ast_free
 
139
};
 
140
 
 
141
struct ext_include_ast_context *ext_include_create_ast_context
 
142
(struct sieve_ast *ast, struct sieve_ast *parent)
 
143
{
 
144
        struct ext_include_ast_context *actx;
 
145
 
 
146
        pool_t pool = sieve_ast_pool(ast);
 
147
        actx = p_new(pool, struct ext_include_ast_context, 1);
 
148
        p_array_init(&actx->included_scripts, pool, 32);
 
149
 
 
150
        if ( parent != NULL ) {
 
151
                struct ext_include_ast_context *parent_ctx =
 
152
                        (struct ext_include_ast_context *)
 
153
                                sieve_ast_extension_get_context(parent, &include_extension);
 
154
                actx->global_vars = parent_ctx->global_vars;
 
155
 
 
156
                i_assert( actx->global_vars != NULL );
 
157
 
 
158
                sieve_variable_scope_ref(actx->global_vars);
 
159
        } else
 
160
                actx->global_vars = sieve_variable_scope_create(&include_extension);                    
 
161
 
 
162
        sieve_ast_extension_register(ast, &include_ast_extension, (void *) actx);
 
163
 
 
164
        return actx;
 
165
}
 
166
 
 
167
struct ext_include_ast_context *ext_include_get_ast_context
 
168
(struct sieve_ast *ast)
 
169
{
 
170
        struct ext_include_ast_context *actx = (struct ext_include_ast_context *)
 
171
                sieve_ast_extension_get_context(ast, &include_extension);
 
172
 
 
173
        if ( actx != NULL ) return actx;
 
174
 
 
175
        return ext_include_create_ast_context(ast, NULL);
 
176
}
 
177
 
 
178
void ext_include_ast_link_included_script
 
179
(struct sieve_ast *ast, struct sieve_script *script) 
 
180
{
 
181
        struct ext_include_ast_context *actx = ext_include_get_ast_context(ast);
 
182
 
 
183
        array_append(&actx->included_scripts, &script, 1);
 
184
}
 
185
 
 
186
/* 
 
187
 * Generator context management 
 
188
 */
 
189
 
 
190
static struct ext_include_generator_context *
 
191
        ext_include_create_generator_context
 
192
(struct sieve_generator *gentr, struct ext_include_generator_context *parent, 
 
193
        struct sieve_script *script)
 
194
{       
 
195
        struct ext_include_generator_context *ctx;
 
196
 
 
197
        pool_t pool = sieve_generator_pool(gentr);
 
198
        ctx = p_new(pool, struct ext_include_generator_context, 1);
 
199
        ctx->parent = parent;
 
200
        ctx->script = script;
 
201
        if ( parent == NULL ) {
 
202
                ctx->nesting_level = 0;
 
203
        } else {
 
204
                ctx->nesting_level = parent->nesting_level + 1;
 
205
        }
 
206
        
 
207
        return ctx;
 
208
}
 
209
 
 
210
static inline struct ext_include_generator_context *
 
211
        ext_include_get_generator_context
 
212
(struct sieve_generator *gentr)
 
213
{
 
214
        return (struct ext_include_generator_context *)
 
215
                sieve_generator_extension_get_context(gentr, &include_extension);
 
216
}
 
217
 
 
218
static inline void ext_include_initialize_generator_context
 
219
(struct sieve_generator *gentr, struct ext_include_generator_context *parent, 
 
220
        struct sieve_script *script)
 
221
{
 
222
        sieve_generator_extension_set_context(gentr, &include_extension,
 
223
                ext_include_create_generator_context(gentr, parent, script));
 
224
}
 
225
 
 
226
void ext_include_register_generator_context
 
227
(const struct sieve_codegen_env *cgenv)
 
228
{
 
229
        struct ext_include_generator_context *ctx = 
 
230
                ext_include_get_generator_context(cgenv->gentr);
 
231
        
 
232
        /* Initialize generator context if necessary */
 
233
        if ( ctx == NULL ) {
 
234
                ctx = ext_include_create_generator_context(
 
235
                        cgenv->gentr, NULL, cgenv->script);
 
236
                
 
237
                sieve_generator_extension_set_context
 
238
                        (cgenv->gentr, &include_extension, (void *) ctx);               
 
239
        }
 
240
 
 
241
        /* Initialize ast context if necessary */
 
242
        (void)ext_include_get_ast_context(cgenv->ast);
 
243
        (void)ext_include_binary_init(cgenv->sbin, cgenv->ast);
 
244
}
 
245
 
 
246
/*
 
247
 * Runtime initialization
 
248
 */
 
249
 
 
250
static void ext_include_runtime_init
 
251
    (const struct sieve_runtime_env *renv, void *context)
 
252
{
 
253
        struct ext_include_interpreter_context *ctx = 
 
254
                (struct ext_include_interpreter_context *) context;
 
255
 
 
256
        if ( ctx->parent == NULL ) {
 
257
                ctx->global = p_new(ctx->pool, struct ext_include_interpreter_global, 1);
 
258
                ctx->global->variables = sieve_variable_storage_create
 
259
                        (ctx->pool, ext_include_binary_get_global_scope(renv->sbin), 0);
 
260
                p_array_init(&ctx->global->included_scripts, ctx->pool, 10);
 
261
        } else {
 
262
                ctx->global = ctx->parent->global;
 
263
        }
 
264
 
 
265
        sieve_ext_variables_set_storage
 
266
                (renv->interp, ctx->global->variables, &include_extension);     
 
267
}
 
268
 
 
269
static struct sieve_interpreter_extension include_interpreter_extension = {
 
270
        &include_extension,
 
271
        ext_include_runtime_init,
 
272
        NULL,
 
273
};
 
274
 
 
275
/* 
 
276
 * Interpreter context management 
 
277
 */
 
278
 
 
279
static struct ext_include_interpreter_context *
 
280
        ext_include_interpreter_context_create
 
281
(struct sieve_interpreter *interp, 
 
282
        struct ext_include_interpreter_context *parent, 
 
283
        struct sieve_script *script, const struct ext_include_script_info *sinfo)
 
284
{       
 
285
        struct ext_include_interpreter_context *ctx;
 
286
 
 
287
        pool_t pool = sieve_interpreter_pool(interp);
 
288
        ctx = p_new(pool, struct ext_include_interpreter_context, 1);
 
289
        ctx->pool = pool;
 
290
        ctx->parent = parent;
 
291
        ctx->interp = interp;
 
292
        ctx->script = script;
 
293
        ctx->script_info = sinfo;
 
294
 
 
295
        if ( parent == NULL ) {
 
296
                ctx->nesting_level = 0;
 
297
        } else {
 
298
                ctx->nesting_level = parent->nesting_level + 1;
 
299
        }
 
300
 
 
301
        return ctx;
 
302
}
 
303
 
 
304
static inline struct ext_include_interpreter_context *
 
305
        ext_include_get_interpreter_context
 
306
(struct sieve_interpreter *interp)
 
307
{
 
308
        return (struct ext_include_interpreter_context *)
 
309
                sieve_interpreter_extension_get_context(interp, &include_extension);
 
310
}
 
311
 
 
312
static inline struct ext_include_interpreter_context *
 
313
        ext_include_interpreter_context_init_child
 
314
(struct sieve_interpreter *interp, 
 
315
        struct ext_include_interpreter_context *parent, 
 
316
        struct sieve_script *script, const struct ext_include_script_info *sinfo)
 
317
{
 
318
        struct ext_include_interpreter_context *ctx = 
 
319
                ext_include_interpreter_context_create(interp, parent, script, sinfo);
 
320
                
 
321
        sieve_interpreter_extension_register
 
322
                (interp, &include_interpreter_extension, ctx);
 
323
        
 
324
        return ctx;
 
325
}
 
326
 
 
327
void ext_include_interpreter_context_init
 
328
(struct sieve_interpreter *interp)
 
329
{
 
330
        struct ext_include_interpreter_context *ctx = 
 
331
                ext_include_get_interpreter_context(interp);
 
332
 
 
333
        /* Is this is the top-level interpreter ? */    
 
334
        if ( ctx == NULL ) {
 
335
                struct sieve_script *script;
 
336
 
 
337
                /* Initialize top context */
 
338
                script = sieve_interpreter_script(interp);
 
339
                ctx = ext_include_interpreter_context_create
 
340
                        (interp, NULL, script, NULL);
 
341
                
 
342
                sieve_interpreter_extension_register
 
343
                        (interp, &include_interpreter_extension, (void *) ctx);                 
 
344
        }
 
345
}
 
346
 
 
347
struct sieve_variable_storage *ext_include_interpreter_get_global_variables
 
348
(struct sieve_interpreter *interp)
 
349
{
 
350
        struct ext_include_interpreter_context *ctx =
 
351
                ext_include_get_interpreter_context(interp);
 
352
                
 
353
        return ctx->global->variables;
 
354
}
 
355
 
 
356
/* 
 
357
 * Including a script during code generation 
 
358
 */
 
359
 
 
360
bool ext_include_generate_include
 
361
(const struct sieve_codegen_env *cgenv, struct sieve_command_context *cmd,
 
362
        enum ext_include_script_location location, struct sieve_script *script, 
 
363
        const struct ext_include_script_info **included_r, bool once)
 
364
{
 
365
        bool result = TRUE;
 
366
        struct sieve_ast *ast;
 
367
        struct sieve_binary *sbin = cgenv->sbin;
 
368
        struct sieve_generator *gentr = cgenv->gentr;
 
369
        struct ext_include_binary_context *binctx;
 
370
        struct sieve_generator *subgentr;
 
371
        struct ext_include_generator_context *ctx =
 
372
                ext_include_get_generator_context(gentr);
 
373
        struct ext_include_generator_context *pctx;
 
374
        struct sieve_error_handler *ehandler = sieve_generator_error_handler(gentr);
 
375
        const struct ext_include_script_info *included;
 
376
                
 
377
        *included_r = NULL;
 
378
 
 
379
        /* Just to be sure: do not include more scripts when errors have occured 
 
380
         * already. 
 
381
         */
 
382
        if ( sieve_get_errors(ehandler) > 0 )
 
383
                return FALSE;
 
384
                
 
385
        /* Limit nesting level */
 
386
        if ( ctx->nesting_level >= EXT_INCLUDE_MAX_NESTING_LEVEL ) {
 
387
                sieve_command_generate_error
 
388
                        (gentr, cmd, "cannot nest includes deeper than %d levels",
 
389
                                EXT_INCLUDE_MAX_NESTING_LEVEL);
 
390
                return FALSE;
 
391
        }
 
392
        
 
393
        /* Check for circular include */
 
394
        if ( !once ) {
 
395
                pctx = ctx;
 
396
                while ( pctx != NULL ) {
 
397
                        if ( sieve_script_equals(pctx->script, script) ) {
 
398
                                sieve_command_generate_error(gentr, cmd, "circular include");
 
399
                                
 
400
                                return FALSE;
 
401
                        }
 
402
                
 
403
                        pctx = pctx->parent;
 
404
                }
 
405
        }
 
406
 
 
407
        /* Get binary context */
 
408
        binctx = ext_include_binary_init(sbin, cgenv->ast);
 
409
 
 
410
        /* Is the script already compiled into the current binary? */
 
411
        if ( !ext_include_binary_script_is_included(binctx, script, &included) )        
 
412
        {       
 
413
                unsigned int inc_block_id, this_block_id;
 
414
                const char *script_name = sieve_script_name(script);
 
415
 
 
416
                /* Check whether include limit is exceeded */
 
417
                if ( ext_include_binary_script_get_count(binctx) >= 
 
418
                        EXT_INCLUDE_MAX_INCLUDES ) {
 
419
                        sieve_command_generate_error(gentr, cmd, 
 
420
                                "failed to include script '%s': no more than %u includes allowed", 
 
421
                                str_sanitize(script_name, 80), EXT_INCLUDE_MAX_INCLUDES);
 
422
                        return FALSE;                   
 
423
                }
 
424
                
 
425
                /* No, allocate a new block in the binary and mark the script as included.
 
426
                 */
 
427
                inc_block_id = sieve_binary_block_create(sbin);
 
428
                included = ext_include_binary_script_include
 
429
                        (binctx, script, location, inc_block_id);
 
430
 
 
431
                /* Parse */
 
432
                if ( (ast = sieve_parse(script, ehandler)) == NULL ) {
 
433
                        sieve_command_generate_error(gentr, cmd, 
 
434
                                "failed to parse included script '%s'", str_sanitize(script_name, 80));
 
435
                        return FALSE;
 
436
                }
 
437
                
 
438
                /* Included scripts inherit global variable scope */
 
439
                (void)ext_include_create_ast_context(ast, cmd->ast_node->ast);
 
440
 
 
441
                /* Validate */
 
442
                if ( !sieve_validate(ast, ehandler) ) {
 
443
                        sieve_command_generate_error(gentr, cmd, 
 
444
                                "failed to validate included script '%s'", str_sanitize(script_name, 80));
 
445
                        sieve_ast_unref(&ast);
 
446
                        return FALSE;
 
447
                }
 
448
 
 
449
                /* Generate 
 
450
                 *
 
451
                 * FIXME: It might not be a good idea to recurse code generation for 
 
452
                 * included scripts.
 
453
                 */
 
454
                if ( sieve_binary_block_set_active(sbin, inc_block_id, &this_block_id) ) {
 
455
                        subgentr = sieve_generator_create(ast, ehandler);                       
 
456
                        ext_include_initialize_generator_context(subgentr, ctx, script);
 
457
                                
 
458
                        if ( !sieve_generator_run(subgentr, &sbin) ) {
 
459
                                sieve_command_generate_error(gentr, cmd, 
 
460
                                        "failed to generate code for included script '%s'", 
 
461
                                        str_sanitize(script_name, 80));
 
462
                                result = FALSE;
 
463
                        }
 
464
                        
 
465
                        if ( sbin != NULL )             
 
466
                                (void) sieve_binary_block_set_active(sbin, this_block_id, NULL);        
 
467
                        sieve_generator_free(&subgentr);
 
468
                } else {
 
469
                        sieve_sys_error("include: failed to activate binary  block %d for "
 
470
                                "generating code for the included script", inc_block_id);
 
471
                        result = FALSE;
 
472
                }
 
473
                
 
474
                /* Cleanup */
 
475
                sieve_ast_unref(&ast);          
 
476
        } 
 
477
 
 
478
        if ( result ) *included_r = included;
 
479
        
 
480
        return result;
 
481
}
 
482
 
 
483
/* 
 
484
 * Executing an included script during interpretation 
 
485
 */
 
486
 
 
487
static int ext_include_runtime_check_circular
 
488
(struct ext_include_interpreter_context *ctx,
 
489
        const struct ext_include_script_info *include)
 
490
{
 
491
        struct ext_include_interpreter_context *pctx;
 
492
 
 
493
        pctx = ctx;
 
494
        while ( pctx != NULL ) {
 
495
 
 
496
                if ( sieve_script_equals(include->script, pctx->script) )
 
497
                        return TRUE;
 
498
 
 
499
                pctx = pctx->parent;
 
500
        }
 
501
 
 
502
        return FALSE;
 
503
}
 
504
 
 
505
static bool ext_include_runtime_include_mark
 
506
(struct ext_include_interpreter_context *ctx,
 
507
        const struct ext_include_script_info *include, bool once)
 
508
{
 
509
        struct sieve_script *const *includes;
 
510
        unsigned int count, i;
 
511
        
 
512
        includes = array_get(&ctx->global->included_scripts, &count);
 
513
        for ( i = 0; i < count; i++ )   {
 
514
                if ( sieve_script_equals(include->script, includes[i]) )
 
515
                        return ( !once );
 
516
        }
 
517
        
 
518
        array_append(&ctx->global->included_scripts, &include->script, 1);
 
519
 
 
520
        return TRUE;
 
521
}
 
522
 
 
523
int ext_include_execute_include
 
524
(const struct sieve_runtime_env *renv, unsigned int include_id, bool once)
 
525
{
 
526
        int result = SIEVE_EXEC_OK;
 
527
        struct ext_include_interpreter_context *ctx;
 
528
        const struct ext_include_script_info *included;
 
529
        struct ext_include_binary_context *binctx = 
 
530
                ext_include_binary_get_context(renv->sbin);
 
531
 
 
532
        /* Check for invalid include id (== corrupt binary) */
 
533
        included = ext_include_binary_script_get_included(binctx, include_id);
 
534
        if ( included == NULL ) {
 
535
                sieve_runtime_trace_error(renv, "invalid include id: %d", include_id);
 
536
                return SIEVE_EXEC_BIN_CORRUPT;
 
537
        }
 
538
 
 
539
        ctx = ext_include_get_interpreter_context(renv->interp);
 
540
        
 
541
        sieve_runtime_trace(renv, 
 
542
                "INCLUDE command (script: %s, id: %d block: %d) START::", 
 
543
                sieve_script_name(included->script), include_id, included->block_id);
 
544
 
 
545
        /* If :once modifier is specified, check for duplicate include */
 
546
        if ( !ext_include_runtime_include_mark(ctx, included, once) ) {
 
547
                /* skip */
 
548
 
 
549
                sieve_runtime_trace(renv, 
 
550
                        "INCLUDE command (block: %d) SKIPPED ::", included->block_id);
 
551
                return result;
 
552
        }
 
553
 
 
554
        /* Check circular include during interpretation as well. 
 
555
         * Let's not trust binaries.
 
556
         */
 
557
        if ( ext_include_runtime_check_circular(ctx, included) ) {
 
558
                sieve_runtime_trace_error(renv, 
 
559
                        "circular include for script: %s [%d]", 
 
560
                        sieve_script_name(included->script), included->block_id);
 
561
 
 
562
                /* Situation has no valid way to emerge at runtime */
 
563
                return SIEVE_EXEC_BIN_CORRUPT; 
 
564
        }
 
565
 
 
566
        if ( ctx->parent == NULL ) {
 
567
                struct ext_include_interpreter_context *curctx = NULL;
 
568
                struct sieve_error_handler *ehandler = 
 
569
                        sieve_interpreter_get_error_handler(renv->interp);
 
570
                struct sieve_interpreter *subinterp;
 
571
                unsigned int this_block_id;
 
572
                bool interrupted = FALSE;       
 
573
 
 
574
                /* We are the top-level interpreter instance */ 
 
575
                
 
576
                /* Activate block for included script */
 
577
                if ( !sieve_binary_block_set_active
 
578
                        (renv->sbin, included->block_id, &this_block_id) ) {                    
 
579
                        sieve_runtime_trace_error(renv, "invalid block id: %d", 
 
580
                                included->block_id);
 
581
                        result = SIEVE_EXEC_BIN_CORRUPT;
 
582
                }
 
583
 
 
584
                if ( result == SIEVE_EXEC_OK ) {
 
585
                        /* Create interpreter for top-level included script
 
586
                         * (first sub-interpreter) 
 
587
                         */
 
588
                        subinterp = sieve_interpreter_create(renv->sbin, ehandler);
 
589
 
 
590
                        if ( subinterp != NULL ) {                      
 
591
                                curctx = ext_include_interpreter_context_init_child
 
592
                                        (subinterp, ctx, included->script, included);
 
593
 
 
594
                                /* Activate and start the top-level included script */
 
595
                                result = ( sieve_interpreter_start
 
596
                                        (subinterp, renv->msgdata, renv->scriptenv, renv->result, 
 
597
                                                &interrupted) == 1 );
 
598
                        } else
 
599
                                result = SIEVE_EXEC_BIN_CORRUPT;
 
600
                }
 
601
                
 
602
                /* Included scripts can have includes of their own. This is not implemented
 
603
                 * recursively. Rather, the sub-interpreter interrupts and defers the 
 
604
                 * include to the top-level interpreter, which is here.
 
605
                 */
 
606
                if ( result == SIEVE_EXEC_OK && interrupted && !curctx->returned ) {
 
607
                        while ( result == SIEVE_EXEC_OK ) {
 
608
 
 
609
                                if ( ( (interrupted && curctx->returned) || (!interrupted) ) && 
 
610
                                        curctx->parent != NULL ) {
 
611
                                        
 
612
                                        /* Sub-interpreter ended or executed return */
 
613
                                        
 
614
                                        sieve_runtime_trace(renv, "INCLUDE command (block: %d) END ::", 
 
615
                                                curctx->script_info->block_id);
 
616
 
 
617
                                        /* Ascend interpreter stack */
 
618
                                        curctx = curctx->parent;
 
619
                                        sieve_interpreter_free(&subinterp);
 
620
                                        
 
621
                                        /* This is the top-most sub-interpreter, bail out */
 
622
                                        if ( curctx->parent == NULL ) break;
 
623
                                        
 
624
                                        /* Reactivate parent */
 
625
                                        (void) sieve_binary_block_set_active
 
626
                                                (renv->sbin, curctx->script_info->block_id, NULL);
 
627
                                        subinterp = curctx->interp;     
 
628
                                        
 
629
                                        /* Continue parent */
 
630
                                        curctx->include = NULL;
 
631
                                        curctx->returned = FALSE;
 
632
 
 
633
                                        result = ( sieve_interpreter_continue(subinterp, &interrupted) == 1 );
 
634
                                } else {
 
635
                                        if ( curctx->include != NULL ) {
 
636
 
 
637
                                                /* Sub-include requested */
 
638
                                                                                                                        
 
639
                                                /* Activate the sub-include's block */
 
640
                                                if ( !sieve_binary_block_set_active
 
641
                                                        (renv->sbin, curctx->include->block_id, NULL) ) {
 
642
                                                        sieve_runtime_trace_error(renv, "invalid block id: %d", 
 
643
                                                                curctx->include->block_id);
 
644
                                                        result = SIEVE_EXEC_BIN_CORRUPT;
 
645
                                                }
 
646
                                
 
647
                                                if ( result == SIEVE_EXEC_OK ) {
 
648
                                                        /* Create sub-interpreter */
 
649
                                                        subinterp = sieve_interpreter_create(renv->sbin, ehandler);                     
 
650
 
 
651
                                                        if ( subinterp != NULL ) {
 
652
                                                                curctx = ext_include_interpreter_context_init_child
 
653
                                                                        (subinterp, curctx, curctx->include->script, 
 
654
                                                                                curctx->include);
 
655
 
 
656
                                                                /* Start the sub-include's interpreter */
 
657
                                                                curctx->include = NULL;
 
658
                                                                curctx->returned = FALSE;
 
659
                                                                result = ( sieve_interpreter_start
 
660
                                                                        (subinterp, renv->msgdata, renv->scriptenv, renv->result, 
 
661
                                                                                &interrupted) == 1 );                   
 
662
                                                        } else
 
663
                                                                result = SIEVE_EXEC_BIN_CORRUPT;
 
664
                                                }
 
665
                                        } else {
 
666
                                                /* Sub-interpreter was interrupted outside this extension, probably
 
667
                                                 * stop command was executed. Generate an interrupt ourselves, 
 
668
                                                 * ending all script execution.
 
669
                                                 */
 
670
                                                sieve_interpreter_interrupt(renv->interp);
 
671
                                                break;
 
672
                                        }
 
673
                                }
 
674
                        }
 
675
                } else 
 
676
                        sieve_runtime_trace(renv, "INCLUDE command (block: %d) END ::", 
 
677
                                curctx->script_info->block_id);
 
678
 
 
679
                /* Free any sub-interpreters that might still be active */
 
680
                while ( curctx != NULL && curctx->parent != NULL ) {
 
681
                        struct ext_include_interpreter_context *nextctx = curctx->parent;
 
682
                        struct sieve_interpreter *killed_interp = curctx->interp;
 
683
 
 
684
                        /* This kills curctx too */
 
685
                        sieve_interpreter_free(&killed_interp);
 
686
 
 
687
                        /* Luckily we recorded the parent earlier */
 
688
                        curctx = nextctx;
 
689
                }
 
690
 
 
691
                /* Return to our own block */
 
692
                (void) sieve_binary_block_set_active(renv->sbin, this_block_id, NULL);  
 
693
        } else {
 
694
                /* We are an included script already, defer inclusion to main interpreter */
 
695
 
 
696
                ctx->include = included;
 
697
                sieve_interpreter_interrupt(renv->interp);
 
698
        }
 
699
        
 
700
        return result;
 
701
}
 
702
 
 
703
void ext_include_execute_return(const struct sieve_runtime_env *renv)
 
704
{
 
705
        struct ext_include_interpreter_context *ctx =
 
706
                ext_include_get_interpreter_context(renv->interp);
 
707
        
 
708
        ctx->returned = TRUE;
 
709
        sieve_interpreter_interrupt(renv->interp);      
 
710
}
 
711