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

/*
 * Check connections for invalid hosts
 */

#include "sos.h"
#include "dll.h"


#define MATCH(nm, test) (((nm)->addr.s_addr & (nm)->mask.s_addr) == ((test.s_addr) & (nm)->mask.s_addr))

#ifdef DEBUG
extern char *program;
char libsos_information[8192];
#define LIBSOS_LOG(x) sprintf(libsos_information,"%s: %s: %s\n",program, (x), strerror(errno))
#else
#define LIBSOS_LOG(x) ((void)(x))
#endif


/*
 * Initialize SecureNet information
 */
SOS_Snets
sos_InitSecureNets()
{
  SOS_Snets *new;

  new = dll_create(NULL, NULL, DICT_UNORDERED, NULL);

  return(new);
}



/*
 * External routine to get rid of SecureNet information
 */
void
sos_FreeSecureNets(SOS_Snets old)
{
  dict_obj llcur;

  if (old)
    {
      for(llcur = dll_maximum(old);llcur != NULL;llcur = dll_maximum(old))
	{
	  dll_delete(old, llcur);
	  free(llcur);		/* Free data */
	}
      dll_destroy(old);
    }
}



/*
 * Add a good or bad netmask to the SecureNet info
 */
int
sos_AddSecureNets(SOS_Snets snets, struct sos_netmask *mask)
{

  if (!snets || !mask)
    {
      LIBSOS_LOG("Invalid parameters");
      return(-1);
    }

  dll_insert(snets, mask);

  return(0);
}



/*
 * Check SecureNets
 */
int 
sos_CheckSecureNets(SOS_Snets snets, struct in_addr test)
{
  dict_obj llcur;
  struct sos_netmask *nm;

  if (!snets)
    {
      LIBSOS_LOG("Invalid parameters");
      return(-1);
    }

  /* Check for matches */
  for(llcur = dll_maximum(snets);llcur != NULL;llcur = dll_predecessor(snets, llcur))
    {
      nm = (struct sos_netmask *)llcur;

      if (MATCH(nm, test))
	return(nm->good);	/* we matched!!! */
    }

  /* Default failure */
  return(0);
}



/*
 * Check SecureNets from a fd
 */
int
sos_CheckSecureNets_fd(SOS_Snets snets, int fd)
{
  struct sockaddr_in name;
  int namelen = sizeof(name);

  if (getpeername(fd, (struct sockaddr *)&name, &namelen) < 0)
    {
      LIBSOS_LOG("Could not find peer");
      return(-1);
    }

  return(sos_CheckSecureNets(snets, name.sin_addr));
}



/*
 * Load SecureNets from config file
 */
SOS_Snets
sos_LoadSecureNets_Config(sos_config_t config, char *key)
{
  struct sos_netmask *entry;
  sos_config_value value;
  SOS_Snets nets;
  char *line;
  char goodchar;
  char *addrchar;
  char *maskchar;

  nets = sos_InitSecureNets();

  while ((value = (char *)sos_config_getnext(config,key, 
					     SOS_CONFIG_FORWARD,
					     SOS_CONFIG_LINEAR)) !=
	 (sos_config_value) NULL)
    {
      line = value;
      line += strspn(line,SOS_WHITESPACE);

      goodchar = *line++;
      if (goodchar != '+' && goodchar != '-')
	{
	  LIBSOS_LOG("Invalid format (must start with +/-)");
	  goto bad;		/* Invalid format */
	}

      line += strspn(line,SOS_WHITESPACE);
      if (!(maskchar = strstr(line, "/")))
	{
	  LIBSOS_LOG("Invalid format (address/mask)");
	  goto bad;		/* Invalid format */
	}

      /* Split the line into a address/netmask character pair */
      *maskchar++ = '\0';
      maskchar += strspn(maskchar,SOS_WHITESPACE);
      addrchar = line;

      /* Allocate storage */
      if (!(entry = malloc(sizeof(struct sos_netmask))))
	{
	  LIBSOS_LOG("Could not allocate memory");
	  return(NULL);
	}

      /* Fill out the data structure */
      if (sos_getabyfoo(addrchar, &(entry->addr)) < 0)
	{
	  LIBSOS_LOG("Could not lookup address");
	  goto bad;
	}
      if (sos_getabyfoo(maskchar, &(entry->mask)) < 0)
	{
	  LIBSOS_LOG("Could not lookup mask");
	  goto bad;
	}
      entry->good = goodchar == '+' ? 1 : 0;

      /* Add the net as a secure network */
      if (sos_AddSecureNets(nets, entry) < 0)
	{
	  LIBSOS_LOG("Could not add securenets");
	  goto bad;
	}
    }

  return(nets);
      
 bad:
  sos_FreeSecureNets(nets);
  return(NULL);
}



/*
 * Load SecureNets from SecureNets file
 */
SOS_Snets
sos_LoadSecureNets_File(char *file)
{
  FILE *config;
  struct sos_netmask *entry;
  char value[SOS_NORMAL_LINE];
  SOS_Snets nets;
  char *line;
  char goodchar;
  char *addrchar;
  char *maskchar;

  if ((config = fopen(file, "r")) == NULL)
    {
      LIBSOS_LOG("Could not open file");
      return (NULL);
    }

  nets = sos_InitSecureNets();

  while (fgets(value, SOS_NORMAL_LINE, config))
    {
      if (value[0] == '#' || value[0] == '\n')
	continue;

      line = value;
      line += strspn(line,SOS_WHITESPACE);
      
      goodchar = *line++;
      if (goodchar != '+' && goodchar != '-')
	{
	  /* LOG */
	  goto bad;		/* Invalid format */
	}
      
      line += strspn(line,SOS_WHITESPACE);
      if (!(maskchar = strstr(line, "/")))
	{
	  /* LOG */
	  goto bad;		/* Invalid format */
	}
      
      /* Split the line into a address/netmask character pair */
      *maskchar++ = '\0';
      maskchar += strspn(maskchar,SOS_WHITESPACE);
      addrchar = line;
      
      /* Allocate storage */
      if (!(entry = malloc(sizeof(struct sos_netmask))))
	{
	  LIBSOS_LOG("Could not allocate memory");
	  return(NULL);
	}

      /* Fill out the data structure */
      if (sos_getabyfoo(addrchar, &(entry->addr)) < 0)
	{
	  /* LOG */
	  goto bad;
	}
      if (sos_getabyfoo(maskchar, &(entry->mask)) < 0)
	{
	  /* LOG */
	  goto bad;
	}
      entry->good = goodchar == '+' ? 1 : 0;
      
      /* Add the net as a secure network */
      if (sos_AddSecureNets(nets, entry) < 0)
	{
	  /* LOG */
	  goto bad;
	}
    }

  return(nets);
      
 bad:
  sos_FreeSecureNets(nets);
  return(NULL);
}
