tmuck2.4/
tmuck2.4/admin/scripts/
tmuck2.4/docs/
tmuck2.4/minimal-db/
tmuck2.4/minimal-db/data/
tmuck2.4/minimal-db/logs/
tmuck2.4/minimal-db/muf/
tmuck2.4/old/
tmuck2.4/src/
tmuck2.4/src/compile/
tmuck2.4/src/editor/
tmuck2.4/src/game/
tmuck2.4/src/interface/
tmuck2.4/src/scripts/
tmuck2.4/src/utilprogs/
/* Copyright (c) 1992 by David Moore.  All rights reserved. */
/* lockout.c,v 2.9 1994/03/10 04:14:04 dmoore Exp */
#include "config.h"

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "db.h"
#include "buffer.h"
#include "lockout.h"
#include "externs.h"

/* Written by dmoore on 2/26/92.  Idea for being able to force site
   specific creation due to Jiro. */

static void load_lockout(void);
static int lockout_match(const char *, const char *);


#define LOCK_CONN	1
#define LOCK_CREATE	2
#define LOCK_PLAYER	3

typedef struct site_node {
    const char *site_name;	/* Name of site to lock out. */
    unsigned int kind : 2;	/* Lockout any connection or just creation. */
    unsigned int allow : 1;	/* 1 if this connection allowed, else 0. */
    const char *player_pattern; /* Pattern of dbref for player entries. */
    struct site_node *next;	/* Linked list. */
} site_node;


static site_node *sites = NULL;
static int sites_loaded = 0;


/* This routine is exported out to allow the USR2 signal handler to force
   a reload of the lockout file. */
void reload_lockout(const int signum)
{
    sites_loaded = 0;
    signal(signum, reload_lockout);
}


/* Deallocates any memory used by the lockout code. */
void free_lockout(void)
{
    site_node *temp;

    /* Free up any existing sites. */
    while (sites) {
	temp = sites->next;
	FREE_STRING(sites->site_name);
	if (sites->player_pattern) FREE_STRING(sites->player_pattern);
	FREE(sites);
	sites = temp;
    }
    sites = NULL;
}


/* This loads up the lockout file, making a linked list of sites
   mentioned. */
static void load_lockout(void)
{
    Buffer buf, site_name;
    site_node *temp;
    FILE *fp;
    char *p, *q, *player_pattern;
    int kind;
    int allow;

    free_lockout();		/* Clean up any existing sites. */

    sites_loaded = 1;

    /* Read in the new file.  Each line should be an address followed
       by whitespace followed by either 'connection' or 'creation'. */
    fp = fopen(LOCKOUT_FILE, "r");
    if (!fp) return;

    while (Bufgets(&buf, fp, NULL)) {
	p = Buftext(&buf);

	/* Skip any leading white space. */
	while (*p && isspace(*p)) p++;

	/* First char is ; or line is empty, skip. */
	if (!*p || *p == ';') continue;

	/* Skip to the end of the hostname. */
	for (q = p; *q && !isspace(*q); q++);

	/* Error if we're at the end of the string already. */
	if (!*q) {
	    log_status("LOCKOUT: bad entry (host) %s", Buftext(&buf));
	    continue;
	}

	/* Slip in a NUL, and use this string to get the host address. */
	*q = '\0';
	Bufcpy(&site_name, p);
	*q = ' ';		/* We know that it was whitespace. */

	/* Skip the white space. */
	for (p = q; *p && isspace(*p); p++);

	/* Skip to the end of the type, and slip in a NUL. */
	for (q = p; *q && !isspace(*q); q++);
	*q = '\0';

	/* Check for ! symbol. */
	if (*p == '!') { 
	    allow = 0;
	    p++;
	} else {
	    allow = 1;
	}

	/* Check out the specifier. */
	if (!strcmp(p, "connection")) {
	    kind = LOCK_CONN;
	} else if (!strcmp(p, "creation")) {
	    kind = LOCK_CREATE;
	} else if (*p == '#') {
	    kind = LOCK_PLAYER;
	    player_pattern = p + 1;
	} else {
	    log_status("LOCKOUT: bad entry (kind) %s", Buftext(&buf));
	    continue;
	}

	/* We got to here so this entry is fine.  Make a new node, and link
	   it into the list. */
	MALLOC(temp, struct site_node, 1);
	temp->site_name = ALLOC_STRING(Buftext(&site_name));
	temp->kind = kind;
	temp->allow = allow;
	if (kind == LOCK_PLAYER) {
	    temp->player_pattern = ALLOC_STRING(player_pattern);
	} else {
	    temp->player_pattern = NULL;
	}
	temp->next = sites;
	sites = temp;

    }
    fclose(fp);
}


/* This routine checks whether a given site is allowed to connect to the
   muck. */
int ok_conn_site(const char *hostname)
{
    site_node *temp;

    if (!sites_loaded) load_lockout();

    for (temp = sites; temp; temp = temp->next) {
	if ((temp->kind == LOCK_CONN)
	    && (lockout_match(temp->site_name, hostname))) 
	    return temp->allow;
    }

    return 1;
}


/* This routine checks whether a given site is allowed to create new
   characters on the muck. */
int ok_create_site(const char *hostname)
{
    site_node *temp;

    if (!sites_loaded) load_lockout();

    for (temp = sites; temp; temp = temp->next) {
	if ((temp->kind == LOCK_CREATE)
	    && (lockout_match(temp->site_name, hostname)))
	    return temp->allow;
    }

    return 1;
}


/* This routines checks that this site is allowed to connect to a
   specific character. */
int ok_player_site(const char *hostname, const dbref who_dbref)
{
    Buffer who;
    site_node *temp;

    if (!sites_loaded) load_lockout();

    /* Turn the dbref into a string for comparison. */
    Bufsprint(&who, "%d", who_dbref);

    for (temp = sites; temp; temp = temp->next) {
	if ((temp->kind == LOCK_PLAYER)
	    && (lockout_match(temp->site_name, hostname))
	    && (lockout_match(temp->player_pattern, Buftext(&who))))
	    return temp->allow;
    }

    return 1;
}


/* Match a pattern which might contain * for wildcard against the string. */
/* Return 1 if matched, 0 otherwise. */
static int lockout_match(const char *pattern, const char *str)
{
    if ((!pattern) || (!str)) return 0;
    while (*pattern) {
	if (*pattern != '*') {
	    if (tolower(*pattern) != tolower(*str)) return 0;
	    pattern++;
	    str++;
	} else {
	    while (*pattern == '*') pattern++;
	    if (!*pattern) return 1;
	    while (str = strchr(str, *pattern)) {
		if (lockout_match(pattern, str)) return 1;
		str++;
	    }
	    return 0;
	}
    }
    /* Only matched if we got to the end of both strings. */
    if (*str) return 0;
    else return 1;
}