#if !defined(lint) && !defined(__INSIGHT__)
static char sos__rcsid[] = "readconf.c,v 1.1.1.1 1995/06/16 21:10:47 seth Exp";
static char sos__copyright[] = "Copyright (c) 1994, 1995 SOS Corporation";
static char sos__contact[] = "SOS Corporation <sos-info@soscorp.com> +1 800 SOS UNIX";
#endif /* not lint */

/*
 * ++Copyright Released Product++
 *
 * Copyright (c) 1994, 1995 Sources of Supply Corporation ("SOS").
 * All rights reserved.
 *
 * The SOS Released Product License Agreement specifies the terms and
 * conditions for redistribution.  You may find the License Agreement
 * in the file LICENSE.
 *
 * SOS Corporation
 * 461 5th Ave.; 16th floor
 * New York, NY 10017
 *
 * +1 800 SOS UNIX
 * <sos-info@soscorp.com>
 *
 * --Copyright Released Product--
 */

/*
 * Parse the configuration file with lex and yacc
 * (plus other minor functions used by same)
 */

#include "interface.h"
#include "readconf.h"

extern int yyparse();

char *startfile = "stdin";
char *configfile = NULL;

/* Defaults for hash trees */
struct ht_args TimeSize = { 64, 1, phashfstr, hashfstr };
struct ht_args DateSize = { 64, 1, phashfstr, hashfstr };
struct ht_args AddrSize = { 256, 1, phashfstr, hashfstr };
struct ht_args ServSize = { 32, 1, phashfstr, hashfstr };
struct ht_args GroupSize = { 256, 1, phashfstr, hashfstr };
struct ht_args UserSize = { 512, 1, phashfstr, hashfstr };
struct ht_args FileSize = { 2, 1, phashfstr, hashfstr };


/* Hash trees */
dict_h TimeTbl, DateTbl, AddrTbl, ServTbl, GroupTbl, UserTbl, FileTbl;

static configinit=0;



/*
 * Check to see if we have read the configuration file
 */
int
bs_isconfig()
{
  return(configinit);
}



/*
 * Set the variables so that the configuration file will be reloaded
 */
int
resetconfiginit()
{
  return(configinit = 0);
}



/*
 * Read the configuration file if necessary
 */
int
readconfig(char *userfile)
{
  int retval;

  if ( configinit ) return(AUTH_SUCCEED);

  if (userfile)
    {
      configfile = userfile;
    }
  else
    {
      configfile = SOS_ENV_GWD(BS_ACL_CONF_ENV,BS_ACL_CONF);
    }

  startfile = configfile;

  if ((yyin = fopen(configfile,"r")) == NULL)
    {
      sprintf(bs_auth_extended,"Config file (%s) cannot be opened (%d)",configfile,errno);
      return(AUTH_ERROR);
    }

  /* Add base configuration file to list of files to be checked for changes */
  if ((retval = initFiles(configfile)) != AUTH_SUCCEED)
    {
      return(retval);
    }

  /* Parse config */
  if (yyparse())
    {
      retval = AUTH_ERROR;
    }
  else
    {
      retval = AUTH_SUCCEED;
    }

  if (fclose(yyin))
    {
      sprintf(bs_auth_extended,"Config file cannot be closed (%d)",errno);
      return(AUTH_ERROR);
    }

  if (retval == AUTH_SUCCEED)
    configinit = 1;

  return(retval);
}



/*
 * Create new files database
 */
int initFiles(char *name)
{
  int retval;

  if (FileTbl && (retval = unlinkFiles()) != AUTH_SUCCEED)
    {
      return(retval);
    }

  FileTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&FileSize);
  FileSize.ht_table_entries = 0;

  if ((retval = AddFiles(name)) != AUTH_SUCCEED)
    {
      return(retval);
    }

  return(AUTH_SUCCEED);
}



/*
 * Add a file to the list of files being checked for modifications
 */
int AddFiles(char *name)
{
  struct fileinfo_t *fi;

  if ((fi = (struct fileinfo_t *)malloc(sizeof(struct fileinfo_t))) == NULL)
    {
      sprintf(bs_auth_extended,"Out of memory %d",errno);
      return(AUTH_ERROR);
    }

  if (stat(name,&(fi->buf)) < 0)
    {
      sprintf(bs_auth_extended,"Could not stat file %s (%d)",name,errno);
      return(AUTH_ERROR);
    }

  fi->file = strdup(name);

  if (ht_insert_uniq(FileTbl,fi,NULL) == DICT_ERR)
    {
      sprintf(bs_auth_extended,"We have already loaded file %s (%d)",name,dict_errno);
      return(AUTH_ERROR);
    }

  FileSize.ht_table_entries++;

  return(AUTH_SUCCEED);
}



