1 /* SAMHAIN file system integrity testing                                   */
2 /* Copyright (C) 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 <string.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <time.h>
27 
28 #include "samhain.h"
29 #include "sh_error.h"
30 #include "sh_utils.h"
31 #include "sh_tiger.h"
32 
33 #if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
34 #include <sys/mman.h>
35 #endif
36 
37 
38 #undef  FIL__
39 #define FIL__  _("sh_err_log.c")
40 
41 #undef  FIX_XML
42 #define FIX_XML 1
43 
44 #define MYSIGLEN (2*KEY_LEN + 32)
45 
46 typedef struct _sh_log_buf {
47   char   signature[KEY_LEN+1];
48   char   timestamp[KEY_LEN+1];
49 #ifdef SH_USE_XML
50   char   sig[MYSIGLEN];
51 #endif
52   char * msg;
53 } sh_sh_log_buf;
54 
55 extern struct  _errFlags  errFlags;
56 
57 #define CHK_KEY 0
58 #define CHK_FIL 1
59 #define CHK_NON 2
60 
get_key_from_file(char * path,char * keyid,char * key)61 static int get_key_from_file(char * path, char * keyid, char * key)
62 {
63   SL_TICKET  fd;
64   char * buf;
65   char * bufc;
66 
67   if (path[strlen(path)-1] == '\n')
68     path[strlen(path)-1] = '\0';
69 
70   /* open the file, then check it
71    */
72   if ( SL_ISERROR(fd = sl_open_read (FIL__, __LINE__, path, SL_NOPRIV)))
73     {
74       fprintf(stderr, _("Could not open file <%s>\n"), path);
75       _exit (EXIT_FAILURE);
76     }
77 
78   buf     = SH_ALLOC( (size_t)(SH_BUFSIZE+1));
79   bufc    = SH_ALLOC( (size_t)(SH_MAXBUF+1));
80 
81   while (1 == 1)
82     {
83       buf[0]  = '\0';
84       bufc[0] = '\0';
85 
86       /* find start of next key
87        */
88       while (0 != sl_strncmp(buf, _("-----BEGIN LOGKEY-----"),
89 			     sizeof("-----BEGIN LOGKEY-----")-1))
90 	{
91 	  (void) sh_unix_getline (fd, buf, SH_BUFSIZE);
92 	  if (buf[0] == '\0')
93 	    {
94 	      /* End of file reached, return.
95 	       */
96 	      (void) fflush(stdout);
97 	      (void) sl_close(fd);
98 	      return -1;
99 	    }
100 	}
101 
102       /* read key
103        */
104       (void) sh_unix_getline (fd, buf, SH_BUFSIZE);
105 
106       if (0 == sl_strncmp(keyid, &buf[KEY_LEN], strlen(keyid)))
107 	{
108 	  (void) sl_strlcpy(key, buf, KEY_LEN+1);
109 	  (void) sl_close(fd);
110 	  return 0;
111 	}
112     }
113 
114   /*@notreached@*/
115 }
116 
117 static int just_list = S_FALSE;
118 
sh_error_logverify_mod(const char * s)119 int sh_error_logverify_mod (const char * s)
120 {
121   just_list = S_TRUE;
122   if (s)      /* compiler warning (unused var) fix */
123     return 0;
124   else
125     return 0;
126 }
127 
sh_error_logverify(const char * s)128 int sh_error_logverify (const char * s)
129 {
130   SL_TICKET fd;
131   int len;
132   int status;
133   int count =  0;
134   int start = -1;
135   char * buf;
136   char * bufc;
137 #ifdef SH_USE_XML
138   char * ptr;
139   int fixed_xml = S_TRUE;
140   char c_start;
141 #endif
142   char signature[64];
143   char key[KEY_LEN+2];
144   char path[KEY_LEN+1];
145   char timestamp[64];
146   char c_cont;
147   int  chk_mode = CHK_KEY;
148   char hashbuf[KEYBUF_SIZE];
149 
150   sh_error_logoff();
151 
152   if (s == NULL || sl_strlen(s) >= PATH_MAX)
153     {
154       fprintf(stderr, _("FAIL: msg=\"Invalid input\", path=\"%s\"\n"), s);
155       _exit (EXIT_FAILURE);
156     }
157 
158   /* Open the file, then check it.
159    */
160   if (0 != sl_is_suid())
161     {
162       fprintf(stderr, _("Cannot open file %s in suid mode\n"), s);
163       _exit (EXIT_FAILURE);
164     }
165 
166   if ( SL_ISERROR(fd = sl_open_read (FIL__, __LINE__, s, SL_NOPRIV)) )
167     {
168       fprintf(stderr,
169 	      _("FAIL: msg=\"File not accessible\", error=\"%ld\", path=\"%s\"\n"), fd, s);
170       _exit (EXIT_FAILURE);
171     }
172 
173   /* Find space value.
174    */
175   c_cont  = ' ';
176 #ifdef SH_STEALTH
177   c_cont ^= XOR_CODE;
178 #endif
179 
180 #ifdef SH_USE_XML
181   c_start  = '<';
182 #ifdef SH_STEALTH
183   c_start ^= XOR_CODE;
184 #endif
185 #endif
186 
187   buf  = (char *) SH_ALLOC( 2*SH_MSG_BUF+1 );
188   bufc = (char *) SH_ALLOC( 2*SH_MSG_BUF+1 );
189 
190   while (1 == 1)
191     {
192       /* get the log message
193        */
194       if (sh_unix_getline (fd, buf, (2*SH_MSG_BUF)) < 0)
195 	break;
196 
197       len = (int) sl_strlen(buf);
198 
199 #ifdef SH_USE_XML
200 #ifdef SH_STEALTH
201       if (0 == sl_strncmp (buf, N_("<trail>"), 7))
202 #else
203       if (0 == sl_strncmp (buf, _("<trail>"),  7))
204 #endif
205 #else
206 #ifdef SH_STEALTH
207       if (0 == sl_strncmp (buf, N_("[SOF]"), 5))
208 #else
209       if (0 == sl_strncmp (buf, _("[SOF]"),  5))
210 #endif
211 #endif
212 	{
213 	  if (just_list == S_TRUE)
214 	    {
215 #ifdef SH_STEALTH
216 	      sh_do_decode (buf, sl_strlen(buf));
217 #endif
218 	      fprintf (stdout, _("%s\n"), buf);
219 	    }
220 
221 	  /* Found start of audit trail, read first line.
222 	   */
223 	  start = 1;
224 	  do {
225 	    if ( sh_unix_getline (fd, buf, (2*SH_MSG_BUF)) < 0)
226 	      break;
227 	  } while (buf[0] == '\0' || buf[0] == '\n');
228 	  len = (int) sl_strlen(buf);
229 
230 	  if (just_list == S_TRUE)
231 	    {
232 #ifdef SH_STEALTH
233 	      if (buf[0] != '\n')
234 		sh_do_decode (buf, sl_strlen(buf));
235 #endif
236 	      fprintf (stdout, _("%s\n"), buf);
237 	      start = 0;
238 	    }
239 
240 	  ++count;
241 	}
242       else if (buf[0] == '\n'
243 #ifdef SH_USE_XML
244 	       ||
245 #ifdef SH_STEALTH
246 	       0 == sl_strncmp(buf, N_("</trail>"), 7)
247 #else
248 	       0 == sl_strncmp(buf,  _("</trail>"), 7)
249 #endif
250 #endif
251 	       )
252 	{
253 	  if (just_list == S_TRUE)
254 	    {
255 #ifdef SH_STEALTH
256 	      if (buf[0] != '\n')
257 		sh_do_decode (buf, sl_strlen(buf));
258 #endif
259 	      fprintf (stdout, _("%s\n"), buf);
260 	    }
261 
262 	  /* A newline.
263 	   */
264 	  ++count;
265 	  continue;
266 	}
267       else if (start == 0)
268 	{
269 	  /* We are inside an audit trail.
270 	   */
271 	  ++count;
272 	  if (just_list == S_TRUE)
273 	    {
274 #ifdef SH_STEALTH
275 	      sh_do_decode (buf, sl_strlen(buf));
276 #endif
277 	      fprintf (stdout, _("%s\n"), buf);
278 	      continue;
279 	    }
280 	}
281       else
282 	{
283 	  /* No start-of-file found yet.
284 	   */
285 	  continue;
286 	}
287 
288       if (just_list == S_TRUE)
289 	continue;
290 
291       /* Check for a continuation line.
292        */
293       while (1 == 1)
294 	{
295 	  do {
296 	    if ( sh_unix_getline (fd, bufc, (2*SH_MSG_BUF)) < 0)
297 	      break;
298 	  } while (bufc[0] == '\0' || bufc[0] == '\n');
299 	  ++count;
300 	  if (bufc[0] == c_cont)
301 	    {
302 	      /* A continuation line. Add the newline.
303 	       */
304 	      (void) sl_strlcat(buf, "\n", 2*SH_MSG_BUF+1);
305 	      ++len;
306 	      (void) sl_strlcat(buf, bufc, 2*SH_MSG_BUF+1);
307 	      len += (int) sl_strlen(bufc);
308 	    }
309 	  else
310 	    {
311 	      /* No continuation line. Use it as signature.
312 	       * A48014C05604EF7C9472330E85453E704024943E556163C2
313 	       */
314 #ifdef SH_USE_XML
315 #ifdef SH_STEALTH
316 	      if (bufc[0] == c_start) /* FIX XML */
317 #else
318 	      if (bufc[0] == c_start)
319 #endif
320 		{
321 		  (void) sl_strlcpy(signature, &bufc[5], KEY_LEN+1);
322 		  fixed_xml = S_TRUE;
323 		}
324 	      else
325 		{
326 		  (void) sl_strlcpy(signature, &bufc[4], KEY_LEN+1);
327 		  fixed_xml = S_FALSE;
328 		}
329 	      if (sl_strlen(bufc) > (KEY_LEN+18))
330 		{
331 #ifdef SH_STEALTH
332 		  if (bufc[0] == c_start) /* FIX XML */
333 #else
334 		  if (bufc[0] == c_start)
335 #endif
336 		    (void) sl_strlcpy(timestamp, &bufc[KEY_LEN+5], 64);
337 		  else
338 		    (void) sl_strlcpy(timestamp, &bufc[KEY_LEN+4], 64);
339 #ifdef SH_STEALTH
340 		  ptr = strchr(timestamp, c_start);
341 #else
342 		  ptr = strchr(timestamp, c_start);
343 #endif
344 		  if (ptr) *ptr = '\0';
345 		}
346 	      break;
347 #else
348 	      sl_strlcpy(signature, bufc, KEY_LEN+1);
349 	      if (sl_strlen(bufc) > KEY_LEN)
350 		sl_strlcpy(timestamp, &bufc[KEY_LEN], 64);
351 	      break;
352 #endif
353 	    }
354 	}
355 
356       /* Get starting key from command line.
357        */
358       if (start == 1)
359 	{
360 
361 	  /* Get the timestamp.
362 	   */
363 
364 #ifdef SH_STEALTH
365 	  sh_do_decode (timestamp, sl_strlen(timestamp));
366 #endif
367 	  key[0] = '\0';
368 
369 	findKey:
370 
371 	  if (chk_mode != CHK_FIL)
372 	    {
373 	      /* Ask for the key.
374 	       */
375 	      chk_mode = CHK_KEY;
376 	      fprintf(stdout, _("\nNew audit trail (%s), enter key|keyfile: "),
377 		      /*@-usedef@*/timestamp/*@+usedef@*/);
378 	      key[0] = '\0';
379 
380 	      while (strlen(key) < KEY_LEN )
381 		{
382 		  if (key[0] != '\n' && key[0] != '\0')
383 		    fprintf(stdout, "%s",_("New audit trail, enter key: "));
384 		  else if (key[0] == '\n')
385 		    {
386 		      (void) sl_strlcpy(key,
387 					sh_tiger_hash(NULL, TIGER_DATA, 0,
388 						      hashbuf, sizeof(hashbuf)),
389 					KEY_LEN+1);
390 		      chk_mode = CHK_NON;
391 		      break;
392 		    }
393 		  (void) fflush(stdout);
394 		  key[0] = '\0';
395 		  if (NULL != fgets(key, sizeof(key), stdin))
396 		    {
397 		      if (key[0] != '\n')
398 			{
399 			  if (key[strlen(key) - 1] == '\n')
400 			    key[strlen(key) - 1] = '\0';
401 			}
402 		      if (key[0] == '/')
403 			{
404 			  chk_mode = CHK_FIL;
405 			  (void) sl_strlcpy(path, key, KEY_LEN+1);
406 			  break;
407 			}
408 		    }
409 		}
410 	    }
411 	  /* we now have either a key (chk_mode == CHK_NON|CHK_KEY)
412 	   * or a file (chk_mode == CHK_FIL)
413 	   */
414 	  if (chk_mode == CHK_FIL)
415 	    {
416 	      fprintf(stdout, _("\nAudit trail (%s), searching file %s\n"),
417 		      /*@-usedef@*/timestamp, path/*@+usedef@*/);
418 	      if (-1 == get_key_from_file(path, timestamp, key))
419 		{
420 		  chk_mode = CHK_KEY;
421 		  fprintf(stdout, "%s",_("Key not found in file\n"));
422 		  goto findKey;
423 		}
424 	    }
425 
426 
427 	  sh_util_encode(key, buf, 1, 'B');
428 	  start = 0;
429 	}
430       else
431 	{
432 	  /* Iterate the key.
433 	   */
434 	  (void) sl_strlcpy (key,
435 			     sh_tiger_hash (key, TIGER_DATA, KEY_LEN,
436 					    hashbuf, sizeof(hashbuf)),
437 			     KEY_LEN+1);
438 	}
439 
440       (void) sl_strlcat ( buf, key, 2*SH_MSG_BUF + 1);
441 
442 #ifdef SH_STEALTH
443       sh_do_decode (signature, sl_strlen(signature));
444 #endif
445 
446       status = sl_strncmp (signature,
447 			   sh_tiger_hash (buf, TIGER_DATA,
448 					  (unsigned long) sl_strlen(buf),
449 					  hashbuf, sizeof(hashbuf)),
450 			   KEY_LEN);
451 
452       buf[len] = '\0';    /* do not print out the key */
453 #ifdef SH_STEALTH
454       sh_do_decode (buf, sl_strlen(buf));
455 #endif
456 
457       if (status != 0)
458 	{
459 #ifdef SH_USE_XML
460 	  if (chk_mode == CHK_NON)
461 	    {
462 	      if (fixed_xml == S_FALSE)
463 		fprintf (stdout, _("XFAIL: line=%05d %s/log>\n"),
464 			 count-1, buf);
465 	      else
466 		fprintf (stdout, _("XFAIL: line=%05d %s</log>\n"),
467 			 count-1, buf);
468 	    }
469 	  else
470 	    {
471 	      if (fixed_xml == S_FALSE)
472 		fprintf (stdout, _("FAIL:  line=%05d %s/log>\n"),
473 			 count-1, buf);
474 	      else
475 		fprintf (stdout, _("FAIL:  line=%05d %s</log>\n"),
476 			 count-1, buf);
477 	    }
478 #else
479 	  if (chk_mode == CHK_NON)
480 	    fprintf (stdout, _("XFAIL: line=%5d %s\n"), count-1, buf);
481 	  else
482 	    fprintf (stdout, _("FAIL:  line=%5d %s\n"), count-1, buf);
483 #endif
484 	}
485       else
486 	{
487 #ifdef SH_USE_XML
488 	  if (fixed_xml == S_FALSE)
489 	    fprintf (stdout, _("PASS:  line=%05d %s/log>\n"),  count-1, buf);
490 	  else
491 	    fprintf (stdout, _("PASS:  line=%05d %s</log>\n"), count-1, buf);
492 #else
493 	  fprintf (stdout, _("PASS:  line=%5d %s\n"), count-1, buf);
494 #endif
495 	}
496     }
497 
498   /* Cleanup and exit.
499    */
500   (void) sl_close (fd);
501   SH_FREE  (buf);
502   SH_FREE  (bufc);
503   (void) fflush   (stdout);
504   _exit    (EXIT_SUCCESS);
505 
506   /* Make compilers happy.
507    */
508   /*@notreached@*/
509   return 0;
510 }
511 
512 /********************************************************************
513  *
514  *  Runtime code
515  *
516  ********************************************************************/
517 static
sh_log_open(char * inet_peer,char * logfile,int * service_failure,SL_TICKET * fildesc)518 int sh_log_open (char * inet_peer,
519                  char * logfile, int * service_failure, SL_TICKET * fildesc)
520 {
521   SL_TICKET            fd = -1;
522   long int             status;
523   char               * tmp = NULL;
524   uid_t                uid;
525   size_t               len;
526   char               * lockfile = NULL;
527 
528   SL_ENTER(_("sh_log_open"));
529 
530   /* open/create the file, then check it
531    */
532 
533   if (  0 !=  (status = tf_trust_check (logfile, SL_YESPRIV))
534         && (*service_failure) == 0)
535     {
536       tmp  = sh_util_safe_name (logfile);
537       sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_TRUST,
538                       (long) sh.effective.uid, tmp);
539     }
540 
541   if (status == 0)
542     {
543       fd = sl_open_write (FIL__, __LINE__, logfile, SL_YESPRIV);
544       if (SL_ISERROR(fd))
545         {
546 	  tmp  = sh_util_safe_name (logfile);
547 	  (void) sl_get_euid(&uid);
548           if ((*service_failure) == 0)
549             sh_error_handle ((-1), FIL__, __LINE__, fd, MSG_E_ACCESS,
550                              (long) uid, tmp);
551           status = -1;
552         }
553     }
554 
555 
556   if (status == 0 && inet_peer == NULL )
557     {
558       status = sh_unix_write_lock_file(logfile);
559       if (status < 0)
560         {
561 	  tmp  = sh_util_safe_name (logfile);
562 	  len      = sl_strlen(tmp);
563 	  if (sl_ok_adds (6, len))
564 	    len += 6;
565 	  lockfile = SH_ALLOC(len);
566 	  (void) sl_strlcpy(lockfile,        tmp, len);
567 	  (void) sl_strlcat(lockfile, _(".lock"), len);
568           (void) sl_get_euid(&uid);
569           if ((*service_failure) == 0)
570             sh_error_handle ((-1), FIL__, __LINE__, status, MSG_LOCKED,
571                              (long) uid, tmp, lockfile);
572           status = -1;
573 	  SH_FREE(lockfile);
574           (void) sl_close(fd);
575         }
576     }
577 
578   if (status == 0)
579     {
580       status = sl_forward(fd);
581       if (SL_ISERROR(status))
582         {
583 	  tmp  = sh_util_safe_name (logfile);
584           (void) sl_get_euid(&uid);
585           if ((*service_failure) == 0)
586             sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_ACCESS,
587                              (long) uid, tmp);
588           status = -1;
589           (void) sl_close(fd);
590         }
591     }
592 
593   if (status < 0)
594     {
595       if ((*service_failure) == 0) {
596         sh_error_handle ((-1), FIL__, __LINE__, status, MSG_SRV_FAIL,
597                          _("logfile"), tmp);
598         (*service_failure) = 1;
599       }
600       if (tmp)
601 	SH_FREE(tmp);
602       SL_RETURN(-1, _("sh_log_open"));
603     }
604 
605   *fildesc         = fd;
606   *service_failure = 0;
607   SL_RETURN(0, _("sh_log_open"));
608 }
609 
610 typedef struct lfstc {
611   char          * logfile;
612   int             service_failure;
613   int             log_start;
614   char            sigkey_old[KEY_LEN+1];
615   char            sigkey_new[KEY_LEN+1];
616   char            crypto[KEY_LEN+1];
617   struct  lfstc * next;
618 } open_logfile;
619 
620 static open_logfile * logfile_list = NULL;
621 
622 static int flag_sep_log = S_FALSE;
623 
624 #ifdef SH_WITH_SERVER
set_flag_sep_log(const char * str)625 int set_flag_sep_log (const char * str)
626 {
627   return sh_util_flagval(str, &flag_sep_log);
628 }
629 #endif
630 
631 /*
632  *   --- Log error message to log file. ---
633  */
sh_log_file(char * errmsg,char * inet_peer)634 int  sh_log_file (/*@null@*/char *errmsg, /*@null@*/char * inet_peer)
635 {
636   int                  store1;
637   int                  store2;
638   int                  store3;
639   int                  store4;
640   int                  store5;
641   int                  store6;
642   int                  store7;
643   int                  store8;
644 
645   SL_TICKET            fd = -1;
646   size_t               status;
647   struct _sh_log_buf   log_msg;
648 
649   char                 logfile[SH_PATHBUF+SH_MINIBUF+2];
650   open_logfile       * current = logfile_list;
651   open_logfile       * next    = NULL;
652   char               * sigkey_new;
653   char               * sigkey_old;
654   char               * crypto;
655   char                 hashbuf[KEYBUF_SIZE];
656 
657   SL_ENTER(_("sh_log_file"));
658 
659   if (errFlags.HaveLog == BAD)  /* paranoia */
660     SL_RETURN((-1), _("sh_log_file"));
661 
662 #ifdef SH_USE_XML
663   if (NULL == errmsg)
664     {
665       while (current != NULL)
666         {
667 	  /* don't write second EOF mark
668 	   */
669 	  if (current->log_start != S_TRUE && sh.flag.islocked == GOOD)
670 	    {
671 	      /* Don't use inet_peer == NULL, userwise a lock file will
672 	       * be created.
673 	       */
674 	      (void) sh_log_open ("\0",
675 				  current->logfile,
676 				  &(current->service_failure), &fd);
677 
678 #ifdef SH_STEALTH
679 	      (void) sl_write_line (fd, N_("</trail>"), 7);
680 	      (void) sl_write (fd, "\n", 1);
681 	      (void) sl_sync(fd);
682 #else
683 	      (void) sl_write_line (fd, _("</trail>\n"),  8);
684 	      (void) sl_sync(fd);
685 #endif
686 	      (void) sl_close(fd);
687 	      /* sh_unix_rm_lock_file (current->logfile); */
688 	    }
689 	  next    = current->next;
690 	  SH_FREE(current->logfile);
691 	  SH_FREE(current);
692 	  current = next;
693 	}
694       logfile_list = NULL;
695       SL_RETURN( 0, _("sh_log_file"));
696     }
697 #else
698   if (NULL == errmsg)
699     {
700       while (current != NULL)
701         {
702 	  /* sh_unix_rm_lock_file (current->logfile); */
703 	  next    = current->next;
704           SH_FREE(current->logfile);
705           SH_FREE(current);
706           current = next;
707         }
708       logfile_list = NULL;
709       SL_RETURN( 0, _("sh_log_file"));
710     }
711 #endif
712 
713   (void) sl_strlcpy (logfile, sh.srvlog.name, sizeof(logfile));
714   if (inet_peer != NULL && flag_sep_log == S_TRUE)
715     {
716       (void) sl_strlcat (logfile, ".",       sizeof(logfile));
717       (void) sl_strlcat (logfile, inet_peer, sizeof(logfile));
718     }
719 
720   if (sh.flag.log_start == S_TRUE)
721     {
722       while (current != NULL)
723         {
724           current->log_start = S_TRUE;
725           current = current->next;
726         }
727       sh.flag.log_start    = S_FALSE;
728       current = logfile_list;
729     }
730 
731   while (current != NULL)
732     {
733       if (strcmp(logfile, current->logfile) == 0)
734         break;
735       current = current->next;
736     }
737 
738   if (current == NULL)
739     {
740       current                  = SH_ALLOC(sizeof(open_logfile));
741       current->logfile         = SH_ALLOC(strlen(logfile) + 1);
742       (void) sl_strlcpy(current->logfile, logfile, strlen(logfile) + 1);
743       current->service_failure = 0;
744       current->log_start       = S_TRUE;
745       memset(current->sigkey_old, 0, KEY_LEN+1);
746       memset(current->sigkey_new, 0, KEY_LEN+1);
747       memset(current->crypto,     0, KEY_LEN+1);
748       current->next            = logfile_list;
749       logfile_list             = current;
750     }
751 
752   if (0 != sh_log_open (inet_peer, current->logfile,
753                         &(current->service_failure), &fd))
754     {
755       SL_RETURN ((-1), _("sh_log_file"));
756     }
757 
758 
759   /* --- Allocate storage and mlock it. ---
760    */
761 
762   status      =  sl_strlen (errmsg);
763   if (!sl_ok_adds(status, (2*KEY_LEN)) || !sl_ok_adds((2*KEY_LEN + status),32))
764     {
765       sl_close(fd);
766       SL_RETURN ((-1), _("sh_log_file"));
767     }
768 
769   log_msg.msg = (char *) SH_ALLOC ((size_t) (2*KEY_LEN + status + 32));
770 
771 #if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
772   if (skey->mlock_failed == S_FALSE)
773     {
774       if ( (-1) == sh_unix_mlock( FIL__, __LINE__, log_msg.msg,
775 				  (size_t)(2*KEY_LEN + status + 32) ) )
776 	{
777 	  skey->mlock_failed = S_TRUE;
778 #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
779 	  sh_error_handle ((-1), FIL__, __LINE__, EPERM, MSG_MLOCK);
780 #endif
781 	}
782     }
783 #else
784   if (skey->mlock_failed == S_FALSE)
785     {
786       skey->mlock_failed = S_TRUE;
787 #if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
788       sh_error_handle ((-1), FIL__, __LINE__, EPERM, MSG_MLOCK);
789 #endif
790     }
791 #endif
792 
793   /* --- Write the start marker. ---
794    */
795 
796   if (current->log_start == S_TRUE)
797     {
798 #ifdef SH_USE_XML
799 #ifdef SH_STEALTH
800       (void) sl_write (fd, "\n", 1);
801       (void) sl_write_line (fd, N_("<trail>"), 7);
802       (void) sl_sync(fd);
803 #else
804       (void) sl_write_line (fd, _("\n<trail>"),  8);
805       (void) sl_sync(fd);
806 #endif
807 #else
808 #ifdef SH_STEALTH
809       (void) sl_write (fd, "\n", 1);
810       (void) sl_write_line (fd, N_("[SOF]"), 5);
811       (void) sl_sync(fd);
812 #else
813       (void) sl_write_line (fd, _("\n[SOF]"),  6);
814       (void) sl_sync(fd);
815 #endif
816 #endif
817     }
818 
819   /* reserve KEY_LEN chars at end for key
820    */
821   (void) sl_strlcpy (log_msg.msg, errmsg, (size_t) status+1 );
822 
823 
824 #ifdef SH_USE_XML
825   /* cut the trailing "/>"
826    */
827   if (log_msg.msg[status-2] == '/')
828     {
829 #ifdef FIX_XML
830       log_msg.msg[status-2] = ' '; /* ' ' FIX XML */
831       log_msg.msg[status-1] = '>'; /* '>' FIX XML */
832 #else
833       log_msg.msg[status-2] = '>'; /* ' ' FIX XML */
834       log_msg.msg[status-1] = '<'; /* '>' FIX XML */
835 #endif
836       log_msg.msg[status]   = '\0';
837     }
838   else if (status >= 6 && log_msg.msg[status-5] == '/' &&
839 	   log_msg.msg[status-6] == '<')
840     {
841 #ifdef FIX_XML
842       log_msg.msg[status-6]   = '\0';
843       status -= 6;
844 #else
845       log_msg.msg[status-5]   = '\0';
846       status -= 5;
847 #endif
848     }
849 #endif
850 
851 
852 #ifdef SH_STEALTH
853   sh_do_encode (log_msg.msg, status);
854 #endif
855 
856   if (flag_sep_log == S_TRUE && inet_peer != NULL)
857     {
858       sigkey_old = current->sigkey_old;
859       sigkey_new = current->sigkey_new;
860       crypto     = current->crypto;
861     }
862   else
863     {
864       sigkey_old = skey->sigkey_old;
865       sigkey_new = skey->sigkey_new;
866       crypto     = skey->crypt;      /* flawfinder: ignore */
867     }
868 
869   /* write the signature
870    */
871   if (current->log_start == S_TRUE)
872     {
873       if (sh.real.user[0] == '\0')
874 	(void) sh_unix_getUser();
875 
876       /* Initialize the key.
877        */
878       (void) sh_util_keyinit(sigkey_old, KEY_LEN+1);
879 
880       /* Hash the key to make sure it has the correct format.
881        */
882       (void) sl_strlcpy(sigkey_new,
883 			sh_tiger_hash (sigkey_old, TIGER_DATA, KEY_LEN,
884 				       hashbuf, sizeof(hashbuf)),
885 			KEY_LEN+1);
886 
887       /* Copy it to 'crypt' for encryption.
888        */
889       (void) sl_strlcpy(crypto, sigkey_new, KEY_LEN+1);
890 
891       /* Use message and compiled-in key to encrypt.
892        */
893       BREAKEXIT(sh_util_encode);
894       sh_util_encode(crypto, log_msg.msg, 0, 'B');
895 
896       /* Send out the key.
897        */
898       (void) sh_unix_time(0, log_msg.timestamp, KEY_LEN+1);
899 
900       store1               = errFlags.loglevel;
901       store2               = errFlags.sysloglevel;
902       store3               = errFlags.printlevel;
903       store4               = errFlags.exportlevel;
904       store5               = errFlags.maillevel;
905       store6               = errFlags.externallevel;
906       store7               = errFlags.databaselevel;
907       store8               = errFlags.preludelevel;
908 
909       /* mail the key
910        */
911       errFlags.loglevel       = SH_ERR_NOT;
912       errFlags.sysloglevel    = SH_ERR_NOT;
913       errFlags.printlevel     = SH_ERR_NOT;
914       errFlags.exportlevel    = SH_ERR_NOT;
915       errFlags.externallevel  = SH_ERR_NOT;
916       errFlags.databaselevel  = SH_ERR_NOT;
917       errFlags.preludelevel   = SH_ERR_NOT;
918 
919       sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_KEY_MAIL,
920 		       sh.prg_name, crypto,
921 		       crypto, log_msg.timestamp);
922 
923       /* send to other allowed channels
924        */
925       errFlags.maillevel      = SH_ERR_NOT;
926       /* errFlags.printlevel     = store3; */
927       errFlags.exportlevel    = store4;
928       errFlags.externallevel  = store6;
929       errFlags.databaselevel  = store7;
930       errFlags.preludelevel   = store8;
931 
932       sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_START_KEY,
933 		       sh.prg_name, crypto);
934 
935       /* Cleanup.
936        */
937       errFlags.loglevel       = store1;
938       errFlags.sysloglevel    = store2;
939       errFlags.printlevel     = store3;
940       errFlags.exportlevel    = store4;
941       errFlags.maillevel      = store5;
942       errFlags.externallevel  = store6;
943       errFlags.databaselevel  = store7;
944 
945 
946       memset (crypto, 0, KEY_LEN);
947       sh.flag.log_start    = S_FALSE;
948       current->log_start   = S_FALSE;
949     }
950   else
951     {
952       log_msg.timestamp[0] = '\0';
953       (void) sl_strlcpy (sigkey_new,
954 			 sh_tiger_hash (sigkey_old, TIGER_DATA, KEY_LEN,
955 					hashbuf, sizeof(hashbuf)),
956 			 KEY_LEN+1);
957     }
958 
959   /* --- Sign the message with the signature key. ---
960    */
961   sh_tiger_hash (log_msg.msg, TIGER_DATA,
962 		 (unsigned long)(status + KEY_LEN),
963 		 (char *) hashbuf, (size_t) sizeof(hashbuf));
964 
965   (void) sl_strlcat (log_msg.msg, sigkey_new, (size_t)(status + KEY_LEN + 2));
966   (void) sl_strlcpy (log_msg.signature,
967 		     sh_tiger_hash (log_msg.msg, (TigerType) TIGER_DATA,
968 				    (unsigned long)(status + KEY_LEN),
969 				    hashbuf, sizeof(hashbuf)),
970 		     KEY_LEN+1);
971   (void) sl_strlcpy (sigkey_old, sigkey_new, KEY_LEN+1);
972 
973   /*@-usedef@*/
974 #ifdef SH_USE_XML
975   if (log_msg.timestamp[0] != '\0')
976     sl_snprintf(log_msg.sig, sizeof(log_msg.sig),
977 #ifdef FIX_XML
978 		_("\n<sig>%s%s</sig></log>\n"),          /* <sig> FIX XML */
979 #else
980 		_("\nsig>%s%s</sig></log>\n"),          /* <sig> FIX XML */
981 #endif
982 		log_msg.signature, log_msg.timestamp);
983   else
984     sl_snprintf(log_msg.sig, sizeof(log_msg.sig),
985 #ifdef FIX_XML
986 		_("\n<sig>%s</sig></log>\n"),            /* <sig> FIX XML */
987 #else
988 		_("\nsig>%s</sig></log>\n"),            /* <sig> FIX XML */
989 #endif
990 		log_msg.signature);
991   /*@+usedef@*/
992 
993 #ifdef SH_STEALTH
994   /* don't encode the line breaks (0 + last char)
995    */
996   sh_do_encode (&log_msg.sig[1], (sl_strlen(log_msg.sig)-2) );
997 #endif
998 #else
999 #ifdef SH_STEALTH
1000   sh_do_encode (log_msg.signature, KEY_LEN);
1001   sh_do_encode (log_msg.timestamp, sl_strlen(log_msg.timestamp));
1002 #endif
1003 #endif
1004 
1005 #ifdef SH_USE_XML
1006   log_msg.msg[status] = '\0';
1007   (void) sl_strlcat (log_msg.msg,   log_msg.sig,
1008 		     (size_t)(status + 2*KEY_LEN + 32));
1009 #ifdef SH_STEALTH
1010   if (NULL != sl_strstr(log_msg.msg, N_("EXIT")) &&
1011       NULL == sl_strstr(log_msg.msg, N_("remote_host")))
1012     {
1013       (void) sl_strlcat (log_msg.msg,  N_("</trail>"),
1014 			 (size_t)(status + 2*KEY_LEN + 32));
1015 #else
1016   if (NULL != sl_strstr(log_msg.msg,  _("msg=\"EXIT\"")) &&
1017       NULL == sl_strstr(log_msg.msg,  _("remote_host")))
1018     {
1019       (void) sl_strlcat (log_msg.msg,   _("</trail>"),
1020 			 (size_t)(status + 2*KEY_LEN + 32));
1021 #endif
1022 
1023       (void) sl_strlcat (log_msg.msg,   _("\n"),
1024 			 (size_t)(status + 2*KEY_LEN + 32));
1025       current->log_start = S_TRUE;
1026     }
1027 #else
1028   log_msg.msg[status] = '\0';
1029   (void) sl_strlcat (log_msg.msg,              "\n",
1030 		     (size_t)(status + KEY_LEN + 2));
1031   (void) sl_strlcat (log_msg.msg, log_msg.signature,
1032 		     (size_t)(status + KEY_LEN + 2));
1033   if (log_msg.timestamp[0] != '\0')
1034     (void) sl_strlcat (log_msg.msg, log_msg.timestamp,
1035 		       (size_t)(status + 2*KEY_LEN + 2));
1036   (void) sl_strlcat (log_msg.msg,              "\n",
1037 		     (size_t)(status + 2*KEY_LEN + 3));
1038 #endif
1039 
1040   /* --- Write out the record. ---
1041    */
1042   (void) sl_write (fd, log_msg.msg, (long) strlen(log_msg.msg));
1043   (void) sl_sync  (fd);
1044   (void) sl_close (fd);
1045 
1046   /* --- Clean up and free record. ---
1047    */
1048   memset (log_msg.msg,       0, (size_t)(status + 2*KEY_LEN + 32));
1049   memset (log_msg.signature, 0, KEY_LEN);
1050   (void) sh_unix_munlock (log_msg.msg,
1051 			  (size_t)(status + 2*KEY_LEN + 32));
1052   SH_FREE(log_msg.msg);
1053 
1054   SL_RETURN (0, _("sh_log_file"));
1055 }
1056 
1057 /* >>>>>>>>>>>>>>>>>>>>>>>>>>>> efile <<<<<<<<<<<<<<<<<< */
1058 
1059 static char * gEfile = NULL;
1060 static int    gFail  = 0;
1061 static long   gGid   = 0;
1062 
1063 int sh_efile_group(const char * str)
1064 {
1065   int  fail;
1066   long gid = sh_group_to_gid(str, &fail);
1067 
1068   if (fail < 0)
1069     {
1070       return -1;
1071     }
1072   gGid = gid;
1073   return 0;
1074 }
1075 
1076 
1077 int sh_efile_path(const char * str)
1078 {
1079   if (!str || !strcmp(str, _("none")))
1080     {
1081       if (gEfile)
1082 	SH_FREE(gEfile);
1083       gEfile = NULL;
1084     }
1085   else if (str[0] != '/')
1086     {
1087       return -1;
1088     }
1089   else
1090     {
1091       if (gEfile)
1092 	SH_FREE(gEfile);
1093       gEfile = sh_util_strdup(str);
1094     }
1095   gFail = 0;
1096   return 0;
1097 }
1098 
1099 /* write lock for filename
1100  */
1101 static int sh_efile_lock (char * filename, int flag)
1102 {
1103   extern int get_the_fd (SL_TICKET ticket);
1104   size_t len;
1105   int    res = -1;
1106   char myPid[64];
1107   SL_TICKET  fd;
1108   char * lockfile;
1109   int    status;
1110 
1111   sprintf (myPid, "%ld\n", (long) sh.pid);             /* known to fit  */
1112 
1113   if (filename == NULL)
1114     return res;
1115 
1116   len = sl_strlen(filename);
1117   if (sl_ok_adds(len, 6))
1118     len += 6;
1119   lockfile = SH_ALLOC(len);
1120   sl_strlcpy(lockfile, filename,   len);
1121   sl_strlcat(lockfile, _(".lock"), len);
1122 
1123   if (  0 !=  (status = tf_trust_check (lockfile, SL_YESPRIV))
1124 	&& gFail == 0)
1125     {
1126       char * tmp  = sh_util_safe_name (lockfile);
1127       sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_TRUST,
1128 			   (long) sh.effective.uid, tmp);
1129       ++gFail;
1130       SH_FREE(tmp);
1131     }
1132 
1133   if (status == 0)
1134     {
1135       if (flag == 0)
1136 	{
1137 	  /* --- Delete the lock file. ---
1138 	   */
1139 	  res = retry_aud_unlink (FIL__, __LINE__, lockfile);
1140 	}
1141       else
1142 	{
1143 	  unsigned int count = 0;
1144 
1145 	  /* fails if file exists
1146 	   */
1147 	  do {
1148 	    fd = sl_open_safe_rdwr (FIL__, __LINE__,
1149 				    lockfile, SL_YESPRIV);
1150 	    if (SL_ISERROR(fd))
1151 	      {
1152 		retry_msleep(0, 100);
1153 		++count;
1154 	      }
1155 
1156 	  } while (SL_ISERROR(fd) && count < 3);
1157 
1158 	  if (!SL_ISERROR(fd))
1159 	    {
1160 	      int filed;
1161 
1162 	      res = sl_write (fd, myPid, sl_strlen(myPid));
1163 	      filed = get_the_fd(fd);
1164 	      fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
1165 	      sl_close (fd);
1166 	    }
1167 	  else
1168 	    {
1169 	      static int nFail = 0;
1170 
1171 	      if (nFail == 0)
1172 		{
1173 		  char errmsg[1024];
1174 		  char * tmp  = sh_util_safe_name (lockfile);
1175 
1176 		  sl_snprintf(errmsg, sizeof(errmsg),
1177 			      _("Error creating lockfile %s"),
1178 			      tmp);
1179 
1180 		  sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1181 				   0, MSG_E_SUBGEN,
1182 				   errmsg, _("sh_efile_lock"));
1183 		  ++nFail;
1184 		  SH_FREE(tmp);
1185 		}
1186 	    }
1187 	}
1188     }
1189 
1190   SH_FREE(lockfile);
1191   return res;
1192 }
1193 
1194 static size_t gSave[6] = { 0 };
1195 
1196 static void sh_efile_clear()
1197 {
1198   int i;
1199 
1200   for (i = 0; i < 6; ++i)
1201     gSave[i] = 0;
1202   return;
1203 }
1204 
1205 static void sh_efile_load(size_t * tmp)
1206 {
1207   int i;
1208 
1209   if (S_TRUE == sl_ok_adds (gSave[0], sh.statistics.bytes_hashed))
1210     gSave[0] += sh.statistics.bytes_hashed;
1211   if (S_TRUE == sl_ok_adds (gSave[1], sh.statistics.dirs_checked))
1212     gSave[1] += sh.statistics.dirs_checked;
1213   if (S_TRUE == sl_ok_adds (gSave[2], sh.statistics.files_checked))
1214     gSave[2] += sh.statistics.files_checked;
1215   if (S_TRUE == sl_ok_adds (gSave[3], sh.statistics.files_report))
1216     gSave[3] += sh.statistics.files_report;
1217   if (S_TRUE == sl_ok_adds (gSave[4], sh.statistics.files_error))
1218     gSave[4] += sh.statistics.files_error;
1219   if (S_TRUE == sl_ok_adds (gSave[5], sh.statistics.files_nodir))
1220     gSave[5] += sh.statistics.files_nodir;
1221 
1222   for (i = 0; i < 6; ++i)
1223     tmp[i] = gSave[i];
1224   return;
1225 }
1226 
1227 void sh_efile_report()
1228 {
1229   extern int get_the_fd (SL_TICKET ticket);
1230   SL_TICKET     fd;
1231   char         *efile;
1232   int           status = -1;
1233 
1234   if (gEfile)
1235     {
1236       size_t tmp[6];
1237 
1238       sh_efile_load(tmp);
1239 
1240       efile = sh_util_strdup(gEfile);
1241 
1242       if (sh_efile_lock (efile, 1) < 0)
1243 	goto end;
1244 
1245       if (  0 !=  (status = tf_trust_check (efile, SL_YESPRIV))
1246 	    && gFail == 0)
1247 	{
1248 	  char * tmp  = sh_util_safe_name (efile);
1249 	  sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_TRUST,
1250 			   (long) sh.effective.uid, tmp);
1251 	  ++gFail;
1252 	  SH_FREE(tmp);
1253 	}
1254 
1255       if (status == 0)
1256 	{
1257 	  fd = sl_open_write (FIL__, __LINE__, efile, SL_YESPRIV);
1258 
1259 	  if (!SL_ISERROR(fd))
1260 	    {
1261 	      char report[511];
1262 	      char tstamp[TIM_MAX];
1263 
1264 	      time_t now = time(NULL);
1265 	      int  filed = get_the_fd(fd);
1266 
1267 	      (void) sh_unix_time (now, tstamp, sizeof(tstamp));
1268 #ifdef HAVE_LONG_LONG
1269 	      sl_snprintf(report, sizeof(report),
1270 			  _("%s %lld %ld %ld %ld %ld %ld %ld\n"),
1271 			  tstamp,
1272 			  (long long) now,
1273 			  (long) tmp[0], (long) tmp[1], (long) tmp[2],
1274 			  (long) tmp[3], (long) tmp[4], (long) tmp[5]);
1275 #else
1276 	      sl_snprintf(report, sizeof(report),
1277 			  _("%s %ld %ld %ld %ld %ld %ld %ld\n"),
1278 			  tstamp,
1279 			  (long) now,
1280 			  (long) tmp[0], (long) tmp[1], (long) tmp[2],
1281 			  (long) tmp[3], (long) tmp[4], (long) tmp[5]);
1282 #endif
1283 
1284 	      status = sl_forward(fd);
1285 	      if (!SL_ISERROR(status))
1286 		sl_write (fd, report,  strlen(report));
1287 	      (void) sl_sync(fd);
1288 
1289 	      /* make group writeable, such that nagios can truncate */
1290 	      fchmod (filed, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
1291 	      status = fchown (filed, -1, gGid);
1292 	      if (status < 0)
1293 		{
1294 		  int  errnum = errno;
1295 		  static int nFail = 0;
1296 		  if (nFail == 0)
1297 		    {
1298 		      char errmsg[1024];
1299 		      char buf[256];
1300 		      char * tmp  = sh_util_safe_name (efile);
1301 
1302 		      sl_snprintf(errmsg, sizeof(errmsg),
1303 				  _("Error changing group of %s to %ld: %s"),
1304 				  tmp, gGid,
1305 				  sh_error_message (errnum, buf, sizeof(buf)));
1306 		      sh_error_handle (SH_ERR_ERR, FIL__, __LINE__,
1307 				       errnum, MSG_E_SUBGEN,
1308 				       errmsg, _("sh_efile_report"));
1309 		      ++nFail;
1310 		      SH_FREE(tmp);
1311 		    }
1312 		}
1313 
1314 	      (void) sl_close(fd);
1315 	    }
1316 	  else
1317 	    {
1318 	      status = -1;
1319 	    }
1320 	}
1321 
1322       (void) sh_efile_lock (efile, 0);
1323     end:
1324       SH_FREE(efile);
1325 
1326       if (!SL_ISERROR(status))
1327 	{
1328 	  sh_efile_clear();
1329 	}
1330     }
1331   return;
1332 }
1333