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