/*
 * Use Sedgewick simple hash function
 *
 * (for CLC sorting)
 */
ht_val phashfstr(char **a) { return(hashfstr(*a)); }
ht_val hashfstr(char *a)
{
  ht_val ret;
  const unsigned int M = (unsigned)2147486459U; /* Arbitrary large prime */
  int h;

  dprintf(" Mashing %x %s %d\n",a,a,strlen(a));

  for(h = 0; *a; a++)
    h = ( h + *a ) % M;

  memcpy(&ret,&h,sizeof(ret));

  return(ret);
}



/*
 * Debugging printf
 */
int
dprintf(const char *fmt, ...)
{
#ifdef DEBUG
  va_list	args;

  if (!bs_debug) return(0);

  va_start(args,fmt);
  vfprintf(stderr,fmt,args);
  va_end(args);
  return(0);
#else
  return(0);
#endif
}



/*
 * hour2bit -- go from hour number into bitmask
 *
 * hourmask is exclusive on the right [a-b)
 *
 * Internal function for YACC
 */
int hour2bit(int a, int b)
{
  int ret = 0;
  int count;

  dprintf("Hours2bit %d %d (%d)\n",a,b,1<<a);

  /* Check for sane hours */
  if (a < 0 || a > 24 || b > 24)
    {
      sprintf(bs_auth_extended,"Hour in day range is from 0 to 24 (%d,%d)",a,b);
      return(AUTH_ERROR);
    }

  /* If it is one hour, fastpath it */
  if (b < 0)
    return (htonl(1<<a));

  /*
   * Start at the beginning and mark every hour as valid
   * until we get to the last hour.  Note that the final
   * hour is NOT counted
   */
  for(count = a; count != b; count++)
    {
      /* wrap around */
      if (count > 23)
	{
	  count = 0;
	  if (count == b)
	    break;
	}

      ret |= (1<<count);
    }

  return(htonl(ret));
}



/*
 * day2bit -- go from day number into bitmask
 *
 * daymask is inclusive [a-b]
 *
 * Sunday is zero
 *
 * Internal function for YACC
 */
int days2bit(int a, int b)
{
  int ret = 0;
  int count;

  dprintf("Day2bit %d %d (%d)\n",a,b,1<<a);
  
  /* Check for sane day numbers */
  if (a < 0 || a > 6 || b > 6)
    {
      sprintf(bs_auth_extended,"Day of week range is from 0 to 6 (%d,%d)",a,b);
      return(AUTH_ERROR);
    }

  /* fastpath if we only have one day */
  if (b < 0)
    return (htonl(1<<a));

  /*
   * Start at the beginning and mark every day as valid
   * until we get to the last day.  Note that the final
   * day IS counted
   */
  for(count = a; count != b; count++)
    {
      /* handle wraparound */
      if (count > 6)
	{
	  count = 0;
	  if (count == b)
	    break;
	}

      ret |= (1<<count);
    }
  ret |= (1<<count);		/* With day, we include the last day */

  return(htonl(ret));
}



/*
 * Create a null config file
 *
 * Note: this is not as useful as you might think (if, indeed
 * you think so).  The configuration file generated when you
 * copyout this struct is not valid.  This is just a starting
 * place.
 */
int
nullconfig()
{
  int retval;

  if ( configinit ) return(AUTH_SUCCEED);

  startfile = configfile = "/dev/zero";

  /* Add base configuration file to list of files to be checked for changes */
  if ((retval = initFiles(configfile)) != AUTH_SUCCEED)
    {
      return(retval);
    }

  TimeTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&TimeSize);
  TimeSize.ht_table_entries = 0;
  
  DateTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&DateSize);
  DateSize.ht_table_entries = 0;
  
  AddrTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&AddrSize);
  AddrSize.ht_table_entries = 0;
  
  ServTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&ServSize);
  ServSize.ht_table_entries = 0;
  
  GroupTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&GroupSize);
  GroupSize.ht_table_entries = 0;

  UserTbl = ht_create(mystrcmp,mykeycmp,DICT_UNIQUE_KEYS,NULL,&UserSize);
  UserSize.ht_table_entries = 0;

  configinit = 1;
  return(AUTH_SUCCEED);
}



/*
 * Compare two pointers to strings
 *
 * Function for CLC sorting
 */
int
mystrcmp(char **a, char **b)
{
#if 0
  int ret = strcmp(*a,*b);
  printf("--Compare %s %s -> %d\n",*a,*b,ret);
#endif
  return(strcmp(*a,*b));
}



/*
 * Compare a string with a pointer to a string
 *
 * Function for CLC sorting
 */
int
mykeycmp(char *a, char **b)
{
#if 0
  int ret = strcmp(a,*b);
  printf("--Compare %s %s -> %d\n",a,*b,ret);
#endif
  return(strcmp(a,*b));
}
