xref: /openbsd-src/usr.sbin/radiusd/radiusd_module.c (revision 7c0ec4b8992567abb1e1536622dc789a9a39d9f1)
1 /*	$OpenBSD: radiusd_module.c,v 1.19 2024/07/14 15:27:57 yasuoka Exp $	*/
2 
3 /*
4  * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* radiusd_module.c -- helper functions for radiusd modules */
20 
21 #include <sys/types.h>
22 #include <sys/queue.h>
23 #include <sys/uio.h>
24 
25 #include <err.h>
26 #include <errno.h>
27 #include <event.h>
28 #include <fcntl.h>
29 #include <imsg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <syslog.h>
34 #include <unistd.h>
35 #include <pwd.h>
36 
37 #include "radiusd.h"
38 #include "radiusd_module.h"
39 #include "imsg_subr.h"
40 
41 static void	(*module_config_set) (void *, const char *, int,
42 		    char * const *) = NULL;
43 static void	(*module_start_module) (void *) = NULL;
44 static void	(*module_stop_module) (void *) = NULL;
45 static void	(*module_userpass) (void *, u_int, const char *, const char *)
46 		    = NULL;
47 static void	(*module_access_request) (void *, u_int, const u_char *,
48 		    size_t) = NULL;
49 static void	(*module_next_response) (void *, u_int, const u_char *,
50 		    size_t) = NULL;
51 static void	(*module_request_decoration) (void *, u_int, const u_char *,
52 		    size_t) = NULL;
53 static void	(*module_response_decoration) (void *, u_int, const u_char *,
54 		    size_t, const u_char *, size_t) = NULL;
55 static void	(*module_accounting_request) (void *, u_int, const u_char *,
56 		    size_t) = NULL;
57 static void	(*module_dispatch_control) (void *, struct imsg *) = NULL;
58 
59 struct module_base {
60 	void			*ctx;
61 	struct imsgbuf		 ibuf;
62 	bool			 priv_dropped;
63 
64 	/* Buffer for receiving the RADIUS packet */
65 	u_char			*radpkt;
66 	int			 radpktsiz;
67 	int			 radpktoff;
68 	u_char			*radpkt2;
69 	int			 radpkt2siz;	/* allocated size */
70 	int			 radpkt2len;	/* actual size */
71 
72 #ifdef USE_LIBEVENT
73 	struct module_imsgbuf	*module_imsgbuf;
74 	bool			 writeready;
75 	bool			 stopped;
76 	bool			 ev_onhandler;
77 	struct event		 ev;
78 #endif
79 };
80 
81 static int	 module_common_radpkt(struct module_base *, uint32_t, u_int,
82 		    const u_char *, size_t);
83 static int	 module_recv_imsg(struct module_base *);
84 static int	 module_imsg_handler(struct module_base *, struct imsg *);
85 #ifdef USE_LIBEVENT
86 static void	 module_on_event(int, short, void *);
87 #endif
88 static void	 module_reset_event(struct module_base *);
89 
90 struct module_base *
91 module_create(int sock, void *ctx, struct module_handlers *handler)
92 {
93 	struct module_base	*base;
94 
95 	if ((base = calloc(1, sizeof(struct module_base))) == NULL)
96 		return (NULL);
97 
98 	imsg_init(&base->ibuf, sock);
99 	base->ctx = ctx;
100 
101 	module_userpass = handler->userpass;
102 	module_access_request = handler->access_request;
103 	module_next_response = handler->next_response;
104 	module_config_set = handler->config_set;
105 	module_request_decoration = handler->request_decoration;
106 	module_response_decoration = handler->response_decoration;
107 	module_accounting_request = handler->accounting_request;
108 	module_start_module = handler->start;
109 	module_stop_module = handler->stop;
110 	module_dispatch_control = handler->dispatch_control;
111 
112 	return (base);
113 }
114 
115 void
116 module_start(struct module_base *base)
117 {
118 #ifdef USE_LIBEVENT
119 	int	 ival;
120 
121 	if ((ival = fcntl(base->ibuf.fd, F_GETFL)) == -1)
122 		err(1, "Failed to F_GETFL");
123 	if (fcntl(base->ibuf.fd, F_SETFL, ival | O_NONBLOCK) == -1)
124 		err(1, "Failed to setup NONBLOCK");
125 	event_set(&base->ev, base->ibuf.fd, EV_READ, module_on_event, base);
126 	event_add(&base->ev, NULL);
127 #endif
128 }
129 
130 int
131 module_run(struct module_base *base)
132 {
133 	int	 ret;
134 
135 	ret = module_recv_imsg(base);
136 	if (ret == 0)
137 		imsg_flush(&base->ibuf);
138 
139 	return (ret);
140 }
141 
142 void
143 module_destroy(struct module_base *base)
144 {
145 	if (base != NULL) {
146 		free(base->radpkt);
147 		free(base->radpkt2);
148 		imsg_clear(&base->ibuf);
149 	}
150 	free(base);
151 }
152 
153 void
154 module_load(struct module_base *base)
155 {
156 	struct radiusd_module_load_arg	 load;
157 
158 	memset(&load, 0, sizeof(load));
159 	if (module_userpass != NULL)
160 		load.cap |= RADIUSD_MODULE_CAP_USERPASS;
161 	if (module_access_request != NULL)
162 		load.cap |= RADIUSD_MODULE_CAP_ACCSREQ;
163 	if (module_next_response != NULL)
164 		load.cap |= RADIUSD_MODULE_CAP_NEXTRES;
165 	if (module_request_decoration != NULL)
166 		load.cap |= RADIUSD_MODULE_CAP_REQDECO;
167 	if (module_response_decoration != NULL)
168 		load.cap |= RADIUSD_MODULE_CAP_RESDECO;
169 	if (module_accounting_request != NULL)
170 		load.cap |= RADIUSD_MODULE_CAP_ACCTREQ;
171 	if (module_dispatch_control != NULL)
172 		load.cap |= RADIUSD_MODULE_CAP_CONTROL;
173 	imsg_compose(&base->ibuf, IMSG_RADIUSD_MODULE_LOAD, 0, 0, -1, &load,
174 	    sizeof(load));
175 	imsg_flush(&base->ibuf);
176 }
177 
178 void
179 module_drop_privilege(struct module_base *base, int nochroot)
180 {
181 	struct passwd	*pw;
182 
183 	tzset();
184 
185 	/* Drop the privilege */
186 	if ((pw = getpwnam(RADIUSD_USER)) == NULL)
187 		goto on_fail;
188 	if (nochroot == 0 && chroot(pw->pw_dir) == -1)
189 		goto on_fail;
190 	if (chdir("/") == -1)
191 		goto on_fail;
192 	if (setgroups(1, &pw->pw_gid) ||
193 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
194 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
195 		goto on_fail;
196 	base->priv_dropped = true;
197 
198 on_fail:
199 	return;
200 }
201 
202 int
203 module_notify_secret(struct module_base *base, const char *secret)
204 {
205 	int		 ret;
206 
207 	ret = imsg_compose(&base->ibuf, IMSG_RADIUSD_MODULE_NOTIFY_SECRET,
208 	    0, 0, -1, secret, strlen(secret) + 1);
209 	module_reset_event(base);
210 
211 	return (ret);
212 }
213 
214 int
215 module_send_message(struct module_base *base, uint32_t cmd, const char *fmt,
216     ...)
217 {
218 	char	*msg;
219 	va_list	 ap;
220 	int	 ret;
221 
222 	if (fmt == NULL)
223 		ret = imsg_compose(&base->ibuf, cmd, 0, 0, -1, NULL, 0);
224 	else {
225 		va_start(ap, fmt);
226 		vasprintf(&msg, fmt, ap);
227 		va_end(ap);
228 		if (msg == NULL)
229 			return (-1);
230 		ret = imsg_compose(&base->ibuf, cmd, 0, 0, -1, msg,
231 		    strlen(msg) + 1);
232 		free(msg);
233 	}
234 	module_reset_event(base);
235 
236 	return (ret);
237 }
238 
239 int
240 module_userpass_ok(struct module_base *base, u_int q_id, const char *msg)
241 {
242 	int		 ret;
243 	struct iovec	 iov[2];
244 
245 	iov[0].iov_base = &q_id;
246 	iov[0].iov_len = sizeof(q_id);
247 	iov[1].iov_base = (char *)msg;
248 	iov[1].iov_len = strlen(msg) + 1;
249 	ret = imsg_composev(&base->ibuf, IMSG_RADIUSD_MODULE_USERPASS_OK,
250 	    0, 0, -1, iov, 2);
251 	module_reset_event(base);
252 
253 	return (ret);
254 }
255 
256 int
257 module_userpass_fail(struct module_base *base, u_int q_id, const char *msg)
258 {
259 	int		 ret;
260 	struct iovec	 iov[2];
261 
262 	iov[0].iov_base = &q_id;
263 	iov[0].iov_len = sizeof(q_id);
264 	iov[1].iov_base = (char *)msg;
265 	iov[1].iov_len = strlen(msg) + 1;
266 	ret = imsg_composev(&base->ibuf, IMSG_RADIUSD_MODULE_USERPASS_FAIL,
267 	    0, 0, -1, iov, 2);
268 	module_reset_event(base);
269 
270 	return (ret);
271 }
272 
273 int
274 module_accsreq_answer(struct module_base *base, u_int q_id, const u_char *pkt,
275     size_t pktlen)
276 {
277 	return (module_common_radpkt(base, IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER,
278 	    q_id, pkt, pktlen));
279 }
280 
281 int
282 module_accsreq_next(struct module_base *base, u_int q_id, const u_char *pkt,
283     size_t pktlen)
284 {
285 	return (module_common_radpkt(base, IMSG_RADIUSD_MODULE_ACCSREQ_NEXT,
286 	    q_id, pkt, pktlen));
287 }
288 
289 int
290 module_accsreq_aborted(struct module_base *base, u_int q_id)
291 {
292 	int	 ret;
293 
294 	ret = imsg_compose(&base->ibuf, IMSG_RADIUSD_MODULE_ACCSREQ_ABORTED,
295 	    0, 0, -1, &q_id, sizeof(u_int));
296 	module_reset_event(base);
297 
298 	return (ret);
299 }
300 
301 int
302 module_reqdeco_done(struct module_base *base, u_int q_id, const u_char *pkt,
303     size_t pktlen)
304 {
305 	return (module_common_radpkt(base, IMSG_RADIUSD_MODULE_REQDECO_DONE,
306 	    q_id, pkt, pktlen));
307 }
308 
309 int
310 module_resdeco_done(struct module_base *base, u_int q_id, const u_char *pkt,
311     size_t pktlen)
312 {
313 	return (module_common_radpkt(base, IMSG_RADIUSD_MODULE_RESDECO_DONE,
314 	    q_id, pkt, pktlen));
315 }
316 
317 static int
318 module_common_radpkt(struct module_base *base, uint32_t imsg_type, u_int q_id,
319     const u_char *pkt, size_t pktlen)
320 {
321 	int		 ret = 0, off = 0, len, siz;
322 	struct iovec	 iov[2];
323 	struct radiusd_module_radpkt_arg	 ans;
324 
325 	len = pktlen;
326 	ans.q_id = q_id;
327 	ans.pktlen = pktlen;
328 	ans.final = false;
329 
330 	while (!ans.final) {
331 		siz = MAX_IMSGSIZE - sizeof(ans);
332 		if (len - off <= siz) {
333 			ans.final = true;
334 			siz = len - off;
335 		}
336 		iov[0].iov_base = &ans;
337 		iov[0].iov_len = sizeof(ans);
338 		if (siz > 0) {
339 			iov[1].iov_base = (u_char *)pkt + off;
340 			iov[1].iov_len = siz;
341 		}
342 		ret = imsg_composev(&base->ibuf, imsg_type, 0, 0, -1, iov,
343 		    (siz > 0)? 2 : 1);
344 		if (ret == -1)
345 			break;
346 		off += siz;
347 	}
348 	module_reset_event(base);
349 
350 	return (ret);
351 }
352 
353 static int
354 module_recv_imsg(struct module_base *base)
355 {
356 	ssize_t		 n;
357 	struct imsg	 imsg;
358 
359 	if (((n = imsg_read(&base->ibuf)) == -1 && errno != EAGAIN) || n == 0) {
360 		if (n != 0)
361 			syslog(LOG_ERR, "%s: imsg_read(): %m", __func__);
362 		module_stop(base);
363 		return (-1);
364 	}
365 	for (;;) {
366 		if ((n = imsg_get(&base->ibuf, &imsg)) == -1) {
367 			syslog(LOG_ERR, "%s: imsg_get(): %m", __func__);
368 			module_stop(base);
369 			return (-1);
370 		}
371 		if (n == 0)
372 			break;
373 		module_imsg_handler(base, &imsg);
374 		imsg_free(&imsg);
375 	}
376 	module_reset_event(base);
377 
378 	return (0);
379 }
380 
381 static int
382 module_imsg_handler(struct module_base *base, struct imsg *imsg)
383 {
384 	ssize_t	 datalen;
385 
386 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
387 	switch (imsg->hdr.type) {
388 	case IMSG_RADIUSD_MODULE_SET_CONFIG:
389 	    {
390 		struct radiusd_module_set_arg	 *arg;
391 		struct radiusd_module_object	 *val;
392 		u_int				  i;
393 		size_t				  off;
394 		char				**argv;
395 
396 		arg = (struct radiusd_module_set_arg *)imsg->data;
397 		off = sizeof(struct radiusd_module_set_arg);
398 
399 		if ((argv = calloc(sizeof(const char *), arg->nparamval))
400 		    == NULL) {
401 			module_send_message(base, IMSG_NG,
402 			    "Out of memory: %s", strerror(errno));
403 			break;
404 		}
405 		for (i = 0; i < arg->nparamval; i++) {
406 			if (datalen - off <
407 			    sizeof(struct radiusd_module_object))
408 				break;
409 			val = (struct radiusd_module_object *)
410 			    ((caddr_t)imsg->data + off);
411 			if (datalen - off < val->size)
412 				break;
413 			argv[i] = (char *)(val + 1);
414 			off += val->size;
415 		}
416 		if (i >= arg->nparamval)
417 			module_config_set(base->ctx, arg->paramname,
418 			    arg->nparamval, argv);
419 		else
420 			module_send_message(base, IMSG_NG,
421 			    "Internal protocol error");
422 		free(argv);
423 
424 		break;
425 	    }
426 	case IMSG_RADIUSD_MODULE_START:
427 		if (module_start_module != NULL) {
428 			module_start_module(base->ctx);
429 			if (!base->priv_dropped) {
430 				syslog(LOG_ERR, "Module tried to start with "
431 				    "root privileges");
432 				abort();
433 			}
434 		} else {
435 			if (!base->priv_dropped) {
436 				syslog(LOG_ERR, "Module tried to start with "
437 				    "root privileges");
438 				abort();
439 			}
440 			module_send_message(base, IMSG_OK, NULL);
441 		}
442 		break;
443 	case IMSG_RADIUSD_MODULE_STOP:
444 		module_stop(base);
445 		break;
446 	case IMSG_RADIUSD_MODULE_USERPASS:
447 	    {
448 		struct radiusd_module_userpass_arg *userpass;
449 
450 		if (module_userpass == NULL) {
451 			syslog(LOG_ERR, "Received USERPASS message, but "
452 			    "module doesn't support");
453 			break;
454 		}
455 		if (datalen <
456 		    (ssize_t)sizeof(struct radiusd_module_userpass_arg)) {
457 			syslog(LOG_ERR, "Received USERPASS message, but "
458 			    "length is wrong");
459 			break;
460 		}
461 		userpass = (struct radiusd_module_userpass_arg *)imsg->data;
462 		module_userpass(base->ctx, userpass->q_id, userpass->user,
463 		    (userpass->has_pass)? userpass->pass : NULL);
464 		explicit_bzero(userpass,
465 		    sizeof(struct radiusd_module_userpass_arg));
466 		break;
467 	    }
468 	case IMSG_RADIUSD_MODULE_ACCSREQ:
469 	case IMSG_RADIUSD_MODULE_NEXTRES:
470 	case IMSG_RADIUSD_MODULE_REQDECO:
471 	case IMSG_RADIUSD_MODULE_RESDECO0_REQ:
472 	case IMSG_RADIUSD_MODULE_RESDECO:
473 	case IMSG_RADIUSD_MODULE_ACCTREQ:
474 	    {
475 		struct radiusd_module_radpkt_arg	*accessreq;
476 		int					 chunklen;
477 		const char				*typestr;
478 
479 		if (imsg->hdr.type == IMSG_RADIUSD_MODULE_ACCSREQ) {
480 			if (module_access_request == NULL) {
481 				syslog(LOG_ERR, "Received ACCSREQ message, but "
482 				    "module doesn't support");
483 				break;
484 			}
485 			typestr = "ACCSREQ";
486 		} else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_NEXTRES) {
487 			if (module_next_response == NULL) {
488 				syslog(LOG_ERR, "Received NEXTRES message, but "
489 				    "module doesn't support");
490 				break;
491 			}
492 			typestr = "NEXTRES";
493 		} else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_ACCTREQ) {
494 			if (module_accounting_request == NULL) {
495 				syslog(LOG_ERR, "Received ACCTREQ message, but "
496 				    "module doesn't support");
497 				break;
498 			}
499 			typestr = "ACCTREQ";
500 		} else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_REQDECO) {
501 			if (module_request_decoration == NULL) {
502 				syslog(LOG_ERR, "Received REQDECO message, but "
503 				    "module doesn't support");
504 				break;
505 			}
506 			typestr = "REQDECO";
507 		} else {
508 			if (module_response_decoration == NULL) {
509 				syslog(LOG_ERR, "Received RESDECO message, but "
510 				    "module doesn't support");
511 				break;
512 			}
513 			if (imsg->hdr.type == IMSG_RADIUSD_MODULE_RESDECO0_REQ)
514 				typestr = "RESDECO0_REQ";
515 			else
516 				typestr = "RESDECO";
517 		}
518 
519 		if (datalen <
520 		    (ssize_t)sizeof(struct radiusd_module_radpkt_arg)) {
521 			syslog(LOG_ERR, "Received %s message, but "
522 			    "length is wrong", typestr);
523 			break;
524 		}
525 		accessreq = (struct radiusd_module_radpkt_arg *)imsg->data;
526 		if (base->radpktsiz < accessreq->pktlen) {
527 			u_char *nradpkt;
528 			if ((nradpkt = realloc(base->radpkt,
529 			    accessreq->pktlen)) == NULL) {
530 				syslog(LOG_ERR, "Could not handle received "
531 				    "%s message: %m", typestr);
532 				base->radpktoff = 0;
533 				goto accsreq_out;
534 			}
535 			base->radpkt = nradpkt;
536 			base->radpktsiz = accessreq->pktlen;
537 		}
538 		chunklen = datalen - sizeof(struct radiusd_module_radpkt_arg);
539 		if (chunklen > base->radpktsiz - base->radpktoff){
540 			syslog(LOG_ERR,
541 			    "Could not handle received %s message: "
542 			    "received length is too big", typestr);
543 			base->radpktoff = 0;
544 			goto accsreq_out;
545 		}
546 		memcpy(base->radpkt + base->radpktoff,
547 		    (caddr_t)(accessreq + 1), chunklen);
548 		base->radpktoff += chunklen;
549 		if (!accessreq->final)
550 			goto accsreq_out;
551 		if (base->radpktoff != accessreq->pktlen) {
552 			syslog(LOG_ERR,
553 			    "Could not handle received %s "
554 			    "message: length is mismatch", typestr);
555 			base->radpktoff = 0;
556 			goto accsreq_out;
557 		}
558 		if (imsg->hdr.type == IMSG_RADIUSD_MODULE_ACCSREQ)
559 			module_access_request(base->ctx, accessreq->q_id,
560 			    base->radpkt, base->radpktoff);
561 		else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_NEXTRES)
562 			module_next_response(base->ctx, accessreq->q_id,
563 			    base->radpkt, base->radpktoff);
564 		else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_REQDECO)
565 			module_request_decoration(base->ctx, accessreq->q_id,
566 			    base->radpkt, base->radpktoff);
567 		else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_RESDECO0_REQ) {
568 			/* preserve request */
569 			if (base->radpktoff > base->radpkt2siz) {
570 				u_char *nradpkt;
571 				if ((nradpkt = realloc(base->radpkt2,
572 				    base->radpktoff)) == NULL) {
573 					syslog(LOG_ERR, "Could not handle "
574 					    "received %s message: %m", typestr);
575 					base->radpktoff = 0;
576 					goto accsreq_out;
577 				}
578 				base->radpkt2 = nradpkt;
579 				base->radpkt2siz = base->radpktoff;
580 			}
581 			memcpy(base->radpkt2, base->radpkt, base->radpktoff);
582 			base->radpkt2len = base->radpktoff;
583 		} else if (imsg->hdr.type == IMSG_RADIUSD_MODULE_RESDECO) {
584 			module_response_decoration(base->ctx, accessreq->q_id,
585 			    base->radpkt2, base->radpkt2len, base->radpkt,
586 			    base->radpktoff);
587 			base->radpkt2len = 0;
588 		} else
589 			module_accounting_request(base->ctx, accessreq->q_id,
590 			    base->radpkt, base->radpktoff);
591 		base->radpktoff = 0;
592  accsreq_out:
593 		break;
594 	    }
595 	case IMSG_RADIUSD_MODULE_CTRL_UNBIND:
596 		goto forward_msg;
597 		break;
598 	default:
599 		if (imsg->hdr.type >= IMSG_RADIUSD_MODULE_MIN) {
600  forward_msg:
601 			if (module_dispatch_control == NULL) {
602 				const char msg[] =
603 				    "the module doesn't handle any controls";
604 				imsg_compose(&base->ibuf, IMSG_NG,
605 				    imsg->hdr.peerid, 0, -1, msg, sizeof(msg));
606 			} else
607 				module_dispatch_control(base->ctx, imsg);
608 		}
609 	}
610 
611 	return (0);
612 }
613 
614 void
615 module_stop(struct module_base *base)
616 {
617 	if (module_stop_module != NULL)
618 		module_stop_module(base->ctx);
619 #ifdef USE_LIBEVENT
620 	event_del(&base->ev);
621 	base->stopped = true;
622 #endif
623 	close(base->ibuf.fd);
624 }
625 
626 #ifdef USE_LIBEVENT
627 static void
628 module_on_event(int fd, short evmask, void *ctx)
629 {
630 	struct module_base	*base = ctx;
631 	int			 ret;
632 
633 	base->ev_onhandler = true;
634 	if (evmask & EV_WRITE)
635 		base->writeready = true;
636 	if (evmask & EV_READ) {
637 		ret = module_recv_imsg(base);
638 		if (ret < 0)
639 			return;
640 	}
641 	while (base->writeready && base->ibuf.w.queued) {
642 		ret = msgbuf_write(&base->ibuf.w);
643 		if (ret > 0)
644 			continue;
645 		base->writeready = false;
646 		if (ret == 0 && errno == EAGAIN)
647 			break;
648 		syslog(LOG_ERR, "%s: msgbuf_write: %m", __func__);
649 		module_stop(base);
650 		return;
651 	}
652 	base->ev_onhandler = false;
653 	module_reset_event(base);
654 	return;
655 }
656 #endif
657 
658 static void
659 module_reset_event(struct module_base *base)
660 {
661 #ifdef USE_LIBEVENT
662 	short		 evmask = 0;
663 	struct timeval	*tvp = NULL, tv = { 0, 0 };
664 
665 	if (base->ev_onhandler)
666 		return;
667 	if (base->stopped)
668 		return;
669 	event_del(&base->ev);
670 
671 	evmask |= EV_READ;
672 	if (base->ibuf.w.queued) {
673 		if (!base->writeready)
674 			evmask |= EV_WRITE;
675 		else
676 			tvp = &tv;	/* fire immediately */
677 	}
678 	event_set(&base->ev, base->ibuf.fd, evmask, module_on_event, base);
679 	if (event_add(&base->ev, tvp) == -1)
680 		syslog(LOG_ERR, "event_add() failed in %s()", __func__);
681 #endif
682 }
683 
684 int
685 module_imsg_compose(struct module_base *base, uint32_t type, uint32_t id,
686     pid_t pid, int fd, const void *data, size_t datalen)
687 {
688 	int	 ret;
689 
690 	if ((ret = imsg_compose(&base->ibuf, type, id, pid, fd, data, datalen))
691 	    != -1)
692 		module_reset_event(base);
693 
694 	return (ret);
695 }
696 
697 int
698 module_imsg_composev(struct module_base *base, uint32_t type, uint32_t id,
699     pid_t pid, int fd, const struct iovec *iov, int iovcnt)
700 {
701 	int	 ret;
702 
703 	if ((ret = imsg_composev(&base->ibuf, type, id, pid, fd, iov, iovcnt))
704 	    != -1)
705 		module_reset_event(base);
706 
707 	return (ret);
708 }
709