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