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