1 /*
2  * Copyright (c) 2003 Niels Provos <provos@citi.umich.edu>
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 2 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include <sys/queue.h>
40 #ifdef HAVE_SYS_TIME_H
41 #include <sys/time.h>
42 #endif
43 #include <sys/tree.h>
44 
45 #include <err.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <dirent.h>
51 #include <unistd.h>
52 #include <ctype.h>
53 #include <syslog.h>
54 #ifdef HAVE_TIME_H
55 #include <time.h>
56 #endif
57 #include <dnet.h>
58 #include <pcap.h>
59 
60 #undef timeout_pending
61 #undef timeout_initialized
62 
63 #include <event.h>
64 
65 #include <Python.h>
66 
67 #include "honeyd.h"
68 #include "template.h"
69 #include "personality.h"
70 #include "interface.h"
71 #include "log.h"
72 #include "pyextend.h"
73 #include "histogram.h"
74 #include "osfp.h"
75 #include "debug.h"
76 
77 int make_socket(int (*f)(int, const struct sockaddr *, socklen_t), int type,
78     char *, uint16_t);
79 
80 /*
81  * Can be used externally to share Python dictionaries with the user interface
82  */
83 PyObject *pyextend_dict_global;
84 PyObject *pyextend_dict_local;
85 
86 /*
87  * Functions that we need to call for this script.
88  * This is stateless and shared among connections.
89  */
90 
91 struct pyextend {
92 	SPLAY_ENTRY(pyextend) node;
93 	char *name;
94 	PyObject *pFuncInit;
95 	PyObject *pFuncReadData;
96 	PyObject *pFuncWriteData;
97 	PyObject *pFuncEnd;
98 };
99 
100 SPLAY_HEAD(pyetree, pyextend) pyextends;
101 
102 int
pye_compare(struct pyextend * a,struct pyextend * b)103 pye_compare(struct pyextend *a, struct pyextend *b)
104 {
105 	return (strcmp(a->name, b->name));
106 }
107 
108 SPLAY_PROTOTYPE(pyetree, pyextend, node, pye_compare);
109 SPLAY_GENERATE(pyetree, pyextend, node, pye_compare);
110 
111 struct pywrite {
112 	TAILQ_ENTRY(pywrite) next;
113 
114 	u_char *buf;
115 	size_t size;
116 };
117 
118 struct pystate {
119 	PyObject *state;
120 
121 	struct pyextend *pye;
122 
123 	int fd;
124 
125 	struct event pread;
126 	struct event pwrite;
127 
128 	int wantwrite;
129 
130 	TAILQ_HEAD(pywbufs, pywrite) writebuffers;
131 
132 	struct command *cmd;
133 	void *con;
134 };
135 
136 static PyObject *pyextend_readselector(PyObject *, PyObject *);
137 static PyObject *pyextend_writeselector(PyObject *, PyObject *);
138 static PyObject *pyextend_log(PyObject *, PyObject *);
139 static PyObject *pyextend_raw_log(PyObject *, PyObject *);
140 static PyObject *pyextend_uptime(PyObject *, PyObject *);
141 static PyObject *pyextend_interfaces(PyObject *, PyObject *);
142 static PyObject *pyextend_stats_network(PyObject *, PyObject *);
143 static PyObject *pyextend_status_connections(PyObject *, PyObject *);
144 static PyObject *pyextend_config(PyObject *, PyObject *);
145 static PyObject *pyextend_config_ips(PyObject *, PyObject *);
146 static PyObject *pyextend_delete_template(PyObject *, PyObject *);
147 static PyObject *pyextend_delete_connection(PyObject *, PyObject *);
148 static PyObject *pyextend_security_info(PyObject *, PyObject *);
149 
150 static PyMethodDef HoneydMethods[] = {
151     {"read_selector", pyextend_readselector, METH_VARARGS,
152      "Tells Honeyd if the embedded Python application wants to read or not."},
153     {"write_selector", pyextend_writeselector, METH_VARARGS,
154      "Tells Honeyd if the embedded Python application wants to write or not."},
155     {"log", pyextend_log, METH_VARARGS,
156      "Allows a python script to pass a string to generate service logs."},
157     {"raw_log", pyextend_raw_log, METH_VARARGS,
158      "Allows a python script to log directly to syslog."},
159     {"uptime", pyextend_uptime, METH_VARARGS,
160      "Returns the number of seconds that Honeyd has been running."},
161     {"interfaces", pyextend_interfaces, METH_VARARGS,
162      "Returns an array of configured interfaces."},
163     {"stats_network", pyextend_stats_network, METH_VARARGS,
164      "Returns a dictionary with network statistics."},
165     {"status_connections", pyextend_status_connections, METH_VARARGS,
166      "Returns a list of active UDP or TCP connections."},
167     {"config", pyextend_config, METH_VARARGS,
168      "Returns an associative array with config information."},
169     {"config_ips", pyextend_config_ips, METH_VARARGS,
170      "Returns an array with bound IP addresses."},
171     {"delete_template", pyextend_delete_template, METH_VARARGS,
172      "Deletes the specified template."},
173     {"delete_connection", pyextend_delete_connection, METH_VARARGS,
174      "Deletes the specified connection."},
175     {"security_info", pyextend_security_info, METH_VARARGS,
176      "Returns a string with pertinent security information."},
177     {NULL, NULL, 0, NULL}
178 };
179 
180 static struct pystate *current_state;
181 
182 struct pyextend_count {
183 	int offset;
184 	PyObject *pArgs;
185 };
186 
187 static int
pyextend_populate_connections(struct tuple * hdr,void * arg)188 pyextend_populate_connections(struct tuple *hdr, void *arg)
189 {
190 	PyObject *pArgs = arg, *pValue;
191 	struct addr src, dst;
192 
193 	addr_pack(&src, ADDR_TYPE_IP, IP_ADDR_BITS, &hdr->ip_src, IP_ADDR_LEN);
194 	addr_pack(&dst, ADDR_TYPE_IP, IP_ADDR_BITS, &hdr->ip_dst, IP_ADDR_LEN);
195 
196 	pValue = Py_BuildValue("{sssssisisisi}",
197 	    "src", addr_ntoa(&src),
198 	    "dst", addr_ntoa(&dst),
199 	    "sport", hdr->sport,
200 	    "dport", hdr->dport,
201 	    "received", hdr->received,
202 	    "sent", hdr->sent);
203 	if (pValue == NULL) {
204 		PyErr_Print();
205 		errx(1, "%s: failed to build argument list", __func__);
206 	}
207 
208 	/* pValue reference stolen here */
209 	PyList_Append(pArgs, pValue);
210 
211 	return (0);
212 }
213 
214 static PyObject*
pyextend_status_connections(PyObject * self,PyObject * args)215 pyextend_status_connections(PyObject *self, PyObject *args)
216 {
217 	PyObject *pArgs;
218 	char *string;
219 	extern struct conlru tcplru;
220 	extern struct conlru udplru;
221 	struct conlru *head;
222 
223 	if (!PyArg_ParseTuple(args, "s", &string))
224 		return NULL;
225 
226 	/* Check that we are asking for either UDP or TCP */
227 	if (!strcmp(string, "udp"))
228 		head = &udplru;
229 	else if (!strcmp(string, "tcp"))
230 		head = &tcplru;
231 	else
232 		return NULL;
233 
234 	pArgs = PyList_New(0);
235 
236 	/* Populate tuple with per IP address information */
237 	tuple_iterate(head, pyextend_populate_connections, pArgs);
238 
239 	return (pArgs);
240 }
241 
242 /*
243  * Returns 1 if the template name corresponds to an IP address
244  */
245 
246 int
pyextend_is_ipaddress(struct template * tmpl)247 pyextend_is_ipaddress(struct template *tmpl)
248 {
249 	ip_addr_t addr;
250 
251 	return (ip_pton(tmpl->name, &addr) != -1);
252 }
253 
254 int
pyextend_count_ips(struct template * tmpl,void * arg)255 pyextend_count_ips(struct template *tmpl, void *arg)
256 {
257 	int *num_ips = arg;
258 
259 	if (!pyextend_is_ipaddress(tmpl))
260 		return (0);
261 
262 	(*num_ips)++;
263 
264 	return (0);
265 }
266 
267 void
pyextend_humanreadable_action(struct action * action,char * buffer,size_t len)268 pyextend_humanreadable_action(struct action *action, char *buffer, size_t len)
269 {
270 	char *flags = NULL;
271 	if (action->flags & PORT_TARPIT) {
272 		flags = "tarpit ";
273 	}
274 
275 	switch (action->status) {
276 	case PORT_BLOCK:
277 		snprintf(buffer, len, "block");
278 		break;
279 
280 	case PORT_RESET:
281 		snprintf(buffer, len, "reset");
282 		break;
283 
284 	case PORT_OPEN:
285 		snprintf(buffer, len, "%s%s",
286 		    flags != NULL ? flags : "",
287 		    action->action != NULL ? action->action : "open");
288 		break;
289 	case PORT_PYTHON:
290 		snprintf(buffer, len, "%sinternal %s",
291 		    flags != NULL ? flags : "",
292 		    action->action);
293 		break;
294 	case PORT_PROXY:
295 		if (action->action != NULL) {
296 			snprintf(buffer, len, "%sproxy %s",
297 			    flags != NULL ? flags : "",
298 			    action->action);
299 		} else if (action->aitop != NULL) {
300 			struct addrinfo *ai = action->aitop;
301 			char addr[NI_MAXHOST];
302 			char port[NI_MAXSERV];
303 
304 			if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
305 				addr, sizeof(addr), port, sizeof(port),
306 				NI_NUMERICHOST|NI_NUMERICSERV) != 0)
307 				err(1, "%s: getnameinfo", __func__);
308 
309 			snprintf(buffer, len, "%sproxy %s:%s",
310 			    flags != NULL ? flags : "",
311 			    addr, port);
312 		} else {
313 			snprintf(buffer, len, "proxy UNKNOWN");
314 		}
315 		break;
316 	default:
317 		snprintf(buffer, len, "UNKNOWN");
318 		break;
319 	}
320 }
321 
322 int
pyextend_populate_ips(struct template * tmpl,void * arg)323 pyextend_populate_ips(struct template *tmpl, void *arg)
324 {
325 	struct pyextend_count *count = arg;
326 	char icmp_action[1024];
327 	char tcp_action[1024];
328 	char udp_action[1024];
329 	PyObject *pArgs = count->pArgs;
330 	PyObject *pValue;
331 
332 	if (!pyextend_is_ipaddress(tmpl))
333 		return (0);
334 
335 	/* Fill in the default actions that we take */
336 	pyextend_humanreadable_action(&tmpl->icmp,
337 	    icmp_action, sizeof(icmp_action));
338 	pyextend_humanreadable_action(&tmpl->tcp,
339 	    tcp_action, sizeof(tcp_action));
340 	pyextend_humanreadable_action(&tmpl->udp,
341 	    udp_action, sizeof(udp_action));
342 
343 	pValue = Py_BuildValue("{ssssssssssss}",
344 	    "address", tmpl->name,
345 	    "personality", tmpl->person != NULL ? tmpl->person->name : NULL,
346 	    "icmp_action", icmp_action,
347 	    "tcp_action", tcp_action,
348 	    "udp_action", udp_action,
349 	    "ethernet", tmpl->ethernet_addr != NULL ?
350 	    addr_ntoa(tmpl->ethernet_addr) : NULL);
351 	if (pValue == NULL) {
352 		PyErr_Print();
353 		errx(1, "%s: failed to build argument list", __func__);
354 	}
355 	/* pValue reference stolen here */
356 	PyList_SetItem(pArgs, count->offset++, pValue);
357 
358 	return (0);
359 }
360 
361 static PyObject*
pyextend_config_ips(PyObject * self,PyObject * args)362 pyextend_config_ips(PyObject *self, PyObject *args)
363 {
364 	PyObject *pArgs;
365 	int num_ips = 0;
366 	struct pyextend_count count;
367 
368 	/* Count all IP addresses */
369 	template_iterate(pyextend_count_ips, &num_ips);
370 
371 	pArgs = PyList_New(num_ips);
372 
373 	/* Populate tuple with per IP address information */
374 	memset(&count, 0, sizeof(count));
375 	count.pArgs = pArgs;
376 	template_iterate(pyextend_populate_ips, &count);
377 
378 	return (pArgs);
379 }
380 
381 static PyObject*
pyextend_stats_network(PyObject * self,PyObject * args)382 pyextend_stats_network(PyObject *self, PyObject *args)
383 {
384 	PyObject *pValue;
385 	extern struct stats_network stats_network;
386 
387 	pValue = Py_BuildValue("{s:(d,d,d),s:(d,d,d)}",
388 	    "Input Bytes",
389 	    (double)count_get_minute(stats_network.input_bytes)/60.0,
390 	    (double)count_get_hour(stats_network.input_bytes)/3600.0,
391 	    (double)count_get_day(stats_network.input_bytes)/86400.0,
392 	    "Output Bytes",
393 	    (double)count_get_minute(stats_network.output_bytes)/60.0,
394 	    (double)count_get_hour(stats_network.output_bytes)/3600.0,
395 	    (double)count_get_day(stats_network.output_bytes)/86400.0);
396 
397 	if (pValue == NULL) {
398 		PyErr_Print();
399 		errx(1, "%s: failed to build argument list", __func__);
400 	}
401 
402 	return (pValue);
403 }
404 
405 static PyObject*
pyextend_config(PyObject * self,PyObject * args)406 pyextend_config(PyObject *self, PyObject *args)
407 {
408 	PyObject *pValue;
409 	extern struct config config;
410 
411 	pValue = Py_BuildValue("{ssssssssssss}",
412 	    "version", VERSION,
413 	    "config", config.config,
414 	    "personality", config.pers,
415 	    "xprobe", config.xprobe,
416 	    "assoc", config.assoc,
417 	    "osfp", config.osfp);
418 	if (pValue == NULL) {
419 		PyErr_Print();
420 		errx(1, "%s: failed to build argument list", __func__);
421 	}
422 
423 	return (pValue);
424 }
425 
426 static PyObject*
pyextend_interfaces(PyObject * self,PyObject * args)427 pyextend_interfaces(PyObject *self, PyObject *args)
428 {
429 	PyObject *pArgs;
430 	int i;
431 
432 	pArgs = PyTuple_New(interface_count());
433 	for (i = 0; i < interface_count(); i++) {
434 		struct interface *inter = interface_get(i);
435 		struct intf_entry *if_ent = &inter->if_ent;
436 		PyObject *pValue;
437 
438 		pValue = Py_BuildValue("{sssssiss}",
439 		    "name", if_ent->intf_name,
440 		    "address", addr_ntoa(&if_ent->intf_addr),
441 		    "mtu", if_ent->intf_mtu,
442 		    "link", addr_ntoa(&if_ent->intf_link_addr));
443 		if (pValue == NULL) {
444 			PyErr_Print();
445 			errx(1, "%s: failed to build argument list", __func__);
446 		}
447 		/* pValue reference stolen here */
448 		PyTuple_SetItem(pArgs, i, pValue);
449 	}
450 
451 	return (pArgs);
452 }
453 
454 static PyObject*
pyextend_uptime(PyObject * self,PyObject * args)455 pyextend_uptime(PyObject *self, PyObject *args)
456 {
457 	extern struct timeval honeyd_uptime;
458 	struct timeval tv;
459 
460 	gettimeofday(&tv, NULL);
461 	timersub(&tv, &honeyd_uptime, &tv);
462 
463 	return (Py_BuildValue("i", tv.tv_sec));
464 }
465 
466 static PyObject*
pyextend_delete_template(PyObject * self,PyObject * args)467 pyextend_delete_template(PyObject *self, PyObject *args)
468 {
469 	char *string;
470 	struct template *tmpl;
471 	int result = 0;
472 
473 	if (!PyArg_ParseTuple(args, "s", &string))
474 		goto done;
475 
476 	if ((tmpl = template_find(string)) == NULL)
477 		goto done;
478 
479 	result = 1;
480 	template_remove(tmpl);
481 
482  done:
483 	return (Py_BuildValue("i", result));
484 }
485 
486 static PyObject*
pyextend_delete_connection(PyObject * self,PyObject * args)487 pyextend_delete_connection(PyObject *self, PyObject *args)
488 {
489 	extern struct tree tcpcons;
490 	extern struct tree udpcons;
491 	struct tuple tmp, *hdr;
492 	char *protocol;
493 	char *asrc, *adst, *asport, *adport;
494 	struct addr src, dst;
495 	int result = 0;
496 
497 	if (!PyArg_ParseTuple(args, "sssss", &protocol,
498 		&asrc, &asport, &adst, &adport))
499 		goto done;
500 
501 	if (addr_aton(asrc, &src) == -1)
502 		goto done;
503 	if (addr_aton(adst, &dst) == -1)
504 		goto done;
505 
506 	tmp.ip_src = src.addr_ip;
507 	tmp.ip_dst = dst.addr_ip;
508 	tmp.sport = atoi(asport);
509 	tmp.dport = atoi(adport);
510 
511 	if (!strcmp(protocol, "tcp")) {
512 		hdr = tuple_find(&tcpcons, &tmp);
513 		if (hdr == NULL)
514 			goto done;
515 		tcp_free((struct tcp_con *)hdr);
516 	} else if (!strcmp(protocol, "udp")) {
517 		hdr = tuple_find(&udpcons, &tmp);
518 		if (hdr == NULL)
519 			goto done;
520 		udp_free((struct udp_con *)hdr);
521 	}
522 
523 	result = 1;
524 
525  done:
526 	return (Py_BuildValue("i", result));
527 }
528 
529 static PyObject*
pyextend_security_info(PyObject * self,PyObject * args)530 pyextend_security_info(PyObject *self, PyObject *args)
531 {
532 	extern char *security_update;
533 	PyObject *pValue;
534 
535 	if (security_update == NULL || strlen(security_update) == 0)
536 		return Py_None;
537 
538 	pValue = Py_BuildValue("s", security_update);
539 
540 	return (pValue);
541 }
542 
543 static PyObject*
pyextend_log(PyObject * self,PyObject * args)544 pyextend_log(PyObject *self, PyObject *args)
545 {
546 	extern FILE *honeyd_servicefp;
547 	struct tuple *hdr;
548 	char *string;
549 
550 	if (current_state == NULL)
551 		return (Py_BuildValue("i", -1));
552 
553 	hdr = current_state->con;
554 
555 	if(!PyArg_ParseTuple(args, "s:read_selector", &string))
556 		return (NULL);
557 
558 	honeyd_log_service(honeyd_servicefp,
559 	    hdr->type == SOCK_STREAM ? IP_PROTO_TCP : IP_PROTO_UDP,
560 	    hdr, string);
561 
562 	return (Py_BuildValue("i", 0));
563 }
564 
565 static PyObject*
pyextend_raw_log(PyObject * self,PyObject * args)566 pyextend_raw_log(PyObject *self, PyObject *args)
567 {
568 	char *string;
569 
570 	if(!PyArg_ParseTuple(args, "s:read_selector", &string))
571 		return (NULL);
572 
573 	syslog(LOG_NOTICE, "%s", string);
574 
575 	return Py_BuildValue("i", 0);;
576 }
577 
578 static PyObject*
pyextend_selector(PyObject * args,struct event * ev,const char * name)579 pyextend_selector(PyObject *args, struct event *ev, const char *name)
580 {
581 	int on = 0;
582 
583 	if(!PyArg_ParseTuple(args, "i:read_selector", &on))
584 		return (NULL);
585 	DFPRINTF(1, (stderr, "%s: called selector with %d\n", name, on));
586 
587 	if (on)
588 		event_add(ev, NULL);
589 	else
590 		event_del(ev);
591 
592 	return Py_BuildValue("i", 0);;
593 }
594 
595 static PyObject*
pyextend_readselector(PyObject * self,PyObject * args)596 pyextend_readselector(PyObject *self, PyObject *args)
597 {
598 	if (current_state == NULL)
599 		return (NULL);
600 
601 	return (pyextend_selector(args, &current_state->pread, __func__));
602 }
603 
604 static PyObject*
pyextend_writeselector(PyObject * self,PyObject * args)605 pyextend_writeselector(PyObject *self, PyObject *args)
606 {
607 	struct pystate *state = current_state;
608 
609 	PyObject *pValue;
610 	if (state == NULL)
611 		return (NULL);
612 
613 	pValue = pyextend_selector(args, &state->pwrite, __func__);
614 	if (pValue == NULL)
615 		return (NULL);
616 
617 	/*
618 	 * We need to keep track of this, so that in case we have buffered
619 	 * data to write, we know if we should schedule the python script.
620 	 */
621 	state->wantwrite = event_pending(&state->pwrite, EV_WRITE, NULL);
622 
623 	return (pValue);
624 }
625 
626 static void
pyextend_cbread(int fd,short what,void * arg)627 pyextend_cbread(int fd, short what, void *arg)
628 {
629 	static char buf[4096];
630 	PyObject *pArgs, *pValue;
631 	struct pystate *state = arg;
632 	struct pyextend *pye = state->pye;
633 	int n;
634 
635 	n = read(fd, buf, sizeof(buf));
636 
637 	if (n <= 0)
638 		goto error;
639 
640 	pArgs = Py_BuildValue("(O,s#)", state->state, buf, n);
641 	if (pArgs == NULL) {
642 		fprintf(stderr, "Failed to build value\n");
643 		goto error;
644 	}
645 
646 	current_state = state;
647 	pValue = PyObject_CallObject(pye->pFuncReadData, pArgs);
648 	current_state = NULL;
649 
650 	Py_DECREF(pArgs);
651 
652 	if (pValue == NULL) {
653 		PyErr_Print();
654 		goto error;
655 	}
656 	Py_DECREF(pValue);
657 
658 	return;
659 
660  error:
661 	pyextend_connection_end(state);
662 	return;
663 }
664 
665 static int
pyextend_addbuffer(struct pystate * state,u_char * buf,size_t size)666 pyextend_addbuffer(struct pystate *state, u_char *buf, size_t size)
667 {
668 	struct pywrite *write;
669 
670 	if ((write = malloc(sizeof(struct pywrite))) == NULL)
671 		return (-1);
672 
673 	if ((write->buf = malloc(size)) == NULL) {
674 		free(write);
675 		return (-1);
676 	}
677 
678 	memcpy(write->buf, buf, size);
679 	write->size = size;
680 
681 	TAILQ_INSERT_TAIL(&state->writebuffers, write, next);
682 
683 	return (0);
684 }
685 
686 static void
pyextend_cbwrite(int fd,short what,void * arg)687 pyextend_cbwrite(int fd, short what, void *arg)
688 {
689 	PyObject *pArgs, *pValue;
690 	struct pystate *state = arg;
691 	struct pyextend *pye = state->pye;
692 	struct pywrite *writebuf;
693 	char *buf;
694 	int size, res;
695 
696 	/* If we still have buffered data from before, we are going
697 	 * to send it now and reschedule us if necessary.
698 	 */
699 	if ((writebuf = TAILQ_FIRST(&state->writebuffers)) != NULL) {
700 		res = write(fd, writebuf->buf, writebuf->size);
701 		if (res <= 0)
702 			goto error;
703 		if (res < writebuf->size) {
704 			writebuf->size -= res;
705 			memmove(writebuf->buf, writebuf->buf + res,
706 			    writebuf->size);
707 			event_add(&state->pwrite, NULL);
708 		} else {
709 			TAILQ_REMOVE(&state->writebuffers, writebuf, next);
710 			free(writebuf->buf);
711 			free(writebuf);
712 			if (state->wantwrite ||
713 			    TAILQ_FIRST(&state->writebuffers) != NULL)
714 				event_add(&state->pwrite, NULL);
715 		}
716 
717 		return;
718 	}
719 
720 
721 	pArgs = Py_BuildValue("(O)", state->state);
722 	if (pArgs == NULL) {
723 		fprintf(stderr, "Failed to build value\n");
724 		goto error;
725 	}
726 
727 	current_state = state;
728 	pValue = PyObject_CallObject(pye->pFuncWriteData, pArgs);
729 	current_state = NULL;
730 
731 	Py_DECREF(pArgs);
732 
733 	if (pValue == NULL) {
734 		PyErr_Print();
735 		goto error;
736 	}
737 
738 	/*
739 	 * Addition to support closing connections from the server
740 	 * side. - AJ 2.4.2004
741 	 */
742 	if (pValue == Py_None) {
743 		Py_DECREF(pValue);
744 		goto error;
745 	}
746 
747 	res = PyString_AsStringAndSize(pValue, &buf, &size);
748 
749 	if (res == -1) {
750 		Py_DECREF(pValue);
751 		goto error;
752 	}
753 
754 	/* XXX - What to do about left over data */
755 	res = write(fd, buf, size);
756 
757 	if (res <= 0) {
758 		Py_DECREF(pValue);
759 		goto error;
760 	}
761 
762 	if (res != size) {
763 		pyextend_addbuffer(state, buf + res, size - res);
764 		event_add(&state->pwrite, NULL);
765 	}
766 
767 	Py_DECREF(pValue);
768 
769 	return;
770 
771  error:
772 	pyextend_connection_end(state);
773 	return;
774 }
775 
776 /* Initializes our Python extension support */
777 
778 void
pyextend_init(void)779 pyextend_init(void)
780 {
781 	PyObject *pModule;
782 	char path[1024], singlepath[1024];
783 	extern char *honeyd_webserver_root;
784 	char *p;
785 
786 	SPLAY_INIT(&pyextends);
787 
788 	Py_Initialize();
789 	strlcpy(path, Py_GetPath(), sizeof(path));
790 	/* Append the current path */
791 	strlcat(path, ":.", sizeof(path));
792 	strlcat(path, ":webserver", sizeof(path));
793 
794 	/* Append the webserver root directory */
795 	snprintf(singlepath, sizeof(singlepath), ":%s", honeyd_webserver_root);
796 	if ((p = strstr(singlepath, "/htdocs")) != NULL) {
797 		*p = '\0';
798 		strlcat(path, singlepath, sizeof(path));
799 	}
800 
801 	/* Append the Honeyd shared data directory */
802 	snprintf(singlepath, sizeof(singlepath),
803 	    ":%s", PATH_HONEYDDATA);
804 	strlcat(path, singlepath, sizeof(path));
805 	snprintf(singlepath, sizeof(singlepath),
806 	    ":%s/webserver", PATH_HONEYDDATA);
807 	strlcat(path, singlepath, sizeof(path));
808 	PySys_SetPath(path);
809 
810 	pModule = Py_InitModule("honeyd", HoneydMethods);
811 	PyModule_AddIntConstant(pModule, "EVENT_ON", 1);
812 	PyModule_AddIntConstant(pModule, "EVENT_OFF", 0);
813 	PyModule_AddStringConstant(pModule, "version", VERSION);
814 }
815 
816 /* Cleans up all Python stuff when we exit */
817 
818 void
pyextend_exit(void)819 pyextend_exit(void)
820 {
821 	Py_Finalize();
822 }
823 
824 void
pyextend_run(struct evbuffer * output,char * command)825 pyextend_run(struct evbuffer *output, char *command)
826 {
827 	PyObject *res = NULL, *compiled_code;
828 	char *data;
829 	int datlen;
830 
831 	char *preamble = "import StringIO\n"
832 	    "import sys\n"
833 	    "myout = StringIO.StringIO()\n"
834 	    "myerr = StringIO.StringIO()\n"
835 	    "saveout = sys.stdout\n"
836 	    "saveerr = sys.stderr\n"
837 	    "try:\n"
838 	    "  sys.stdout = myout\n"
839 	    "  sys.stderr = myerr\n"
840 	    "  try:\n"
841 	    "    %s\n"
842 	    "  except:\n"
843 	    "    import traceback\n"
844 	    "    traceback.print_exc()\n"
845 	    "finally:\n"
846 	    "  sys.stdout = saveerr\n"
847 	    "  sys.stderr = saveerr\n"
848 	    "output = \"%%s%%s\" %% (myout.getvalue(), myerr.getvalue())";
849 
850 	char *code = NULL;
851 
852 	if (asprintf(&code, preamble, command) == -1)
853 		err(1, "%s: asprintf", __func__);
854 
855 	compiled_code = Py_CompileStringFlags(code, "<filter>",
856 	    Py_file_input, 0);
857 
858 	free(code);
859 
860 	if (compiled_code == NULL) {
861 		const char *err = "Compilation of Python code failed.\n";
862 		evbuffer_add(output, (char *)err, strlen(err));
863 		PyErr_Print();
864 		return;
865 	}
866 
867 	if (pyextend_dict_local == NULL) {
868 		pyextend_dict_local = PyDict_New();
869 		assert(pyextend_dict_local != NULL);
870 	}
871 
872 	if (pyextend_dict_global == NULL) {
873 		PyObject *m;
874 
875 		/* Extract the global dictionary object */
876 		if ((m = PyImport_AddModule("__main__")) == NULL) {
877 			PyErr_Print();
878 			return;
879 		}
880 
881 		if ((pyextend_dict_global = PyModule_GetDict(m)) == NULL) {
882 			PyErr_Print();
883 			return;
884 		}
885 		Py_INCREF(pyextend_dict_global);
886 
887 		if (PyDict_GetItemString(pyextend_dict_global, "__builtins__") == NULL&&
888 		    PyDict_SetItemString(pyextend_dict_global, "__builtins__", PyEval_GetBuiltins()) == 0) {
889 			Py_DECREF(pyextend_dict_global);
890 			pyextend_dict_global = NULL;
891 			return;
892 		}
893 	}
894 
895 	res = PyEval_EvalCode((PyCodeObject *)compiled_code,
896 	    pyextend_dict_global, pyextend_dict_local);
897 	Py_DECREF(compiled_code);
898 
899 	if (res == NULL) {
900 		PyErr_Print();
901 		return;
902 	}
903 	Py_DECREF(res);
904 
905 	res = PyDict_GetItemString(pyextend_dict_local, "output");
906 	assert(res != NULL);
907 
908 	if (PyString_AsStringAndSize(res, &data, &datlen) == 0)
909 		evbuffer_add(output, data, datlen);
910 }
911 
912 #define CHECK_FUNC(f, x) do { \
913 	f = PyDict_GetItemString(pDict, x); \
914 	if ((f) == NULL || !PyCallable_Check(f)) { \
915 		warnx("%s: Cannot find function \"%s\"", \
916 			__func__, x); \
917 		goto error; \
918 	} \
919 } while (0)
920 
921 void *
pyextend_load_module(const char * name)922 pyextend_load_module(const char *name)
923 {
924 	PyObject *pName, *pModule, *pDict, *pFunc;
925 	struct pyextend *pye, tmp;
926 
927 	char line[1024];
928 	char *script, *p;
929 
930 	if (strlcpy(line, name, sizeof(line)) >= sizeof(line))
931 		return (NULL);
932 	p = line;
933 
934 	script = strsep(&p, " ");
935 
936 	tmp.name = script;
937 	if ((pye = SPLAY_FIND(pyetree, &pyextends, &tmp)) != NULL)
938 		return (pye);
939 
940 	pName = PyString_FromString(script);
941 	pModule = PyImport_Import(pName);
942 	Py_DECREF(pName);
943 
944 	if (pModule == NULL) {
945 		PyErr_Print();
946 		warn("%s: could not load python module: %s",
947 		    __func__, script);
948 		return (NULL);
949 	}
950 
951 	pDict = PyModule_GetDict(pModule); /* Borrowed */
952 
953 	CHECK_FUNC(pFunc, "honeyd_init");
954 	CHECK_FUNC(pFunc, "honeyd_readdata");
955 	CHECK_FUNC(pFunc, "honeyd_writedata");
956 	CHECK_FUNC(pFunc, "honeyd_end");
957 
958 	if ((pye = calloc(1, sizeof(struct pyextend))) == NULL)
959 		err(1, "calloc");
960 
961 	CHECK_FUNC(pye->pFuncInit, "honeyd_init");
962 	CHECK_FUNC(pye->pFuncReadData, "honeyd_readdata");
963 	CHECK_FUNC(pye->pFuncWriteData, "honeyd_writedata");
964 	CHECK_FUNC(pye->pFuncEnd, "honeyd_end");
965 
966 	if ((pye->name = strdup(script)) == NULL)
967 		err(1, "%s: strdup", __func__);
968 
969 	SPLAY_INSERT(pyetree, &pyextends, pye);
970 
971 	return (pye);
972 
973  error:
974 	Py_DECREF(pModule);
975 	return (NULL);
976 }
977 
978 static struct pystate *
pyextend_newstate(struct command * cmd,void * con,struct pyextend * pye)979 pyextend_newstate(struct command *cmd, void *con, struct pyextend *pye)
980 {
981 	struct pystate *state;
982 
983 	if ((state = calloc(1, sizeof(struct pystate))) == NULL)
984 		return (NULL);
985 
986 	/* Initialize structure */
987 	state->fd = -1;
988 	state->cmd = cmd;
989 	state->con = con;
990 	state->pye = pye;
991 
992 	TAILQ_INIT(&state->writebuffers);
993 
994 	return (state);
995 }
996 
997 static void
pyextend_freestate(struct pystate * state)998 pyextend_freestate(struct pystate *state)
999 {
1000 	struct pywrite *writes;
1001 
1002 	while ((writes = TAILQ_FIRST(&state->writebuffers)) != NULL) {
1003 		TAILQ_REMOVE(&state->writebuffers, writes, next);
1004 		free(writes->buf);
1005 		free(writes);
1006 	}
1007 
1008 	/* Cleanup our state */
1009 	event_del(&state->pread);
1010 	event_del(&state->pwrite);
1011 
1012 	if (state->fd != -1)
1013 		close(state->fd);
1014 	free(state);
1015 }
1016 
1017 int
pyextend_connection_start(struct tuple * hdr,struct command * cmd,void * con,void * pye_generic)1018 pyextend_connection_start(struct tuple *hdr, struct command *cmd,
1019     void *con, void *pye_generic)
1020 {
1021 	struct pyextend *pye = pye_generic;
1022 	struct pystate *state;
1023 	PyObject *pArgs, *pValue;
1024 	struct addr src, dst;
1025 	struct ip_hdr ip;
1026 	char *os_name = NULL;
1027 
1028 	if ((state = pyextend_newstate(cmd, con, pye)) == NULL)
1029 		return (-1);
1030 
1031 	if ((state->fd = cmd_python(hdr, cmd, con)) == -1) {
1032 		free(state);
1033 		return (-1);
1034 	}
1035 
1036 	/* Set up state with event callbacks */
1037 	event_set(&state->pread, state->fd, EV_READ, pyextend_cbread, state);
1038 	event_set(&state->pwrite, state->fd, EV_WRITE, pyextend_cbwrite,state);
1039 
1040 	addr_pack(&src, ADDR_TYPE_IP, IP_ADDR_BITS, &hdr->ip_src,IP_ADDR_LEN);
1041 	addr_pack(&dst, ADDR_TYPE_IP, IP_ADDR_BITS, &hdr->ip_dst,IP_ADDR_LEN);
1042 
1043 	/* Determine the remote operating system */
1044 	ip.ip_src = hdr->ip_src;
1045 	os_name = honeyd_osfp_name(&ip);
1046 
1047 	pArgs = PyTuple_New(1);
1048 	pValue = Py_BuildValue("{sssssisiss}",
1049 	    "HONEYD_IP_SRC", addr_ntoa(&src),
1050 	    "HONEYD_IP_DST", addr_ntoa(&dst),
1051 	    "HONEYD_SRC_PORT", hdr->sport,
1052 	    "HONEYD_DST_PORT", hdr->dport,
1053 	    "HONEYD_REMOTE_OS", os_name);
1054 	if (pValue == NULL) {
1055 		fprintf(stderr, "Failed to build value\n");
1056 		Py_DECREF(pArgs);
1057 		goto error;
1058 	}
1059 
1060 	/* Set up the current state for Python */
1061 	current_state = state;
1062 
1063 	/* pValue reference stolen here: */
1064 	PyTuple_SetItem(pArgs, 0, pValue);
1065 
1066 	pValue = PyObject_CallObject(pye->pFuncInit, pArgs);
1067 	Py_DECREF(pArgs);
1068 
1069 	/* Take away the current state */
1070 	current_state = NULL;
1071 
1072 	if (pValue == NULL) {
1073 		PyErr_Print();
1074 		goto error;
1075 	}
1076 
1077 	state->state = pValue;
1078 
1079 	/*
1080 	 * Registers state with command structure so that we can do
1081 	 * proper cleanup if things go wrong.
1082 	 */
1083 	cmd->state = state;
1084 	return (0);
1085 
1086  error:
1087 	pyextend_freestate(state);
1088 	return (-1);
1089 }
1090 
1091 void
pyextend_connection_end(struct pystate * state)1092 pyextend_connection_end(struct pystate *state)
1093 {
1094 	struct command *cmd = state->cmd;
1095 	struct pyextend *pye = state->pye;
1096 	PyObject *pArgs;
1097 
1098 	pArgs = PyTuple_New(1);
1099 
1100 	/* state->state reference stolen here: */
1101 	PyTuple_SetItem(pArgs, 0, state->state);
1102 
1103 	PyObject_CallObject(pye->pFuncEnd, pArgs);
1104 	Py_DECREF(pArgs);
1105 
1106 	pyextend_freestate(state);
1107 
1108 	cmd->state = NULL;
1109 
1110 	return;
1111 }
1112 
1113 /*
1114  * We register our own web server so that we can get some stats reporting
1115  * via a web browser.
1116  */
1117 
1118 static PyObject *pWebServer;	/* web server instance */
1119 static PyObject *pFuncRequest;	/* handle request function */
1120 
1121 static int pyserver_fd = -1;
1122 static struct event ev_accept;
1123 
1124 void pyextend_request_free(struct pyextend_request *);
1125 
1126 void
pyextend_evb_readcb(struct bufferevent * bev,void * parameter)1127 pyextend_evb_readcb(struct bufferevent *bev, void *parameter)
1128 {
1129 	struct pyextend_request *req = parameter;
1130 	PyObject *pArgs, *pValue;
1131 	char *client_address = addr_ntoa(&req->src);
1132 	char *buf;
1133 	int size, res;
1134 
1135 	/* Check if we have received the complete request */
1136 	if (evbuffer_find(bev->input, "\r\n\r\n", 4) == NULL) {
1137 		/*
1138 		 * If we did not receive the complete request and we have
1139 		 * waited for too long already, then we drop the request.
1140 		 */
1141 		if (EVBUFFER_LENGTH(bev->input) > PYEXTEND_MAX_REQUEST_SIZE) {
1142 			syslog(LOG_NOTICE,
1143 			    "Dropping request from %s with size %d",
1144 			    client_address, EVBUFFER_LENGTH(bev->input));
1145 			pyextend_request_free(req);
1146 		}
1147 		return;
1148 	}
1149 
1150 	pArgs = Py_BuildValue("(O,s#,s#)", pWebServer,
1151 	    EVBUFFER_DATA(bev->input), EVBUFFER_LENGTH(bev->input),
1152 	    client_address, strlen(client_address));
1153 	if (pArgs == NULL)
1154 		goto error;
1155 
1156 	pValue = PyObject_CallObject(pFuncRequest, pArgs);
1157 	Py_DECREF(pArgs);
1158 
1159 	if (pValue == NULL)
1160 		goto error;
1161 
1162 	res = PyString_AsStringAndSize(pValue, &buf, &size);
1163 
1164 	if (res == -1) {
1165 		Py_DECREF(pValue);
1166 		goto error;
1167 	}
1168 
1169 	/* Write the data to the network stream and be done with it */
1170 	bufferevent_write(req->evb, buf, size);
1171 
1172 	return;
1173 
1174  error:
1175 	PyErr_Print();
1176 	pyextend_request_free(req);
1177 }
1178 
1179 void
pyextend_evb_writecb(struct bufferevent * bev,void * parameter)1180 pyextend_evb_writecb(struct bufferevent *bev, void *parameter)
1181 {
1182 	/*
1183 	 * At this point, we have written all of our result data, so
1184 	 * we just close the connection.
1185 	 */
1186 	struct pyextend_request *req = parameter;
1187 	pyextend_request_free(req);
1188 }
1189 
1190 void
pyextend_evb_errcb(struct bufferevent * bev,short what,void * parameter)1191 pyextend_evb_errcb(struct bufferevent *bev, short what, void *parameter)
1192 {
1193 	struct pyextend_request *req = parameter;
1194 	pyextend_request_free(req);
1195 }
1196 
1197 /* Frees a request object and closes the connection */
1198 
1199 void
pyextend_request_free(struct pyextend_request * req)1200 pyextend_request_free(struct pyextend_request *req)
1201 {
1202 	bufferevent_free(req->evb);
1203 	close(req->fd);
1204 	free(req);
1205 }
1206 
1207 /* Creates a request object that can be used for streaming data */
1208 
1209 struct pyextend_request *
pyextend_request_new(int fd,struct addr * src)1210 pyextend_request_new(int fd, struct addr *src)
1211 {
1212 	struct pyextend_request *req = NULL;
1213 
1214 	if ((req = calloc(1, sizeof(struct pyextend_request))) == NULL)
1215 		return (NULL);
1216 
1217 	req->fd = fd;
1218 	req->src = *src;
1219 
1220 	if ((req->evb = bufferevent_new(fd,
1221 		 pyextend_evb_readcb, pyextend_evb_writecb, pyextend_evb_errcb,
1222 		 req)) == NULL) {
1223 		free(req);
1224 		return (NULL);
1225 	}
1226 
1227 	/* Highest priority to UI requests */
1228 	bufferevent_priority_set(req->evb, 0);
1229 
1230 	bufferevent_enable(req->evb, EV_READ);
1231 	return (req);
1232 }
1233 
1234 void
pyextend_accept(int fd,short what,void * arg)1235 pyextend_accept(int fd, short what, void *arg)
1236 {
1237 	struct sockaddr_storage ss;
1238 	socklen_t socklen = sizeof(ss);
1239 	struct addr src;
1240 	struct pyextend_request *req = NULL;
1241 	int newfd;
1242 
1243 	if ((newfd = accept(fd, (struct sockaddr *)&ss, &socklen)) == -1) {
1244 		warn("%s: accept", __func__);
1245 		return;
1246 	}
1247 
1248 	addr_ston((struct sockaddr *)&ss, &src);
1249 	syslog(LOG_DEBUG, "%s: new request from %s",
1250 	    __func__, addr_ntoa(&src));
1251 
1252 	/* Create a new request structure and dispatch the request */
1253 	if ((req = pyextend_request_new(newfd, &src)) == NULL) {
1254 		warn("%s: calloc", __func__);
1255 		close(newfd);
1256 		return;
1257 	}
1258 }
1259 
1260 void
pyextend_webserver_fix_permissions(const char * path,uid_t uid,gid_t gid)1261 pyextend_webserver_fix_permissions(const char *path, uid_t uid, gid_t gid)
1262 {
1263 	static int created_dirs;
1264 	DIR *dir;
1265 	struct dirent *file;
1266 	struct stat sb;
1267 	char fullname[PATH_MAX];
1268 	int off;
1269 
1270 	/* Create special directories */
1271 	if (!created_dirs) {
1272 		created_dirs = 1;
1273 		if (snprintf(fullname, sizeof(fullname), "%s/graphs", path) >=
1274 		    sizeof(fullname))
1275 			errx(1, "Path too long: %s/graphs", path);
1276 		if (lstat(fullname, &sb) == -1 && errno == ENOENT) {
1277 			syslog(LOG_INFO, "Creating directory %s", fullname);
1278 			if (mkdir(fullname, 0722) == -1)
1279 				err(1, "mkdir(%s)", fullname);
1280 		}
1281 	}
1282 
1283 	/* Fix permissions */
1284 	if (strlen(path) >= sizeof (fullname) - 2)
1285 		errx(1, "directory name too long");
1286 
1287 	dir = opendir(path);
1288 	if (dir == NULL)
1289 		err(1, "opendir(%s)", path);
1290 
1291 	strlcpy(fullname, path, sizeof (fullname));
1292 	off = strlen(fullname);
1293 	if (fullname[off - 1] != '/') {
1294 		strlcat(fullname, "/", sizeof(fullname));
1295 		off++;
1296 	}
1297 
1298 	while ((file = readdir(dir)) != NULL) {
1299 		char *filename = file->d_name;
1300 		if (!strcmp(filename, "..") || !strcmp(filename, "CVS"))
1301 			continue;
1302 
1303 		strlcpy(fullname + off, filename, sizeof(fullname) - off);
1304 
1305 		if (lstat(fullname, &sb) == -1)
1306 			err(1, "lstat(%s)", fullname);
1307 
1308 		/* We ignore symbolic links - shoot yourself in the foot */
1309 		if (sb.st_mode & S_IFLNK)
1310 			continue;
1311 
1312 		/* Change owner ship to us */
1313 		if (sb.st_uid != uid || sb.st_gid != gid) {
1314 			syslog(LOG_INFO, "Fixing ownership: %s", fullname);
1315 			if (chown(fullname, uid, gid) == -1)
1316 				err(1, "chown(%s)", fullname);
1317 		}
1318 
1319 		if ((sb.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR) ||
1320 		    (sb.st_mode & S_IWOTH)) {
1321 			int mode = (sb.st_mode & 0777);
1322 			mode |= (S_IRUSR|S_IWUSR);
1323 			/* No write access for others */
1324 			mode &= ~S_IWOTH;
1325 
1326 			syslog(LOG_INFO, "Fixing modes: %s", fullname);
1327 			if (chmod(fullname, mode) == -1)
1328 				err(1, "chmod(%s)", fullname);
1329 		}
1330 
1331 		if ((sb.st_mode & S_IFDIR) && filename[0] != '.')
1332 			pyextend_webserver_fix_permissions(fullname, uid, gid);
1333 	}
1334 	closedir(dir);
1335 }
1336 
1337 void
pyextend_webserver_verify_setup(const char * root_dir)1338 pyextend_webserver_verify_setup(const char *root_dir)
1339 {
1340 	char filename[1024];
1341 	struct _dirs {
1342 		const char *path;
1343 		int mode;
1344 	} dirs[] = {
1345 		{ "styles", R_OK },
1346 		{ "images", R_OK },
1347 		{ ".", W_OK|R_OK },
1348 		{ "graphs", W_OK|R_OK },
1349 		{ "templates", W_OK|R_OK },
1350 		{ NULL, 0 }
1351 	};
1352 	struct _dirs *p;
1353 
1354 	for (p = &dirs[0]; p->path != NULL; p++) {
1355 		snprintf(filename, sizeof(filename), "%s/%s",
1356 		    root_dir, p->path);
1357 		if (access(filename, p->mode) == -1) {
1358 			syslog(LOG_ERR,
1359 			    "webserver: require%s%s access to %s: %m",
1360 			    p->mode & W_OK ? " write" : "",
1361 			    p->mode & R_OK ? " read" : "",
1362 			    filename);
1363 			exit(1);
1364 		}
1365 	}
1366 }
1367 
1368 /*
1369  * Intializes the Python webserver.  It listens on the specified port
1370  * and serves documents from the specified directory.
1371  */
1372 
1373 void
pyextend_webserver_init(char * address,int port,char * root_dir)1374 pyextend_webserver_init(char *address, int port, char *root_dir)
1375 {
1376 	PyObject *pArgs, *pName, *pModule, *pDict, *pFuncWebInit;
1377 	char *script = "server";
1378 
1379 	pName = PyString_FromString(script);
1380 	pModule = PyImport_Import(pName);
1381 	Py_DECREF(pName);
1382 
1383 	if (pModule == NULL) {
1384 		PyErr_Print();
1385 		err(1, "%s: could not load python module: %s",
1386 		    __func__, script);
1387 	}
1388 
1389 	pDict = PyModule_GetDict(pModule); /* Borrowed */
1390 
1391 	CHECK_FUNC(pFuncWebInit, "make_server");
1392 	CHECK_FUNC(pFuncRequest, "handle_request");
1393 	pArgs = Py_BuildValue("(s)", root_dir);
1394 	if (pArgs == NULL) {
1395 		PyErr_Print();
1396 		errx(1, "%s: Failed to build value", __func__);
1397 	}
1398 	pWebServer = PyObject_CallObject(pFuncWebInit, pArgs);
1399 	Py_DECREF(pArgs);
1400 	if (pWebServer == NULL) {
1401 		PyErr_Print();
1402 		errx(1, "%s: make_server function returned error.", __func__);
1403 	}
1404 
1405 	pyserver_fd = make_socket(bind, SOCK_STREAM, address, port);
1406 
1407 	if (pyserver_fd == -1) {
1408 		fprintf(stderr,
1409 		    "\nA web server might already be running on port %d.\n"
1410 		    "Choose another port via --webserver-port or disable\n"
1411 		    "the built in webserver via --disable-webserver.\n", port);
1412 		exit(1);
1413 	}
1414 
1415 	if (listen(pyserver_fd, 10) == -1)
1416 		err(1, "%s: listen", __func__);
1417 
1418 	syslog(LOG_NOTICE, "HTTP server listening on %s:%d", address, port);
1419 	syslog(LOG_NOTICE, "HTTP server root at %s", root_dir);
1420 
1421 	/* Accept connections */
1422 	event_set(&ev_accept, pyserver_fd, EV_READ | EV_PERSIST,
1423 	    pyextend_accept, NULL);
1424 
1425 	/* Give the highest priority to the accept */
1426 	event_priority_set(&ev_accept, 0);
1427 	event_add(&ev_accept, NULL);
1428 	return;
1429 
1430  error:
1431 	Py_DECREF(pModule);
1432 	errx(1, "Cannot initialize module.");
1433 }
1434 
1435 void
pyextend_webserver_exit(void)1436 pyextend_webserver_exit(void)
1437 {
1438 	event_del(&ev_accept);
1439 	close(pyserver_fd);
1440 }
1441