source: trunk/src/sh_mail.c@ 28

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

Minor code revisions.

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