Logo Search packages:      
Sourcecode: samhain version File versions  Download package

sh_utils.c

/* SAMHAIN file system integrity testing                                   */
/* Copyright (C) 1999, 2000 Rainer Wichmann                                */
/*                                                                         */
/*  This program is free software; you can redistribute it                 */
/*  and/or modify                                                          */
/*  it under the terms of the GNU General Public License as                */
/*  published by                                                           */
/*  the Free Software Foundation; either version 2 of the License, or      */
/*  (at your option) any later version.                                    */
/*                                                                         */
/*  This program is distributed in the hope that it will be useful,        */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of         */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
/*  GNU General Public License for more details.                           */
/*                                                                         */
/*  You should have received a copy of the GNU General Public License      */
/*  along with this program; if not, write to the Free Software            */
/*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */

#include "config_xor.h"


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>

#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif


#include "samhain.h"
#include "sh_error.h"
#include "sh_utils.h"
#include "sh_unix.h"
#include "sh_tiger.h"
#include "sh_entropy.h"

#undef  FIL__
#define FIL__  _("sh_utils.c")

UINT32 ErrFlag[2];

int sh_util_flagval(char * c, int * fval)
{
  SL_ENTER(_("sh_util_flagval"));
  if (c == NULL)
    SL_RETURN( (-1), _("sh_util_flagval"));
  if ( c[0] == '1'  || c[0] == 'y'  || c[0] == 'Y' ||
       c[0] == 't'  || c[0] == 'T')
    {
      *fval = S_TRUE;
      SL_RETURN( (0), _("sh_util_flagval"));
    }
  if ( c[0] == '0'  || c[0] == 'n'  || c[0] == 'N' ||
       c[0] == 'f'  || c[0] == 'F')
    {
      *fval = S_FALSE;
      SL_RETURN( (0), _("sh_util_flagval"));
    }
  SL_RETURN( (-1), _("sh_util_flagval"));
}

int sh_util_timeout_check (SH_TIMEOUT * sh_timer)
{
  UINT64 now = (UINT64) time(NULL);
  UINT64 dif;
  
  if (sh_timer->flag_ok == S_FALSE)
    {
      /* first time
       */
      if (sh_timer->time_last == 0)
      {
        sh_timer->time_last = now;
        return S_TRUE;
      }
      /* later on
       */
      dif = now - sh_timer->time_last;
      if (dif < sh_timer->time_dist)
      {
        return S_FALSE;
      }
      sh_timer->time_last = now;
      return S_TRUE;
    }
  sh_timer->time_last = now;
  return S_FALSE;
}

static int sh_ask_update = S_FALSE;

int sh_util_set_interactive(char * str)
{
  if (str == NULL)
    sh_ask_update = S_TRUE;
  else
    sh_ask_update = S_TRUE;

  return 0;
}

#if !defined(STDIN_FILENO)
#define STDIN_FILENO 0
#endif
#if !defined(STDERR_FILENO)
#define STDERR_FILENO 0
#endif

int sh_util_ask_update(char * path)
{
  int    inchar, c;
  int    i = S_TRUE;
  char * tmp = NULL;

  SL_ENTER(_("sh_util_ask_update"));

  if (sh_ask_update != S_TRUE)
    {
      SL_RETURN(i, _("sh_util_ask_update"));
    }

#ifdef HAVE_TTYNAME
  if (!ttyname(STDIN_FILENO))
    {
      if (NULL != ttyname(STDERR_FILENO))
        {
          if (NULL == freopen(ttyname(STDERR_FILENO), "r", stdin))
            {
              fprintf(stderr, _("Cannot continue: stdin is not a terminal\n"));
              exit(EXIT_FAILURE);
          }
        }
      else
        {
          fprintf(stderr, _("Cannot continue: stdin is not a terminal\n"));
          exit(EXIT_FAILURE);
        }
    }
#endif

  if (sh_ask_update == S_TRUE)
    {
      tmp = sh_util_safe_name (path);
      fprintf (stderr, _("Update %s [Y/n] ? "), tmp);
      SH_FREE(tmp);
      while (1 == 1)
      {
        c = fgetc(stdin); inchar = c;
        /*@+charintliteral@*/
        while (c != '\n' && c != EOF)
          c = fgetc(stdin);
        /* fprintf(stderr, "CHAR (1): %c\n", inchar); */
        if (inchar == 'Y' || inchar == 'y' || inchar == '\n')
          {
            break;
          }
        else if (inchar == 'n' || inchar == 'N')
          {
            i = S_FALSE;
          }
        else
          {
            fprintf(stderr, _("Please answer y(es) or n(o)\n"));
          }
        /*@-charintliteral@*/
      }
    }

  SL_RETURN(i, _("sh_util_ask_update"));
}

int sh_util_hidesetup(char * c)
{
  int i;
  SL_ENTER(_("sh_util_hidesetup"));
  i = sh_util_flagval(c, &(sh.flag.hidefile));

  SL_RETURN(i, _("sh_util_hidesetup"));
}
    
char * sh_util_strdup (const char * str) 
{
  char * p = NULL;
  size_t len;

  SL_ENTER(_("sh_util_strdup"));

  if (str != NULL)
    {
      len = sl_strlen(str);
      p   = SH_ALLOC (len + 1);
      (void) sl_strlcpy (p, str, len+1);
    }
  SL_RETURN( p, _("sh_util_strdup"));
}

/* by the eircom.net computer incident
 * response team
 */
char * sh_util_strsep (char **str, const char *delim) 
{
  char *ret, *c, *d;

  SL_ENTER(_("sh_util_strsep"));
  ret = *str;

  if (ret == NULL) {
    SL_RETURN(ret, _("sh_util_strsep"));
  }

  for (c = *str; *c != '\0'; c++) {
    for (d = (char *) delim; *d != '\0'; d++) {
      if (*c == *d) {
        *c = '\0';
        *str = c + 1;
        SL_RETURN(ret, _("sh_util_strsep"));
      }
    }
  }

  /* If we get to here, there's no delimiters in the string */
  *str = NULL;
  SL_RETURN(ret, _("sh_util_strsep"));
}


