source: trunk/src/sh_utils.c @ 560

Last change on this file since 560 was 560, checked in by katerina, 15 months ago

Fix for ticket #449 (gcc 10 compile issues).

File size: 54.5 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
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <ctype.h>
27#include <unistd.h>
28
29#if TIME_WITH_SYS_TIME
30#include <sys/time.h>
31#include <time.h>
32#else
33#if HAVE_SYS_TIME_H
34#include <sys/time.h>
35#else
36#include <time.h>
37#endif
38#endif
39
40
41#include "samhain.h"
42#include "sh_error.h"
43#include "sh_utils.h"
44#include "sh_unix.h"
45#include "sh_tiger.h"
46#include "sh_entropy.h"
47#include "sh_pthread.h"
48
49#undef  FIL__
50#define FIL__  _("sh_utils.c")
51
52UINT32 ErrFlag[2];
53
54int sh_util_flagval(const char * c, int * fval)
55{
56  SL_ENTER(_("sh_util_flagval"));
57  if (c == NULL)
58    SL_RETURN( (-1), _("sh_util_flagval"));
59  if ( c[0] == '1'  || c[0] == 'y'  || c[0] == 'Y' ||
60       c[0] == 't'  || c[0] == 'T')
61    {
62      *fval = S_TRUE;
63      SL_RETURN( (0), _("sh_util_flagval"));
64    }
65  if ( c[0] == '0'  || c[0] == 'n'  || c[0] == 'N' ||
66       c[0] == 'f'  || c[0] == 'F')
67    {
68      *fval = S_FALSE;
69      SL_RETURN( (0), _("sh_util_flagval"));
70    }
71  SL_RETURN( (-1), _("sh_util_flagval"));
72}
73
74int sh_util_timeout_check (SH_TIMEOUT * sh_timer)
75{
76  UINT64 now = (UINT64) time(NULL);
77  UINT64 dif;
78 
79  if (sh_timer->flag_ok == S_FALSE)
80    {
81      /* first time
82       */
83      if (sh_timer->time_last == 0)
84        {
85          sh_timer->time_last = now;
86          return S_TRUE;
87        }
88      /* later on
89       */
90      dif = now - sh_timer->time_last;
91      if (dif < sh_timer->time_dist)
92        {
93          return S_FALSE;
94        }
95      sh_timer->time_last = now;
96      return S_TRUE;
97    }
98  sh_timer->time_last = now;
99  return S_FALSE;
100}
101
102static int sh_ask_update = S_FALSE;
103
104int sh_util_set_interactive(const char * str)
105{
106  (void) str;
107
108  sh_ask_update = S_TRUE;
109  sh_unix_setnodeamon(NULL);
110
111  return 0;
112}
113
114static char * sh_update_file = NULL;
115
116int sh_util_update_file (const char * str)
117{
118  if (str)
119    {
120      if (0 == access(str, R_OK)) /* flawfinder: ignore */
121        {
122          if (NULL != sh_update_file)
123            SH_FREE(sh_update_file);
124          sh_update_file = sh_util_strdup(str);
125          sh_ask_update = S_TRUE;
126          sh_unix_setnodeamon(NULL);
127          return 0;
128        }
129      else
130        {
131          char ebuf[SH_ERRBUF_SIZE];
132          int  errnum = errno;
133
134          sh_error_message(errnum, ebuf, sizeof(ebuf));
135          sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_E_SUBGEN,
136                           ebuf, _("sh_util_update_file") );
137         
138          return -1;
139        }
140    }
141
142  return -1;
143}
144
145
146#if !defined(STDIN_FILENO)
147#define STDIN_FILENO 0
148#endif
149#if !defined(STDERR_FILENO)
150#define STDERR_FILENO 0
151#endif
152
153/* Returns S_FALSE if no update desired
154 */
155int sh_util_update_checkfile(const char * path)
156{
157  FILE * fd = fopen(sh_update_file, "r");
158  char * line;
159
160  if (!fd)
161    {
162      uid_t  euid;
163      int errnum = errno;
164      sl_get_euid(&euid);
165      sh_error_handle (SH_ERR_ERR, FIL__, __LINE__, errnum, MSG_NOACCESS,
166                       (long) euid, sh_update_file);
167      aud_exit (FIL__, __LINE__, EXIT_FAILURE);
168      return S_FALSE;
169    }
170
171  line = SH_ALLOC(8192);
172
173  while (NULL != fgets(line, 8192, fd))
174    {
175      char * nl = strrchr(line, '\n');
176
177      if (nl)
178        {
179          *nl = '\0';
180
181          /* Check for MS Windows line terminator
182           */
183          if (nl > line) --nl;
184          if (*nl == '\r')
185            *nl = '\0';
186        }
187
188      if (0 == sl_strcmp(line, path))
189        {
190          SH_FREE(line);
191          fclose(fd);
192          return S_TRUE;
193        }
194    }
195  SH_FREE(line);
196  fclose(fd);
197  return S_FALSE;
198}
199
200/* Returns S_FALSE if no update desired
201 */
202int sh_util_ask_update(const char * path)
203{
204  int    inchar, c;
205  int    i = S_TRUE;
206  char * tmp = NULL;
207
208  SL_ENTER(_("sh_util_ask_update"));
209
210  if (sh_ask_update != S_TRUE)
211    {
212      SL_RETURN(i, _("sh_util_ask_update"));
213    }
214
215  if (sh_update_file)
216    {
217      i = sh_util_update_checkfile(path);
218      SL_RETURN(i, _("sh_util_ask_update"));
219    }
220
221#ifdef HAVE_TTYNAME
222  if (!ttyname(STDIN_FILENO))
223    {
224      if (NULL != ttyname(STDERR_FILENO))
225        {
226          /* cppcheck-suppress leakReturnValNotUsed */
227          if (NULL == freopen(ttyname(STDERR_FILENO), "r", stdin))
228            {
229              sh_error_handle ((-1), FIL__, __LINE__, 0, 
230                               MSG_E_SUBGEN,
231                               _("Cannot continue: stdin is not a terminal"),
232                               _("sh_util_ask_update"));
233              exit(EXIT_FAILURE);
234            }
235        }
236      else
237        {
238          sh_error_handle ((-1), FIL__, __LINE__, 0, 
239                           MSG_E_SUBGEN,
240                           _("Cannot continue: stdin is not a terminal"),
241                           _("sh_util_ask_update"));
242          exit(EXIT_FAILURE);
243        }
244    }
245#endif
246
247  if (sh_ask_update == S_TRUE)
248    {
249      tmp = sh_util_safe_name (path);
250      fprintf (stderr, _("Update %s [Y/n] ? "), tmp);
251      SH_FREE(tmp);
252      while (1 == 1)
253        {
254          c = fgetc(stdin); inchar = c;
255          /*@+charintliteral@*/
256          while (c != '\n' && c != EOF)
257            c = fgetc(stdin);
258          /* fprintf(stderr, "CHAR (1): %c\n", inchar); */
259          if (inchar == 'Y' || inchar == 'y' || inchar == '\n')
260            {
261              break;
262            }
263          else if (inchar == 'n' || inchar == 'N')
264            {
265              i = S_FALSE;
266              break;
267            }
268          else
269            {
270              fprintf(stderr, "%s", _("Please answer y(es) or n(o)\n"));
271            }
272          /*@-charintliteral@*/
273        }
274    }
275
276  SL_RETURN(i, _("sh_util_ask_update"));
277}
278
279int sh_util_hidesetup(const char * c)
280{
281  int i;
282  SL_ENTER(_("sh_util_hidesetup"));
283  i = sh_util_flagval(c, &(sh.flag.hidefile));
284
285  SL_RETURN(i, _("sh_util_hidesetup"));
286}
287
288char * sh_util_acl_compact(char * buf, ssize_t len)
289{
290  unsigned char  * p = (unsigned char *) buf;
291  int       state = 0;
292  ssize_t   rem = 0;
293  char    * out;
294 
295  SH_VALIDATE_NE(buf, NULL);
296  SH_VALIDATE_GE(len, 0);
297
298  out = SH_ALLOC(len + 1);
299
300  while (*p != '\0')  {
301
302    /* -- not at start or after newline
303     */
304    if (state == 1) {
305      if (*p == '\n' || *p == ' ' || *p == '\t' || *p == '#') {
306        while (*p != '\n') {
307          ++p;
308          if (*p == '\0') {
309            goto exit_it;
310          }
311        }
312        out[rem] = ','; ++rem;    /* <-- ensures (rem > 0) is true    */ 
313        while (p[1] == '\n') ++p; /* scan over consecutive newlines   */
314        state = 0;
315        if (p[1] == '\0') {
316          out[rem-1] = '\0';      /* rem > 0 because of 4 lines above */
317          break;
318        }
319      }
320      else {
321        if (*p <= 0x7F && isgraph((int) *p)) {
322          out[rem] = (char) *p; ++rem;
323        }
324      }
325    }
326
327    /* -- at start or after newline
328     */
329    else /* if (state == 0) */ {
330      if        (0 == strncmp((char *) p, "user", 4)) {
331        out[rem] = 'u'; ++rem;
332        p += 3;
333      } else if (0 == strncmp((char *) p, "group", 5)) {
334        out[rem] = 'g'; ++rem;
335        p += 4; 
336      } else if (0 == strncmp((char *) p, "mask", 4)) {
337        out[rem] = 'm'; ++rem;
338        p += 3;
339      } else if (0 == strncmp((char *) p, "other", 5)) {
340        out[rem] = 'o';
341        p += 4; ++rem;
342      } else if (*p == '\0') {
343        if (rem > 0) { out[rem-1] = '\0'; }
344        break;
345      } else {
346        if (*p <= 0x7F && isprint((int) *p)) {
347          out[rem] = (char) *p; ++rem;
348        }
349      }
350      state = 1;
351    }
352    ++p;
353  }
354 exit_it:
355  out[rem] = '\0';
356  return out;
357}
358
359
360char * sh_util_strdup_l (const char * str, size_t len)
361{
362  char * p = NULL;
363
364  SL_ENTER(_("sh_util_strdup_l"));
365
366  SH_VALIDATE_NE(str, NULL);
367  SH_VALIDATE_NE(len, 0);
368
369  if (str && sl_ok_adds (len, 1))
370    {
371      p   = SH_ALLOC (len + 1);
372      (void) memcpy (p, str, len+1);
373    }
374  else
375    {
376      safe_fatal(_("integer overflow in sh_util_strdup_l"), FIL__, __LINE__);
377    }
378  SL_RETURN( p, _("sh_util_strdup_l"));
379}
380
381char * sh_util_strdup (const char * str) 
382{
383  char * p = NULL;
384  size_t len;
385
386  SL_ENTER(_("sh_util_strdup"));
387
388  SH_VALIDATE_NE(str, NULL);
389
390  if (str)
391    {
392      len = sl_strlen(str);
393      p   = SH_ALLOC (len + 1);
394      (void) memcpy (p, str, len+1);
395    }
396  SL_RETURN( p, _("sh_util_strdup"));
397}
398
399char * sh_util_strdup_track (const char * str, char * file, int line) 
400{
401  char * p = NULL;
402  size_t len;
403
404  SL_ENTER(_("sh_util_strdup_track"));
405
406  SH_VALIDATE_NE(str, NULL);
407
408  if (str)
409    {
410      len = sl_strlen(str);
411      p   = SH_OALLOC (len + 1, file, line);
412      (void) memcpy (p, str, len+1);
413    }
414  SL_RETURN( p, _("sh_util_strdup_track"));
415}
416
417/* by the eircom.net computer incident
418 * response team
419 */
420char * sh_util_strsep (char **str, const char *delim) 
421{
422  char *ret, *c;
423  const char *d;
424
425  SL_ENTER(_("sh_util_strsep"));
426  ret = *str;
427
428  SH_VALIDATE_NE(ret, NULL);
429
430  if (*str)
431    {
432      for (c = *str; *c != '\0'; c++) {
433        for (d = delim; *d != '\0'; d++) {
434          if (*c == *d) {
435            *c = '\0';
436            *str = c + 1;
437            SL_RETURN(ret, _("sh_util_strsep"));
438          }
439        }
440      }
441    }
442
443  /* If we get to here, there's no delimiters in the string */
444  *str = NULL;
445  SL_RETURN(ret, _("sh_util_strsep"));
446}
447
448
449/* returned string must be free'd by caller.
450 */
451char * sh_util_formatted (const char * formatt, st_format * ftab)
452{
453  struct tm   * time_ptr;
454  size_t size;
455  size_t isiz;
456  char * fmt = NULL;
457  char * p;
458  char * q;
459  char * outstr;
460  int    i;
461  int    j;
462  time_t inpp;
463
464  char * clist[16] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
465                       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
466  int    nn = 0;
467
468  SL_ENTER(_("sh_util_formatted"));
469
470  if (formatt == NULL || ftab == NULL || *formatt == '\0')
471    SL_RETURN(NULL, _("sh_util_formatted"));
472
473  /* -- save the format (we overwrite it !!) --
474   */
475  size = sl_strlen(formatt);
476
477  if (!sl_ok_adds(size, 1))
478    SL_RETURN(NULL, _("sh_util_formatted"));
479
480  ++size;
481  fmt = SH_ALLOC(size);
482  (void) sl_strlcpy(fmt, formatt, size);
483
484  p = fmt;
485
486  j = 0;
487  while (ftab[j].fchar != '\0') {
488    if (ftab[j].type != S_FMT_STRING)
489      ftab[j].data_str = NULL;
490    ++j;
491  }
492 
493  while (p != NULL && *p != '\0' && NULL != (q = strchr(p, '%')))
494    {
495      ++q;
496
497      /* fprintf(stderr, "p ==  %s   q == %s\n", p, q); */
498
499      /* -- end of string is a '%' --
500       */
501      if (*q == '\0')
502        {
503          --q;
504          *q = '\0';
505          break;
506        }
507
508      i = 0;
509      j = 0;
510
511      /* -- search the format char in input table --
512       * put (nn < 16) here -> all remaining %foo will be
513       * converted to %%
514       */
515      while (ftab[j].fchar != '\0' && nn < 16)
516        {
517          if (ftab[j].fchar == *q)
518            {
519              /* -- Convert it to a string format (%s). --
520               */
521              *q = 's'
522;
523              i  = 1;
524             
525              switch(ftab[j].type) {
526
527              case S_FMT_STRING:
528                {
529                  isiz = sl_strlen(ftab[j].data_str);
530                  if (isiz > 0 && sl_ok_adds(size, isiz))
531                    {
532                      size += isiz;
533                      clist[nn] = ftab[j].data_str;
534                      ++nn;
535                    }
536                  else
537                    *q = '%';
538                  goto endsrch;
539                }
540                break;
541
542              case S_FMT_ULONG:
543                {
544                  ftab[j].data_str = (char *) SH_ALLOC(64);
545                  /*@-bufferoverflowhigh@*/
546                  sprintf (ftab[j].data_str, "%lu",      /* known to fit  */
547                           ftab[j].data_ulong);
548                  /*@+bufferoverflowhigh@*/
549                  isiz = sl_strlen(ftab[j].data_str);
550                  if (isiz > 0 && sl_ok_adds(size, isiz))
551                    {
552                      size += isiz;
553                      clist[nn] = ftab[j].data_str;
554                      ++nn;
555                    }
556                  else
557                    *q = '%';
558                  goto endsrch;
559                }
560                break;
561
562              case S_FMT_LONG:
563                {
564                  ftab[j].data_str = (char *) SH_ALLOC(64);
565                  /*@-bufferoverflowhigh@*/
566                  sprintf (ftab[j].data_str, "%ld",      /* known to fit  */
567                           ftab[j].data_long);
568                  /*@+bufferoverflowhigh@*/
569                  isiz = sl_strlen(ftab[j].data_str);
570                  if (isiz > 0 && sl_ok_adds(size, isiz))
571                    {
572                      size += isiz;
573                      clist[nn] = ftab[j].data_str;
574                      ++nn;
575                    }
576                  else
577                    *q = '%';
578                  goto endsrch;
579                }
580                break;
581
582              case S_FMT_TIME:
583                {
584                  ftab[j].data_str = (char *) SH_ALLOC(64);
585                  inpp = (time_t)ftab[j].data_ulong;
586                  if (inpp != 0)
587                    {
588                      time_ptr = localtime (&(inpp));
589                      if (time_ptr != NULL) 
590                        (void) strftime(ftab[j].data_str, 64, 
591                                        _("%d-%m-%Y %H:%M:%S"), time_ptr);
592                      else
593                        (void) sl_strlcpy(ftab[j].data_str, 
594                                          _("00-00-0000 00:00:00"), 64);
595                    }
596                  else
597                    {
598                      (void) sl_strlcpy(ftab[j].data_str, 
599                                        _("(None)"), 64);
600                    }
601                  isiz = sl_strlen(ftab[j].data_str);
602                  if (isiz > 0 && sl_ok_adds(size, isiz))
603                    {
604                      size += isiz;
605                      clist[nn] = ftab[j].data_str;
606                      ++nn;
607                    }
608                  else
609                    *q = '%';
610                  goto endsrch;
611                }
612                break;
613
614              default:
615                /* do nothing */;
616              }
617
618            }
619          ++j;
620        }
621
622    endsrch:
623
624      p = q;
625
626      /* -- not found -- */
627      if (i == 0)
628        {
629          *q = '%';
630          ++p;
631        }
632
633    }
634
635  /* -- Format string evaluated.
636     clist[]   List of strings
637     size      Total size of format string + clist[] strings
638     -- */
639 
640  /* -- closing '\0' --
641   */
642  if (sl_ok_adds(size, 1))
643    size++;
644  outstr = (char *) SH_ALLOC(size);
645
646  /* -- print it --
647   */
648  (void) sl_snprintf( outstr, size, fmt,
649                      clist[0],  clist[1], clist[2],  clist[3], 
650                      clist[4],  clist[5], clist[6],  clist[7], 
651                      clist[8],  clist[9], clist[10], clist[11], 
652                      clist[12], clist[13], clist[14], clist[15]); 
653  outstr[size-1] = '\0';
654
655  /* -- cleanup --
656   */
657  j = 0;
658  while (ftab[j].fchar != '\0') {
659    if (ftab[j].type != S_FMT_STRING && ftab[j].data_str != NULL)
660      SH_FREE(ftab[j].data_str);
661    ++j;
662  }
663  SH_FREE(fmt);
664
665  SL_RETURN(outstr, _("sh_util_formatted"));
666}
667
668/* read a hexchar, return int value (0-15)
669 * can't inline (AIX)
670 */
671int sh_util_hexchar( const char c )
672{
673  /*@+charint@*/
674  if      ( c >= '0' && c <= '9' )
675    return c - '0';
676  else if ( c >= 'a' && c <= 'f' )
677    return c - 'a' + 10;
678  else if ( c >= 'A' && c <= 'F' )
679    return c - 'A' + 10;
680  else return -1;
681  /*@-charint@*/
682}
683
684char * sh_util_charhex( unsigned char i , char * i2h)
685{
686  int j, k;
687
688  j = i / 16;
689  k = i - (j*16);
690
691  if (j < 10) i2h[0] = '0'+j;
692  else        i2h[0] = 'A'+(j-10);
693 
694  if (k < 10) i2h[1] = '0'+k;
695  else        i2h[1] = 'A'+(k-10);
696
697  return i2h;
698}
699
700/* read a hexadecimal key, convert to binary
701 */
702int sh_util_hextobinary (char * binary, const char * hex, int bytes)
703{
704  int i = 0, j, k, l = 0;
705  char c;
706
707#define SH_HEXCHAR(x, y) \
708    c = (x); \
709    if ( c >= '0' && c <= '9' ) \
710      y = c - '0'; \
711    else if ( c >= 'a' && c <= 'f' ) \
712      y = c - 'a' + 10; \
713    else if ( c >= 'A' && c <= 'F' ) \
714      y = c - 'A' + 10; \
715    else \
716      SL_RETURN((-1), _("sh_util_hextobinary"))
717
718
719  SL_ENTER(_("sh_util_hextobinary"));
720
721  if (bytes < 2)
722    SL_RETURN((-1), _("sh_util_hextobinary"));
723
724  while (i < (bytes-1))
725    {
726      SH_HEXCHAR(hex[i],   k);
727      SH_HEXCHAR(hex[i+1], j);
728     
729      binary[l] = (char)(k * 16 + j);
730      ++l; i+= 2;
731    }
732 
733  SL_RETURN((0), _("sh_util_hextobinary"));
734}
735
736static void copy_four (unsigned char * dest, UINT32 in)
737{
738  UINT32 i, j;
739  int    count;
740
741  SL_ENTER(_("copy_four"));
742  for (count = 0; count < 4; ++count)
743    {
744      i  = in / 256;
745      j  = in - (i*256);
746      dest[count] = (unsigned char) j;
747      in = i;
748    }
749  SL_RET0(_("copy_four"));
750}
751
752/* compute HMAC-TIGER
753 */
754static char * sh_util_hmac_tiger (char * hexkey, 
755                                  char * text, size_t textlen,
756                                  char * res, size_t len)
757{
758  static char opad[KEY_BLOCK] = { 
759    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
760    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
761    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
762    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C
763  };
764  static char ipad[KEY_BLOCK] = { 
765    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, 
766    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, 
767    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, 
768    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36
769  };
770  static char  zap[KEY_BLOCK] = { 
771    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 
772    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 
773    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 
774    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00
775  };
776  char        K[KEY_BLOCK];
777  char        outer[KEY_BLOCK];
778  char      * inner;
779  UINT32    * h1;
780  UINT32    * h2;
781  UINT32      cc[KEY_LEN/4];
782  UINT32      kbuf[KEY_BYT/sizeof(UINT32)];
783  char hashbuf[KEYBUF_SIZE];
784
785  int         result;
786  size_t      i;
787
788  SL_ENTER(_("sh_util_hmac_tiger"));
789
790  ASSERT((KEY_BLOCK <= (KEY_LEN/2)), _("KEY_BLOCK <= (KEY_LEN/2)"));
791
792  memcpy (K, zap, KEY_BLOCK);
793
794  result = sh_util_hextobinary (K, hexkey, KEY_LEN);
795
796  ASSERT((result >= 0), _("result >= 0"));
797
798  if ((result >= 0) && sl_ok_adds(textlen, KEY_BLOCK))
799    {
800      inner = (char *) SH_ALLOC (textlen + KEY_BLOCK); 
801
802      for (i = 0; i < KEY_BLOCK; ++i)
803        {
804          outer[i]  = K[i] ^ opad[i];
805          inner[i]  = K[i] ^ ipad[i];
806        }
807      for (i = KEY_BLOCK; i < (KEY_BLOCK+textlen); ++i)
808        {
809          inner[i] = text[i - KEY_BLOCK];
810        }
811    }
812  else
813    {
814      sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
815                      _("integer overflow"), 
816                      _("sh_util_hmac_tiger"));
817      (void) sh_tiger_hash (NULL, TIGER_DATA, 0, hashbuf, sizeof(hashbuf));
818      sl_strlcpy(res, hashbuf, len);
819      SL_RETURN(res, _("sh_util_hmac_tiger"));
820    }
821
822  /* now compute the hash
823   */
824  h1 = sh_tiger_hash_uint32 ( outer, TIGER_DATA, KEY_BLOCK,
825                              kbuf, KEY_BYT/sizeof(UINT32));
826  for (i = 0; i < (KEY_LEN/8); ++i)
827    copy_four ( (unsigned char *) &(cc[i]), h1[i]);
828
829  /* cppcheck-suppress uninitvar */
830  h2 = sh_tiger_hash_uint32 ( inner, TIGER_DATA,
831                              (unsigned long) KEY_BLOCK+textlen,
832                              kbuf, KEY_BYT/sizeof(UINT32));
833  for (i = KEY_LEN/8; i < (KEY_LEN/4); ++i)
834    copy_four ( (unsigned char *) &(cc[i]), h2[i - (KEY_LEN/8)]);
835
836  /* cppcheck-suppress uninitvar */
837  SH_FREE(inner);
838 
839  (void) sh_tiger_hash ((char *) &cc[0],
840                        TIGER_DATA,
841                        (unsigned long) (KEY_LEN/4 * sizeof(UINT32)),
842                        hashbuf, sizeof(hashbuf));
843
844  sl_strlcpy(res, hashbuf, len);
845  SL_RETURN(res, _("sh_util_hmac_tiger"));
846}
847
848static char * sh_util_hash_tiger ( char * hexkey, 
849                                   char * text, size_t textlen,
850                                   char * res, size_t len)
851{
852  char           h2[2*KEY_LEN+1];
853  char hashbuf[KEYBUF_SIZE];
854
855  SL_ENTER(_("sh_util_hash_tiger"));
856
857  (void) sl_strlcpy(h2, hexkey, KEY_LEN+1); 
858  (void) sl_strlcat(h2, 
859                    sh_tiger_hash(text, TIGER_DATA, 
860                                  (unsigned long) textlen,
861                                  hashbuf, sizeof(hashbuf)), 
862                    2*KEY_LEN+1
863                    );
864
865  (void) sh_tiger_hash(h2, TIGER_DATA, 2*KEY_LEN, hashbuf, sizeof(hashbuf));
866
867  sl_strlcpy(res, hashbuf, len);
868  SL_RETURN(res, _("sh_util_hash_tiger"));
869}
870
871/* --- compute signature on data ---
872 */
873#define TYPE_HMAC 0
874#define TYPE_HASH 1
875
876static int sigtype = TYPE_HMAC;
877
878int sh_util_sigtype (const char * c)
879{
880  SL_ENTER(_("sh_util_sigtype"));
881  if (c == NULL)
882    SL_RETURN( -1, _("sh_util_sigtype"));
883
884  if (0 == strcmp(_("HMAC-TIGER"), c))
885    sigtype = TYPE_HMAC;
886  else if  (0 == strcmp(_("HASH-TIGER"), c))
887    sigtype = TYPE_HASH;
888  else
889    SL_RETURN( -1, _("sh_util_sigtype"));
890
891  SL_RETURN( 0, _("sh_util_sigtype"));
892}
893
894char * sh_util_siggen (char * hexkey, 
895                       char * text, size_t textlen,
896                       char * res, size_t len) 
897{
898  char * p;
899 
900  SL_ENTER(_("sh_util_siggen"));
901  if (sigtype == TYPE_HMAC)
902    p = sh_util_hmac_tiger (hexkey, 
903                            text, textlen, res, len);
904  else
905    p = sh_util_hash_tiger (hexkey, 
906                            text, textlen, res, len);
907  SL_RETURN(p, _("sh_util_siggen"));
908}   
909
910 
911/* a simple compressor
912 */
913size_t sh_util_compress (char * dest, char * src, size_t dest_size)
914{
915  char * add;
916  char * get;
917  size_t   count = 0;
918  size_t   dest_end;
919
920  SL_ENTER(_("sh_util_compress"));
921
922  if (dest_size == 0)
923    SL_RETURN((0), _("sh_util_compress"));
924 
925  if ((dest == NULL) || (src == NULL))
926    SL_RETURN((0), _("sh_util_compress"));
927 
928  dest_end = sl_strlen(dest);
929
930  if (dest_end > dest_size)
931    SL_RETURN((0), _("sh_util_compress"));
932
933  add      = &dest[dest_end];
934  get      = src;
935
936  while (count < (dest_size-dest_end))
937    {
938      if (isalnum((int) *get)) 
939        {
940          *add = *get;
941          ++add;
942          ++count;
943        }
944      ++get; 
945      if (*get == '\0' && (count < (dest_size-dest_end))) 
946        /* end of src reached */
947        {
948          *add = *get;  /* copy the '\0'      */
949          break;        /* and stop copying   */
950        }
951    }
952
953  dest[dest_size-1] = '\0'; /* paranoia       */
954  SL_RETURN((count), _("sh_util_compress")); /* no of chars copied */   
955}
956
957
958/* copy the four least significant bytes
959 */
960void sh_util_cpylong (char * dest, const char * src, int len )
961{
962  int i, j;
963  union
964  {
965    long l;
966    char c[sizeof(long)];
967  } u;
968#ifdef WORDS_BIGENDIAN
969  unsigned char swap;
970  unsigned char * ii = (unsigned char *) dest;
971#endif
972
973  SL_ENTER(_("sh_util_cpylong"));   
974
975  u.l = 1;
976
977  /* MSB is first
978   */
979  if (sizeof(long)>4 &&/*@+charint@*/(u.c[sizeof(long)-1] == 1)/*@-charint@*/)
980    {
981      j = (int) (sizeof(long)-4);
982      for (i = 0; i < j; ++i) ++src;
983    }
984
985  i = 0;
986
987  while (i < 4)
988    {
989      *dest = (*src);
990      ++dest; ++src;
991      if (i == (len-1)) break;
992      ++i;
993    }
994#ifdef WORDS_BIGENDIAN
995  swap = ii[0]; ii[0] = ii[3]; ii[3] = swap;
996  swap = ii[1]; ii[1] = ii[2]; ii[2] = swap;
997#endif
998  SL_RET0(_("sh_util_cpylong"));
999}
1000
1001/*  This is a maximally equidistributed combined Tausworthe
1002 *  generator. The sequence is,
1003 *
1004 *   x_n = (s1_n ^ s2_n ^ s3_n)
1005 *
1006 *   s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
1007 *   s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
1008 *   s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
1009 *
1010 *   computed modulo 2^32. In the three formulas above '^' means
1011 *   exclusive-or (C-notation), not exponentiation. Note that the
1012 *   algorithm relies on the properties of 32-bit unsigned integers (it
1013 *   is formally defined on bit-vectors of length 32).
1014 *
1015 *   Stolen from GSL (GNU scientific library) and modified somewhat.
1016 *   I am using UINT32, which is guaranteed to be 32 bits. Also made
1017 *   sure that the initialization vector is valid.
1018 */
1019
1020
1021/* interval [0, 4294967295]
1022 */
1023static UINT32 taus_get_long (void *vstate)
1024{
1025  UINT32 * state = (UINT32 *) vstate;
1026
1027  /*
1028  if (skey->rngI == BAD)
1029    (void)taus_seed();
1030  */
1031
1032#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
1033  /*@+ignorequals@*/
1034  state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12);
1035  state[1] = TAUSWORTHE (state[1],  2, 25, 4294967288UL,  4);
1036  state[2] = TAUSWORTHE (state[2],  3, 11, 4294967280UL, 17);
1037  /*@-ignorequals@*/
1038  return (state[0] ^ state[1] ^ state[2]);
1039}
1040
1041/* Hide the internal state of the PRNG by using its output as
1042 * input for a one-way hash function.
1043 */
1044
1045UINT32 taus_get ()
1046{
1047#define TAUS_SAMPLE 12
1048
1049  UINT32   taus_svec[TAUS_SAMPLE];
1050  UINT32   retval;
1051  UINT32 * res;
1052  UINT32 * res_vec = &(skey->res_vec[0]);
1053  static   int      res_num = 0;
1054  register int i;
1055  UINT32       kbuf[KEY_BYT/sizeof(UINT32)];
1056
1057  SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1058  if (res_num > 0)
1059    {
1060      retval  = res_vec[res_num];
1061      res_num = (res_num == 5) ? 0 : (res_num + 1);
1062      SH_MUTEX_UNLOCK_UNSAFE(mutex_skey); /* alternative path */
1063      return  retval;
1064    }
1065  SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1066
1067  (void)taus_seed();
1068
1069  SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1070  for (i = 0; i < (TAUS_SAMPLE/3); ++i)
1071    {
1072      taus_svec[i*3]   = taus_get_long (&(skey->rng0[0]));
1073      taus_svec[i*3+1] = taus_get_long (&(skey->rng1[0]));
1074      taus_svec[i*3+2] = taus_get_long (&(skey->rng2[0]));
1075    }
1076  SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1077
1078  res     = sh_tiger_hash_uint32 ( (char *) &taus_svec[0], 
1079                                   TIGER_DATA, 
1080                                   (unsigned long)(TAUS_SAMPLE * sizeof(UINT32)),
1081                                   kbuf, KEY_BYT/sizeof(UINT32));
1082
1083  SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1084  for (i = 1; i < 6; ++i)
1085    { 
1086      res_vec[i] = res[i];
1087    }
1088  retval  = res[0];
1089  res_num = 1;
1090  SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1091
1092  memset(taus_svec, 0, TAUS_SAMPLE * sizeof(UINT32));
1093
1094  return retval;
1095}
1096
1097/* interval [0,1)
1098 */
1099double taus_get_double (void *vstate)
1100{
1101  return taus_get_long (vstate) / (4294967296.0 + 1.0) ;
1102}
1103
1104#define LCG(n) ((69069 * n) & 0xffffffffUL)
1105
1106/* TAKE CARE: state[0], state[1], state[2] must be > 2,8,16, respectively
1107 */
1108static void taus_set_from_ulong (void *vstate, unsigned long int s)
1109{
1110  UINT32  *state = (UINT32  *) vstate;
1111
1112  if (s == 0)
1113    s = 1;      /* default seed is 1 */
1114
1115  state[0] = (UINT32)(LCG (s)        | (UINT32) 0x03);
1116  state[1] = (UINT32)(LCG (state[0]) | (UINT32) 0x09);
1117  state[2] = (UINT32)(LCG (state[1]) | (UINT32) 0x17);
1118
1119  /* 'warm up'
1120   */
1121  (void) taus_get_long (state);
1122  (void) taus_get_long (state);
1123  (void) taus_get_long (state);
1124  (void) taus_get_long (state);
1125  (void) taus_get_long (state);
1126  (void) taus_get_long (state);
1127
1128  return;
1129}
1130
1131static void taus_set_from_state (void *vstate, void *init_state)
1132{
1133  UINT32  *state  = (UINT32  *) vstate;
1134  UINT32  *state0 = (UINT32  *) init_state;
1135
1136  state[0] = state0[0]  | (UINT32) 0x03;
1137  state[1] = state0[1]  | (UINT32) 0x09;
1138  state[2] = state0[2]  | (UINT32) 0x17;
1139 
1140  return;
1141}
1142
1143 
1144int taus_seed ()
1145{
1146  char                 bufx[9 * sizeof(UINT32) + 1];
1147  int                  status;
1148  static unsigned long seed_time    = 0;
1149  static unsigned long seed_counter = 3000;
1150  unsigned long        gtime;
1151
1152  SL_ENTER(_("taus_seed"));
1153
1154  if (skey->rngI == GOOD)
1155    {
1156      ++seed_counter;
1157
1158      if ( ((sh_unix_longtime () - seed_time) < 1800) &&
1159           ( seed_counter                     < 3000))
1160        SL_RETURN( (0), _("taus_seed"));
1161    }
1162 
1163  seed_time    = sh_unix_longtime ();
1164  seed_counter = 0;
1165
1166  status = sh_entropy (24, bufx);
1167
1168  if (!SL_ISERROR(status))
1169    {
1170      SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1171      memcpy (&skey->rng0[0], &bufx[0],                  2*sizeof(UINT32));
1172      memcpy (&skey->rng1[0], &bufx[2*sizeof(UINT32)],   2*sizeof(UINT32));
1173      memcpy (&skey->rng2[0], &bufx[4*sizeof(UINT32)],   2*sizeof(UINT32));
1174      memset (bufx, 0, 9 * sizeof(UINT32) + 1);
1175
1176      skey->rng0[2] = 0;
1177      skey->rng1[2] = 0;
1178      skey->rng2[2] = 0;
1179
1180      taus_set_from_state( &(skey->rng0[0]), &(skey->rng0[0]));
1181      taus_set_from_state( &(skey->rng1[0]), &(skey->rng1[0]));
1182      taus_set_from_state( &(skey->rng2[0]), &(skey->rng2[0]));
1183
1184      skey->rngI = GOOD;
1185      SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1186      SL_RETURN( (0), _("taus_seed"));
1187    }
1188
1189  sh_error_handle ((-1), FIL__, __LINE__, status, MSG_ES_ENT,
1190                   _("sh_entropy"));
1191
1192  /* emergency backup - unsafe !
1193   */
1194#ifdef HAVE_GETTIMEOFDAY
1195  gtime = sh_unix_notime();
1196#else
1197  gtime = seed_time;
1198#endif
1199
1200  SH_MUTEX_LOCK_UNSAFE(mutex_skey);
1201  taus_set_from_ulong ( &(skey->rng0[0]), LCG (gtime)          );
1202  taus_set_from_ulong ( &(skey->rng1[0]), LCG (skey->rng0[0])  );
1203  taus_set_from_ulong ( &(skey->rng2[0]), LCG (skey->rng1[0])  );
1204  skey->rngI = BAD;
1205  SH_MUTEX_UNLOCK_UNSAFE(mutex_skey);
1206
1207  SL_RETURN( (-1), _("taus_seed"));
1208}
1209
1210/*@+charint@*/
1211static unsigned char new_key[] = { 0xA7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xA7 };
1212/*@-charint@*/
1213static void copy_four (unsigned char * dest, UINT32 in);
1214
1215int sh_util_set_newkey (const char * new_in)
1216{
1217  size_t i, j = 0;
1218  size_t len;
1219  SL_TICKET fp;
1220  SL_TICKET fout;
1221  char * key;
1222  char * path = NULL;
1223  char * outpath = NULL;
1224  unsigned char * image = NULL;
1225  long s = 0;
1226  long ilen = 0;
1227  long ii, k = 0;
1228  UINT32    * h1;
1229  char * new = NULL;
1230
1231  if (0 != sl_is_suid())
1232    {
1233      fprintf(stderr, "%s", _("ERROR: insufficient privilege\n"));
1234      _exit (EXIT_FAILURE);
1235      /*@notreached@*/
1236      return -1;  /* braindead MAC OSX compiler needs this */
1237    }
1238       
1239  if (new_in == NULL || new_in[0] == '\0')
1240    {
1241      fprintf(stderr, "%s", 
1242              _("ERROR: no key given\n Argument must be 'key@path'\n"));
1243      _exit (EXIT_FAILURE);
1244      /*@notreached@*/
1245      return -1;
1246    }
1247
1248  if (NULL == (new = calloc(1,strlen(new_in) + 1)))
1249    goto bail_mem;
1250  sl_strncpy(new, new_in, strlen(new_in) + 1);
1251
1252  key = new;
1253  len = strlen(new);
1254  for (i = 1; i < (len-2); ++i)
1255    {
1256      if (new[i] == '@' && new[i+1] == '/')
1257        {
1258          j = i+1; new[i] = '\0'; break;
1259        }
1260    }
1261  if (j == 0)
1262    {
1263      fprintf(stderr, "%s",
1264              _("ERROR: no path to executable given\n Argument must be 'key@path'\n"));
1265      free(new);
1266      _exit (EXIT_FAILURE);
1267      /*@notreached@*/
1268      return -1;
1269    }
1270  else
1271    path = &new[j];
1272
1273  len = strlen(path) + 1 + 4;
1274  /*@-usedef@*/
1275  if (NULL == (outpath = calloc(1,len)))
1276    goto bail_mem;
1277  /*@-usedef@*/
1278  sl_snprintf (outpath, len, _("%s.out"), path);
1279
1280  fp = sl_open_read(FIL__, __LINE__, path, SL_NOPRIV);
1281  if (SL_ISERROR(fp))
1282    {
1283      fprintf(stderr, 
1284              _("ERROR: cannot open %s for read (errnum = %ld)\n"), path, fp);
1285      free(new); free (outpath);
1286      _exit (EXIT_FAILURE);
1287      /*@notreached@*/
1288      return -1;
1289    }
1290 
1291  fout = sl_open_write(FIL__, __LINE__, outpath, SL_NOPRIV);
1292  if (SL_ISERROR(fout))
1293    {
1294      fprintf(stderr, 
1295              _("ERROR: cannot open %s (errnum = %ld)\n"), outpath, fout);
1296      free(new); free (outpath);
1297      _exit (EXIT_FAILURE);
1298      /*@notreached@*/
1299      return -1;
1300    }
1301
1302
1303  image = calloc(1,4096);
1304  if (!image)
1305    goto bail_mem;
1306  while (0 < (ii = sl_read (fp, &image[s], 4096)))
1307    {
1308      unsigned char * ptr;
1309      ilen += ii;
1310      s    += 4096;
1311      ptr = realloc (image, (size_t) (4096 + s));
1312      if (ptr)
1313        image = ptr;
1314      else
1315        { free(image); image = NULL; }
1316      if (!image)
1317        goto bail_mem;
1318    }
1319
1320  printf(_("%ld bytes read\n"), ilen);
1321
1322 
1323  for (k = 0; k < (ilen - 8); ++k) 
1324    {
1325      if (image[k]   == new_key[0] &&
1326          image[k+1] == new_key[1] &&
1327          image[k+2] == new_key[2] &&
1328          image[k+3] == new_key[3] &&
1329          image[k+4] == new_key[4] &&
1330          image[k+5] == new_key[5] &&
1331          image[k+6] == new_key[6] &&
1332          image[k+7] == new_key[7])
1333        {
1334          UINT32 kbuf[KEY_BYT/sizeof(UINT32)];
1335
1336          printf("%s", _("old key found\n")); 
1337          h1 = sh_tiger_hash_uint32 (key, TIGER_DATA, 
1338                                     (unsigned long)strlen(key),
1339                                     kbuf, KEY_BYT/sizeof(UINT32));
1340          copy_four( (unsigned char *) &(image[k]),   h1[0]);
1341          copy_four( (unsigned char *) &(image[k+4]), h1[1]);
1342          (void) sl_write (fout, image, ilen);
1343          (void) sl_close (fout);
1344          printf(_("new file %s written\n"), outpath);
1345          free(new); free (outpath); free(image);
1346          _exit (EXIT_SUCCESS);
1347          /*@notreached@*/
1348          return 0;
1349        }
1350    }
1351
1352  fprintf(stderr, "%s",
1353          _("ERROR: old key not found\n"));
1354  free(new); free (outpath); free(image);
1355  _exit (EXIT_FAILURE);
1356  /*@notreached@*/
1357  return -1;
1358
1359
1360 bail_mem:
1361  fprintf(stderr, "%s",
1362          _("ERROR: out of memory\n"));
1363  if (new) free(new); 
1364  if (outpath) free (outpath);
1365  if (image) free (image);
1366  _exit (EXIT_FAILURE);
1367  /*@notreached@*/
1368  return -1;
1369}
1370
1371 
1372
1373       
1374/* A simple en-/decoder, based on Vernam cipher. We use the
1375 * message as salt to hide the key by obtaining a different one-time
1376 * pad each time.
1377 * Should be safe against a listener on the network, but not against someone
1378 * with read access to the binary.
1379 */
1380void sh_util_encode (char * data, char * salt, int mode, char fill)
1381{
1382  static char     cc1[17] = N_("0123456789ABCDEF");
1383  char            cc[17] = "\0";
1384  register int    i, j, j1 = 0, j2 = 0, j3;
1385  char          * dez; 
1386  char hashbuf[KEYBUF_SIZE];
1387
1388  SL_ENTER(_("sh_util_encode"));
1389
1390  /* init
1391   */
1392  (void) sl_strlcpy( cc, _(cc1), sizeof(cc));
1393
1394  /* max 128 bits keyspace
1395   */
1396  memset (skey->vernam, (int)fill, KEY_LEN+1);
1397
1398  dez    = (char *) &(skey->ErrFlag[0]);
1399  sh_util_cpylong (skey->vernam,     dez, 4);
1400  dez    = (char *) &(skey->ErrFlag[1]);
1401  sh_util_cpylong (&skey->vernam[4], dez, 4);
1402
1403  skey->vernam[KEY_LEN] = '\0';
1404
1405  (void) sl_strlcpy(skey->vernam, 
1406                    sh_tiger_hash(skey->vernam, TIGER_DATA, KEY_LEN,
1407                                  hashbuf, sizeof(hashbuf)), 
1408                    KEY_LEN+1);
1409
1410  (void) sl_strlcpy(skey->vernam, 
1411                    sh_util_hmac_tiger (skey->vernam, salt, strlen(salt),
1412                                        hashbuf, sizeof(hashbuf)),
1413                    KEY_LEN+1);
1414
1415  (void) sl_strlcpy(skey->vernam, 
1416                    sh_util_hmac_tiger (skey->vernam, (char*) new_key, 8,
1417                                        hashbuf, sizeof(hashbuf)),
1418                    KEY_LEN+1);
1419
1420  /* The following routine adds/subtracts  data[j] and vernam[j] mod 16.
1421   */
1422  j = 0;
1423  while (j < KEY_LEN)
1424    {
1425      for (i = 0; i < 16; ++i)
1426        {
1427          if (cc[i] == data[j])   j1 = i;
1428          if (cc[i] == skey->vernam[j])    j2 = i;
1429        }
1430      if (mode == 0)
1431        {
1432          j3 = j1 + j2;
1433          if (j3 > 15) j3 -= 16;
1434          data[j] = cc[j3];
1435        }
1436      else
1437        {
1438          j3 = j1 - j2;
1439          if (j3 <  0) j3 += 16;
1440          data[j] = cc[j3];
1441        }
1442      ++j;
1443    }
1444  SL_RET0(_("sh_util_encode"));
1445}
1446
1447/* server mode
1448 */
1449int sh_util_setserver (const char * dummy)
1450{
1451  SL_ENTER(_("sh_util_setserver"));
1452
1453  (void) dummy;
1454  sh.flag.isserver = GOOD;
1455  SL_RETURN((0),_("sh_util_setserver"));
1456}
1457
1458
1459int sh_util_setlooptime (const char * str)
1460{
1461  int i = atoi (str);
1462 
1463  SL_ENTER(_("sh_util_setlooptime"));
1464
1465  if (i >= 0 && i < INT_MAX) {
1466    sh.looptime = i;
1467    SL_RETURN((0),_("sh_util_setlooptime"));
1468  } else {
1469    sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1470                     _("loop time"), str);
1471    SL_RETURN((-1),_("sh_util_setlooptime"));
1472  }
1473}
1474
1475#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
1476int  sh_util_setchecksum (const char * str)
1477{
1478  static int reject = 0;
1479
1480  SL_ENTER(_("sh_util_setchecksum"));
1481
1482  if (reject == 1)
1483    SL_RETURN((0), _("sh_util_setchecksum"));
1484  reject = 1;
1485
1486  if (sl_strncmp (str, _("init"), sizeof("init")-1) == 0)
1487    {
1488      sh.flag.checkSum = SH_CHECK_INIT;
1489    }
1490  else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0)
1491    {
1492      if (S_TRUE == file_is_remote()) 
1493        {
1494          sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1495                           _("checksum testing"), str);
1496          SL_RETURN((-1), _("sh_util_setchecksum"));
1497        }
1498      else
1499        {
1500          sh.flag.checkSum = SH_CHECK_CHECK;
1501          sh.flag.update   = S_TRUE;
1502        }
1503    }
1504  else if (sl_strncmp (str, _("check"), sizeof("check")-1) == 0)
1505    {
1506      sh.flag.checkSum = SH_CHECK_CHECK;
1507    }
1508  /*
1509  else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0)
1510    {
1511      sh.flag.checkSum = SH_CHECK_INIT;
1512      sh.flag.update   = S_TRUE;
1513    }
1514  */
1515  else if (sl_strncmp (str, _("none"), sizeof("none")-1) == 0)
1516    {
1517      sh.flag.checkSum = SH_CHECK_NONE;
1518    }
1519  else 
1520    {
1521      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1522                       _("checksum testing"), str);
1523      SL_RETURN((-1), _("sh_util_setchecksum"));
1524    }
1525  SL_RETURN((0), _("sh_util_setchecksum"));
1526}
1527#endif
1528 
1529/*@+charint@*/
1530unsigned char TcpFlag[8][PW_LEN+1] = { 
1531#if (POS_TF == 1)
1532  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1533#endif
1534  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1535#if (POS_TF == 2)
1536  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1537#endif
1538  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1539#if (POS_TF == 3)
1540  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1541#endif
1542  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1543#if (POS_TF == 4)
1544  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1545#endif
1546  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1547#if (POS_TF == 5)
1548  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1549#endif
1550  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1551#if (POS_TF == 6)
1552  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1553#endif
1554  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1555#if (POS_TF == 7)
1556  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1557#endif
1558  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1559#if (POS_TF == 8)
1560  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1561#endif
1562};
1563/*@-charint@*/
1564
1565/* initialize a key to a random value
1566 * rev 0.8
1567 */
1568int sh_util_keyinit (char * buf, long size)
1569{
1570  UINT32       bufy[6];
1571  int          i;
1572  int          status = 0;
1573  char       * p;
1574  char hashbuf[KEYBUF_SIZE];
1575
1576  SL_ENTER(_("sh_util_keyinit"));
1577
1578  ASSERT((size <= KEY_LEN+1), _("size <= KEY_LEN+1"))
1579
1580  if (size > KEY_LEN+1)
1581    size = KEY_LEN+1;
1582
1583  /* seed / re-seed the PRNG if required
1584   */
1585  status = taus_seed ();
1586
1587  if (status == -1)
1588    sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_ES_KEY1,
1589                     _("taus_seed"));
1590
1591  for (i = 0; i < 6; ++i)
1592    bufy[i] = taus_get();
1593
1594  p = sh_tiger_hash ((char *) bufy, TIGER_DATA, 
1595                     (unsigned long)(6*sizeof(UINT32)),
1596                     hashbuf, sizeof(hashbuf));
1597
1598  i = sl_strlcpy(buf, p, (size_t)size);
1599
1600  memset (bufy, 0, 6*sizeof(UINT32));
1601
1602  if ((status == 0) && (!SL_ISERROR(i)) )
1603    SL_RETURN((0),_("sh_util_keyinit"));
1604
1605  if (SL_ISERROR(i))
1606    sh_error_handle ((-1), FIL__, __LINE__, i, MSG_ES_KEY2, 
1607                     _("sl_strlcpy"));
1608
1609  SL_RETURN((-1),_("sh_util_keyinit"));
1610}
1611
1612#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
1613
1614static unsigned char sh_obscure_index[256];
1615static int sh_obscure_no_check = S_FALSE;
1616
1617int sh_util_valid_utf8 (const unsigned char * str) 
1618{
1619  const int     sh_val_utf8_1 = 1;
1620  const int     sh_val_utf8_2 = 2;
1621  const int     sh_val_utf8_3 = 3;
1622  const int     sh_val_utf8_4 = 4;
1623
1624  size_t        len = strlen((const char *)str);
1625  size_t        l   = 0;
1626  int           typ = 0;
1627  unsigned char c     = '\0';
1628  unsigned char c2[2] = { 0x00, 0x00 };
1629  unsigned char c3[3] = { 0x00, 0x00, 0x00 };
1630
1631
1632#define SH_VAL_UTF8_1 ((c != '\0') && ((c & 0x80) == 0x00))
1633#define SH_VAL_UTF8_2 ((c != '\0') && ((c & 0xE0) == 0xC0)) /* 110x xxxx */
1634#define SH_VAL_UTF8_3 ((c != '\0') && ((c & 0xF0) == 0xE0)) /* 1110 xxxx */
1635#define SH_VAL_UTF8_4 ((c != '\0') && ((c & 0xF8) == 0xF0)) /* 1111 0xxx */
1636#define SH_VAL_UTF8_N ((c != '\0') && ((c & 0xC0) == 0x80)) /* 10xx xxxx */
1637#define SH_VAL_BAD    ((c == '"')  || (c == '\t') || (c == '\b') || \
1638                       (c == '\f') || (c == '\n') || \
1639                       (c == '\r') || (c == '\v') || iscntrl((int) c) || \
1640                       (c != ' ' && !isgraph ((int) c)))
1641   
1642  while(l < len) 
1643    {
1644      c = str[l];
1645
1646      if      (SH_VAL_UTF8_1) 
1647        {
1648          if (!(SH_VAL_BAD && (sh_obscure_index[c] != 1)))
1649            {
1650              typ = sh_val_utf8_1;
1651              ++l; continue;
1652            }
1653          else
1654            {
1655              return S_FALSE;
1656            }
1657        } 
1658      else if (SH_VAL_UTF8_2) 
1659        { 
1660          typ = sh_val_utf8_2;
1661          c2[0] = c;
1662          if ((c & 0x3e) != 0x00) /* !(overlong 2-byte seq.) */
1663            {
1664              ++l; 
1665              if (l != len) {
1666                c = str[l];
1667                if(SH_VAL_UTF8_N) {
1668                  c2[1] = c;
1669                  ++l; continue;
1670                } 
1671                else {
1672                  return S_FALSE;
1673                } 
1674              } 
1675              else {
1676                return S_FALSE; 
1677              }
1678            }
1679          else
1680            {
1681              return S_FALSE; /* overlong 2-byte seq. */
1682            }
1683        } 
1684      else if (SH_VAL_UTF8_3) 
1685        {
1686          typ = sh_val_utf8_3;
1687          c3[0] = c;
1688          ++l; if (l == len) return S_FALSE; c = str[l];
1689          if(!SH_VAL_UTF8_N) return S_FALSE;
1690          if (((str[l-1] & 0x1F) == 0x00) && ((c & 0x60) == 0x00))
1691            return S_FALSE; /* overlong 3-byte seq. */
1692          c3[1] = c;
1693          ++l; if (l == len) return S_FALSE; c = str[l];
1694          if(!SH_VAL_UTF8_N) return S_FALSE;
1695          c3[2] = c;
1696          ++l; continue;
1697        } 
1698      else if (SH_VAL_UTF8_4) 
1699        {
1700          typ = sh_val_utf8_4;
1701          ++l; if (l == len) return S_FALSE; c = str[l];
1702          if(!SH_VAL_UTF8_N) return S_FALSE;
1703          if (((str[l-1] & 0x0F) == 0x00) && ((c & 0x70) == 0x00))
1704            return S_FALSE; /* overlong 4-byte seq. */
1705          ++l; if (l == len) return S_FALSE; c = str[l];
1706          if(!SH_VAL_UTF8_N) return S_FALSE;
1707          ++l; if (l == len) return S_FALSE; c = str[l];
1708          if(!SH_VAL_UTF8_N) return S_FALSE;
1709          ++l; continue;
1710        }
1711      return S_FALSE;
1712    }
1713
1714  /* last character is invisible (space or else)
1715   */
1716  if (typ == sh_val_utf8_1)
1717    { 
1718      if (c != ' ')
1719        return S_TRUE;
1720      else
1721        return S_FALSE;
1722    }
1723  else if (typ == sh_val_utf8_2)
1724    {
1725      if (c2[0] == 0xC2 && c2[1] == 0xA0) /* nbsp */
1726        return S_FALSE;
1727      else
1728        return S_TRUE;
1729    }
1730  else if (typ == sh_val_utf8_3)
1731    {
1732      if (c3[0] == 0xE2) 
1733        {
1734          if (c3[1] == 0x80 && c3[2] >= 0x80 && c3[2] <= 0x8F)
1735            return S_FALSE; /* various spaces, left-to-right, right-to-left */
1736          else if (c3[1] == 0x80 && (c3[2] == 0xA8 || c3[2] == 0xA9 || 
1737                                     c3[2] == 0xAD || c3[2] == 0xAF))
1738            return S_FALSE; /* line sep, para sep, zw word joiner, nnbsp */
1739          else if (c3[1] == 0x81 && (c3[2] == 0xA0 || c3[2] == 0xA1 || 
1740                                     c3[2] == 0x9F))
1741            return S_FALSE; /* word joiner, function app, math space */
1742          else
1743            return S_TRUE;
1744        }
1745      else if (c3[0] == 0xE3 && c3[1] == 0x80 && c3[2] == 0x80)
1746        {
1747          return S_FALSE; /* ideographic space */
1748        }
1749      else if (c3[0] == 0xEF && c3[1] == 0xBB && c3[2] == 0xBF)
1750        {
1751          return S_FALSE; /* zwnbsp */
1752        }
1753      else
1754        {
1755          return S_TRUE;
1756        }
1757    }
1758  else
1759    {
1760      return S_TRUE;
1761    }
1762}
1763
1764
1765int sh_util_obscure_ok (const char * str)
1766{
1767  unsigned long   i;
1768  char * endptr = NULL;
1769
1770  SL_ENTER(_("sh_util_obscure_ok"));
1771
1772  if (0 == sl_strncmp("all", str, 3))
1773    {
1774      for (i = 0; i < 255; ++i)
1775        {
1776          sh_obscure_index[i] = (unsigned char)1;
1777        }
1778      sh_obscure_no_check = S_TRUE;
1779      SL_RETURN(0, _("sh_util_obscure_ok"));
1780    }
1781
1782  sh_obscure_no_check = S_FALSE;
1783
1784  for (i = 0; i < 255; ++i)
1785    {
1786      sh_obscure_index[i] = (unsigned char)0;
1787    }
1788
1789  i = strtoul (str, &endptr, 0);
1790  if (i > 255)
1791    {
1792      SL_RETURN(-1, _("sh_util_obscure_ok"));
1793    }
1794  sh_obscure_index[i] = (unsigned char)1;
1795  if (*endptr == ',')
1796    ++endptr;
1797
1798  while (*endptr != '\0')
1799    {
1800      i = strtoul (endptr, &endptr, 0);
1801      if (i > 255)
1802        {
1803          SL_RETURN(-1, _("sh_util_obscure_ok"));
1804        }
1805      sh_obscure_index[i] = (unsigned char)1;
1806      if (*endptr == ',')
1807        ++endptr;
1808    }
1809  SL_RETURN(0, _("sh_util_obscure_ok"));
1810}
1811
1812static int sh_obscure_check_utf8 = S_FALSE;
1813
1814int sh_util_obscure_utf8 (const char * c)
1815{
1816  int i;
1817  SL_ENTER(_("sh_util_obscure_utf8"));
1818  i = sh_util_flagval(c, &(sh_obscure_check_utf8));
1819  if (sh_obscure_check_utf8 == S_TRUE)
1820    sh_obscure_no_check = S_FALSE;
1821  SL_RETURN(i, _("sh_util_obscure_utf8"));
1822}
1823
1824
1825int sh_util_obscurename (ShErrLevel level, const char * name_orig, int flag)
1826{
1827  const unsigned char * name = (const unsigned char *) name_orig;
1828  char * safe;
1829  unsigned int i;
1830  size_t len = 0;
1831
1832  SL_ENTER(_("sh_util_obscurename"));
1833
1834  ASSERT_RET((name != NULL), _("name != NULL"), (0))
1835
1836  if (sh_obscure_no_check == S_FALSE)
1837    {
1838      if (sh_obscure_check_utf8 != S_TRUE)
1839        {
1840          /* -- Check name. --
1841           */
1842          while (*name != '\0') 
1843            {
1844              if ( (*name) >  0x7F || (*name) == '"'  || (*name) == '\t' ||
1845                   (*name) == '\b' || (*name) == '\f' || 
1846                   (*name) == '\n' || (*name) == '\r' ||
1847                   (*name) == '\v' || iscntrl((int) *name) || 
1848                   ((*name) != ' ' && !isgraph ((int) *name)) ) 
1849                {
1850                  i = (unsigned char) *name;
1851                  if (sh_obscure_index[i] != (unsigned char)1)
1852                    {
1853                      goto err;
1854                    }
1855                }
1856              name++; ++len;
1857            }
1858
1859          /* Check for blank at end of name
1860           */
1861          if ((len > 0) && (name_orig[len-1] == ' '))
1862            {
1863              goto err;
1864            }
1865        }
1866      else
1867        {
1868          if (S_FALSE == sh_util_valid_utf8(name))
1869            {
1870              goto err;
1871            }
1872          SL_RETURN((0),_("sh_util_obscurename"));
1873        }
1874    }
1875     
1876  SL_RETURN((0),_("sh_util_obscurename"));
1877
1878 err:
1879 
1880  if (flag == S_TRUE)
1881    {
1882      safe = sh_util_safe_name (name_orig); 
1883      sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_OBSC, 
1884                       safe);
1885      SH_FREE(safe);
1886    }
1887  SL_RETURN((-1),_("sh_util_obscurename"));
1888}
1889
1890#endif
1891
1892/* returns freshly allocated memory, return value should be free'd
1893 */
1894char * sh_util_dirname(const char * fullpath)
1895{
1896  char * retval;
1897  size_t len;
1898  char * tmp;
1899
1900  SL_ENTER(_("sh_util_dirname"));
1901
1902  ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
1903  ASSERT_RET ((*fullpath == '/'), _("*fullpath == '/'"), (NULL))
1904
1905  retval = sh_util_strdup(fullpath);
1906
1907  tmp    = retval;
1908  while (*tmp == '/') ++tmp;
1909
1910  /* (1) only leading slashes -- return exact copy
1911   */
1912  if (*tmp == '\0')
1913    {
1914      SL_RETURN(retval, _("sh_util_dirname"));
1915    }
1916
1917  /* (2) there are non-slash characters, so delete trailing slashes
1918   */
1919  len    = sl_strlen (retval);     /* retval[len] is terminating '\0' */
1920
1921  while (len > 1 && retval[len-1] == '/')    /* delete trailing slash */
1922    {
1923      retval[len-1] = '\0';
1924      --len;
1925    }
1926
1927  /* (3) now delete all non-slash characters up to the preceding slash
1928   */
1929  while (len > 1 && retval[len-1] != '/') {
1930    retval[len-1] = '\0';
1931    --len;
1932  }
1933
1934  /* (4a) only leading slashes left, so return this
1935   */
1936  if (&(retval[len]) == tmp)
1937    {
1938      SL_RETURN(retval, _("sh_util_dirname"));
1939    }
1940
1941  /* (4b) strip trailing slash(es) of parent directory
1942   */
1943  while (len > 1 && retval[len-1] == '/') {
1944    retval[len-1] = '\0';
1945    --len;
1946  }
1947  SL_RETURN(retval, _("sh_util_dirname"));
1948
1949}
1950
1951/* returns freshly allocated memory, return value should be free'd
1952 */
1953char * sh_util_basename(const char * fullpath)
1954{
1955  char       * retval = NULL;
1956  const char * tmp;
1957  char       * tmp2;
1958  char       * c;
1959  size_t       len;
1960
1961  SL_ENTER(_("sh_util_basename"));
1962
1963  ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
1964
1965  tmp = fullpath; while (*tmp == '/') ++tmp;
1966  if (*tmp == '\0')
1967    {
1968      retval = sh_util_strdup(fullpath);
1969    }
1970  else
1971    {
1972      tmp2 = sh_util_strdup(tmp);
1973      len  = sl_strlen (tmp2);
1974
1975      while (len > 1 && tmp2[len-1] == '/')
1976        {
1977          tmp2[len-1] = '\0';
1978          --len;
1979        }
1980
1981      if (tmp2) /* for llvm/clang analyzer */
1982        {
1983          c = strrchr(tmp2, '/');
1984          if (c)
1985            {
1986              retval = sh_util_strdup(++c);
1987              SH_FREE(tmp2);
1988            }
1989          else
1990            {
1991              retval = tmp2;
1992            }
1993        }
1994    }
1995
1996  SL_RETURN(retval, _("sh_util_basename"));
1997}
1998
1999#define SH_ESCAPE_SPACE      1
2000#define SH_DONT_ESCAPE_SPACE 0   
2001char * sh_util_safe_name_int (const char * name, int escape_space);
2002
2003char * sh_util_safe_name (const char * name)
2004{
2005  return sh_util_safe_name_int (name, SH_ESCAPE_SPACE); 
2006}
2007
2008char * sh_util_safe_name_keepspace (const char * name)
2009{
2010  return sh_util_safe_name_int (name, SH_DONT_ESCAPE_SPACE); 
2011}
2012
2013/* returns freshly allocated memory, return value should be free'd
2014 */
2015char * sh_util_safe_name_int (const char * name, int escape_space)
2016{
2017  register int  i = 0;
2018  const char  * p;
2019  char        * retval;
2020  char          oct[32];
2021  char          format[16];
2022  size_t        len;
2023
2024  SL_ENTER(_("sh_util_safe_name"));
2025
2026  if (name == NULL)
2027    {
2028      /* return an allocated array
2029       */
2030      retval = SH_ALLOC(7);
2031      (void) sl_strlcpy(retval, _("(null)"), 7);
2032      SL_RETURN(retval, _("sh_util_safe_name"));
2033    }
2034
2035  /*
2036  ASSERT_RET ((name != NULL), _("name != NULL"), _("NULL"))
2037  */
2038
2039  len = sl_strlen(name);
2040  p   = name;
2041
2042#ifdef SH_USE_XML
2043  if (sl_ok_muls (6, len) && sl_ok_adds ((6*len), 2))
2044    { retval = SH_ALLOC(6 * len + 2); }
2045  else
2046    {
2047      /* return an allocated array
2048       */
2049      retval = SH_ALLOC(11);
2050      (void) sl_strlcpy(retval, _("(overflow)"), 11);
2051      SL_RETURN(retval, _("sh_util_safe_name"));
2052    }
2053#else
2054  if (sl_ok_muls (4, len) && sl_ok_adds ((4*len), 2))
2055    { retval = SH_ALLOC(4 * len + 2); }
2056  else
2057    {
2058      /* return an allocated array
2059       */
2060      retval = SH_ALLOC(11);
2061      (void) sl_strlcpy(retval, _("(overflow)"), 11);
2062      SL_RETURN(retval, _("sh_util_safe_name"));
2063    }
2064#endif
2065
2066  (void) sl_strncpy(format, _("%c%03o"), 16);
2067
2068  while (*p != '\0') {
2069    /* Most frequent cases first
2070     */
2071    if ( ((*p) >= 'a' && (*p) <= 'z')  || ((*p) == '/') || ((*p) == '.') ||
2072         ((*p) >= '0' && (*p) <= '9')  || 
2073         ((*p) >= 'A' && (*p) <= 'Z')) {
2074      retval[i] = *p; 
2075    } else if ( (*p) == '\\') {           /* backslash        */
2076      retval[i] = '\\'; ++i; 
2077      retval[i] = '\\';
2078    } else if ( (*p) == '\n') {    /* newline          */
2079      retval[i] = '\\'; ++i; 
2080      retval[i] = 'n';
2081    } else if ( (*p) == '\b') {    /* backspace        */
2082      retval[i] = '\\'; ++i; 
2083      retval[i] = 'b';
2084    } else if ( (*p) == '\r') {    /* carriage  return */
2085      retval[i] = '\\'; ++i; 
2086      retval[i] = 'r';
2087    } else if ( (*p) == '\t') {    /* horizontal tab   */
2088      retval[i] = '\\'; ++i; 
2089      retval[i] = 't';
2090    } else if ( (*p) == '\v') {    /* vertical tab     */
2091      retval[i] = '\\'; ++i; 
2092      retval[i] = 'v';
2093    } else if ( (*p) == '\f') {    /* form-feed        */
2094      retval[i] = '\\'; ++i; 
2095      retval[i] = 'f';
2096#ifdef WITH_DATABASE
2097    } else if ( (*p) == '\'') {    /* single quote     */
2098      retval[i] = '\\'; ++i; 
2099      retval[i] = '\'';
2100#endif
2101    } else if ( (*p) == ' ') {     /* space            */
2102      if (escape_space) {
2103        retval[i] = '\\'; ++i; 
2104        retval[i] = ' ';
2105      }
2106      else {
2107        retval[i] = *p;
2108      }
2109#ifdef SH_USE_XML
2110    } else if ( (*p) == '"') {     /* double quote     */
2111      retval[i] = '&'; ++i; 
2112      retval[i] = 'q'; ++i;
2113      retval[i] = 'u'; ++i;
2114      retval[i] = 'o'; ++i;
2115      retval[i] = 't'; ++i;
2116      retval[i] = ';';
2117    } else if ( (*p) == '&') {     /* ampersand        */
2118      retval[i] = '&'; ++i; 
2119      retval[i] = 'a'; ++i;
2120      retval[i] = 'm'; ++i;
2121      retval[i] = 'p'; ++i;
2122      retval[i] = ';';
2123    } else if ( (*p) == '<') {     /* left angle       */
2124      retval[i] = '&'; ++i; 
2125      retval[i] = 'l'; ++i;
2126      retval[i] = 't'; ++i;
2127      retval[i] = ';';
2128    } else if ( (*p) == '>') {     /* right angle      */
2129      retval[i] = '&'; ++i; 
2130      retval[i] = 'g'; ++i;
2131      retval[i] = 't'; ++i;
2132      retval[i] = ';';
2133#else
2134    } else if ( (*p) == '"') {     /* double quote     */
2135      retval[i] = '\\'; ++i; 
2136      retval[i] = '\"';
2137#endif
2138    } else if (!isgraph ((int) *p)) {    /* not printable    */
2139      /*@-bufferoverflowhigh -formatconst@*/
2140      /* flawfinder: ignore */
2141      sprintf(oct, format, '\\',                 /* known to fit  */
2142              (unsigned char) *p);
2143      /*@+bufferoverflowhigh +formatconst@*/
2144      retval[i] = oct[0]; ++i;
2145      retval[i] = oct[1]; ++i;
2146      retval[i] = oct[2]; ++i;
2147      retval[i] = oct[3]; 
2148    } else {
2149      retval[i] = *p;
2150    }
2151    ++p;
2152    ++i;
2153  }
2154  retval[i] = '\0';
2155  SL_RETURN(retval, _("sh_util_safe_name"));
2156}
2157
2158int sh_util_isnum (const char *str)
2159{
2160  const char *p = str;
2161
2162  SL_ENTER(_("sh_util_isnum"));
2163
2164  ASSERT_RET ((str != NULL), _("str != NULL"), (-1))
2165
2166  while (p) {
2167    if (!isdigit((int) *p) ) 
2168      SL_RETURN((-1), _("sh_util_isnum"));
2169    ++p;
2170  }
2171  SL_RETURN((0), _("sh_util_isnum"));
2172}
2173
2174char * sh_util_strconcat (const char * arg1, ...)
2175{
2176  size_t    length, l2;
2177  char    * s;
2178  char    * strnew;
2179  va_list vl;
2180
2181  SL_ENTER(_("sh_util_strconcat"));
2182
2183  ASSERT_RET ((arg1 != NULL), _("arg1 != NULL"), (NULL))
2184
2185  length = sl_strlen (arg1) + 1;
2186
2187  va_start (vl, arg1);
2188  s = va_arg (vl, char * );
2189  while (s != NULL)
2190    {
2191      l2 = sl_strlen (s);
2192      if (sl_ok_adds(length, l2))
2193        length += l2;
2194      else
2195        SL_RETURN(NULL, _("sh_util_strconcat"));
2196      s = va_arg (vl, char * );
2197    }
2198  va_end (vl);
2199
2200  if (sl_ok_adds(length, 2))
2201    strnew = SH_ALLOC( length + 2 );
2202  else
2203    SL_RETURN(NULL, _("sh_util_strconcat"));
2204
2205  /* cppcheck-suppress uninitvar */
2206  strnew[0] = '\0';
2207
2208  (void) sl_strlcpy (strnew, arg1, length + 2); 
2209
2210  va_start (vl, arg1);
2211  s = va_arg (vl, char * );
2212  while (s)
2213    {
2214      (void) sl_strlcat (strnew, s, length + 2);
2215      s = va_arg (vl, char * );
2216    }
2217  va_end (vl);
2218
2219  SL_RETURN(strnew, _("sh_util_strconcat"));
2220}
2221
2222static const char bto64_0[] = N_("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789()");
2223static char bto64[65] = { '\0' };
2224
2225 
2226size_t sh_util_base64_enc (unsigned char * out, 
2227                           const unsigned char * instr, 
2228                           size_t lin)
2229{
2230  int             ll;
2231  unsigned char   a, b, c;
2232  size_t          len  = 0;
2233  size_t          j    = 0;
2234
2235 start:
2236  if (bto64[0] != '\0')
2237    {
2238      if (instr /* && *instr *//* need to handle binary data */)
2239        {
2240          if (lin == 0)
2241            lin = strlen((const char *)instr);
2242
2243          if (lin > 0)
2244            {
2245              do {
2246                ll = 0;
2247               
2248                if (len < lin) 
2249                  { a = *instr; ++instr; ++len; ++ll; }
2250                else 
2251                  { a = 0; }
2252                if (len < lin) 
2253                  { b = *instr; ++instr; ++len; ++ll; }
2254                else 
2255                  { b = 0; }
2256                if (len < lin) 
2257                  { c = *instr; ++instr; ++len; ++ll; }
2258                else 
2259                  { c = 0; }
2260               
2261                *out = bto64[ a >> 2 ];
2262                ++j; ++out;
2263                *out = bto64[ ((a & 0x03) << 4) | ((b & 0xf0) >> 4) ];
2264                ++j; ++out;
2265                *out = (unsigned char) (ll > 1 ? bto64[ ((b & 0x0f) << 2) | ((c & 0xc0) >> 6) ] : '?');
2266                ++j; ++out;
2267                *out = (unsigned char) (ll > 2 ? bto64[ c & 0x3f ] : '?');
2268                ++j; ++out;
2269              } while (len < lin);
2270            }
2271        }
2272      *out = '\0';
2273      return j;
2274    }
2275
2276  memcpy(bto64, _(bto64_0), 65);
2277  goto start;
2278}
2279
2280size_t sh_util_base64_enc_alloc (char **out, const char *in, size_t inlen)
2281{
2282  size_t outlen = SH_B64_SIZ(inlen);
2283
2284  if (inlen > outlen) /* overflow */
2285    {
2286      *out = NULL;
2287      return 0;
2288    }
2289
2290  *out = SH_ALLOC(outlen);
2291  return sh_util_base64_enc((unsigned char *)*out, (const unsigned char *)in, inlen);
2292}
2293
2294size_t sh_util_base64_dec (unsigned char *out, 
2295                           const unsigned char *in, 
2296                           size_t lin)
2297{
2298  size_t i;
2299  unsigned char c;
2300  unsigned char b;
2301  size_t lout = 0;
2302  unsigned int  w = 0;
2303
2304  if (out && in)
2305    {
2306      if (lin == 0)
2307        lin = strlen((const char *)in);
2308
2309      for (i = 0; i < lin; i++)
2310        {
2311          c = *in; ++in;
2312          b = 0;
2313         
2314          if ((c >= 'A') && (c <= 'Z'))
2315            {
2316              b = (c - 'A');
2317            }
2318          else if ((c >= 'a') && (c <= 'z'))
2319            {
2320              b = (c - 'a' + 26);
2321            }
2322          else if ((c >= '0') && (c <= '9'))
2323            {
2324              b = (c - '0' + 52);
2325            }
2326          else if (c == '(' || c == '+')
2327            {
2328              b = 62;
2329            }
2330          else if (c == ')' || c == '/')
2331            {
2332              b = 63;
2333            }
2334          else if (c == '?' || c == '=')
2335            {
2336              /* last byte was written to, but will now get
2337               * truncated
2338               */
2339              if (lout > 0) --lout;
2340              break;
2341            }
2342         
2343          if (w == 0)
2344            {
2345              *out = (b << 2) & 0xfc;
2346              ++lout;
2347            }
2348          else if (w == 1)
2349            {
2350              *out |= (b >> 4) & 0x03;
2351              ++out;
2352              *out = (b << 4) & 0xf0;
2353              ++lout;
2354            }
2355          else if (w == 2)
2356            {
2357              *out |= (b >> 2) & 0x0f;
2358              ++out;
2359              *out = (b << 6) & 0xc0;
2360              ++lout;
2361            }
2362          else if (w == 3)
2363            {
2364              *out |= b & 0x3f;
2365              ++out;
2366            }
2367         
2368          ++w;
2369         
2370          if (w == 4)
2371            {
2372              w = 0;
2373            }
2374        }
2375      *out = '\0';
2376    }
2377  return lout;
2378}
2379
2380size_t sh_util_base64_dec_alloc (unsigned char **out, const unsigned char *in, 
2381                                 size_t lin)
2382{
2383  size_t lout = 3 * (lin / 4) + 2;
2384
2385  *out = SH_ALLOC(lout);
2386
2387  return sh_util_base64_dec (*out, in, lin);
2388}
2389
2390
2391#ifdef HAVE_REGEX_H
2392
2393#include <regex.h>
2394
2395int sh_util_regcmp (char * regex_str, char * in_str)
2396{
2397#if defined(REG_ESPACE)
2398  int        status = REG_ESPACE;
2399#else
2400  int        status = -1;
2401#endif
2402  regex_t    preg;
2403  char     * errbuf;
2404
2405  SL_ENTER(_("sh_util_regcmp"));
2406
2407  status = regcomp(&preg, regex_str, REG_NOSUB|REG_EXTENDED);
2408
2409  if (status == 0)
2410    {
2411      if ((status = regexec(&preg, in_str, 0, NULL, 0)) == 0) 
2412        {
2413          regfree (&preg);
2414          SL_RETURN((0), _("sh_util_regcmp"));
2415        }
2416    }
2417
2418  if (status != 0 && status != REG_NOMATCH) 
2419    {
2420      errbuf = SH_ALLOC(BUFSIZ);
2421      (void) regerror(status, &preg, errbuf, BUFSIZ); 
2422      errbuf[BUFSIZ-1] = '\0';
2423      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_REGEX,
2424                       errbuf, regex_str);
2425      SH_FREE(errbuf);
2426    }
2427       
2428  regfree (&preg);
2429  SL_RETURN((-1), _("sh_util_regcmp"));
2430}
2431
2432#endif
2433
2434
2435
2436
2437
2438
2439
2440
Note: See TracBrowser for help on using the repository browser.