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 const char *error; 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 ((error = dlerror()) != NULL) { 267 log_error_write(srv, __FILE__, __LINE__, "s", error); 268 269 plugin_free(p); 270 return -1; 271 } 272 273 #endif 274 if ((*init)(p)) { 275 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" ); 276 277 plugin_free(p); 278 return -1; 279 } 280 #if 0 281 log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" ); 282 #endif 283 plugins_register(srv, p); 284 } 285 286 return 0; 287 } 288 #endif /* defined(LIGHTTPD_STATIC) */ 289 290 #define PLUGIN_TO_SLOT(x, y) \ 291 handler_t plugins_call_##y(server *srv, connection *con) {\ 292 plugin **slot;\ 293 size_t j;\ 294 if (!srv->plugin_slots) return HANDLER_GO_ON;\ 295 slot = ((plugin ***)(srv->plugin_slots))[x];\ 296 if (!slot) return HANDLER_GO_ON;\ 297 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 298 plugin *p = slot[j];\ 299 handler_t r;\ 300 switch(r = p->y(srv, con, p->data)) {\ 301 case HANDLER_GO_ON:\ 302 break;\ 303 case HANDLER_FINISHED:\ 304 case HANDLER_COMEBACK:\ 305 case HANDLER_WAIT_FOR_EVENT:\ 306 case HANDLER_WAIT_FOR_FD:\ 307 case HANDLER_ERROR:\ 308 return r;\ 309 default:\ 310 log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\ 311 return HANDLER_ERROR;\ 312 }\ 313 }\ 314 return HANDLER_GO_ON;\ 315 } 316 317 /** 318 * plugins that use 319 * 320 * - server *srv 321 * - connection *con 322 * - void *p_d (plugin_data *) 323 */ 324 325 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean) 326 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw) 327 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done) 328 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) 329 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest) 330 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start) 331 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot) 332 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical) 333 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset) 334 335 #undef PLUGIN_TO_SLOT 336 337 #define PLUGIN_TO_SLOT(x, y) \ 338 handler_t plugins_call_##y(server *srv) {\ 339 plugin **slot;\ 340 size_t j;\ 341 if (!srv->plugin_slots) return HANDLER_GO_ON;\ 342 slot = ((plugin ***)(srv->plugin_slots))[x];\ 343 if (!slot) return HANDLER_GO_ON;\ 344 for (j = 0; j < srv->plugins.used && slot[j]; j++) { \ 345 plugin *p = slot[j];\ 346 handler_t r;\ 347 switch(r = p->y(srv, p->data)) {\ 348 case HANDLER_GO_ON:\ 349 break;\ 350 case HANDLER_FINISHED:\ 351 case HANDLER_COMEBACK:\ 352 case HANDLER_WAIT_FOR_EVENT:\ 353 case HANDLER_WAIT_FOR_FD:\ 354 case HANDLER_ERROR:\ 355 return r;\ 356 default:\ 357 log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\ 358 return HANDLER_ERROR;\ 359 }\ 360 }\ 361 return HANDLER_GO_ON;\ 362 } 363 364 /** 365 * plugins that use 366 * 367 * - server *srv 368 * - void *p_d (plugin_data *) 369 */ 370 371 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger) 372 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup) 373 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup) 374 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults) 375 376 #undef PLUGIN_TO_SLOT 377 378 #if 0 379 /** 380 * 381 * special handler 382 * 383 */ 384 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) { 385 size_t i; 386 plugin **ps; 387 388 ps = srv->plugins.ptr; 389 390 for (i = 0; i < srv->plugins.used; i++) { 391 plugin *p = ps[i]; 392 if (p->handle_fdevent) { 393 handler_t r; 394 switch(r = p->handle_fdevent(srv, fdc, p->data)) { 395 case HANDLER_GO_ON: 396 break; 397 case HANDLER_FINISHED: 398 case HANDLER_COMEBACK: 399 case HANDLER_WAIT_FOR_EVENT: 400 case HANDLER_ERROR: 401 return r; 402 default: 403 log_error_write(srv, __FILE__, __LINE__, "d", r); 404 break; 405 } 406 } 407 } 408 409 return HANDLER_GO_ON; 410 } 411 #endif 412 /** 413 * 414 * - call init function of all plugins to init the plugin-internals 415 * - added each plugin that supports has callback to the corresponding slot 416 * 417 * - is only called once. 418 */ 419 420 handler_t plugins_call_init(server *srv) { 421 size_t i; 422 plugin **ps; 423 424 ps = srv->plugins.ptr; 425 426 /* fill slots */ 427 428 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps)); 429 force_assert(NULL != srv->plugin_slots); 430 431 for (i = 0; i < srv->plugins.used; i++) { 432 size_t j; 433 /* check which calls are supported */ 434 435 plugin *p = ps[i]; 436 437 #define PLUGIN_TO_SLOT(x, y) \ 438 if (p->y) { \ 439 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \ 440 if (!slot) { \ 441 slot = calloc(srv->plugins.used, sizeof(*slot));\ 442 force_assert(NULL != slot); \ 443 ((plugin ***)(srv->plugin_slots))[x] = slot; \ 444 } \ 445 for (j = 0; j < srv->plugins.used; j++) { \ 446 if (slot[j]) continue;\ 447 slot[j] = p;\ 448 break;\ 449 }\ 450 } 451 452 453 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); 454 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); 455 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done); 456 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close); 457 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger); 458 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup); 459 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest); 460 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start); 461 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot); 462 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical); 463 PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset); 464 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup); 465 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults); 466 #undef PLUGIN_TO_SLOT 467 468 if (p->init) { 469 if (NULL == (p->data = p->init())) { 470 log_error_write(srv, __FILE__, __LINE__, "sb", 471 "plugin-init failed for module", p->name); 472 return HANDLER_ERROR; 473 } 474 475 /* used for con->mode, DIRECT == 0, plugins above that */ 476 ((plugin_data *)(p->data))->id = i + 1; 477 478 if (p->version != LIGHTTPD_VERSION_ID) { 479 log_error_write(srv, __FILE__, __LINE__, "sb", 480 "plugin-version doesn't match lighttpd-version for", p->name); 481 return HANDLER_ERROR; 482 } 483 } else { 484 p->data = NULL; 485 } 486 } 487 488 return HANDLER_GO_ON; 489 } 490 491 void plugins_free(server *srv) { 492 size_t i; 493 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