/* returned string must be free'd by caller
 */
char * sh_util_formatted (const char * formatt, st_format * ftab)
{
  struct tm   * time_ptr;
  size_t size;
  size_t isiz;
  char * fmt = NULL;
  char * p;
  char * q;
  char * outstr;
  int    i;
  int    j;
  time_t inpp;

  char * clist[16];
  int    nn = 0;

  SL_ENTER(_("sh_util_formatted"));

  if (formatt == NULL || ftab == NULL)
    SL_RETURN(NULL, _("sh_util_formatted"));

  /* -- save the format (we overwrite it !!) --
   */
  size = sl_strlen(formatt);
  if (size > 0)
    {
      fmt = (char *) SH_ALLOC(size + 1);
      (void) sl_strlcpy(fmt, formatt, size + 1);
    }
  else
    SL_RETURN(NULL, _("sh_util_formatted"));

  p = fmt;

  j = 0;
  while (ftab[j].fchar != '\0')
    {
      if (ftab[j].type != S_FMT_STRING)
      ftab[j].data_str = NULL;
      ++j;
    }

  for (j = 0; j < 16; ++j)
    clist[j] = NULL;

  while (p != NULL && *p != '\0' && NULL != (q = strchr(p, '%')))
    {
      ++q;

      /* fprintf(stderr, "p ==  %s   q == %s\n", p, q); */

      /* -- end of string is a '%' --
       */
      if (*q == '\0')
      {
        --q;
        *q = '\0';
        break;
      }

      i = 0;
      j = 0;

      /* -- search the format char in input table --
       * put (nn < 16) here -> all remaining %foo will be
       * converted to %%
       */
      while (ftab[j].fchar != '\0' && nn < 16)
      {
        if (ftab[j].fchar == *q)
          {
            /* -- Convert it to a string format (%s). --
             */
            *q = 's'
;
            i  = 1;
            
            if (ftab[j].type == S_FMT_STRING)
            {
              isiz = sl_strlen(ftab[j].data_str);
              if (isiz > 0)
                {
                  size += isiz;
                  clist[nn] = ftab[j].data_str;
                  ++nn;
                }
              else
                *q = '%';
              break;
            }
            else if (ftab[j].type == S_FMT_ULONG)
            {
              ftab[j].data_str = (char *) SH_ALLOC(64);
              /*@-bufferoverflowhigh@*/
              sprintf (ftab[j].data_str, "%lu",      /* known to fit  */
                     ftab[j].data_ulong);
              /*@+bufferoverflowhigh@*/
              isiz = sl_strlen(ftab[j].data_str);
              if (isiz > 0)
                {
                  size += isiz;
                  clist[nn] = ftab[j].data_str;
                  ++nn;
                }
              else
                *q = '%';
              break;
            }
            else if (ftab[j].type == S_FMT_LONG)
            {
              ftab[j].data_str = (char *) SH_ALLOC(64);
              /*@-bufferoverflowhigh@*/
              sprintf (ftab[j].data_str, "%ld",      /* known to fit  */
                     ftab[j].data_long);
              /*@+bufferoverflowhigh@*/
              isiz = sl_strlen(ftab[j].data_str);
              if (isiz > 0)
                {
                  size += isiz;
                  clist[nn] = ftab[j].data_str;
                  ++nn;
                }
              else
                *q = '%';
              break;
            }
            else if (ftab[j].type == S_FMT_TIME)
            {
              ftab[j].data_str = (char *) SH_ALLOC(64);
                  inpp = (time_t)ftab[j].data_ulong;
              if (inpp != 0)
                {
                  time_ptr = localtime (&(inpp));
                  if (time_ptr != NULL) 
                  (void) strftime(ftab[j].data_str, 64, 
                              _("%d-%m-%Y %H:%M:%S"), time_ptr);
                  else
                  (void) sl_strlcpy(ftab[j].data_str, 
                                _("00-00-0000 00:00:00"), 64);
                }
              else
                {
                  (void) sl_strlcpy(ftab[j].data_str, 
                              _("(None)"), 64);
                }
              isiz = sl_strlen(ftab[j].data_str);
              if (isiz > 0)
                {
                  size += isiz;
                  clist[nn] = ftab[j].data_str;
                  ++nn;
                }
              else
                *q = '%';
              break;
            }

          }
        else
          ++j;
      }

      /* -- not found -- */
      if (i == 0)
      {
        *q = '%';
        p = q;
        ++p;
      }
      else
      {
        p = q;
      }
    }

  /* -- Format string evaluated.
     clist[]   List of strings
     size      Total size of format string + clist[] strings
     -- */
  
  /* -- closing '\0' --
   */
  size++;
  outstr = (char *) SH_ALLOC(size);

  /* -- print it --
   */
  (void) sl_snprintf( outstr, size, fmt,
                  clist[0],  clist[1], clist[2],  clist[3], 
                  clist[4],  clist[5], clist[6],  clist[7], 
                  clist[8],  clist[9], clist[10], clist[11], 
                  clist[12], clist[13], clist[14], clist[15]); 
  
  /* -- cleanup --
   */
  j = 0;
  while (ftab[j].fchar != '\0')
    {
      if (ftab[j].type != S_FMT_STRING && ftab[j].data_str != NULL)
      SH_FREE(ftab[j].data_str);
      ++j;
    }
  SH_FREE(fmt);

  SL_RETURN(outstr, _("sh_util_formatted"));
}

/* can't inline (AIX)
 */
