source: trunk/src/sh_mail.c@ 135

Last change on this file since 135 was 134, checked in by rainer, 17 years ago

More thread-safety changes.

File size: 49.3 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000 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#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <pwd.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <errno.h>
31#include <signal.h>
32#include <setjmp.h>
33
34#if defined(SH_WITH_MAIL)
35
36#if TIME_WITH_SYS_TIME
37#include <sys/time.h>
38#include <time.h>
39#else
40#if HAVE_SYS_TIME_H
41#include <sys/time.h>
42#else
43#include <time.h>
44#endif
45#endif
46
47
48#ifdef HAVE_MEMORY_H
49#include <memory.h>
50#endif
51
52#include "samhain.h"
53#include "sh_error.h"
54#include "sh_unix.h"
55#include "sh_tiger.h"
56#include "sh_mail.h"
57#include "sh_utils.h"
58#include "sh_fifo.h"
59#include "sh_tools.h"
60
61#undef FIL__
62#define FIL__ _("sh_mail.c")
63#undef GOOD
64#undef BAD
65
66static int failedMail = SL_FALSE;
67
68/* MX Resolver Struct
69 */
70typedef struct mx_ {
71 int pref;
72 char * address;
73} mx;
74
75typedef struct dnsrep_ {
76 int count;
77 mx * reply;
78} dnsrep;
79
80static int free_mx (dnsrep * answers);
81static dnsrep * return_mx (char *domain);
82
83/*********************************************
84 * utility function for verifying mails
85 *********************************************/
86
87typedef struct mail_trail_struct {
88 char trail_id[2*SH_MINIBUF];
89 char trail_key[KEY_LEN+1];
90 struct mail_trail_struct * next;
91} mail_trail_type;
92
93static mail_trail_type * mail_trail = NULL;
94
95int sh_mail_sigverify (const char * s)
96{
97 SL_TICKET fd;
98 long i;
99 char * buf;
100 char * bufc;
101 char key[81];
102 char number[2*SH_MINIBUF];
103 char audit_id[2 * SH_MINIBUF];
104 long numsig;
105 char key2[KEY_LEN+1];
106
107 char * theSig;
108
109 mail_trail_type * mail_trail_ptr = NULL;
110
111 sh_error_logoff();
112
113 ASSERT((s != NULL && sl_strlen(s) < PATH_MAX),
114 _("(s != NULL && sl_strlen(s) < PATH_MAX)"));
115
116 if (s == NULL || sl_strlen(s) >= PATH_MAX)
117 _exit (EXIT_FAILURE);
118
119 /* open the file, then check it
120 */
121 if (0 != sl_is_suid())
122 {
123 fprintf(stderr, _("Cannot open file %s in suid mode\n"), s);
124 _exit (EXIT_FAILURE);
125 }
126 if ( SL_ISERROR(fd = sl_open_read (s, SL_NOPRIV)))
127 {
128 fprintf(stderr, _("Could not open file %s\n"), s);
129 _exit (EXIT_FAILURE);
130 }
131
132 buf = SH_ALLOC( (size_t)(SH_BUFSIZE+1));
133 bufc = SH_ALLOC( (size_t)(SH_MAXBUF+1));
134
135 while (1 == 1)
136 {
137 buf[0] = '\0';
138 bufc[0] = '\0';
139
140 /* find start of next message
141 */
142 while (0 != sl_strncmp(buf, _("-----BEGIN MESSAGE-----"),
143 sizeof("-----BEGIN MESSAGE-----")-1))
144 {
145 (void) sh_unix_getline (fd, buf, SH_BUFSIZE);
146 if (buf[0] == '\0')
147 {
148 /* End of mailbox reached, exit.
149 */
150 (void) fflush(stdout);
151 _exit (EXIT_SUCCESS);
152
153 /* Fix for AIX cc complaint.
154 */
155 /*@notreached@*/
156 return 0;
157 }
158 }
159
160 /* Read message, compress into bufc.
161 */
162 while (1 == 1)
163 {
164 (void) sh_unix_getline (fd, buf, SH_BUFSIZE);
165 if (0 == sl_strncmp(buf, _("-----BEGIN SIGNATURE-----"),
166 sizeof("-----BEGIN SIGNATURE-----")-1))
167 break;
168 if (buf[0] == '\0')
169 _exit (EXIT_FAILURE);
170 (void) sh_util_compress(bufc, buf, SH_MAXBUF-KEY_LEN);
171 }
172
173 /* get signature and number
174 */
175 (void) sh_unix_getline (fd, key, (int)sizeof(key));
176 key[KEY_LEN] = '\0';
177
178 (void) sh_unix_getline (fd, number, (int)sizeof(number));
179 number[(2*SH_MINIBUF) - 2] = '\0';
180 numsig = atol (number);
181 (void) sl_strlcpy (audit_id, &number[7], 2*SH_MINIBUF);
182
183 fprintf(stderr, _("Message %06ld Trail %s\n"),
184 numsig, /*@-usedef@*/ audit_id /*@+usedef@*/);
185
186 mail_trail_ptr = mail_trail;
187 while (mail_trail_ptr)
188 {
189 if (0 == sl_strcmp(mail_trail_ptr->trail_id, audit_id))
190 break;
191 mail_trail_ptr = mail_trail_ptr->next;
192 }
193
194 if (!mail_trail_ptr)
195 {
196 if (numsig > 0)
197 {
198 fprintf (stderr, _("ERROR (no key -- cannot check)\n"));
199 continue;
200 }
201 else
202 {
203 mail_trail_ptr = SH_ALLOC (sizeof(mail_trail_type));
204 mail_trail_ptr->next = mail_trail;
205 mail_trail = mail_trail_ptr;
206 (void) sl_strlcpy (mail_trail_ptr->trail_id,
207 audit_id, 2*SH_MINIBUF);
208 }
209 }
210 else if (numsig == 0)
211 {
212 fprintf (stderr, _("ERROR (repeated audit trail)\n"));
213 continue;
214 }
215
216
217 if (numsig == 0)
218 {
219 sh_util_encode(key, bufc, 1, 'A');
220 (void) sl_strlcpy (mail_trail_ptr->trail_key, key, KEY_LEN+1);
221 fprintf (stderr, _("(unchecked)\n"));
222 }
223 else
224 {
225 char sigbuf[KEYBUF_SIZE];
226
227 /* iterate key
228 */
229 (void) sl_strlcpy(key2, mail_trail_ptr->trail_key, KEY_LEN+1);
230 for (i = 0; i < numsig; ++i)
231 {
232 char hashbuf[KEYBUF_SIZE];
233 (void) sl_strlcpy (key2,
234 sh_tiger_hash (key2, TIGER_DATA, KEY_LEN,
235 hashbuf, sizeof(hashbuf)),
236 KEY_LEN+1);
237 }
238
239
240 theSig = sh_util_siggen (key2, bufc, sl_strlen(bufc), sigbuf, sizeof(sigbuf));
241 if (sl_strncmp (key,
242 theSig,
243 KEY_LEN) != 0)
244 {
245 fprintf (stderr, _("(FAILED)\n"));
246 }
247 else
248 {
249 fprintf (stderr, _("(passed)\n"));
250 }
251
252 }
253
254 } /* end scan mailbox */
255
256 /*@notreached@*/
257}
258
259#define SH_FILT_NUM 32
260#define SH_FILT_OR 0
261#define SH_FILT_AND 1
262#define SH_FILT_NOT 2
263#define SH_FILT_INIT { 0, { NULL }, 0, { NULL }, 0, { NULL }}
264
265typedef struct _sh_filter_type
266{
267 int for_c;
268 char * for_v[SH_FILT_NUM];
269 int fand_c;
270 char * fand_v[SH_FILT_NUM];
271 int fnot_c;
272 char * fnot_v[SH_FILT_NUM];
273
274} sh_filter_type;
275
276static
277int sh_filter_filteradd (const char * argstring,
278 sh_filter_type * filter, int ftype)
279{
280 int i = 0;
281 int flag = 0;
282 size_t s;
283
284 char * dup;
285 char * p;
286 char * end;
287 int * ntok;
288 char ** stok;
289
290 SL_ENTER(_("sh_filter_filteradd"));
291
292 if (NULL == argstring)
293 {
294 SL_RETURN((-1), _("sh_filter_filteradd"));
295 }
296
297 if (ftype == SH_FILT_OR) {
298 ntok = &(filter->for_c);
299 stok = filter->for_v;
300 }
301 else if (ftype == SH_FILT_AND) {
302 ntok = &(filter->fand_c);
303 stok = filter->fand_v;
304 }
305 else if (ftype == SH_FILT_NOT) {
306 ntok = &(filter->fnot_c);
307 stok = filter->fnot_v;
308 }
309 else {
310 SL_RETURN((-1), _("sh_filter_filteradd"));
311 }
312
313 *ntok = 0;
314
315 dup = sh_util_strdup(argstring);
316 p = dup;
317
318 do
319 {
320 while (*p == ',' || *p == ' ' || *p == '\t')
321 ++p;
322 if (*p == '\0')
323 break;
324
325 end = p; ++end;
326 if (*end == '\0')
327 break;
328
329 if (*p == '\'')
330 {
331 ++p; end = p; ++end;
332 if (*p == '\0' || *end == '\0')
333 break;
334 while (*end != '\0' && *end != '\'')
335 ++end;
336 }
337 else if (*p == '"')
338 {
339 ++p; end = p; ++end;
340 if (*p == '\0' || *end == '\0')
341 break;
342 while (*end != '\0' && *end != '"')
343 ++end;
344 }
345 else
346 {
347 while (*end != '\0' && *end != ',' && *end != ' ' && *end != '\t')
348 ++end;
349 }
350 if (*end == '\0')
351 flag = 1;
352 else
353 *end = '\0';
354
355 s = strlen(p) + 1;
356 if (stok[i] != NULL)
357 SH_FREE(stok[i]);
358 stok[i] = SH_ALLOC(s);
359 (void) sl_strlcpy(stok[i], p, s);
360
361 p = end; ++p;
362
363 ++i;
364 if (i == SH_FILT_NUM)
365 break;
366 }
367 while (p != NULL && *p != '\0' && flag == 0);
368
369 *ntok = i;
370 SH_FREE(dup);
371
372 SL_RETURN (0, _("sh_filter_filteradd"));
373}
374
375/*
376 * -- check filters
377 */
378static
379int sh_filter_filter (const char * message, sh_filter_type * filter)
380{
381 int i;
382 int j = 0;
383
384 SL_ENTER(_("sh_mail_filter"));
385
386 /* Presence of any of these keywords prevents execution.
387 */
388 if (filter->fnot_c > 0)
389 {
390 for (i = 0; i < filter->fnot_c; ++i)
391 {
392 if (NULL != sl_strstr(message, filter->fnot_v[i]))
393 {
394 SL_RETURN ((-1), _("sh_filter_filter"));
395 }
396 }
397 }
398
399 /* Presence of all of these keywords is required for execution.
400 */
401 if (filter->fand_c > 0)
402 {
403 j = 0;
404
405 for (i = 0; i < filter->fand_c; ++i)
406 if (NULL != sl_strstr(message, filter->fand_v[i]))
407 ++j;
408
409 if (j != filter->fand_c)
410 {
411 SL_RETURN ((-1), _("sh_filter_filter"));
412 }
413 }
414
415 /* Presence of at least one of these keywords is required for execution.
416 */
417 if (filter->for_c > 0)
418 {
419 for (i = 0; i < filter->for_c; ++i)
420 {
421 if (NULL != sl_strstr(message, filter->for_v[i]))
422 {
423 goto isok;
424 }
425 }
426 SL_RETURN ((-1), _("sh_filter_filter"));
427 }
428
429 isok:
430 SL_RETURN ((0), _("sh_filter_filter"));
431}
432
433
434static sh_filter_type mail_filter = SH_FILT_INIT;
435
436/*
437 * -- add keywords to the OR filter
438 */
439int sh_mail_add_or (const char * str)
440{
441 return (sh_filter_filteradd (str, &(mail_filter), SH_FILT_OR));
442}
443
444/*
445 * -- add keywords to the AND filter
446 */
447int sh_mail_add_and (const char * str)
448{
449 return (sh_filter_filteradd (str, &(mail_filter), SH_FILT_AND));
450}
451
452/*
453 * -- add keywords to the NOT filter
454 */
455int sh_mail_add_not (const char * str)
456{
457 return (sh_filter_filteradd (str, &(mail_filter), SH_FILT_NOT));
458}
459
460
461static char * address_list[8] = {
462 NULL, NULL, NULL, NULL,
463 NULL, NULL, NULL, NULL
464};
465
466static int address_num = 0;
467static int address_num_compiled = 0;
468static int setaddress_compiled = S_FALSE;
469
470void reset_count_dev_mail(void)
471{
472 /* if not, then we still have the compiled-in address (if any), so we
473 * don' touch them
474 */
475 if (address_num_compiled == -99)
476 address_num = 0;
477 return;
478}
479
480int sh_mail_setaddress (const char * address)
481{
482 char * p;
483
484 SL_ENTER(_("sh_mail_setaddress"));
485
486 if (0 == strcmp(address, _("NULL")))
487 SL_RETURN ( (0), _("sh_mail_setaddress"));
488
489 if (address != NULL && address_num < (2 * SH_PATHBUF / 64 ))
490 {
491 if (address_num < (SH_PATHBUF / 64 ))
492 p = &sh.srvmail.name[address_num*64];
493 else
494 p = &sh.srvmail.alt[address_num*64];
495
496 (void) sl_strlcpy (p, address, 64);
497
498 if ((p == NULL) || ( sl_strlen(address) != sl_strlen(p)))
499 {
500 memset(p, (int)'\0', 64);
501 SL_RETURN ( (-1), _("sh_mail_setaddress"));
502 }
503 address_list[address_num] = p;
504#if 0
505 if (!sl_is_suid())
506 {
507 TPT(( 0, FIL__, __LINE__, _("msg=<address_list[%d] = %s>\n"),
508 address_num, address_list[address_num]));
509 }
510#endif
511 if (setaddress_compiled == S_TRUE)
512 {
513 ++address_num;
514 ++address_num_compiled;
515 }
516 else
517 {
518 if (address_num == address_num_compiled)
519 {
520 address_num = 0;
521 address_num_compiled = -99;
522 }
523 ++address_num;
524 }
525 SL_RETURN ( (0), _("sh_mail_setaddress"));
526 }
527 SL_RETURN ( (-1), _("sh_mail_setaddress"));
528}
529
530int sh_mail_setaddress_int (const char * address)
531{
532 int i;
533 SL_ENTER(_("sh_mail_setaddress_int"));
534 setaddress_compiled = S_TRUE;
535 i = sh_mail_setaddress(address);
536 setaddress_compiled = S_FALSE;
537 SL_RETURN(i, _("sh_mail_setaddress_int"));
538}
539
540int sh_mail_setNum (const char * str)
541{
542 int i = atoi (str);
543
544 SL_ENTER(_("sh_mail_setNum"));
545
546 if (i >= 0 && i < SH_FIFO_MAX)
547 sh.mailNum.alarm_interval = (time_t) i;
548 else
549 SL_RETURN ((-1), _("sh_mail_setNum"));
550 SL_RETURN( (0), _("sh_mail_setNum"));
551}
552
553
554static int all_in_one = S_FALSE;
555
556int sh_mail_setFlag (const char * str)
557{
558 int i;
559 SL_ENTER(_("sh_mail_setFlag"));
560 i = sh_util_flagval(str, &all_in_one);
561 SL_RETURN(i, _("sh_mail_setFlag"));
562}
563
564static char * mail_subject = NULL;
565
566int set_mail_subject (const char * str)
567{
568 SL_ENTER(_("set_mail_subject"));
569 if (!str)
570 SL_RETURN( (-1), _("set_mail_subject"));
571
572 if (mail_subject != NULL)
573 SH_FREE(mail_subject);
574
575 if (0 == sl_strncmp(str, _("NULL"), 4))
576 {
577 mail_subject = NULL;
578 SL_RETURN( 0, _("set_mail_subject"));
579 }
580
581 mail_subject = sh_util_strdup(str);
582 SL_RETURN( (0), _("set_mail_subject"));
583}
584
585
586static SH_FIFO * fifo_mail = NULL;
587
588static
589void sh_mail_emptystack (void)
590{
591 char * msg;
592 size_t len;
593
594 SL_ENTER(_("sh_mail_emptystack"));
595
596 if (fifo_mail == NULL)
597 SL_RET0(_("sh_mail_emptystack"));
598
599 while (NULL != (msg = pop_list(fifo_mail)))
600 {
601 len = sl_strlen(msg);
602 memset(msg, 0, len);
603 SH_FREE(msg);
604 }
605
606 SL_RET0(_("sh_mail_emptystack"));
607}
608
609/* insert "\r\n" after each 998 char
610 */
611static char * split_string(char * str);
612
613int sh_mail_pushstack (/*@null@*/char * msg)
614{
615 char * p;
616 int retval = 0;
617 int status;
618
619 SL_ENTER(_("sh_mail_pushstack"));
620
621 if (msg == NULL || failedMail == SL_TRUE || sh.srvmail.name[0] == '\0')
622 SL_RETURN((0), (_("sh_mail_pushstack")));
623
624 if (0 != sh_filter_filter(msg, &mail_filter))
625 SL_RETURN((0), (_("sh_mail_pushstack")));
626
627#if 0
628 if (msg != NULL && sl_strlen(msg) > 998) /* RFC 2822 */
629 msg[998] = '\0';
630#endif
631
632 p = split_string(msg);
633
634 if (fifo_mail == NULL)
635 {
636 fifo_mail = SH_ALLOC(sizeof(SH_FIFO));
637 fifo_init(fifo_mail);
638 }
639
640 status = push_list (fifo_mail, p);
641 if (status >= 0)
642 ++sh.mailNum.alarm_last;
643
644 SH_FREE(p);
645
646 if (sh.mailNum.alarm_last >= sh.mailNum.alarm_interval)
647 {
648 BREAKEXIT(sh_mail_msg);
649 retval = sh_mail_msg (NULL);
650 }
651
652 if (status == SH_FIFO_MAX)
653 retval = -2;
654 SL_RETURN(retval, (_("sh_mail_pushstack")));
655}
656
657
658/* The mailer.
659 */
660static int sh_mail_end_conn (FILE * connfile, int fd);
661static FILE * sh_mail_start_conn (int aFlag, int * fd);
662
663static
664void sh_mail_get_subject(char * message,
665 char * mheader, size_t len)
666{
667 st_format rep_serv_tab[] = {
668 { 'T', S_FMT_TIME, 0, 0, NULL},
669 { 'H', S_FMT_STRING, 0, 0, NULL},
670 { 'M', S_FMT_STRING, 0, 0, NULL},
671 { 'S', S_FMT_STRING, 0, 0, NULL},
672 {'\0', S_FMT_ULONG, 0, 0, NULL},
673 };
674
675 char * p;
676 char * mptr;
677 char sev[8];
678
679 SL_ENTER(_("sh_mail_get_subject"));
680
681 (void) sl_strlcpy(mheader, _("Subject: "), len);
682 if (NULL == strchr(mail_subject, '%'))
683 {
684 (void) sl_strlcat(mheader, mail_subject, len);
685 SL_RET0(_("sh_mail_get_subject"));
686 }
687
688
689 rep_serv_tab[0].data_ulong = (unsigned long) time(NULL);
690 rep_serv_tab[1].data_str = sh.host.name;
691
692 /* fast forward to the important part
693 */
694 mptr = sl_strstr(message, _("msg="));
695 if (mptr)
696 {
697 mptr += 4;
698 rep_serv_tab[2].data_str = mptr;
699 }
700 else
701 rep_serv_tab[2].data_str = message;
702
703 mptr = sl_strstr(message, _("sev="));
704 if (mptr)
705 {
706 mptr += 5;
707 sev[0] = *mptr; ++mptr;
708 sev[1] = *mptr; ++mptr;
709 sev[2] = *mptr; ++mptr;
710 sev[3] = *mptr; ++mptr;
711 sev[4] = '\0';
712 }
713 else
714 {
715 mptr = message;
716 sev[0] = *mptr; ++mptr;
717 sev[1] = *mptr; ++mptr;
718 sev[2] = *mptr; ++mptr;
719 sev[3] = *mptr; ++mptr;
720 if (*mptr == ' ') {
721 sev[4] = '\0';
722 } else {
723 sev[4] = *mptr; ++mptr;
724 if (*mptr == ' ') {
725 sev[5] = '\0';
726 } else {
727 sev[5] = *mptr;
728 sev[6] = '\0';
729 }
730 }
731 }
732 rep_serv_tab[3].data_str = sev;
733
734
735 p = sh_util_formatted(mail_subject, rep_serv_tab);
736 (void) sl_strlcat(mheader, p, len);
737 SH_FREE(p);
738 SL_RET0(_("sh_mail_get_subject"));
739}
740
741
742#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
743#include <sys/mman.h>
744#endif
745
746static char * sh_mail_realloc (char * inbuf, size_t * insize, size_t increase)
747{
748 size_t newsize;
749 char * outbuf = inbuf;
750
751 SL_ENTER(_("sh_mail_realloc"));
752
753 if (sl_ok_adds((*insize), 1))
754 {
755 newsize = (*insize) + 1;
756
757 if (sl_ok_adds(newsize, increase))
758 {
759 newsize += increase;
760
761 outbuf = SH_ALLOC(newsize);
762 MLOCK(outbuf, newsize);
763 (void) sl_strlcpy(outbuf, inbuf, newsize);
764
765 memset (inbuf, 0, (*insize));
766 MUNLOCK(inbuf, (*insize));
767 SH_FREE(inbuf);
768
769 *insize = newsize;
770 }
771 }
772
773 SL_RETURN( (outbuf), _("sh_mail_realloc"));
774}
775
776int sh_mail_msg (/*@null@*/char * message)
777{
778 char subject[32+32+SH_MINIBUF+2+3+SH_PATHBUF];
779 char mheader[32+32+SH_MINIBUF+2+3];
780
781 char * mailMsg;
782 char * popMsg;
783 int status = 0, errcount;
784 size_t wrlen;
785 int i;
786 int num_popped = 0;
787 int retval = -1;
788
789 char * bufcompress;
790 static int failcount = 0;
791 static int isfirst = 1;
792 static int mailcount = 0;
793 FILE * connfile = NULL;
794
795 struct sigaction old_act;
796 struct sigaction new_act;
797
798 static time_t id_audit = 0;
799 static time_t fail_time = 0;
800 static time_t success_time = 0;
801
802 static int ma_block = 0;
803
804 int ma_socket = -1;
805
806 SH_FIFO * fifo_temp = NULL;
807
808 char * theSig;
809 char * theMsg = NULL;
810
811 /* #define SH_MAILBUF (256) */
812#define SH_MAILBUF (8*4096)
813
814 size_t msgbufsize = SH_MAILBUF;
815 size_t combufsize = SH_MAILBUF;
816 char timebuf[81];
817 char hashbuf[KEYBUF_SIZE];
818
819 SL_ENTER(_("sh_mail_msg"));
820
821 if (ma_block == 1)
822 SL_RETURN( (0), _("sh_mail_msg"));
823
824 /* Return if we cannot mail.
825 */
826 if (failedMail == SL_TRUE)
827 SL_RETURN((-1), _("sh_mail_msg"));
828
829 if (failedMail == SL_FALSE && address_list[0] == NULL)
830 {
831 TPT((0, FIL__, __LINE__,
832 _("msg=<Mail error: no recipient address.>\n")));
833 failedMail = SL_TRUE;
834 SL_RETURN((-1), _("sh_mail_msg"));
835 }
836
837 if ( (success_time > 0) && (fail_time > 0) &&
838 (time(NULL) - success_time) > 3600*SH_MAX_FAIL)
839 {
840 ma_block = 1;
841 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
842 _("mail"), address_list[0]);
843 ma_block = 0;
844 sh_mail_emptystack();
845 sh.mailNum.alarm_last = 0;
846 failedMail = SL_TRUE;
847 SL_RETURN((-1), _("sh_mail_msg"));
848 }
849
850 /* Try at most each hour.
851 */
852 if ((fail_time > 0) && (time(NULL) - fail_time) < 3/*600*/)
853 {
854 if (failcount > 3)
855 {
856 /* -- Save for later. --
857 */
858 sh_mail_pushstack (message);
859 ++failcount;
860
861 SL_RETURN((-1), _("sh_mail_msg"));
862 }
863 else
864 {
865 (void) retry_msleep(2, 0);
866 ++failcount;
867 }
868 }
869
870 /* -- Reset time of last failure. --
871 */
872 fail_time = 0;
873
874 /* -- Polling, empty queue. --
875 */
876 if (message == NULL && sh.mailNum.alarm_last == 0)
877 SL_RETURN((-1), _("sh_mail_msg"));
878
879 /* -- Filtered. --
880 */
881 if (message != NULL && 0 != sh_filter_filter(message, &mail_filter))
882 SL_RETURN((-1), (_("sh_mail_msg")));
883
884
885
886 /* --------- Build complete message. ------------------------ */
887
888 theMsg = split_string(message);
889
890 /* ---------- Header ---------------------------------------- */
891
892 if (mail_subject == NULL)
893 {
894 (void) sl_strlcpy(mheader, _("Subject: "), sizeof(mheader)-5);
895 (void) sl_strlcat(mheader, sh_unix_time (0, timebuf, sizeof(timebuf)),
896 sizeof(mheader)-5);
897 (void) sl_strlcat(mheader, " ", sizeof(mheader)-5);
898 (void) sl_strlcat(mheader, sh.host.name, sizeof(mheader)-5);
899 }
900 else
901 {
902
903 if (message == NULL)
904 {
905 theMsg = pop_list(fifo_mail);
906 message = theMsg;
907 if (message)
908 --sh.mailNum.alarm_last;
909 }
910
911 if (message)
912 {
913 sh_mail_get_subject(message, mheader, sizeof(mheader)-5);
914 }
915 else
916 {
917 (void) sl_strlcpy(mheader, _("Subject: "), sizeof(mheader)-5);
918 (void) sl_strlcat(mheader, sh_unix_time (0, timebuf, sizeof(timebuf)),
919 sizeof(mheader)-5);
920 (void) sl_strlcat(mheader, " ", sizeof(mheader)-5);
921 (void) sl_strlcat(mheader, sh.host.name, sizeof(mheader)-5);
922 }
923 }
924
925 /* RFC 821: Header is terminated by an empty line
926 */
927 (void) sl_strlcat(mheader, "\015\012\015\012", sizeof(mheader));
928
929 /* ---------- Message --------------------------------------- */
930
931 (void) sl_strlcpy(subject, sh_unix_time (0, timebuf, sizeof(timebuf)),
932 sizeof(subject));
933 (void) sl_strlcat(subject, " ", sizeof(subject));
934 (void) sl_strlcat(subject, sh.host.name, sizeof(subject));
935 (void) sl_strlcat(subject, "\r\n", sizeof(subject));
936
937
938 mailMsg = (char *) SH_ALLOC (msgbufsize);
939 bufcompress = (char *) SH_ALLOC (combufsize);
940
941 MLOCK(mailMsg , msgbufsize);
942 MLOCK(bufcompress , combufsize);
943
944 (void) sl_strlcpy(mailMsg, mheader, msgbufsize);
945 bufcompress[0] = '\0';
946
947 (void) sl_strlcat(mailMsg, _("-----BEGIN MESSAGE-----\r\n"), msgbufsize);
948 (void) sl_strlcat(mailMsg, subject, msgbufsize);
949 (void) sh_util_compress (bufcompress, subject,
950 (combufsize - KEY_LEN - 1));
951 if (message != NULL)
952 {
953 if ((sl_strlen(theMsg) + sl_strlen(mailMsg) + 1) >
954 (msgbufsize-(4*KEY_LEN)))
955 {
956 mailMsg = sh_mail_realloc(mailMsg,
957 &msgbufsize, sl_strlen(theMsg)+2);
958 bufcompress = sh_mail_realloc(bufcompress,
959 &combufsize, sl_strlen(theMsg));
960 }
961 (void) sl_strlcat(mailMsg, theMsg, msgbufsize-(4*KEY_LEN));
962 (void) sl_strlcat(mailMsg, "\r\n", msgbufsize-(4*KEY_LEN));
963
964 (void) sh_util_compress (bufcompress, theMsg, combufsize-KEY_LEN-1);
965 }
966
967 if (sh.mailNum.alarm_last > 0)
968 {
969 fifo_temp = SH_ALLOC (sizeof(SH_FIFO));
970 fifo_init (fifo_temp);
971
972 while ( NULL != (popMsg = pop_list(fifo_mail)) )
973 {
974 (void) push_list (fifo_temp, popMsg);
975
976 if ((sl_strlen(popMsg) + sl_strlen(mailMsg) + 1) >
977 (msgbufsize-(4*KEY_LEN)))
978 {
979 mailMsg = sh_mail_realloc(mailMsg,
980 &msgbufsize,
981 sl_strlen(popMsg)+2);
982 bufcompress = sh_mail_realloc(bufcompress,
983 &combufsize,
984 sl_strlen(popMsg));
985 }
986
987 (void) sl_strlcat(mailMsg, popMsg, msgbufsize-(4*KEY_LEN));
988 (void) sl_strlcat(mailMsg, "\r\n", msgbufsize-(4*KEY_LEN));
989 (void) sh_util_compress(bufcompress, popMsg, combufsize-KEY_LEN-1);
990 SH_FREE(popMsg);
991 --sh.mailNum.alarm_last;
992 ++num_popped;
993 }
994 }
995
996 /* ------ signature block ------------------------------------ */
997
998 (void) sl_strlcat(mailMsg, _("-----BEGIN SIGNATURE-----\r\n"), msgbufsize);
999
1000 /* Generate new signature key.
1001 */
1002 if (isfirst == 1)
1003 {
1004 BREAKEXIT(sh_util_keyinit);
1005 (void) sh_util_keyinit (skey->mailkey_old, KEY_LEN+1);
1006 }
1007
1008 /* iterate the key
1009 */
1010 (void) sl_strlcpy(skey->mailkey_new,
1011 sh_tiger_hash (skey->mailkey_old, TIGER_DATA, KEY_LEN,
1012 hashbuf, sizeof(hashbuf)),
1013 KEY_LEN+1);
1014
1015 if (isfirst == 0)
1016 {
1017 char sigbuf[KEYBUF_SIZE];
1018
1019 /* Sign the message with the signature key.
1020 */
1021 theSig = sh_util_siggen (skey->mailkey_new,
1022 bufcompress, sl_strlen(bufcompress),
1023 sigbuf, sizeof(sigbuf));
1024 (void) sl_strlcat (mailMsg,
1025 theSig,
1026 msgbufsize);
1027 }
1028 else
1029 {
1030 id_audit = time (NULL);
1031
1032 /* reveal first signature key
1033 */
1034 /* flawfinder: ignore */
1035 (void) sl_strlcpy(skey->crypt, skey->mailkey_new, KEY_LEN+1);
1036
1037 BREAKEXIT(sh_util_encode);
1038 /* flawfinder: ignore */
1039 sh_util_encode(skey->crypt, bufcompress, 0, 'A');
1040
1041 /* flawfinder: ignore */
1042 (void) sl_strlcat (mailMsg, skey->crypt, msgbufsize);
1043 /* flawfinder: ignore */
1044 memset (skey->crypt, 0, KEY_LEN);
1045 isfirst = 0;
1046 }
1047 (void) sl_strlcat (mailMsg, "\r\n", msgbufsize);
1048
1049 /* X(n) -> X(n-1)
1050 */
1051 (void) sl_strlcpy (skey->mailkey_old, skey->mailkey_new, KEY_LEN+1);
1052
1053 sl_snprintf(subject, sizeof(subject), _("%06d %010ld::%s\r\n"),
1054 mailcount, (long) id_audit, sh.host.name);
1055
1056 (void) sl_strlcat (mailMsg, subject, msgbufsize);
1057 ++mailcount;
1058
1059 (void) sl_strlcat (mailMsg, _("-----END MESSAGE-----"), msgbufsize);
1060
1061
1062
1063 /* ---------- Connect ---------------------------------------- */
1064
1065
1066
1067 /* -- Catch (ignore) 'broken pipe'.
1068 */
1069 new_act.sa_handler = SIG_IGN;
1070 sigemptyset( &new_act.sa_mask ); /* set an empty mask */
1071 new_act.sa_flags = 0; /* init sa_flags */
1072
1073 (void) sigaction (SIGPIPE, &new_act, &old_act);
1074
1075 i = 0;
1076 errcount = 0;
1077
1078 if (all_in_one == S_FALSE)
1079 {
1080 while (address_list[i] != NULL && i < address_num)
1081 {
1082 connfile = sh_mail_start_conn (i, &ma_socket);
1083
1084 if (NULL != connfile)
1085 {
1086 wrlen = fwrite (mailMsg, 1, sl_strlen(mailMsg),
1087 connfile);
1088 wrlen -= sl_strlen(mailMsg);
1089 if (wrlen == 0)
1090 status = sh_mail_end_conn (connfile, ma_socket);
1091 else
1092 status = -1;
1093 }
1094 if (NULL == connfile || status != 0)
1095 {
1096 ma_block = 1;
1097 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
1098 _("mail"), address_list[i]);
1099 ma_block = 0;
1100 ++errcount;
1101 ++sh.statistics.mail_failed;
1102 }
1103 else
1104 {
1105 ++sh.statistics.mail_success;
1106 }
1107
1108 if (connfile != NULL)
1109 {
1110 (void) fclose (connfile);
1111 connfile = NULL;
1112 }
1113 ++i;
1114 }
1115 }
1116 else
1117 {
1118 connfile = sh_mail_start_conn ( -9 , &ma_socket);
1119
1120 if (NULL != connfile)
1121 {
1122 wrlen = fwrite (mailMsg, 1, sl_strlen(mailMsg), connfile);
1123 wrlen -= sl_strlen(mailMsg);
1124 if (wrlen == 0)
1125 status = sh_mail_end_conn (connfile, ma_socket);
1126 else
1127 status = -1;
1128 }
1129 if (NULL == connfile || status != 0)
1130 {
1131 ma_block = 1;
1132 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
1133 _("mail"), address_list[0]);
1134 ma_block = 0;
1135 errcount = address_num;
1136 ++sh.statistics.mail_failed;
1137 }
1138 else
1139 {
1140 ++sh.statistics.mail_success;
1141 }
1142
1143 if (connfile != NULL)
1144 {
1145 (void) fclose (connfile);
1146 connfile = NULL;
1147 }
1148 }
1149
1150
1151 memset (bufcompress, 0, combufsize);
1152 MUNLOCK(bufcompress , combufsize);
1153 SH_FREE(bufcompress);
1154
1155 memset (mailMsg, 0, msgbufsize);
1156 MUNLOCK(mailMsg , msgbufsize);
1157 SH_FREE(mailMsg);
1158
1159 /* --- Stay responsible for delivery in case of failure --- */
1160
1161 if (errcount == address_num && fifo_temp != NULL)
1162 {
1163 while ( (NULL != (popMsg = pop_list(fifo_temp))) )
1164 {
1165 if (push_list (fifo_mail, popMsg) >= 0)
1166 ++sh.mailNum.alarm_last;
1167 SH_FREE(popMsg);
1168 }
1169 if (message != NULL)
1170 {
1171 if (fifo_mail == NULL)
1172 {
1173 fifo_mail = SH_ALLOC(sizeof(SH_FIFO));
1174 fifo_init(fifo_mail);
1175 }
1176 retval = push_list (fifo_mail, theMsg);
1177 if (retval >= 0)
1178 ++sh.mailNum.alarm_last;
1179 if (retval == SH_FIFO_MAX)
1180 retval = -2;
1181 else
1182 retval = -1;
1183 }
1184 }
1185 else if (fifo_temp != NULL)
1186 {
1187 while ( (NULL != (popMsg = pop_list(fifo_temp))) )
1188 {
1189 SH_FREE(popMsg);
1190 }
1191 }
1192 if (fifo_temp != NULL)
1193 SH_FREE(fifo_temp);
1194
1195 /*
1196 if (connfile != NULL)
1197 fclose (connfile);
1198 */
1199
1200 if (theMsg != NULL)
1201 SH_FREE(theMsg);
1202
1203 /* --- Reset signal. ---
1204 */
1205 (void) sigaction (SIGPIPE, &old_act, NULL);
1206
1207 if (errcount == address_num)
1208 {
1209 fail_time = time(NULL);
1210 SL_RETURN((retval), _("sh_mail_msg"));
1211 }
1212 success_time = time(NULL);
1213 failcount = 0;
1214
1215 SL_RETURN((0), _("sh_mail_msg"));
1216}
1217
1218
1219/*
1220 *
1221 * SMTP CODE BELOW
1222 *
1223 *
1224 */
1225
1226#include <ctype.h>
1227#ifdef HOST_IS_HPUX
1228#define _XOPEN_SOURCE_EXTENDED
1229#endif
1230#include <netdb.h>
1231#include <sys/types.h>
1232#include <sys/socket.h>
1233#include <netinet/in.h>
1234#ifndef S_SPLINT_S
1235#include <arpa/inet.h>
1236#else
1237#define AF_INET 2
1238#endif
1239
1240#define SH_NEED_GETHOSTBYXXX
1241#include "sh_static.h"
1242
1243/* missing on HP-UX 10.20 */
1244#ifndef IPPORT_SMTP
1245#define IPPORT_SMTP 25
1246#endif
1247
1248static int sh_mail_wait(int code, FILE * m_socket);
1249
1250static char * relay_host = NULL;
1251
1252int sh_mail_set_relay (const char * str_s)
1253{
1254 SL_ENTER(_("sh_mail_set_relay"));
1255
1256 if (str_s == NULL)
1257 SL_RETURN( -1, _("sh_mail_set_relay"));
1258
1259 if (relay_host != NULL)
1260 {
1261 SH_FREE (relay_host);
1262 relay_host = NULL;
1263 }
1264
1265 if (0 == sl_strncmp(str_s, _("NULL"), 4))
1266 {
1267 SL_RETURN( 0, _("sh_mail_set_relay"));
1268 }
1269
1270 relay_host = sh_util_strdup(str_s);
1271
1272 SL_RETURN( 0, _("sh_mail_set_relay"));
1273}
1274
1275static char * mail_sender = NULL;
1276
1277int sh_mail_set_sender (const char *str)
1278{
1279 if (mail_sender != NULL)
1280 {
1281 SH_FREE (mail_sender);
1282 mail_sender = NULL;
1283 }
1284 if (str != NULL)
1285 {
1286 mail_sender = sh_util_strdup (str);
1287 }
1288 if (mail_sender == NULL)
1289 {
1290 return -1;
1291 }
1292 return 0;
1293}
1294
1295
1296/*************************
1297 *
1298 * start connection
1299 * for details on SMTP, see RFC 821
1300 */
1301
1302static time_t time_wait = 300;
1303
1304static FILE * sh_mail_start_conn (int aFlag, int * ma_socket)
1305{
1306 char * address;
1307
1308 int ecount;
1309
1310 char this_address[256];
1311 char ma_machine[256];
1312 char ma_user[256];
1313 char error_msg[256];
1314 char error_call[SH_MINIBUF];
1315 int error_num = 0;
1316 register int i, j, k;
1317 FILE * connFile = NULL;
1318 struct tm * my_tm;
1319#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
1320 struct tm time_tm;
1321#endif
1322 time_t my_time;
1323 char my_tbuf[128];
1324
1325 int fd;
1326
1327 dnsrep * answers;
1328 mx * result;
1329
1330 SL_ENTER(_("sh_mail_start_conn"));
1331
1332 *ma_socket = -1;
1333 time_wait = 300;
1334
1335 if (aFlag >= 0)
1336 address = address_list[aFlag];
1337 else
1338 address = address_list[0];
1339
1340 TPT(( 0, FIL__, __LINE__, _("msg=<aFlag %d address %s>\n"),
1341 aFlag, address));
1342
1343 /* ------- split adress ------------------ */
1344
1345 if (0 == strcmp(address, _("NULL")))
1346 {
1347 SL_RETURN( NULL, _("sh_mail_start_conn"));
1348 }
1349
1350 if (strchr (address, '@') == NULL) {
1351 (void) sl_strlcpy(ma_user, address, 256);
1352 (void) sl_strlcpy(ma_machine, _("localhost"), 256);
1353 } else {
1354 i = 0;
1355 while (i < 255 && address[i] != '@') {
1356 ma_user[i] = address[i];
1357 ++i;
1358 }
1359
1360 /* adress[i] = '@'
1361 */
1362 ma_user[i] = '\0';
1363 j = i + 1; k = i; i = 0;
1364 while (i < 255 && address[i+j] != '\0') {
1365 ma_machine[i] = address[i+j];
1366 ++i;
1367 }
1368 ma_machine[i] = '\0';
1369 if (address[k] != '@' || address[k+i+1] != '\0')
1370 {
1371 SL_RETURN( NULL, _("sh_mail_start_conn"));
1372 }
1373 }
1374
1375
1376 if (relay_host != NULL)
1377 {
1378 (void) sl_strlcpy (ma_machine, relay_host, sizeof(ma_machine));
1379 TPT((0, FIL__, __LINE__, _("msg=<user %s machine %s>\n"),
1380 ma_user, ma_machine));
1381 fd = connect_port (ma_machine, IPPORT_SMTP,
1382 error_call, &error_num, error_msg, 256);
1383 }
1384 else
1385 {
1386 answers = return_mx (ma_machine);
1387 if (answers)
1388 {
1389 result = answers->reply;
1390 fd = -1;
1391 for (i = 0; i < answers->count; ++i)
1392 {
1393 (void) sl_strlcpy(ma_machine, result[i].address,
1394 sizeof(ma_machine));
1395 TPT((0, FIL__, __LINE__,
1396 _("msg=<user %s mx %s pref %d>\n"),
1397 ma_user, ma_machine, result[i].pref));
1398 fd = connect_port (ma_machine, IPPORT_SMTP,
1399 error_call, &error_num, error_msg, 256);
1400 if (fd >= 0)
1401 break;
1402 }
1403 (void) free_mx(answers);
1404 }
1405 else
1406 {
1407 (void) sl_strlcpy(error_call, _("return_mx"), SH_MINIBUF);
1408 (void) sl_strlcpy(error_msg, _("The specified host is unknown: "),
1409 256);
1410 (void) sl_strlcat(error_msg, ma_machine, 256);
1411 fd = -1;
1412 }
1413 }
1414
1415
1416 if (fd < 0)
1417 {
1418 sh_error_handle ((-1), FIL__, __LINE__, error_num,
1419 MSG_E_NET, error_msg, error_call,
1420 _("email"), ma_machine);
1421 SL_RETURN( NULL, _("sh_mail_start_conn"));
1422 }
1423
1424 /* associate a FILE structure with it
1425 */
1426 connFile = fdopen (fd, "r+");
1427 if (connFile == NULL)
1428 {
1429 TPT(( 0, FIL__, __LINE__, _("msg=<fdopen() failed>\n")));
1430 (void) close(fd);
1431 SL_RETURN( NULL, _("sh_mail_start_conn"));
1432 }
1433
1434
1435 /* say HELO to the other socket
1436 */
1437 if (0 == sh_mail_wait (220, fd))
1438 {
1439 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1440 _("Timeout on SMTP session init"),
1441 _("sh_mail_start_conn"),
1442 _("mail"), sh.host.name);
1443 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout>\n")));
1444 (void) fclose(connFile);
1445 SL_RETURN( NULL, _("sh_mail_start_conn"));
1446 }
1447
1448 (void) fflush(connFile);
1449
1450 if (0 != is_numeric(sh.host.name))
1451 {
1452 TPT(( 0, FIL__, __LINE__, _("msg=<HELO [%s]>%c%c"),
1453 sh.host.name, 13, 10));
1454 }
1455 else
1456 {
1457 TPT(( 0, FIL__, __LINE__, _("msg=<HELO %s>%c%c"),
1458 sh.host.name, 13, 10));
1459 }
1460 if (0 != is_numeric(sh.host.name))
1461 fprintf(connFile, _("HELO [%s]%c%c"), sh.host.name, 13, 10);
1462 else
1463 fprintf(connFile, _("HELO %s%c%c"), sh.host.name, 13, 10);
1464
1465 (void) fflush(connFile);
1466
1467 if (0 == sh_mail_wait(250, fd))
1468 {
1469 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1470 _("HELO failed"), _("sh_mail_start_conn"),
1471 _("mail"), sh.host.name);
1472
1473 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1474 (void) fclose(connFile);
1475 SL_RETURN( NULL, _("sh_mail_start_conn"));
1476 }
1477
1478 /* tell them who we are
1479 */
1480 (void) sl_strlcpy (this_address,
1481 mail_sender ? mail_sender : DEFAULT_SENDER, 256);
1482 if (NULL == strchr(this_address, '@'))
1483 {
1484 (void) sl_strlcat (this_address, "@", 256);
1485 if (0 != is_numeric(sh.host.name))
1486 (void) sl_strlcat (this_address, _("example.com"), 256);
1487 else
1488 (void) sl_strlcat (this_address, sh.host.name, 256);
1489 }
1490
1491 TPT(( 0, FIL__, __LINE__, _("msg=<MAIL FROM:<%s>>%c%c"),
1492 this_address, 13, 10));
1493
1494 (void) fflush(connFile);
1495 /*@-usedef@*/
1496 fprintf(connFile, _("MAIL FROM:<%s>%c%c"), this_address, 13, 10);
1497 /*@+usedef@*/
1498 (void) fflush(connFile);
1499
1500 if (0 == sh_mail_wait(250, fd))
1501 {
1502 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1503 _("MAIL FROM failed"), _("sh_mail_start_conn"),
1504 _("mail"), this_address);
1505 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1506 (void) fclose(connFile);
1507 SL_RETURN( NULL, _("sh_mail_start_conn"));
1508 }
1509
1510 /* tell them who to send mail to
1511 */
1512 if (aFlag >= 0)
1513 {
1514 TPT(( 0, FIL__, __LINE__, _("msg=<RCPT TO:<%s>>%c%c"),
1515 address, 13, 10));
1516
1517 (void) fflush(connFile);
1518 fprintf(connFile, _("RCPT TO:<%s>%c%c"), address, 13, 10);
1519 (void) fflush(connFile);
1520
1521 if (0 == sh_mail_wait(250, fd))
1522 {
1523 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1524 _("RCPT TO failed"), _("sh_mail_start_conn"),
1525 _("mail"), address);
1526 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1527 (void) fclose(connFile);
1528 SL_RETURN( NULL, _("sh_mail_start_conn"));
1529 }
1530 }
1531 else
1532 {
1533 ecount = 0;
1534 for (i = 0; i < address_num; ++i)
1535 {
1536 if (address_list[i] == NULL) /* paranoia */
1537 break;
1538 TPT(( 0, FIL__, __LINE__, _("msg=<RCPT TO:<%s>>%c%c"),
1539 address_list[i], 13, 10));
1540
1541 (void) fflush(connFile);
1542 fprintf(connFile, _("RCPT TO:<%s>%c%c"), address_list[i], 13, 10);
1543 (void) fflush(connFile);
1544
1545 if (0 == sh_mail_wait(250, fd))
1546 {
1547 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1548 _("RCPT TO failed"), _("sh_mail_start_conn"),
1549 _("mail"), address_list[i]);
1550
1551 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1552 ++ecount;
1553 }
1554 }
1555 if (ecount == address_num)
1556 {
1557 (void) fclose(connFile);
1558 SL_RETURN( NULL, _("sh_mail_start_conn"));
1559 }
1560 }
1561
1562 /* Send the message
1563 */
1564 TPT(( 0, FIL__, __LINE__, _("msg=<DATA>%c%c"), 13, 10));
1565
1566 (void) fflush(connFile);
1567 fprintf(connFile, _("DATA%c%c"), 13, 10);
1568 (void) fflush(connFile);
1569
1570 if (0 == sh_mail_wait(354, fd))
1571 {
1572 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1573 _("DATA failed"), _("sh_mail_start_conn"),
1574 _("mail"), address);
1575 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1576 (void) fclose(connFile);
1577 SL_RETURN( NULL, _("sh_mail_start_conn"));
1578 }
1579
1580
1581 my_time = time(NULL);
1582#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
1583 my_tm = localtime_r(&my_time, &time_tm);
1584#else
1585 my_tm = localtime(&my_time);
1586#endif
1587 (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %Z"), my_tm);
1588
1589 TPT(( 0, FIL__, __LINE__, _("msg=<From: <%s>%c%cTo: <%s>%c%cDate: %s>%c%c"),
1590 this_address, 13, 10, address, 13, 10, my_tbuf, 13, 10));
1591
1592 (void) fflush(connFile);
1593 fprintf(connFile,
1594 _("From: <%s>%c%c"\
1595 "To: <%s>%c%c"\
1596 "Date: %s%c%c"),
1597 this_address, 13, 10,
1598 address, 13, 10,
1599 my_tbuf, 13, 10);
1600
1601 *ma_socket = fd;
1602 SL_RETURN( connFile, _("sh_mail_start_conn"));
1603}
1604
1605/*************************
1606 *
1607 * end connection
1608 *
1609 */
1610
1611static int sh_mail_end_conn (FILE * connFile, int fd)
1612{
1613 SL_ENTER(_("sh_mail_end_conn"));
1614
1615 time_wait = 300;
1616
1617 (void) fflush(connFile);
1618 fprintf(connFile, _("%c%c.%c%c"), 13, 10, 13, 10);
1619 (void) fflush(connFile);
1620
1621 TPT(( 0, FIL__, __LINE__, _("msg=<message end written>\n")));
1622
1623 if (0 != sh_mail_wait(250, fd))
1624 {
1625 (void) fflush(connFile);
1626 fprintf(connFile, _("QUIT%c%c"), 13, 10);
1627 (void) fflush(connFile);
1628 TPT(( 0, FIL__, __LINE__, _("msg=<exit>\n")));
1629
1630 SL_RETURN (0, _("sh_mail_end_conn"));
1631 }
1632
1633 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1634 _("QUIT failed"), _("sh_mail_end_conn"),
1635 _("mail"), _("SMTP server"));
1636
1637 TPT(( 0, FIL__, __LINE__, _("msg=<abnormal exit>\n")));
1638
1639 SL_RETURN ((-1), _("sh_mail_end_conn"));
1640}
1641
1642
1643
1644/****************************
1645 *
1646 * Handle server replies
1647 *
1648 *
1649 */
1650
1651static int sh_mail_wait(int code, int ma_socket)
1652{
1653 int rcode, g;
1654
1655 char c;
1656
1657 char errmsg[128];
1658
1659 enum {
1660 WAIT_CODE_START,
1661 WAIT_CODE,
1662 WAIT_NL,
1663 WAIT_NL_CONT
1664 } state;
1665
1666 time_t waited_time;
1667
1668 SL_ENTER(_("mail_wait"));
1669
1670 waited_time = time(NULL);
1671
1672 /* timeout after 5 minutes
1673 */
1674
1675 rcode = 0;
1676 state = WAIT_CODE_START;
1677
1678 while (sl_read_timeout_fd (ma_socket, &c, 1, time_wait, SL_FALSE) > 0) {
1679
1680 g = (int) c;
1681
1682 if ( (g=fgetc(ma_socket)) == EOF)
1683 {
1684 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: EOF>\n")));
1685 SL_RETURN( 0, _("mail_wait"));
1686 }
1687
1688 switch(state) {
1689
1690 /* wait for start of a numerical code
1691 */
1692 case WAIT_CODE_START:
1693 if (0 != isspace(g))
1694 break; /* Skip white space */
1695 if (0 == isdigit(g))
1696 return 0; /* No leading number */
1697 rcode = g-(int)'0'; /* convert to number */
1698 state = WAIT_CODE;
1699 break;
1700
1701 /* wait for completion of numerical code
1702 */
1703 case WAIT_CODE:
1704 if (0 != isdigit(g)) {
1705 rcode = rcode * 10 + (g-(int)'0'); /* next digit */
1706 break;
1707 }
1708 /*@+charintliteral@*/
1709 state = ((g == '-') ? WAIT_NL_CONT : WAIT_NL);
1710 /*@-charintliteral@*/
1711 break;
1712
1713 /* wait for newline, then return with status code
1714 */
1715 case WAIT_NL:
1716 /*@+charintliteral@*/
1717 if (g != '\n')
1718 break;
1719 /*@-charintliteral@*/
1720
1721 TPT((0, FIL__, __LINE__,
1722 _("msg=<mail_wait: OK got %d (%d) need %d (%d)>\n"),
1723 rcode, (int)(rcode/100), code, (int)(code/100) ));
1724 g = ((int)(rcode/100) == (int)(code/100)) ? 1 : 0;
1725 if (g != 1)
1726 {
1727 sl_snprintf(errmsg, sizeof(errmsg),
1728 _("Bad response (%d), expected %d"), rcode, code);
1729
1730 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1731 errmsg, _("sh_mail_wait"),
1732 _("mail"), _("SMTP server"));
1733 }
1734 waited_time = time(NULL) - waited_time;
1735 time_wait -= waited_time;
1736 TPT((0, FIL__, __LINE__,
1737 _("msg=<mail_wait: time_wait reduced to %d sec>\n"),
1738 (int) time_wait));
1739 SL_RETURN( (g), _("mail_wait")) ;
1740
1741 /* wait for continuation line
1742 */
1743 /*@fallthrough@*//* no, but splint doesn't understand */
1744 case WAIT_NL_CONT:
1745 /*@+charintliteral@*/
1746 if (g == '\n')
1747 state = WAIT_CODE_START; /* There is a continuation line */
1748 /*@-charintliteral@*/
1749 break;
1750
1751 default:
1752
1753 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: bad>\n")));
1754 SL_RETURN( 0, _("mail_wait"));
1755
1756 }
1757 }
1758
1759 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: failed>\n")));
1760
1761 /* Failed, EOF or error on socket */
1762 SL_RETURN( 0, _("mail_wait"));
1763}
1764
1765/* -- function to insert "\r\n" after each 998 chars --
1766 */
1767
1768#define SPLIT_AT 998
1769
1770static char * split_string(char * str)
1771{
1772 size_t size;
1773 size_t blocks;
1774 int count = 0;
1775
1776 char * p, * p0;
1777 char * q;
1778
1779 if (!str)
1780 return NULL;
1781
1782 size = strlen(str) + 1;
1783 blocks = 1 + (size / SPLIT_AT);
1784
1785 if (sl_ok_muls(2, blocks) && sl_ok_adds(size, (2*blocks)))
1786 {
1787 size = size + (2*blocks);
1788 }
1789 else
1790 {
1791 /* integer overflow, do not split */
1792 p = sh_util_strdup(str);
1793 return p;
1794 }
1795
1796 p = SH_ALLOC(size);
1797 memset(p, 0, size);
1798
1799 p0 = p;
1800
1801 q = str;
1802 while (*q != '\0') {
1803 *p = *q;
1804 ++p;
1805 ++q;
1806 ++count;
1807 if (0 == (count % SPLIT_AT)) {
1808 count = 0;
1809 *p = '\r';
1810 ++p;
1811 *p = '\n';
1812 ++p;
1813 }
1814 }
1815 /* fprintf(stderr, "used = %d\n", strlen(p0)); */
1816
1817 return p0;
1818}
1819
1820
1821
1822/*****************************************************************
1823 *
1824 * MX Resolver Routines
1825 *
1826 *****************************************************************/
1827
1828#if defined(HAVE_ARPA_NAMESER_H)
1829
1830#include <netinet/in.h>
1831#ifdef __APPLE__
1832#define BIND_8_COMPAT 1
1833#endif
1834#ifndef S_SPLINT_S
1835#include <arpa/nameser.h>
1836#include <resolv.h>
1837#endif
1838#include <netdb.h>
1839#include <sys/socket.h>
1840#ifndef S_SPLINT_S
1841#include <arpa/inet.h>
1842#endif
1843
1844#include "sh_tools.h"
1845
1846#ifndef HFIXEDSZ
1847#define HFIXEDSZ 12
1848#endif
1849#ifndef QFIXEDSZ
1850#define QFIXEDSZ 4
1851#endif
1852
1853/*@unused@*//* used in get_mx() which is not parsed by splint */
1854static unsigned int get_short (unsigned char * loc)
1855{
1856 unsigned int retval = 0;
1857 if (loc)
1858 {
1859 /* byte order: MSB first
1860 */
1861 /*@+charint@*/
1862 retval = (((unsigned char) * loc) * 256) | ((unsigned char) * (loc + 1));
1863 /*@-charint@*/
1864 }
1865 return (retval);
1866}
1867
1868/* parser errors with splint */
1869#ifndef S_SPLINT_S
1870static dnsrep * get_mx (char *hostname)
1871{
1872 int ret, length, status;
1873 mx * result;
1874 size_t len;
1875
1876 typedef union
1877 {
1878 HEADER head;
1879 unsigned char buffer[4096];
1880 } querybuf;
1881
1882 querybuf reply;
1883 char expanded[1024];
1884 unsigned char * comp_dn, * eom;
1885 HEADER * header;
1886 int type, rdlength, pref;
1887 unsigned int count, index;
1888 dnsrep * retval;
1889
1890 SL_ENTER(_("get_mx"));
1891
1892 if (0 != res_init ())
1893 SL_RETURN (NULL, _("get_mx"));
1894
1895 errno = 0;
1896 length = res_query (hostname, C_IN, T_MX,
1897 (unsigned char *) &reply, 4095);
1898 if (length < 1)
1899 {
1900 char errbuf[SH_ERRBUF_SIZE];
1901
1902 /* error handling
1903 */
1904 if (length == -1)
1905 {
1906 if (errno == ECONNREFUSED)
1907 status = ECONNREFUSED;
1908 else
1909 status = h_errno;
1910
1911#ifdef FIL__
1912 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
1913 (errno == ECONNREFUSED) ?
1914 sh_error_message (status, errbuf, sizeof(errbuf)) :
1915 sh_tools_errmessage(status, errbuf, sizeof(errbuf)),
1916 _("res_query"));
1917#else
1918 if (errno == ECONNREFUSED)
1919 fprintf(stderr, " ERROR: %s: \n", strerror(errno)); /* TESTONLY */
1920 else
1921 fprintf(stderr, "HERROR: %s\n", hstrerror(h_errno));/* TESTONLY */
1922#endif
1923 }
1924 SL_RETURN (NULL, _("get_mx"));
1925 }
1926
1927 ret = 0;
1928 header = (HEADER *) &reply;
1929
1930 /* start of data section
1931 */
1932 comp_dn = (unsigned char *) &reply + HFIXEDSZ;
1933
1934 /* end-of-message
1935 */
1936 eom = (unsigned char *) &reply + length;
1937
1938 /* HEADER NAME -- must be skipped or decompressed
1939 * TYPE -- type of data we got back, 16 bit integer
1940 * CLASS -- class we got back, also a 16 bit integer
1941 * TTL -- 32 bit time-to-live. just skip this
1942 * RDLENGTH -- length of the data to follow
1943 * RDATA -- the data:
1944 * PREF -- 16 bit preference
1945 * MX -- name of mail exchanger, must be decompressed
1946 */
1947
1948 /* Skip the query data.
1949 * QDCOUNT is the number of entries (unsigned 16 bit int).
1950 */
1951 count = ntohs (header->qdcount);
1952 for (index = 0; index < count; ++index)
1953 {
1954 ret = dn_skipname (comp_dn, eom);
1955 comp_dn += ret + QFIXEDSZ;
1956 if (ret < 1 || comp_dn >= eom)
1957 SL_RETURN (NULL, _("get_mx"));
1958 }
1959 count = ntohs (header->ancount);
1960 if (count < 1)
1961 SL_RETURN (NULL, _("get_mx"));
1962
1963 retval = SH_ALLOC (sizeof (dnsrep));
1964 if (!retval)
1965 SL_RETURN (NULL, _("get_mx"));
1966 retval->count = count;
1967
1968 /* allocate space for the results */
1969
1970 if (!sl_ok_muls(count, sizeof (mx)))
1971 {
1972 SH_FREE (retval);
1973 SL_RETURN (NULL, _("get_mx"));
1974 }
1975
1976 result = SH_ALLOC (count * sizeof (mx));
1977
1978 if (!result)
1979 {
1980 SH_FREE (retval);
1981 SL_RETURN (NULL, _("get_mx"));
1982 }
1983 retval->reply = result;
1984
1985 do
1986 {
1987 /* HEADER NAME
1988 */
1989 ret = dn_expand ((unsigned char *) &reply, eom, comp_dn,
1990 (char *) expanded, 1023);
1991 comp_dn += ret;
1992 if (ret < 1 || comp_dn >= eom)
1993 {
1994 SH_FREE (result);
1995 SH_FREE (retval);
1996 SL_RETURN (NULL, _("get_mx"));
1997 }
1998
1999 /* TYPE
2000 */
2001 type = get_short (comp_dn);
2002 comp_dn += 2;
2003 if (type != T_MX || comp_dn >= eom)
2004 {
2005 SH_FREE (result);
2006 SH_FREE (retval);
2007 SL_RETURN (NULL, _("get_mx"));
2008 }
2009
2010 /* CLASS (re-use 'type' var)
2011 */
2012 type = get_short (comp_dn);
2013 comp_dn += 2;
2014 if (comp_dn >= eom)
2015 {
2016 SH_FREE (result);
2017 SH_FREE (retval);
2018 SL_RETURN (NULL, _("get_mx"));
2019 }
2020
2021 /* TTL
2022 */
2023 comp_dn += 4;
2024 if (comp_dn >= eom)
2025 {
2026 SH_FREE (result);
2027 SH_FREE (retval);
2028 SL_RETURN (NULL, _("get_mx"));
2029 }
2030
2031 /* RDLENGTH
2032 */
2033 rdlength = get_short (comp_dn);
2034 comp_dn += 2;
2035 if (rdlength < 1 || comp_dn >= eom)
2036 {
2037 SH_FREE (result);
2038 SH_FREE (retval);
2039 SL_RETURN (NULL, _("get_mx"));
2040 }
2041
2042 /* RDATA
2043 */
2044 pref = get_short (comp_dn);
2045 comp_dn += 2;
2046 if (comp_dn >= eom)
2047 {
2048 SH_FREE (result);
2049 SH_FREE (retval);
2050 SL_RETURN (NULL, _("get_mx"));
2051 }
2052
2053 ret = dn_expand ((unsigned char *) &reply, eom, comp_dn,
2054 (char *) expanded, 1023);
2055 comp_dn += ret;
2056 if (ret < 1)
2057 {
2058 SH_FREE (result);
2059 SH_FREE (retval);
2060 SL_RETURN (NULL, _("get_mx"));
2061 }
2062 count--;
2063
2064 /* fill in the struct
2065 */
2066 result[count].pref = pref;
2067 len = strlen (expanded) + 1;
2068 result[count].address = SH_ALLOC (len);
2069 sl_strlcpy (result[count].address, expanded, len);
2070 }
2071 while (ret > 0 && comp_dn < eom && count);
2072
2073 SL_RETURN (retval, _("get_mx"));
2074}
2075/* ifndef S_SPLINT_S */
2076#endif
2077
2078/* #if defined(HAVE_ARPA_NAMESER_H) */
2079#endif
2080
2081
2082static int comp_mx_pref (const void * a, const void * b)
2083{
2084 const mx * ax = (const mx *) a;
2085 const mx * bx = (const mx *) b;
2086
2087 if (ax->pref > bx->pref)
2088 return 1;
2089 else if (ax->pref < bx->pref)
2090 return -1;
2091 else
2092 return 0;
2093}
2094
2095/*
2096 * return_mx returns a list of valid mail exchangers for domain
2097 */
2098static dnsrep * return_mx (char *domain)
2099{
2100 struct hostent *host = NULL;
2101 dnsrep * answers = NULL;
2102 mx * result;
2103 dnsrep * retval;
2104 char errmsg[128];
2105 size_t len;
2106
2107 SL_ENTER(_("return_mx"));
2108
2109#if defined(HAVE_ARPA_NAMESER_H)
2110 if (domain != NULL)
2111 answers = /*@-unrecog@*/get_mx (domain)/*@+unrecog@*/;
2112#endif
2113
2114 if (answers != NULL && answers->count > 0)
2115 {
2116 qsort(answers->reply, (size_t) answers->count, sizeof(mx),
2117 comp_mx_pref);
2118 SL_RETURN (answers, _("return_mx"));
2119 }
2120 else
2121 {
2122 if (domain != NULL)
2123 {
2124#if defined(HAVE_ARPA_NAMESER_H)
2125#ifdef FIL__
2126 (void) sl_strlcpy (errmsg, _("No MX record for domain "), 127);
2127 (void) sl_strlcat (errmsg, domain, 127);
2128 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
2129 errmsg,
2130 _("get_mx"));
2131#else
2132 /* flawfinder: ignore *//* test code only */
2133 strcpy (errmsg, /* known to fit */
2134 _("No MX record for domain "));
2135 strncat (errmsg, domain, 100);
2136 errmsg[122] = '\0';
2137 fprintf(stderr, "Warning: %s\n", errmsg);
2138#endif
2139#endif
2140 }
2141
2142 SH_MUTEX_LOCK(mutex_resolv);
2143 if (domain != NULL)
2144 host = /*@-unrecog@*/sh_gethostbyname (domain)/*@+unrecog@*/;
2145
2146 if (host)
2147 {
2148 result = SH_ALLOC (sizeof (mx));
2149 retval = SH_ALLOC (sizeof (dnsrep));
2150 retval->reply = result;
2151 retval->count = 1;
2152 result->pref = 0;
2153 /*@-type@*/
2154 len = strlen (host->h_name) + 1;
2155 result->address = SH_ALLOC (len);
2156 sl_strlcpy (result->address, host->h_name, len);
2157 /*@+type@*/
2158 }
2159 SH_MUTEX_UNLOCK(mutex_resolv);
2160
2161 if (!host)
2162 {
2163#ifdef FIL__
2164 (void) sl_strlcpy (errmsg, _("Unknown host "), 127);
2165 (void) sl_strlcat (errmsg, domain, 127);
2166 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
2167 errmsg,
2168 _("return_mx"));
2169#endif
2170 SL_RETURN (NULL, _("return_mx"));
2171 }
2172
2173 SL_RETURN (retval, _("return_mx"));
2174 }
2175}
2176
2177static int free_mx (dnsrep * answers)
2178{
2179 mx * result;
2180 int i;
2181
2182 SL_ENTER(_("free_mx"));
2183 if (!answers)
2184 SL_RETURN (0, _("return_mx"));
2185
2186 result = answers->reply;
2187 for (i = 0; i < answers->count; ++i)
2188 {
2189 SH_FREE (result[i].address);
2190 }
2191 SH_FREE(result);
2192 SH_FREE(answers);
2193 SL_RETURN (0, _("return_mx"));
2194}
2195
2196#ifdef TEST_ONLY
2197int main(int argc, char * argv[])
2198{
2199 int i;
2200 dnsrep * answers;
2201 mx * result;
2202
2203 if (argc < 2)
2204 {
2205 fprintf(stderr, "Usage: dns <hostname>\n");
2206 return -1;
2207 }
2208 answers = return_mx(argv[1]);
2209
2210 if (!answers)
2211 {
2212 fprintf(stderr, "No answer\n");
2213 return -1;
2214 }
2215
2216 if (answers->count > 0)
2217 {
2218 result = answers->reply;
2219 for (i = 0; i < answers->count; ++i)
2220 {
2221 fprintf(stderr, "Record %3d: [%3d] %s\n", i,
2222 result[i].pref, result[i].address);
2223 }
2224 }
2225 else
2226 {
2227 fprintf(stderr, "No answer\n");
2228 free_mx(answers);
2229 return -1;
2230 }
2231 free_mx(answers);
2232 return (0);
2233}
2234#endif
2235
2236
2237
2238/* if defined(SH_WITH_MAIL) */
2239#endif
2240
2241
2242
Note: See TracBrowser for help on using the repository browser.