1 1.12 christos /* $NetBSD: radlib.c,v 1.12 2018/02/05 00:43:06 christos Exp $ */ 2 1.1 manu 3 1.1 manu /*- 4 1.1 manu * Copyright 1998 Juniper Networks, Inc. 5 1.1 manu * All rights reserved. 6 1.1 manu * 7 1.1 manu * Redistribution and use in source and binary forms, with or without 8 1.1 manu * modification, are permitted provided that the following conditions 9 1.1 manu * are met: 10 1.1 manu * 1. Redistributions of source code must retain the above copyright 11 1.1 manu * notice, this list of conditions and the following disclaimer. 12 1.1 manu * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 manu * notice, this list of conditions and the following disclaimer in the 14 1.1 manu * documentation and/or other materials provided with the distribution. 15 1.1 manu * 16 1.1 manu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 manu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 manu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 manu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 manu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 manu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 manu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 manu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 manu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 manu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 manu * SUCH DAMAGE. 27 1.1 manu */ 28 1.1 manu 29 1.1 manu #include <sys/cdefs.h> 30 1.1 manu #ifdef __FreeBSD__ 31 1.1 manu __FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libradius/radlib.c,v 1.12 2004/06/14 20:55:30 stefanf Exp $"); 32 1.1 manu #else 33 1.12 christos __RCSID("$NetBSD: radlib.c,v 1.12 2018/02/05 00:43:06 christos Exp $"); 34 1.1 manu #endif 35 1.1 manu 36 1.1 manu #include <sys/types.h> 37 1.1 manu #include <sys/socket.h> 38 1.1 manu #include <sys/time.h> 39 1.1 manu #include <netinet/in.h> 40 1.1 manu #include <arpa/inet.h> 41 1.1 manu #ifdef WITH_SSL 42 1.1 manu #include <openssl/hmac.h> 43 1.1 manu #include <openssl/md5.h> 44 1.1 manu #define MD5Init MD5_Init 45 1.1 manu #define MD5Update MD5_Update 46 1.1 manu #define MD5Final MD5_Final 47 1.7 christos #define MD5Len size_t 48 1.6 christos #define MD5Buf const void * 49 1.1 manu #else 50 1.1 manu #define MD5_DIGEST_LENGTH 16 51 1.2 christos #define MD5Len unsigned int 52 1.6 christos #define MD5Buf const unsigned char * 53 1.1 manu #include <md5.h> 54 1.1 manu #endif 55 1.1 manu 56 1.1 manu /* We need the MPPE_KEY_LEN define */ 57 1.1 manu #ifdef __FreeBSD__ 58 1.1 manu #include <netgraph/ng_mppc.h> 59 1.1 manu #else 60 1.1 manu #define MPPE_KEY_LEN 16 61 1.1 manu #endif 62 1.1 manu 63 1.1 manu #include <errno.h> 64 1.1 manu #include <netdb.h> 65 1.1 manu #include <stdarg.h> 66 1.1 manu #include <stddef.h> 67 1.1 manu #include <stdio.h> 68 1.1 manu #include <stdlib.h> 69 1.1 manu #include <string.h> 70 1.1 manu #include <unistd.h> 71 1.1 manu 72 1.1 manu #include "radlib_private.h" 73 1.1 manu #if !defined(__printflike) 74 1.1 manu #define __printflike(fmtarg, firstvararg) \ 75 1.1 manu __attribute__((__format__ (__printf__, fmtarg, firstvararg))) 76 1.1 manu #endif 77 1.1 manu 78 1.1 manu #ifdef __NetBSD__ 79 1.1 manu #define srandomdev(x) 80 1.1 manu #define random arc4random 81 1.1 manu #endif 82 1.1 manu 83 1.1 manu static void clear_password(struct rad_handle *); 84 1.1 manu static void generr(struct rad_handle *, const char *, ...) 85 1.1 manu __printflike(2, 3); 86 1.10 lukem static void insert_scrambled_password(struct rad_handle *, size_t); 87 1.10 lukem static void insert_request_authenticator(struct rad_handle *, size_t); 88 1.10 lukem static void insert_message_authenticator(struct rad_handle *, size_t); 89 1.10 lukem static int is_valid_response(struct rad_handle *, size_t, 90 1.1 manu const struct sockaddr_in *); 91 1.1 manu static int put_password_attr(struct rad_handle *, int, 92 1.1 manu const void *, size_t); 93 1.1 manu static int put_raw_attr(struct rad_handle *, int, 94 1.1 manu const void *, size_t); 95 1.11 jmmv static size_t split(char *, const char *[], size_t, char *, size_t); 96 1.1 manu 97 1.1 manu static void 98 1.1 manu clear_password(struct rad_handle *h) 99 1.1 manu { 100 1.1 manu if (h->pass_len != 0) { 101 1.3 christos (void)memset(h->pass, 0, h->pass_len); 102 1.1 manu h->pass_len = 0; 103 1.1 manu } 104 1.1 manu h->pass_pos = 0; 105 1.1 manu } 106 1.1 manu 107 1.1 manu static void 108 1.1 manu generr(struct rad_handle *h, const char *format, ...) 109 1.1 manu { 110 1.1 manu va_list ap; 111 1.1 manu 112 1.1 manu va_start(ap, format); 113 1.3 christos vsnprintf(h->errmsg, (size_t)ERRSIZE, format, ap); 114 1.1 manu va_end(ap); 115 1.1 manu } 116 1.1 manu 117 1.1 manu static void 118 1.10 lukem insert_scrambled_password(struct rad_handle *h, size_t srv) 119 1.1 manu { 120 1.1 manu MD5_CTX ctx; 121 1.1 manu unsigned char md5[MD5_DIGEST_LENGTH]; 122 1.1 manu const struct rad_server *srvp; 123 1.3 christos size_t padded_len, pos; 124 1.1 manu 125 1.1 manu srvp = &h->servers[srv]; 126 1.3 christos padded_len = h->pass_len == 0 ? (size_t)16 : (h->pass_len+15) & ~0xf; 127 1.1 manu 128 1.3 christos (void)memcpy(md5, &h->request[POS_AUTH], (size_t)LEN_AUTH); 129 1.1 manu for (pos = 0; pos < padded_len; pos += 16) { 130 1.1 manu int i; 131 1.1 manu 132 1.1 manu /* Calculate the new scrambler */ 133 1.1 manu MD5Init(&ctx); 134 1.6 christos MD5Update(&ctx, (MD5Buf)srvp->secret, 135 1.2 christos (MD5Len)strlen(srvp->secret)); 136 1.2 christos MD5Update(&ctx, md5, (MD5Len)16); 137 1.1 manu MD5Final(md5, &ctx); 138 1.1 manu 139 1.1 manu /* 140 1.1 manu * Mix in the current chunk of the password, and copy 141 1.1 manu * the result into the right place in the request. Also 142 1.1 manu * modify the scrambler in place, since we will use this 143 1.1 manu * in calculating the scrambler for next time. 144 1.1 manu */ 145 1.1 manu for (i = 0; i < 16; i++) 146 1.1 manu h->request[h->pass_pos + pos + i] = 147 1.1 manu md5[i] ^= h->pass[pos + i]; 148 1.1 manu } 149 1.1 manu } 150 1.1 manu 151 1.1 manu static void 152 1.10 lukem insert_request_authenticator(struct rad_handle *h, size_t srv) 153 1.1 manu { 154 1.1 manu MD5_CTX ctx; 155 1.1 manu const struct rad_server *srvp; 156 1.1 manu 157 1.1 manu srvp = &h->servers[srv]; 158 1.1 manu 159 1.1 manu /* Create the request authenticator */ 160 1.1 manu MD5Init(&ctx); 161 1.2 christos MD5Update(&ctx, &h->request[POS_CODE], 162 1.2 christos (MD5Len)(POS_AUTH - POS_CODE)); 163 1.2 christos MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, (size_t)LEN_AUTH), 164 1.2 christos (MD5Len)LEN_AUTH); 165 1.2 christos MD5Update(&ctx, &h->request[POS_ATTRS], 166 1.2 christos (MD5Len)(h->req_len - POS_ATTRS)); 167 1.6 christos MD5Update(&ctx, (MD5Buf)srvp->secret, 168 1.2 christos (MD5Len)strlen(srvp->secret)); 169 1.1 manu MD5Final(&h->request[POS_AUTH], &ctx); 170 1.1 manu } 171 1.1 manu 172 1.1 manu static void 173 1.6 christos /*ARGSUSED*/ 174 1.10 lukem insert_message_authenticator(struct rad_handle *h, size_t srv) 175 1.1 manu { 176 1.1 manu #ifdef WITH_SSL 177 1.1 manu u_char md[EVP_MAX_MD_SIZE]; 178 1.1 manu u_int md_len; 179 1.1 manu const struct rad_server *srvp; 180 1.12 christos HMAC_CTX *ctx; 181 1.1 manu srvp = &h->servers[srv]; 182 1.1 manu 183 1.1 manu if (h->authentic_pos != 0) { 184 1.12 christos ctx = HMAC_CTX_new(); 185 1.12 christos HMAC_Init_ex(ctx, srvp->secret, 186 1.12 christos (int)strlen(srvp->secret), EVP_md5(), NULL); 187 1.12 christos HMAC_Update(ctx, &h->request[POS_CODE], (size_t)(POS_AUTH - POS_CODE)); 188 1.12 christos HMAC_Update(ctx, &h->request[POS_AUTH], (size_t)LEN_AUTH); 189 1.12 christos HMAC_Update(ctx, &h->request[POS_ATTRS], 190 1.7 christos (size_t)(h->req_len - POS_ATTRS)); 191 1.12 christos HMAC_Final(ctx, md, &md_len); 192 1.12 christos HMAC_CTX_free(ctx); 193 1.3 christos (void)memcpy(&h->request[h->authentic_pos + 2], md, 194 1.3 christos (size_t)md_len); 195 1.1 manu } 196 1.1 manu #endif 197 1.1 manu } 198 1.1 manu 199 1.1 manu /* 200 1.1 manu * Return true if the current response is valid for a request to the 201 1.1 manu * specified server. 202 1.1 manu */ 203 1.1 manu static int 204 1.10 lukem is_valid_response(struct rad_handle *h, size_t srv, 205 1.1 manu const struct sockaddr_in *from) 206 1.1 manu { 207 1.1 manu MD5_CTX ctx; 208 1.1 manu unsigned char md5[MD5_DIGEST_LENGTH]; 209 1.1 manu const struct rad_server *srvp; 210 1.10 lukem size_t len; 211 1.1 manu #ifdef WITH_SSL 212 1.12 christos HMAC_CTX *hctx; 213 1.1 manu u_char resp[MSGSIZE], md[EVP_MAX_MD_SIZE]; 214 1.10 lukem size_t pos; 215 1.2 christos u_int md_len; 216 1.1 manu #endif 217 1.1 manu 218 1.1 manu srvp = &h->servers[srv]; 219 1.1 manu 220 1.1 manu /* Check the source address */ 221 1.1 manu if (from->sin_family != srvp->addr.sin_family || 222 1.1 manu from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr || 223 1.1 manu from->sin_port != srvp->addr.sin_port) 224 1.1 manu return 0; 225 1.1 manu 226 1.1 manu /* Check the message length */ 227 1.1 manu if (h->resp_len < POS_ATTRS) 228 1.1 manu return 0; 229 1.1 manu len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1]; 230 1.1 manu if (len > h->resp_len) 231 1.1 manu return 0; 232 1.1 manu 233 1.1 manu /* Check the response authenticator */ 234 1.1 manu MD5Init(&ctx); 235 1.2 christos MD5Update(&ctx, &h->response[POS_CODE], 236 1.2 christos (MD5Len)(POS_AUTH - POS_CODE)); 237 1.2 christos MD5Update(&ctx, &h->request[POS_AUTH], 238 1.2 christos (MD5Len)LEN_AUTH); 239 1.2 christos MD5Update(&ctx, &h->response[POS_ATTRS], 240 1.2 christos (MD5Len)(len - POS_ATTRS)); 241 1.6 christos MD5Update(&ctx, (MD5Buf)srvp->secret, 242 1.2 christos (MD5Len)strlen(srvp->secret)); 243 1.1 manu MD5Final(md5, &ctx); 244 1.1 manu if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0) 245 1.1 manu return 0; 246 1.1 manu 247 1.1 manu #ifdef WITH_SSL 248 1.1 manu /* 249 1.1 manu * For non accounting responses check the message authenticator, 250 1.1 manu * if any. 251 1.1 manu */ 252 1.1 manu if (h->response[POS_CODE] != RAD_ACCOUNTING_RESPONSE) { 253 1.1 manu 254 1.3 christos (void)memcpy(resp, h->response, (size_t)MSGSIZE); 255 1.1 manu pos = POS_ATTRS; 256 1.1 manu 257 1.1 manu /* Search and verify the Message-Authenticator */ 258 1.1 manu while (pos < len - 2) { 259 1.1 manu 260 1.1 manu if (h->response[pos] == RAD_MESSAGE_AUTHENTIC) { 261 1.1 manu /* zero fill the Message-Authenticator */ 262 1.3 christos (void)memset(&resp[pos + 2], 0, 263 1.3 christos (size_t)MD5_DIGEST_LENGTH); 264 1.1 manu 265 1.12 christos hctx = HMAC_CTX_new(); 266 1.12 christos HMAC_Init_ex(hctx, srvp->secret, 267 1.12 christos (int)strlen(srvp->secret), EVP_md5(), NULL); 268 1.12 christos HMAC_Update(hctx, &h->response[POS_CODE], 269 1.8 christos (size_t)(POS_AUTH - POS_CODE)); 270 1.12 christos HMAC_Update(hctx, &h->request[POS_AUTH], 271 1.8 christos (size_t)LEN_AUTH); 272 1.12 christos HMAC_Update(hctx, &resp[POS_ATTRS], 273 1.7 christos (size_t)(h->resp_len - POS_ATTRS)); 274 1.12 christos HMAC_Final(hctx, md, &md_len); 275 1.12 christos HMAC_CTX_free(hctx); 276 1.1 manu if (memcmp(md, &h->response[pos + 2], 277 1.3 christos (size_t)MD5_DIGEST_LENGTH) != 0) 278 1.1 manu return 0; 279 1.1 manu break; 280 1.1 manu } 281 1.1 manu pos += h->response[pos + 1]; 282 1.1 manu } 283 1.1 manu } 284 1.1 manu #endif 285 1.1 manu return 1; 286 1.1 manu } 287 1.1 manu 288 1.1 manu static int 289 1.1 manu put_password_attr(struct rad_handle *h, int type, const void *value, size_t len) 290 1.1 manu { 291 1.2 christos size_t padded_len; 292 1.2 christos size_t pad_len; 293 1.1 manu 294 1.1 manu if (h->pass_pos != 0) { 295 1.1 manu generr(h, "Multiple User-Password attributes specified"); 296 1.1 manu return -1; 297 1.1 manu } 298 1.1 manu if (len > PASSSIZE) 299 1.1 manu len = PASSSIZE; 300 1.2 christos padded_len = len == 0 ? 16 : (len + 15) & ~0xf; 301 1.1 manu pad_len = padded_len - len; 302 1.1 manu 303 1.1 manu /* 304 1.1 manu * Put in a place-holder attribute containing all zeros, and 305 1.1 manu * remember where it is so we can fill it in later. 306 1.1 manu */ 307 1.1 manu clear_password(h); 308 1.1 manu put_raw_attr(h, type, h->pass, padded_len); 309 1.4 he h->pass_pos = (int)(h->req_len - padded_len); 310 1.1 manu 311 1.1 manu /* Save the cleartext password, padded as necessary */ 312 1.2 christos (void)memcpy(h->pass, value, len); 313 1.1 manu h->pass_len = len; 314 1.2 christos (void)memset(h->pass + len, 0, pad_len); 315 1.1 manu return 0; 316 1.1 manu } 317 1.1 manu 318 1.1 manu static int 319 1.1 manu put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len) 320 1.1 manu { 321 1.1 manu if (len > 253) { 322 1.1 manu generr(h, "Attribute too long"); 323 1.1 manu return -1; 324 1.1 manu } 325 1.1 manu if (h->req_len + 2 + len > MSGSIZE) { 326 1.1 manu generr(h, "Maximum message length exceeded"); 327 1.1 manu return -1; 328 1.1 manu } 329 1.1 manu h->request[h->req_len++] = type; 330 1.3 christos h->request[h->req_len++] = (unsigned char)(len + 2); 331 1.2 christos (void)memcpy(&h->request[h->req_len], value, len); 332 1.1 manu h->req_len += len; 333 1.1 manu return 0; 334 1.1 manu } 335 1.1 manu 336 1.1 manu int 337 1.1 manu rad_add_server(struct rad_handle *h, const char *host, int port, 338 1.1 manu const char *secret, int timeout, int tries) 339 1.1 manu { 340 1.1 manu struct rad_server *srvp; 341 1.1 manu 342 1.1 manu if (h->num_servers >= MAXSERVERS) { 343 1.1 manu generr(h, "Too many RADIUS servers specified"); 344 1.1 manu return -1; 345 1.1 manu } 346 1.1 manu srvp = &h->servers[h->num_servers]; 347 1.1 manu 348 1.3 christos (void)memset(&srvp->addr, 0, sizeof srvp->addr); 349 1.1 manu srvp->addr.sin_len = sizeof srvp->addr; 350 1.1 manu srvp->addr.sin_family = AF_INET; 351 1.1 manu if (!inet_aton(host, &srvp->addr.sin_addr)) { 352 1.1 manu struct hostent *hent; 353 1.1 manu 354 1.1 manu if ((hent = gethostbyname(host)) == NULL) { 355 1.1 manu generr(h, "%s: host not found", host); 356 1.1 manu return -1; 357 1.1 manu } 358 1.3 christos (void)memcpy(&srvp->addr.sin_addr, hent->h_addr, 359 1.1 manu sizeof srvp->addr.sin_addr); 360 1.1 manu } 361 1.1 manu if (port != 0) 362 1.1 manu srvp->addr.sin_port = htons((u_short)port); 363 1.1 manu else { 364 1.1 manu struct servent *sent; 365 1.1 manu 366 1.1 manu if (h->type == RADIUS_AUTH) 367 1.1 manu srvp->addr.sin_port = 368 1.1 manu (sent = getservbyname("radius", "udp")) != NULL ? 369 1.1 manu sent->s_port : htons(RADIUS_PORT); 370 1.1 manu else 371 1.1 manu srvp->addr.sin_port = 372 1.1 manu (sent = getservbyname("radacct", "udp")) != NULL ? 373 1.1 manu sent->s_port : htons(RADACCT_PORT); 374 1.1 manu } 375 1.1 manu if ((srvp->secret = strdup(secret)) == NULL) { 376 1.1 manu generr(h, "Out of memory"); 377 1.1 manu return -1; 378 1.1 manu } 379 1.1 manu srvp->timeout = timeout; 380 1.1 manu srvp->max_tries = tries; 381 1.1 manu srvp->num_tries = 0; 382 1.1 manu h->num_servers++; 383 1.1 manu return 0; 384 1.1 manu } 385 1.1 manu 386 1.1 manu void 387 1.1 manu rad_close(struct rad_handle *h) 388 1.1 manu { 389 1.10 lukem size_t srv; 390 1.1 manu 391 1.1 manu if (h->fd != -1) 392 1.1 manu close(h->fd); 393 1.1 manu for (srv = 0; srv < h->num_servers; srv++) { 394 1.3 christos (void)memset(h->servers[srv].secret, 0, 395 1.1 manu strlen(h->servers[srv].secret)); 396 1.1 manu free(h->servers[srv].secret); 397 1.1 manu } 398 1.1 manu clear_password(h); 399 1.1 manu free(h); 400 1.1 manu } 401 1.1 manu 402 1.1 manu int 403 1.1 manu rad_config(struct rad_handle *h, const char *path) 404 1.1 manu { 405 1.1 manu FILE *fp; 406 1.1 manu char buf[MAXCONFLINE]; 407 1.1 manu int linenum; 408 1.1 manu int retval; 409 1.1 manu 410 1.1 manu if (path == NULL) 411 1.1 manu path = PATH_RADIUS_CONF; 412 1.1 manu if ((fp = fopen(path, "r")) == NULL) { 413 1.1 manu generr(h, "Cannot open \"%s\": %s", path, strerror(errno)); 414 1.1 manu return -1; 415 1.1 manu } 416 1.1 manu retval = 0; 417 1.1 manu linenum = 0; 418 1.3 christos while (fgets(buf, (int)sizeof buf, fp) != NULL) { 419 1.3 christos size_t len; 420 1.2 christos const char *fields[5]; 421 1.11 jmmv size_t nfields; 422 1.1 manu char msg[ERRSIZE]; 423 1.2 christos const char *type; 424 1.2 christos const char *host; 425 1.2 christos char *res; 426 1.2 christos const char *port_str; 427 1.2 christos const char *secret; 428 1.2 christos const char *timeout_str; 429 1.2 christos const char *maxtries_str; 430 1.1 manu char *end; 431 1.2 christos const char *wanttype; 432 1.1 manu unsigned long timeout; 433 1.1 manu unsigned long maxtries; 434 1.1 manu int port; 435 1.3 christos size_t i; 436 1.1 manu 437 1.1 manu linenum++; 438 1.1 manu len = strlen(buf); 439 1.1 manu /* We know len > 0, else fgets would have returned NULL. */ 440 1.1 manu if (buf[len - 1] != '\n') { 441 1.1 manu if (len == sizeof buf - 1) 442 1.1 manu generr(h, "%s:%d: line too long", path, 443 1.1 manu linenum); 444 1.1 manu else 445 1.1 manu generr(h, "%s:%d: missing newline", path, 446 1.1 manu linenum); 447 1.1 manu retval = -1; 448 1.1 manu break; 449 1.1 manu } 450 1.1 manu buf[len - 1] = '\0'; 451 1.1 manu 452 1.1 manu /* Extract the fields from the line. */ 453 1.11 jmmv msg[0] = '\0'; 454 1.2 christos nfields = split(buf, fields, sizeof(fields) / sizeof(fields[0]), 455 1.2 christos msg, sizeof msg); 456 1.11 jmmv if (msg[0] != '\0') { 457 1.1 manu generr(h, "%s:%d: %s", path, linenum, msg); 458 1.1 manu retval = -1; 459 1.1 manu break; 460 1.1 manu } 461 1.1 manu if (nfields == 0) 462 1.1 manu continue; 463 1.1 manu /* 464 1.1 manu * The first field should contain "auth" or "acct" for 465 1.1 manu * authentication or accounting, respectively. But older 466 1.1 manu * versions of the file didn't have that field. Default 467 1.1 manu * it to "auth" for backward compatibility. 468 1.1 manu */ 469 1.1 manu if (strcmp(fields[0], "auth") != 0 && 470 1.1 manu strcmp(fields[0], "acct") != 0) { 471 1.1 manu if (nfields >= 5) { 472 1.1 manu generr(h, "%s:%d: invalid service type", path, 473 1.1 manu linenum); 474 1.1 manu retval = -1; 475 1.1 manu break; 476 1.1 manu } 477 1.1 manu nfields++; 478 1.1 manu for (i = nfields; --i > 0; ) 479 1.1 manu fields[i] = fields[i - 1]; 480 1.1 manu fields[0] = "auth"; 481 1.1 manu } 482 1.1 manu if (nfields < 3) { 483 1.1 manu generr(h, "%s:%d: missing shared secret", path, 484 1.1 manu linenum); 485 1.1 manu retval = -1; 486 1.1 manu break; 487 1.1 manu } 488 1.1 manu type = fields[0]; 489 1.1 manu host = fields[1]; 490 1.1 manu secret = fields[2]; 491 1.1 manu timeout_str = fields[3]; 492 1.1 manu maxtries_str = fields[4]; 493 1.1 manu 494 1.1 manu /* Ignore the line if it is for the wrong service type. */ 495 1.1 manu wanttype = h->type == RADIUS_AUTH ? "auth" : "acct"; 496 1.1 manu if (strcmp(type, wanttype) != 0) 497 1.1 manu continue; 498 1.1 manu 499 1.1 manu /* Parse and validate the fields. */ 500 1.2 christos res = __UNCONST(host); 501 1.1 manu host = strsep(&res, ":"); 502 1.1 manu port_str = strsep(&res, ":"); 503 1.1 manu if (port_str != NULL) { 504 1.3 christos port = (int)strtoul(port_str, &end, 10); 505 1.1 manu if (*end != '\0') { 506 1.1 manu generr(h, "%s:%d: invalid port", path, 507 1.1 manu linenum); 508 1.1 manu retval = -1; 509 1.1 manu break; 510 1.1 manu } 511 1.1 manu } else 512 1.1 manu port = 0; 513 1.1 manu if (timeout_str != NULL) { 514 1.1 manu timeout = strtoul(timeout_str, &end, 10); 515 1.1 manu if (*end != '\0') { 516 1.1 manu generr(h, "%s:%d: invalid timeout", path, 517 1.1 manu linenum); 518 1.1 manu retval = -1; 519 1.1 manu break; 520 1.1 manu } 521 1.1 manu } else 522 1.1 manu timeout = TIMEOUT; 523 1.1 manu if (maxtries_str != NULL) { 524 1.1 manu maxtries = strtoul(maxtries_str, &end, 10); 525 1.1 manu if (*end != '\0') { 526 1.1 manu generr(h, "%s:%d: invalid maxtries", path, 527 1.1 manu linenum); 528 1.1 manu retval = -1; 529 1.1 manu break; 530 1.1 manu } 531 1.1 manu } else 532 1.1 manu maxtries = MAXTRIES; 533 1.1 manu 534 1.2 christos if (rad_add_server(h, host, port, secret, (int)timeout, 535 1.2 christos (int)maxtries) == -1) { 536 1.2 christos (void)strcpy(msg, h->errmsg); 537 1.1 manu generr(h, "%s:%d: %s", path, linenum, msg); 538 1.1 manu retval = -1; 539 1.1 manu break; 540 1.1 manu } 541 1.1 manu } 542 1.1 manu /* Clear out the buffer to wipe a possible copy of a shared secret */ 543 1.3 christos (void)memset(buf, 0, sizeof buf); 544 1.1 manu fclose(fp); 545 1.1 manu return retval; 546 1.1 manu } 547 1.1 manu 548 1.1 manu /* 549 1.1 manu * rad_init_send_request() must have previously been called. 550 1.1 manu * Returns: 551 1.1 manu * 0 The application should select on *fd with a timeout of tv before 552 1.1 manu * calling rad_continue_send_request again. 553 1.1 manu * < 0 Failure 554 1.1 manu * > 0 Success 555 1.1 manu */ 556 1.1 manu int 557 1.1 manu rad_continue_send_request(struct rad_handle *h, int selected, int *fd, 558 1.1 manu struct timeval *tv) 559 1.1 manu { 560 1.3 christos ssize_t n; 561 1.1 manu 562 1.1 manu if (selected) { 563 1.1 manu struct sockaddr_in from; 564 1.2 christos socklen_t fromlen; 565 1.2 christos ssize_t rv; 566 1.1 manu 567 1.1 manu fromlen = sizeof from; 568 1.3 christos rv = recvfrom(h->fd, h->response, (size_t)MSGSIZE, 569 1.3 christos MSG_WAITALL, (struct sockaddr *)(void *)&from, &fromlen); 570 1.2 christos if (rv == -1) { 571 1.1 manu generr(h, "recvfrom: %s", strerror(errno)); 572 1.1 manu return -1; 573 1.1 manu } 574 1.2 christos h->resp_len = rv; 575 1.1 manu if (is_valid_response(h, h->srv, &from)) { 576 1.1 manu h->resp_len = h->response[POS_LENGTH] << 8 | 577 1.1 manu h->response[POS_LENGTH+1]; 578 1.1 manu h->resp_pos = POS_ATTRS; 579 1.1 manu return h->response[POS_CODE]; 580 1.1 manu } 581 1.1 manu } 582 1.1 manu 583 1.1 manu if (h->try == h->total_tries) { 584 1.1 manu generr(h, "No valid RADIUS responses received"); 585 1.1 manu return -1; 586 1.1 manu } 587 1.1 manu 588 1.1 manu /* 589 1.1 manu * Scan round-robin to the next server that has some 590 1.1 manu * tries left. There is guaranteed to be one, or we 591 1.1 manu * would have exited this loop by now. 592 1.1 manu */ 593 1.1 manu while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries) 594 1.1 manu if (++h->srv >= h->num_servers) 595 1.1 manu h->srv = 0; 596 1.1 manu 597 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) 598 1.1 manu /* Insert the request authenticator into the request */ 599 1.1 manu insert_request_authenticator(h, h->srv); 600 1.1 manu else 601 1.1 manu /* Insert the scrambled password into the request */ 602 1.1 manu if (h->pass_pos != 0) 603 1.1 manu insert_scrambled_password(h, h->srv); 604 1.1 manu 605 1.1 manu insert_message_authenticator(h, h->srv); 606 1.1 manu 607 1.1 manu /* Send the request */ 608 1.1 manu n = sendto(h->fd, h->request, h->req_len, 0, 609 1.2 christos (const struct sockaddr *)(void *)&h->servers[h->srv].addr, 610 1.2 christos (socklen_t)sizeof h->servers[h->srv].addr); 611 1.3 christos if (n != (ssize_t)h->req_len) { 612 1.1 manu if (n == -1) 613 1.1 manu generr(h, "sendto: %s", strerror(errno)); 614 1.1 manu else 615 1.1 manu generr(h, "sendto: short write"); 616 1.1 manu return -1; 617 1.1 manu } 618 1.1 manu 619 1.1 manu h->try++; 620 1.1 manu h->servers[h->srv].num_tries++; 621 1.1 manu tv->tv_sec = h->servers[h->srv].timeout; 622 1.1 manu tv->tv_usec = 0; 623 1.1 manu *fd = h->fd; 624 1.1 manu 625 1.1 manu return 0; 626 1.1 manu } 627 1.1 manu 628 1.1 manu int 629 1.1 manu rad_create_request(struct rad_handle *h, int code) 630 1.1 manu { 631 1.1 manu int i; 632 1.1 manu 633 1.1 manu h->request[POS_CODE] = code; 634 1.1 manu h->request[POS_IDENT] = ++h->ident; 635 1.1 manu /* Create a random authenticator */ 636 1.1 manu for (i = 0; i < LEN_AUTH; i += 2) { 637 1.2 christos uint32_t r; 638 1.2 christos r = (uint32_t)random(); 639 1.1 manu h->request[POS_AUTH+i] = (u_char)r; 640 1.1 manu h->request[POS_AUTH+i+1] = (u_char)(r >> 8); 641 1.1 manu } 642 1.1 manu h->req_len = POS_ATTRS; 643 1.1 manu clear_password(h); 644 1.1 manu h->request_created = 1; 645 1.1 manu return 0; 646 1.1 manu } 647 1.1 manu 648 1.1 manu struct in_addr 649 1.1 manu rad_cvt_addr(const void *data) 650 1.1 manu { 651 1.1 manu struct in_addr value; 652 1.1 manu 653 1.3 christos (void)memcpy(&value.s_addr, data, sizeof value.s_addr); 654 1.1 manu return value; 655 1.1 manu } 656 1.1 manu 657 1.1 manu u_int32_t 658 1.1 manu rad_cvt_int(const void *data) 659 1.1 manu { 660 1.1 manu u_int32_t value; 661 1.1 manu 662 1.3 christos (void)memcpy(&value, data, sizeof value); 663 1.1 manu return ntohl(value); 664 1.1 manu } 665 1.1 manu 666 1.1 manu char * 667 1.1 manu rad_cvt_string(const void *data, size_t len) 668 1.1 manu { 669 1.1 manu char *s; 670 1.1 manu 671 1.1 manu s = malloc(len + 1); 672 1.1 manu if (s != NULL) { 673 1.3 christos (void)memcpy(s, data, len); 674 1.1 manu s[len] = '\0'; 675 1.1 manu } 676 1.1 manu return s; 677 1.1 manu } 678 1.1 manu 679 1.1 manu /* 680 1.1 manu * Returns the attribute type. If none are left, returns 0. On failure, 681 1.1 manu * returns -1. 682 1.1 manu */ 683 1.1 manu int 684 1.1 manu rad_get_attr(struct rad_handle *h, const void **value, size_t *len) 685 1.1 manu { 686 1.1 manu int type; 687 1.1 manu 688 1.1 manu if (h->resp_pos >= h->resp_len) 689 1.1 manu return 0; 690 1.1 manu if (h->resp_pos + 2 > h->resp_len) { 691 1.1 manu generr(h, "Malformed attribute in response"); 692 1.1 manu return -1; 693 1.1 manu } 694 1.1 manu type = h->response[h->resp_pos++]; 695 1.1 manu *len = h->response[h->resp_pos++] - 2; 696 1.1 manu if (h->resp_pos + (int)*len > h->resp_len) { 697 1.1 manu generr(h, "Malformed attribute in response"); 698 1.1 manu return -1; 699 1.1 manu } 700 1.1 manu *value = &h->response[h->resp_pos]; 701 1.4 he h->resp_pos += (int)*len; 702 1.1 manu return type; 703 1.1 manu } 704 1.1 manu 705 1.1 manu /* 706 1.1 manu * Returns -1 on error, 0 to indicate no event and >0 for success 707 1.1 manu */ 708 1.1 manu int 709 1.1 manu rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv) 710 1.1 manu { 711 1.10 lukem size_t srv; 712 1.1 manu 713 1.1 manu /* Make sure we have a socket to use */ 714 1.1 manu if (h->fd == -1) { 715 1.1 manu struct sockaddr_in saddr; 716 1.1 manu 717 1.1 manu if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { 718 1.1 manu generr(h, "Cannot create socket: %s", strerror(errno)); 719 1.1 manu return -1; 720 1.1 manu } 721 1.3 christos (void)memset(&saddr, 0, sizeof saddr); 722 1.1 manu saddr.sin_len = sizeof saddr; 723 1.1 manu saddr.sin_family = AF_INET; 724 1.1 manu saddr.sin_addr.s_addr = INADDR_ANY; 725 1.1 manu saddr.sin_port = htons(0); 726 1.2 christos if (bind(h->fd, (const struct sockaddr *)(void *)&saddr, 727 1.3 christos (socklen_t)sizeof saddr) == -1) { 728 1.1 manu generr(h, "bind: %s", strerror(errno)); 729 1.1 manu close(h->fd); 730 1.1 manu h->fd = -1; 731 1.1 manu return -1; 732 1.1 manu } 733 1.1 manu } 734 1.1 manu 735 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { 736 1.1 manu /* Make sure no password given */ 737 1.1 manu if (h->pass_pos || h->chap_pass) { 738 1.1 manu generr(h, "User or Chap Password" 739 1.1 manu " in accounting request"); 740 1.1 manu return -1; 741 1.1 manu } 742 1.1 manu } else { 743 1.1 manu if (h->eap_msg == 0) { 744 1.1 manu /* Make sure the user gave us a password */ 745 1.1 manu if (h->pass_pos == 0 && !h->chap_pass) { 746 1.1 manu generr(h, "No User or Chap Password" 747 1.1 manu " attributes given"); 748 1.1 manu return -1; 749 1.1 manu } 750 1.1 manu if (h->pass_pos != 0 && h->chap_pass) { 751 1.1 manu generr(h, "Both User and Chap Password" 752 1.1 manu " attributes given"); 753 1.1 manu return -1; 754 1.1 manu } 755 1.1 manu } 756 1.1 manu } 757 1.1 manu 758 1.1 manu /* Fill in the length field in the message */ 759 1.3 christos h->request[POS_LENGTH] = (unsigned char)(h->req_len >> 8); 760 1.3 christos h->request[POS_LENGTH+1] = (unsigned char)h->req_len; 761 1.1 manu 762 1.1 manu /* 763 1.1 manu * Count the total number of tries we will make, and zero the 764 1.1 manu * counter for each server. 765 1.1 manu */ 766 1.1 manu h->total_tries = 0; 767 1.1 manu for (srv = 0; srv < h->num_servers; srv++) { 768 1.1 manu h->total_tries += h->servers[srv].max_tries; 769 1.1 manu h->servers[srv].num_tries = 0; 770 1.1 manu } 771 1.1 manu if (h->total_tries == 0) { 772 1.1 manu generr(h, "No RADIUS servers specified"); 773 1.1 manu return -1; 774 1.1 manu } 775 1.1 manu 776 1.1 manu h->try = h->srv = 0; 777 1.1 manu 778 1.1 manu return rad_continue_send_request(h, 0, fd, tv); 779 1.1 manu } 780 1.1 manu 781 1.1 manu /* 782 1.1 manu * Create and initialize a rad_handle structure, and return it to the 783 1.1 manu * caller. Can fail only if the necessary memory cannot be allocated. 784 1.1 manu * In that case, it returns NULL. 785 1.1 manu */ 786 1.1 manu struct rad_handle * 787 1.1 manu rad_auth_open(void) 788 1.1 manu { 789 1.1 manu struct rad_handle *h; 790 1.1 manu 791 1.1 manu h = (struct rad_handle *)malloc(sizeof(struct rad_handle)); 792 1.1 manu if (h != NULL) { 793 1.5 he srandomdev(0); 794 1.1 manu h->fd = -1; 795 1.1 manu h->num_servers = 0; 796 1.1 manu h->ident = random(); 797 1.1 manu h->errmsg[0] = '\0'; 798 1.3 christos (void)memset(h->pass, 0, sizeof h->pass); 799 1.1 manu h->pass_len = 0; 800 1.1 manu h->pass_pos = 0; 801 1.1 manu h->chap_pass = 0; 802 1.1 manu h->authentic_pos = 0; 803 1.1 manu h->type = RADIUS_AUTH; 804 1.1 manu h->request_created = 0; 805 1.1 manu h->eap_msg = 0; 806 1.1 manu } 807 1.1 manu return h; 808 1.1 manu } 809 1.1 manu 810 1.1 manu struct rad_handle * 811 1.1 manu rad_acct_open(void) 812 1.1 manu { 813 1.1 manu struct rad_handle *h; 814 1.1 manu 815 1.1 manu h = rad_open(); 816 1.1 manu if (h != NULL) 817 1.1 manu h->type = RADIUS_ACCT; 818 1.1 manu return h; 819 1.1 manu } 820 1.1 manu 821 1.1 manu struct rad_handle * 822 1.1 manu rad_open(void) 823 1.1 manu { 824 1.1 manu return rad_auth_open(); 825 1.1 manu } 826 1.1 manu 827 1.1 manu int 828 1.1 manu rad_put_addr(struct rad_handle *h, int type, struct in_addr addr) 829 1.1 manu { 830 1.1 manu return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr); 831 1.1 manu } 832 1.1 manu 833 1.1 manu int 834 1.1 manu rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len) 835 1.1 manu { 836 1.1 manu int result; 837 1.1 manu 838 1.1 manu if (!h->request_created) { 839 1.1 manu generr(h, "Please call rad_create_request()" 840 1.1 manu " before putting attributes"); 841 1.1 manu return -1; 842 1.1 manu } 843 1.1 manu 844 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { 845 1.1 manu if (type == RAD_EAP_MESSAGE) { 846 1.1 manu generr(h, "EAP-Message attribute is not valid" 847 1.1 manu " in accounting requests"); 848 1.1 manu return -1; 849 1.1 manu } 850 1.1 manu } 851 1.1 manu 852 1.1 manu /* 853 1.1 manu * When proxying EAP Messages, the Message Authenticator 854 1.1 manu * MUST be present; see RFC 3579. 855 1.1 manu */ 856 1.1 manu if (type == RAD_EAP_MESSAGE) { 857 1.1 manu if (rad_put_message_authentic(h) == -1) 858 1.1 manu return -1; 859 1.1 manu } 860 1.1 manu 861 1.1 manu if (type == RAD_USER_PASSWORD) { 862 1.1 manu result = put_password_attr(h, type, value, len); 863 1.1 manu } else if (type == RAD_MESSAGE_AUTHENTIC) { 864 1.1 manu result = rad_put_message_authentic(h); 865 1.1 manu } else { 866 1.1 manu result = put_raw_attr(h, type, value, len); 867 1.1 manu if (result == 0) { 868 1.1 manu if (type == RAD_CHAP_PASSWORD) 869 1.1 manu h->chap_pass = 1; 870 1.1 manu else if (type == RAD_EAP_MESSAGE) 871 1.1 manu h->eap_msg = 1; 872 1.1 manu } 873 1.1 manu } 874 1.1 manu 875 1.1 manu return result; 876 1.1 manu } 877 1.1 manu 878 1.1 manu int 879 1.1 manu rad_put_int(struct rad_handle *h, int type, u_int32_t value) 880 1.1 manu { 881 1.1 manu u_int32_t nvalue; 882 1.1 manu 883 1.1 manu nvalue = htonl(value); 884 1.1 manu return rad_put_attr(h, type, &nvalue, sizeof nvalue); 885 1.1 manu } 886 1.1 manu 887 1.1 manu int 888 1.1 manu rad_put_string(struct rad_handle *h, int type, const char *str) 889 1.1 manu { 890 1.1 manu return rad_put_attr(h, type, str, strlen(str)); 891 1.1 manu } 892 1.1 manu 893 1.1 manu int 894 1.1 manu rad_put_message_authentic(struct rad_handle *h) 895 1.1 manu { 896 1.1 manu #ifdef WITH_SSL 897 1.1 manu u_char md_zero[MD5_DIGEST_LENGTH]; 898 1.1 manu 899 1.1 manu if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { 900 1.1 manu generr(h, "Message-Authenticator is not valid" 901 1.1 manu " in accounting requests"); 902 1.1 manu return -1; 903 1.1 manu } 904 1.1 manu 905 1.1 manu if (h->authentic_pos == 0) { 906 1.4 he h->authentic_pos = (int)h->req_len; 907 1.3 christos (void)memset(md_zero, 0, sizeof(md_zero)); 908 1.1 manu return (put_raw_attr(h, RAD_MESSAGE_AUTHENTIC, md_zero, 909 1.1 manu sizeof(md_zero))); 910 1.1 manu } 911 1.1 manu return 0; 912 1.1 manu #else 913 1.1 manu generr(h, "Message Authenticator not supported," 914 1.1 manu " please recompile libradius with SSL support"); 915 1.1 manu return -1; 916 1.1 manu #endif 917 1.1 manu } 918 1.1 manu 919 1.1 manu /* 920 1.1 manu * Returns the response type code on success, or -1 on failure. 921 1.1 manu */ 922 1.1 manu int 923 1.1 manu rad_send_request(struct rad_handle *h) 924 1.1 manu { 925 1.1 manu struct timeval timelimit; 926 1.1 manu struct timeval tv; 927 1.1 manu int fd; 928 1.1 manu int n; 929 1.1 manu 930 1.1 manu n = rad_init_send_request(h, &fd, &tv); 931 1.1 manu 932 1.1 manu if (n != 0) 933 1.1 manu return n; 934 1.1 manu 935 1.1 manu gettimeofday(&timelimit, NULL); 936 1.1 manu timeradd(&tv, &timelimit, &timelimit); 937 1.1 manu 938 1.1 manu for ( ; ; ) { 939 1.1 manu fd_set readfds; 940 1.1 manu 941 1.1 manu FD_ZERO(&readfds); 942 1.1 manu FD_SET(fd, &readfds); 943 1.1 manu 944 1.1 manu n = select(fd + 1, &readfds, NULL, NULL, &tv); 945 1.1 manu 946 1.1 manu if (n == -1) { 947 1.1 manu generr(h, "select: %s", strerror(errno)); 948 1.1 manu return -1; 949 1.1 manu } 950 1.1 manu 951 1.1 manu if (!FD_ISSET(fd, &readfds)) { 952 1.1 manu /* Compute a new timeout */ 953 1.1 manu gettimeofday(&tv, NULL); 954 1.1 manu timersub(&timelimit, &tv, &tv); 955 1.1 manu if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0)) 956 1.1 manu /* Continue the select */ 957 1.1 manu continue; 958 1.1 manu } 959 1.1 manu 960 1.1 manu n = rad_continue_send_request(h, n, &fd, &tv); 961 1.1 manu 962 1.1 manu if (n != 0) 963 1.1 manu return n; 964 1.1 manu 965 1.1 manu gettimeofday(&timelimit, NULL); 966 1.1 manu timeradd(&tv, &timelimit, &timelimit); 967 1.1 manu } 968 1.1 manu } 969 1.1 manu 970 1.1 manu const char * 971 1.1 manu rad_strerror(struct rad_handle *h) 972 1.1 manu { 973 1.1 manu return h->errmsg; 974 1.1 manu } 975 1.1 manu 976 1.1 manu /* 977 1.1 manu * Destructively split a string into fields separated by white space. 978 1.1 manu * `#' at the beginning of a field begins a comment that extends to the 979 1.1 manu * end of the string. Fields may be quoted with `"'. Inside quoted 980 1.1 manu * strings, the backslash escapes `\"' and `\\' are honored. 981 1.1 manu * 982 1.1 manu * Pointers to up to the first maxfields fields are stored in the fields 983 1.1 manu * array. Missing fields get NULL pointers. 984 1.1 manu * 985 1.1 manu * The return value is the actual number of fields parsed, and is always 986 1.1 manu * <= maxfields. 987 1.1 manu * 988 1.11 jmmv * On a syntax error, places a message in the msg string, and returns 989 1.11 jmmv * SIZE_MAX. 990 1.1 manu */ 991 1.11 jmmv static size_t 992 1.3 christos split(char *str, const char *fields[], size_t maxfields, char *msg, 993 1.3 christos size_t msglen) 994 1.1 manu { 995 1.1 manu char *p; 996 1.10 lukem size_t i; 997 1.1 manu static const char ws[] = " \t"; 998 1.1 manu 999 1.1 manu for (i = 0; i < maxfields; i++) 1000 1.1 manu fields[i] = NULL; 1001 1.1 manu p = str; 1002 1.1 manu i = 0; 1003 1.1 manu while (*p != '\0') { 1004 1.1 manu p += strspn(p, ws); 1005 1.1 manu if (*p == '#' || *p == '\0') 1006 1.1 manu break; 1007 1.1 manu if (i >= maxfields) { 1008 1.1 manu snprintf(msg, msglen, "line has too many fields"); 1009 1.11 jmmv return SIZE_MAX; 1010 1.1 manu } 1011 1.1 manu if (*p == '"') { 1012 1.1 manu char *dst; 1013 1.1 manu 1014 1.1 manu dst = ++p; 1015 1.1 manu fields[i] = dst; 1016 1.1 manu while (*p != '"') { 1017 1.1 manu if (*p == '\\') { 1018 1.1 manu p++; 1019 1.1 manu if (*p != '"' && *p != '\\' && 1020 1.1 manu *p != '\0') { 1021 1.1 manu snprintf(msg, msglen, 1022 1.1 manu "invalid `\\' escape"); 1023 1.11 jmmv return SIZE_MAX; 1024 1.1 manu } 1025 1.1 manu } 1026 1.1 manu if (*p == '\0') { 1027 1.1 manu snprintf(msg, msglen, 1028 1.1 manu "unterminated quoted string"); 1029 1.11 jmmv return SIZE_MAX; 1030 1.1 manu } 1031 1.1 manu *dst++ = *p++; 1032 1.1 manu } 1033 1.1 manu *dst = '\0'; 1034 1.1 manu p++; 1035 1.1 manu if (*fields[i] == '\0') { 1036 1.1 manu snprintf(msg, msglen, 1037 1.1 manu "empty quoted string not permitted"); 1038 1.11 jmmv return SIZE_MAX; 1039 1.1 manu } 1040 1.1 manu if (*p != '\0' && strspn(p, ws) == 0) { 1041 1.1 manu snprintf(msg, msglen, "quoted string not" 1042 1.1 manu " followed by white space"); 1043 1.11 jmmv return SIZE_MAX; 1044 1.1 manu } 1045 1.1 manu } else { 1046 1.1 manu fields[i] = p; 1047 1.1 manu p += strcspn(p, ws); 1048 1.1 manu if (*p != '\0') 1049 1.1 manu *p++ = '\0'; 1050 1.1 manu } 1051 1.1 manu i++; 1052 1.1 manu } 1053 1.1 manu return i; 1054 1.1 manu } 1055 1.1 manu 1056 1.1 manu int 1057 1.1 manu rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len) 1058 1.1 manu { 1059 1.2 christos const struct vendor_attribute *attr; 1060 1.1 manu 1061 1.2 christos attr = (const struct vendor_attribute *)*data; 1062 1.1 manu *vendor = ntohl(attr->vendor_value); 1063 1.1 manu *data = attr->attrib_data; 1064 1.1 manu *len = attr->attrib_len - 2; 1065 1.1 manu 1066 1.1 manu return (attr->attrib_type); 1067 1.1 manu } 1068 1.1 manu 1069 1.1 manu int 1070 1.1 manu rad_put_vendor_addr(struct rad_handle *h, int vendor, int type, 1071 1.1 manu struct in_addr addr) 1072 1.1 manu { 1073 1.1 manu return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr, 1074 1.1 manu sizeof addr.s_addr)); 1075 1.1 manu } 1076 1.1 manu 1077 1.1 manu int 1078 1.1 manu rad_put_vendor_attr(struct rad_handle *h, int vendor, int type, 1079 1.1 manu const void *value, size_t len) 1080 1.1 manu { 1081 1.1 manu struct vendor_attribute *attr; 1082 1.1 manu int res; 1083 1.1 manu 1084 1.1 manu if (!h->request_created) { 1085 1.1 manu generr(h, "Please call rad_create_request()" 1086 1.1 manu " before putting attributes"); 1087 1.1 manu return -1; 1088 1.1 manu } 1089 1.1 manu 1090 1.1 manu if ((attr = malloc(len + 6)) == NULL) { 1091 1.1 manu generr(h, "malloc failure (%zu bytes)", len + 6); 1092 1.1 manu return -1; 1093 1.1 manu } 1094 1.1 manu 1095 1.2 christos attr->vendor_value = htonl((uint32_t)vendor); 1096 1.1 manu attr->attrib_type = type; 1097 1.3 christos attr->attrib_len = (unsigned char)(len + 2); 1098 1.3 christos (void)memcpy(attr->attrib_data, value, len); 1099 1.1 manu 1100 1.1 manu res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6); 1101 1.1 manu free(attr); 1102 1.1 manu if (res == 0 && vendor == RAD_VENDOR_MICROSOFT 1103 1.1 manu && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE 1104 1.1 manu || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) { 1105 1.1 manu h->chap_pass = 1; 1106 1.1 manu } 1107 1.1 manu return (res); 1108 1.1 manu } 1109 1.1 manu 1110 1.1 manu int 1111 1.1 manu rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i) 1112 1.1 manu { 1113 1.1 manu u_int32_t value; 1114 1.1 manu 1115 1.1 manu value = htonl(i); 1116 1.1 manu return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value)); 1117 1.1 manu } 1118 1.1 manu 1119 1.1 manu int 1120 1.1 manu rad_put_vendor_string(struct rad_handle *h, int vendor, int type, 1121 1.1 manu const char *str) 1122 1.1 manu { 1123 1.1 manu return (rad_put_vendor_attr(h, vendor, type, str, strlen(str))); 1124 1.1 manu } 1125 1.1 manu 1126 1.1 manu ssize_t 1127 1.1 manu rad_request_authenticator(struct rad_handle *h, char *buf, size_t len) 1128 1.1 manu { 1129 1.1 manu if (len < LEN_AUTH) 1130 1.1 manu return (-1); 1131 1.3 christos (void)memcpy(buf, h->request + POS_AUTH, (size_t)LEN_AUTH); 1132 1.1 manu if (len > LEN_AUTH) 1133 1.1 manu buf[LEN_AUTH] = '\0'; 1134 1.1 manu return (LEN_AUTH); 1135 1.1 manu } 1136 1.1 manu 1137 1.1 manu u_char * 1138 1.1 manu rad_demangle(struct rad_handle *h, const void *mangled, size_t mlen) 1139 1.1 manu { 1140 1.1 manu char R[LEN_AUTH]; 1141 1.1 manu const char *S; 1142 1.1 manu int i, Ppos; 1143 1.1 manu MD5_CTX Context; 1144 1.2 christos u_char b[MD5_DIGEST_LENGTH], *demangled; 1145 1.2 christos const u_char *C; 1146 1.1 manu 1147 1.1 manu if ((mlen % 16 != 0) || mlen > 128) { 1148 1.1 manu generr(h, "Cannot interpret mangled data of length %lu", 1149 1.1 manu (u_long)mlen); 1150 1.1 manu return NULL; 1151 1.1 manu } 1152 1.1 manu 1153 1.2 christos C = (const u_char *)mangled; 1154 1.1 manu 1155 1.1 manu /* We need the shared secret as Salt */ 1156 1.1 manu S = rad_server_secret(h); 1157 1.1 manu 1158 1.1 manu /* We need the request authenticator */ 1159 1.1 manu if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) { 1160 1.1 manu generr(h, "Cannot obtain the RADIUS request authenticator"); 1161 1.1 manu return NULL; 1162 1.1 manu } 1163 1.1 manu 1164 1.1 manu demangled = malloc(mlen); 1165 1.1 manu if (!demangled) 1166 1.1 manu return NULL; 1167 1.1 manu 1168 1.1 manu MD5Init(&Context); 1169 1.6 christos MD5Update(&Context, (MD5Buf)S, (MD5Len)strlen(S)); 1170 1.6 christos MD5Update(&Context, (MD5Buf)R, (MD5Len)LEN_AUTH); 1171 1.1 manu MD5Final(b, &Context); 1172 1.1 manu Ppos = 0; 1173 1.1 manu while (mlen) { 1174 1.1 manu 1175 1.1 manu mlen -= 16; 1176 1.1 manu for (i = 0; i < 16; i++) 1177 1.1 manu demangled[Ppos++] = C[i] ^ b[i]; 1178 1.1 manu 1179 1.1 manu if (mlen) { 1180 1.1 manu MD5Init(&Context); 1181 1.6 christos MD5Update(&Context, (MD5Buf)S, (MD5Len)strlen(S)); 1182 1.6 christos MD5Update(&Context, (MD5Buf)C, (MD5Len)16); 1183 1.1 manu MD5Final(b, &Context); 1184 1.1 manu } 1185 1.1 manu 1186 1.1 manu C += 16; 1187 1.1 manu } 1188 1.1 manu 1189 1.1 manu return demangled; 1190 1.1 manu } 1191 1.1 manu 1192 1.1 manu u_char * 1193 1.1 manu rad_demangle_mppe_key(struct rad_handle *h, const void *mangled, 1194 1.1 manu size_t mlen, size_t *len) 1195 1.1 manu { 1196 1.1 manu char R[LEN_AUTH]; /* variable names as per rfc2548 */ 1197 1.1 manu const char *S; 1198 1.9 christos u_char b[MD5_DIGEST_LENGTH], *demangled = NULL; 1199 1.1 manu const u_char *A, *C; 1200 1.1 manu MD5_CTX Context; 1201 1.2 christos size_t Slen, Clen, i, Ppos; 1202 1.1 manu u_char *P; 1203 1.1 manu 1204 1.1 manu if (mlen % 16 != SALT_LEN) { 1205 1.1 manu generr(h, "Cannot interpret mangled data of length %lu", 1206 1.1 manu (u_long)mlen); 1207 1.1 manu return NULL; 1208 1.1 manu } 1209 1.1 manu 1210 1.1 manu /* We need the RADIUS Request-Authenticator */ 1211 1.1 manu if (rad_request_authenticator(h, R, sizeof R) != LEN_AUTH) { 1212 1.1 manu generr(h, "Cannot obtain the RADIUS request authenticator"); 1213 1.1 manu return NULL; 1214 1.1 manu } 1215 1.1 manu 1216 1.1 manu A = (const u_char *)mangled; /* Salt comes first */ 1217 1.1 manu C = (const u_char *)mangled + SALT_LEN; /* Then the ciphertext */ 1218 1.1 manu Clen = mlen - SALT_LEN; 1219 1.1 manu S = rad_server_secret(h); /* We need the RADIUS secret */ 1220 1.1 manu Slen = strlen(S); 1221 1.9 christos P = malloc(Clen); /* We derive our plaintext */ 1222 1.1 manu 1223 1.1 manu MD5Init(&Context); 1224 1.6 christos MD5Update(&Context, (MD5Buf)S, (MD5Len)Slen); 1225 1.6 christos MD5Update(&Context, (MD5Buf)R, (MD5Len)LEN_AUTH); 1226 1.6 christos MD5Update(&Context, (MD5Buf)A, (MD5Len)SALT_LEN); 1227 1.1 manu MD5Final(b, &Context); 1228 1.1 manu Ppos = 0; 1229 1.1 manu 1230 1.1 manu while (Clen) { 1231 1.1 manu Clen -= 16; 1232 1.1 manu 1233 1.1 manu for (i = 0; i < 16; i++) 1234 1.1 manu P[Ppos++] = C[i] ^ b[i]; 1235 1.1 manu 1236 1.1 manu if (Clen) { 1237 1.1 manu MD5Init(&Context); 1238 1.6 christos MD5Update(&Context, (MD5Buf)S, (MD5Len)Slen); 1239 1.6 christos MD5Update(&Context, (MD5Buf)C, (MD5Len)16); 1240 1.1 manu MD5Final(b, &Context); 1241 1.1 manu } 1242 1.1 manu 1243 1.1 manu C += 16; 1244 1.1 manu } 1245 1.1 manu 1246 1.1 manu /* 1247 1.1 manu * The resulting plain text consists of a one-byte length, the text and 1248 1.1 manu * maybe some padding. 1249 1.1 manu */ 1250 1.1 manu *len = *P; 1251 1.1 manu if (*len > mlen - 1) { 1252 1.1 manu generr(h, "Mangled data seems to be garbage %zu %zu", 1253 1.1 manu *len, mlen-1); 1254 1.9 christos goto out; 1255 1.1 manu } 1256 1.1 manu 1257 1.1 manu if (*len > MPPE_KEY_LEN * 2) { 1258 1.1 manu generr(h, "Key to long (%zu) for me max. %d", 1259 1.1 manu *len, MPPE_KEY_LEN * 2); 1260 1.9 christos goto out; 1261 1.1 manu } 1262 1.1 manu demangled = malloc(*len); 1263 1.1 manu if (!demangled) 1264 1.9 christos goto out; 1265 1.1 manu 1266 1.3 christos (void)memcpy(demangled, P + 1, *len); 1267 1.9 christos out: 1268 1.9 christos free(P); 1269 1.1 manu return demangled; 1270 1.1 manu } 1271 1.1 manu 1272 1.1 manu const char * 1273 1.1 manu rad_server_secret(struct rad_handle *h) 1274 1.1 manu { 1275 1.1 manu return (h->servers[h->srv].secret); 1276 1.1 manu } 1277