~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-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/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.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2012 Pigeonhole authors, see the included COPYING file 
 
1
/* Copyright (c) 2002-2013 Pigeonhole authors, see the included COPYING file
2
2
 */
3
 
  
 
3
 
4
4
/* FIXME: URI syntax conforms to something somewhere in between RFC 2368 and
5
5
 *   draft-duerst-mailto-bis-05.txt. Should fully migrate to new specification
6
6
 *   when it matures. This requires modifications to the address parser (no
7
7
 *   whitespace allowed within the address itself) and UTF-8 support will be
8
8
 *   required in the URL.
9
9
 */
10
 
 
 
10
 
11
11
#include "lib.h"
12
12
#include "array.h"
13
13
#include "str.h"
26
26
 
27
27
#define uri_mailto_error(PARSER, ...) \
28
28
        sieve_error((PARSER)->ehandler, NULL, "invalid mailto URI: " __VA_ARGS__ )
29
 
        
 
29
 
30
30
#define uri_mailto_warning(PARSER, ...) \
31
31
        sieve_warning((PARSER)->ehandler, NULL, "mailto URI: " __VA_ARGS__ )
32
32
 
45
45
        int max_headers;
46
46
};
47
47
 
48
 
/* 
49
 
 * Reserved and unique headers 
 
48
/*
 
49
 * Reserved and unique headers
50
50
 */
51
 
 
 
51
 
52
52
static inline bool uri_mailto_header_is_reserved
53
53
(struct uri_mailto_parser *parser, const char *field_name)
54
54
{
81
81
        }
82
82
 
83
83
        return FALSE;
84
 
 
84
}
85
85
 
86
 
/* 
 
86
/*
87
87
 * Low-level URI parsing.
88
88
 *
89
89
 * FIXME: much of this implementation will be common to other URI schemes. This
114
114
{
115
115
        return _qchar_lookup[c];
116
116
}
117
 
  
 
117
 
118
118
static inline int _decode_hex_digit(unsigned char digit)
119
119
{
120
120
        switch ( digit ) {
121
 
        case '0': case '1': case '2': case '3': case '4': 
122
 
        case '5': case '6': case '7': case '8': case '9': 
 
121
        case '0': case '1': case '2': case '3': case '4':
 
122
        case '5': case '6': case '7': case '8': case '9':
123
123
                return (int) digit - '0';
124
124
 
125
125
        case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
126
126
                return (int) digit - 'a' + 0x0a;
127
 
                
 
127
 
128
128
        case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
129
129
                return (int) digit - 'A' + 0x0A;
130
130
        }
131
 
        
 
131
 
132
132
        return -1;
133
133
}
134
134
 
135
135
static bool _parse_hex_value(const char **in, char *out)
136
136
{
137
137
        int value, digit;
138
 
                
 
138
 
139
139
        if ( (digit=_decode_hex_digit((unsigned char) **in)) < 0 )
140
140
                return FALSE;
141
 
        
 
141
 
142
142
        value = digit << 4;
143
143
        (*in)++;
144
 
        
 
144
 
145
145
        if ( (digit=_decode_hex_digit((unsigned char) **in)) < 0 )
146
 
                return FALSE;   
 
146
                return FALSE;
147
147
 
148
148
        value |= digit;
149
149
        (*in)++;
152
152
                return FALSE;
153
153
 
154
154
        *out = (char) value;
155
 
        return TRUE;    
 
155
        return TRUE;
156
156
}
157
157
 
158
 
/* 
159
 
 * URI recipient parsing 
160
 
 */ 
 
158
/*
 
159
 * URI recipient parsing
 
160
 */
161
161
 
162
162
static bool uri_mailto_add_valid_recipient
163
163
(struct uri_mailto_parser *parser, string_t *recipient, bool cc)
168
168
        unsigned int count, i;
169
169
        const char *error;
170
170
        const char *normalized;
171
 
         
 
171
 
172
172
        /* Verify recipient */
173
173
        if ( (normalized=sieve_address_normalize(recipient, &error)) == NULL ) {
174
174
                uri_mailto_error(parser, "invalid recipient '%s': %s",
175
175
                        str_sanitize(str_c(recipient), 80), error);
176
176
                return FALSE;
177
177
        }
178
 
        
 
178
 
179
179
        /* Add recipient to the uri */
