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
plugin_init(void)51 static plugin *plugin_init(void) {
52 plugin *p;
53
54 p = calloc(1, sizeof(*p));
55
56 return p;
57 }
58
plugin_free(plugin * p)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
plugins_register(server * srv,plugin * p)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
plugins_load(server * srv)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
plugins_load(server * srv)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_string_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
PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN,handle_uri_clean)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
plugins_free(server * srv)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