#if !defined(lint) && !defined(__INSIGHT__)
static char sos__rcsid[] = "subint.c,v 1.1.1.1 1995/06/16 21:10:48 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--
 */

/*
 * Internal functions to check data against
 * ACL permissions internally known
 */

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



/*
 * Recurse and loop over the group list to check permissions
 */
int
CheckGroup(char *metaname, struct timeinfo_t date, int epoch,
	   struct in_addr srcaddr, unsigned short srcserv,
	   struct in_addr dstaddr, unsigned short dstserv)
{
  int retval;
  struct FirstLevel_t *fl;
  dict_h linklist;
  struct groupinfo_t *cur;
  struct element_t *elem;

  dprintf("  Checking key %s\n",metaname);

  if (!(metaname) || ((fl = (struct FirstLevel_t *)ht_search(GroupTbl,metaname)) == NULL))
    {
      sprintf(bs_auth_extended,"Group %s is invalid",metaname);
      return(AUTH_FAIL);
    }
  linklist = fl->info;

  /* linked list is a LIFO, but we want FIFO, so we will check from the end */
  for (elem = (struct element_t *)dll_maximum(linklist);elem != NULL;elem = (struct element_t *)dll_predecessor(linklist,elem))
    {
      if (elem->meta)
	{			/* Indirect */
	  retval = CheckGroup(elem->ptr.meta,date,epoch,srcaddr,srcserv,dstaddr,dstserv);
	  switch (retval)
	    {
	    case AUTH_FAIL:
	    case AUTH_ERROR:
	      return(retval);
	    case AUTH_SUCCEED:
	      return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
	    case AUTH_CONTINUE:
	      continue;
	    }
	  abort();		/* Should never get here */
	}

      /* Direct entry */
      cur = elem->ptr.group;

      /* Check time */
      retval=CheckTime(cur->metatime,date);
      if (retval != AUTH_ERROR) sprintf(bs_auth_extended,"Connection not allowed now.");
      switch (retval)
	{
	case AUTH_FAIL:
	case AUTH_ERROR:
	  return(retval);
	case AUTH_CONTINUE:
	  continue;
	case AUTH_SUCCEED:
	  if (elem->neg) return(AUTH_FAIL);
	}
      dprintf("I got %d back from CheckTime\n",retval);
      
      /* Check date */
      retval=CheckDate(cur->metadate,epoch);
      if (retval != AUTH_ERROR) sprintf(bs_auth_extended,"Connection not allowed today.");
      switch (retval)
	{
	case AUTH_FAIL:
	case AUTH_ERROR:
	  return(retval);
	case AUTH_CONTINUE:
	  continue;
	case AUTH_SUCCEED:
	  if (elem->neg) return(AUTH_FAIL);
	}
      dprintf("I got %d back from CheckDate\n",retval);
      
      /* Check src addr */
      retval=CheckAddr(cur->srcmetaaddr,srcaddr);
      if (retval != AUTH_ERROR) sprintf(bs_auth_extended,"Connection not allowed from this address.");
      switch (retval)
	{
	case AUTH_FAIL:
	case AUTH_ERROR:
	  return(retval);
	case AUTH_CONTINUE:
	  continue;
	case AUTH_SUCCEED:
	  if (elem->neg) return(AUTH_FAIL);
	}
      dprintf("I got %d back from CheckAddr\n",retval);
      
      /* Check src service */
      retval=CheckServ(cur->srcmetaserv,srcserv);
      if (retval != AUTH_ERROR) sprintf(bs_auth_extended,"Connection not allowed from this port.");
      switch (retval)
	{
	case AUTH_FAIL:
	case AUTH_ERROR:
	  return(retval);
	case AUTH_CONTINUE:
	  continue;
	case AUTH_SUCCEED:
	  if (elem->neg) return(AUTH_FAIL);
	}
      dprintf("I got %d back from CheckAddr\n",retval);
      
      /* Check dst addr */
      retval=CheckAddr(cur->dstmetaaddr,dstaddr);
      if (retval != AUTH_ERROR) sprintf(bs_auth_extended,"Connection not allowed to this address.");
      switch (retval)
	{
	case AUTH_FAIL:
	case AUTH_ERROR:
	  return(retval);
	case AUTH_CONTINUE:
	  continue;
	case AUTH_SUCCEED:
	  if (elem->neg) return(AUTH_FAIL);
	}
      dprintf("I got %d back from CheckAddr\n",retval);
      
      /* Check dest service */
      retval=CheckServ(cur->dstmetaserv,dstserv);
      if (retval != AUTH_ERROR) sprintf(bs_auth_extended,"Connection not allowed to this port.");
      switch (retval)
	{
	case AUTH_FAIL:
	case AUTH_ERROR:
	  return(retval);
	case AUTH_CONTINUE:
	  continue;
	case AUTH_SUCCEED:
	  if (elem->neg) return(AUTH_FAIL);
	}
      dprintf("I got %d back from CheckAddr\n",retval);
      
      return (AUTH_SUCCEED);
    }

