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