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