source: trunk/src/sh_mail.c@ 20

Last change on this file since 20 was 20, checked in by rainer, 19 years ago

Enable command-line parsing for prelude, and make prelude regression test safer.

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