source: trunk/src/sh_mail.c@ 183

Last change on this file since 183 was 171, checked in by katerina, 16 years ago

Include dnmalloc (ticket #108) and fix bugs #106 (EINPROGRESS) and #107 (compressBound).

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