  /* Nothing here.  Try to go onward... */
  sprintf(bs_auth_extended,"I dunno");
  return(AUTH_CONTINUE);
}



/*
 * Check to see if the times allowed by this entry match
 *
 * recursion is your friend!
 */
int
CheckTime(char *metaname, struct timeinfo_t time)
{
  dict_h linklist;
  struct timeinfo_t *cur;
  struct element_t *elem;
  struct FirstLevel_t *fl;
  int retval;

  dprintf("  Checking key %s against %x %x\n",metaname,time.day,time.hour);

  /* MAGIC COOKIE */
  if (!strcmp(metaname,"ANY"))
    return(AUTH_SUCCEED);

  if (!(metaname) || ((fl = (struct FirstLevel_t *)ht_search(TimeTbl,metaname)) == NULL))
    {
      sprintf(bs_auth_extended,"Time %s is invalid",metaname);
      return(AUTH_FAIL);
    }
  linklist = fl->info;

  /* linked list is a LIFO, but we want FIFO, so we will check from the end */
  for (elem = (struct element_t *)dll_maximum(linklist);elem != NULL;elem = (struct element_t *)dll_predecessor(linklist,elem))
    {
      if (elem->meta)
	{			/* Indirect */
	  retval = CheckTime(elem->ptr.meta,time);
	  switch (retval)
	    {
	    case AUTH_FAIL:
	    case AUTH_ERROR:
	      return(retval);
	    case AUTH_SUCCEED:
	      return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
	    case AUTH_CONTINUE:
	      continue;
	    }
	  abort();		/* Should never get here */
	}

      /* Direct entry */
      cur = elem->ptr.time;

      if (((time.day & cur->day) == time.day) &&
	  ((time.hour & cur->hour) == time.hour))
	return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
    }

  return(AUTH_CONTINUE);
}



/*
 * Check to see if the dates allowed by this entry match
 *
 * recursion is your friend!
 */
int
CheckDate(char *metaname, int date)
{
  dict_h linklist;
  struct dateinfo_t *cur;
  struct element_t *elem;
  struct FirstLevel_t *fl;
  int retval;

  dprintf("  Checking key %s against %d\n",metaname,date);

  /* MAGIC COOKIE */
  if (!strcmp(metaname,"ANY"))
    return(AUTH_SUCCEED);

  if (!(metaname) || ((fl = (struct FirstLevel_t *)ht_search(DateTbl,metaname)) == NULL))
    {
      sprintf(bs_auth_extended,"Date %s is invalid",metaname);
      return(AUTH_FAIL);
    }
  linklist = fl->info;

  /* linked list is a LIFO, but we want FIFO, so we will check from the end */
  for (elem = (struct element_t *)dll_maximum(linklist);elem != NULL;elem = (struct element_t *)dll_predecessor(linklist,elem))
    {
      if (elem->meta)
	{			/* Indirect */
	  retval = CheckDate(elem->ptr.meta,date);
	  switch (retval)
	    {
	    case AUTH_FAIL:
	    case AUTH_ERROR:
	      return(retval);
	    case AUTH_SUCCEED:
	      return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
	    case AUTH_CONTINUE:
	      continue;
	    }
	  abort();		/* Should never get here */
	}

      /* Direct entry */
      cur = elem->ptr.date;

      if (cur->days == date)
	return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
    }

  return(AUTH_CONTINUE);
}



