source: trunk/src/sh_error.c

Last change on this file was 541, checked in by katerina, 3 years ago

Fix for ticket #433 (coding standardisation).

File size: 43.3 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 1999, 2000 Rainer Wichmann                                */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  published by                                                           */
8/*  the Free Software Foundation; either version 2 of the License, or      */
9/*  (at your option) any later version.                                    */
10/*                                                                         */
11/*  This program is distributed in the hope that it will be useful,        */
12/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
13/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
14/*  GNU General Public License for more details.                           */
15/*                                                                         */
16/*  You should have received a copy of the GNU General Public License      */
17/*  along with this program; if not, write to the Free Software            */
18/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20#include "config_xor.h"
21
22/* Required on Linux to get the correct strerror_r function. Also
23 * for recursive mutexes (_XOPEN_SOURCE >= 500). Gives funny error
24 * on Solaris 10/gcc ('c99' compiler required - huh? Isn't gcc
25 * good enough?).
26 */
27#if !defined(__sun__) && !defined(__sun)
28#define _XOPEN_SOURCE 600
29#undef  _GNU_SOURCE
30#endif
31#include <string.h>
32#include <stdio.h>    
33#include <stdlib.h>    
34#include <stdarg.h>
35#include <ctype.h>
36#include <limits.h>
37#include <errno.h>
38
39/* Required on FreeBSD
40 */
41#include <sys/types.h>
42
43#ifdef HAVE_MEMORY_H
44#include <memory.h>
45#endif
46
47#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
48#include <sys/mman.h>
49#endif
50
51
52
53#include "samhain.h"
54
55#include "sh_cat.h"
56#include "sh_database.h"
57#include "sh_error.h"
58#include "sh_utils.h"
59#include "sh_unix.h"
60#include "sh_tiger.h"
61#include "sh_nmail.h"
62#include "sh_xfer.h"
63#include "sh_prelude.h"
64#include "sh_pthread.h"
65
66#if defined(WITH_DATABASE)
67#include "sh_tools.h"
68#endif
69
70#if defined(WITH_EXTERNAL)
71#include "sh_extern.h"
72#endif
73
74#undef  FIL__
75#define FIL__  _("sh_error.c")
76/*@-noret -compmempass@*/
77extern int clt_class;
78
79int flag_err_debug = S_FALSE;
80int flag_err_info  = S_FALSE;
81
82int  ShDFLevel[SH_ERR_T_END];
83
84typedef struct _log_t {
85  char file[SH_PATHBUF];
86  char format[SH_PATHBUF];
87  /*@null@*/char * msg;
88  size_t  msg_len;
89  int  severity;
90  int  class;
91  int  pid;
92  long status;
93  long line;
94  char timestamp[TIM_MAX];
95} sh_log_t;
96
97
98struct  _errFlags  errFlags;
99
100static int  sh_error_init (void);
101
102inline
103static const char * get_format(unsigned long msg_id, int * priority, 
104                               unsigned int * class);
105
106static int sh_error_string (struct _log_t * lmsg, va_list vl);
107
108extern int  sh_log_console (/*@null@*/const char *message);
109extern int  sh_log_syslog  (int  severity, /*@null@*/char *message);
110extern int  sh_log_file    (/*@null@*/char *message, 
111                            /*@null@*/char * inet_peer);
112/* convert a string to a numeric priority
113 */ 
114int sh_error_convert_level (const char * str_s);
115
116static int  IsInitialized = BAD;
117
118/* --- Only log to stderr. ---
119 */
120int  OnlyStderr    = S_TRUE; 
121
122/* --- Enable facilities not safe for closeall(). ---
123 */
124int  enableUnsafe  = S_FALSE;
125
126/*********************************************
127 *  utility functions for verifying entries
128 *********************************************/
129
130int sh_error_verify (const char * s)
131{
132  char * foo;
133  char hashbuf[KEYBUF_SIZE];
134
135  if (s[0] == '/')
136    {
137      foo = sh_tiger_hash_gpg (s, TIGER_FILE, TIGER_NOLIM);
138      fprintf (stdout, _("%s\n"),  foo);
139      SH_FREE(foo);
140    }
141  else
142    {
143      fprintf (stdout, _("string=<%s>, hash=<%s>\n"), 
144               s, sh_tiger_hash (s, TIGER_DATA, 
145                                 (unsigned long) sl_strlen(s), 
146                                 hashbuf, sizeof(hashbuf))
147               );
148    }
149  (void) fflush(stdout);
150  _exit (EXIT_SUCCESS);
151  /*@i@*/return 0;
152}
153
154
155
156/*********************************************
157 *  end utility functions
158 *********************************************/
159
160void sh_error_only_stderr (int flag)
161{
162  OnlyStderr    = flag;
163  return;
164}
165
166void sh_error_enable_unsafe (int flag)
167{
168  enableUnsafe    = flag;
169  return;
170}
171
172static int dbg_store = 0;
173static int dbg_flag  = 0;
174
175static
176void compute_flag_err_debug(void)
177{
178  if ((errFlags.loglevel & SH_ERR_ALL) != 0)
179    flag_err_debug = S_TRUE;
180  else if ((errFlags.printlevel & SH_ERR_ALL) != 0)
181    flag_err_debug = S_TRUE;
182  else if ((errFlags.maillevel & SH_ERR_ALL) != 0)
183    flag_err_debug = S_TRUE;
184  else if ((errFlags.exportlevel & SH_ERR_ALL) != 0)
185    flag_err_debug = S_TRUE;
186  else if ((errFlags.sysloglevel & SH_ERR_ALL) != 0)
187    flag_err_debug = S_TRUE;
188  else if ((errFlags.externallevel & SH_ERR_ALL) != 0)
189    flag_err_debug = S_TRUE;
190  else if ((errFlags.databaselevel & SH_ERR_ALL) != 0)
191    flag_err_debug = S_TRUE;
192  else if ((errFlags.preludelevel & SH_ERR_ALL) != 0)
193    flag_err_debug = S_TRUE;
194  else
195    flag_err_debug = S_FALSE;
196  return;
197}
198
199static
200void compute_flag_err_info(void)
201{
202  if ((errFlags.loglevel & SH_ERR_INFO) != 0)
203    flag_err_info = S_TRUE;
204  else if ((errFlags.printlevel & SH_ERR_INFO) != 0)
205    flag_err_info = S_TRUE;
206  else if ((errFlags.maillevel & SH_ERR_INFO) != 0)
207    flag_err_info = S_TRUE;
208  else if ((errFlags.exportlevel & SH_ERR_INFO) != 0)
209    flag_err_info = S_TRUE;
210  else if ((errFlags.sysloglevel & SH_ERR_INFO) != 0)
211    flag_err_info = S_TRUE;
212  else if ((errFlags.externallevel & SH_ERR_INFO) != 0)
213    flag_err_info = S_TRUE;
214  else if ((errFlags.databaselevel & SH_ERR_INFO) != 0)
215    flag_err_info = S_TRUE;
216  else if ((errFlags.preludelevel & SH_ERR_INFO) != 0)
217    flag_err_info = S_TRUE;
218  else
219    flag_err_info = S_FALSE;
220  return;
221}
222
223void sh_error_dbg_switch(void)
224{
225  if (dbg_flag == 0)
226    {
227      dbg_store           = errFlags.printlevel;
228      errFlags.printlevel = (SH_ERR_ALL    | SH_ERR_INFO  | SH_ERR_NOTICE | 
229                             SH_ERR_WARN   | SH_ERR_STAMP | SH_ERR_ERR    | 
230                             SH_ERR_SEVERE | SH_ERR_FATAL);
231      dbg_flag  = 1;
232      flag_err_debug = S_TRUE;
233    }
234  else {
235    errFlags.printlevel = dbg_store;
236    dbg_store = 0;
237    dbg_flag  = 0;
238    compute_flag_err_debug();
239  }
240  return;
241}
242
243static int sh_error_set_classmask (const char * str, int * facility_mask)
244{
245  char * p;
246  char * q;
247  int    num = 0;
248  unsigned int    i;
249  size_t len;
250  char * c;
251
252  SL_ENTER(_("sh_error_set_classmask"));
253 
254  if (str == NULL)
255    SL_RETURN( -1, _("sh_error_set_classmask"));
256
257  if (IsInitialized == BAD) 
258    (void) sh_error_init();
259
260  if (str[0] == (char) 34)
261    ++str;
262  len = strlen(str);
263
264  c = SH_ALLOC(len+1);
265  sl_strlcpy(c, str, len+1);
266
267  if (c[len-1] == (char) 34)
268    c[len-1] = '\0';
269
270  *facility_mask = 0;
271
272  do {
273#if defined(HAVE_PTHREAD) && defined (_POSIX_THREAD_SAFE_FUNCTIONS) && defined(HAVE_STRTOK_R)
274    char * saveptr;
275    if (num == 0) {
276      p = strtok_r (c, " ,\t", &saveptr);
277      ++num;
278    } else {
279      p = strtok_r (NULL, " ,\t", &saveptr);
280    }
281#else
282    if (num == 0) {
283      p = strtok (c, " ,\t");
284      ++num;
285    } else {
286      p = strtok (NULL, " ,\t");
287    }
288#endif
289
290    if (p == NULL)
291      break;
292
293    q = p; while (*q != '\0') { *q = toupper( (int) *q); ++q; }
294
295    for (i = 0; i < SH_CLA_MAX; ++i)
296      {
297        if (i < SH_CLA_RAW_MAX) {
298          if (0 == strcmp(p, _(class_cat[i])))
299            *facility_mask |= (1 << i);
300        } else {
301          if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 0])))
302            *facility_mask |= OTHER_CLA;
303          if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 1])))
304            *facility_mask |= RUN_NEW;
305          if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 2])))
306            *facility_mask |= FIL_NEW;
307          if (0 == strcmp(p, _(class_cat[SH_CLA_RAW_MAX + 3])))
308            *facility_mask |= ERROR_CLA;
309        }         
310      }
311
312  } while (p);
313
314  SH_FREE(c);
315  SL_RETURN( 0, _("sh_error_set_classmask"));
316}
317
318int sh_error_log_mask (const char * c)
319{
320  return (sh_error_set_classmask(c, &(errFlags.log_class)));
321}
322int sh_error_mail_mask (const char * c)
323{
324  return (sh_error_set_classmask(c, &(errFlags.mail_class)));
325}
326int sh_error_print_mask (const char * c)
327{
328  return (sh_error_set_classmask(c, &(errFlags.print_class)));
329}
330int sh_error_export_mask (const char * c)
331{
332  return (sh_error_set_classmask(c, &(errFlags.export_class)));
333}
334int sh_error_syslog_mask (const char * c)
335{
336  return (sh_error_set_classmask(c, &(errFlags.syslog_class)));
337}
338int sh_error_external_mask (const char * c)
339{
340  return (sh_error_set_classmask(c, &(errFlags.external_class)));
341}
342int sh_error_database_mask (const char * c)
343{
344  return (sh_error_set_classmask(c, &(errFlags.database_class)));
345}
346int sh_error_prelude_mask (const char * c)
347{
348  return (sh_error_set_classmask(c, &(errFlags.prelude_class)));
349}
350 
351
352
353char * sh_error_message (int tellme, char * str, size_t len)
354{
355
356#if defined(HAVE_STRERROR_R)
357  if (len > 0) str[0] = '\0';
358  strerror_r(tellme, str, len);
359  return str;
360#elif defined(HAVE_STRERROR)
361  sl_strlcpy(str, strerror(tellme), len);
362  return str;
363#else
364
365  char *p = NULL;
366#ifdef EACCES
367    if (tellme == EACCES)  p = _("Permission denied.");
368#endif
369#ifdef EAGAIN
370    if (tellme == EAGAIN)  p = _("Try again.");
371#endif
372#ifdef EBADF
373    if (tellme == EBADF)   p = _("File descriptor in bad state.");
374#endif
375#ifdef EEXIST
376    if (tellme == EEXIST)  p = _("File exists.");
377#endif
378#ifdef EFAULT
379    if (tellme == EFAULT)  p = _("Bad address.");
380#endif
381#ifdef EINVAL
382    if (tellme == EINVAL)  p = _("Invalid argument.");
383#endif
384#ifdef EISDIR
385    if (tellme == EISDIR)  p = _("Is a directory.");
386#endif
387#ifdef EINTR
388    if (tellme == EINTR)   p = _("System call was interrupted.");
389#endif
390#ifdef EIO
391    if (tellme == EIO)     p = _("Low-level I/O error.");
392#endif
393#ifdef ELOOP
394    if (tellme == ELOOP)   p = _("Too many symbolic links encountered.");
395#endif
396#ifdef EMFILE
397    if (tellme == EMFILE)  p = _("Too many open files.");
398#endif
399#ifdef EMLINK
400    if (tellme == EMLINK)  p = _("Too many links.");
401#endif
402#ifdef ENAMETOOLONG
403    if (tellme == ENAMETOOLONG) 
404                           p = _("File name too long."); 
405#endif
406#ifdef ENFILE
407    if (tellme == ENFILE)  p = _("File table overflow.");
408#endif
409#ifdef ENOENT
410    if (tellme == ENOENT)  p = _("File does not exist.");
411#endif
412#ifdef ENOMEM
413    if (tellme == ENOMEM)  p = _("Out of memory.");
414#endif
415#ifdef ENOSPC
416    if (tellme == ENOSPC)  p = _("No space on device.");
417#endif
418#ifdef ENOTDIR
419    if (tellme == ENOTDIR) p = _("Not a directory.");
420#endif
421#ifdef ENOTSOCK
422    if (tellme == ENOTSOCK) p = _("Not a socket.");
423#endif
424#ifdef EOPNOTSUPP
425    if (tellme == EOPNOTSUPP) p = _("Socket is not of type SOCK_STREAM.");
426#endif
427#ifdef EPERM
428    if (tellme == EPERM)   p = _("Permission denied.");
429#endif
430#ifdef EPIPE
431    if (tellme == EPIPE)   p = _("No read on pipe.");
432#endif
433#ifdef EROFS
434    if (tellme == EROFS)    p = _("Read-only file system.");
435#endif
436#ifdef ETXTBSY
437    if (tellme == ETXTBSY) p = _("Text file busy.");
438#endif
439#ifdef EWOULDBLOCK
440    if (tellme == EWOULDBLOCK) 
441      p = _("No connections on non-blocking socket.");
442#endif
443#ifdef EXDEV
444    if (tellme == EXDEV)    p = _("Not on same file system.");
445#endif
446    if (!p) p = _("Unknown error");
447    sl_strlcpy(str, p, len);
448    return str;
449#endif /* ifndef HAVE_STRERROR */
450}
451
452
453/* switch off file log
454 */
455void sh_error_logoff()
456{
457  errFlags.HaveLog = BAD;
458  return;
459}
460
461/* switch on file log
462 */
463void sh_error_logrestore()
464{
465  errFlags.HaveLog = GOOD;
466  return;
467}
468
469/* --- Relate priority levels to literals. ---
470 */
471typedef struct eef
472{
473  const char * str;
474  int    val;
475} eef_struc;
476
477static eef_struc eef_tab[] =
478{
479  { N_("none"),    SH_ERR_NOT    },
480  { N_("debug"),   SH_ERR_ALL    },
481  { N_("info"),    SH_ERR_INFO   },
482  { N_("notice"),  SH_ERR_NOTICE },
483  { N_("warn"),    SH_ERR_WARN   },
484  { N_("mark"),    SH_ERR_STAMP  },
485  { N_("err"),     SH_ERR_ERR    },
486  { N_("crit"),    SH_ERR_SEVERE },
487  { N_("alert"),   SH_ERR_FATAL  },
488#if defined(SH_WITH_SERVER)
489#define SH_EEF_MAX 10
490  { N_("inet"),    SH_ERR_INET   },
491#else
492#define SH_EEF_MAX 9
493#endif
494};
495
496int sh_error_convert_level (const char * str_s)
497{
498  int i;
499  int level = (-1);
500  char * tmp;
501  char * q;
502 
503  SL_ENTER(_("sh_error_convert_level"));
504 
505  if (str_s == NULL)
506     SL_RETURN( -1, _("sh_error_convert_level"));
507
508  q = sh_util_strdup(str_s);
509  tmp = q; while (*tmp != '\0') { *tmp = tolower( (int) *tmp); ++tmp; }
510 
511  for (i = 0; i < SH_EEF_MAX; ++i)
512    {
513      if (0 == sl_strncmp(q, _(eef_tab[i].str), 
514                          sl_strlen(eef_tab[i].str))) 
515        {
516          level = eef_tab[i].val;
517          break;
518        }
519    }
520
521  SH_FREE(q);
522  SL_RETURN( level, _("sh_error_convert_level"));
523}
524
525
526/* --- Set severity levels. ---
527 */
528int sh_error_set_iv (int iv, const char *  str_s)
529{
530  int level = (-1);
531
532  SL_ENTER(_("sh_error_set_iv"));
533 
534  if (IsInitialized == BAD) 
535    (void) sh_error_init();
536
537  level = sh_error_convert_level (str_s);
538
539  if (level == (-1)) 
540    {
541      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
542                       _("severity"), 
543                       str_s != NULL ? str_s : _("(NULL)"));
544      SL_RETURN (-1, _("sh_error_set_iv"));
545    }
546
547  if (iv > SH_ERR_T_START && iv < SH_ERR_T_END) 
548    {
549      ShDFLevel[iv] =  level;
550    } 
551  else 
552    {
553      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALL, 
554                       _("severity"), (long) iv);
555      SL_RETURN (-1, _("sh_error_set_iv"));
556    }
557  SL_RETURN (0, _("sh_error_set_iv"));
558}
559
560int sh_error_set_level(const char * str_in, int * facility)
561{
562  register int  i, j, f = BAD;
563
564  int  old_facility;
565  char * str_s;
566  char * str_orig;
567  char * tmp;
568
569  SL_ENTER(_("sh_error_set_level"));
570
571  str_s = sh_util_strdup(str_in);
572  str_orig = str_s;
573 
574  tmp = str_s; while (*tmp != '\0') { *tmp = tolower( (int) *tmp); ++tmp; }
575 
576  if (IsInitialized == BAD) 
577    (void) sh_error_init();
578
579  old_facility = *facility;
580  *facility    = 0;
581
582 checkstr:
583
584  if (str_s != NULL) 
585    {
586      if (0 == sl_strncmp(str_s, _(eef_tab[0].str), sl_strlen(eef_tab[0].str)))
587        {
588          *facility |= eef_tab[0].val;  /* This is 'none' */
589          for (i = 1; i < SH_EEF_MAX; ++i)
590            *facility &= ~eef_tab[i].val;
591          f = GOOD;
592        }
593      else if (str_s[0] == '*') /* all */
594        {
595          for (i = 1; i < SH_EEF_MAX; ++i)
596            *facility |= eef_tab[i].val;
597          f = GOOD;
598        }
599      else if (str_s[0] == '=')
600        {
601          for (i = 1; i < SH_EEF_MAX; ++i)
602            if (0 == sl_strncmp(&str_s[1], _(eef_tab[i].str), 
603                                sl_strlen(eef_tab[i].str)))
604              { 
605                *facility |= eef_tab[i].val; 
606                f = GOOD; 
607              }
608        }
609      else if (str_s[0] == '!')
610        {
611          if (str_s[1] == '*' ||
612              0 == sl_strncmp(&str_s[1], _(eef_tab[1].str), 
613                              sl_strlen(eef_tab[1].str)))
614            {
615              *facility |= eef_tab[0].val;  /* This is 'none' */
616              for (i = 1; i < SH_EEF_MAX; ++i)
617                *facility &= ~eef_tab[i].val;
618              f = GOOD;
619            }
620          else if (str_s[1] == '=')
621            {
622              for (i = 1; i < SH_EEF_MAX; ++i)
623                {
624                  if (0 == sl_strncmp(&str_s[2], _(eef_tab[i].str), 
625                                      sl_strlen(eef_tab[i].str)))
626                    { 
627                      *facility &= ~eef_tab[i].val;
628                      f = GOOD; 
629                    }
630                }
631            }
632          else
633            {
634              for (i = 1; i < SH_EEF_MAX; ++i)
635                {
636                  if (0 == sl_strncmp(&str_s[1], _(eef_tab[i].str), 
637                                      sl_strlen(eef_tab[i].str)))
638                    { 
639                      for (j = i; j < SH_EEF_MAX; ++j)
640                        {
641                          *facility &= ~eef_tab[j].val;
642                        }
643                      f = GOOD; 
644                    }
645                }
646            }
647        }
648      else /* plain severity name */
649        {
650          for (i = 1; i < SH_EEF_MAX; ++i)
651            {
652              if (0 == sl_strncmp(str_s, _(eef_tab[i].str), 
653                                  sl_strlen(eef_tab[i].str))) 
654                {
655                  for (j = i; j < SH_EEF_MAX; ++j)
656                    {
657                      *facility |= eef_tab[j].val;
658                    }
659                  f = GOOD; 
660                  break;
661                }
662            }
663        }
664    }
665
666  if (!str_s)
667    {
668      if (str_orig) SH_FREE(str_orig);
669      SL_RETURN ((-1), _("sh_error_set_level"));
670    }
671  /* skip to end of string
672   */
673  while (*str_s != '\0' && *str_s != ';' && *str_s != ',' && 
674         *str_s != ' '  && *str_s != '\t')
675    ++str_s;
676
677  /* skip seperator
678   */
679  while ((*str_s != '\0') && 
680         (*str_s == ';' || *str_s == ',' || *str_s == ' '  || *str_s == '\t'))
681    ++str_s;
682
683  if (*str_s != '\0')
684    {
685      f = BAD;
686      goto checkstr;
687    }
688
689  if (f == BAD) 
690    {
691      *facility = old_facility; 
692      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS, 
693                       _("priority"), str_in);
694      SH_FREE(str_orig);
695      SL_RETURN (-1, _("sh_error_set_level"));
696    }
697  compute_flag_err_debug();
698  compute_flag_err_info();
699  SH_FREE(str_orig);
700  SL_RETURN (0, _("sh_error_set_level"));
701}
702
703#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
704/* set severity for TCP export
705 */
706int sh_error_setexport(const char *  str_s)
707{
708  static int reject = 0;
709  if (reject == 1)
710    return (0);
711
712  if (sh.flag.opts == S_TRUE) 
713    reject = 1;
714
715  return (sh_error_set_level(str_s, &errFlags.exportlevel));
716}
717#endif
718
719/* set severity for printing
720 */
721extern void dlog_set_active(int flag);
722
723int sh_error_setprint(const char *  str_s)
724{
725  static int reject = 0;
726  int        retval;
727
728  if (reject == 1)
729    return (0);
730
731  if (sh.flag.opts == S_TRUE)   
732    reject = 1;
733
734  retval = sh_error_set_level(str_s, &errFlags.printlevel);
735
736  if (0 != (errFlags.printlevel & SH_ERR_INFO))
737    dlog_set_active(1);
738  if (0 != (errFlags.printlevel & SH_ERR_ALL))
739    dlog_set_active(2);
740  return retval;
741}
742
743
744/* set level for error logging
745 */
746int sh_error_setlog(const char * str_s)
747{
748  static int reject = 0;
749  if (reject == 1)
750    return (0);
751
752  if (sh.flag.opts == S_TRUE) 
753    reject = 1;
754
755  return ( sh_error_set_level(str_s, &errFlags.loglevel) );
756}
757
758
759/* set severity for syslog
760 */
761int sh_error_set_syslog (const char * str_s)
762{
763  static int reject = 0;
764  if (reject == 1)
765    return (0);
766
767  if (sh.flag.opts == S_TRUE) 
768    reject = 1;
769
770  return (sh_error_set_level(str_s, &errFlags.sysloglevel));
771}
772
773#if defined(WITH_EXTERNAL)
774/* set severity for external
775 */
776int sh_error_set_external (const char * str_s)
777{
778  static int reject = 0;
779  if (reject == 1)
780    return (0);
781
782  if (sh.flag.opts == S_TRUE) 
783    reject = 1;
784
785  return (sh_error_set_level(str_s, &errFlags.externallevel));
786}
787#endif
788
789#if defined(WITH_DATABASE)
790/* set severity for database
791 */
792int sh_error_set_database (const char * str_s)
793{
794  static int reject = 0;
795  if (reject == 1)
796    return (0);
797
798  if (sh.flag.opts == S_TRUE) 
799    reject = 1;
800
801  return (sh_error_set_level(str_s, &errFlags.databaselevel));
802}
803#endif
804
805#if defined(HAVE_LIBPRELUDE)
806/* set severity for prelude
807 */
808int sh_error_set_prelude (const char * str_s)
809{
810  static int reject = 0;
811
812  if (reject == 1)
813    return (0);
814
815  if (sh.flag.opts == S_TRUE) 
816    reject = 1;
817
818  return sh_error_set_level(str_s, &errFlags.preludelevel);
819}
820#endif
821
822/* init or re-init log facilities that need it
823 */
824void sh_error_fixup(void)
825{
826#if defined(HAVE_LIBPRELUDE)
827  if ((errFlags.preludelevel & SH_ERR_NOT)   == 0)
828    sh_prelude_init();
829  else
830    sh_prelude_stop();
831#endif
832#ifdef WITH_DATABASE
833  sh_database_reset();
834#endif
835  return;
836}
837
838/* to be called from sh_prelude_reset
839 */
840void sh_error_init_prelude(void)
841{
842#if defined(HAVE_LIBPRELUDE)
843  if ((errFlags.preludelevel & SH_ERR_NOT)   == 0)
844    sh_prelude_init();
845  else
846    sh_prelude_stop();
847#endif
848  return;
849}
850
851
852/* set severity for mailing
853 */
854int sh_error_setseverity (const char * str_s)
855{
856  static int reject = 0;
857  if (reject == 1)
858    return (0);
859
860  if (sh.flag.opts == S_TRUE) 
861    reject = 1;
862
863  return (sh_error_set_level(str_s, &errFlags.maillevel));
864}
865
866#ifdef SH_WITH_SERVER
867static char inet_peer[SH_MINIBUF] = { '\0' };
868#ifdef HAVE_LIBPRELUDE
869static char inet_peer_ip[SH_IP_BUF] = { '\0' };
870
871void sh_error_set_peer_ip(const char * str)
872{
873  if (str == NULL)
874    inet_peer_ip[0] = '\0';
875  else
876    sl_strlcpy(inet_peer_ip, str, sizeof(inet_peer_ip));
877}
878#endif
879
880void sh_error_set_peer(const char * str)
881{
882  if (str == NULL)
883    inet_peer[0] = '\0';
884  else
885    sl_strlcpy(inet_peer, str, sizeof(inet_peer));
886}
887#endif
888
889#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
890#include "sh_checksum.h"
891static char * sh_error_replace(const char * msg)
892{
893  char * ret   = NULL;
894
895  if (sh_tiger_get_hashtype () == SH_SHA256)
896    {
897      char * store = NULL;
898
899#ifdef SH_USE_XML
900      char c_end  = '"';
901      char * str  = _("chksum_old=\"");
902      char * str2 = _("chksum_new=\"");
903#else
904      char c_end  = '>';
905      char * str  = _("chksum_old=<");
906      char * str2 = _("chksum_new=<");
907#endif
908
909      ret = SHA256_ReplaceBaseByHex(msg, str, c_end);
910
911      if (ret) {
912        store = ret;
913        ret   = SHA256_ReplaceBaseByHex(ret, str2, c_end);
914        if (ret)
915          SH_FREE(store);
916        else
917          ret = store;
918      } else {
919        ret   = SHA256_ReplaceBaseByHex(msg, str2, c_end);
920      }
921    }
922  return ret;
923}
924static void sh_replace_free(char * msg)
925{
926  if (msg)
927    SH_FREE(msg);
928  return;
929}
930#else
931static char * sh_error_replace(const char * msg) { (void) msg; return NULL; }
932static void sh_replace_free(char * msg) { (void) msg; return; }
933#endif
934
935/**********************************************************
936 **********************************************************
937 *
938 * --------  MAIN ERROR HANDLING FUNCTION -----------------
939 *
940 *
941 * this function should be called to report an error
942 *
943 **********************************************************
944 **********************************************************/
945
946SH_MUTEX_RECURSIVE(mutex_err_handle);
947
948void sh_error_handle (int sev1, const char * file, long line, 
949                      long status, unsigned long msg_id, ...)
950{
951  va_list         vl;                 /* argument list          */
952  struct _log_t * lmsg;
953
954  int    severity;
955  unsigned int class;
956  const char * fmt;
957  volatile int sev = sev1;            /* Avoids the 'clobbered by longjmp' warning. */
958
959  int    flag_inet;
960
961#ifdef SH_WITH_SERVER
962  int    class_inet = clt_class;      /* initialize from global */
963  char   local_inet_peer[SH_MINIBUF];
964#ifdef HAVE_LIBPRELUDE
965  char   local_inet_peer_ip[SH_IP_BUF];
966#endif   
967#endif
968
969#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
970  char   * ex_msg;
971#endif
972#if defined(WITH_DATABASE)
973  char   * escape_msg;
974#endif
975
976  char   * hexmsg = NULL;
977
978  static int    own_block = 0;
979
980  /*
981   * Block a facility for errors generated
982   * within that facility.
983   */
984  static int print_block  = 0;
985#if defined(SH_WITH_MAIL)
986  static int mail_block   = 0;
987#endif
988  static int syslog_block = 0;
989  static int log_block    = 0;
990#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
991  static int export_block = 0;
992#endif
993#if defined(WITH_EXTERNAL)
994  static int external_block = 0;
995#endif
996#if defined(WITH_DATABASE)
997  static int database_block = 0;
998#endif
999#ifdef HAVE_LIBPRELUDE
1000  static int prelude_block = 0;
1001#endif
1002
1003  SL_ENTER(_("sh_error_handle"));
1004
1005  SH_MUTEX_RECURSIVE_INIT(mutex_err_handle);
1006  SH_MUTEX_RECURSIVE_LOCK(mutex_err_handle);
1007
1008#ifdef SH_WITH_SERVER
1009  /* copy the global string into a local array
1010   */
1011  if ((msg_id == MSG_TCP_MSG) && (inet_peer[0] != '\0'))
1012    {
1013      sl_strlcpy(local_inet_peer, inet_peer, sizeof(local_inet_peer));
1014      sh_error_set_peer(NULL);
1015    }
1016  else
1017    local_inet_peer[0] = '\0';
1018
1019#ifdef HAVE_LIBPRELUDE
1020  if ((msg_id == MSG_TCP_MSG) && (inet_peer_ip[0] != '\0'))
1021    {
1022      sl_strlcpy(local_inet_peer_ip, inet_peer_ip, sizeof(local_inet_peer_ip));
1023      sh_error_set_peer_ip(NULL);
1024    }
1025  else
1026    local_inet_peer_ip[0] = '\0';
1027#endif
1028
1029  clt_class = (-1);      /* reset global */
1030#endif
1031
1032
1033  if (own_block == 1)
1034    {
1035      goto exit_here;
1036    }
1037
1038  /* --- Initialize to default values. ---
1039   */
1040  if (IsInitialized == BAD) 
1041    (void) sh_error_init();
1042
1043  /* Returns pointer to (constant|thread-specific) static memory
1044   */
1045  fmt = /*@i@*/get_format (msg_id, &severity, &class);
1046
1047#ifdef SH_WITH_SERVER
1048  if (class_inet != (-1))
1049    class = (unsigned int) class_inet;
1050#endif
1051
1052  /* --- Consistency check. ---
1053   */
1054  ASSERT((fmt != NULL), _("fmt != NULL"))
1055  if (fmt == NULL)
1056    {
1057      fprintf(stderr, 
1058              _("ERROR: msg=<NULL format>, file=<%s>, line=<%ld>\n"), 
1059              file, line);
1060      goto exit_here;
1061    }
1062
1063  /* --- Override the catalogue severity. ---
1064   */
1065  if (sev != (-1))
1066    severity = sev;
1067
1068  /* --- Some statistics. ---
1069   */
1070#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
1071  if ( ((1 << class) & ERROR_CLA) && 
1072       (severity & (SH_ERR_ERR|SH_ERR_SEVERE|SH_ERR_FATAL)))
1073    {
1074      ++sh.statistics.files_error;
1075    }
1076#endif
1077
1078  /* these are messages from remote sources
1079   */
1080  if ((severity  & SH_ERR_INET) != 0)
1081    {
1082      flag_inet = S_TRUE;
1083    }
1084  else
1085    {
1086      flag_inet  = S_FALSE;
1087    }
1088
1089  /* --- Messages not wanted for logging. ---
1090   */
1091  if ( ( (errFlags.printlevel   & severity    ) == 0 || 
1092         (errFlags.print_class  & (1 << class)) == 0 )     &&
1093       ( (errFlags.loglevel     & severity    ) == 0 ||
1094         (errFlags.log_class    & (1 << class)) == 0 )     &&
1095       ( (errFlags.sysloglevel  & severity    ) == 0 || 
1096         (errFlags.syslog_class & (1 << class)) == 0 )     &&
1097#if defined(SH_WITH_CLIENT) || defined(SH_WITH_CLIENT)
1098       ( (errFlags.exportlevel  & severity    ) == 0 ||
1099         (errFlags.export_class & (1 << class)) == 0 )     &&
1100#endif
1101#ifdef WITH_EXTERNAL
1102       ( (errFlags.externallevel  & severity    ) == 0 ||
1103         (errFlags.external_class & (1 << class)) == 0 )     &&
1104#endif
1105#ifdef HAVE_LIBPRELUDE
1106       ( (errFlags.preludelevel   & severity    ) == 0 ||
1107         (errFlags.prelude_class  & (1 << class)) == 0 )     &&
1108#endif
1109#ifdef WITH_DATABASE
1110       ( (errFlags.databaselevel  & severity    ) == 0 ||
1111         (errFlags.database_class & (1 << class)) == 0 )     &&
1112#endif
1113       ( (errFlags.maillevel     & severity    ) == 0 ||
1114         (errFlags.mail_class    & (1 << class)) == 0 )
1115#ifdef SH_WITH_SERVER
1116       && (flag_inet == S_FALSE) /* still log messages from remote sources */
1117#endif
1118       )
1119    {
1120      goto exit_here;
1121    }
1122
1123  if ((severity & SH_ERR_NOT) != 0)
1124    {
1125      goto exit_here;
1126    }
1127 
1128#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
1129  if ((sh_global_check_silent > SH_SILENT_STD) &&
1130      (((1 << FIL) & (1 << class)) != 0))
1131    {
1132      goto exit_here;
1133    }
1134#endif
1135
1136  /* Allocate space for the message.
1137   */
1138  own_block = 1;
1139  lmsg = (struct _log_t *) SH_ALLOC(sizeof(struct _log_t));
1140  MLOCK( (char *) lmsg, sizeof(struct _log_t));
1141  /*@i@*/lmsg->msg = NULL;
1142
1143  /*@i@*/(void) sl_strlcpy(lmsg->format, fmt, SH_PATHBUF);
1144  (void) sl_strlcpy(lmsg->file, file, SH_PATHBUF);
1145  lmsg->severity = severity;
1146  lmsg->class    = (int) class;
1147  lmsg->line     = line;
1148  lmsg->status   = status;
1149
1150  /* Format the log message with timestamp etc.
1151   * Allocate lmsg->msg
1152   */
1153  va_start (vl, msg_id);
1154  (void) sh_error_string (lmsg, vl);
1155  va_end (vl);
1156  own_block = 0;
1157
1158  hexmsg = sh_error_replace(lmsg->msg);
1159
1160  /* Log to stderr.
1161   */
1162  if ( ((errFlags.printlevel  & severity)     != 0   && 
1163        (errFlags.print_class & (1 << class)) != 0   &&
1164        (errFlags.printlevel  & SH_ERR_NOT)   == 0)
1165#ifdef SH_WITH_SERVER
1166       || (flag_inet == S_TRUE) 
1167#endif
1168       )
1169    { 
1170      if (print_block == 0 && (errFlags.printlevel & SH_ERR_NOT) == 0) 
1171        {
1172          /* no truncation
1173           */
1174          print_block = 1;
1175          TPT(( 0, FIL__, __LINE__, lmsg->msg)); 
1176          /*
1177           *  Reports first error after failure. Always tries.
1178           */
1179          (void) sh_log_console (hexmsg ? hexmsg : lmsg->msg);
1180          print_block = 0;
1181        }
1182    }
1183
1184
1185  /* Full logging enabled.
1186   */
1187  if (OnlyStderr == S_FALSE)  /* full error logging enabled */
1188    {
1189
1190      /* Log to syslog.
1191       */
1192      if ( (errFlags.sysloglevel  & severity)      != 0 &&
1193           (errFlags.syslog_class & (1 << class))  != 0 &&
1194#ifndef INET_SYSLOG
1195           (flag_inet != S_TRUE)                        && /* !inet->syslog */
1196#endif
1197           (errFlags.sysloglevel  & SH_ERR_NOT)    == 0 ) 
1198        {
1199          /* will truncate to 1023 bytes
1200           */
1201          if (syslog_block == 0)
1202            {
1203              syslog_block = 1;
1204              /*
1205               * Ignores errors. Always tries.
1206               */
1207              (void) sh_log_syslog (lmsg->severity, hexmsg ? hexmsg : lmsg->msg);
1208              syslog_block = 0;
1209            }
1210        }
1211
1212#if defined(WITH_EXTERNAL)
1213      /*
1214       * -- external facility
1215       */
1216      if ((errFlags.externallevel  & severity)     != 0 && 
1217          (errFlags.external_class & (1 << class)) != 0 &&
1218          (errFlags.externallevel  & SH_ERR_NOT)   == 0 &&
1219          class != AUD)
1220        {
1221          if (external_block == 0)
1222            {
1223              /* no truncation
1224               */
1225              external_block = 1;
1226              /*
1227               *  Reports first error after failure. Always tries.
1228               */
1229              (void) sh_ext_execute ('l', 'o', 'g', hexmsg ? hexmsg : lmsg->msg, 0);
1230              external_block = 0;
1231            }
1232        }
1233#endif
1234
1235#if defined(WITH_DATABASE)
1236      /*
1237       * -- database facility
1238       */
1239      if ((errFlags.databaselevel  & severity)     != 0 && 
1240          (errFlags.database_class & (1 << class)) != 0 &&
1241          (errFlags.databaselevel  & SH_ERR_NOT)   == 0 &&
1242          class != AUD)
1243        {
1244          if (database_block == 0 && enableUnsafe == S_TRUE)
1245            {
1246              /* truncates; query_max is 16k
1247               */
1248              database_block = 1;
1249#ifndef SH_STANDALONE
1250              if (msg_id == MSG_TCP_MSG
1251#ifdef INET_SYSLOG
1252                  || msg_id == MSG_INET_SYSLOG
1253#endif
1254                  )
1255                {
1256                  /* do not escape twice
1257                   */
1258                  /*
1259                   *  Reports failure every 60 min. Always tries.
1260                   */
1261                  (void) sh_database_insert (lmsg->msg);
1262                }
1263              else
1264#endif
1265                {
1266                  escape_msg = sh_tools_safe_name(lmsg->msg, 0);
1267                  /*
1268                   *  Reports failure every 60 min. Always tries.
1269                   */
1270                  (void) sh_database_insert (escape_msg);
1271                  SH_FREE(escape_msg);
1272                }
1273              database_block = 0;
1274            }
1275        }
1276#endif
1277
1278      /****************************************************
1279       * Optionally include client code for TCP forwarding
1280       * to log server
1281       ****************************************************/
1282#if defined(SH_WITH_CLIENT) || defined(SH_WITH_SERVER)
1283      /* Export by TCP.
1284       */
1285
1286      if ( ((errFlags.exportlevel  & severity  )   != 0 &&
1287            (errFlags.export_class & (1 << class)) != 0 &&
1288            (errFlags.exportlevel  & SH_ERR_NOT)   == 0 &&
1289            class != AUD                               )
1290#ifdef SH_WITH_SERVER
1291           /* always log inet to export */
1292           || (flag_inet == S_TRUE && sh.srvexport.name[0] != '\0') 
1293#endif
1294          /* sh.flag.isserver != GOOD                    && */
1295          /* (flag_inet == S_FALSE) */ /* don't log inet to export */
1296           )
1297        {
1298          if (export_block == 0)
1299            {
1300              int retval;
1301              size_t ex_len;
1302
1303              /* will truncate to 65280 bytes
1304               */
1305              export_block = 1;
1306              /* ex_len = 64 + sl_strlen(lmsg->msg) + 1; */
1307              ex_len = sl_strlen(lmsg->msg);
1308              if (sl_ok_adds(ex_len, 65))
1309                ex_len = 64 + ex_len + 1;
1310              ex_msg = SH_ALLOC (ex_len);
1311
1312              sl_snprintf(ex_msg, ex_len, _("%d?%u?%s"),
1313                      severity, class, lmsg->msg);
1314              retval = sh_xfer_report (ex_msg);
1315              SH_FREE(ex_msg);
1316              export_block = 0;
1317              if (retval == -2)
1318                {
1319                  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_QUEUE_FULL,
1320                                   _("log server"));
1321                }
1322            }
1323        }
1324#endif
1325
1326
1327      /* Log to mail.
1328       */
1329#if defined(SH_WITH_MAIL)
1330      if ((errFlags.maillevel  & severity  )   != 0  &&
1331          (errFlags.mail_class & (1 << class)) != 0  &&
1332          (errFlags.maillevel  & SH_ERR_NOT)   == 0  &&
1333          class != AUD                               &&
1334          (flag_inet == S_FALSE) ) /* don't log inet to email */
1335        {
1336          if (mail_block == 0)
1337            {
1338              int retval; 
1339
1340              /* will truncate to 998 bytes
1341               */
1342              mail_block = 1;
1343
1344              BREAKEXIT(sh_nmail_msg);
1345              if ( (severity & SH_ERR_FATAL) == 0) 
1346                retval = sh_nmail_pushstack (severity, hexmsg ? hexmsg : lmsg->msg, NULL);
1347              else 
1348                retval = sh_nmail_msg (severity, hexmsg ? hexmsg : lmsg->msg, NULL);
1349
1350              mail_block = 0;
1351              if (retval == -2)
1352                {
1353                  sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_QUEUE_FULL,
1354                                   _("email"));
1355                }
1356            }
1357        }
1358#endif
1359
1360#ifdef HAVE_LIBPRELUDE
1361      if (((errFlags.preludelevel  & severity  )   != 0  &&
1362           (errFlags.prelude_class & (1 << class)) != 0  &&
1363           (errFlags.preludelevel  & SH_ERR_NOT)   == 0  &&
1364           (class != AUD)) 
1365#ifdef SH_WITH_SERVER
1366             || (flag_inet == S_TRUE)
1367#endif
1368          )
1369        {
1370          if (prelude_block == 0 && enableUnsafe == S_TRUE)
1371            {
1372              /* will truncate to 998 bytes
1373               */
1374              prelude_block = 1;
1375
1376              BREAKEXIT(sh_prelude_alert);
1377              /*
1378               *  Reports first error after failure. Always tries.
1379               */
1380#if defined(HAVE_LIBPRELUDE) && defined(SH_WITH_SERVER)
1381              (void) sh_prelude_alert (severity, (int) class, 
1382                                       hexmsg ? hexmsg : lmsg->msg, lmsg->status, msg_id, 
1383                                       local_inet_peer_ip);
1384#else
1385              (void) sh_prelude_alert (severity, (int) class, 
1386                                       hexmsg ? hexmsg : lmsg->msg, lmsg->status, msg_id, 
1387                                       NULL);
1388#endif
1389              prelude_block = 0;
1390            }
1391        }
1392#endif
1393
1394      /* Log to logfile
1395       */
1396
1397      if ( ( (  (errFlags.loglevel  & severity)     != 0 &&
1398                (errFlags.log_class & (1 << class)) != 0 &&
1399                (errFlags.loglevel  & SH_ERR_NOT)   == 0 )
1400#ifdef SH_WITH_SERVER
1401             || (flag_inet == S_TRUE)
1402#endif
1403             )                       &&
1404           class != AUD              &&
1405           (errFlags.HaveLog != BAD) &&  /* temporary switched off */
1406           (severity & SH_ERR_NOT) == 0 /* paranoia */
1407          ) 
1408        {
1409          if (log_block == 0)
1410            {
1411              /* no truncation
1412               */
1413              log_block = 1;
1414              BREAKEXIT(sh_log_file);
1415#ifdef SH_WITH_SERVER
1416              if (0 != sl_ret_euid())
1417                {
1418                  /*
1419                   *  Reports first error after failure. Always tries.
1420                   */
1421                  if (local_inet_peer[0] == '\0')
1422                    (void) sh_log_file (lmsg->msg, NULL);
1423                  else
1424                    (void) sh_log_file (lmsg->msg, local_inet_peer);
1425                }
1426#else
1427              (void) sh_log_file (hexmsg ? hexmsg : lmsg->msg, NULL);
1428#endif
1429              /* sh_log_file (lmsg->msg); */
1430              log_block = 0;
1431            }
1432        }
1433
1434    }
1435
1436  /* Cleanup.
1437   */
1438  own_block = 1;
1439
1440  if (lmsg->msg)
1441    SH_FREE( lmsg->msg );
1442  sh_replace_free(hexmsg);
1443
1444  memset ( lmsg, 0, sizeof(struct _log_t) );
1445  MUNLOCK( (char *) lmsg,       sizeof(struct _log_t) );
1446  SH_FREE( lmsg );
1447  own_block = 0;
1448
1449 exit_here:
1450  ; /* label at end of compound statement */
1451  SH_MUTEX_RECURSIVE_UNLOCK(mutex_err_handle);
1452
1453  /*@i@*/SL_RET0(_("sh_error_handle"));
1454/*@i@*/}
1455
1456#if defined(SH_WITH_MAIL)
1457void sh_error_mail (const char * alias, int sev, 
1458                    const char * file, long line, 
1459                    long status, unsigned long msg_id, ...)
1460{
1461  va_list         vl;                 /* argument list          */
1462  struct _log_t * lmsg;
1463
1464  int    severity;
1465  unsigned int class;
1466  const char * fmt;
1467  int retval; 
1468
1469  SL_ENTER(_("sh_error_mail"));
1470
1471  /* Returns pointer to (constant|thread-specific) static memory
1472   */
1473  fmt = /*@i@*/get_format (msg_id, &severity, &class);
1474
1475  if (!fmt)
1476    {
1477      SL_RET0(_("sh_error_mail"));
1478    }
1479
1480  /* --- Override the catalogue severity. ---
1481   */
1482  if (sev != (-1))
1483    severity = sev;
1484
1485  /* --- Build the message. ---
1486   */
1487  lmsg = (struct _log_t *) SH_ALLOC(sizeof(struct _log_t));
1488  MLOCK( (char *) lmsg, sizeof(struct _log_t));
1489  /*@i@*/lmsg->msg = NULL;
1490
1491  /*@i@*/(void) sl_strlcpy(lmsg->format, fmt, SH_PATHBUF);
1492  (void) sl_strlcpy(lmsg->file, file, SH_PATHBUF);
1493  lmsg->severity = severity;
1494  lmsg->class    = (int) class;
1495  lmsg->line     = line;
1496  lmsg->status   = status;
1497
1498  /* Format the log message with timestamp etc.
1499   * Allocate lmsg->msg
1500   */
1501  va_start (vl, msg_id);
1502  (void) sh_error_string (lmsg, vl);
1503  va_end (vl);
1504
1505  if ( (severity & SH_ERR_FATAL) == 0) 
1506    retval = sh_nmail_pushstack (severity, lmsg->msg, alias);
1507  else 
1508    retval = sh_nmail_msg (severity, lmsg->msg, alias);
1509 
1510  if (retval == -2)
1511    {
1512      sh_error_handle ((-1), FIL__, __LINE__, 0, MSG_QUEUE_FULL,
1513                       _("email"));
1514    }
1515  SL_RET0(_("sh_error_mail"));
1516}
1517#else
1518void sh_error_mail (const char * alias, int sev, 
1519                    const char * file, long line, 
1520                    long status, unsigned long msg_id, ...)
1521{
1522  (void) alias;
1523  (void) sev;
1524  (void) file;
1525  (void) line;
1526  (void) status;
1527  (void) msg_id;
1528
1529  return;
1530}
1531/* defined(SH_WITH_MAIL) */
1532#endif
1533
1534/* ------------------------- 
1535 *
1536 * private functions below
1537 *
1538 * -------------------------
1539 */
1540
1541
1542/* --- Get the format from the message catalog. ---
1543 */
1544/*@owned@*/ /*@null@*/inline
1545static const char * get_format(unsigned long msg_id, /*@out@*/ int * priority, 
1546                         /*@out@*/unsigned int * class)
1547{
1548  int i = 0;
1549
1550  SL_ENTER(_("get_format"));
1551  while (1 == 1)
1552    {
1553      if ( msg_cat[i].format == NULL )
1554        break;
1555
1556      if ( (unsigned long) msg_cat[i].id == msg_id)
1557        {
1558          *priority = (int) msg_cat[i].priority;
1559          *class    = (unsigned int) msg_cat[i].class;
1560          SL_RETURN (((const char *) _(msg_cat[i].format)), _("get_format"));
1561        }
1562      ++i;
1563    }
1564  *priority = SH_ERR_ERR;
1565  *class = ERR;
1566  SL_RETURN (NULL, _("get_format"));
1567}
1568
1569/*@null@*//*@only@*/static char * ehead_format = NULL;
1570
1571/* allocate space for user-defined message header
1572 */
1573int sh_error_ehead (/*@null@*/const char * str_s)
1574{
1575  size_t size;
1576  const char * s;
1577
1578  SL_ENTER(_("sh_error_ehead"));
1579
1580  if (str_s == NULL)
1581    {
1582      SL_RETURN (-1, _("sh_error_ehead"));
1583    }
1584
1585  /* ascii 34 ist t\"ttelchen
1586   */
1587  /*@i@*/ if (str_s[0] == 34) s = &str_s[1];
1588  else s = str_s;
1589 
1590  size = /*@i@*/strlen(s);
1591  if (/*@i@*/s[size-1] == (char) 34) --size; /* truncate */
1592
1593  if (ehead_format != NULL)
1594    SH_FREE(ehead_format);
1595 
1596  /*@i@*/ehead_format = SH_ALLOC(size+1);
1597  /*@i@*/ (void) sl_strlcpy(ehead_format, s, size+1);
1598
1599  SL_RETURN( 0, _("sh_error_ehead"));
1600}
1601
1602#if !defined(VA_COPY)
1603#if defined(__GNUC__) && defined(__PPC__) && (defined(_CALL_SYSV) || defined(_WIN32))
1604#define VA_COPY(ap1, ap2)     (*(ap1) = *(ap2))
1605#elif defined(VA_COPY_AS_ARRAY)
1606#define VA_COPY(ap1, ap2)     memmove ((ap1), (ap2), sizeof (va_list))
1607#else /* va_list is a pointer */
1608#define VA_COPY(ap1, ap2)     ((ap1) = (ap2))
1609#endif
1610#endif
1611
1612
1613/* print an error  into string
1614 */
1615static int sh_error_string (struct _log_t * lmsg, va_list vl)
1616{
1617  size_t len;
1618  int required;
1619  unsigned long line;
1620  char sev[16] = "";
1621  char cla[16] = "";
1622  char tst[64] = "";
1623  char *p;
1624  va_list       vl2;
1625
1626  st_format rep_ehead_tab[] = {
1627    { 'S', S_FMT_STRING,  0, 0, NULL},  /* severity  */
1628    { 'T', S_FMT_STRING,  0, 0, NULL},  /* timestamp */
1629    { 'F', S_FMT_STRING,  0, 0, NULL},  /* file      */
1630    { 'L', S_FMT_ULONG,   0, 0, NULL},  /* line      */
1631    { 'C', S_FMT_STRING,  0, 0, NULL},  /* class     */
1632    { 'E', S_FMT_LONG,    0, 0, NULL},  /* status    */
1633    {'\0', S_FMT_ULONG,   0, 0, NULL},
1634  };
1635
1636  SL_ENTER(_("sh_error_string"));
1637
1638  if (ehead_format == NULL)
1639    {
1640      ehead_format = SH_ALLOC(64);
1641#ifdef SH_USE_XML
1642      if ((errFlags.printlevel & SH_ERR_ALL) == 0) 
1643        (void) sl_strlcpy(ehead_format, 
1644                          _("<log sev=\"%S\" tstamp=\"%T\" "), 64);
1645      else
1646        (void) sl_strlcpy(ehead_format, 
1647                          _("<log sev=\"%S\" tstamp=\"%T\" p.f=\"%F\" p.l=\"%L\" p.s=\"%E\" "), 64);
1648#else
1649      if ((errFlags.printlevel & SH_ERR_ALL) == 0) 
1650        (void) sl_strlcpy(ehead_format, _("%S %T "), 64);
1651      else
1652        (void) sl_strlcpy(ehead_format, _("%S %T (%F, %L, %E) "), 64);
1653#endif
1654    }
1655
1656  /* header of error message
1657   */
1658#ifdef SH_USE_XML
1659  if      ( (lmsg->severity & SH_ERR_INET) != 0)
1660    (void) sl_strlcpy (sev, _("RCVT"), 11);
1661  else if ( (lmsg->severity & SH_ERR_ALL) != 0)
1662    (void) sl_strlcpy (sev, _("DEBG"), 11);
1663  else if ( (lmsg->severity & SH_ERR_INFO) != 0)
1664    (void) sl_strlcpy (sev, _("INFO"), 11);
1665  else if ( (lmsg->severity & SH_ERR_NOTICE) != 0)
1666    (void) sl_strlcpy (sev, _("NOTE"), 11);
1667  else if ( (lmsg->severity & SH_ERR_WARN) != 0)
1668    (void) sl_strlcpy (sev, _("WARN"), 11);
1669  else if ( (lmsg->severity & SH_ERR_STAMP) != 0)
1670    (void) sl_strlcpy (sev, _("MARK"), 11);
1671  else if ( (lmsg->severity & SH_ERR_ERR) != 0)
1672    (void) sl_strlcpy (sev, _("ERRO"), 11);
1673  else if ( (lmsg->severity & SH_ERR_SEVERE) != 0)
1674    (void) sl_strlcpy (sev, _("CRIT"), 11);
1675  else if ( (lmsg->severity & SH_ERR_FATAL) != 0)
1676    (void) sl_strlcpy (sev, _("ALRT"), 11);
1677  else {
1678    (void) sl_strlcpy (sev, _("????"), 11);
1679#else
1680#if defined(INET_SYSLOG)
1681  if      ( (lmsg->severity & SH_ERR_INET) != 0)
1682    (void) sl_strlcpy (sev, _("<NET>  : "), 11);
1683#else
1684  if      ( (lmsg->severity & SH_ERR_INET) != 0)
1685    (void) sl_strlcpy (sev, _("<TCP>  : "), 11);
1686#endif
1687  else if ( (lmsg->severity & SH_ERR_ALL) != 0)
1688    (void) sl_strlcpy (sev, _("DEBUG  : "), 11);
1689  else if ( (lmsg->severity & SH_ERR_INFO) != 0)
1690    (void) sl_strlcpy (sev, _("INFO   : "), 11);
1691  else if ( (lmsg->severity & SH_ERR_NOTICE) != 0)
1692    (void) sl_strlcpy (sev, _("NOTICE : "), 11);
1693  else if ( (lmsg->severity & SH_ERR_WARN) != 0)
1694    (void) sl_strlcpy (sev, _("WARN   : "), 11);
1695  else if ( (lmsg->severity & SH_ERR_STAMP) != 0)
1696    (void) sl_strlcpy (sev, _("MARK   : "), 11);
1697  else if ( (lmsg->severity & SH_ERR_ERR) != 0)
1698    (void) sl_strlcpy (sev, _("ERROR  : "), 11);
1699  else if ( (lmsg->severity & SH_ERR_SEVERE) != 0)
1700    (void) sl_strlcpy (sev, _("CRIT   : "), 11);
1701  else if ( (lmsg->severity & SH_ERR_FATAL) != 0)
1702    (void) sl_strlcpy (sev, _("ALERT  : "), 11);
1703  else {
1704    (void) sl_strlcpy (sev, _("???    : "), 11);
1705#endif
1706  }
1707
1708  (void) sh_unix_time (0, tst, 64);
1709  line = (unsigned long) lmsg->line;
1710  (void) sl_strlcpy (cla, _(class_cat[lmsg->class]), 11);
1711
1712  /*@i@*/rep_ehead_tab[0].data_str   = sev;
1713  /*@i@*/rep_ehead_tab[1].data_str   = tst;
1714  /*@i@*/rep_ehead_tab[2].data_str   = lmsg->file;
1715  /*@i@*/rep_ehead_tab[3].data_ulong = line;
1716  /*@i@*/rep_ehead_tab[4].data_str   = cla;
1717  /*@i@*/rep_ehead_tab[5].data_long  = lmsg->status;
1718 
1719  p = /*@i@*/sh_util_formatted(ehead_format, rep_ehead_tab);
1720
1721  /* ---  copy the header to lmsg->msg  ---
1722   */
1723  /*@i@*/lmsg->msg     = SH_ALLOC(SH_BUFSIZE);
1724  lmsg->msg_len = SH_BUFSIZE;
1725
1726  if (p)
1727    {
1728      (void) sl_strlcpy (lmsg->msg, p, SH_BUFSIZE);
1729      SH_FREE(p);
1730    }
1731  else
1732    {
1733      lmsg->msg[0] = '\0';
1734    }
1735
1736
1737  /* --- copy message to lmsg->msg ---
1738   */
1739  if ( NULL == strchr(lmsg->format, '%') ) 
1740    {
1741      (void) sl_strlcat (lmsg->msg, lmsg->format, (size_t) lmsg->msg_len);
1742    }
1743  else 
1744    {
1745      /* use VA_COPY */
1746      /*@i@*/VA_COPY(vl2, vl);
1747      len      = sl_strlen(lmsg->msg);
1748      /*@i@*/required = sl_vsnprintf(&(lmsg->msg[len]), 
1749                                     (lmsg->msg_len - len), lmsg->format, vl);
1750
1751      if ((required >= 0) && 
1752          sl_ok_adds(required, len) &&
1753          sl_ok_adds((required+len), 4) &&
1754          ((required + len) > (lmsg->msg_len - 4)) )
1755        {
1756          /*@i@*/p = SH_ALLOC(required + len + 4);
1757          (void) sl_strlcpy (p, lmsg->msg, required + len + 1);
1758          SH_FREE(lmsg->msg);
1759          lmsg->msg = p;
1760          lmsg->msg_len = required + len + 4;
1761          (void) sl_vsnprintf(&(lmsg->msg[len]), 
1762                              (required + 1), lmsg->format, vl2);
1763        }
1764      va_end(vl2);
1765    }
1766
1767#ifdef SH_USE_XML
1768  /* closing tag
1769   */
1770  if (lmsg->msg[sl_strlen(lmsg->msg)-1] != '>')
1771    (void) sl_strlcat (lmsg->msg, _(" />"), lmsg->msg_len);
1772#endif
1773
1774  SL_RETURN(0, _("sh_error_string"));
1775}
1776
1777     
1778
1779
1780/* --- Initialize. ---
1781 */
1782static int  sh_error_init ()
1783{
1784  register int j;
1785
1786  SL_ENTER(_("sh_error_init"));
1787
1788  errFlags.debug          = 0;
1789  errFlags.HaveLog        = GOOD;
1790  errFlags.sysloglevel    = SH_ERR_NOT;
1791#if defined(SH_STEALTH)
1792  errFlags.loglevel       = SH_ERR_NOT;
1793#else
1794  errFlags.loglevel       = (SH_ERR_STAMP | SH_ERR_ERR    | SH_ERR_SEVERE |
1795                             SH_ERR_FATAL);
1796#endif
1797  errFlags.externallevel  = SH_ERR_NOT;
1798  errFlags.databaselevel  = SH_ERR_NOT;
1799  errFlags.preludelevel   = SH_ERR_NOT;
1800  errFlags.maillevel      = SH_ERR_FATAL;
1801#if defined(SH_STEALTH)
1802  errFlags.printlevel     = SH_ERR_NOT;
1803#else
1804  errFlags.printlevel     = (SH_ERR_INFO  | SH_ERR_NOTICE | SH_ERR_WARN   | 
1805                             SH_ERR_STAMP | SH_ERR_ERR    | SH_ERR_SEVERE |
1806                             SH_ERR_FATAL);
1807  flag_err_info           = S_TRUE;
1808#endif
1809
1810#if defined(SH_WITH_SERVER)
1811  errFlags.exportlevel    = SH_ERR_NOT;
1812#else
1813  errFlags.exportlevel    = (SH_ERR_STAMP | SH_ERR_ERR    | SH_ERR_SEVERE |
1814                             SH_ERR_FATAL);
1815#endif
1816
1817  errFlags.log_class      = 0xFFFF;
1818  errFlags.print_class    = 0xFFFF;
1819  errFlags.mail_class     = 0xFFFF;
1820  errFlags.export_class   = 0xFFFF;
1821  errFlags.syslog_class   = 0xFFFF;
1822  errFlags.external_class = 0xFFFF;
1823  errFlags.database_class = 0xFFFF;
1824  errFlags.prelude_class  = 0xFFFF;
1825
1826
1827  for (j = 0; j < SH_ERR_T_END; ++j) 
1828    ShDFLevel[j] = SH_ERR_SEVERE;
1829
1830  IsInitialized = GOOD;
1831  SL_RETURN (0, _("sh_error_init"));
1832}
Note: See TracBrowser for help on using the repository browser.