/*
 * ----------------------------------------------------------------
 * Night Light IRC Proxy - Access Configuration Functions
 * ----------------------------------------------------------------
 * Copyright (C) 1997-2007 Jonas Kvinge <jonas@night-light.net>
 * All rights reserved.
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Last modified by:
 * Jonas Kvinge (15.11.2006)
 *
 */

#define ACCESS_CONF_C

#define NEED_SYS_TYPES_H 1		/* Extra types */
#define NEED_SYS_PARAM_H 1		/* Some systems need this */
#define NEED_LIMITS_H 0			/* Kernel limits */
#define NEED_STDARG_H 1			/* va_list, etc */
#define NEED_ERRNO_H 1			/* errno */
#define NEED_CTYPE_H 1			/* isdigit(), etc */
#define NEED_NETINET_IN_H 0		/* in_addr, sockaddr_in, etc */
#define NEED_ARPA_INET_H 0		/* inet_ntoa(), inet_aton(), etc */
#define NEED_STDIO_H 1			/* Standard C UNIX functions */
#define NEED_STDLIB_H 1			/* malloc(), exit(), atoi(), etc */
#define NEED_TIME_H 1			/* time(), etc */
#define NEED_SYSCTL_H 0			/* sysctl(), etc */
#define NEED_SYS_STAT_H 0		/* chmod(), mkdir(), etc */
#define NEED_SYS_UIO_H 0		/* iovec, etc */
#define NEED_FCNTL_H 1			/* open(), creat(), fcntl(), etc */
#define NEED_SYS_IOCTL_H 0		/* ioctl(), etc */
#define NEED_SYS_FILIO_H 0		/* Solaris need this for ioctl(), etc */
#define NEED_UNISTD_H 1			/* Unix standard functions */
#define NEED_STRING_H 1			/* C string functions */
#define NEED_SIGNAL_H 0			/* Signal functions */
#define NEED_SYS_SOCKET_H 0		/* Socket functions */
#define NEED_NETDB_H 0			/* Network database functions */
#define NEED_ARPA_NAMESER_H 0		/* Nameserver definitions */
#define NEED_GETUSERPW_HEADERS 0 	/* Functions to retrive system passwords */

#include "includes.h"

#include "conf.h"

#include "access_conf.h"

/* VARIABLES - JONAS (31.07.2001) */

unsigned long int AccessConfs = 0;

struct AccessConf_Struct *Allow_Head = NULL;
struct AccessConf_Struct *Allow_Tail = NULL;

struct AccessConf_Struct *Deny_Head = NULL;
struct AccessConf_Struct *Deny_Tail = NULL;

unsigned short int Access_CheckFirst = ACCESS_DENY;
unsigned short int Access_Default = ACCESS_DENY;

extern struct Conf_Struct ConfS;

/* ACCESS_CONF_READ FUNCTION - JONAS (31.07.2001) */

