radius.c revision 51449
119304Speter/* 219304Speter * Copyright 1999 Internet Business Solutions Ltd., Switzerland 319304Speter * All rights reserved. 419304Speter * 519304Speter * Redistribution and use in source and binary forms, with or without 619304Speter * modification, are permitted provided that the following conditions 719304Speter * are met: 819304Speter * 1. Redistributions of source code must retain the above copyright 919304Speter * notice, this list of conditions and the following disclaimer. 1019304Speter * 2. Redistributions in binary form must reproduce the above copyright 1119304Speter * notice, this list of conditions and the following disclaimer in the 1219304Speter * documentation and/or other materials provided with the distribution. 1319304Speter * 1419304Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1519304Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1619304Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1719304Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1819304Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1919304Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2019304Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2119304Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2219304Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2319304Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2419304Speter * SUCH DAMAGE. 2519304Speter * 2619304Speter * $FreeBSD: head/usr.sbin/ppp/radius.c 51449 1999-09-20 07:36:46Z brian $ 2719304Speter * 2819304Speter */ 2919304Speter 3019304Speter#include <sys/param.h> 3119304Speter#include <netinet/in_systm.h> 3219304Speter#include <netinet/in.h> 3319304Speter#include <netinet/ip.h> 3419304Speter#include <arpa/inet.h> 3519304Speter#include <sys/un.h> 3619304Speter 3719304Speter#include <errno.h> 3819304Speter#include <radlib.h> 3919304Speter#ifdef __NetBSD__ 4019304Speter#include <signal.h> /* for `errno' ?!? */ 4119304Speter#endif 4219304Speter#include <stdio.h> 4319304Speter#include <stdlib.h> 4419304Speter#include <string.h> 4519304Speter#include <sys/time.h> 4619304Speter#include <termios.h> 4719304Speter#include <ttyent.h> 4819304Speter#include <unistd.h> 4919304Speter#include <netdb.h> 5019304Speter 5119304Speter#include "layer.h" 5219304Speter#include "defs.h" 5319304Speter#include "log.h" 5419304Speter#include "descriptor.h" 5519304Speter#include "prompt.h" 5619304Speter#include "timer.h" 5719304Speter#include "fsm.h" 5819304Speter#include "iplist.h" 5919304Speter#include "slcompress.h" 6019304Speter#include "throughput.h" 6119304Speter#include "lqr.h" 6219304Speter#include "hdlc.h" 6319304Speter#include "mbuf.h" 6419304Speter#include "ipcp.h" 6519304Speter#include "route.h" 6619304Speter#include "command.h" 6719304Speter#include "filter.h" 6819304Speter#include "lcp.h" 6919304Speter#include "ccp.h" 7019304Speter#include "link.h" 7119304Speter#include "mp.h" 7219304Speter#include "radius.h" 7319304Speter#include "auth.h" 7419304Speter#include "async.h" 7519304Speter#include "physical.h" 7619304Speter#include "chat.h" 7719304Speter#include "cbcp.h" 7819304Speter#include "chap.h" 7919304Speter#include "datalink.h" 8019304Speter#include "bundle.h" 8119304Speter 8219304Speter/* 8319304Speter * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 8419304Speter */ 8519304Speterstatic void 8619304Speterradius_Process(struct radius *r, int got) 8719304Speter{ 8819304Speter char *argv[MAXARGS], *nuke; 8919304Speter struct bundle *bundle; 9019304Speter int argc, addrs; 9119304Speter size_t len; 9219304Speter struct in_range dest; 9319304Speter struct in_addr gw; 9419304Speter const void *data; 9519304Speter 9619304Speter r->cx.fd = -1; /* Stop select()ing */ 9719304Speter 9819304Speter switch (got) { 9919304Speter case RAD_ACCESS_ACCEPT: 10019304Speter log_Printf(LogPHASE, "Radius: ACCEPT received\n"); 10119304Speter break; 10219304Speter 10319304Speter case RAD_ACCESS_REJECT: 10419304Speter log_Printf(LogPHASE, "Radius: REJECT received\n"); 10519304Speter auth_Failure(r->cx.auth); 10619304Speter rad_close(r->cx.rad); 10719304Speter return; 10819304Speter 10919304Speter case RAD_ACCESS_CHALLENGE: 11019304Speter /* we can't deal with this (for now) ! */ 11119304Speter log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); 11219304Speter auth_Failure(r->cx.auth); 11319304Speter rad_close(r->cx.rad); 11419304Speter return; 11519304Speter 11619304Speter case -1: 11719304Speter log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad)); 11819304Speter auth_Failure(r->cx.auth); 11919304Speter rad_close(r->cx.rad); 12019304Speter return; 12119304Speter 12219304Speter default: 12319304Speter log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n", 12419304Speter got, rad_strerror(r->cx.rad)); 12519304Speter auth_Failure(r->cx.auth); 12619304Speter rad_close(r->cx.rad); 12719304Speter return; 12819304Speter } 12919304Speter 13019304Speter /* So we've been accepted ! Let's see what we've got in our reply :-I */ 13119304Speter r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 13219304Speter r->mtu = 0; 13319304Speter r->vj = 0; 13419304Speter while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 13519304Speter switch (got) { 13619304Speter case RAD_FRAMED_IP_ADDRESS: 13719304Speter r->ip = rad_cvt_addr(data); 13819304Speter log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip)); 13919304Speter break; 14019304Speter 14119304Speter case RAD_FRAMED_IP_NETMASK: 14219304Speter r->mask = rad_cvt_addr(data); 14319304Speter log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); 14419304Speter break; 14519304Speter 14619304Speter case RAD_FRAMED_MTU: 14719304Speter r->mtu = rad_cvt_int(data); 148 log_Printf(LogPHASE, " MTU %lu\n", r->mtu); 149 break; 150 151 case RAD_FRAMED_ROUTING: 152 /* Disabled for now - should we automatically set up some filters ? */ 153 /* rad_cvt_int(data); */ 154 /* bit 1 = Send routing packets */ 155 /* bit 2 = Receive routing packets */ 156 break; 157 158 case RAD_FRAMED_COMPRESSION: 159 r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 160 log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); 161 break; 162 163 case RAD_FRAMED_ROUTE: 164 /* 165 * We expect a string of the format ``dest[/bits] gw [metrics]'' 166 * Any specified metrics are ignored. MYADDR and HISADDR are 167 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 168 * as ``HISADDR''. 169 */ 170 171 if ((nuke = rad_cvt_string(data, len)) == NULL) { 172 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 173 rad_close(r->cx.rad); 174 return; 175 } 176 177 log_Printf(LogPHASE, " Route: %s\n", nuke); 178 bundle = r->cx.auth->physical->dl->bundle; 179 dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY; 180 dest.width = 0; 181 argc = command_Interpret(nuke, strlen(nuke), argv); 182 if (argc < 2) 183 log_Printf(LogWARN, "radius: %s: Invalid route\n", 184 argc == 1 ? argv[0] : "\"\""); 185 else if ((strcasecmp(argv[0], "default") != 0 && 186 !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr, 187 &dest.mask, &dest.width)) || 188 !ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL)) 189 log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 190 argv[0], argv[1]); 191 else { 192 if (dest.width == 32 && strchr(argv[0], '/') == NULL) 193 /* No mask specified - use the natural mask */ 194 dest.mask = addr2mask(dest.ipaddr); 195 addrs = 0; 196 197 if (!strncasecmp(argv[0], "HISADDR", 7)) 198 addrs = ROUTE_DSTHISADDR; 199 else if (!strncasecmp(argv[0], "MYADDR", 6)) 200 addrs = ROUTE_DSTMYADDR; 201 202 if (gw.s_addr == INADDR_ANY) { 203 addrs |= ROUTE_GWHISADDR; 204 gw = bundle->ncp.ipcp.peer_ip; 205 } else if (strcasecmp(argv[1], "HISADDR") == 0) 206 addrs |= ROUTE_GWHISADDR; 207 208 route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw); 209 } 210 free(nuke); 211 break; 212 } 213 } 214 215 if (got == -1) { 216 log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 217 rad_strerror(r->cx.rad)); 218 auth_Failure(r->cx.auth); 219 rad_close(r->cx.rad); 220 } else { 221 r->valid = 1; 222 auth_Success(r->cx.auth); 223 rad_close(r->cx.rad); 224 } 225} 226 227/* 228 * We've either timed out or select()ed on the read descriptor 229 */ 230static void 231radius_Continue(struct radius *r, int sel) 232{ 233 struct timeval tv; 234 int got; 235 236 timer_Stop(&r->cx.timer); 237 if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 238 log_Printf(LogPHASE, "Radius: Request re-sent\n"); 239 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 240 timer_Start(&r->cx.timer); 241 return; 242 } 243 244 radius_Process(r, got); 245} 246 247/* 248 * Time to call rad_continue_send_request() - timed out. 249 */ 250static void 251radius_Timeout(void *v) 252{ 253 radius_Continue((struct radius *)v, 0); 254} 255 256/* 257 * Time to call rad_continue_send_request() - something to read. 258 */ 259static void 260radius_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 261{ 262 radius_Continue(descriptor2radius(d), 1); 263} 264 265/* 266 * Behave as a struct descriptor (descriptor.h) 267 */ 268static int 269radius_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 270{ 271 struct radius *rad = descriptor2radius(d); 272 273 if (r && rad->cx.fd != -1) { 274 FD_SET(rad->cx.fd, r); 275 if (*n < rad->cx.fd + 1) 276 *n = rad->cx.fd + 1; 277 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 278 return 1; 279 } 280 281 return 0; 282} 283 284/* 285 * Behave as a struct descriptor (descriptor.h) 286 */ 287static int 288radius_IsSet(struct descriptor *d, const fd_set *fdset) 289{ 290 struct radius *r = descriptor2radius(d); 291 292 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 293} 294 295/* 296 * Behave as a struct descriptor (descriptor.h) 297 */ 298static int 299radius_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset) 300{ 301 /* We never want to write here ! */ 302 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 303 return 0; 304} 305 306/* 307 * Initialise ourselves 308 */ 309void 310radius_Init(struct radius *r) 311{ 312 r->valid = 0; 313 r->cx.fd = -1; 314 *r->cfg.file = '\0';; 315 r->desc.type = RADIUS_DESCRIPTOR; 316 r->desc.UpdateSet = radius_UpdateSet; 317 r->desc.IsSet = radius_IsSet; 318 r->desc.Read = radius_Read; 319 r->desc.Write = radius_Write; 320 memset(&r->cx.timer, '\0', sizeof r->cx.timer); 321} 322 323/* 324 * Forget everything and go back to initialised state. 325 */ 326void 327radius_Destroy(struct radius *r) 328{ 329 r->valid = 0; 330 timer_Stop(&r->cx.timer); 331 route_DeleteAll(&r->routes); 332 if (r->cx.fd != -1) { 333 r->cx.fd = -1; 334 rad_close(r->cx.rad); 335 } 336} 337 338/* 339 * Start an authentication request to the RADIUS server. 340 */ 341void 342radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 343 const char *key, const char *challenge) 344{ 345 struct ttyent *ttyp; 346 struct timeval tv; 347 int got, slot; 348 char hostname[MAXHOSTNAMELEN]; 349 struct hostent *hp; 350 struct in_addr hostaddr; 351 352 if (!*r->cfg.file) 353 return; 354 355 if (r->cx.fd != -1) 356 /* 357 * We assume that our name/key/challenge is the same as last time, 358 * and just continue to wait for the RADIUS server(s). 359 */ 360 return; 361 362 radius_Destroy(r); 363 364 if ((r->cx.rad = rad_open()) == NULL) { 365 log_Printf(LogERROR, "rad_open: %s\n", strerror(errno)); 366 return; 367 } 368 369 if (rad_config(r->cx.rad, r->cfg.file) != 0) { 370 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 371 rad_close(r->cx.rad); 372 return; 373 } 374 375 if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 376 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 377 rad_close(r->cx.rad); 378 return; 379 } 380 381 if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 382 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 383 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 384 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 385 rad_close(r->cx.rad); 386 return; 387 } 388 389 if (challenge != NULL) { 390 /* We're talking CHAP */ 391 if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 || 392 rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) { 393 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 394 rad_strerror(r->cx.rad)); 395 rad_close(r->cx.rad); 396 return; 397 } 398 } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) { 399 /* We're talking PAP */ 400 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad)); 401 rad_close(r->cx.rad); 402 return; 403 } 404 405 if (gethostname(hostname, sizeof hostname) != 0) 406 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 407 else { 408 if ((hp = gethostbyname(hostname)) != NULL) { 409 hostaddr.s_addr = *(u_long *)hp->h_addr; 410 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) { 411 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 412 rad_strerror(r->cx.rad)); 413 rad_close(r->cx.rad); 414 return; 415 } 416 } 417 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 418 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 419 rad_strerror(r->cx.rad)); 420 rad_close(r->cx.rad); 421 return; 422 } 423 } 424 425 if (authp->physical->handler && 426 authp->physical->handler->type == TTY_DEVICE) { 427 setttyent(); 428 for (slot = 1; (ttyp = getttyent()); ++slot) 429 if (!strcmp(ttyp->ty_name, authp->physical->name.base)) { 430 if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) { 431 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 432 rad_strerror(r->cx.rad)); 433 rad_close(r->cx.rad); 434 endttyent(); 435 return; 436 } 437 break; 438 } 439 endttyent(); 440 } 441 442 443 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 444 radius_Process(r, got); 445 else { 446 log_Printf(LogPHASE, "Radius: Request sent\n"); 447 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 448 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 449 r->cx.timer.func = radius_Timeout; 450 r->cx.timer.name = "radius"; 451 r->cx.timer.arg = r; 452 r->cx.auth = authp; 453 timer_Start(&r->cx.timer); 454 } 455} 456 457/* 458 * How do things look at the moment ? 459 */ 460void 461radius_Show(struct radius *r, struct prompt *p) 462{ 463 prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none"); 464 if (r->valid) { 465 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 466 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 467 prompt_Printf(p, " MTU: %lu\n", r->mtu); 468 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 469 if (r->routes) 470 route_ShowSticky(p, r->routes, " Routes", 16); 471 } else 472 prompt_Printf(p, " (not authenticated)\n"); 473} 474