int sh_util_hexchar( char c )
{
  /*@+charint@*/
  if      ( c >= '0' && c <= '9' )
    return c - '0';
  else if ( c >= 'a' && c <= 'f' )
    return c - 'a' + 10;
  else if ( c >= 'A' && c <= 'F' )
    return c - 'A' + 10;
  else return -1;
  /*@-charint@*/
}

/* read a hexadecimal key, convert to binary
 */
int sh_util_hextobinary (char * binary, char * hex, int bytes)
{
  int i = 0, j, k, l = 0;

  SL_ENTER(_("sh_util_hextobinary"));

  while (i < bytes)
    {
      k = sh_util_hexchar(hex[i]); j = sh_util_hexchar(hex[i+1]); 
      if (k != -1 && j != -1) 
        {
          binary[l] = (char)(k * 16 + j);
          ++l; i+= 2;
        }
      else
        {
        SL_RETURN((-1), _("sh_util_hextobinary"));
        }
    }
  
  SL_RETURN((0), _("sh_util_hextobinary"));
}

static void copy_four (unsigned char * dest, UINT32 in)
{
  UINT32 i, j;
  int    count;

  SL_ENTER(_("copy_four"));
  for (count = 0; count < 4; ++count)
    {
      i  = in / 256;
      j  = in - (i*256);
      dest[count] = (unsigned char) j;
      in = i;
    }
  SL_RET0(_("copy_four"));
}

/* compute HMAC-TIGER
 */
