1 #include "first.h" 2 3 #include "plugin.h" 4 #include "log.h" 5 6 #include <string.h> 7 #include <stdlib.h> 8 9 #include <stdio.h> 10 11 #ifdef HAVE_VALGRIND_VALGRIND_H 12 # include <valgrind/valgrind.h> 13 #endif 14 15 #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC) 16 # include <dlfcn.h> 17 #endif 18 /* 19 * 20 * if you change this enum to add a new callback, be sure 21 * - that PLUGIN_FUNC_SIZEOF is the last entry 22 * - that you add PLUGIN_TO_SLOT twice: 23 * 1. as callback-dispatcher 24 * 2. in plugins_call_init() 25 * 26 */ 27 28 typedef struct { 29 PLUGIN_DATA; 30 } plugin_data; 31 32 typedef enum { 33 PLUGIN_FUNC_UNSET, 34 35 PLUGIN_FUNC_HANDLE_URI_CLEAN, 36 PLUGIN_FUNC_HANDLE_URI_RAW, 37 PLUGIN_FUNC_HANDLE_REQUEST_ENV, 38 PLUGIN_FUNC_HANDLE_REQUEST_DONE, 39 PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, 40 PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, 41 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, 42 PLUGIN_FUNC_HANDLE_TRIGGER, 43 PLUGIN_FUNC_HANDLE_SIGHUP, 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 if (!srv->plugin_slots) return HANDLER_GO_ON;\ 303 slot = ((plugin ***)(srv->plugin_slots))[x];\ 304 if (!slot) return HANDLER_GO_ON;\ 305 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 306 plugin *p = slot[j];\ 307 handler_t r;\ 308 switch(r = p->y(srv, con, p->data)) {\ 309 case HANDLER_GO_ON:\ 310 break;\ 311 case HANDLER_FINISHED:\ 312 case HANDLER_COMEBACK:\ 313 case HANDLER_WAIT_FOR_EVENT:\ 314 case HANDLER_WAIT_FOR_FD:\ 315 case HANDLER_ERROR:\ 316 return r;\ 317 default:\ 318 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\ 319 return HANDLER_ERROR;\ 320 }\ 321 }\ 322 return HANDLER_GO_ON;\ 323 } 324 325 /** 326 * plugins that use 327 * 328 * - server *srv 329 * - connection *con 330 * - void *p_d (plugin_data *) 331 */ 332 333 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean) 334 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw) 335 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env) 336 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done) 337 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept) 338 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr) 339 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) 340 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest) 341 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start) 342 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start) 343 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot) 344 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical) 345 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset) 346 347 #undef PLUGIN_TO_SLOT 348 349 #define PLUGIN_TO_SLOT(x, y) \ 350 handler_t plugins_call_##y(server *srv) {\ 351 plugin **slot;\ 352 size_t j;\ 353 if (!srv->plugin_slots) return HANDLER_GO_ON;\ 354 slot = ((plugin ***)(srv->plugin_slots))[x];\ 355 if (!slot) return HANDLER_GO_ON;\ 356 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 357 plugin *p = slot[j];\ 358 handler_t r;\ 359 switch(r = p->y(srv, p->data)) {\ 360 case HANDLER_GO_ON:\ 361 break;\ 362 case HANDLER_FINISHED:\ 363 case HANDLER_COMEBACK:\ 364 case HANDLER_WAIT_FOR_EVENT:\ 365 case HANDLER_WAIT_FOR_FD:\ 366 case HANDLER_ERROR:\ 367 return r;\ 368 default:\ 369 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\ 370 return HANDLER_ERROR;\ 371 }\ 372 }\ 373 return HANDLER_GO_ON;\ 374 } 375 376 /** 377 * plugins that use 378 * 379 * - server *srv 380 * - void *p_d (plugin_data *) 381 */ 382 383 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger) 384 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup) 385 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup) 386 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults) 387 388 #undef PLUGIN_TO_SLOT 389 390 #if 0 391 /** 392 * 393 * special handler 394 * 395 */ 396 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) { 397 size_t i; 398 plugin **ps; 399 400 ps = srv->plugins.ptr; 401 402 for (i = 0; i < srv->plugins.used; i++) { 403 plugin *p = ps[i]; 404 if (p->handle_fdevent) { 405 handler_t r; 406 switch(r = p->handle_fdevent(srv, fdc, p->data)) { 407 case HANDLER_GO_ON: 408 break; 409 case HANDLER_FINISHED: 410 case HANDLER_COMEBACK: 411 case HANDLER_WAIT_FOR_EVENT: 412 case HANDLER_ERROR: 413 return r; 414 default: 415 log_error_write(srv, __FILE__, __LINE__, "d", r); 416 break; 417 } 418 } 419 } 420 421 return HANDLER_GO_ON; 422 } 423 #endif 424 /** 425 * 426 * - call init function of all plugins to init the plugin-internals 427 * - added each plugin that supports has callback to the corresponding slot 428 * 429 * - is only called once. 430 */ 431 432 handler_t plugins_call_init(server *srv) { 433 size_t i; 434 plugin **ps; 435 436 ps = srv->plugins.ptr; 437 438 /* fill slots */ 439 440 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps)); 441 force_assert(NULL != srv->plugin_slots); 442 443 for (i = 0; i < srv->plugins.used; i++) { 444 size_t j; 445 /* check which calls are supported */ 446 447 plugin *p = ps[i]; 448 449 #define PLUGIN_TO_SLOT(x, y) \ 450 if (p->y) { \ 451 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \ 452 if (!slot) { \ 453 slot = calloc(srv->plugins.used, sizeof(*slot));\ 454 force_assert(NULL != slot); \ 455 ((plugin ***)(srv->plugin_slots))[x] = slot; \ 456 } \ 457 for (j = 0; j < srv->plugins.used; j++) { \ 458 if (slot[j]) continue;\ 459 slot[j] = p;\ 460 break;\ 461 }\ 462 } 463 464 465 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 466 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 467 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_ENV, handle_request_env); 468 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done); 469 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_ACCEPT, handle_connection_accept); 470 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_SHUT_WR, handle_connection_shut_wr); 471 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close); 472 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger); 473 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup); 474 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest); 475 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start); 476 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_START, handle_response_start); 477 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot); 478 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical); 479 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset); 480 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup); 481 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults); 482 #undef PLUGIN_TO_SLOT 483 484 if (p->init) { 485 if (NULL == (p->data = p->init())) { 486 log_error_write(srv, __FILE__, __LINE__, "sb", 487 "plugin-init failed for module", p->name); 488 return HANDLER_ERROR; 489 } 490 491 /* used for con->mode, DIRECT == 0, plugins above that */ 492 ((plugin_data *)(p->data))->id = i + 1; 493 494 if (p->version != LIGHTTPD_VERSION_ID) { 495 log_error_write(srv, __FILE__, __LINE__, "sb", 496 "plugin-version doesn't match lighttpd-version for", p->name); 497 return HANDLER_ERROR; 498 } 499 } else { 500 p->data = NULL; 501 } 502 } 503 504 return HANDLER_GO_ON; 505 } 506 507 void plugins_free(server *srv) { 508 size_t i; 509 plugins_call_cleanup(srv); 510 511 for (i = 0; i < srv->plugins.used; i++) { 512 plugin *p = ((plugin **)srv->plugins.ptr)[i]; 513 514 plugin_free(p); 515 } 516 517 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) { 518 plugin **slot = ((plugin ***)(srv->plugin_slots))[i]; 519 520 if (slot) free(slot); 521 } 522 523 free(srv->plugin_slots); 524 srv->plugin_slots = NULL; 525 526 free(srv->plugins.ptr); 527 srv->plugins.ptr = NULL; 528 srv->plugins.used = 0; 529 } 530