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 * handler is called twice: 122 * - after the clean up of the URL and 123 * - after the pathinfo checks are done 124 * 125 * this handles the issue of trailing slashes 126 */ 127 URIHANDLER_FUNC(mod_access_uri_handler) { 128 plugin_data *p = p_d; 129 mod_access_patch_config(r, p); 130 if (NULL == p->conf.access_allow && NULL == p->conf.access_deny) 131 return HANDLER_GO_ON; /* access allowed; nothing to match */ 132 133 return mod_access_check(p->conf.access_allow, p->conf.access_deny, 134 &r->uri.path, r->conf.force_lowercase_filenames) 135 ? HANDLER_GO_ON /* access allowed */ 136 : mod_access_reject(r, p); /* access denied */ 137 } 138 139 140 __attribute_cold__ 141 int mod_access_plugin_init(plugin *p); 142 int mod_access_plugin_init(plugin *p) { 143 p->version = LIGHTTPD_VERSION_ID; 144 p->name = "access"; 145 146 p->init = mod_access_init; 147 p->set_defaults = mod_access_set_defaults; 148 p->handle_uri_clean = mod_access_uri_handler; 149 p->handle_subrequest_start = mod_access_uri_handler; 150 151 return 0; 152 } 153