source: trunk/src/sh_mail.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

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