source: trunk/src/sh_mail.c@ 309

Last change on this file since 309 was 295, checked in by katerina, 14 years ago

Support for IPv6 (ticket #222).

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