xref: /netbsd-src/sbin/iscsid/iscsid_main.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /*	$NetBSD: iscsid_main.c,v 1.11 2016/05/30 21:58:32 mlelstv Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005,2006,2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Wasabi Systems, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "iscsid_globals.h"
33 
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <sys/un.h>
37 #include <sys/sysctl.h>
38 
39 #include <ctype.h>
40 #include <err.h>
41 #include <fcntl.h>
42 #include <syslog.h>
43 #include <util.h>
44 
45 #define DEVICE    "/dev/iscsi0"
46 
47 /* -------------------------------------------------------------------------- */
48 
49 list_head_t list[NUM_DAEMON_LISTS];	/* the lists this daemon keeps */
50 
51 pthread_mutex_t sesslist_lock;	/* session list lock */
52 pthread_t main_thread;		/* main thread handle */
53 pthread_t event_thread;		/* event thread handle */
54 
55 int driver = -1;		/* the driver's file desc */
56 int client_sock;		/* the client communication socket */
57 
58 int debug_level;		/* How much info to display */
59 int debugging;
60 
61 /*
62    To avoid memory fragmentation (and speed things up a bit), we use the
63    static bufs unless the request or response exceeds the buffer size
64    (which it normally shouldn't, assuming we don't have thousands
65    of list entries).
66 */
67 static uint8_t req_buf[REQ_BUFFER_SIZE];	/* default buffer for requests */
68 static uint8_t rsp_buf[RSP_BUFFER_SIZE];	/* default buffer for responses */
69 
70 /* -------------------------------------------------------------------------- */
71 
72 static void __dead
73 usage(void)
74 {
75 	fprintf(stderr, "Usage: %s [-d <lvl>] [-n]\n", getprogname());
76 	exit(EXIT_FAILURE);
77 }
78 
79 /*
80  * create_node_name:
81  *    Create and set default node name.
82  *
83  *    Returns 0 on success, else an error code.
84  */
85 
86 static int
87 create_node_name(void)
88 {
89 	iscsi_set_node_name_parameters_t snp;
90 	uint32_t hid = 0;
91 	size_t siz;
92 	int mib[2];
93 	unsigned char *s;
94 
95 	(void) memset(&snp, 0x0, sizeof(snp));
96 	mib[0] = CTL_KERN;
97 	mib[1] = KERN_HOSTID;
98 	siz = sizeof(hid);
99 	sysctl(mib, 2, &hid, &siz, NULL, 0);
100 	mib[1] = KERN_HOSTNAME;
101 	siz = ISCSI_STRING_LENGTH - 45;
102 	sysctl(mib, 2, snp.InitiatorAlias, &siz, NULL, 0);
103 
104 	DEB(3, ("Host Name: <%s>, Host ID: %u", snp.InitiatorAlias, hid));
105 	if (!snp.InitiatorAlias[0]) {
106 		printf("Warning: iSCSI Node Name not set (No Host Name)!\n");
107 		return ISCSID_STATUS_NO_INITIATOR_NAME;
108 	}
109 	for (s = snp.InitiatorAlias; *s; s++)
110 		if (!isalnum((unsigned char) *s) && *s != '-' && *s != '.' && *s != ':')
111 			*s = '-';
112 	snprintf((char *)snp.InitiatorName, sizeof(snp.InitiatorName),
113 		"iqn.1994-04.org.netbsd:iscsi.%s:%u", snp.InitiatorAlias, hid);
114 
115 	ioctl(driver, ISCSI_SET_NODE_NAME, &snp);
116 	return snp.status;
117 }
118 
119 
120 /*
121  * init_daemon:
122  *    Open driver, create communication socket.
123  *
124  *    Returns:    <0 on error
125  */
126 
127 static int
128 init_daemon(void)
129 {
130 	int sock, i;
131 	struct sockaddr_un name;
132 	iscsid_request_t req;
133 
134 	if ((driver = open(DEVICE, O_RDONLY)) < 0) {
135 		perror("opening " DEVICE);
136 		return -1;
137 	}
138 
139 	sock = socket(AF_UNIX, SOCK_DGRAM, 0);
140 	if (sock < 0) {
141 		perror("opening datagram socket");
142 		return -1;
143 	}
144 
145 	name.sun_family = AF_UNIX;
146 	strlcpy(name.sun_path, ISCSID_SOCK_NAME, sizeof(name.sun_path));
147 
148 	req.request = ISCSID_DAEMON_TEST;
149 	req.parameter_length = 0;
150 
151 	i = sendto(sock, &req, sizeof(req), 0, (struct sockaddr *)(void *)&name,
152 				(socklen_t)sizeof(struct sockaddr_un));
153 	if (i == sizeof(req)) {
154 		printf("Daemon already loaded!\n");
155 		close(sock);
156 		return -1;
157 	}
158 
159 	unlink(ISCSID_SOCK_NAME);
160 	if (bind(sock, (struct sockaddr *)(void *)&name, (socklen_t)sizeof(struct sockaddr_un))) {
161 		perror("binding name to socket");
162 		return -1;
163 	}
164 
165 	for (i = 0; i < NUM_DAEMON_LISTS; i++) {
166 		TAILQ_INIT(&list[i].list);
167 		list[i].num_entries = 0;
168 	}
169 
170 	if ((i = pthread_mutex_init(&sesslist_lock, NULL)) != 0) {
171 		printf("Mutex init failed (%d)\n", i);
172 		close(sock);
173 		return -1;
174 	}
175 
176 	if (!register_event_handler()) {
177 		printf("Couldn't register event handler\n");
178 		close(sock);
179 		unlink(ISCSID_SOCK_NAME);
180 		pthread_mutex_destroy(&sesslist_lock);
181 		return -1;
182 	}
183 
184 	create_node_name();
185 
186 	return sock;
187 }
188 
189 
190 /*
191  * make_rsp:
192  *    Allocate a response buffer if the static buffer is insufficient, set
193  *    the response parameter length.
194  *
195  *    Parameter:
196  *          len         Response parameter size (not counting header)
197  *          prsp        Pointer to address of response buffer
198  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
199  *                      for static buffer.
200  *
201  *    Returns:    Pointer to response buffer, NULL if allocation failed.
202  */
203 
204 iscsid_response_t *
205 make_rsp(size_t len, iscsid_response_t ** prsp, int *prsp_temp)
206 {
207 	iscsid_response_t *rsp;
208 
209 	if ((len + sizeof(iscsid_response_t)) > RSP_BUFFER_SIZE) {
210 		if ((rsp = calloc(1, len)) == NULL) {
211 			(*prsp)->status = ISCSID_STATUS_NO_RESOURCES;
212 			return NULL;
213 		}
214 		*prsp_temp = TRUE;
215 		*prsp = rsp;
216 	} else
217 		rsp = *prsp;
218 
219 	memset (rsp, 0, len + sizeof(iscsid_response_t));
220 	rsp->parameter_length = (uint32_t)len;
221 	return rsp;
222 }
223 
224 
225 /*
226  * process_message:
227  *    minimal parameter check and dispatch for the daemon functions.
228  *
229  *    Parameter:
230  *          req         The request
231  *          prsp        Pointer to address of response buffer
232  *          prsp_temp   Will be set to TRUE if buffer was allocated, FALSE
233  *                      for static buffer.
234  */
235 
236 static void
237 process_message(iscsid_request_t *req, iscsid_response_t **prsp, int *prsp_temp)
238 {
239 	iscsid_response_t *rsp;
240 	void *p = req->parameter;
241 
242 	*prsp_temp = FALSE;
243 	*prsp = rsp = (iscsid_response_t *)(void *)rsp_buf;
244 	rsp->parameter_length = 0;
245 	rsp->status = ISCSID_STATUS_SUCCESS;
246 
247 	switch (req->request) {
248 	case ISCSID_ADD_TARGET:
249 		if (req->parameter_length < sizeof(iscsid_add_target_req_t)) {
250 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
251 			break;
252 		}
253 		add_target((iscsid_add_target_req_t *)p, prsp, prsp_temp);
254 		break;
255 
256 	case ISCSID_ADD_PORTAL:
257 		if (req->parameter_length != sizeof(iscsid_add_portal_req_t)) {
258 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
259 			break;
260 		}
261 		add_portal((iscsid_add_portal_req_t *)p, prsp, prsp_temp);
262 		break;
263 
264 	case ISCSID_SET_TARGET_OPTIONS:
265 		if (req->parameter_length != sizeof(iscsid_get_set_target_options_t)) {
266 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
267 			break;
268 		}
269 		rsp->status = set_target_options((iscsid_get_set_target_options_t *)p);
270 		break;
271 
272 	case ISCSID_GET_TARGET_OPTIONS:
273 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
274 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
275 			break;
276 		}
277 		rsp->status = ISCSID_STATUS_NOTIMPL;
278 		break;
279 
280 	case ISCSID_SET_TARGET_AUTHENTICATION:
281 		if (req->parameter_length !=
282 			sizeof(iscsid_set_target_authentication_req_t)) {
283 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
284 			break;
285 		}
286 		rsp->status = set_target_auth((iscsid_set_target_authentication_req_t *)p);
287 		break;
288 
289 	case ISCSID_SLP_FIND_TARGETS:
290 		rsp->status = ISCSID_STATUS_NOTIMPL;
291 		break;
292 
293 	case ISCSID_REFRESH_TARGETS:
294 		if (req->parameter_length < sizeof(iscsid_refresh_req_t)) {
295 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
296 			break;
297 		}
298 		rsp->status = refresh_targets((iscsid_refresh_req_t *)p);
299 		break;
300 
301 	case ISCSID_REMOVE_TARGET:
302 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
303 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
304 			break;
305 		}
306 		rsp->status = remove_target((iscsid_list_id_t *)p);
307 		break;
308 
309 	case ISCSID_SEARCH_LIST:
310 		if (req->parameter_length != sizeof(iscsid_search_list_req_t)) {
311 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
312 			break;
313 		}
314 		search_list((iscsid_search_list_req_t *)p, prsp, prsp_temp);
315 		break;
316 
317 	case ISCSID_GET_LIST:
318 		if (req->parameter_length != sizeof(iscsid_get_list_req_t)) {
319 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
320 			break;
321 		}
322 		get_list((iscsid_get_list_req_t *)p, prsp, prsp_temp);
323 		break;
324 
325 	case ISCSID_GET_TARGET_INFO:
326 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
327 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
328 			break;
329 		}
330 		get_target_info((iscsid_list_id_t *)p, prsp, prsp_temp);
331 		break;
332 
333 	case ISCSID_GET_PORTAL_INFO:
334 		if (req->parameter_length != sizeof(iscsid_list_id_t)) {
335 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
336 			break;
337 		}
338 		get_portal_info((iscsid_list_id_t *)p, prsp, prsp_temp);
339 		break;
340 
341 #ifndef ISCSI_MINIMAL
342 	case ISCSID_ADD_ISNS_SERVER:
343 		if (req->parameter_length != sizeof(iscsid_add_isns_server_req_t)) {
344 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
345 			break;
346 		}
347 		add_isns_server((iscsid_add_isns_server_req_t *)p,
348 						prsp, prsp_temp);
349 		break;
350 
351 	case ISCSID_GET_ISNS_SERVER:
352 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
353 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
354 			break;
355 		}
356 		get_isns_server((iscsid_sym_id_t *)p, prsp, prsp_temp);
357 		break;
358 
359 	case ISCSID_SLP_FIND_ISNS_SERVERS:
360 		rsp->status = ISCSID_STATUS_NOTIMPL;
361 		break;
362 
363 	case ISCSID_REMOVE_ISNS_SERVER:
364 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
365 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
366 			break;
367 		}
368 		rsp->status = remove_isns_server((iscsid_sym_id_t *)p);
369 		break;
370 #endif
371 
372 	case ISCSID_ADD_INITIATOR_PORTAL:
373 		if (req->parameter_length != sizeof(iscsid_add_initiator_req_t)) {
374 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
375 			break;
376 		}
377 		add_initiator_portal((iscsid_add_initiator_req_t *)p,
378 							prsp, prsp_temp);
379 		break;
380 
381 	case ISCSID_GET_INITIATOR_PORTAL:
382 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
383 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
384 			break;
385 		}
386 		get_initiator_portal((iscsid_sym_id_t *)p, prsp, prsp_temp);
387 		break;
388 
389 	case ISCSID_REMOVE_INITIATOR_PORTAL:
390 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
391 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
392 			break;
393 		}
394 		rsp->status = remove_initiator_portal((iscsid_sym_id_t *)p);
395 		break;
396 
397 	case ISCSID_LOGIN:
398 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
399 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
400 			break;
401 		}
402 		log_in((iscsid_login_req_t *)p, rsp);
403 		break;
404 
405 	case ISCSID_ADD_CONNECTION:
406 		if (req->parameter_length != sizeof(iscsid_login_req_t)) {
407 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
408 			break;
409 		}
410 		add_connection((iscsid_login_req_t *)p, rsp);
411 		break;
412 
413 	case ISCSID_LOGOUT:
414 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
415 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
416 			break;
417 		}
418 		rsp->status = log_out((iscsid_sym_id_t *)p);
419 		break;
420 
421 	case ISCSID_REMOVE_CONNECTION:
422 		if (req->parameter_length != sizeof(iscsid_remove_connection_req_t)) {
423 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
424 			break;
425 		}
426 		rsp->status = remove_connection((iscsid_remove_connection_req_t *)p);
427 		break;
428 
429 	case ISCSID_GET_SESSION_LIST:
430 		get_session_list(prsp, prsp_temp);
431 		break;
432 
433 	case ISCSID_GET_CONNECTION_LIST:
434 		if (req->parameter_length != sizeof(iscsid_sym_id_t)) {
435 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
436 			break;
437 		}
438 		get_connection_list((iscsid_sym_id_t *)p, prsp, prsp_temp);
439 		break;
440 
441 	case ISCSID_GET_CONNECTION_INFO:
442 		if (req->parameter_length != sizeof(iscsid_get_connection_info_req_t)) {
443 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
444 			break;
445 		}
446 		get_connection_info((iscsid_get_connection_info_req_t *)p,
447 							prsp, prsp_temp);
448 		break;
449 
450 	case ISCSID_SET_NODE_NAME:
451 		if (req->parameter_length != sizeof(iscsid_set_node_name_req_t)) {
452 			rsp->status = ISCSID_STATUS_INVALID_PARAMETER;
453 			break;
454 		}
455 		rsp->status = set_node_name((iscsid_set_node_name_req_t *)p);
456 		break;
457 
458 	case ISCSID_GET_VERSION:
459 		get_version(prsp, prsp_temp);
460 		break;
461 
462 	default:
463 		rsp->status = ISCSID_STATUS_INVALID_REQUEST;
464 		break;
465 	}
466 }
467 
468 void
469 iscsid_log(const char *fmt, ...)
470 {
471 	va_list ap;
472 	va_start(ap, fmt);
473 	vsyslog(LOG_INFO, fmt, ap);
474 	va_end(ap);
475 }
476 
477 /*
478  * exit_daemon:
479  *    Deregister the event handler, deregister isns servers, then exit program.
480  */
481 
482 static void __dead
483 exit_daemon(void)
484 {
485 	LOCK_SESSIONS;
486 	deregister_event_handler();
487 
488 #ifndef ISCSI_MINIMAL
489 	dereg_all_isns_servers();
490 #endif
491 	exit(0);
492 }
493 
494 static void
495 handler_exit(void)
496 {
497 	pthread_kill(main_thread, SIGINT);
498 }
499 
500 static void
501 sighandler(int sig)
502 {
503 }
504 
505 /*
506  * main:
507  *    init, go daemon, then loop reading requests, processing them,
508  *    and sending responses.
509  *    Stops on receiving a terminate message (no response to that one is sent),
510  *    or when an error occurs reading or writing the socket.
511  *
512  *    Parameter:  argc, argv currently ignored.
513  */
514 
515 int
516 /*ARGSUSED*/
517 main(int argc, char **argv)
518 {
519 	int req_temp, rsp_temp, c;
520 	ssize_t ret;
521 	size_t len;
522 	struct sockaddr_un from;
523 	socklen_t fromlen;
524 	iscsid_request_t *req;
525 	iscsid_response_t *rsp;
526 	char *p;
527 	struct sigaction sa;
528 
529 	while ((c = getopt(argc, argv, "Dd:")) != -1)
530 		switch (c) {
531 		case 'D':
532 			debugging++;
533 			break;
534 		case 'd':
535 			debug_level=(int)strtol(optarg, &p, 10);
536 			if (*p)
537 				errx(EXIT_FAILURE, "illegal log level -- %s",
538 				    optarg);
539 			break;
540 		default:
541 			usage();
542 		}
543 
544 	openlog("iscsid", (debugging ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON);
545 
546 	client_sock = init_daemon();
547 	if (client_sock < 0)
548 		exit(1);
549 
550 	DEBOUT(("iSCSI daemon loaded"));
551 
552 	if (!debugging) {
553 		if (daemon(0, 1) < 0)
554 			err(EXIT_FAILURE, "daemon() failed");
555 		pidfile(NULL);
556 	}
557 
558 	memset(&sa, 0, sizeof(sa));
559 	sa.sa_handler = sighandler;
560 	sigaction(SIGINT, &sa, NULL);
561 	sigaction(SIGTERM, &sa, NULL);
562 
563 	main_thread = pthread_self();
564 	ret = pthread_create(&event_thread, NULL, event_handler, handler_exit);
565 	if (ret) {
566 		printf("Thread creation failed (%zd)\n", ret);
567 		close(client_sock);
568 		unlink(ISCSID_SOCK_NAME);
569 		deregister_event_handler();
570 		pthread_mutex_destroy(&sesslist_lock);
571 		return -1;
572 	}
573 
574     /* ---------------------------------------------------------------------- */
575 
576 	for (;;) {
577 
578 		/* First, get size of request */
579 		req = (iscsid_request_t *)(void *)req_buf;
580 		fromlen = sizeof(from);
581 		len = sizeof(iscsid_request_t);
582 
583 		do {
584 			ret = recvfrom(client_sock, req, len, MSG_PEEK |
585 			    MSG_WAITALL, (struct sockaddr *) &from,
586 			    &fromlen);
587 		} while (ret == -1 && errno == EAGAIN);
588 
589 		if ((size_t)ret != len) {
590 			DEBOUT(("Receiving from socket: %s",strerror(errno)));
591 			break;
592 		}
593 		DEB(2, ("Request %d, parlen %d",
594 				req->request, req->parameter_length));
595 
596 		len += req->parameter_length;
597 
598 		/* now that we know the size, get the buffer for it */
599 		req_temp = (len > REQ_BUFFER_SIZE);
600 
601 		if (req_temp) {
602 			req = malloc(len);
603 			if (!req) {
604 				printf("Can't alloc %zu bytes\n", len);
605 				break;
606 			}
607 		}
608 		/* read the complete request */
609 		fromlen = sizeof(from);
610 		ret = recvfrom(client_sock, req, len, MSG_WAITALL,
611 						(struct sockaddr *)(void *)&from, &fromlen);
612 		if ((size_t)ret != len) {
613 			DEB(2, ("Error receiving from socket!"));
614 			if (req_temp)
615 				free(req);
616 			continue;
617 		}
618 		/* terminate? then go die. */
619 		if (req->request == ISCSID_DAEMON_TERMINATE)
620 			break;
621 
622 		/* No reply required to test message */
623 		if (req->request == ISCSID_DAEMON_TEST) {
624 			if (req_temp)
625 				free(req);
626 			DEB(2, ("Test message!"));
627 			continue;
628 		}
629 		/* no return path? then we can't send a reply, */
630 		/* so don't process the command */
631 		if (!from.sun_path[0]) {
632 			if (req_temp)
633 				free(req);
634 			DEB(2, ("No Return Address!"));
635 			continue;
636 		}
637 		/* process the request */
638 		process_message(req, &rsp, &rsp_temp);
639 		if (rsp == NULL) {
640 			if (req_temp)
641 				free(req);
642 			DEB(2, ("Invalid message!"));
643 			continue;
644 		}
645 
646 		DEB(2, ("Sending reply: status %d, len %d",
647 				rsp->status, rsp->parameter_length));
648 
649 		/* send the response */
650 		len = sizeof(iscsid_response_t) + rsp->parameter_length;
651 		ret = sendto(client_sock, rsp, len, 0,
652 					(struct sockaddr *)(void *)&from, fromlen);
653 		if (len != (size_t)ret) {
654 			DEB(2, ("Error sending reply!"));
655 		}
656 		/* free temp buffers if we needed them */
657 		if (req_temp)
658 			free(req);
659 		if (rsp_temp)
660 			free(rsp);
661 	}
662 
663 	pthread_join(event_thread, NULL);
664 
665 	DEBOUT(("Exiting daemon"));
666 
667 	exit_daemon();
668 
669 	/* we never get here */
670 	return 0;
671 }
672