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_reset(srv->tmp_buf); 240 buffer_copy_string(srv->tmp_buf, module); 241 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init")); 242 243 #ifdef __WIN32 244 init = GetProcAddress(p->lib, srv->tmp_buf->ptr); 245 246 if (init == NULL) { 247 LPVOID lpMsgBuf; 248 FormatMessage( 249 FORMAT_MESSAGE_ALLOCATE_BUFFER | 250 FORMAT_MESSAGE_FROM_SYSTEM, 251 NULL, 252 GetLastError(), 253 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 254 (LPTSTR) &lpMsgBuf, 255 0, NULL); 256 257 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf); 258 259 plugin_free(p); 260 return -1; 261 } 262 263 #else 264 #if 1 265 init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr); 266 #else 267 *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr); 268 #endif 269 if (NULL == init) { 270 const char *error = dlerror(); 271 if (error != NULL) { 272 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym:", error); 273 } else { 274 log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym symbol not found:", srv->tmp_buf->ptr); 275 } 276 277 plugin_free(p); 278 return -1; 279 } 280 281 #endif 282 if ((*init)(p)) { 283 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" ); 284 285 plugin_free(p); 286 return -1; 287 } 288 #if 0 289 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" ); 290 #endif 291 plugins_register(srv, p); 292 } 293 294 return 0; 295 } 296 #endif /* defined(LIGHTTPD_STATIC) */ 297 298 #define PLUGIN_TO_SLOT(x, y) \ 299 handler_t plugins_call_##y(server *srv, connection *con) {\ 300 plugin **slot;\ 301 size_t j;\ 302 slot = ((plugin ***)(srv->plugin_slots))[x];\ 303 if (!slot) return HANDLER_GO_ON;\ 304 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 305 plugin *p = slot[j];\ 306 handler_t r;\ 307 switch(r = p->y(srv, con, p->data)) {\ 308 case HANDLER_GO_ON:\ 309 break;\ 310 case HANDLER_FINISHED:\ 311 case HANDLER_COMEBACK:\ 312 case HANDLER_WAIT_FOR_EVENT:\ 313 case HANDLER_WAIT_FOR_FD:\ 314 case HANDLER_ERROR:\ 315 return r;\ 316 default:\ 317 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\ 318 return HANDLER_ERROR;\ 319 }\ 320 }\ 321 return HANDLER_GO_ON;\ 322 } 323 324 /** 325 * plugins that use 326 * 327 * - server *srv 328 * - connection *con 329 * - void *p_d (plugin_data *) 330 */ 331 332 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean) 333 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw) 334 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env) 335 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done) 336 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept) 337 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr) 338 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) 339 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest) 340 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start) 341 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start) 342 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot) 343 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical) 344 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset) 345 346 #undef PLUGIN_TO_SLOT 347 348 #define PLUGIN_TO_SLOT(x, y) \ 349 handler_t plugins_call_##y(server *srv) {\ 350 plugin **slot;\ 351 size_t j;\ 352 if (!srv->plugin_slots) return HANDLER_GO_ON;\ 353 slot = ((plugin ***)(srv->plugin_slots))[x];\ 354 if (!slot) return HANDLER_GO_ON;\ 355 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 356 plugin *p = slot[j];\ 357 handler_t r;\ 358 switch(r = p->y(srv, p->data)) {\ 359 case HANDLER_GO_ON:\ 360 break;\ 361 case HANDLER_FINISHED:\ 362 case HANDLER_COMEBACK:\ 363 case HANDLER_WAIT_FOR_EVENT:\ 364 case HANDLER_WAIT_FOR_FD:\ 365 case HANDLER_ERROR:\ 366 return r;\ 367 default:\ 368 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\ 369 return HANDLER_ERROR;\ 370 }\ 371 }\ 372 return HANDLER_GO_ON;\ 373 } 374 375 /** 376 * plugins that use 377 * 378 * - server *srv 379 * - void *p_d (plugin_data *) 380 */ 381 382 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger) 383 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup) 384 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup) 385 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults) 386 387 #undef PLUGIN_TO_SLOT 388 389 handler_t plugins_call_handle_waitpid(server *srv, pid_t pid, int status) { 390 plugin ** const slot = 391 ((plugin ***)(srv->plugin_slots))[PLUGIN_FUNC_HANDLE_WAITPID]; 392 if (!slot) return HANDLER_GO_ON; 393 for (size_t i = 0; i < srv->plugins.used && slot[i]; ++i) { 394 plugin *p = slot[i]; 395 handler_t r = p->handle_waitpid(srv, p->data, pid, status); 396 if (r != HANDLER_GO_ON) return r; 397 } 398 return HANDLER_GO_ON; 399 } 400 401 #if 0 402 /** 403 * 404 * special handler 405 * 406 */ 407 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) { 408 size_t i; 409 plugin **ps; 410 411 ps = srv->plugins.ptr; 412 413 for (i = 0; i < srv->plugins.used; i++) { 414 plugin *p = ps[i]; 415 if (p->handle_fdevent) { 416 handler_t r; 417 switch(r = p->handle_fdevent(srv, fdc, p->data)) { 418 case HANDLER_GO_ON: 419 break; 420 case HANDLER_FINISHED: 421 case HANDLER_COMEBACK: 422 case HANDLER_WAIT_FOR_EVENT: 423 case HANDLER_ERROR: 424 return r; 425 default: 426 log_error_write(srv, __FILE__, __LINE__, "d", r); 427 break; 428 } 429 } 430 } 431 432 return HANDLER_GO_ON; 433 } 434 #endif 435 /** 436 * 437 * - call init function of all plugins to init the plugin-internals 438 * - added each plugin that supports has callback to the corresponding slot 439 * 440 * - is only called once. 441 */ 442 443 handler_t plugins_call_init(server *srv) { 444 size_t i; 445 plugin **ps; 446 447 ps = srv->plugins.ptr; 448 449 /* fill slots */ 450 451 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps)); 452 force_assert(NULL != srv->plugin_slots); 453 454 for (i = 0; i < srv->plugins.used; i++) { 455 size_t j; 456 /* check which calls are supported */ 457 458 plugin *p = ps[i]; 459 460 #define PLUGIN_TO_SLOT(x, y) \ 461 if (p->y) { \ 462 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \ 463 if (!slot) { \ 464 slot = calloc(srv->plugins.used, sizeof(*slot));\ 465 force_assert(NULL != slot); \ 466 ((plugin ***)(srv->plugin_slots))[x] = slot; \ 467 } \ 468 for (j = 0; j < srv->plugins.used; j++) { \ 469 if (slot[j]) continue;\ 470 slot[j] = p;\ 471 break;\ 472 }\ 473 } 474 475 476 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 477 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 478 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env); 479 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done); 480 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept); 481 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr); 482 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close); 483 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger); 484 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup); 485 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_WAITPID, handle_waitpid); 486 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest); 487 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start); 488 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start); 489 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot); 490 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical); 491 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset); 492 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup); 493 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults); 494 #undef PLUGIN_TO_SLOT 495 496 if (p->init) { 497 if (NULL == (p->data = p->init())) { 498 log_error_write(srv, __FILE__, __LINE__, "sb", 499 "plugin-init failed for module", p->name); 500 return HANDLER_ERROR; 501 } 502 503 /* used for con->mode, DIRECT == 0, plugins above that */ 504 ((plugin_data *)(p->data))->id = i + 1; 505 506 if (p->version != LIGHTTPD_VERSION_ID) { 507 log_error_write(srv, __FILE__, __LINE__, "sb", 508 "plugin-version doesn't match lighttpd-version for", p->name); 509 return HANDLER_ERROR; 510 } 511 } else { 512 p->data = NULL; 513 } 514 515 if (p->priv_defaults && HANDLER_ERROR==p->priv_defaults(srv, p->data)) { 516 return HANDLER_ERROR; 517 } 518 } 519 520 return HANDLER_GO_ON; 521 } 522 523 void plugins_free(server *srv) { 524 size_t i; 525 plugins_call_cleanup(srv); 526 527 for (i = 0; i < srv->plugins.used; i++) { 528 plugin *p = ((plugin **)srv->plugins.ptr)[i]; 529 530 plugin_free(p); 531 } 532 533 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) { 534 plugin **slot = ((plugin ***)(srv->plugin_slots))[i]; 535 536 if (slot) free(slot); 537 } 538 539 free(srv->plugin_slots); 540 srv->plugin_slots = NULL; 541 542 free(srv->plugins.ptr); 543 srv->plugins.ptr = NULL; 544 srv->plugins.used = 0; 545 } 546