1 /* 2 * $Id: avpair.c,v 1.1 2004/11/14 07:26:26 paulus Exp $ 3 * 4 * Copyright (C) 1995 Lars Fenneberg 5 * 6 * Copyright 1992 Livingston Enterprises, Inc. 7 * 8 * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan 9 * and Merit Network, Inc. All Rights Reserved 10 * 11 * See the file COPYRIGHT for the respective terms and conditions. 12 * If the file is missing contact me at lf (at) elemental.net 13 * and I'll send you a copy. 14 * 15 */ 16 17 #include <includes.h> 18 #include <radiusclient.h> 19 20 static void rc_extract_vendor_specific_attributes(int attrlen, 21 unsigned char *ptr, 22 VALUE_PAIR **vp); 23 /* 24 * Function: rc_avpair_add 25 * 26 * Purpose: add an attribute-value pair to the given list. 27 * 28 * Returns: pointer to added a/v pair upon success, NULL pointer upon failure. 29 * 30 * Remarks: Always appends the new pair to the end of the list. 31 * 32 */ 33 34 VALUE_PAIR *rc_avpair_add (VALUE_PAIR **list, int attrid, void *pval, int len, 35 int vendorcode) 36 { 37 VALUE_PAIR *vp; 38 39 vp = rc_avpair_new (attrid, pval, len, vendorcode); 40 41 if (vp != (VALUE_PAIR *) NULL) 42 { 43 rc_avpair_insert (list, (VALUE_PAIR *) NULL, vp); 44 } 45 46 return vp; 47 48 } 49 50 /* 51 * Function: rc_avpair_assign 52 * 53 * Purpose: assign the given value to an attribute-value pair. 54 * 55 * Returns: 0 on success, 56 * -1 on failure. 57 * 58 */ 59 60 int rc_avpair_assign (VALUE_PAIR *vp, void *pval, int len) 61 { 62 int result = -1; 63 64 switch (vp->type) 65 { 66 case PW_TYPE_STRING: 67 68 if (((len == 0) && (strlen ((char *) pval)) > AUTH_STRING_LEN) 69 || (len > AUTH_STRING_LEN)) { 70 error("rc_avpair_assign: bad attribute length"); 71 return result; 72 } 73 74 if (len > 0) { 75 memcpy(vp->strvalue, (char *)pval, len); 76 vp->strvalue[len] = '\0'; 77 vp->lvalue = len; 78 } else { 79 strncpy (vp->strvalue, (char *) pval, AUTH_STRING_LEN); 80 vp->lvalue = strlen((char *) pval); 81 } 82 83 result = 0; 84 break; 85 86 case PW_TYPE_DATE: 87 case PW_TYPE_INTEGER: 88 case PW_TYPE_IPADDR: 89 90 vp->lvalue = * (UINT4 *) pval; 91 92 result = 0; 93 break; 94 95 default: 96 error("rc_avpair_assign: unknown attribute %d", vp->type); 97 } 98 return result; 99 } 100 101 /* 102 * Function: rc_avpair_new 103 * 104 * Purpose: make a new attribute-value pair with given parameters. 105 * 106 * Returns: pointer to generated a/v pair when successful, NULL when failure. 107 * 108 */ 109 110 VALUE_PAIR *rc_avpair_new (int attrid, void *pval, int len, int vendorcode) 111 { 112 VALUE_PAIR *vp = (VALUE_PAIR *) NULL; 113 DICT_ATTR *pda; 114 115 if ((pda = rc_dict_getattr (attrid, vendorcode)) == (DICT_ATTR *) NULL) 116 { 117 error("rc_avpair_new: unknown attribute %d", attrid); 118 } 119 else 120 { 121 if ((vp = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) 122 != (VALUE_PAIR *) NULL) 123 { 124 strncpy (vp->name, pda->name, sizeof (vp->name)); 125 vp->attribute = attrid; 126 vp->vendorcode = vendorcode; 127 vp->next = (VALUE_PAIR *) NULL; 128 vp->type = pda->type; 129 if (rc_avpair_assign (vp, pval, len) == 0) 130 { 131 return vp; 132 } 133 free (vp); 134 vp = (VALUE_PAIR *) NULL; 135 } 136 else 137 novm("rc_avpair_new"); 138 } 139 return vp; 140 } 141 142 /* 143 * 144 * Function: rc_avpair_gen 145 * 146 * Purpose: takes attribute/value pairs from buffer and builds a 147 * value_pair list using allocated memory. 148 * 149 * Returns: value_pair list or NULL on failure 150 */ 151 152 VALUE_PAIR *rc_avpair_gen (AUTH_HDR *auth) 153 { 154 int length; 155 int x_len; 156 int attribute; 157 int attrlen; 158 UINT4 lvalue; 159 unsigned char *x_ptr; 160 unsigned char *ptr; 161 DICT_ATTR *attr; 162 VALUE_PAIR *vp; 163 VALUE_PAIR *pair; 164 unsigned char hex[3]; /* For hex string conversion. */ 165 char buffer[512]; 166 167 /* 168 * Extract attribute-value pairs 169 */ 170 ptr = auth->data; 171 length = ntohs ((unsigned short) auth->length) - AUTH_HDR_LEN; 172 vp = (VALUE_PAIR *) NULL; 173 174 while (length > 0) 175 { 176 attribute = *ptr++; 177 attrlen = *ptr++; 178 attrlen -= 2; 179 if (attrlen < 0) 180 { 181 error("rc_avpair_gen: received attribute with invalid length"); 182 break; 183 } 184 185 /* Handle vendor-specific specially */ 186 if (attribute == PW_VENDOR_SPECIFIC) { 187 rc_extract_vendor_specific_attributes(attrlen, ptr, &vp); 188 ptr += attrlen; 189 length -= (attrlen + 2); 190 continue; 191 } 192 if ((attr = rc_dict_getattr (attribute, VENDOR_NONE)) == (DICT_ATTR *) NULL) 193 { 194 *buffer= '\0'; /* Initial length. */ 195 for (x_ptr = ptr, x_len = attrlen ; 196 x_len > 0 ; 197 x_len--, x_ptr++) 198 { 199 sprintf (hex, "%2.2X", *x_ptr); 200 strcat (buffer, hex); 201 } 202 warn("rc_avpair_gen: received unknown attribute %d of length %d: 0x%s", 203 attribute, attrlen, buffer); 204 } 205 else 206 { 207 if ((pair = 208 (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) == 209 (VALUE_PAIR *) NULL) 210 { 211 novm("rc_avpair_gen"); 212 rc_avpair_free(vp); 213 return NULL; 214 } 215 strcpy (pair->name, attr->name); 216 pair->attribute = attr->value; 217 pair->vendorcode = VENDOR_NONE; 218 pair->type = attr->type; 219 pair->next = (VALUE_PAIR *) NULL; 220 221 switch (attr->type) 222 { 223 224 case PW_TYPE_STRING: 225 memcpy (pair->strvalue, (char *) ptr, (size_t) attrlen); 226 pair->strvalue[attrlen] = '\0'; 227 pair->lvalue = attrlen; 228 rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair); 229 break; 230 231 case PW_TYPE_INTEGER: 232 case PW_TYPE_IPADDR: 233 memcpy ((char *) &lvalue, (char *) ptr, 234 sizeof (UINT4)); 235 pair->lvalue = ntohl (lvalue); 236 rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair); 237 break; 238 239 default: 240 warn("rc_avpair_gen: %s has unknown type", attr->name); 241 free (pair); 242 break; 243 } 244 245 } 246 ptr += attrlen; 247 length -= attrlen + 2; 248 } 249 return (vp); 250 } 251 252 /* 253 * Function: rc_extract_vendor_specific_attributes 254 * 255 * Purpose: Extracts vendor-specific attributes, assuming they are in 256 * the "SHOULD" format recommended by RCF 2138. 257 * 258 * Returns: found value_pair 259 * 260 */ 261 static void rc_extract_vendor_specific_attributes(int attrlen, 262 unsigned char *ptr, 263 VALUE_PAIR **vp) 264 { 265 int vendor_id; 266 int vtype; 267 int vlen; 268 UINT4 lvalue; 269 DICT_ATTR *attr; 270 VALUE_PAIR *pair; 271 272 /* ptr is sitting at vendor-ID */ 273 if (attrlen < 8) { 274 /* Nothing to see here... */ 275 return; 276 } 277 278 /* High-order octet of Vendor-Id must be zero (RFC2138) */ 279 if (*ptr) { 280 return; 281 } 282 283 /* Extract vendor_id */ 284 vendor_id = (int) ( 285 ((unsigned int) ptr[1]) * 256 * 256 + 286 ((unsigned int) ptr[2]) * 256 + 287 ((unsigned int) ptr[3])); 288 /* Bump ptr up to contents */ 289 ptr += 4; 290 291 /* Set attrlen to length of data */ 292 attrlen -= 4; 293 for (; attrlen; attrlen -= vlen+2, ptr += vlen) { 294 vtype = *ptr++; 295 vlen = *ptr++; 296 vlen -= 2; 297 if (vlen < 0 || vlen > attrlen - 2) { 298 /* Do not log an error. We are supposed to be able to cope with 299 arbitrary vendor-specific gunk */ 300 return; 301 } 302 /* Looks plausible... */ 303 if ((attr = rc_dict_getattr(vtype, vendor_id)) == NULL) { 304 continue; 305 } 306 307 /* TODO: Check that length matches data size!!!!! */ 308 pair = (VALUE_PAIR *) malloc(sizeof(VALUE_PAIR)); 309 if (!pair) { 310 novm("rc_avpair_gen"); 311 return; 312 } 313 strcpy(pair->name, attr->name); 314 pair->attribute = attr->value; 315 pair->vendorcode = vendor_id; 316 pair->type = attr->type; 317 pair->next = NULL; 318 switch (attr->type) { 319 case PW_TYPE_STRING: 320 memcpy (pair->strvalue, (char *) ptr, (size_t) vlen); 321 pair->strvalue[vlen] = '\0'; 322 pair->lvalue = vlen; 323 rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair); 324 break; 325 326 case PW_TYPE_INTEGER: 327 case PW_TYPE_IPADDR: 328 memcpy ((char *) &lvalue, (char *) ptr, 329 sizeof (UINT4)); 330 pair->lvalue = ntohl (lvalue); 331 rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair); 332 break; 333 334 default: 335 warn("rc_avpair_gen: %s has unknown type", attr->name); 336 free (pair); 337 break; 338 } 339 } 340 } 341 342 /* 343 * Function: rc_avpair_get 344 * 345 * Purpose: Find the first attribute value-pair (which matches the given 346 * attribute) from the specified value-pair list. 347 * 348 * Returns: found value_pair 349 * 350 */ 351 352 VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, UINT4 attr) 353 { 354 for (; vp != (VALUE_PAIR *) NULL && vp->attribute != attr; vp = vp->next) 355 { 356 continue; 357 } 358 return (vp); 359 } 360 361 /* 362 * Function: rc_avpair_copy 363 * 364 * Purpose: Return a copy of the existing list "p" ala strdup(). 365 * 366 */ 367 VALUE_PAIR *rc_avpair_copy(VALUE_PAIR *p) 368 { 369 VALUE_PAIR *vp, *fp = NULL, *lp = NULL; 370 371 while (p) { 372 vp = malloc(sizeof(VALUE_PAIR)); 373 if (!vp) { 374 novm("rc_avpair_copy"); 375 return NULL; /* leaks a little but so what */ 376 } 377 *vp = *p; 378 if (!fp) 379 fp = vp; 380 if (lp) 381 lp->next = vp; 382 lp = vp; 383 p = p->next; 384 } 385 386 return fp; 387 } 388 389 /* 390 * Function: rc_avpair_insert 391 * 392 * Purpose: Given the address of an existing list "a" and a pointer 393 * to an entry "p" in that list, add the list "b" to 394 * the "a" list after the "p" entry. If "p" is NULL, add 395 * the list "b" to the end of "a". 396 * 397 */ 398 399 void rc_avpair_insert (VALUE_PAIR **a, VALUE_PAIR *p, VALUE_PAIR *b) 400 { 401 VALUE_PAIR *this_node = NULL; 402 VALUE_PAIR *vp; 403 404 if (*a == (VALUE_PAIR *) NULL) 405 { 406 *a = b; 407 return; 408 } 409 410 if (!b) 411 return; 412 413 vp = *a; 414 415 if ( p == (VALUE_PAIR *) NULL) /* run to end of "a" list */ 416 { 417 while (vp != (VALUE_PAIR *) NULL) 418 { 419 this_node = vp; 420 vp = vp->next; 421 } 422 } 423 else /* look for the "p" entry in the "a" list (or run to end) */ 424 { 425 this_node = *a; 426 while (this_node != (VALUE_PAIR *) NULL) 427 { 428 if (this_node == p) 429 { 430 break; 431 } 432 this_node = this_node->next; 433 } 434 } 435 436 /* add "b" at this_node */ 437 vp = this_node->next; 438 this_node->next = b; 439 440 /* run to end of "b" and connect the rest of "a" */ 441 while (b->next) 442 b = b->next; 443 b->next = vp; 444 445 return; 446 } 447 448 /* 449 * Function: rc_avpair_free 450 * 451 * Purpose: frees all value_pairs in the list 452 * 453 */ 454 455 void rc_avpair_free (VALUE_PAIR *pair) 456 { 457 VALUE_PAIR *next; 458 459 while (pair != (VALUE_PAIR *) NULL) 460 { 461 next = pair->next; 462 free (pair); 463 pair = next; 464 } 465 } 466 467 /* 468 * Function: rc_fieldcpy 469 * 470 * Purpose: Copy a data field from the buffer. Advance the buffer 471 * past the data field. 472 * 473 */ 474 475 static void rc_fieldcpy (char *string, char **uptr) 476 { 477 char *ptr; 478 479 ptr = *uptr; 480 if (*ptr == '"') 481 { 482 ptr++; 483 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') 484 { 485 *string++ = *ptr++; 486 } 487 *string = '\0'; 488 if (*ptr == '"') 489 { 490 ptr++; 491 } 492 *uptr = ptr; 493 return; 494 } 495 496 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' && 497 *ptr != '=' && *ptr != ',') 498 { 499 *string++ = *ptr++; 500 } 501 *string = '\0'; 502 *uptr = ptr; 503 return; 504 } 505 506 507 /* 508 * Function: rc_avpair_parse 509 * 510 * Purpose: parses the buffer to extract the attribute-value pairs. 511 * 512 * Returns: 0 = successful parse of attribute-value pair, 513 * -1 = syntax (or other) error detected. 514 * 515 */ 516 517 #define PARSE_MODE_NAME 0 518 #define PARSE_MODE_EQUAL 1 519 #define PARSE_MODE_VALUE 2 520 #define PARSE_MODE_INVALID 3 521 522 int rc_avpair_parse (char *buffer, VALUE_PAIR **first_pair) 523 { 524 int mode; 525 char attrstr[AUTH_ID_LEN]; 526 char valstr[AUTH_ID_LEN]; 527 DICT_ATTR *attr = NULL; 528 DICT_VALUE *dval; 529 VALUE_PAIR *pair; 530 VALUE_PAIR *link; 531 struct tm *tm; 532 time_t timeval; 533 534 mode = PARSE_MODE_NAME; 535 while (*buffer != '\n' && *buffer != '\0') 536 { 537 if (*buffer == ' ' || *buffer == '\t') 538 { 539 buffer++; 540 continue; 541 } 542 543 switch (mode) 544 { 545 case PARSE_MODE_NAME: /* Attribute Name */ 546 rc_fieldcpy (attrstr, &buffer); 547 if ((attr = 548 rc_dict_findattr (attrstr)) == (DICT_ATTR *) NULL) 549 { 550 error("rc_avpair_parse: unknown attribute"); 551 if (*first_pair) { 552 rc_avpair_free(*first_pair); 553 *first_pair = (VALUE_PAIR *) NULL; 554 } 555 return (-1); 556 } 557 mode = PARSE_MODE_EQUAL; 558 break; 559 560 case PARSE_MODE_EQUAL: /* Equal sign */ 561 if (*buffer == '=') 562 { 563 mode = PARSE_MODE_VALUE; 564 buffer++; 565 } 566 else 567 { 568 error("rc_avpair_parse: missing or misplaced equal sign"); 569 if (*first_pair) { 570 rc_avpair_free(*first_pair); 571 *first_pair = (VALUE_PAIR *) NULL; 572 } 573 return (-1); 574 } 575 break; 576 577 case PARSE_MODE_VALUE: /* Value */ 578 rc_fieldcpy (valstr, &buffer); 579 580 if ((pair = 581 (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) 582 == (VALUE_PAIR *) NULL) 583 { 584 novm("rc_avpair_parse"); 585 if (*first_pair) { 586 rc_avpair_free(*first_pair); 587 *first_pair = (VALUE_PAIR *) NULL; 588 } 589 return (-1); 590 } 591 strcpy (pair->name, attr->name); 592 pair->attribute = attr->value; 593 pair->type = attr->type; 594 pair->vendorcode = attr->vendorcode; 595 596 switch (pair->type) 597 { 598 599 case PW_TYPE_STRING: 600 strcpy (pair->strvalue, valstr); 601 pair->lvalue = strlen(valstr); 602 break; 603 604 case PW_TYPE_INTEGER: 605 if (isdigit (*valstr)) 606 { 607 pair->lvalue = atoi (valstr); 608 } 609 else 610 { 611 if ((dval = rc_dict_findval (valstr)) 612 == (DICT_VALUE *) NULL) 613 { 614 error("rc_avpair_parse: unknown attribute value: %s", valstr); 615 if (*first_pair) { 616 rc_avpair_free(*first_pair); 617 *first_pair = (VALUE_PAIR *) NULL; 618 } 619 free (pair); 620 return (-1); 621 } 622 else 623 { 624 pair->lvalue = dval->value; 625 } 626 } 627 break; 628 629 case PW_TYPE_IPADDR: 630 pair->lvalue = rc_get_ipaddr(valstr); 631 break; 632 633 case PW_TYPE_DATE: 634 timeval = time (0); 635 tm = localtime (&timeval); 636 tm->tm_hour = 0; 637 tm->tm_min = 0; 638 tm->tm_sec = 0; 639 rc_str2tm (valstr, tm); 640 #ifdef TIMELOCAL 641 pair->lvalue = (UINT4) timelocal (tm); 642 #else /* TIMELOCAL */ 643 pair->lvalue = (UINT4) mktime (tm); 644 #endif /* TIMELOCAL */ 645 break; 646 647 default: 648 error("rc_avpair_parse: unknown attribute type %d", pair->type); 649 if (*first_pair) { 650 rc_avpair_free(*first_pair); 651 *first_pair = (VALUE_PAIR *) NULL; 652 } 653 free (pair); 654 return (-1); 655 } 656 pair->next = (VALUE_PAIR *) NULL; 657 658 if (*first_pair == (VALUE_PAIR *) NULL) 659 { 660 *first_pair = pair; 661 } 662 else 663 { 664 link = *first_pair; 665 while (link->next != (VALUE_PAIR *) NULL) 666 { 667 link = link->next; 668 } 669 link->next = pair; 670 } 671 672 mode = PARSE_MODE_NAME; 673 break; 674 675 default: 676 mode = PARSE_MODE_NAME; 677 break; 678 } 679 } 680 return (0); 681 } 682 683 /* 684 * Function: rc_avpair_tostr 685 * 686 * Purpose: Translate an av_pair into two strings 687 * 688 * Returns: 0 on success, -1 on failure 689 * 690 */ 691 692 int rc_avpair_tostr (VALUE_PAIR *pair, char *name, int ln, char *value, int lv) 693 { 694 DICT_VALUE *dval; 695 char buffer[32]; 696 struct in_addr inad; 697 unsigned char *ptr; 698 699 *name = *value = '\0'; 700 701 if (!pair || pair->name[0] == '\0') { 702 error("rc_avpair_tostr: pair is NULL or empty"); 703 return (-1); 704 } 705 706 strncpy(name, pair->name, (size_t) ln); 707 708 switch (pair->type) 709 { 710 case PW_TYPE_STRING: 711 lv--; 712 ptr = (unsigned char *) pair->strvalue; 713 while (*ptr != '\0') 714 { 715 if (!(isprint (*ptr))) 716 { 717 sprintf (buffer, "\\%03o", *ptr); 718 strncat(value, buffer, (size_t) lv); 719 lv -= 4; 720 if (lv < 0) break; 721 } 722 else 723 { 724 strncat(value, ptr, 1); 725 lv--; 726 if (lv < 0) break; 727 } 728 ptr++; 729 } 730 break; 731 732 case PW_TYPE_INTEGER: 733 dval = rc_dict_getval (pair->lvalue, pair->name); 734 if (dval != (DICT_VALUE *) NULL) 735 { 736 strncpy(value, dval->name, (size_t) lv-1); 737 } 738 else 739 { 740 sprintf (buffer, "%ld", pair->lvalue); 741 strncpy(value, buffer, (size_t) lv); 742 } 743 break; 744 745 case PW_TYPE_IPADDR: 746 inad.s_addr = htonl(pair->lvalue); 747 strncpy (value, inet_ntoa (inad), (size_t) lv-1); 748 break; 749 750 case PW_TYPE_DATE: 751 strftime (buffer, sizeof (buffer), "%m/%d/%y %H:%M:%S", 752 gmtime ((time_t *) & pair->lvalue)); 753 strncpy(value, buffer, lv-1); 754 break; 755 756 default: 757 error("rc_avpair_tostr: unknown attribute type %d", pair->type); 758 return (-1); 759 break; 760 } 761 762 return 0; 763 } 764 765 /* 766 * Function: rc_avpair_readin 767 * 768 * Purpose: get a sequence of attribute value pairs from the file input 769 * and make them into a list of value_pairs 770 * 771 */ 772 773 VALUE_PAIR *rc_avpair_readin(FILE *input) 774 { 775 VALUE_PAIR *vp = NULL; 776 char buffer[1024], *q; 777 778 while (fgets(buffer, sizeof(buffer), input) != NULL) 779 { 780 q = buffer; 781 782 while(*q && isspace(*q)) q++; 783 784 if ((*q == '\n') || (*q == '#') || (*q == '\0')) 785 continue; 786 787 if (rc_avpair_parse(q, &vp) < 0) { 788 error("rc_avpair_readin: malformed attribute: %s", buffer); 789 rc_avpair_free(vp); 790 return NULL; 791 } 792 } 793 794 return vp; 795 } 796