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

« back to all changes in this revision

Viewing changes to libsieve/src/lib-sieve/sieve-error.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 "str.h"
 
6
#include "ostream.h"
 
7
#include "eacces-error.h"
 
8
 
 
9
#include "sieve-common.h"
 
10
#include "sieve-script.h"
 
11
#include "sieve-error-private.h"
 
12
 
 
13
#include <sys/types.h>
 
14
#include <sys/stat.h>
 
15
#include <fcntl.h>
 
16
#include <stdlib.h>
 
17
#include <unistd.h>
 
18
#include <stdio.h>
 
19
 
 
20
/*
 
21
 * Definitions
 
22
 */
 
23
 
 
24
#define CRITICAL_MSG \
 
25
        "internal error occurred: refer to server log for more information."
 
26
#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
 
27
 
 
28
/* Logfile error handler will rotate log when it exceeds 10k bytes */
 
29
#define LOGFILE_MAX_SIZE (10 * 1024)
 
30
 
 
31
/*
 
32
 * Utility
 
33
 */
 
34
 
 
35
const char *sieve_error_script_location
 
36
(const struct sieve_script *script, unsigned int source_line)
 
37
{
 
38
    const char *sname;
 
39
 
 
40
        sname = ( script == NULL ? NULL : sieve_script_name(script) );
 
41
 
 
42
    if ( sname == NULL || *sname == '\0' )
 
43
        return t_strdup_printf("line %d", source_line);
 
44
 
 
45
    return t_strdup_printf("%s: line %d", sname, source_line);
 
46
}
 
47
 
 
48
/*
 
49
 * Main error functions
 
50
 */
 
51
 
 
52
void sieve_verror
 
53
        (struct sieve_error_handler *ehandler, const char *location, 
 
54
                const char *fmt, va_list args)
 
55
{
 
56
        if ( ehandler == NULL ) return;
 
57
        
 
58
        if ( ehandler->log_master ) {
 
59
                va_list args_copy;
 
60
 
 
61
                VA_COPY(args_copy, args);
 
62
 
 
63
                if ( location == NULL || *location == '\0' )
 
64
                        sieve_sys_error("%s", t_strdup_vprintf(fmt, args_copy));
 
65
                else
 
66
                        sieve_sys_error("%s: %s", location, t_strdup_vprintf(fmt, args_copy));
 
67
        }
 
68
 
 
69
        if ( sieve_errors_more_allowed(ehandler) ) {
 
70
                if ( ehandler->verror != NULL )
 
71
                        ehandler->verror(ehandler, location, fmt, args);
 
72
                
 
73
                if ( ehandler->pool != NULL )
 
74
                        ehandler->errors++;
 
75
        }
 
76
}
 
77
 
 
78
void sieve_vwarning
 
79
        (struct sieve_error_handler *ehandler, const char *location, 
 
80
                const char *fmt, va_list args)
 
81
{
 
82
        if ( ehandler == NULL ) return;
 
83
 
 
84
        if ( ehandler->log_master ) {
 
85
                va_list args_copy;
 
86
 
 
87
                VA_COPY(args_copy, args);
 
88
 
 
89
                if ( location == NULL || *location == '\0' )
 
90
                        sieve_sys_warning("%s", t_strdup_vprintf(fmt, args_copy));
 
91
                else
 
92
                        sieve_sys_warning("%s: %s", location, t_strdup_vprintf(fmt, args_copy));
 
93
        }
 
94
        
 
95
        if ( ehandler->vwarning != NULL )       
 
96
                ehandler->vwarning(ehandler, location, fmt, args);
 
97
 
 
98
        if ( ehandler->pool != NULL )
 
99
                ehandler->warnings++;
 
100
}
 
101
 
 
102
void sieve_vinfo
 
103
        (struct sieve_error_handler *ehandler, const char *location, 
 
104
                const char *fmt, va_list args)
 