static char * sh_util_hmac_tiger (char * hexkey,  
                          char * text, size_t textlen)
{
  static char opad[KEY_BLOCK] = { 
    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, 
    (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C, (char)0x5C
  };
  static char ipad[KEY_BLOCK] = { 
    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36,  
    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36,  
    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36,  
    (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36, (char)0x36
  };
  char        K[KEY_BLOCK];
  char        outer[KEY_BLOCK];
  char      * inner;
  UINT32    * h1;
  UINT32    * h2;
  UINT32      cc[KEY_LEN/4];
  char      * res;

  size_t      i;

  SL_ENTER(_("sh_util_hmac_tiger"));
  ASSERT((KEY_BLOCK <= (KEY_LEN/2)), _("KEY_BLOCK <= (KEY_LEN/2)"))

  if (KEY_BLOCK > (KEY_LEN/2))
    {
      res = sh_tiger_hash (NULL, TIGER_DATA, 0);
      SL_RETURN(res, _("sh_util_hmac_tiger"));
    }

  memset (K, 0x00, KEY_BLOCK);

  if (sh_util_hextobinary (K, hexkey, KEY_LEN) < 0)
    {
      res = sh_tiger_hash (NULL, TIGER_DATA, 0);
      SL_RETURN(res, _("sh_util_hmac_tiger"));
    }

  inner = (char *) SH_ALLOC (textlen + KEY_BLOCK); 

  for (i = 0; i < KEY_BLOCK; ++i)
    {
      outer[i]  = K[i] ^ opad[i];
      inner[i]  = K[i] ^ ipad[i];
    }
  for (i = KEY_BLOCK; i < (KEY_BLOCK+textlen); ++i)
    {
      inner[i] = text[i - KEY_BLOCK];
    }

  /* now compute the hash 
   */
  h1 = sh_tiger_hash_uint32 ( outer,
                        TIGER_DATA,
                        KEY_BLOCK);
  for (i = 0; i < (KEY_LEN/8); ++i)
    {
      /* cc[i] = h1[i]; */
      copy_four ( (unsigned char *) &(cc[i]), h1[i]);
    }

  h2 = sh_tiger_hash_uint32 ( inner,
                        TIGER_DATA,
                        (unsigned long) KEY_BLOCK+textlen);
  for (i = KEY_LEN/8; i < (KEY_LEN/4); ++i)
    {
      copy_four ( (unsigned char *) &(cc[i]), h2[i - (KEY_LEN/8)]);
      /* cc[i] = h2[i - (KEY_LEN/8)]; */
    }
  SH_FREE(inner);
  
  res = sh_tiger_hash ((char *) &cc[0],
                   TIGER_DATA,
                   (unsigned long) (KEY_LEN/4 * sizeof(UINT32)));

  SL_RETURN(res, _("sh_util_hmac_tiger"));
}

static char * sh_util_hash_tiger ( char * hexkey,  
                           char * text, size_t textlen)
{
  char         * res;
  char           h2[2*KEY_LEN+1];
  SL_ENTER(_("sh_util_hash_tiger"));

  (void) sl_strlcpy(h2, hexkey, KEY_LEN+1); 
  (void) sl_strlcat(h2, sh_tiger_hash(text, TIGER_DATA, 
                              (unsigned long) textlen), 2*KEY_LEN+1);

  res = sh_tiger_hash(h2, TIGER_DATA, 2*KEY_LEN);

  SL_RETURN(res, _("sh_util_hash_tiger"));
}

/* --- compute signature on data ---
 */
#define TYPE_HMAC 0
#define TYPE_HASH 1

static int sigtype = TYPE_HMAC;

int sh_util_sigtype (char * c)
{
  SL_ENTER(_("sh_util_sigtype"));
  if (c == NULL)
    SL_RETURN( -1, _("sh_util_sigtype"));

  if (0 == strcmp(_("HMAC-TIGER"), c))
    sigtype = TYPE_HMAC;
  else if  (0 == strcmp(_("HASH-TIGER"), c))
    sigtype = TYPE_HASH;
  else
    SL_RETURN( -1, _("sh_util_sigtype"));

  SL_RETURN( 0, _("sh_util_sigtype"));
}

char * sh_util_siggen (char * hexkey,  
                   char * text, size_t textlen)  
{
  char * p;
  
  SL_ENTER(_("sh_util_siggen"));
  if (sigtype == TYPE_HMAC)
    p = sh_util_hmac_tiger (hexkey,  
                      text, textlen);
  else
    p = sh_util_hash_tiger (hexkey,  
                      text, textlen);
  SL_RETURN(p, _("sh_util_siggen"));
}    

  
 
/* a simple compressor
 */
long sh_util_compress (char * dest, char * src, size_t dest_size)
{
  char * add;
  char * get;
  size_t   count = 0;
  size_t   dest_end;

  SL_ENTER(_("sh_util_compress"));

  if (dest_size == 0)
    SL_RETURN((0), _("sh_util_compress"));
  
  if ((dest == NULL) || (src == NULL))
    SL_RETURN((0), _("sh_util_compress"));
  
  dest_end = sl_strlen(dest);

  if (dest_end > dest_size)
    SL_RETURN((0), _("sh_util_compress"));

  add      = &dest[dest_end];
  get      = src;

  while (count < (dest_size-dest_end))
    {
      if (isalnum((int) *get)) 
      {
        *add = *get;
        ++add;
        ++count;
      }
      ++get; 
      if (*get == '\0' && (count < (dest_size-dest_end))) 
      /* end of src reached */
      {
        *add = *get;  /* copy the '\0'      */
        break;        /* and stop copying   */
      }
    }

  dest[dest_size-1] = '\0'; /* paranoia       */
  SL_RETURN(((long)count), _("sh_util_compress")); /* no of chars copied */    
}


/* copy the four least significant bytes 
 */
void sh_util_cpylong (char * dest, const char * src, int len )
{
  int i, j;
  union
  {
    long l;
    char c[sizeof(long)];
  } u;

  SL_ENTER(_("sh_util_cpylong"));    

  u.l = 1;

  /* MSB is first
   */
  if (sizeof(long)>4 &&/*@+charint@*/(u.c[sizeof(long)-1] == 1)/*@-charint@*/)
    {
      j = (int) (sizeof(long)-4);
      for (i = 0; i < j; ++i) ++src;
    }

  i = 0;

  while (i < 4)
    {
      *dest = (*src);
      ++dest; ++src;
      if (i == (len-1)) break;
      ++i;
    }
  SL_RET0(_("sh_util_cpylong"));
}

/*  This is a maximally equidistributed combined Tausworthe
 *  generator. The sequence is,
 *
 *   x_n = (s1_n ^ s2_n ^ s3_n) 
 *
 *   s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
 *   s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
 *   s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
 *
 *   computed modulo 2^32. In the three formulas above '^' means
 *   exclusive-or (C-notation), not exponentiation. Note that the
 *   algorithm relies on the properties of 32-bit unsigned integers (it
 *   is formally defined on bit-vectors of length 32). 
 *
 *   Stolen from GSL (GNU scientific library) and modified somewhat.
 *   I am using UINT32, which is guaranteed to be 32 bits. Also made
 *   sure that the initialization vector is valid.
 */


/* interval [0, 4294967296]
 */
static UINT32 taus_get_long (void *vstate)
{
  UINT32 * state = (UINT32 *) vstate;

  if (skey->rngI == BAD)
    (void)taus_seed();

#define TAUSWORTHE(s,a,b,c,d) ((s &c) <<d) ^ (((s <<a) ^s) >>b)
  /*@+ignorequals@*/
  state[0] = TAUSWORTHE (state[0], 13, 19, 4294967294UL, 12);
  state[1] = TAUSWORTHE (state[1],  2, 25, 4294967288UL,  4);
  state[2] = TAUSWORTHE (state[2],  3, 11, 4294967280UL, 17);
  /*@-ignorequals@*/
  return (state[0] ^ state[1] ^ state[2]);
}

/* Hide the internal state of the PRNG by using its output as
 * input for a one-way hash function.
 */
UINT32 taus_get (void *state1, void *state2, void *state3)
{
  UINT32   svec[6];
  UINT32   retval;
  UINT32 * res;
  register int i;

  svec[0] = taus_get_long (state1);
  svec[1] = taus_get_long (state2);
  svec[2] = taus_get_long (state3);
  svec[3] = taus_get_long (state1);
  svec[4] = taus_get_long (state2);
  svec[5] = taus_get_long (state3);

  res     = sh_tiger_hash_uint32 ( (char *) &svec[0], 
                           TIGER_DATA, 
                           (unsigned long)(6 * sizeof(UINT32)));

  for (i = 1; i < KEY_BYT/4; ++i)
    res[0] ^= res[i];
  retval = res[0];

  memset (res,  0,            KEY_BYT);
  memset (svec, 0, 6 * sizeof(UINT32));

  return retval;
}

/* interval [0,1)
 */
double taus_get_double (void *vstate)
{
  return taus_get_long (vstate) / (4294967296.0 + 1.0) ;
}

#define LCG(n) ((69069 * n) & 0xffffffffUL)

/* TAKE CARE: state[0], state[1], state[2] must be > 2,8,16, respectively 
 */
static void taus_set_from_ulong (void *vstate, unsigned long int s)
{
  UINT32  *state = (UINT32  *) vstate;

  if (s == 0)
    s = 1;  /* default seed is 1 */

  state[0] = (UINT32)(LCG (s)        | (UINT32) 0x03);
  state[1] = (UINT32)(LCG (state[0]) | (UINT32) 0x09);
  state[2] = (UINT32)(LCG (state[1]) | (UINT32) 0x17);

  /* 'warm up'
   */
  (void) taus_get_long (state);
  (void) taus_get_long (state);
  (void) taus_get_long (state);
  (void) taus_get_long (state);
  (void) taus_get_long (state);
  (void) taus_get_long (state);

  return;
}

static void taus_set_from_state (void *vstate, void *init_state)
{
  UINT32  *state  = (UINT32  *) vstate;
  UINT32  *state0 = (UINT32  *) init_state;

  state[0] = state0[0]  | (UINT32) 0x03;
  state[1] = state0[1]  | (UINT32) 0x09;
  state[2] = state0[2]  | (UINT32) 0x17;
  
  return;
}

 
int taus_seed ()
{
  char                 bufx[9 * sizeof(UINT32) + 1];
  int                  status;
  static unsigned long seed_time = 0;

  SL_ENTER(_("taus_seed"));

  if (skey->rngI == GOOD)
    {
      if ( (sh_unix_longtime () - seed_time) < 3600)
      SL_RETURN( (0), _("taus_seed"));
    }
  
  seed_time = sh_unix_longtime ();

  status = sh_entropy (24, bufx);

  if (!SL_ISERROR(status))
    {
      skey->rngI = GOOD;
      memcpy (&skey->rng0[0], &bufx[0],                  2*sizeof(UINT32));
      memcpy (&skey->rng1[0], &bufx[2*sizeof(UINT32)],   2*sizeof(UINT32));
      memcpy (&skey->rng2[0], &bufx[4*sizeof(UINT32)],   2*sizeof(UINT32));
      memset (bufx, 0, 9 * sizeof(UINT32) + 1);

      skey->rng0[2] = 0;
      skey->rng1[2] = 0;
      skey->rng2[2] = 0;

      taus_set_from_state( &(skey->rng0[0]), &(skey->rng0[0]));
      taus_set_from_state( &(skey->rng1[0]), &(skey->rng1[0]));
      taus_set_from_state( &(skey->rng2[0]), &(skey->rng2[0]));

      SL_RETURN( (0), _("taus_seed"));
    }

  sh_error_handle ((-1), FIL__, __LINE__, status, MSG_ES_ENT,
               _("sh_entropy"));

  /* emergency backup - unsafe !
   */
  skey->rngI = GOOD;
#ifdef HAVE_GETTIMEOFDAY
  taus_set_from_ulong ( &(skey->rng0[0]), LCG (sh_unix_notime())      );
#else
  taus_set_from_ulong ( &(skey->rng0[0]), LCG (seed_time)      );
#endif
  taus_set_from_ulong ( &(skey->rng1[0]), LCG (skey->rng0[0])  );
  taus_set_from_ulong ( &(skey->rng2[0]), LCG (skey->rng1[0])  );
  skey->rngI = BAD;

  SL_RETURN( (-1), _("taus_seed"));
}

/*@+charint@*/
static unsigned char new_key[] = { 0xA7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xA7 };
/*@-charint@*/
static void copy_four (unsigned char * dest, UINT32 in);

int sh_util_set_newkey (char * new)
{
  size_t i, j = 0;
  size_t len;
  SL_TICKET fp;
  SL_TICKET fout;
  char * key;
  char * path;
  char * outpath;
  unsigned char * image = NULL;
  long s = 0;
  long ilen = 0;
  long ii, k = 0;
  UINT32    * h1;

  if (0 != sl_is_suid())
    {
      fprintf(stderr, _("ERROR: insufficient privilege\n"));
      _exit (EXIT_FAILURE);
      /*@notreached@*/
      return -1;  /* braindead MAC OSX compiler needs this */
    }
        
  if (new == NULL || new[0] == '\0')
    {
      fprintf(stderr, 
            _("ERROR: no key given\n Argument must be 'key@path'\n"));
      _exit (EXIT_FAILURE);
      /*@notreached@*/
      return -1;
    }
  key = new;
  len = strlen(new);
  for (i = 1; i < (len-2); ++i)
    {
      if (new[i] == '@' && new[i+1] == '/')
      {
        j = i+1; new[i] = '\0'; break;
      }
    }
  if (j == 0)
    {
      fprintf(stderr, 
            _("ERROR: no path to executable given\n Argument must be 'key@path'\n"));
      _exit (EXIT_FAILURE);
      /*@notreached@*/
      return -1;
    }
  else
    path = &new[j];
  /*@-usedef@*/
  if (NULL == (outpath = malloc(strlen(path) + 1 + 4)))
    goto bail_mem;
  /*@-usedef@*/
  /*@-bufferoverflowhigh@*/
  sprintf (outpath, _("%s.out"), path);               /* known to fit  */ 
  /*@+bufferoverflowhigh@*/

  fp = sl_open_read(path, SL_NOPRIV);
  if (SL_ISERROR(fp))
    {
      fprintf(stderr, 
            _("ERROR: cannot open %s for read\n"), path);
      _exit (EXIT_FAILURE);
      /*@notreached@*/
      return -1;
    }
  
  fout = sl_open_write(outpath, SL_NOPRIV);
  if (SL_ISERROR(fout))
    {
      fprintf(stderr, 
            _("ERROR: cannot open %s\n"), outpath);
      _exit (EXIT_FAILURE);
      /*@notreached@*/
      return -1;
    }


  image = malloc (4096);
  if (!image)
    goto bail_mem;
  while (0 < (ii = sl_read (fp, &image[s], 4096)))
    {
      ilen += ii;
      s    += 4096;
      image = realloc (image, (size_t) (4096 + s));
      if (!image)
      goto bail_mem;
    }

  printf(_("%ld bytes read\n"), ilen);

  
  for (k = 0; k < (ilen - 8); ++k) 
    {
      if (image[k]   == new_key[0] &&
        image[k+1] == new_key[1] &&
        image[k+2] == new_key[2] &&
        image[k+3] == new_key[3] &&
        image[k+4] == new_key[4] &&
        image[k+5] == new_key[5] &&
        image[k+6] == new_key[6] &&
        image[k+7] == new_key[7])
      {
        printf(_("old key found\n")); 
        h1 = sh_tiger_hash_uint32 (key, TIGER_DATA, 
                             (unsigned long)strlen(key));
        copy_four( (unsigned char *) &(image[k]),   h1[0]);
        copy_four( (unsigned char *) &(image[k+4]), h1[1]);
        (void) sl_write (fout, image, ilen);
        (void) sl_close (fout);
        printf(_("new file %s written\n"), outpath);
        _exit (EXIT_SUCCESS);
        /*@notreached@*/
        return 0;
      }
    }

  fprintf(stderr, 
        _("ERROR: old key not found\n"));
  _exit (EXIT_FAILURE);
  /*@notreached@*/
  return -1;


 bail_mem:
  fprintf(stderr, 
        _("ERROR: out of memory\n"));
  _exit (EXIT_FAILURE);
  /*@notreached@*/
  return -1;
}

  

      
/* A simple en-/decoder, based on Vernam cipher. We use the
 * message as salt to hide the key by obtaining a different one-time 
 * pad each time.
 * Should be safe against a listener on the network, but not against someone
 * with read access to the binary.
 */
void sh_util_encode (char * data, char * salt, int mode, char fill)
{
  static char     cc1[17] = N_("0123456789ABCDEF");
  char            cc[17] = "\0";
  register int    i, j, j1 = 0, j2 = 0, j3;
  char          * dez; 

  SL_ENTER(_("sh_util_encode"));

  /* init
   */
  (void) sl_strlcpy( cc, _(cc1), sizeof(cc));

  /* max 128 bits keyspace
   */
  memset (skey->vernam, (int)fill, KEY_LEN+1);

  dez    = (char *) &(skey->ErrFlag[0]);
  sh_util_cpylong (skey->vernam,     dez, 4);
  dez    = (char *) &(skey->ErrFlag[1]);
  sh_util_cpylong (&skey->vernam[4], dez, 4);

  skey->vernam[KEY_LEN] = '\0';

  (void) sl_strlcpy(skey->vernam, 
                sh_tiger_hash(skey->vernam, TIGER_DATA, KEY_LEN), 
                KEY_LEN+1);

  (void) sl_strlcpy(skey->vernam, 
                sh_util_hmac_tiger (skey->vernam, salt, strlen(salt)),
           KEY_LEN+1);

  (void) sl_strlcpy(skey->vernam, 
                sh_util_hmac_tiger (skey->vernam, (char*) new_key, 8),
                KEY_LEN+1);

  /* The following routine adds/subtracts  data[j] and vernam[j] mod 16.
   */
  j = 0;
  while (j < KEY_LEN)
    {
      for (i = 0; i < 16; ++i)
      {
        if (cc[i] == data[j])   j1 = i;
        if (cc[i] == skey->vernam[j])    j2 = i;
      }
      if (mode == 0)
      {
        j3 = j1 + j2;
        if (j3 > 15) j3 -= 16;
        data[j] = cc[j3];
      }
      else
      {
        j3 = j1 - j2;
        if (j3 <  0) j3 += 16;
        data[j] = cc[j3];
      }
      ++j;
    }
  SL_RET0(_("sh_util_encode"));
}

/* server mode 
 */
int sh_util_setserver (char * dummy)
{
  SL_ENTER(_("sh_util_setserver"));

  if (dummy)
    sh.flag.isserver = GOOD;
  else
    sh.flag.isserver = GOOD;
  SL_RETURN((0),_("sh_util_setserver"));
}


int sh_util_setlooptime (char * str)
{
  int i = atoi (str);
  
  SL_ENTER(_("sh_util_setlooptime"));

  if (i >= 0 && i < INT_MAX) {
    sh.looptime = i;
    SL_RETURN((0),_("sh_util_setlooptime"));
  } else {
    sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
                 _("loop time"), str);
    SL_RETURN((-1),_("sh_util_setlooptime"));
  }
}

#if defined (SH_WITH_CLIENT) || defined (SH_STANDALONE)
int  sh_util_setchecksum (char * str)
{
  static int reject = 0;

  SL_ENTER(_("sh_util_setchecksum"));

  if (reject == 1)
    SL_RETURN((0), _("sh_util_setchecksum"));
  reject = 1;

  if (sl_strncmp (str, _("init"), sizeof("init")-1) == 0)
    sh.flag.checkSum = SH_CHECK_INIT;
  else if (sl_strncmp (str, _("check"), sizeof("check")-1) == 0)
    sh.flag.checkSum = SH_CHECK_CHECK;
  else if (sl_strncmp (str, _("update"), sizeof("update")-1) == 0)
    {
      sh.flag.checkSum = SH_CHECK_INIT;
      sh.flag.update   = S_TRUE;
    }
  else if (sl_strncmp (str, _("none"), sizeof("none")-1) == 0)
    sh.flag.checkSum = SH_CHECK_NONE;
  else {
    sh_error_handle ((-1), FIL__, __LINE__, EINVAL, MSG_EINVALS,
                 _("checksum testing"), str);
    SL_RETURN((-1), _("sh_util_setchecksum"));
  }
  SL_RETURN((0), _("sh_util_setchecksum"));
}
#endif
 
/*@+charint@*/
unsigned char TcpFlag[8][PW_LEN+1] = { 
#if (POS_TF == 1)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
#if (POS_TF == 2)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
#if (POS_TF == 3)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
#if (POS_TF == 4)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
#if (POS_TF == 5)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
#if (POS_TF == 6)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
#if (POS_TF == 7)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
  { 0xFF,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xFF,0x00 },
#if (POS_TF == 8)
  { 0xF7,0xC3,0x12,0xAA,0xAA,0x12,0xC3,0xF7,0x00 },
#endif
};
/*@-charint@*/

/* initialize a key to a random value
 * rev 0.8
 */
int sh_util_keyinit (char * buf, long size)
{
  UINT32       bufy[6];
  int          i;
  int          status = 0;
  char       * p;

  SL_ENTER(_("sh_util_keyinit"));

  ASSERT((size <= KEY_LEN+1), _("size <= KEY_LEN+1"))

  if (size > KEY_LEN+1)
    size = KEY_LEN+1;

  /* seed / re-seed the PRNG if required
   */
  status = taus_seed ();

  if (status == -1)
    sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_ES_KEY1,
                 _("taus_seed"));

  for (i = 0; i < 6; ++i)
    bufy[i] = taus_get(&(skey->rng0[0]), &(skey->rng1[0]), &(skey->rng2[0]));

  p = sh_tiger_hash ((char *) bufy, TIGER_DATA, 
                 (unsigned long)(6*sizeof(UINT32)));
  p[size-1] = '\0';

  i = sl_strlcpy(buf, p, (size_t)size);

  memset (bufy, 0, 6*sizeof(UINT32));

  if ((status == 0) && (!SL_ISERROR(i)) )
    SL_RETURN((0),_("sh_util_keyinit"));

  if (SL_ISERROR(i))
    sh_error_handle ((-1), FIL__, __LINE__, i, MSG_ES_KEY2, 
                 _("sl_strlcpy"));

  SL_RETURN((-1),_("sh_util_keyinit"));
}

