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