105
{
 
106
        if ( ehandler == NULL ) return;
 
107
 
 
108
        if ( ehandler->log_master ) {
 
109
                va_list args_copy;
 
110
 
 
111
                VA_COPY(args_copy, args);
 
112
 
 
113
 
 
114
                if ( location == NULL || *location == '\0' )
 
115
                        sieve_sys_info("%s", t_strdup_vprintf(fmt, args_copy));
 
116
                else    
 
117
                        sieve_sys_info("%s: %s", location, t_strdup_vprintf(fmt, args_copy));
 
118
        }
 
119
        
 
120
        if ( ehandler->log_info && ehandler->vinfo != NULL )    
 
121
                ehandler->vinfo(ehandler, location, fmt, args);
 
122
}
 
123
 
 
124
void sieve_vcritical
 
125
        (struct sieve_error_handler *ehandler, const char *location, 
 
126
                const char *fmt, va_list args)
 
127
{
 
128
        char str[256];
 
129
        struct tm *tm; 
 
130
        
 
131
        tm = localtime(&ioloop_time);
 
132
        
 
133
        if ( location == NULL || *location == '\0' )
 
134
                sieve_sys_error("%s", t_strdup_vprintf(fmt, args));
 
135
        else
 
136
                sieve_sys_error("%s: %s", location, t_strdup_vprintf(fmt, args));
 
137
                
 
138
        if ( ehandler == NULL ) return;
 
139
        
 
140
        sieve_error(ehandler, location, "%s", 
 
141
                strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ? 
 
142
                        str : CRITICAL_MSG );   
 
143
}
 
144
 
 
145
/*
 
146
 * Error statistics
 
147
 */
 
148
 
 
149
unsigned int sieve_get_errors(struct sieve_error_handler *ehandler) 
 
150
{
 
151
        if ( ehandler == NULL || ehandler->pool == NULL ) return 0;
 
152
        
 
153
        return ehandler->errors;
 
154
}
 
155
 
 
156
unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler) 
 
157
{
 
158
        if ( ehandler == NULL || ehandler->pool == NULL ) return 0;
 
159
 
 
160
        return ehandler->errors;
 
161
}
 
162
 
 
163
bool sieve_errors_more_allowed(struct sieve_error_handler *ehandler) 
 
164
{
 
165
        if ( ehandler == NULL || ehandler->pool == NULL ) 
 
166
                return TRUE;
 
167
 
 
168
        return ehandler->max_errors == 0 || ehandler->errors < ehandler->max_errors;
 
169
}
 
170
 
 
171
/*
 
172
 * Error handler configuration
 
173
 */
 
174
 
 
175
void sieve_error_handler_accept_infolog
 
176
        (struct sieve_error_handler *ehandler, bool enable)
 
177
{
 
178
        ehandler->log_info = enable;    
 
179
}
 
180
 
 
181
void sieve_error_handler_copy_masterlog
 
182
        (struct sieve_error_handler *ehandler, bool enable)
 
183
{
 
184
        ehandler->log_master = enable;
 
185
}
 
186
 
 
187
/*
 
188
 * Error handler init
 
189
 */
 
190
 
 
191
void sieve_error_handler_init
 
192
        (struct sieve_error_handler *ehandler, pool_t pool, unsigned int max_errors)
 
193
{
 
194
        ehandler->pool = pool;
 
195
        ehandler->refcount = 1;
 
196
        ehandler->max_errors = max_errors;
 
197
        
 
198
        ehandler->errors = 0;
 
199
        ehandler->warnings = 0;
 
200
}
 
201
 
 
202
void sieve_error_handler_ref(struct sieve_error_handler *ehandler)
 
203
{
 
204
        if ( ehandler == NULL || ehandler->pool == NULL ) return;
 
205
 
 
206
        ehandler->refcount++;
 
207
}
 
208
 
 
209
void sieve_error_handler_unref(struct sieve_error_handler **ehandler)
 
210
{
 
211
        if ( *ehandler == NULL || (*ehandler)->pool == NULL ) return;
 
212
 
 
213
        i_assert((*ehandler)->refcount > 0);
 
214
 
 
215
        if (--(*ehandler)->refcount != 0)
 
216
                return;
 
217
 
 
218
        if ( (*ehandler)->free != NULL )
 
219
                (*ehandler)->free(*ehandler);
 
220
 
 
221
        pool_unref(&((*ehandler)->pool));
 
222
 
 
223
        *ehandler = NULL;
 
224
}
 
