source: trunk/src/sh_mail.c@ 292

Last change on this file since 292 was 290, checked in by katerina, 14 years ago

Fixes for tickets #215, #216, #217, #218, version bumped to 2.7.2

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