source: trunk/src/sh_mail.c @ 132

Last change on this file since 132 was 132, checked in by rainer, 12 years ago

Make utility functions thread-safe.

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