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