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