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

« back to all changes in this revision

Viewing changes to libsieve/src/lib-sieve/plugins/regex/mcht-regex.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
/* Match-type ':regex'
 
5
 */
 
6
 
 
7
#include "lib.h"
 
8
#include "mempool.h"
 
9
#include "buffer.h"
 
10
#include "array.h"
 
11
#include "str.h"
 
12
 
 
13
#include "sieve-common.h"
 
14
#include "sieve-limits.h"
 
15
#include "sieve-ast.h"
 
16
#include "sieve-commands.h"
 
17
#include "sieve-validator.h"
 
18
#include "sieve-comparators.h"
 
19
#include "sieve-match-types.h"
 
20
#include "sieve-match.h"
 
21
 
 
22
#include "ext-regex-common.h"
 
23
 
 
24
#include <sys/types.h>
 
25
#include <regex.h>
 
26
#include <ctype.h>
 
27
 
 
28
/*
 
29
 * Configuration
 
30
 */
 
31
 
 
32
#define MCHT_REGEX_MAX_SUBSTITUTIONS SIEVE_MAX_MATCH_VALUES
 
33
 
 
34
/* 
 
35
 * Match type
 
36
 */
 
37
 
 
38
bool mcht_regex_validate_context
 
39
(struct sieve_validator *validator, struct sieve_ast_argument *arg,
 
40
    struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg);
 
41
 
 
42
static void mcht_regex_match_init(struct sieve_match_context *mctx);
 
43
static int mcht_regex_match
 
44
        (struct sieve_match_context *mctx, const char *val, size_t val_size,
 
45
        const char *key, size_t key_size, int key_index);
 
46
static int mcht_regex_match_deinit(struct sieve_match_context *mctx);
 
47
 
 
48
const struct sieve_match_type regex_match_type = {
 
49
        SIEVE_OBJECT("regex", &regex_match_type_operand, 0),
 
50
        TRUE, FALSE,
 
51
        NULL,
 
52
        mcht_regex_validate_context,
 
53
        mcht_regex_match_init,
 
54
        mcht_regex_match,
 
55
        mcht_regex_match_deinit
 
56
};
 
57
 
 
58
/* 
 
59
 * Match type validation 
 
60
 */
 
61
 
 
62
/* Wrapper around the regerror function for easy access */
 
63
static const char *_regexp_error(regex_t *regexp, int errorcode)
 
64
{
 
65
        size_t errsize = regerror(errorcode, regexp, NULL, 0); 
 
66
 
 
67
        if ( errsize > 0 ) {
 
68
                char *errbuf;
 
69
 
 
70
                buffer_t *error_buf = 
 
71
                        buffer_create_dynamic(pool_datastack_create(), errsize);
 
72
                errbuf = buffer_get_space_unsafe(error_buf, 0, errsize);
 
73
 
 
74
                errsize = regerror(errorcode, regexp, errbuf, errsize);
 
75
         
 
76
                /* We don't want the error to start with a capital letter */
 
77
                errbuf[0] = i_tolower(errbuf[0]);
 
78
 
 
79
                buffer_append_space_unsafe(error_buf, errsize);
 
80
 
 
81
                return str_c(error_buf);
 
82
        }
 
83
 
 
84
        return "";
 
85
}
 
86
 
 
87
static int mcht_regex_validate_regexp
 
88
(struct sieve_validator *validator, 
 
89
        struct sieve_match_type_context *ctx ATTR_UNUSED,
 
90
        struct sieve_ast_argument *key, int cflags) 
 
91
{
 
92
        int ret;
 
93
        regex_t regexp;
 
94
 
 
95
        if ( (ret=regcomp(&regexp, sieve_ast_argument_strc(key), cflags)) != 0 ) {
 
96
                sieve_argument_validate_error(validator, key,
 
97
                        "invalid regular expression for regex match: %s", 
 
98
                        _regexp_error(&regexp, ret));
 
99
 
 
100
                regfree(&regexp);       
 
101
                return FALSE;
 
102
        }
 
103
 
 
104
        regfree(&regexp);
 
105
        return TRUE;
 
106
}
 
107
 
 
108
struct _regex_key_context {
 
109
        struct sieve_validator *valdtr;
 
110
        struct sieve_match_type_context *mctx;
 
111
        int cflags;
 
112
};
 
113
 
 
114
static int mcht_regex_validate_key_argument
 
115
(void *context, struct sieve_ast_argument *key)
 
