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