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 #include "sh_pthread.h"
61 #include "sh_filter.h"
62 #include "sh_mail_int.h"
63 #include "sh_nmail.h"
64 #include "sh_ipvx.h"
65 
66 #undef  FIL__
67 #define FIL__  _("sh_mail.c")
68 #undef  GOOD
69 #undef  BAD
70 
71 static int failedMail = S_FALSE;
72 
73 static dnsrep * return_mx (char *domain);
74 
75 /*********************************************
76  *  utility function for verifying mails
77  *********************************************/
78 
79 typedef 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 
85 static mail_trail_type * mail_trail = NULL;
86 
sh_mail_sigverify(const char * s)87 int sh_mail_sigverify (const char * s)
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     }
118   if ( SL_ISERROR(fd = sl_open_read (FIL__, __LINE__, s, SL_NOPRIV)))
119     {
120       fprintf(stderr, _("Could not open file %s\n"), s);
121       _exit (EXIT_FAILURE);
122     }
123 
124   buf     = SH_ALLOC( (size_t)(SH_MSG_BUF+SH_BUFSIZE+1));
125   bufc    = SH_ALLOC( (size_t)(SH_MSG_BUF+SH_MAXBUF+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 	{
137 	  (void) sh_unix_getline (fd, buf, SH_MSG_BUF+SH_BUFSIZE);
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 	{
156 	  (void) sh_unix_getline (fd, buf, SH_MSG_BUF+SH_BUFSIZE);
157 	  if (0 == sl_strncmp(buf, _("-----BEGIN SIGNATURE-----"),
158 			      sizeof("-----BEGIN SIGNATURE-----")-1))
159 	    break;
160 	  if (buf[0] == '\0')
161 	    _exit (EXIT_FAILURE);
162 	  (void) sh_util_compress(bufc, buf, SH_MSG_BUF+SH_MAXBUF-KEY_LEN);
163 	}
164 
165       /* get signature and number
166        */
167       (void) sh_unix_getline (fd, key, (int)sizeof(key));
168       key[KEY_LEN] = '\0';
169 
170       (void) sh_unix_getline (fd, number, (int)sizeof(number));
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 	    {
190 	      fprintf (stderr, "%s",_("ERROR (no key -- cannot check)\n"));
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 	{
204 	  fprintf (stderr, "%s",_("ERROR (repeated audit trail)\n"));
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);
213 	  fprintf (stderr, "%s",_("(unchecked)\n"));
214 	}
215       else
216 	{
217 	  char sigbuf[KEYBUF_SIZE];
218 
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 	    {
224 	      char hashbuf[KEYBUF_SIZE];
225 	      (void) sl_strlcpy (key2,
226 				 sh_tiger_hash (key2, TIGER_DATA, KEY_LEN,
227 						hashbuf, sizeof(hashbuf)),
228 				 KEY_LEN+1);
229 	    }
230 
231 	  theSig = sh_util_siggen (key2, bufc, sl_strlen(bufc),
232 				   sigbuf, sizeof(sigbuf));
233 
234 	  if (sl_strncmp (key,
235 			  theSig,
236 			  KEY_LEN) != 0)
237 	    {
238 	      fprintf (stderr, "%s",_("(FAILED)\n"));
239 	    }
240 	  else
241 	    {
242 	      fprintf (stderr, "%s",_("(passed)\n"));
243 	    }
244 
245 	}
246 
247     } /* end scan mailbox */
248 
249   /*@notreached@*/
250 }
251 
sh_mail_setNum(const char * str)252 int sh_mail_setNum (const char * str)
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 
266 int sh_mail_all_in_one = S_FALSE;
267 
sh_mail_setFlag(const char * str)268 int sh_mail_setFlag (const char * str)
269 {
270   int i;
271   SL_ENTER(_("sh_mail_setFlag"));
272   i = sh_util_flagval(str, &sh_mail_all_in_one);
273   SL_RETURN(i, _("sh_mail_setFlag"));
274 }
275 
276 static char * mail_subject = NULL;
277 
set_mail_subject(const char * str)278 int set_mail_subject (const char * str)
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 
297 SH_MUTEX_INIT(mutex_fifo_mail, PTHREAD_MUTEX_INITIALIZER);
298 
299 SH_FIFO * fifo_mail = NULL;
300 
301 static
sh_mail_emptystack(void)302 void 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 
312   SH_MUTEX_LOCK(mutex_fifo_mail);
313   while (NULL != (msg = pop_list(fifo_mail)))
314     {
315       len = sl_strlen(msg);
316       memset(msg, 0, len);
317       SH_FREE(msg);
318     }
319   SH_MUTEX_UNLOCK(mutex_fifo_mail);
320 
321   SL_RET0(_("sh_mail_emptystack"));
322 }
323 
324 /* insert "\r\n" after each 998 char
325  */
326 static char * split_string(const char * str);
327 
328 /* fixes warning: variable ‘p’ might be clobbered by ‘longjmp’ or ‘vfork’*/
329 static char ** p_dummy;
330 
sh_mail_pushstack(int severity,const char * msg,const char * alias)331 int sh_mail_pushstack (int severity, const char * msg, const char * alias)
332 {
333   char * p;
334   volatile int    retval = 0;
335   int    status;
336 
337   SL_ENTER(_("sh_mail_pushstack"));
338 
339   if (msg == NULL || failedMail == S_TRUE /* || sh.srvmail.name[0] == '\0' */)
340     SL_RETURN((0), (_("sh_mail_pushstack")));
341 
342   p = split_string(msg);
343   /* fixes "variable ‘p’ might be clobbered by ‘longjmp’ or ‘vfork’" */
344   p_dummy = &p;
345 
346   SH_MUTEX_LOCK(mutex_fifo_mail);
347 
348   if (fifo_mail == NULL)
349     {
350       fifo_mail = SH_ALLOC(sizeof(SH_FIFO));
351       fifo_init(fifo_mail);
352     }
353   status = push_list (fifo_mail, p, severity, alias);
354   SH_MUTEX_UNLOCK(mutex_fifo_mail);
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     {
363       BREAKEXIT(sh_nmail_flush);
364       retval = sh_nmail_flush ();
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  */
375 static int sh_mail_end_conn (FILE * connfile, int fd);
376 static FILE * sh_mail_start_conn (struct alias * address, int * fd, int * anum);
377 
378 static
sh_mail_get_subject(const char * message,char * mheader,size_t len)379 void sh_mail_get_subject(const char * message,
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];
393   char * msg;
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    */
410   msg  = sh_util_strdup(message);
411 
412   mptr = sl_strstr(msg, _("msg="));
413   if (mptr)
414     {
415       mptr += 4;
416       rep_serv_tab[2].data_str   = mptr;
417     }
418   else
419     rep_serv_tab[2].data_str   = msg;
420 
421   mptr = sl_strstr(msg, _("sev="));
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     {
433       mptr = msg;
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);
456   SH_FREE(msg);
457   SL_RET0(_("sh_mail_get_subject"));
458 }
459 
sh_mail_signature_block(sh_string * sigMsg,char * recipient,char * bufcompress)460 sh_string * sh_mail_signature_block (sh_string  * sigMsg, char * recipient,
461 				     char * bufcompress)
462 {
463   time_t         id_audit;
464   char         * theSig;
465   char ibuf[80];
466   unsigned int count;
467 
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)
477     {
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     }
504 
505     sigMsg     = sh_string_add_from_char(sigMsg, "\r\n");
506 
507     sl_snprintf(ibuf, sizeof(ibuf), _("%06u %010lu::%s\r\n"),
508 		count, (unsigned long) id_audit, sh.host.name);
509 
510     sigMsg     = sh_string_add_from_char(sigMsg, ibuf);
511     sigMsg     = sh_string_add_from_char(sigMsg, _("-----END MESSAGE-----"));
512 
513     return sigMsg;
514 }
515 
sh_mail_msg(const char * message)516 int sh_mail_msg (const char * message)
517 {
518     char         subject[32+32+SH_MINIBUF+2+3+SH_PATHBUF];
519     char         mheader[32+32+SH_MINIBUF+2+3];
520 
521     sh_string  * mailMsg;
522     sh_string  * compMsg;
523     int          status = 0;
524     volatile int errcount;
525     size_t       wrlen;
526     volatile int retval = -1;
527 
528     char       * bufcompress;
529     size_t       compressed;
530 
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 
537     int       ma_socket = -1;
538 
539     int            address_num = 0;
540     sh_string    * theMsg = NULL;
541 
542     /* #define SH_MAILBUF (256)    */
543 #define SH_MAILBUF 4096
544 
545     char      timebuf[81];
546 
547     SL_ENTER(_("sh_mail_msg"));
548 
549     /*
550      * Return if we cannot mail.
551      */
552     if (failedMail == S_TRUE)
553       SL_RETURN((-1), _("sh_mail_msg"));
554 
555     /*
556      * Final failure, can't mail for SH_MAX_FAIL hours.
557      */
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,
562 			 _("mail"),
563 			 sh_string_str(all_recipients->recipient));
564 	sh_mail_emptystack();
565 	sh.mailNum.alarm_last = 0;
566 	failedMail = S_TRUE;
567 	SL_RETURN((-1), _("sh_mail_msg"));
568       }
569 
570     /*
571      * Try at most every three seconds to mail if there was a failure.
572      */
573     if ((fail_time > 0) && (time(NULL) - fail_time) < 3/*600*/)
574       {
575 	if (failcount > 3)
576 	  {
577 	    /* -- Save for later. Changed: done by caller. --
578 	     *	    sh_nmail_pushstack (severity, message, alias);
579 	     */
580 	    ++failcount;
581 
582 	    SL_RETURN((-2), _("sh_mail_msg"));
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 
596     /* ---------  Build complete message. ------------------------ */
597 
598     /* Don't flush the queue here, because tag_list doesn't know
599      * how to filter messages. */
600 
601     theMsg = sh_string_new_from_lchar(message, sl_strlen(message));
602     if (!theMsg)
603       {
604 	SL_RETURN((-1), _("sh_mail_msg"));
605       }
606 
607     /* ---------- Header  ---------------------------------------- */
608 
609     if (mail_subject == NULL)
610       {
611 	(void) sl_strlcpy(mheader, _("Subject: "),       sizeof(mheader)-5);
612 	(void) sl_strlcat(mheader,
613 			  sh_unix_time (0, timebuf, sizeof(timebuf)),
614 			  sizeof(mheader)-5);
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);
628 	    (void) sl_strlcat(mheader,
629 			      sh_unix_time (0, timebuf, sizeof(timebuf)),
630 			      sizeof(mheader)-5);
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 
642     (void) sl_strlcpy(subject, sh_unix_time (0, timebuf, sizeof(timebuf)),
643 		      sizeof(subject));
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 
649     mailMsg     = sh_string_new (SH_MAILBUF);
650     compMsg     = sh_string_new (SH_MAILBUF);
651 
652     mailMsg     = sh_string_add_from_char(mailMsg, mheader);
653     mailMsg     = sh_string_add_from_char(mailMsg,
654 					  _("-----BEGIN MESSAGE-----\r\n"));
655 
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");
659 
660     /* ---------- Compressed Message  ---------------------------- */
661 
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");
665 
666     bufcompress = SH_ALLOC(sh_string_len(compMsg) + KEY_LEN + 1);
667     bufcompress[0] = '\0';
668 
669     compressed = sh_util_compress (bufcompress,
670 				   sh_string_str(compMsg),
671 				   sh_string_len(compMsg) + 1);
672 
673     /* ---------- Connect ---------------------------------------- */
674 
675     errcount = 0;
676 
677     if (sh_mail_all_in_one == S_FALSE)
678       {
679 	struct alias * address_list;
680 
681 	address_list = all_recipients;
682 
683 	while (address_list)
684 	  {
685 	    if (address_list->send_mail == 1)
686 	      {
687 		connfile = sh_mail_start_conn (address_list,
688 					       &ma_socket, &address_num);
689 
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 
700 			sigMsg = sh_mail_signature_block (sigMsg,
701 							  sh_string_str(address_list->recipient),
702 							  bufcompress);
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 		  }
724 		else
725 		  {
726 		    ++sh.statistics.mail_success;
727 		  }
728 
729 		if (connfile != NULL)
730 		  {
731 		    (void) sl_fclose (FIL__, __LINE__, connfile);
732 		    connfile = NULL;
733 		  }
734 	      }
735 	    address_list = address_list->all_next;
736 	  }
737       }
738     else
739       {
740 	connfile = sh_mail_start_conn (NULL, &ma_socket, &address_num);
741 
742 	if (NULL != connfile)
743 	  {
744 	    wrlen = fwrite (sh_string_str(mailMsg), 1,
745 			    sh_string_len(mailMsg), connfile);
746 	    wrlen -= sh_string_len(mailMsg);
747 
748 	    if (wrlen == 0)
749 	      {
750 		sh_string  * sigMsg  = sh_string_new (0);
751 
752 		sigMsg  = sh_mail_signature_block (sigMsg,
753 						   NULL,
754 						   bufcompress);
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)
764 	      status = sh_mail_end_conn (connfile, ma_socket);
765 	    else
766 	      status = -1;
767 	  }
768 
769 	if (NULL == connfile || status != 0)
770 	  {
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 
780 	    if (ma_address)
781 	      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_SRV_FAIL,
782 			       _("mail"),
783 			       sh_string_str(ma_address->recipient));
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 	  {
794 	    (void) sl_fclose (FIL__, __LINE__, connfile);
795 	    connfile = NULL;
796 	  }
797       }
798 
799     memset (bufcompress, 0, compressed);
800     SH_FREE(bufcompress);
801 
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));
805 
806     sh_string_destroy(&mailMsg);
807     sh_string_destroy(&compMsg);
808     sh_string_destroy(&theMsg);
809 
810     /* --- Stay responsible for delivery in case of failure --- */
811 
812     if (errcount == address_num)
813       {
814 	rollback_list(fifo_mail);
815 	retval = -3;
816       }
817     else
818       {
819 	mark_list(fifo_mail);
820       }
821 
822     if (errcount == address_num)
823       {
824 	fail_time = time(NULL);
825 	SL_RETURN((retval), _("sh_mail_msg"));
826       }
827 
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 
864 static int sh_mail_wait(int code, int ma_socket);
865 
866 static char * relay_host = NULL;
867 
sh_mail_set_relay(const char * str_s)868 int sh_mail_set_relay (const char * str_s)
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)
876     {
877       SH_FREE (relay_host);
878       relay_host = NULL;
879     }
880 
881   if (0 == sl_strncmp(str_s, _("NULL"), 4))
882     {
883       SL_RETURN( 0, _("sh_mail_set_relay"));
884     }
885 
886   relay_host = sh_util_strdup(str_s);
887 
888   SL_RETURN( 0, _("sh_mail_set_relay"));
889 }
890 
891 static char * mail_sender = NULL;
892 
sh_mail_set_sender(const char * str)893 int sh_mail_set_sender (const char *str)
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 
911 static int sh_mail_port = IPPORT_SMTP;
912 
sh_mail_set_port(const char * str)913 int 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 
932 /*************************
933  *
934  * start connection
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.
939  */
940 
941 static time_t time_wait = 300;
942 static void report_smtp (char * reply);
943 
sh_mail_start_conn(struct alias * ma_address,int * ma_socket,int * anum)944 static FILE * sh_mail_start_conn (struct alias * ma_address,
945 				  int * ma_socket, int * anum)
946 {
947   char       * address;
948   int          aFlag = 0;
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;
961 #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
962   struct tm    time_tm;
963 #endif
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 
974   *ma_socket = -1;
975   time_wait  = 300;
976 
977   if (ma_address == NULL)
978     {
979       aFlag = 1;
980       ma_address = all_recipients;
981 
982       while (ma_address)
983 	{
984 	  if (ma_address->send_mail == 1)
985 	    break;
986 	  ma_address = ma_address->all_next;
987 	}
988     }
989 
990   if (!ma_address)
991     {
992       SL_RETURN( NULL, _("sh_mail_start_conn"));
993     }
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 
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     }
1011 
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));
1033       fd = connect_port (ma_machine, sh_mail_port,
1034 			 error_call, &error_num, error_msg, 256);
1035     }
1036   else
1037     {
1038       answers = ma_address->mx_list;
1039       if (!answers)
1040 	{
1041 	  answers = return_mx (ma_machine);
1042 	  ma_address->mx_list = answers;
1043 	}
1044 
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));
1056 	      fd = connect_port (ma_machine, sh_mail_port,
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")));
1087       (void) sl_close_fd(FIL__, __LINE__, fd);
1088       SL_RETURN( NULL, _("sh_mail_start_conn"));
1089     }
1090 
1091 
1092   /* say HELO to the other socket
1093    */
1094   if (0 == sh_mail_wait (220, fd))
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")));
1101       (void) sl_fclose(FIL__, __LINE__, connFile);
1102       SL_RETURN( NULL, _("sh_mail_start_conn"));
1103     }
1104 
1105   (void) fflush(connFile);
1106 
1107   if (0 != sh_ipvx_is_numeric(sh.host.name))
1108     {
1109       sl_snprintf(error_msg, sizeof(error_msg), "HELO [%s]",
1110 		  sh.host.name);
1111     }
1112   else
1113     {
1114       sl_snprintf(error_msg, sizeof(error_msg), "HELO %s",
1115 		  sh.host.name);
1116     }
1117   report_smtp(error_msg);
1118 
1119   if (0 != sh_ipvx_is_numeric(sh.host.name))
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 
1126   if (0 == sh_mail_wait(250, fd))
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")));
1133       (void) sl_fclose(FIL__, __LINE__, connFile);
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);
1144       if (0 != sh_ipvx_is_numeric(sh.host.name))
1145 	(void) sl_strlcat (this_address, _("example.com"), 256);
1146       else
1147 	(void) sl_strlcat (this_address, sh.host.name, 256);
1148     }
1149 
1150   sl_snprintf(error_msg, sizeof(error_msg), "MAIL FROM:<%s>",
1151 	      this_address);
1152   report_smtp(error_msg);
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 
1160   if (0 == sh_mail_wait(250, fd))
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")));
1166       (void) sl_fclose(FIL__, __LINE__, connFile);
1167       SL_RETURN( NULL, _("sh_mail_start_conn"));
1168     }
1169 
1170   /* tell them who to send mail to
1171    */
1172   if (aFlag == 0)
1173     {
1174       sl_snprintf(error_msg, sizeof(error_msg), "RCPT TO:<%s>",
1175 		  address);
1176       report_smtp(error_msg);
1177 
1178       (void) fflush(connFile);
1179       fprintf(connFile, _("RCPT TO:<%s>%c%c"), address, 13, 10);
1180       (void) fflush(connFile);
1181 
1182       if (0 == sh_mail_wait(250, fd))
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")));
1188 	  (void) sl_fclose(FIL__, __LINE__, connFile);
1189 	  SL_RETURN( NULL, _("sh_mail_start_conn"));
1190 	}
1191       *anum = 1;
1192     }
1193   else
1194     {
1195       int address_num = 0;
1196       ecount      = 0;
1197 
1198       ma_address = all_recipients;
1199 
1200       while (ma_address)
1201 	{
1202 	  if (ma_address->send_mail != 1)
1203 	    {
1204 	      ma_address = ma_address->next;
1205 	      continue;
1206 	    }
1207 
1208 	  ++address_num;
1209 
1210 	  sl_snprintf(error_msg, sizeof(error_msg), "RCPT TO:<%s>",
1211 		      sh_string_str(ma_address->recipient));
1212 	  report_smtp(error_msg);
1213 
1214 	  (void) fflush(connFile);
1215 	  fprintf(connFile, _("RCPT TO:<%s>%c%c"),
1216 		  sh_string_str(ma_address->recipient), 13, 10);
1217 	  (void) fflush(connFile);
1218 
1219 	  if (0 == sh_mail_wait(250, fd))
1220 	    {
1221 	      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1222 			      _("RCPT TO failed"), _("sh_mail_start_conn"),
1223 			      _("mail"), sh_string_str(ma_address->recipient));
1224 
1225 	      TPT(( 0, FIL__, __LINE__, _("msg=<Timeout.>\n")));
1226 	      ++ecount;
1227 	    }
1228 	  ma_address = ma_address->next;
1229 	}
1230 
1231       *anum += address_num;
1232 
1233       if (ecount == address_num)
1234 	{
1235 	  (void) sl_fclose(FIL__, __LINE__, connFile);
1236 	  SL_RETURN( NULL, _("sh_mail_start_conn"));
1237 	}
1238     }
1239 
1240   /* Send the message
1241    */
1242   report_smtp(_("DATA"));
1243 
1244   (void) fflush(connFile);
1245   fprintf(connFile, _("DATA%c%c"), 13, 10);
1246   (void) fflush(connFile);
1247 
1248   if (0 == sh_mail_wait(354, fd))
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")));
1254       (void) sl_fclose(FIL__, __LINE__, connFile);
1255       SL_RETURN( NULL, _("sh_mail_start_conn"));
1256     }
1257 
1258 
1259   my_time = time(NULL);
1260 #if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_LOCALTIME_R)
1261   my_tm = localtime_r(&my_time, &time_tm);
1262 #else
1263   my_tm = localtime(&my_time);
1264 #endif
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     {
1272 #if defined(HAVE_STRFTIME_Z)
1273       (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %z"), my_tm);
1274 #else
1275       (void) strftime(my_tbuf, 127, _("%a, %d %b %Y %H:%M:%S %Z"), my_tm);
1276 #endif
1277     }
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 
1282   report_smtp(_("sending data.."));
1283 
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 
1293   *ma_socket = fd;
1294   SL_RETURN( connFile, _("sh_mail_start_conn"));
1295 }
1296 
1297 /*************************
1298  *
1299  * end connection
1300  *
1301  */
1302 
sh_mail_end_conn(FILE * connFile,int fd)1303 static int sh_mail_end_conn (FILE * connFile, int fd)
1304 {
1305   SL_ENTER(_("sh_mail_end_conn"));
1306 
1307   time_wait = 300;
1308 
1309   report_smtp(_("."));
1310 
1311   (void) fflush(connFile);
1312   fprintf(connFile, _("%c%c.%c%c"), 13, 10, 13, 10);
1313   (void) fflush(connFile);
1314 
1315   if (0 != sh_mail_wait(250, fd))
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  */
1342 extern int flag_err_debug;
1343 
report_smtp(char * reply)1344 static void report_smtp (char * reply)
1345 {
1346   char * tmp;
1347 
1348   if (flag_err_debug == S_TRUE)
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 
sh_mail_wait(int code,int ma_socket)1361 static int sh_mail_wait(int code, int ma_socket)
1362 {
1363   int rcode, g;
1364 
1365   char c;
1366 
1367   char errmsg[194];
1368   char reply[128];
1369   unsigned int  ireply = 0;
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 
1387   rcode    = 0;
1388   state    = WAIT_CODE_START;
1389   reply[0] = '\0';
1390 
1391   while (sl_read_timeout_fd (ma_socket, &c, 1, time_wait, S_FALSE) > 0) {
1392 
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 
1403     g = (int) c;
1404 
1405     /*
1406     if (g == EOF)
1407       {
1408 	TPT((0, FIL__, __LINE__, _("msg=<mail_wait: EOF>\n")));
1409 	SL_RETURN( 0, _("mail_wait"));
1410       }
1411     */
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                    */
1420       if (0 == isdigit(g))
1421 	{
1422 	  report_smtp(reply);
1423 	  SL_RETURN( 0, _("mail_wait")); /* No leading number     */
1424 	}
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 	{
1455 	  char * tmp = sh_util_safe_name_keepspace(reply);
1456           sl_snprintf(errmsg, sizeof(errmsg),
1457 		      _("Bad response (%s), expected %d"), tmp, code);
1458 	  SH_FREE(tmp);
1459 
1460 	  sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_NET,
1461 			  errmsg, _("sh_mail_wait"),
1462 			  _("mail"), _("SMTP server"));
1463 	}
1464       else
1465 	{
1466 	  report_smtp(reply);
1467 	}
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")));
1488       report_smtp(reply);
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 */
1497   report_smtp(reply);
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 
split_string(const char * str)1506 static char * split_string(const char * str)
1507 {
1508   size_t size;
1509   size_t blocks;
1510   int    count = 0;
1511 
1512   char * p, * p0;
1513   const char * q;
1514 
1515   if (!str)
1516     return NULL;
1517 
1518   size   = strlen(str) + 1;
1519   blocks = 1 + (size / SPLIT_AT);
1520 
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 
1532   p = SH_ALLOC(size);
1533   memset(p, 0, size);
1534 
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 */
get_short(unsigned char * loc)1590 static 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
get_mx(char * hostname)1606 static dnsrep * get_mx (char *hostname)
1607 {
1608   int  ret, length, status;
1609   mx * result;
1610   size_t len;
1611 
1612   typedef union
1613   {
1614     HEADER head;
1615     unsigned char buffer[4096];
1616   } querybuf;
1617 
1618   querybuf * reply;
1619   char expanded[1024];
1620   unsigned char * comp_dn, * eom;
1621   HEADER * header;
1622   int      type, rdlength, pref;
1623   unsigned int count, theindex;
1624   dnsrep * retval;
1625 
1626   SL_ENTER(_("get_mx"));
1627 
1628   if (0 != res_init ())
1629     SL_RETURN (NULL, _("get_mx"));
1630 
1631   reply = SH_ALLOC(sizeof(querybuf));
1632 
1633   errno = 0;
1634   length = res_query (hostname, C_IN, T_MX,
1635 		      (unsigned char *) reply, 4095);
1636 
1637   if (length < 1)
1638     {
1639       char errbuf[SH_ERRBUF_SIZE];
1640 
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) ?
1653 			   sh_error_message (status, errbuf, sizeof(errbuf)) :
1654 			   sh_tools_errmessage(status, errbuf, sizeof(errbuf)),
1655 			   _("res_query"));
1656 #else
1657 	  if (errno == ECONNREFUSED)
1658 	    fprintf(stderr, " ERROR: %s: \n", strerror(errno)); /* TESTONLY */
1659 	  else
1660 	    fprintf(stderr, "HERROR: %s\n", hstrerror(h_errno));/* TESTONLY */
1661 #endif
1662 	}
1663       SH_FREE(reply);
1664       SL_RETURN (NULL, _("get_mx"));
1665     }
1666 
1667 
1668   header  = (HEADER *) reply;
1669 
1670   /* start of data section
1671    */
1672   comp_dn = (unsigned char *) reply + HFIXEDSZ;
1673 
1674   /* end-of-message
1675    */
1676   eom     = (unsigned char *) reply + length;
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);
1692   for (theindex = 0; theindex < count; ++theindex)
1693     {
1694       ret = dn_skipname (comp_dn, eom);
1695       comp_dn += ret + QFIXEDSZ;
1696       if (ret < 1 || comp_dn >= eom)
1697 	{
1698 	  SH_FREE(reply);
1699 	  SL_RETURN (NULL, _("get_mx"));
1700 	}
1701     }
1702 
1703   count         = ntohs (header->ancount);
1704   if (count < 1)
1705     {
1706       SH_FREE(reply);
1707       SL_RETURN (NULL, _("get_mx"));
1708     }
1709 
1710   retval        = SH_ALLOC (sizeof (dnsrep));
1711   if (!retval)
1712     {
1713       SH_FREE(reply);
1714       SL_RETURN (NULL, _("get_mx"));
1715     }
1716 
1717   retval->count = count;
1718 
1719   /* allocate space for the results */
1720 
1721   if (!sl_ok_muls(count, sizeof (mx)))
1722     {
1723       SH_FREE(reply);
1724       SH_FREE   (retval);
1725       SL_RETURN (NULL, _("get_mx"));
1726     }
1727 
1728   result        = SH_ALLOC (count * sizeof (mx));
1729 
1730   if (!result)
1731     {
1732       SH_FREE(reply);
1733       SH_FREE   (retval);
1734       SL_RETURN (NULL, _("get_mx"));
1735     }
1736   retval->reply = result;
1737 
1738   do
1739     {
1740       /* HEADER NAME
1741        */
1742       ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
1743 		       (char *) expanded, 1023);
1744       comp_dn += ret;
1745       if (ret < 1 || comp_dn >= eom)
1746 	{
1747 	  SH_FREE(reply);
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 	{
1759 	  SH_FREE(reply);
1760 	  SH_FREE (result);
1761 	  SH_FREE (retval);
1762 	  SL_RETURN (NULL, _("get_mx"));
1763 	}
1764 
1765 
1766       /* CLASS (re-use 'type' var)
1767        */
1768       /* type = get_short (comp_dn); *//* don't care */
1769       comp_dn += 2;
1770       if (comp_dn >= eom)
1771 	{
1772 	  SH_FREE(reply);
1773 	  SH_FREE (result);
1774 	  SH_FREE (retval);
1775 	  SL_RETURN (NULL, _("get_mx"));
1776 	}
1777 
1778 
1779       /* TTL
1780        */
1781       comp_dn += 4;
1782       if (comp_dn >= eom)
1783 	{
1784 	  SH_FREE(reply);
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 	{
1796 	  SH_FREE(reply);
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 	{
1808 	  SH_FREE(reply);
1809 	  SH_FREE (result);
1810 	  SH_FREE (retval);
1811 	  SL_RETURN (NULL, _("get_mx"));
1812 	}
1813 
1814       ret = dn_expand ((unsigned char *) reply, eom, comp_dn,
1815 		       (char *) expanded, 1023);
1816       comp_dn += ret;
1817       if (ret < 1)
1818 	{
1819 	  SH_FREE(reply);
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;
1829       len = strlen (expanded) + 1;
1830       result[count].address = SH_ALLOC (len);
1831       sl_strlcpy (result[count].address, expanded, len);
1832     }
1833   while (ret > 0 && comp_dn < eom && count);
1834 
1835   SH_FREE(reply);
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 
comp_mx_pref(const void * a,const void * b)1845 static 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  */
return_mx(char * domain)1861 static dnsrep * return_mx (char *domain)
1862 {
1863   dnsrep * answers = NULL;
1864   mx     * result;
1865   dnsrep * retval;
1866   char   * address = NULL;
1867   char     errmsg[128];
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     {
1884       char numeric[SH_IP_BUF];
1885 
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
1896 	  /* flawfinder: ignore *//* test code only */
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 	}
1905 
1906       retval = NULL;
1907 
1908       if (domain != NULL)
1909 	address = sh_ipvx_canonical(domain, numeric, sizeof(numeric));
1910 
1911       if (address)
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;
1918 
1919 	  result->address = address;
1920 	}
1921       else
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 	}
1932 
1933       SL_RETURN (retval, _("return_mx"));
1934     }
1935 }
1936 
free_mx(dnsrep * answers)1937 int free_mx (dnsrep * answers)
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
main(int argc,char * argv[])1957 int 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 
2003