180
 
        if ( uri != NULL ) {                            
 
180
        if ( uri != NULL ) {
181
181
                /* Get current recipients */
182
182
                rcpts = array_get_modifiable(&uri->recipients, &count);
183
 
                
 
183
 
184
184
                /* Enforce limits */
185
185
                if ( parser->max_recipients > 0 && (int)count >= parser->max_recipients ) {
186
186
                        if ( (int)count == parser->max_recipients) {
187
 
                                uri_mailto_warning(parser, 
 
187
                                uri_mailto_warning(parser,
188
188
                                        "more than the maximum %u recipients specified; "
189
189
                                        "rest is discarded", parser->max_recipients);
190
190
                        }
191
 
                        return TRUE;    
 
191
                        return TRUE;
192
192
                }
193
 
        
 
193
 
194
194
                /* Check for duplicate first */
195
195
                for ( i = 0; i < count; i++ ) {
196
 
                        if ( sieve_address_compare(rcpts[i].normalized, normalized, TRUE) == 0 ) 
 
196
                        if ( sieve_address_compare(rcpts[i].normalized, normalized, TRUE) == 0 )
197
197
                                {
198
198
                                /* Upgrade existing Cc: recipient to a To: recipient if possible */
199
199
                                rcpts[i].carbon_copy = ( rcpts[i].carbon_copy && cc );
200
 
                        
 
200
 
201
201
                                uri_mailto_warning(parser, "ignored duplicate recipient '%s'",
202
202
                                        str_sanitize(str_c(recipient), 80));
203
203
                                return TRUE;
204
 
                        } 
205
 
                }                       
 
204
                        }
 
205
                }
206
206
 
207
207
                /* Add */
208
208
                new_recipient = array_append_space(&uri->recipients);
219
219
{
220
220
        string_t *to = t_str_new(128);
221
221
        const char *p = *uri_p;
222
 
        
 
222
 
223
223
        if ( *p == '\0' || *p == '?' )
224
224
                return TRUE;
225
 
                
 
225
 
226
226
        while ( *p != '\0' && *p != '?' ) {
227
227
                if ( *p == '%' ) {
228
228
                        /* % encoded character */
229
229
                        char ch;
230
 
                        
 
230
 
231
231
                        p++;
232
 
                        
 
232
 
233
233
                        /* Parse 2-digit hex value */
234
234
                        if ( !_parse_hex_value(&p, &ch) ) {
235
235
                                uri_mailto_error(parser, "invalid %% encoding");
241
241
                                /* Verify and add recipient */
242
242
                                if ( !uri_mailto_add_valid_recipient(parser, to, FALSE) )
243
243
                                        return FALSE;
244
 
                        
 
244
 
245
245
                                /* Reset for next recipient */
246
246
                                str_truncate(to, 0);
247
247
                        }       else {
259
259
                        str_append_c(to, *p);
260
260
                        p++;
261
261
                }
262
 
        }       
263
 
        
 
262
        }
 
263
 
264
264
        /* Skip '?' */
265
265
        if ( *p != '\0' ) p++;
266
 
        
 
266
 
267
267
        /* Verify and add recipient */
268
268
        if ( !uri_mailto_add_valid_recipient(parser, to, FALSE) )
269
269
                return FALSE;
278
278
        string_t *to = t_str_new(128);
279
279
        const char *p = (const char *) str_data(rcpt_header);
280
280
        const char *pend = p + str_len(rcpt_header);
281
 
                
 
281
 
282
282
        while ( p < pend ) {
283
283
                if ( *p == ',' ) {
284
284
                        /* Verify and add recipient */
285
285
                        if ( !uri_mailto_add_valid_recipient(parser, to, cc) )
286
286
                                return FALSE;
287
 
                        
 
287
 
288
288
                        /* Reset for next recipient */
289
289
                        str_truncate(to, 0);
290
290
                } else {
292
292
                        str_append_c(to, *p);
293
293
                }
294
294
                p++;
295
 
        }       
296
 
        
 
295
        }
 
296
 
297
297
        /* Verify and add recipient */
298
298
        if ( !uri_mailto_add_valid_recipient(parser, to, cc) )
299
299
                return FALSE;
300
300
 
301
 
        return TRUE;    
 
301
        return TRUE;
302
302
}
303
303
 
304
304
/* URI header parsing */
305
305
 
306
306
static bool uri_mailto_header_is_duplicate
307
307
(struct uri_mailto_parser *parser, const char *field_name)
308
 
{       
 
308
{
309
309
        struct uri_mailto *uri = parser->uri;
310
310
 
311
311
        if ( uri == NULL ) return FALSE;
314
314
                const struct uri_mailto_header_field *hdrs;
315
315
                unsigned int count, i;
316
316
 
317
 
                hdrs = array_get(&uri->headers, &count);        
 
317
                hdrs = array_get(&uri->headers, &count);
318
318
                for ( i = 0; i < count; i++ ) {
319
 
                        if ( strcasecmp(hdrs[i].name, field_name) == 0 ) 
 
319
                        if ( strcasecmp(hdrs[i].name, field_name) == 0 )
320
320
                                return TRUE;
321
321
                }
322
322
        }
323
 
        
 
323
 
324
324
        return FALSE;
325
325
}
326
326
 
