source: trunk/src/sh_mail.c@ 584

Last change on this file since 584 was 583, checked in by katerina, 2 months ago

Fix for ticket #471 (autoreconf throws warnings/errors).

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