#if defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)

static unsigned char sh_obscure_index[256];

int sh_util_obscure_ok (char * str)
{
  unsigned long   i;
  char * endptr = str;

  SL_ENTER(_("sh_util_obscure_ex"));

  if (0 == sl_strncmp("all", str, 3))
    {
      for (i = 0; i < 255; ++i)
      {
        sh_obscure_index[i] = (unsigned char)1;
      }
      SL_RETURN(0, _("sh_util_obscure_ex"));
    }

  for (i = 0; i < 255; ++i)
    {
      sh_obscure_index[i] = (unsigned char)0;
    }

  while (*endptr != '\0')
    {
      i = strtoul (endptr, &endptr, 0);
      if (i > 255)
      {
        SL_RETURN(-1, _("sh_util_obscure_ex"));
      }
      sh_obscure_index[i] = (unsigned char)1;
      if (*endptr == ',')
      ++endptr;
    }
  SL_RETURN(0, _("sh_util_obscure_ex"));
}

int sh_util_obscurename (ShErrLevel level, char * name_orig, int flag)
{
  char * name = name_orig;
  char * safe;
  unsigned int i;

  SL_ENTER(_("sh_util_obscurename"));

  ASSERT_RET((name != NULL), _("name != NULL"), (0))

  /* -- Check name. --
   */
  while (*name != '\0') 
    {
      if ( (*name) == '"'  || (*name) == '\t' ||
         (*name) == '\b' || (*name) == '\f' || 
         (*name) == '\n' || (*name) == '\r' ||
         (*name) == '\v' || iscntrl((int) *name) || 
         ((*name) != ' ' && !isgraph ((int) *name)) ) 
      {
        i = (unsigned char) *name;
        if (sh_obscure_index[i] != (unsigned char)1)
          {
            if (flag == S_TRUE)
            {
              safe = sh_util_safe_name (name_orig);  
              sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_OBSC, 
                           safe);
              SH_FREE(safe);
            }
            SL_RETURN((-1),_("sh_util_obscurename"));
          }
      }
      name++;
    }

  SL_RETURN((0),_("sh_util_obscurename"));
}
#endif

