/* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * Portions of this software are based upon public domain software * originally written at the National Center for Supercomputing Applications, * University of Illinois, Urbana-Champaign. */ /* * mod_allowdev: prohibit files from being served unless they're * on a listed device. * * v0.05 * * Author: Dean Gaudet * dirkx@webweaving.org AllowDev directive */ /* Why do you want this? Let me put it this way: the symlink protection options (FollowSymLinks and SymLinksIfOwnerMatch) are lame in many ways: - They're slow, they require a component by component stat() and/or lstat(). - They're hard to get correct because apache won't readlink() so it doesn't rewrite the destination. This can lead to situations where you thought you had protected a filesystem, but you really hadn't because a symlink may let the user into it. - They're overkill. Frequently all you're trying to do is to protect /etc from being served, and frequently /etc is on a partition that users' files are not on (if not you've got other problems, see a book on unix security). There's an easier way to do this. We just tell Apache what *devices* we are willing to serve files from. That's what this module does. */ /* Usage: Stick an appropriate "AddModule modules/extra/mod_allowdev.o" directive at the very bottom of your src/Configuration file, rebuild. Static mount points: This probably covers most internet servers. You list all the mount points that have content you wish to serve on the net like this: AllowDev /mount-point1 /mount-point2 ... For example, "AllowDev /var" would allow any file on the /var device to be served. Note that, for example, "AllowDev /var/foo" where foo is not a mount point, probably doesn't do what you expect. This case too would allow all files on /var to be served. Dynamic mount points: This probably covers most intranet servers. AllowDevDynamic regex subst If the file to be served matches regex, then perform subst. The resulting path must be on the same device as the file served. For example: AllowDevDynamic /home/([^/]*)/public_html /home/$1 Says that if a file /home/userid/public_html/foobar is to be served, then its device must match /home/userid. */ #include #include #include #include #include #include #include "httpd.h" #include "http_config.h" #include "http_log.h" module MODULE_VAR_EXPORT allowdev_module; typedef struct { regex_t *regexp; char *subst; } a_dynamic_dev; typedef struct { array_header *static_devs; array_header *dynamic_devs; } a_server_config; static void *create_server_config(pool *p, server_rec *s) { a_server_config *sec; sec = ap_palloc(p, sizeof(*sec)); sec->static_devs = ap_make_array(p, 5, sizeof(dev_t)); sec->dynamic_devs = ap_make_array(p, 5, sizeof(a_dynamic_dev)); return sec; } static const char *add_dev_slot(cmd_parms *cmd, void *dummy, char *args) { a_server_config *sec; struct stat buf; dev_t *cur; dev_t *end; if ((!(*args)) || (strlen(args)==0)) return "Must define a file/device to stat"; if (stat(args, &buf) == -1) { ap_log_error(APLOG_MARK, APLOG_WARNING, NULL, "unable to stat %s, files on this device will not be served", args); return NULL; } sec = ap_get_module_config(cmd->server->module_config, &allowdev_module); /* though we could return an error; we try to * just silently avoid putting the same device * in twice. */ cur = (dev_t *)sec->static_devs->elts; end = cur + sec->static_devs->nelts; while (cur < end) { if (*cur == buf.st_dev) { return NULL; } ++cur; } cur = ap_push_array(sec->static_devs); *cur = buf.st_dev; return NULL; } static const char *add_dynamic(cmd_parms *cmd, void *dummy, char *rx, char *subst) { regex_t *regexp; a_dynamic_dev *dyn; a_server_config *sec; regexp = ap_pregcomp(cmd->pool, rx, REG_EXTENDED); if (regexp == NULL) { return "regex could not be compiled"; } sec = ap_get_module_config(cmd->server->module_config, &allowdev_module); dyn = ap_push_array(sec->dynamic_devs); dyn->regexp = regexp; dyn->subst = subst; return NULL; } static command_rec allowdev_cmds[] = { {"AllowDev", add_dev_slot, NULL, RSRC_CONF, ITERATE, "A space seperated list of devices or files"}, {"AllowDevDynamic", add_dynamic, NULL, RSRC_CONF, TAKE2, "A regexp and an expansion, if uri matches regexp, file must be on device specified by expansion"}, { NULL } }; /* We run this in the fixup phase because the fixup phase is * guaranteed to be run on all requests, and sub requests. * We can't use the "check access" phase because that is overridden * trivially with the Satisfy directive. */ static int check_device(request_rec *r) { a_server_config *sec; dev_t *s_cur; dev_t *s_end; a_dynamic_dev *d_cur; a_dynamic_dev *d_end; regmatch_t regm[10]; if (r->finfo.st_mode == 0) { return DECLINED; } sec = ap_get_module_config(r->server->module_config, &allowdev_module); s_cur = (dev_t *)sec->static_devs->elts; s_end = s_cur + sec->static_devs->nelts; while (s_cur < s_end) { if (*s_cur == r->finfo.st_dev) { return DECLINED; } ++s_cur; } d_cur = (a_dynamic_dev *)sec->dynamic_devs->elts; d_end = d_cur + sec->dynamic_devs->nelts; while (d_cur < d_end) { if (!regexec(d_cur->regexp, r->uri, d_cur->regexp->re_nsub + 1, regm, 0)) { char *found; struct stat buf; found = ap_pregsub(r->pool, d_cur->subst, r->uri, d_cur->regexp->re_nsub + 1, regm); if (stat(found, &buf) == 0 && buf.st_dev == r->finfo.st_dev) { return DECLINED; } } ++d_cur; } ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server, "mod_allowdev: request to %s is on device 0x%x, forbidden", r->uri, r->finfo.st_dev); return HTTP_FORBIDDEN; } module MODULE_VAR_EXPORT allowdev_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ create_server_config, /* server config */ NULL, /* merge server config */ allowdev_cmds, /* command handlers */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ check_device, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ };