diff -urN boa-0.94.14rc7-orig/configure.in boa-0.94.14rc7/configure.in
--- boa-0.94.14rc7-orig/configure.in	2002-10-26 16:42:43.000000000 +0200
+++ boa-0.94.14rc7/configure.in	2002-12-07 15:53:58.000000000 +0100
@@ -142,6 +142,24 @@
   ])
 fi
 
+AC_MSG_CHECKING(whether to enable access control support)
+AC_ARG_ENABLE(access-control,
+[  --enable-access-control Enable support for allow/deny rules],
+[
+ if test "$enableval" = "yes" ; then
+    AC_MSG_RESULT(yes)
+    CFLAGS="$CFLAGS -DACCESS_CONTROL"
+    ACCESSCONTROL_SOURCE="access.c"	
+  else
+    AC_MSG_RESULT(no)
+  fi
+],
+[
+    AC_MSG_RESULT(no)
+])
+AC_SUBST(ACCESSCONTROL_SOURCE)
+
+
 AC_MSG_CHECKING(whether to compile and link debugging code)
 AC_ARG_ENABLE(debug,
 [  --disable-debug         Compile and link debugging code],
diff -urN boa-0.94.14rc7-orig/docs/boa.texi boa-0.94.14rc7/docs/boa.texi
--- boa-0.94.14rc7-orig/docs/boa.texi	2002-10-14 02:21:29.000000000 +0200
+++ boa-0.94.14rc7/docs/boa.texi	2002-12-07 15:53:58.000000000 +0100
@@ -422,6 +422,25 @@
   
  @item ScriptAlias <path1> <path2>
   maps a virtual path to a directory for serving scripts. 
+
+ @item Allow, Deny
+ Only supported if Boa is compiled with --enable-access-control. 
+ Allow and Deny allows pattern based access control using shell
+ wildcards. The string the matching is performed on is the absolute
+ filesystem filename. The Allow, Deny directives are processed in
+ order until the first match is found, so to allow files containing
+ the substring 123 but not the ones containing 1234 you would do:
+     @itemize @bullet
+         @item Deny *1234*
+         @item Allow *123*
+     @end itemize   
+
+ @item Allow <pattern>
+ Allows files matching <pattern>
+
+ @item Deny <pattern>
+ Disallowes files matching <pattern>
+
 @end table
 
 @comment node-name,     next,           previous, up
@@ -545,6 +564,8 @@
   read.  The expectation is that you will configure Boa to run as user
   "nobody", and only files configured world readable will come
   out.
+  If Boa is compiled with --enable-access-control, access control is
+  supported using the Allow, Deny directives.
   
  @item No chroot option
  
diff -urN boa-0.94.14rc7-orig/src/Makefile.in boa-0.94.14rc7/src/Makefile.in
--- boa-0.94.14rc7-orig/src/Makefile.in	2002-11-18 03:28:52.000000000 +0100
+++ boa-0.94.14rc7/src/Makefile.in	2002-12-07 16:13:06.000000000 +0100
@@ -31,7 +31,7 @@
 SOURCES = alias.c boa.c buffer.c cgi.c cgi_header.c config.c escape.c \
 	get.c hash.c ip.c log.c mmap_cache.c pipe.c queue.c range.c \
 	read.c request.c response.c signals.c util.c sublog.c \
-	@ASYNCIO_SOURCE@
+	@ASYNCIO_SOURCE@ @ACCESSCONTROL_SOURCE@
 
 OBJS = $(SOURCES:.c=.o) timestamp.o @STRUTIL@
 
diff -urN boa-0.94.14rc7-orig/src/access.c boa-0.94.14rc7/src/access.c
--- boa-0.94.14rc7-orig/src/access.c	1970-01-01 01:00:00.000000000 +0100
+++ boa-0.94.14rc7/src/access.c	2002-12-07 15:53:58.000000000 +0100
@@ -0,0 +1,71 @@
+/*
+ *  Boa, an http server
+ *  Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
+ *
+ *  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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* $Id$ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include "access.h"
+
+struct access_node
+{
+  char *pattern;
+  char type;
+};
+
+static int n_access;
+
+static struct access_node *nodes = NULL;
+
+
+void access_init(void)
+{
+  n_access = 0;
+
+} /* access_init */
+
+
+void access_add(const char *pattern, const int type)
+{
+  n_access++;
+
+  nodes = realloc(nodes, n_access*sizeof(struct access_node));
+
+  nodes[n_access - 1].type    = type;
+  nodes[n_access - 1].pattern = strdup(pattern);
+
+} /* access_add */
+
+
+int access_allow(const char *file)
+{
+  int i;
+
+  /* find first match in allow / deny rules */
+  for (i=0; i<n_access; i++) {
+    if (fnmatch(nodes[i].pattern, file, 0) == 0) {
+      return nodes[i].type;
+    }
+  }
+
+  /* default to allow */
+  return ACCESS_ALLOW;
+
+} /* access_allow */
diff -urN boa-0.94.14rc7-orig/src/access.h boa-0.94.14rc7/src/access.h
--- boa-0.94.14rc7-orig/src/access.h	1970-01-01 01:00:00.000000000 +0100
+++ boa-0.94.14rc7/src/access.h	2002-12-07 15:53:58.000000000 +0100
@@ -0,0 +1,36 @@
+/*
+ *  Boa, an http server
+ *  Copyright (C) 1999 Larry Doolittle <ldoolitt@boa.org>
+ *
+ *  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 1, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/* $Id$ */
+
+#ifndef _ACCESS_H
+#define _ACCESS_H
+
+#define ACCESS_DENY 0
+#define ACCESS_ALLOW 1
+
+void access_init(void);
+
+void access_add(const char *pattern, const int type);
+
+int access_allow(const char *file);
+
+#endif /* _ACCESS_H */
+
diff -urN boa-0.94.14rc7-orig/src/config.c boa-0.94.14rc7/src/config.c
--- boa-0.94.14rc7-orig/src/config.c	2002-11-12 03:50:50.000000000 +0100
+++ boa-0.94.14rc7/src/config.c	2002-12-07 15:58:19.000000000 +0100
@@ -21,6 +21,7 @@
 /* $Id: config.c,v 1.31.2.13 2002/11/12 02:50:50 jnelson Exp $*/
 
 #include "boa.h"
+#include "access.h"
 #include <sys/resource.h>
 
 #define DEBUG_CONFIG 0
@@ -77,6 +78,7 @@
 static void c_add_mime_types_file(char *v1, char *v2, void *t);
 static void c_add_mime_type(char *v1, char *v2, void *t);
 static void c_add_alias(char *v1, char *v2, void *t);
+static void c_add_access(char *v1, char *v2, void *t);
 
 /* Fakery to keep the value passed to action() a void *,
    see usage in table and c_add_alias() below */
@@ -142,6 +144,8 @@
     {"MaxConnections", S1A, c_set_int, &max_connections},
     {"CGIumask", S1A, c_set_int, &cgi_umask},
     {"CGILog", S1A, c_set_string, &cgi_log_name},
+    {"Allow", S1A, c_add_access, (void*)ACCESS_ALLOW},
+    {"Deny", S1A, c_add_access, (void*)ACCESS_DENY},
 };
 
 static void c_set_user(char *v1, char *v2, void *t)
