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