225
 
 
226
void sieve_error_handler_reset(struct sieve_error_handler *ehandler)
 
227
{
 
228
        if ( ehandler == NULL || ehandler->pool == NULL ) return;
 
229
 
 
230
        ehandler->errors = 0;
 
231
        ehandler->warnings = 0;
 
232
}
 
233
 
 
234
/* 
 
235
 * Master/System error handler
 
236
 *
 
237
 * - Output errors directly to Dovecot master log
 
238
 */
 
239
 
 
240
static void sieve_master_verror
 
241
(struct sieve_error_handler *ehandler, const char *location, 
 
242
        const char *fmt, va_list args) 
 
243
{
 
244
        if ( ehandler->log_master ) return;
 
245
 
 
246
        if ( location == NULL || *location == '\0' )
 
247
                i_error("sieve: %s", t_strdup_vprintf(fmt, args));
 
248
        else
 
249
                i_error("sieve: %s: %s", location, t_strdup_vprintf(fmt, args));
 
250
}
 
251
 
 
252
static void sieve_master_vwarning
 
253
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, 
 
254
        const char *fmt, va_list args) 
 
255
{
 
256
        if ( ehandler->log_master ) return;
 
257
 
 
258
        if ( location == NULL || *location == '\0' )
 
259
                i_warning("sieve: %s", t_strdup_vprintf(fmt, args));
 
260
        else
 
261
                i_warning("sieve: %s: %s", location, t_strdup_vprintf(fmt, args));
 
262
}
 
263
 
 
264
static void sieve_master_vinfo
 
265
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, 
 
266
        const char *fmt, va_list args) 
 
267
{
 
268
        if ( ehandler->log_master ) return;
 
269
 
 
270
        if ( location == NULL || *location == '\0' )
 
271
                i_info("sieve: %s", t_strdup_vprintf(fmt, args));
 
272
        else
 
273
                i_info("sieve: %s: %s", location, t_strdup_vprintf(fmt, args));
 
274
}
 
275
 
 
276
struct sieve_error_handler *sieve_master_ehandler_create
 
277
(unsigned int max_errors) 
 
278
{
 
279
        pool_t pool;
 
280
        struct sieve_error_handler *ehandler;
 
281
        
 
282
        /* Pool is not strictly necessary, but other handler types will need a pool,
 
283
         * so this one will have one too.
 
284
         */
 
285
        pool = pool_alloconly_create
 
286
                ("master_error_handler", sizeof(struct sieve_error_handler));
 
287
        ehandler = p_new(pool, struct sieve_error_handler, 1);
 
288
        sieve_error_handler_init(ehandler, pool, max_errors);
 
289
 
 
290
        ehandler->verror = sieve_master_verror;
 
291
        ehandler->vwarning = sieve_master_vwarning;
 
292
        ehandler->vinfo = sieve_master_vinfo;
 
293
        
 
294
        return ehandler;        
 
295
}
 
296
 
 
297
struct sieve_error_handler _sieve_system_ehandler_object = {
 
298
        NULL, 0, 0, 0, 0,
 
299
        FALSE,
 
300
        TRUE,
 
301
        sieve_master_verror,
 
302
        sieve_master_vwarning,
 
303
        sieve_master_vinfo,
 
304
        NULL
 
305
};
 
306
 
 
307
struct sieve_error_handler *_sieve_system_ehandler = &_sieve_system_ehandler_object;
 
308
 
 
309
void sieve_system_ehandler_set(struct sieve_error_handler *ehandler)
 
310
{
 
311
        sieve_error_handler_unref(&_sieve_system_ehandler);
 
312
        _sieve_system_ehandler = ehandler;
 
313
        sieve_error_handler_ref(_sieve_system_ehandler);
 
314
}
 
315
 
 
316
void sieve_system_ehandler_reset(void)
 
317
{
 
318
        sieve_error_handler_unref(&_sieve_system_ehandler);
 
319
        _sieve_system_ehandler = &_sieve_system_ehandler_object;        
 
320
}
 