signed long int access_conf_read(void) {

  char File[FILELEN+1] = "";
  FILE *FilePT = NULL;
  unsigned short int Count = 0;
  unsigned short int Skip = 0;

  DEBUGPRINT(BITMASK_DEBUG_CONF, "Reading access configuration file.");

  if (ConfS.AccessConfFile[0] != '/') {
    strncat(File, ConfS.DataPath, FILELEN);
    if (ConfS.DataPath[strlen(ConfS.DataPath)] != '/') { strncat(File, "/", (FILELEN - strlen(File))); }
  }
  strncat(File, ConfS.AccessConfFile, (FILELEN - strlen(File)));

  FilePT = fopen(File, "r");
  if (FilePT == NULL) {
    sysprint(BITMASK_ERROR, "Unable to open access configuration file %s: [%d] %s", File, errno, strerror(errno));
    return(ERROR);
  }

  access_conf_destroy();

  FOREVERLOOP {

    char Line[LINELEN+1] = "";
    char *LinePT = NULL;
    char *TempPT = NULL;
    char *EntryPT = NULL;
    char *DataPT = NULL;

    memset(&Line, 0, LINELEN+1);
    TempPT = fgets(Line, LINELEN, FilePT);
    if (TempPT == NULL) { break; }
    ++Count;
    LinePT = Line;

    while ((TempPT = strchr(LinePT, '\r')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(LinePT, '\n')) != NULL) { *TempPT = '\0'; }
    while ((TempPT = strchr(LinePT, '\t')) != NULL) { *TempPT = ' '; }

    while ((LinePT[0] == ' ') || (LinePT[0] == '\t')) { ++LinePT; }
    if ((LinePT[0] == '#') || (LinePT[0] == ';') || (LinePT[0] == '\0')) { continue; }

    EntryPT = LinePT;
    StrMovePastToken(LinePT, ' ');

    if (strcasecmp(EntryPT, "CONNECTION") == FALSE) { Skip = TRUE; continue; }
    if (EntryPT[0] == '}') { Skip = FALSE; continue; }
    if (Skip == TRUE) { continue; }

    if (LinePT == NULL) {
      sysprint(BITMASK_ERROR, "Access configuration error in file %s line %d: Expecting more data.", File, Count);
      continue;
    }
    DataPT = LinePT;
    StrMovePastToken(LinePT, ' ');

    if (strcasecmp(EntryPT, "ORDER") == FALSE) {

      char *OrderFPT = NULL;
      char *OrderLPT = NULL;

      OrderFPT = DataPT;
      OrderLPT = strchr(DataPT, ',');
      if (OrderLPT == NULL) {
        sysprint(BITMASK_ERROR, "Access configuration error in file %s line %d: Order incorrectly specified.", File, Count);
        continue;
      }
      OrderLPT[0] = '\0';
      ++OrderLPT;

      while(OrderFPT[0] == ' ') { ++OrderFPT; }
      while(OrderLPT[0] == ' ') { ++OrderLPT; }

      while (((TempPT = strchr(OrderFPT, ' ')) != NULL) || ((TempPT = strchr(OrderFPT, '\t')) != NULL) || ((TempPT = strchr(OrderFPT, ';')) != NULL) || ((TempPT = strchr(OrderFPT, '#')) != NULL)) {
        if (TempPT == OrderFPT) { ++OrderFPT; }
        else { *TempPT = '\0'; }
      }

      while (((TempPT = strchr(OrderLPT, ' ')) != NULL) || ((TempPT = strchr(OrderLPT, '\t')) != NULL) || ((TempPT = strchr(OrderLPT, ';')) != NULL) || ((TempPT = strchr(OrderLPT, '#')) != NULL)) {
        if (TempPT == OrderLPT) { OrderLPT++; }
        else { *TempPT = '\0'; }
      }

      if ((strcasecmp(OrderFPT, "ALLOW") == FALSE) && (strcasecmp(OrderLPT, "DENY") == FALSE)) {
        Access_CheckFirst = ACCESS_ALLOW;
        DEBUGPRINT(BITMASK_DEBUG_CONF, "Access configuration: Rule order: Allow, Deny.");
      }
      if ((strcasecmp(OrderFPT, "DENY") == FALSE) && (strcasecmp(OrderLPT, "ALLOW") == FALSE)) {
        Access_CheckFirst = ACCESS_DENY;
        DEBUGPRINT(BITMASK_DEBUG_CONF, "Access configuration: Rule order: Deny, Allow.");
      }
      else { sysprint(BITMASK_ERROR, "Access configuration error, file %s line %d: Order incorrectly specified.", File, Count); continue; }

      continue;
    }
    else if (strcasecmp(EntryPT, "DEFAULT") == FALSE) {
      if (strcasecmp(DataPT, "ALLOW") == FALSE) {
        Access_Default = ACCESS_ALLOW;
        DEBUGPRINT(BITMASK_DEBUG_CONF, "Access configuration: Default rule: Allow.");
      }
      else if (strcasecmp(DataPT, "DENY") == FALSE) {
        Access_Default = ACCESS_DENY;
        DEBUGPRINT(BITMASK_DEBUG_CONF, "Access configuration: Default rule: Deny.");
      }
      else { sysprint(BITMASK_ERROR, "Access configuration error, file %s line %d: Default rule incorrectly specified.", File, Count); continue; }
      continue;
    }
    else if (strcasecmp(EntryPT, "ALLOW") == FALSE) {
      (void) access_conf_addallow(DataPT, (LinePT == NULL ? ACCESS_CONF_NOREASON : LinePT));
      continue;
    }
    else if (strcasecmp(EntryPT, "DENY") == FALSE) {
      (void) access_conf_adddeny(DataPT, (LinePT == NULL ? ACCESS_CONF_NOREASON : LinePT));
      continue;
    }
    else {
#if 0
      sysprint(BITMASK_ERROR, "Access configuration error, file %s line %d: Invalid entry \"%s\"", File, Count, EntryPT);
#endif
      continue;
    }

  }

  (void) fclose(FilePT);

  return(AccessConfs);

}

/* ACCESS_CONF_ADDALLOW - JONAS (31.07.2001) */

struct AccessConf_Struct *access_conf_addallow(const char *const HostPT, const char *const ReasonPT) {

  struct AccessConf_Struct *AccessConf = NULL;
  struct AccessConf_Struct *AccessConf_NEW = NULL;

