radius.c revision 1.9
1/* $OpenBSD: radius.c,v 1.9 2024/08/08 03:58:53 yasuoka Exp $ */ 2 3/* 4 * Copyright (c) 2024 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 <sys/time.h> 23#include <arpa/inet.h> 24#include <netinet/ip_ipsp.h> 25 26#include <endian.h> 27#include <event.h> 28#include <errno.h> 29#include <imsg.h> 30#include <limits.h> 31#include <netinet/in.h> 32#include <radius.h> 33#include <stdint.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <strings.h> 38#include <time.h> 39 40#include "iked.h" 41#include "eap.h" 42#include "ikev2.h" 43#include "types.h" 44 45void iked_radius_request_send(struct iked *, void *); 46void iked_radius_fill_attributes(struct iked_sa *, RADIUS_PACKET *); 47void iked_radius_config(struct iked_radserver_req *, const RADIUS_PACKET *, 48 int, uint32_t, uint8_t); 49void iked_radius_acct_request(struct iked *, struct iked_sa *, uint8_t); 50 51const struct iked_radcfgmap radius_cfgmaps[] = { 52 { IKEV2_CFG_INTERNAL_IP4_ADDRESS, 0, RADIUS_TYPE_FRAMED_IP_ADDRESS }, 53 { IKEV2_CFG_INTERNAL_IP4_NETMASK, 0, RADIUS_TYPE_FRAMED_IP_NETMASK }, 54 { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT, 55 RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER }, 56 { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT, 57 RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER }, 58 { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT, 59 RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER }, 60 { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT, 61 RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER }, 62 { 0 } 63}; 64 65int 66iked_radius_request(struct iked *env, struct iked_sa *sa, 67 struct iked_message *msg) 68{ 69 struct eap_message *eap; 70 RADIUS_PACKET *pkt; 71 size_t len; 72 73 eap = ibuf_data(msg->msg_eapmsg); 74 len = betoh16(eap->eap_length); 75 if (eap->eap_code != EAP_CODE_RESPONSE) { 76 log_debug("%s: eap_code is not response %u", __func__, 77 (unsigned)eap->eap_code); 78 return -1; 79 } 80 81 if (eap->eap_type == EAP_TYPE_IDENTITY) { 82 if ((sa->sa_radreq = calloc(1, 83 sizeof(struct iked_radserver_req))) == NULL) { 84 log_debug( 85 "%s: calloc failed for iked_radserver_req: %s", 86 __func__, strerror(errno)); 87 return (-1); 88 } 89 timer_set(env, &sa->sa_radreq->rr_timer, 90 iked_radius_request_send, sa->sa_radreq); 91 sa->sa_radreq->rr_user = strdup(msg->msg_eap.eam_identity); 92 } 93 94 if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST)) 95 == NULL) { 96 log_debug("%s: radius_new_request_packet failed %s", __func__, 97 strerror(errno)); 98 return -1; 99 } 100 101 radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME, 102 sa->sa_radreq->rr_user); 103 if (sa->sa_radreq->rr_state != NULL) 104 radius_put_raw_attr(pkt, RADIUS_TYPE_STATE, 105 ibuf_data(sa->sa_radreq->rr_state), 106 ibuf_size(sa->sa_radreq->rr_state)); 107 108 if (radius_put_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, 109 (uint8_t *)eap, len) == -1) { 110 log_debug("%s: radius_put_raw_attr_cat failed %s", __func__, 111 strerror(errno)); 112 return -1; 113 } 114 115 iked_radius_fill_attributes(sa, pkt); 116 117 /* save the request, it'll be needed for message authentication */ 118 if (sa->sa_radreq->rr_reqpkt != NULL) 119 radius_delete_packet(sa->sa_radreq->rr_reqpkt); 120 sa->sa_radreq->rr_reqpkt = pkt; 121 sa->sa_radreq->rr_sa = sa; 122 sa->sa_radreq->rr_ntry = 0; 123 124 iked_radius_request_send(env, sa->sa_radreq); 125 126 return 0; 127} 128 129void 130iked_radius_request_free(struct iked *env, struct iked_radserver_req *req) 131{ 132 if (req == NULL) 133 return; 134 timer_del(env, &req->rr_timer); 135 free(req->rr_user); 136 ibuf_free(req->rr_state); 137 if (req->rr_reqpkt) 138 radius_delete_packet(req->rr_reqpkt); 139 if (req->rr_sa) 140 req->rr_sa->sa_radreq = NULL; 141 if (req->rr_server) 142 TAILQ_REMOVE(&req->rr_server->rs_reqs, req, rr_entry); 143 free(req); 144} 145 146void 147iked_radius_on_event(int fd, short ev, void *ctx) 148{ 149 struct iked *env; 150 struct iked_radserver *server = ctx; 151 struct iked_radserver_req *req; 152 const struct iked_radcfgmap *cfgmap; 153 RADIUS_PACKET *pkt; 154 int i, resid; 155 struct ibuf *e; 156 const void *attrval; 157 size_t attrlen; 158 uint8_t code; 159 char username[256]; 160 u_char eapmsk[128]; 161 /* RFC 3748 defines the MSK minimum size is 64 bytes */ 162 size_t eapmsksiz = sizeof(eapmsk); 163 164 env = server->rs_env; 165 pkt = radius_recv(server->rs_sock, 0); 166 if (pkt == NULL) { 167 log_info("%s: receiving a RADIUS message failed: %s", __func__, 168 strerror(errno)); 169 return; 170 } 171 resid = radius_get_id(pkt); 172 173 TAILQ_FOREACH(req, &server->rs_reqs, rr_entry) { 174 if (req->rr_reqid == resid) 175 break; 176 } 177 if (req == NULL) { 178 log_debug("%s: received an unknown RADIUS message: id=%u", 179 __func__, (unsigned)resid); 180 radius_delete_packet(pkt); 181 return; 182 } 183 184 radius_set_request_packet(pkt, req->rr_reqpkt); 185 if (radius_check_response_authenticator(pkt, server->rs_secret) != 0) { 186 log_info("%s: received an invalid RADIUS message: bad " 187 "response authenticator", __func__); 188 radius_delete_packet(pkt); 189 return; 190 } 191 if (req->rr_accounting) { 192 /* accounting */ 193 code = radius_get_code(pkt); 194 switch (code) { 195 case RADIUS_CODE_ACCOUNTING_RESPONSE: /* Expected */ 196 break; 197 default: 198 log_info("%s: received an invalid RADIUS message: " 199 "code %u", __func__, (unsigned)code); 200 } 201 timer_del(env, &req->rr_timer); 202 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 203 req->rr_server = NULL; 204 free(req); 205 radius_delete_packet(pkt); 206 return; 207 } 208 209 /* authentication */ 210 if (radius_check_message_authenticator(pkt, server->rs_secret) != 0) { 211 log_info("%s: received an invalid RADIUS message: bad " 212 "message authenticator", __func__); 213 radius_delete_packet(pkt); 214 return; 215 } 216 217 timer_del(env, &req->rr_timer); 218 req->rr_ntry = 0; 219 220 if (req->rr_sa == NULL) 221 goto fail; 222 223 code = radius_get_code(pkt); 224 switch (code) { 225 case RADIUS_CODE_ACCESS_CHALLENGE: 226 if (radius_get_raw_attr_ptr(pkt, RADIUS_TYPE_STATE, &attrval, 227 &attrlen) != 0) { 228 log_info("%s: received an invalid RADIUS message: no " 229 "state attribute", __func__); 230 goto fail; 231 } 232 if ((req->rr_state != NULL && 233 ibuf_set(req->rr_state, 0, attrval, attrlen) != 0) || 234 (req->rr_state = ibuf_new(attrval, attrlen)) == NULL) { 235 log_info("%s: ibuf_new() failed: %s", __func__, 236 strerror(errno)); 237 goto fail; 238 } 239 break; 240 case RADIUS_CODE_ACCESS_ACCEPT: 241 log_info("%s: received Access-Accept for %s", 242 SPI_SA(req->rr_sa, __func__), req->rr_user); 243 /* Try to retrieve the EAP MSK from the RADIUS response */ 244 if (radius_get_eap_msk(pkt, eapmsk, &eapmsksiz, 245 server->rs_secret) == 0) { 246 ibuf_free(req->rr_sa->sa_eapmsk); 247 if ((req->rr_sa->sa_eapmsk = ibuf_new(eapmsk, 248 eapmsksiz)) == NULL) { 249 log_info("%s: ibuf_new() failed: %s", __func__, 250 strerror(errno)); 251 goto fail; 252 } 253 } else 254 log_debug("Could not retrieve the EAP MSK from the " 255 "RADIUS message"); 256 257 free(req->rr_sa->sa_eapid); 258 /* The EAP identity might be protected (RFC 3748 7.3) */ 259 if (radius_get_string_attr(pkt, RADIUS_TYPE_USER_NAME, 260 username, sizeof(username)) == 0 && 261 strcmp(username, req->rr_user) != 0) { 262 /* 263 * The Access-Accept might have a User-Name. It 264 * should be used for Accouting (RFC 2865 5.1). 265 */ 266 free(req->rr_user); 267 req->rr_sa->sa_eapid = strdup(username); 268 } else 269 req->rr_sa->sa_eapid = req->rr_user; 270 req->rr_user = NULL; 271 272 sa_state(env, req->rr_sa, IKEV2_STATE_AUTH_SUCCESS); 273 274 /* Map RADIUS attributes to cp */ 275 if (TAILQ_EMPTY(&env->sc_radcfgmaps)) { 276 for (i = 0; radius_cfgmaps[i].cfg_type != 0; i++) { 277 cfgmap = &radius_cfgmaps[i]; 278 iked_radius_config(req, pkt, cfgmap->cfg_type, 279 cfgmap->vendor_id, cfgmap->attr_type); 280 } 281 } else { 282 TAILQ_FOREACH(cfgmap, &env->sc_radcfgmaps, entry) 283 iked_radius_config(req, pkt, cfgmap->cfg_type, 284 cfgmap->vendor_id, cfgmap->attr_type); 285 } 286 287 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 288 req->rr_server = NULL; 289 break; 290 case RADIUS_CODE_ACCESS_REJECT: 291 log_info("%s: received Access-Reject for %s", 292 SPI_SA(req->rr_sa, __func__), req->rr_user); 293 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 294 req->rr_server = NULL; 295 break; 296 default: 297 log_debug("%s: received an invalid RADIUS message: code %u", 298 __func__, (unsigned)code); 299 break; 300 } 301 302 /* get the length first */ 303 if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, NULL, 304 &attrlen) != 0) { 305 log_info("%s: failed to retrieve the EAP message", __func__); 306 goto fail; 307 } 308 /* allocate a buffer */ 309 if ((e = ibuf_new(NULL, attrlen)) == NULL) { 310 log_info("%s: ibuf_new() failed: %s", __func__, 311 strerror(errno)); 312 goto fail; 313 } 314 /* copy the message to the buffer */ 315 if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, 316 ibuf_data(e), &attrlen) != 0) { 317 ibuf_free(e); 318 log_info("%s: failed to retrieve the EAP message", __func__); 319 goto fail; 320 } 321 radius_delete_packet(pkt); 322 ikev2_send_ike_e(env, req->rr_sa, e, IKEV2_PAYLOAD_EAP, 323 IKEV2_EXCHANGE_IKE_AUTH, 1); 324 /* keep request for challenge state and config parameters */ 325 req->rr_reqid = -1; /* release reqid */ 326 return; 327 fail: 328 radius_delete_packet(pkt); 329 if (req->rr_server != NULL) 330 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 331 req->rr_server = NULL; 332 if (req->rr_sa != NULL) { 333 ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed"); 334 sa_free(env, req->rr_sa); 335 } 336} 337 338void 339iked_radius_request_send(struct iked *env, void *ctx) 340{ 341 struct iked_radserver_req *req = ctx, *req0; 342 struct iked_radserver *server = req->rr_server; 343 const int timeouts[] = { 2, 4, 8 }; 344 uint8_t seq; 345 int i, max_tries, max_failovers; 346 struct sockaddr_storage ss; 347 socklen_t sslen; 348 struct iked_radservers *radservers; 349 struct timespec now; 350 351 if (!req->rr_accounting) { 352 max_tries = env->sc_radauth.max_tries; 353 max_failovers = env->sc_radauth.max_failovers; 354 radservers = &env->sc_radauthservers; 355 } else { 356 max_tries = env->sc_radacct.max_tries; 357 max_failovers = env->sc_radacct.max_failovers; 358 radservers = &env->sc_radacctservers; 359 } 360 361 if (req->rr_ntry > max_tries) { 362 req->rr_ntry = 0; 363 log_info("%s: RADIUS server %s failed", __func__, 364 print_addr(&server->rs_sockaddr)); 365 next_server: 366 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 367 req->rr_server = NULL; 368 if (req->rr_nfailover >= max_failovers || 369 TAILQ_NEXT(server, rs_entry) == NULL) { 370 log_info("%s: No more RADIUS server", __func__); 371 goto fail; 372 } else if (req->rr_state != NULL) { 373 log_info("%s: Can't change RADIUS server: " 374 "client has a state already", __func__); 375 goto fail; 376 } else { 377 TAILQ_REMOVE(radservers, server, rs_entry); 378 TAILQ_INSERT_TAIL(radservers, server, rs_entry); 379 server = TAILQ_FIRST(radservers); 380 log_info("%s: RADIUS server %s is active", 381 __func__, print_addr(&server->rs_sockaddr)); 382 } 383 req->rr_nfailover++; 384 } 385 386 if (req->rr_server != NULL && 387 req->rr_server != TAILQ_FIRST(radservers)) { 388 /* Current server is marked fail */ 389 if (req->rr_state != NULL || req->rr_nfailover >= max_failovers) 390 goto fail; /* can't fail over */ 391 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 392 req->rr_server = NULL; 393 req->rr_nfailover++; 394 } 395 396 if (req->rr_server == NULL) { 397 /* Select a new server */ 398 server = TAILQ_FIRST(radservers); 399 if (server == NULL) { 400 log_info("%s: No RADIUS server is configured", 401 __func__); 402 goto fail; 403 } 404 TAILQ_INSERT_TAIL(&server->rs_reqs, req, rr_entry); 405 req->rr_server = server; 406 407 /* Prepare NAS-IP-Address */ 408 if (server->rs_nas_ipv4.s_addr == INADDR_ANY && 409 IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6)) { 410 sslen = sizeof(ss); 411 if (getsockname(server->rs_sock, (struct sockaddr *)&ss, 412 &sslen) == 0) { 413 if (ss.ss_family == AF_INET) 414 server->rs_nas_ipv4 = 415 ((struct sockaddr_in *)&ss) 416 ->sin_addr; 417 else 418 server->rs_nas_ipv6 = 419 ((struct sockaddr_in6 *)&ss) 420 ->sin6_addr; 421 } 422 } 423 } 424 if (req->rr_ntry == 0) { 425 /* decide the ID */ 426 seq = ++server->rs_reqseq; 427 for (i = 0; i <= UCHAR_MAX; i++) { 428 TAILQ_FOREACH(req0, &server->rs_reqs, rr_entry) { 429 if (req0->rr_reqid == -1) 430 continue; 431 if (req0->rr_reqid == seq) 432 break; 433 } 434 if (req0 == NULL) 435 break; 436 seq++; 437 } 438 if (i > UCHAR_MAX) { 439 log_info("%s: RADIUS server %s failed. Too many " 440 "pending requests", __func__, 441 print_addr(&server->rs_sockaddr)); 442 if (TAILQ_NEXT(server, rs_entry) != NULL) 443 goto next_server; 444 goto fail; 445 } 446 req->rr_reqid = seq; 447 radius_set_id(req->rr_reqpkt, req->rr_reqid); 448 } 449 450 if (server->rs_nas_ipv4.s_addr != INADDR_ANY) 451 radius_put_ipv4_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IP_ADDRESS, 452 server->rs_nas_ipv4); 453 else if (!IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6)) 454 radius_put_ipv6_attr(req->rr_reqpkt, 455 RADIUS_TYPE_NAS_IPV6_ADDRESS, &server->rs_nas_ipv6); 456 /* Identifier */ 457 radius_put_string_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IDENTIFIER, 458 IKED_NAS_ID); 459 460 if (req->rr_accounting) { 461 if (req->rr_ntry == 0 && req->rr_nfailover == 0) 462 radius_put_uint32_attr(req->rr_reqpkt, 463 RADIUS_TYPE_ACCT_DELAY_TIME, 0); 464 else { 465 clock_gettime(CLOCK_MONOTONIC, &now); 466 timespecsub(&now, &req->rr_accttime, &now); 467 radius_put_uint32_attr(req->rr_reqpkt, 468 RADIUS_TYPE_ACCT_DELAY_TIME, now.tv_sec); 469 } 470 radius_set_accounting_request_authenticator(req->rr_reqpkt, 471 server->rs_secret); 472 } else { 473 radius_put_message_authenticator(req->rr_reqpkt, 474 server->rs_secret); 475 } 476 477 if (radius_send(server->rs_sock, req->rr_reqpkt, 0) < 0) 478 log_info("%s: sending a RADIUS message failed: %s", __func__, 479 strerror(errno)); 480 481 if (req->rr_ntry >= (int)nitems(timeouts)) 482 timer_add(env, &req->rr_timer, timeouts[nitems(timeouts) - 1]); 483 else 484 timer_add(env, &req->rr_timer, timeouts[req->rr_ntry]); 485 req->rr_ntry++; 486 return; 487 fail: 488 if (req->rr_server != NULL) 489 TAILQ_REMOVE(&server->rs_reqs, req, rr_entry); 490 req->rr_server = NULL; 491 if (req->rr_sa != NULL) { 492 ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed"); 493 sa_free(env, req->rr_sa); 494 } 495} 496 497void 498iked_radius_fill_attributes(struct iked_sa *sa, RADIUS_PACKET *pkt) 499{ 500 /* NAS Port Type = Virtual */ 501 radius_put_uint32_attr(pkt, 502 RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL); 503 /* Service Type = Framed */ 504 radius_put_uint32_attr(pkt, RADIUS_TYPE_SERVICE_TYPE, 505 RADIUS_SERVICE_TYPE_FRAMED); 506 /* Tunnel Type = EAP */ 507 radius_put_uint32_attr(pkt, RADIUS_TYPE_TUNNEL_TYPE, 508 RADIUS_TUNNEL_TYPE_ESP); 509 510 radius_put_string_attr(pkt, RADIUS_TYPE_CALLED_STATION_ID, 511 print_addr(&sa->sa_local.addr)); 512 radius_put_string_attr(pkt, RADIUS_TYPE_CALLING_STATION_ID, 513 print_addr(&sa->sa_peer.addr)); 514} 515 516void 517iked_radius_config(struct iked_radserver_req *req, const RADIUS_PACKET *pkt, 518 int cfg_type, uint32_t vendor_id, uint8_t attr_type) 519{ 520 unsigned int i; 521 struct iked_sa *sa = req->rr_sa; 522 struct in_addr ia4; 523 struct in6_addr ia6; 524 struct sockaddr_in *sin4; 525 struct sockaddr_in6 *sin6; 526 struct iked_addr *addr; 527 struct iked_cfg *ikecfg; 528 529 for (i = 0; i < sa->sa_policy->pol_ncfg; i++) { 530 ikecfg = &sa->sa_policy->pol_cfg[i]; 531 if (ikecfg->cfg_type == cfg_type && 532 ikecfg->cfg_type != IKEV2_CFG_INTERNAL_IP4_ADDRESS) 533 return; /* use config rather than radius */ 534 } 535 switch (cfg_type) { 536 case IKEV2_CFG_INTERNAL_IP4_ADDRESS: 537 case IKEV2_CFG_INTERNAL_IP4_NETMASK: 538 case IKEV2_CFG_INTERNAL_IP4_DNS: 539 case IKEV2_CFG_INTERNAL_IP4_NBNS: 540 case IKEV2_CFG_INTERNAL_IP4_DHCP: 541 case IKEV2_CFG_INTERNAL_IP4_SERVER: 542 if (vendor_id == 0 && radius_has_attr(pkt, attr_type)) 543 radius_get_ipv4_attr(pkt, attr_type, &ia4); 544 else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id, 545 attr_type)) 546 radius_get_vs_ipv4_attr(pkt, vendor_id, attr_type, 547 &ia4); 548 else 549 break; /* no attribute contained */ 550 551 if (cfg_type == IKEV2_CFG_INTERNAL_IP4_NETMASK) { 552 /* 553 * This assumes IKEV2_CFG_INTERNAL_IP4_ADDRESS is 554 * called before IKEV2_CFG_INTERNAL_IP4_NETMASK 555 */ 556 if (sa->sa_rad_addr == NULL) { 557 /* 558 * RFC 7296, IKEV2_CFG_INTERNAL_IP4_NETMASK 559 * must be used with 560 * IKEV2_CFG_INTERNAL_IP4_ADDRESS 561 */ 562 break; 563 } 564 if (ia4.s_addr == 0) { 565 log_debug("%s: netmask is wrong", __func__); 566 break; 567 } 568 if (ia4.s_addr == htonl(0)) 569 sa->sa_rad_addr->addr_mask = 0; 570 else 571 sa->sa_rad_addr->addr_mask = 572 33 - ffs(ntohl(ia4.s_addr)); 573 if (sa->sa_rad_addr->addr_mask < 32) 574 sa->sa_rad_addr->addr_net = 1; 575 } 576 if (cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS) { 577 if ((addr = calloc(1, sizeof(*addr))) == NULL) { 578 log_warn("%s: calloc", __func__); 579 return; 580 } 581 sa->sa_rad_addr = addr; 582 } else { 583 req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY; 584 req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type; 585 addr = &req->rr_cfg[req->rr_ncfg].cfg.address; 586 req->rr_ncfg++; 587 } 588 addr->addr_af = AF_INET; 589 sin4 = (struct sockaddr_in *)&addr->addr; 590 sin4->sin_family = AF_INET; 591 sin4->sin_len = sizeof(struct sockaddr_in); 592 sin4->sin_addr = ia4; 593 break; 594 case IKEV2_CFG_INTERNAL_IP6_ADDRESS: 595 case IKEV2_CFG_INTERNAL_IP6_DNS: 596 case IKEV2_CFG_INTERNAL_IP6_NBNS: 597 case IKEV2_CFG_INTERNAL_IP6_DHCP: 598 case IKEV2_CFG_INTERNAL_IP6_SERVER: 599 if (vendor_id == 0 && radius_has_attr(pkt, attr_type)) 600 radius_get_ipv6_attr(pkt, attr_type, &ia6); 601 else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id, 602 attr_type)) 603 radius_get_vs_ipv6_attr(pkt, vendor_id, attr_type, 604 &ia6); 605 else 606 break; /* no attribute contained */ 607 608 if (cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS) { 609 if ((addr = calloc(1, sizeof(*addr))) == NULL) { 610 log_warn("%s: calloc", __func__); 611 return; 612 } 613 sa->sa_rad_addr = addr; 614 } else { 615 req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY; 616 req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type; 617 addr = &req->rr_cfg[req->rr_ncfg].cfg.address; 618 req->rr_ncfg++; 619 } 620 addr->addr_af = AF_INET; 621 sin6 = (struct sockaddr_in6 *)&addr->addr; 622 sin6->sin6_family = AF_INET6; 623 sin6->sin6_len = sizeof(struct sockaddr_in6); 624 sin6->sin6_addr = ia6; 625 break; 626 } 627 return; 628} 629 630void 631iked_radius_acct_on(struct iked *env) 632{ 633 if (TAILQ_EMPTY(&env->sc_radacctservers)) 634 return; 635 if (env->sc_radaccton == 0) { /* trigger once */ 636 iked_radius_acct_request(env, NULL, 637 RADIUS_ACCT_STATUS_TYPE_ACCT_ON); 638 env->sc_radaccton = 1; 639 } 640} 641 642void 643iked_radius_acct_off(struct iked *env) 644{ 645 iked_radius_acct_request(env, NULL, RADIUS_ACCT_STATUS_TYPE_ACCT_OFF); 646} 647 648void 649iked_radius_acct_start(struct iked *env, struct iked_sa *sa) 650{ 651 iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_START); 652} 653 654void 655iked_radius_acct_stop(struct iked *env, struct iked_sa *sa) 656{ 657 iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_STOP); 658} 659 660void 661iked_radius_acct_request(struct iked *env, struct iked_sa *sa, uint8_t stype) 662{ 663 struct iked_radserver_req *req; 664 RADIUS_PACKET *pkt; 665 struct iked_addr *addr4 = NULL; 666 struct iked_addr *addr6 = NULL; 667 struct in_addr mask4; 668 char sa_id[IKED_ID_SIZE]; 669 char sid[16 + 1]; 670 struct timespec now; 671 int cause; 672 673 if (TAILQ_EMPTY(&env->sc_radacctservers)) 674 return; 675 /* 676 * In RFC2866 5.6, "Users who are delivered service without 677 * being authenticated SHOULD NOT generate Accounting records 678 */ 679 if (sa != NULL && sa->sa_eapid == NULL) { 680 /* fallback to IKEID for accounting */ 681 if (ikev2_print_id(IKESA_DSTID(sa), sa_id, sizeof(sa_id)) != -1) 682 sa->sa_eapid = strdup(sa_id); 683 if (sa->sa_eapid == NULL) 684 return; 685 } 686 687 if ((req = calloc(1, sizeof(struct iked_radserver_req))) == NULL) { 688 log_debug("%s: calloc faile for iked_radserver_req: %s", 689 __func__, strerror(errno)); 690 return; 691 } 692 req->rr_accounting = 1; 693 clock_gettime(CLOCK_MONOTONIC, &now); 694 req->rr_accttime = now; 695 timer_set(env, &req->rr_timer, iked_radius_request_send, req); 696 697 if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST)) 698 == NULL) { 699 log_debug("%s: radius_new_request_packet failed %s", __func__, 700 strerror(errno)); 701 return; 702 } 703 704 /* RFC 2866 5.1. Acct-Status-Type */ 705 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE, stype); 706 707 if (sa == NULL) { 708 /* ASSERT(stype == RADIUS_ACCT_STATUS_TYPE_ACCT_ON || 709 stype == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) */ 710 req->rr_reqpkt = pkt; 711 req->rr_ntry = 0; 712 iked_radius_request_send(env, req); 713 return; 714 } 715 716 iked_radius_fill_attributes(sa, pkt); 717 718 radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME, sa->sa_eapid); 719 720 /* RFC 2866 5.5. Acct-Session-Id */ 721 snprintf(sid, sizeof(sid), "%016llx", 722 (unsigned long long)sa->sa_hdr.sh_ispi); 723 radius_put_string_attr(pkt, RADIUS_TYPE_ACCT_SESSION_ID, sid); 724 725 /* Accounting Request must have Framed-IP-Address */ 726 addr4 = sa->sa_addrpool; 727 if (addr4 != NULL) { 728 radius_put_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, 729 ((struct sockaddr_in *)&addr4->addr)->sin_addr); 730 if (addr4->addr_mask != 0) { 731 mask4.s_addr = htonl( 732 0xFFFFFFFFUL << (32 - addr4->addr_mask)); 733 radius_put_ipv4_attr(pkt, 734 RADIUS_TYPE_FRAMED_IP_NETMASK, mask4); 735 } 736 } 737 addr6 = sa->sa_addrpool6; 738 if (addr6 != NULL) 739 radius_put_ipv6_attr(pkt, RADIUS_TYPE_FRAMED_IPV6_ADDRESS, 740 &((struct sockaddr_in6 *)&addr6->addr)->sin6_addr); 741 742 /* RFC2866 5.6 Acct-Authentic */ 743 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_AUTHENTIC, 744 (sa->sa_radreq != NULL)? RADIUS_ACCT_AUTHENTIC_RADIUS : 745 RADIUS_ACCT_AUTHENTIC_LOCAL); 746 747 switch (stype) { 748 case RADIUS_ACCT_STATUS_TYPE_START: 749 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE, 750 RADIUS_ACCT_STATUS_TYPE_START); 751 break; 752 case RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE: 753 case RADIUS_ACCT_STATUS_TYPE_STOP: 754 /* RFC 2866 5.7. Acct-Session-Time */ 755 timespecsub(&now, &sa->sa_starttime, &now); 756 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_SESSION_TIME, 757 now.tv_sec); 758 /* RFC 2866 5.10 Acct-Terminate-Cause */ 759 cause = RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL; 760 if (sa->sa_reason) { 761 if (strcmp(sa->sa_reason, "received delete") == 0) { 762 cause = RADIUS_TERMNATE_CAUSE_USER_REQUEST; 763 } else if (strcmp(sa->sa_reason, "SA rekeyed") == 0) { 764 cause = RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT; 765 } else if (strncmp(sa->sa_reason, "retransmit", 766 strlen("retransmit")) == 0) { 767 cause = RADIUS_TERMNATE_CAUSE_LOST_SERVICE; 768 } else if (strcmp(sa->sa_reason, 769 "disconnect requested") == 0) { 770 cause = RADIUS_TERMNATE_CAUSE_ADMIN_RESET; 771 } 772 } 773 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_TERMINATE_CAUSE, 774 cause); 775 /* I/O statistics {Input,Output}-{Packets,Octets,Gigawords} */ 776 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_PACKETS, 777 sa->sa_stats.sas_ipackets); 778 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS, 779 sa->sa_stats.sas_opackets); 780 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_OCTETS, 781 sa->sa_stats.sas_ibytes & 0xffffffffUL); 782 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_OCTETS, 783 sa->sa_stats.sas_obytes & 0xffffffffUL); 784 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, 785 sa->sa_stats.sas_ibytes >> 32); 786 radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS, 787 sa->sa_stats.sas_obytes >> 32); 788 break; 789 } 790 req->rr_reqpkt = pkt; 791 req->rr_ntry = 0; 792 iked_radius_request_send(env, req); 793} 794 795void 796iked_radius_dae_on_event(int fd, short ev, void *ctx) 797{ 798 struct iked_raddae *dae = ctx; 799 struct iked *env = dae->rd_env; 800 RADIUS_PACKET *req = NULL, *res = NULL; 801 struct sockaddr_storage ss; 802 socklen_t sslen; 803 struct iked_radclient *client; 804 struct iked_sa *sa = NULL; 805 char attr[256], username[256]; 806 char *endp, *reason, *nakcause = NULL; 807 int code, n = 0; 808 uint64_t ispi = 0; 809 uint32_t u32, cause = 0; 810 struct iked_addr *addr4 = NULL; 811 812 reason = "disconnect requested"; 813 814 sslen = sizeof(ss); 815 req = radius_recvfrom(dae->rd_sock, 0, (struct sockaddr *)&ss, &sslen); 816 if (req == NULL) { 817 log_warn("%s: receiving a RADIUS message failed: %s", __func__, 818 strerror(errno)); 819 return; 820 } 821 TAILQ_FOREACH(client, &env->sc_raddaeclients, rc_entry) { 822 if (sockaddr_cmp((struct sockaddr *)&client->rc_sockaddr, 823 (struct sockaddr *)&ss, -1) == 0) 824 break; 825 } 826 if (client == NULL) { 827 log_warnx("%s: received RADIUS message from %s: " 828 "unknown client", __func__, print_addr(&ss)); 829 goto out; 830 } 831 832 if (radius_check_accounting_request_authenticator(req, 833 client->rc_secret) != 0) { 834 log_warnx("%s: received an invalid RADIUS message from %s: bad " 835 "response authenticator", __func__, print_addr(&ss)); 836 goto out; 837 } 838 839 if ((code = radius_get_code(req)) != RADIUS_CODE_DISCONNECT_REQUEST) { 840 /* Code other than Disconnect-Request is not supported */ 841 if (code == RADIUS_CODE_COA_REQUEST) { 842 code = RADIUS_CODE_COA_NAK; 843 cause = RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED; 844 nakcause = "Coa-Request is not supported"; 845 goto send; 846 } 847 log_warnx("%s: received an invalid RADIUS message " 848 "from %s: unknown code %d", __func__, 849 print_addr(&ss), code); 850 goto out; 851 } 852 853 log_info("received Disconnect-Request from %s", print_addr(&ss)); 854 855 if (radius_get_string_attr(req, RADIUS_TYPE_NAS_IDENTIFIER, attr, 856 sizeof(attr)) == 0 && strcmp(attr, IKED_NAS_ID) != 0) { 857 cause = RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH; 858 nakcause = "NAS-Identifier is not matched"; 859 goto search_done; 860 } 861 862 /* prepare User-Name attribute */ 863 memset(username, 0, sizeof(username)); 864 radius_get_string_attr(req, RADIUS_TYPE_USER_NAME, username, 865 sizeof(username)); 866 867 if (radius_get_string_attr(req, RADIUS_TYPE_ACCT_SESSION_ID, attr, 868 sizeof(attr)) == 0) { 869 /* the client is to disconnect a session */ 870 ispi = strtoull(attr, &endp, 16); 871 if (attr[0] == '\0' || *endp != '\0' || errno == ERANGE || 872 ispi == ULLONG_MAX) { 873 cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE; 874 nakcause = "Session-Id is wrong"; 875 goto search_done; 876 877 } 878 RB_FOREACH(sa, iked_sas, &env->sc_sas) { 879 if (sa->sa_hdr.sh_ispi == ispi) 880 break; 881 } 882 if (sa == NULL) 883 goto search_done; 884 if (username[0] != '\0' && (sa->sa_eapid == NULL || 885 strcmp(username, sa->sa_eapid) != 0)) { 886 /* specified User-Name attribute is mismatched */ 887 cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE; 888 nakcause = "User-Name is not matched"; 889 goto search_done; 890 } 891 ikev2_ike_sa_setreason(sa, reason); 892 ikev2_ike_sa_delete(env, sa); 893 n++; 894 } else if (username[0] != '\0') { 895 RB_FOREACH(sa, iked_sas, &env->sc_sas) { 896 if (sa->sa_eapid != NULL && 897 strcmp(sa->sa_eapid, username) == 0) { 898 ikev2_ike_sa_setreason(sa, reason); 899 ikev2_ike_sa_delete(env, sa); 900 n++; 901 } 902 } 903 } else if (radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS, 904 &u32) == 0) { 905 RB_FOREACH(sa, iked_sas, &env->sc_sas) { 906 addr4 = sa->sa_addrpool; 907 if (addr4 != NULL) { 908 if (u32 == ((struct sockaddr_in *)&addr4->addr) 909 ->sin_addr.s_addr) { 910 ikev2_ike_sa_setreason(sa, reason); 911 ikev2_ike_sa_delete(env, sa); 912 n++; 913 } 914 } 915 } 916 } 917 search_done: 918 if (n > 0) 919 code = RADIUS_CODE_DISCONNECT_ACK; 920 else { 921 if (nakcause == NULL) 922 nakcause = "session not found"; 923 if (cause == 0) 924 cause = RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND; 925 code = RADIUS_CODE_DISCONNECT_NAK; 926 } 927 send: 928 res = radius_new_response_packet(code, req); 929 if (res == NULL) { 930 log_warn("%s: radius_new_response_packet", __func__); 931 goto out; 932 } 933 if (cause != 0) 934 radius_put_uint32_attr(res, RADIUS_TYPE_ERROR_CAUSE, cause); 935 radius_set_response_authenticator(res, client->rc_secret); 936 if (radius_sendto(dae->rd_sock, res, 0, (struct sockaddr *)&ss, sslen) 937 == -1) 938 log_warn("%s: sendto", __func__); 939 log_info("send %s for %s%s%s", 940 (code == RADIUS_CODE_DISCONNECT_ACK)? "Disconnect-ACK" : 941 (code == RADIUS_CODE_DISCONNECT_NAK)? "Disconnect-NAK" : "CoA-NAK", 942 print_addr(&ss), (nakcause)? ": " : "", (nakcause)? nakcause : ""); 943 out: 944 radius_delete_packet(req); 945 if (res != NULL) 946 radius_delete_packet(res); 947} 948