source: trunk/src/sh_mail.c @ 133

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

Reentrant checksum/hash functions.

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