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