@@ -326,6 +330,17 @@
     add_alias(v1, v2, *(int *) t);
 }
 
+static void c_add_access(char *v1, char *v2, void *t)
+{
+#ifdef ACCESS_CONTROL
+  access_add(v1, (int)t);
+#else
+  log_error_time();
+  fprintf(stderr,"This version of Boa doesn't support access controls.\n"
+	  "Please recompile with --enable-access-control.\n");
+#endif /* ACCESS_CONTROL */
+}
+
 struct ccommand *lookup_keyword(char *c)
 {
     struct ccommand *p;
@@ -467,6 +482,10 @@
     parse(config);
     fclose(config);
 
+#ifdef ACCESS_CONTROL
+    access_init();
+#endif /* ACCESS_CONTROL */
+
     if (!server_name) {
         struct hostent *he;
         char temp_name[100];
diff -urN boa-0.94.14rc7-orig/src/get.c boa-0.94.14rc7/src/get.c
--- boa-0.94.14rc7-orig/src/get.c	2002-11-25 00:53:01.000000000 +0100
+++ boa-0.94.14rc7/src/get.c	2002-12-07 15:53:58.000000000 +0100
@@ -23,6 +23,7 @@
 /* $Id: get.c,v 1.76.2.18 2002/11/24 23:53:01 jnelson Exp $*/
 
 #include "boa.h"
+#include "access.h"
 
 /* I think that permanent redirections (301) are supposed
  * to be absolute URIs, but they can be troublesome.
@@ -111,6 +112,13 @@
         return 0;
     }
 
+#ifdef ACCESS_CONTROL
+    if (!access_allow(req->pathname)) {
+      send_r_forbidden(req);
+      return 0;
+    }
+#endif
+
     fstat(data_fd, &statbuf);
 
     if (S_ISDIR(statbuf.st_mode)) { /* directory */
