1 /* SAMHAIN file system integrity testing */
2 /* Copyright (C) 2008 Rainer Wichmann */
3 /* */
4 /* This program is free software; you can redistribute it */
5 /* and/or modify */
6 /* it under the terms of the GNU General Public License as */
7 /* published by */
8 /* the Free Software Foundation; either version 2 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* This program is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with this program; if not, write to the Free Software */
18 /* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "config_xor.h"
21
22 #if defined(HAVE_PTHREAD_MUTEX_RECURSIVE)
23 #define _XOPEN_SOURCE 500
24 #endif
25
26 #if defined(GCC_VERSION_MAJOR) && !defined(__clang__)
27 #if (GCC_VERSION_MAJOR > 4) || ((GCC_VERSION_MAJOR == 4) && (GCC_VERSION_MINOR > 8))
28 #pragma GCC diagnostic ignored "-Wclobbered"
29 #endif
30 #endif
31
32 #include <string.h>
33 #include <time.h>
34
35 #if defined(SH_WITH_MAIL)
36
37 #undef FIL__
38 #define FIL__ _("sh_nmail.c")
39
40 #include "samhain.h"
41 #include "sh_pthread.h"
42 #include "sh_mem.h"
43 #include "sh_mail.h"
44 #include "sh_tiger.h"
45 #include "sh_string.h"
46 #include "sh_utils.h"
47 #include "sh_fifo.h"
48 #include "sh_filter.h"
49 #include "sh_mail_int.h"
50
51 SH_MUTEX_INIT(mutex_listall, PTHREAD_MUTEX_INITIALIZER);
52 SH_MUTEX_INIT(mutex_flush_l, PTHREAD_MUTEX_INITIALIZER);
53
54 /* Pointer to last address */
55
56 static struct alias * last = NULL;
57
58 /* List of mail recipients */
59
60 static struct alias * recipient_list = NULL;
61
62 static struct alias * compiled_recipient_list = NULL;
63 static sh_filter_type compiled_mail_filter = SH_FILT_INIT;
64
65 /* List of mail aliases */
66
67 static struct alias * alias_list = NULL;
68
69 /* List of all recipients */
70
71 struct alias * all_recipients = NULL;
72
73 /* Check if addr is in list. If list is all_recipients,
74 * must iterate over ->all_next instead of ->next
75 */
check_double(const char * str,struct alias * list,int isAll)76 static int check_double (const char * str, struct alias * list, int isAll)
77 {
78 if (str && list)
79 {
80 struct alias * item = list;
81
82 while (item)
83 {
84 if (0 == strcmp(sh_string_str(item->recipient), str))
85 return -1;
86 if (isAll)
87 item = item->all_next;
88 else
89 item = item->next;
90 }
91 }
92 return 0;
93 }
94
95 /* Add recipient to 'list' AND to all_recipients. If
96 * it already is in all_recipients, mark it as an alias
97 * (isAlias = 1).
98 */
add_recipient_intern(const char * str,struct alias * list)99 struct alias * add_recipient_intern(const char * str,
100 struct alias * list)
101 {
102 if (str)
103 {
104 struct alias * new = SH_ALLOC(sizeof(struct alias));
105 new->next = list;
106 new->mx_list = NULL;
107 new->mail_filter = NULL;
108 new->recipient_list = NULL;
109 new->severity = (-1);
110 new->send_mail = 0;
111 new->isAlias = 0;
112 new->recipient = sh_string_new_from_lchar(str, strlen(str));
113 list = new;
114
115 SH_MUTEX_LOCK_UNSAFE(mutex_listall);
116 if (0 != check_double(str, all_recipients, S_TRUE))
117 {
118 new->isAlias = 1;
119 }
120 new->all_next = all_recipients;
121 all_recipients = new;
122 SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
123 }
124 return list;
125 }
126
sh_nmail_close_recipient(const char * str)127 int sh_nmail_close_recipient(const char * str)
128 {
129 (void) str;
130
131 if (last)
132 {
133 last = NULL;
134 return 0;
135 }
136 return -1;
137 }
138
139 /* Add a single recipient. Must not be in in
140 * recipient_list already, and not in all_recipients.
141 */
sh_nmail_add_recipient(const char * str)142 int sh_nmail_add_recipient(const char * str)
143 {
144 /* return error if duplicate, or
145 * already defined within an alias list.
146 */
147 if (0 == check_double(str, recipient_list, S_FALSE) &&
148 0 == check_double(str, all_recipients, S_TRUE))
149 {
150 recipient_list = add_recipient_intern(str, recipient_list);
151 last = recipient_list;
152 return 0;
153 }
154 return -1;
155 }
156
157 /* Add a compiled-in address. These share the compiled_mail_filter
158 */
sh_nmail_add_compiled_recipient(const char * str)159 int sh_nmail_add_compiled_recipient(const char * str)
160 {
161 if (0 == check_double(str, compiled_recipient_list, S_FALSE))
162 {
163 compiled_recipient_list =
164 add_recipient_intern(str, compiled_recipient_list);
165 if (compiled_recipient_list)
166 compiled_recipient_list->mail_filter = &compiled_mail_filter;
167 last = compiled_recipient_list;
168 return 0;
169 }
170 return -1;
171 }
172
173 /* Add an alias; format is name ":" comma-delimited_list_of_recipients
174 */
sh_nmail_add_alias(const char * str)175 int sh_nmail_add_alias(const char * str)
176 {
177 #define SH_ALIASES_RECP_NUM 256
178 size_t lengths[SH_ALIASES_RECP_NUM];
179 unsigned int nfields = SH_ALIASES_RECP_NUM;
180 char * new = sh_util_strdup(str);
181 char * p = strchr(new, ':');
182 char * q;
183
184 if (p && strlen(p) > 1)
185 {
186 unsigned int i;
187 char ** array;
188
189 *p = '\0'; q = p; ++p;
190 if (strlen(new) > 0)
191 {
192 /* strip trailing space
193 */
194 --q; while ((q != new) && *q == ' ') { *q = '\0'; --q; }
195 }
196 else
197 {
198 goto err;
199 }
200
201 if (0 == check_double(new, alias_list, S_FALSE))
202 {
203 array = split_array_list(p, &nfields, lengths);
204
205 if (array && nfields > 0)
206 {
207 struct alias * newalias = NULL;
208
209 /* Enforce that all list members are defined already
210 */
211 int nflag = 0;
212
213 for (i = 0; i < nfields; ++i) {
214 if (0 == check_double(array[i], all_recipients, S_TRUE))
215 nflag = 1; /* not in all_recipients --> bad */
216 }
217
218 if (nflag == 0)
219 {
220 newalias = SH_ALLOC(sizeof(struct alias));
221 newalias->recipient_list = NULL;
222 newalias->mail_filter = NULL;
223 newalias->mx_list = NULL;
224 newalias->severity = (-1);
225
226 /* This is the alias */
227 newalias->recipient = sh_string_new_from_lchar(new, strlen(new));
228
229 for (i = 0; i < nfields; ++i)
230 {
231 if (lengths[i] > 0 &&
232 0 == check_double(array[i], newalias->recipient_list, S_FALSE))
233 {
234 newalias->recipient_list =
235 add_recipient_intern(array[i], newalias->recipient_list);
236 }
237 }
238 }
239
240 SH_FREE(array);
241
242 if (newalias == NULL || newalias->recipient_list == NULL)
243 {
244 if (newalias)
245 SH_FREE(newalias);
246 goto err;
247 }
248
249 newalias->next = alias_list;
250 alias_list = newalias;
251 last = alias_list;
252
253 SH_FREE(new);
254 return 0;
255 }
256 }
257 }
258 err:
259 SH_FREE(new);
260 return -1;
261 }
262
263
264 /* <<<<<<<<<<<<<<< Recipient List >>>>>>>>>>>>>>>>>>>>>> */
265
find_list(const char * alias,int * single)266 static struct alias * find_list (const char * alias, int * single)
267 {
268 struct alias * list = NULL;
269
270 *single = 0;
271
272 if (!alias)
273 {
274 list = all_recipients;
275 }
276 else
277 {
278 struct alias * test = alias_list;
279
280 while (test)
281 {
282 if (0 == strcmp(alias, sh_string_str(test->recipient)))
283 {
284 list = test->recipient_list;
285 break;
286 }
287 test = test->next;
288 }
289
290 if (!list)
291 {
292 test = recipient_list;
293 while (test)
294 {
295 if (0 == strcmp(alias, sh_string_str(test->recipient)))
296 {
297 list = test;
298 *single = 1;
299 break;
300 }
301 test = test->next;
302 }
303 }
304
305 if (!list)
306 {
307 test = compiled_recipient_list;
308 while (test)
309 {
310 if (0 == strcmp(alias, sh_string_str(test->recipient)))
311 {
312 list = test;
313 *single = 1;
314 break;
315 }
316 test = test->next;
317 }
318 }
319 }
320 return list;
321 }
322
323 /* Returns zero (no) or one (yes). Used to tag messages that are
324 * valid for a given recipient (or mailing list alias).
325 */
sh_nmail_valid_message_for_alias(int level,const char * message,const char * alias,const void * rcv_info)326 int sh_nmail_valid_message_for_alias (int level,
327 const char * message,
328 const char * alias,
329 const void * rcv_info)
330 {
331 const struct alias * rcv = (const struct alias *) rcv_info;
332
333 if (!alias || 0 == strcmp(alias, sh_string_str(rcv->recipient)))
334 {
335 if ((level & rcv->severity) == 0)
336 {
337 return 0;
338 }
339
340 if (rcv->mail_filter)
341 {
342 if (0 != sh_filter_filter(message, rcv->mail_filter))
343 {
344 return 0;
345 }
346 }
347 }
348
349 return 1;
350 }
351
352 /* Returns number of recipients */
353
354 static
sh_nmail_compute_recipients(int level,const char * message,const char * alias,int flagit)355 int sh_nmail_compute_recipients (int level, const char * message,
356 const char * alias, int flagit)
357 {
358 struct alias * list = NULL;
359 int single = 0;
360 int retval = 0;
361
362 if (flagit)
363 {
364 list = all_recipients;
365 while (list)
366 {
367 list->send_mail = 0;
368 list = list->all_next;
369 }
370 list = NULL;
371 }
372
373 if (message)
374 {
375 int flag = 0;
376
377 list = find_list (alias, &single);
378 if (list == all_recipients)
379 flag = 1;
380
381 while (list)
382 {
383 /* Check severity
384 */
385 if ((list->severity & level) == 0)
386 {
387 if (single) break;
388 if (flag)
389 list = list->all_next;
390 else
391 list = list->next;
392 continue;
393 }
394
395 /* Check filter
396 */
397 if (list->mail_filter &&
398 0 != sh_filter_filter(message, list->mail_filter))
399 {
400 if (single) break;
401 if (flag)
402 list = list->all_next;
403 else
404 list = list->next;
405 continue;
406 }
407
408 /* Mark the entry
409 */
410 if (flag)
411 {
412 /* Don't mark aliases
413 */
414 if (flagit && list->isAlias == 0)
415 {
416 list->send_mail = 1;
417 }
418 list = list->all_next;
419 }
420 else
421 {
422 if (flagit)
423 list->send_mail = 1;
424 list = list->next;
425 }
426 ++retval;
427 }
428 }
429 return retval;
430 }
431
432 /* Is not called from same(recursively) or different thread
433 */
434 static
sh_nmail_flag_recipients(int level,const char * message,const char * alias)435 int sh_nmail_flag_recipients (int level, const char * message,
436 const char * alias)
437 {
438 int retval = 0;
439
440 if (message)
441 {
442 SH_MUTEX_LOCK_UNSAFE(mutex_listall);
443 retval = sh_nmail_compute_recipients (level, message, alias, 1);
444 SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
445 }
446 return retval;
447 }
448
449 /* Can be called from same thread with mutex_listall held via sh_nmail_flush()
450 */
451 static
sh_nmail_test_recipients(int level,const char * message,const char * alias)452 int sh_nmail_test_recipients (int level, const char * message,
453 const char * alias)
454 {
455 int retval = 0;
456
457 if (message)
458 {
459 if (0 == SH_MUTEX_TRYLOCK_UNSAFE(mutex_flush_l))
460 {
461 SH_MUTEX_LOCK_UNSAFE(mutex_listall);
462 retval = sh_nmail_compute_recipients (level, message, alias, 0);
463 SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
464 SH_MUTEX_UNLOCK_UNSAFE(mutex_flush_l);
465 }
466 }
467 return retval;
468 }
469
470 /* <<<<<<<<<<<<<<<<<<< Mail the message >>>>>>>>>>>>>>>>>>>>>> */
471
472 SH_MUTEX_RECURSIVE(mutex_nmail_msg);
473 SH_MUTEX_STATIC(nmail_lock, PTHREAD_MUTEX_INITIALIZER);
474
475 /*
476 * First test list of recipients, then call sh_mail_pushstack().
477 */
sh_nmail_pushstack(int level,const char * message,const char * alias)478 int sh_nmail_pushstack (int level, const char * message,
479 const char * alias)
480 {
481 int retval = 0;
482
483 if (0 != sh_nmail_test_recipients (level, message, alias))
484 {
485 retval = sh_mail_pushstack(level, message, alias);
486 }
487 return retval;
488 }
489
490 static int nmail_count = 0;
491
492 /*
493 * First mark list of recipients, then call sh_mail_msg().
494 */
sh_nmail_msg(int level,const char * message,const char * alias)495 int sh_nmail_msg (int level, const char * message,
496 const char * alias)
497 {
498 volatile int retval = 0;
499
500 /* Need to:
501 * -- wait if different thread, and
502 * -- fail if same thread. */
503 SH_MUTEX_RECURSIVE_INIT(mutex_nmail_msg);
504 SH_MUTEX_RECURSIVE_LOCK(mutex_nmail_msg);
505
506 /* Only same thread beyond this point. We fail
507 * if count > 0 already. */
508 if (0 == SH_MUTEX_TRYLOCK_UNSAFE(nmail_lock))
509 {
510 ++nmail_count;
511 if (nmail_count != 1)
512 {
513 --nmail_count;
514 SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
515 goto cleanup;
516 }
517 SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
518
519 if (0 != sh_nmail_flag_recipients (level, message, alias))
520 {
521 /* Need to keep info for sh_nmail_pushstack()
522 */
523 SH_MUTEX_LOCK(mutex_listall);
524 retval = sh_mail_msg(message);
525 SH_MUTEX_UNLOCK(mutex_listall);
526
527 if (retval != 0)
528 {
529 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__,
530 retval, MSG_E_SUBGEN,
531 _("could not mail immediately"),
532 _("sh_nmail_msg") );
533 sh_mail_pushstack(level, message, alias);
534 }
535 }
536 SH_MUTEX_LOCK_UNSAFE(nmail_lock);
537 --nmail_count;
538 SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
539 }
540 cleanup:
541 ; /* label at end of compound statement */
542 SH_MUTEX_RECURSIVE_UNLOCK(mutex_nmail_msg);
543 return retval;
544 }
545
546 static int sh_nmail_flush_int (void);
547
sh_nmail_flush()548 int sh_nmail_flush ()
549 {
550 int retval = 0;
551
552 if (0 == SH_MUTEX_TRYLOCK_UNSAFE(nmail_lock))
553 {
554 ++nmail_count;
555 if (nmail_count != 1)
556 {
557 --nmail_count;
558 SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
559 return retval;
560 }
561 SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
562
563 retval = sh_nmail_flush_int ();
564
565 SH_MUTEX_LOCK_UNSAFE(nmail_lock);
566 --nmail_count;
567 SH_MUTEX_UNLOCK_UNSAFE(nmail_lock);
568 }
569 return retval;
570 }
571
572 /* warning: variable ‘list’ might be clobbered by ‘longjmp’ or ‘vfork’*/
573 static struct alias ** list_dummy;
574
575 /*
576 * Loop over all recipients in stack.
577 * For each distinct one, mark all messages for sending.
578 * Then call sh_mail_msg().
579 */
580
sh_nmail_flush_int()581 static int sh_nmail_flush_int ()
582 {
583 int retval = 0;
584 sh_string * msg = NULL;
585 sh_string * smsg = NULL;
586 struct alias * list;
587 struct alias * dlist;
588
589 /* warning: variable ‘list’ might be clobbered by ‘longjmp’ or ‘vfork’*/
590 list_dummy = &list;
591
592 SH_MUTEX_LOCK(mutex_listall);
593
594 /* Reset recipient list
595 */
596 list = all_recipients;
597 while (list)
598 {
599 list->send_mail = 0;
600 list = list->all_next;
601 }
602
603 /* Check (i) compiled recipients, (b) aliases, (c) single recipients.
604 * For each, tag all messages, then call sh_mail_msg with
605 * appropriate address list.
606 */
607
608 reset_list(fifo_mail);
609
610 /* Compiled recipients. These share threshold and filter,
611 * hence only the first recipient needs to be tested.
612 */
613 list = compiled_recipient_list;
614
615 if (list)
616 {
617 msg = tag_list(fifo_mail, sh_string_str(list->recipient),
618 sh_nmail_valid_message_for_alias, list, S_TRUE);
619 }
620
621 if (msg)
622 {
623 while (list)
624 {
625 list->send_mail = 1;
626 list = list->next;
627 }
628
629 list = compiled_recipient_list;
630
631 SH_MUTEX_LOCK(mutex_flush_l);
632 (void) sh_mail_msg(sh_string_str(msg));
633 SH_MUTEX_UNLOCK(mutex_flush_l);
634
635 sh_string_destroy(&msg);
636
637 list = compiled_recipient_list;
638 while (list)
639 {
640 list->send_mail = 0;
641 list = list->next;
642 }
643 }
644
645 /* Aliases
646 */
647 list = alias_list;
648
649 while (list) {
650
651 /* Work through the recipient list. As smsg stores last msg,
652 * we send a batch whenever msg != smsg, and continue from
653 * that point in the recipient list.
654 */
655 struct alias * lnew;
656
657 while (list)
658 {
659 msg = tag_list(fifo_mail, sh_string_str(list->recipient),
660 sh_nmail_valid_message_for_alias, list, S_FALSE);
661
662 if (msg)
663 {
664 if (!smsg) /* init */
665 {
666 smsg = sh_string_copy(msg);
667 }
668 else
669 {
670 if (0 != strcmp(sh_string_str(smsg), sh_string_str(msg)))
671 {
672 /*
673 * Don't set list = list->next here, since we want
674 * to continue with this recipient in the next batch.
675 */
676 sh_string_destroy(&msg);
677 break;
678 }
679 }
680 lnew = list->recipient_list;
681 while (lnew)
682 {
683 lnew->send_mail = 1;
684 lnew= lnew->next;
685 }
686 sh_string_destroy(&msg);
687 }
688 list = list->next;
689 }
690
691 /* Continue here if smsg != msg */
692
693 if (smsg)
694 {
695 SH_MUTEX_LOCK(mutex_flush_l);
696 (void) sh_mail_msg(sh_string_str(smsg));
697 SH_MUTEX_UNLOCK(mutex_flush_l);
698 sh_string_destroy(&smsg);
699 }
700
701 /* Reset old list of recipients (up to current point in list)
702 * and then continue with list from current point on.
703 */
704 dlist = alias_list;
705 while (dlist)
706 {
707 lnew = dlist->recipient_list;
708 while (lnew)
709 {
710 lnew->send_mail = 0;
711 lnew = lnew->next;
712 }
713 dlist = dlist->next;
714 }
715 }
716
717
718 /* Single recipients
719 */
720 list = recipient_list;
721
722 while (list) {
723
724 /* Work through the recipient list. As smsg stores last msg,
725 * we send a batch whenever msg != smsg, and continue from
726 * that point in the recipient list.
727 */
728
729 while (list)
730 {
731 msg = tag_list(fifo_mail, sh_string_str(list->recipient),
732 sh_nmail_valid_message_for_alias, list, S_TRUE);
733
734 if (msg)
735 {
736 if (!smsg) /* init */
737 {
738 smsg = sh_string_copy(msg);
739 }
740 else
741 {
742 if (0 != strcmp(sh_string_str(smsg), sh_string_str(msg)))
743 {
744 /*
745 * Don't set list = list->next here, since we want
746 * to continue with this recipient in the next batch.
747 */
748 sh_string_destroy(&msg);
749 break;
750 }
751 }
752 list->send_mail = 1;
753 sh_string_destroy(&msg);
754 }
755 list = list->next;
756 }
757
758 /* Continue here if smsg != msg */
759
760 if (smsg)
761 {
762 SH_MUTEX_LOCK(mutex_flush_l);
763 (void) sh_mail_msg(sh_string_str(smsg));
764 SH_MUTEX_UNLOCK(mutex_flush_l);
765 sh_string_destroy(&smsg);
766 }
767
768 /* Reset old list of recipients (up to current point in list)
769 * and then continue with list from current point on.
770 */
771 dlist = recipient_list;
772 while (dlist)
773 {
774 dlist->send_mail = 0;
775 dlist = dlist->next;
776 }
777 }
778
779 /* Remove all mails for which no recipient failed
780 */
781
782 sh.mailNum.alarm_last -= commit_list(fifo_mail);
783 SH_MUTEX_UNLOCK(mutex_listall);
784
785 return retval;
786 }
787
788
789
790 /* <<<<<<<<<<<<<<<<<<< Severity >>>>>>>>>>>>>>>>>>>>>> */
791
792 /*
793 * -- set severity threshold for recipient or alias
794 */
sh_nmail_set_severity(const char * str)795 int sh_nmail_set_severity (const char * str)
796 {
797 if (last == recipient_list || last == alias_list)
798 {
799 if (0 == sh_error_set_level(str, &(last->severity)))
800 {
801 /* All recipients in alias share the severity
802 */
803 if (last == alias_list)
804 {
805 struct alias * ptr = last->recipient_list;
806
807 while (ptr)
808 {
809 ptr->severity = last->severity;
810 ptr = ptr->next;
811 }
812 }
813 return 0;
814 }
815 }
816 return (-1);
817 }
818
819 /* <<<<<<<<<<<<<<<<<<< Filters >>>>>>>>>>>>>>>>>>>>>> */
820
821
sh_nmail_add_generic(const char * str,int flag)822 int sh_nmail_add_generic (const char * str, int flag)
823 {
824 if (last)
825 {
826 if (NULL == last->mail_filter)
827 last->mail_filter = sh_filter_alloc();
828
829 /* All recipients in alias share the mail filter
830 */
831 if (last == alias_list)
832 {
833 struct alias * ptr = last->recipient_list;
834
835 while (ptr)
836 {
837 ptr->mail_filter = last->mail_filter;
838 ptr = ptr->next;
839 }
840 }
841
842 return (sh_filter_add (str, last->mail_filter, flag));
843 }
844 return (-1);
845 }
846
847 /*
848 * -- add keywords to the OR filter
849 */
sh_nmail_add_or(const char * str)850 int sh_nmail_add_or (const char * str)
851 {
852 return sh_nmail_add_generic(str, SH_FILT_OR);
853 }
854
855 /*
856 * -- add keywords to the AND filter
857 */
sh_nmail_add_and(const char * str)858 int sh_nmail_add_and (const char * str)
859 {
860 return sh_nmail_add_generic(str, SH_FILT_AND);
861 }
862
863 /*
864 * -- add keywords to the NOT filter
865 */
sh_nmail_add_not(const char * str)866 int sh_nmail_add_not (const char * str)
867 {
868 return sh_nmail_add_generic(str, SH_FILT_NOT);
869 }
870
871
872 /* <<<<<<<<<<<<<<<<<<< Mailkey per Alias >>>>>>>>>>>>>>>>>>>>>>>>> */
873
874 #if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
875 #include <sys/mman.h>
876 #endif
877
878 #include "zAVLTree.h"
879
880 zAVLTree * mailkeys = NULL;
881
882 struct alias_mailkey {
883 char * alias;
884 unsigned int mailcount;
885 time_t id_audit;
886 char mailkey_old[KEY_LEN+1];
887 char mailkey_new[KEY_LEN+1];
888 };
889
sh_nmail_getkey(void const * item)890 static zAVLKey sh_nmail_getkey(void const *item)
891 {
892 const struct alias_mailkey * t = (const struct alias_mailkey *) item;
893 return (zAVLKey) t->alias;
894 }
895
896 /* Return mailkey for alias. If there's no key yet, create it and
897 * store it in the AVL tree.
898 * This is called from sh_mail_msg,
899 * which is called from sh_nmail_msg,
900 * which is protected by a mutex.
901 */
sh_nmail_get_mailkey(const char * alias,char * buf,size_t bufsiz,time_t * id_audit)902 int sh_nmail_get_mailkey (const char * alias, char * buf, size_t bufsiz,
903 time_t * id_audit)
904 {
905 char hashbuf[KEYBUF_SIZE];
906
907 start:
908
909 if (mailkeys)
910 {
911 struct alias_mailkey * t;
912
913 if (!alias)
914 t = (struct alias_mailkey *) zAVLSearch (mailkeys, _("(null)"));
915 else
916 t = (struct alias_mailkey *) zAVLSearch (mailkeys, alias);
917
918 if (t)
919 {
920 /* iterate the key
921 */
922 (void) sl_strlcpy(t->mailkey_new,
923 sh_tiger_hash (t->mailkey_old, TIGER_DATA, KEY_LEN,
924 hashbuf, sizeof(hashbuf)),
925 KEY_LEN+1);
926 (void) sl_strlcpy(buf, t->mailkey_new, bufsiz);
927 ++(t->mailcount);
928 }
929 else
930 {
931 t = SH_ALLOC(sizeof(struct alias_mailkey));
932
933 MLOCK(t, sizeof(struct alias_mailkey));
934
935 if (!alias)
936 t->alias = sh_util_strdup(_("(null)"));
937 else
938 t->alias = sh_util_strdup(alias);
939
940 t->mailcount = 0;
941 t->id_audit = time(NULL);
942
943 BREAKEXIT(sh_util_keyinit);
944 (void) sh_util_keyinit (t->mailkey_old, KEY_LEN+1);
945
946 /* iterate the key
947 */
948 (void) sl_strlcpy(t->mailkey_new,
949 sh_tiger_hash (t->mailkey_old, TIGER_DATA, KEY_LEN,
950 hashbuf, sizeof(hashbuf)),
951 KEY_LEN+1);
952 (void) sl_strlcpy(buf, t->mailkey_new, bufsiz);
953 (void) zAVLInsert(mailkeys, t);
954 }
955
956 /* X(n) -> X(n-1)
957 */
958 (void) sl_strlcpy (t->mailkey_old, t->mailkey_new, KEY_LEN+1);
959
960 *id_audit = t->id_audit;
961
962 return (t->mailcount);
963 }
964
965 mailkeys = zAVLAllocTree (sh_nmail_getkey, zAVL_KEY_STRING);
966 goto start;
967 }
968
969 /* <<<<<<<<<<<<<<<<<<< Free for Reconfigure >>>>>>>>>>>>>>>>>>>>>> */
970
971
free_recipient_list(struct alias * list)972 static void free_recipient_list(struct alias * list)
973 {
974 struct alias * new;
975 sh_filter_type * p = NULL;
976
977 while (list)
978 {
979 new = list;
980 list = new->next;
981 if (new->mx_list)
982 free_mx(new->mx_list);
983 if (new->mail_filter)
984 {
985 sh_filter_free(new->mail_filter);
986 if (!p || p != new->mail_filter)
987 {
988 p = new->mail_filter;
989 SH_FREE(new->mail_filter);
990 }
991 }
992 sh_string_destroy(&(new->recipient));
993 SH_FREE(new);
994 }
995 }
996
997 /* Free everything to prepare for reconfigure
998 */
sh_nmail_free()999 void sh_nmail_free()
1000 {
1001 SH_MUTEX_LOCK_UNSAFE(mutex_listall);
1002 all_recipients = NULL;
1003 SH_MUTEX_UNLOCK_UNSAFE(mutex_listall);
1004
1005 free_recipient_list(recipient_list);
1006 recipient_list = NULL;
1007
1008 sh_filter_free(&compiled_mail_filter);
1009
1010 while (alias_list)
1011 {
1012 struct alias * item = alias_list;
1013
1014 alias_list = item->next;
1015
1016 sh_string_destroy(&(item->recipient));
1017 free_recipient_list(item->recipient_list);
1018 if (item->mail_filter)
1019 {
1020 sh_filter_free(item->mail_filter);
1021 /* SH_FREE(item->mail_filter); */
1022 }
1023 SH_FREE(item);
1024 }
1025 alias_list = NULL;
1026
1027 last = compiled_recipient_list;
1028 return;
1029 }
1030
1031 /* defined(SH_WITH_MAIL) */
1032 #endif
1033