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