321
 
 
322
/* 
 
323
 * STDERR error handler
 
324
 *
 
325
 * - Output errors directly to stderror 
 
326
 */
 
327
 
 
328
static void sieve_stderr_verror
 
329
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, 
 
330
        const char *fmt, va_list args) 
 
331
{
 
332
        if ( location == NULL || *location == '\0' )
 
333
                fprintf(stderr, "error: %s.\n", t_strdup_vprintf(fmt, args));
 
334
        else
 
335
                fprintf(stderr, "%s: error: %s.\n", location, t_strdup_vprintf(fmt, args));
 
336
}
 
337
 
 
338
static void sieve_stderr_vwarning
 
339
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, 
 
340
        const char *fmt, va_list args) 
 
341
{
 
342
        if ( location == NULL || *location == '\0' )
 
343
                fprintf(stderr, "warning: %s.\n", t_strdup_vprintf(fmt, args));
 
344
        else
 
345
                fprintf(stderr, "%s: warning: %s.\n", location, t_strdup_vprintf(fmt, args));
 
346
}
 
347
 
 
348
static void sieve_stderr_vinfo
 
349
(struct sieve_error_handler *ehandler ATTR_UNUSED, const char *location, 
 
350
        const char *fmt, va_list args) 
 
351
{
 
352
        if ( location == NULL || *location == '\0' )
 
353
                fprintf(stderr, "info: %s.\n", t_strdup_vprintf(fmt, args));
 
354
        else
 
355
                fprintf(stderr, "%s: info: %s.\n", location, t_strdup_vprintf(fmt, args));
 
356
}
 
357
 
 
358
struct sieve_error_handler *sieve_stderr_ehandler_create
 
359
(unsigned int max_errors) 
 
360
{
 
361
        pool_t pool;
 
362
        struct sieve_error_handler *ehandler;
 
363
        
 
364
        /* Pool is not strictly necessary, but other handler types will need a pool,
 
365
         * so this one will have one too.
 
366
         */
 
367
        pool = pool_alloconly_create
 
368
                ("stderr_error_handler", sizeof(struct sieve_error_handler));
 
369
        ehandler = p_new(pool, struct sieve_error_handler, 1);
 
370
        sieve_error_handler_init(ehandler, pool, max_errors);
 
371
 
 
372
        ehandler->verror = sieve_stderr_verror;
 
373
        ehandler->vwarning = sieve_stderr_vwarning;
 
374
        ehandler->vinfo = sieve_stderr_vinfo;
 
375
        
 
376
        return ehandler;        
 
377
}
 
378
 
 
379
/* String buffer error handler
 
380
 *
 
381
 * - Output errors to a string buffer 
 
382
 */
 
383
 
 
384
struct sieve_strbuf_ehandler {
 
385
        struct sieve_error_handler handler;
 
386
 
 
387
        string_t *errors;
 
388
        bool crlf;
 
389
};
 
390
 
 
391
static void sieve_strbuf_verror
 
392
(struct sieve_error_handler *ehandler, const char *location,
 
393
    const char *fmt, va_list args)
 
394
{
 
395
        struct sieve_strbuf_ehandler *handler =
 
396
                (struct sieve_strbuf_ehandler *) ehandler;
 
397
 
 
398
        if ( location != NULL && *location != '\0' )
 
399
                str_printfa(handler->errors, "%s: ", location);
 
400
        str_append(handler->errors, "error: ");
 
401
        str_vprintfa(handler->errors, fmt, args);
 
402
 
 
403
        if ( !handler->crlf )
 
404
                str_append(handler->errors, ".\n");
 
405
        else
 
406
                str_append(handler->errors, ".\r\n");
 
407
}
 
408
 
 
409
static void sieve_strbuf_vwarning
 
410
(struct sieve_error_handler *ehandler, const char *location,
 
411
    const char *fmt, va_list args)
 
412
{
 
413
        struct sieve_strbuf_ehandler *handler =
 
414
                (struct sieve_strbuf_ehandler *) ehandler;
 
415
 
 
416
        if ( location != NULL && *location != '\0' )
 
417
                str_printfa(handler->errors, "%s: ", location);
 
418
        str_printfa(handler->errors, "warning: ");
 
419
        str_vprintfa(handler->errors, fmt, args);
 
420
 
 
421
        if ( !handler->crlf )
 
422
                str_append(handler->errors, ".\n");
 
423
        else
 
424
                str_append(handler->errors, ".\r\n");
 
425
}
 
