1 /* $OpenBSD: radiusd_radius.c,v 1.17 2019/06/28 13:32:49 deraadt 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/queue.h> 21 #include <sys/socket.h> 22 #include <netinet/in.h> 23 24 #include <err.h> 25 #include <errno.h> 26 #include <event.h> 27 #include <fcntl.h> 28 #include <stdbool.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <syslog.h> 33 #include <unistd.h> 34 35 #include <radius.h> 36 37 #include "radiusd.h" 38 #include "radiusd_module.h" 39 #include "util.h" 40 #include "log.h" 41 42 struct radius_server { 43 struct module_radius *module; 44 int sock; 45 union { 46 struct sockaddr_in6 sin6; 47 struct sockaddr_in sin4; 48 } addr; 49 union { 50 struct sockaddr_in6 sin6; 51 struct sockaddr_in sin4; 52 } local; 53 struct event ev; 54 u_char req_id_seq; 55 }; 56 57 struct module_radius { 58 struct module_base *base; 59 struct radius_server server[4]; 60 char secret[RADIUSD_SECRET_MAX]; 61 u_int nserver; 62 u_int curr_server; 63 u_int req_timeout; 64 u_int max_tries; 65 u_int max_failovers; 66 u_int nfailover; 67 TAILQ_HEAD(,module_radius_req) req; 68 }; 69 70 struct module_radius_req { 71 struct module_radius *module; 72 struct radius_server *server; 73 u_int q_id; 74 RADIUS_PACKET *q_pkt; 75 u_int ntry; 76 u_int nfailover; 77 u_char req_id; 78 struct event ev; 79 TAILQ_ENTRY(module_radius_req) next; 80 }; 81 82 static void module_radius_init(struct module_radius *); 83 static void module_radius_config_set(void *, const char *, int, 84 char * const *); 85 static void module_radius_start(void *); 86 static void module_radius_stop(void *); 87 static void module_radius_access_request(void *, u_int, const u_char *, 88 size_t); 89 static int radius_server_start(struct radius_server *); 90 static void radius_server_stop(struct radius_server *); 91 static void radius_server_on_event(int, short, void *); 92 static void radius_server_on_fail(struct radius_server *, const char *); 93 static void module_radius_req_send(struct module_radius_req *); 94 static int module_radius_req_reset_event(struct module_radius_req *); 95 static void module_radius_req_on_timeout(int, short, void *); 96 static void module_radius_req_on_success(struct module_radius_req *, 97 const u_char *, size_t); 98 static void module_radius_req_on_failure(struct module_radius_req *); 99 100 static void module_radius_req_free(struct module_radius_req *); 101 static void module_radius_req_select_server(struct module_radius_req *); 102 103 static void module_radius_req_reset_msgauth(struct module_radius_req *); 104 static void module_radius_log(struct module_radius *, int, const char *, ...); 105 106 static struct module_handlers module_radius_handlers = { 107 .config_set = module_radius_config_set, 108 .start = module_radius_start, 109 .stop = module_radius_stop, 110 .access_request = module_radius_access_request 111 }; 112 113 #ifndef nitems 114 #define nitems(_x) (sizeof((_x)) / sizeof((_x)[0])) 115 #endif 116 117 int 118 main(int argc, char *argv[]) 119 { 120 static struct module_radius module_radius; 121 122 module_radius_init(&module_radius); 123 openlog(NULL, LOG_PID, LOG_DAEMON); 124 125 if ((module_radius.base = module_create( 126 STDIN_FILENO, &module_radius, &module_radius_handlers)) == NULL) 127 err(1, "Could not create a module instance"); 128 module_drop_privilege(module_radius.base); 129 setproctitle("[main]"); 130 131 module_load(module_radius.base); 132 log_init(0); 133 event_init(); 134 135 if (pledge("stdio inet", NULL) == -1) 136 err(EXIT_FAILURE, "pledge"); 137 138 module_start(module_radius.base); 139 event_loop(0); 140 141 exit(EXIT_SUCCESS); 142 } 143 144 static void 145 module_radius_init(struct module_radius *module) 146 { 147 memset(module, 0, sizeof(struct module_radius)); 148 TAILQ_INIT(&module->req); 149 } 150 151 static void 152 module_radius_config_set(void *ctx, const char *paramname, int paramvalc, 153 char * const * paramvalv) 154 { 155 const char *errmsg = NULL; 156 struct addrinfo *res; 157 struct module_radius *module = ctx; 158 159 if (strcmp(paramname, "server") == 0) { 160 SYNTAX_ASSERT(paramvalc == 1, 161 "`server' must have just one argument"); 162 SYNTAX_ASSERT(module->nserver < (int)nitems(module->server), 163 "number of server reached limit"); 164 165 if (addrport_parse(paramvalv[0], IPPROTO_UDP, &res) != 0) 166 SYNTAX_ASSERT(0, "could not parse address and port"); 167 memcpy(&module->server[module->nserver].addr, res->ai_addr, 168 res->ai_addrlen); 169 170 if (ntohs(module->server[module->nserver].addr.sin4.sin_port) 171 == 0) 172 module->server[module->nserver].addr.sin4.sin_port 173 = htons(RADIUS_DEFAULT_PORT); 174 175 module->server[module->nserver].sock = -1; 176 module->nserver++; 177 freeaddrinfo(res); 178 } else if (strcmp(paramname, "request-timeout") == 0) { 179 SYNTAX_ASSERT(paramvalc == 1, 180 "`request-timeout' must have just one argument"); 181 module->req_timeout = (int)strtonum(paramvalv[0], 0, 182 UINT16_MAX, &errmsg); 183 if (module->req_timeout == 0 && errmsg != NULL) { 184 module_send_message(module->base, IMSG_NG, 185 "`request-timeout must be 0-%d", UINT16_MAX); 186 return; 187 } 188 } else if (strcmp(paramname, "max-tries") == 0) { 189 SYNTAX_ASSERT(paramvalc == 1, 190 "`max-tries' must have just one argument"); 191 module->max_tries = (int)strtonum(paramvalv[0], 0, 192 UINT16_MAX, &errmsg); 193 if (module->max_tries == 0 && errmsg != NULL) { 194 module_send_message(module->base, IMSG_NG, 195 "`max-tries must be 0-%d", UINT16_MAX); 196 return; 197 } 198 199 } else if (strcmp(paramname, "max-failovers") == 0) { 200 SYNTAX_ASSERT(paramvalc == 1, 201 "`max-failovers' must have just one argument"); 202 module->max_failovers = (int)strtonum(paramvalv[0], 0, 203 UINT16_MAX, &errmsg); 204 if (module->max_failovers == 0 && errmsg != NULL) { 205 module_send_message(module->base, IMSG_NG, 206 "`max-failovers' must be 0-%d", UINT16_MAX); 207 return; 208 } 209 } else if (strcmp(paramname, "secret") == 0) { 210 SYNTAX_ASSERT(paramvalc == 1, 211 "`secret' must have just one argument"); 212 if (strlcpy(module->secret, paramvalv[0], 213 sizeof(module->secret)) >= sizeof(module->secret)) { 214 module_send_message(module->base, IMSG_NG, 215 "`secret' length must be 0-%lu", 216 (u_long) sizeof(module->secret) - 1); 217 return; 218 } 219 } else if (strcmp(paramname, "_debug") == 0) 220 log_init(1); 221 else if (strncmp(paramname, "_", 1) == 0) 222 /* ignore all internal messages */ 223 module_send_message(module->base, IMSG_OK, NULL); 224 else { 225 module_send_message(module->base, IMSG_NG, 226 "Unknown config parameter name `%s'", paramname); 227 return; 228 } 229 module_send_message(module->base, IMSG_OK, NULL); 230 231 return; 232 syntax_error: 233 module_send_message(module->base, IMSG_NG, "%s", errmsg); 234 } 235 236 static void 237 module_radius_start(void *ctx) 238 { 239 u_int i; 240 struct module_radius *module = ctx; 241 242 if (module->nserver <= 0) { 243 module_send_message(module->base, IMSG_NG, 244 "needs one `server' at least"); 245 return; 246 } 247 248 if (module->secret[0] == '\0') { 249 module_send_message(module->base, IMSG_NG, 250 "`secret' configuration is required"); 251 return; 252 } 253 254 for (i = 0; i < module->nserver; i++) { 255 module->server[i].module = module; 256 if (radius_server_start(&module->server[i]) != 0) { 257 module_send_message(module->base, IMSG_NG, 258 "module `radius' failed to start one of " 259 "the servers"); 260 return; 261 } 262 } 263 module_send_message(module->base, IMSG_OK, NULL); 264 265 module_notify_secret(module->base, module->secret); 266 } 267 268 static void 269 module_radius_stop(void *ctx) 270 { 271 u_int i; 272 struct module_radius_req *req, *treq; 273 struct module_radius *module = ctx; 274 275 TAILQ_FOREACH_SAFE(req, &module->req, next, treq) 276 module_radius_req_on_failure(req); 277 278 for (i = 0; i < module->nserver; i++) 279 radius_server_stop(&module->server[i]); 280 } 281 282 static void 283 module_radius_access_request(void *ctx, u_int q_id, const u_char *pkt, 284 size_t pktlen) 285 { 286 struct module_radius *module = ctx; 287 struct module_radius_req *req; 288 u_char attrbuf[256]; 289 ssize_t attrlen; 290 291 req = calloc(1, sizeof(struct module_radius_req)); 292 if (req == NULL) { 293 module_radius_log(module, LOG_WARNING, 294 "%s: Out of memory: %m", __func__); 295 goto on_fail; 296 } 297 298 req->ntry = 0; 299 req->module = module; 300 req->q_id = q_id; 301 if ((req->q_pkt = radius_convert_packet(pkt, pktlen)) == NULL) { 302 module_radius_log(module, LOG_WARNING, 303 "%s: radius_convert_packet() failed: %m", __func__); 304 goto on_fail; 305 } 306 evtimer_set(&req->ev, module_radius_req_on_timeout, req); 307 TAILQ_INSERT_TAIL(&req->module->req, req, next); 308 309 /* 310 * radiusd decrypt User-Password attribute. crypt it again with our 311 * secret. 312 */ 313 attrlen = sizeof(attrbuf); 314 if (radius_get_raw_attr(req->q_pkt, RADIUS_TYPE_USER_PASSWORD, 315 attrbuf, &attrlen) == 0) { 316 attrbuf[attrlen] = '\0'; 317 radius_del_attr_all(req->q_pkt, RADIUS_TYPE_USER_PASSWORD); 318 radius_put_user_password_attr(req->q_pkt, attrbuf, 319 module->secret); 320 } 321 322 /* select current server */ 323 module_radius_req_select_server(req); 324 325 module_radius_req_send(req); 326 327 return; 328 329 on_fail: 330 free(req); 331 module_accsreq_aborted(module->base, q_id); 332 } 333 334 /* 335 * radius_server 336 */ 337 static int 338 radius_server_start(struct radius_server *server) 339 { 340 socklen_t locallen; 341 char buf0[NI_MAXHOST + NI_MAXSERV + 32]; 342 char buf1[NI_MAXHOST + NI_MAXSERV + 32]; 343 344 if ((server->sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) 345 == -1) { 346 module_radius_log(server->module, LOG_WARNING, 347 "%s: socket() failed", __func__); 348 goto on_error; 349 } 350 if (connect(server->sock, (struct sockaddr *)&server->addr, 351 server->addr.sin4.sin_len) != 0) { 352 module_radius_log(server->module, LOG_WARNING, 353 "%s: connect to %s failed", __func__, 354 addrport_tostring((struct sockaddr *)&server->addr, 355 server->addr.sin4.sin_len, buf1, sizeof(buf1))); 356 goto on_error; 357 } 358 locallen = sizeof(server->local); 359 if (getsockname(server->sock, (struct sockaddr *)&server->local, 360 &locallen) != 0) { 361 module_radius_log(server->module, LOG_WARNING, 362 "%s: getsockanme() failed", __func__); 363 goto on_error; 364 } 365 module_radius_log(server->module, LOG_INFO, 366 "Use %s to send requests for %s", 367 addrport_tostring((struct sockaddr *)&server->local, 368 locallen, buf0, sizeof(buf0)), 369 addrport_tostring((struct sockaddr *)&server->addr, 370 server->addr.sin4.sin_len, buf1, sizeof(buf1))); 371 372 event_set(&server->ev, server->sock, EV_READ | EV_PERSIST, 373 radius_server_on_event, server); 374 if (event_add(&server->ev, NULL)) { 375 module_radius_log(server->module, LOG_WARNING, 376 "%s: event_add() failed", __func__); 377 goto on_error; 378 } 379 380 return (0); 381 on_error: 382 if (server->sock >= 0) 383 close(server->sock); 384 server->sock = -1; 385 return (-1); 386 } 387 388 static void 389 radius_server_stop(struct radius_server *server) 390 { 391 event_del(&server->ev); 392 if (server->sock >= 0) 393 close(server->sock); 394 server->sock = -1; 395 } 396 397 static void 398 radius_server_on_event(int fd, short evmask, void *ctx) 399 { 400 int sz, res_id; 401 u_char pkt[65535]; 402 char buf[NI_MAXHOST + NI_MAXSERV + 32]; 403 struct radius_server *server = ctx; 404 RADIUS_PACKET *radpkt = NULL; 405 struct module_radius_req *req; 406 struct sockaddr *peer; 407 408 peer = (struct sockaddr *)&server->addr; 409 if ((sz = recv(server->sock, pkt, sizeof(pkt), 0)) == -1) { 410 if (errno == EAGAIN) 411 return; 412 module_radius_log(server->module, LOG_WARNING, 413 "server=%s recv() failed: %m", 414 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf))); 415 return; 416 } 417 if ((radpkt = radius_convert_packet(pkt, sz)) == NULL) { 418 module_radius_log(server->module, LOG_WARNING, 419 "server=%s could not convert the received message to a " 420 "RADIUS packet object: %m", 421 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf))); 422 return; 423 } 424 res_id = radius_get_id(radpkt); 425 TAILQ_FOREACH(req, &server->module->req, next) { 426 if (req->server == server && req->req_id == res_id) 427 break; 428 } 429 if (req == NULL) { 430 module_radius_log(server->module, LOG_WARNING, 431 "server=%s Received radius message has unknown id=%d", 432 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)), 433 res_id); 434 goto out; 435 } 436 radius_set_request_packet(radpkt, req->q_pkt); 437 438 if (radius_check_response_authenticator(radpkt, 439 server->module->secret) != 0) { 440 module_radius_log(server->module, LOG_WARNING, 441 "server=%s Received radius message(id=%d) has bad " 442 "authenticator", 443 addrport_tostring(peer, peer->sa_len, buf, 444 sizeof(buf)), res_id); 445 goto out; 446 } 447 if (radius_has_attr(radpkt, 448 RADIUS_TYPE_MESSAGE_AUTHENTICATOR) && 449 radius_check_message_authenticator(radpkt, 450 server->module->secret) != 0) { 451 module_radius_log(server->module, LOG_WARNING, 452 "server=%s Received radius message(id=%d) has bad " 453 "message authenticator", 454 addrport_tostring(peer, peer->sa_len, buf, 455 sizeof(buf)), res_id); 456 goto out; 457 } 458 459 module_radius_log(server->module, LOG_INFO, 460 "q=%u received a response from server %s", req->q_id, 461 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf))); 462 463 module_radius_req_on_success(req, radius_get_data(radpkt), 464 radius_get_length(radpkt)); 465 out: 466 if (radpkt != NULL) 467 radius_delete_packet(radpkt); 468 } 469 470 static void 471 radius_server_on_fail(struct radius_server *server, const char *failmsg) 472 { 473 char buf0[NI_MAXHOST + NI_MAXSERV + 32]; 474 char buf1[NI_MAXHOST + NI_MAXSERV + 32]; 475 struct sockaddr *caddr, *naddr; 476 477 caddr = (struct sockaddr *)&server->addr; 478 if (server->module->nserver <= 1) { 479 module_radius_log(server->module, LOG_WARNING, 480 "Server %s failed: %s", 481 addrport_tostring(caddr, caddr->sa_len, buf0, sizeof(buf0)), 482 failmsg); 483 return; 484 } 485 server->module->curr_server++; 486 server->module->curr_server %= server->module->nserver; 487 naddr = (struct sockaddr *) 488 &server->module->server[server->module->curr_server].addr; 489 490 module_radius_log(server->module, LOG_WARNING, 491 "Server %s failed: %s Fail over to %s", 492 addrport_tostring(caddr, caddr->sa_len, buf0, sizeof(buf0)), 493 failmsg, 494 addrport_tostring(naddr, naddr->sa_len, buf1, sizeof(buf1))); 495 } 496 497 /* module_radius_req */ 498 499 static void 500 module_radius_req_send(struct module_radius_req *req) 501 { 502 int sz; 503 struct sockaddr *peer; 504 char msg[BUFSIZ]; 505 506 peer = (struct sockaddr *)&req->server->addr; 507 if ((sz = send(req->server->sock, radius_get_data(req->q_pkt), 508 radius_get_length(req->q_pkt), 0)) < 0) { 509 module_radius_log(req->module, LOG_WARNING, 510 "Sending RADIUS query q=%u to %s failed: %m", 511 req->q_id, 512 addrport_tostring(peer, peer->sa_len, msg, sizeof(msg))); 513 /* retry anyway */ 514 } 515 module_radius_log(req->module, LOG_INFO, 516 "Send RADIUS query q=%u id=%d to %s successfully", 517 req->q_id, req->req_id, 518 addrport_tostring(peer, peer->sa_len, msg, sizeof(msg))); 519 if (module_radius_req_reset_event(req) != -1) 520 req->ntry++; 521 } 522 523 static int 524 module_radius_req_reset_event(struct module_radius_req *req) 525 { 526 struct timeval tv; 527 static int timeouts[] = { 2, 4, 8 }; 528 529 tv.tv_usec = 0; 530 if (req->module->req_timeout != 0) 531 tv.tv_sec = req->module->req_timeout; 532 else { 533 if (req->ntry < nitems(timeouts)) 534 tv.tv_sec = timeouts[req->ntry]; 535 else 536 tv.tv_sec = timeouts[nitems(timeouts) - 1]; 537 } 538 if (evtimer_add(&req->ev, &tv) != 0) { 539 module_radius_log(req->module, LOG_WARNING, 540 "Cannot proccess the request for q=%u: " 541 "evtimer_add() failed: %m", req->q_id); 542 module_radius_req_on_failure(req); 543 return (-1); 544 } 545 return (0); 546 } 547 548 static void 549 module_radius_req_on_timeout(int fd, short evmask, void *ctx) 550 { 551 struct module_radius_req *req = ctx; 552 char msg[BUFSIZ]; 553 554 555 if (req->module->max_tries <= req->ntry) { 556 snprintf(msg, sizeof(msg), "q=%u didn't response RADIUS query " 557 "%d time%s", req->q_id, req->ntry, 558 (req->ntry > 0)? "s" : ""); 559 radius_server_on_fail(req->server, msg); 560 if (++req->nfailover >= req->module->max_failovers) { 561 module_radius_log(req->module, 562 LOG_WARNING, "RADIUS query q=%u time out", 563 req->q_id); 564 module_radius_req_on_failure(req); 565 return; 566 } 567 /* select the next server */ 568 module_radius_req_select_server(req); 569 } 570 module_radius_req_send(req); 571 } 572 573 static void 574 module_radius_req_on_success(struct module_radius_req *req, 575 const u_char *pkt, size_t pktlen) 576 { 577 module_accsreq_answer(req->module->base, req->q_id, pkt, pktlen); 578 module_radius_req_free(req); 579 } 580 581 static void 582 module_radius_req_on_failure(struct module_radius_req *req) 583 { 584 module_accsreq_aborted(req->module->base, req->q_id); 585 module_radius_req_free(req); 586 } 587 588 589 static void 590 module_radius_req_free(struct module_radius_req *req) 591 { 592 evtimer_del(&req->ev); 593 TAILQ_REMOVE(&req->module->req, req, next); 594 if (req->q_pkt != NULL) 595 radius_delete_packet(req->q_pkt); 596 free(req); 597 } 598 599 static void 600 module_radius_req_select_server(struct module_radius_req *req) 601 { 602 req->server = &req->module->server[req->module->curr_server]; 603 req->ntry = 0; 604 req->req_id = req->server->req_id_seq++; 605 radius_set_id(req->q_pkt, req->req_id); 606 module_radius_req_reset_msgauth(req); 607 } 608 609 static void 610 module_radius_req_reset_msgauth(struct module_radius_req *req) 611 { 612 if (radius_has_attr(req->q_pkt, RADIUS_TYPE_MESSAGE_AUTHENTICATOR)) 613 radius_del_attr_all(req->q_pkt, 614 RADIUS_TYPE_MESSAGE_AUTHENTICATOR); 615 radius_put_message_authenticator(req->q_pkt, 616 req->module->secret); 617 } 618 619 static void 620 module_radius_log(struct module_radius *module, int pri, const char *fmt, ...) 621 { 622 char fmt0[BUFSIZ]; 623 va_list va; 624 625 snprintf(fmt0, sizeof(fmt0), "radius: %s", fmt); 626 va_start(va, fmt); 627 vlog(pri, fmt0, va); 628 va_end(va); 629 } 630