source: trunk/src/sh_utils.c @ 76

Last change on this file since 76 was 76, checked in by rainer, 14 years ago

Fix for ticket #38 (csv escaping) and #39 (building on cygwin). Also optimize a bit.

File size: 46.5 KB
Line 
1/* SAMHAIN file system integrity testing                                   */
2/* Copyright (C) 1999, 2000 Rainer Wichmann                                */
3/*                                                                         */
4/*  This program is free software; you can redistribute it                 */
5/*  and/or modify                                                          */
6/*  it under the terms of the GNU General Public License as                */
7/*  published by                                                           */
8/*  the Free Software Foundation; either version 2 of the License, or      */
9/*  (at your option) any later version.                                    */
10/*                                                                         */
11/*  This program is distributed in the hope that it will be useful,        */
12/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
13/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
14/*  GNU General Public License for more details.                           */
15/*                                                                         */
16/*  You should have received a copy of the GNU General Public License      */
17/*  along with this program; if not, write to the Free Software            */
18/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
19
20#include "config_xor.h"
21
22
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <ctype.h>
27#include <unistd.h>
28
29#if TIME_WITH_SYS_TIME
30#include <sys/time.h>
31#include <time.h>
32#else
33#if HAVE_SYS_TIME_H
34#include <sys/time.h>
35#else
36#include <time.h>
37#endif
38#endif
39
40
41#include "samhain.h"
42#include "sh_error.h"
43#include "sh_utils.h"
44#include "sh_unix.h"
45#include "sh_tiger.h"
46#include "sh_entropy.h"
47
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/* can't inline (AIX)
557 */
558int sh_util_hexchar( const char c )
559{
560  /*@+charint@*/
561  if      ( c >= '0' && c <= '9' )
562    return c - '0';
563  else if ( c >= 'a' && c <= 'f' )
564    return c - 'a' + 10;
565  else if ( c >= 'A' && c <= 'F' )
566    return c - 'A' + 10;
567  else return -1;
568  /*@-charint@*/
569}
570
571/* read a hexadecimal key, convert to binary
572 */
573int sh_util_hextobinary (char * binary, const char * hex, int bytes)
574{
575  int i = 0, j, k, l = 0;
576  char c;
577
578#define SH_HEXCHAR(x, y) \
579    c = (x); \
580    if ( c >= '0' && c <= '9' ) \
581      y = c - '0'; \
582    else if ( c >= 'a' && c <= 'f' ) \
583      y = c - 'a' + 10; \
584    else if ( c >= 'A' && c <= 'F' ) \
585      y = c - 'A' + 10; \
586    else \
587      SL_RETURN((-1), _("sh_util_hextobinary"))
588
589
590  SL_ENTER(_("sh_util_hextobinary"));
591
592  if (bytes < 2)
593    SL_RETURN((-1), _("sh_util_hextobinary"));
594
595  while (i < (bytes-1))
596    {
597      SH_HEXCHAR(hex[i],   k);
598      SH_HEXCHAR(hex[i+1], j);
599     
600      binary[l] = (char)(k * 16 + j);
601      ++l; i+= 2;
602    }
603 
604  SL_RETURN((0), _("sh_util_hextobinary"));
605}
606
607static void copy_four (unsigned char * dest, UINT32 in)
608{
609  UINT32 i, j;
610  int    count;
611
612  SL_ENTER(_("copy_four"));
613  for (count = 0; count < 4; ++count)
614    {
615      i  = in / 256;
616      j  = in - (i*256);
617      dest[count] = (unsigned char) j;
618      in = i;
619    }
620  SL_RET0(_("copy_four"));
621}
622
623/* compute HMAC-TIGER
624 */
625static char * sh_util_hmac_tiger (char * hexkey, 
626                                  char * text, size_t textlen)
627{
628  static char opad[KEY_BLOCK] = { 
629    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
630    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
631    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
632    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C
633  };
634  static char ipad[KEY_BLOCK] = { 
635    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, 
636    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, 
637    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, 
638    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36
639  };
640  static char  zap[KEY_BLOCK] = { 
641    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 
642    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 
643    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, 
644    (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00
645  };
646  char        K[KEY_BLOCK];
647  char        outer[KEY_BLOCK];
648  char      * inner;
649  UINT32    * h1;
650  UINT32    * h2;
651  UINT32      cc[KEY_LEN/4];
652  char      * res;
653
654  size_t      i;
655
656  SL_ENTER(_("sh_util_hmac_tiger"));
657  ASSERT((KEY_BLOCK <= (KEY_LEN/2)), _("KEY_BLOCK <= (KEY_LEN/2)"))
658
659  if (KEY_BLOCK > (KEY_LEN/2))
660    {
661      res = sh_tiger_hash (NULL, TIGER_DATA, 0);
662      SL_RETURN(res, _("sh_util_hmac_tiger"));
663    }
664
665  memcpy (K, zap, KEY_BLOCK);
666
667  if (sh_util_hextobinary (K, hexkey, KEY_LEN) < 0)
668    {
669      res = sh_tiger_hash (NULL, TIGER_DATA, 0);
670      SL_RETURN(res, _("sh_util_hmac_tiger"));
671    }
672
673  if (sl_ok_adds(textlen, KEY_BLOCK))
674    {
675      inner = (char *) SH_ALLOC (textlen + KEY_BLOCK); 
676
677      for (i = 0; i < KEY_BLOCK; ++i)
678        {
679          outer[i]  = K[i] ^ opad[i];
680          inner[i]  = K[i] ^ ipad[i];
681        }
682      for (i = KEY_BLOCK; i < (KEY_BLOCK+textlen); ++i)
683        {
684          inner[i] = text[i - KEY_BLOCK];
685        }
686    }
687  else
688    {
689      sh_error_handle((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
690                      _("integer overflow"), 
691                      _("sh_util_hmac_tiger"));
692      res = sh_tiger_hash (NULL, TIGER_DATA, 0);
693      SL_RETURN(res, _("sh_util_hmac_tiger"));
694    }
695
696  /* now compute the hash
697   */
698  h1 = sh_tiger_hash_uint32 ( outer,
699                              TIGER_DATA,
700                              KEY_BLOCK);
701  for (i = 0; i < (KEY_LEN/8); ++i)
702    {
703      /* cc[i] = h1[i]; */
704      copy_four ( (unsigned char *) &(cc[i]), h1[i]);
705    }
706
707  h2 = sh_tiger_hash_uint32 ( inner,
708                              TIGER_DATA,
709                              (unsigned long) KEY_BLOCK+textlen);
710  for (i = KEY_LEN/8; i < (KEY_LEN/4); ++i)
711    {
712      copy_four ( (unsigned char *) &(cc[i]), h2[i - (KEY_LEN/8)]);
713      /* cc[i] = h2[i - (KEY_LEN/8)]; */
714    }
715  SH_FREE(inner);
716 
717  res = sh_tiger_hash ((char *) &cc[0],
718                       TIGER_DATA,
719                       (unsigned long) (KEY_LEN/4 * sizeof(UINT32)));
720
721  SL_RETURN(res, _("sh_util_hmac_tiger"));
722}
723
724static char * sh_util_hash_tiger ( char * hexkey, 
725                                   char * text, size_t textlen)
726{
727  char         * res;
728  char           h2[2*KEY_LEN+1];
729  SL_ENTER(_("sh_util_hash_tiger"));
730
731  (void) sl_strlcpy(h2, hexkey, KEY_LEN+1); 
732  (void) sl_strlcat(h2, sh_tiger_hash(text, TIGER_DATA, 
733                                      (unsigned long) textlen), 2*KEY_LEN+1);
734
735  res = sh_tiger_hash(h2, TIGER_DATA, 2*KEY_LEN);
736
737  SL_RETURN(res, _("sh_util_hash_tiger"));
738}
739
740/* --- compute signature on data ---
741 */
742#define TYPE_HMAC 0
743#define TYPE_HASH 1
744
745static int sigtype = TYPE_HMAC;
746
747int sh_util_sigtype (const char * c)
748{
749  SL_ENTER(_("sh_util_sigtype"));
750  if (c == NULL)
751    SL_RETURN( -1, _("sh_util_sigtype"));
752
753  if (0 == strcmp(_("HMAC-TIGER"), c))
754    sigtype = TYPE_HMAC;
755  else if  (0 == strcmp(_("HASH-TIGER"), c))
756    sigtype = TYPE_HASH;
757  else
758    SL_RETURN( -1, _("sh_util_sigtype"));
759
760  SL_RETURN( 0, _("sh_util_sigtype"));
761}
762
763char * sh_util_siggen (char * hexkey, 
764                       char * text, size_t textlen) 
765{
766  char * p;
767 
768  SL_ENTER(_("sh_util_siggen"));
769  if (sigtype == TYPE_HMAC)
770    p = sh_util_hmac_tiger (hexkey, 
771                            text, textlen);
772  else
773    p = sh_util_hash_tiger (hexkey, 
774                            text, textlen);
775  SL_RETURN(p, _("sh_util_siggen"));
776}   
777
778 
779/* a simple compressor
780 */
781long sh_util_compress (char * dest, char * src, size_t dest_size)
782{
783  char * add;
784  char * get;
785  size_t   count = 0;
786  size_t   dest_end;
787
788  SL_ENTER(_("sh_util_compress"));
789
790  if (dest_size == 0)
791    SL_RETURN((0), _("sh_util_compress"));
792 
793  if ((dest == NULL) || (src == NULL))
794    SL_RETURN((0), _("sh_util_compress"));
795 
796  dest_end = sl_strlen(dest);
797
798  if (dest_end > dest_size)
799    SL_RETURN((0), _("sh_util_compress"));
800
801  add      = &dest[dest_end];
802  get      = src;
803
804  while (count < (dest_size-dest_end))
805    {
806      if (isalnum((int) *get)) 
807        {
808          *add = *get;
809          ++add;
810          ++count;
811        }
812      ++get; 
813      if (*get == '\0' && (count < (dest_size-dest_end))) 
814        /* end of src reached */
815        {
816          *add = *get;  /* copy the '\0'      */
817          break;        /* and stop copying   */
818        }
819    }
820
821  dest[dest_size-1] = '\0'; /* paranoia       */
822  SL_RETURN(((long)count), _("sh_util_compress")); /* no of chars copied */   
823}
824
825
826/* copy the four least significant bytes
827 */
828void sh_util_cpylong (char * dest, const char * src, int len )
829{
830  int i, j;
831  union
832  {
833    long l;
834    char c[sizeof(long)];
835  } u;
836
837  SL_ENTER(_("sh_util_cpylong"));   
838
839  u.l = 1;
840
841  /* MSB is first
842   */
843  if (sizeof(long)>4 &&/*@+charint@*/(u.c[sizeof(long)-1] == 1)/*@-charint@*/)
844    {
845      j = (int) (sizeof(long)-4);
846      for (i = 0; i < j; ++i) ++src;
847    }
848
849  i = 0;
850
851  while (i < 4)
852    {
853      *dest = (*src);
854      ++dest; ++src;
855      if (i == (len-1)) break;
856      ++i;
857    }
858  SL_RET0(_("sh_util_cpylong"));
859}
860
861/*  This is a maximally equidistributed combined Tausworthe
862 *  generator. The sequence is,
863 *
864 *   x_n = (s1_n ^ s2_n ^ s3_n)
865 *
866 *   s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
867 *   s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
868 *   s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
869 *
870 *   computed modulo 2^32. In the three formulas above '^' means
871 *   exclusive-or (C-notation), not exponentiation. Note that the
872 *   algorithm relies on the properties of 32-bit unsigned integers (it
873 *   is formally defined on bit-vectors of length 32).
874 *
875 *   Stolen from GSL (GNU scientific library) and modified somewhat.
876 *   I am using UINT32, which is guaranteed to be 32 bits. Also made
877 *   sure that the initialization vector is valid.
878 */
879
880
881/* interval [0, 4294967296]
882 */
883static UINT32 taus_get_long (void *vstate)
884{
885  UINT32 * state = (UINT32 *) vstate;
886
887  if (skey->rngI == BAD)
888    (void)taus_seed();
889
890#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
891  /*@+ignorequals@*/
892  state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12);
893  state[1] = TAUSWORTHE (state[1],  2, 25, 4294967288UL,  4);
894  state[2] = TAUSWORTHE (state[2],  3, 11, 4294967280UL, 17);
895  /*@-ignorequals@*/
896  return (state[0] ^ state[1] ^ state[2]);
897}
898
899/* Hide the internal state of the PRNG by using its output as
900 * input for a one-way hash function.
901 */
902UINT32   taus_svec[6];
903
904UINT32 taus_get (void *state1, void *state2, void *state3)
905{
906  UINT32   retval;
907  UINT32 * res;
908  static   UINT32   res_vec[6];
909  static   int      res_num = 0;
910  register int i;
911
912  if (res_num > 0)
913    {
914      retval  = res_vec[res_num];
915      res_num = (res_num == 5) ? 0 : (res_num + 1);
916      return  retval;
917    }
918
919  taus_svec[0] = taus_get_long (state1);
920  taus_svec[1] = taus_get_long (state2);
921  taus_svec[2] = taus_get_long (state3);
922  taus_svec[3] = taus_get_long (state1);
923  taus_svec[4] = taus_get_long (state2);
924  taus_svec[5] = taus_get_long (state3);
925
926  res     = sh_tiger_hash_uint32 ( (char *) &taus_svec[0], 
927                                   TIGER_DATA, 
928                                   (unsigned long)(6 * sizeof(UINT32)));
929
930  for (i = 1; i < 6; ++i)
931    { 
932      res_vec[i] = res[i];
933    }
934  retval  = taus_svec[0];
935  res_num = 1;
936
937  taus_svec[0] = 0; taus_svec[1] = 0; taus_svec[2] = 0; 
938  taus_svec[3] = 0; taus_svec[4] = 0; taus_svec[5] = 0; 
939
940  return retval;
941}
942
943/* interval [0,1)
944 */
945double taus_get_double (void *vstate)
946{
947  return taus_get_long (vstate) / (4294967296.0 + 1.0) ;
948}
949
950#define LCG(n) ((69069 * n) & 0xffffffffUL)
951
952/* TAKE CARE: state[0], state[1], state[2] must be > 2,8,16, respectively
953 */
954static void taus_set_from_ulong (void *vstate, unsigned long int s)
955{
956  UINT32  *state = (UINT32  *) vstate;
957
958  if (s == 0)
959    s = 1;      /* default seed is 1 */
960
961  state[0] = (UINT32)(LCG (s)        | (UINT32) 0x03);
962  state[1] = (UINT32)(LCG (state[0]) | (UINT32) 0x09);
963  state[2] = (UINT32)(LCG (state[1]) | (UINT32) 0x17);
964
965  /* 'warm up'
966   */
967  (void) taus_get_long (state);
968  (void) taus_get_long (state);
969  (void) taus_get_long (state);
970  (void) taus_get_long (state);
971  (void) taus_get_long (state);
972  (void) taus_get_long (state);
973
974  return;
975}
976
977static void taus_set_from_state (void *vstate, void *init_state)
978{
979  UINT32  *state  = (UINT32  *) vstate;
980  UINT32  *state0 = (UINT32  *) init_state;
981
982  state[0] = state0[0]  | (UINT32) 0x03;
983  state[1] = state0[1]  | (UINT32) 0x09;
984  state[2] = state0[2]  | (UINT32) 0x17;
985 
986  return;
987}
988
989 
990int taus_seed ()
991{
992  char                 bufx[9 * sizeof(UINT32) + 1];
993  int                  status;
994  static unsigned long seed_time = 0;
995
996  SL_ENTER(_("taus_seed"));
997
998  if (skey->rngI == GOOD)
999    {
1000      if ( (sh_unix_longtime () - seed_time) < 3600)
1001        SL_RETURN( (0), _("taus_seed"));
1002    }
1003 
1004  seed_time = sh_unix_longtime ();
1005
1006  status = sh_entropy (24, bufx);
1007
1008  if (!SL_ISERROR(status))
1009    {
1010      skey->rngI = GOOD;
1011      memcpy (&skey->rng0[0], &bufx[0],                  2*sizeof(UINT32));
1012      memcpy (&skey->rng1[0], &bufx[2*sizeof(UINT32)],   2*sizeof(UINT32));
1013      memcpy (&skey->rng2[0], &bufx[4*sizeof(UINT32)],   2*sizeof(UINT32));
1014      memset (bufx, 0, 9 * sizeof(UINT32) + 1);
1015
1016      skey->rng0[2] = 0;
1017      skey->rng1[2] = 0;
1018      skey->rng2[2] = 0;
1019
1020      taus_set_from_state( &(skey->rng0[0]), &(skey->rng0[0]));
1021      taus_set_from_state( &(skey->rng1[0]), &(skey->rng1[0]));
1022      taus_set_from_state( &(skey->rng2[0]), &(skey->rng2[0]));
1023
1024      SL_RETURN( (0), _("taus_seed"));
1025    }
1026
1027  sh_error_handle ((-1), FIL__, __LINE__, status, MSG_ES_ENT,
1028                   _("sh_entropy"));
1029
1030  /* emergency backup - unsafe !
1031   */
1032  skey->rngI = GOOD;
1033#ifdef HAVE_GETTIMEOFDAY
1034  taus_set_from_ulong ( &(skey->rng0[0]), LCG (sh_unix_notime())      );
1035#else
1036  taus_set_from_ulong ( &(skey->rng0[0]), LCG (seed_time)      );
1037#endif
1038  taus_set_from_ulong ( &(skey->rng1[0]), LCG (skey->rng0[0])  );
1039  taus_set_from_ulong ( &(skey->rng2[0]), LCG (skey->rng1[0])  );
1040  skey->rngI = BAD;
1041
1042  SL_RETURN( (-1), _("taus_seed"));
1043}
1044
1045/*@+charint@*/
1046static unsigned char new_key[] = { 0xA7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xA7 };
1047/*@-charint@*/
1048static void copy_four (unsigned char * dest, UINT32 in);
1049
1050int sh_util_set_newkey (const char * new_in)
1051{
1052  size_t i, j = 0;
1053  size_t len;
1054  SL_TICKET fp;
1055  SL_TICKET fout;
1056  char * key;
1057  char * path;
1058  char * outpath = NULL;
1059  unsigned char * image = NULL;
1060  long s = 0;
1061  long ilen = 0;
1062  long ii, k = 0;
1063  UINT32    * h1;
1064  char * new = NULL;
1065
1066  if (0 != sl_is_suid())
1067    {
1068      fprintf(stderr, _("ERROR: insufficient privilege\n"));
1069      _exit (EXIT_FAILURE);
1070      /*@notreached@*/
1071      return -1;  /* braindead MAC OSX compiler needs this */
1072    }
1073       
1074  if (new_in == NULL || new_in[0] == '\0')
1075    {
1076      fprintf(stderr, 
1077              _("ERROR: no key given\n Argument must be 'key@path'\n"));
1078      _exit (EXIT_FAILURE);
1079      /*@notreached@*/
1080      return -1;
1081    }
1082
1083  if (NULL == (new = malloc(strlen(new_in) + 1)))
1084    goto bail_mem;
1085  sl_strncpy(new, new_in, strlen(new_in) + 1);
1086
1087  key = new;
1088  len = strlen(new);
1089  for (i = 1; i < (len-2); ++i)
1090    {
1091      if (new[i] == '@' && new[i+1] == '/')
1092        {
1093          j = i+1; new[i] = '\0'; break;
1094        }
1095    }
1096  if (j == 0)
1097    {
1098      fprintf(stderr, 
1099              _("ERROR: no path to executable given\n Argument must be 'key@path'\n"));
1100      free(new);
1101      _exit (EXIT_FAILURE);
1102      /*@notreached@*/
1103      return -1;
1104    }
1105  else
1106    path = &new[j];
1107
1108  len = strlen(path) + 1 + 4;
1109  /*@-usedef@*/
1110  if (NULL == (outpath = malloc(len)))
1111    goto bail_mem;
1112  /*@-usedef@*/
1113  sl_snprintf (outpath, len, _("%s.out"), path);
1114
1115  fp = sl_open_read(path, SL_NOPRIV);
1116  if (SL_ISERROR(fp))
1117    {
1118      fprintf(stderr, 
1119              _("ERROR: cannot open %s for read (errnum = %ld)\n"), path, fp);
1120      free(new); free (outpath);
1121      _exit (EXIT_FAILURE);
1122      /*@notreached@*/
1123      return -1;
1124    }
1125 
1126  fout = sl_open_write(outpath, SL_NOPRIV);
1127  if (SL_ISERROR(fout))
1128    {
1129      fprintf(stderr, 
1130              _("ERROR: cannot open %s (errnum = %ld)\n"), outpath, fout);
1131      free(new); free (outpath);
1132      _exit (EXIT_FAILURE);
1133      /*@notreached@*/
1134      return -1;
1135    }
1136
1137
1138  image = malloc (4096);
1139  if (!image)
1140    goto bail_mem;
1141  while (0 < (ii = sl_read (fp, &image[s], 4096)))
1142    {
1143      ilen += ii;
1144      s    += 4096;
1145      image = realloc (image, (size_t) (4096 + s));
1146      if (!image)
1147        goto bail_mem;
1148    }
1149
1150  printf(_("%ld bytes read\n"), ilen);
1151
1152 
1153  for (k = 0; k < (ilen - 8); ++k) 
1154    {
1155      if (image[k]   == new_key[0] &&
1156          image[k+1] == new_key[1] &&
1157          image[k+2] == new_key[2] &&
1158          image[k+3] == new_key[3] &&
1159          image[k+4] == new_key[4] &&
1160          image[k+5] == new_key[5] &&
1161          image[k+6] == new_key[6] &&
1162          image[k+7] == new_key[7])
1163        {
1164          printf(_("old key found\n")); 
1165          h1 = sh_tiger_hash_uint32 (key, TIGER_DATA, 
1166                                     (unsigned long)strlen(key));
1167          copy_four( (unsigned char *) &(image[k]),   h1[0]);
1168          copy_four( (unsigned char *) &(image[k+4]), h1[1]);
1169          (void) sl_write (fout, image, ilen);
1170          (void) sl_close (fout);
1171          printf(_("new file %s written\n"), outpath);
1172          free(new); free (outpath); free(image);
1173          _exit (EXIT_SUCCESS);
1174          /*@notreached@*/
1175          return 0;
1176        }
1177    }
1178
1179  fprintf(stderr, 
1180          _("ERROR: old key not found\n"));
1181  free(new); free (outpath); free(image);
1182  _exit (EXIT_FAILURE);
1183  /*@notreached@*/
1184  return -1;
1185
1186
1187 bail_mem:
1188  fprintf(stderr, 
1189          _("ERROR: out of memory\n"));
1190  if (new) free(new); 
1191  if (outpath) free (outpath);
1192  if (image) free (image);
1193  _exit (EXIT_FAILURE);
1194  /*@notreached@*/
1195  return -1;
1196}
1197
1198 
1199
1200       
1201/* A simple en-/decoder, based on Vernam cipher. We use the
1202 * message as salt to hide the key by obtaining a different one-time
1203 * pad each time.
1204 * Should be safe against a listener on the network, but not against someone
1205 * with read access to the binary.
1206 */
1207void sh_util_encode (char * data, char * salt, int mode, char fill)
1208{
1209  static char     cc1[17] = N_("0123456789ABCDEF");
1210  char            cc[17] = "\0";
1211  register int    i, j, j1 = 0, j2 = 0, j3;
1212  char          * dez; 
1213
1214  SL_ENTER(_("sh_util_encode"));
1215
1216  /* init
1217   */
1218  (void) sl_strlcpy( cc, _(cc1), sizeof(cc));
1219
1220  /* max 128 bits keyspace
1221   */
1222  memset (skey->vernam, (int)fill, KEY_LEN+1);
1223
1224  dez    = (char *) &(skey->ErrFlag[0]);
1225  sh_util_cpylong (skey->vernam,     dez, 4);
1226  dez    = (char *) &(skey->ErrFlag[1]);
1227  sh_util_cpylong (&skey->vernam[4], dez, 4);
1228
1229  skey->vernam[KEY_LEN] = '\0';
1230
1231  (void) sl_strlcpy(skey->vernam, 
1232                    sh_tiger_hash(skey->vernam, TIGER_DATA, KEY_LEN), 
1233                    KEY_LEN+1);
1234
1235  (void) sl_strlcpy(skey->vernam, 
1236                    sh_util_hmac_tiger (skey->vernam, salt, strlen(salt)),
1237             KEY_LEN+1);
1238
1239  (void) sl_strlcpy(skey->vernam, 
1240                    sh_util_hmac_tiger (skey->vernam, (char*) new_key, 8),
1241                    KEY_LEN+1);
1242
1243  /* The following routine adds/subtracts  data[j] and vernam[j] mod 16.
1244   */
1245  j = 0;
1246  while (j < KEY_LEN)
1247    {
1248      for (i = 0; i < 16; ++i)
1249        {
1250          if (cc[i] == data[j])   j1 = i;
1251          if (cc[i] == skey->vernam[j])    j2 = i;
1252        }
1253      if (mode == 0)
1254        {
1255          j3 = j1 + j2;
1256          if (j3 > 15) j3 -= 16;
1257          data[j] = cc[j3];
1258        }
1259      else
1260        {
1261          j3 = j1 - j2;
1262          if (j3 <  0) j3 += 16;
1263          data[j] = cc[j3];
1264        }
1265      ++j;
1266    }
1267  SL_RET0(_("sh_util_encode"));
1268}
1269
1270/* server mode
1271 */
1272int sh_util_setserver (const char * dummy)
1273{
1274  SL_ENTER(_("sh_util_setserver"));
1275
1276  (void) dummy;
1277  sh.flag.isserver = GOOD;
1278  SL_RETURN((0),_("sh_util_setserver"));
1279}
1280
1281
1282int sh_util_setlooptime (const char * str)
1283{
1284  int i = atoi (str);
1285 
1286  SL_ENTER(_("sh_util_setlooptime"));
1287
1288  if (i >= 0 && i < INT_MAX) {
1289    sh.looptime = i;
1290    SL_RETURN((0),_("sh_util_setlooptime"));
1291  } else {
1292    sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1293                     _("loop time"), str);
1294    SL_RETURN((-1),_("sh_util_setlooptime"));
1295  }
1296}
1297
1298#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
1299int  sh_util_setchecksum (const char * str)
1300{
1301  static int reject = 0;
1302
1303  SL_ENTER(_("sh_util_setchecksum"));
1304
1305  if (reject == 1)
1306    SL_RETURN((0), _("sh_util_setchecksum"));
1307  reject = 1;
1308
1309  if (sl_strncmp (str, _("init"), sizeof("init")-1) == 0)
1310    {
1311      sh.flag.checkSum = SH_CHECK_INIT;
1312    }
1313  else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0)
1314    {
1315      if (S_TRUE == file_is_remote()) 
1316        {
1317          sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1318                           _("checksum testing"), str);
1319          SL_RETURN((-1), _("sh_util_setchecksum"));
1320        }
1321      else
1322        {
1323          sh.flag.checkSum = SH_CHECK_CHECK;
1324          sh.flag.update   = S_TRUE;
1325        }
1326    }
1327  else if (sl_strncmp (str, _("check"), sizeof("check")-1) == 0)
1328    {
1329      sh.flag.checkSum = SH_CHECK_CHECK;
1330    }
1331  /*
1332  else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0)
1333    {
1334      sh.flag.checkSum = SH_CHECK_INIT;
1335      sh.flag.update   = S_TRUE;
1336    }
1337  */
1338  else if (sl_strncmp (str, _("none"), sizeof("none")-1) == 0)
1339    {
1340      sh.flag.checkSum = SH_CHECK_NONE;
1341    }
1342  else 
1343    {
1344      sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
1345                       _("checksum testing"), str);
1346      SL_RETURN((-1), _("sh_util_setchecksum"));
1347    }
1348  SL_RETURN((0), _("sh_util_setchecksum"));
1349}
1350#endif
1351 
1352/*@+charint@*/
1353unsigned char TcpFlag[8][PW_LEN+1] = { 
1354#if (POS_TF == 1)
1355  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1356#endif
1357  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1358#if (POS_TF == 2)
1359  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1360#endif
1361  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1362#if (POS_TF == 3)
1363  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1364#endif
1365  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1366#if (POS_TF == 4)
1367  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1368#endif
1369  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1370#if (POS_TF == 5)
1371  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1372#endif
1373  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1374#if (POS_TF == 6)
1375  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1376#endif
1377  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1378#if (POS_TF == 7)
1379  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1380#endif
1381  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
1382#if (POS_TF == 8)
1383  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
1384#endif
1385};
1386/*@-charint@*/
1387
1388/* initialize a key to a random value
1389 * rev 0.8
1390 */
1391int sh_util_keyinit (char * buf, long size)
1392{
1393  UINT32       bufy[6];
1394  int          i;
1395  int          status = 0;
1396  char       * p;
1397
1398  SL_ENTER(_("sh_util_keyinit"));
1399
1400  ASSERT((size <= KEY_LEN+1), _("size <= KEY_LEN+1"))
1401
1402  if (size > KEY_LEN+1)
1403    size = KEY_LEN+1;
1404
1405  /* seed / re-seed the PRNG if required
1406   */
1407  status = taus_seed ();
1408
1409  if (status == -1)
1410    sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_ES_KEY1,
1411                     _("taus_seed"));
1412
1413  for (i = 0; i < 6; ++i)
1414    bufy[i] = taus_get(&(skey->rng0[0]), &(skey->rng1[0]), &(skey->rng2[0]));
1415
1416  p = sh_tiger_hash ((char *) bufy, TIGER_DATA, 
1417                     (unsigned long)(6*sizeof(UINT32)));
1418  p[size-1] = '\0';
1419
1420  i = sl_strlcpy(buf, p, (size_t)size);
1421
1422  memset (bufy, 0, 6*sizeof(UINT32));
1423
1424  if ((status == 0) && (!SL_ISERROR(i)) )
1425    SL_RETURN((0),_("sh_util_keyinit"));
1426
1427  if (SL_ISERROR(i))
1428    sh_error_handle ((-1), FIL__, __LINE__, i, MSG_ES_KEY2, 
1429                     _("sl_strlcpy"));
1430
1431  SL_RETURN((-1),_("sh_util_keyinit"));
1432}
1433
1434#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)
1435
1436static unsigned char sh_obscure_index[256];
1437static int sh_obscure_no_check = S_FALSE;
1438
1439int sh_util_valid_utf8 (const unsigned char * str) 
1440{
1441  const int     sh_val_utf8_1 = 1;
1442  const int     sh_val_utf8_2 = 2;
1443  const int     sh_val_utf8_3 = 3;
1444  const int     sh_val_utf8_4 = 4;
1445
1446  size_t        len = strlen((char *)str);
1447  size_t        l   = 0;
1448  int           typ = 0;
1449  unsigned char c     = '\0';
1450  unsigned char c2[2] = { 0x00, 0x00 };
1451  unsigned char c3[3] = { 0x00, 0x00, 0x00 };
1452
1453
1454#define SH_VAL_UTF8_1 ((c != '\0') && ((c & 0x80) == 0x00))
1455#define SH_VAL_UTF8_2 ((c != '\0') && ((c & 0xE0) == 0xC0)) /* 110x xxxx */
1456#define SH_VAL_UTF8_3 ((c != '\0') && ((c & 0xF0) == 0xE0)) /* 1110 xxxx */
1457#define SH_VAL_UTF8_4 ((c != '\0') && ((c & 0xF8) == 0xF0)) /* 1111 0xxx */
1458#define SH_VAL_UTF8_N ((c != '\0') && ((c & 0xC0) == 0x80)) /* 10xx xxxx */
1459#define SH_VAL_BAD    ((c == '"')  || (c == '\t') || (c == '\b') || \
1460                       (c == '\f') || (c == '\n') || \
1461                       (c == '\r') || (c == '\v') || iscntrl((int) c) || \
1462                       (c != ' ' && !isgraph ((int) c)))
1463   
1464  while(l < len) 
1465    {
1466      c = str[l];
1467
1468      if      (SH_VAL_UTF8_1) 
1469        {
1470          if (!(SH_VAL_BAD && (sh_obscure_index[c] != 1)))
1471            {
1472              typ = sh_val_utf8_1;
1473              ++l; continue;
1474            }
1475          else
1476            {
1477              return S_FALSE;
1478            }
1479        } 
1480      else if (SH_VAL_UTF8_2) 
1481        { 
1482          typ = sh_val_utf8_2;
1483          c2[0] = c;
1484          if ((c & 0x3e) != 0x00) /* !(overlong 2-byte seq.) */
1485            {
1486              ++l; 
1487              if (l != len) {
1488                c = str[l];
1489                if(SH_VAL_UTF8_N) {
1490                  c2[1] = c;
1491                  ++l; continue;
1492                } 
1493                else {
1494                  return S_FALSE;
1495                } 
1496              } 
1497              else {
1498                return S_FALSE; 
1499              }
1500            }
1501          else
1502            {
1503              return S_FALSE; /* overlong 2-byte seq. */
1504            }
1505        } 
1506      else if (SH_VAL_UTF8_3) 
1507        {
1508          typ = sh_val_utf8_3;
1509          c3[0] = c;
1510          ++l; if (l == len) return S_FALSE; c = str[l];
1511          if(!SH_VAL_UTF8_N) return S_FALSE;
1512          if (((str[l-1] & 0x1F) == 0x00) && ((c & 0x60) == 0x00))
1513            return S_FALSE; /* overlong 3-byte seq. */
1514          c3[1] = c;
1515          ++l; if (l == len) return S_FALSE; c = str[l];
1516          if(!SH_VAL_UTF8_N) return S_FALSE;
1517          c3[2] = c;
1518          ++l; continue;
1519        } 
1520      else if (SH_VAL_UTF8_4) 
1521        {
1522          typ = sh_val_utf8_4;
1523          ++l; if (l == len) return S_FALSE; c = str[l];
1524          if(!SH_VAL_UTF8_N) return S_FALSE;
1525          if (((str[l-1] & 0x0F) == 0x00) && ((c & 0x70) == 0x00))
1526            return S_FALSE; /* overlong 4-byte seq. */
1527          ++l; if (l == len) return S_FALSE; c = str[l];
1528          if(!SH_VAL_UTF8_N) return S_FALSE;
1529          ++l; if (l == len) return S_FALSE; c = str[l];
1530          if(!SH_VAL_UTF8_N) return S_FALSE;
1531          ++l; continue;
1532        }
1533      return S_FALSE;
1534    }
1535
1536  /* last character is invisible (space or else)
1537   */
1538  if (typ == sh_val_utf8_1)
1539    { 
1540      if (c != ' ')
1541        return S_TRUE;
1542      else
1543        return S_FALSE;
1544    }
1545  else if (typ == sh_val_utf8_2)
1546    {
1547      if (c2[0] == 0xC2 && c2[1] == 0xA0) /* nbsp */
1548        return S_FALSE;
1549      else
1550        return S_TRUE;
1551    }
1552  else if (typ == sh_val_utf8_3)
1553    {
1554      if (c3[0] == 0xE2) 
1555        {
1556          if (c3[1] == 0x80 && c3[2] >= 0x80 && c3[2] <= 0x8F)
1557            return S_FALSE; /* various spaces, left-to-right, right-to-left */
1558          else if (c3[1] == 0x80 && (c3[2] == 0xA8 || c3[2] == 0xA9 || 
1559                                     c3[2] == 0xAD || c3[2] == 0xAF))
1560            return S_FALSE; /* line sep, para sep, zw word joiner, nnbsp */
1561          else if (c3[1] == 0x81 && (c3[2] == 0xA0 || c3[2] == 0xA1 || 
1562                                     c3[2] == 0x9F))
1563            return S_FALSE; /* word joiner, function app, math space */
1564          else
1565            return S_TRUE;
1566        }
1567      else if (c3[0] == 0xE3 && c3[1] == 0x80 && c3[2] == 0x80)
1568        {
1569          return S_FALSE; /* ideographic space */
1570        }
1571      else if (c3[0] == 0xEF && c3[1] == 0xBB && c3[2] == 0xBF)
1572        {
1573          return S_FALSE; /* zwnbsp */
1574        }
1575      else
1576        {
1577          return S_TRUE;
1578        }
1579    }
1580  else
1581    {
1582      return S_TRUE;
1583    }
1584}
1585
1586
1587int sh_util_obscure_ok (const char * str)
1588{
1589  unsigned long   i;
1590  char * endptr = NULL;
1591
1592  SL_ENTER(_("sh_util_obscure_ok"));
1593
1594  if (0 == sl_strncmp("all", str, 3))
1595    {
1596      for (i = 0; i < 255; ++i)
1597        {
1598          sh_obscure_index[i] = (unsigned char)1;
1599        }
1600      sh_obscure_no_check = S_TRUE;
1601      SL_RETURN(0, _("sh_util_obscure_ok"));
1602    }
1603
1604  sh_obscure_no_check = S_FALSE;
1605
1606  for (i = 0; i < 255; ++i)
1607    {
1608      sh_obscure_index[i] = (unsigned char)0;
1609    }
1610
1611  i = strtoul (str, &endptr, 0);
1612  if (i > 255)
1613    {
1614      SL_RETURN(-1, _("sh_util_obscure_ok"));
1615    }
1616  sh_obscure_index[i] = (unsigned char)1;
1617  if (*endptr == ',')
1618    ++endptr;
1619
1620  while (*endptr != '\0')
1621    {
1622      i = strtoul (endptr, &endptr, 0);
1623      if (i > 255)
1624        {
1625          SL_RETURN(-1, _("sh_util_obscure_ok"));
1626        }
1627      sh_obscure_index[i] = (unsigned char)1;
1628      if (*endptr == ',')
1629        ++endptr;
1630    }
1631  SL_RETURN(0, _("sh_util_obscure_ok"));
1632}
1633
1634static int sh_obscure_check_utf8 = S_FALSE;
1635
1636int sh_util_obscure_utf8 (const char * c)
1637{
1638  int i;
1639  SL_ENTER(_("sh_util_obscure_utf8"));
1640  i = sh_util_flagval(c, &(sh_obscure_check_utf8));
1641  if (sh_obscure_check_utf8 == S_TRUE)
1642    sh_obscure_no_check = S_FALSE;
1643  SL_RETURN(i, _("sh_util_obscure_utf8"));
1644}
1645
1646
1647int sh_util_obscurename (ShErrLevel level, char * name_orig, int flag)
1648{
1649  unsigned char * name = (unsigned char *) name_orig;
1650  char * safe;
1651  unsigned int i;
1652  size_t len = 0;
1653
1654  SL_ENTER(_("sh_util_obscurename"));
1655
1656  ASSERT_RET((name != NULL), _("name != NULL"), (0))
1657
1658  if (sh_obscure_no_check == S_FALSE)
1659    {
1660      if (sh_obscure_check_utf8 != S_TRUE)
1661        {
1662          /* -- Check name. --
1663           */
1664          while (*name != '\0') 
1665            {
1666              if ( (*name) >  0x7F || (*name) == '"'  || (*name) == '\t' ||
1667                   (*name) == '\b' || (*name) == '\f' || 
1668                   (*name) == '\n' || (*name) == '\r' ||
1669                   (*name) == '\v' || iscntrl((int) *name) || 
1670                   ((*name) != ' ' && !isgraph ((int) *name)) ) 
1671                {
1672                  i = (unsigned char) *name;
1673                  if (sh_obscure_index[i] != (unsigned char)1)
1674                    {
1675                      goto err;
1676                    }
1677                }
1678              name++; ++len;
1679            }
1680
1681          /* Check for blank at end of name
1682           */
1683          if ((len > 0) && (name_orig[len-1] == ' '))
1684            {
1685              goto err;
1686            }
1687        }
1688      else
1689        {
1690          if (S_FALSE == sh_util_valid_utf8(name))
1691            {
1692              goto err;
1693            }
1694          SL_RETURN((0),_("sh_util_obscurename"));
1695        }
1696    }
1697     
1698  SL_RETURN((0),_("sh_util_obscurename"));
1699
1700 err:
1701 
1702  if (flag == S_TRUE)
1703    {
1704      safe = sh_util_safe_name (name_orig); 
1705      sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_OBSC, 
1706                       safe);
1707      SH_FREE(safe);
1708    }
1709  SL_RETURN((-1),_("sh_util_obscurename"));
1710}
1711
1712#endif
1713
1714/* returns freshly allocated memory, return value should be free'd
1715 */
1716char * sh_util_dirname(const char * fullpath)
1717{
1718  char * retval;
1719  size_t len;
1720
1721  SL_ENTER(_("sh_util_dirname"));
1722
1723  ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
1724
1725  len = sl_strlen (fullpath);  /* fullpath[i] is terminating '\0' */
1726
1727  if (len > 1 && fullpath[len-1] == '/') /* skip trailing '/' */
1728    --len;
1729
1730  while (len > 0) {
1731    --len;
1732    if (fullpath[len] == '/') 
1733      {
1734        if (len == 0) ++len; /* copy the '/' to output */
1735        break;
1736      }
1737  }
1738
1739  /* -- Not an absolute path. --
1740   */
1741  if ((len == 0) && (fullpath[len] != '/'))
1742    { 
1743      SL_RETURN(NULL, _("sh_util_dirname"));
1744    }
1745
1746  retval = SH_ALLOC(len + 1);
1747  (void) sl_strlcpy (retval, fullpath, len+1);
1748
1749  SL_RETURN(retval, _("sh_util_dirname"));
1750}
1751
1752/* returns freshly allocated memory, return value should be free'd
1753 */
1754char * sh_util_basename(const char * fullpath)
1755{
1756  char * retval = NULL;
1757  char * tmp;
1758  char * c;
1759  size_t len;
1760
1761  SL_ENTER(_("sh_util_basename"));
1762
1763  ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))
1764
1765  c = strrchr(fullpath, '/');
1766  len = sl_strlen (c);
1767
1768  if (c == fullpath)
1769    {
1770      if (len <= 1)
1771        retval = sh_util_strdup(c);
1772      else
1773        retval = sh_util_strdup(++c);
1774    }
1775  else
1776    {
1777      if (len > 1)
1778        {
1779          retval = sh_util_strdup(++c);
1780        }
1781      else
1782        {
1783          /* input ends in '/' */
1784          tmp = sh_util_strdup(fullpath);
1785          tmp[strlen(tmp)-1] = '\0';
1786          retval = sh_util_basename(tmp);
1787          SH_FREE(tmp);
1788        }
1789    }
1790
1791  SL_RETURN(retval, _("sh_util_basename"));
1792}
1793
1794   
1795/* returns freshly allocated memory, return value should be free'd
1796 */
1797char * sh_util_safe_name (const char * name)
1798{
1799  register int  i = 0;
1800  const char  * p;
1801  char        * retval;
1802  char          oct[32];
1803  char          format[16];
1804  size_t        len;
1805
1806  SL_ENTER(_("sh_util_safe_name"));
1807
1808  if (name == NULL)
1809    {
1810      /* return an allocated array
1811       */
1812      retval = SH_ALLOC(7);
1813      (void) sl_strlcpy(retval, _("(null)"), 7);
1814      SL_RETURN(retval, _("sh_util_safe_name"));
1815    }
1816
1817  /*
1818  ASSERT_RET ((name != NULL), _("name != NULL"), _("NULL"))
1819  */
1820
1821  len = sl_strlen(name);
1822  p   = name;
1823
1824#ifdef SH_USE_XML
1825  if (sl_ok_muls (6, len) && sl_ok_adds ((6*len), 2))
1826    { retval = SH_ALLOC(6 * len + 2); }
1827  else
1828    {
1829      /* return an allocated array
1830       */
1831      retval = SH_ALLOC(11);
1832      (void) sl_strlcpy(retval, _("(overflow)"), 11);
1833      SL_RETURN(retval, _("sh_util_safe_name"));
1834    }
1835#else
1836  if (sl_ok_muls (4, len) && sl_ok_adds ((4*len), 2))
1837    { retval = SH_ALLOC(4 * len + 2); }
1838  else
1839    {
1840      /* return an allocated array
1841       */
1842      retval = SH_ALLOC(11);
1843      (void) sl_strlcpy(retval, _("(overflow)"), 11);
1844      SL_RETURN(retval, _("sh_util_safe_name"));
1845    }
1846#endif
1847
1848  (void) sl_strncpy(format, _("%c%03o"), 16);
1849
1850  while (*p != '\0') {
1851    /* Most frequent cases first
1852     */
1853    if ( ((*p) >= 'a' && (*p) <= 'z')  || ((*p) == '/') || ((*p) == '.') ||
1854         ((*p) >= '0' && (*p) <= '9')  || 
1855         ((*p) >= 'A' && (*p) <= 'Z')) {
1856      retval[i] = *p; 
1857    } else if ( (*p) == '\\') {           /* backslash        */
1858      retval[i] = '\\'; ++i; 
1859      retval[i] = '\\';
1860    } else if ( (*p) == '\n') {    /* newline          */
1861      retval[i] = '\\'; ++i; 
1862      retval[i] = 'n';
1863    } else if ( (*p) == '\b') {    /* backspace        */
1864      retval[i] = '\\'; ++i; 
1865      retval[i] = 'b';
1866    } else if ( (*p) == '\r') {    /* carriage  return */
1867      retval[i] = '\\'; ++i; 
1868      retval[i] = 'r';
1869    } else if ( (*p) == '\t') {    /* horizontal tab   */
1870      retval[i] = '\\'; ++i; 
1871      retval[i] = 't';
1872    } else if ( (*p) == '\v') {    /* vertical tab     */
1873      retval[i] = '\\'; ++i; 
1874      retval[i] = 'v';
1875    } else if ( (*p) == '\f') {    /* form-feed        */
1876      retval[i] = '\\'; ++i; 
1877      retval[i] = 'f';
1878#ifdef WITH_DATABASE
1879    } else if ( (*p) == '\'') {    /* single quote     */
1880      retval[i] = '\\'; ++i; 
1881      retval[i] = '\'';
1882#endif
1883    } else if ( (*p) == ' ') {     /* space            */
1884      retval[i] = '\\'; ++i; 
1885      retval[i] = ' ';
1886#ifdef SH_USE_XML
1887    } else if ( (*p) == '"') {     /* double quote     */
1888      retval[i] = '&'; ++i; 
1889      retval[i] = 'q'; ++i;
1890      retval[i] = 'u'; ++i;
1891      retval[i] = 'o'; ++i;
1892      retval[i] = 't'; ++i;
1893      retval[i] = ';';
1894    } else if ( (*p) == '&') {     /* ampersand        */
1895      retval[i] = '&'; ++i; 
1896      retval[i] = 'a'; ++i;
1897      retval[i] = 'm'; ++i;
1898      retval[i] = 'p'; ++i;
1899      retval[i] = ';';
1900    } else if ( (*p) == '<') {     /* left angle       */
1901      retval[i] = '&'; ++i; 
1902      retval[i] = 'l'; ++i;
1903      retval[i] = 't'; ++i;
1904      retval[i] = ';';
1905    } else if ( (*p) == '>') {     /* right angle      */
1906      retval[i] = '&'; ++i; 
1907      retval[i] = 'g'; ++i;
1908      retval[i] = 't'; ++i;
1909      retval[i] = ';';
1910#else
1911    } else if ( (*p) == '"') {     /* double quote     */
1912      retval[i] = '\\'; ++i; 
1913      retval[i] = '\"';
1914#endif
1915    } else if (!isgraph ((int) *p)) {    /* not printable    */
1916      /*@-bufferoverflowhigh -formatconst@*/
1917      /* flawfinder: ignore */
1918      sprintf(oct, format, '\\',                 /* known to fit  */
1919              (unsigned char) *p);
1920      /*@+bufferoverflowhigh +formatconst@*/
1921      retval[i] = oct[0]; ++i;
1922      retval[i] = oct[1]; ++i;
1923      retval[i] = oct[2]; ++i;
1924      retval[i] = oct[3]; 
1925    } else {
1926      retval[i] = *p;
1927    }
1928    ++p;
1929    ++i;
1930  }
1931  retval[i] = '\0';
1932  SL_RETURN(retval, _("sh_util_safe_name"));
1933}
1934
1935int sh_util_isnum (char *str)
1936{
1937  char *p = str;
1938
1939  SL_ENTER(_("sh_util_isnum"));
1940
1941  ASSERT_RET ((str != NULL), _("str != NULL"), (-1))
1942
1943  while (p) {
1944    if (!isdigit((int) *p) ) 
1945      SL_RETURN((-1), _("sh_util_isnum"));
1946    ++p;
1947  }
1948  SL_RETURN((0), _("sh_util_isnum"));
1949}
1950
1951char * sh_util_strconcat (const char * arg1, ...) 
1952{
1953  size_t    length, l2;
1954  char    * s;
1955  char    * strnew;
1956  va_list vl;
1957
1958  SL_ENTER(_("sh_util_strconcat"));
1959
1960  ASSERT_RET ((arg1 != NULL), _("arg1 != NULL"), (NULL))
1961
1962  length = sl_strlen (arg1) + 1;
1963
1964  va_start (vl, arg1);
1965  s = va_arg (vl, char * );
1966  while (s != NULL)
1967    {
1968      l2 = sl_strlen (s);
1969      if (sl_ok_adds(length, l2))
1970        length += l2;
1971      else
1972        SL_RETURN(NULL, _("sh_util_strconcat"));
1973      s = va_arg (vl, char * );
1974    }
1975  va_end (vl);
1976
1977  if (sl_ok_adds(length, 2))
1978    strnew = SH_ALLOC( length + 2 );
1979  else
1980    SL_RETURN(NULL, _("sh_util_strconcat"));
1981
1982  strnew[0] = '\0';
1983
1984  (void) sl_strlcpy (strnew, arg1, length + 2); 
1985
1986  va_start (vl, arg1);
1987  s = va_arg (vl, char * );
1988  while (s)
1989    {
1990      (void) sl_strlcat (strnew, s, length + 2);
1991      s = va_arg (vl, char * );
1992    }
1993  va_end (vl);
1994
1995  SL_RETURN(strnew, _("sh_util_strconcat"));
1996}
1997
1998
1999#ifdef HAVE_REGEX_H
2000
2001#include <regex.h>
2002
2003int sh_util_regcmp (char * regex_str, char * in_str)
2004{
2005#if defined(REG_ESPACE)
2006  int        status = REG_ESPACE;
2007#else
2008  int        status = -1;
2009#endif
2010  regex_t    preg;
2011  char     * errbuf;
2012
2013  SL_ENTER(_("sh_util_regcmp"));
2014
2015  status = regcomp(&preg, regex_str, REG_NOSUB|REG_EXTENDED);
2016
2017  if (status == 0)
2018    {
2019      if ((status = regexec(&preg, in_str, 0, NULL, 0)) == 0) 
2020        {
2021          regfree (&preg);
2022          SL_RETURN((0), _("sh_util_regcmp"));
2023        }
2024    }
2025
2026  if (status != 0 && status != REG_NOMATCH) 
2027    {
2028      errbuf = SH_ALLOC(BUFSIZ);
2029      (void) regerror(status, &preg, errbuf, BUFSIZ); 
2030      errbuf[BUFSIZ-1] = '\0';
2031      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_REGEX,
2032                       errbuf, regex_str);
2033      SH_FREE(errbuf);
2034    }
2035       
2036  regfree (&preg);
2037  SL_RETURN((-1), _("sh_util_regcmp"));
2038}
2039
2040#endif
2041
2042
2043
2044
2045
2046
2047
2048
Note: See TracBrowser for help on using the repository browser.