1 /* $OpenBSD: radiusd_radius.c,v 1.13 2017/05/30 16:30:22 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/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 { 220 module_send_message(module->base, IMSG_NG, 221 "Unknown config parameter name `%s'", paramname); 222 return; 223 } 224 module_send_message(module->base, IMSG_OK, NULL); 225 226 return; 227 syntax_error: 228 module_send_message(module->base, IMSG_NG, "%s", errmsg); 229 } 230 231 static void 232 module_radius_start(void *ctx) 233 { 234 u_int i; 235 struct module_radius *module = ctx; 236 237 if (module->nserver <= 0) { 238 module_send_message(module->base, IMSG_NG, 239 "module `radius' needs one `server' at least"); 240 return; 241 } 242 243 for (i = 0; i < module->nserver; i++) { 244 module->server[i].module = module; 245 if (radius_server_start(&module->server[i]) != 0) { 246 module_send_message(module->base, IMSG_NG, 247 "module `radius' failed to start one of " 248 "the servers"); 249 return; 250 } 251 } 252 module_send_message(module->base, IMSG_OK, NULL); 253 254 if (module->secret[0] != '\0') 255 module_notify_secret(module->base, module->secret); 256 } 257 258 static void 259 module_radius_stop(void *ctx) 260 { 261 u_int i; 262 struct module_radius_req *req, *treq; 263 struct module_radius *module = ctx; 264 265 TAILQ_FOREACH_SAFE(req, &module->req, next, treq) 266 module_radius_req_on_failure(req); 267 268 for (i = 0; i < module->nserver; i++) 269 radius_server_stop(&module->server[i]); 270 } 271 272 static void 273 module_radius_access_request(void *ctx, u_int q_id, const u_char *pkt, 274 size_t pktlen) 275 { 276 struct module_radius *module = ctx; 277 struct module_radius_req *req; 278 u_char attrbuf[256]; 279 ssize_t attrlen; 280 281 req = calloc(1, sizeof(struct module_radius_req)); 282 if (req == NULL) { 283 module_radius_log(module, LOG_WARNING, 284 "%s: Out of memory: %m", __func__); 285 goto on_fail; 286 } 287 288 req->ntry = 0; 289 req->module = module; 290 req->q_id = q_id; 291 if ((req->q_pkt = radius_convert_packet(pkt, pktlen)) == NULL) { 292 module_radius_log(module, LOG_WARNING, 293 "%s: radius_convert_packet() failed: %m", __func__); 294 goto on_fail; 295 } 296 evtimer_set(&req->ev, module_radius_req_on_timeout, req); 297 TAILQ_INSERT_TAIL(&req->module->req, req, next); 298 299 /* 300 * radiusd decrypt User-Password attribute. crypt it again with our 301 * secret. 302 */ 303 attrlen = sizeof(attrbuf); 304 if (module->secret[0] != '\0' && 305 radius_get_raw_attr(req->q_pkt, RADIUS_TYPE_USER_PASSWORD, 306 attrbuf, &attrlen) == 0) { 307 attrbuf[attrlen] = '\0'; 308 radius_del_attr_all(req->q_pkt, RADIUS_TYPE_USER_PASSWORD); 309 radius_put_user_password_attr(req->q_pkt, attrbuf, 310 module->secret); 311 } 312 313 /* select current server */ 314 module_radius_req_select_server(req); 315 316 module_radius_req_send(req); 317 318 return; 319 320 on_fail: 321 free(req); 322 module_accsreq_aborted(module->base, q_id); 323 } 324 325 /* 326 * radius_server 327 */ 328 static int 329 radius_server_start(struct radius_server *server) 330 { 331 socklen_t locallen; 332 char buf0[NI_MAXHOST + NI_MAXSERV + 32]; 333 char buf1[NI_MAXHOST + NI_MAXSERV + 32]; 334 335 if ((server->sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) 336 < 0) { 337 module_radius_log(server->module, LOG_WARNING, 338 "%s: socket() failed", __func__); 339 goto on_error; 340 } 341 if (connect(server->sock, (struct sockaddr *)&server->addr, 342 server->addr.sin4.sin_len) != 0) { 343 module_radius_log(server->module, LOG_WARNING, 344 "%s: connect to %s failed", __func__, 345 addrport_tostring((struct sockaddr *)&server->addr, 346 server->addr.sin4.sin_len, buf1, sizeof(buf1))); 347 goto on_error; 348 } 349 locallen = sizeof(server->local); 350 if (getsockname(server->sock, (struct sockaddr *)&server->local, 351 &locallen) != 0) { 352 module_radius_log(server->module, LOG_WARNING, 353 "%s: getsockanme() failed", __func__); 354 goto on_error; 355 } 356 module_radius_log(server->module, LOG_INFO, 357 "Use %s to send requests for %s", 358 addrport_tostring((struct sockaddr *)&server->local, 359 locallen, buf0, sizeof(buf0)), 360 addrport_tostring((struct sockaddr *)&server->addr, 361 server->addr.sin4.sin_len, buf1, sizeof(buf1))); 362 363 event_set(&server->ev, server->sock, EV_READ | EV_PERSIST, 364 radius_server_on_event, server); 365 if (event_add(&server->ev, NULL)) { 366 module_radius_log(server->module, LOG_WARNING, 367 "%s: event_add() failed", __func__); 368 goto on_error; 369 } 370 371 return (0); 372 on_error: 373 if (server->sock >= 0) 374 close(server->sock); 375 server->sock = -1; 376 return (-1); 377 } 378 379 static void 380 radius_server_stop(struct radius_server *server) 381 { 382 event_del(&server->ev); 383 if (server->sock >= 0) 384 close(server->sock); 385 server->sock = -1; 386 } 387 388 static void 389 radius_server_on_event(int fd, short evmask, void *ctx) 390 { 391 int sz, res_id; 392 u_char pkt[65535]; 393 char buf[NI_MAXHOST + NI_MAXSERV + 32]; 394 struct radius_server *server = ctx; 395 RADIUS_PACKET *radpkt = NULL; 396 struct module_radius_req *req; 397 struct sockaddr *peer; 398 399 peer = (struct sockaddr *)&server->addr; 400 if ((sz = recv(server->sock, pkt, sizeof(pkt), 0)) == -1) { 401 if (errno == EAGAIN) 402 return; 403 module_radius_log(server->module, LOG_WARNING, 404 "server=%s recv() failed: %m", 405 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf))); 406 return; 407 } 408 if ((radpkt = radius_convert_packet(pkt, sz)) == NULL) { 409 module_radius_log(server->module, LOG_WARNING, 410 "server=%s could not convert the received message to a " 411 "RADIUS packet object: %m", 412 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf))); 413 return; 414 } 415 res_id = radius_get_id(radpkt); 416 TAILQ_FOREACH(req, &server->module->req, next) { 417 if (req->server == server && req->req_id == res_id) 418 break; 419 } 420 if (req == NULL) { 421 module_radius_log(server->module, LOG_WARNING, 422 "server=%s Received radius message has unknown id=%d", 423 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)), 424 res_id); 425 goto out; 426 } 427 radius_set_request_packet(radpkt, req->q_pkt); 428 429 if (server->module->secret[0] != '\0') { 430 if (radius_check_response_authenticator(radpkt, 431 server->module->secret) != 0) { 432 module_radius_log(server->module, LOG_WARNING, 433 "server=%s Received radius message(id=%d) has bad " 434 "authenticator", 435 addrport_tostring(peer, peer->sa_len, buf, 436 sizeof(buf)), res_id); 437 goto out; 438 } 439 if (radius_has_attr(radpkt, 440 RADIUS_TYPE_MESSAGE_AUTHENTICATOR) && 441 radius_check_message_authenticator(radpkt, 442 server->module->secret) != 0) { 443 module_radius_log(server->module, LOG_WARNING, 444 "server=%s Received radius message(id=%d) has bad " 445 "message authenticator", 446 addrport_tostring(peer, peer->sa_len, buf, 447 sizeof(buf)), res_id); 448 goto out; 449 } 450 } 451 452 module_radius_log(server->module, LOG_INFO, 453 "q=%u received a response from server %s", req->q_id, 454 addrport_tostring(peer, peer->sa_len, buf, sizeof(buf))); 455 456 module_radius_req_on_success(req, radius_get_data(radpkt), 457 radius_get_length(radpkt)); 458 out: 459 if (radpkt != NULL) 460 radius_delete_packet(radpkt); 461 } 462 463 static void 464 radius_server_on_fail(struct radius_server *server, const char *failmsg) 465 { 466 char buf0[NI_MAXHOST + NI_MAXSERV + 32]; 467 char buf1[NI_MAXHOST + NI_MAXSERV + 32]; 468 struct sockaddr *caddr, *naddr; 469 470 caddr = (struct sockaddr *)&server->addr; 471 if (server->module->nserver <= 1) { 472 module_radius_log(server->module, LOG_WARNING, 473 "Server %s failed: %s", 474 addrport_tostring(caddr, caddr->sa_len, buf0, sizeof(buf0)), 475 failmsg); 476 return; 477 } 478 server->module->curr_server++; 479 server->module->curr_server %= server->module->nserver; 480 naddr = (struct sockaddr *) 481 &server->module->server[server->module->curr_server].addr; 482 483 module_radius_log(server->module, LOG_WARNING, 484 "Server %s failed: %s Fail over to %s", 485 addrport_tostring(caddr, caddr->sa_len, buf0, sizeof(buf0)), 486 failmsg, 487 addrport_tostring(naddr, naddr->sa_len, buf1, sizeof(buf1))); 488 } 489 490 /* module_radius_req */ 491 492 static void 493 module_radius_req_send(struct module_radius_req *req) 494 { 495 int sz; 496 struct sockaddr *peer; 497 char msg[BUFSIZ]; 498 499 peer = (struct sockaddr *)&req->server->addr; 500 if ((sz = send(req->server->sock, radius_get_data(req->q_pkt), 501 radius_get_length(req->q_pkt), 0)) < 0) { 502 module_radius_log(req->module, LOG_WARNING, 503 "Sending RADIUS query q=%u to %s failed: %m", 504 req->q_id, 505 addrport_tostring(peer, peer->sa_len, msg, sizeof(msg))); 506 /* retry anyway */ 507 } 508 module_radius_log(req->module, LOG_INFO, 509 "Send RADIUS query q=%u id=%d to %s successfully", 510 req->q_id, req->req_id, 511 addrport_tostring(peer, peer->sa_len, msg, sizeof(msg))); 512 if (module_radius_req_reset_event(req) != -1) 513 req->ntry++; 514 } 515 516 static int 517 module_radius_req_reset_event(struct module_radius_req *req) 518 { 519 struct timeval tv; 520 static int timeouts[] = { 2, 4, 8 }; 521 522 tv.tv_usec = 0; 523 if (req->module->req_timeout != 0) 524 tv.tv_sec = req->module->req_timeout; 525 else { 526 if (req->ntry < nitems(timeouts)) 527 tv.tv_sec = timeouts[req->ntry]; 528 else 529 tv.tv_sec = timeouts[nitems(timeouts) - 1]; 530 } 531 if (evtimer_add(&req->ev, &tv) != 0) { 532 module_radius_log(req->module, LOG_WARNING, 533 "Cannot proccess the request for q=%u: " 534 "evtimer_add() failed: %m", req->q_id); 535 module_radius_req_on_failure(req); 536 return (-1); 537 } 538 return (0); 539 } 540 541 static void 542 module_radius_req_on_timeout(int fd, short evmask, void *ctx) 543 { 544 struct module_radius_req *req = ctx; 545 char msg[BUFSIZ]; 546 547 548 if (req->module->max_tries <= req->ntry) { 549 snprintf(msg, sizeof(msg), "q=%u didn't response RADIUS query " 550 "%d time%s", req->q_id, req->ntry, 551 (req->ntry > 0)? "s" : ""); 552 radius_server_on_fail(req->server, msg); 553 if (++req->nfailover >= req->module->max_failovers) { 554 module_radius_log(req->module, 555 LOG_WARNING, "RADIUS query q=%u time out", 556 req->q_id); 557 module_radius_req_on_failure(req); 558 return; 559 } 560 /* select the next server */ 561 module_radius_req_select_server(req); 562 } 563 module_radius_req_send(req); 564 } 565 566 static void 567 module_radius_req_on_success(struct module_radius_req *req, 568 const u_char *pkt, size_t pktlen) 569 { 570 module_accsreq_answer(req->module->base, req->q_id, 1, pkt, pktlen); 571 module_radius_req_free(req); 572 } 573 574 static void 575 module_radius_req_on_failure(struct module_radius_req *req) 576 { 577 module_accsreq_aborted(req->module->base, req->q_id); 578 module_radius_req_free(req); 579 } 580 581 582 static void 583 module_radius_req_free(struct module_radius_req *req) 584 { 585 evtimer_del(&req->ev); 586 TAILQ_REMOVE(&req->module->req, req, next); 587 if (req->q_pkt != NULL) 588 radius_delete_packet(req->q_pkt); 589 free(req); 590 } 591 592 static void 593 module_radius_req_select_server(struct module_radius_req *req) 594 { 595 req->server = &req->module->server[req->module->curr_server]; 596 req->ntry = 0; 597 req->req_id = req->server->req_id_seq++; 598 radius_set_id(req->q_pkt, req->req_id); 599 module_radius_req_reset_msgauth(req); 600 } 601 602 static void 603 module_radius_req_reset_msgauth(struct module_radius_req *req) 604 { 605 if (radius_has_attr(req->q_pkt, RADIUS_TYPE_MESSAGE_AUTHENTICATOR)) 606 radius_del_attr_all(req->q_pkt, 607 RADIUS_TYPE_MESSAGE_AUTHENTICATOR); 608 if (req->module->secret[0] != '\0') 609 radius_put_message_authenticator(req->q_pkt, 610 req->module->secret); 611 } 612 613 static void 614 module_radius_log(struct module_radius *module, int pri, const char *fmt, ...) 615 { 616 char fmt0[BUFSIZ]; 617 va_list va; 618 619 snprintf(fmt0, sizeof(fmt0), "radius: %s", fmt); 620 va_start(va, fmt); 621 vlog(pri, fmt0, va); 622 va_end(va); 623 } 624