1 /* $Id: npppd_radius.c,v 1.13 2024/07/12 15:54:11 yasuoka Exp $ */
2 /*-
3 * Copyright (c) 2009 Internet Initiative Japan Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * RFC 2865 Remote Authentication Dial In User Service (RADIUS)
30 * RFC 2866 RADIUS Accounting
31 * RFC 2868 RADIUS Attributes for Tunnel Protocol Support
32 * RFC 2869 RADIUS Extensions
33 */
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <sys/syslog.h>
39 #include <netinet/in.h>
40 #include <net/if_dl.h>
41 #include <arpa/inet.h>
42 #include <stdio.h>
43 #include <netdb.h>
44 #include <stdint.h>
45 #include <string.h>
46 #include <stdbool.h>
47 #include <radius.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <errno.h>
51
52 #include <event.h>
53
54 #include "radius_req.h"
55 #include "npppd_local.h"
56 #include "npppd_radius.h"
57 #include "net_utils.h"
58
59 #ifdef NPPPD_RADIUS_DEBUG
60 #define NPPPD_RADIUS_DBG(x) ppp_log x
61 #define NPPPD_RADIUS_ASSERT(x) ASSERT(x)
62 #else
63 #define NPPPD_RADIUS_DBG(x)
64 #define NPPPD_RADIUS_ASSERT(x)
65 #endif
66
67 static int l2tp_put_tunnel_attributes(RADIUS_PACKET *, void *);
68 static int pptp_put_tunnel_attributes(RADIUS_PACKET *, void *);
69 static int radius_acct_request(npppd *, npppd_ppp *, int );
70 static void radius_acct_on_cb(void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX);
71 static void npppd_ppp_radius_acct_reqcb(void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX);
72
73 /***********************************************************************
74 * RADIUS common functions
75 ***********************************************************************/
76 /**
77 * Retribute Framed-IP-Address and Framed-IP-Netmask attribute of from
78 * the given RADIUS packet and set them as the fields of ppp context.
79 */
80 void
ppp_process_radius_attrs(npppd_ppp * _this,RADIUS_PACKET * pkt)81 ppp_process_radius_attrs(npppd_ppp *_this, RADIUS_PACKET *pkt)
82 {
83 struct in_addr ip4;
84 int got_pri, got_sec;
85 char buf0[40], buf1[40];
86
87 if (radius_get_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, &ip4)
88 == 0)
89 _this->realm_framed_ip_address = ip4;
90
91 _this->realm_framed_ip_netmask.s_addr = 0xffffffffL;
92 #ifndef NPPPD_COMPAT_4_2
93 if (radius_get_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_NETMASK, &ip4)
94 == 0)
95 _this->realm_framed_ip_netmask = ip4;
96 #endif
97
98 if (!ppp_ipcp(_this)->dns_configured) {
99 got_pri = got_sec = 0;
100 if (radius_get_vs_ipv4_attr(pkt, RADIUS_VENDOR_MICROSOFT,
101 RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, &ip4) == 0) {
102 got_pri = 1;
103 _this->ipcp.dns_pri = ip4;
104 }
105 if (radius_get_vs_ipv4_attr(pkt, RADIUS_VENDOR_MICROSOFT,
106 RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER, &ip4) == 0) {
107 got_sec = 1;
108 _this->ipcp.dns_sec = ip4;
109 }
110 if (got_pri || got_sec)
111 ppp_log(_this, LOG_INFO, "DNS server address%s "
112 "(%s%s%s) %s configured by RADIUS server",
113 ((got_pri + got_sec) > 1)? "es" : "",
114 (got_pri)? inet_ntop(AF_INET, &_this->ipcp.dns_pri,
115 buf0, sizeof(buf0)) : "",
116 (got_pri != 0 && got_sec != 0)? "," : "",
117 (got_sec)? inet_ntop(AF_INET, &_this->ipcp.dns_sec,
118 buf1, sizeof(buf1)) : "",
119 ((got_pri + got_sec) > 1)? "are" : "is");
120 }
121 if (!ppp_ipcp(_this)->nbns_configured) {
122 got_pri = got_sec = 0;
123 if (radius_get_vs_ipv4_attr(pkt, RADIUS_VENDOR_MICROSOFT,
124 RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER, &ip4) == 0) {
125 got_pri = 1;
126 _this->ipcp.nbns_pri = ip4;
127 }
128 if (radius_get_vs_ipv4_attr(pkt, RADIUS_VENDOR_MICROSOFT,
129 RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER, &ip4) == 0) {
130 got_sec = 1;
131 _this->ipcp.nbns_sec = ip4;
132 }
133 if (got_pri || got_sec)
134 ppp_log(_this, LOG_INFO, "NBNS server address%s "
135 "(%s%s%s) %s configured by RADIUS server",
136 ((got_pri + got_sec) > 1)? "es" : "",
137 (got_pri)? inet_ntop(AF_INET, &_this->ipcp.nbns_pri,
138 buf0, sizeof(buf0)) : "",
139 (got_pri != 0 && got_sec != 0)? "," : "",
140 (got_sec)? inet_ntop(AF_INET, &_this->ipcp.nbns_sec,
141 buf1, sizeof(buf1)) : "",
142 ((got_pri + got_sec) > 1)? "are" : "is");
143 }
144 }
145
146 /***********************************************************************
147 * RADIUS Accounting Events
148 ***********************************************************************/
149
150 /** Called by PPP on start */
151 void
npppd_ppp_radius_acct_start(npppd * pppd,npppd_ppp * ppp)152 npppd_ppp_radius_acct_start(npppd *pppd, npppd_ppp *ppp)
153 {
154 NPPPD_RADIUS_DBG((ppp, LOG_INFO, "%s()", __func__));
155
156 if (ppp->realm == NULL || !npppd_ppp_is_realm_radius(pppd, ppp))
157 return;
158 radius_acct_request(pppd, ppp, 0);
159 }
160
161 /** Called by PPP on stop*/
162 void
npppd_ppp_radius_acct_stop(npppd * pppd,npppd_ppp * ppp)163 npppd_ppp_radius_acct_stop(npppd *pppd, npppd_ppp *ppp)
164 {
165 NPPPD_RADIUS_DBG((ppp, LOG_INFO, "%s()", __func__));
166
167 if (ppp->realm == NULL || !npppd_ppp_is_realm_radius(pppd, ppp))
168 return;
169 radius_acct_request(pppd, ppp, 1);
170 }
171
172 /** Called by radius_req.c */
173 static void
npppd_ppp_radius_acct_reqcb(void * context,RADIUS_PACKET * pkt,int flags,RADIUS_REQUEST_CTX ctx)174 npppd_ppp_radius_acct_reqcb(void *context, RADIUS_PACKET *pkt, int flags,
175 RADIUS_REQUEST_CTX ctx)
176 {
177 u_int ppp_id;
178
179 ppp_id = (uintptr_t)context;
180 if ((flags & RADIUS_REQUEST_TIMEOUT) != 0) {
181 log_printf(LOG_WARNING, "ppp id=%u radius accounting request "
182 "failed: no response from the server.", ppp_id);
183 }
184 else if ((flags & RADIUS_REQUEST_ERROR) != 0)
185 log_printf(LOG_WARNING, "ppp id=%u radius accounting request "
186 "failed: %m", ppp_id);
187 else if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0 &&
188 (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0)
189 log_printf(LOG_WARNING, "ppp id=%d radius accounting request "
190 "failed: the server responses with bad authenticator",
191 ppp_id);
192 else {
193 #ifdef NPPPD_RADIUS_DEBUG
194 log_printf(LOG_DEBUG, "ppp id=%u radius accounting request "
195 "succeeded.", ppp_id);
196 #endif
197 return;
198 /* NOTREACHED */
199 }
200 if (radius_request_can_failover(ctx)) {
201 if (radius_request_failover(ctx) == 0) {
202 struct sockaddr *sa;
203 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
204
205 sa = radius_get_server_address(ctx);
206 if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf),
207 sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV)
208 != 0) {
209 strlcpy(hbuf, "unknown", sizeof(hbuf));
210 strlcpy(sbuf, "", sizeof(sbuf));
211 }
212 log_printf(LOG_DEBUG, "ppp id=%u "
213 "fail over to %s:%s for radius accounting request",
214 ppp_id, hbuf, sbuf);
215 } else {
216 log_printf(LOG_WARNING, "ppp id=%u "
217 "failed to fail over for radius accounting request",
218 ppp_id);
219 }
220 }
221 }
222
223 /***********************************************************************
224 * RADIUS attributes
225 ***********************************************************************/
226 #define ATTR_INT32(_a,_v) \
227 do { \
228 if (radius_put_uint32_attr(radpkt, (_a), (_v)) != 0) \
229 goto fail; \
230 } while (0 /* CONSTCOND */)
231 #define ATTR_STR(_a,_v) \
232 do { \
233 if (radius_put_string_attr(radpkt, (_a), (_v)) != 0) \
234 goto fail; \
235 } while (0 /* CONSTCOND */)
236
237 static int
radius_acct_request(npppd * pppd,npppd_ppp * ppp,int stop)238 radius_acct_request(npppd *pppd, npppd_ppp *ppp, int stop)
239 {
240 RADIUS_PACKET *radpkt;
241 RADIUS_REQUEST_CTX radctx;
242 radius_req_setting *rad_setting;
243 char buf[128];
244
245 if (ppp->username[0] == '\0')
246 return 0;
247
248 radpkt = NULL;
249 radctx = NULL;
250 rad_setting = npppd_auth_radius_get_radius_acct_setting(ppp->realm);
251 if (!radius_req_setting_has_server(rad_setting))
252 return 0;
253 if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST))
254 == NULL)
255 goto fail;
256
257 if (radius_prepare(rad_setting, (void *)(uintptr_t)ppp->id, &radctx,
258 npppd_ppp_radius_acct_reqcb) != 0)
259 goto fail;
260
261 /* NAS Information */
262 /*
263 * RFC 2865 "5.4. NAS-IP-Address" or RFC 3162 "2.1. NAS-IPv6-Address"
264 */
265 if (radius_prepare_nas_address(rad_setting, radpkt) != 0)
266 goto fail;
267
268 /* RFC 2865 "5.41. NAS-Port-Type" */
269 ATTR_INT32(RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL);
270
271 /* RFC 2865 "5.5. NAS-Port" */
272 ATTR_INT32(RADIUS_TYPE_NAS_PORT, ppp->id);
273 /* npppd has no physical / virtual ports in design. */
274
275 /* RFC 2865 5.32. NAS-Identifier */
276 ATTR_STR(RADIUS_TYPE_NAS_IDENTIFIER, pppd->conf.nas_id);
277
278 /* RFC 2865 5.31. Calling-Station-Id */
279 if (ppp->calling_number[0] != '\0')
280 ATTR_STR(RADIUS_TYPE_CALLING_STATION_ID, ppp->calling_number);
281
282 /* Tunnel Protocol Information */
283 switch (ppp->tunnel_type) {
284 case NPPPD_TUNNEL_L2TP:
285 /* RFC 2868 3.1. Tunnel-Type */
286 ATTR_INT32(RADIUS_TYPE_TUNNEL_TYPE, RADIUS_TUNNEL_TYPE_L2TP);
287 if (l2tp_put_tunnel_attributes(radpkt, ppp->phy_context) != 0)
288 goto fail;
289 break;
290 case NPPPD_TUNNEL_PPTP:
291 /* RFC 2868 3.1. Tunnel-Type */
292 ATTR_INT32(RADIUS_TYPE_TUNNEL_TYPE, RADIUS_TUNNEL_TYPE_PPTP);
293 if (pptp_put_tunnel_attributes(radpkt, ppp->phy_context) != 0)
294 goto fail;
295 break;
296 }
297
298 /* Framed Protocol (PPP) Information */
299 /* RFC 2865 5.1 User-Name */
300 ATTR_STR(RADIUS_TYPE_USER_NAME, ppp->username);
301
302 /* RFC 2865 "5.7. Service-Type" */
303 ATTR_INT32(RADIUS_TYPE_SERVICE_TYPE, RADIUS_SERVICE_TYPE_FRAMED);
304
305 /* RFC 2865 "5.8. Framed-Protocol" */
306 ATTR_INT32(RADIUS_TYPE_FRAMED_PROTOCOL, RADIUS_FRAMED_PROTOCOL_PPP);
307
308 /* RFC 2865 "5.8. Framed-IP-Address" */
309 if (ppp->acct_framed_ip_address.s_addr != INADDR_ANY)
310 ATTR_INT32(RADIUS_TYPE_FRAMED_IP_ADDRESS,
311 ntohl(ppp->acct_framed_ip_address.s_addr));
312
313 /* Accounting */
314 /* RFC 2866 5.1. Acct-Status-Type */
315 ATTR_INT32(RADIUS_TYPE_ACCT_STATUS_TYPE, (stop)
316 ? RADIUS_ACCT_STATUS_TYPE_STOP : RADIUS_ACCT_STATUS_TYPE_START);
317
318 /* RFC 2866 5.2. Acct-Delay-Time */
319 ATTR_INT32(RADIUS_TYPE_ACCT_DELAY_TIME, 0);
320
321 if (stop) {
322 /* RFC 2866 5.3 Acct-Input-Octets */
323 ATTR_INT32(RADIUS_TYPE_ACCT_INPUT_OCTETS,
324 (uint32_t)(ppp->ibytes & 0xFFFFFFFFU)); /* LSB 32bit */
325
326 /* RFC 2866 5.4 Acct-Output-Octets */
327 ATTR_INT32(RADIUS_TYPE_ACCT_OUTPUT_OCTETS,
328 (uint32_t)(ppp->obytes & 0xFFFFFFFFU)); /* LSB 32bit */
329 }
330
331 /* RFC 2866 5.5 Acct-Session-Id */
332 snprintf(buf, sizeof(buf), "%08X%08X", pppd->boot_id, ppp->id);
333 ATTR_STR(RADIUS_TYPE_ACCT_SESSION_ID, buf);
334
335 /* RFC 2866 5.6. Acct-Authentic */
336 ATTR_INT32(RADIUS_TYPE_ACCT_AUTHENTIC, RADIUS_ACCT_AUTHENTIC_RADIUS);
337
338 if (stop) {
339 /* RFC 2866 5.7. Acct-Session-Time */
340 ATTR_INT32(RADIUS_TYPE_ACCT_SESSION_TIME,
341 ppp->end_monotime - ppp->start_monotime);
342
343 /* RFC 2866 5.8 Acct-Input-Packets */
344 ATTR_INT32(RADIUS_TYPE_ACCT_INPUT_PACKETS, ppp->ipackets);
345
346 /* RFC 2866 5.9 Acct-Output-Packets */
347 ATTR_INT32(RADIUS_TYPE_ACCT_OUTPUT_PACKETS, ppp->opackets);
348
349 /* RFC 2866 5.10. Acct-Terminate-Cause */
350 if (ppp->terminate_cause != 0)
351 ATTR_INT32(RADIUS_TYPE_ACCT_TERMINATE_CAUSE,
352 ppp->terminate_cause);
353
354 /* RFC 2869 5.1 Acct-Input-Gigawords */
355 ATTR_INT32(RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, ppp->ibytes >> 32);
356
357 /* RFC 2869 5.2 Acct-Output-Gigawords */
358 ATTR_INT32(RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS,
359 ppp->obytes >> 32);
360 }
361
362 /* Send the request */
363 radius_request(radctx, radpkt);
364
365 return 0;
366
367 fail:
368 ppp_log(ppp, LOG_WARNING, "radius accounting request failed: %m");
369
370 if (radctx != NULL)
371 radius_cancel_request(radctx);
372 if (radpkt != NULL)
373 radius_delete_packet(radpkt);
374
375 return -1;
376 }
377
378 void
radius_acct_on(npppd * pppd,radius_req_setting * rad_setting)379 radius_acct_on(npppd *pppd, radius_req_setting *rad_setting)
380 {
381 RADIUS_REQUEST_CTX radctx = NULL;
382 RADIUS_PACKET *radpkt = NULL;
383
384 if (!radius_req_setting_has_server(rad_setting))
385 return;
386 if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST))
387 == NULL)
388 goto fail;
389
390 if (radius_prepare(rad_setting, NULL, &radctx, radius_acct_on_cb) != 0)
391 goto fail;
392
393 /*
394 * RFC 2865 "5.4. NAS-IP-Address" or RFC 3162 "2.1. NAS-IPv6-Address"
395 */
396 if (radius_prepare_nas_address(rad_setting, radpkt) != 0)
397 goto fail;
398
399 /* RFC 2865 "5.41. NAS-Port-Type" */
400 ATTR_INT32(RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL);
401
402 /* RFC 2866 5.1. Acct-Status-Type */
403 ATTR_INT32(RADIUS_TYPE_ACCT_STATUS_TYPE, RADIUS_ACCT_STATUS_TYPE_ACCT_ON);
404 /* RFC 2865 5.32. NAS-Identifier */
405 ATTR_STR(RADIUS_TYPE_NAS_IDENTIFIER, pppd->conf.nas_id);
406
407 /* Send the request */
408 radius_request(radctx, radpkt);
409
410 return;
411 fail:
412 if (radctx != NULL)
413 radius_cancel_request(radctx);
414 if (radpkt != NULL)
415 radius_delete_packet(radpkt);
416 }
417
418 static void
radius_acct_on_cb(void * context,RADIUS_PACKET * pkt,int flags,RADIUS_REQUEST_CTX ctx)419 radius_acct_on_cb(void *context, RADIUS_PACKET *pkt, int flags,
420 RADIUS_REQUEST_CTX ctx)
421 {
422 if ((flags & (RADIUS_REQUEST_TIMEOUT | RADIUS_REQUEST_ERROR)) != 0)
423 radius_request_failover(ctx);
424 }
425
426 #ifdef USE_NPPPD_PPTP
427 #include "pptp.h"
428 #endif
429
430 static int
pptp_put_tunnel_attributes(RADIUS_PACKET * radpkt,void * call0)431 pptp_put_tunnel_attributes(RADIUS_PACKET *radpkt, void *call0)
432 {
433 #ifdef USE_NPPPD_PPTP
434 pptp_call *call = call0;
435 pptp_ctrl *ctrl;
436 char hbuf[NI_MAXHOST], buf[128];
437
438 ctrl = call->ctrl;
439
440 /* RFC 2868 3.2. Tunnel-Medium-Type */
441 switch (ctrl->peer.ss_family) {
442 case AF_INET:
443 ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE,
444 RADIUS_TUNNEL_MEDIUM_TYPE_IPV4);
445 break;
446
447 case AF_INET6:
448 ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE,
449 RADIUS_TUNNEL_MEDIUM_TYPE_IPV6);
450 break;
451
452 default:
453 return -1;
454 }
455
456 /* RFC 2868 3.3. Tunnel-Client-Endpoint */
457 if (getnameinfo((struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf,
458 sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
459 return 1;
460 ATTR_STR(RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, hbuf);
461
462 /* RFC 2868 3.4. Tunnel-Server-Endpoint */
463 if (getnameinfo((struct sockaddr *)&ctrl->our, ctrl->our.ss_len, hbuf,
464 sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
465 return 1;
466 ATTR_STR(RADIUS_TYPE_TUNNEL_SERVER_ENDPOINT, hbuf);
467
468 /* RFC 2868 3.7. Tunnel-Assignment-ID */
469 snprintf(buf, sizeof(buf), "PPTP-CALL-%d", call->id);
470 ATTR_STR(RADIUS_TYPE_TUNNEL_ASSIGNMENT_ID, buf);
471
472 /* RFC 2867 4.1. Acct-Tunnel-Connection */
473 snprintf(buf, sizeof(buf), "PPTP-CTRL-%d", ctrl->id);
474 ATTR_STR(RADIUS_TYPE_ACCT_TUNNEL_CONNECTION, buf);
475
476 return 0;
477 fail:
478 #endif
479 return 1;
480 }
481
482 #ifdef USE_NPPPD_L2TP
483 #include "l2tp.h"
484 #endif
485
486 static int
l2tp_put_tunnel_attributes(RADIUS_PACKET * radpkt,void * call0)487 l2tp_put_tunnel_attributes(RADIUS_PACKET *radpkt, void *call0)
488 {
489 #ifdef USE_NPPPD_L2TP
490 l2tp_call *call = call0;
491 l2tp_ctrl *ctrl;
492 char hbuf[NI_MAXHOST], buf[128];
493
494 ctrl = call->ctrl;
495
496 /* RFC 2868 3.2. Tunnel-Medium-Type */
497 switch (ctrl->peer.ss_family) {
498 case AF_INET:
499 ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE,
500 RADIUS_TUNNEL_MEDIUM_TYPE_IPV4);
501 break;
502
503 case AF_INET6:
504 ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE,
505 RADIUS_TUNNEL_MEDIUM_TYPE_IPV6);
506 break;
507
508 default:
509 return -1;
510 }
511
512 /* RFC 2868 3.3. Tunnel-Client-Endpoint */
513 if (getnameinfo((struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf,
514 sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
515 return 1;
516 ATTR_STR(RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, hbuf);
517
518 /* RFC 2868 3.4. Tunnel-Server-Endpoint */
519 if (getnameinfo((struct sockaddr *)&ctrl->sock, ctrl->sock.ss_len, hbuf,
520 sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
521 return 1;
522 ATTR_STR(RADIUS_TYPE_TUNNEL_SERVER_ENDPOINT, hbuf);
523
524 /* RFC 2868 3.7. Tunnel-Assignment-ID */
525 snprintf(buf, sizeof(buf), "L2TP-CALL-%d", call->id);
526 ATTR_STR(RADIUS_TYPE_TUNNEL_ASSIGNMENT_ID, buf);
527
528 /* RFC 2867 4.1. Acct-Tunnel-Connection */
529 snprintf(buf, sizeof(buf), "L2TP-CTRL-%d", ctrl->id);
530 ATTR_STR(RADIUS_TYPE_ACCT_TUNNEL_CONNECTION, buf);
531
532 return 0;
533 fail:
534 #endif
535 return 1;
536 }
537
538 /**
539 * Set RADIUS attributes for RADIUS authentication request.
540 * Return 0 on success.
541 */
542 int
ppp_set_radius_attrs_for_authreq(npppd_ppp * _this,radius_req_setting * rad_setting,RADIUS_PACKET * radpkt)543 ppp_set_radius_attrs_for_authreq(npppd_ppp *_this,
544 radius_req_setting *rad_setting, RADIUS_PACKET *radpkt)
545 {
546 /* RFC 2865 "5.4 NAS-IP-Address" or RFC3162 "2.1. NAS-IPv6-Address" */
547 if (radius_prepare_nas_address(rad_setting, radpkt) != 0)
548 goto fail;
549
550 /* RFC 2865 "5.6. Service-Type" */
551 if (radius_put_uint32_attr(radpkt, RADIUS_TYPE_SERVICE_TYPE,
552 RADIUS_SERVICE_TYPE_FRAMED) != 0)
553 goto fail;
554
555 /* RFC 2865 "5.7. Framed-Protocol" */
556 if (radius_put_uint32_attr(radpkt, RADIUS_TYPE_FRAMED_PROTOCOL,
557 RADIUS_FRAMED_PROTOCOL_PPP) != 0)
558 goto fail;
559
560 if (_this->calling_number[0] != '\0') {
561 if (radius_put_string_attr(radpkt,
562 RADIUS_TYPE_CALLING_STATION_ID, _this->calling_number) != 0)
563 return 1;
564 }
565 return 0;
566 fail:
567 return 1;
568 }
569
570 /***********************************************************************
571 * Dynamic Authorization Extensions for RADIUS
572 ***********************************************************************/
573 static int npppd_radius_dae_listen_start(struct npppd_radius_dae_listen *);
574 static void npppd_radius_dae_on_event(int, short, void *);
575 static void npppd_radius_dae_listen_stop(struct npppd_radius_dae_listen *);
576
577 void
npppd_radius_dae_init(npppd * _this)578 npppd_radius_dae_init(npppd *_this)
579 {
580 struct npppd_radius_dae_listens listens;
581 struct npppd_radius_dae_listen *listen, *listent;
582 struct radlistenconf *listenconf;
583
584 TAILQ_INIT(&listens);
585
586 TAILQ_FOREACH(listenconf, &_this->conf.raddaelistenconfs, entry) {
587 TAILQ_FOREACH_SAFE(listen, &_this->raddae_listens, entry,
588 listent) {
589 if ((listen->addr.sin4.sin_family == AF_INET &&
590 listenconf->addr.sin4.sin_family == AF_INET &&
591 memcmp(&listen->addr.sin4, &listenconf->addr.sin4,
592 sizeof(struct sockaddr_in)) == 0) ||
593 (listen->addr.sin6.sin6_family == AF_INET6 &&
594 listenconf->addr.sin6.sin6_family == AF_INET6 &&
595 memcmp(&listen->addr.sin6, &listenconf->addr.sin6,
596 sizeof(struct sockaddr_in6)) == 0))
597 break;
598 }
599 if (listen != NULL)
600 /* keep using this */
601 TAILQ_REMOVE(&_this->raddae_listens, listen, entry);
602 else {
603 if ((listen = calloc(1, sizeof(*listen))) == NULL) {
604 log_printf(LOG_ERR, "%s: calloc failed: %m",
605 __func__);
606 goto fail;
607 }
608 listen->pppd = _this;
609 listen->sock = -1;
610 if (listenconf->addr.sin4.sin_family == AF_INET)
611 listen->addr.sin4 = listenconf->addr.sin4;
612 else
613 listen->addr.sin6 = listenconf->addr.sin6;
614 }
615 TAILQ_INSERT_TAIL(&listens, listen, entry);
616 }
617
618 /* listen on the new addresses */
619 TAILQ_FOREACH(listen, &listens, entry) {
620 if (listen->sock == -1)
621 npppd_radius_dae_listen_start(listen);
622 }
623
624 /* stop listening on the old addresses */
625 TAILQ_FOREACH_SAFE(listen, &_this->raddae_listens, entry, listent) {
626 TAILQ_REMOVE(&_this->raddae_listens, listen, entry);
627 npppd_radius_dae_listen_stop(listen);
628 free(listen);
629 }
630 fail:
631 TAILQ_CONCAT(&_this->raddae_listens, &listens, entry);
632
633 return;
634 }
635
636 void
npppd_radius_dae_fini(npppd * _this)637 npppd_radius_dae_fini(npppd *_this)
638 {
639 struct npppd_radius_dae_listen *listen, *listent;
640
641 TAILQ_FOREACH_SAFE(listen, &_this->raddae_listens, entry, listent) {
642 TAILQ_REMOVE(&_this->raddae_listens, listen, entry);
643 npppd_radius_dae_listen_stop(listen);
644 free(listen);
645 }
646 }
647
648 int
npppd_radius_dae_listen_start(struct npppd_radius_dae_listen * listen)649 npppd_radius_dae_listen_start(struct npppd_radius_dae_listen *listen)
650 {
651 char buf[80];
652 int sock = -1, on = 1;
653
654 if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
655 log_printf(LOG_ERR, "%s: socket(): %m", __func__);
656 goto on_error;
657 }
658 on = 1;
659 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) {
660 log_printf(LOG_WARNING, "%s: setsockopt(,,SO_REUSEADDR): %m",
661 __func__);
662 goto on_error;
663 }
664 if (bind(sock, (struct sockaddr *)&listen->addr,
665 listen->addr.sin4.sin_len) == -1) {
666 log_printf(LOG_ERR, "%s: bind(): %m", __func__);
667 goto on_error;
668 }
669
670 listen->sock = sock;
671 event_set(&listen->evsock, listen->sock, EV_READ | EV_PERSIST,
672 npppd_radius_dae_on_event, listen);
673 event_add(&listen->evsock, NULL);
674 log_printf(LOG_INFO, "radius Listening %s/udp (DAE)",
675 addrport_tostring((struct sockaddr *)&listen->addr,
676 listen->addr.sin4.sin_len, buf, sizeof(buf)));
677
678 return (0);
679 on_error:
680 if (sock >= 0)
681 close(sock);
682
683 return (-1);
684 }
685
686 void
npppd_radius_dae_on_event(int fd,short ev,void * ctx)687 npppd_radius_dae_on_event(int fd, short ev, void *ctx)
688 {
689 char buf[80], attr[256], username[256];
690 char *endp;
691 const char *reason, *nakcause = NULL;
692 struct npppd_radius_dae_listen *listen = ctx;
693 struct radclientconf *client;
694 npppd *_this = listen->pppd;
695 RADIUS_PACKET *req = NULL, *res = NULL;
696 struct sockaddr_storage ss;
697 socklen_t sslen;
698 unsigned long long ppp_id;
699 int code, n = 0;
700 uint32_t cause = 0;
701 struct in_addr ina;
702 slist *users;
703 npppd_ppp *ppp;
704
705 reason = "disconnect requested";
706 sslen = sizeof(ss);
707 req = radius_recvfrom(listen->sock, 0, (struct sockaddr *)&ss, &sslen);
708 if (req == NULL) {
709 log_printf(LOG_WARNING, "%s: receiving a RADIUS message "
710 "failed: %m", __func__);
711 return;
712 }
713 TAILQ_FOREACH(client, &_this->conf.raddaeclientconfs, entry) {
714 if (ss.ss_family == AF_INET &&
715 ((struct sockaddr_in *)&ss)->sin_addr.s_addr ==
716 client->addr.sin4.sin_addr.s_addr)
717 break;
718 else if (ss.ss_family == AF_INET6 &&
719 IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *)&ss)->sin6_addr,
720 &client->addr.sin6.sin6_addr))
721 break;
722 }
723
724 if (client == NULL) {
725 log_printf(LOG_WARNING, "radius received a RADIUS message from "
726 "%s: unknown client", addrport_tostring(
727 (struct sockaddr *)&ss, ss.ss_len, buf, sizeof(buf)));
728 goto out;
729 }
730
731 if (radius_check_accounting_request_authenticator(req,
732 client->secret) != 0) {
733 log_printf(LOG_WARNING, "radius received an invalid RADIUS "
734 "message from %s: bad response authenticator",
735 addrport_tostring(
736 (struct sockaddr *)&ss, ss.ss_len, buf, sizeof(buf)));
737 goto out;
738 }
739 if ((code = radius_get_code(req)) != RADIUS_CODE_DISCONNECT_REQUEST) {
740 /* Code other than Disconnect-Request is not supported */
741 if (code == RADIUS_CODE_COA_REQUEST) {
742 code = RADIUS_CODE_COA_NAK;
743 cause = RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED;
744 nakcause = "Coa-Request is not supported";
745 goto send;
746 }
747 log_printf(LOG_WARNING, "radius received an invalid RADIUS "
748 "message from %s: unknown code %d",
749 addrport_tostring((struct sockaddr *)&ss, ss.ss_len, buf,
750 sizeof(buf)), code);
751 goto out;
752 }
753
754 log_printf(LOG_INFO, "radius received Disconnect-Request from %s",
755 addrport_tostring((struct sockaddr *)&ss, ss.ss_len, buf,
756 sizeof(buf)));
757
758 if (radius_get_string_attr(req, RADIUS_TYPE_NAS_IDENTIFIER, attr,
759 sizeof(attr)) == 0 && strcmp(attr, _this->conf.nas_id) != 0) {
760 cause = RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH;
761 nakcause = "NAS Identifier is not matched";
762 goto search_done;
763 }
764
765 /* prepare User-Name attribute */
766 memset(username, 0, sizeof(username));
767 radius_get_string_attr(req, RADIUS_TYPE_USER_NAME, username,
768 sizeof(username));
769
770 /* Our Session-Id is represented in "%08X%08x" (boot_id, ppp_id) */
771 snprintf(buf, sizeof(buf), "%08X", _this->boot_id);
772 if (radius_get_string_attr(req, RADIUS_TYPE_ACCT_SESSION_ID, attr,
773 sizeof(attr)) == 0) {
774 ppp = NULL;
775 /* the client is to disconnect a session */
776 if (strlen(attr) != 16 || strncmp(buf, attr, 8) != 0) {
777 cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
778 nakcause = "Session-Id is wrong";
779 goto search_done;
780 }
781 ppp_id = strtoull(attr + 8, &endp, 16);
782 if (*endp != '\0' || errno == ERANGE || ppp_id == ULLONG_MAX) {
783 cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
784 nakcause = "Session-Id is invalid";
785 goto search_done;
786 }
787 if ((ppp = npppd_get_ppp_by_id(_this, ppp_id)) == NULL)
788 goto search_done;
789 if (username[0] != '\0' &&
790 strcmp(username, ppp->username) != 0) {
791 /* specified User-Name attribute is mismatched */
792 cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
793 nakcause = "User-Name is not matched";
794 goto search_done;
795 }
796 ppp_stop(ppp, reason);
797 n++;
798 } else if (username[0] != '\0') {
799 users = npppd_get_ppp_by_user(_this, username);
800 if (users == NULL)
801 goto search_done;
802 memset(&ina, 0, sizeof(ina));
803 radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS,
804 &ina.s_addr);
805 slist_itr_first(users);
806 while ((ppp = slist_itr_next(users)) != NULL) {
807 if (ntohl(ina.s_addr) != 0 &&
808 ina.s_addr != ppp->ppp_framed_ip_address.s_addr)
809 continue;
810 ppp_stop(ppp, reason);
811 n++;
812 }
813 } else if (radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS,
814 &ina.s_addr) == 0) {
815 ppp = npppd_get_ppp_by_ip(_this, ina);
816 if (ppp != NULL) {
817 ppp_stop(ppp, reason);
818 n++;
819 }
820 }
821 search_done:
822 if (n > 0)
823 code = RADIUS_CODE_DISCONNECT_ACK;
824 else {
825 if (nakcause == NULL)
826 nakcause = "session not found";
827 if (cause == 0)
828 cause = RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND;
829 code = RADIUS_CODE_DISCONNECT_NAK;
830 }
831 send:
832 res = radius_new_response_packet(code, req);
833 if (res == NULL) {
834 log_printf(LOG_WARNING, "%s: radius_new_response_packet: %m",
835 __func__);
836 goto out;
837 }
838 if (cause != 0)
839 radius_put_uint32_attr(res, RADIUS_TYPE_ERROR_CAUSE, cause);
840 radius_set_response_authenticator(res, client->secret);
841 if (radius_sendto(listen->sock, res, 0, (struct sockaddr *)&ss, sslen)
842 == -1)
843 log_printf(LOG_WARNING, "%s: sendto(): %m", __func__);
844 log_printf(LOG_INFO, "radius send %s to %s%s%s",
845 (code == RADIUS_CODE_DISCONNECT_ACK)? "Disconnect-ACK" :
846 (code == RADIUS_CODE_DISCONNECT_NAK)? "Disconnect-NAK" : "CoA-NAK",
847 addrport_tostring((struct sockaddr *)&ss, ss.ss_len, buf,
848 sizeof(buf)), (nakcause)? ": " : "", (nakcause)? nakcause : "");
849 out:
850 radius_delete_packet(req);
851 if (res != NULL)
852 radius_delete_packet(res);
853 }
854
855 void
npppd_radius_dae_listen_stop(struct npppd_radius_dae_listen * listen)856 npppd_radius_dae_listen_stop(struct npppd_radius_dae_listen *listen)
857 {
858 char buf[80];
859
860 if (listen->sock >= 0) {
861 log_printf(LOG_INFO, "radius Shutdown %s/udp (DAE)",
862 addrport_tostring((struct sockaddr *)&listen->addr,
863 listen->addr.sin4.sin_len, buf, sizeof(buf)));
864 event_del(&listen->evsock);
865 close(listen->sock);
866 listen->sock = -1;
867 }
868 }
869