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