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, ¤t_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