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