source: trunk/src/sh_utils.c @ 93

Last change on this file since 93 was 93, checked in by rainer, 13 years ago

Add check for PCI ROMs; fix ticket #51 (symlinks in root directory reported with leading double slash).

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