1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "str.h"
6 #include "array.h"
7 #include "ostream.h"
8 #include "var-expand.h"
9 #include "eacces-error.h"
10
11 #include "sieve-common.h"
12 #include "sieve-script.h"
13 #include "sieve-error-private.h"
14
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <ctype.h>
21
22 /*
23 * Definitions
24 */
25
26 #define CRITICAL_MSG \
27 "internal error occurred: refer to server log for more information."
28 #define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
29
30 /* Logfile error handler will rotate log when it exceeds 10k bytes */
31 #define LOGFILE_MAX_SIZE (10 * 1024)
32
33 /*
34 * Utility
35 */
36
37 const char *
sieve_error_script_location(const struct sieve_script * script,unsigned int source_line)38 sieve_error_script_location(const struct sieve_script *script,
39 unsigned int source_line)
40 {
41 const char *sname;
42
43 sname = (script == NULL ? NULL : sieve_script_name(script));
44
45 if (sname == NULL || *sname == '\0') {
46 if (source_line == 0)
47 return NULL;
48
49 return t_strdup_printf("line %d", source_line);
50 }
51
52 if (source_line == 0)
53 return sname;
54
55 return t_strdup_printf("%s: line %d", sname, source_line);
56 }
57
sieve_error_from_external(const char * msg)58 const char *sieve_error_from_external(const char *msg)
59 {
60 char *new_msg;
61
62 if (msg == NULL || *msg == '\0')
63 return msg;
64
65 new_msg = t_strdup_noconst(msg);
66 new_msg[0] = i_tolower(new_msg[0]);
67
68 return new_msg;
69 }
70
71 /*
72 * Initialization
73 */
74
sieve_errors_init(struct sieve_instance * svinst ATTR_UNUSED)75 void sieve_errors_init(struct sieve_instance *svinst ATTR_UNUSED)
76 {
77 /* nothing */
78 }
79
sieve_errors_deinit(struct sieve_instance * svinst ATTR_UNUSED)80 void sieve_errors_deinit(struct sieve_instance *svinst ATTR_UNUSED)
81 {
82 /* nothing */
83 }
84
85 /*
86 * Direct handler calls
87 */
88
89 static void
sieve_direct_master_log(struct sieve_instance * svinst,const struct sieve_error_params * params,const char * message)90 sieve_direct_master_log(struct sieve_instance *svinst,
91 const struct sieve_error_params *params,
92 const char *message)
93 {
94 struct event_log_params event_params = {
95 .log_type = params->log_type,
96 .source_filename = params->csrc.filename,
97 .source_linenum = params->csrc.linenum,
98
99 .base_event = svinst->event,
100 };
101 struct event *event = (params->event != NULL ?
102 params->event : svinst->event);
103
104 if (params->location != NULL && *params->location != '\0') {
105 event_params.base_send_prefix =
106 t_strconcat(params->location, ": ", NULL);
107 }
108
109 event_log(event, &event_params, "%s", message);
110 }
111
sieve_direct_logv(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const struct sieve_error_params * params,enum sieve_error_flags flags,const char * fmt,va_list args)112 void sieve_direct_logv(struct sieve_instance *svinst,
113 struct sieve_error_handler *ehandler,
114 const struct sieve_error_params *params,
115 enum sieve_error_flags flags,
116 const char *fmt, va_list args)
117 {
118 struct event_log_params event_params = {
119 .log_type = params->log_type,
120 .source_filename = params->csrc.filename,
121 .source_linenum = params->csrc.linenum,
122 .base_event = svinst->event,
123 .base_str_out = NULL,
124 .no_send = TRUE,
125 };
126 struct event *event = (params->event != NULL ?
127 params->event : svinst->event);
128 bool event_log = FALSE, ehandler_log = FALSE;
129
130 if (ehandler != NULL) {
131 switch (params->log_type) {
132 case LOG_TYPE_ERROR:
133 ehandler_log = sieve_errors_more_allowed(ehandler);
134 break;
135 case LOG_TYPE_WARNING:
136 ehandler_log = TRUE;
137 break;
138 case LOG_TYPE_INFO:
139 ehandler_log = ehandler->log_info;
140 break;
141 case LOG_TYPE_DEBUG:
142 ehandler_log = ehandler->log_debug;
143 break;
144 case LOG_TYPE_FATAL:
145 case LOG_TYPE_PANIC:
146 case LOG_TYPE_COUNT:
147 case LOG_TYPE_OPTION:
148 i_unreached();
149 }
150 }
151
152 if (ehandler != NULL && ehandler->master_log) {
153 event_log = ehandler_log;
154 ehandler_log = FALSE;
155 }
156 if ((flags & SIEVE_ERROR_FLAG_GLOBAL) != 0) {
157 event_log = TRUE;
158 if ((flags & SIEVE_ERROR_FLAG_GLOBAL_MAX_INFO) != 0 &&
159 params->log_type > LOG_TYPE_INFO)
160 event_params.log_type = LOG_TYPE_INFO;
161 }
162
163 if (event_log) {
164 event_params.no_send = FALSE;
165 if (params->location != NULL && *params->location != '\0') {
166 event_params.base_send_prefix =
167 t_strconcat(params->location, ": ", NULL);
168 }
169 }
170 if (ehandler_log) {
171 if (ehandler->log == NULL)
172 ehandler_log = FALSE;
173 else
174 event_params.base_str_out = t_str_new(128);
175 }
176
177 if (event_log || ehandler_log)
178 event_logv(event, &event_params, fmt, args);
179
180 if (ehandler_log) {
181 ehandler->log(ehandler, params, flags,
182 str_c(event_params.base_str_out));
183 }
184
185 if (ehandler != NULL && ehandler->pool != NULL) {
186 switch (params->log_type) {
187 case LOG_TYPE_ERROR:
188 ehandler->errors++;
189 break;
190 case LOG_TYPE_WARNING:
191 ehandler->warnings++;
192 break;
193 default:
194 break;
195 }
196 }
197 }
198
199 /*
200 * User errors
201 */
202
sieve_global_logv(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const struct sieve_error_params * params,const char * fmt,va_list args)203 void sieve_global_logv(struct sieve_instance *svinst,
204 struct sieve_error_handler *ehandler,
205 const struct sieve_error_params *params,
206 const char *fmt, va_list args)
207 {
208 sieve_direct_logv(svinst, ehandler, params,
209 SIEVE_ERROR_FLAG_GLOBAL, fmt, args);
210 }
211
sieve_global_info_logv(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const struct sieve_error_params * params,const char * fmt,va_list args)212 void sieve_global_info_logv(struct sieve_instance *svinst,
213 struct sieve_error_handler *ehandler,
214 const struct sieve_error_params *params,
215 const char *fmt, va_list args)
216 {
217 sieve_direct_logv(svinst, ehandler, params,
218 (SIEVE_ERROR_FLAG_GLOBAL |
219 SIEVE_ERROR_FLAG_GLOBAL_MAX_INFO), fmt, args);
220 }
221
222 #undef sieve_global_error
sieve_global_error(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)223 void sieve_global_error(struct sieve_instance *svinst,
224 struct sieve_error_handler *ehandler,
225 const char *csrc_filename, unsigned int csrc_linenum,
226 const char *location, const char *fmt, ...)
227 {
228 struct sieve_error_params params = {
229 .log_type = LOG_TYPE_ERROR,
230 .csrc = {
231 .filename = csrc_filename,
232 .linenum = csrc_linenum,
233 },
234 .location = location,
235 };
236 va_list args;
237 va_start(args, fmt);
238
239 T_BEGIN {
240 sieve_global_logv(svinst, ehandler, ¶ms, fmt, args);
241 } T_END;
242
243 va_end(args);
244 }
245
246 #undef sieve_global_warning
sieve_global_warning(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)247 void sieve_global_warning(struct sieve_instance *svinst,
248 struct sieve_error_handler *ehandler,
249 const char *csrc_filename, unsigned int csrc_linenum,
250 const char *location, const char *fmt, ...)
251 {
252 struct sieve_error_params params = {
253 .log_type = LOG_TYPE_WARNING,
254 .csrc = {
255 .filename = csrc_filename,
256 .linenum = csrc_linenum,
257 },
258 .location = location,
259 };
260 va_list args;
261 va_start(args, fmt);
262
263 T_BEGIN {
264 sieve_global_logv(svinst, ehandler, ¶ms, fmt, args);
265 } T_END;
266
267 va_end(args);
268 }
269
270 #undef sieve_global_info
sieve_global_info(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)271 void sieve_global_info(struct sieve_instance *svinst,
272 struct sieve_error_handler *ehandler,
273 const char *csrc_filename, unsigned int csrc_linenum,
274 const char *location, const char *fmt, ...)
275 {
276 struct sieve_error_params params = {
277 .log_type = LOG_TYPE_INFO,
278 .csrc = {
279 .filename = csrc_filename,
280 .linenum = csrc_linenum,
281 },
282 .location = location,
283 };
284 va_list args;
285 va_start(args, fmt);
286
287 T_BEGIN {
288 sieve_global_logv(svinst, ehandler, ¶ms, fmt, args);
289 } T_END;
290
291 va_end(args);
292 }
293
294 #undef sieve_global_info_error
sieve_global_info_error(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)295 void sieve_global_info_error(struct sieve_instance *svinst,
296 struct sieve_error_handler *ehandler,
297 const char *csrc_filename,
298 unsigned int csrc_linenum,
299 const char *location, const char *fmt, ...)
300 {
301 struct sieve_error_params params = {
302 .log_type = LOG_TYPE_ERROR,
303 .csrc = {
304 .filename = csrc_filename,
305 .linenum = csrc_linenum,
306 },
307 .location = location,
308 };
309 va_list args;
310 va_start(args, fmt);
311
312 T_BEGIN {
313 sieve_global_info_logv(svinst, ehandler, ¶ms, fmt, args);
314 } T_END;
315
316 va_end(args);
317 }
318
319 #undef sieve_global_info_warning
sieve_global_info_warning(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)320 void sieve_global_info_warning(struct sieve_instance *svinst,
321 struct sieve_error_handler *ehandler,
322 const char *csrc_filename,
323 unsigned int csrc_linenum,
324 const char *location, const char *fmt, ...)
325 {
326 struct sieve_error_params params = {
327 .log_type = LOG_TYPE_WARNING,
328 .csrc = {
329 .filename = csrc_filename,
330 .linenum = csrc_linenum,
331 },
332 .location = location,
333 };
334 va_list args;
335 va_start(args, fmt);
336
337 T_BEGIN {
338 sieve_global_info_logv(svinst, ehandler, ¶ms, fmt, args);
339 } T_END;
340
341 va_end(args);
342 }
343
344 /*
345 * Default (user) error functions
346 */
347
sieve_internal_error_params(struct sieve_error_handler * ehandler,const struct sieve_error_params * params,const char * user_prefix)348 void sieve_internal_error_params(struct sieve_error_handler *ehandler,
349 const struct sieve_error_params *params,
350 const char *user_prefix)
351 {
352 char str[256];
353 const char *msg;
354 struct tm *tm;
355
356 if (ehandler == NULL || ehandler->master_log)
357 return;
358
359 tm = localtime(&ioloop_time);
360 msg = (strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
361 str : CRITICAL_MSG);
362
363 if (user_prefix == NULL || *user_prefix == '\0') {
364 sieve_direct_log(ehandler->svinst, ehandler, params, 0,
365 "%s", msg);
366 } else {
367 sieve_direct_log(ehandler->svinst, ehandler, params, 0,
368 "%s: %s", user_prefix, msg);
369 }
370 }
371
372 #undef sieve_internal_error
sieve_internal_error(struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * user_prefix)373 void sieve_internal_error(struct sieve_error_handler *ehandler,
374 const char *csrc_filename, unsigned int csrc_linenum,
375 const char *location, const char *user_prefix)
376
377 {
378 struct sieve_error_params params = {
379 .log_type = LOG_TYPE_ERROR,
380 .csrc = {
381 .filename = csrc_filename,
382 .linenum = csrc_linenum,
383 },
384 .location = location,
385 };
386
387 sieve_internal_error_params(ehandler, ¶ms, user_prefix);
388 }
389
sieve_logv(struct sieve_error_handler * ehandler,const struct sieve_error_params * params,const char * fmt,va_list args)390 void sieve_logv(struct sieve_error_handler *ehandler,
391 const struct sieve_error_params *params,
392 const char *fmt, va_list args)
393 {
394 if (ehandler == NULL) return;
395
396 sieve_direct_logv(ehandler->svinst, ehandler, params, 0, fmt, args);
397 }
398
sieve_event_logv(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,struct event * event,enum log_type log_type,const char * csrc_filename,unsigned int csrc_linenum,const char * location,enum sieve_error_flags flags,const char * fmt,va_list args)399 void sieve_event_logv(struct sieve_instance *svinst,
400 struct sieve_error_handler *ehandler,
401 struct event *event, enum log_type log_type,
402 const char *csrc_filename, unsigned int csrc_linenum,
403 const char *location, enum sieve_error_flags flags,
404 const char *fmt, va_list args)
405 {
406 struct sieve_error_params params = {
407 .log_type = log_type,
408 .csrc = {
409 .filename = csrc_filename,
410 .linenum = csrc_linenum,
411 },
412 .event = event,
413 .location = location,
414 };
415
416 T_BEGIN {
417 sieve_direct_logv(svinst, ehandler, ¶ms, flags, fmt, args);
418 } T_END;
419 }
420
421
422 #undef sieve_event_log
sieve_event_log(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,struct event * event,enum log_type log_type,const char * csrc_filename,unsigned int csrc_linenum,const char * location,enum sieve_error_flags flags,const char * fmt,...)423 void sieve_event_log(struct sieve_instance *svinst,
424 struct sieve_error_handler *ehandler,
425 struct event *event, enum log_type log_type,
426 const char *csrc_filename, unsigned int csrc_linenum,
427 const char *location, enum sieve_error_flags flags,
428 const char *fmt, ...)
429 {
430 va_list args;
431 va_start(args, fmt);
432
433 sieve_event_logv(svinst, ehandler, event, log_type, csrc_filename,
434 csrc_linenum, location, flags, fmt, args);
435
436 va_end(args);
437 }
438
sieve_criticalv(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const struct sieve_error_params * params,const char * user_prefix,const char * fmt,va_list args)439 void sieve_criticalv(struct sieve_instance *svinst,
440 struct sieve_error_handler *ehandler,
441 const struct sieve_error_params *params,
442 const char *user_prefix, const char *fmt, va_list args)
443 {
444 struct sieve_error_params new_params = *params;
445
446 new_params.log_type = LOG_TYPE_ERROR;
447
448 sieve_direct_master_log(svinst, &new_params,
449 t_strdup_vprintf(fmt, args));
450 sieve_internal_error_params(ehandler, &new_params, user_prefix);
451 }
452
453 #undef sieve_error
sieve_error(struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)454 void sieve_error(struct sieve_error_handler *ehandler,
455 const char *csrc_filename, unsigned int csrc_linenum,
456 const char *location, const char *fmt, ...)
457 {
458 struct sieve_error_params params = {
459 .log_type = LOG_TYPE_ERROR,
460 .csrc = {
461 .filename = csrc_filename,
462 .linenum = csrc_linenum,
463 },
464 .location = location,
465 };
466 va_list args;
467 va_start(args, fmt);
468
469 T_BEGIN {
470 sieve_logv(ehandler, ¶ms, fmt, args);
471 } T_END;
472
473 va_end(args);
474 }
475
476 #undef sieve_warning
sieve_warning(struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)477 void sieve_warning(struct sieve_error_handler *ehandler,
478 const char *csrc_filename, unsigned int csrc_linenum,
479 const char *location, const char *fmt, ...)
480 {
481 struct sieve_error_params params = {
482 .log_type = LOG_TYPE_WARNING,
483 .csrc = {
484 .filename = csrc_filename,
485 .linenum = csrc_linenum,
486 },
487 .location = location,
488 };
489 va_list args;
490 va_start(args, fmt);
491
492 T_BEGIN {
493 sieve_logv(ehandler, ¶ms, fmt, args);
494 } T_END;
495
496 va_end(args);
497 }
498
499 #undef sieve_info
sieve_info(struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)500 void sieve_info(struct sieve_error_handler *ehandler,
501 const char *csrc_filename, unsigned int csrc_linenum,
502 const char *location, const char *fmt, ...)
503 {
504 struct sieve_error_params params = {
505 .log_type = LOG_TYPE_INFO,
506 .csrc = {
507 .filename = csrc_filename,
508 .linenum = csrc_linenum,
509 },
510 .location = location,
511 };
512 va_list args;
513 va_start(args, fmt);
514
515 T_BEGIN {
516 sieve_logv(ehandler, ¶ms, fmt, args);
517 } T_END;
518
519 va_end(args);
520 }
521
522 #undef sieve_debug
sieve_debug(struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)523 void sieve_debug(struct sieve_error_handler *ehandler,
524 const char *csrc_filename, unsigned int csrc_linenum,
525 const char *location, const char *fmt, ...)
526 {
527 struct sieve_error_params params = {
528 .log_type = LOG_TYPE_DEBUG,
529 .csrc = {
530 .filename = csrc_filename,
531 .linenum = csrc_linenum,
532 },
533 .location = location,
534 };
535 va_list args;
536 va_start(args, fmt);
537
538 T_BEGIN {
539 sieve_logv(ehandler, ¶ms, fmt, args);
540 } T_END;
541
542 va_end(args);
543 }
544
545 #undef sieve_critical
sieve_critical(struct sieve_instance * svinst,struct sieve_error_handler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * user_prefix,const char * fmt,...)546 void sieve_critical(struct sieve_instance *svinst,
547 struct sieve_error_handler *ehandler,
548 const char *csrc_filename, unsigned int csrc_linenum,
549 const char *location, const char *user_prefix,
550 const char *fmt, ...)
551 {
552 struct sieve_error_params params = {
553 .log_type = LOG_TYPE_ERROR,
554 .csrc = {
555 .filename = csrc_filename,
556 .linenum = csrc_linenum,
557 },
558 .location = location,
559 };
560 va_list args;
561
562 va_start(args, fmt);
563
564 T_BEGIN {
565 sieve_criticalv(svinst, ehandler, ¶ms, user_prefix,
566 fmt, args);
567 } T_END;
568
569 va_end(args);
570 }
571
572 /*
573 * Error statistics
574 */
575
sieve_get_errors(struct sieve_error_handler * ehandler)576 unsigned int sieve_get_errors(struct sieve_error_handler *ehandler)
577 {
578 if (ehandler == NULL || ehandler->pool == NULL)
579 return 0;
580
581 return ehandler->errors;
582 }
583
sieve_get_warnings(struct sieve_error_handler * ehandler)584 unsigned int sieve_get_warnings(struct sieve_error_handler *ehandler)
585 {
586 if (ehandler == NULL || ehandler->pool == NULL)
587 return 0;
588
589 return ehandler->warnings;
590 }
591
sieve_errors_more_allowed(struct sieve_error_handler * ehandler)592 bool sieve_errors_more_allowed(struct sieve_error_handler *ehandler)
593 {
594 if (ehandler == NULL || ehandler->pool == NULL)
595 return TRUE;
596
597 return (ehandler->max_errors == 0 ||
598 ehandler->errors < ehandler->max_errors);
599 }
600
601 /*
602 * Error handler configuration
603 */
604
sieve_error_handler_accept_infolog(struct sieve_error_handler * ehandler,bool enable)605 void sieve_error_handler_accept_infolog(struct sieve_error_handler *ehandler,
606 bool enable)
607 {
608 ehandler->log_info = enable;
609 }
610
sieve_error_handler_accept_debuglog(struct sieve_error_handler * ehandler,bool enable)611 void sieve_error_handler_accept_debuglog(struct sieve_error_handler *ehandler,
612 bool enable)
613 {
614 ehandler->log_debug = enable;
615 }
616
617 /*
618 * Error handler init
619 */
620
sieve_error_handler_init(struct sieve_error_handler * ehandler,struct sieve_instance * svinst,pool_t pool,unsigned int max_errors)621 void sieve_error_handler_init(struct sieve_error_handler *ehandler,
622 struct sieve_instance *svinst,
623 pool_t pool, unsigned int max_errors)
624 {
625 ehandler->pool = pool;
626 ehandler->svinst = svinst;
627 ehandler->refcount = 1;
628 ehandler->max_errors = max_errors;
629
630 ehandler->errors = 0;
631 ehandler->warnings = 0;
632 }
633
sieve_error_handler_ref(struct sieve_error_handler * ehandler)634 void sieve_error_handler_ref(struct sieve_error_handler *ehandler)
635 {
636 if (ehandler == NULL || ehandler->pool == NULL)
637 return;
638
639 ehandler->refcount++;
640 }
641
sieve_error_handler_unref(struct sieve_error_handler ** ehandler)642 void sieve_error_handler_unref(struct sieve_error_handler **ehandler)
643 {
644 if (*ehandler == NULL || (*ehandler)->pool == NULL)
645 return;
646
647 i_assert((*ehandler)->refcount > 0);
648
649 if (--(*ehandler)->refcount != 0)
650 return;
651
652 if ((*ehandler)->free != NULL)
653 (*ehandler)->free(*ehandler);
654
655 pool_unref(&((*ehandler)->pool));
656 *ehandler = NULL;
657 }
658
sieve_error_handler_reset(struct sieve_error_handler * ehandler)659 void sieve_error_handler_reset(struct sieve_error_handler *ehandler)
660 {
661 if (ehandler == NULL || ehandler->pool == NULL)
662 return;
663
664 ehandler->errors = 0;
665 ehandler->warnings = 0;
666 }
667
668 /*
669 * Error params utility
670 */
671
672 static void
sieve_error_params_add_prefix(struct sieve_error_handler * ehandler ATTR_UNUSED,const struct sieve_error_params * params,string_t * prefix)673 sieve_error_params_add_prefix(struct sieve_error_handler *ehandler ATTR_UNUSED,
674 const struct sieve_error_params *params,
675 string_t *prefix)
676 {
677 if (params->location != NULL && *params->location != '\0') {
678 str_append(prefix, params->location);
679 str_append(prefix, ": ");
680 }
681
682 switch (params->log_type) {
683 case LOG_TYPE_ERROR:
684 str_append(prefix, "error: ");
685 break;
686 case LOG_TYPE_WARNING:
687 str_append(prefix, "warning: ");
688 break;
689 case LOG_TYPE_INFO:
690 str_append(prefix, "info: ");
691 break;
692 case LOG_TYPE_DEBUG:
693 str_append(prefix, "debug: ");
694 break;
695 default:
696 i_unreached();
697 }
698 }
699
700 /*
701 * Master/System error handler
702 *
703 * - Output errors directly to Dovecot master log
704 */
705
706 struct sieve_error_handler *
sieve_master_ehandler_create(struct sieve_instance * svinst,unsigned int max_errors)707 sieve_master_ehandler_create(struct sieve_instance *svinst,
708 unsigned int max_errors)
709 {
710 struct sieve_error_handler *ehandler;
711 pool_t pool;
712
713 pool = pool_alloconly_create("master_error_handler", 256);
714 ehandler = p_new(pool, struct sieve_error_handler, 1);
715 sieve_error_handler_init(ehandler, svinst, pool, max_errors);
716 ehandler->master_log = TRUE;
717 ehandler->log_debug = svinst->debug;
718
719 return ehandler;
720 }
721
722 /*
723 * STDERR error handler
724 *
725 * - Output errors directly to stderror
726 */
727
728 static void
sieve_stderr_log(struct sieve_error_handler * ehandler,const struct sieve_error_params * params,enum sieve_error_flags flags ATTR_UNUSED,const char * message)729 sieve_stderr_log(struct sieve_error_handler *ehandler,
730 const struct sieve_error_params *params,
731 enum sieve_error_flags flags ATTR_UNUSED,
732 const char *message)
733 {
734 string_t *prefix = t_str_new(64);
735
736 sieve_error_params_add_prefix(ehandler, params, prefix);
737
738 fprintf(stderr, "%s%s.\n", str_c(prefix), message);
739 }
740
741 struct sieve_error_handler *
sieve_stderr_ehandler_create(struct sieve_instance * svinst,unsigned int max_errors)742 sieve_stderr_ehandler_create(struct sieve_instance *svinst,
743 unsigned int max_errors)
744 {
745 pool_t pool;
746 struct sieve_error_handler *ehandler;
747
748 /* Pool is not strictly necessary, but other handler types will need
749 * a pool, so this one will have one too.
750 */
751 pool = pool_alloconly_create("stderr_error_handler",
752 sizeof(struct sieve_error_handler));
753 ehandler = p_new(pool, struct sieve_error_handler, 1);
754 sieve_error_handler_init(ehandler, svinst, pool, max_errors);
755
756 ehandler->log = sieve_stderr_log;
757
758 return ehandler;
759 }
760
761 /* String buffer error handler
762 *
763 * - Output errors to a string buffer
764 */
765
766 struct sieve_strbuf_ehandler {
767 struct sieve_error_handler handler;
768
769 string_t *errors;
770 bool crlf;
771 };
772
773 static void
sieve_strbuf_log(struct sieve_error_handler * ehandler,const struct sieve_error_params * params,enum sieve_error_flags flags ATTR_UNUSED,const char * message)774 sieve_strbuf_log(struct sieve_error_handler *ehandler,
775 const struct sieve_error_params *params,
776 enum sieve_error_flags flags ATTR_UNUSED, const char *message)
777 {
778 struct sieve_strbuf_ehandler *handler =
779 (struct sieve_strbuf_ehandler *) ehandler;
780
781 sieve_error_params_add_prefix(ehandler, params, handler->errors);
782 str_append(handler->errors, message);
783
784 if (!handler->crlf)
785 str_append(handler->errors, ".\n");
786 else
787 str_append(handler->errors, ".\r\n");
788 }
789
790 struct sieve_error_handler *
sieve_strbuf_ehandler_create(struct sieve_instance * svinst,string_t * strbuf,bool crlf,unsigned int max_errors)791 sieve_strbuf_ehandler_create(struct sieve_instance *svinst, string_t *strbuf,
792 bool crlf, unsigned int max_errors)
793 {
794 pool_t pool;
795 struct sieve_strbuf_ehandler *ehandler;
796
797 pool = pool_alloconly_create("strbuf_error_handler", 256);
798 ehandler = p_new(pool, struct sieve_strbuf_ehandler, 1);
799 ehandler->errors = strbuf;
800
801 sieve_error_handler_init(&ehandler->handler, svinst, pool, max_errors);
802
803 ehandler->handler.log = sieve_strbuf_log;
804 ehandler->crlf = crlf;
805
806 return &(ehandler->handler);
807 }
808
809 /*
810 * Logfile error handler
811 *
812 * - Output errors to a log file
813 */
814
815 struct sieve_logfile_ehandler {
816 struct sieve_error_handler handler;
817
818 const char *logfile;
819 bool started;
820 int fd;
821 struct ostream *stream;
822 };
823
824 static void
sieve_logfile_write(struct sieve_logfile_ehandler * ehandler,const struct sieve_error_params * params,const char * message)825 sieve_logfile_write(struct sieve_logfile_ehandler *ehandler,
826 const struct sieve_error_params *params,
827 const char *message)
828 {
829 string_t *outbuf;
830 ssize_t ret = 0, remain;
831 const char *data;
832
833 if (ehandler->stream == NULL)
834 return;
835
836 T_BEGIN {
837 outbuf = t_str_new(256);
838 sieve_error_params_add_prefix(&ehandler->handler,
839 params, outbuf);
840 str_append(outbuf, message);
841 str_append(outbuf, ".\n");
842
843 remain = str_len(outbuf);
844 data = (const char *) str_data(outbuf);
845
846 while (remain > 0) {
847 if ((ret = o_stream_send(ehandler->stream,
848 data, remain)) < 0)
849 break;
850
851 remain -= ret;
852 data += ret;
853 }
854 } T_END;
855
856 if (ret < 0) {
857 e_error(ehandler->handler.svinst->event,
858 "o_stream_send() failed on logfile %s: %m",
859 ehandler->logfile);
860 }
861 }
862
863 inline static void ATTR_FORMAT(5, 6)
sieve_logfile_printf(struct sieve_logfile_ehandler * ehandler,const char * csrc_filename,unsigned int csrc_linenum,const char * location,const char * fmt,...)864 sieve_logfile_printf(struct sieve_logfile_ehandler *ehandler,
865 const char *csrc_filename, unsigned int csrc_linenum,
866 const char *location, const char *fmt, ...)
867 {
868 struct sieve_error_params params = {
869 .log_type = LOG_TYPE_INFO,
870 .csrc = {
871 .filename = csrc_filename,
872 .linenum = csrc_linenum,
873 },
874 .location = location,
875 };
876 va_list args;
877 va_start(args, fmt);
878
879 sieve_logfile_write(ehandler, ¶ms, t_strdup_vprintf(fmt, args));
880
881 va_end(args);
882 }
883
sieve_logfile_start(struct sieve_logfile_ehandler * ehandler)884 static void sieve_logfile_start(struct sieve_logfile_ehandler *ehandler)
885 {
886 struct sieve_instance *svinst = ehandler->handler.svinst;
887 struct ostream *ostream = NULL;
888 struct stat st;
889 struct tm *tm;
890 char buf[256];
891 time_t now;
892 int fd;
893
894 /* Open the logfile */
895
896 fd = open(ehandler->logfile, O_CREAT | O_APPEND | O_WRONLY, 0600);
897 if (fd == -1) {
898 if (errno == EACCES) {
899 e_error(svinst->event,
900 "failed to open logfile "
901 "(LOGGING TO STDERR): %s",
902 eacces_error_get_creating("open",
903 ehandler->logfile));
904 } else {
905 e_error(svinst->event, "failed to open logfile "
906 "(LOGGING TO STDERR): "
907 "open(%s) failed: %m", ehandler->logfile);
908 }
909 fd = STDERR_FILENO;
910 } else {
911 /* fd_close_on_exec(fd, TRUE); Necessary? */
912
913 /* Stat the log file to obtain size information */
914 if (fstat(fd, &st) != 0) {
915 e_error(svinst->event, "failed to stat logfile "
916 "(logging to STDERR): "
917 "fstat(fd=%s) failed: %m", ehandler->logfile);
918
919 if (close(fd) < 0) {
920 e_error(svinst->event,
921 "failed to close logfile after error: "
922 "close(fd=%s) failed: %m",
923 ehandler->logfile);
924 }
925
926 fd = STDERR_FILENO;
927 }
928
929 /* Rotate log when it has grown too large */
930 if (st.st_size >= LOGFILE_MAX_SIZE) {
931 const char *rotated;
932
933 /* Close open file */
934 if (close(fd) < 0) {
935 e_error(svinst->event,
936 "failed to close logfile: "
937 "close(fd=%s) failed: %m",
938 ehandler->logfile);
939 }
940
941 /* Rotate logfile */
942 rotated = t_strconcat(ehandler->logfile, ".0", NULL);
943 if (rename(ehandler->logfile, rotated) < 0 &&
944 errno != ENOENT) {
945 if (errno == EACCES) {
946 const char *target =
947 t_strconcat(ehandler->logfile,
948 ", ", rotated, NULL);
949 e_error(svinst->event,
950 "failed to rotate logfile: %s",
951 eacces_error_get_creating(
952 "rename", target));
953 } else {
954 e_error(svinst->event,
955 "failed to rotate logfile: "
956 "rename(%s, %s) failed: %m",
957 ehandler->logfile, rotated);
958 }
959 }
960
961 /* Open clean logfile (overwrites existing if rename() failed earlier) */
962 fd = open(ehandler->logfile,
963 O_CREAT | O_APPEND | O_WRONLY | O_TRUNC, 0600);
964 if (fd == -1) {
965 if (errno == EACCES) {
966 e_error(svinst->event,
967 "failed to open logfile "
968 "(LOGGING TO STDERR): %s",
969 eacces_error_get_creating(
970 "open", ehandler->logfile));
971 } else {
972 e_error(svinst->event,
973 "failed to open logfile "
974 "(LOGGING TO STDERR): "
975 "open(%s) failed: %m",
976 ehandler->logfile);
977 }
978 fd = STDERR_FILENO;
979 }
980 }
981 }
982
983 ostream = o_stream_create_fd(fd, 0);
984 if (ostream == NULL) {
985 /* Can't we do anything else in this most awkward situation? */
986 e_error(svinst->event,
987 "failed to open log stream on open file: "
988 "o_stream_create_fd(fd=%s) failed "
989 "(non-critical messages are not logged!)",
990 ehandler->logfile);
991 }
992
993 ehandler->fd = fd;
994 ehandler->stream = ostream;
995 ehandler->started = TRUE;
996
997 if (ostream != NULL) {
998 now = time(NULL);
999 tm = localtime(&now);
1000
1001 if (strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z", tm) > 0) {
1002 sieve_logfile_printf(ehandler, __FILE__, __LINE__,
1003 "sieve", "started log at %s", buf);
1004 }
1005 }
1006 }
1007
1008 static void
sieve_logfile_log(struct sieve_error_handler * ehandler,const struct sieve_error_params * params,enum sieve_error_flags flags ATTR_UNUSED,const char * message)1009 sieve_logfile_log(struct sieve_error_handler *ehandler,
1010 const struct sieve_error_params *params,
1011 enum sieve_error_flags flags ATTR_UNUSED,
1012 const char *message)
1013 {
1014 struct sieve_logfile_ehandler *handler =
1015 (struct sieve_logfile_ehandler *) ehandler;
1016
1017 if (!handler->started)
1018 sieve_logfile_start(handler);
1019
1020 sieve_logfile_write(handler, params, message);
1021 }
1022
sieve_logfile_free(struct sieve_error_handler * ehandler)1023 static void sieve_logfile_free(struct sieve_error_handler *ehandler)
1024 {
1025 struct sieve_logfile_ehandler *handler =
1026 (struct sieve_logfile_ehandler *) ehandler;
1027
1028 if (handler->stream != NULL) {
1029 o_stream_destroy(&(handler->stream));
1030 if (handler->fd != STDERR_FILENO) {
1031 if (close(handler->fd) < 0) {
1032 e_error(ehandler->svinst->event,
1033 "failed to close logfile: "
1034 "close(fd=%s) failed: %m",
1035 handler->logfile);
1036 }
1037 }
1038 }
1039 }
1040
1041 struct sieve_error_handler *
sieve_logfile_ehandler_create(struct sieve_instance * svinst,const char * logfile,unsigned int max_errors)1042 sieve_logfile_ehandler_create(struct sieve_instance *svinst,
1043 const char *logfile, unsigned int max_errors)
1044 {
1045 pool_t pool;
1046 struct sieve_logfile_ehandler *ehandler;
1047
1048 pool = pool_alloconly_create("logfile_error_handler", 512);
1049 ehandler = p_new(pool, struct sieve_logfile_ehandler, 1);
1050 sieve_error_handler_init(&ehandler->handler, svinst, pool, max_errors);
1051
1052 ehandler->handler.log = sieve_logfile_log;
1053 ehandler->handler.free = sieve_logfile_free;
1054
1055 /* Don't open logfile until something is actually logged.
1056 * Let's not pullute the sieve directory with useless logfiles.
1057 */
1058 ehandler->logfile = p_strdup(pool, logfile);
1059 ehandler->started = FALSE;
1060 ehandler->stream = NULL;
1061 ehandler->fd = -1;
1062
1063 return &(ehandler->handler);
1064 }
1065