1 /*- 2 * Copyright 1998 Juniper Networks, Inc. 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 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <sys/time.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 36 #include <errno.h> 37 #include <md5.h> 38 #include <netdb.h> 39 #include <stdarg.h> 40 #include <stddef.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "radlib_private.h" 47 48 static void clear_password(struct rad_handle *); 49 static void generr(struct rad_handle *, const char *, ...) 50 __printflike(2, 3); 51 static void insert_scrambled_password(struct rad_handle *, int); 52 static void insert_request_authenticator(struct rad_handle *, int); 53 static int is_valid_response(struct rad_handle *, int, 54 const struct sockaddr_in *); 55 static int put_password_attr(struct rad_handle *, int, 56 const void *, size_t); 57 static int put_raw_attr(struct rad_handle *, int, 58 const void *, size_t); 59 static int split(char *, char *[], int, char *, size_t); 60 61 static void 62 clear_password(struct rad_handle *h) 63 { 64 if (h->pass_len != 0) { 65 memset(h->pass, 0, h->pass_len); 66 h->pass_len = 0; 67 } 68 h->pass_pos = 0; 69 } 70 71 static void 72 generr(struct rad_handle *h, const char *format, ...) 73 { 74 va_list ap; 75 76 va_start(ap, format); 77 vsnprintf(h->errmsg, ERRSIZE, format, ap); 78 va_end(ap); 79 } 80 81 static void 82 insert_scrambled_password(struct rad_handle *h, int srv) 83 { 84 MD5_CTX ctx; 85 unsigned char md5[16]; 86 const struct rad_server *srvp; 87 int padded_len; 88 int pos; 89 90 srvp = &h->servers[srv]; 91 padded_len = h->pass_len == 0 ? 16 : (h->pass_len+15) & ~0xf; 92 93 memcpy(md5, &h->request[POS_AUTH], LEN_AUTH); 94 for (pos = 0; pos < padded_len; pos += 16) { 95 int i; 96 97 /* Calculate the new scrambler */ 98 MD5Init(&ctx); 99 MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); 100 MD5Update(&ctx, md5, 16); 101 MD5Final(md5, &ctx); 102 103 /* 104 * Mix in the current chunk of the password, and copy 105 * the result into the right place in the request. Also 106 * modify the scrambler in place, since we will use this 107 * in calculating the scrambler for next time. 108 */ 109 for (i = 0; i < 16; i++) 110 h->request[h->pass_pos + pos + i] = 111 md5[i] ^= h->pass[pos + i]; 112 } 113 } 114 115 static void 116 insert_request_authenticator(struct rad_handle *h, int srv) 117 { 118 MD5_CTX ctx; 119 const struct rad_server *srvp; 120 121 srvp = &h->servers[srv]; 122 123 /* Create the request authenticator */ 124 MD5Init(&ctx); 125 MD5Update(&ctx, &h->request[POS_CODE], POS_AUTH - POS_CODE); 126 MD5Update(&ctx, memset(&h->request[POS_AUTH], 0, LEN_AUTH), LEN_AUTH); 127 MD5Update(&ctx, &h->request[POS_ATTRS], h->req_len - POS_ATTRS); 128 MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); 129 MD5Final(&h->request[POS_AUTH], &ctx); 130 } 131 132 /* 133 * Return true if the current response is valid for a request to the 134 * specified server. 135 */ 136 static int 137 is_valid_response(struct rad_handle *h, int srv, 138 const struct sockaddr_in *from) 139 { 140 MD5_CTX ctx; 141 unsigned char md5[16]; 142 const struct rad_server *srvp; 143 int len; 144 145 srvp = &h->servers[srv]; 146 147 /* Check the source address */ 148 if (from->sin_family != srvp->addr.sin_family || 149 from->sin_addr.s_addr != srvp->addr.sin_addr.s_addr || 150 from->sin_port != srvp->addr.sin_port) 151 return 0; 152 153 /* Check the message length */ 154 if (h->resp_len < POS_ATTRS) 155 return 0; 156 len = h->response[POS_LENGTH] << 8 | h->response[POS_LENGTH+1]; 157 if (len > h->resp_len) 158 return 0; 159 160 /* Check the response authenticator */ 161 MD5Init(&ctx); 162 MD5Update(&ctx, &h->response[POS_CODE], POS_AUTH - POS_CODE); 163 MD5Update(&ctx, &h->request[POS_AUTH], LEN_AUTH); 164 MD5Update(&ctx, &h->response[POS_ATTRS], len - POS_ATTRS); 165 MD5Update(&ctx, srvp->secret, strlen(srvp->secret)); 166 MD5Final(md5, &ctx); 167 if (memcmp(&h->response[POS_AUTH], md5, sizeof md5) != 0) 168 return 0; 169 170 return 1; 171 } 172 173 static int 174 put_password_attr(struct rad_handle *h, int type, const void *value, size_t len) 175 { 176 int padded_len; 177 int pad_len; 178 179 if (h->pass_pos != 0) { 180 generr(h, "Multiple User-Password attributes specified"); 181 return -1; 182 } 183 if (len > PASSSIZE) 184 len = PASSSIZE; 185 padded_len = len == 0 ? 16 : (len+15) & ~0xf; 186 pad_len = padded_len - len; 187 188 /* 189 * Put in a place-holder attribute containing all zeros, and 190 * remember where it is so we can fill it in later. 191 */ 192 clear_password(h); 193 put_raw_attr(h, type, h->pass, padded_len); 194 h->pass_pos = h->req_len - padded_len; 195 196 /* Save the cleartext password, padded as necessary */ 197 memcpy(h->pass, value, len); 198 h->pass_len = len; 199 memset(h->pass + len, 0, pad_len); 200 return 0; 201 } 202 203 static int 204 put_raw_attr(struct rad_handle *h, int type, const void *value, size_t len) 205 { 206 if (len > 253) { 207 generr(h, "Attribute too long"); 208 return -1; 209 } 210 if (h->req_len + 2 + len > MSGSIZE) { 211 generr(h, "Maximum message length exceeded"); 212 return -1; 213 } 214 h->request[h->req_len++] = type; 215 h->request[h->req_len++] = len + 2; 216 memcpy(&h->request[h->req_len], value, len); 217 h->req_len += len; 218 return 0; 219 } 220 221 int 222 rad_add_server(struct rad_handle *h, const char *host, int port, 223 const char *secret, int timeout, int tries) 224 { 225 struct rad_server *srvp; 226 227 if (h->num_servers >= MAXSERVERS) { 228 generr(h, "Too many RADIUS servers specified"); 229 return -1; 230 } 231 srvp = &h->servers[h->num_servers]; 232 233 memset(&srvp->addr, 0, sizeof srvp->addr); 234 srvp->addr.sin_len = sizeof srvp->addr; 235 srvp->addr.sin_family = AF_INET; 236 if (!inet_aton(host, &srvp->addr.sin_addr)) { 237 struct hostent *hent; 238 239 if ((hent = gethostbyname(host)) == NULL) { 240 generr(h, "%s: host not found", host); 241 return -1; 242 } 243 memcpy(&srvp->addr.sin_addr, hent->h_addr, 244 sizeof srvp->addr.sin_addr); 245 } 246 if (port != 0) 247 srvp->addr.sin_port = htons(port); 248 else { 249 struct servent *sent; 250 251 if (h->type == RADIUS_AUTH) 252 srvp->addr.sin_port = 253 (sent = getservbyname("radius", "udp")) != NULL ? 254 sent->s_port : htons(RADIUS_PORT); 255 else 256 srvp->addr.sin_port = 257 (sent = getservbyname("radacct", "udp")) != NULL ? 258 sent->s_port : htons(RADACCT_PORT); 259 } 260 if ((srvp->secret = strdup(secret)) == NULL) { 261 generr(h, "Out of memory"); 262 return -1; 263 } 264 srvp->timeout = timeout; 265 srvp->max_tries = tries; 266 srvp->num_tries = 0; 267 h->num_servers++; 268 return 0; 269 } 270 271 void 272 rad_close(struct rad_handle *h) 273 { 274 int srv; 275 276 if (h->fd != -1) 277 close(h->fd); 278 for (srv = 0; srv < h->num_servers; srv++) { 279 memset(h->servers[srv].secret, 0, 280 strlen(h->servers[srv].secret)); 281 free(h->servers[srv].secret); 282 } 283 clear_password(h); 284 free(h); 285 } 286 287 int 288 rad_config(struct rad_handle *h, const char *path) 289 { 290 FILE *fp; 291 char buf[MAXCONFLINE]; 292 int linenum; 293 int retval; 294 295 if (path == NULL) 296 path = PATH_RADIUS_CONF; 297 if ((fp = fopen(path, "r")) == NULL) { 298 generr(h, "Cannot open \"%s\": %s", path, strerror(errno)); 299 return -1; 300 } 301 retval = 0; 302 linenum = 0; 303 while (fgets(buf, sizeof buf, fp) != NULL) { 304 int len; 305 char *fields[5]; 306 int nfields; 307 char msg[ERRSIZE]; 308 char *type; 309 char *host, *res; 310 char *port_str; 311 char *secret; 312 char *timeout_str; 313 char *maxtries_str; 314 char *end; 315 char *wanttype; 316 unsigned long timeout; 317 unsigned long maxtries; 318 int port; 319 int i; 320 321 linenum++; 322 len = strlen(buf); 323 /* We know len > 0, else fgets would have returned NULL. */ 324 if (buf[len - 1] != '\n') { 325 if (len == sizeof buf - 1) 326 generr(h, "%s:%d: line too long", path, 327 linenum); 328 else 329 generr(h, "%s:%d: missing newline", path, 330 linenum); 331 retval = -1; 332 break; 333 } 334 buf[len - 1] = '\0'; 335 336 /* Extract the fields from the line. */ 337 nfields = split(buf, fields, 5, msg, sizeof msg); 338 if (nfields == -1) { 339 generr(h, "%s:%d: %s", path, linenum, msg); 340 retval = -1; 341 break; 342 } 343 if (nfields == 0) 344 continue; 345 /* 346 * The first field should contain "auth" or "acct" for 347 * authentication or accounting, respectively. But older 348 * versions of the file didn't have that field. Default 349 * it to "auth" for backward compatibility. 350 */ 351 if (strcmp(fields[0], "auth") != 0 && 352 strcmp(fields[0], "acct") != 0) { 353 if (nfields >= 5) { 354 generr(h, "%s:%d: invalid service type", path, 355 linenum); 356 retval = -1; 357 break; 358 } 359 nfields++; 360 for (i = nfields; --i > 0; ) 361 fields[i] = fields[i - 1]; 362 fields[0] = "auth"; 363 } 364 if (nfields < 3) { 365 generr(h, "%s:%d: missing shared secret", path, 366 linenum); 367 retval = -1; 368 break; 369 } 370 type = fields[0]; 371 host = fields[1]; 372 secret = fields[2]; 373 timeout_str = fields[3]; 374 maxtries_str = fields[4]; 375 376 /* Ignore the line if it is for the wrong service type. */ 377 wanttype = h->type == RADIUS_AUTH ? "auth" : "acct"; 378 if (strcmp(type, wanttype) != 0) 379 continue; 380 381 /* Parse and validate the fields. */ 382 res = host; 383 host = strsep(&res, ":"); 384 port_str = strsep(&res, ":"); 385 if (port_str != NULL) { 386 port = strtoul(port_str, &end, 10); 387 if (*end != '\0') { 388 generr(h, "%s:%d: invalid port", path, 389 linenum); 390 retval = -1; 391 break; 392 } 393 } else 394 port = 0; 395 if (timeout_str != NULL) { 396 timeout = strtoul(timeout_str, &end, 10); 397 if (*end != '\0') { 398 generr(h, "%s:%d: invalid timeout", path, 399 linenum); 400 retval = -1; 401 break; 402 } 403 } else 404 timeout = TIMEOUT; 405 if (maxtries_str != NULL) { 406 maxtries = strtoul(maxtries_str, &end, 10); 407 if (*end != '\0') { 408 generr(h, "%s:%d: invalid maxtries", path, 409 linenum); 410 retval = -1; 411 break; 412 } 413 } else 414 maxtries = MAXTRIES; 415 416 if (rad_add_server(h, host, port, secret, timeout, maxtries) == 417 -1) { 418 strcpy(msg, h->errmsg); 419 generr(h, "%s:%d: %s", path, linenum, msg); 420 retval = -1; 421 break; 422 } 423 } 424 /* Clear out the buffer to wipe a possible copy of a shared secret */ 425 memset(buf, 0, sizeof buf); 426 fclose(fp); 427 return retval; 428 } 429 430 /* 431 * rad_init_send_request() must have previously been called. 432 * Returns: 433 * 0 The application should select on *fd with a timeout of tv before 434 * calling rad_continue_send_request again. 435 * < 0 Failure 436 * > 0 Success 437 */ 438 int 439 rad_continue_send_request(struct rad_handle *h, int selected, int *fd, 440 struct timeval *tv) 441 { 442 int n; 443 444 if (selected) { 445 struct sockaddr_in from; 446 int fromlen; 447 448 fromlen = sizeof from; 449 h->resp_len = recvfrom(h->fd, h->response, 450 MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen); 451 if (h->resp_len == -1) { 452 generr(h, "recvfrom: %s", strerror(errno)); 453 return -1; 454 } 455 if (is_valid_response(h, h->srv, &from)) { 456 h->resp_len = h->response[POS_LENGTH] << 8 | 457 h->response[POS_LENGTH+1]; 458 h->resp_pos = POS_ATTRS; 459 return h->response[POS_CODE]; 460 } 461 } 462 463 if (h->try == h->total_tries) { 464 generr(h, "No valid RADIUS responses received"); 465 return -1; 466 } 467 468 /* 469 * Scan round-robin to the next server that has some 470 * tries left. There is guaranteed to be one, or we 471 * would have exited this loop by now. 472 */ 473 while (h->servers[h->srv].num_tries >= h->servers[h->srv].max_tries) 474 if (++h->srv >= h->num_servers) 475 h->srv = 0; 476 477 if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) 478 /* Insert the request authenticator into the request */ 479 insert_request_authenticator(h, h->srv); 480 else 481 /* Insert the scrambled password into the request */ 482 if (h->pass_pos != 0) 483 insert_scrambled_password(h, h->srv); 484 485 /* Send the request */ 486 n = sendto(h->fd, h->request, h->req_len, 0, 487 (const struct sockaddr *)&h->servers[h->srv].addr, 488 sizeof h->servers[h->srv].addr); 489 if (n != h->req_len) { 490 if (n == -1) 491 generr(h, "sendto: %s", strerror(errno)); 492 else 493 generr(h, "sendto: short write"); 494 return -1; 495 } 496 497 h->try++; 498 h->servers[h->srv].num_tries++; 499 tv->tv_sec = h->servers[h->srv].timeout; 500 tv->tv_usec = 0; 501 *fd = h->fd; 502 503 return 0; 504 } 505 506 int 507 rad_create_request(struct rad_handle *h, int code) 508 { 509 int i; 510 511 h->request[POS_CODE] = code; 512 h->request[POS_IDENT] = ++h->ident; 513 /* Create a random authenticator */ 514 for (i = 0; i < LEN_AUTH; i += 2) { 515 long r; 516 r = random(); 517 h->request[POS_AUTH+i] = r; 518 h->request[POS_AUTH+i+1] = r >> 8; 519 } 520 h->req_len = POS_ATTRS; 521 clear_password(h); 522 return 0; 523 } 524 525 struct in_addr 526 rad_cvt_addr(const void *data) 527 { 528 struct in_addr value; 529 530 memcpy(&value.s_addr, data, sizeof value.s_addr); 531 return value; 532 } 533 534 u_int32_t 535 rad_cvt_int(const void *data) 536 { 537 u_int32_t value; 538 539 memcpy(&value, data, sizeof value); 540 return ntohl(value); 541 } 542 543 char * 544 rad_cvt_string(const void *data, size_t len) 545 { 546 char *s; 547 548 s = malloc(len + 1); 549 if (s != NULL) { 550 memcpy(s, data, len); 551 s[len] = '\0'; 552 } 553 return s; 554 } 555 556 /* 557 * Returns the attribute type. If none are left, returns 0. On failure, 558 * returns -1. 559 */ 560 int 561 rad_get_attr(struct rad_handle *h, const void **value, size_t *len) 562 { 563 int type; 564 565 if (h->resp_pos >= h->resp_len) 566 return 0; 567 if (h->resp_pos + 2 > h->resp_len) { 568 generr(h, "Malformed attribute in response"); 569 return -1; 570 } 571 type = h->response[h->resp_pos++]; 572 *len = h->response[h->resp_pos++] - 2; 573 if (h->resp_pos + *len > h->resp_len) { 574 generr(h, "Malformed attribute in response"); 575 return -1; 576 } 577 *value = &h->response[h->resp_pos]; 578 h->resp_pos += *len; 579 return type; 580 } 581 582 /* 583 * Returns -1 on error, 0 to indicate no event and >0 for success 584 */ 585 int 586 rad_init_send_request(struct rad_handle *h, int *fd, struct timeval *tv) 587 { 588 int srv; 589 590 /* Make sure we have a socket to use */ 591 if (h->fd == -1) { 592 struct sockaddr_in sin; 593 594 if ((h->fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { 595 generr(h, "Cannot create socket: %s", strerror(errno)); 596 return -1; 597 } 598 memset(&sin, 0, sizeof sin); 599 sin.sin_len = sizeof sin; 600 sin.sin_family = AF_INET; 601 sin.sin_addr.s_addr = INADDR_ANY; 602 sin.sin_port = htons(0); 603 if (bind(h->fd, (const struct sockaddr *)&sin, 604 sizeof sin) == -1) { 605 generr(h, "bind: %s", strerror(errno)); 606 close(h->fd); 607 h->fd = -1; 608 return -1; 609 } 610 } 611 612 if (h->request[POS_CODE] == RAD_ACCOUNTING_REQUEST) { 613 /* Make sure no password given */ 614 if (h->pass_pos || h->chap_pass) { 615 generr(h, "User or Chap Password in accounting request"); 616 return -1; 617 } 618 } else { 619 /* Make sure the user gave us a password */ 620 if (h->pass_pos == 0 && !h->chap_pass) { 621 generr(h, "No User or Chap Password attributes given"); 622 return -1; 623 } 624 if (h->pass_pos != 0 && h->chap_pass) { 625 generr(h, "Both User and Chap Password attributes given"); 626 return -1; 627 } 628 } 629 630 /* Fill in the length field in the message */ 631 h->request[POS_LENGTH] = h->req_len >> 8; 632 h->request[POS_LENGTH+1] = h->req_len; 633 634 /* 635 * Count the total number of tries we will make, and zero the 636 * counter for each server. 637 */ 638 h->total_tries = 0; 639 for (srv = 0; srv < h->num_servers; srv++) { 640 h->total_tries += h->servers[srv].max_tries; 641 h->servers[srv].num_tries = 0; 642 } 643 if (h->total_tries == 0) { 644 generr(h, "No RADIUS servers specified"); 645 return -1; 646 } 647 648 h->try = h->srv = 0; 649 650 return rad_continue_send_request(h, 0, fd, tv); 651 } 652 653 /* 654 * Create and initialize a rad_handle structure, and return it to the 655 * caller. Can fail only if the necessary memory cannot be allocated. 656 * In that case, it returns NULL. 657 */ 658 struct rad_handle * 659 rad_auth_open(void) 660 { 661 struct rad_handle *h; 662 663 h = (struct rad_handle *)malloc(sizeof(struct rad_handle)); 664 if (h != NULL) { 665 srandomdev(); 666 h->fd = -1; 667 h->num_servers = 0; 668 h->ident = random(); 669 h->errmsg[0] = '\0'; 670 memset(h->pass, 0, sizeof h->pass); 671 h->pass_len = 0; 672 h->pass_pos = 0; 673 h->chap_pass = 0; 674 h->type = RADIUS_AUTH; 675 } 676 return h; 677 } 678 679 struct rad_handle * 680 rad_acct_open(void) 681 { 682 struct rad_handle *h; 683 684 h = rad_open(); 685 if (h != NULL) 686 h->type = RADIUS_ACCT; 687 return h; 688 } 689 690 struct rad_handle * 691 rad_open(void) 692 { 693 return rad_auth_open(); 694 } 695 696 int 697 rad_put_addr(struct rad_handle *h, int type, struct in_addr addr) 698 { 699 return rad_put_attr(h, type, &addr.s_addr, sizeof addr.s_addr); 700 } 701 702 int 703 rad_put_attr(struct rad_handle *h, int type, const void *value, size_t len) 704 { 705 int result; 706 707 if (type == RAD_USER_PASSWORD) 708 result = put_password_attr(h, type, value, len); 709 else { 710 result = put_raw_attr(h, type, value, len); 711 if (result == 0 && type == RAD_CHAP_PASSWORD) 712 h->chap_pass = 1; 713 } 714 715 return result; 716 } 717 718 int 719 rad_put_int(struct rad_handle *h, int type, u_int32_t value) 720 { 721 u_int32_t nvalue; 722 723 nvalue = htonl(value); 724 return rad_put_attr(h, type, &nvalue, sizeof nvalue); 725 } 726 727 int 728 rad_put_string(struct rad_handle *h, int type, const char *str) 729 { 730 return rad_put_attr(h, type, str, strlen(str)); 731 } 732 733 /* 734 * Returns the response type code on success, or -1 on failure. 735 */ 736 int 737 rad_send_request(struct rad_handle *h) 738 { 739 struct timeval timelimit; 740 struct timeval tv; 741 int fd; 742 int n; 743 744 n = rad_init_send_request(h, &fd, &tv); 745 746 if (n != 0) 747 return n; 748 749 gettimeofday(&timelimit, NULL); 750 timeradd(&tv, &timelimit, &timelimit); 751 752 for ( ; ; ) { 753 fd_set readfds; 754 755 FD_ZERO(&readfds); 756 FD_SET(fd, &readfds); 757 758 n = select(fd + 1, &readfds, NULL, NULL, &tv); 759 760 if (n == -1) { 761 generr(h, "select: %s", strerror(errno)); 762 return -1; 763 } 764 765 if (!FD_ISSET(fd, &readfds)) { 766 /* Compute a new timeout */ 767 gettimeofday(&tv, NULL); 768 timersub(&timelimit, &tv, &tv); 769 if (tv.tv_sec > 0 || (tv.tv_sec == 0 && tv.tv_usec > 0)) 770 /* Continue the select */ 771 continue; 772 } 773 774 n = rad_continue_send_request(h, n, &fd, &tv); 775 776 if (n != 0) 777 return n; 778 779 gettimeofday(&timelimit, NULL); 780 timeradd(&tv, &timelimit, &timelimit); 781 } 782 } 783 784 const char * 785 rad_strerror(struct rad_handle *h) 786 { 787 return h->errmsg; 788 } 789 790 /* 791 * Destructively split a string into fields separated by white space. 792 * `#' at the beginning of a field begins a comment that extends to the 793 * end of the string. Fields may be quoted with `"'. Inside quoted 794 * strings, the backslash escapes `\"' and `\\' are honored. 795 * 796 * Pointers to up to the first maxfields fields are stored in the fields 797 * array. Missing fields get NULL pointers. 798 * 799 * The return value is the actual number of fields parsed, and is always 800 * <= maxfields. 801 * 802 * On a syntax error, places a message in the msg string, and returns -1. 803 */ 804 static int 805 split(char *str, char *fields[], int maxfields, char *msg, size_t msglen) 806 { 807 char *p; 808 int i; 809 static const char ws[] = " \t"; 810 811 for (i = 0; i < maxfields; i++) 812 fields[i] = NULL; 813 p = str; 814 i = 0; 815 while (*p != '\0') { 816 p += strspn(p, ws); 817 if (*p == '#' || *p == '\0') 818 break; 819 if (i >= maxfields) { 820 snprintf(msg, msglen, "line has too many fields"); 821 return -1; 822 } 823 if (*p == '"') { 824 char *dst; 825 826 dst = ++p; 827 fields[i] = dst; 828 while (*p != '"') { 829 if (*p == '\\') { 830 p++; 831 if (*p != '"' && *p != '\\' && 832 *p != '\0') { 833 snprintf(msg, msglen, 834 "invalid `\\' escape"); 835 return -1; 836 } 837 } 838 if (*p == '\0') { 839 snprintf(msg, msglen, 840 "unterminated quoted string"); 841 return -1; 842 } 843 *dst++ = *p++; 844 } 845 *dst = '\0'; 846 p++; 847 if (*fields[i] == '\0') { 848 snprintf(msg, msglen, 849 "empty quoted string not permitted"); 850 return -1; 851 } 852 if (*p != '\0' && strspn(p, ws) == 0) { 853 snprintf(msg, msglen, "quoted string not" 854 " followed by white space"); 855 return -1; 856 } 857 } else { 858 fields[i] = p; 859 p += strcspn(p, ws); 860 if (*p != '\0') 861 *p++ = '\0'; 862 } 863 i++; 864 } 865 return i; 866 } 867 868 int 869 rad_get_vendor_attr(u_int32_t *vendor, const void **data, size_t *len) 870 { 871 struct vendor_attribute *attr; 872 873 attr = (struct vendor_attribute *)*data; 874 *vendor = ntohl(attr->vendor_value); 875 *data = attr->attrib_data; 876 *len = attr->attrib_len - 2; 877 878 return (attr->attrib_type); 879 } 880 881 int 882 rad_put_vendor_addr(struct rad_handle *h, int vendor, int type, 883 struct in_addr addr) 884 { 885 return (rad_put_vendor_attr(h, vendor, type, &addr.s_addr, 886 sizeof addr.s_addr)); 887 } 888 889 int 890 rad_put_vendor_attr(struct rad_handle *h, int vendor, int type, 891 const void *value, size_t len) 892 { 893 struct vendor_attribute *attr; 894 int res; 895 896 if ((attr = malloc(len + 6)) == NULL) { 897 generr(h, "malloc failure (%d bytes)", len + 6); 898 return -1; 899 } 900 901 attr->vendor_value = htonl(vendor); 902 attr->attrib_type = type; 903 attr->attrib_len = len + 2; 904 memcpy(attr->attrib_data, value, len); 905 906 res = put_raw_attr(h, RAD_VENDOR_SPECIFIC, attr, len + 6); 907 free(attr); 908 if (res == 0 && vendor == RAD_VENDOR_MICROSOFT 909 && (type == RAD_MICROSOFT_MS_CHAP_RESPONSE 910 || type == RAD_MICROSOFT_MS_CHAP2_RESPONSE)) { 911 h->chap_pass = 1; 912 } 913 return (res); 914 } 915 916 int 917 rad_put_vendor_int(struct rad_handle *h, int vendor, int type, u_int32_t i) 918 { 919 u_int32_t value; 920 921 value = htonl(i); 922 return (rad_put_vendor_attr(h, vendor, type, &value, sizeof value)); 923 } 924 925 int 926 rad_put_vendor_string(struct rad_handle *h, int vendor, int type, 927 const char *str) 928 { 929 return (rad_put_vendor_attr(h, vendor, type, str, strlen(str))); 930 } 931 932 ssize_t 933 rad_request_authenticator(struct rad_handle *h, char *buf, size_t len) 934 { 935 if (len < LEN_AUTH) 936 return (-1); 937 memcpy(buf, h->request + POS_AUTH, LEN_AUTH); 938 if (len > LEN_AUTH) 939 buf[LEN_AUTH] = '\0'; 940 return (LEN_AUTH); 941 } 942 943 const char * 944 rad_server_secret(struct rad_handle *h) 945 { 946 return (h->servers[h->srv].secret); 947 } 948