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