1 /* 2 * Copyright 1999 Internet Business Solutions Ltd., Switzerland 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 * 28 */ 29 30 #include <sys/param.h> 31 #include <sys/socket.h> 32 #include <netinet/in_systm.h> 33 #include <netinet/in.h> 34 #include <netinet/ip.h> 35 #include <arpa/inet.h> 36 #include <sys/un.h> 37 #include <net/route.h> 38 39 #ifdef LOCALRAD 40 #include "radlib.h" 41 #else 42 #include <radlib.h> 43 #endif 44 45 #include <errno.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <sys/time.h> 50 #include <termios.h> 51 #include <ttyent.h> 52 #include <unistd.h> 53 #include <netdb.h> 54 55 #include "layer.h" 56 #include "defs.h" 57 #include "log.h" 58 #include "descriptor.h" 59 #include "prompt.h" 60 #include "timer.h" 61 #include "fsm.h" 62 #include "iplist.h" 63 #include "slcompress.h" 64 #include "throughput.h" 65 #include "lqr.h" 66 #include "hdlc.h" 67 #include "mbuf.h" 68 #include "ipcp.h" 69 #include "route.h" 70 #include "command.h" 71 #include "filter.h" 72 #include "lcp.h" 73 #include "ccp.h" 74 #include "link.h" 75 #include "mp.h" 76 #include "radius.h" 77 #include "auth.h" 78 #include "async.h" 79 #include "physical.h" 80 #include "chat.h" 81 #include "cbcp.h" 82 #include "chap.h" 83 #include "datalink.h" 84 #include "bundle.h" 85 86 /* 87 * rad_continue_send_request() has given us `got' (non-zero). Deal with it. 88 */ 89 static void 90 radius_Process(struct radius *r, int got) 91 { 92 char *argv[MAXARGS], *nuke; 93 struct bundle *bundle; 94 int argc, addrs; 95 size_t len; 96 struct in_range dest; 97 struct in_addr gw; 98 const void *data; 99 100 r->cx.fd = -1; /* Stop select()ing */ 101 102 switch (got) { 103 case RAD_ACCESS_ACCEPT: 104 log_Printf(LogPHASE, "Radius: ACCEPT received\n"); 105 break; 106 107 case RAD_ACCESS_REJECT: 108 log_Printf(LogPHASE, "Radius: REJECT received\n"); 109 auth_Failure(r->cx.auth); 110 rad_close(r->cx.rad); 111 return; 112 113 case RAD_ACCESS_CHALLENGE: 114 /* we can't deal with this (for now) ! */ 115 log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n"); 116 auth_Failure(r->cx.auth); 117 rad_close(r->cx.rad); 118 return; 119 120 case -1: 121 log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad)); 122 auth_Failure(r->cx.auth); 123 rad_close(r->cx.rad); 124 return; 125 126 default: 127 log_Printf(LogERROR, "rad_send_request: Failed %d: %s\n", 128 got, rad_strerror(r->cx.rad)); 129 auth_Failure(r->cx.auth); 130 rad_close(r->cx.rad); 131 return; 132 } 133 134 /* So we've been accepted ! Let's see what we've got in our reply :-I */ 135 r->ip.s_addr = r->mask.s_addr = INADDR_NONE; 136 r->mtu = 0; 137 r->vj = 0; 138 while ((got = rad_get_attr(r->cx.rad, &data, &len)) > 0) { 139 switch (got) { 140 case RAD_FRAMED_IP_ADDRESS: 141 r->ip = rad_cvt_addr(data); 142 log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip)); 143 break; 144 145 case RAD_FRAMED_IP_NETMASK: 146 r->mask = rad_cvt_addr(data); 147 log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask)); 148 break; 149 150 case RAD_FRAMED_MTU: 151 r->mtu = rad_cvt_int(data); 152 log_Printf(LogPHASE, " MTU %lu\n", r->mtu); 153 break; 154 155 case RAD_FRAMED_ROUTING: 156 /* Disabled for now - should we automatically set up some filters ? */ 157 /* rad_cvt_int(data); */ 158 /* bit 1 = Send routing packets */ 159 /* bit 2 = Receive routing packets */ 160 break; 161 162 case RAD_FRAMED_COMPRESSION: 163 r->vj = rad_cvt_int(data) == 1 ? 1 : 0; 164 log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis"); 165 break; 166 167 case RAD_FRAMED_ROUTE: 168 /* 169 * We expect a string of the format ``dest[/bits] gw [metrics]'' 170 * Any specified metrics are ignored. MYADDR and HISADDR are 171 * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same 172 * as ``HISADDR''. 173 */ 174 175 if ((nuke = rad_cvt_string(data, len)) == NULL) { 176 log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad)); 177 rad_close(r->cx.rad); 178 return; 179 } 180 181 log_Printf(LogPHASE, " Route: %s\n", nuke); 182 bundle = r->cx.auth->physical->dl->bundle; 183 dest.ipaddr.s_addr = dest.mask.s_addr = INADDR_ANY; 184 dest.width = 0; 185 argc = command_Interpret(nuke, strlen(nuke), argv); 186 if (argc < 0) 187 log_Printf(LogWARN, "radius: %s: Syntax error\n", 188 argc == 1 ? argv[0] : "\"\""); 189 else if (argc < 2) 190 log_Printf(LogWARN, "radius: %s: Invalid route\n", 191 argc == 1 ? argv[0] : "\"\""); 192 else if ((strcasecmp(argv[0], "default") != 0 && 193 !ParseAddr(&bundle->ncp.ipcp, argv[0], &dest.ipaddr, 194 &dest.mask, &dest.width)) || 195 !ParseAddr(&bundle->ncp.ipcp, argv[1], &gw, NULL, NULL)) 196 log_Printf(LogWARN, "radius: %s %s: Invalid route\n", 197 argv[0], argv[1]); 198 else { 199 if (dest.width == 32 && strchr(argv[0], '/') == NULL) 200 /* No mask specified - use the natural mask */ 201 dest.mask = addr2mask(dest.ipaddr); 202 addrs = 0; 203 204 if (!strncasecmp(argv[0], "HISADDR", 7)) 205 addrs = ROUTE_DSTHISADDR; 206 else if (!strncasecmp(argv[0], "MYADDR", 6)) 207 addrs = ROUTE_DSTMYADDR; 208 209 if (gw.s_addr == INADDR_ANY) { 210 addrs |= ROUTE_GWHISADDR; 211 gw = bundle->ncp.ipcp.peer_ip; 212 } else if (strcasecmp(argv[1], "HISADDR") == 0) 213 addrs |= ROUTE_GWHISADDR; 214 215 route_Add(&r->routes, addrs, dest.ipaddr, dest.mask, gw); 216 } 217 free(nuke); 218 break; 219 } 220 } 221 222 if (got == -1) { 223 log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n", 224 rad_strerror(r->cx.rad)); 225 auth_Failure(r->cx.auth); 226 rad_close(r->cx.rad); 227 } else { 228 r->valid = 1; 229 auth_Success(r->cx.auth); 230 rad_close(r->cx.rad); 231 } 232 } 233 234 /* 235 * We've either timed out or select()ed on the read descriptor 236 */ 237 static void 238 radius_Continue(struct radius *r, int sel) 239 { 240 struct timeval tv; 241 int got; 242 243 timer_Stop(&r->cx.timer); 244 if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) { 245 log_Printf(LogPHASE, "Radius: Request re-sent\n"); 246 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 247 timer_Start(&r->cx.timer); 248 return; 249 } 250 251 radius_Process(r, got); 252 } 253 254 /* 255 * Time to call rad_continue_send_request() - timed out. 256 */ 257 static void 258 radius_Timeout(void *v) 259 { 260 radius_Continue((struct radius *)v, 0); 261 } 262 263 /* 264 * Time to call rad_continue_send_request() - something to read. 265 */ 266 static void 267 radius_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 268 { 269 radius_Continue(descriptor2radius(d), 1); 270 } 271 272 /* 273 * Behave as a struct fdescriptor (descriptor.h) 274 */ 275 static int 276 radius_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 277 { 278 struct radius *rad = descriptor2radius(d); 279 280 if (r && rad->cx.fd != -1) { 281 FD_SET(rad->cx.fd, r); 282 if (*n < rad->cx.fd + 1) 283 *n = rad->cx.fd + 1; 284 log_Printf(LogTIMER, "Radius: fdset(r) %d\n", rad->cx.fd); 285 return 1; 286 } 287 288 return 0; 289 } 290 291 /* 292 * Behave as a struct fdescriptor (descriptor.h) 293 */ 294 static int 295 radius_IsSet(struct fdescriptor *d, const fd_set *fdset) 296 { 297 struct radius *r = descriptor2radius(d); 298 299 return r && r->cx.fd != -1 && FD_ISSET(r->cx.fd, fdset); 300 } 301 302 /* 303 * Behave as a struct fdescriptor (descriptor.h) 304 */ 305 static int 306 radius_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset) 307 { 308 /* We never want to write here ! */ 309 log_Printf(LogALERT, "radius_Write: Internal error: Bad call !\n"); 310 return 0; 311 } 312 313 /* 314 * Initialise ourselves 315 */ 316 void 317 radius_Init(struct radius *r) 318 { 319 r->valid = 0; 320 r->cx.fd = -1; 321 *r->cfg.file = '\0';; 322 r->desc.type = RADIUS_DESCRIPTOR; 323 r->desc.UpdateSet = radius_UpdateSet; 324 r->desc.IsSet = radius_IsSet; 325 r->desc.Read = radius_Read; 326 r->desc.Write = radius_Write; 327 memset(&r->cx.timer, '\0', sizeof r->cx.timer); 328 } 329 330 /* 331 * Forget everything and go back to initialised state. 332 */ 333 void 334 radius_Destroy(struct radius *r) 335 { 336 r->valid = 0; 337 timer_Stop(&r->cx.timer); 338 route_DeleteAll(&r->routes); 339 if (r->cx.fd != -1) { 340 r->cx.fd = -1; 341 rad_close(r->cx.rad); 342 } 343 } 344 345 /* 346 * Start an authentication request to the RADIUS server. 347 */ 348 void 349 radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name, 350 const char *key, const char *challenge) 351 { 352 struct ttyent *ttyp; 353 struct timeval tv; 354 int got, slot; 355 char hostname[MAXHOSTNAMELEN]; 356 struct hostent *hp; 357 struct in_addr hostaddr; 358 359 if (!*r->cfg.file) 360 return; 361 362 if (r->cx.fd != -1) 363 /* 364 * We assume that our name/key/challenge is the same as last time, 365 * and just continue to wait for the RADIUS server(s). 366 */ 367 return; 368 369 radius_Destroy(r); 370 371 if ((r->cx.rad = rad_open()) == NULL) { 372 log_Printf(LogERROR, "rad_open: %s\n", strerror(errno)); 373 return; 374 } 375 376 if (rad_config(r->cx.rad, r->cfg.file) != 0) { 377 log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad)); 378 rad_close(r->cx.rad); 379 return; 380 } 381 382 if (rad_create_request(r->cx.rad, RAD_ACCESS_REQUEST) != 0) { 383 log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad)); 384 rad_close(r->cx.rad); 385 return; 386 } 387 388 if (rad_put_string(r->cx.rad, RAD_USER_NAME, name) != 0 || 389 rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 || 390 rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0) { 391 log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad)); 392 rad_close(r->cx.rad); 393 return; 394 } 395 396 if (challenge != NULL) { 397 /* We're talking CHAP */ 398 if (rad_put_string(r->cx.rad, RAD_CHAP_PASSWORD, key) != 0 || 399 rad_put_string(r->cx.rad, RAD_CHAP_CHALLENGE, challenge) != 0) { 400 log_Printf(LogERROR, "CHAP: rad_put_string: %s\n", 401 rad_strerror(r->cx.rad)); 402 rad_close(r->cx.rad); 403 return; 404 } 405 } else if (rad_put_string(r->cx.rad, RAD_USER_PASSWORD, key) != 0) { 406 /* We're talking PAP */ 407 log_Printf(LogERROR, "PAP: rad_put_string: %s\n", rad_strerror(r->cx.rad)); 408 rad_close(r->cx.rad); 409 return; 410 } 411 412 if (gethostname(hostname, sizeof hostname) != 0) 413 log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno)); 414 else { 415 if ((hp = gethostbyname(hostname)) != NULL) { 416 hostaddr.s_addr = *(u_long *)hp->h_addr; 417 if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 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 if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) { 425 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 426 rad_strerror(r->cx.rad)); 427 rad_close(r->cx.rad); 428 return; 429 } 430 } 431 432 if (authp->physical->handler && 433 authp->physical->handler->type == TTY_DEVICE) { 434 setttyent(); 435 for (slot = 1; (ttyp = getttyent()); ++slot) 436 if (!strcmp(ttyp->ty_name, authp->physical->name.base)) { 437 if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) { 438 log_Printf(LogERROR, "rad_put: rad_put_string: %s\n", 439 rad_strerror(r->cx.rad)); 440 rad_close(r->cx.rad); 441 endttyent(); 442 return; 443 } 444 break; 445 } 446 endttyent(); 447 } 448 449 450 if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv))) 451 radius_Process(r, got); 452 else { 453 log_Printf(LogPHASE, "Radius: Request sent\n"); 454 log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout); 455 r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS; 456 r->cx.timer.func = radius_Timeout; 457 r->cx.timer.name = "radius"; 458 r->cx.timer.arg = r; 459 r->cx.auth = authp; 460 timer_Start(&r->cx.timer); 461 } 462 } 463 464 /* 465 * How do things look at the moment ? 466 */ 467 void 468 radius_Show(struct radius *r, struct prompt *p) 469 { 470 prompt_Printf(p, " Radius config: %s", *r->cfg.file ? r->cfg.file : "none"); 471 if (r->valid) { 472 prompt_Printf(p, "\n IP: %s\n", inet_ntoa(r->ip)); 473 prompt_Printf(p, " Netmask: %s\n", inet_ntoa(r->mask)); 474 prompt_Printf(p, " MTU: %lu\n", r->mtu); 475 prompt_Printf(p, " VJ: %sabled\n", r->vj ? "en" : "dis"); 476 if (r->routes) 477 route_ShowSticky(p, r->routes, " Routes", 16); 478 } else 479 prompt_Printf(p, " (not authenticated)\n"); 480 } 481