| /* |
| * $Id: avpair.c,v 1.1 2004/11/14 07:26:26 paulus Exp $ |
| * |
| * Copyright (C) 1995 Lars Fenneberg |
| * |
| * Copyright 1992 Livingston Enterprises, Inc. |
| * |
| * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan |
| * and Merit Network, Inc. All Rights Reserved |
| * |
| * See the file COPYRIGHT for the respective terms and conditions. |
| * If the file is missing contact me at lf@elemental.net |
| * and I'll send you a copy. |
| * |
| */ |
| |
| #include <includes.h> |
| #include <radiusclient.h> |
| |
| static void rc_extract_vendor_specific_attributes(int attrlen, |
| unsigned char *ptr, |
| VALUE_PAIR **vp); |
| /* |
| * Function: rc_avpair_add |
| * |
| * Purpose: add an attribute-value pair to the given list. |
| * |
| * Returns: pointer to added a/v pair upon success, NULL pointer upon failure. |
| * |
| * Remarks: Always appends the new pair to the end of the list. |
| * |
| */ |
| |
| VALUE_PAIR *rc_avpair_add (VALUE_PAIR **list, int attrid, void *pval, int len, |
| int vendorcode) |
| { |
| VALUE_PAIR *vp; |
| |
| vp = rc_avpair_new (attrid, pval, len, vendorcode); |
| |
| if (vp != (VALUE_PAIR *) NULL) |
| { |
| rc_avpair_insert (list, (VALUE_PAIR *) NULL, vp); |
| } |
| |
| return vp; |
| |
| } |
| |
| /* |
| * Function: rc_avpair_assign |
| * |
| * Purpose: assign the given value to an attribute-value pair. |
| * |
| * Returns: 0 on success, |
| * -1 on failure. |
| * |
| */ |
| |
| int rc_avpair_assign (VALUE_PAIR *vp, void *pval, int len) |
| { |
| int result = -1; |
| |
| switch (vp->type) |
| { |
| case PW_TYPE_STRING: |
| |
| if (((len == 0) && (strlen ((char *) pval)) > AUTH_STRING_LEN) |
| || (len > AUTH_STRING_LEN)) { |
| error("rc_avpair_assign: bad attribute length"); |
| return result; |
| } |
| |
| if (len > 0) { |
| memcpy(vp->strvalue, (char *)pval, len); |
| vp->strvalue[len] = '\0'; |
| vp->lvalue = len; |
| } else { |
| strncpy (vp->strvalue, (char *) pval, AUTH_STRING_LEN); |
| vp->lvalue = strlen((char *) pval); |
| } |
| |
| result = 0; |
| break; |
| |
| case PW_TYPE_DATE: |
| case PW_TYPE_INTEGER: |
| case PW_TYPE_IPADDR: |
| |
| vp->lvalue = * (UINT4 *) pval; |
| |
| result = 0; |
| break; |
| |
| default: |
| error("rc_avpair_assign: unknown attribute %d", vp->type); |
| } |
| return result; |
| } |
| |
| /* |
| * Function: rc_avpair_new |
| * |
| * Purpose: make a new attribute-value pair with given parameters. |
| * |
| * Returns: pointer to generated a/v pair when successful, NULL when failure. |
| * |
| */ |
| |
| VALUE_PAIR *rc_avpair_new (int attrid, void *pval, int len, int vendorcode) |
| { |
| VALUE_PAIR *vp = (VALUE_PAIR *) NULL; |
| DICT_ATTR *pda; |
| |
| if ((pda = rc_dict_getattr (attrid, vendorcode)) == (DICT_ATTR *) NULL) |
| { |
| error("rc_avpair_new: unknown attribute %d", attrid); |
| } |
| else |
| { |
| if ((vp = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) |
| != (VALUE_PAIR *) NULL) |
| { |
| strncpy (vp->name, pda->name, sizeof (vp->name)); |
| vp->attribute = attrid; |
| vp->vendorcode = vendorcode; |
| vp->next = (VALUE_PAIR *) NULL; |
| vp->type = pda->type; |
| if (rc_avpair_assign (vp, pval, len) == 0) |
| { |
| return vp; |
| } |
| free (vp); |
| vp = (VALUE_PAIR *) NULL; |
| } |
| else |
| novm("rc_avpair_new"); |
| } |
| return vp; |
| } |
| |
| /* |
| * |
| * Function: rc_avpair_gen |
| * |
| * Purpose: takes attribute/value pairs from buffer and builds a |
| * value_pair list using allocated memory. |
| * |
| * Returns: value_pair list or NULL on failure |
| */ |
| |
| VALUE_PAIR *rc_avpair_gen (AUTH_HDR *auth) |
| { |
| int length; |
| int x_len; |
| int attribute; |
| int attrlen; |
| UINT4 lvalue; |
| unsigned char *x_ptr; |
| unsigned char *ptr; |
| DICT_ATTR *attr; |
| VALUE_PAIR *vp; |
| VALUE_PAIR *pair; |
| unsigned char hex[3]; /* For hex string conversion. */ |
| char buffer[512]; |
| |
| /* |
| * Extract attribute-value pairs |
| */ |
| ptr = auth->data; |
| length = ntohs ((unsigned short) auth->length) - AUTH_HDR_LEN; |
| vp = (VALUE_PAIR *) NULL; |
| |
| while (length > 0) |
| { |
| attribute = *ptr++; |
| attrlen = *ptr++; |
| attrlen -= 2; |
| if (attrlen < 0) |
| { |
| error("rc_avpair_gen: received attribute with invalid length"); |
| break; |
| } |
| |
| /* Handle vendor-specific specially */ |
| if (attribute == PW_VENDOR_SPECIFIC) { |
| rc_extract_vendor_specific_attributes(attrlen, ptr, &vp); |
| ptr += attrlen; |
| length -= (attrlen + 2); |
| continue; |
| } |
| if ((attr = rc_dict_getattr (attribute, VENDOR_NONE)) == (DICT_ATTR *) NULL) |
| { |
| *buffer= '\0'; /* Initial length. */ |
| for (x_ptr = ptr, x_len = attrlen ; |
| x_len > 0 ; |
| x_len--, x_ptr++) |
| { |
| sprintf (hex, "%2.2X", *x_ptr); |
| strcat (buffer, hex); |
| } |
| warn("rc_avpair_gen: received unknown attribute %d of length %d: 0x%s", |
| attribute, attrlen, buffer); |
| } |
| else |
| { |
| if ((pair = |
| (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) == |
| (VALUE_PAIR *) NULL) |
| { |
| novm("rc_avpair_gen"); |
| rc_avpair_free(vp); |
| return NULL; |
| } |
| strcpy (pair->name, attr->name); |
| pair->attribute = attr->value; |
| pair->vendorcode = VENDOR_NONE; |
| pair->type = attr->type; |
| pair->next = (VALUE_PAIR *) NULL; |
| |
| switch (attr->type) |
| { |
| |
| case PW_TYPE_STRING: |
| memcpy (pair->strvalue, (char *) ptr, (size_t) attrlen); |
| pair->strvalue[attrlen] = '\0'; |
| pair->lvalue = attrlen; |
| rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair); |
| break; |
| |
| case PW_TYPE_INTEGER: |
| case PW_TYPE_IPADDR: |
| memcpy ((char *) &lvalue, (char *) ptr, |
| sizeof (UINT4)); |
| pair->lvalue = ntohl (lvalue); |
| rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair); |
| break; |
| |
| default: |
| warn("rc_avpair_gen: %s has unknown type", attr->name); |
| free (pair); |
| break; |
| } |
| |
| } |
| ptr += attrlen; |
| length -= attrlen + 2; |
| } |
| return (vp); |
| } |
| |
| /* |
| * Function: rc_extract_vendor_specific_attributes |
| * |
| * Purpose: Extracts vendor-specific attributes, assuming they are in |
| * the "SHOULD" format recommended by RCF 2138. |
| * |
| * Returns: found value_pair |
| * |
| */ |
| static void rc_extract_vendor_specific_attributes(int attrlen, |
| unsigned char *ptr, |
| VALUE_PAIR **vp) |
| { |
| int vendor_id; |
| int vtype; |
| int vlen; |
| UINT4 lvalue; |
| DICT_ATTR *attr; |
| VALUE_PAIR *pair; |
| |
| /* ptr is sitting at vendor-ID */ |
| if (attrlen < 8) { |
| /* Nothing to see here... */ |
| return; |
| } |
| |
| /* High-order octet of Vendor-Id must be zero (RFC2138) */ |
| if (*ptr) { |
| return; |
| } |
| |
| /* Extract vendor_id */ |
| vendor_id = (int) ( |
| ((unsigned int) ptr[1]) * 256 * 256 + |
| ((unsigned int) ptr[2]) * 256 + |
| ((unsigned int) ptr[3])); |
| /* Bump ptr up to contents */ |
| ptr += 4; |
| |
| /* Set attrlen to length of data */ |
| attrlen -= 4; |
| for (; attrlen; attrlen -= vlen+2, ptr += vlen) { |
| vtype = *ptr++; |
| vlen = *ptr++; |
| vlen -= 2; |
| if (vlen < 0 || vlen > attrlen - 2) { |
| /* Do not log an error. We are supposed to be able to cope with |
| arbitrary vendor-specific gunk */ |
| return; |
| } |
| /* Looks plausible... */ |
| if ((attr = rc_dict_getattr(vtype, vendor_id)) == NULL) { |
| continue; |
| } |
| |
| /* TODO: Check that length matches data size!!!!! */ |
| pair = (VALUE_PAIR *) malloc(sizeof(VALUE_PAIR)); |
| if (!pair) { |
| novm("rc_avpair_gen"); |
| return; |
| } |
| strcpy(pair->name, attr->name); |
| pair->attribute = attr->value; |
| pair->vendorcode = vendor_id; |
| pair->type = attr->type; |
| pair->next = NULL; |
| switch (attr->type) { |
| case PW_TYPE_STRING: |
| memcpy (pair->strvalue, (char *) ptr, (size_t) vlen); |
| pair->strvalue[vlen] = '\0'; |
| pair->lvalue = vlen; |
| rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair); |
| break; |
| |
| case PW_TYPE_INTEGER: |
| case PW_TYPE_IPADDR: |
| memcpy ((char *) &lvalue, (char *) ptr, |
| sizeof (UINT4)); |
| pair->lvalue = ntohl (lvalue); |
| rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair); |
| break; |
| |
| default: |
| warn("rc_avpair_gen: %s has unknown type", attr->name); |
| free (pair); |
| break; |
| } |
| } |
| } |
| |
| /* |
| * Function: rc_avpair_get |
| * |
| * Purpose: Find the first attribute value-pair (which matches the given |
| * attribute) from the specified value-pair list. |
| * |
| * Returns: found value_pair |
| * |
| */ |
| |
| VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, UINT4 attr) |
| { |
| for (; vp != (VALUE_PAIR *) NULL && vp->attribute != attr; vp = vp->next) |
| { |
| continue; |
| } |
| return (vp); |
| } |
| |
| /* |
| * Function: rc_avpair_copy |
| * |
| * Purpose: Return a copy of the existing list "p" ala strdup(). |
| * |
| */ |
| VALUE_PAIR *rc_avpair_copy(VALUE_PAIR *p) |
| { |
| VALUE_PAIR *vp, *fp = NULL, *lp = NULL; |
| |
| while (p) { |
| vp = malloc(sizeof(VALUE_PAIR)); |
| if (!vp) { |
| novm("rc_avpair_copy"); |
| return NULL; /* leaks a little but so what */ |
| } |
| *vp = *p; |
| if (!fp) |
| fp = vp; |
| if (lp) |
| lp->next = vp; |
| lp = vp; |
| p = p->next; |
| } |
| |
| return fp; |
| } |
| |
| /* |
| * Function: rc_avpair_insert |
| * |
| * Purpose: Given the address of an existing list "a" and a pointer |
| * to an entry "p" in that list, add the list "b" to |
| * the "a" list after the "p" entry. If "p" is NULL, add |
| * the list "b" to the end of "a". |
| * |
| */ |
| |
| void rc_avpair_insert (VALUE_PAIR **a, VALUE_PAIR *p, VALUE_PAIR *b) |
| { |
| VALUE_PAIR *this_node = NULL; |
| VALUE_PAIR *vp; |
| |
| if (*a == (VALUE_PAIR *) NULL) |
| { |
| *a = b; |
| return; |
| } |
| |
| if (!b) |
| return; |
| |
| vp = *a; |
| |
| if ( p == (VALUE_PAIR *) NULL) /* run to end of "a" list */ |
| { |
| while (vp != (VALUE_PAIR *) NULL) |
| { |
| this_node = vp; |
| vp = vp->next; |
| } |
| } |
| else /* look for the "p" entry in the "a" list (or run to end) */ |
| { |
| this_node = *a; |
| while (this_node != (VALUE_PAIR *) NULL) |
| { |
| if (this_node == p) |
| { |
| break; |
| } |
| this_node = this_node->next; |
| } |
| } |
| |
| /* add "b" at this_node */ |
| vp = this_node->next; |
| this_node->next = b; |
| |
| /* run to end of "b" and connect the rest of "a" */ |
| while (b->next) |
| b = b->next; |
| b->next = vp; |
| |
| return; |
| } |
| |
| /* |
| * Function: rc_avpair_free |
| * |
| * Purpose: frees all value_pairs in the list |
| * |
| */ |
| |
| void rc_avpair_free (VALUE_PAIR *pair) |
| { |
| VALUE_PAIR *next; |
| |
| while (pair != (VALUE_PAIR *) NULL) |
| { |
| next = pair->next; |
| free (pair); |
| pair = next; |
| } |
| } |
| |
| /* |
| * Function: rc_fieldcpy |
| * |
| * Purpose: Copy a data field from the buffer. Advance the buffer |
| * past the data field. |
| * |
| */ |
| |
| static void rc_fieldcpy (char *string, char **uptr) |
| { |
| char *ptr; |
| |
| ptr = *uptr; |
| if (*ptr == '"') |
| { |
| ptr++; |
| while (*ptr != '"' && *ptr != '\0' && *ptr != '\n') |
| { |
| *string++ = *ptr++; |
| } |
| *string = '\0'; |
| if (*ptr == '"') |
| { |
| ptr++; |
| } |
| *uptr = ptr; |
| return; |
| } |
| |
| while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' && |
| *ptr != '=' && *ptr != ',') |
| { |
| *string++ = *ptr++; |
| } |
| *string = '\0'; |
| *uptr = ptr; |
| return; |
| } |
| |
| |
| /* |
| * Function: rc_avpair_parse |
| * |
| * Purpose: parses the buffer to extract the attribute-value pairs. |
| * |
| * Returns: 0 = successful parse of attribute-value pair, |
| * -1 = syntax (or other) error detected. |
| * |
| */ |
| |
| #define PARSE_MODE_NAME 0 |
| #define PARSE_MODE_EQUAL 1 |
| #define PARSE_MODE_VALUE 2 |
| #define PARSE_MODE_INVALID 3 |
| |
| int rc_avpair_parse (char *buffer, VALUE_PAIR **first_pair) |
| { |
| int mode; |
| char attrstr[AUTH_ID_LEN]; |
| char valstr[AUTH_ID_LEN]; |
| DICT_ATTR *attr = NULL; |
| DICT_VALUE *dval; |
| VALUE_PAIR *pair; |
| VALUE_PAIR *link; |
| struct tm *tm; |
| time_t timeval; |
| |
| mode = PARSE_MODE_NAME; |
| while (*buffer != '\n' && *buffer != '\0') |
| { |
| if (*buffer == ' ' || *buffer == '\t') |
| { |
| buffer++; |
| continue; |
| } |
| |
| switch (mode) |
| { |
| case PARSE_MODE_NAME: /* Attribute Name */ |
| rc_fieldcpy (attrstr, &buffer); |
| if ((attr = |
| rc_dict_findattr (attrstr)) == (DICT_ATTR *) NULL) |
| { |
| error("rc_avpair_parse: unknown attribute"); |
| if (*first_pair) { |
| rc_avpair_free(*first_pair); |
| *first_pair = (VALUE_PAIR *) NULL; |
| } |
| return (-1); |
| } |
| mode = PARSE_MODE_EQUAL; |
| break; |
| |
| case PARSE_MODE_EQUAL: /* Equal sign */ |
| if (*buffer == '=') |
| { |
| mode = PARSE_MODE_VALUE; |
| buffer++; |
| } |
| else |
| { |
| error("rc_avpair_parse: missing or misplaced equal sign"); |
| if (*first_pair) { |
| rc_avpair_free(*first_pair); |
| *first_pair = (VALUE_PAIR *) NULL; |
| } |
| return (-1); |
| } |
| break; |
| |
| case PARSE_MODE_VALUE: /* Value */ |
| rc_fieldcpy (valstr, &buffer); |
| |
| if ((pair = |
| (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) |
| == (VALUE_PAIR *) NULL) |
| { |
| novm("rc_avpair_parse"); |
| if (*first_pair) { |
| rc_avpair_free(*first_pair); |
| *first_pair = (VALUE_PAIR *) NULL; |
| } |
| return (-1); |
| } |
| strcpy (pair->name, attr->name); |
| pair->attribute = attr->value; |
| pair->type = attr->type; |
| pair->vendorcode = attr->vendorcode; |
| |
| switch (pair->type) |
| { |
| |
| case PW_TYPE_STRING: |
| strcpy (pair->strvalue, valstr); |
| pair->lvalue = strlen(valstr); |
| break; |
| |
| case PW_TYPE_INTEGER: |
| if (isdigit (*valstr)) |
| { |
| pair->lvalue = atoi (valstr); |
| } |
| else |
| { |
| if ((dval = rc_dict_findval (valstr)) |
| == (DICT_VALUE *) NULL) |
| { |
| error("rc_avpair_parse: unknown attribute value: %s", valstr); |
| if (*first_pair) { |
| rc_avpair_free(*first_pair); |
| *first_pair = (VALUE_PAIR *) NULL; |
| } |
| free (pair); |
| return (-1); |
| } |
| else |
| { |
| pair->lvalue = dval->value; |
| } |
| } |
| break; |
| |
| case PW_TYPE_IPADDR: |
| pair->lvalue = rc_get_ipaddr(valstr); |
| break; |
| |
| case PW_TYPE_DATE: |
| timeval = time (0); |
| tm = localtime (&timeval); |
| tm->tm_hour = 0; |
| tm->tm_min = 0; |
| tm->tm_sec = 0; |
| rc_str2tm (valstr, tm); |
| #ifdef TIMELOCAL |
| pair->lvalue = (UINT4) timelocal (tm); |
| #else /* TIMELOCAL */ |
| pair->lvalue = (UINT4) mktime (tm); |
| #endif /* TIMELOCAL */ |
| break; |
| |
| default: |
| error("rc_avpair_parse: unknown attribute type %d", pair->type); |
| if (*first_pair) { |
| rc_avpair_free(*first_pair); |
| *first_pair = (VALUE_PAIR *) NULL; |
| } |
| free (pair); |
| return (-1); |
| } |
| pair->next = (VALUE_PAIR *) NULL; |
| |
| if (*first_pair == (VALUE_PAIR *) NULL) |
| { |
| *first_pair = pair; |
| } |
| else |
| { |
| link = *first_pair; |
| while (link->next != (VALUE_PAIR *) NULL) |
| { |
| link = link->next; |
| } |
| link->next = pair; |
| } |
| |
| mode = PARSE_MODE_NAME; |
| break; |
| |
| default: |
| mode = PARSE_MODE_NAME; |
| break; |
| } |
| } |
| return (0); |
| } |
| |
| /* |
| * Function: rc_avpair_tostr |
| * |
| * Purpose: Translate an av_pair into two strings |
| * |
| * Returns: 0 on success, -1 on failure |
| * |
| */ |
| |
| int rc_avpair_tostr (VALUE_PAIR *pair, char *name, int ln, char *value, int lv) |
| { |
| DICT_VALUE *dval; |
| char buffer[32]; |
| struct in_addr inad; |
| unsigned char *ptr; |
| |
| *name = *value = '\0'; |
| |
| if (!pair || pair->name[0] == '\0') { |
| error("rc_avpair_tostr: pair is NULL or empty"); |
| return (-1); |
| } |
| |
| strncpy(name, pair->name, (size_t) ln); |
| |
| switch (pair->type) |
| { |
| case PW_TYPE_STRING: |
| lv--; |
| ptr = (unsigned char *) pair->strvalue; |
| while (*ptr != '\0') |
| { |
| if (!(isprint (*ptr))) |
| { |
| sprintf (buffer, "\\%03o", *ptr); |
| strncat(value, buffer, (size_t) lv); |
| lv -= 4; |
| if (lv < 0) break; |
| } |
| else |
| { |
| strncat(value, ptr, 1); |
| lv--; |
| if (lv < 0) break; |
| } |
| ptr++; |
| } |
| break; |
| |
| case PW_TYPE_INTEGER: |
| dval = rc_dict_getval (pair->lvalue, pair->name); |
| if (dval != (DICT_VALUE *) NULL) |
| { |
| strncpy(value, dval->name, (size_t) lv-1); |
| } |
| else |
| { |
| sprintf (buffer, "%ld", pair->lvalue); |
| strncpy(value, buffer, (size_t) lv); |
| } |
| break; |
| |
| case PW_TYPE_IPADDR: |
| inad.s_addr = htonl(pair->lvalue); |
| strncpy (value, inet_ntoa (inad), (size_t) lv-1); |
| break; |
| |
| case PW_TYPE_DATE: |
| strftime (buffer, sizeof (buffer), "%m/%d/%y %H:%M:%S", |
| gmtime ((time_t *) & pair->lvalue)); |
| strncpy(value, buffer, lv-1); |
| break; |
| |
| default: |
| error("rc_avpair_tostr: unknown attribute type %d", pair->type); |
| return (-1); |
| break; |
| } |
| |
| return 0; |
| } |
| |
| /* |
| * Function: rc_avpair_readin |
| * |
| * Purpose: get a sequence of attribute value pairs from the file input |
| * and make them into a list of value_pairs |
| * |
| */ |
| |
| VALUE_PAIR *rc_avpair_readin(FILE *input) |
| { |
| VALUE_PAIR *vp = NULL; |
| char buffer[1024], *q; |
| |
| while (fgets(buffer, sizeof(buffer), input) != NULL) |
| { |
| q = buffer; |
| |
| while(*q && isspace(*q)) q++; |
| |
| if ((*q == '\n') || (*q == '#') || (*q == '\0')) |
| continue; |
| |
| if (rc_avpair_parse(q, &vp) < 0) { |
| error("rc_avpair_readin: malformed attribute: %s", buffer); |
| rc_avpair_free(vp); |
| return NULL; |
| } |
| } |
| |
| return vp; |
| } |