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