426
 
 
427
static void sieve_strbuf_vinfo
 
428
(struct sieve_error_handler *ehandler, const char *location,
 
429
    const char *fmt, va_list args)
 
430
{
 
431
        struct sieve_strbuf_ehandler *handler =
 
432
                (struct sieve_strbuf_ehandler *) ehandler;
 
433
 
 
434
        if ( location != NULL && *location != '\0' )
 
435
                str_printfa(handler->errors, "%s: ", location); 
 
436
        str_printfa(handler->errors, "info: ");
 
437
        str_vprintfa(handler->errors, fmt, args);
 
438
 
 
439
        if ( !handler->crlf )
 
440
                str_append(handler->errors, ".\n");
 
441
        else
 
442
                str_append(handler->errors, ".\r\n");
 
443
}
 
444
 
 
445
struct sieve_error_handler *sieve_strbuf_ehandler_create
 
446
(string_t *strbuf, bool crlf, unsigned int max_errors)
 
447
{
 
448
        pool_t pool;
 
449
        struct sieve_strbuf_ehandler *ehandler;
 
450
 
 
451
        pool = pool_alloconly_create("strbuf_error_handler", 256);
 
452
        ehandler = p_new(pool, struct sieve_strbuf_ehandler, 1);
 
453
        ehandler->errors = strbuf;
 
454
    
 
455
        sieve_error_handler_init(&ehandler->handler, pool, max_errors);
 
456
 
 
457
        ehandler->handler.verror = sieve_strbuf_verror;
 
458
        ehandler->handler.vwarning = sieve_strbuf_vwarning;
 
459
        ehandler->handler.vinfo = sieve_strbuf_vinfo;
 
460
 
 
461
        ehandler->crlf = crlf;
 
462
 
 
463
        return &(ehandler->handler);
 
464
}
 
465
 
 
466
/* 
 
467
 * Logfile error handler
 
468
 * 
 
469
 * - Output errors to a log file 
 
470
 */
 
471
 
 
472
struct sieve_logfile_ehandler {
 
473
        struct sieve_error_handler handler;
 
474
        
 
475
        const char *logfile;
 
476
        bool started;
 
477
        int fd;
 
478
        struct ostream *stream;
 
479
};
 
480
 
 
481
static void sieve_logfile_vprintf
 
482
(struct sieve_logfile_ehandler *ehandler, const char *location, 
 
483
        const char *prefix, const char *fmt, va_list args) 
 
484
{
 
485
        string_t *outbuf;
 
486
        ssize_t ret = 0, remain;
 
487
        const char *data;
 
488
        
 
489
        if ( ehandler->stream == NULL ) return;
 
490
        
 
491
        T_BEGIN {
 
492
                outbuf = t_str_new(256);
 
493
                if ( location != NULL && *location != '\0' )
 
494
                        str_printfa(outbuf, "%s: ", location);
 
495
                str_printfa(outbuf, "%s: ", prefix);    
 
496
                str_vprintfa(outbuf, fmt, args);
 
497
                str_append(outbuf, ".\n");
 
498
        
 
499
                remain = str_len(outbuf);
 
500
                data = (const char *) str_data(outbuf);
 
501
 
 
502
                while ( remain > 0 ) { 
 
503
                        if ( (ret=o_stream_send(ehandler->stream, data, remain)) < 0 )
 
504
                                break;
 
505
 
 
506
                        remain -= ret;
 
507
                        data += ret;
 
508
                }
 
509
        } T_END;
 
510
 
 
511
        if ( ret < 0 ) {
 
512
                sieve_sys_error(
 
513
                        "o_stream_send() failed on logfile %s: %m", ehandler->logfile);         
 
514
        }
 
515
}
 
516
 
 
517
inline static void sieve_logfile_printf
 
518
(struct sieve_logfile_ehandler *ehandler, const char *location, const char *prefix,
 
519
        const char *fmt, ...) 
 