/* returns freshly allocated memory, return value should be free'd
 */
char * sh_util_basename(char * fullpath)
{
  char * retval;
  size_t i;

  SL_ENTER(_("sh_util_basename"));

  ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))

  i = sl_strlen (fullpath);  /* fullpath[i] is terminating '\0' */

  while (i > 0) {
    --i;
    if (fullpath[i] == '/') break;
  }

  /* -- Not a valid path. --
   */
  if ((fullpath[i] != '/') && (i == 0) ) 
    SL_RETURN(NULL, _("sh_util_basename"));

  retval = SH_ALLOC(i + 1);

  (void) sl_strlcpy (retval, fullpath, i+1);

  SL_RETURN(retval, _("sh_util_basename"));
}

/* returns freshly allocated memory, return value should be free'd
 */
char * sh_util_filename(char * fullpath)
{
  char * retval;
  char * c;
  size_t i;

  SL_ENTER(_("sh_util_filename"));

  ASSERT_RET ((fullpath != NULL), _("fullpath != NULL"), (NULL))

  c = strrchr(fullpath, '/');
  i = sl_strlen (c);
  if (i <= 1) SL_RETURN(NULL, _("sh_util_filename")); /* ends in '/' */
  ++c;
  --i;

  retval = SH_ALLOC(i + 1);

  (void) sl_strlcpy (retval, c, i+1);

  SL_RETURN(retval, _("sh_util_filename"));
}

    
/* returns freshly allocated memory, return value should be free'd
 */
