2 * $Id: avpair.c,v 1.1 2004/11/14 07:26:26 paulus Exp $
4 * Copyright (C) 1995 Lars Fenneberg
6 * Copyright 1992 Livingston Enterprises, Inc.
8 * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
9 * and Merit Network, Inc. All Rights Reserved
11 * See the file COPYRIGHT for the respective terms and conditions.
12 * If the file is missing contact me at lf@elemental.net
13 * and I'll send you a copy.
18 #include <radiusclient.h>
20 static void rc_extract_vendor_specific_attributes(int attrlen,
24 * Function: rc_avpair_add
26 * Purpose: add an attribute-value pair to the given list.
28 * Returns: pointer to added a/v pair upon success, NULL pointer upon failure.
30 * Remarks: Always appends the new pair to the end of the list.
34 VALUE_PAIR *rc_avpair_add (VALUE_PAIR **list, int attrid, void *pval, int len,
39 vp = rc_avpair_new (attrid, pval, len, vendorcode);
41 if (vp != (VALUE_PAIR *) NULL)
43 rc_avpair_insert (list, (VALUE_PAIR *) NULL, vp);
51 * Function: rc_avpair_assign
53 * Purpose: assign the given value to an attribute-value pair.
55 * Returns: 0 on success,
60 int rc_avpair_assign (VALUE_PAIR *vp, void *pval, int len)
68 if (((len == 0) && (strlen ((char *) pval)) > AUTH_STRING_LEN)
69 || (len > AUTH_STRING_LEN)) {
70 error("rc_avpair_assign: bad attribute length");
75 memcpy(vp->strvalue, (char *)pval, len);
76 vp->strvalue[len] = '\0';
79 strncpy ((char*) vp->strvalue, (char *) pval, AUTH_STRING_LEN);
80 vp->lvalue = strlen((char *) pval);
90 vp->lvalue = * (UINT4 *) pval;
96 error("rc_avpair_assign: unknown attribute %d", vp->type);
102 * Function: rc_avpair_new
104 * Purpose: make a new attribute-value pair with given parameters.
106 * Returns: pointer to generated a/v pair when successful, NULL when failure.
110 VALUE_PAIR *rc_avpair_new (int attrid, void *pval, int len, int vendorcode)
112 VALUE_PAIR *vp = (VALUE_PAIR *) NULL;
115 if ((pda = rc_dict_getattr (attrid, vendorcode)) == (DICT_ATTR *) NULL)
117 error("rc_avpair_new: unknown attribute %d", attrid);
121 if ((vp = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR)))
122 != (VALUE_PAIR *) NULL)
124 strlcpy (vp->name, pda->name, NAME_LENGTH);
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)
134 vp = (VALUE_PAIR *) NULL;
137 novm("rc_avpair_new");
144 * Function: rc_avpair_gen
146 * Purpose: takes attribute/value pairs from buffer and builds a
147 * value_pair list using allocated memory.
149 * Returns: value_pair list or NULL on failure
152 VALUE_PAIR *rc_avpair_gen (AUTH_HDR *auth)
159 unsigned char *x_ptr;
164 char hex[3]; /* For hex string conversion. */
168 * Extract attribute-value pairs
171 length = ntohs ((unsigned short) auth->length) - AUTH_HDR_LEN;
172 vp = (VALUE_PAIR *) NULL;
178 if (attrlen < 2 || attrlen > length)
180 error("rc_avpair_gen: received attribute with invalid length");
185 /* Handle vendor-specific specially */
186 if (attribute == PW_VENDOR_SPECIFIC) {
187 rc_extract_vendor_specific_attributes(attrlen, ptr, &vp);
189 length -= (attrlen + 2);
192 if ((attr = rc_dict_getattr (attribute, VENDOR_NONE)) == (DICT_ATTR *) NULL)
194 *buffer= '\0'; /* Initial length. */
195 for (x_ptr = ptr, x_len = attrlen ;
199 sprintf (hex, "%2.2X", *x_ptr);
200 strcat (buffer, hex);
202 warn("rc_avpair_gen: received unknown attribute %d of length %d: 0x%s",
203 attribute, attrlen, buffer);
208 (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) ==
211 novm("rc_avpair_gen");
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;
226 case PW_TYPE_IPV6ADDR:
227 case PW_TYPE_IPV6PREFIX:
228 memcpy (pair->strvalue, (char *) ptr, (size_t) attrlen);
229 pair->strvalue[attrlen] = '\0';
230 pair->lvalue = attrlen;
231 rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair);
234 case PW_TYPE_INTEGER:
236 memcpy ((char *) &lvalue, (char *) ptr,
238 pair->lvalue = ntohl (lvalue);
239 rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair);
243 warn("rc_avpair_gen: %s has unknown type", attr->name);
250 length -= attrlen + 2;
256 * Function: rc_extract_vendor_specific_attributes
258 * Purpose: Extracts vendor-specific attributes, assuming they are in
259 * the "SHOULD" format recommended by RCF 2138.
261 * Returns: found value_pair
264 static void rc_extract_vendor_specific_attributes(int attrlen,
275 /* ptr is sitting at vendor-ID */
277 /* Nothing to see here... */
281 /* High-order octet of Vendor-Id must be zero (RFC2138) */
286 /* Extract vendor_id */
288 ((unsigned int) ptr[1]) * 256 * 256 +
289 ((unsigned int) ptr[2]) * 256 +
290 ((unsigned int) ptr[3]));
291 /* Bump ptr up to contents */
294 /* Set attrlen to length of data */
296 for (; attrlen; attrlen -= vlen+2, ptr += vlen) {
300 if (vlen < 0 || vlen > attrlen - 2) {
301 /* Do not log an error. We are supposed to be able to cope with
302 arbitrary vendor-specific gunk */
305 /* Looks plausible... */
306 if ((attr = rc_dict_getattr(vtype, vendor_id)) == NULL) {
310 /* TODO: Check that length matches data size!!!!! */
311 pair = (VALUE_PAIR *) malloc(sizeof(VALUE_PAIR));
313 novm("rc_avpair_gen");
316 strcpy(pair->name, attr->name);
317 pair->attribute = attr->value;
318 pair->vendorcode = vendor_id;
319 pair->type = attr->type;
321 switch (attr->type) {
323 memcpy (pair->strvalue, (char *) ptr, (size_t) vlen);
324 pair->strvalue[vlen] = '\0';
326 rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair);
329 case PW_TYPE_INTEGER:
331 memcpy ((char *) &lvalue, (char *) ptr,
333 pair->lvalue = ntohl (lvalue);
334 rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair);
338 warn("rc_avpair_gen: %s has unknown type", attr->name);
346 * Function: rc_avpair_get
348 * Purpose: Find the first attribute value-pair (which matches the given
349 * attribute) from the specified value-pair list.
351 * Returns: found value_pair
355 VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, UINT4 attr)
357 for (; vp != (VALUE_PAIR *) NULL && vp->attribute != attr; vp = vp->next)
365 * Function: rc_avpair_copy
367 * Purpose: Return a copy of the existing list "p" ala strdup().
370 VALUE_PAIR *rc_avpair_copy(VALUE_PAIR *p)
372 VALUE_PAIR *vp, *fp = NULL, *lp = NULL;
375 vp = malloc(sizeof(VALUE_PAIR));
377 novm("rc_avpair_copy");
378 return NULL; /* leaks a little but so what */
393 * Function: rc_avpair_insert
395 * Purpose: Given the address of an existing list "a" and a pointer
396 * to an entry "p" in that list, add the list "b" to
397 * the "a" list after the "p" entry. If "p" is NULL, add
398 * the list "b" to the end of "a".
402 void rc_avpair_insert (VALUE_PAIR **a, VALUE_PAIR *p, VALUE_PAIR *b)
404 VALUE_PAIR *this_node = NULL;
407 if (*a == (VALUE_PAIR *) NULL)
418 if ( p == (VALUE_PAIR *) NULL) /* run to end of "a" list */
420 while (vp != (VALUE_PAIR *) NULL)
426 else /* look for the "p" entry in the "a" list (or run to end) */
429 while (this_node != (VALUE_PAIR *) NULL)
435 this_node = this_node->next;
439 /* add "b" at this_node */
440 vp = this_node->next;
443 /* run to end of "b" and connect the rest of "a" */
452 * Function: rc_avpair_free
454 * Purpose: frees all value_pairs in the list
458 void rc_avpair_free (VALUE_PAIR *pair)
462 while (pair != (VALUE_PAIR *) NULL)
471 * Function: rc_fieldcpy
473 * Purpose: Copy a data field from the buffer. Advance the buffer
474 * past the data field.
478 static void rc_fieldcpy (char *string, char **uptr)
486 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n')
499 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
500 *ptr != '=' && *ptr != ',')
511 * Function: rc_avpair_parse
513 * Purpose: parses the buffer to extract the attribute-value pairs.
515 * Returns: 0 = successful parse of attribute-value pair,
516 * -1 = syntax (or other) error detected.
520 #define PARSE_MODE_NAME 0
521 #define PARSE_MODE_EQUAL 1
522 #define PARSE_MODE_VALUE 2
523 #define PARSE_MODE_INVALID 3
525 int rc_avpair_parse (char *buffer, VALUE_PAIR **first_pair)
528 char attrstr[AUTH_ID_LEN];
529 char valstr[AUTH_ID_LEN];
530 DICT_ATTR *attr = NULL;
537 mode = PARSE_MODE_NAME;
538 while (*buffer != '\n' && *buffer != '\0')
540 if (*buffer == ' ' || *buffer == '\t')
548 case PARSE_MODE_NAME: /* Attribute Name */
549 rc_fieldcpy (attrstr, &buffer);
551 rc_dict_findattr (attrstr)) == (DICT_ATTR *) NULL)
553 error("rc_avpair_parse: unknown attribute");
555 rc_avpair_free(*first_pair);
556 *first_pair = (VALUE_PAIR *) NULL;
560 mode = PARSE_MODE_EQUAL;
563 case PARSE_MODE_EQUAL: /* Equal sign */
566 mode = PARSE_MODE_VALUE;
571 error("rc_avpair_parse: missing or misplaced equal sign");
573 rc_avpair_free(*first_pair);
574 *first_pair = (VALUE_PAIR *) NULL;
580 case PARSE_MODE_VALUE: /* Value */
581 rc_fieldcpy (valstr, &buffer);
584 (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR)))
585 == (VALUE_PAIR *) NULL)
587 novm("rc_avpair_parse");
589 rc_avpair_free(*first_pair);
590 *first_pair = (VALUE_PAIR *) NULL;
594 strcpy (pair->name, attr->name);
595 pair->attribute = attr->value;
596 pair->type = attr->type;
597 pair->vendorcode = attr->vendorcode;
603 strcpy ((char*) pair->strvalue, valstr);
604 pair->lvalue = strlen(valstr);
607 case PW_TYPE_INTEGER:
608 if (isdigit (*valstr))
610 pair->lvalue = atoi (valstr);
614 if ((dval = rc_dict_findval (valstr))
615 == (DICT_VALUE *) NULL)
617 error("rc_avpair_parse: unknown attribute value: %s", valstr);
619 rc_avpair_free(*first_pair);
620 *first_pair = (VALUE_PAIR *) NULL;
627 pair->lvalue = dval->value;
633 pair->lvalue = rc_get_ipaddr(valstr);
638 tm = localtime (&timeval);
642 rc_str2tm (valstr, tm);
644 pair->lvalue = (UINT4) timelocal (tm);
645 #else /* TIMELOCAL */
646 pair->lvalue = (UINT4) mktime (tm);
647 #endif /* TIMELOCAL */
651 error("rc_avpair_parse: unknown attribute type %d", pair->type);
653 rc_avpair_free(*first_pair);
654 *first_pair = (VALUE_PAIR *) NULL;
659 pair->next = (VALUE_PAIR *) NULL;
661 if (*first_pair == (VALUE_PAIR *) NULL)
668 while (link->next != (VALUE_PAIR *) NULL)
675 mode = PARSE_MODE_NAME;
679 mode = PARSE_MODE_NAME;
687 * Function: rc_avpair_tostr
689 * Purpose: Translate an av_pair into two strings
691 * Returns: 0 on success, -1 on failure
695 int rc_avpair_tostr (VALUE_PAIR *pair, char *name, int ln, char *value, int lv)
698 char buffer[INET6_ADDRSTRLEN + 4]; // for a prefix: addr + '/' + prefixlen
703 *name = *value = '\0';
705 if (!pair || pair->name[0] == '\0') {
706 error("rc_avpair_tostr: pair is NULL or empty");
710 strncpy(name, pair->name, (size_t) ln);
716 ptr = (unsigned char *) pair->strvalue;
719 if (!(isprint (*ptr)))
721 sprintf (buffer, "\\%03o", *ptr);
722 strncat(value, buffer, (size_t) lv);
728 strncat(value, (char*) ptr, 1);
736 case PW_TYPE_INTEGER:
737 dval = rc_dict_getval (pair->lvalue, pair->name);
738 if (dval != (DICT_VALUE *) NULL)
740 strncpy(value, dval->name, (size_t) lv-1);
744 sprintf (buffer, "%d", pair->lvalue);
745 strncpy(value, buffer, (size_t) lv);
750 inad.s_addr = htonl(pair->lvalue);
751 strncpy (value, inet_ntoa (inad), (size_t) lv-1);
755 strftime (buffer, sizeof (buffer), "%m/%d/%y %H:%M:%S",
756 gmtime ((time_t *) & pair->lvalue));
757 strncpy(value, buffer, lv-1);
761 ptr = pair->strvalue;
762 snprintf(buffer, sizeof (buffer), "%x:%x:%x:%x",
763 (ptr[0] << 8) + ptr[1], (ptr[2] << 8) + ptr[3],
764 (ptr[4] << 8) + ptr[5], (ptr[6] << 8) + ptr[7]);
765 strncpy(value, buffer, lv-1);
768 case PW_TYPE_IPV6ADDR:
769 inet_ntop(AF_INET6, pair->strvalue, buffer, sizeof (buffer));
770 strncpy(value, buffer, lv-1);
773 case PW_TYPE_IPV6PREFIX:
774 inet_ntop(AF_INET6, pair->strvalue + 2, buffer, sizeof (buffer));
775 str = buffer + strlen(buffer);
776 snprintf(str, sizeof (buffer) - (str - buffer), "/%d", *(pair->strvalue + 1));
777 strncpy(value, buffer, lv-1);
781 error("rc_avpair_tostr: unknown attribute type %d", pair->type);
790 * Function: rc_avpair_readin
792 * Purpose: get a sequence of attribute value pairs from the file input
793 * and make them into a list of value_pairs
797 VALUE_PAIR *rc_avpair_readin(FILE *input)
799 VALUE_PAIR *vp = NULL;
800 char buffer[1024], *q;
802 while (fgets(buffer, sizeof(buffer), input) != NULL)
806 while(*q && isspace(*q)) q++;
808 if ((*q == '\n') || (*q == '#') || (*q == '\0'))
811 if (rc_avpair_parse(q, &vp) < 0) {
812 error("rc_avpair_readin: malformed attribute: %s", buffer);