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 21 INIT_FUNC(mod_access_init) { 22 return ck_calloc(1, sizeof(plugin_data)); 23 } 24 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 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 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 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__ 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__ 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 */ 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); 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