1 #include "first.h" 2 3 #include "plugin.h" 4 #include "log.h" 5 6 #include <string.h> 7 #include <stdlib.h> 8 9 #ifdef HAVE_VALGRIND_VALGRIND_H 10 # include <valgrind/valgrind.h> 11 #endif 12 13 #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC) 14 # include <dlfcn.h> 15 #endif 16 /* 17 * 18 * if you change this enum to add a new callback, be sure 19 * - that PLUGIN_FUNC_SIZEOF is the last entry 20 * - that you add PLUGIN_TO_SLOT twice: 21 * 1. as callback-dispatcher 22 * 2. in plugins_call_init() 23 * 24 */ 25 26 typedef struct { 27 PLUGIN_DATA; 28 } plugin_data; 29 30 typedef enum { 31 PLUGIN_FUNC_UNSET, 32 33 PLUGIN_FUNC_HANDLE_URI_CLEAN, 34 PLUGIN_FUNC_HANDLE_URI_RAW, 35 PLUGIN_FUNC_HANDLE_REQUEST_ENV, 36 PLUGIN_FUNC_HANDLE_REQUEST_DONE, 37 PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, 38 PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, 39 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, 40 PLUGIN_FUNC_HANDLE_TRIGGER, 41 PLUGIN_FUNC_HANDLE_SIGHUP, 42 PLUGIN_FUNC_HANDLE_WAITPID, 43 PLUGIN_FUNC_HANDLE_SUBREQUEST, 44 PLUGIN_FUNC_HANDLE_SUBREQUEST_START, 45 PLUGIN_FUNC_HANDLE_RESPONSE_START, 46 PLUGIN_FUNC_HANDLE_DOCROOT, 47 PLUGIN_FUNC_HANDLE_PHYSICAL, 48 PLUGIN_FUNC_CONNECTION_RESET, 49 PLUGIN_FUNC_INIT, 50 PLUGIN_FUNC_CLEANUP, 51 PLUGIN_FUNC_SET_DEFAULTS, 52 53 PLUGIN_FUNC_SIZEOF 54 } plugin_t; 55 56 static plugin *plugin_init(void) { 57 plugin *p; 58 59 p = calloc(1, sizeof(*p)); 60 force_assert(NULL != p); 61 62 return p; 63 } 64 65 static void plugin_free(plugin *p) { 66 #if !defined(LIGHTTPD_STATIC) 67 int use_dlclose = 1; 68 #endif 69 70 if (p->name) buffer_free(p->name); 71 #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC) 72 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/ 73 #endif 74 75 #if !defined(LIGHTTPD_STATIC) 76 if (use_dlclose && p->lib) { 77 #if defined(__WIN32) 78 ) FreeLibrary(p->lib); 79 #else 80 dlclose(p->lib); 81 #endif 82 } 83 #endif 84 85 free(p); 86 } 87 88 static int plugins_register(server *srv, plugin *p) { 89 plugin **ps; 90 if (0 == srv->plugins.size) { 91 srv->plugins.size = 4; 92 srv->plugins.ptr = malloc(srv->plugins.size * sizeof(*ps)); 93 force_assert(NULL != srv->plugins.ptr); 94 srv->plugins.used = 0; 95 } else if (srv->plugins.used == srv->plugins.size) { 96 srv->plugins.size += 4; 97 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps)); 98 force_assert(NULL != srv->plugins.ptr); 99 } 100 101 ps = srv->plugins.ptr; 102 ps[srv->plugins.used++] = p; 103 104 return 0; 105 } 106 107 /** 108 * 109 * 110 * 111 */ 112 113 #if defined(LIGHTTPD_STATIC) 114 115 /* pre-declare functions, as there is no header for them */ 116 #define PLUGIN_INIT(x)\ 117 int x ## _plugin_init(plugin *p); 118 119 #include "plugin-static.h" 120 121 #undef PLUGIN_INIT 122 123 /* build NULL-terminated table of name + init-function */ 124 125 typedef struct { 126 const char* name; 127 int (*plugin_init)(plugin *p); 128 } plugin_load_functions; 129 130 static const plugin_load_functions load_functions[] = { 131 #define PLUGIN_INIT(x) \ 132 { #x, &x ## _plugin_init }, 133 134 #include "plugin-static.h" 135 136 { NULL, NULL } 137 #undef PLUGIN_INIT 138 }; 139 140 int plugins_load(server *srv) { 141 plugin *p; 142 size_t i, j; 143 144 for (i = 0; i < srv->srvconf.modules->used; i++) { 145 data_string *d = (data_string *)srv->srvconf.modules->data[i]; 146 char *module = d->value->ptr; 147 148 for (j = 0; j < i; j++) { 149 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) { 150 log_error_write(srv, __FILE__, __LINE__, "sbs", 151 "Cannot load plugin", d->value, 152 "more than once, please fix your config (lighttpd may not accept such configs in future releases)"); 153 continue; 154 } 155 } 156 157 for (j = 0; load_functions[j].name; ++j) { 158 if (0 == strcmp(load_functions[j].name, module)) { 159 p = plugin_init(); 160 if ((*load_functions[j].plugin_init)(p)) { 161 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" ); 162 plugin_free(p); 163 return -1; 164 } 165 plugins_register(srv, p); 166 break; 167 } 168 } 169 if (!load_functions[j].name) { 170 log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" ); 171 return -1; 172 } 173 } 174 175 return 0; 176 } 177 #else /* defined(LIGHTTPD_STATIC) */ 178 int plugins_load(server *srv) { 179 plugin *p; 180 int (*init)(plugin *pl); 181 size_t i, j; 182 183 for (i = 0; i < srv->srvconf.modules->used; i++) { 184 data_string *d = (data_string *)srv->srvconf.modules->data[i]; 185 char *module = d->value->ptr; 186 187 for (j = 0; j < i; j++) { 188 if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) { 189 log_error_write(srv, __FILE__, __LINE__, "sbs", 190 "Cannot load plugin", d->value, 191 "more than once, please fix your config (lighttpd may not accept such configs in future releases)"); 192 continue; 193 } 194 } 195 196 buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir); 197 198 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/")); 199 buffer_append_string(srv->tmp_buf, module); 200 #if defined(__WIN32) || defined(__CYGWIN__) 201 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll")); 202 #else 203 buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so")); 204 #endif 205 206 p = plugin_init(); 207 #ifdef __WIN32 208 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) { 209 LPVOID lpMsgBuf; 210 FormatMessage( 211 FORMAT_MESSAGE_ALLOCATE_BUFFER | 212 FORMAT_MESSAGE_FROM_SYSTEM, 213 NULL, 214 GetLastError(), 215 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 216 (LPTSTR) &lpMsgBuf, 217 0, NULL); 218 219 log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", 220 lpMsgBuf, srv->tmp_buf); 221 222 plugin_free(p); 223 224 return -1; 225 226 } 227 #else 228 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) { 229 log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", 230 srv->tmp_buf, dlerror()); 231 232 plugin_free(p); 233 234 return -1; 235 } 236 237 #endif 238 buffer_reset(srv->tmp_buf); 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