char * sh_util_safe_name (const char * name)
{
  register int  i = 0;
  const char  * p;
  char        * retval;
  char          oct[32];
  char          format[16];

  SL_ENTER(_("sh_util_safe_name"));

  if (name == NULL)
    {
      /* return an allocated array
       */
      retval = SH_ALLOC(7);
      (void) sl_strlcpy(retval, _("(null)"), 7);
      SL_RETURN(retval, _("sh_util_safe_name"));
    }

  /*
  ASSERT_RET ((name != NULL), _("name != NULL"), _("NULL"))
  */

#ifdef SH_USE_XML
  retval = SH_ALLOC(6 * sl_strlen(name) + 2);
#else
  retval = SH_ALLOC(4 * sl_strlen(name) + 2);
#endif 

  (void) sl_strncpy(format, _("%c%03o"), 16);

  p = name;

  while (*p != '\0') {
    /* Most frequent cases first
     */
    if ( ((*p) >= 'a' && (*p) <= 'z')  || ((*p) == '/') || ((*p) == '.') ||
       ((*p) >= '0' && (*p) <= '9')  || 
       ((*p) >= 'A' && (*p) <= 'Z')) {
      retval[i] = *p; 
    } else if ( (*p) == '\\') {           /* backslash        */
      retval[i] = '\\'; ++i; 
      retval[i] = '\\';
    } else if ( (*p) == '\n') {    /* newline          */
      retval[i] = '\\'; ++i; 
      retval[i] = 'n';
    } else if ( (*p) == '\b') {    /* backspace        */
      retval[i] = '\\'; ++i; 
      retval[i] = 'b';
    } else if ( (*p) == '\r') {    /* carriage  return */
      retval[i] = '\\'; ++i; 
      retval[i] = 'r';
    } else if ( (*p) == '\t') {    /* horizontal tab   */
      retval[i] = '\\'; ++i; 
      retval[i] = 't';
    } else if ( (*p) == '\v') {    /* vertical tab     */
      retval[i] = '\\'; ++i; 
      retval[i] = 'v';
    } else if ( (*p) == '\f') {    /* form-feed        */
      retval[i] = '\\'; ++i; 
      retval[i] = 'f';
#ifdef WITH_DATABASE
    } else if ( (*p) == '\'') {    /* single quote     */
      retval[i] = '\\'; ++i; 
      retval[i] = '\'';
#endif
    } else if ( (*p) == ' ') {     /* space            */
      retval[i] = '\\'; ++i; 
      retval[i] = ' ';
#ifdef SH_USE_XML
    } else if ( (*p) == '"') {     /* double quote     */
      retval[i] = '&'; ++i; 
      retval[i] = 'q'; ++i;
      retval[i] = 'u'; ++i;
      retval[i] = 'o'; ++i;
      retval[i] = 't'; ++i;
      retval[i] = ';';
    } else if ( (*p) == '&') {     /* ampersand        */
      retval[i] = '&'; ++i; 
      retval[i] = 'a'; ++i;
      retval[i] = 'm'; ++i;
      retval[i] = 'p'; ++i;
      retval[i] = ';';
    } else if ( (*p) == '<') {     /* left angle       */
      retval[i] = '&'; ++i; 
      retval[i] = 'l'; ++i;
      retval[i] = 't'; ++i;
      retval[i] = ';';
    } else if ( (*p) == '>') {     /* right angle      */
      retval[i] = '&'; ++i; 
      retval[i] = 'g'; ++i;
      retval[i] = 't'; ++i;
      retval[i] = ';';
#else
    } else if ( (*p) == '"') {     /* double quote     */
      retval[i] = '\\'; ++i; 
      retval[i] = '\"';
#endif
    } else if (!isgraph ((int) *p)) {    /* not printable    */
      /*@-bufferoverflowhigh -formatconst@*/
      sprintf(oct, format, '\\',                 /* known to fit  */
            (unsigned char) *p);
      /*@+bufferoverflowhigh +formatconst@*/
      retval[i] = oct[0]; ++i;
      retval[i] = oct[1]; ++i;
      retval[i] = oct[2]; ++i;
      retval[i] = oct[3]; 
    } else {
      retval[i] = *p;
    }
    ++p;
    ++i;
  }
  retval[i] = '\0';
  SL_RETURN(retval, _("sh_util_safe_name"));
}

