1 /* $OpenBSD: radiusd.c,v 1.34 2024/01/08 04:16:48 yasuoka Exp $ */ 2 3 /* 4 * Copyright (c) 2013, 2023 Internet Initiative Japan Inc. 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 #include <sys/types.h> 20 #include <netinet/in.h> 21 #include <arpa/inet.h> 22 #include <sys/queue.h> 23 #include <sys/socket.h> 24 #include <sys/time.h> 25 #include <sys/uio.h> 26 #include <sys/wait.h> 27 28 #include <err.h> 29 #include <errno.h> 30 #include <event.h> 31 #include <fcntl.h> 32 #include <fnmatch.h> 33 #include <imsg.h> 34 #include <md5.h> 35 #include <netdb.h> 36 #include <pwd.h> 37 #include <signal.h> 38 #include <stdbool.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <unistd.h> 44 45 #include <radius.h> 46 47 #include "radiusd.h" 48 #include "radiusd_local.h" 49 #include "log.h" 50 #include "util.h" 51 #include "imsg_subr.h" 52 53 static int radiusd_start(struct radiusd *); 54 static void radiusd_stop(struct radiusd *); 55 static void radiusd_free(struct radiusd *); 56 static void radiusd_listen_on_event(int, short, void *); 57 static void radiusd_on_sigterm(int, short, void *); 58 static void radiusd_on_sigint(int, short, void *); 59 static void radiusd_on_sighup(int, short, void *); 60 static void radiusd_on_sigchld(int, short, void *); 61 static void radius_query_request(struct radius_query *); 62 static void radius_query_response(struct radius_query *); 63 static const char *radius_code_string(int); 64 static int radiusd_access_response_fixup (struct radius_query *); 65 66 67 68 static void radiusd_module_reset_ev_handler( 69 struct radiusd_module *); 70 static int radiusd_module_imsg_read(struct radiusd_module *, 71 bool); 72 static void radiusd_module_imsg(struct radiusd_module *, 73 struct imsg *); 74 75 static struct radiusd_module_radpkt_arg * 76 radiusd_module_recv_radpkt(struct radiusd_module *, 77 struct imsg *, uint32_t, const char *); 78 static void radiusd_module_on_imsg_io(int, short, void *); 79 void radiusd_module_start(struct radiusd_module *); 80 void radiusd_module_stop(struct radiusd_module *); 81 static void radiusd_module_close(struct radiusd_module *); 82 static void radiusd_module_userpass(struct radiusd_module *, 83 struct radius_query *); 84 static void radiusd_module_access_request(struct radiusd_module *, 85 struct radius_query *); 86 static void radiusd_module_request_decoration( 87 struct radiusd_module *, struct radius_query *); 88 static void radiusd_module_response_decoration( 89 struct radiusd_module *, struct radius_query *); 90 static int imsg_compose_radius_packet(struct imsgbuf *, 91 uint32_t, u_int, RADIUS_PACKET *); 92 93 static u_int radius_query_id_seq = 0; 94 int debug = 0; 95 96 static __dead void 97 usage(void) 98 { 99 extern char *__progname; 100 101 fprintf(stderr, "usage: %s [-dn] [-f file]\n", __progname); 102 exit(EXIT_FAILURE); 103 } 104 105 int 106 main(int argc, char *argv[]) 107 { 108 extern char *__progname; 109 const char *conffile = CONFFILE; 110 int ch; 111 struct radiusd *radiusd; 112 bool noaction = false; 113 struct passwd *pw; 114 115 while ((ch = getopt(argc, argv, "df:n")) != -1) 116 switch (ch) { 117 case 'd': 118 debug++; 119 break; 120 121 case 'f': 122 conffile = optarg; 123 break; 124 125 case 'n': 126 noaction = true; 127 break; 128 129 default: 130 usage(); 131 /* NOTREACHED */ 132 } 133 134 argc -= optind; 135 argv += optind; 136 137 if (argc != 0) 138 usage(); 139 140 if ((radiusd = calloc(1, sizeof(*radiusd))) == NULL) 141 err(1, "calloc"); 142 TAILQ_INIT(&radiusd->listen); 143 TAILQ_INIT(&radiusd->query); 144 145 log_init(debug); 146 if (parse_config(conffile, radiusd) != 0) 147 errx(EXIT_FAILURE, "config error"); 148 if (noaction) { 149 fprintf(stderr, "configuration OK\n"); 150 exit(EXIT_SUCCESS); 151 } 152 153 if (debug == 0) 154 daemon(0, 0); 155 event_init(); 156 157 if ((pw = getpwnam(RADIUSD_USER)) == NULL) 158 errx(EXIT_FAILURE, "user `%s' is not found in password " 159 "database", RADIUSD_USER); 160 161 if (chroot(pw->pw_dir) == -1) 162 err(EXIT_FAILURE, "chroot"); 163 if (chdir("/") == -1) 164 err(EXIT_FAILURE, "chdir(\"/\")"); 165 166 if (setgroups(1, &pw->pw_gid) || 167 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 168 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 169 err(EXIT_FAILURE, "cannot drop privileges"); 170 171 signal(SIGPIPE, SIG_IGN); 172 openlog(NULL, LOG_PID, LOG_DAEMON); 173 174 signal_set(&radiusd->ev_sigterm, SIGTERM, radiusd_on_sigterm, radiusd); 175 signal_set(&radiusd->ev_sigint, SIGINT, radiusd_on_sigint, radiusd); 176 signal_set(&radiusd->ev_sighup, SIGHUP, radiusd_on_sighup, radiusd); 177 signal_set(&radiusd->ev_sigchld, SIGCHLD, radiusd_on_sigchld, radiusd); 178 179 if (radiusd_start(radiusd) != 0) 180 errx(EXIT_FAILURE, "start failed"); 181 182 if (pledge("stdio inet", NULL) == -1) 183 err(EXIT_FAILURE, "pledge"); 184 185 if (event_loop(0) < 0) 186 radiusd_stop(radiusd); 187 188 radiusd_free(radiusd); 189 event_base_free(NULL); 190 191 exit(EXIT_SUCCESS); 192 } 193 194 static int 195 radiusd_start(struct radiusd *radiusd) 196 { 197 struct radiusd_listen *l; 198 struct radiusd_module *module; 199 int s; 200 char hbuf[NI_MAXHOST]; 201 202 TAILQ_FOREACH(l, &radiusd->listen, next) { 203 if (getnameinfo( 204 (struct sockaddr *)&l->addr, l->addr.ipv4.sin_len, 205 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 206 log_warn("%s: getnameinfo()", __func__); 207 goto on_error; 208 } 209 if ((s = socket(l->addr.ipv4.sin_family, 210 l->stype | SOCK_NONBLOCK, l->sproto)) == -1) { 211 log_warn("Listen %s port %d is failed: socket()", 212 hbuf, (int)htons(l->addr.ipv4.sin_port)); 213 goto on_error; 214 } 215 if (bind(s, (struct sockaddr *)&l->addr, l->addr.ipv4.sin_len) 216 != 0) { 217 log_warn("Listen %s port %d is failed: bind()", 218 hbuf, (int)htons(l->addr.ipv4.sin_port)); 219 close(s); 220 goto on_error; 221 } 222 if (l->addr.ipv4.sin_family == AF_INET) 223 log_info("Start listening on %s:%d/udp", hbuf, 224 (int)ntohs(l->addr.ipv4.sin_port)); 225 else 226 log_info("Start listening on [%s]:%d/udp", hbuf, 227 (int)ntohs(l->addr.ipv4.sin_port)); 228 event_set(&l->ev, s, EV_READ | EV_PERSIST, 229 radiusd_listen_on_event, l); 230 if (event_add(&l->ev, NULL) != 0) { 231 log_warn("event_add() failed at %s()", __func__); 232 close(s); 233 goto on_error; 234 } 235 l->sock = s; 236 l->radiusd = radiusd; 237 } 238 239 signal_add(&radiusd->ev_sigterm, NULL); 240 signal_add(&radiusd->ev_sigint, NULL); 241 signal_add(&radiusd->ev_sighup, NULL); 242 signal_add(&radiusd->ev_sigchld, NULL); 243 244 TAILQ_FOREACH(module, &radiusd->module, next) { 245 if (debug > 0) 246 radiusd_module_set(module, "_debug", 0, NULL); 247 radiusd_module_start(module); 248 } 249 250 return (0); 251 on_error: 252 radiusd_stop(radiusd); 253 254 return (-1); 255 } 256 257 static void 258 radiusd_stop(struct radiusd *radiusd) 259 { 260 char hbuf[NI_MAXHOST]; 261 struct radiusd_listen *l; 262 struct radiusd_module *module; 263 264 TAILQ_FOREACH_REVERSE(l, &radiusd->listen, radiusd_listen_head, next) { 265 if (l->sock >= 0) { 266 if (getnameinfo( 267 (struct sockaddr *)&l->addr, l->addr.ipv4.sin_len, 268 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 269 strlcpy(hbuf, "error", sizeof(hbuf)); 270 if (l->addr.ipv4.sin_family == AF_INET) 271 log_info("Stop listening on %s:%d/udp", hbuf, 272 (int)ntohs(l->addr.ipv4.sin_port)); 273 else 274 log_info("Stop listening on [%s]:%d/udp", hbuf, 275 (int)ntohs(l->addr.ipv4.sin_port)); 276 event_del(&l->ev); 277 close(l->sock); 278 } 279 l->sock = -1; 280 } 281 TAILQ_FOREACH(module, &radiusd->module, next) { 282 radiusd_module_stop(module); 283 radiusd_module_close(module); 284 } 285 if (signal_pending(&radiusd->ev_sigterm, NULL)) 286 signal_del(&radiusd->ev_sigterm); 287 if (signal_pending(&radiusd->ev_sigint, NULL)) 288 signal_del(&radiusd->ev_sigint); 289 if (signal_pending(&radiusd->ev_sighup, NULL)) 290 signal_del(&radiusd->ev_sighup); 291 if (signal_pending(&radiusd->ev_sigchld, NULL)) 292 signal_del(&radiusd->ev_sigchld); 293 } 294 295 static void 296 radiusd_free(struct radiusd *radiusd) 297 { 298 int i; 299 struct radiusd_listen *listn, *listnt; 300 struct radiusd_client *client, *clientt; 301 struct radiusd_module *module, *modulet; 302 struct radiusd_module_ref *modref, *modreft; 303 struct radiusd_authentication *authen, *authent; 304 305 TAILQ_FOREACH_SAFE(authen, &radiusd->authen, next, authent) { 306 TAILQ_REMOVE(&radiusd->authen, authen, next); 307 free(authen->auth); 308 TAILQ_FOREACH_SAFE(modref, &authen->deco, next, modreft) { 309 TAILQ_REMOVE(&authen->deco, modref, next); 310 free(modref); 311 } 312 for (i = 0; authen->username[i] != NULL; i++) 313 free(authen->username[i]); 314 free(authen->username); 315 free(authen); 316 } 317 TAILQ_FOREACH_SAFE(module, &radiusd->module, next, modulet) { 318 TAILQ_REMOVE(&radiusd->module, module, next); 319 radiusd_module_unload(module); 320 } 321 TAILQ_FOREACH_SAFE(client, &radiusd->client, next, clientt) { 322 TAILQ_REMOVE(&radiusd->client, client, next); 323 explicit_bzero(client->secret, sizeof(client->secret)); 324 free(client); 325 } 326 TAILQ_FOREACH_SAFE(listn, &radiusd->listen, next, listnt) { 327 TAILQ_REMOVE(&radiusd->listen, listn, next); 328 free(listn); 329 } 330 free(radiusd); 331 } 332 333 /*********************************************************************** 334 * Network event handlers 335 ***********************************************************************/ 336 #define IPv4_cmp(_in, _addr, _mask) ( \ 337 ((_in)->s_addr & (_mask)->addr.ipv4.s_addr) == \ 338 (_addr)->addr.ipv4.s_addr) 339 #define s6_addr32(_in6) ((uint32_t *)(_in6)->s6_addr) 340 #define IPv6_cmp(_in6, _addr, _mask) ( \ 341 ((s6_addr32(_in6)[3] & (_mask)->addr.addr32[3]) \ 342 == (_addr)->addr.addr32[3]) && \ 343 ((s6_addr32(_in6)[2] & (_mask)->addr.addr32[2]) \ 344 == (_addr)->addr.addr32[2]) && \ 345 ((s6_addr32(_in6)[1] & (_mask)->addr.addr32[1]) \ 346 == (_addr)->addr.addr32[1]) && \ 347 ((s6_addr32(_in6)[0] & (_mask)->addr.addr32[0]) \ 348 == (_addr)->addr.addr32[0])) 349 350 static void 351 radiusd_listen_on_event(int fd, short evmask, void *ctx) 352 { 353 int i, sz, req_id, req_code; 354 struct radiusd_listen *listn = ctx; 355 static u_char buf[65535]; 356 static char username[256]; 357 struct sockaddr_storage peer; 358 socklen_t peersz; 359 RADIUS_PACKET *packet = NULL; 360 char peerstr[NI_MAXHOST + NI_MAXSERV + 30]; 361 struct radiusd_authentication *authen; 362 struct radiusd_client *client; 363 struct radius_query *q; 364 #define in(_x) (((struct sockaddr_in *)_x)->sin_addr) 365 #define in6(_x) (((struct sockaddr_in6 *)_x)->sin6_addr) 366 367 if (evmask & EV_READ) { 368 peersz = sizeof(peer); 369 if ((sz = recvfrom(listn->sock, buf, sizeof(buf), 0, 370 (struct sockaddr *)&peer, &peersz)) == -1) { 371 if (errno == EAGAIN) 372 return; 373 log_warn("%s: recvfrom() failed", __func__); 374 goto on_error; 375 } 376 RADIUSD_ASSERT(peer.ss_family == AF_INET || 377 peer.ss_family == AF_INET6); 378 379 /* prepare some information about this messages */ 380 if (addrport_tostring((struct sockaddr *)&peer, peersz, 381 peerstr, sizeof(peerstr)) == NULL) { 382 log_warn("%s: getnameinfo() failed", __func__); 383 goto on_error; 384 } 385 if ((packet = radius_convert_packet(buf, sz)) == NULL) { 386 log_warn("%s: radius_convert_packet() failed", 387 __func__); 388 goto on_error; 389 } 390 req_id = radius_get_id(packet); 391 req_code = radius_get_code(packet); 392 393 /* 394 * Find a matching `client' entry 395 */ 396 TAILQ_FOREACH(client, &listn->radiusd->client, next) { 397 if (client->af != peer.ss_family) 398 continue; 399 if (peer.ss_family == AF_INET && 400 IPv4_cmp(&((struct sockaddr_in *)&peer)->sin_addr, 401 &client->addr, &client->mask)) 402 break; 403 else if (peer.ss_family == AF_INET6 && 404 IPv6_cmp(&((struct sockaddr_in6 *)&peer)->sin6_addr, 405 &client->addr, &client->mask)) 406 break; 407 } 408 if (client == NULL) { 409 log_warnx("Received %s(code=%d) from %s id=%d: " 410 "no `client' matches", radius_code_string(req_code), 411 req_code, peerstr, req_id); 412 goto on_error; 413 } 414 415 /* Check the client's Message-Authenticator */ 416 if (client->msgauth_required && 417 !radius_has_attr(packet, 418 RADIUS_TYPE_MESSAGE_AUTHENTICATOR)) { 419 log_warnx("Received %s(code=%d) from %s id=%d: " 420 "no message authenticator", 421 radius_code_string(req_code), req_code, peerstr, 422 req_id); 423 goto on_error; 424 } 425 426 if (radius_has_attr(packet, 427 RADIUS_TYPE_MESSAGE_AUTHENTICATOR) && 428 radius_check_message_authenticator(packet, client->secret) 429 != 0) { 430 log_warnx("Received %s(code=%d) from %s id=%d: " 431 "bad message authenticator", 432 radius_code_string(req_code), req_code, peerstr, 433 req_id); 434 goto on_error; 435 } 436 437 /* 438 * Find a duplicate request. In RFC 2865, it has the same 439 * source IP address and source UDP port and Identifier. 440 */ 441 TAILQ_FOREACH(q, &listn->radiusd->query, next) { 442 if (peer.ss_family == q->clientaddr.ss_family && 443 ((peer.ss_family == AF_INET && 444 in(&q->clientaddr).s_addr == 445 in(&peer).s_addr) || 446 (peer.ss_family == AF_INET6 && 447 IN6_ARE_ADDR_EQUAL( 448 &in6(&q->clientaddr), &in6(&peer)))) && 449 ((struct sockaddr_in *)&q->clientaddr)->sin_port == 450 ((struct sockaddr_in *)&peer)->sin_port && 451 req_id == q->req_id) 452 break; /* found it */ 453 } 454 if (q != NULL) { 455 log_info("Received %s(code=%d) from %s id=%d: " 456 "duplicate request by q=%u", 457 radius_code_string(req_code), req_code, peerstr, 458 req_id, q->id); 459 /* XXX RFC 5080 suggests to answer the cached result */ 460 goto on_error; 461 } 462 463 /* FIXME: we can support other request codes */ 464 if (req_code != RADIUS_CODE_ACCESS_REQUEST) { 465 log_info("Received %s(code=%d) from %s id=%d: %s " 466 "is not supported in this implementation", 467 radius_code_string(req_code), req_code, peerstr, 468 req_id, radius_code_string(req_code)); 469 goto on_error; 470 } 471 472 /* 473 * Find a matching `authenticate' entry 474 */ 475 if (radius_get_string_attr(packet, RADIUS_TYPE_USER_NAME, 476 username, sizeof(username)) != 0) { 477 log_info("Received %s(code=%d) from %s id=%d: " 478 "no User-Name attribute", 479 radius_code_string(req_code), req_code, peerstr, 480 req_id); 481 goto on_error; 482 } 483 TAILQ_FOREACH(authen, &listn->radiusd->authen, next) { 484 for (i = 0; authen->username[i] != NULL; i++) { 485 if (fnmatch(authen->username[i], username, 0) 486 == 0) 487 goto found; 488 } 489 } 490 found: 491 if (authen == NULL) { 492 log_warnx("Received %s(code=%d) from %s id=%d " 493 "username=%s: no `authenticate' matches.", 494 radius_code_string(req_code), req_code, peerstr, 495 req_id, username); 496 goto on_error; 497 } 498 RADIUSD_ASSERT(authen->auth != NULL); 499 500 if (!MODULE_DO_USERPASS(authen->auth->module) && 501 !MODULE_DO_ACCSREQ(authen->auth->module)) { 502 log_warnx("Received %s(code=%d) from %s id=%d " 503 "username=%s: module `%s' is not running.", 504 radius_code_string(req_code), req_code, peerstr, 505 req_id, username, authen->auth->module->name); 506 goto on_error; 507 } 508 if ((q = calloc(1, sizeof(struct radius_query))) == NULL) { 509 log_warn("%s: Out of memory", __func__); 510 goto on_error; 511 } 512 memcpy(&q->clientaddr, &peer, peersz); 513 strlcpy(q->username, username, sizeof(q->username)); 514 q->id = ++radius_query_id_seq; 515 q->clientaddrlen = peersz; 516 q->authen = authen; 517 q->listen = listn; 518 q->req = packet; 519 q->client = client; 520 q->req_id = req_id; 521 radius_get_authenticator(packet, q->req_auth); 522 523 log_info("Received %s(code=%d) from %s id=%d username=%s " 524 "q=%u: `%s' authentication is starting", 525 radius_code_string(req_code), req_code, peerstr, q->req_id, 526 q->username, q->id, q->authen->auth->module->name); 527 TAILQ_INSERT_TAIL(&listn->radiusd->query, q, next); 528 529 radius_query_request(q); 530 531 return; 532 } 533 on_error: 534 if (packet != NULL) 535 radius_delete_packet(packet); 536 #undef in 537 #undef in6 538 539 return; 540 } 541 542 static void 543 radius_query_request(struct radius_query *q) 544 { 545 struct radiusd_authentication *authen = q->authen; 546 547 /* first or next request decoration */ 548 for (;;) { 549 if (q->deco == NULL) 550 q->deco = TAILQ_FIRST(&q->authen->deco); 551 else 552 q->deco = TAILQ_NEXT(q->deco, next); 553 if (q->deco == NULL || MODULE_DO_REQDECO(q->deco->module)) 554 break; 555 } 556 557 if (q->deco != NULL) 558 radiusd_module_request_decoration(q->deco->module, q); 559 else { 560 RADIUSD_ASSERT(authen->auth != NULL); 561 if (MODULE_DO_ACCSREQ(authen->auth->module)) 562 radiusd_module_access_request(authen->auth->module, q); 563 else if (MODULE_DO_USERPASS(authen->auth->module)) 564 radiusd_module_userpass(authen->auth->module, q); 565 } 566 } 567 568 static void 569 radius_query_response(struct radius_query *q) 570 { 571 int sz, res_id, res_code; 572 char buf[NI_MAXHOST + NI_MAXSERV + 30]; 573 574 /* first or next response decoration */ 575 for (;;) { 576 if (q->deco == NULL) 577 q->deco = TAILQ_FIRST(&q->authen->deco); 578 else 579 q->deco = TAILQ_NEXT(q->deco, next); 580 if (q->deco == NULL || MODULE_DO_RESDECO(q->deco->module)) 581 break; 582 } 583 584 if (q->deco != NULL) { 585 radiusd_module_response_decoration(q->deco->module, q); 586 return; 587 } 588 589 if (radiusd_access_response_fixup(q) != 0) 590 goto on_error; 591 592 res_id = radius_get_id(q->res); 593 res_code = radius_get_code(q->res); 594 595 /* Reset response/message authenticator */ 596 if (radius_has_attr(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR)) 597 radius_del_attr_all(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR); 598 radius_put_message_authenticator(q->res, q->client->secret); 599 radius_set_response_authenticator(q->res, q->client->secret); 600 601 log_info("Sending %s(code=%d) to %s id=%u q=%u", 602 radius_code_string(res_code), res_code, 603 addrport_tostring((struct sockaddr *)&q->clientaddr, 604 q->clientaddrlen, buf, sizeof(buf)), res_id, q->id); 605 606 if ((sz = sendto(q->listen->sock, radius_get_data(q->res), 607 radius_get_length(q->res), 0, 608 (struct sockaddr *)&q->clientaddr, q->clientaddrlen)) <= 0) 609 log_warn("Sending a RADIUS response failed"); 610 on_error: 611 radiusd_access_request_aborted(q); 612 613 } 614 615 /*********************************************************************** 616 * Callback functions from the modules 617 ***********************************************************************/ 618 void 619 radiusd_access_request_answer(struct radius_query *q) 620 { 621 const char *authen_secret = q->authen->auth->module->secret; 622 623 radius_set_request_packet(q->res, q->req); 624 625 if (authen_secret == NULL) { 626 /* 627 * The module diddn't check the authenticators 628 */ 629 if (radius_check_response_authenticator(q->res, 630 q->client->secret) != 0) { 631 log_info("Response from module has bad response " 632 "authenticator: id=%d", q->id); 633 goto on_error; 634 } 635 if (radius_has_attr(q->res, 636 RADIUS_TYPE_MESSAGE_AUTHENTICATOR) && 637 radius_check_message_authenticator(q->res, 638 q->client->secret) != 0) { 639 log_info("Response from module has bad message " 640 "authenticator: id=%d", q->id); 641 goto on_error; 642 } 643 } 644 645 RADIUSD_ASSERT(q->deco == NULL); 646 radius_query_response(q); 647 648 return; 649 on_error: 650 radiusd_access_request_aborted(q); 651 } 652 653 void 654 radiusd_access_request_aborted(struct radius_query *q) 655 { 656 if (q->req != NULL) 657 radius_delete_packet(q->req); 658 if (q->res != NULL) 659 radius_delete_packet(q->res); 660 TAILQ_REMOVE(&q->listen->radiusd->query, q, next); 661 free(q); 662 } 663 664 /*********************************************************************** 665 * Signal handlers 666 ***********************************************************************/ 667 static void 668 radiusd_on_sigterm(int fd, short evmask, void *ctx) 669 { 670 struct radiusd *radiusd = ctx; 671 672 log_info("Received SIGTERM"); 673 radiusd_stop(radiusd); 674 } 675 676 static void 677 radiusd_on_sigint(int fd, short evmask, void *ctx) 678 { 679 struct radiusd *radiusd = ctx; 680 681 log_info("Received SIGINT"); 682 radiusd_stop(radiusd); 683 } 684 685 static void 686 radiusd_on_sighup(int fd, short evmask, void *ctx) 687 { 688 log_info("Received SIGHUP"); 689 } 690 691 static void 692 radiusd_on_sigchld(int fd, short evmask, void *ctx) 693 { 694 struct radiusd *radiusd = ctx; 695 struct radiusd_module *module; 696 pid_t pid; 697 int status; 698 699 log_debug("Received SIGCHLD"); 700 while ((pid = wait3(&status, WNOHANG, NULL)) != 0) { 701 if (pid == -1) 702 break; 703 TAILQ_FOREACH(module, &radiusd->module, next) { 704 if (module->pid == pid) { 705 if (WIFEXITED(status)) 706 log_warnx("module `%s'(pid=%d) exited " 707 "with status %d", module->name, 708 (int)pid, WEXITSTATUS(status)); 709 else 710 log_warnx("module `%s'(pid=%d) exited " 711 "by signal %d", module->name, 712 (int)pid, WTERMSIG(status)); 713 break; 714 } 715 } 716 if (!module) { 717 if (WIFEXITED(status)) 718 log_warnx("unkown child process pid=%d exited " 719 "with status %d", (int)pid, 720 WEXITSTATUS(status)); 721 else 722 log_warnx("unkown child process pid=%d exited " 723 "by signal %d", (int)pid, 724 WTERMSIG(status)); 725 } 726 } 727 } 728 729 static const char * 730 radius_code_string(int code) 731 { 732 int i; 733 struct _codestrings { 734 int code; 735 const char *string; 736 } codestrings[] = { 737 { RADIUS_CODE_ACCESS_REQUEST, "Access-Request" }, 738 { RADIUS_CODE_ACCESS_ACCEPT, "Access-Accept" }, 739 { RADIUS_CODE_ACCESS_REJECT, "Access-Reject" }, 740 { RADIUS_CODE_ACCOUNTING_REQUEST, "Accounting-Request" }, 741 { RADIUS_CODE_ACCOUNTING_RESPONSE, "Accounting-Response" }, 742 { RADIUS_CODE_ACCESS_CHALLENGE, "Access-Challenge" }, 743 { RADIUS_CODE_STATUS_SERVER, "Status-Server" }, 744 { RADIUS_CODE_STATUS_CLIENT, "Status-Client" }, 745 { -1, NULL } 746 }; 747 748 for (i = 0; codestrings[i].code != -1; i++) 749 if (codestrings[i].code == code) 750 return (codestrings[i].string); 751 752 return ("Unknown"); 753 } 754 755 void 756 radiusd_conf_init(struct radiusd *conf) 757 { 758 759 TAILQ_INIT(&conf->listen); 760 TAILQ_INIT(&conf->module); 761 TAILQ_INIT(&conf->authen); 762 TAILQ_INIT(&conf->client); 763 764 return; 765 } 766 767 /* 768 * Fix some attributes which depend the secret value. 769 */ 770 static int 771 radiusd_access_response_fixup(struct radius_query *q) 772 { 773 int res_id; 774 size_t attrlen; 775 u_char req_auth[16], attrbuf[256]; 776 const char *authen_secret = q->authen->auth->module->secret; 777 778 radius_get_authenticator(q->req, req_auth); 779 780 if ((authen_secret != NULL && 781 strcmp(authen_secret, q->client->secret) != 0) || 782 timingsafe_bcmp(q->req_auth, req_auth, 16) != 0) { 783 const char *olds = q->client->secret; 784 const char *news = authen_secret; 785 786 if (news == NULL) 787 news = olds; 788 789 /* RFC 2865 Tunnel-Password */ 790 attrlen = sizeof(attrbuf); 791 if (radius_get_raw_attr(q->res, RADIUS_TYPE_TUNNEL_PASSWORD, 792 attrbuf, &attrlen) == 0) { 793 radius_attr_unhide(news, req_auth, 794 attrbuf, attrbuf + 3, attrlen - 3); 795 radius_attr_hide(olds, q->req_auth, 796 attrbuf, attrbuf + 3, attrlen - 3); 797 798 radius_del_attr_all(q->res, 799 RADIUS_TYPE_TUNNEL_PASSWORD); 800 radius_put_raw_attr(q->res, 801 RADIUS_TYPE_TUNNEL_PASSWORD, attrbuf, attrlen); 802 } 803 804 /* RFC 2548 Microsoft MPPE-{Send,Recv}-Key */ 805 attrlen = sizeof(attrbuf); 806 if (radius_get_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, 807 RADIUS_VTYPE_MPPE_SEND_KEY, attrbuf, &attrlen) == 0) { 808 809 /* Re-crypt the KEY */ 810 radius_attr_unhide(news, req_auth, 811 attrbuf, attrbuf + 2, attrlen - 2); 812 radius_attr_hide(olds, q->req_auth, 813 attrbuf, attrbuf + 2, attrlen - 2); 814 815 radius_del_vs_attr_all(q->res, RADIUS_VENDOR_MICROSOFT, 816 RADIUS_VTYPE_MPPE_SEND_KEY); 817 radius_put_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, 818 RADIUS_VTYPE_MPPE_SEND_KEY, attrbuf, attrlen); 819 } 820 attrlen = sizeof(attrbuf); 821 if (radius_get_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, 822 RADIUS_VTYPE_MPPE_RECV_KEY, attrbuf, &attrlen) == 0) { 823 824 /* Re-crypt the KEY */ 825 radius_attr_unhide(news, req_auth, 826 attrbuf, attrbuf + 2, attrlen - 2); 827 radius_attr_hide(olds, q->req_auth, 828 attrbuf, attrbuf + 2, attrlen - 2); 829 830 radius_del_vs_attr_all(q->res, RADIUS_VENDOR_MICROSOFT, 831 RADIUS_VTYPE_MPPE_RECV_KEY); 832 radius_put_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT, 833 RADIUS_VTYPE_MPPE_RECV_KEY, attrbuf, attrlen); 834 } 835 } 836 837 res_id = radius_get_id(q->res); 838 if (res_id != q->req_id) { 839 /* authentication server change the id */ 840 radius_set_id(q->res, q->req_id); 841 } 842 843 return (0); 844 } 845 846 void 847 radius_attr_hide(const char *secret, const char *authenticator, 848 const u_char *salt, u_char *plain, int plainlen) 849 { 850 int i, j; 851 u_char b[16]; 852 MD5_CTX md5ctx; 853 854 i = 0; 855 do { 856 MD5Init(&md5ctx); 857 MD5Update(&md5ctx, secret, strlen(secret)); 858 if (i == 0) { 859 MD5Update(&md5ctx, authenticator, 16); 860 if (salt != NULL) 861 MD5Update(&md5ctx, salt, 2); 862 } else 863 MD5Update(&md5ctx, plain + i - 16, 16); 864 MD5Final(b, &md5ctx); 865 866 for (j = 0; j < 16 && i < plainlen; i++, j++) 867 plain[i] ^= b[j]; 868 } while (i < plainlen); 869 } 870 871 void 872 radius_attr_unhide(const char *secret, const char *authenticator, 873 const u_char *salt, u_char *crypt0, int crypt0len) 874 { 875 int i, j; 876 u_char b[16]; 877 MD5_CTX md5ctx; 878 879 i = 16 * ((crypt0len - 1) / 16); 880 while (i >= 0) { 881 MD5Init(&md5ctx); 882 MD5Update(&md5ctx, secret, strlen(secret)); 883 if (i == 0) { 884 MD5Update(&md5ctx, authenticator, 16); 885 if (salt != NULL) 886 MD5Update(&md5ctx, salt, 2); 887 } else 888 MD5Update(&md5ctx, crypt0 + i - 16, 16); 889 MD5Final(b, &md5ctx); 890 891 for (j = 0; j < 16 && i + j < crypt0len; j++) 892 crypt0[i + j] ^= b[j]; 893 i -= 16; 894 } 895 } 896 897 static struct radius_query * 898 radiusd_find_query(struct radiusd *radiusd, u_int q_id) 899 { 900 struct radius_query *q; 901 902 TAILQ_FOREACH(q, &radiusd->query, next) { 903 if (q->id == q_id) 904 return (q); 905 } 906 return (NULL); 907 } 908 909 /*********************************************************************** 910 * radiusd module handling 911 ***********************************************************************/ 912 struct radiusd_module * 913 radiusd_module_load(struct radiusd *radiusd, const char *path, const char *name) 914 { 915 struct radiusd_module *module = NULL; 916 pid_t pid; 917 int ival, pairsock[] = { -1, -1 }; 918 const char *av[3]; 919 ssize_t n; 920 struct imsg imsg; 921 922 module = calloc(1, sizeof(struct radiusd_module)); 923 if (module == NULL) 924 fatal("Out of memory"); 925 module->radiusd = radiusd; 926 927 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pairsock) == -1) { 928 log_warn("Could not load module `%s'(%s): pipe()", name, path); 929 goto on_error; 930 } 931 932 pid = fork(); 933 if (pid == -1) { 934 log_warn("Could not load module `%s'(%s): fork()", name, path); 935 goto on_error; 936 } 937 if (pid == 0) { 938 setsid(); 939 close(pairsock[0]); 940 av[0] = path; 941 av[1] = name; 942 av[2] = NULL; 943 dup2(pairsock[1], STDIN_FILENO); 944 dup2(pairsock[1], STDOUT_FILENO); 945 close(pairsock[1]); 946 closefrom(STDERR_FILENO + 1); 947 execv(path, (char * const *)av); 948 log_warn("Failed to execute %s", path); 949 _exit(EXIT_FAILURE); 950 } 951 close(pairsock[1]); 952 953 module->fd = pairsock[0]; 954 if ((ival = fcntl(module->fd, F_GETFL)) == -1) { 955 log_warn("Could not load module `%s': fcntl(F_GETFL)", 956 name); 957 goto on_error; 958 } 959 if (fcntl(module->fd, F_SETFL, ival | O_NONBLOCK) == -1) { 960 log_warn("Could not load module `%s': fcntl(F_SETFL,O_NONBLOCK)", 961 name); 962 goto on_error; 963 } 964 strlcpy(module->name, name, sizeof(module->name)); 965 module->pid = pid; 966 imsg_init(&module->ibuf, module->fd); 967 968 if (imsg_sync_read(&module->ibuf, MODULE_IO_TIMEOUT) <= 0 || 969 (n = imsg_get(&module->ibuf, &imsg)) <= 0) { 970 log_warnx("Could not load module `%s': module didn't " 971 "respond", name); 972 goto on_error; 973 } 974 if (imsg.hdr.type != IMSG_RADIUSD_MODULE_LOAD) { 975 imsg_free(&imsg); 976 log_warnx("Could not load module `%s': unknown imsg type=%d", 977 name, imsg.hdr.type); 978 goto on_error; 979 } 980 981 module->capabilities = 982 ((struct radiusd_module_load_arg *)imsg.data)->cap; 983 984 log_debug("Loaded module `%s' successfully. pid=%d", module->name, 985 module->pid); 986 imsg_free(&imsg); 987 988 return (module); 989 990 on_error: 991 free(module); 992 if (pairsock[0] >= 0) 993 close(pairsock[0]); 994 if (pairsock[1] >= 0) 995 close(pairsock[1]); 996 997 return (NULL); 998 } 999 1000 void 1001 radiusd_module_start(struct radiusd_module *module) 1002 { 1003 int datalen; 1004 struct imsg imsg; 1005 struct timeval tv = { 0, 0 }; 1006 1007 RADIUSD_ASSERT(module->fd >= 0); 1008 imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_START, 0, 0, -1, 1009 NULL, 0); 1010 imsg_sync_flush(&module->ibuf, MODULE_IO_TIMEOUT); 1011 if (imsg_sync_read(&module->ibuf, MODULE_IO_TIMEOUT) <= 0 || 1012 imsg_get(&module->ibuf, &imsg) <= 0) { 1013 log_warnx("Module `%s' could not start: no response", 1014 module->name); 1015 goto on_fail; 1016 } 1017 1018 datalen = imsg.hdr.len - IMSG_HEADER_SIZE; 1019 if (imsg.hdr.type != IMSG_OK) { 1020 if (imsg.hdr.type == IMSG_NG) { 1021 if (datalen > 0) 1022 log_warnx("Module `%s' could not start: %s", 1023 module->name, (char *)imsg.data); 1024 else 1025 log_warnx("Module `%s' could not start", 1026 module->name); 1027 } else 1028 log_warnx("Module `%s' could not started: module " 1029 "returned unknown message type %d", module->name, 1030 imsg.hdr.type); 1031 goto on_fail; 1032 } 1033 1034 event_set(&module->ev, module->fd, EV_READ, radiusd_module_on_imsg_io, 1035 module); 1036 event_add(&module->ev, &tv); 1037 log_debug("Module `%s' started successfully", module->name); 1038 1039 return; 1040 on_fail: 1041 radiusd_module_close(module); 1042 return; 1043 } 1044 1045 void 1046 radiusd_module_stop(struct radiusd_module *module) 1047 { 1048 module->stopped = true; 1049 1050 if (module->secret != NULL) { 1051 freezero(module->secret, strlen(module->secret)); 1052 module->secret = NULL; 1053 } 1054 1055 if (module->fd >= 0) { 1056 imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_STOP, 0, 0, -1, 1057 NULL, 0); 1058 radiusd_module_reset_ev_handler(module); 1059 } 1060 } 1061 1062 static void 1063 radiusd_module_close(struct radiusd_module *module) 1064 { 1065 if (module->fd >= 0) { 1066 event_del(&module->ev); 1067 imsg_clear(&module->ibuf); 1068 close(module->fd); 1069 module->fd = -1; 1070 } 1071 } 1072 1073 void 1074 radiusd_module_unload(struct radiusd_module *module) 1075 { 1076 free(module->radpkt); 1077 radiusd_module_close(module); 1078 free(module); 1079 } 1080 1081 static void 1082 radiusd_module_on_imsg_io(int fd, short evmask, void *ctx) 1083 { 1084 struct radiusd_module *module = ctx; 1085 int ret; 1086 1087 if (evmask & EV_WRITE) 1088 module->writeready = true; 1089 1090 if (evmask & EV_READ || module->ibuf.r.wpos > IMSG_HEADER_SIZE) { 1091 if (radiusd_module_imsg_read(module, 1092 (evmask & EV_READ)? true : false) == -1) 1093 goto on_error; 1094 } 1095 1096 while (module->writeready && module->ibuf.w.queued) { 1097 ret = msgbuf_write(&module->ibuf.w); 1098 if (ret > 0) 1099 continue; 1100 module->writeready = false; 1101 if (ret == 0 && errno == EAGAIN) 1102 break; 1103 log_warn("Failed to write to module `%s': msgbuf_write()", 1104 module->name); 1105 goto on_error; 1106 } 1107 radiusd_module_reset_ev_handler(module); 1108 1109 return; 1110 on_error: 1111 radiusd_module_close(module); 1112 } 1113 1114 static void 1115 radiusd_module_reset_ev_handler(struct radiusd_module *module) 1116 { 1117 short evmask; 1118 struct timeval *tvp = NULL, tv = { 0, 0 }; 1119 1120 RADIUSD_ASSERT(module->fd >= 0); 1121 event_del(&module->ev); 1122 1123 evmask = EV_READ; 1124 if (module->ibuf.w.queued) { 1125 if (!module->writeready) 1126 evmask |= EV_WRITE; 1127 else 1128 tvp = &tv; /* fire immediately */ 1129 } else if (module->ibuf.r.wpos > IMSG_HEADER_SIZE) 1130 tvp = &tv; /* fire immediately */ 1131 1132 /* module stopped and no event handler is set */ 1133 if (evmask & EV_WRITE && tvp == NULL && module->stopped) { 1134 /* stop requested and no more to write */ 1135 radiusd_module_close(module); 1136 return; 1137 } 1138 1139 event_set(&module->ev, module->fd, evmask, radiusd_module_on_imsg_io, 1140 module); 1141 if (event_add(&module->ev, tvp) == -1) { 1142 log_warn("Could not set event handlers for module `%s': " 1143 "event_add()", module->name); 1144 radiusd_module_close(module); 1145 } 1146 } 1147 1148 static int 1149 radiusd_module_imsg_read(struct radiusd_module *module, bool doread) 1150 { 1151 int n; 1152 struct imsg imsg; 1153 1154 if (doread) { 1155 if ((n = imsg_read(&module->ibuf)) == -1 || n == 0) { 1156 if (n == -1 && errno == EAGAIN) 1157 return (0); 1158 if (n == -1) 1159 log_warn("Receiving a message from module `%s' " 1160 "failed: imsg_read", module->name); 1161 /* else closed */ 1162 radiusd_module_close(module); 1163 return (-1); 1164 } 1165 } 1166 for (;;) { 1167 if ((n = imsg_get(&module->ibuf, &imsg)) == -1) { 1168 log_warn("Receiving a message from module `%s' failed: " 1169 "imsg_get", module->name); 1170 return (-1); 1171 } 1172 if (n == 0) 1173 return (0); 1174 radiusd_module_imsg(module, &imsg); 1175 } 1176 1177 return (0); 1178 } 1179 1180 static void 1181 radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg) 1182 { 1183 int datalen; 1184 struct radius_query *q; 1185 u_int q_id; 1186 1187 datalen = imsg->hdr.len - IMSG_HEADER_SIZE; 1188 switch (imsg->hdr.type) { 1189 case IMSG_RADIUSD_MODULE_NOTIFY_SECRET: 1190 if (datalen > 0) { 1191 module->secret = strdup(imsg->data); 1192 if (module->secret == NULL) 1193 log_warn("Could not handle NOTIFY_SECRET " 1194 "from `%s'", module->name); 1195 } 1196 break; 1197 case IMSG_RADIUSD_MODULE_USERPASS_OK: 1198 case IMSG_RADIUSD_MODULE_USERPASS_FAIL: 1199 { 1200 char *msg = NULL; 1201 const char *msgtypestr; 1202 1203 msgtypestr = (imsg->hdr.type == IMSG_RADIUSD_MODULE_USERPASS_OK) 1204 ? "USERPASS_OK" : "USERPASS_NG"; 1205 1206 q_id = *(u_int *)imsg->data; 1207 if (datalen > (ssize_t)sizeof(u_int)) 1208 msg = (char *)(((u_int *)imsg->data) + 1); 1209 1210 q = radiusd_find_query(module->radiusd, q_id); 1211 if (q == NULL) { 1212 log_warnx("Received %s from `%s', but query id=%u " 1213 "unknown", msgtypestr, module->name, q_id); 1214 break; 1215 } 1216 1217 if ((q->res = radius_new_response_packet( 1218 (imsg->hdr.type == IMSG_RADIUSD_MODULE_USERPASS_OK) 1219 ? RADIUS_CODE_ACCESS_ACCEPT : RADIUS_CODE_ACCESS_REJECT, 1220 q->req)) == NULL) { 1221 log_warn("radius_new_response_packet() failed"); 1222 radiusd_access_request_aborted(q); 1223 } else { 1224 if (msg) 1225 radius_put_string_attr(q->res, 1226 RADIUS_TYPE_REPLY_MESSAGE, msg); 1227 radius_set_response_authenticator(q->res, 1228 q->client->secret); 1229 radiusd_access_request_answer(q); 1230 } 1231 break; 1232 } 1233 case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER: 1234 case IMSG_RADIUSD_MODULE_REQDECO_DONE: 1235 case IMSG_RADIUSD_MODULE_RESDECO_DONE: 1236 { 1237 static struct radiusd_module_radpkt_arg *ans; 1238 const char *typestr = "unknown"; 1239 1240 switch (imsg->hdr.type) { 1241 case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER: 1242 typestr = "ACCSREQ_ANSWER"; 1243 break; 1244 case IMSG_RADIUSD_MODULE_REQDECO_DONE: 1245 typestr = "REQDECO_DONE"; 1246 break; 1247 case IMSG_RADIUSD_MODULE_RESDECO_DONE: 1248 typestr = "RESDECO_DONE"; 1249 break; 1250 } 1251 1252 if (datalen < 1253 (ssize_t)sizeof(struct radiusd_module_radpkt_arg)) { 1254 log_warnx("Received %s message, but length is wrong", 1255 typestr); 1256 break; 1257 } 1258 q_id = ((struct radiusd_module_radpkt_arg *)imsg->data)->q_id; 1259 q = radiusd_find_query(module->radiusd, q_id); 1260 if (q == NULL) { 1261 log_warnx("Received %s from %s, but query id=%u " 1262 "unknown", typestr, module->name, q_id); 1263 break; 1264 } 1265 if ((ans = radiusd_module_recv_radpkt(module, imsg, 1266 imsg->hdr.type, typestr)) != NULL) { 1267 RADIUS_PACKET *radpkt = NULL; 1268 1269 if (module->radpktoff > 0 && 1270 (radpkt = radius_convert_packet( 1271 module->radpkt, module->radpktoff)) == NULL) { 1272 log_warn("q=%u radius_convert_packet() failed", 1273 q->id); 1274 radiusd_access_request_aborted(q); 1275 break; 1276 } 1277 module->radpktoff = 0; 1278 switch (imsg->hdr.type) { 1279 case IMSG_RADIUSD_MODULE_REQDECO_DONE: 1280 if (radpkt != NULL) { 1281 radius_delete_packet(q->req); 1282 q->req = radpkt; 1283 } 1284 radius_query_request(q); 1285 break; 1286 case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER: 1287 if (radpkt == NULL) { 1288 log_warn("q=%u wrong pkt from module", 1289 q->id); 1290 radiusd_access_request_aborted(q); 1291 } 1292 q->res = radpkt; 1293 radiusd_access_request_answer(q); 1294 break; 1295 case IMSG_RADIUSD_MODULE_RESDECO_DONE: 1296 if (radpkt != NULL) { 1297 radius_delete_packet(q->res); 1298 radius_set_request_packet(radpkt, 1299 q->req); 1300 q->res = radpkt; 1301 } 1302 radius_query_response(q); 1303 break; 1304 } 1305 } 1306 break; 1307 } 1308 case IMSG_RADIUSD_MODULE_ACCSREQ_ABORTED: 1309 { 1310 q_id = *((u_int *)imsg->data); 1311 q = radiusd_find_query(module->radiusd, q_id); 1312 if (q == NULL) { 1313 log_warnx("Received ACCSREQ_ABORT from %s, but query " 1314 "id=%u unknown", module->name, q_id); 1315 break; 1316 } 1317 radiusd_access_request_aborted(q); 1318 break; 1319 } 1320 default: 1321 RADIUSD_DBG(("Unhandled imsg type=%d from %s", imsg->hdr.type, 1322 module->name)); 1323 } 1324 } 1325 1326 static struct radiusd_module_radpkt_arg * 1327 radiusd_module_recv_radpkt(struct radiusd_module *module, struct imsg *imsg, 1328 uint32_t imsg_type, const char *type_str) 1329 { 1330 struct radiusd_module_radpkt_arg *ans; 1331 int datalen, chunklen; 1332 1333 datalen = imsg->hdr.len - IMSG_HEADER_SIZE; 1334 ans = (struct radiusd_module_radpkt_arg *)imsg->data; 1335 if (module->radpktsiz < ans->pktlen) { 1336 u_char *nradpkt; 1337 if ((nradpkt = realloc(module->radpkt, ans->pktlen)) == NULL) { 1338 log_warn("Could not handle received %s message from " 1339 "`%s'", type_str, module->name); 1340 goto on_fail; 1341 } 1342 module->radpkt = nradpkt; 1343 module->radpktsiz = ans->pktlen; 1344 } 1345 chunklen = datalen - sizeof(struct radiusd_module_radpkt_arg); 1346 if (chunklen > module->radpktsiz - module->radpktoff) { 1347 log_warnx("Could not handle received %s message from `%s': " 1348 "received length is too big", type_str, module->name); 1349 goto on_fail; 1350 } 1351 if (chunklen > 0) { 1352 memcpy(module->radpkt + module->radpktoff, 1353 (caddr_t)(ans + 1), chunklen); 1354 module->radpktoff += chunklen; 1355 } 1356 if (!ans->final) 1357 return (NULL); /* again */ 1358 if (module->radpktoff != ans->pktlen) { 1359 log_warnx("Could not handle received %s message from `%s': " 1360 "length is mismatch", type_str, module->name); 1361 goto on_fail; 1362 } 1363 1364 return (ans); 1365 on_fail: 1366 module->radpktoff = 0; 1367 return (NULL); 1368 } 1369 1370 int 1371 radiusd_module_set(struct radiusd_module *module, const char *name, 1372 int argc, char * const * argv) 1373 { 1374 struct radiusd_module_set_arg arg; 1375 struct radiusd_module_object *val; 1376 int i, niov = 0; 1377 u_char *buf = NULL, *buf0; 1378 ssize_t n; 1379 size_t bufsiz = 0, bufoff = 0, bufsiz0; 1380 size_t vallen, valsiz; 1381 struct iovec iov[2]; 1382 struct imsg imsg; 1383 1384 memset(&arg, 0, sizeof(arg)); 1385 arg.nparamval = argc; 1386 strlcpy(arg.paramname, name, sizeof(arg.paramname)); 1387 1388 iov[niov].iov_base = &arg; 1389 iov[niov].iov_len = sizeof(struct radiusd_module_set_arg); 1390 niov++; 1391 1392 for (i = 0; i < argc; i++) { 1393 vallen = strlen(argv[i]) + 1; 1394 valsiz = sizeof(struct radiusd_module_object) + vallen; 1395 if (bufsiz < bufoff + valsiz) { 1396 bufsiz0 = bufoff + valsiz + 128; 1397 if ((buf0 = realloc(buf, bufsiz0)) == NULL) { 1398 log_warn("Failed to set config parameter to " 1399 "module `%s': realloc", module->name); 1400 goto on_error; 1401 } 1402 buf = buf0; 1403 bufsiz = bufsiz0; 1404 memset(buf + bufoff, 0, bufsiz - bufoff); 1405 } 1406 val = (struct radiusd_module_object *)(buf + bufoff); 1407 val->size = valsiz; 1408 memcpy(val + 1, argv[i], vallen); 1409 1410 bufoff += valsiz; 1411 } 1412 iov[niov].iov_base = buf; 1413 iov[niov].iov_len = bufoff; 1414 niov++; 1415 1416 if (imsg_composev(&module->ibuf, IMSG_RADIUSD_MODULE_SET_CONFIG, 0, 0, 1417 -1, iov, niov) == -1) { 1418 log_warn("Failed to set config parameter to module `%s': " 1419 "imsg_composev", module->name); 1420 goto on_error; 1421 } 1422 if (imsg_sync_flush(&module->ibuf, MODULE_IO_TIMEOUT) == -1) { 1423 log_warn("Failed to set config parameter to module `%s': " 1424 "imsg_flush_timeout", module->name); 1425 goto on_error; 1426 } 1427 for (;;) { 1428 if (imsg_sync_read(&module->ibuf, MODULE_IO_TIMEOUT) <= 0) { 1429 log_warn("Failed to get reply from module `%s': " 1430 "imsg_sync_read", module->name); 1431 goto on_error; 1432 } 1433 if ((n = imsg_get(&module->ibuf, &imsg)) > 0) 1434 break; 1435 if (n < 0) { 1436 log_warn("Failed to get reply from module `%s': " 1437 "imsg_get", module->name); 1438 goto on_error; 1439 } 1440 } 1441 if (imsg.hdr.type == IMSG_NG) { 1442 log_warnx("Could not set `%s' for module `%s': %s", name, 1443 module->name, (char *)imsg.data); 1444 goto on_error; 1445 } else if (imsg.hdr.type != IMSG_OK) { 1446 imsg_free(&imsg); 1447 log_warnx("Failed to get reply from module `%s': " 1448 "unknown imsg type=%d", module->name, imsg.hdr.type); 1449 goto on_error; 1450 } 1451 imsg_free(&imsg); 1452 1453 free(buf); 1454 return (0); 1455 1456 on_error: 1457 free(buf); 1458 return (-1); 1459 } 1460 1461 static void 1462 radiusd_module_userpass(struct radiusd_module *module, struct radius_query *q) 1463 { 1464 struct radiusd_module_userpass_arg userpass; 1465 1466 memset(&userpass, 0, sizeof(userpass)); 1467 userpass.q_id = q->id; 1468 1469 if (radius_get_user_password_attr(q->req, userpass.pass, 1470 sizeof(userpass.pass), q->client->secret) == 0) 1471 userpass.has_pass = true; 1472 else 1473 userpass.has_pass = false; 1474 if (radius_get_string_attr(q->req, RADIUS_TYPE_USER_NAME, 1475 userpass.user, sizeof(userpass.user)) != 0) { 1476 log_warnx("q=%u no User-Name attribute", q->id); 1477 goto on_error; 1478 } 1479 imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_USERPASS, 0, 0, -1, 1480 &userpass, sizeof(userpass)); 1481 radiusd_module_reset_ev_handler(module); 1482 return; 1483 on_error: 1484 radiusd_access_request_aborted(q); 1485 } 1486 1487 static void 1488 radiusd_module_access_request(struct radiusd_module *module, 1489 struct radius_query *q) 1490 { 1491 RADIUS_PACKET *radpkt; 1492 char pass[256]; 1493 1494 if ((radpkt = radius_convert_packet(radius_get_data(q->req), 1495 radius_get_length(q->req))) == NULL) { 1496 log_warn("q=%u Could not send ACCSREQ to `%s'", q->id, 1497 module->name); 1498 radiusd_access_request_aborted(q); 1499 return; 1500 } 1501 if (q->client->secret[0] != '\0' && module->secret != NULL && 1502 radius_get_user_password_attr(radpkt, pass, sizeof(pass), 1503 q->client->secret) == 0) { 1504 radius_del_attr_all(radpkt, RADIUS_TYPE_USER_PASSWORD); 1505 (void)radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD, 1506 pass, strlen(pass)); 1507 } 1508 if (imsg_compose_radius_packet(&module->ibuf, 1509 IMSG_RADIUSD_MODULE_ACCSREQ, q->id, radpkt) == -1) { 1510 log_warn("q=%u Could not send ACCSREQ to `%s'", q->id, 1511 module->name); 1512 radiusd_access_request_aborted(q); 1513 } 1514 radiusd_module_reset_ev_handler(module); 1515 radius_delete_packet(radpkt); 1516 } 1517 1518 static void 1519 radiusd_module_request_decoration(struct radiusd_module *module, 1520 struct radius_query *q) 1521 { 1522 if (module->fd < 0) { 1523 log_warnx("q=%u Could not send REQDECO to `%s': module is " 1524 "not running?", q->id, module->name); 1525 radiusd_access_request_aborted(q); 1526 return; 1527 } 1528 if (imsg_compose_radius_packet(&module->ibuf, 1529 IMSG_RADIUSD_MODULE_REQDECO, q->id, q->req) == -1) { 1530 log_warn("q=%u Could not send REQDECO to `%s'", q->id, 1531 module->name); 1532 radiusd_access_request_aborted(q); 1533 return; 1534 } 1535 radiusd_module_reset_ev_handler(module); 1536 } 1537 1538 static void 1539 radiusd_module_response_decoration(struct radiusd_module *module, 1540 struct radius_query *q) 1541 { 1542 if (module->fd < 0) { 1543 log_warnx("q=%u Could not send RESDECO to `%s': module is " 1544 "not running?", q->id, module->name); 1545 radiusd_access_request_aborted(q); 1546 return; 1547 } 1548 if (imsg_compose_radius_packet(&module->ibuf, 1549 IMSG_RADIUSD_MODULE_RESDECO0_REQ, q->id, q->req) == -1) { 1550 log_warn("q=%u Could not send RESDECO0_REQ to `%s'", q->id, 1551 module->name); 1552 radiusd_access_request_aborted(q); 1553 return; 1554 } 1555 if (imsg_compose_radius_packet(&module->ibuf, 1556 IMSG_RADIUSD_MODULE_RESDECO, q->id, q->res) == -1) { 1557 log_warn("q=%u Could not send RESDECO to `%s'", q->id, 1558 module->name); 1559 radiusd_access_request_aborted(q); 1560 return; 1561 } 1562 radiusd_module_reset_ev_handler(module); 1563 } 1564 1565 static int 1566 imsg_compose_radius_packet(struct imsgbuf *ibuf, uint32_t type, u_int q_id, 1567 RADIUS_PACKET *radpkt) 1568 { 1569 struct radiusd_module_radpkt_arg arg; 1570 int off = 0, len, siz; 1571 struct iovec iov[2]; 1572 const u_char *pkt; 1573 1574 pkt = radius_get_data(radpkt); 1575 len = radius_get_length(radpkt); 1576 memset(&arg, 0, sizeof(arg)); 1577 arg.q_id = q_id; 1578 arg.pktlen = len; 1579 while (off < len) { 1580 siz = MAX_IMSGSIZE - sizeof(arg); 1581 if (len - off > siz) 1582 arg.final = false; 1583 else { 1584 arg.final = true; 1585 siz = len - off; 1586 } 1587 iov[0].iov_base = &arg; 1588 iov[0].iov_len = sizeof(arg); 1589 iov[1].iov_base = (caddr_t)pkt + off; 1590 iov[1].iov_len = siz; 1591 if (imsg_composev(ibuf, type, 0, 0, -1, iov, 2) == -1) 1592 return (-1); 1593 off += siz; 1594 } 1595 return (0); 1596 } 1597