diff options
author | YASUOKA Masahiko <yasuoka@cvs.openbsd.org> | 2011-07-06 20:52:29 +0000 |
---|---|---|
committer | YASUOKA Masahiko <yasuoka@cvs.openbsd.org> | 2011-07-06 20:52:29 +0000 |
commit | 71439565dc13acd0c12565c5ffe0070c15a31cb8 (patch) | |
tree | 17fd5e40db40780fd57bab6971fbf17c07e50f98 /usr.sbin/npppd | |
parent | bc9b906bf38e2c685a6c283bb2b36af90689a981 (diff) |
Add RADIUS accounting support and some authentication related changes:
- Add functions to radius+.c that are required to implement RADIUS
accounting.
- Send RADIUS Account-Start and Account-Stop messages with attributes that
are defined by RFC 2866, 2868, 2869.
- If any authentication realm is deleted from the configuration, npppd may
exit by segmentation fault.
- Delete radius_common.c, radius_common.h and eap.c because they are not
used.
- Retransmission and failover are reimplemented.
- Cleanup
Diffstat (limited to 'usr.sbin/npppd')
24 files changed, 1307 insertions, 1377 deletions
diff --git a/usr.sbin/npppd/HOWTO_PIPEX_NPPPD.txt b/usr.sbin/npppd/HOWTO_PIPEX_NPPPD.txt index 986dee38ebe..58ab59329a1 100644 --- a/usr.sbin/npppd/HOWTO_PIPEX_NPPPD.txt +++ b/usr.sbin/npppd/HOWTO_PIPEX_NPPPD.txt @@ -1,4 +1,4 @@ -$Id: HOWTO_PIPEX_NPPPD.txt,v 1.3 2010/09/26 06:54:44 yasuoka Exp $ +$Id: HOWTO_PIPEX_NPPPD.txt,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ How to test npppd and pipex --------------------------- @@ -88,7 +88,7 @@ How to test L2TP/IPsec # # Simplest npppd.conf sample # -# $Id: HOWTO_PIPEX_NPPPD.txt,v 1.3 2010/09/26 06:54:44 yasuoka Exp $ +# $Id: HOWTO_PIPEX_NPPPD.txt,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ interface_list: tun0 interface.tun0.ip4addr: 10.0.0.1 @@ -97,11 +97,19 @@ interface.tun0.ip4addr: 10.0.0.1 pool.dyna_pool: 10.0.0.0/25 pool.pool: 10.0.0.128/25 -# Authentication +# Local file authentication auth.local.realm_list: local auth.local.realm.acctlist: /etc/npppd/npppd-users.csv realm.local.concentrate: tun0 +# RADIUS authentication / accounting +#auth.radius.realm_list: radius +#auth.radius.realm.server.address: 127.0.0.1:1812 +#auth.radius.realm.server.secret: hogehoge +#auth.radius.realm.acct_server.address: 127.0.0.1:1813 +#auth.radius.realm.acct_server.secret: hogehoge +#realm.radius.concentrate: tun0 + lcp.mru: 1400 auth.method: mschapv2 chap #auth.method: mschapv2 chap pap diff --git a/usr.sbin/npppd/npppd/Makefile b/usr.sbin/npppd/npppd/Makefile index cae2ef7f1f6..647cd0cf6cd 100644 --- a/usr.sbin/npppd/npppd/Makefile +++ b/usr.sbin/npppd/npppd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.7 2010/09/23 01:45:10 jsg Exp $ +# $OpenBSD: Makefile,v 1.8 2011/07/06 20:52:28 yasuoka Exp $ NPPPD_COMMON_DIR= ${.CURDIR}/../common @@ -7,12 +7,12 @@ NOMAN= noman #MAN= npppd.8 npppd.conf.5 npppd-users.csv.5 CPPFLAGS+= -I${NPPPD_COMMON_DIR} -I${.CURDIR} SRCS= ccp.c chap.c chap_ms.c fsm.c ipcp.c lcp.c -SRCS+= mppe.c pap.c ppp.c radius_req.c +SRCS+= mppe.c pap.c ppp.c SRCS+= npppd.c npppd_config.c npppd_subr.c npppd_auth.c npppd_iface.c SRCS+= config_helper.c slist.c hash.c properties.c rtev_common.c SRCS+= rtev_libevent.c bytebuf.c debugutil.c csvreader.c net_utils.c SRCS+= radish.c time_utils.c npppd_pool.c addr_range.c -SRCS+= radius+.c +SRCS+= radius+.c radius_req.c npppd_radius.c SRCS+= recvfromto.c SRCS+= privsep.c #SRCS+= ipsec_util.c @@ -32,8 +32,6 @@ CPPFLAGS+= -DUSE_NPPPD_PPPOE -I${.CURDIR}/../pppoe SRCS+= pppoe_session.c pppoed.c .PATH: ${.CURDIR}/../pppoe -#SRCS+= eap.c radius_common.c - CPPFLAGS+= -D__COPYRIGHT\(x\)= -D__RCSID\(x\)= CPPFLAGS+= -DUSE_NPPPD_MPPE CPPFLAGS+= -DUSE_NPPPD_PIPEX diff --git a/usr.sbin/npppd/npppd/chap.c b/usr.sbin/npppd/npppd/chap.c index fdd9774f81f..bb6fd991ef3 100644 --- a/usr.sbin/npppd/npppd/chap.c +++ b/usr.sbin/npppd/npppd/chap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chap.c,v 1.4 2010/09/22 11:48:38 yasuoka Exp $ */ +/* $OpenBSD: chap.c,v 1.5 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -36,7 +36,7 @@ * </ul></p> */ /* RFC 1994, 2433 */ -/* $Id: chap.c,v 1.4 2010/09/22 11:48:38 yasuoka Exp $ */ +/* $Id: chap.c,v 1.5 2011/07/06 20:52:28 yasuoka Exp $ */ #include <sys/types.h> #include <sys/param.h> #include <sys/socket.h> @@ -49,6 +49,7 @@ #include <string.h> #include <unistd.h> #include <stdarg.h> +#include <errno.h> #include <time.h> #include <event.h> #include <md5.h> @@ -59,6 +60,7 @@ #ifdef USE_NPPPD_RADIUS #include "radius_chap_const.h" +#include "npppd_radius.h" #endif #include "npppd_defs.h" @@ -118,7 +120,7 @@ static void mschapv2_send_error (chap *, int, int); static void mschapv2_authenticate (chap *, int, char *, u_char *, int, u_char *); #ifdef USE_NPPPD_RADIUS static void chap_radius_authenticate (chap *, int, char *, u_char *, int, u_char *); -static void chap_radius_response (void *, RADIUS_PACKET *, int); +static void chap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX); #endif static char *strip_nt_domain (char *); static void chap_log (chap *, uint32_t, const char *, ...) __printflike(3,4); @@ -176,10 +178,10 @@ chap_start(chap *_this) chap_log(_this, LOG_ALERT, "Requested authentication type(0x%x) " "is not supported.", _this->type); - ppp_stop_ex(_this->ppp, - "Authentication Required", + ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, PPP_PROTO_CHAP, 2 /* local */, NULL); + ppp_stop(_this->ppp, "Authentication Required"); return; } @@ -191,10 +193,10 @@ chap_start(chap *_this) chap_log(_this, LOG_ALERT, "mppe is required but try to start chap " "type=0x%02x", _this->type); - ppp_stop_ex(_this->ppp, - "Authentication Required", + ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, PPP_PROTO_CHAP, 2 /* local */, NULL); + ppp_stop(_this->ppp, "Authentication Required"); return; } #endif @@ -226,9 +228,10 @@ chap_start(chap *_this) } else { chap_log(_this, LOG_INFO, "Client did't respond our challenage."); - ppp_stop_ex(_this->ppp, "Authentication Required", + ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_FSM_TIMEOUT, PPP_PROTO_CHAP, 0, NULL); + ppp_stop(_this->ppp, "Authentication Required"); } } } @@ -440,8 +443,9 @@ chap_response(chap *_this, int authok, u_char *pktp, int lpktp) realm_name); chap_stop(_this); /* Stop the PPP if the authentication is failed. */ - ppp_stop_ex(_this->ppp, "Authentication Required", + ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_FAILED, PPP_PROTO_CHAP, 1 /* peer */, NULL); + ppp_stop(_this->ppp, "Authentication Required"); } else { strlcpy(_this->ppp->username, _this->name, sizeof(_this->ppp->username)); @@ -746,7 +750,7 @@ chap_radius_authenticate(chap *_this, int id, char *username, radpkt = NULL; radctx = NULL; - if ((rad_setting = npppd_get_radius_req_setting(_this->ppp->pppd, + if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd, _this->ppp)) == NULL) { goto fail; /* no radius server */ } @@ -835,7 +839,8 @@ fail: } static void -chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags) +chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags, + RADIUS_REQUEST_CTX reqctx) { int code, lrespkt; const char *secret, *reason = ""; @@ -857,15 +862,12 @@ chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags) + HEADERLEN; lrespkt = _this->ppp->mru - HEADERLEN; if (pkt == NULL) { - if (flags & RADIUS_REQUST_TIMEOUT) { + if (flags & RADIUS_REQUEST_TIMEOUT) reason = "timeout"; - npppd_radius_server_failure_notify(_this->ppp->pppd, - _this->ppp, radctx, "request timeout"); - } else { + else if (flags & RADIUS_REQUEST_ERROR) + reason = strerror(errno); + else reason = "error"; - npppd_radius_server_failure_notify(_this->ppp->pppd, - _this->ppp, radctx, "unknown error"); - } goto auth_failed; } @@ -879,11 +881,9 @@ chap_radius_response(void *context, RADIUS_PACKET *pkt, int flags) reason="error"; goto auth_failed; } - if ((flags & RADIUS_REQUST_CHECK_AUTHENTICTOR_OK) == 0 && - (flags & RADIUS_REQUST_CHECK_AUTHENTICTOR_NO_CHECK) == 0) { + if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 && + (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) { reason="bad_authenticator"; - npppd_radius_server_failure_notify(_this->ppp->pppd, _this->ppp, - radctx, "bad authenticator"); goto auth_failed; } /* diff --git a/usr.sbin/npppd/npppd/eap.c b/usr.sbin/npppd/npppd/eap.c index 1de8875d53f..e69de29bb2d 100644 --- a/usr.sbin/npppd/npppd/eap.c +++ b/usr.sbin/npppd/npppd/eap.c @@ -1,971 +0,0 @@ -/* $OpenBSD: eap.c,v 1.6 2011/01/20 23:12:33 jasper Exp $ */ - -/*- - * Copyright (c) 2009 Internet Initiative Japan Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -/**@file - * This file provides EAP(Extensible Authentication Protocols, RFC 3748) - * handlers. This currently provides only EAP Pass-through Authenticator. - * @see RFC3748 - * Extensible Authentication Protocols(EAP) - * @see RFC3579 - * RADIUS (Remote Authentication Dial In User Service) Support For - * Extensible Authentication Protocol (EAP). B. Aboba, P. Calhoun. - */ -/* $Id: eap.c,v 1.6 2011/01/20 23:12:33 jasper Exp $ */ - -/* FIXME: This must be rewritten. */ - -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <netinet/in.h> -#include <net/if_dl.h> -#include <stdlib.h> -#include <stdio.h> -#include <syslog.h> -#include <string.h> -#include <unistd.h> -#include <stdarg.h> -#include <time.h> -#include <event.h> - -#ifdef USE_NPPPD_RADIUS -#include <radius+.h> -#include <radiusconst.h> -#endif - -#include "debugutil.h" -#ifdef USE_NPPPD_RADIUS -#include "radius_chap_const.h" -#endif -#include "npppd_local.h" -#include "chap_ms.h" - -/* initital state */ -#define EAP_STATE_INITIAL 1 -#define EAP_STATE_SEND_REQUEST_TO_PEER 2 -#define EAP_STATE_STOPPED 3 - -#define EAP_HEADERLEN 4 - -#define EAP_TIMEOUT_INIT 3 /* Initial retry internval */ -#define EAP_TIMEOUT_MAX 20 /* Maximum retry internval */ -#define EAP_RETRY 4 /* Number of retry */ - -#define EAP_REQUEST 1 -#define EAP_RESPONSE 2 -#define EAP_SUCCESS 3 -#define EAP_FAILURE 4 - -/* MprError.h */ -#define ERROR_AUTH_SERVER_TIMEOUT 930 - -#define EAP_DEBUG -#ifdef EAP_DEBUG -#define EAP_DBG(x) eap_log x -#define EAP_ASSERT(cond) \ - if (!(cond)) { \ - fprintf(stderr, \ - "\nASSERT(" #cond ") failed on %s() at %s:%d.\n"\ - , __func__, __FILE__, __LINE__); \ - abort(); \ - } -#else -#define EAP_ASSERT(cond) -#define EAP_DBG(x) -#endif - -#define TMPBUF 256 -#define IDENT_STRING "What your name?" -#define TIMER_CBFUNC void(*)(void *) - -#define INIT_EAPID 1 - -static void eap_restart(eap *_this); -static void eap_forward_to_radius(eap *_this, u_int8_t *data, int datalen); -static void eap_recv_from_radius(void *context, RADIUS_PACKET *pkt, int flags); -static int eap_forward_to_peer(eap *_this, u_int8_t *data, int datalen, int type, u_int8_t id); -static void eap_log(eap *_this, uint32_t prio, const char *fmt, ...) __printflike(3,4); -#ifdef USE_NPPPD_MPPE -static int get_mppe_keys(eap *_this, RADIUS_PACKET *pkt, const char *secret); -#endif - -/** Initialize the EAP */ -void -eap_init(eap *_this, npppd_ppp *ppp) -{ - EAP_ASSERT(ppp != NULL); - EAP_ASSERT(_this != NULL); - /* initiallize */ - memset(_this, 0, sizeof(eap)); - _this->ntry = EAP_RETRY; - _this->ppp = ppp; - _this->state = EAP_STATE_INITIAL; -} - -/** Start the EAP as a authenticator. Send a identity request */ -void -eap_start(eap *_this) -{ - u_int8_t *req,*req0; - int len; - - EAP_ASSERT(_this != NULL); - EAP_ASSERT(_this->ppp != NULL); - - /* - * initialize for timeout callback - */ - _this->name_len = 0; - memset(_this->name, 0, sizeof(_this->name)); - _this->attr_state_len = 0; - memset(_this->attr_state, 0, RADIUS_ATTR_STATE_LEN); - - if (_this->state == EAP_STATE_INITIAL || - _this->state == EAP_STATE_SEND_REQUEST_TO_PEER){ - if (_this->ntry > 0) { - _this->ntry--; - - /* eap header - * code: 1 (request) [1 byte] - * ID: 0x01 (sequence) [1 byte] - * length: ? [2 byte] - */ - - /* - * type: Identity [1 byte] - * data: data [ ? ] - */ - - req = ppp_packetbuf(_this->ppp, PPP_AUTH_EAP); - req += PPP_HDRLEN; - req0 = req; - - PUTCHAR(PPP_AUTH_EAP_IDENTITY, req); - BCOPY(IDENT_STRING, req, (len = strlen(IDENT_STRING))); - req += strlen(IDENT_STRING); - - if (_this->eapid == 0) - _this->eapid = INIT_EAPID; - else - _this->eapid++; - - /* - * send eap request - */ - ppp_output(_this->ppp, PPP_PROTO_EAP, EAP_REQUEST, - _this->eapid, req0, req - req0); - _this->state = EAP_STATE_SEND_REQUEST_TO_PEER; - - TIMEOUT((TIMER_CBFUNC)eap_restart, _this, - EAP_TIMEOUT_INIT); - } else { - eap_log(_this, LOG_NOTICE, - "Client didn't respond our EAP request"); - eap_stop(_this); - ppp_stop(_this->ppp, "Authentication Required"); - } - } -} - -void -eap_restart(eap *_this) { - if (_this == NULL) { - log_printf(LOG_INFO, "Failed restart authentication, " - "already peer session closed with eap"); - return; - } - - eap_log(_this, LOG_INFO, "Retry authentication"); - _this->name_len = 0; - _this->attr_state_len = 0; - memset(_this->name, 0, sizeof(_this->name)); - memset(_this->attr_state, 0, sizeof(_this->attr_state)); - if (_this->radctx != NULL) - radius_cancel_request(_this->radctx); - - eap_start(_this); -} - -void -eap_input(eap *_this, unsigned char *pktp, int len){ - u_int8_t *pkthp; - int code, id, length, type; - - if (_this->state == EAP_STATE_INITIAL || - _this->state == EAP_STATE_STOPPED) { - eap_log(_this, LOG_INFO, "Received eap packet. But eap is " - "not started"); - return; - } - pkthp = pktp; - - UNTIMEOUT(eap_restart, _this); - - if(len < EAP_HEADERLEN + 1){ - /* discard */ - eap_log(_this, LOG_NOTICE, "Packet has unexpect length"); - return; - } - - GETCHAR(code, pkthp); - if (code == EAP_FAILURE) { - /* discard */ - eap_log(_this, LOG_NOTICE, - "Received unexpected packet from peer (code = %d)", code); - return; - } - - GETCHAR(id, pkthp); - if (id != _this->eapid) { - /* discard */ - eap_log(_this, LOG_NOTICE, - "Not match EAP identifier (request = %d, response = %d)", - _this->eapid, id); - return; - } - - /* - * get user name from itentity response - */ - GETSHORT(length, pkthp); - GETCHAR(type, pkthp); - if (type == PPP_AUTH_EAP_IDENTITY && _this->name_len == 0) { - if (length != len) { - /* discard */ - eap_log(_this, LOG_NOTICE, - "Identity packet has Invalid length"); - return; - } else { - _this->name_len = length - ( EAP_HEADERLEN + 1 ); - if (_this->name_len <= MAX_USERNAME_LENGTH) { - memcpy(_this->name, pkthp, _this->name_len); - _this->name[_this->name_len] = '\0'; - } else { - /* discard */ - _this->name_len = 0; - eap_log(_this, LOG_ERR, - "Identity name is too long"); - return; - } - } - } - - if (type == PPP_AUTH_EAP_NAK){ - /* - * Nak check - */ - _this->flags |= PPP_EAP_FLAG_NAK_RESPONSE; - eap_log(_this, LOG_DEBUG, "peer response is nak"); - } - - if(_this->name_len != 0){ - eap_forward_to_radius(_this, pktp, len); - return; - } - - /* unexpected process - * discard - */ - eap_log(_this, LOG_DEBUG, - "receive eap length = %d, " - "eap info: code = %d, id = %d, length = %d, type = %d, " - "name length = %d", - len, code, id, length, type, _this->name_len ); - eap_log(_this, LOG_NOTICE, "Received unexpected eap packet from peer"); - return; -} - -static void -eap_forward_to_radius(eap *_this, u_int8_t *data, int datalen) -{ - RADIUS_REQUEST_CTX radctx; - RADIUS_PACKET *radpkt = NULL; - const char *secret; - int secretlen; - int rlength = datalen; - radius_req_setting *rad_setting; - int retry = 0; - unsigned int timeout; - char buf0[MAX_USERNAME_LENGTH]; - - /* - * FIXME: Whenever a radius packet is forwarded, is - * FIXME: npppd_ppp_bind_realm() called? - */ - if (npppd_ppp_bind_realm(_this->ppp->pppd, _this->ppp, _this->name, 1) - != 0) { - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, "Not found realm"); - retry = 1; - goto fail; - } - - if (npppd_ppp_is_realm_radius( - _this->ppp->pppd, _this->ppp) == 0) { - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, "Not found realm"); - retry = 1; - goto fail; - } - - if ((rad_setting = npppd_get_radius_req_setting( - _this->ppp->pppd, _this->ppp)) == NULL) { - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, "Not found radius server setting"); - retry = 1; - goto fail; - } - - /* - * make new request packet - */ - if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST)) - == NULL){ - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, "Can't make new request packet"); - retry = 1; - goto fail; - } - - if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt) - != 0) { - /* - * internal error - * retry - */ - retry = 1; - goto fail; - } - - /* avoid EAP fragmentation */ - if (radius_put_uint32_attr(radpkt, RADIUS_TYPE_FRAMED_MTU, - _this->ppp->mru) != 0) { - /* - * internal error - * retry - */ - retry = 1; - goto fail; - } - - /* - * set user name attribute - */ - if (_this->name_len != 0) { - if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME, - npppd_ppp_get_username_for_auth(_this->ppp->pppd, - _this->ppp, _this->name, buf0)) != 0) { - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, - "Can't put attribute to radius packet. type = %d", - RADIUS_TYPE_USER_NAME); - retry = 1; - goto fail; - } - } else { - /* - * none Identity - * discard - */ - eap_log(_this, LOG_NOTICE, "Identity name is not seted"); - goto fail; - } - - /* - * set state attribute - */ - if (_this->attr_state_len != 0) { - if (radius_put_raw_attr(radpkt, - RADIUS_TYPE_STATE, - _this->attr_state, - _this->attr_state_len) != 0) { - /* - * internal error - * discard - */ - eap_log(_this, LOG_ERR, - "Can't put attribute to radius packet. type = %d", - RADIUS_TYPE_STATE); - goto fail; - } - } - - /* - * set EAP message attribute - * radius packet has some eap message attribute - */ - while (rlength > 0) { - if (rlength > 253) { - if (radius_put_raw_attr(radpkt, - RADIUS_TYPE_EAP_MESSAGE, - data+(datalen-rlength), 253) != 0) { - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, - "Can't put attribute to radius packet. " - "type = %d", RADIUS_TYPE_EAP_MESSAGE); - retry = 1; - goto fail; - } - rlength -= 253; - } else { - if (radius_put_raw_attr(radpkt, - RADIUS_TYPE_EAP_MESSAGE, - data+(datalen-rlength), - rlength) != 0) { - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, - "Can't put attribute to radius packet. " - "type = %d", RADIUS_TYPE_EAP_MESSAGE); - retry = 1; - goto fail; - } - rlength -= rlength; - } - } - - /* - * request cancel - */ - if (_this->radctx != NULL) - radius_cancel_request(_this->radctx); - - /* - * prepare request - */ - if (_this->session_timeout != 0) -/* - * FIXME: Is the timer other than authentication timeout timer really - * FIXME: necessary? - */ - timeout = _this->session_timeout/2; - else - timeout = _this->ppp->auth_timeout; - if (radius_prepare(rad_setting, _this, &radctx, - eap_recv_from_radius, timeout) != 0) { - /* - * internal error - * retry - */ - eap_log(_this, LOG_ERR, "Can't prepare to send access request " - "packet to radius"); - if (!npppd_ppp_is_realm_ready(_this->ppp->pppd, _this->ppp)) { - eap_log(_this, LOG_ERR, - "radius server setting is not ready"); - } - retry = 1; - goto fail; - } - _this->radctx = radctx; - - /* - * get secret password - * for radius - */ - secret = radius_get_server_secret(_this->radctx); - secretlen = strlen(secret); - - /* - * set message authenticator attribute - */ - if (radius_put_message_authenticator(radpkt, secret) != 0) { - eap_log(_this, LOG_ERR, "couldn't put message authentication " - "attribute to radius packet"); - retry = 1; - goto fail; - } - - radius_get_authenticator(radpkt, _this->authenticator); - - /* - * send request - */ - radius_request(_this->radctx, radpkt); - return; -fail: - /* - * don't give peer user infomation - */ - if (radpkt != NULL) - radius_delete_packet(radpkt); - eap_log(_this, LOG_NOTICE, "Can't forward packet to radius from peer"); - if (retry) { - eap_restart(_this); - } - return; -} - -static void -eap_recv_from_radius(void *context, RADIUS_PACKET *pkt, int flags) -{ - int code; - eap *_this; - int errorCode; - int finish; - int retry = 0; - char *notify_reason = NULL; - RADIUS_REQUEST_CTX radctx; - u_char msgbuf[4096], *cp; /* FIXME: May be enough? */ - int len; - u_int8_t attrlen = 0; - - u_int8_t eap_code = 0; - u_int8_t eap_id = 0; - size_t eap_length; - - const char *secret; - int secretlen; - - EAP_ASSERT(context != NULL); - - _this = context; - radctx = _this->radctx; - errorCode = ERROR_AUTH_SERVER_TIMEOUT; - _this->radctx = NULL; - - if (pkt == NULL) { - if (flags & RADIUS_REQUST_TIMEOUT) { - /* - * timeout - * retry - */ - eap_log(_this, LOG_WARNING, "Timeout radius response"); - retry = 1; - notify_reason = "timeout"; - } else { - /* - * internal error - * retry - */ - eap_log(_this, LOG_WARNING, - "Internal error with radius packet"); - retry = 1; - notify_reason = "intenal error"; - } - goto auth_failed; - } - - if(!(flags & RADIUS_REQUST_CHECK_AUTHENTICTOR_NO_CHECK) && - !(flags & RADIUS_REQUST_CHECK_AUTHENTICTOR_OK)){ - /* discard */ - eap_log(_this, LOG_WARNING, "Header has invalid authticator"); - notify_reason = "bad authenticator"; - retry = 1; - goto auth_failed; - } - - /* - * get secret password from the radius request context - */ - secret = radius_get_server_secret(radctx); - secretlen = strlen(secret); - - /* - * get radius code - */ - code = radius_get_code(pkt); - if (radius_check_message_authenticator(pkt, secret) != 0) { - eap_log(_this, LOG_WARNING, "bad message authenticator."); - goto auth_failed; - } else { - EAP_DBG((_this, LOG_INFO, "good message authenticator.")); - } - - /* - * get first eap message and get length of eap message - */ - if (radius_get_raw_attr(pkt, RADIUS_TYPE_EAP_MESSAGE, msgbuf, &attrlen) - != 0) { - /* - * check reject - */ - if ((_this->flags & PPP_EAP_FLAG_NAK_RESPONSE) - && code == RADIUS_CODE_ACCESS_REJECT) { - /* - * nak and reject - */ - eap_log(_this, LOG_NOTICE, - "Authentication reject with nak"); - } else if (code == RADIUS_CODE_ACCESS_REJECT) { - /* - * reject - */ - eap_log(_this, LOG_NOTICE, "Authentication reject"); - } else { - /* - * discard - */ - eap_log(_this, LOG_WARNING, "Not found eap attribute"); - goto auth_failed; - } - eap_stop(_this); - ppp_stop(_this->ppp, "Authentication reject"); - goto auth_failed; - } - if (attrlen < 4) { - /* - * discard - */ - eap_log(_this, LOG_WARNING, "EAP message is too short"); - goto auth_failed; - } - cp = msgbuf; - GETCHAR(eap_code, cp); - GETCHAR(eap_id, cp); - _this->eapid = eap_id; - GETSHORT(eap_length, cp); - - /* - * if challenge packet, try get state attribute - */ - if (code == RADIUS_CODE_ACCESS_CHALLENGE) { - _this->attr_state_len = RADIUS_ATTR_STATE_LEN; - if (radius_get_raw_attr(pkt, - RADIUS_TYPE_STATE, - _this->attr_state, - &(_this->attr_state_len)) != 0) { - /* discard */ - eap_log(_this, LOG_ERR, "Not found state attribute"); - goto auth_failed; - } - if (_this->attr_state_len < 1) { - /* discard */ - _this->attr_state_len = 0; - eap_log(_this, LOG_WARNING, - "State attribute has invalid length"); - goto auth_failed; - } - } - - /* - * get session timeout field - */ - if (radius_get_uint32_attr(pkt, RADIUS_TYPE_SESSION_TIMEOUT, - &_this->session_timeout) == 0) { - if (_this->session_timeout > EAP_TIMEOUT_MAX) - _this->session_timeout = EAP_TIMEOUT_MAX; - eap_log(_this, LOG_DEBUG, "Found session timeout attribute"); - } - - /* - * get eap message attribute - */ - if (radius_get_raw_attr_all(pkt, RADIUS_TYPE_EAP_MESSAGE, - NULL, &len) != 0) { - eap_log(_this, LOG_INFO, "Failed to get eap-message from the " - "radius"); - retry = 1; - goto auth_failed; - } - - if (len != eap_length) { - eap_log(_this, LOG_INFO, "Received a bad eap-message: " - "length in the header is wrong."); - retry = 1; - goto auth_failed; - } - if (radius_get_raw_attr_all(pkt, RADIUS_TYPE_EAP_MESSAGE, msgbuf, &len) - != 0) { - eap_log(_this, LOG_INFO, - "failed to get eap-message from the radius response."); - retry = 1; - goto auth_failed; - } - - /* - * forwarding validation - * RFC 3579, RFC 3784 - * - */ - finish = 0; - switch (code) { - case RADIUS_CODE_ACCESS_REQUEST: - eap_log(_this, LOG_INFO, - "Invalid radius code (access request) code=%d eap_code=%d", - code, eap_code); - goto auth_failed; - break; - case RADIUS_CODE_ACCESS_REJECT: - switch (eap_code) { - case EAP_REQUEST: - eap_log(_this, LOG_INFO, "Abnormal reject"); - eap_stop(_this); - ppp_stop(_this->ppp, "Authentication failed"); - finish = 1; - break; - case EAP_RESPONSE: - eap_log(_this, LOG_INFO, - "Unexpected eap code(access reject)"); - goto auth_failed; - break; - case EAP_FAILURE: - eap_log(_this, LOG_INFO, "Eap failure"); - eap_stop(_this); - finish = eap_forward_to_peer(_this, - msgbuf+EAP_HEADERLEN, len-EAP_HEADERLEN, - eap_code, eap_id); - break; - case EAP_SUCCESS: - default: - eap_log(_this, LOG_INFO, - "Invalid combination code: radius code = %d and " - "eap code = %d", code ,eap_code); - goto auth_failed; - break; - } - break; - case RADIUS_CODE_ACCESS_ACCEPT: - switch (eap_code) { - case EAP_REQUEST: - finish = eap_forward_to_peer(_this, - msgbuf+EAP_HEADERLEN, len-EAP_HEADERLEN, - eap_code, eap_id); - break; - case EAP_RESPONSE: - eap_log(_this, LOG_INFO, - "unexpected eap code(access accept)"); - goto auth_failed; - break; - case EAP_FAILURE: - eap_log(_this, LOG_INFO, - "Invalid combination code: radius code = %d and " - "eap code = %d", - code ,eap_code); - goto auth_failed; - break; - case EAP_SUCCESS: - ppp_process_radius_framed_ip(_this->ppp, pkt); -#ifdef USE_NPPPD_MPPE - if (get_mppe_keys(_this, pkt, secret)) { - if (MPPE_REQUIRED(_this->ppp)) { - eap_log(_this, LOG_ERR, - "mppe is required but can't get " - "mppe keys"); - eap_stop(_this); - ppp_stop(_this->ppp, "can't get mppe " - "attribute"); - } else { - eap_log(_this, LOG_INFO, - "can't get mppe keys, unuse " - "encryption"); - } - } else { - eap_log(_this, LOG_DEBUG, - "Found attribute of mppe keys"); - } - -#endif - finish = eap_forward_to_peer(_this, - msgbuf+EAP_HEADERLEN, len-EAP_HEADERLEN, - eap_code, eap_id); - break; - default: - eap_log(_this, LOG_INFO, - "Invalid combination code: radius code = %d and " - "eap code = %d", code ,eap_code); - goto auth_failed; - break; - } - break; - case RADIUS_CODE_ACCESS_CHALLENGE: - switch (eap_code) { - case EAP_REQUEST: - finish = eap_forward_to_peer(_this, - msgbuf+EAP_HEADERLEN, len-EAP_HEADERLEN, - eap_code, eap_id); - break; - case EAP_RESPONSE: - eap_log(_this, LOG_INFO, - "Unexpected eap code(access challenge)"); - goto auth_failed; - break; - case EAP_FAILURE: - case EAP_SUCCESS: - default: - eap_log(_this, LOG_INFO, - "Invalid combination code: radius code = %d and " - "eap code = %d", code ,eap_code); - goto auth_failed; - break; - } - /* XXX TODO:not forward EAP-START */ - break; - default: - eap_log(_this, LOG_INFO, - "Unknown radius code type code = %d and eap code = %d", - code ,eap_code); - goto auth_failed; - break; - } - - if(!finish) { - if (_this->session_timeout != 0) { - TIMEOUT((TIMER_CBFUNC)eap_restart, _this, - _this->session_timeout/2); - } else { - TIMEOUT((TIMER_CBFUNC)eap_restart, _this, - EAP_TIMEOUT_INIT); - } - } - return; - -auth_failed: - eap_log(_this, LOG_WARNING, - "Can't forward packet to peer from radius"); - if (notify_reason != NULL) { - npppd_radius_server_failure_notify( - _this->ppp->pppd, _this->ppp, radctx, notify_reason); - } - if (retry) { - eap_restart(_this); - } - return; -} - -#ifdef USE_NPPPD_MPPE -int -get_mppe_keys(eap *_this, RADIUS_PACKET *pkt, const char *secret) { - struct RADIUS_MPPE_KEY sendkey, recvkey; - u_int8_t len; - - EAP_ASSERT(_this != NULL); - EAP_ASSERT(_this->ppp != NULL); - - - if (_this->ppp->mppe.enabled == 0) { - return 1; - } - len = sizeof(sendkey); - /* XXX: radius_get_vs_raw_attr doesn't read 'len' */ - if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT, - RADIUS_VTYPE_MPPE_SEND_KEY, &sendkey, &len) != 0) { - eap_log(_this, LOG_ERR, "no mppe_send_key"); - return 1; - } - len = sizeof(recvkey); - /* XXX: radius_get_vs_raw_attr doesn't read 'len' */ - if (radius_get_vs_raw_attr(pkt, RADIUS_VENDOR_MICROSOFT, - RADIUS_VTYPE_MPPE_RECV_KEY, &recvkey, &len) != 0) { - eap_log(_this, LOG_ERR, "no mppe_recv_key"); - return 1; - } - mschap_radiuskey(_this->ppp->mppe.send.master_key, - sendkey.salt, _this->authenticator, secret); - - mschap_radiuskey(_this->ppp->mppe.recv.master_key, - recvkey.salt, _this->authenticator, secret); - - return 0; -} -#endif - -void -eap_stop(eap *_this) -{ - _this->state = EAP_STATE_STOPPED; - UNTIMEOUT(eap_restart, _this); - if (_this->radctx != NULL) { - radius_cancel_request(_this->radctx); - _this->radctx = NULL; - } -} - -static int -eap_forward_to_peer(eap *_this, u_int8_t *data, int datalen, int type, u_int8_t id) -{ - int finish = 0; - EAP_ASSERT(_this != NULL); - EAP_ASSERT(data != NULL); - - switch (type) { - case EAP_REQUEST: - ppp_output(_this->ppp, PPP_PROTO_EAP, EAP_REQUEST, id, data, - datalen); - break; - case EAP_SUCCESS: - ppp_output(_this->ppp, PPP_PROTO_EAP, EAP_SUCCESS, id, data, - datalen); - eap_log(_this, LOG_INFO, "Authentication succeeded"); - eap_stop(_this); - memcpy(_this->ppp->username, _this->name, _this->name_len); - ppp_auth_ok(_this->ppp); - finish = 1; - break; - case EAP_FAILURE: - ppp_output(_this->ppp, PPP_PROTO_EAP, EAP_FAILURE, id, data, - datalen); - eap_log(_this, LOG_INFO, "eap-failure has been received from the peer."); - eap_log(_this, LOG_INFO, "Authentication failed"); - eap_stop(_this); - ppp_stop(_this->ppp, "Authentication failed"); - finish = 1; - break; - default: - break; - } - return finish; -} - -/************************************************************************ - * Miscellaneous functions - ************************************************************************/ -void -eap_log(eap *_this, uint32_t prio, const char *fmt, ...) -{ - char logbuf[BUFSIZ]; - va_list ap; - - EAP_ASSERT(_this != NULL); - EAP_ASSERT(_this->ppp != NULL); - - va_start(ap, fmt); - snprintf(logbuf, sizeof(logbuf), "ppp id=%u layer=eap %s", - _this->ppp->id, fmt); - vlog_printf(prio, logbuf, ap); - va_end(ap); -} diff --git a/usr.sbin/npppd/npppd/lcp.c b/usr.sbin/npppd/npppd/lcp.c index 44e5f57b47e..25cd8ecd1a6 100644 --- a/usr.sbin/npppd/npppd/lcp.c +++ b/usr.sbin/npppd/npppd/lcp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lcp.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: lcp.c,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -/* $Id: lcp.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $Id: lcp.c,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /**@file * This file provides LCP related functions. *<pre> @@ -204,6 +204,10 @@ lcp_open(fsm *f) fsm_log(f, LOG_INFO, "failed to negotiate a auth protocol."); fsm_close(f, "Authentication is required"); + ppp_set_disconnect_cause(f->ppp, + PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, + _this->auth_order[0] /* first one */, + 1 /* peer refused */, NULL); ppp_stop(f->ppp, "Authentication is required"); return; } @@ -232,6 +236,20 @@ static void lcp_down(fsm *f) { lcp *_this; + + if (f->ppp->disconnect_code == PPP_DISCON_NO_INFORMATION) { + /* + * disconnect code is set when we are closing the lcp, so + * 'no info' means the lcp is going down by peer's termreq. + */ + ppp_set_disconnect_cause(f->ppp, PPP_DISCON_NORMAL, 0, + 1 /* peer */, NULL); +#ifdef USE_NPPPD_RADIUS + ppp_set_radius_terminate_cause(f->ppp, + RADIUS_TERMNATE_CAUSE_USER_REQUEST); +#endif + } + _this = &f->ppp->lcp; UNTIMEOUT(lcp_timeout, _this); } @@ -707,6 +725,10 @@ lcp_nakci(fsm *f, u_char *inp, int inlen) "protocols are agreeable. peer's " "auth proto=%s", peer_auth); + ppp_set_disconnect_cause(f->ppp, + PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, + authproto, 2 /* couldn't accept peer's */, + NULL); ppp_stop(f->ppp, "Authentication is required"); return 1; } @@ -811,6 +833,9 @@ lcp_rejci(fsm *f, u_char *inp, int inlen) if (NO_AUTH_AGREEABLE(_this)) { fsm_log(f, LOG_INFO, "No authentication " "protocols are agreeable."); + ppp_set_disconnect_cause(f->ppp, + PPP_DISCON_AUTH_PROTOCOL_UNACCEPTABLE, + authproto, 1 /* rejected by peer */, NULL); ppp_stop(f->ppp, "Authentication is required"); return 1; } @@ -911,8 +936,13 @@ lcp_timeout(void *ctx) _this = ctx; if (_this->echo_failures >= _this->echo_max_retries) { fsm_log(&_this->fsm, LOG_NOTICE, "keepalive failure."); - if (_this->fsm.ppp != NULL) + if (_this->fsm.ppp != NULL) { +#ifdef USE_NPPPD_RADIUS + ppp_set_radius_terminate_cause(_this->fsm.ppp, + RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT); +#endif ppp_stop(_this->fsm.ppp, NULL); + } return; } cp = buf; @@ -976,11 +1006,11 @@ lcp_ext(fsm *f, int code, int id, u_char *inp, int inlen) return 1; case ECHOREP: if (f->state == OPENED) { - if (inlen >= 4) { - GETLONG(magic, inp); - if (_this->peer_magic_number == magic) { - _this->echo_failures = 0; - lcp_reset_timeout(_this); + if (inlen >= 4) { + GETLONG(magic, inp); + if (_this->peer_magic_number == magic) { + _this->echo_failures = 0; + lcp_reset_timeout(_this); } } } diff --git a/usr.sbin/npppd/npppd/npppd.c b/usr.sbin/npppd/npppd/npppd.c index edb6266b0b2..002d92ab6b4 100644 --- a/usr.sbin/npppd/npppd/npppd.c +++ b/usr.sbin/npppd/npppd/npppd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: npppd.c,v 1.10 2011/05/15 15:47:52 markus Exp $ */ +/* $OpenBSD: npppd.c,v 1.11 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -29,7 +29,7 @@ * Next pppd(nppd). This file provides a npppd daemon process and operations * for npppd instance. * @author Yasuoka Masahiko - * $Id: npppd.c,v 1.10 2011/05/15 15:47:52 markus Exp $ + * $Id: npppd.c,v 1.11 2011/07/06 20:52:28 yasuoka Exp $ */ #include <sys/cdefs.h> #include "version.h" @@ -287,6 +287,8 @@ npppd_init(npppd *_this, const char *config_file) seed_random(&seed); srandom(seed); + _this->boot_id = (uint32_t)random(); + /* load configuration */ if ((status = npppd_reload_config(_this)) != 0) return status; @@ -1284,6 +1286,11 @@ pipex_periodic(npppd *_this) continue; } ppp_log(ppp, LOG_INFO, "Stop requested by the kernel"); + /* TODO: PIPEX doesn't return the disconect reason */ +#ifdef USE_NPPPD_RADIUS + ppp_set_radius_terminate_cause(ppp, + RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT); +#endif ppp_stop(ppp, NULL); } pipex_done: @@ -2020,10 +2027,10 @@ npppd_ppp_bind_realm(npppd *_this, npppd_ppp *ppp, const char *username, int strcmp(username + lusername - lsuffix, npppd_auth_get_suffix(realm0)) == 0))) { /* check prefix */ - lprefix = strlen(npppd_auth_get_suffix(realm0)); + lprefix = strlen(npppd_auth_get_prefix(realm0)); if (lprefix > 0 && strncmp(username, - npppd_auth_get_suffix(realm0), + npppd_auth_get_prefix(realm0), lprefix) != 0) continue; @@ -2218,7 +2225,7 @@ npppd_rd_walktree_delete(struct radish_head *rh) * @return return NULL if no usable RADIUS setting. */ void * -npppd_get_radius_req_setting(npppd *_this, npppd_ppp *ppp) +npppd_get_radius_auth_setting(npppd *_this, npppd_ppp *ppp) { NPPPD_ASSERT(_this != NULL); NPPPD_ASSERT(ppp != NULL); @@ -2228,21 +2235,7 @@ npppd_get_radius_req_setting(npppd *_this, npppd_ppp *ppp) if (!npppd_ppp_is_realm_radius(_this, ppp)) return NULL; - return npppd_auth_radius_get_radius_req_setting( - (npppd_auth_radius *)ppp->realm); -} - -/** Notice a failure on RAIDUS request/response */ -void -npppd_radius_server_failure_notify(npppd *_this, npppd_ppp *ppp, void *rad_ctx, - const char *reason) -{ - NPPPD_ASSERT(rad_ctx != NULL); - NPPPD_ASSERT(ppp != NULL); - - npppd_auth_radius_server_failure_notify( - (npppd_auth_radius *)ppp->realm, radius_get_server_address(rad_ctx), - reason); + return npppd_auth_radius_get_radius_auth_setting(ppp->realm); } #endif @@ -2288,8 +2281,10 @@ npppd_auth_finalizer_periodic(npppd *_this) slist_itr_remove(&users); } } - if (refcnt == 0) + if (refcnt == 0) { npppd_auth_destroy(auth_base); + slist_itr_remove(&_this->realms); + } } if (ndisposing > 0) slist_fini(&users); diff --git a/usr.sbin/npppd/npppd/npppd.h b/usr.sbin/npppd/npppd/npppd.h index 104914fb973..f0004194f4c 100644 --- a/usr.sbin/npppd/npppd/npppd.h +++ b/usr.sbin/npppd/npppd/npppd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: npppd.h,v 1.5 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: npppd.h,v 1.6 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -35,10 +35,11 @@ #endif -#define DEFAULT_RADIUS_AUTH_IPADDR "127.0.0.1" #define DEFAULT_RADIUS_AUTH_PORT 1812 -#define DEFAULT_RADIUS_AUTH_TIMEOUT 9 - +#define DEFAULT_RADIUS_ACCT_PORT 1813 +#define DEFAULT_RADIUS_TIMEOUT 9 +#define DEFAULT_RADIUS_MAX_TRIES 3 +#define DEFAULT_RADIUS_MAX_FAILOVERS 1 #define DEFAULT_AUTH_TIMEOUT 30 /** assign fixed IP address */ @@ -117,8 +118,8 @@ const char *npppd_ppp_get_realm_name(npppd *, npppd_ppp *); int npppd_ppp_bind_iface(npppd *, npppd_ppp *); void npppd_ppp_unbind_iface(npppd *, npppd_ppp *); const char *npppd_ppp_get_iface_name(npppd *, npppd_ppp *); -void * npppd_get_radius_req_setting(npppd *, npppd_ppp *); -void npppd_radius_server_failure_notify(npppd *, npppd_ppp *, void *, const char *); +void * npppd_get_radius_auth_setting(npppd *, npppd_ppp *); +void npppd_radius_auth_server_failure_notify(npppd *, npppd_ppp *, void *, const char *); int npppd_ppp_pipex_enable(npppd *, npppd_ppp *); int npppd_ppp_pipex_disable(npppd *, npppd_ppp *); const char *npppd_ppp_get_username_for_auth(npppd *, npppd_ppp *, const char *, char *); diff --git a/usr.sbin/npppd/npppd/npppd_auth.c b/usr.sbin/npppd/npppd/npppd_auth.c index 479ef06888d..9138a691067 100644 --- a/usr.sbin/npppd/npppd/npppd_auth.c +++ b/usr.sbin/npppd/npppd/npppd_auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: npppd_auth.c,v 1.6 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: npppd_auth.c,v 1.7 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -26,7 +26,7 @@ * SUCH DAMAGE. */ /**@file authentication realm */ -/* $Id: npppd_auth.c,v 1.6 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $Id: npppd_auth.c,v 1.7 2011/07/06 20:52:28 yasuoka Exp $ */ /* I hope to write the source code in npppd-independent as possible. */ #include <sys/types.h> #include <sys/stat.h> @@ -93,14 +93,31 @@ npppd_auth_create(int auth_type, const char *label, void *_npppd) #ifdef USE_NPPPD_RADIUS case NPPPD_AUTH_TYPE_RADIUS: if ((base = malloc(sizeof(npppd_auth_radius))) != NULL) { + npppd_auth_radius *_this = (npppd_auth_radius *)base; memset(base, 0, sizeof(npppd_auth_radius)); base->type = NPPPD_AUTH_TYPE_RADIUS; base->strip_nt_domain = 0; strlcpy(base->label, label, sizeof(base->label)); base->npppd = _npppd; + if ((_this->rad_auth_setting = + radius_req_setting_create()) == NULL) + goto radius_reigai; + if ((_this->rad_acct_setting = + radius_req_setting_create()) == NULL) + goto radius_reigai; return base; +radius_reigai: + if (_this->rad_auth_setting != NULL) + radius_req_setting_destroy( + _this->rad_auth_setting); + if (_this->rad_acct_setting != NULL) + radius_req_setting_destroy( + _this->rad_acct_setting); + free(base); + return NULL; } + break; #endif @@ -153,8 +170,17 @@ npppd_auth_destroy(npppd_auth_base *base) break; case NPPPD_AUTH_TYPE_RADIUS: + { + npppd_auth_radius *_this = (npppd_auth_radius *)base; + if (_this->rad_auth_setting != NULL) + radius_req_setting_destroy(_this->rad_auth_setting); + _this->rad_auth_setting = NULL; + if (_this->rad_acct_setting != NULL) + radius_req_setting_destroy(_this->rad_acct_setting); + _this->rad_acct_setting = NULL; memset(base, 0, sizeof(npppd_auth_local)); break; + } } free(base); @@ -432,6 +458,12 @@ npppd_auth_get_suffix(npppd_auth_base *base) } const char * +npppd_auth_get_prefix(npppd_auth_base *base) +{ + return base->pppprefix; +} + +const char * npppd_auth_username_for_auth(npppd_auth_base *base, const char *username, char *username_buffer) { @@ -690,10 +722,10 @@ npppd_auth_find_user(npppd_auth_base *base, const char *username) static int radius_server_address_load(radius_req_setting *radius, int idx, - const char *address) + const char *address, enum RADIUS_SERVER_TYPE type) { struct addrinfo *ai; - struct sockaddr_in *sin; + struct sockaddr_in *sin4; memset(&radius->server[idx], 0, sizeof(radius->server[0])); @@ -709,9 +741,11 @@ radius_server_address_load(radius_req_setting *radius, int idx, break; } - sin = (struct sockaddr_in *)(ai->ai_addr); - if (sin->sin_port == 0) - sin->sin_port = htons(DEFAULT_RADIUS_AUTH_PORT); + sin4 = (struct sockaddr_in *)(ai->ai_addr); + if (sin4->sin_port == 0) + sin4->sin_port = htons((type == RADIUS_SERVER_TYPE_AUTH) + ? DEFAULT_RADIUS_AUTH_PORT : DEFAULT_RADIUS_ACCT_PORT); + memcpy(&radius->server[idx].peer, ai->ai_addr, MIN(sizeof(radius->server[idx].peer), ai->ai_addrlen)); @@ -721,131 +755,161 @@ radius_server_address_load(radius_req_setting *radius, int idx, return 0; } +#define VAL_SEP " \t\r\n" /** reload the configuration of RADIUS authentication realm */ static int npppd_auth_radius_reload(npppd_auth_base *base) { npppd_auth_radius *_this = (npppd_auth_radius *)base; + int i, nauth, nacct; + + _this->rad_acct_setting->timeout = _this->rad_auth_setting->timeout = + npppd_auth_config_int(base, "timeout", DEFAULT_RADIUS_TIMEOUT); + + _this->rad_acct_setting->max_tries = + _this->rad_auth_setting->max_tries = + npppd_auth_config_int(base, "max_tries", + DEFAULT_RADIUS_MAX_TRIES); + + _this->rad_acct_setting->max_failovers = + _this->rad_auth_setting->max_failovers = + npppd_auth_config_int(base, "max_failovers", + DEFAULT_RADIUS_MAX_FAILOVERS); + + _this->rad_acct_setting->curr_server = + _this->rad_auth_setting->curr_server = 0; + if ((nauth = radius_loadconfig(base, _this->rad_auth_setting, + RADIUS_SERVER_TYPE_AUTH)) < 0) + goto reigai; + if ((nacct = radius_loadconfig(base, _this->rad_acct_setting, + RADIUS_SERVER_TYPE_ACCT)) < 0) + goto reigai; + + for (i = 0; i < countof(_this->rad_auth_setting->server); i++) { + if (_this->rad_auth_setting->server[i].enabled) + base->radius_ready = 1; + } + + npppd_auth_base_log(&_this->nar_base, LOG_INFO, + "Loaded configuration. %d authentication server%s, %d accounting " + "server%s. timeout=%dsec", + nauth, (nauth > 1)? "s" : "", nacct, (nacct > 1)? "s" : "", + _this->rad_auth_setting->timeout); + + return 0; +reigai: + npppd_auth_destroy(base); + + return 1; +} + +static int +radius_loadconfig(npppd_auth_base *base, radius_req_setting *radius, + enum RADIUS_SERVER_TYPE srvtype) +{ + npppd_auth_radius *_this = (npppd_auth_radius *)base; int i, n; const char *val; - char *tok, *buf0, buf[NPPPD_CONFIG_BUFSIZ], logbuf[BUFSIZ]; + char *tok, *buf0, buf[NPPPD_CONFIG_BUFSIZ]; char label[256]; + struct rad_cfglabel { + const char *list; + const char *address; + const char *secret; + const char *addressL; + const char *secretL; + } const rad_auth_cfglabel = { + .list = "server_list", + .address = "server.address", + .secret = "server.secret", + .addressL = "server.%s.address", + .secretL = "server.%s.secret" + }, rad_acct_cfglabel = { + .list = "acct_server_list", + .address = "acct_server.address", + .secret = "acct_server.secret", + .addressL = "acct_server.%s.address", + .secretL = "acct_server.%s.secret" + }, *cfglabel; + + if (srvtype == RADIUS_SERVER_TYPE_AUTH) + cfglabel = &rad_auth_cfglabel; + else + cfglabel = &rad_acct_cfglabel; -#define VAL_SEP " \t\r\n" - n = 0; - _this->rad_setting.timeout = - npppd_auth_config_int(base, "timeout", DEFAULT_RADIUS_AUTH_TIMEOUT); - _this->rad_setting.curr_server = 0; + for (i = 0; i < countof(radius->server); i++) + radius->server[i].enabled = 0; - if ((val = npppd_auth_config_str(base, "server_list")) != NULL) { + n = 0; + if ((val = npppd_auth_config_str(base, cfglabel->list)) != NULL) { strlcpy(buf, val, sizeof(buf)); buf0 = buf; while ((tok = strsep(&buf0, VAL_SEP)) != NULL) { if (tok[0] == '\0') continue; - snprintf(label, sizeof(label), "server.%s.address",tok); - if ((val = npppd_auth_config_str(base, label)) == NULL) + snprintf(label, sizeof(label), cfglabel->addressL,tok); + if ((val = npppd_auth_config_str(base, label)) == NULL){ + npppd_auth_base_log(&_this->nar_base, LOG_INFO, + "property %s is not found", label); goto fail; - if (radius_server_address_load(&_this->rad_setting, n, - val) != 0) { + } + if (radius_server_address_load(radius, n, val, srvtype) + != 0) { npppd_auth_base_log(base, LOG_INFO, "parse error at %s", label); goto fail; } - snprintf(label, sizeof(label), "server.%s.secret", - tok); + snprintf(label, sizeof(label), cfglabel->secretL, tok); if ((val = npppd_auth_config_str(base, label)) != NULL) - strlcpy(_this->rad_setting.server[n].secret, - val, sizeof(_this->rad_setting - .server[n].secret)); + strlcpy(radius->server[n].secret, val, + sizeof(radius->server[n].secret)); else - _this->rad_setting.server[n].secret[0] = '\0'; - if (n != 0) - strlcat(logbuf, " ", sizeof(logbuf)); + radius->server[n].secret[0] = '\0'; n++; } - } else if ((val = npppd_auth_config_str(base, "server.address")) + } else if ((val = npppd_auth_config_str(base, cfglabel->address)) != NULL) { - if (radius_server_address_load(&_this->rad_setting, n, val) - != 0) { + if (radius_server_address_load(radius, n, val, srvtype) != 0) { npppd_auth_base_log(base, LOG_INFO, "parse error at %s", label); goto fail; } - if ((val = npppd_auth_config_str(base, "server.secret"))!= NULL) - strlcpy(_this->rad_setting.server[n].secret, val, - sizeof(_this->rad_setting.server[n].secret)); + if ((val = npppd_auth_config_str(base, cfglabel->secret)) + != NULL) + strlcpy(radius->server[n].secret, val, + sizeof(radius->server[n].secret)); else - _this->rad_setting.server[n].secret[0] = '\0'; + radius->server[n].secret[0] = '\0'; n++; } - for (i = n; i < countof(_this->rad_setting.server); i++) { - memset(&_this->rad_setting.server[i], 0, - sizeof(_this->rad_setting.server[0])); - } - for (i = 0; i < countof(_this->rad_setting.server); i++) { - if (_this->rad_setting.server[i].enabled) - base->radius_ready = 1; - } - - npppd_auth_base_log(base, LOG_INFO, - "Loaded configuration timeout=%d nserver=%d", - _this->rad_setting.timeout, n); + for (i = n; i < countof(radius->server); i++) + memset(&radius->server[i], 0, sizeof(radius->server[0])); - return 0; + return n; fail: - npppd_auth_destroy(base); - - return 1; + return -1; } /** - * Get {@link ::radius_req_setting} of specified {@link ::npppd_auth_base} - * object. + * Get {@link ::radius_req_setting} for RADIUS authentication of specified + * {@link ::npppd_auth_base} object. */ void * -npppd_auth_radius_get_radius_req_setting(npppd_auth_radius *_this) +npppd_auth_radius_get_radius_auth_setting(npppd_auth_radius *_this) { - return &_this->rad_setting; + return _this->rad_auth_setting; } -/** This function notifies that RADIUS server failed the request. */ -void -npppd_auth_radius_server_failure_notify(npppd_auth_radius *_this, - struct sockaddr *server, const char *reason) +/** + * Get {@link ::radius_req_setting} for RADIUS accounting of specified + * {@link ::npppd_auth_base} object. + */ +void * +npppd_auth_radius_get_radius_acct_setting(npppd_auth_radius *_this) { - int i, n; - radius_req_setting *rad_setting; - char buf0[BUFSIZ]; - - NPPPD_AUTH_ASSERT(_this != NULL); - NPPPD_AUTH_ASSERT(server != NULL); - - if (reason == NULL) - reason = "failure"; - - rad_setting = &_this->rad_setting; - if (memcmp(&rad_setting->server[rad_setting->curr_server].peer, - server, server->sa_len) == 0) { - /* - * The RADIUS server which request was failed is currently selected, - * so next RADIUS server will be selected. - */ - for (i = 1; i < countof(rad_setting->server); i++) { - n = (rad_setting->curr_server + i) % - countof(rad_setting->server); - if (rad_setting->server[n].enabled == 0) - continue; - rad_setting->curr_server = n; - break; - } - } - - npppd_auth_base_log(&_this->nar_base, LOG_NOTICE, - "server=%s request failure: %s", - addrport_tostring(server, server->sa_len, buf0, sizeof(buf0)), - reason); + return _this->rad_acct_setting; } + #endif /*********************************************************************** diff --git a/usr.sbin/npppd/npppd/npppd_auth.h b/usr.sbin/npppd/npppd/npppd_auth.h index b3cf65bc049..d84504f8836 100644 --- a/usr.sbin/npppd/npppd/npppd_auth.h +++ b/usr.sbin/npppd/npppd/npppd_auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: npppd_auth.h,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: npppd_auth.h,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -64,9 +64,10 @@ int npppd_auth_is_eap_capable (npppd_auth_base *); const char *npppd_auth_get_label (npppd_auth_base *); const char *npppd_auth_get_name (npppd_auth_base *); const char *npppd_auth_get_suffix (npppd_auth_base *); +const char *npppd_auth_get_prefix (npppd_auth_base *); const char *npppd_auth_username_for_auth (npppd_auth_base *, const char *, char *); -void *npppd_auth_radius_get_radius_req_setting (npppd_auth_radius *); -void npppd_auth_radius_server_failure_notify (npppd_auth_radius *, struct sockaddr *, const char *); +void *npppd_auth_radius_get_radius_auth_setting (npppd_auth_radius *); +void *npppd_auth_radius_get_radius_acct_setting (npppd_auth_radius *); #ifdef __cplusplus } diff --git a/usr.sbin/npppd/npppd/npppd_auth_local.h b/usr.sbin/npppd/npppd/npppd_auth_local.h index 829e4d36f3d..04e8e605472 100644 --- a/usr.sbin/npppd/npppd/npppd_auth_local.h +++ b/usr.sbin/npppd/npppd/npppd_auth_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: npppd_auth_local.h,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: npppd_auth_local.h,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -73,12 +73,11 @@ struct _npppd_auth_radius { /** parent of npppd_auth_base */ npppd_auth_base nar_base; - /** server currently in use */ - int curr_server; - - /** RADIUS server */ - radius_req_setting rad_setting; + /** RADIUS authentication server setting */ + radius_req_setting *rad_auth_setting; + /** RADIUS accounting server setting */ + radius_req_setting *rad_acct_setting; }; #endif @@ -106,8 +105,6 @@ typedef struct _npppd_auth_user { static int npppd_auth_reload_acctlist (npppd_auth_base *); static npppd_auth_user *npppd_auth_find_user (npppd_auth_base *, const char *); -static int radius_server_address_load (radius_req_setting *, int, const char *); -static int npppd_auth_radius_reload (npppd_auth_base *); static int npppd_auth_base_log (npppd_auth_base *, int, const char *, ...); static uint32_t str_hash (const void *, int); static const char * npppd_auth_default_label(npppd_auth_base *); @@ -116,6 +113,17 @@ static const char *npppd_auth_config_str (npppd_auth_base *, const char static int npppd_auth_config_int (npppd_auth_base *, const char *, int); static int npppd_auth_config_str_equal (npppd_auth_base *, const char *, const char *, int); +#ifdef USE_NPPPD_RADIUS +enum RADIUS_SERVER_TYPE { + RADIUS_SERVER_TYPE_AUTH, + RADIUS_SERVER_TYPE_ACCT +}; + +static int npppd_auth_radius_reload (npppd_auth_base *); +static int radius_server_address_load (radius_req_setting *, int, const char *, enum RADIUS_SERVER_TYPE); +static int radius_loadconfig(npppd_auth_base *, radius_req_setting *, enum RADIUS_SERVER_TYPE); +#endif + #ifdef NPPPD_AUTH_DEBUG #define NPPPD_AUTH_DBG(x) npppd_auth_base_log x #define NPPPD_AUTH_ASSERT(x) ASSERT(x) diff --git a/usr.sbin/npppd/npppd/npppd_local.h b/usr.sbin/npppd/npppd/npppd_local.h index a63e151a1a1..c87e1c6d013 100644 --- a/usr.sbin/npppd/npppd/npppd_local.h +++ b/usr.sbin/npppd/npppd/npppd_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: npppd_local.h,v 1.5 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: npppd_local.h,v 1.6 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -203,6 +203,9 @@ struct _npppd { /** process id */ pid_t pid; + /** boot identifier */ + uint32_t boot_id; + #ifdef USE_NPPPD_L2TP /** structure of L2TP daemon */ l2tpd l2tpd; diff --git a/usr.sbin/npppd/npppd/npppd_radius.c b/usr.sbin/npppd/npppd/npppd_radius.c new file mode 100644 index 00000000000..ccdde2c3317 --- /dev/null +++ b/usr.sbin/npppd/npppd/npppd_radius.c @@ -0,0 +1,435 @@ +/* $Id: npppd_radius.c,v 1.1 2011/07/06 20:52:28 yasuoka Exp $ */ +/*- + * Copyright (c) 2009 Internet Initiative Japan Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * RFC 2865 Remote Authentication Dial In User Service (RADIUS) + * RFC 2866 RADIUS Accounting + * RFC 2868 RADIUS Attributes for Tunnel Protocol Support + * RFC 2869 RADIUS Extensions + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/syslog.h> +#include <netinet/in.h> +#include <net/if_dl.h> +#include <stdio.h> +#include <netdb.h> +#include <stdint.h> +#include <string.h> + +#include <event.h> /* event(3) */ +#include <radius+.h> /* radius+(3) */ +#include <radiusconst.h> /* radius+(3) */ + +#include "radius_req.h" +#include "npppd_local.h" +#include "npppd_radius.h" + +#ifdef NPPPD_RADIUS_DEBUG +#define NPPPD_RADIUS_DBG(x) ppp_log x +#define NPPPD_RADIUS_ASSERT(x) ASSERT(x) +#else +#define NPPPD_RADIUS_DBG(x) +#define NPPPD_RADIUS_ASSERT(x) +#endif + +static int l2tp_put_tunnel_attributes(RADIUS_PACKET *, void *); +static int pptp_put_tunnel_attributes(RADIUS_PACKET *, void *); +static int radius_acct_request(npppd *, npppd_ppp *, int ); +static void npppd_ppp_radius_acct_reqcb(void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX); + +/*********************************************************************** + * RADIUS common fucntions + ***********************************************************************/ +/** + * Retribute Framed-IP-Address and Framed-IP-Netmask attribute of from + * the given RADIUS packet and set them as the fields of ppp context. + */ +void +ppp_proccess_radius_framed_ip(npppd_ppp *_this, RADIUS_PACKET *pkt) +{ + struct in_addr ip4; + + if (radius_get_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, &ip4) + == 0) + _this->realm_framed_ip_address = ip4; + + _this->realm_framed_ip_netmask.s_addr = 0xffffffffL; +#ifndef NPPPD_COMPAT_4_2 + if (radius_get_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_NETMASK, &ip4) + == 0) + _this->realm_framed_ip_netmask = ip4; +#endif +} + +/*********************************************************************** + * RADIUS Accounting Events + ***********************************************************************/ + +/** Called by PPP on start */ +void +npppd_ppp_radius_acct_start(npppd *pppd, npppd_ppp *ppp) +{ + NPPPD_RADIUS_DBG((ppp, LOG_INFO, "%s()", __func__)); + + if (ppp->realm == NULL || !npppd_ppp_is_realm_radius(pppd, ppp)) + return; + radius_acct_request(pppd, ppp, 0); +} + +/** Called by PPP on stop*/ +void +npppd_ppp_radius_acct_stop(npppd *pppd, npppd_ppp *ppp) +{ + NPPPD_RADIUS_DBG((ppp, LOG_INFO, "%s()", __func__)); + + if (ppp->realm == NULL || !npppd_ppp_is_realm_radius(pppd, ppp)) + return; + radius_acct_request(pppd, ppp, 1); +} + +/** Called by radius_req.c */ +static void +npppd_ppp_radius_acct_reqcb(void *context, RADIUS_PACKET *pkt, int flags, + RADIUS_REQUEST_CTX ctx) +{ + int ppp_id; + + ppp_id = (int)context; + if ((flags & RADIUS_REQUEST_TIMEOUT) != 0) { + log_printf(LOG_WARNING, "ppp id=%d radius accounting request " + "failed: no response from the server.", ppp_id); + } + else if ((flags & RADIUS_REQUEST_ERROR) != 0) + log_printf(LOG_WARNING, "ppp id=%d radius accounting request " + "failed: %m", ppp_id); + else if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0 && + (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0) + log_printf(LOG_WARNING, "ppp id=%d radius accounting request " + "failed: the server responses with bad authenticator", + ppp_id); + else { +#ifdef NPPPD_RADIUS_DEBUG + log_printf(LOG_DEBUG, "ppp id=%d radius accounting request " + "succeeded.", ppp_id); +#endif + return; + /* NOTREACHED */ + } + if (radius_request_can_failover(ctx)) { + if (radius_request_failover(ctx) == 0) { + struct sockaddr *sa; + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + + sa = radius_get_server_address(ctx); + if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), + sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV) + != 0) { + strlcpy(hbuf, "unknown", sizeof(hbuf)); + strlcpy(sbuf, "", sizeof(hbuf)); + } + log_printf(LOG_DEBUG, "ppp id=%d " + "fail over to %s:%s for radius accounting request", + ppp_id, hbuf, sbuf); + } else { + log_printf(LOG_WARNING, "ppp id=%d " + "failed to fail over for radius accounting request", + ppp_id); + } + } +} + +/*********************************************************************** + * RADIUS attributes + ***********************************************************************/ +#define ATTR_INT32(_a,_v) \ + do { \ + if (radius_put_uint32_attr(radpkt, (_a), (_v)) != 0) \ + goto reigai; \ + } while (0 /* CONSTCOND */) +#define ATTR_STR(_a,_v) \ + do { \ + if (radius_put_string_attr(radpkt, (_a), (_v)) != 0) \ + goto reigai; \ + } while (0 /* CONSTCOND */) + +static int +radius_acct_request(npppd *pppd, npppd_ppp *ppp, int stop) +{ + RADIUS_PACKET *radpkt; + RADIUS_REQUEST_CTX radctx; + radius_req_setting *rad_setting; + char buf[128]; + + if (ppp->username[0] == '\0') + return 0; + + radpkt = NULL; + radctx = NULL; + rad_setting = npppd_auth_radius_get_radius_acct_setting(ppp->realm); + if (!radius_req_setting_has_server(rad_setting)) + return 0; + if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST)) + == NULL) + goto reigai; + + if (radius_prepare(rad_setting, (void *)ppp->id, &radctx, + npppd_ppp_radius_acct_reqcb, 0) != 0) + goto reigai; + + /* NAS Information */ + /* + * RFC 2865 "5.4. NAS-IP-Address" or RFC 3162 "2.1. NAS-IPv6-Address" + */ + if (radius_prepare_nas_address(rad_setting, radpkt) != 0) + goto reigai; + + /* RFC 2865 "5.41. NAS-Port-Type" */ + ATTR_INT32(RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL); + + /* RFC 2865 "5.5. NAS-Port" */ + ATTR_INT32(RADIUS_TYPE_NAS_PORT, ppp->id); + /* npppd has no physical / virtual ports in design. */ + + /* RFC 2865 5.31. Calling-Station-Id */ + if (ppp->calling_number[0] != '\0') + ATTR_STR(RADIUS_TYPE_CALLING_STATION_ID, ppp->calling_number); + + /* Tunnel Protocol Information */ + switch (ppp->tunnel_type) { + case PPP_TUNNEL_L2TP: + /* RFC 2868 3.1. Tunnel-Type */ + ATTR_INT32(RADIUS_TYPE_TUNNEL_TYPE, RADIUS_TUNNEL_TYPE_L2TP); + if (l2tp_put_tunnel_attributes(radpkt, ppp->phy_context) != 0) + goto reigai; + break; + case PPP_TUNNEL_PPTP: + /* RFC 2868 3.1. Tunnel-Type */ + ATTR_INT32(RADIUS_TYPE_TUNNEL_TYPE, RADIUS_TUNNEL_TYPE_PPTP); + if (pptp_put_tunnel_attributes(radpkt, ppp->phy_context) != 0) + goto reigai; + break; + } + + /* Framed Protocol (PPP) Information */ + /* RFC 2865 5.1 User-Name */ + ATTR_STR(RADIUS_TYPE_USER_NAME, ppp->username); + + /* RFC 2865 "5.7. Service-Type" */ + ATTR_INT32(RADIUS_TYPE_SERVICE_TYPE, RADIUS_SERVICE_TYPE_FRAMED); + + /* RFC 2865 "5.8. Framed-Protocol" */ + ATTR_INT32(RADIUS_TYPE_FRAMED_PROTOCOL, RADIUS_FRAMED_PROTOCOL_PPP); + + /* RFC 2865 "5.8. Framed-IP-Address" */ + if (ppp_ip_assigned(ppp) && !stop) + ppp->realm_framed_ip_address = ppp->ppp_framed_ip_address; + if (ppp->realm_framed_ip_address.s_addr != INADDR_ANY) { + ATTR_INT32(RADIUS_TYPE_FRAMED_IP_ADDRESS, + ntohl(ppp->realm_framed_ip_address.s_addr)); + } + + /* Accounting */ + /* RFC 2866 5.1. Acct-Status-Type */ + ATTR_INT32(RADIUS_TYPE_ACCT_STATUS_TYPE, (stop) + ? RADIUS_ACCT_STATUS_TYPE_STOP : RADIUS_ACCT_STATUS_TYPE_START); + + /* RFC 2866 5.2. Acct-Delay-Time */ + ATTR_INT32(RADIUS_TYPE_ACCT_DELAY_TIME, 0); + + if (stop) { + /* RFC 2866 5.3 Acct-Input-Octets */ + ATTR_INT32(RADIUS_TYPE_ACCT_INPUT_OCTETS, + (uint32_t)(ppp->ibytes & 0xFFFFFFFFU)); /* LSB 32bit */ + + /* RFC 2866 5.4 Acct-Output-Octets */ + ATTR_INT32(RADIUS_TYPE_ACCT_OUTPUT_OCTETS, + (uint32_t)(ppp->obytes & 0xFFFFFFFFU)); /* LSB 32bit */ + } + + /* RFC 2866 5.5 Acct-Session-Id */ + snprintf(buf, sizeof(buf), "%08X%08X", pppd->boot_id, ppp->id); + ATTR_STR(RADIUS_TYPE_ACCT_SESSION_ID, buf); + + /* RFC 2866 5.6. Acct-Authentic */ + ATTR_INT32(RADIUS_TYPE_ACCT_AUTHENTIC, RADIUS_ACCT_AUTHENTIC_RADIUS); + + if (stop) { + /* RFC 2866 5.7. Acct-Session-Time */ + ATTR_INT32(RADIUS_TYPE_ACCT_SESSION_TIME, + ppp->end_monotime - ppp->start_monotime); + + /* RFC 2866 5.8 Acct-Input-Packets */ + ATTR_INT32(RADIUS_TYPE_ACCT_INPUT_PACKETS, ppp->ipackets); + + /* RFC 2866 5.9 Acct-Output-Packets */ + ATTR_INT32(RADIUS_TYPE_ACCT_OUTPUT_PACKETS, ppp->opackets); + + /* RFC 2866 5.10. Acct-Terminate-Cause */ + if (ppp->terminate_cause != 0) + ATTR_INT32(RADIUS_TYPE_ACCT_TERMINATE_CAUSE, + ppp->terminate_cause); + + /* RFC 2869 5.1 Acct-Input-Gigawords */ + ATTR_INT32(RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, ppp->ibytes >> 32); + + /* RFC 2869 5.2 Acct-Output-Gigawords */ + ATTR_INT32(RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS, + ppp->obytes >> 32); + } + + radius_set_request_authenticator(radpkt, + radius_get_server_secret(radctx)); + + /* Send the request */ + radius_request(radctx, radpkt); + + return 0; + +reigai: + ppp_log(ppp, LOG_WARNING, "radius accounting request failed: %m"); + + if (radctx != NULL) + radius_cancel_request(radctx); + if (radpkt != NULL) + radius_delete_packet(radpkt); + + return -1; +} + +#ifdef USE_NPPPD_PPTP +#include "pptp.h" +#endif + +static int +pptp_put_tunnel_attributes(RADIUS_PACKET *radpkt, void *call0) +{ +#ifdef USE_NPPPD_PPTP + pptp_call *call = call0; + pptp_ctrl *ctrl; + char hbuf[NI_MAXHOST], buf[128]; + + ctrl = call->ctrl; + + /* RFC 2868 3.2. Tunnel-Medium-Type */ + switch (ctrl->peer.ss_family) { + case AF_INET: + ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, + RADIUS_TUNNEL_MEDIUM_TYPE_IPV4); + break; + + case AF_INET6: + ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, + RADIUS_TUNNEL_MEDIUM_TYPE_IPV6); + break; + + default: + return -1; + } + + /* RFC 2868 3.3. Tunnel-Client-Endpoint */ + if (getnameinfo((struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) + return 1; + ATTR_STR(RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, hbuf); + + /* RFC 2868 3.4. Tunnel-Server-Endpoint */ + if (getnameinfo((struct sockaddr *)&ctrl->our, ctrl->our.ss_len, hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) + return 1; + ATTR_STR(RADIUS_TYPE_TUNNEL_SERVER_ENDPOINT, hbuf); + + /* RFC 2868 3.7. Tunnel-Assignment-ID */ + snprintf(buf, sizeof(buf), "PPTP-CALL-%d", call->id); + ATTR_STR(RADIUS_TYPE_TUNNEL_ASSIGNMENT_ID, buf); + + /* RFC 2867 4.1. Acct-Tunnel-Connection */ + snprintf(buf, sizeof(buf), "PPTP-CTRL-%d", ctrl->id); + ATTR_STR(RADIUS_TYPE_ACCT_TUNNEL_CONNECTION, buf); + + return 0; +reigai: +#endif + return 1; +} + +#ifdef USE_NPPPD_L2TP +#include "l2tp.h" +#endif + +static int +l2tp_put_tunnel_attributes(RADIUS_PACKET *radpkt, void *call0) +{ +#ifdef USE_NPPPD_L2TP + l2tp_call *call = call0; + l2tp_ctrl *ctrl; + char hbuf[NI_MAXHOST], buf[128]; + + ctrl = call->ctrl; + + /* RFC 2868 3.2. Tunnel-Medium-Type */ + switch (ctrl->peer.ss_family) { + case AF_INET: + ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, + RADIUS_TUNNEL_MEDIUM_TYPE_IPV4); + break; + + case AF_INET6: + ATTR_INT32(RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, + RADIUS_TUNNEL_MEDIUM_TYPE_IPV6); + break; + + default: + return -1; + } + + /* RFC 2868 3.3. Tunnel-Client-Endpoint */ + if (getnameinfo((struct sockaddr *)&ctrl->peer, ctrl->peer.ss_len, hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) + return 1; + ATTR_STR(RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, hbuf); + + /* RFC 2868 3.4. Tunnel-Server-Endpoint */ + if (getnameinfo((struct sockaddr *)&ctrl->sock, ctrl->sock.ss_len, hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) + return 1; + ATTR_STR(RADIUS_TYPE_TUNNEL_SERVER_ENDPOINT, hbuf); + + /* RFC 2868 3.7. Tunnel-Assignment-ID */ + snprintf(buf, sizeof(buf), "L2TP-CALL-%d", call->id); + ATTR_STR(RADIUS_TYPE_TUNNEL_ASSIGNMENT_ID, buf); + + /* RFC 2867 4.1. Acct-Tunnel-Connection */ + snprintf(buf, sizeof(buf), "L2TP-CTRL-%d", ctrl->id); + ATTR_STR(RADIUS_TYPE_ACCT_TUNNEL_CONNECTION, buf); + + return 0; +reigai: +#endif + return 1; +} diff --git a/usr.sbin/npppd/npppd/npppd_radius.h b/usr.sbin/npppd/npppd/npppd_radius.h new file mode 100644 index 00000000000..e9b7d743681 --- /dev/null +++ b/usr.sbin/npppd/npppd/npppd_radius.h @@ -0,0 +1,16 @@ +#ifndef NPPPD_RADIUS_H +#define NPPPD_RADIUS_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +void ppp_proccess_radius_framed_ip (npppd_ppp *, RADIUS_PACKET *); +int ppp_set_radius_attrs_for_authreq (npppd_ppp *, radius_req_setting *, RADIUS_PACKET *); +void npppd_ppp_radius_acct_start (npppd *, npppd_ppp *); +void npppd_ppp_radius_acct_stop (npppd *, npppd_ppp *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/usr.sbin/npppd/npppd/pap.c b/usr.sbin/npppd/npppd/pap.c index db8f9c1d87a..d5bf98408ee 100644 --- a/usr.sbin/npppd/npppd/pap.c +++ b/usr.sbin/npppd/npppd/pap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pap.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: pap.c,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -/* $Id: pap.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $Id: pap.c,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /**@file * This file provides Password Authentication Protocol (PAP) handlers. * @author Yasuoka Masahiko @@ -44,14 +44,18 @@ #include <stdlib.h> #include <string.h> #include <syslog.h> +#include <errno.h> #include "slist.h" #include "npppd.h" #include "ppp.h" #ifdef USE_NPPPD_RADIUS +#include <radius+.h> #include "radius_chap_const.h" +#include "npppd_radius.h" #endif + #include "debugutil.h" #define AUTHREQ 0x01 @@ -89,7 +93,7 @@ static void pap_authenticate(pap *, const char *); static void pap_local_authenticate (pap *, const char *, const char *); #ifdef USE_NPPPD_RADIUS static void pap_radius_authenticate (pap *, const char *, const char *); -static void pap_radius_response (void *, RADIUS_PACKET *, int); +static void pap_radius_response (void *, RADIUS_PACKET *, int, RADIUS_REQUEST_CTX); #endif #ifdef __cplusplus @@ -307,8 +311,9 @@ pap_response(pap *_this, int authok, const char *mes) "logtype=Failure username=\"%s\" realm=%s", _this->name, realm); pap_stop(_this); - ppp_stop_ex(_this->ppp, "Authentication Required", + ppp_set_disconnect_cause(_this->ppp, PPP_DISCON_AUTH_FAILED, PPP_PROTO_PAP, 1 /* peer */, NULL); + ppp_stop(_this->ppp, "Authentication Required"); } else { strlcpy(_this->ppp->username, _this->name, sizeof(_this->ppp->username)); @@ -388,7 +393,7 @@ pap_radius_authenticate(pap *_this, const char *username, const char *password) radius_req_setting *rad_setting = NULL; char buf0[MAX_USERNAME_LENGTH]; - if ((rad_setting = npppd_get_radius_req_setting(_this->ppp->pppd, + if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd, _this->ppp)) == NULL) goto fail; @@ -463,7 +468,8 @@ fail: } static void -pap_radius_response(void *context, RADIUS_PACKET *pkt, int flags) +pap_radius_response(void *context, RADIUS_PACKET *pkt, int flags, + RADIUS_REQUEST_CTX reqctx) { int code = -1; const char *reason = NULL; @@ -475,15 +481,12 @@ pap_radius_response(void *context, RADIUS_PACKET *pkt, int flags) _this->radctx = NULL; /* important */ if (pkt == NULL) { - if (flags & RADIUS_REQUST_TIMEOUT) { + if (flags & RADIUS_REQUEST_TIMEOUT) reason = "timeout"; - npppd_radius_server_failure_notify(_this->ppp->pppd, - _this->ppp, radctx, "request timeout"); - } else { + else if (flags & RADIUS_REQUEST_ERROR) + reason = strerror(errno); + else reason = "error"; - npppd_radius_server_failure_notify(_this->ppp->pppd, - _this->ppp, radctx, "unknown error"); - } goto auth_failed; } code = radius_get_code(pkt); @@ -494,11 +497,9 @@ pap_radius_response(void *context, RADIUS_PACKET *pkt, int flags) reason="error"; goto auth_failed; } - if ((flags & RADIUS_REQUST_CHECK_AUTHENTICTOR_OK) == 0 && - (flags & RADIUS_REQUST_CHECK_AUTHENTICTOR_NO_CHECK) == 0) { + if ((flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK) == 0 && + (flags & RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK) == 0) { reason="bad_authenticator"; - npppd_radius_server_failure_notify(_this->ppp->pppd, _this->ppp, - radctx, "bad authenticator"); goto auth_failed; } /* Autentication succeeded */ diff --git a/usr.sbin/npppd/npppd/ppp.c b/usr.sbin/npppd/npppd/ppp.c index 68740307922..fc772df8f5c 100644 --- a/usr.sbin/npppd/npppd/ppp.c +++ b/usr.sbin/npppd/npppd/ppp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ppp.c,v 1.7 2010/09/24 14:50:30 yasuoka Exp $ */ +/* $OpenBSD: ppp.c,v 1.8 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -/* $Id: ppp.c,v 1.7 2010/09/24 14:50:30 yasuoka Exp $ */ +/* $Id: ppp.c,v 1.8 2011/07/06 20:52:28 yasuoka Exp $ */ /**@file * This file provides PPP(Point-to-Point Protocol, RFC 1661) and * {@link :: _npppd_ppp PPP instance} related functions. @@ -54,6 +54,10 @@ #include "time_utils.h" #include "ppp.h" #include "psm-opt.h" +#ifdef USE_NPPPD_RADIUS +#include <radius+.h> +#include "npppd_radius.h" +#endif #include "debugutil.h" @@ -281,37 +285,54 @@ ppp_down_others(npppd_ppp *_this) evtimer_del(&_this->idle_event); } -void -ppp_stop(npppd_ppp *_this, const char *reason) -{ - ppp_stop_ex(_this, reason, PPP_DISCON_NO_INFORMATION, 0, 0, NULL); -} - /** * Stop the PPP and destroy the npppd_ppp instance * @param reason Reason of stopping the PPP. Specify NULL if there is * no special reason. This reason will be used as a * reason field of LCP Terminate-Request message and * notified to the peer. + */ +void +ppp_stop(npppd_ppp *_this, const char *reason) +{ + + PPP_ASSERT(_this != NULL); + +#ifdef USE_NPPPD_RADIUS + ppp_set_radius_terminate_cause(_this, + RADIUS_TERMNATE_CAUSE_ADMIN_RESET); +#endif + ppp_set_disconnect_cause(_this, PPP_DISCON_NORMAL, 0, 2 /* by local */, + NULL); + + ppp_down_others(_this); + fsm_close(&_this->lcp.fsm, reason); +} + +/** + * Set disconnect cause * @param code disconnect code in {@link ::npppd_ppp_disconnect_code}. * @param proto control protocol number. see RFC3145. * @param direction disconnect direction. see RFC 3145 */ void -ppp_stop_ex(npppd_ppp *_this, const char *reason, - npppd_ppp_disconnect_code code, int proto, int direction, - const char *message) +ppp_set_disconnect_cause(npppd_ppp *_this, npppd_ppp_disconnect_code code, + int proto, int direction, const char *message) { - PPP_ASSERT(_this != NULL); - if (_this->disconnect_code == PPP_DISCON_NO_INFORMATION) { _this->disconnect_code = code; _this->disconnect_proto = proto; _this->disconnect_direction = direction; _this->disconnect_message = message; } - ppp_down_others(_this); - fsm_close(&_this->lcp.fsm, reason); +} + +/** Set RADIUS Acct-Terminate-Cause code */ +void +ppp_set_radius_terminate_cause(npppd_ppp *_this, int cause) +{ + if (_this->terminate_cause == 0) + _this->terminate_cause = cause; } static void @@ -320,6 +341,12 @@ ppp_stop0(npppd_ppp *_this) char mppe_str[BUFSIZ]; char label[512]; +#ifdef USE_NPPPD_RADIUS + ppp_set_radius_terminate_cause(_this, RADIUS_TERMNATE_CAUSE_NAS_ERROR); +#endif + ppp_set_disconnect_cause(_this, PPP_DISCON_NORMAL, 0, 1 /* by local */, + NULL); + _this->end_monotime = get_monosec(); if (_this->phy_close != NULL) @@ -372,6 +399,9 @@ ppp_stop0(npppd_ppp *_this) _this->ierrors, _this->oerrors, mppe_str, npppd_ppp_get_iface_name(_this->pppd, _this)); +#ifdef USE_NPPPD_RADIUS + npppd_ppp_radius_acct_stop(_this->pppd, _this); +#endif npppd_ppp_unbind_iface(_this->pppd, _this); #ifdef USE_NPPPD_MPPE mppe_fini(&_this->mppe); @@ -500,6 +530,10 @@ ppp_phy_downed(npppd_ppp *_this) fsm_lowerdown(&_this->lcp.fsm); fsm_close(&_this->lcp.fsm, NULL); +#ifdef USE_NPPPD_RADIUS + ppp_set_radius_terminate_cause(_this, + RADIUS_TERMNATE_CAUSE_LOST_CARRIER); +#endif ppp_stop0(_this); } @@ -592,6 +626,10 @@ ppp_idle_timeout(int fd, short evtype, void *context) _this = context; ppp_log(_this, LOG_NOTICE, "Idle timeout(%d sec)", _this->timeout_sec); +#ifdef USE_NPPPD_RADIUS + ppp_set_radius_terminate_cause(_this, + RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT); +#endif ppp_stop(_this, NULL); } @@ -643,6 +681,10 @@ ppp_ipcp_opened(npppd_ppp *_this) ipstr, npppd_ppp_get_iface_name(_this->pppd, _this), (_this->lcp.dialin_proxy != 0)? " dialin_proxy=yes" : "" ); +#ifdef USE_NPPPD_RADIUS + npppd_ppp_radius_acct_start(_this->pppd, _this); +#endif + _this->logged_acct_start = 1; ppp_reset_idle_timeout(_this); } diff --git a/usr.sbin/npppd/npppd/ppp.h b/usr.sbin/npppd/npppd/ppp.h index 3f8658ba7ff..1b3879ef761 100644 --- a/usr.sbin/npppd/npppd/ppp.h +++ b/usr.sbin/npppd/npppd/ppp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ppp.h,v 1.5 2010/09/24 02:57:43 yasuoka Exp $ */ +/* $OpenBSD: ppp.h,v 1.6 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -520,6 +520,9 @@ struct _npppd_ppp { /** Address pool used by IP asssignment */ void *assigned_pool; + /** Framed-IP-Address for Accounting */ + struct in_addr acct_framed_ip_address; + struct in_addr realm_framed_ip_address; struct in_addr realm_framed_ip_netmask; @@ -581,6 +584,9 @@ struct _npppd_ppp { /** Number of output packet bytes */ uint64_t obytes; + /** RADIUS Accouting (RFC2866) Terminate Cause */ + int terminate_cause; + /* * Disconnect cause information for RFC3145 */ @@ -746,7 +752,8 @@ int ppp_init (npppd *, npppd_ppp *); void ppp_start (npppd_ppp *); int ppp_dialin_proxy_prepare (npppd_ppp *, dialin_proxy_info *); void ppp_stop (npppd_ppp *, const char *); -void ppp_stop_ex (npppd_ppp *, const char *, npppd_ppp_disconnect_code, int, int, const char *); +void ppp_set_disconnect_cause (npppd_ppp *, npppd_ppp_disconnect_code, int, int, const char *); +void ppp_set_radius_terminate_cause(npppd_ppp *, int); void ppp_destroy (void *); void ppp_lcp_up (npppd_ppp *); diff --git a/usr.sbin/npppd/npppd/radius+.c b/usr.sbin/npppd/npppd/radius+.c index b067349b51f..bf37cb7a19f 100644 --- a/usr.sbin/npppd/npppd/radius+.c +++ b/usr.sbin/npppd/npppd/radius+.c @@ -1,4 +1,4 @@ -/* $OpenBSD: radius+.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: radius+.c,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -33,10 +33,10 @@ #include <mpatrol.h> #endif +#include <sys/param.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> #include <md5.h> #include "radius+.h" #include "radiusconst.h" @@ -185,6 +185,11 @@ u_int8_t radius_get_id(const RADIUS_PACKET* packet) return packet->pdata->id; } +void radius_update_id(RADIUS_PACKET* packet) +{ + packet->pdata->id = radius_id_counter++; +} + void radius_get_authenticator(const RADIUS_PACKET* packet, char* authenticator) { memcpy(authenticator, packet->pdata->authenticator, 16); @@ -240,6 +245,23 @@ void radius_set_response_authenticator(RADIUS_PACKET* packet, MD5Final((unsigned char*)packet->pdata->authenticator ,&ctx); } +void radius_set_request_authenticator(RADIUS_PACKET* packet, + const char* secret) +{ + MD5_CTX ctx; + u_char zero[16]; + + memset(zero, 0, sizeof(zero)); + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*)packet->pdata, 4); + MD5Update(&ctx, zero, 16); + MD5Update(&ctx, + (unsigned char*)packet->pdata->attributes, + radius_get_length(packet) - 20); + MD5Update(&ctx, (unsigned char*)secret, strlen(secret)); + MD5Final((unsigned char*)packet->pdata->authenticator ,&ctx); +} + u_int16_t radius_get_length(const RADIUS_PACKET* packet) { return ntohs(packet->pdata->length); @@ -348,6 +370,31 @@ int radius_put_raw_attr_all(RADIUS_PACKET* packet, u_int8_t type, return 0; } +static int radius_set_raw_attr(RADIUS_PACKET* packet, u_int8_t type, + const void* buf, u_int8_t length) +{ + RADIUS_ATTRIBUTE* attr; + const RADIUS_ATTRIBUTE* end; + + if(length > 255-2) + return 1; + + attr = ATTRS_BEGIN(packet->pdata); + end = ATTRS_END(packet->pdata); + + for(; attr<end; ADVANCE(attr)) + { + if(attr->type != type) + continue; + if(attr->length != length + 2) + return 1; /* XXX */ + memcpy(attr->data, buf, length); + return 0; + } + + return 1; +} + int radius_get_vs_raw_attr(const RADIUS_PACKET* packet, u_int32_t vendor, u_int8_t vtype, void* buf, u_int8_t* length) { @@ -524,6 +571,14 @@ int radius_put_uint32_attr(RADIUS_PACKET* packet, u_int8_t type, u_int32_t val) return radius_put_raw_attr(packet, type, &nval, sizeof(u_int32_t)); } +int radius_set_uint32_attr(RADIUS_PACKET* packet, u_int8_t type, u_int32_t val) +{ + u_int32_t nval; + + nval = htonl(val); + return radius_set_raw_attr(packet, type, &nval, sizeof(u_int32_t)); +} + int radius_get_string_attr(const RADIUS_PACKET* packet, u_int8_t type, char* str) { @@ -590,6 +645,11 @@ int radius_put_ipv4_attr(RADIUS_PACKET* packet, u_int8_t type, struct in_addr ad return radius_put_raw_attr(packet, type, &addr, sizeof(struct in_addr)); } +int radius_set_ipv4_attr(RADIUS_PACKET* packet, u_int8_t type, struct in_addr addr) +{ + return radius_set_raw_attr(packet, type, &addr, sizeof(struct in_addr)); +} + RADIUS_PACKET* radius_recvfrom(int s, int flags, struct sockaddr* addr, socklen_t* len) { char buf[0x10000]; @@ -613,6 +673,28 @@ int radius_sendto(int s, const RADIUS_PACKET* packet, return 0; } +RADIUS_PACKET* radius_recv(int s, int flags) +{ + char buf[0x10000]; + ssize_t n; + + n = recv(s, buf, sizeof(buf), flags); + if(n <= 0) + return NULL; + + return radius_convert_packet(buf, (size_t)n); +} + +int radius_send(int s, const RADIUS_PACKET* packet, int flags) +{ + ssize_t n; + + n = send(s, packet->pdata, radius_get_length(packet), flags); + if(n != radius_get_length(packet)) + return 1; + return 0; +} + /** * Calculate keyed-hashing for message authenticaiton using md5. * diff --git a/usr.sbin/npppd/npppd/radius+.h b/usr.sbin/npppd/npppd/radius+.h index a239f17f045..0bdef81e3bf 100644 --- a/usr.sbin/npppd/npppd/radius+.h +++ b/usr.sbin/npppd/npppd/radius+.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radius+.h,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: radius+.h,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -55,11 +55,14 @@ int radius_delete_packet(RADIUS_PACKET* packet); /* accessors - header values */ u_int8_t radius_get_id(const RADIUS_PACKET* packet); +void radius_update_id(RADIUS_PACKET* packet); u_int8_t radius_get_code(const RADIUS_PACKET* packet); void radius_get_authenticator(const RADIUS_PACKET* packet, char* authenticator); void radius_set_request_packet(RADIUS_PACKET* packet, const RADIUS_PACKET* response); int radius_check_response_authenticator(const RADIUS_PACKET* packet, const char *secret); const char* radius_get_authenticator_retval(const RADIUS_PACKET* packet); +void radius_set_request_authenticator(RADIUS_PACKET* packet, + const char* secret); void radius_set_response_authenticator(RADIUS_PACKET* packet, const char* secret); u_int16_t radius_get_length(const RADIUS_PACKET* packet); @@ -93,6 +96,8 @@ u_int32_t radius_get_uint32_attr_retval(const RADIUS_PACKET* packet, u_int8_t type); int radius_put_uint32_attr(RADIUS_PACKET* packet, u_int8_t type, u_int32_t val); +int radius_set_uint32_attr(RADIUS_PACKET* packet, u_int8_t type, u_int32_t val); + int radius_get_string_attr(const RADIUS_PACKET* packet, u_int8_t type, char* str); int radius_put_string_attr(RADIUS_PACKET* packet, u_int8_t type, @@ -107,6 +112,8 @@ int radius_get_ipv4_attr(const RADIUS_PACKET* packet, u_int8_t type, struct in_addr radius_get_ipv4_attr_retval(const RADIUS_PACKET* packet, u_int8_t type); int radius_put_ipv4_attr(RADIUS_PACKET* packet, u_int8_t type, struct in_addr addr); +int radius_set_ipv4_attr(RADIUS_PACKET* packet, u_int8_t type, + struct in_addr addr); int radius_put_message_authenticator(RADIUS_PACKET *packet, const char *secret); int radius_check_message_authenticator(RADIUS_PACKET *packet, const char *secret); @@ -116,6 +123,8 @@ RADIUS_PACKET* radius_recvfrom(int s, int flags, struct sockaddr* saddr, socklen_t* slen); int radius_sendto(int s, const RADIUS_PACKET* packet, int flags, const struct sockaddr* saddr, socklen_t slen); +RADIUS_PACKET* radius_recv(int s, int flags); +int radius_send(int s, const RADIUS_PACKET* packet, int flags); /******* client support (sending request / receiving response) *******/ diff --git a/usr.sbin/npppd/npppd/radius+_local.h b/usr.sbin/npppd/npppd/radius+_local.h index 450016cefc2..4d3601362ba 100644 --- a/usr.sbin/npppd/npppd/radius+_local.h +++ b/usr.sbin/npppd/npppd/radius+_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radius+_local.h,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: radius+_local.h,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -77,8 +77,4 @@ extern u_int8_t radius_id_counter; #define ATTRS_END(pdata) \ ((RADIUS_ATTRIBUTE*)(((char*)pdata) + ntohs(pdata->length))) -#ifndef MIN -#define MIN(m,n) (((m) < (n))? (m) : (n)) -#endif - #endif /* RADIUSPLUS_LOCAL_H */ diff --git a/usr.sbin/npppd/npppd/radius_common.c b/usr.sbin/npppd/npppd/radius_common.c index 39484590481..e69de29bb2d 100644 --- a/usr.sbin/npppd/npppd/radius_common.c +++ b/usr.sbin/npppd/npppd/radius_common.c @@ -1,74 +0,0 @@ -/* $OpenBSD: radius_common.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ - -/*- - * Copyright (c) 2009 Internet Initiative Japan Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/**@file - * This file provides functions commonly used for RADIUS request. - * @author Yasuoka Masahiko - * $Id: radius_common.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ - */ -#include <sys/types.h> -#include <sys/param.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <time.h> -#include <event.h> -#include <stdio.h> - -#include <radius+.h> -#include <radiusconst.h> - -#include "slist.h" -#include "npppd.h" -#include "npppd_local.h" - -#include "radius_common.h" - -void -ppp_proccess_radius_framed_ip_address(npppd_ppp *_this, RADIUS_PACKET *pkt) -{ - uint8_t len; - u_char buf[256], *bufp; - - if ((_this->pppd->ip_assign_flags & NPPPD_IP_ASSIGN_RADIUS) == 0) - return; - - if (radius_get_raw_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, buf, - &len) != 0) - return; - - bufp = buf; - if (len == 4) - GETLONG(_this->radius_framed_ip_address.s_addr, bufp); - -} - -radius_req_setting * -npppd_get_radius_req_setting(npppd *_this) -{ - return &_this->rad_auth; -} diff --git a/usr.sbin/npppd/npppd/radius_common.h b/usr.sbin/npppd/npppd/radius_common.h index 0754232314b..e69de29bb2d 100644 --- a/usr.sbin/npppd/npppd/radius_common.h +++ b/usr.sbin/npppd/npppd/radius_common.h @@ -1,42 +0,0 @@ -/* $OpenBSD: radius_common.h,v 1.2 2010/07/02 21:20:57 yasuoka Exp $ */ - -/*- - * Copyright (c) 2009 Internet Initiative Japan Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#ifndef RADIUS_COMMON_H -#define RADIUS_COMMON_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -void ppp_proccess_radius_framed_ip_address (npppd_ppp *, RADIUS_PACKET *); -radius_req_setting *npppd_get_radius_req_setting (npppd *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/usr.sbin/npppd/npppd/radius_req.c b/usr.sbin/npppd/npppd/radius_req.c index 1d97ac0d8dc..1b9d098eb99 100644 --- a/usr.sbin/npppd/npppd/radius_req.c +++ b/usr.sbin/npppd/npppd/radius_req.c @@ -1,4 +1,4 @@ -/* $OpenBSD: radius_req.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: radius_req.c,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -28,7 +28,7 @@ /**@file * This file provides functions for RADIUS request using radius+.c and event(3). * @author Yasuoka Masahiko - * $Id: radius_req.c,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ + * $Id: radius_req.c,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ #include <sys/types.h> #include <sys/param.h> @@ -45,26 +45,40 @@ #include <time.h> #include <event.h> #include <string.h> +#include <errno.h> #include "radius_req.h" +#ifndef nitems +#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) +#endif + struct overlapped { struct event ev_sock; int socket; int ntry; - int timeout; + int max_tries; + int failovers; struct sockaddr_storage ss; + struct timespec req_time; void *context; radius_response *response_fn; char secret[MAX_RADIUS_SECRET]; RADIUS_PACKET *pkt; + radius_req_setting *setting; + int acct_delay_time; }; -static int radius_request0 (struct overlapped *); +static int radius_request0 (struct overlapped *, int); +static int radius_prepare_socket(struct overlapped *); static void radius_request_io_event (int, short, void *); -static int select_srcaddr(struct sockaddr const *, struct sockaddr *, socklen_t *); +static void radius_on_response(RADIUS_REQUEST_CTX, RADIUS_PACKET *, int, int); +static int select_srcaddr(struct sockaddr const *, struct sockaddr *, socklen_t *); +static void radius_req_setting_ref(radius_req_setting *); +static void radius_req_setting_unref(radius_req_setting *); #ifdef RADIUS_REQ_DEBUG +#define RADIUS_REQ_DBG(x) log_printf x #define RADIUS_REQ_ASSERT(cond) \ if (!(cond)) { \ fprintf(stderr, \ @@ -74,6 +88,7 @@ static int select_srcaddr(struct sockaddr const *, struct sockaddr *, socklen_t } #else #define RADIUS_REQ_ASSERT(cond) +#define RADIUS_REQ_DBG(x) #endif /** @@ -83,17 +98,17 @@ static int select_srcaddr(struct sockaddr const *, struct sockaddr *, socklen_t void radius_request(RADIUS_REQUEST_CTX ctx, RADIUS_PACKET *pkt) { + uint32_t ival; struct overlapped *lap; RADIUS_REQ_ASSERT(pkt != NULL); RADIUS_REQ_ASSERT(ctx != NULL); lap = ctx; lap->pkt = pkt; - if (radius_request0(lap) != 0) { - if (lap->response_fn != NULL) - lap->response_fn(lap->context, NULL, - RADIUS_REQUST_ERROR); - } + if (radius_get_uint32_attr(pkt, RADIUS_TYPE_ACCT_DELAY_TIME, &ival) + == 0) + lap->acct_delay_time = 1; + radius_request0(lap, 0); } /** @@ -156,6 +171,83 @@ fail: return 1; } + +/** Checks whether the request can fail over to another server */ +int +radius_request_can_failover(RADIUS_REQUEST_CTX ctx) +{ + struct overlapped *lap; + radius_req_setting *setting; + + lap = ctx; + setting = lap->setting; + + if (lap->failovers >= setting->max_failovers) + return 0; + if (memcmp(&lap->ss, &setting->server[setting->curr_server].peer, + setting->server[setting->curr_server].peer.sin6.sin6_len) == 0) + /* flagged server doesn't differ from the last server. */ + return 0; + + return 1; +} + +/** Send RADIUS request failing over to another server. */ +int +radius_request_failover(RADIUS_REQUEST_CTX ctx) +{ + struct overlapped *lap; + + lap = ctx; + RADIUS_REQ_ASSERT(lap != NULL); + RADIUS_REQ_ASSERT(lap->socket >= 0) + + if (!radius_request_can_failover(lap)) + return -1; + + if (radius_prepare_socket(lap) != 0) + return -1; + + if (radius_request0(lap, 1) != 0) + return -1; + + lap->failovers++; + + return 0; +} + +static int +radius_prepare_socket(struct overlapped *lap) +{ + int sock; + radius_req_setting *setting; + struct sockaddr *sa; + + setting = lap->setting; + if (lap->socket >= 0) + close(lap->socket); + lap->socket = -1; + + sa = (struct sockaddr *)&setting->server[setting->curr_server].peer; + + if ((sock = socket(sa->sa_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + log_printf(LOG_ERR, "socket() failed in %s: %m", __func__); + return -1; + } + if (connect(sock, sa, sa->sa_len) != 0) { + log_printf(LOG_ERR, "connect() failed in %s: %m", __func__); + close(sock); + return -1; + } + memcpy(&lap->ss, sa, sa->sa_len); + lap->socket = sock; + memcpy(lap->secret, setting->server[setting->curr_server].secret, + sizeof(lap->secret)); + lap->ntry = lap->max_tries; + + return 0; +} + /** * Prepare sending RADIUS request. This implementation will call back to * notice that it receives the response or it fails for timeouts to the @@ -175,9 +267,7 @@ int radius_prepare(radius_req_setting *setting, void *context, RADIUS_REQUEST_CTX *pctx, radius_response response_fn, int timeout) { - int sock; struct overlapped *lap; - struct sockaddr_in6 *sin6; RADIUS_REQ_ASSERT(setting != NULL); lap = NULL; @@ -188,25 +278,30 @@ radius_prepare(radius_req_setting *setting, void *context, log_printf(LOG_ERR, "malloc() failed in %s: %m", __func__); goto fail; } - sin6 = &setting->server[setting->curr_server].peer.sin6; - if ((sock = socket(sin6->sin6_family, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - log_printf(LOG_ERR, "socket() failed in %s: %m", __func__); - goto fail; - } memset(lap, 0, sizeof(struct overlapped)); - memcpy(&lap->ss, &setting->server[setting->curr_server].peer, - setting->server[setting->curr_server].peer.sin6.sin6_len); - - lap->socket = sock; - lap->timeout = MIN(setting->timeout, timeout); - lap->ntry = timeout / lap->timeout; lap->context = context; lap->response_fn = response_fn; - memcpy(lap->secret, setting->server[setting->curr_server].secret, - sizeof(lap->secret)); + lap->socket = -1; + lap->setting = setting; + + if (timeout != 0 && + (setting->max_tries == 0 || + timeout < setting->max_tries * setting->timeout)) + lap->max_tries = timeout / setting->timeout; + else + lap->max_tries = setting->max_tries; + + if (lap->max_tries <= 0) + lap->max_tries = 3; /* default max tries */ + + if (radius_prepare_socket(lap) != 0) + goto fail; + if (pctx != NULL) *pctx = lap; + radius_req_setting_ref(setting); + return 0; fail: if (lap != NULL) @@ -234,6 +329,8 @@ radius_cancel_request(RADIUS_REQUEST_CTX ctx) radius_delete_packet(lap->pkt); lap->pkt = NULL; } + radius_req_setting_unref(lap->setting); + memset(lap->secret, 0x41, sizeof(lap->secret)); free(lap); @@ -264,20 +361,47 @@ radius_get_server_address(RADIUS_REQUEST_CTX ctx) } static int -radius_request0(struct overlapped *lap) +radius_request0(struct overlapped *lap, int new_message) { struct timeval tv0; RADIUS_REQ_ASSERT(lap->ntry > 0); + if (lap->acct_delay_time != 0) { + struct timespec curr, delta; + + if (clock_gettime(CLOCK_MONOTONIC, &curr) != 0) { + log_printf(LOG_CRIT, + "clock_gettime(CLOCK_MONOTONIC,) failed: %m"); + RADIUS_REQ_ASSERT(0); + } + if (!timespecisset(&lap->req_time)) + lap->req_time = curr; + else { + timespecsub(&curr, &lap->req_time, &delta); + if (radius_set_uint32_attr(lap->pkt, + RADIUS_TYPE_ACCT_DELAY_TIME, delta.tv_sec) == 0) { + radius_update_id(lap->pkt); + new_message = 1; + } + } + } + if (new_message) { + radius_set_request_authenticator(lap->pkt, + radius_get_server_secret(lap)); + } + lap->ntry--; - if (radius_sendto(lap->socket, lap->pkt, 0, (struct sockaddr *) - &lap->ss, lap->ss.ss_len) != 0) + if (radius_send(lap->socket, lap->pkt, 0) != 0) { + log_printf(LOG_ERR, "sendto() failed in %s: %m", + __func__); + radius_on_response(lap, NULL, RADIUS_REQUEST_ERROR, 1); return 1; + } tv0.tv_usec = 0; - tv0.tv_sec = lap->timeout; + tv0.tv_sec = lap->setting->timeout; - event_set(&lap->ev_sock, lap->socket, EV_READ, + event_set(&lap->ev_sock, lap->socket, EV_READ | EV_PERSIST, radius_request_io_event, lap); event_add(&lap->ev_sock, &tv0); @@ -295,53 +419,87 @@ radius_request_io_event(int fd, short evmask, void *context) RADIUS_REQ_ASSERT(context != NULL); + lap = context; + respkt = NULL; + flags = 0; if ((evmask & EV_READ) != 0) { - lap = context; - flags = 0; - RADIUS_REQ_ASSERT(lap->socket >= 0); if (lap->socket < 0) return; RADIUS_REQ_ASSERT(lap->pkt != NULL); - memset(&ss, 0, sizeof(ss)); len = sizeof(ss); - if ((respkt = radius_recvfrom(lap->socket, 0, - (struct sockaddr *)&ss, &len)) == NULL) { - log_printf(LOG_ERR, "recvfrom() failed in %s: %m", - __func__); - flags |= RADIUS_REQUST_ERROR; + if ((respkt = radius_recv(lap->socket, 0)) == NULL) { + RADIUS_REQ_DBG((LOG_DEBUG, + "radius_recv() on %s(): %m", __func__)); + /* + * Ignore error by icmp. Wait a response from the + * server anyway, it may eventually become ready. + */ + switch (errno) { + case EHOSTDOWN: case EHOSTUNREACH: case ECONNREFUSED: + return; /* sleep the rest of timeout time */ + } + flags |= RADIUS_REQUEST_ERROR; } else if (lap->secret[0] == '\0') { - flags |= RADIUS_REQUST_CHECK_AUTHENTICTOR_NO_CHECK; + flags |= RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK; } else { radius_set_request_packet(respkt, lap->pkt); if (!radius_check_response_authenticator(respkt, lap->secret)) - flags |= RADIUS_REQUST_CHECK_AUTHENTICTOR_OK; + flags |= RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK; } - - if (lap->response_fn != NULL) - lap->response_fn(lap->context, respkt, flags); - - if (respkt != NULL) - radius_delete_packet(respkt); - radius_cancel_request(lap); + radius_on_response(lap, respkt, flags, 0); + radius_delete_packet(respkt); } else if ((evmask & EV_TIMEOUT) != 0) { - lap = context; if (lap->ntry > 0) { - if (radius_request0(lap) != 0) { - if (lap->response_fn != NULL) - lap->response_fn(lap->context, NULL, - RADIUS_REQUST_ERROR); - radius_cancel_request(lap); - } + RADIUS_REQ_DBG((LOG_DEBUG, + "%s() timed out retry", __func__)); + radius_request0(lap, 0); return; } - if (lap->response_fn != NULL) - lap->response_fn(lap->context, NULL, - RADIUS_REQUST_TIMEOUT); - radius_cancel_request(lap); + RADIUS_REQ_DBG((LOG_DEBUG, "%s() timed out", __func__)); + flags |= RADIUS_REQUEST_TIMEOUT; + radius_on_response(lap, NULL, flags, 1); + } +} + +static void +radius_on_response(RADIUS_REQUEST_CTX ctx, RADIUS_PACKET *pkt, int flags, + int server_failure) +{ + struct overlapped *lap; + int failovers; + + lap = ctx; + if (server_failure) { + int i, n; + struct sockaddr *sa_curr; + + sa_curr = (struct sockaddr *)&lap->setting->server[ + lap->setting->curr_server].peer; + if (sa_curr->sa_len == lap->ss.ss_len && + memcmp(sa_curr, &lap->ss, sa_curr->sa_len) == 0) { + /* + * The server on failure is flagged as the current. + * change the current + */ + for (i = 1; i < nitems(lap->setting->server); i++) { + n = (lap->setting->curr_server + i) % + nitems(lap->setting->server); + if (lap->setting->server[n].enabled) { + lap->setting->curr_server = n; + break; + } + } + } } + + failovers = lap->failovers; + if (lap->response_fn != NULL) + lap->response_fn(lap->context, pkt, flags, ctx); + if (failovers == lap->failovers) + radius_cancel_request(lap); } static int @@ -367,3 +525,44 @@ fail: return 1; } + +radius_req_setting * +radius_req_setting_create(void) +{ + radius_req_setting *setting; + + if ((setting = malloc(sizeof(radius_req_setting))) == NULL) + return NULL; + memset(setting, 0, sizeof(radius_req_setting)); + + return setting; +} + +int +radius_req_setting_has_server(radius_req_setting *setting) +{ + return setting->server[setting->curr_server].enabled; +} + +void +radius_req_setting_destroy(radius_req_setting *setting) +{ + setting->destroyed = 1; + + if (setting->refcnt == 0) + free(setting); +} + +static void +radius_req_setting_ref(radius_req_setting *setting) +{ + setting->refcnt++; +} + +static void +radius_req_setting_unref(radius_req_setting *setting) +{ + setting->refcnt--; + if (setting->destroyed) + radius_req_setting_destroy(setting); +} diff --git a/usr.sbin/npppd/npppd/radius_req.h b/usr.sbin/npppd/npppd/radius_req.h index 65caf36bf00..b2a70146ca4 100644 --- a/usr.sbin/npppd/npppd/radius_req.h +++ b/usr.sbin/npppd/npppd/radius_req.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radius_req.h,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: radius_req.h,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -35,23 +35,23 @@ #define MAX_RADIUS_SERVERS 16 /** RADIUS request failed */ -#define RADIUS_REQUST_ERROR 0x0001 +#define RADIUS_REQUEST_ERROR 0x0001 /** RADIUS request timed out */ -#define RADIUS_REQUST_TIMEOUT 0x0002 +#define RADIUS_REQUEST_TIMEOUT 0x0002 /** response has valid authenticator */ -#define RADIUS_REQUST_CHECK_AUTHENTICTOR_OK 0x0010 +#define RADIUS_REQUEST_CHECK_AUTHENTICATOR_OK 0x0010 /** authenticator is not checked */ -#define RADIUS_REQUST_CHECK_AUTHENTICTOR_NO_CHECK 0x0020 - -/** type for callback function to receive the RADIUS response */ -typedef void (radius_response)(void *context, RADIUS_PACKET *pkt, int flags); +#define RADIUS_REQUEST_CHECK_AUTHENTICATOR_NO_CHECK 0x0020 /** type for context to handle RADIUS request / response */ typedef void * RADIUS_REQUEST_CTX; +/** type for callback function to receive the RADIUS response */ +typedef void (radius_response)(void *context, RADIUS_PACKET *pkt, int flags, RADIUS_REQUEST_CTX reqctx); + /** type for setting of RADIUS request */ typedef struct _radius_req_setting { @@ -74,18 +74,33 @@ typedef struct _radius_req_setting int curr_server; /** request timeout(in second) */ int timeout; + /** The maximum number of RADIUS request transmission */ + int max_tries; + /** The maximum number of RADIUS request failover */ + int max_failovers; + + /** references by radius request */ + int refcnt; + /** destroy is requested */ + int destroyed; + } radius_req_setting; #ifdef __cplusplus extern "C" { #endif -int radius_prepare (radius_req_setting *, void *, RADIUS_REQUEST_CTX *, radius_response *, int); -void radius_request (RADIUS_REQUEST_CTX, RADIUS_PACKET *); -void radius_cancel_request (RADIUS_REQUEST_CTX); -const char *radius_get_server_secret(RADIUS_REQUEST_CTX); -struct sockaddr *radius_get_server_address(RADIUS_REQUEST_CTX); -int radius_prepare_nas_address(radius_req_setting *, RADIUS_PACKET *); +void radius_request (RADIUS_REQUEST_CTX, RADIUS_PACKET *); +int radius_prepare_nas_address (radius_req_setting *, RADIUS_PACKET *); +int radius_request_can_failover (RADIUS_REQUEST_CTX); +int radius_request_failover (RADIUS_REQUEST_CTX); +int radius_prepare (radius_req_setting *, void *, RADIUS_REQUEST_CTX *, radius_response, int); +void radius_cancel_request (RADIUS_REQUEST_CTX); +const char *radius_get_server_secret (RADIUS_REQUEST_CTX); +struct sockaddr *radius_get_server_address (RADIUS_REQUEST_CTX); +radius_req_setting *radius_req_setting_create (void); +int radius_req_setting_has_server(radius_req_setting *); +void radius_req_setting_destroy (radius_req_setting *); #ifdef __cplusplus } diff --git a/usr.sbin/npppd/npppd/radiusconst.h b/usr.sbin/npppd/npppd/radiusconst.h index 91056b4bcd0..0fbbe0a9e5f 100644 --- a/usr.sbin/npppd/npppd/radiusconst.h +++ b/usr.sbin/npppd/npppd/radiusconst.h @@ -1,4 +1,4 @@ -/* $OpenBSD: radiusconst.h,v 1.3 2010/07/02 21:20:57 yasuoka Exp $ */ +/* $OpenBSD: radiusconst.h,v 1.4 2011/07/06 20:52:28 yasuoka Exp $ */ /*- * Copyright (c) 2009 Internet Initiative Japan Inc. @@ -138,18 +138,18 @@ #define RADIUS_TYPE_TUNNEL_CLIENT_AUTH_ID 90 #define RADIUS_TYPE_TUNNEL_SERVER_AUTH_ID 91 -/* RFC 3162 "RADIUS and IPv6" */ -#define RADIUS_TYPE_NAS_IPV6_ADDRESS 95 -#define RADIUS_TYPE_FRAMED_INTERFACE_ID 96 -#define RADIUS_TYPE_FRAMED_IPV6_PREFIX 97 -#define RADIUS_TYPE_LOGIN_IPV6_HOST 98 -#define RADIUS_TYPE_FRAMED_IPV6_ROUTE 99 -#define RADIUS_TYPE_FRAMED_IPV6_POOL 100 /* RFC 2865 "5.6. Service-Type" */ -#define RADIUS_FRAMED_PROTOCOL_PPP 1 +#define RADIUS_FRAMED_PROTOCOL_PPP 1 /* PPP */ +#define RADIUS_FRAMED_PROTOCOL_SLIP 2 /* SLIP */ +#define RADIUS_FRAMED_PROTOCOL_ARAP 3 /* AppleTalk Remote Access Protocol + (ARAP) */ +#define RADIUS_FRAMED_PROTOCOL_GANDALF 4 /* Gandalf proprietary + SingleLink/MultiLink protocol */ +#define RADIUS_FRAMED_PROTOCOL_XYLOGICS 5 /* Xylogics proprietary IPX/SLIP */ +#define RADIUS_FRAMED_PROTOCOL_X75 6 /* X.75 Synchronous */ -/* RFC 2865 "5.7. Framed-Protocol" */ +/* RFC 2865 "5.7. Service-Type" */ #define RADIUS_SERVICE_TYPE_LOGIN 1 #define RADIUS_SERVICE_TYPE_FRAMED 2 #define RADIUS_SERVICE_TYPE_CB_LOGIN 3 @@ -197,6 +197,113 @@ /* unassigned? 32 */ #define RADIUS_VTYPE_MS_ARAP_CHALLENGE 33 +/* NAS-Port-Type: see RFC2865 */ +#define RADIUS_NAS_PORT_TYPE_ASYNC 0 /* Async */ +#define RADIUS_NAS_PORT_TYPE_SYNC 1 /* Sync */ +#define RADIUS_NAS_PORT_TYPE_ISDN_SYNC 2 /* ISDN Sync */ +#define RADIUS_NAS_PORT_TYPE_ISDN_ASYNC_V120 3 /* ISDN Async V.120 */ +#define RADIUS_NAS_PORT_TYPE_ISDN_ASYNC_V110 4 /* ISDN Async V.110 */ +#define RADIUS_NAS_PORT_TYPE_VIRTUAL 5 /* Virtual */ +#define RADIUS_NAS_PORT_TYPE_PIAFS 6 /* PIAFS */ +#define RADIUS_NAS_PORT_TYPE_HDLC_CLEAR_CHANNEL 7 /* HDLC Clear Channel */ +#define RADIUS_NAS_PORT_TYPE_X_25 8 /* X.25 */ +#define RADIUS_NAS_PORT_TYPE_X_75 9 /* X.75 */ +#define RADIUS_NAS_PORT_TYPE_G3_FAX 10 /* G.3 Fax */ +#define RADIUS_NAS_PORT_TYPE_SDSL 11 /* SDSL - Symmetric DSL */ +#define RADIUS_NAS_PORT_TYPE_ADSL_CAP 12 /* ADSL-CAP - Asymmetric DSL, + Carrierless Amplitude + Phase Modulation */ +#define RADIUS_NAS_PORT_TYPE_ADSL_DMT 13 /* ADSL-DMT - Asymmetric DSL, + Discrete Multi-Tone */ +#define RADIUS_NAS_PORT_TYPE_IDSL 14 /* IDSL - ISDN Digital + Subscriber Line */ +#define RADIUS_NAS_PORT_TYPE_ETHERNET 15 /* Ethernet */ +#define RADIUS_NAS_PORT_TYPE_XDSL 16 /* xDSL - Digital Subscriber + Line of unknown type */ +#define RADIUS_NAS_PORT_TYPE_CABLE 17 /* Cable */ +#define RADIUS_NAS_PORT_TYPE_WIRELESS 18 /* Wireless - Other */ +#define RADIUS_NAS_PORT_TYPE_WIRELESS_802_11 19 /* Wireless - IEEE 802.11 */ + + +/* RFC 2866 5.1. Acct-Status-Type */ +#define RADIUS_ACCT_STATUS_TYPE_START 1 /* Start */ +#define RADIUS_ACCT_STATUS_TYPE_STOP 2 /* Stop */ +#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3 /* Interim-Update */ +#define RADIUS_ACCT_STATUS_TYPE_ACCT_ON 7 /* Accounting-On */ +#define RADIUS_ACCT_STATUS_TYPE_ACCT_OFF 8 /* Accounting-Off */ + + +/* RFC 2866 5.6. Acct-Authentic */ +#define RADIUS_ACCT_AUTHENTIC_RADIUS 1 /* RADIUS */ +#define RADIUS_ACCT_AUTHENTIC_LOCAL 2 /* Local */ +#define RADIUS_ACCT_AUTHENTIC_REMOTE 3 /* Remote */ + + +/* RFC 2866 5.10. Acct-Terminate-Cause */ +#define RADIUS_TERMNATE_CAUSE_USER_REQUEST 1 /* User Request */ +#define RADIUS_TERMNATE_CAUSE_LOST_CARRIER 2 /* Lost Carrier */ +#define RADIUS_TERMNATE_CAUSE_LOST_SERVICE 3 /* Lost Service */ +#define RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT 4 /* Idle Timeout */ +#define RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT 5 /* Session Timeout */ +#define RADIUS_TERMNATE_CAUSE_ADMIN_RESET 6 /* Admin Reset */ +#define RADIUS_TERMNATE_CAUSE_ADMIN_REBOOT 7 /* Admin Reboot */ +#define RADIUS_TERMNATE_CAUSE_PORT_ERROR 8 /* Port Error */ +#define RADIUS_TERMNATE_CAUSE_NAS_ERROR 9 /* NAS Error */ +#define RADIUS_TERMNATE_CAUSE_NAS_RESET 10 /* NAS Request */ +#define RADIUS_TERMNATE_CAUSE_NAS_REBOOT 11 /* NAS Reboot */ +#define RADIUS_TERMNATE_CAUSE_PORT_UNNEEDED 12 /* Port Unneeded */ +#define RADIUS_TERMNATE_CAUSE_PORT_PREEMPTED 13 /* Port Preempted */ +#define RADIUS_TERMNATE_CAUSE_PORT_SUSPENDED 14 /* Port Suspended */ +#define RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL 15 /* Service Unavailable */ +#define RADIUS_TERMNATE_CAUSE_CALLBACK 16 /* Callback */ +#define RADIUS_TERMNATE_CAUSE_USER_ERROR 17 /* User Error */ +#define RADIUS_TERMNATE_CAUSE_HOST_REQUEST 18 /* Host Request */ + + +/* RFC 2868 3.1. Tunnel-Type */ +#define RADIUS_TUNNEL_TYPE_PPTP 1 /* Point-to-Point Tunneling Protocol + (PPTP) */ +#define RADIUS_TUNNEL_TYPE_L2F 2 /* Layer Two Forwarding (L2F) */ +#define RADIUS_TUNNEL_TYPE_L2TP 3 /* Layer Two Tunneling Protocol + (L2TP) */ +#define RADIUS_TUNNEL_TYPE_ATMP 4 /* Ascend Tunnel Management Protocol + (ATMP) */ +#define RADIUS_TUNNEL_TYPE_VTP 5 /* Virtual Tunneling Protocol (VTP)*/ +#define RADIUS_TUNNEL_TYPE_AH 6 /* IP Authentication Header in the + Tunnel-mode (AH) */ +#define RADIUS_TUNNEL_TYPE_IP 7 /* IP-in-IP Encapsulation (IP-IP) */ +#define RADIUS_TUNNEL_TYPE_MOBILE 8 /* Minimal IP-in-IP Encapsulation + (MIN-IP-IP) */ +#define RADIUS_TUNNEL_TYPE_ESP 9 /* IP Encapsulating Security Payload + in the Tunnel-mode (ESP) */ +#define RADIUS_TUNNEL_TYPE_GRE 10 /* Generic Route Encapsulation + (GRE) */ +#define RADIUS_TUNNEL_TYPE_VDS 11 /* Bay Dial Virtual Services (DVS) */ +#define RADIUS_TUNNEL_TYPE_IPIP 12 /* IP-in-IP Tunneling */ + +/* RFC 2868 3.2. Tunnel-Medium-Type */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1 /* IPv4 (IP version 4) */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2 /* IPv6 (IP version 6) */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_NSAP 3 /* NSAP */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_HDLC 4 /* HDLC (8-bit multidrop) */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_BBN1822 5 /* BBN 1822 */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6 /* 802 (includes all 802 + media plus Ethernet + "canonical format") */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_E163 7 /* E.163 (POTS) */ +#define RADIUS_TUNNEL_MEDIUM_TYPE_E164 8 /* E.164 (SMDS, Frame Relay, + ATM) */ + + +/* RFC 3162 "RADIUS and IPv6" */ +#define RADIUS_TYPE_NAS_IPV6_ADDRESS 95 +#define RADIUS_TYPE_FRAMED_INTERFACE_ID 96 +#define RADIUS_TYPE_FRAMED_IPV6_PREFIX 97 +#define RADIUS_TYPE_LOGIN_IPV6_HOST 98 +#define RADIUS_TYPE_FRAMED_IPV6_ROUTE 99 +#define RADIUS_TYPE_FRAMED_IPV6_POOL 100 + + /* IIJ vendor specific attributes */ #define RADIUS_VENDOR_IIJ 770 |