xref: /openbsd/usr.sbin/npppd/npppd/npppd_radius.c (revision e79d315b)
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