  assert(HostPT != NULL);
  assert(ReasonPT != NULL);

  DEBUGPRINT(BITMASK_DEBUG_CONF, "Access configuration: Allow rule: %s: %s", HostPT, ReasonPT);

  AccessConf_NEW = malloc(sizeof(struct AccessConf_Struct));
  if (AccessConf_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(AccessConf_NEW, 0, sizeof(struct AccessConf_Struct));

  AccessConf_NEW->Host = strdup(HostPT);
  AccessConf_NEW->Reason = strdup(ReasonPT);

  if ((AccessConf_NEW->Host == NULL) || (AccessConf_NEW->Reason == NULL)) {
    free(AccessConf_NEW->Host);
    free(AccessConf_NEW->Reason);
    free(AccessConf_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  if (Allow_Head == NULL) {
    Allow_Head = AccessConf_NEW;
    Allow_Tail = AccessConf_NEW;
  }
  else {
    AccessConf = Allow_Tail;
    AccessConf->Next = AccessConf_NEW;
    AccessConf_NEW->Prev = AccessConf;
    Allow_Tail = AccessConf_NEW;
  }

  AccessConf++;

  aerrno = AESUCCESS;
  return(AccessConf_NEW);

}

/* ACCESS_CONF_REMALLOW FUNCTION - JONAS (31.07.2001) */

void access_conf_remallow(struct AccessConf_Struct *AccessConf) {

  assert(AccessConf != NULL);

  if (AccessConf->Prev == NULL) { Allow_Head = AccessConf->Next; }
  else { AccessConf->Prev->Next = AccessConf->Next; }

  if (AccessConf->Next == NULL) { Allow_Tail = AccessConf->Prev; }
  else { AccessConf->Next->Prev = AccessConf->Prev; }

  free(AccessConf->Host);
  free(AccessConf->Reason);
  free(AccessConf);

  AccessConf--;

}

/* ACCESS_CONF_ADDDENY - JONAS (31.07.2001) */

struct AccessConf_Struct *access_conf_adddeny(const char *const HostPT, const char *const ReasonPT) {

  struct AccessConf_Struct *AccessConf = NULL;
  struct AccessConf_Struct *AccessConf_NEW = NULL;

  assert(HostPT != NULL);
  assert(ReasonPT != NULL);

  DEBUGPRINT(BITMASK_DEBUG_CONF, "Access configuration: Deny rule: %s: %s", HostPT, ReasonPT);

  AccessConf_NEW = malloc(sizeof(struct AccessConf_Struct));
  if (AccessConf_NEW == NULL) {
    aerrno = AEMALLOC;
    return(NULL);
  }

  memset(AccessConf_NEW, 0, sizeof(struct AccessConf_Struct));

  AccessConf_NEW->Host = strdup(HostPT);
  AccessConf_NEW->Reason = strdup(ReasonPT);

  if ((AccessConf_NEW->Host == NULL) || (AccessConf_NEW->Reason == NULL)) {
    free(AccessConf_NEW->Host);
    free(AccessConf_NEW->Reason);
    free(AccessConf_NEW);
    aerrno = AEMALLOC;
    return(NULL);
  }

  if (Deny_Head == NULL) {
    Deny_Head = AccessConf_NEW;
    Deny_Tail = AccessConf_NEW;
  }
  else {
    AccessConf = Deny_Tail;
    AccessConf->Next = AccessConf_NEW;
    AccessConf_NEW->Prev = AccessConf;
    Deny_Tail = AccessConf_NEW;
  }

  AccessConfs++;

  aerrno = AESUCCESS;
  return(AccessConf_NEW);

}

/* ACCESS_CONF_REMDENY FUNCTION - JONAS (31.07.2001) */

void access_conf_remdeny(struct AccessConf_Struct *AccessConf) {

  assert(AccessConf != NULL);

  if (AccessConf->Prev == NULL) { Deny_Head = AccessConf->Next; }
  else { AccessConf->Prev->Next = AccessConf->Next; }

  if (AccessConf->Next == NULL) { Deny_Tail = AccessConf->Prev; }
  else { AccessConf->Next->Prev = AccessConf->Prev; }

  free(AccessConf->Host);
  free(AccessConf->Reason);
  free(AccessConf);

  AccessConfs--;

}

/* ACCESS_CONF_DESTROY FUNCTION - JONAS (31.07.2001) */

void access_conf_destroy(void) {

  while (Allow_Head != NULL) { access_conf_remallow(Allow_Head); }
  while (Deny_Head != NULL) { access_conf_remdeny(Deny_Head); }

}


syntax highlighted by Code2HTML, v. 0.9.1