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