int sh_util_isnum (char *str)
{
  char *p = str;

  SL_ENTER(_("sh_util_isnum"));

  ASSERT_RET ((str != NULL), _("str != NULL"), (-1))

  while (p) {
    if (!isdigit((int) *p) ) 
      SL_RETURN((-1), _("sh_util_isnum"));
    ++p;
  }
  SL_RETURN((0), _("sh_util_isnum"));
}

char * sh_util_strconcat (const char * arg1, ...)
{
  size_t    length;
  char    * s;
  char    * strnew;
  va_list vl;

  SL_ENTER(_("sh_util_strconcat"));

  ASSERT_RET ((arg1 != NULL), _("arg1 != NULL"), (NULL))

  length = sl_strlen (arg1) + 1;

  va_start (vl, arg1);
  s = va_arg (vl, char * );
  while (s != NULL)
    {
      length = length + sl_strlen (s);
      s = va_arg (vl, char * );
    }
  va_end (vl);

  strnew = SH_ALLOC( length + 2 ); 
  strnew[0] = '\0';

  (void) sl_strlcpy (strnew, arg1, length + 2); 

  va_start (vl, arg1);
  s = va_arg (vl, char * );
  while (s)
    {
      (void) sl_strlcat (strnew, s, length + 2);
      s = va_arg (vl, char * );
    }
  va_end (vl);

  SL_RETURN(strnew, _("sh_util_strconcat"));
}


#ifdef HAVE_REGEX_H

#include <regex.h>

int sh_util_regcmp (char * regex_str, char * in_str)
{
#if defined(REG_ESPACE)
  int        status = REG_ESPACE;
#else
  int        status = -1;
#endif
  regex_t    preg;
  char     * errbuf;

  SL_ENTER(_("sh_util_regcmp"));

  status = regcomp(&preg, regex_str, REG_NOSUB|REG_EXTENDED);

  if (status == 0)
    {
      if ((status = regexec(&preg, in_str, 0, NULL, 0)) == 0) 
      {
        regfree (&preg);
        SL_RETURN((0), _("sh_util_regcmp"));
      }
    }

  if (status != 0 && status != REG_NOMATCH) 
    {
      errbuf = SH_ALLOC(BUFSIZ+2);
      (void) regerror(status, &preg, errbuf, BUFSIZ); 
      errbuf[BUFSIZ] = '\0';
      sh_error_handle ((-1), FIL__, __LINE__, status, MSG_E_REGEX,
                   errbuf, regex_str);
      SH_FREE(errbuf);
    }
      
  regfree (&preg);
  SL_RETURN((-1), _("sh_util_regcmp"));
}

#endif









Generated by  Doxygen 1.6.0   Back to index