520
{
 
521
        va_list args;
 
522
        va_start(args, fmt);
 
523
        
 
524
        sieve_logfile_vprintf(ehandler, location, prefix, fmt, args);
 
525
        
 
526
        va_end(args);
 
527
}
 
528
 
 
529
static void sieve_logfile_start(struct sieve_logfile_ehandler *ehandler)
 
530
{
 
531
        int fd;
 
532
        struct ostream *ostream = NULL;
 
533
        struct stat st;
 
534
        struct tm *tm;
 
535
        char buf[256];
 
536
        time_t now;
 
537
 
 
538
        /* Open the logfile */
 
539
 
 
540
        fd = open(ehandler->logfile, O_CREAT | O_APPEND | O_WRONLY, 0600);
 
541
        if (fd == -1) {
 
542
                if ( errno == EACCES ) {
 
543
                        sieve_sys_error("failed to open logfile (LOGGING TO STDERR): %s",
 
544
                                eacces_error_get_creating("open", ehandler->logfile));
 
545
                } else {
 
546
                        sieve_sys_error("failed to open logfile (LOGGING TO STDERR): "
 
547
                                "open(%s) failed: %m", ehandler->logfile);
 
548
                }
 
549
                fd = STDERR_FILENO;
 
550
        } else {
 
551
                /* fd_close_on_exec(fd, TRUE); Necessary? */
 
552
 
 
553
                /* Stat the log file to obtain size information */
 
554
                if ( fstat(fd, &st) != 0 ) {
 
555
                        sieve_sys_error("failed to stat logfile (logging to STDERR): "
 
556
                                "fstat(fd=%s) failed: %m", ehandler->logfile);
 
557
                        
 
558
                        if ( close(fd) < 0 ) {
 
559
                                sieve_sys_error("failed to close logfile after error: "
 
560
                                        "close(fd=%s) failed: %m", ehandler->logfile);
 
561
                        }
 
562
 
 
563
                        fd = STDERR_FILENO;
 
564
                }
 
565
                
 
566
                /* Rotate log when it has grown too large */
 
567
                if ( st.st_size >= LOGFILE_MAX_SIZE ) {
 
568
                        const char *rotated;
 
569
                        
 
570
                        /* Close open file */
 
571
                        if ( close(fd) < 0 ) {
 
572
                                sieve_sys_error("failed to close logfile: close(fd=%s) failed: %m",
 
573
                                        ehandler->logfile);
 
574
                        }
 
575
                        
 
576
                        /* Rotate logfile */
 
577
                        rotated = t_strconcat(ehandler->logfile, ".0", NULL);
 
578
                        if ( rename(ehandler->logfile, rotated) < 0 ) {
 
579
                                sieve_sys_error("failed to rotate logfile: rename(%s, %s) failed: %m", 
 
580
                                        ehandler->logfile, rotated);
 
581
                        }
 
582
                        
 
583
                        /* Open clean logfile (overwrites existing if rename() failed earlier) */
 
584
                        fd = open(ehandler->logfile, O_CREAT | O_WRONLY | O_TRUNC, 0600);
 
585
                        if (fd == -1) {
 
586
                                if ( errno == EACCES ) {
 
587
                                        sieve_sys_error("failed to open logfile (LOGGING TO STDERR): %s",
 
588
                                                eacces_error_get_creating("open", ehandler->logfile));
 
589
                                } else {
 
590
                                        sieve_sys_error("failed to open logfile (LOGGING TO STDERR): "
 
591
                                                "open(%s) failed: %m", ehandler->logfile);
 
592
                                }
 
593
                                fd = STDERR_FILENO;
 
594
                        }
 
595
                }
 
596
        }
 
597
 
 
598
        ostream = o_stream_create_fd(fd, 0, FALSE);
 
599
        if ( ostream == NULL ) {
 
600
                /* Can't we do anything else in this most awkward situation? */
 
601
                sieve_sys_error("failed to open log stream on open file: "
 
602
                        "o_stream_create_fd(fd=%s) failed "
 
603
                        "(non-critical messages are not logged!)", ehandler->logfile);
 
604
        } 
 
605
 
 
606
        ehandler->fd = fd;
 
607
        ehandler->stream = ostream;
 
608
        ehandler->started = TRUE;
 
609
        
 
610
        if ( ostream != NULL ) {
 
611
                now = time(NULL);       
 
612
                tm = localtime(&now);
 
613
 
 
614
                if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", tm) > 0) {
 
615
                        sieve_logfile_printf(ehandler, "sieve", "info",
 
616
                                "started log at %s", buf);
 
617
                }
 
618
        }
 
