source: trunk/src/sh_mail.c@ 265

Last change on this file since 265 was 252, checked in by katerina, 15 years ago

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

File size: 44.1 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 (FIL__, __LINE__, 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) sl_fclose (FIL__, __LINE__, 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) sl_fclose (FIL__, __LINE__, 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) sl_close_fd(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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) sl_fclose(FIL__, __LINE__, 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
1587 if (length < 1)
1588 {
1589 char errbuf[SH_ERRBUF_SIZE];
1590
1591 /* error handling
1592 */
1593 if (length == -1)
1594 {
1595 if (errno == ECONNREFUSED)
1596 status = ECONNREFUSED;
1597 else
1598 status = h_errno;
1599
1600#ifdef FIL__
1601 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
1602 (errno == ECONNREFUSED) ?
1603 sh_error_message (status, errbuf, sizeof(errbuf)) :
1604 sh_tools_errmessage(status, errbuf, sizeof(errbuf)),
1605 _("res_query"));
1606#else
1607 if (errno == ECONNREFUSED)
1608 fprintf(stderr, " ERROR: %s: \n", strerror(errno)); /* TESTONLY */
1609 else
1610 fprintf(stderr, "HERROR: %s\n", hstrerror(h_errno));/* TESTONLY */
1611#endif
1612 }
1613 SH_FREE(reply);
1614 SL_RETURN (NULL, _("get_mx"));
1615 }
1616
1617 ret = 0;
1618 header = (HEADER *) reply;
1619
1620 /* start of data section
1621 */
1622 comp_dn = (unsigned char *) reply + HFIXEDSZ;
1623
1624 /* end-of-message
1625 */
1626 eom = (unsigned char *) reply + length;
1627
1628 /* HEADER NAME -- must be skipped or decompressed
1629 * TYPE -- type of data we got back, 16 bit integer
1630 * CLASS -- class we got back, also a 16 bit integer
1631 * TTL -- 32 bit time-to-live. just skip this
1632 * RDLENGTH -- length of the data to follow
1633 * RDATA -- the data:
1634 * PREF -- 16 bit preference
1635 * MX -- name of mail exchanger, must be decompressed
1636 */
1637
1638 /* Skip the query data.
1639 * QDCOUNT is the number of entries (unsigned 16 bit int).
1640 */
1641 count = ntohs (header->qdcount);
1642 for (theindex = 0; theindex < count; ++theindex)
1643 {
1644 ret = dn_skipname (comp_dn, eom);
1645 comp_dn += ret + QFIXEDSZ;
1646 if (ret < 1 || comp_dn >= eom)
1647 {
1648 SH_FREE(reply);
1649 SL_RETURN (NULL, _("get_mx"));
1650 }
1651 }
1652
1653 count = ntohs (header->ancount);
1654 if (count < 1)
1655 {
1656 SH_FREE(reply);
1657 SL_RETURN (NULL, _("get_mx"));
1658 }
1659
1660 retval = SH_ALLOC (sizeof (dnsrep));
1661 if (!retval)
1662 {
1663 SH_FREE(reply);
1664 SL_RETURN (NULL, _("get_mx"));
1665 }
1666
1667 retval->count = count;
1668
1669 /* allocate space for the results */
1670
1671 if (!sl_ok_muls(count, sizeof (mx)))
1672 {
1673 SH_FREE(reply);
1674 SH_FREE (retval);
1675 SL_RETURN (NULL, _("get_mx"));
1676 }
1677
1678 result = SH_ALLOC (count * sizeof (mx));
1679
1680 if (!result)
1681 {
1682 SH_FREE(reply);
1683 SH_FREE (retval);
1684 SL_RETURN (NULL, _("get_mx"));
1685 }
1686 retval->reply = result;
1687
1688 do
1689 {
1690 /* HEADER NAME
1691 */
1692 ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
1693 (char *) expanded, 1023);
1694 comp_dn += ret;
1695 if (ret < 1 || comp_dn >= eom)
1696 {
1697 SH_FREE(reply);
1698 SH_FREE (result);
1699 SH_FREE (retval);
1700 SL_RETURN (NULL, _("get_mx"));
1701 }
1702
1703 /* TYPE
1704 */
1705 type = get_short (comp_dn);
1706 comp_dn += 2;
1707 if (type != T_MX || comp_dn >= eom)
1708 {
1709 SH_FREE(reply);
1710 SH_FREE (result);
1711 SH_FREE (retval);
1712 SL_RETURN (NULL, _("get_mx"));
1713 }
1714
1715
1716 /* CLASS (re-use 'type' var)
1717 */
1718 type = get_short (comp_dn);
1719 comp_dn += 2;
1720 if (comp_dn >= eom)
1721 {
1722 SH_FREE(reply);
1723 SH_FREE (result);
1724 SH_FREE (retval);
1725 SL_RETURN (NULL, _("get_mx"));
1726 }
1727
1728
1729 /* TTL
1730 */
1731 comp_dn += 4;
1732 if (comp_dn >= eom)
1733 {
1734 SH_FREE(reply);
1735 SH_FREE (result);
1736 SH_FREE (retval);
1737 SL_RETURN (NULL, _("get_mx"));
1738 }
1739
1740 /* RDLENGTH
1741 */
1742 rdlength = get_short (comp_dn);
1743 comp_dn += 2;
1744 if (rdlength < 1 || comp_dn >= eom)
1745 {
1746 SH_FREE(reply);
1747 SH_FREE (result);
1748 SH_FREE (retval);
1749 SL_RETURN (NULL, _("get_mx"));
1750 }
1751
1752 /* RDATA
1753 */
1754 pref = get_short (comp_dn);
1755 comp_dn += 2;
1756 if (comp_dn >= eom)
1757 {
1758 SH_FREE(reply);
1759 SH_FREE (result);
1760 SH_FREE (retval);
1761 SL_RETURN (NULL, _("get_mx"));
1762 }
1763
1764 ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
1765 (char *) expanded, 1023);
1766 comp_dn += ret;
1767 if (ret < 1)
1768 {
1769 SH_FREE(reply);
1770 SH_FREE (result);
1771 SH_FREE (retval);
1772 SL_RETURN (NULL, _("get_mx"));
1773 }
1774 count--;
1775
1776 /* fill in the struct
1777 */
1778 result[count].pref = pref;
1779 len = strlen (expanded) + 1;
1780 result[count].address = SH_ALLOC (len);
1781 sl_strlcpy (result[count].address, expanded, len);
1782 }
1783 while (ret > 0 && comp_dn < eom && count);
1784
1785 SH_FREE(reply);
1786 SL_RETURN (retval, _("get_mx"));
1787}
1788/* ifndef S_SPLINT_S */
1789#endif
1790
1791/* #if defined(HAVE_ARPA_NAMESER_H) */
1792#endif
1793
1794
1795static int comp_mx_pref (const void * a, const void * b)
1796{
1797 const mx * ax = (const mx *) a;
1798 const mx * bx = (const mx *) b;
1799
1800 if (ax->pref > bx->pref)
1801 return 1;
1802 else if (ax->pref < bx->pref)
1803 return -1;
1804 else
1805 return 0;
1806}
1807
1808/*
1809 * return_mx returns a list of valid mail exchangers for domain
1810 */
1811static dnsrep * return_mx (char *domain)
1812{
1813 struct hostent *host;
1814 dnsrep * answers = NULL;
1815 mx * result;
1816 dnsrep * retval;
1817 char errmsg[128];
1818 size_t len;
1819
1820 SL_ENTER(_("return_mx"));
1821
1822#if defined(HAVE_ARPA_NAMESER_H)
1823 if (domain != NULL)
1824 answers = /*@-unrecog@*/get_mx (domain)/*@+unrecog@*/;
1825#endif
1826
1827 if (answers != NULL && answers->count > 0)
1828 {
1829 qsort(answers->reply, (size_t) answers->count, sizeof(mx),
1830 comp_mx_pref);
1831 SL_RETURN (answers, _("return_mx"));
1832 }
1833 else
1834 {
1835 if (domain != NULL)
1836 {
1837#if defined(HAVE_ARPA_NAMESER_H)
1838#ifdef FIL__
1839 (void) sl_strlcpy (errmsg, _("No MX record for domain "), 127);
1840 (void) sl_strlcat (errmsg, domain, 127);
1841 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1842 errmsg,
1843 _("get_mx"));
1844#else
1845 /* flawfinder: ignore *//* test code only */
1846 strcpy (errmsg, /* known to fit */
1847 _("No MX record for domain "));
1848 strncat (errmsg, domain, 100);
1849 errmsg[122] = '\0';
1850 fprintf(stderr, "Warning: %s\n", errmsg);
1851#endif
1852#endif
1853 }
1854
1855 SH_MUTEX_LOCK(mutex_resolv);
1856
1857 host = NULL;
1858 retval = NULL;
1859
1860 if (domain != NULL)
1861 host = /*@-unrecog@*/sh_gethostbyname (domain)/*@+unrecog@*/;
1862
1863 if (host)
1864 {
1865 result = SH_ALLOC (sizeof (mx));
1866 retval = SH_ALLOC (sizeof (dnsrep));
1867 retval->reply = result;
1868 retval->count = 1;
1869 result->pref = 0;
1870 /*@-type@*/
1871 len = strlen (host->h_name) + 1;
1872 result->address = SH_ALLOC (len);
1873 sl_strlcpy (result->address, host->h_name, len);
1874 /*@+type@*/
1875 }
1876 SH_MUTEX_UNLOCK(mutex_resolv);
1877
1878 if (!host)
1879 {
1880#ifdef FIL__
1881 (void) sl_strlcpy (errmsg, _("Unknown host "), 127);
1882 (void) sl_strlcat (errmsg, domain, 127);
1883 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1884 errmsg,
1885 _("return_mx"));
1886#endif
1887 SL_RETURN (NULL, _("return_mx"));
1888 }
1889
1890 SL_RETURN (retval, _("return_mx"));
1891 }
1892}
1893
1894int free_mx (dnsrep * answers)
1895{
1896 mx * result;
1897 int i;
1898
1899 SL_ENTER(_("free_mx"));
1900 if (!answers)
1901 SL_RETURN (0, _("return_mx"));
1902
1903 result = answers->reply;
1904 for (i = 0; i < answers->count; ++i)
1905 {
1906 SH_FREE (result[i].address);
1907 }
1908 SH_FREE(result);
1909 SH_FREE(answers);
1910 SL_RETURN (0, _("return_mx"));
1911}
1912
1913#ifdef TEST_ONLY
1914int main(int argc, char * argv[])
1915{
1916 int i;
1917 dnsrep * answers;
1918 mx * result;
1919
1920 if (argc < 2)
1921 {
1922 fprintf(stderr, "Usage: dns <hostname>\n");
1923 return -1;
1924 }
1925 answers = return_mx(argv[1]);
1926
1927 if (!answers)
1928 {
1929 fprintf(stderr, "No answer\n");
1930 return -1;
1931 }
1932
1933 if (answers->count > 0)
1934 {
1935 result = answers->reply;
1936 for (i = 0; i < answers->count; ++i)
1937 {
1938 fprintf(stderr, "Record %3d: [%3d] %s\n", i,
1939 result[i].pref, result[i].address);
1940 }
1941 }
1942 else
1943 {
1944 fprintf(stderr, "No answer\n");
1945 free_mx(answers);
1946 return -1;
1947 }
1948 free_mx(answers);
1949 return (0);
1950}
1951#endif
1952
1953
1954
1955/* if defined(SH_WITH_MAIL) */
1956#endif
1957
1958
1959
Note: See TracBrowser for help on using the repository browser.