source: trunk/src/sh_utils.c @ 137

Last change on this file since 137 was 137, checked in by rainer, 12 years ago

Fix compile errors.

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