diff -urN freeradius-0.8.1/src/modules/rlm_skunk/Makefile freeradius-0.8.1-skunk/src/modules/rlm_skunk/Makefile
--- freeradius-0.8.1/src/modules/rlm_skunk/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ freeradius-0.8.1-skunk/src/modules/rlm_skunk/Makefile	2003-06-19 15:35:09.000000000 +0100
@@ -0,0 +1,4 @@
+TARGET	= rlm_skunk
+SRCS	= rlm_skunk.c skunk.c
+
+include ../rules.mak
diff -urN freeradius-0.8.1/src/modules/rlm_skunk/rlm_skunk.c freeradius-0.8.1-skunk/src/modules/rlm_skunk/rlm_skunk.c
--- freeradius-0.8.1/src/modules/rlm_skunk/rlm_skunk.c	1970-01-01 01:00:00.000000000 +0100
+++ freeradius-0.8.1-skunk/src/modules/rlm_skunk/rlm_skunk.c	2003-06-19 16:00:15.000000000 +0100
@@ -0,0 +1,164 @@
+/*
+ *   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
+ *
+ * Copyright (c) 2003 Gianni Tedesco <gianni@scaramanga.co.uk>
+ */
+
+#include	"autoconf.h"
+#include	"libradius.h"
+
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<string.h>
+#include	<errno.h>
+#include	<sys/types.h>
+#include	<sys/stat.h>
+#include	<fcntl.h>
+
+#if HAVE_SYSLOG_H
+#include	<syslog.h>
+#endif
+
+#include	"radiusd.h"
+#include	"modules.h"
+#include	"skunk.h"
+
+typedef struct rlm_skunk_t {
+	struct skunk_db *db;
+	struct rec res;
+	char *file;
+} rlm_skunk_t;
+
+static CONF_PARSER module_config[] = {
+	{ "file",    PW_TYPE_STRING_PTR, offsetof(rlm_skunk_t,file),
+	  NULL, "userdb.sdb" },
+	{ NULL, -1, 0, NULL, NULL }
+};
+
+/*
+ *	(Re-)read radiusd.conf into memory.
+ */
+static int skunk_instantiate(CONF_SECTION *conf, void **instance)
+{
+	rlm_skunk_t *data;
+	int fd;
+
+	data = rad_malloc(sizeof(*data));
+
+	if (cf_section_parse(conf, data, module_config) < 0) {
+		goto err;
+	}
+
+	fd = open(data->file, O_RDONLY);
+	if ( fd < 0 ) {
+		radlog(L_ERR|L_CONS, "rlm_skunk: %s: open: %s",
+			data->file, strerror(errno));
+		goto err;
+	}
+
+	data->db = skunk_open(fd);
+	if ( data->db == NULL ) {
+		radlog(L_ERR|L_CONS, "rlm_skunk: %s: skunk_open: %s",
+			data->file, errno ? strerror(errno) : "unknown error");
+		goto err_close;
+	}
+
+	/* NOTE: FD is closed now */
+
+	skunk_set_result(data->db, &data->res);
+
+	*instance = data;
+	return 0;
+
+err_close:
+	close(fd);
+err:
+	free(data);
+	return -1;
+}
+
+/*
+ *	Clean up.
+ */
+static int skunk_detach(void *instance)
+{
+	rlm_skunk_t *data = instance;
+	
+	if (data->file)
+		free(data->file);
+	if (data->db)
+		skunk_close(data->db);
+	free(data);
+	return 0;
+}
+
+/* translate between function declarations */
+static int skunk_auth(void *instance, REQUEST *request)
+{
+	rlm_skunk_t *data = instance;
+
+	if (!request->username) {
+		radlog(L_AUTH, "rlm_skunk: Attribute \"User-Name\" is required for authentication.");
+		return RLM_MODULE_INVALID;
+	}
+
+	if (!request->password) {
+		radlog(L_AUTH, "rlm_skunk: Attribute \"User-Password\" is required for authentication.");
+		return RLM_MODULE_INVALID;
+	}
+
+	if (request->password->attribute != PW_PASSWORD) {
+		radlog(L_AUTH, "rlm_skunk: Attribute \"User-Password\" is required for authentication. "
+				"Cannot use \"%s\".", request->password->name);
+		return RLM_MODULE_INVALID;
+	}
+
+	/* Lookup the username */
+	if ( skunk_select(data->db,
+			request->username->strvalue,
+			strlen(request->username->strvalue)) <= 0 )
+		return RLM_MODULE_REJECT;
+
+	/* Check if the password length is the same as our password */
+	if ( strlen(request->password->strvalue) != data->res.val_len )
+		return RLM_MODULE_REJECT;
+
+	/* Make sure the password match */
+	if ( memcpy(request->password->strvalue, data->res.val, data->res.val_len) )
+		return RLM_MODULE_REJECT;
+
+	/* YAY, its a good guy!! */
+	return RLM_MODULE_OK;
+}
+
+module_t rlm_skunk = {
+  "Pam",
+  RLM_TYPE_THREAD_SAFE,		/* Should be OK ;) */
+  NULL,				/* initialize */
+  skunk_instantiate,		/* instantiation */
+  {
+	  skunk_auth,		/* authenticate */
+	  NULL,			/* authorize */
+	  NULL,			/* pre-accounting */
+	  NULL,			/* accounting */
+	  NULL,			/* checksimul */
+	  NULL,			/* pre-proxy */
+	  NULL,			/* post-proxy */
+	  NULL			/* post-auth */
+  },
+  skunk_detach,			/* detach */
+  NULL,				/* destroy */
+};
+
diff -urN freeradius-0.8.1/src/modules/rlm_skunk/skunk.c freeradius-0.8.1-skunk/src/modules/rlm_skunk/skunk.c
--- freeradius-0.8.1/src/modules/rlm_skunk/skunk.c	1970-01-01 01:00:00.000000000 +0100
+++ freeradius-0.8.1-skunk/src/modules/rlm_skunk/skunk.c	2003-06-19 15:36:48.000000000 +0100
@@ -0,0 +1,109 @@
+/*
+ * This file is part of SkunkDB
+ * Copyright (c) 2002 Gianni Tedesco
+ * Released under the terms of the GNU GPL version 2
+ *
+ * TODO
+ *  o Support cursors.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "skunk.h"
+
+/* Map in the database */
+struct skunk_db *skunk_open(int fd)
+{
+	struct skunk_db *d;
+	struct stat st;
+
+	if ( fstat(fd, &st) )
+		return NULL;
+
+	if ( st.st_size < SKUNK_HASHSZ * 
+		sizeof(struct skunk_table) )
+		return NULL;
+
+	if ( !(d=calloc(1, sizeof(*d))) )
+		return NULL;
+
+	if ( (d->map=mmap(NULL, st.st_size, PROT_READ,
+		MAP_SHARED, fd, 0))==MAP_FAILED ) {
+		free(d);
+		return NULL;
+	}
+
+	d->maplen=st.st_size;
+	d->end=d->map + st.st_size;
+
+	/* Closing the file does not unmap it, we
+	 * just close it to save resources, heh */
+	close(fd);
+
+	return d;
+}
+
+/* Grab the first matching record from the database */
+int skunk_select(struct skunk_db *d, char *key, size_t klen)
+{
+	struct skunk_table *t;
+	struct skunk_bucket *b;
+	skunk_ofs_t i, dist=0;
+	skunk_hash_t h;
+
+	if ( !klen )
+		return -1;
+
+	h=skunk_hash(key, klen);
+
+	t=((struct skunk_table *)d->map) + (h % SKUNK_HASHSZ);
+
+	if ( !t->ofs || !t->len )
+		return 0;
+
+	if ( t->ofs > d->maplen )
+		return -1;
+
+	i=(h ^ klen) % t->len;
+	for(;;) {
+		b=((struct skunk_bucket *)(d->map+t->ofs)) + i;
+
+		if ( (char *)b > d->end )
+			return -1;
+
+		if ( b->hash == h && b->klen == klen ) {
+			char *record=(char *)(d->map + b->ofs);
+
+			if ( b->ofs + b->klen + b->vlen > d->maplen )
+				goto not_this;
+
+			if ( memcmp(record, key, klen) != 0 )
+				goto not_this;
+
+			d->result->key=record;
+			d->result->val=record+b->klen;
+			d->result->key_len=b->klen;
+			d->result->val_len=b->vlen;
+			return 1;
+		}
+not_this:
+		if ( ++dist>t->len )
+			break;
+
+		i=(i+1) % t->len;
+	}
+	return 0;
+}
+
+/* Close the database */
+void skunk_close(struct skunk_db *d)
+{
+	munmap(d->map, d->maplen);
+	free(d);
+}
diff -urN freeradius-0.8.1/src/modules/rlm_skunk/skunk.h freeradius-0.8.1-skunk/src/modules/rlm_skunk/skunk.h
--- freeradius-0.8.1/src/modules/rlm_skunk/skunk.h	1970-01-01 01:00:00.000000000 +0100
+++ freeradius-0.8.1-skunk/src/modules/rlm_skunk/skunk.h	2003-06-19 15:37:18.000000000 +0100
@@ -0,0 +1,103 @@
+/*
+ * This file is part of SkunkDB
+ * Copyright (c) 2002 Gianni Tedesco
+ * Released under the terms of the GNU GPL version 2
+*/
+#ifndef __SKUNK_HEADER_INCLUDED__
+#define __SKUNK_HEADER_INCLUDED__
+
+#define SKUNK_HASHSZ 2048UL
+
+typedef u_int32_t skunk_ofs_t;
+
+/* Hash size */
+#ifdef SKUNK_HASH_64
+typedef u_int64_t skunk_hash_t;
+#define FNV_PRIME       1099511628211ULL
+#define FNV_OFFSET      14695981039346656037ULL
+#else
+typedef u_int32_t skunk_hash_t;
+#define FNV_PRIME       16777619UL
+#define FNV_OFFSET      2166136261UL
+#endif
+
+/* Generic record structure */
+struct rec {
+	char *key, *val;
+	size_t key_len, val_len;
+};
+
+/* Database creation structures */
+struct skunk_rec {
+	struct skunk_rec *next;
+	size_t key_len, val_len;
+	void *key, *val;
+	skunk_hash_t hash;
+};
+
+struct skunk_head {
+	size_t count;
+	struct skunk_rec *list;
+};
+
+#if 0
+struct skunk_make {
+	int fd;
+	struct mpool rec;
+	struct skunk_head head[SKUNK_HASHSZ];
+};
+#endif
+
+/* Database query structures */
+struct skunk_db {
+	char	*map;
+	char	*end;
+	size_t	maplen;
+	struct rec *result;
+};
+
+/* These are our two on-disk structures */
+struct skunk_table{
+	skunk_ofs_t	ofs;
+	skunk_ofs_t	len;
+};
+
+struct skunk_bucket {
+	skunk_hash_t	hash;
+	skunk_ofs_t	ofs;
+	skunk_ofs_t	klen;
+	skunk_ofs_t	vlen;
+};
+
+/* Database creation API */
+#if 0
+struct skunk_make *skunk_new_db(int);
+int skunk_insert(struct skunk_make *, char *, size_t, char *, size_t);
+int skunk_commit(struct skunk_make *);
+int skunk_abort(struct skunk_make *);
+#endif
+
+/* Database query API */
+struct skunk_db *skunk_open(int);
+int skunk_select(struct skunk_db *, char *, size_t);
+void skunk_close(struct skunk_db *);
+
+static inline
+void skunk_set_result(struct skunk_db *d, struct rec *r)
+{
+	d->result=r;
+}
+
+/* Fowler/Noll/Vo hash 
+ * Its fast to compute, its obvious code, it performs well... */
+static inline skunk_hash_t skunk_hash(char *data, size_t len)
+{
+	skunk_hash_t h=FNV_OFFSET;
+
+	while(len--)
+		h = (h*FNV_PRIME) ^ *data++;
+
+	return h;
+}
+
+#endif /* __SKUNK_HEADER_INCLUDED__ */
diff -urN freeradius-0.8.1/src/modules/stable freeradius-0.8.1-skunk/src/modules/stable
--- freeradius-0.8.1/src/modules/stable	2002-11-01 16:16:51.000000000 +0000
+++ freeradius-0.8.1-skunk/src/modules/stable	2003-06-19 15:00:31.000000000 +0100
@@ -22,3 +22,4 @@
 rlm_sql
 rlm_unix
 rlm_x99_token
+rlm_skunk
