source: trunk/src/sh_mail.c@ 239

Last change on this file since 239 was 238, checked in by katerina, 15 years ago

Fix timezone format in email date header (ticket #158).

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