source: trunk/src/sh_mail.c@ 382

Last change on this file since 382 was 379, checked in by katerina, 13 years ago

Fix for ticket #277 (sigpipe).

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