xref: /lighttpd1.4/src/mod_access.c (revision e11f72b1)
1 #include "first.h"
2 
3 #include "base.h"
4 #include "array.h"
5 #include "buffer.h"
6 #include "log.h"
7 
8 #include "plugin.h"
9 
10 #include <stdlib.h>
11 #include <string.h>
12 
13 typedef struct {
14     const array *access_allow;
15     const array *access_deny;
16 } plugin_config;
17 
18 typedef struct {
19     PLUGIN_DATA;
20     plugin_config defaults;
21     plugin_config conf;
22 } plugin_data;
23 
24 INIT_FUNC(mod_access_init) {
25     return calloc(1, sizeof(plugin_data));
26 }
27 
28 static void mod_access_merge_config_cpv(plugin_config * const pconf, const config_plugin_value_t * const cpv) {
29     switch (cpv->k_id) { /* index into static config_plugin_keys_t cpk[] */
30       case 0: /* url.access-deny */
31         pconf->access_deny = cpv->v.a;
32         break;
33       case 1: /* url.access-allow */
34         pconf->access_allow = cpv->v.a;
35         break;
36       default:/* should not happen */
37         return;
38     }
39 }
40 
41 static void mod_access_merge_config(plugin_config * const pconf, const config_plugin_value_t *cpv) {
42     do {
43         mod_access_merge_config_cpv(pconf, cpv);
44     } while ((++cpv)->k_id != -1);
45 }
46 
47 static void mod_access_patch_config(request_st * const r, plugin_data * const p) {
48     p->conf = p->defaults; /* copy small struct instead of memcpy() */
49     /*memcpy(&p->conf, &p->defaults, sizeof(plugin_config));*/
50     for (int i = 1, used = p->nconfig; i < used; ++i) {
51         if (config_check_cond(r, (uint32_t)p->cvlist[i].k_id))
52             mod_access_merge_config(&p->conf, p->cvlist + p->cvlist[i].v.u2[0]);
53     }
54 }
55 
56 SETDEFAULTS_FUNC(mod_access_set_defaults) {
57     static const config_plugin_keys_t cpk[] = {
58       { CONST_STR_LEN("url.access-deny"),
59         T_CONFIG_ARRAY_VLIST,
60         T_CONFIG_SCOPE_CONNECTION }
61      ,{ CONST_STR_LEN("url.access-allow"),
62         T_CONFIG_ARRAY_VLIST,
63         T_CONFIG_SCOPE_CONNECTION }
64      ,{ NULL, 0,
65         T_CONFIG_UNSET,
66         T_CONFIG_SCOPE_UNSET }
67     };
68 
69     plugin_data * const p = p_d;
70     if (!config_plugin_values_init(srv, p, cpk, "mod_access"))
71         return HANDLER_ERROR;
72 
73     /* initialize p->defaults from global config context */
74     if (p->nconfig > 0 && p->cvlist->v.u2[1]) {
75         const config_plugin_value_t *cpv = p->cvlist + p->cvlist->v.u2[0];
76         if (-1 != cpv->k_id)
77             mod_access_merge_config(&p->defaults, cpv);
78     }
79 
80     return HANDLER_GO_ON;
81 }
82 
83 __attribute_cold__
84 static handler_t mod_access_reject (request_st * const r, plugin_data * const p) {
85     if (r->conf.log_request_handling) {
86         if (p->conf.access_allow && p->conf.access_allow->used)
87             log_error(r->conf.errh, __FILE__, __LINE__,
88               "url denied as failed to match any from access_allow %s",
89               r->uri.path.ptr);
90         else
91             log_error(r->conf.errh, __FILE__, __LINE__,
92               "url denied as we match access_deny %s",
93               r->uri.path.ptr);
94     }
95 
96     r->http_status = 403;
97     r->handler_module = NULL;
98     return HANDLER_FINISHED;
99 }
100 
101 static int mod_access_check (const array *allow, const array *deny, const buffer *urlpath, const int lc) {
102 
103     if (allow && allow->used) {
104         const buffer *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 *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