116
{
 
117
        struct _regex_key_context *keyctx = (struct _regex_key_context *) context;
 
118
 
 
119
        /* FIXME: We can currently only handle string literal argument, so
 
120
         * variables are not allowed.
 
121
         */
 
122
        if ( !sieve_argument_is_string_literal(key) ) {
 
123
                sieve_argument_validate_error(keyctx->valdtr, key,
 
124
                        "this Sieve implementation currently only accepts a literal string "
 
125
                        "for a regular expression");
 
126
                return FALSE;
 
127
        }
 
128
 
 
129
        return mcht_regex_validate_regexp
 
130
                (keyctx->valdtr, keyctx->mctx, key, keyctx->cflags);
 
131
}
 
132
        
 
133
bool mcht_regex_validate_context
 
134
(struct sieve_validator *validator, struct sieve_ast_argument *arg ATTR_UNUSED,
 
135
        struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg)
 
136
{
 
137
        const struct sieve_comparator *cmp = ctx->comparator;
 
138
        int cflags = REG_EXTENDED | REG_NOSUB;
 
139
        struct _regex_key_context keyctx;
 
140
        struct sieve_ast_argument *kitem;
 
141
 
 
142
        if ( cmp != NULL ) { 
 
143
                if ( cmp == &i_ascii_casemap_comparator )
 
144
                        cflags =  REG_EXTENDED | REG_NOSUB | REG_ICASE;
 
145
                else if ( cmp == &i_octet_comparator )
 
146
                        cflags =  REG_EXTENDED | REG_NOSUB;
 
147
                else {
 
148
                        sieve_argument_validate_error(validator, ctx->match_type_arg, 
 
149
                                "regex match type only supports "
 
150
                                "i;octet and i;ascii-casemap comparators" );
 
151
                        return FALSE;   
 
152
                }
 
153
        }
 
154
 
 
155
        /* Validate regular expression keys */
 
156
 
 
157
        keyctx.valdtr = validator;
 
158
        keyctx.mctx = ctx;
 
159
        keyctx.cflags = cflags;
 
160
 
 
161
        kitem = key_arg;
 
162
        if ( !sieve_ast_stringlist_map(&kitem, (void *) &keyctx,
 
163
                mcht_regex_validate_key_argument) )
 
164
                return FALSE;
 
165
 
 
166
        return TRUE;
 
167
}
 
168
 
 
169
/* 
 
170
 * Match type implementation 
 
171
 */
 
172
 
 
173
struct mcht_regex_context {
 
174
        ARRAY_DEFINE(reg_expressions, regex_t);
 
175
        int value_index;
 
176
        regmatch_t *pmatch;
 
177
        size_t nmatch;
 
178
};
 
179
 
 
180
static void mcht_regex_match_init
 
181
(struct sieve_match_context *mctx)
 
182
{
 
183
        pool_t pool = mctx->pool;
 
184
        struct mcht_regex_context *ctx;
 
185
 
 
186
        /* Create context */    
 
187
        ctx = p_new(pool, struct mcht_regex_context, 1);
 
188
        p_array_init(&ctx->reg_expressions, pool, 4);
 
189
        ctx->value_index = -1;
 
190
 
 
191
        /* Create storage for match values if match values are requested */
 
192
        if ( sieve_match_values_are_enabled(mctx->interp) ) {
 
193
                ctx->pmatch = p_new(pool, regmatch_t, MCHT_REGEX_MAX_SUBSTITUTIONS);
 
194
                ctx->nmatch = MCHT_REGEX_MAX_SUBSTITUTIONS;
 
195
        } else {
 
196
                ctx->pmatch = NULL;
 
197
                ctx->nmatch = 0;
 
198
        }
 
199
        
 
200
        /* Assign context */
 
201
        mctx->data = (void *) ctx;
 
202
}
 
203
 
 
204
static regex_t *mcht_regex_get
 
205
(struct mcht_regex_context *ctx,
 
206
        const struct sieve_comparator *cmp, 
 
207
        const char *key, unsigned int key_index)
 