619
}
 
620
 
 
621
static void sieve_logfile_verror
 
622
(struct sieve_error_handler *ehandler, const char *location, 
 
623
        const char *fmt, va_list args) 
 
624
{
 
625
        struct sieve_logfile_ehandler *handler = 
 
626
                (struct sieve_logfile_ehandler *) ehandler;
 
627
 
 
628
        if ( !handler->started ) sieve_logfile_start(handler);  
 
629
 
 
630
        sieve_logfile_vprintf(handler, location, "error", fmt, args);
 
631
}
 
632
 
 
633
static void sieve_logfile_vwarning
 
634
(struct sieve_error_handler *ehandler, const char *location, 
 
635
        const char *fmt, va_list args) 
 
636
{
 
637
        struct sieve_logfile_ehandler *handler = 
 
638
                (struct sieve_logfile_ehandler *) ehandler;
 
639
 
 
640
        if ( !handler->started ) sieve_logfile_start(handler);  
 
641
 
 
642
        sieve_logfile_vprintf(handler, location, "warning", fmt, args);
 
643
}
 
644
 
 
645
static void sieve_logfile_vinfo
 
646
(struct sieve_error_handler *ehandler, const char *location, 
 
647
        const char *fmt, va_list args) 
 
648
{
 
649
        struct sieve_logfile_ehandler *handler = 
 
650
                (struct sieve_logfile_ehandler *) ehandler;
 
651
 
 
652
        if ( !handler->started ) sieve_logfile_start(handler);  
 
653
 
 
654
        sieve_logfile_vprintf(handler, location, "info", fmt, args);
 
655
}
 
656
 
 
657
static void sieve_logfile_free
 
658
(struct sieve_error_handler *ehandler)
 
659
{
 
660
        struct sieve_logfile_ehandler *handler = 
 
661
                (struct sieve_logfile_ehandler *) ehandler;
 
662
                
 
663
        if ( handler->stream != NULL ) {
 
664
                o_stream_destroy(&(handler->stream));
 
665
                if ( handler->fd != STDERR_FILENO ){
 
666
                        if ( close(handler->fd) < 0 ) {
 
667
                                sieve_sys_error("failed to close logfile: "
 
668
                                        "close(fd=%s) failed: %m", handler->logfile);
 
669
                        }
 
670
                }
 
671
        }
 
672
}
 
673
 
 
674
struct sieve_error_handler *sieve_logfile_ehandler_create
 
675
(const char *logfile, unsigned int max_errors) 
 
676
{
 
677
        pool_t pool;
 
678
        struct sieve_logfile_ehandler *ehandler;
 
679
        
 
680
        pool = pool_alloconly_create("logfile_error_handler", 256);     
 
681
        ehandler = p_new(pool, struct sieve_logfile_ehandler, 1);
 
682
        sieve_error_handler_init(&ehandler->handler, pool, max_errors);
 
683
 
 
684
        ehandler->handler.verror = sieve_logfile_verror;
 
685
        ehandler->handler.vwarning = sieve_logfile_vwarning;
 
686
        ehandler->handler.vinfo = sieve_logfile_vinfo;
 
687
        ehandler->handler.free = sieve_logfile_free;
 
688
        
 
689
        /* Don't open logfile until something is actually logged. 
 
690
         * Let's not pullute the sieve directory with useless logfiles.
 
691
         */
 
692
        ehandler->logfile = p_strdup(pool, logfile);
 
693
        ehandler->started = FALSE;
 
694
        ehandler->stream = NULL;
 
695
        ehandler->fd = -1;
 
696
        
 
697
        return &(ehandler->handler);    
 
698
}
 
699