source: trunk/src/sh_mail.c@ 215

Last change on this file since 215 was 215, checked in by katerina, 16 years ago

Consolidate filtering code (ticket #142) and match on regular expressions (ticket #143).

File size: 43.4 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
918
919/*************************
920 *
921 * start connection
[214]922 * for details on SMTP, see RFC 821
923 *
924 * If ma_address == NULL, will send to all marked with
925 * send_mail=1 in recipient list, else to ma_address.
[1]926 */
927
928static time_t time_wait = 300;
929
[214]930static FILE * sh_mail_start_conn (struct alias * ma_address,
931 int * ma_socket, int * anum)
[1]932{
933 char * address;
[214]934 int aFlag = 0;
[1]935
936 int ecount;
937
938 char this_address[256];
939 char ma_machine[256];
940 char ma_user[256];
941 char error_msg[256];
942 char error_call[SH_MINIBUF];
943 int error_num = 0;
944 register int i, j, k;
945 FILE * connFile = NULL;
946 struct tm * my_tm;
[131]947#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
948 struct tm time_tm;
949#endif
[1]950 time_t my_time;
951 char my_tbuf[128];
952
953 int fd;
954
955 dnsrep * answers;
956 mx * result;
957
958 SL_ENTER(_("sh_mail_start_conn"));
959
[131]960 *ma_socket = -1;
961 time_wait = 300;
[1]962
[214]963 if (ma_address == NULL)
964 {
965 aFlag = 1;
966 ma_address = all_recipients;
[1]967
[214]968 while (ma_address)
969 {
970 if (ma_address->send_mail == 1)
971 break;
972 ma_address = ma_address->all_next;
973 }
974 }
[1]975
[214]976 if (!ma_address)
[1]977 {
978 SL_RETURN( NULL, _("sh_mail_start_conn"));
979 }
[214]980
981 address = sh_string_str(ma_address->recipient);
982
983 TPT(( 0, FIL__, __LINE__, _("msg=<address %s>\n"),
984 address));
985
986 /* ------- split adress ------------------ */
987
[1]988 if (strchr (address, '@') == NULL) {
989 (void) sl_strlcpy(ma_user, address, 256);
990 (void) sl_strlcpy(ma_machine, _("localhost"), 256);
991 } else {
992 i = 0;
993 while (i < 255 && address[i] != '@') {
994 ma_user[i] = address[i];
995 ++i;
996 }
[214]997
[1]998 /* adress[i] = '@'
999 */
1000 ma_user[i] = '\0';
1001 j = i + 1; k = i; i = 0;
1002 while (i < 255 && address[i+j] != '\0') {
1003 ma_machine[i] = address[i+j];
1004 ++i;
1005 }
1006 ma_machine[i] = '\0';
1007 if (address[k] != '@' || address[k+i+1] != '\0')
1008 {
1009 SL_RETURN( NULL, _("sh_mail_start_conn"));
1010 }
1011 }
1012
1013
1014 if (relay_host != NULL)
1015 {
1016 (void) sl_strlcpy (ma_machine, relay_host, sizeof(ma_machine));
1017 TPT((0, FIL__, __LINE__, _("msg=<user %s machine %s>\n"),
1018 ma_user, ma_machine));
1019 fd = connect_port (ma_machine, IPPORT_SMTP,
1020 error_call, &error_num, error_msg, 256);
1021 }
1022 else
1023 {
[214]1024 answers = ma_address->mx_list;
1025 if (!answers)
1026 {
1027 answers = return_mx (ma_machine);
1028 ma_address->mx_list = answers;
1029 }
1030
[1]1031 if (answers)
1032 {
1033 result = answers->reply;
1034 fd = -1;
1035 for (i = 0; i < answers->count; ++i)
1036 {
1037 (void) sl_strlcpy(ma_machine, result[i].address,
1038 sizeof(ma_machine));
1039 TPT((0, FIL__, __LINE__,
1040 _("msg=<user %s mx %s pref %d>\n"),
1041 ma_user, ma_machine, result[i].pref));
1042 fd = connect_port (ma_machine, IPPORT_SMTP,
1043 error_call, &error_num, error_msg, 256);
1044 if (fd >= 0)
1045 break;
1046 }
1047 }
1048 else
1049 {
1050 (void) sl_strlcpy(error_call, _("return_mx"), SH_MINIBUF);
1051 (void) sl_strlcpy(error_msg, _("The specified host is unknown: "),
1052 256);
1053 (void) sl_strlcat(error_msg, ma_machine, 256);
1054 fd = -1;
1055 }
1056 }
1057
1058
1059 if (fd < 0)
1060 {
1061 sh_error_handle ((-1), FIL__, __LINE__, error_num,
1062 MSG_E_NET, error_msg, error_call,
1063 _("email"), ma_machine);
1064 SL_RETURN( NULL, _("sh_mail_start_conn"));
1065 }
1066
1067 /* associate a FILE structure with it
1068 */
1069 connFile = fdopen (fd, "r+");
1070 if (connFile == NULL)
1071 {
1072 TPT(( 0, FIL__, __LINE__, _("msg=<fdopen() failed>\n")));
1073 (void) close(fd);
1074 SL_RETURN( NULL, _("sh_mail_start_conn"));
1075 }
1076
1077
1078 /* say HELO to the other socket
1079 */
[131]1080 if (0 == sh_mail_wait (220, fd))
[1]1081 {
1082 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1083 _("Timeout on SMTP session init"),
1084 _("sh_mail_start_conn"),
1085 _("mail"), sh.host.name);
1086 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout>\n")));
1087 (void) fclose(connFile);
1088 SL_RETURN( NULL, _("sh_mail_start_conn"));
1089 }
1090
1091 (void) fflush(connFile);
1092
1093 if (0 != is_numeric(sh.host.name))
1094 {
1095 TPT(( 0, FIL__, __LINE__, _("msg=<HELO [%s]>%c%c"),
1096 sh.host.name, 13, 10));
1097 }
1098 else
1099 {
1100 TPT(( 0, FIL__, __LINE__, _("msg=<HELO %s>%c%c"),
1101 sh.host.name, 13, 10));
1102 }
1103 if (0 != is_numeric(sh.host.name))
1104 fprintf(connFile, _("HELO [%s]%c%c"), sh.host.name, 13, 10);
1105 else
1106 fprintf(connFile, _("HELO %s%c%c"), sh.host.name, 13, 10);
1107
1108 (void) fflush(connFile);
1109
[131]1110 if (0 == sh_mail_wait(250, fd))
[1]1111 {
1112 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1113 _("HELO failed"), _("sh_mail_start_conn"),
1114 _("mail"), sh.host.name);
1115
1116 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1117 (void) fclose(connFile);
1118 SL_RETURN( NULL, _("sh_mail_start_conn"));
1119 }
1120
1121 /* tell them who we are
1122 */
1123 (void) sl_strlcpy (this_address,
1124 mail_sender ? mail_sender : DEFAULT_SENDER, 256);
1125 if (NULL == strchr(this_address, '@'))
1126 {
1127 (void) sl_strlcat (this_address, "@", 256);
1128 if (0 != is_numeric(sh.host.name))
1129 (void) sl_strlcat (this_address, _("example.com"), 256);
1130 else
1131 (void) sl_strlcat (this_address, sh.host.name, 256);
1132 }
1133
1134 TPT(( 0, FIL__, __LINE__, _("msg=<MAIL FROM:<%s>>%c%c"),
1135 this_address, 13, 10));
1136
1137 (void) fflush(connFile);
1138 /*@-usedef@*/
1139 fprintf(connFile, _("MAIL FROM:<%s>%c%c"), this_address, 13, 10);
1140 /*@+usedef@*/
1141 (void) fflush(connFile);
1142
[131]1143 if (0 == sh_mail_wait(250, fd))
[1]1144 {
1145 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1146 _("MAIL FROM failed"), _("sh_mail_start_conn"),
1147 _("mail"), this_address);
1148 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1149 (void) fclose(connFile);
1150 SL_RETURN( NULL, _("sh_mail_start_conn"));
1151 }
1152
1153 /* tell them who to send mail to
1154 */
[214]1155 if (aFlag == 0)
[1]1156 {
1157 TPT(( 0, FIL__, __LINE__, _("msg=<RCPT TO:<%s>>%c%c"),
1158 address, 13, 10));
1159
1160 (void) fflush(connFile);
1161 fprintf(connFile, _("RCPT TO:<%s>%c%c"), address, 13, 10);
1162 (void) fflush(connFile);
1163
[131]1164 if (0 == sh_mail_wait(250, fd))
[1]1165 {
1166 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1167 _("RCPT TO failed"), _("sh_mail_start_conn"),
1168 _("mail"), address);
1169 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1170 (void) fclose(connFile);
1171 SL_RETURN( NULL, _("sh_mail_start_conn"));
1172 }
[214]1173 *anum = 1;
[1]1174 }
1175 else
1176 {
[214]1177 int address_num = 0;
1178 ecount = 0;
1179
1180 ma_address = all_recipients;
1181
1182 while (ma_address)
[1]1183 {
[214]1184 if (ma_address->send_mail != 1)
1185 {
1186 ma_address = ma_address->next;
1187 continue;
1188 }
1189
1190 ++address_num;
1191
[1]1192 TPT(( 0, FIL__, __LINE__, _("msg=<RCPT TO:<%s>>%c%c"),
[214]1193 sh_string_str(ma_address->recipient), 13, 10));
[1]1194
1195 (void) fflush(connFile);
[214]1196 fprintf(connFile, _("RCPT TO:<%s>%c%c"),
1197 sh_string_str(ma_address->recipient), 13, 10);
[1]1198 (void) fflush(connFile);
1199
[131]1200 if (0 == sh_mail_wait(250, fd))
[1]1201 {
1202 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1203 _("RCPT TO failed"), _("sh_mail_start_conn"),
[214]1204 _("mail"), sh_string_str(ma_address->recipient));
[1]1205
1206 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1207 ++ecount;
1208 }
[214]1209 ma_address = ma_address->next;
[1]1210 }
[214]1211
1212 *anum += address_num;
1213
[1]1214 if (ecount == address_num)
1215 {
1216 (void) fclose(connFile);
1217 SL_RETURN( NULL, _("sh_mail_start_conn"));
1218 }
1219 }
1220
1221 /* Send the message
1222 */
1223 TPT(( 0, FIL__, __LINE__, _("msg=<DATA>%c%c"), 13, 10));
1224
1225 (void) fflush(connFile);
1226 fprintf(connFile, _("DATA%c%c"), 13, 10);
1227 (void) fflush(connFile);
1228
[131]1229 if (0 == sh_mail_wait(354, fd))
[1]1230 {
1231 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1232 _("DATA failed"), _("sh_mail_start_conn"),
1233 _("mail"), address);
1234 TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1235 (void) fclose(connFile);
1236 SL_RETURN( NULL, _("sh_mail_start_conn"));
1237 }
1238
1239
1240 my_time = time(NULL);
[131]1241#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
1242 my_tm = localtime_r(&my_time, &time_tm);
1243#else
[1]1244 my_tm = localtime(&my_time);
[131]1245#endif
[1]1246 (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %Z"), my_tm);
1247
1248 TPT(( 0, FIL__, __LINE__, _("msg=<From: <%s>%c%cTo: <%s>%c%cDate: %s>%c%c"),
1249 this_address, 13, 10, address, 13, 10, my_tbuf, 13, 10));
1250
1251 (void) fflush(connFile);
1252 fprintf(connFile,
1253 _("From: <%s>%c%c"\
1254 "To: <%s>%c%c"\
1255 "Date: %s%c%c"),
1256 this_address, 13, 10,
1257 address, 13, 10,
1258 my_tbuf, 13, 10);
1259
[131]1260 *ma_socket = fd;
[1]1261 SL_RETURN( connFile, _("sh_mail_start_conn"));
1262}
1263
1264/*************************
1265 *
1266 * end connection
1267 *
1268 */
1269
[131]1270static int sh_mail_end_conn (FILE * connFile, int fd)
[1]1271{
1272 SL_ENTER(_("sh_mail_end_conn"));
1273
1274 time_wait = 300;
1275
1276 (void) fflush(connFile);
1277 fprintf(connFile, _("%c%c.%c%c"), 13, 10, 13, 10);
1278 (void) fflush(connFile);
1279
1280 TPT(( 0, FIL__, __LINE__, _("msg=<message end written>\n")));
1281
[131]1282 if (0 != sh_mail_wait(250, fd))
[1]1283 {
1284 (void) fflush(connFile);
1285 fprintf(connFile, _("QUIT%c%c"), 13, 10);
1286 (void) fflush(connFile);
1287 TPT(( 0, FIL__, __LINE__, _("msg=<exit>\n")));
1288
1289 SL_RETURN (0, _("sh_mail_end_conn"));
1290 }
1291
1292 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1293 _("QUIT failed"), _("sh_mail_end_conn"),
1294 _("mail"), _("SMTP server"));
1295
1296 TPT(( 0, FIL__, __LINE__, _("msg=<abnormal exit>\n")));
1297
1298 SL_RETURN ((-1), _("sh_mail_end_conn"));
1299}
1300
1301
1302
1303/****************************
1304 *
1305 * Handle server replies
1306 *
1307 *
1308 */
1309
[131]1310static int sh_mail_wait(int code, int ma_socket)
[1]1311{
[131]1312 int rcode, g;
[1]1313
[131]1314 char c;
[1]1315
1316 char errmsg[128];
1317
1318 enum {
1319 WAIT_CODE_START,
1320 WAIT_CODE,
1321 WAIT_NL,
1322 WAIT_NL_CONT
1323 } state;
1324
1325 time_t waited_time;
1326
1327 SL_ENTER(_("mail_wait"));
1328
1329 waited_time = time(NULL);
1330
1331 /* timeout after 5 minutes
1332 */
1333
1334 rcode = 0;
1335 state = WAIT_CODE_START;
1336
[131]1337 while (sl_read_timeout_fd (ma_socket, &c, 1, time_wait, SL_FALSE) > 0) {
[1]1338
[131]1339 g = (int) c;
1340
[137]1341 /*
1342 if (g == EOF)
[1]1343 {
1344 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: EOF>\n")));
1345 SL_RETURN( 0, _("mail_wait"));
1346 }
[137]1347 */
[1]1348
1349 switch(state) {
1350
1351 /* wait for start of a numerical code
1352 */
1353 case WAIT_CODE_START:
1354 if (0 != isspace(g))
1355 break; /* Skip white space */
1356 if (0 == isdigit(g))
1357 return 0; /* No leading number */
1358 rcode = g-(int)'0'; /* convert to number */
1359 state = WAIT_CODE;
1360 break;
1361
1362 /* wait for completion of numerical code
1363 */
1364 case WAIT_CODE:
1365 if (0 != isdigit(g)) {
1366 rcode = rcode * 10 + (g-(int)'0'); /* next digit */
1367 break;
1368 }
1369 /*@+charintliteral@*/
1370 state = ((g == '-') ? WAIT_NL_CONT : WAIT_NL);
1371 /*@-charintliteral@*/
1372 break;
1373
1374 /* wait for newline, then return with status code
1375 */
1376 case WAIT_NL:
1377 /*@+charintliteral@*/
1378 if (g != '\n')
1379 break;
1380 /*@-charintliteral@*/
1381
1382 TPT((0, FIL__, __LINE__,
1383 _("msg=<mail_wait: OK got %d (%d) need %d (%d)>\n"),
1384 rcode, (int)(rcode/100), code, (int)(code/100) ));
1385 g = ((int)(rcode/100) == (int)(code/100)) ? 1 : 0;
1386 if (g != 1)
1387 {
[22]1388 sl_snprintf(errmsg, sizeof(errmsg),
1389 _("Bad response (%d), expected %d"), rcode, code);
1390
[1]1391 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1392 errmsg, _("sh_mail_wait"),
1393 _("mail"), _("SMTP server"));
1394 }
1395 waited_time = time(NULL) - waited_time;
1396 time_wait -= waited_time;
1397 TPT((0, FIL__, __LINE__,
1398 _("msg=<mail_wait: time_wait reduced to %d sec>\n"),
1399 (int) time_wait));
1400 SL_RETURN( (g), _("mail_wait")) ;
1401
1402 /* wait for continuation line
1403 */
1404 /*@fallthrough@*//* no, but splint doesn't understand */
1405 case WAIT_NL_CONT:
1406 /*@+charintliteral@*/
1407 if (g == '\n')
1408 state = WAIT_CODE_START; /* There is a continuation line */
1409 /*@-charintliteral@*/
1410 break;
1411
1412 default:
1413
1414 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: bad>\n")));
1415 SL_RETURN( 0, _("mail_wait"));
1416
1417 }
1418 }
1419
1420 TPT((0, FIL__, __LINE__, _("msg=<mail_wait: failed>\n")));
1421
1422 /* Failed, EOF or error on socket */
1423 SL_RETURN( 0, _("mail_wait"));
1424}
1425
1426/* -- function to insert "\r\n" after each 998 chars --
1427 */
1428
1429#define SPLIT_AT 998
1430
[214]1431static char * split_string(const char * str)
[1]1432{
1433 size_t size;
1434 size_t blocks;
1435 int count = 0;
1436
1437 char * p, * p0;
[214]1438 const char * q;
[1]1439
1440 if (!str)
1441 return NULL;
1442
[34]1443 size = strlen(str) + 1;
[1]1444 blocks = 1 + (size / SPLIT_AT);
1445
[34]1446 if (sl_ok_muls(2, blocks) && sl_ok_adds(size, (2*blocks)))
1447 {
1448 size = size + (2*blocks);
1449 }
1450 else
1451 {
1452 /* integer overflow, do not split */
1453 p = sh_util_strdup(str);
1454 return p;
1455 }
1456
[1]1457 p = SH_ALLOC(size);
1458 memset(p, 0, size);
[34]1459
[1]1460 p0 = p;
1461
1462 q = str;
1463 while (*q != '\0') {
1464 *p = *q;
1465 ++p;
1466 ++q;
1467 ++count;
1468 if (0 == (count % SPLIT_AT)) {
1469 count = 0;
1470 *p = '\r';
1471 ++p;
1472 *p = '\n';
1473 ++p;
1474 }
1475 }
1476 /* fprintf(stderr, "used = %d\n", strlen(p0)); */
1477
1478 return p0;
1479}
1480
1481
1482
1483/*****************************************************************
1484 *
1485 * MX Resolver Routines
1486 *
1487 *****************************************************************/
1488
1489#if defined(HAVE_ARPA_NAMESER_H)
1490
1491#include <netinet/in.h>
1492#ifdef __APPLE__
1493#define BIND_8_COMPAT 1
1494#endif
1495#ifndef S_SPLINT_S
1496#include <arpa/nameser.h>
1497#include <resolv.h>
1498#endif
1499#include <netdb.h>
1500#include <sys/socket.h>
1501#ifndef S_SPLINT_S
1502#include <arpa/inet.h>
1503#endif
1504
1505#include "sh_tools.h"
1506
1507#ifndef HFIXEDSZ
1508#define HFIXEDSZ 12
1509#endif
1510#ifndef QFIXEDSZ
1511#define QFIXEDSZ 4
1512#endif
1513
1514/*@unused@*//* used in get_mx() which is not parsed by splint */
1515static unsigned int get_short (unsigned char * loc)
1516{
1517 unsigned int retval = 0;
1518 if (loc)
1519 {
1520 /* byte order: MSB first
1521 */
1522 /*@+charint@*/
1523 retval = (((unsigned char) * loc) * 256) | ((unsigned char) * (loc + 1));
1524 /*@-charint@*/
1525 }
1526 return (retval);
1527}
1528
1529/* parser errors with splint */
1530#ifndef S_SPLINT_S
1531static dnsrep * get_mx (char *hostname)
1532{
1533 int ret, length, status;
1534 mx * result;
[22]1535 size_t len;
[1]1536
1537 typedef union
1538 {
1539 HEADER head;
1540 unsigned char buffer[4096];
1541 } querybuf;
1542
[171]1543 querybuf * reply;
[1]1544 char expanded[1024];
1545 unsigned char * comp_dn, * eom;
1546 HEADER * header;
[34]1547 int type, rdlength, pref;
[170]1548 unsigned int count, theindex;
[1]1549 dnsrep * retval;
1550
1551 SL_ENTER(_("get_mx"));
1552
1553 if (0 != res_init ())
1554 SL_RETURN (NULL, _("get_mx"));
1555
[171]1556 reply = SH_ALLOC(sizeof(querybuf));
1557
[1]1558 errno = 0;
1559 length = res_query (hostname, C_IN, T_MX,
[171]1560 (unsigned char *) reply, 4095);
[1]1561 if (length < 1)
1562 {
[132]1563 char errbuf[SH_ERRBUF_SIZE];
1564
[1]1565 /* error handling
1566 */
1567 if (length == -1)
1568 {
1569 if (errno == ECONNREFUSED)
1570 status = ECONNREFUSED;
1571 else
1572 status = h_errno;
1573
1574#ifdef FIL__
1575 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, status, MSG_E_SUBGEN,
1576 (errno == ECONNREFUSED) ?
[132]1577 sh_error_message (status, errbuf, sizeof(errbuf)) :
1578 sh_tools_errmessage(status, errbuf, sizeof(errbuf)),
[1]1579 _("res_query"));
1580#else
1581 if (errno == ECONNREFUSED)
[132]1582 fprintf(stderr, " ERROR: %s: \n", strerror(errno)); /* TESTONLY */
[1]1583 else
[132]1584 fprintf(stderr, "HERROR: %s\n", hstrerror(h_errno));/* TESTONLY */
[1]1585#endif
1586 }
[171]1587 SH_FREE(reply);
[1]1588 SL_RETURN (NULL, _("get_mx"));
1589 }
1590
1591 ret = 0;
[171]1592 header = (HEADER *) reply;
[1]1593
1594 /* start of data section
1595 */
[171]1596 comp_dn = (unsigned char *) reply + HFIXEDSZ;
[1]1597
1598 /* end-of-message
1599 */
[171]1600 eom = (unsigned char *) reply + length;
[1]1601
1602 /* HEADER NAME -- must be skipped or decompressed
1603 * TYPE -- type of data we got back, 16 bit integer
1604 * CLASS -- class we got back, also a 16 bit integer
1605 * TTL -- 32 bit time-to-live. just skip this
1606 * RDLENGTH -- length of the data to follow
1607 * RDATA -- the data:
1608 * PREF -- 16 bit preference
1609 * MX -- name of mail exchanger, must be decompressed
1610 */
1611
1612 /* Skip the query data.
1613 * QDCOUNT is the number of entries (unsigned 16 bit int).
1614 */
1615 count = ntohs (header->qdcount);
[170]1616 for (theindex = 0; theindex < count; ++theindex)
[1]1617 {
1618 ret = dn_skipname (comp_dn, eom);
1619 comp_dn += ret + QFIXEDSZ;
1620 if (ret < 1 || comp_dn >= eom)
[171]1621 {
1622 SH_FREE(reply);
1623 SL_RETURN (NULL, _("get_mx"));
1624 }
[1]1625 }
1626 count = ntohs (header->ancount);
1627 if (count < 1)
[171]1628 {
1629 SH_FREE(reply);
1630 SL_RETURN (NULL, _("get_mx"));
1631 }
[1]1632
1633 retval = SH_ALLOC (sizeof (dnsrep));
1634 if (!retval)
[171]1635 {
1636 SH_FREE(reply);
1637 SL_RETURN (NULL, _("get_mx"));
1638 }
1639
[1]1640 retval->count = count;
1641
1642 /* allocate space for the results */
1643
[34]1644 if (!sl_ok_muls(count, sizeof (mx)))
1645 {
[171]1646 SH_FREE(reply);
[34]1647 SH_FREE (retval);
1648 SL_RETURN (NULL, _("get_mx"));
1649 }
1650
[1]1651 result = SH_ALLOC (count * sizeof (mx));
[34]1652
[1]1653 if (!result)
1654 {
[171]1655 SH_FREE(reply);
[1]1656 SH_FREE (retval);
1657 SL_RETURN (NULL, _("get_mx"));
1658 }
1659 retval->reply = result;
1660
1661 do
1662 {
1663 /* HEADER NAME
1664 */
1665 ret = dn_expand ((unsigned char *) &reply, eom, comp_dn,
1666 (char *) expanded, 1023);
1667 comp_dn += ret;
1668 if (ret < 1 || comp_dn >= eom)
1669 {
[171]1670 SH_FREE(reply);
[1]1671 SH_FREE (result);
1672 SH_FREE (retval);
1673 SL_RETURN (NULL, _("get_mx"));
1674 }
1675
1676 /* TYPE
1677 */
1678 type = get_short (comp_dn);
1679 comp_dn += 2;
1680 if (type != T_MX || comp_dn >= eom)
1681 {
[171]1682 SH_FREE(reply);
[1]1683 SH_FREE (result);
1684 SH_FREE (retval);
1685 SL_RETURN (NULL, _("get_mx"));
1686 }
1687
1688 /* CLASS (re-use 'type' var)
1689 */
1690 type = get_short (comp_dn);
1691 comp_dn += 2;
1692 if (comp_dn >= eom)
1693 {
[171]1694 SH_FREE(reply);
[1]1695 SH_FREE (result);
1696 SH_FREE (retval);
1697 SL_RETURN (NULL, _("get_mx"));
1698 }
1699
1700 /* TTL
1701 */
1702 comp_dn += 4;
1703 if (comp_dn >= eom)
1704 {
[171]1705 SH_FREE(reply);
[1]1706 SH_FREE (result);
1707 SH_FREE (retval);
1708 SL_RETURN (NULL, _("get_mx"));
1709 }
1710
1711 /* RDLENGTH
1712 */
1713 rdlength = get_short (comp_dn);
1714 comp_dn += 2;
1715 if (rdlength < 1 || comp_dn >= eom)
1716 {
[171]1717 SH_FREE(reply);
[1]1718 SH_FREE (result);
1719 SH_FREE (retval);
1720 SL_RETURN (NULL, _("get_mx"));
1721 }
1722
1723 /* RDATA
1724 */
1725 pref = get_short (comp_dn);
1726 comp_dn += 2;
1727 if (comp_dn >= eom)
1728 {
[171]1729 SH_FREE(reply);
[1]1730 SH_FREE (result);
1731 SH_FREE (retval);
1732 SL_RETURN (NULL, _("get_mx"));
1733 }
1734
1735 ret = dn_expand ((unsigned char *) &reply, eom, comp_dn,
1736 (char *) expanded, 1023);
1737 comp_dn += ret;
1738 if (ret < 1)
1739 {
[171]1740 SH_FREE(reply);
[1]1741 SH_FREE (result);
1742 SH_FREE (retval);
1743 SL_RETURN (NULL, _("get_mx"));
1744 }
1745 count--;
1746
1747 /* fill in the struct
1748 */
1749 result[count].pref = pref;
[22]1750 len = strlen (expanded) + 1;
1751 result[count].address = SH_ALLOC (len);
1752 sl_strlcpy (result[count].address, expanded, len);
[1]1753 }
1754 while (ret > 0 && comp_dn < eom && count);
1755
[171]1756 SH_FREE(reply);
[1]1757 SL_RETURN (retval, _("get_mx"));
1758}
1759/* ifndef S_SPLINT_S */
1760#endif
1761
1762/* #if defined(HAVE_ARPA_NAMESER_H) */
1763#endif
1764
1765
1766static int comp_mx_pref (const void * a, const void * b)
1767{
1768 const mx * ax = (const mx *) a;
1769 const mx * bx = (const mx *) b;
1770
1771 if (ax->pref > bx->pref)
1772 return 1;
1773 else if (ax->pref < bx->pref)
1774 return -1;
1775 else
1776 return 0;
1777}
1778
1779/*
1780 * return_mx returns a list of valid mail exchangers for domain
1781 */
1782static dnsrep * return_mx (char *domain)
1783{
[170]1784 struct hostent *host;
[1]1785 dnsrep * answers = NULL;
1786 mx * result;
[170]1787 dnsrep * retval;
[22]1788 char errmsg[128];
1789 size_t len;
[1]1790
1791 SL_ENTER(_("return_mx"));
1792
1793#if defined(HAVE_ARPA_NAMESER_H)
1794 if (domain != NULL)
1795 answers = /*@-unrecog@*/get_mx (domain)/*@+unrecog@*/;
1796#endif
1797
1798 if (answers != NULL && answers->count > 0)
1799 {
1800 qsort(answers->reply, (size_t) answers->count, sizeof(mx),
1801 comp_mx_pref);
1802 SL_RETURN (answers, _("return_mx"));
1803 }
1804 else
1805 {
1806 if (domain != NULL)
1807 {
1808#if defined(HAVE_ARPA_NAMESER_H)
1809#ifdef FIL__
1810 (void) sl_strlcpy (errmsg, _("No MX record for domain "), 127);
1811 (void) sl_strlcat (errmsg, domain, 127);
1812 sh_error_handle (SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
1813 errmsg,
1814 _("get_mx"));
1815#else
[22]1816 /* flawfinder: ignore *//* test code only */
[1]1817 strcpy (errmsg, /* known to fit */
1818 _("No MX record for domain "));
1819 strncat (errmsg, domain, 100);
1820 errmsg[122] = '\0';
1821 fprintf(stderr, "Warning: %s\n", errmsg);
1822#endif
1823#endif
1824 }
[134]1825
1826 SH_MUTEX_LOCK(mutex_resolv);
[170]1827
1828 host = NULL;
1829 retval = NULL;
1830
[1]1831 if (domain != NULL)
1832 host = /*@-unrecog@*/sh_gethostbyname (domain)/*@+unrecog@*/;
[134]1833
1834 if (host)
1835 {
1836 result = SH_ALLOC (sizeof (mx));
1837 retval = SH_ALLOC (sizeof (dnsrep));
1838 retval->reply = result;
1839 retval->count = 1;
1840 result->pref = 0;
1841 /*@-type@*/
1842 len = strlen (host->h_name) + 1;
1843 result->address = SH_ALLOC (len);
1844 sl_strlcpy (result->address, host->h_name, len);
1845 /*@+type@*/
1846 }
1847 SH_MUTEX_UNLOCK(mutex_resolv);
1848
[1]1849 if (!host)
1850 {
1851#ifdef FIL__
1852 (void) sl_strlcpy (errmsg, _("Unknown host "), 127);
1853 (void) sl_strlcat (errmsg, domain, 127);
1854 sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
1855 errmsg,
1856 _("return_mx"));
1857#endif
1858 SL_RETURN (NULL, _("return_mx"));
1859 }
[134]1860
[1]1861 SL_RETURN (retval, _("return_mx"));
1862 }
1863}
1864
[214]1865int free_mx (dnsrep * answers)
[1]1866{
1867 mx * result;
1868 int i;
1869
1870 SL_ENTER(_("free_mx"));
1871 if (!answers)
1872 SL_RETURN (0, _("return_mx"));
1873
1874 result = answers->reply;
1875 for (i = 0; i < answers->count; ++i)
1876 {
1877 SH_FREE (result[i].address);
1878 }
1879 SH_FREE(result);
1880 SH_FREE(answers);
1881 SL_RETURN (0, _("return_mx"));
1882}
1883
1884#ifdef TEST_ONLY
1885int main(int argc, char * argv[])
1886{
1887 int i;
1888 dnsrep * answers;
1889 mx * result;
1890
1891 if (argc < 2)
1892 {
1893 fprintf(stderr, "Usage: dns <hostname>\n");
1894 return -1;
1895 }
1896 answers = return_mx(argv[1]);
1897
1898 if (!answers)
1899 {
1900 fprintf(stderr, "No answer\n");
1901 return -1;
1902 }
1903
1904 if (answers->count > 0)
1905 {
1906 result = answers->reply;
1907 for (i = 0; i < answers->count; ++i)
1908 {
1909 fprintf(stderr, "Record %3d: [%3d] %s\n", i,
1910 result[i].pref, result[i].address);
1911 }
1912 }
1913 else
1914 {
1915 fprintf(stderr, "No answer\n");
1916 free_mx(answers);
1917 return -1;
1918 }
1919 free_mx(answers);
1920 return (0);
1921}
1922#endif
1923
1924
1925
1926/* if defined(SH_WITH_MAIL) */
1927#endif
1928
1929
1930
Note: See TracBrowser for help on using the repository browser.