1#include "base.h" 2#include "log.h" 3#include "buffer.h" 4 5#include "plugin.h" 6 7#include <ctype.h> 8#include <stdlib.h> 9#include <string.h> 10 11typedef struct { 12 array *access_deny; 13} plugin_config; 14 15typedef struct { 16 PLUGIN_DATA; 17 18 plugin_config **config_storage; 19 20 plugin_config conf; 21} plugin_data; 22 23INIT_FUNC(mod_access_init) { 24 plugin_data *p; 25 26 p = calloc(1, sizeof(*p)); 27 28 return p; 29} 30 31FREE_FUNC(mod_access_free) { 32 plugin_data *p = p_d; 33 34 UNUSED(srv); 35 36 if (!p) return HANDLER_GO_ON; 37 38 if (p->config_storage) { 39 size_t i; 40 for (i = 0; i < srv->config_context->used; i++) { 41 plugin_config *s = p->config_storage[i]; 42 43 if (NULL == s) continue; 44 45 array_free(s->access_deny); 46 47 free(s); 48 } 49 free(p->config_storage); 50 } 51 52 free(p); 53 54 return HANDLER_GO_ON; 55} 56 57SETDEFAULTS_FUNC(mod_access_set_defaults) { 58 plugin_data *p = p_d; 59 size_t i = 0; 60 61 config_values_t cv[] = { 62 { "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, 63 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } 64 }; 65 66 p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *)); 67 68 for (i = 0; i < srv->config_context->used; i++) { 69 data_config const* config = (data_config const*)srv->config_context->data[i]; 70 plugin_config *s; 71 72 s = calloc(1, sizeof(plugin_config)); 73 s->access_deny = array_init(); 74 75 cv[0].destination = s->access_deny; 76 77 p->config_storage[i] = s; 78 79 if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) { 80 return HANDLER_ERROR; 81 } 82 } 83 84 return HANDLER_GO_ON; 85} 86 87#define PATCH(x) \ 88 p->conf.x = s->x; 89static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) { 90 size_t i, j; 91 plugin_config *s = p->config_storage[0]; 92 93 PATCH(access_deny); 94 95 /* skip the first, the global context */ 96 for (i = 1; i < srv->config_context->used; i++) { 97 data_config *dc = (data_config *)srv->config_context->data[i]; 98 s = p->config_storage[i]; 99 100 /* condition didn't match */ 101 if (!config_check_cond(srv, con, dc)) continue; 102 103 /* merge config */ 104 for (j = 0; j < dc->value->used; j++) { 105 data_unset *du = dc->value->data[j]; 106 107 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) { 108 PATCH(access_deny); 109 } 110 } 111 } 112 113 return 0; 114} 115#undef PATCH 116 117/** 118 * URI handler 119 * 120 * we will get called twice: 121 * - after the clean up of the URL and 122 * - after the pathinfo checks are done 123 * 124 * this handles the issue of trailing slashes 125 */ 126URIHANDLER_FUNC(mod_access_uri_handler) { 127 plugin_data *p = p_d; 128 int s_len; 129 size_t k; 130 131 if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON; 132 133 mod_access_patch_connection(srv, con, p); 134 135 s_len = buffer_string_length(con->uri.path); 136 137 if (con->conf.log_request_handling) { 138 log_error_write(srv, __FILE__, __LINE__, "s", 139 "-- mod_access_uri_handler called"); 140 } 141 142 for (k = 0; k < p->conf.access_deny->used; k++) { 143 data_string *ds = (data_string *)p->conf.access_deny->data[k]; 144 int ct_len = buffer_string_length(ds->value); 145 int denied = 0; 146 147 148 if (ct_len > s_len) continue; 149 if (buffer_is_empty(ds->value)) continue; 150 151 /* if we have a case-insensitive FS we have to lower-case the URI here too */ 152 153 if (con->conf.force_lowercase_filenames) { 154 if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { 155 denied = 1; 156 } 157 } else { 158 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { 159 denied = 1; 160 } 161 } 162 163 if (denied) { 164 con->http_status = 403; 165 con->mode = DIRECT; 166 167 if (con->conf.log_request_handling) { 168 log_error_write(srv, __FILE__, __LINE__, "sb", 169 "url denied as we match:", ds->value); 170 } 171 172 return HANDLER_FINISHED; 173 } 174 } 175 176 /* not found */ 177 return HANDLER_GO_ON; 178} 179 180 181int mod_access_plugin_init(plugin *p); 182int mod_access_plugin_init(plugin *p) { 183 p->version = LIGHTTPD_VERSION_ID; 184 p->name = buffer_init_string("access"); 185 186 p->init = mod_access_init; 187 p->set_defaults = mod_access_set_defaults; 188 p->handle_uri_clean = mod_access_uri_handler; 189 p->handle_subrequest_start = mod_access_uri_handler; 190 p->cleanup = mod_access_free; 191 192 p->data = NULL; 193 194 return 0; 195} 196