331
331
        unsigned int header_count = 0;
332
332
        string_t *field = t_str_new(128);
333
333
        const char *p = *uri_p;
334
 
                                        
 
334
 
335
335
        while ( *p != '\0' ) {
336
336
                enum {
337
 
                        _HNAME_IGNORED, 
 
337
                        _HNAME_IGNORED,
338
338
                        _HNAME_GENERIC,
339
339
                        _HNAME_TO,
340
340
                        _HNAME_CC,
341
 
                        _HNAME_SUBJECT, 
342
 
                        _HNAME_BODY 
 
341
                        _HNAME_SUBJECT,
 
342
                        _HNAME_BODY
343
343
                } hname_type = _HNAME_GENERIC;
344
344
                struct uri_mailto_header_field *hdrf = NULL;
345
345
                const char *field_name;
346
 
                
 
346
 
347
347
                /* Parse field name */
348
348
                while ( *p != '\0' && *p != '=' ) {
349
349
                        char ch = *p;
350
350
                        p++;
351
 
                        
 
351
 
352
352
                        if ( ch == '%' ) {
353
353
                                /* Encoded, parse 2-digit hex value */
354
354
                                if ( !_parse_hex_value(&p, &ch) ) {
371
371
                        return FALSE;
372
372
                }
373
373
 
374
 
                if ( parser->max_headers > -1 && 
 
374
                if ( parser->max_headers > -1 &&
375
375
                        (int)header_count >= parser->max_headers ) {
376
376
                        /* Refuse to accept more headers than allowed by policy */
377
377
                        if ( (int)header_count == parser->max_headers ) {
378
378
                                uri_mailto_warning(parser, "more than the maximum %u headers specified; "
379
379
                                        "rest is discarded", parser->max_headers);
380
380
                        }
381
 
                        
 
381
 
382
382
                        hname_type = _HNAME_IGNORED;
383
383
                } else {
384
384
                        /* Add new header field to array and assign its name */
385
 
                        
 
385
 
386
386
                        field_name = str_c(field);
387
387
                        if ( strcasecmp(field_name, "to") == 0 )
388
388
                                hname_type = _HNAME_TO;
398
398
                                                hdrf = array_append_space(&uri->headers);
399
399
                                                hdrf->name = p_strdup(parser->pool, field_name);
400
400
                                        } else {
401
 
                                                uri_mailto_warning(parser, 
 
401
                                                uri_mailto_warning(parser,
402
402
                                                        "ignored duplicate for unique header field '%s'",
403
403
                                                        str_sanitize(field_name, 32));
404
404
                                                hname_type = _HNAME_IGNORED;
412
412
                                hname_type = _HNAME_IGNORED;
413
413
                        }
414
414
                }
415
 
                
 
415
 
416
416
                header_count++;
417
 
                        
 
417
 
418
418
                /* Reset for field body */
419
419
                str_truncate(field, 0);
420
 
                
421
 
                /* Parse field body */          
 
420
 
 
421
                /* Parse field body */
422
422
                while ( *p != '\0' && *p != '&' ) {
423
423
                        char ch = *p;
424
424
                        p++;
425
 
                        
 
425
 
426
426
                        if ( ch == '%' ) {
427
427
                                /* Encoded, parse 2-digit hex value */
428
428
                                if ( !_parse_hex_value(&p, &ch) ) {
437
437
                        str_append_c(field, ch);
438
438
                }
439
439
                if ( *p != '\0' ) p++;
440
 
                
 
440
 
441
441
                /* Verify field body */
442
442
                if ( hname_type == _HNAME_BODY ) {
443
 
                        // FIXME: verify body ... 
 
443
                        // FIXME: verify body ...
444
444
                } else {
445
445
                        if ( !rfc2822_header_field_body_verify
446
446
                                (str_c(field), str_len(field), FALSE, FALSE) ) {
448
448
                                return FALSE;
449
449
                        }
450
450
                }
451
 
                
 
451
 
452
452
                /* Assign field body */
453
453
 
454
454
                switch ( hname_type ) {
478
478
                        if ( uri != NULL ) {
479
479
                                if ( uri->body == NULL )
480
480
                                        uri->body = p_strdup(parser->pool, str_c(field));
481
 
                                else 
 
481
                                else
482
482
                                        uri_mailto_warning(parser, "ignored duplicate body field");
483
483
                        }
484
484
                        break;
485
485
                case _HNAME_GENERIC:
486
 
                        if ( uri != NULL && hdrf != NULL ) 
 
486
                        if ( uri != NULL && hdrf != NULL )
487
487
                                hdrf->body = p_strdup(parser->pool, str_c(field));
488
488
                        break;
489
489
                }
490
 
                        
 
490
 
491
491
                /* Reset for next name */
492
492
                str_truncate(field, 0);
493
 
        }       
494
 
        
 
493
        }
 
494
 
495
495
        /* Skip '&' */
496
496
        if ( *p != '\0' ) p++;
497
497
 
503
503
(struct uri_mailto_parser *parser, const char *uri_body)
504
504
{
505
505
        const char *p = uri_body;
506
 
        
507
 
        /* 
 
506
 
 
507
        /*
508
508
         * mailtoURI   = "mailto:" [ to ] [ hfields ]
509
509
         * to          = [ addr-spec *("%2C" addr-spec ) ]
510
510
         * hfields     = "?" hfield *( "&" hfield )
518
518
         *               / "+" / "," / ";" / ":" / "@"
519
519
         *
520
520
         * to         ~= *tqchar
521
 
         * tqchar     ~= <qchar> without ";" and ":" 
522
 
         * 
 
521
         * tqchar     ~= <qchar> without ";" and ":"
 
522
         *
523
523
         * Scheme 'mailto:' already parsed, starting parse after colon
524
524
         */
525
525
 
527
527
         */
528
528
 
529
529
        if ( !uri_mailto_parse_recipients(parser, &p) )
530
 
                return FALSE;   
531
 
 
532
 
        /* Extract hfield items */      
533
 
        
534
 
        while ( *p != '\0' ) {          
 
530
                return FALSE;
 
531
 
 
532
        /* Extract hfield items */
 
533
 
 
534
        while ( *p != '\0' ) {
535
535
                /* Extract hfield item by searching for '&' and decoding '%' items */
536
536
                if ( !uri_mailto_parse_headers(parser, &p) )
537
 
                        return FALSE;           
 
537
                        return FALSE;
538
538
        }
539
 
        
 
539
 
540
540
        return TRUE;
541
541
}
542
542
 
545
545
 */
546
546
 
547
547
bool uri_mailto_validate
548
 
(const char *uri_body, const char **reserved_headers, 
549
 
        const char **unique_headers, int max_recipients, int max_headers, 
 
548
(const char *uri_body, const char **reserved_headers,
 
549
        const char **unique_headers, int max_recipients, int max_headers,
550
550
        struct sieve_error_handler *ehandler)
551
551
{
552
552
        struct uri_mailto_parser parser;
557
557
        parser.max_headers = max_headers;
558
558
        parser.reserved_headers = reserved_headers;
559
559
        parser.unique_headers = unique_headers;
560
 
        
 
560
 
561
561
        /* If no errors are reported, we don't need to record any data */
562
 
        if ( ehandler != NULL ) { 
 
562
        if ( ehandler != NULL ) {
563
563
                parser.pool = pool_datastack_create();
564
564
 
565
565
                parser.uri = p_new(parser.pool, struct uri_mailto, 1);
566
566
                p_array_init(&parser.uri->recipients, parser.pool, max_recipients);
567
567
                p_array_init(&parser.uri->headers, parser.pool, max_headers);
568
568
        }
569
 
        
 
569
 
570
570
        if ( !uri_mailto_parse_uri(&parser, uri_body) )
571
571
                return FALSE;
572
 
                
 
572
 
573
573
        if ( ehandler != NULL ) {
574
574
                if ( array_count(&parser.uri->recipients) == 0 )
575
575
                        uri_mailto_warning(&parser, "notification URI specifies no recipients");
576
576
        }
577
 
   
 
577
 
578
578
        return TRUE;
579
579
}
580
580
 
583
583
 */
584
584
 
585
585
struct uri_mailto *uri_mailto_parse
586
 
(const char *uri_body, pool_t pool, const char **reserved_headers, 
587
 
        const char **unique_headers, int max_recipients, int max_headers, 
 
586
(const char *uri_body, pool_t pool, const char **reserved_headers,
 
587
        const char **unique_headers, int max_recipients, int max_headers,
588
588
        struct sieve_error_handler *ehandler)
589
589
{
590
590
        struct uri_mailto_parser parser;
591
 
        
 
591
 
592
592
        parser.pool = pool;
593
593
        parser.ehandler = ehandler;
594
594
        parser.max_recipients = max_recipients;
599
599
        parser.uri = p_new(pool, struct uri_mailto, 1);
600
600
        p_array_init(&parser.uri->recipients, pool, max_recipients);
601
601
        p_array_init(&parser.uri->headers, pool, max_headers);
602
 
        
 
602
 
603
603
        if ( !uri_mailto_parse_uri(&parser, uri_body) )
604
604
                return FALSE;
605
 
                
 
605
 
606
606
        if ( ehandler != NULL ) {
607
607
                if ( array_count(&parser.uri->recipients) == 0 )
608
608
                        uri_mailto_warning(&parser, "notification URI specifies no recipients");