source: trunk/src/sh_mail.c@ 241

Last change on this file since 241 was 240, checked in by katerina, 15 years ago

Fix bugs in mailer code (ticket #160, #161).

File size: 43.9 KB
RevLine 
[1]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 1999, 2000 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <pwd.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <errno.h>
31#include <signal.h>
32#include <setjmp.h>
33
34#if defined(SH_WITH_MAIL)
35
36#if TIME_WITH_SYS_TIME
37#include <sys/time.h>
38#include <time.h>
39#else
40#if HAVE_SYS_TIME_H
41#include <sys/time.h>
42#else
43#include <time.h>
44#endif
45#endif
46
47
48#ifdef HAVE_MEMORY_H
49#include <memory.h>
50#endif
51
52#include "samhain.h"
53#include "sh_error.h"
54#include "sh_unix.h"
55#include "sh_tiger.h"
56#include "sh_mail.h"
57#include "sh_utils.h"
58#include "sh_fifo.h"
59#include "sh_tools.h"
[137]60#include "sh_pthread.h"
[215]61#include "sh_filter.h"
[214]62#include "sh_mail_int.h"
63#include "sh_nmail.h"
[1]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
[20]86int sh_mail_sigverify (const char * s)
[1]87{
88 SL_TICKET fd;
89 long i;
90 char * buf;
91 char * bufc;
92 char key[81];
93 char number[2*SH_MINIBUF];
94 char audit_id[2 * SH_MINIBUF];
95 long numsig;
96 char key2[KEY_LEN+1];
97
98 char * theSig;
99
100 mail_trail_type * mail_trail_ptr = NULL;
101
102 sh_error_logoff();
103
104 ASSERT((s != NULL && sl_strlen(s) < PATH_MAX),
105 _("(s != NULL && sl_strlen(s) < PATH_MAX)"));
106
107 if (s == NULL || sl_strlen(s) >= PATH_MAX)
108 _exit (EXIT_FAILURE);
109
110 /* open the file, then check it
111 */
112 if (0 != sl_is_suid())
113 {
114 fprintf(stderr, _("Cannot open file %s in suid mode\n"), s);
115 _exit (EXIT_FAILURE);
116 }
117 if ( SL_ISERROR(fd = sl_open_read (s, SL_NOPRIV)))
118 {
119 fprintf(stderr, _("Could not open file %s\n"), s);
120 _exit (EXIT_FAILURE);
121 }
122
[170]123 buf = SH_ALLOC( (size_t)(SH_MSG_BUF+SH_BUFSIZE+1));
124 bufc = SH_ALLOC( (size_t)(SH_MSG_BUF+SH_MAXBUF+1));
[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 {
[170]136 (void) sh_unix_getline (fd, buf, SH_MSG_BUF+SH_BUFSIZE);
[1]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 {
[170]155 (void) sh_unix_getline (fd, buf, SH_MSG_BUF+SH_BUFSIZE);
[1]156 if (0 == sl_strncmp(buf, _("-----BEGIN SIGNATURE-----"),
157 sizeof("-----BEGIN SIGNATURE-----")-1))
158 break;
159 if (buf[0] == '\0')
160 _exit (EXIT_FAILURE);
[170]161 (void) sh_util_compress(bufc, buf, SH_MSG_BUF+SH_MAXBUF-KEY_LEN);
[1]162 }
163
164 /* get signature and number
165 */
[34]166 (void) sh_unix_getline (fd, key, (int)sizeof(key));
[1]167 key[KEY_LEN] = '\0';
168
[34]169 (void) sh_unix_getline (fd, number, (int)sizeof(number));
[1]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 {
[210]189 fprintf (stderr, "%s",_("ERROR (no key -- cannot check)\n"));
[1]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 {
[210]203 fprintf (stderr, "%s",_("ERROR (repeated audit trail)\n"));
[1]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);
[210]212 fprintf (stderr, "%s",_("(unchecked)\n"));
[1]213 }
214 else
215 {
[133]216 char sigbuf[KEYBUF_SIZE];
217
[1]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 {
[133]223 char hashbuf[KEYBUF_SIZE];
[1]224 (void) sl_strlcpy (key2,
[133]225 sh_tiger_hash (key2, TIGER_DATA, KEY_LEN,
226 hashbuf, sizeof(hashbuf)),
[1]227 KEY_LEN+1);
228 }
229
230
[133]231 theSig = sh_util_siggen (key2, bufc, sl_strlen(bufc), sigbuf, sizeof(sigbuf));
[1]232 if (sl_strncmp (key,
233 theSig,
234 KEY_LEN) != 0)
235 {
[210]236 fprintf (stderr, "%s",_("(FAILED)\n"));
[1]237 }
238 else
239 {
[210]240 fprintf (stderr, "%s",_("(passed)\n"));
[1]241 }
242
243 }
244
245 } /* end scan mailbox */
246
247 /*@notreached@*/
248}
249
[22]250int sh_mail_setNum (const char * str)
[1]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
[214]264int sh_mail_all_in_one = S_FALSE;
[1]265
[22]266int sh_mail_setFlag (const char * str)
[1]267{
268 int i;
269 SL_ENTER(_("sh_mail_setFlag"));
[214]270 i = sh_util_flagval(str, &sh_mail_all_in_one);
[1]271 SL_RETURN(i, _("sh_mail_setFlag"));
272}
273
274static char * mail_subject = NULL;
275
[22]276int set_mail_subject (const char * str)
[1]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
[214]295SH_MUTEX_INIT(mutex_fifo_mail, PTHREAD_MUTEX_INITIALIZER);
[1]296
[214]297SH_FIFO * fifo_mail = NULL;
[1]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
[214]310 SH_MUTEX_LOCK(mutex_fifo_mail);
[1]311 while (NULL != (msg = pop_list(fifo_mail)))
312 {
313 len = sl_strlen(msg);
314 memset(msg, 0, len);
315 SH_FREE(msg);
316 }
[214]317 SH_MUTEX_UNLOCK(mutex_fifo_mail);
[1]318
319 SL_RET0(_("sh_mail_emptystack"));
320}
321
322/* insert "\r\n" after each 998 char
323 */
[214]324static char * split_string(const char * str);
[1]325
[214]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)
[1]330{
331 char * p;
[214]332 volatile int retval = 0;
[1]333 int status;
334
335 SL_ENTER(_("sh_mail_pushstack"));
336
[214]337 if (msg == NULL || failedMail == SL_TRUE /* || sh.srvmail.name[0] == '\0' */)
[1]338 SL_RETURN((0), (_("sh_mail_pushstack")));
339
[214]340 p = split_string(msg);
341 /* fixes "variable ‘p’ might be clobbered by ‘longjmp’ or ‘vfork’" */
342 p_dummy = &p;
[1]343
[214]344 SH_MUTEX_LOCK(mutex_fifo_mail);
[1]345
346 if (fifo_mail == NULL)
347 {
348 fifo_mail = SH_ALLOC(sizeof(SH_FIFO));
349 fifo_init(fifo_mail);
350 }
[214]351 status = push_list (fifo_mail, p, severity, alias);
352 SH_MUTEX_UNLOCK(mutex_fifo_mail);
[1]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 {
[214]361 BREAKEXIT(sh_nmail_flush);
362 retval = sh_nmail_flush ();
[1]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 */
[131]373static int sh_mail_end_conn (FILE * connfile, int fd);
[214]374static FILE * sh_mail_start_conn (struct alias * address, int * fd, int * anum);
[1]375
376static
[214]377void sh_mail_get_subject(const char * message,
[1]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];
[214]391 char * msg;
[1]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 */
[214]408 msg = sh_util_strdup(message);
409
410 mptr = sl_strstr(msg, _("msg="));
[1]411 if (mptr)
412 {
413 mptr += 4;
414 rep_serv_tab[2].data_str = mptr;
415 }
416 else
[214]417 rep_serv_tab[2].data_str = msg;
[1]418
[214]419 mptr = sl_strstr(msg, _("sev="));
[1]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 {
[214]431 mptr = msg;
[1]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);
[214]454 SH_FREE(msg);
[1]455 SL_RET0(_("sh_mail_get_subject"));
456}
457
[214]458void sh_mail_signature_block (sh_string * sigMsg, char * recipient,
459 char * bufcompress)
[1]460{
[214]461 time_t id_audit;
462 char * theSig;
463 char ibuf[80];
464 unsigned int count;
[1]465
[214]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)
[34]475 {
[214]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 }
[1]502
[214]503 sigMsg = sh_string_add_from_char(sigMsg, "\r\n");
[1]504
[214]505 sl_snprintf(ibuf, sizeof(ibuf), _("%06u %010lu::%s\r\n"),
506 count, (unsigned long) id_audit, sh.host.name);
[1]507
[214]508 sigMsg = sh_string_add_from_char(sigMsg, ibuf);
509 sigMsg = sh_string_add_from_char(sigMsg, _("-----END MESSAGE-----"));
[34]510
[214]511 return;
[1]512}
513
[214]514int sh_mail_msg (const char * message)
[1]515{
516 char subject[32+32+SH_MINIBUF+2+3+SH_PATHBUF];
517 char mheader[32+32+SH_MINIBUF+2+3];
518
[214]519 sh_string * mailMsg;
520 sh_string * compMsg;
521 int status = 0;
522 volatile int errcount;
[1]523 size_t wrlen;
[214]524 volatile int retval = -1;
[1]525
526 char * bufcompress;
[214]527 size_t compressed;
528
[1]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
[131]538 int ma_socket = -1;
539
[214]540 int address_num = 0;
541 sh_string * theMsg = NULL;
[1]542
543 /* #define SH_MAILBUF (256) */
[214]544#define SH_MAILBUF 4096
[1]545
[132]546 char timebuf[81];
[1]547
548 SL_ENTER(_("sh_mail_msg"));
549
[214]550 /*
551 * Return if we cannot mail.
[1]552 */
553 if (failedMail == SL_TRUE)
554 SL_RETURN((-1), _("sh_mail_msg"));
555
[214]556 /*
557 * Final failure, can't mail for SH_MAX_FAIL hours.
558 */
[1]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,
[214]563 _("mail"),
564 sh_string_str(all_recipients->recipient));
[1]565 sh_mail_emptystack();
566 sh.mailNum.alarm_last = 0;
567 failedMail = SL_TRUE;
568 SL_RETURN((-1), _("sh_mail_msg"));
569 }
570
[214]571 /*
572 * Try at most every three seconds to mail if there was a failure.
[1]573 */
574 if ((fail_time > 0) && (time(NULL) - fail_time) < 3/*600*/)
575 {
576 if (failcount > 3)
577 {
[214]578 /* -- Save for later. Changed: done by caller. --
579 * sh_nmail_pushstack (severity, message, alias);
[1]580 */
581 ++failcount;
582
583 SL_RETURN((-1), _("sh_mail_msg"));
584 }
585 else
586 {
587 (void) retry_msleep(2, 0);
588 ++failcount;
589 }
590 }
591
592 /* -- Reset time of last failure. --
593 */
594 fail_time = 0;
595
596
[214]597 /* --------- Build complete message. ------------------------ */
[1]598
[214]599 /* Don't flush the queue here, because tag_list doesn't know
600 * how to filter messages. */
[1]601
[214]602 theMsg = sh_string_new_from_lchar(message, strlen(message));
[1]603
604 /* ---------- Header ---------------------------------------- */
605
606 if (mail_subject == NULL)
607 {
608 (void) sl_strlcpy(mheader, _("Subject: "), sizeof(mheader)-5);
[214]609 (void) sl_strlcat(mheader,
610 sh_unix_time (0, timebuf, sizeof(timebuf)),
[132]611 sizeof(mheader)-5);
[1]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);
[214]625 (void) sl_strlcat(mheader,
626 sh_unix_time (0, timebuf, sizeof(timebuf)),
[132]627 sizeof(mheader)-5);
[1]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
[132]639 (void) sl_strlcpy(subject, sh_unix_time (0, timebuf, sizeof(timebuf)),
640 sizeof(subject));
[1]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
[214]646 mailMsg = sh_string_new (SH_MAILBUF);
647 compMsg = sh_string_new (SH_MAILBUF);
[1]648
[214]649 mailMsg = sh_string_add_from_char(mailMsg, mheader);
650 mailMsg = sh_string_add_from_char(mailMsg,
651 _("-----BEGIN MESSAGE-----\r\n"));
[1]652
[214]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");
[1]656
[214]657 /* ---------- Compressed Message ---------------------------- */
[1]658
[214]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");
[1]662
[214]663 bufcompress = SH_ALLOC(sh_string_len(compMsg) + KEY_LEN + 1);
664 bufcompress[0] = '\0';
[1]665
[214]666 compressed = sh_util_compress (bufcompress,
667 sh_string_str(compMsg),
668 sh_string_len(compMsg) + 1);
[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
[214]682 if (sh_mail_all_in_one == S_FALSE)
[1]683 {
[214]684 struct alias * address_list;
685
686 address_list = all_recipients;
687
688 while (address_list)
[1]689 {
[214]690 if (address_list->send_mail == 1)
691 {
692 connfile = sh_mail_start_conn (address_list,
693 &ma_socket, &address_num);
[1]694
[214]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 }
[1]729 else
[214]730 {
731 ++sh.statistics.mail_success;
732 }
733
734 if (connfile != NULL)
735 {
736 (void) fclose (connfile);
737 connfile = NULL;
738 }
[1]739 }
[214]740 address_list = address_list->all_next;
[1]741 }
742 }
743 else
744 {
[214]745 connfile = sh_mail_start_conn (NULL, &ma_socket, &address_num);
746
[1]747 if (NULL != connfile)
748 {
[214]749 wrlen = fwrite (sh_string_str(mailMsg), 1,
750 sh_string_len(mailMsg), connfile);
751 wrlen -= sh_string_len(mailMsg);
752
[1]753 if (wrlen == 0)
[214]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)
[131]769 status = sh_mail_end_conn (connfile, ma_socket);
[1]770 else
771 status = -1;
772 }
[214]773
774 if (NULL == connfile || status != 0)
[1]775 {
[214]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
[1]785 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
[214]786 _("mail"), sh_string_str(ma_address->recipient));
[1]787 errcount = address_num;
788 ++sh.statistics.mail_failed;
789 }
790 else
791 {
792 ++sh.statistics.mail_success;
793 }
794
795 if (connfile != NULL)
796 {
797 (void) fclose (connfile);
798 connfile = NULL;
799 }
800 }
801
[214]802 memset (bufcompress, 0, compressed);
[1]803 SH_FREE(bufcompress);
804
[214]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));
[1]808
[214]809 sh_string_destroy(&mailMsg);
810 sh_string_destroy(&compMsg);
811 sh_string_destroy(&theMsg);
812
[1]813 /* --- Stay responsible for delivery in case of failure --- */
814
[214]815 if (errcount == address_num)
[1]816 {
[214]817 rollback_list(fifo_mail);
818 retval = -1;
[1]819 }
[214]820 else
[1]821 {
[214]822 mark_list(fifo_mail);
[1]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 }
[214]834
[1]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
[137]871static int sh_mail_wait(int code, int ma_socket);
[1]872
873static char * relay_host = NULL;
874
[22]875int sh_mail_set_relay (const char * str_s)
[1]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)
[34]883 {
884 SH_FREE (relay_host);
885 relay_host = NULL;
886 }
[1]887
888 if (0 == sl_strncmp(str_s, _("NULL"), 4))
889 {
890 SL_RETURN( 0, _("sh_mail_set_relay"));
891 }
892
[34]893 relay_host = sh_util_strdup(str_s);
894
[1]895 SL_RETURN( 0, _("sh_mail_set_relay"));
896}
897
898static char * mail_sender = NULL;
899
[22]900int sh_mail_set_sender (const char *str)
[1]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
[216]918static int sh_mail_port = IPPORT_SMTP;
[1]919
[216]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
[1]939/*************************
940 *
941 * start connection
[214]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.
[1]946 */
947
948static time_t time_wait = 300;
949
[214]950static FILE * sh_mail_start_conn (struct alias * ma_address,
951 int * ma_socket, int * anum)
[1]952{
953 char * address;
[214]954 int aFlag = 0;
[1]955
956 int ecount;
957
958 char this_address[256];
959 char ma_machine[256];
960 char ma_user[256];
961 char error_msg[256];
962 char error_call[SH_MINIBUF];
963 int error_num = 0;
964 register int i, j, k;
965 FILE * connFile = NULL;
966 struct tm * my_tm;
[131]967#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
968 struct tm time_tm;
969#endif
[1]970 time_t my_time;
971 char my_tbuf[128];
972
973 int fd;
974
975 dnsrep * answers;
976 mx * result;
977
978 SL_ENTER(_("sh_mail_start_conn"));
979
[131]980 *ma_socket = -1;
981 time_wait = 300;
[1]982
[214]983 if (ma_address == NULL)
984 {
985 aFlag = 1;
986 ma_address = all_recipients;
[1]987
[214]988 while (ma_address)
989 {
990 if (ma_address->send_mail == 1)
991 break;
992 ma_address = ma_address->all_next;
993 }
994 }
[1]995
[214]996 if (!ma_address)
[1]997 {
998 SL_RETURN( NULL, _("sh_mail_start_conn"));
999 }
[214]1000
1001 address = sh_string_str(ma_address->recipient);
1002
1003 TPT(( 0, FIL__, __LINE__, _("msg=<address %s>\n"),
1004 address));
1005
1006 /* ------- split adress ------------------ */
1007
[1]1008 if (strchr (address, '@') == NULL) {
1009 (void) sl_strlcpy(ma_user, address, 256);
1010 (void) sl_strlcpy(ma_machine, _("localhost"), 256);
1011 } else {
1012 i = 0;
1013 while (i < 255 && address[i] != '@') {
1014 ma_user[i] = address[i];
1015 ++i;
1016 }
[214]1017
[1]1018 /* adress[i] = '@'
1019 */
1020 ma_user[i] = '\0';
1021 j = i + 1; k = i; i = 0;
1022 while (i < 255 && address[i+j] != '\0') {
1023 ma_machine[i] = address[i+j];
1024 ++i;
1025 }
1026 ma_machine[i] = '\0';
1027 if (address[k] != '@' || address[k+i+1] != '\0')
1028 {
1029 SL_RETURN( NULL, _("sh_mail_start_conn"));
1030 }
1031 }
1032
1033
1034 if (relay_host != NULL)
1035 {
1036 (void) sl_strlcpy (ma_machine, relay_host, sizeof(ma_machine));
1037 TPT((0, FIL__, __LINE__, _("msg=<user %s machine %s>\n"),
1038 ma_user, ma_machine));
[216]1039 fd = connect_port (ma_machine, sh_mail_port,
[1]1040 error_call, &error_num, error_msg, 256);
1041 }
1042 else
1043 {
[214]1044 answers = ma_address->mx_list;
1045 if (!answers)
1046 {
1047 answers = return_mx (ma_machine);
1048 ma_address->mx_list = answers;
1049 }
1050
[1]1051 if (answers)
1052 {
1053 result = answers->reply;
1054 fd = -1;
1055 for (i = 0; i < answers->count; ++i)
1056 {
1057 (void) sl_strlcpy(ma_machine, result[i].address,
1058 sizeof(ma_machine));
1059 TPT((0, FIL__, __LINE__,
1060 _("msg=<user %s mx %s pref %d>\n"),
1061 ma_user, ma_machine, result[i].pref));
[216]1062 fd = connect_port (ma_machine, sh_mail_port,
[1]1063 error_call, &error_num, error_msg, 256);
1064 if (fd >= 0)
1065 break;
1066 }
1067 }
1068 else
1069 {
1070 (void) sl_strlcpy(error_call, _("return_mx"), SH_MINIBUF);
1071 (void) sl_strlcpy(error_msg, _("The specified host is unknown: "),
1072 256);
1073 (void) sl_strlcat(error_msg, ma_machine, 256);
1074 fd = -1;
1075 }
1076 }
1077
1078
1079 if (fd < 0)
1080 {
1081 sh_error_handle ((-1), FIL__, __LINE__, error_num,
1082 MSG_E_NET, error_msg, error_call,
1083 _("email"), ma_machine);
1084 SL_RETURN( NULL, _("sh_mail_start_conn"));
1085 }
1086
1087 /* associate a FILE structure with it
1088 */
1089 connFile = fdopen (fd, "r+");
1090 if (connFile == NULL)
1091 {
1092 TPT(( 0, FIL__, __LINE__, _("msg=<fdopen() failed>\n")));
1093 (void) close(fd);
1094 SL_RETURN( NULL, _("sh_mail_start_conn"));
1095 }
1096
1097
1098 /* say HELO to the other socket
1099 */
[131]1100 if (0 == sh_mail_wait (220, fd))
[1]1101 {
1102 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1103 _("Timeout on SMTP session init"),
1104 _("sh_mail_start_conn"),
1105 _("mail"), sh.host.name);
1106 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout>\n")));
1107 (void) fclose(connFile);
1108 SL_RETURN( NULL, _("sh_mail_start_conn"));
1109 }
1110
1111 (void) fflush(connFile);
1112
1113 if (0 != is_numeric(sh.host.name))
1114 {
1115 TPT(( 0, FIL__, __LINE__, _("msg=<HELO [%s]>%c%c"),
1116 sh.host.name, 13, 10));
1117 }
1118 else
1119 {
1120 TPT(( 0, FIL__, __LINE__, _("msg=<HELO %s>%c%c"),
1121 sh.host.name, 13, 10));
1122 }
1123 if (0 != is_numeric(sh.host.name))
1124 fprintf(connFile, _("HELO [%s]%c%c"), sh.host.name, 13, 10);
1125 else
1126 fprintf(connFile, _("HELO %s%c%c"), sh.host.name, 13, 10);
1127
1128 (void) fflush(connFile);
1129
[131]1130 if (0 == sh_mail_wait(250, fd))
[1]1131 {
1132 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1133 _("HELO failed"), _("sh_mail_start_conn"),
1134 _("mail"), sh.host.name);
1135
1136 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1137 (void) fclose(connFile);
1138 SL_RETURN( NULL, _("sh_mail_start_conn"));
1139 }
1140
1141 /* tell them who we are
1142 */
1143 (void) sl_strlcpy (this_address,
1144 mail_sender ? mail_sender : DEFAULT_SENDER, 256);
1145 if (NULL == strchr(this_address, '@'))
1146 {
1147 (void) sl_strlcat (this_address, "@", 256);
1148 if (0 != is_numeric(sh.host.name))
1149 (void) sl_strlcat (this_address, _("example.com"), 256);
1150 else
1151 (void) sl_strlcat (this_address, sh.host.name, 256);
1152 }
1153
1154 TPT(( 0, FIL__, __LINE__, _("msg=<MAIL FROM:<%s>>%c%c"),
1155 this_address, 13, 10));
1156
1157 (void) fflush(connFile);
1158 /*@-usedef@*/
1159 fprintf(connFile, _("MAIL FROM:<%s>%c%c"), this_address, 13, 10);
1160 /*@+usedef@*/
1161 (void) fflush(connFile);
1162
[131]1163 if (0 == sh_mail_wait(250, fd))
[1]1164 {
1165 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1166 _("MAIL FROM failed"), _("sh_mail_start_conn"),
1167 _("mail"), this_address);
1168 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1169 (void) fclose(connFile);
1170 SL_RETURN( NULL, _("sh_mail_start_conn"));
1171 }
1172
1173 /* tell them who to send mail to
1174 */
[214]1175 if (aFlag == 0)
[1]1176 {
1177 TPT(( 0, FIL__, __LINE__, _("msg=<RCPT TO:<%s>>%c%c"),
1178 address, 13, 10));
1179
1180 (void) fflush(connFile);
1181 fprintf(connFile, _("RCPT TO:<%s>%c%c"), address, 13, 10);
1182 (void) fflush(connFile);
1183
[131]1184 if (0 == sh_mail_wait(250, fd))
[1]1185 {
1186 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1187 _("RCPT TO failed"), _("sh_mail_start_conn"),
1188 _("mail"), address);
1189 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1190 (void) fclose(connFile);
1191 SL_RETURN( NULL, _("sh_mail_start_conn"));
1192 }
[214]1193 *anum = 1;
[1]1194 }
1195 else
1196 {
[214]1197 int address_num = 0;
1198 ecount = 0;
1199
1200 ma_address = all_recipients;
1201
1202 while (ma_address)
[1]1203 {
[214]1204 if (ma_address->send_mail != 1)
1205 {
1206 ma_address = ma_address->next;
1207 continue;
1208 }
1209
1210 ++address_num;
1211
[1]1212 TPT(( 0, FIL__, __LINE__, _("msg=<RCPT TO:<%s>>%c%c"),
[214]1213 sh_string_str(ma_address->recipient), 13, 10));
[1]1214
1215 (void) fflush(connFile);
[214]1216 fprintf(connFile, _("RCPT TO:<%s>%c%c"),
1217 sh_string_str(ma_address->recipient), 13, 10);
[1]1218 (void) fflush(connFile);
1219
[131]1220 if (0 == sh_mail_wait(250, fd))
[1]1221 {
1222 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1223 _("RCPT TO failed"), _("sh_mail_start_conn"),
[214]1224 _("mail"), sh_string_str(ma_address->recipient));
[1]1225
1226 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1227 ++ecount;
1228 }
[214]1229 ma_address = ma_address->next;
[1]1230 }
[214]1231
1232 *anum += address_num;
1233
[1]1234 if (ecount == address_num)
1235 {
1236 (void) fclose(connFile);
1237 SL_RETURN( NULL, _("sh_mail_start_conn"));
1238 }
1239 }
1240
1241 /* Send the message
1242 */
1243 TPT(( 0, FIL__, __LINE__, _("msg=<DATA>%c%c"), 13, 10));
1244
1245 (void) fflush(connFile);
1246 fprintf(connFile, _("DATA%c%c"), 13, 10);
1247 (void) fflush(connFile);
1248
[131]1249 if (0 == sh_mail_wait(354, fd))
[1]1250 {
1251 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1252 _("DATA failed"), _("sh_mail_start_conn"),
1253 _("mail"), address);
1254 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1255 (void) fclose(connFile);
1256 SL_RETURN( NULL, _("sh_mail_start_conn"));
1257 }
1258
1259
1260 my_time = time(NULL);
[131]1261#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
1262 my_tm = localtime_r(&my_time, &time_tm);
1263#else
[1]1264 my_tm = localtime(&my_time);
[131]1265#endif
[238]1266
1267#if defined(HAVE_STRFTIME_Z)
1268 (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %z"), my_tm);
1269#else
[1]1270 (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %Z"), my_tm);
[238]1271#endif
[1]1272
1273 TPT(( 0, FIL__, __LINE__, _("msg=<From: <%s>%c%cTo: <%s>%c%cDate: %s>%c%c"),
1274 this_address, 13, 10, address, 13, 10, my_tbuf, 13, 10));
1275
1276 (void) fflush(connFile);
1277 fprintf(connFile,
1278 _("From: <%s>%c%c"\
1279 "To: <%s>%c%c"\
1280 "Date: %s%c%c"),
1281 this_address, 13, 10,
1282 address, 13, 10,
1283 my_tbuf, 13, 10);
1284
[131]1285 *ma_socket = fd;
[1]1286 SL_RETURN( connFile, _("sh_mail_start_conn"));
1287}
1288
1289/*************************
1290 *
1291 * end connection
1292 *
1293 */
1294
[131]1295static int sh_mail_end_conn (FILE * connFile, int fd)
[1]1296{
1297 SL_ENTER(_("sh_mail_end_conn"));
1298
1299 time_wait = 300;
1300
1301 (void) fflush(connFile);
1302 fprintf(connFile, _("%c%c.%c%c"), 13, 10, 13, 10);
1303 (void) fflush(connFile);
1304
1305 TPT(( 0, FIL__, __LINE__, _("msg=<message end written>\n")));
1306
[131]1307 if (0 != sh_mail_wait(250, fd))
[1]1308 {
1309 (void) fflush(connFile);
1310 fprintf(connFile, _("QUIT%c%c"), 13, 10);
1311 (void) fflush(connFile);
1312 TPT(( 0, FIL__, __LINE__, _("msg=<exit>\n")));
1313
1314 SL_RETURN (0, _("sh_mail_end_conn"));
1315 }
1316
1317 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1318 _("QUIT failed"), _("sh_mail_end_conn"),
1319 _("mail"), _("SMTP server"));
1320
1321 TPT(( 0, FIL__, __LINE__, _("msg=<abnormal exit>\n")));
1322
1323 SL_RETURN ((-1), _("sh_mail_end_conn"));
1324}
1325
1326
1327
1328/****************************
1329 *
1330 * Handle server replies
1331 *
1332 *
1333 */
1334
[131]1335static int sh_mail_wait(int code, int ma_socket)
[1]1336{
[131]1337 int rcode, g;
[1]1338
[131]1339 char c;
[1]1340
1341 char errmsg[128];
1342
1343 enum {
1344 WAIT_CODE_START,
1345 WAIT_CODE,
1346 WAIT_NL,
1347 WAIT_NL_CONT
1348 } state;
1349
1350 time_t waited_time;
1351
1352 SL_ENTER(_("mail_wait"));
1353
1354 waited_time = time(NULL);
1355
1356 /* timeout after 5 minutes
1357 */
1358
1359 rcode = 0;
1360 state = WAIT_CODE_START;
1361
[131]1362 while (sl_read_timeout_fd (ma_socket, &c, 1, time_wait, SL_FALSE) > 0) {
[1]1363
[131]1364 g = (int) c;
1365
[137]1366 /*
1367 if (g == EOF)
[1]1368 {
1369 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: EOF>\n")));
1370 SL_RETURN( 0, _("mail_wait"));
1371 }
[137]1372 */
[1]1373
1374 switch(state) {
1375
1376 /* wait for start of a numerical code
1377 */
1378 case WAIT_CODE_START:
1379 if (0 != isspace(g))
1380 break; /* Skip white space */
1381 if (0 == isdigit(g))
1382 return 0; /* No leading number */
1383 rcode = g-(int)'0'; /* convert to number */
1384 state = WAIT_CODE;
1385 break;
1386
1387 /* wait for completion of numerical code
1388 */
1389 case WAIT_CODE:
1390 if (0 != isdigit(g)) {
1391 rcode = rcode * 10 + (g-(int)'0'); /* next digit */
1392 break;
1393 }
1394 /*@+charintliteral@*/
1395 state = ((g == '-') ? WAIT_NL_CONT : WAIT_NL);
1396 /*@-charintliteral@*/
1397 break;
1398
1399 /* wait for newline, then return with status code
1400 */
1401 case WAIT_NL:
1402 /*@+charintliteral@*/
1403 if (g != '\n')
1404 break;
1405 /*@-charintliteral@*/
1406
1407 TPT((0, FIL__, __LINE__,
1408 _("msg=<mail_wait: OK got %d (%d) need %d (%d)>\n"),
1409 rcode, (int)(rcode/100), code, (int)(code/100) ));
1410 g = ((int)(rcode/100) == (int)(code/100)) ? 1 : 0;
1411 if (g != 1)
1412 {
[22]1413 sl_snprintf(errmsg, sizeof(errmsg),
1414 _("Bad response (%d), expected %d"), rcode, code);
1415
[1]1416 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1417 errmsg, _("sh_mail_wait"),
1418 _("mail"), _("SMTP server"));
1419 }
1420 waited_time = time(NULL) - waited_time;
1421 time_wait -= waited_time;
1422 TPT((0, FIL__, __LINE__,
1423 _("msg=<mail_wait: time_wait reduced to %d sec>\n"),
1424 (int) time_wait));
1425 SL_RETURN( (g), _("mail_wait")) ;
1426
1427 /* wait for continuation line
1428 */
1429 /*@fallthrough@*//* no, but splint doesn't understand */
1430 case WAIT_NL_CONT:
1431 /*@+charintliteral@*/
1432 if (g == '\n')
1433 state = WAIT_CODE_START; /* There is a continuation line */
1434 /*@-charintliteral@*/
1435 break;
1436
1437 default:
1438
1439 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: bad>\n")));
1440 SL_RETURN( 0, _("mail_wait"));
1441
1442 }
1443 }
1444
1445 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: failed>\n")));
1446
1447 /* Failed, EOF or error on socket */
1448 SL_RETURN( 0, _("mail_wait"));
1449}
1450
1451/* -- function to insert "\r\n" after each 998 chars --
1452 */
1453
1454#define SPLIT_AT 998
1455
[214]1456static char * split_string(const char * str)
[1]1457{
1458 size_t size;
1459 size_t blocks;
1460 int count = 0;
1461
1462 char * p, * p0;
[214]1463 const char * q;
[1]1464
1465 if (!str)
1466 return NULL;
1467
[34]1468 size = strlen(str) + 1;
[1]1469 blocks = 1 + (size / SPLIT_AT);
1470
[34]1471 if (sl_ok_muls(2, blocks) && sl_ok_adds(size, (2*blocks)))
1472 {
1473 size = size + (2*blocks);
1474 }
1475 else
1476 {
1477 /* integer overflow, do not split */
1478 p = sh_util_strdup(str);
1479 return p;
1480 }
1481
[1]1482 p = SH_ALLOC(size);
1483 memset(p, 0, size);
[34]1484
[1]1485 p0 = p;
1486
1487 q = str;
1488 while (*q != '\0') {
1489 *p = *q;
1490 ++p;
1491 ++q;
1492 ++count;
1493 if (0 == (count % SPLIT_AT)) {
1494 count = 0;
1495 *p = '\r';
1496 ++p;
1497 *p = '\n';
1498 ++p;
1499 }
1500 }
1501 /* fprintf(stderr, "used = %d\n", strlen(p0)); */
1502
1503 return p0;
1504}
1505
1506
1507
1508/*****************************************************************
1509 *
1510 * MX Resolver Routines
1511 *
1512 *****************************************************************/
1513
1514#if defined(HAVE_ARPA_NAMESER_H)
1515
1516#include <netinet/in.h>
1517#ifdef __APPLE__
1518#define BIND_8_COMPAT 1
1519#endif
1520#ifndef S_SPLINT_S
1521#include <arpa/nameser.h>
1522#include <resolv.h>
1523#endif
1524#include <netdb.h>
1525#include <sys/socket.h>
1526#ifndef S_SPLINT_S
1527#include <arpa/inet.h>
1528#endif
1529
1530#include "sh_tools.h"
1531
1532#ifndef HFIXEDSZ
1533#define HFIXEDSZ 12
1534#endif
1535#ifndef QFIXEDSZ
1536#define QFIXEDSZ 4
1537#endif
1538
1539/*@unused@*//* used in get_mx() which is not parsed by splint */
1540static unsigned int get_short (unsigned char * loc)
1541{
1542 unsigned int retval = 0;
1543 if (loc)
1544 {
1545 /* byte order: MSB first
1546 */
1547 /*@+charint@*/
1548 retval = (((unsigned char) * loc) * 256) | ((unsigned char) * (loc + 1));
1549 /*@-charint@*/
1550 }
1551 return (retval);
1552}
1553
1554/* parser errors with splint */
1555#ifndef S_SPLINT_S
1556static dnsrep * get_mx (char *hostname)
1557{
1558 int ret, length, status;
1559 mx * result;
[22]1560 size_t len;
[1]1561
1562 typedef union
1563 {
1564 HEADER head;
1565 unsigned char buffer[4096];
1566 } querybuf;
1567
[171]1568 querybuf * reply;
[1]1569 char expanded[1024];
1570 unsigned char * comp_dn, * eom;
1571 HEADER * header;
[34]1572 int type, rdlength, pref;
[170]1573 unsigned int count, theindex;
[1]1574 dnsrep * retval;
1575
1576 SL_ENTER(_("get_mx"));
1577
1578 if (0 != res_init ())
1579 SL_RETURN (NULL, _("get_mx"));
1580
[171]1581 reply = SH_ALLOC(sizeof(querybuf));
1582
[1]1583 errno = 0;
1584 length = res_query (hostname, C_IN, T_MX,
[171]1585 (unsigned char *) reply, 4095);
[240]1586
[1]1587 if (length < 1)
1588 {
[132]1589 char errbuf[SH_ERRBUF_SIZE];
1590
[1]1591 /* error handling
1592 */
1593 if (length == -1)
1594 {
1595 if (errno == ECONNREFUSED)
1596 status = ECONNREFUSED;
1597 else
1598 status = h_errno;
1599
1600#ifdef FIL__
1601 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
1602 (errno == ECONNREFUSED) ?
[132]1603 sh_error_message (status, errbuf, sizeof(errbuf)) :
1604 sh_tools_errmessage(status, errbuf, sizeof(errbuf)),
[1]1605 _("res_query"));
1606#else
1607 if (errno == ECONNREFUSED)
[132]1608 fprintf(stderr, " ERROR: %s: \n", strerror(errno)); /* TESTONLY */
[1]1609 else
[132]1610 fprintf(stderr, "HERROR: %s\n", hstrerror(h_errno));/* TESTONLY */
[1]1611#endif
1612 }
[171]1613 SH_FREE(reply);
[1]1614 SL_RETURN (NULL, _("get_mx"));
1615 }
1616
1617 ret = 0;
[171]1618 header = (HEADER *) reply;
[1]1619
1620 /* start of data section
1621 */
[171]1622 comp_dn = (unsigned char *) reply + HFIXEDSZ;
[1]1623
1624 /* end-of-message
1625 */
[171]1626 eom = (unsigned char *) reply + length;
[1]1627
1628 /* HEADER NAME -- must be skipped or decompressed
1629 * TYPE -- type of data we got back, 16 bit integer
1630 * CLASS -- class we got back, also a 16 bit integer
1631 * TTL -- 32 bit time-to-live. just skip this
1632 * RDLENGTH -- length of the data to follow
1633 * RDATA -- the data:
1634 * PREF -- 16 bit preference
1635 * MX -- name of mail exchanger, must be decompressed
1636 */
1637
1638 /* Skip the query data.
1639 * QDCOUNT is the number of entries (unsigned 16 bit int).
1640 */
1641 count = ntohs (header->qdcount);
[170]1642 for (theindex = 0; theindex < count; ++theindex)
[1]1643 {
1644 ret = dn_skipname (comp_dn, eom);
1645 comp_dn += ret + QFIXEDSZ;
1646 if (ret < 1 || comp_dn >= eom)
[171]1647 {
1648 SH_FREE(reply);
1649 SL_RETURN (NULL, _("get_mx"));
1650 }
[1]1651 }
[240]1652
[1]1653 count = ntohs (header->ancount);
1654 if (count < 1)
[171]1655 {
1656 SH_FREE(reply);
1657 SL_RETURN (NULL, _("get_mx"));
1658 }
[1]1659
1660 retval = SH_ALLOC (sizeof (dnsrep));
1661 if (!retval)
[171]1662 {
1663 SH_FREE(reply);
1664 SL_RETURN (NULL, _("get_mx"));
1665 }
1666
[1]1667 retval->count = count;
1668
1669 /* allocate space for the results */
1670
[34]1671 if (!sl_ok_muls(count, sizeof (mx)))
1672 {
[171]1673 SH_FREE(reply);
[34]1674 SH_FREE (retval);
1675 SL_RETURN (NULL, _("get_mx"));
1676 }
1677
[1]1678 result = SH_ALLOC (count * sizeof (mx));
[34]1679
[1]1680 if (!result)
1681 {
[171]1682 SH_FREE(reply);
[1]1683 SH_FREE (retval);
1684 SL_RETURN (NULL, _("get_mx"));
1685 }
1686 retval->reply = result;
1687
1688 do
1689 {
1690 /* HEADER NAME
1691 */
[240]1692 ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
[1]1693 (char *) expanded, 1023);
1694 comp_dn += ret;
1695 if (ret < 1 || comp_dn >= eom)
1696 {
[171]1697 SH_FREE(reply);
[1]1698 SH_FREE (result);
1699 SH_FREE (retval);
1700 SL_RETURN (NULL, _("get_mx"));
1701 }
1702
1703 /* TYPE
1704 */
1705 type = get_short (comp_dn);
1706 comp_dn += 2;
1707 if (type != T_MX || comp_dn >= eom)
1708 {
[171]1709 SH_FREE(reply);
[1]1710 SH_FREE (result);
1711 SH_FREE (retval);
1712 SL_RETURN (NULL, _("get_mx"));
1713 }
1714
[240]1715
[1]1716 /* CLASS (re-use 'type' var)
1717 */
1718 type = get_short (comp_dn);
1719 comp_dn += 2;
1720 if (comp_dn >= eom)
1721 {
[171]1722 SH_FREE(reply);
[1]1723 SH_FREE (result);
1724 SH_FREE (retval);
1725 SL_RETURN (NULL, _("get_mx"));
1726 }
1727
[240]1728
[1]1729 /* TTL
1730 */
1731 comp_dn += 4;
1732 if (comp_dn >= eom)
1733 {
[171]1734 SH_FREE(reply);
[1]1735 SH_FREE (result);
1736 SH_FREE (retval);
1737 SL_RETURN (NULL, _("get_mx"));
1738 }
1739
1740 /* RDLENGTH
1741 */
1742 rdlength = get_short (comp_dn);
1743 comp_dn += 2;
1744 if (rdlength < 1 || comp_dn >= eom)
1745 {
[171]1746 SH_FREE(reply);
[1]1747 SH_FREE (result);
1748 SH_FREE (retval);
1749 SL_RETURN (NULL, _("get_mx"));
1750 }
1751
1752 /* RDATA
1753 */
1754 pref = get_short (comp_dn);
1755 comp_dn += 2;
1756 if (comp_dn >= eom)
1757 {
[171]1758 SH_FREE(reply);
[1]1759 SH_FREE (result);
1760 SH_FREE (retval);
1761 SL_RETURN (NULL, _("get_mx"));
1762 }
1763
[240]1764 ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
[1]1765 (char *) expanded, 1023);
1766 comp_dn += ret;
1767 if (ret < 1)
1768 {
[171]1769 SH_FREE(reply);
[1]1770 SH_FREE (result);
1771 SH_FREE (retval);
1772 SL_RETURN (NULL, _("get_mx"));
1773 }
1774 count--;
1775
1776 /* fill in the struct
1777 */
1778 result[count].pref = pref;
[22]1779 len = strlen (expanded) + 1;
1780 result[count].address = SH_ALLOC (len);
1781 sl_strlcpy (result[count].address, expanded, len);
[1]1782 }
1783 while (ret > 0 && comp_dn < eom && count);
1784
[171]1785 SH_FREE(reply);
[1]1786 SL_RETURN (retval, _("get_mx"));
1787}
1788/* ifndef S_SPLINT_S */
1789#endif
1790
1791/* #if defined(HAVE_ARPA_NAMESER_H) */
1792#endif
1793
1794
1795static int comp_mx_pref (const void * a, const void * b)
1796{
1797 const mx * ax = (const mx *) a;
1798 const mx * bx = (const mx *) b;
1799
1800 if (ax->pref > bx->pref)
1801 return 1;
1802 else if (ax->pref < bx->pref)
1803 return -1;
1804 else
1805 return 0;
1806}
1807
1808/*
1809 * return_mx returns a list of valid mail exchangers for domain
1810 */
1811static dnsrep * return_mx (char *domain)
1812{
[170]1813 struct hostent *host;
[1]1814 dnsrep * answers = NULL;
1815 mx * result;
[170]1816 dnsrep * retval;
[22]1817 char errmsg[128];
1818 size_t len;
[1]1819
1820 SL_ENTER(_("return_mx"));
1821
1822#if defined(HAVE_ARPA_NAMESER_H)
1823 if (domain != NULL)
1824 answers = /*@-unrecog@*/get_mx (domain)/*@+unrecog@*/;
1825#endif
1826
1827 if (answers != NULL && answers->count > 0)
1828 {
1829 qsort(answers->reply, (size_t) answers->count, sizeof(mx),
1830 comp_mx_pref);
1831 SL_RETURN (answers, _("return_mx"));
1832 }
1833 else
1834 {
1835 if (domain != NULL)
1836 {
1837#if defined(HAVE_ARPA_NAMESER_H)
1838#ifdef FIL__
1839 (void) sl_strlcpy (errmsg, _("No MX record for domain "), 127);
1840 (void) sl_strlcat (errmsg, domain, 127);
1841 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1842 errmsg,
1843 _("get_mx"));
1844#else
[22]1845 /* flawfinder: ignore *//* test code only */
[1]1846 strcpy (errmsg, /* known to fit */
1847 _("No MX record for domain "));
1848 strncat (errmsg, domain, 100);
1849 errmsg[122] = '\0';
1850 fprintf(stderr, "Warning: %s\n", errmsg);
1851#endif
1852#endif
1853 }
[134]1854
1855 SH_MUTEX_LOCK(mutex_resolv);
[170]1856
1857 host = NULL;
1858 retval = NULL;
1859
[1]1860 if (domain != NULL)
1861 host = /*@-unrecog@*/sh_gethostbyname (domain)/*@+unrecog@*/;
[134]1862
1863 if (host)
1864 {
1865 result = SH_ALLOC (sizeof (mx));
1866 retval = SH_ALLOC (sizeof (dnsrep));
1867 retval->reply = result;
1868 retval->count = 1;
1869 result->pref = 0;
1870 /*@-type@*/
1871 len = strlen (host->h_name) + 1;
1872 result->address = SH_ALLOC (len);
1873 sl_strlcpy (result->address, host->h_name, len);
1874 /*@+type@*/
1875 }
1876 SH_MUTEX_UNLOCK(mutex_resolv);
1877
[1]1878 if (!host)
1879 {
1880#ifdef FIL__
1881 (void) sl_strlcpy (errmsg, _("Unknown host "), 127);
1882 (void) sl_strlcat (errmsg, domain, 127);
1883 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1884 errmsg,
1885 _("return_mx"));
1886#endif
1887 SL_RETURN (NULL, _("return_mx"));
1888 }
[134]1889
[1]1890 SL_RETURN (retval, _("return_mx"));
1891 }
1892}
1893
[214]1894int free_mx (dnsrep * answers)
[1]1895{
1896 mx * result;
1897 int i;
1898
1899 SL_ENTER(_("free_mx"));
1900 if (!answers)
1901 SL_RETURN (0, _("return_mx"));
1902
1903 result = answers->reply;
1904 for (i = 0; i < answers->count; ++i)
1905 {
1906 SH_FREE (result[i].address);
1907 }
1908 SH_FREE(result);
1909 SH_FREE(answers);
1910 SL_RETURN (0, _("return_mx"));
1911}
1912
1913#ifdef TEST_ONLY
1914int main(int argc, char * argv[])
1915{
1916 int i;
1917 dnsrep * answers;
1918 mx * result;
1919
1920 if (argc < 2)
1921 {
1922 fprintf(stderr, "Usage: dns <hostname>\n");
1923 return -1;
1924 }
1925 answers = return_mx(argv[1]);
1926
1927 if (!answers)
1928 {
1929 fprintf(stderr, "No answer\n");
1930 return -1;
1931 }
1932
1933 if (answers->count > 0)
1934 {
1935 result = answers->reply;
1936 for (i = 0; i < answers->count; ++i)
1937 {
1938 fprintf(stderr, "Record %3d: [%3d] %s\n", i,
1939 result[i].pref, result[i].address);
1940 }
1941 }
1942 else
1943 {
1944 fprintf(stderr, "No answer\n");
1945 free_mx(answers);
1946 return -1;
1947 }
1948 free_mx(answers);
1949 return (0);
1950}
1951#endif
1952
1953
1954
1955/* if defined(SH_WITH_MAIL) */
1956#endif
1957
1958
1959
Note: See TracBrowser for help on using the repository browser.