/*
 * Check to see if the addrs allowed by this entry match
 *
 * recursion is your friend!
 */
int
CheckAddr(char *metaname, struct in_addr addr)
{
  dict_h linklist;
  struct addrinfo_t *cur;
  struct element_t *elem;
  struct FirstLevel_t *fl;
  int retval;

  dprintf("  Checking key %s against %x\n",metaname,addr);

  /* MAGIC COOKIE */
  if (!strcmp(metaname,"ANY"))
    return(AUTH_SUCCEED);

  if (!(metaname) || ((fl = (struct FirstLevel_t *)ht_search(AddrTbl,metaname)) == NULL))
    {
      sprintf(bs_auth_extended,"Addr %s is invalid",metaname);
      return(AUTH_FAIL);
    }
  linklist = fl->info;

  /* linked list is a LIFO, but we want FIFO, so we will check from the end */
  for (elem = (struct element_t *)dll_maximum(linklist);elem != NULL;elem = (struct element_t *)dll_predecessor(linklist,elem))
    {
      if (elem->meta)
	{			/* Indirect */
	  retval = CheckAddr(elem->ptr.meta,addr);
	  switch (retval)
	    {
	    case AUTH_FAIL:
	    case AUTH_ERROR:
	      return(retval);
	    case AUTH_SUCCEED:
	      return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
	    case AUTH_CONTINUE:
	      continue;
	    }
	  abort();		/* Should never get here */
	}

      /* Direct entry */
      cur = elem->ptr.addr;

      if ((cur->Primary.s_addr & cur->Mask.s_addr) == (addr.s_addr & cur->Mask.s_addr))
	return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
    }

  return(AUTH_CONTINUE);
}



/*
 * Check to see if the servs allowed by this entry match
 *
 * recursion is your friend!
 */
int
CheckServ(char *metaname, unsigned short serv)
{
  dict_h linklist;
  struct servinfo_t *cur;
  struct element_t *elem;
  struct FirstLevel_t *fl;
  int retval;

  dprintf("  Checking key %s against %d\n",metaname,serv);

  /* MAGIC COOKIE */
  if (!strcmp(metaname,"ANY"))
    return(AUTH_SUCCEED);

  if (!(metaname) || ((fl = (struct FirstLevel_t *)ht_search(ServTbl,metaname)) == NULL))
    {
      sprintf(bs_auth_extended,"Serv %s is invalid",metaname);
      return(AUTH_FAIL);
    }
  linklist = fl->info;

  /* linked list is a LIFO, but we want FIFO, so we will check from the end */
  for (elem = (struct element_t *)dll_maximum(linklist);elem != NULL;elem = (struct element_t *)dll_predecessor(linklist,elem))
    {
      if (elem->meta)
	{			/* Indirect */
	  retval = CheckServ(elem->ptr.meta,serv);
	  switch (retval)
	    {
	    case AUTH_FAIL:
	    case AUTH_ERROR:
	      return(retval);
	    case AUTH_SUCCEED:
	      return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
	    case AUTH_CONTINUE:
	      continue;
	    }
	  abort();		/* Should never get here */
	}

      /* Direct entry */
      cur = elem->ptr.serv;

      if (cur->service == serv)
	return(elem->neg?AUTH_FAIL:AUTH_SUCCEED);
    }

  return(AUTH_CONTINUE);
}