208
{
 
209
        int ret;
 
210
        int cflags;
 
211
        regex_t *regexp;
 
212
        
 
213
        /* If this is the first matched value, the regexes are not compiled
 
214
         * yet.
 
215
         */
 
216
        if ( ctx->value_index <= 0 ) {
 
217
                /* Allocate space */
 
218
                array_idx_clear(&ctx->reg_expressions, key_index);
 
219
                regexp = array_idx_modifiable(&ctx->reg_expressions, key_index);
 
220
 
 
221
                /* Configure case-sensitivity according to comparator */
 
222
                if ( cmp == &i_octet_comparator ) 
 
223
                        cflags =  REG_EXTENDED;
 
224
                else if ( cmp ==  &i_ascii_casemap_comparator )
 
225
                        cflags =  REG_EXTENDED | REG_ICASE;
 
226
                else
 
227
                        return NULL; /* Not supported */
 
228
                        
 
229
                /* Indicate whether match values need to be produced */
 
230
                if ( ctx->nmatch == 0 ) cflags |= REG_NOSUB;
 
231
 
 
232
                /* Compile regular expression */
 
233
                if ( (ret=regcomp(regexp, key, cflags)) != 0 ) {
 
234
                        /* FIXME: Do something useful, i.e. report error somewhere */
 
235
                        return NULL;
 
236
                }
 
237
        } else {
 
238
                /* Get compiled regex from cache */
 
239
                regexp = array_idx_modifiable(&ctx->reg_expressions, key_index);
 
240
        }
 
241
 
 
242
        return regexp;
 
243
}
 
244
 
 
245
static int mcht_regex_match
 
246
(struct sieve_match_context *mctx, 
 
247
        const char *val, size_t val_size ATTR_UNUSED, 
 
248
        const char *key, size_t key_size ATTR_UNUSED, int key_index)
 
249
{
 
250
        struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data;
 
251
        regex_t *regexp;
 
252
 
 
253
        if ( val == NULL ) {
 
254
                val = "";
 
255
                val_size = 0;
 
256
        }
 
257
 
 
258
        if ( key_index < 0 ) return FALSE;
 
259
 
 
260
        if ( key_index == 0 ) ctx->value_index++;
 
261
 
 
262
        /* Get compiled regex */
 
263
        if ( (regexp=mcht_regex_get(ctx, mctx->comparator, key, key_index)) == NULL )
 
264
                return FALSE;
 
265
 
 
266
        /* Execute regex */
 
267
        if ( regexec(regexp, val, ctx->nmatch, ctx->pmatch, 0) == 0 ) {
 
268
 
 
269
                /* Handle match values if necessary */
 
270
                if ( ctx->nmatch > 0 ) {
 
271
                        struct sieve_match_values *mvalues;
 
272
                        size_t i;
 
273
                        int skipped = 0;
 
274
                        string_t *subst = t_str_new(32);
 
275
 
 
276
                        /* Start new list of match values */
 
277
                        mvalues = sieve_match_values_start(mctx->interp);
 
278
 
 
279
                        i_assert( mvalues != NULL );
 
280
 
 
281
                        /* Add match values from regular expression */
 
282
                        for ( i = 0; i < ctx->nmatch; i++ ) {
 
283
                                str_truncate(subst, 0);
 
284
                        
 
285
                                if ( ctx->pmatch[i].rm_so != -1 ) {
 
286
                                        if ( skipped > 0 ) {
 
287
                                                sieve_match_values_skip(mvalues, skipped);
 
288
                                                skipped = 0;
 
289
                                        }
 
290
                                        
 
291
                                        str_append_n(subst, val + ctx->pmatch[i].rm_so, 
 
292
                                                ctx->pmatch[i].rm_eo - ctx->pmatch[i].rm_so);
 
293
                                        sieve_match_values_add(mvalues, subst);
 
294
                                } else 
 
295
                                        skipped++;
 
296
                        }
 
297
 
 
298
                        /* Substitute the new match values */
 
299
                        sieve_match_values_commit(mctx->interp, &mvalues);
 
300
                }
 
301
 
 
302
                return TRUE;
 
303
        }
 
304
        
 
305
        return FALSE;
 
306
}
 
307
 
 
308
int mcht_regex_match_deinit
 
309
(struct sieve_match_context *mctx)
 
310
{
 
311
        struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data;
 
312
        regex_t *regexps;
 
313
        unsigned int count, i;
 
314
 
 
315
        /* Clean up compiled regular expressions */
 
316
        regexps = array_get_modifiable(&ctx->reg_expressions, &count);
 
317
        for ( i = 0; i < count; i++ ) {
 
318
                regfree(&regexps[i]);
 
319
        }
 
320
 
 
321
        return FALSE;
 
322
}
 
323