1 #include "first.h" 2 3 #include "plugin.h" 4 #include "base.h" 5 #include "log.h" 6 7 #include <string.h> 8 #include <stdlib.h> 9 10 #ifdef HAVE_VALGRIND_VALGRIND_H 11 # include <valgrind/valgrind.h> 12 #endif 13 14 #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC) 15 # include <dlfcn.h> 16 #endif 17 /* 18 * 19 * if you change this enum to add a new callback, be sure 20 * - that PLUGIN_FUNC_SIZEOF is the last entry 21 * - that you add: 22 * 1. PLUGIN_CALL_... as callback-dispatcher 23 * 2. count and assignment in plugins_call_init() 24 * 25 */ 26 27 typedef enum { 28 PLUGIN_FUNC_HANDLE_URI_CLEAN, 29 PLUGIN_FUNC_HANDLE_URI_RAW, 30 PLUGIN_FUNC_HANDLE_REQUEST_ENV, 31 PLUGIN_FUNC_HANDLE_REQUEST_DONE, 32 PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, 33 PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, 34 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, 35 PLUGIN_FUNC_HANDLE_TRIGGER, 36 PLUGIN_FUNC_HANDLE_SIGHUP, 37 PLUGIN_FUNC_HANDLE_WAITPID, 38 PLUGIN_FUNC_HANDLE_SUBREQUEST, 39 PLUGIN_FUNC_HANDLE_SUBREQUEST_START, 40 PLUGIN_FUNC_HANDLE_RESPONSE_START, 41 PLUGIN_FUNC_HANDLE_DOCROOT, 42 PLUGIN_FUNC_HANDLE_PHYSICAL, 43 PLUGIN_FUNC_CONNECTION_RESET, 44 /* PLUGIN_FUNC_INIT, *//* handled here in plugin.c */ 45 /* PLUGIN_FUNC_CLEANUP, *//* handled here in plugin.c */ 46 PLUGIN_FUNC_SET_DEFAULTS, 47 PLUGIN_FUNC_WORKER_INIT, 48 49 PLUGIN_FUNC_SIZEOF 50 } plugin_t; 51 52 static plugin *plugin_init(void) { 53 plugin *p; 54 55 p = calloc(1, sizeof(*p)); 56 force_assert(NULL != p); 57 58 return p; 59 } 60 61 static void plugin_free(plugin *p) { 62 #if !defined(LIGHTTPD_STATIC) 63 if (p->lib) { 64 #if defined(HAVE_VALGRIND_VALGRIND_H) 65 /*if (!RUNNING_ON_VALGRIND) */ 66 #endif 67 #if defined(__WIN32) 68 FreeLibrary(p->lib); 69 #else 70 dlclose(p->lib); 71 #endif 72 } 73 #endif 74 75 free(p); 76 } 77 78 static void plugins_register(server *srv, plugin *p) { 79 plugin **ps; 80 if (srv->plugins.used == srv->plugins.size) { 81 srv->plugins.size += 4; 82 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps)); 83 force_assert(NULL != srv->plugins.ptr); 84 } 85 86 ps = srv->plugins.ptr; 87 ps[srv->plugins.used++] = p; 88 } 89 90 /** 91 * 92 * 93 * 94 */ 95 96 #if defined(LIGHTTPD_STATIC) 97 98 /* pre-declare functions, as there is no header for them */ 99 #define PLUGIN_INIT(x)\ 100 int x ## _plugin_init(plugin *p); 101 102 #include "plugin-static.h" 103 104 #undef PLUGIN_INIT 105 106 /* build NULL-terminated table of name + init-function */ 107 108 typedef struct { 109 const char* name; 110 int (*plugin_init)(plugin *p); 111 } plugin_load_functions; 112 113 static const plugin_load_functions load_functions[] = { 114 #define PLUGIN_INIT(x) \ 115 { #x, &x ## _plugin_init }, 116 117 #include "plugin-static.h" 118 119 { NULL, NULL } 120 #undef PLUGIN_INIT 121 }; 122 123 int plugins_load(server *srv) { 124 for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { 125 data_string *ds = (data_string *)srv->srvconf.modules->data[i]; 126 char *module = ds->value.ptr; 127 128 uint32_t j; 129 for (j = 0; j < i; ++j) { 130 if (buffer_is_equal(&ds->value, &((data_string *) srv->srvconf.modules->data[j])->value)) { 131 log_error(srv->errh, __FILE__, __LINE__, 132 "Cannot load plugin %s " 133 "more than once, please fix your config (lighttpd may not accept such configs in future releases)", 134 ds->value.ptr); 135 continue; 136 } 137 } 138 139 for (j = 0; load_functions[j].name; ++j) { 140 if (0 == strcmp(load_functions[j].name, module)) { 141 plugin * const p = plugin_init(); 142 if ((*load_functions[j].plugin_init)(p)) { 143 log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module); 144 plugin_free(p); 145 return -1; 146 } 147 plugins_register(srv, p); 148 break; 149 } 150 } 151 if (!load_functions[j].name) { 152 log_error(srv->errh, __FILE__, __LINE__, "%s plugin not found", module); 153 return -1; 154 } 155 } 156 157 return 0; 158 } 159 #else /* defined(LIGHTTPD_STATIC) */ 160 int plugins_load(server *srv) { 161 plugin *p; 162 int (*init)(plugin *pl); 163 size_t i, j; 164 165 for (i = 0; i < srv->srvconf.modules->used; i++) { 166 data_string *ds = (data_string *)srv->srvconf.modules->data[i]; 167 char *module = ds->value.ptr; 168 169 for (j = 0; j < i; j++) { 170 if (buffer_is_equal(&ds->value, &((data_string *) srv->srvconf.modules->data[j])->value)) { 171 log_error(srv->errh, __FILE__, __LINE__, 172 "Cannot load plugin %s " 173 "more than once, please fix your config (lighttpd may not accept such configs in future releases)", 174 ds->value.ptr); 175 continue; 176 } 177 } 178 179 buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir); 180 181 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/")); 182 buffer_append_string(srv->tmp_buf, module); 183 #if defined(__WIN32) || defined(__CYGWIN__) 184 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll")); 185 #else 186 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so")); 187 #endif 188 189 p = plugin_init(); 190 #ifdef __WIN32 191 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) { 192 LPVOID lpMsgBuf; 193 FormatMessage( 194 FORMAT_MESSAGE_ALLOCATE_BUFFER | 195 FORMAT_MESSAGE_FROM_SYSTEM, 196 NULL, 197 GetLastError(), 198 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 199 (LPTSTR) &lpMsgBuf, 200 0, NULL); 201 202 log_error(srv->errh, __FILE__, __LINE__, 203 "LoadLibrary() failed %s %s", lpMsgBuf, srv->tmp_buf->ptr); 204 205 plugin_free(p); 206 207 return -1; 208 209 } 210 #else 211 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) { 212 log_error(srv->errh, __FILE__, __LINE__, 213 "dlopen() failed for: %s %s", srv->tmp_buf->ptr, dlerror()); 214 215 plugin_free(p); 216 217 return -1; 218 } 219 220 #endif 221 buffer_copy_string(srv->tmp_buf, module); 222 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init")); 223 224 #ifdef __WIN32 225 init = GetProcAddress(p->lib, srv->tmp_buf->ptr); 226 227 if (init == NULL) { 228 LPVOID lpMsgBuf; 229 FormatMessage( 230 FORMAT_MESSAGE_ALLOCATE_BUFFER | 231 FORMAT_MESSAGE_FROM_SYSTEM, 232 NULL, 233 GetLastError(), 234 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 235 (LPTSTR) &lpMsgBuf, 236 0, NULL); 237 238 log_error(srv->errh, __FILE__, __LINE__, 239 "getprocaddress failed: %s %s", srv->tmp_buf->ptr, lpMsgBuf); 240 241 plugin_free(p); 242 return -1; 243 } 244 245 #else 246 #if 1 247 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr); 248 #else 249 *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr); 250 #endif 251 if (NULL == init) { 252 const char *error = dlerror(); 253 if (error != NULL) { 254 log_error(srv->errh, __FILE__, __LINE__, "dlsym: %s", error); 255 } else { 256 log_error(srv->errh, __FILE__, __LINE__, "dlsym symbol not found: %s", srv->tmp_buf->ptr); 257 } 258 259 plugin_free(p); 260 return -1; 261 } 262 263 #endif 264 if ((*init)(p)) { 265 log_error(srv->errh, __FILE__, __LINE__, "%s plugin init failed", module); 266 267 plugin_free(p); 268 return -1; 269 } 270 #if 0 271 log_error(srv->errh, __FILE__, __LINE__, "%s plugin loaded", module); 272 #endif 273 plugins_register(srv, p); 274 } 275 276 return 0; 277 } 278 #endif /* defined(LIGHTTPD_STATIC) */ 279 280 typedef struct { 281 handler_t(*fn)(); 282 plugin_data_base *data; 283 } plugin_fn_data; 284 285 __attribute_hot__ 286 static handler_t plugins_call_fn_con_data(connection * const con, const int e) { 287 const void * const plugin_slots = con->plugin_slots; 288 const uint32_t offset = ((const uint16_t *)plugin_slots)[e]; 289 if (0 == offset) return HANDLER_GO_ON; 290 const plugin_fn_data *plfd = (const plugin_fn_data *) 291 (((uintptr_t)plugin_slots) + offset); 292 handler_t rc = HANDLER_GO_ON; 293 while (plfd->fn && (rc = plfd->fn(con, plfd->data)) == HANDLER_GO_ON) 294 ++plfd; 295 return rc; 296 } 297 298 static handler_t plugins_call_fn_srv_data(server * const srv, const int e) { 299 const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e]; 300 if (0 == offset) return HANDLER_GO_ON; 301 const plugin_fn_data *plfd = (const plugin_fn_data *) 302 (((uintptr_t)srv->plugin_slots) + offset); 303 handler_t rc = HANDLER_GO_ON; 304 while (plfd->fn && (rc = plfd->fn(srv,plfd->data)) == HANDLER_GO_ON) 305 ++plfd; 306 return rc; 307 } 308 309 static void plugins_call_fn_srv_data_all(server * const srv, const int e) { 310 const uint32_t offset = ((const uint16_t *)srv->plugin_slots)[e]; 311 if (0 == offset) return; 312 const plugin_fn_data *plfd = (const plugin_fn_data *) 313 (((uintptr_t)srv->plugin_slots) + offset); 314 for (; plfd->fn; ++plfd) 315 plfd->fn(srv, plfd->data); 316 } 317 318 /** 319 * plugins that use 320 * 321 * - server *srv 322 * - connection *con 323 * - void *p_d (plugin_data *) 324 */ 325 326 #define PLUGIN_CALL_FN_CON_DATA(x, y) \ 327 handler_t plugins_call_##y(connection *con) {\ 328 return plugins_call_fn_con_data(con, x); \ 329 } 330 331 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean) 332 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw) 333 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env) 334 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done) 335 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept) 336 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr) 337 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) 338 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest) 339 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start) 340 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start) 341 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot) 342 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical) 343 PLUGIN_CALL_FN_CON_DATA(PLUGIN_FUNC_CONNECTION_RESET, connection_reset) 344 345 #undef PLUGIN_CALL_FN_SRV_CON_DATA 346 347 /** 348 * plugins that use 349 * 350 * - server *srv 351 * - void *p_d (plugin_data *) 352 */ 353 354 handler_t plugins_call_set_defaults(server *srv) { 355 return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_SET_DEFAULTS); 356 } 357 358 handler_t plugins_call_worker_init(server *srv) { 359 return plugins_call_fn_srv_data(srv, PLUGIN_FUNC_WORKER_INIT); 360 } 361 362 void plugins_call_handle_trigger(server *srv) { 363 plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_TRIGGER); 364 } 365 366 void plugins_call_handle_sighup(server *srv) { 367 plugins_call_fn_srv_data_all(srv, PLUGIN_FUNC_HANDLE_SIGHUP); 368 } 369 370 handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status) { 371 const uint32_t offset = 372 ((const uint16_t *)srv->plugin_slots)[PLUGIN_FUNC_HANDLE_WAITPID]; 373 if (0 == offset) return HANDLER_GO_ON; 374 const plugin_fn_data *plfd = (const plugin_fn_data *) 375 (((uintptr_t)srv->plugin_slots) + offset); 376 handler_t rc = HANDLER_GO_ON; 377 while (plfd->fn&&(rc=plfd->fn(srv,plfd->data,pid,status))==HANDLER_GO_ON) 378 ++plfd; 379 return rc; 380 } 381 382 static void plugins_call_cleanup(server * const srv) { 383 plugin ** const ps = srv->plugins.ptr; 384 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 385 plugin *p = ps[i]; 386 if (NULL == p) continue; 387 if (NULL != p->data) { 388 plugin_data_base *pd = p->data; 389 if (p->cleanup) 390 p->cleanup(p->data); 391 free(pd->cvlist); 392 free(pd); 393 p->data = NULL; 394 } 395 } 396 } 397 398 /** 399 * 400 * - call init function of all plugins to init the plugin-internals 401 * - added each plugin that supports has callback to the corresponding slot 402 * 403 * - is only called once. 404 */ 405 406 __attribute_cold__ 407 static void plugins_call_init_slot(server *srv, handler_t(*fn)(), void *data, const uint32_t offset) { 408 if (fn) { 409 plugin_fn_data *plfd = (plugin_fn_data *) 410 (((uintptr_t)srv->plugin_slots) + offset); 411 while (plfd->fn) ++plfd; 412 plfd->fn = fn; 413 plfd->data = data; 414 } 415 } 416 417 handler_t plugins_call_init(server *srv) { 418 plugin ** const ps = srv->plugins.ptr; 419 uint16_t offsets[PLUGIN_FUNC_SIZEOF]; 420 memset(offsets, 0, sizeof(offsets)); 421 422 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 423 /* check which calls are supported */ 424 425 plugin *p = ps[i]; 426 427 if (p->init) { 428 if (NULL == (p->data = p->init())) { 429 log_error(srv->errh, __FILE__, __LINE__, 430 "plugin-init failed for module %s", p->name); 431 return HANDLER_ERROR; 432 } 433 434 /* used for con->mode, DIRECT == 0, plugins above that */ 435 ((plugin_data_base *)(p->data))->id = i + 1; 436 437 if (p->version != LIGHTTPD_VERSION_ID) { 438 log_error(srv->errh, __FILE__, __LINE__, 439 "plugin-version doesn't match lighttpd-version for %s", p->name); 440 return HANDLER_ERROR; 441 } 442 } 443 444 if (p->priv_defaults && HANDLER_ERROR==p->priv_defaults(srv, p->data)) { 445 return HANDLER_ERROR; 446 } 447 448 if (p->handle_uri_clean) 449 ++offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]; 450 if (p->handle_uri_raw) 451 ++offsets[PLUGIN_FUNC_HANDLE_URI_RAW]; 452 if (p->handle_request_env) 453 ++offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV]; 454 if (p->handle_request_done) 455 ++offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE]; 456 if (p->handle_connection_accept) 457 ++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT]; 458 if (p->handle_connection_shut_wr) 459 ++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR]; 460 if (p->handle_connection_close) 461 ++offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]; 462 if (p->handle_trigger) 463 ++offsets[PLUGIN_FUNC_HANDLE_TRIGGER]; 464 if (p->handle_sighup) 465 ++offsets[PLUGIN_FUNC_HANDLE_SIGHUP]; 466 if (p->handle_waitpid) 467 ++offsets[PLUGIN_FUNC_HANDLE_WAITPID]; 468 if (p->handle_subrequest) 469 ++offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST]; 470 if (p->handle_subrequest_start) 471 ++offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START]; 472 if (p->handle_response_start) 473 ++offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START]; 474 if (p->handle_docroot) 475 ++offsets[PLUGIN_FUNC_HANDLE_DOCROOT]; 476 if (p->handle_physical) 477 ++offsets[PLUGIN_FUNC_HANDLE_PHYSICAL]; 478 if (p->connection_reset) 479 ++offsets[PLUGIN_FUNC_CONNECTION_RESET]; 480 if (p->set_defaults) 481 ++offsets[PLUGIN_FUNC_SET_DEFAULTS]; 482 if (p->worker_init) 483 ++offsets[PLUGIN_FUNC_WORKER_INIT]; 484 } 485 486 uint32_t nslots = 487 (sizeof(offsets)+sizeof(plugin_fn_data)-1) / sizeof(plugin_fn_data); 488 for (uint32_t i = 0; i < PLUGIN_FUNC_SIZEOF; ++i) { 489 if (offsets[i]) { 490 uint32_t offset = nslots; 491 nslots += offsets[i]+1; /* +1 to mark end of each list */ 492 force_assert(offset * sizeof(plugin_fn_data) <= USHRT_MAX); 493 offsets[i] = (uint16_t)(offset * sizeof(plugin_fn_data)); 494 } 495 } 496 497 /* allocate and fill slots of two dimensional array */ 498 srv->plugin_slots = calloc(nslots, sizeof(plugin_fn_data)); 499 force_assert(NULL != srv->plugin_slots); 500 memcpy(srv->plugin_slots, offsets, sizeof(offsets)); 501 502 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 503 plugin * const p = ps[i]; 504 505 plugins_call_init_slot(srv, p->handle_uri_clean, p->data, 506 offsets[PLUGIN_FUNC_HANDLE_URI_CLEAN]); 507 plugins_call_init_slot(srv, p->handle_uri_raw, p->data, 508 offsets[PLUGIN_FUNC_HANDLE_URI_RAW]); 509 plugins_call_init_slot(srv, p->handle_request_env, p->data, 510 offsets[PLUGIN_FUNC_HANDLE_REQUEST_ENV]); 511 plugins_call_init_slot(srv, p->handle_request_done, p->data, 512 offsets[PLUGIN_FUNC_HANDLE_REQUEST_DONE]); 513 plugins_call_init_slot(srv, p->handle_connection_accept, p->data, 514 offsets[PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT]); 515 plugins_call_init_slot(srv, p->handle_connection_shut_wr, p->data, 516 offsets[PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR]); 517 plugins_call_init_slot(srv, p->handle_connection_close, p->data, 518 offsets[PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE]); 519 plugins_call_init_slot(srv, p->handle_trigger, p->data, 520 offsets[PLUGIN_FUNC_HANDLE_TRIGGER]); 521 plugins_call_init_slot(srv, p->handle_sighup, p->data, 522 offsets[PLUGIN_FUNC_HANDLE_SIGHUP]); 523 plugins_call_init_slot(srv, p->handle_waitpid, p->data, 524 offsets[PLUGIN_FUNC_HANDLE_WAITPID]); 525 plugins_call_init_slot(srv, p->handle_subrequest, p->data, 526 offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST]); 527 plugins_call_init_slot(srv, p->handle_subrequest_start, p->data, 528 offsets[PLUGIN_FUNC_HANDLE_SUBREQUEST_START]); 529 plugins_call_init_slot(srv, p->handle_response_start, p->data, 530 offsets[PLUGIN_FUNC_HANDLE_RESPONSE_START]); 531 plugins_call_init_slot(srv, p->handle_docroot, p->data, 532 offsets[PLUGIN_FUNC_HANDLE_DOCROOT]); 533 plugins_call_init_slot(srv, p->handle_physical, p->data, 534 offsets[PLUGIN_FUNC_HANDLE_PHYSICAL]); 535 plugins_call_init_slot(srv, p->connection_reset, p->data, 536 offsets[PLUGIN_FUNC_CONNECTION_RESET]); 537 plugins_call_init_slot(srv, p->set_defaults, p->data, 538 offsets[PLUGIN_FUNC_SET_DEFAULTS]); 539 plugins_call_init_slot(srv, p->worker_init, p->data, 540 offsets[PLUGIN_FUNC_WORKER_INIT]); 541 } 542 543 return HANDLER_GO_ON; 544 } 545 546 void plugins_free(server *srv) { 547 if (srv->plugin_slots) { 548 plugins_call_cleanup(srv); 549 free(srv->plugin_slots); 550 srv->plugin_slots = NULL; 551 } 552 553 for (uint32_t i = 0; i < srv->plugins.used; ++i) { 554 plugin_free(((plugin **)srv->plugins.ptr)[i]); 555 } 556 free(srv->plugins.ptr); 557 srv->plugins.ptr = NULL; 558 srv->plugins.used = 0; 559 srv->plugins.size = 0; 560 } 561