source: trunk/src/sh_mail.c@ 278

Last change on this file since 278 was 275, checked in by katerina, 15 years ago

Fix for ticket #195 (broken immediate mailing of highest priority messages).

File size: 44.9 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <pwd.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <errno.h>
31#include <signal.h>
32#include <setjmp.h>
33
34#if defined(SH_WITH_MAIL)
35
36#if TIME_WITH_SYS_TIME
37#include <sys/time.h>
38#include <time.h>
39#else
40#if HAVE_SYS_TIME_H
41#include <sys/time.h>
42#else
43#include <time.h>
44#endif
45#endif
46
47
48#ifdef HAVE_MEMORY_H
49#include <memory.h>
50#endif
51
52#include "samhain.h"
53#include "sh_error.h"
54#include "sh_unix.h"
55#include "sh_tiger.h"
56#include "sh_mail.h"
57#include "sh_utils.h"
58#include "sh_fifo.h"
59#include "sh_tools.h"
60#include "sh_pthread.h"
61#include "sh_filter.h"
62#include "sh_mail_int.h"
63#include "sh_nmail.h"
64
65#undef FIL__
66#define FIL__ _("sh_mail.c")
67#undef GOOD
68#undef BAD
69
70static int failedMail = SL_FALSE;
71
72static dnsrep * return_mx (char *domain);
73
74/*********************************************
75 * utility function for verifying mails
76 *********************************************/
77
78typedef struct mail_trail_struct {
79 char trail_id[2*SH_MINIBUF];
80 char trail_key[KEY_LEN+1];
81 struct mail_trail_struct * next;
82} mail_trail_type;
83
84static mail_trail_type * mail_trail = NULL;
85
86int sh_mail_sigverify (const char * s)
87{
88 SL_TICKET fd;
89 long i;
90 char * buf;
91 char * bufc;
92 char key[81];
93 char number[2*SH_MINIBUF];
94 char audit_id[2 * SH_MINIBUF];
95 long numsig;
96 char key2[KEY_LEN+1];
97
98 char * theSig;
99
100 mail_trail_type * mail_trail_ptr = NULL;
101
102 sh_error_logoff();
103
104 ASSERT((s != NULL && sl_strlen(s) < PATH_MAX),
105 _("(s != NULL && sl_strlen(s) < PATH_MAX)"));
106
107 if (s == NULL || sl_strlen(s) >= PATH_MAX)
108 _exit (EXIT_FAILURE);
109
110 /* open the file, then check it
111 */
112 if (0 != sl_is_suid())
113 {
114 fprintf(stderr, _("Cannot open file %s in suid mode\n"), s);
115 _exit (EXIT_FAILURE);
116 }
117 if ( SL_ISERROR(fd = sl_open_read (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((-2), _("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 = -3;
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;
949static void report_smtp (char * reply);
950
951static FILE * sh_mail_start_conn (struct alias * ma_address,
952 int * ma_socket, int * anum)
953{
954 char * address;
955 int aFlag = 0;
956
957 int ecount;
958
959 char this_address[256];
960 char ma_machine[256];
961 char ma_user[256];
962 char error_msg[256];
963 char error_call[SH_MINIBUF];
964 int error_num = 0;
965 register int i, j, k;
966 FILE * connFile = NULL;
967 struct tm * my_tm;
968#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
969 struct tm time_tm;
970#endif
971 time_t my_time;
972 char my_tbuf[128];
973
974 int fd;
975
976 dnsrep * answers;
977 mx * result;
978
979 SL_ENTER(_("sh_mail_start_conn"));
980
981 *ma_socket = -1;
982 time_wait = 300;
983
984 if (ma_address == NULL)
985 {
986 aFlag = 1;
987 ma_address = all_recipients;
988
989 while (ma_address)
990 {
991 if (ma_address->send_mail == 1)
992 break;
993 ma_address = ma_address->all_next;
994 }
995 }
996
997 if (!ma_address)
998 {
999 SL_RETURN( NULL, _("sh_mail_start_conn"));
1000 }
1001
1002 address = sh_string_str(ma_address->recipient);
1003
1004 TPT(( 0, FIL__, __LINE__, _("msg=<address %s>\n"),
1005 address));
1006
1007 /* ------- split adress ------------------ */
1008
1009 if (strchr (address, '@') == NULL) {
1010 (void) sl_strlcpy(ma_user, address, 256);
1011 (void) sl_strlcpy(ma_machine, _("localhost"), 256);
1012 } else {
1013 i = 0;
1014 while (i < 255 && address[i] != '@') {
1015 ma_user[i] = address[i];
1016 ++i;
1017 }
1018
1019 /* adress[i] = '@'
1020 */
1021 ma_user[i] = '\0';
1022 j = i + 1; k = i; i = 0;
1023 while (i < 255 && address[i+j] != '\0') {
1024 ma_machine[i] = address[i+j];
1025 ++i;
1026 }
1027 ma_machine[i] = '\0';
1028 if (address[k] != '@' || address[k+i+1] != '\0')
1029 {
1030 SL_RETURN( NULL, _("sh_mail_start_conn"));
1031 }
1032 }
1033
1034
1035 if (relay_host != NULL)
1036 {
1037 (void) sl_strlcpy (ma_machine, relay_host, sizeof(ma_machine));
1038 TPT((0, FIL__, __LINE__, _("msg=<user %s machine %s>\n"),
1039 ma_user, ma_machine));
1040 fd = connect_port (ma_machine, sh_mail_port,
1041 error_call, &error_num, error_msg, 256);
1042 }
1043 else
1044 {
1045 answers = ma_address->mx_list;
1046 if (!answers)
1047 {
1048 answers = return_mx (ma_machine);
1049 ma_address->mx_list = answers;
1050 }
1051
1052 if (answers)
1053 {
1054 result = answers->reply;
1055 fd = -1;
1056 for (i = 0; i < answers->count; ++i)
1057 {
1058 (void) sl_strlcpy(ma_machine, result[i].address,
1059 sizeof(ma_machine));
1060 TPT((0, FIL__, __LINE__,
1061 _("msg=<user %s mx %s pref %d>\n"),
1062 ma_user, ma_machine, result[i].pref));
1063 fd = connect_port (ma_machine, sh_mail_port,
1064 error_call, &error_num, error_msg, 256);
1065 if (fd >= 0)
1066 break;
1067 }
1068 }
1069 else
1070 {
1071 (void) sl_strlcpy(error_call, _("return_mx"), SH_MINIBUF);
1072 (void) sl_strlcpy(error_msg, _("The specified host is unknown: "),
1073 256);
1074 (void) sl_strlcat(error_msg, ma_machine, 256);
1075 fd = -1;
1076 }
1077 }
1078
1079
1080 if (fd < 0)
1081 {
1082 sh_error_handle ((-1), FIL__, __LINE__, error_num,
1083 MSG_E_NET, error_msg, error_call,
1084 _("email"), ma_machine);
1085 SL_RETURN( NULL, _("sh_mail_start_conn"));
1086 }
1087
1088 /* associate a FILE structure with it
1089 */
1090 connFile = fdopen (fd, "r+");
1091 if (connFile == NULL)
1092 {
1093 TPT(( 0, FIL__, __LINE__, _("msg=<fdopen() failed>\n")));
1094 (void) sl_close_fd(FIL__, __LINE__, fd);
1095 SL_RETURN( NULL, _("sh_mail_start_conn"));
1096 }
1097
1098
1099 /* say HELO to the other socket
1100 */
1101 if (0 == sh_mail_wait (220, fd))
1102 {
1103 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1104 _("Timeout on SMTP session init"),
1105 _("sh_mail_start_conn"),
1106 _("mail"), sh.host.name);
1107 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout>\n")));
1108 (void) sl_fclose(FIL__, __LINE__, connFile);
1109 SL_RETURN( NULL, _("sh_mail_start_conn"));
1110 }
1111
1112 (void) fflush(connFile);
1113
1114 if (0 != is_numeric(sh.host.name))
1115 {
1116 sl_snprintf(error_msg, sizeof(error_msg), "HELO [%s]",
1117 sh.host.name);
1118 }
1119 else
1120 {
1121 sl_snprintf(error_msg, sizeof(error_msg), "HELO %s",
1122 sh.host.name);
1123 }
1124 report_smtp(error_msg);
1125
1126 if (0 != is_numeric(sh.host.name))
1127 fprintf(connFile, _("HELO [%s]%c%c"), sh.host.name, 13, 10);
1128 else
1129 fprintf(connFile, _("HELO %s%c%c"), sh.host.name, 13, 10);
1130
1131 (void) fflush(connFile);
1132
1133 if (0 == sh_mail_wait(250, fd))
1134 {
1135 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1136 _("HELO failed"), _("sh_mail_start_conn"),
1137 _("mail"), sh.host.name);
1138
1139 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1140 (void) sl_fclose(FIL__, __LINE__, connFile);
1141 SL_RETURN( NULL, _("sh_mail_start_conn"));
1142 }
1143
1144 /* tell them who we are
1145 */
1146 (void) sl_strlcpy (this_address,
1147 mail_sender ? mail_sender : DEFAULT_SENDER, 256);
1148 if (NULL == strchr(this_address, '@'))
1149 {
1150 (void) sl_strlcat (this_address, "@", 256);
1151 if (0 != is_numeric(sh.host.name))
1152 (void) sl_strlcat (this_address, _("example.com"), 256);
1153 else
1154 (void) sl_strlcat (this_address, sh.host.name, 256);
1155 }
1156
1157 sl_snprintf(error_msg, sizeof(error_msg), "MAIL FROM:<%s>",
1158 this_address);
1159 report_smtp(error_msg);
1160
1161 (void) fflush(connFile);
1162 /*@-usedef@*/
1163 fprintf(connFile, _("MAIL FROM:<%s>%c%c"), this_address, 13, 10);
1164 /*@+usedef@*/
1165 (void) fflush(connFile);
1166
1167 if (0 == sh_mail_wait(250, fd))
1168 {
1169 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1170 _("MAIL FROM failed"), _("sh_mail_start_conn"),
1171 _("mail"), this_address);
1172 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1173 (void) sl_fclose(FIL__, __LINE__, connFile);
1174 SL_RETURN( NULL, _("sh_mail_start_conn"));
1175 }
1176
1177 /* tell them who to send mail to
1178 */
1179 if (aFlag == 0)
1180 {
1181 sl_snprintf(error_msg, sizeof(error_msg), "RCPT TO:<%s>",
1182 address);
1183 report_smtp(error_msg);
1184
1185 (void) fflush(connFile);
1186 fprintf(connFile, _("RCPT TO:<%s>%c%c"), address, 13, 10);
1187 (void) fflush(connFile);
1188
1189 if (0 == sh_mail_wait(250, fd))
1190 {
1191 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1192 _("RCPT TO failed"), _("sh_mail_start_conn"),
1193 _("mail"), address);
1194 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1195 (void) sl_fclose(FIL__, __LINE__, connFile);
1196 SL_RETURN( NULL, _("sh_mail_start_conn"));
1197 }
1198 *anum = 1;
1199 }
1200 else
1201 {
1202 int address_num = 0;
1203 ecount = 0;
1204
1205 ma_address = all_recipients;
1206
1207 while (ma_address)
1208 {
1209 if (ma_address->send_mail != 1)
1210 {
1211 ma_address = ma_address->next;
1212 continue;
1213 }
1214
1215 ++address_num;
1216
1217 sl_snprintf(error_msg, sizeof(error_msg), "RCPT TO:<%s>",
1218 sh_string_str(ma_address->recipient));
1219 report_smtp(error_msg);
1220
1221 (void) fflush(connFile);
1222 fprintf(connFile, _("RCPT TO:<%s>%c%c"),
1223 sh_string_str(ma_address->recipient), 13, 10);
1224 (void) fflush(connFile);
1225
1226 if (0 == sh_mail_wait(250, fd))
1227 {
1228 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1229 _("RCPT TO failed"), _("sh_mail_start_conn"),
1230 _("mail"), sh_string_str(ma_address->recipient));
1231
1232 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1233 ++ecount;
1234 }
1235 ma_address = ma_address->next;
1236 }
1237
1238 *anum += address_num;
1239
1240 if (ecount == address_num)
1241 {
1242 (void) sl_fclose(FIL__, __LINE__, connFile);
1243 SL_RETURN( NULL, _("sh_mail_start_conn"));
1244 }
1245 }
1246
1247 /* Send the message
1248 */
1249 report_smtp(_("DATA"));
1250
1251 (void) fflush(connFile);
1252 fprintf(connFile, _("DATA%c%c"), 13, 10);
1253 (void) fflush(connFile);
1254
1255 if (0 == sh_mail_wait(354, fd))
1256 {
1257 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1258 _("DATA failed"), _("sh_mail_start_conn"),
1259 _("mail"), address);
1260 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1261 (void) sl_fclose(FIL__, __LINE__, connFile);
1262 SL_RETURN( NULL, _("sh_mail_start_conn"));
1263 }
1264
1265
1266 my_time = time(NULL);
1267#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
1268 my_tm = localtime_r(&my_time, &time_tm);
1269#else
1270 my_tm = localtime(&my_time);
1271#endif
1272
1273#if defined(HAVE_STRFTIME_Z)
1274 (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %z"), my_tm);
1275#else
1276 (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %Z"), my_tm);
1277#endif
1278
1279 TPT(( 0, FIL__, __LINE__, _("msg=<From: <%s>%c%cTo: <%s>%c%cDate: %s>%c%c"),
1280 this_address, 13, 10, address, 13, 10, my_tbuf, 13, 10));
1281
1282 report_smtp(_("sending data.."));
1283
1284 (void) fflush(connFile);
1285 fprintf(connFile,
1286 _("From: <%s>%c%c"\
1287 "To: <%s>%c%c"\
1288 "Date: %s%c%c"),
1289 this_address, 13, 10,
1290 address, 13, 10,
1291 my_tbuf, 13, 10);
1292
1293 *ma_socket = fd;
1294 SL_RETURN( connFile, _("sh_mail_start_conn"));
1295}
1296
1297/*************************
1298 *
1299 * end connection
1300 *
1301 */
1302
1303static int sh_mail_end_conn (FILE * connFile, int fd)
1304{
1305 SL_ENTER(_("sh_mail_end_conn"));
1306
1307 time_wait = 300;
1308
1309 report_smtp(_("."));
1310
1311 (void) fflush(connFile);
1312 fprintf(connFile, _("%c%c.%c%c"), 13, 10, 13, 10);
1313 (void) fflush(connFile);
1314
1315 if (0 != sh_mail_wait(250, fd))
1316 {
1317 (void) fflush(connFile);
1318 fprintf(connFile, _("QUIT%c%c"), 13, 10);
1319 (void) fflush(connFile);
1320 TPT(( 0, FIL__, __LINE__, _("msg=<exit>\n")));
1321
1322 SL_RETURN (0, _("sh_mail_end_conn"));
1323 }
1324
1325 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1326 _("QUIT failed"), _("sh_mail_end_conn"),
1327 _("mail"), _("SMTP server"));
1328
1329 TPT(( 0, FIL__, __LINE__, _("msg=<abnormal exit>\n")));
1330
1331 SL_RETURN ((-1), _("sh_mail_end_conn"));
1332}
1333
1334
1335
1336/****************************
1337 *
1338 * Handle server replies
1339 *
1340 *
1341 */
1342extern int flag_err_debug;
1343
1344static void report_smtp (char * reply)
1345{
1346 char * tmp;
1347
1348 if (flag_err_debug == SL_TRUE)
1349 {
1350 tmp = sh_util_safe_name_keepspace(reply);
1351
1352 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1353 tmp,
1354 _("report_smtp") );
1355 SH_FREE(tmp);
1356 }
1357 return;
1358}
1359
1360
1361static int sh_mail_wait(int code, int ma_socket)
1362{
1363 int rcode, g;
1364
1365 char c;
1366
1367 char errmsg[194];
1368 char reply[128];
1369 unsigned int ireply = 0;
1370
1371 enum {
1372 WAIT_CODE_START,
1373 WAIT_CODE,
1374 WAIT_NL,
1375 WAIT_NL_CONT
1376 } state;
1377
1378 time_t waited_time;
1379
1380 SL_ENTER(_("mail_wait"));
1381
1382 waited_time = time(NULL);
1383
1384 /* timeout after 5 minutes
1385 */
1386
1387 rcode = 0;
1388 state = WAIT_CODE_START;
1389 reply[0] = '\0';
1390
1391 while (sl_read_timeout_fd (ma_socket, &c, 1, time_wait, SL_FALSE) > 0) {
1392
1393 if (ireply < (sizeof(reply) - 1))
1394 {
1395 if (c != '\n' && c != '\r')
1396 {
1397 reply[ireply] = c;
1398 ++ireply;
1399 reply[ireply] = '\0';
1400 }
1401 }
1402
1403 g = (int) c;
1404
1405 /*
1406 if (g == EOF)
1407 {
1408 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: EOF>\n")));
1409 SL_RETURN( 0, _("mail_wait"));
1410 }
1411 */
1412
1413 switch(state) {
1414
1415 /* wait for start of a numerical code
1416 */
1417 case WAIT_CODE_START:
1418 if (0 != isspace(g))
1419 break; /* Skip white space */
1420 if (0 == isdigit(g))
1421 {
1422 report_smtp(reply);
1423 SL_RETURN( 0, _("mail_wait")); /* No leading number */
1424 }
1425 rcode = g-(int)'0'; /* convert to number */
1426 state = WAIT_CODE;
1427 break;
1428
1429 /* wait for completion of numerical code
1430 */
1431 case WAIT_CODE:
1432 if (0 != isdigit(g)) {
1433 rcode = rcode * 10 + (g-(int)'0'); /* next digit */
1434 break;
1435 }
1436 /*@+charintliteral@*/
1437 state = ((g == '-') ? WAIT_NL_CONT : WAIT_NL);
1438 /*@-charintliteral@*/
1439 break;
1440
1441 /* wait for newline, then return with status code
1442 */
1443 case WAIT_NL:
1444 /*@+charintliteral@*/
1445 if (g != '\n')
1446 break;
1447 /*@-charintliteral@*/
1448
1449 TPT((0, FIL__, __LINE__,
1450 _("msg=<mail_wait: OK got %d (%d) need %d (%d)>\n"),
1451 rcode, (int)(rcode/100), code, (int)(code/100) ));
1452 g = ((int)(rcode/100) == (int)(code/100)) ? 1 : 0;
1453 if (g != 1)
1454 {
1455 char * tmp = sh_util_safe_name_keepspace(reply);
1456 sl_snprintf(errmsg, sizeof(errmsg),
1457 _("Bad response (%s), expected %d"), tmp, code);
1458 SH_FREE(tmp);
1459
1460 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1461 errmsg, _("sh_mail_wait"),
1462 _("mail"), _("SMTP server"));
1463 }
1464 else
1465 {
1466 report_smtp(reply);
1467 }
1468 waited_time = time(NULL) - waited_time;
1469 time_wait -= waited_time;
1470 TPT((0, FIL__, __LINE__,
1471 _("msg=<mail_wait: time_wait reduced to %d sec>\n"),
1472 (int) time_wait));
1473 SL_RETURN( (g), _("mail_wait")) ;
1474
1475 /* wait for continuation line
1476 */
1477 /*@fallthrough@*//* no, but splint doesn't understand */
1478 case WAIT_NL_CONT:
1479 /*@+charintliteral@*/
1480 if (g == '\n')
1481 state = WAIT_CODE_START; /* There is a continuation line */
1482 /*@-charintliteral@*/
1483 break;
1484
1485 default:
1486
1487 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: bad>\n")));
1488 report_smtp(reply);
1489 SL_RETURN( 0, _("mail_wait"));
1490
1491 }
1492 }
1493
1494 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: failed>\n")));
1495
1496 /* Failed, EOF or error on socket */
1497 report_smtp(reply);
1498 SL_RETURN( 0, _("mail_wait"));
1499}
1500
1501/* -- function to insert "\r\n" after each 998 chars --
1502 */
1503
1504#define SPLIT_AT 998
1505
1506static char * split_string(const char * str)
1507{
1508 size_t size;
1509 size_t blocks;
1510 int count = 0;
1511
1512 char * p, * p0;
1513 const char * q;
1514
1515 if (!str)
1516 return NULL;
1517
1518 size = strlen(str) + 1;
1519 blocks = 1 + (size / SPLIT_AT);
1520
1521 if (sl_ok_muls(2, blocks) && sl_ok_adds(size, (2*blocks)))
1522 {
1523 size = size + (2*blocks);
1524 }
1525 else
1526 {
1527 /* integer overflow, do not split */
1528 p = sh_util_strdup(str);
1529 return p;
1530 }
1531
1532 p = SH_ALLOC(size);
1533 memset(p, 0, size);
1534
1535 p0 = p;
1536
1537 q = str;
1538 while (*q != '\0') {
1539 *p = *q;
1540 ++p;
1541 ++q;
1542 ++count;
1543 if (0 == (count % SPLIT_AT)) {
1544 count = 0;
1545 *p = '\r';
1546 ++p;
1547 *p = '\n';
1548 ++p;
1549 }
1550 }
1551 /* fprintf(stderr, "used = %d\n", strlen(p0)); */
1552
1553 return p0;
1554}
1555
1556
1557
1558/*****************************************************************
1559 *
1560 * MX Resolver Routines
1561 *
1562 *****************************************************************/
1563
1564#if defined(HAVE_ARPA_NAMESER_H)
1565
1566#include <netinet/in.h>
1567#ifdef __APPLE__
1568#define BIND_8_COMPAT 1
1569#endif
1570#ifndef S_SPLINT_S
1571#include <arpa/nameser.h>
1572#include <resolv.h>
1573#endif
1574#include <netdb.h>
1575#include <sys/socket.h>
1576#ifndef S_SPLINT_S
1577#include <arpa/inet.h>
1578#endif
1579
1580#include "sh_tools.h"
1581
1582#ifndef HFIXEDSZ
1583#define HFIXEDSZ 12
1584#endif
1585#ifndef QFIXEDSZ
1586#define QFIXEDSZ 4
1587#endif
1588
1589/*@unused@*//* used in get_mx() which is not parsed by splint */
1590static unsigned int get_short (unsigned char * loc)
1591{
1592 unsigned int retval = 0;
1593 if (loc)
1594 {
1595 /* byte order: MSB first
1596 */
1597 /*@+charint@*/
1598 retval = (((unsigned char) * loc) * 256) | ((unsigned char) * (loc + 1));
1599 /*@-charint@*/
1600 }
1601 return (retval);
1602}
1603
1604/* parser errors with splint */
1605#ifndef S_SPLINT_S
1606static dnsrep * get_mx (char *hostname)
1607{
1608 int ret, length, status;
1609 mx * result;
1610 size_t len;
1611
1612 typedef union
1613 {
1614 HEADER head;
1615 unsigned char buffer[4096];
1616 } querybuf;
1617
1618 querybuf * reply;
1619 char expanded[1024];
1620 unsigned char * comp_dn, * eom;
1621 HEADER * header;
1622 int type, rdlength, pref;
1623 unsigned int count, theindex;
1624 dnsrep * retval;
1625
1626 SL_ENTER(_("get_mx"));
1627
1628 if (0 != res_init ())
1629 SL_RETURN (NULL, _("get_mx"));
1630
1631 reply = SH_ALLOC(sizeof(querybuf));
1632
1633 errno = 0;
1634 length = res_query (hostname, C_IN, T_MX,
1635 (unsigned char *) reply, 4095);
1636
1637 if (length < 1)
1638 {
1639 char errbuf[SH_ERRBUF_SIZE];
1640
1641 /* error handling
1642 */
1643 if (length == -1)
1644 {
1645 if (errno == ECONNREFUSED)
1646 status = ECONNREFUSED;
1647 else
1648 status = h_errno;
1649
1650#ifdef FIL__
1651 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
1652 (errno == ECONNREFUSED) ?
1653 sh_error_message (status, errbuf, sizeof(errbuf)) :
1654 sh_tools_errmessage(status, errbuf, sizeof(errbuf)),
1655 _("res_query"));
1656#else
1657 if (errno == ECONNREFUSED)
1658 fprintf(stderr, " ERROR: %s: \n", strerror(errno)); /* TESTONLY */
1659 else
1660 fprintf(stderr, "HERROR: %s\n", hstrerror(h_errno));/* TESTONLY */
1661#endif
1662 }
1663 SH_FREE(reply);
1664 SL_RETURN (NULL, _("get_mx"));
1665 }
1666
1667 ret = 0;
1668 header = (HEADER *) reply;
1669
1670 /* start of data section
1671 */
1672 comp_dn = (unsigned char *) reply + HFIXEDSZ;
1673
1674 /* end-of-message
1675 */
1676 eom = (unsigned char *) reply + length;
1677
1678 /* HEADER NAME -- must be skipped or decompressed
1679 * TYPE -- type of data we got back, 16 bit integer
1680 * CLASS -- class we got back, also a 16 bit integer
1681 * TTL -- 32 bit time-to-live. just skip this
1682 * RDLENGTH -- length of the data to follow
1683 * RDATA -- the data:
1684 * PREF -- 16 bit preference
1685 * MX -- name of mail exchanger, must be decompressed
1686 */
1687
1688 /* Skip the query data.
1689 * QDCOUNT is the number of entries (unsigned 16 bit int).
1690 */
1691 count = ntohs (header->qdcount);
1692 for (theindex = 0; theindex < count; ++theindex)
1693 {
1694 ret = dn_skipname (comp_dn, eom);
1695 comp_dn += ret + QFIXEDSZ;
1696 if (ret < 1 || comp_dn >= eom)
1697 {
1698 SH_FREE(reply);
1699 SL_RETURN (NULL, _("get_mx"));
1700 }
1701 }
1702
1703 count = ntohs (header->ancount);
1704 if (count < 1)
1705 {
1706 SH_FREE(reply);
1707 SL_RETURN (NULL, _("get_mx"));
1708 }
1709
1710 retval = SH_ALLOC (sizeof (dnsrep));
1711 if (!retval)
1712 {
1713 SH_FREE(reply);
1714 SL_RETURN (NULL, _("get_mx"));
1715 }
1716
1717 retval->count = count;
1718
1719 /* allocate space for the results */
1720
1721 if (!sl_ok_muls(count, sizeof (mx)))
1722 {
1723 SH_FREE(reply);
1724 SH_FREE (retval);
1725 SL_RETURN (NULL, _("get_mx"));
1726 }
1727
1728 result = SH_ALLOC (count * sizeof (mx));
1729
1730 if (!result)
1731 {
1732 SH_FREE(reply);
1733 SH_FREE (retval);
1734 SL_RETURN (NULL, _("get_mx"));
1735 }
1736 retval->reply = result;
1737
1738 do
1739 {
1740 /* HEADER NAME
1741 */
1742 ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
1743 (char *) expanded, 1023);
1744 comp_dn += ret;
1745 if (ret < 1 || comp_dn >= eom)
1746 {
1747 SH_FREE(reply);
1748 SH_FREE (result);
1749 SH_FREE (retval);
1750 SL_RETURN (NULL, _("get_mx"));
1751 }
1752
1753 /* TYPE
1754 */
1755 type = get_short (comp_dn);
1756 comp_dn += 2;
1757 if (type != T_MX || comp_dn >= eom)
1758 {
1759 SH_FREE(reply);
1760 SH_FREE (result);
1761 SH_FREE (retval);
1762 SL_RETURN (NULL, _("get_mx"));
1763 }
1764
1765
1766 /* CLASS (re-use 'type' var)
1767 */
1768 type = get_short (comp_dn);
1769 comp_dn += 2;
1770 if (comp_dn >= eom)
1771 {
1772 SH_FREE(reply);
1773 SH_FREE (result);
1774 SH_FREE (retval);
1775 SL_RETURN (NULL, _("get_mx"));
1776 }
1777
1778
1779 /* TTL
1780 */
1781 comp_dn += 4;
1782 if (comp_dn >= eom)
1783 {
1784 SH_FREE(reply);
1785 SH_FREE (result);
1786 SH_FREE (retval);
1787 SL_RETURN (NULL, _("get_mx"));
1788 }
1789
1790 /* RDLENGTH
1791 */
1792 rdlength = get_short (comp_dn);
1793 comp_dn += 2;
1794 if (rdlength < 1 || comp_dn >= eom)
1795 {
1796 SH_FREE(reply);
1797 SH_FREE (result);
1798 SH_FREE (retval);
1799 SL_RETURN (NULL, _("get_mx"));
1800 }
1801
1802 /* RDATA
1803 */
1804 pref = get_short (comp_dn);
1805 comp_dn += 2;
1806 if (comp_dn >= eom)
1807 {
1808 SH_FREE(reply);
1809 SH_FREE (result);
1810 SH_FREE (retval);
1811 SL_RETURN (NULL, _("get_mx"));
1812 }
1813
1814 ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
1815 (char *) expanded, 1023);
1816 comp_dn += ret;
1817 if (ret < 1)
1818 {
1819 SH_FREE(reply);
1820 SH_FREE (result);
1821 SH_FREE (retval);
1822 SL_RETURN (NULL, _("get_mx"));
1823 }
1824 count--;
1825
1826 /* fill in the struct
1827 */
1828 result[count].pref = pref;
1829 len = strlen (expanded) + 1;
1830 result[count].address = SH_ALLOC (len);
1831 sl_strlcpy (result[count].address, expanded, len);
1832 }
1833 while (ret > 0 && comp_dn < eom && count);
1834
1835 SH_FREE(reply);
1836 SL_RETURN (retval, _("get_mx"));
1837}
1838/* ifndef S_SPLINT_S */
1839#endif
1840
1841/* #if defined(HAVE_ARPA_NAMESER_H) */
1842#endif
1843
1844
1845static int comp_mx_pref (const void * a, const void * b)
1846{
1847 const mx * ax = (const mx *) a;
1848 const mx * bx = (const mx *) b;
1849
1850 if (ax->pref > bx->pref)
1851 return 1;
1852 else if (ax->pref < bx->pref)
1853 return -1;
1854 else
1855 return 0;
1856}
1857
1858/*
1859 * return_mx returns a list of valid mail exchangers for domain
1860 */
1861static dnsrep * return_mx (char *domain)
1862{
1863 struct hostent *host;
1864 dnsrep * answers = NULL;
1865 mx * result;
1866 dnsrep * retval;
1867 char errmsg[128];
1868 size_t len;
1869
1870 SL_ENTER(_("return_mx"));
1871
1872#if defined(HAVE_ARPA_NAMESER_H)
1873 if (domain != NULL)
1874 answers = /*@-unrecog@*/get_mx (domain)/*@+unrecog@*/;
1875#endif
1876
1877 if (answers != NULL && answers->count > 0)
1878 {
1879 qsort(answers->reply, (size_t) answers->count, sizeof(mx),
1880 comp_mx_pref);
1881 SL_RETURN (answers, _("return_mx"));
1882 }
1883 else
1884 {
1885 if (domain != NULL)
1886 {
1887#if defined(HAVE_ARPA_NAMESER_H)
1888#ifdef FIL__
1889 (void) sl_strlcpy (errmsg, _("No MX record for domain "), 127);
1890 (void) sl_strlcat (errmsg, domain, 127);
1891 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1892 errmsg,
1893 _("get_mx"));
1894#else
1895 /* flawfinder: ignore *//* test code only */
1896 strcpy (errmsg, /* known to fit */
1897 _("No MX record for domain "));
1898 strncat (errmsg, domain, 100);
1899 errmsg[122] = '\0';
1900 fprintf(stderr, "Warning: %s\n", errmsg);
1901#endif
1902#endif
1903 }
1904
1905 SH_MUTEX_LOCK(mutex_resolv);
1906
1907 host = NULL;
1908 retval = NULL;
1909
1910 if (domain != NULL)
1911 host = /*@-unrecog@*/sh_gethostbyname (domain)/*@+unrecog@*/;
1912
1913 if (host)
1914 {
1915 result = SH_ALLOC (sizeof (mx));
1916 retval = SH_ALLOC (sizeof (dnsrep));
1917 retval->reply = result;
1918 retval->count = 1;
1919 result->pref = 0;
1920 /*@-type@*/
1921 len = strlen (host->h_name) + 1;
1922 result->address = SH_ALLOC (len);
1923 sl_strlcpy (result->address, host->h_name, len);
1924 /*@+type@*/
1925 }
1926 SH_MUTEX_UNLOCK(mutex_resolv);
1927
1928 if (!host)
1929 {
1930#ifdef FIL__
1931 (void) sl_strlcpy (errmsg, _("Unknown host "), 127);
1932 (void) sl_strlcat (errmsg, domain, 127);
1933 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1934 errmsg,
1935 _("return_mx"));
1936#endif
1937 SL_RETURN (NULL, _("return_mx"));
1938 }
1939
1940 SL_RETURN (retval, _("return_mx"));
1941 }
1942}
1943
1944int free_mx (dnsrep * answers)
1945{
1946 mx * result;
1947 int i;
1948
1949 SL_ENTER(_("free_mx"));
1950 if (!answers)
1951 SL_RETURN (0, _("return_mx"));
1952
1953 result = answers->reply;
1954 for (i = 0; i < answers->count; ++i)
1955 {
1956 SH_FREE (result[i].address);
1957 }
1958 SH_FREE(result);
1959 SH_FREE(answers);
1960 SL_RETURN (0, _("return_mx"));
1961}
1962
1963#ifdef TEST_ONLY
1964int main(int argc, char * argv[])
1965{
1966 int i;
1967 dnsrep * answers;
1968 mx * result;
1969
1970 if (argc < 2)
1971 {
1972 fprintf(stderr, "Usage: dns <hostname>\n");
1973 return -1;
1974 }
1975 answers = return_mx(argv[1]);
1976
1977 if (!answers)
1978 {
1979 fprintf(stderr, "No answer\n");
1980 return -1;
1981 }
1982
1983 if (answers->count > 0)
1984 {
1985 result = answers->reply;
1986 for (i = 0; i < answers->count; ++i)
1987 {
1988 fprintf(stderr, "Record %3d: [%3d] %s\n", i,
1989 result[i].pref, result[i].address);
1990 }
1991 }
1992 else
1993 {
1994 fprintf(stderr, "No answer\n");
1995 free_mx(answers);
1996 return -1;
1997 }
1998 free_mx(answers);
1999 return (0);
2000}
2001#endif
2002
2003
2004
2005/* if defined(SH_WITH_MAIL) */
2006#endif
2007
2008
2009
Note: See TracBrowser for help on using the repository browser.