source: trunk/src/sh_mail.c@ 214

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

Rewrite mail subsystem for more flexibility (closes ticket #141).

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