xref: /lighttpd1.4/src/mod_access.c (revision 5e14db43)
1 #include "first.h"
2 
3 #include "request.h"
4 #include "array.h"
5 #include "buffer.h"
6 #include "log.h"
7 
8 #include "plugin.h"
9 
10 typedef struct {
11     const array *access_allow;
12     const array *access_deny;
13 } plugin_config;
14 
15 typedef struct {
16     PLUGIN_DATA;
17     plugin_config defaults;
18     plugin_config conf;
19 } plugin_data;
20 
INIT_FUNC(mod_access_init)21 INIT_FUNC(mod_access_init) {
22     return ck_calloc(1, sizeof(plugin_data));
23 }
24 
mod_access_merge_config_cpv(plugin_config * const pconf,const config_plugin_value_t * const cpv)25 static void mod_access_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
26     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
27       case 0: /* url.access-deny */
28         pconf->access_deny = cpv->v.a;
29         break;
30       case 1: /* url.access-allow */
31         pconf->access_allow = cpv->v.a;
32         break;
33       default:/* should not happen */
34         return;
35     }
36 }
37 
mod_access_merge_config(plugin_config * const pconf,const config_plugin_value_t * cpv)38 static void mod_access_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
39     do {
40         mod_access_merge_config_cpv(pconf, cpv);
41     } while ((++cpv)->k_id != -1);
42 }
43 
mod_access_patch_config(request_st * const r,plugin_data * const p)44 static void mod_access_patch_config(request_st * const r, plugin_data * const p) {
45     p->conf = p->defaults; /* copy small struct instead of memcpy() */
46     /*memcpy(&p->conf, &p->defaults, sizeof(plugin_config));*/
47     for (int i = 1, used = p->nconfig; i < used; ++i) {
48         if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
49             mod_access_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
50     }
51 }
52 
SETDEFAULTS_FUNC(mod_access_set_defaults)53 SETDEFAULTS_FUNC(mod_access_set_defaults) {
54     static const config_plugin_keys_t cpk[] = {
55       { CONST_STR_LEN("url.access-deny"),
56         T_CONFIG_ARRAY_VLIST,
57         T_CONFIG_SCOPE_CONNECTION }
58      ,{ CONST_STR_LEN("url.access-allow"),
59         T_CONFIG_ARRAY_VLIST,
60         T_CONFIG_SCOPE_CONNECTION }
61      ,{ NULL, 0,
62         T_CONFIG_UNSET,
63         T_CONFIG_SCOPE_UNSET }
64     };
65 
66     plugin_data * const p = p_d;
67     if (!config_plugin_values_init(srv, p, cpk, "mod_access"))
68         return HANDLER_ERROR;
69 
70     /* initialize p->defaults from global config context */
71     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
72         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
73         if (-1 != cpv->k_id)
74             mod_access_merge_config(&p->defaults, cpv);
75     }
76 
77     return HANDLER_GO_ON;
78 }
79 
80 __attribute_cold__
mod_access_reject(request_st * const r,plugin_data * const p)81 static handler_t mod_access_reject (request_st * const r, plugin_data * const p) {
82     if (r->conf.log_request_handling) {
83         if (p->conf.access_allow && p->conf.access_allow->used)
84             log_error(r->conf.errh, __FILE__, __LINE__,
85               "url denied as failed to match any from access_allow %s",
86               r->uri.path.ptr);
87         else
88             log_error(r->conf.errh, __FILE__, __LINE__,
89               "url denied as we match access_deny %s",
90               r->uri.path.ptr);
91     }
92 
93     r->http_status = 403;
94     r->handler_module = NULL;
95     return HANDLER_FINISHED;
96 }
97 
98 __attribute_pure__
mod_access_check(const array * const allow,const array * const deny,const buffer * const urlpath,const int lc)99 static int mod_access_check (const array * const allow, const array * const deny, const buffer * const urlpath, const int lc) {
100 
101     if (allow && allow->used) {
102         const buffer * const match = (!lc)
103           ? array_match_value_suffix(allow, urlpath)
104           : array_match_value_suffix_nc(allow, urlpath);
105         return (match != NULL); /* allowed if match; denied if none matched */
106     }
107 
108     if (deny && deny->used) {
109         const buffer * const match = (!lc)
110           ? array_match_value_suffix(deny, urlpath)
111           : array_match_value_suffix_nc(deny, urlpath);
112         return (match == NULL); /* deny if match; allow if none matched */
113     }
114 
115     return 1; /* allowed (not denied) */
116 }
117 
118 /**
119  * handler is called twice:
120  * - after the clean up of the URL and
121  * - after the pathinfo checks are done
122  *
123  * this handles the issue of trailing slashes
124  */
URIHANDLER_FUNC(mod_access_uri_handler)125 URIHANDLER_FUNC(mod_access_uri_handler) {
126     plugin_data *p = p_d;
127     mod_access_patch_config(r, p);
128     if (NULL == p->conf.access_allow && NULL == p->conf.access_deny)
129         return HANDLER_GO_ON; /* access allowed; nothing to match */
130 
131     return mod_access_check(p->conf.access_allow, p->conf.access_deny,
132                             &r->uri.path, r->conf.force_lowercase_filenames)
133       ? HANDLER_GO_ON              /* access allowed */
134       : mod_access_reject(r, p);   /* access denied */
135 }
136 
137 
138 __attribute_cold__
139 int mod_access_plugin_init(plugin *p);
mod_access_plugin_init(plugin * p)140 int mod_access_plugin_init(plugin *p) {
141 	p->version     = LIGHTTPD_VERSION_ID;
142 	p->name        = "access";
143 
144 	p->init        = mod_access_init;
145 	p->set_defaults = mod_access_set_defaults;
146 	p->handle_uri_clean = mod_access_uri_handler;
147 	p->handle_subrequest_start  = mod_access_uri_handler;
148 
149 	return 0;
150 }
151