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