source: trunk/src/sh_utils.c @ 68

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

Update trunk to samhain 2.3

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