/* PIPServer - A deamon for finger protocol v2
 *
 * Copyright (C) 1999-2001 Michael Baumer <baumi@vis.ethz.ch>
 *
 * 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/* Reads the global fingerconf and fills in the config datastructure */

#include <stdio.h>
#include <string.h>

#include "finger.h"
#include "configfile.h"
#include "log.h"
#include "compat.h"
#include "acl.h"

aclT * parse_acl(Node *cfnode);

/* Init()
//
// Reads the system config file 
//
// If errors occur we use the defaults
// (that's why we do not check the strdups: 
//  NULL is a valid configuration)
*/
void Init(char *progname, int have_tty)
{
  Node *cfnode, *parent_node;
  char *tmp;
  int i, j;
  aclT *acl, *allow, *deny, _allow, _deny;

  allow = &_allow;
  deny = &_deny;
  allow->next = NULL;
  deny->next = NULL;

  /* open syslog */
  if (have_tty)
    log_open(progname, LOGTYPE_STDERR);
  else
    log_open(progname, LOGTYPE_SYSLOG);

  /* initialize configuration with default values */
  memset(&config, 0, sizeof(config));
  config.first_uid = 100; /* This is obviously site-dependant */
  if (config.gnufinger) {
    config.gnufingerdir = "/usr/local/etc/fingerdir";
    config.dbpath = "/usr/local/etc/fingerdir";
  }
  else
    config.dbpath = "/usr/share/finger";
  config.interval = 30; /* in seconds */
  config.numclients = 0;

  /* Initialize default ACL */
  config.acl = (aclT *)malloc(sizeof(struct aclT));
  config.acl->type = ACLTYPE_ALL;
  config.acl->from = NULL;
  config.acl->next = NULL;
  config.acl->options = (ACL_USERLIST | ACL_MAIL);

  /* read global configfile */
  if ((parent_node = readFingerconf(NULL))) {
    cfnode = parent_node->child;
    i = 0;
    j = 0;
    while(cfnode) {
      if (!strcmp(cfnode->id, "siteinfo"))
	config.siteinfo = strdup(cfnode->value);
      else if (!strcmp(cfnode->id, "userfilepath")) {
	if (strcmp(cfnode->value, "/home"))
	  if (i<3) 
	    config.userfilepath[i++] = strdup(cfnode->value);
	  else
	    log(LOG_ERR, "fingerconf: Only 3 userfilepaths allowed");
      } 
      else if (!strcmp(cfnode->id, "help"))
	config.help = strdup(cfnode->value);
      else if (!strcmp(cfnode->id, "specialfile")) {
	if (j<10) {
	  config.validfile[j] = strdup(cfnode->value);
	  if (cfnode->child)
	    config.filedesc[j] = strdup(cfnode->child->value);
	  j++;
	}
	else 
	  log(LOG_ERR, "fingerconf: Only 10 special files allowed");
      }
      else if (!strcmp(cfnode->id, "gnufinger")) {
	if (cfnode->child && !strcmp(cfnode->child->id, "fingerdir")) {
	  tmp = strdup(cfnode->child->value);
	  if (tmp)
	    config.gnufingerdir = tmp;
	}
      }
      else if (!strcmp(cfnode->id, "dbpath")) {
	tmp = strdup(cfnode->value);
	if (tmp)
	  config.dbpath =tmp;
      }
      else if (!strcmp(cfnode->id, "poll"))
	config.interval = atoi(cfnode->value);
      /* 
       * Compatibility for pfinger config-files =< 0.7.7
       * set the options on the default ACL
       */
      else if (!strcmp(cfnode->id, "option")) {
	if (!strcmp(cfnode->value, "showidle"))
	  config.acl->options |= ACL_IDLETIME;
	else if (!strcmp(cfnode->value, "showfrom")) 
	  config.acl->options |= ACL_FROMHOST;
	else if (!strcmp(cfnode->value, "hidemail")) 
	  config.acl->options &= ~ACL_MAIL;
	else if (!strcmp(cfnode->value, "hideall")) 
	  config.acl->options &= ~ACL_USERLIST;
      }
      /* ACL - Access Control List
       */
      else if (!strcmp(cfnode->id, "acl")) {
	if (cfnode->child) {
	  cfnode=cfnode->child;
	  while(1) {
	    if (!strcmp(cfnode->id, "order"))
	      /* todo */
	      ;
	    else if (!strcmp(cfnode->id, "allow")) {
	      if (allow->next = parse_acl(cfnode->child))
		allow = allow->next;	      
	    }
	    else if (!strcmp(cfnode->id, "deny")) {
	      if (deny->next = parse_acl(cfnode->child))
		deny = deny->next;
	    }

	    /* Iterate */
	    if (cfnode->next)
	      cfnode = cfnode->next;
	    else {
	      cfnode = cfnode->parent;
	      break;
	    }
	  }
	}
      }
      else if (!strcmp(cfnode->id, "clientlist")) {
	/*
	// A list of clients to be called by the master fingerd
	*/
	if (cfnode->child) {
	  cfnode = cfnode->child;
	  /*
	  // The client list is an array of pointers, 
	  // allocated in blocks of 16
	  */
	  config.clients = (char **)malloc(16*sizeof(void *));
	  while (1) {
	    if (!strcmp(cfnode->id, "client")) {
	      tmp = strdup(cfnode->value);
	      if (tmp) {
		config.clients[config.numclients++] = tmp;
		if (!(config.numclients % 16)) {
		    tmp = (char *)realloc(config.clients, (16+config.numclients)*sizeof(void *));
		    if (tmp)
		      config.clients = (char **)tmp;
		    else
		      break;

		}
	      }
	      else
		log(LOG_ERR, "Could not allocate memory for client hostname");
	    }
	    if (!cfnode->next) {
	      cfnode = cfnode->parent;
	      break;
	    }
	    cfnode = cfnode->next;
	  }
	}
      }
      else if ((!strcmp(cfnode->id, "sitehost")) || 
	       (!strcmp(cfnode->id, "sitemaster")))
	config.sitehost = strdup(cfnode->value);

      cfnode = cfnode->next;
    }

    FreeParseTree(parent_node);
  }

  config.allow = _allow.next;
  config.deny = _deny.next;
}
  
aclT * parse_acl(Node *cfnode)
{
  aclT *acl;

  acl = (aclT *)calloc(1, sizeof(aclT));
  if (!acl)
    return(0);

  while(cfnode) {
    if (!strcmp(cfnode->id, "from"))
      acl->from = strdup(cfnode->value);

    else if (!strcmp(cfnode->id, "option")) {

      if (!strcmp(cfnode->value, "idletime"))
	acl->options |= ACL_IDLETIME;
      else if (!strcmp(cfnode->value, "fromhost")) 
	acl->options |= ACL_FROMHOST;
      else if (!strcmp(cfnode->value, "mailstatus")) 
	acl->options |= ACL_MAIL;
      else if (!strcmp(cfnode->value, "userlist")) 
	acl->options |= ACL_USERLIST;
    }
    cfnode = cfnode->next;
  }

  /* ACL Type */
  if (acl->from) {
    if (!strcmp(acl->from, "all"))
      acl->type = ACLTYPE_ALL;
    else if (!strcmp(acl->from, "localhost"))
      acl->type = ACLTYPE_LOCALHOST;
    else
      acl->type = ACLTYPE_DOMAIN;
  }

  /* Fow now we discard acl's without <from> */
  if (!acl->type) {
    free(acl);
    return(0);
  }

  return acl;
}


syntax highlighted by Code2HTML, v. 0.9.1