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