Files
openairinterface5g/openair3/PMIPv6/freeradius-client-1.1.6/lib/avpair.c
T
2013-06-25 09:05:02 +00:00

819 lines
18 KiB
C

/*
* $Id: avpair.c,v 1.23 2008/01/09 07:05:11 sobomax 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 <config.h>
#include <includes.h>
#include <freeradius-client.h>
/*
* 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 (const rc_handle *rh, VALUE_PAIR **list, int attrid, void *pval, int len, int vendorpec)
{
VALUE_PAIR *vp;
vp = rc_avpair_new (rh, attrid, pval, len, vendorpec);
if (vp != NULL)
{
rc_avpair_insert (list, 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)
{
switch (vp->type)
{
case PW_TYPE_STRING:
if (len == -1)
len = (uint32_t)strlen((char *)pval);
if (len > AUTH_STRING_LEN) {
rc_log(LOG_ERR, "rc_avpair_assign: bad attribute length");
return -1;
}
memcpy(vp->strvalue, (char *)pval, len);
vp->strvalue[len] = '\0';
vp->lvalue = len;
break;
case PW_TYPE_DATE:
case PW_TYPE_INTEGER:
case PW_TYPE_IPADDR:
vp->lvalue = * (uint32_t *) pval;
break;
case PW_TYPE_IPV6ADDR:
memcpy(&vp->in6addrvalue, pval, sizeof(struct in6_addr));
//rc_log(LOG_NOTICE, "rc_avpair_assign: PW_TYPE_IPV6ADDR %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&vp->in6addrvalue));
break;
default:
rc_log(LOG_ERR, "rc_avpair_assign: unknown attribute %d", vp->type);
return -1;
}
return 0;
}
/*
* 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 (const rc_handle *rh, int attrid, void *pval, int len, int vendorpec)
{
VALUE_PAIR *vp = NULL;
DICT_ATTR *pda;
attrid = attrid | (vendorpec << 16);
if ((pda = rc_dict_getattr (rh, attrid)) == NULL)
{
rc_log(LOG_ERR,"rc_avpair_new: unknown attribute %d", attrid);
return NULL;
}
if (vendorpec != 0 && rc_dict_getvend(rh, vendorpec) == NULL)
{
rc_log(LOG_ERR,"rc_avpair_new: unknown Vendor-Id %d", vendorpec);
return NULL;
}
if ((vp = malloc (sizeof (VALUE_PAIR))) != NULL)
{
strncpy (vp->name, pda->name, sizeof (vp->name));
vp->attribute = attrid;
vp->next = NULL;
vp->type = pda->type;
if (rc_avpair_assign (vp, pval, len) == 0)
{
/* XXX: Fix up Digest-Attributes */
switch (vp->attribute) {
case PW_DIGEST_REALM:
case PW_DIGEST_NONCE:
case PW_DIGEST_METHOD:
case PW_DIGEST_URI:
case PW_DIGEST_QOP:
case PW_DIGEST_ALGORITHM:
case PW_DIGEST_BODY_DIGEST:
case PW_DIGEST_CNONCE:
case PW_DIGEST_NONCE_COUNT:
case PW_DIGEST_USER_NAME:
/* overlapping! */
if (vp->lvalue > AUTH_STRING_LEN - 2)
vp->lvalue = AUTH_STRING_LEN - 2;
memmove(&vp->strvalue[2], &vp->strvalue[0], vp->lvalue);
vp->strvalue[0] = vp->attribute - PW_DIGEST_REALM + 1;
vp->lvalue += 2;
vp->strvalue[1] = vp->lvalue;
vp->strvalue[vp->lvalue] = '\0';
vp->attribute = PW_DIGEST_ATTRIBUTES;
default:
break;
}
return vp;
}
free (vp);
vp = NULL;
}
else
{
rc_log(LOG_CRIT,"rc_avpair_new: out of memory");
}
return vp;
}
/*
*
* Function: rc_avpair_gen
*
* Purpose: takes attribute/value pairs from buffer and builds a
* value_pair list using allocated memory. Uses recursion.
*
* Returns: value_pair list or NULL on failure
*/
VALUE_PAIR *
rc_avpair_gen(const rc_handle *rh, VALUE_PAIR *pair, unsigned char *ptr,
int length, int vendorpec)
{
int attribute, attrlen, x_len;
unsigned char *x_ptr;
uint32_t lvalue;
DICT_ATTR *attr;
VALUE_PAIR *rpair;
char buffer[(AUTH_STRING_LEN * 2) + 1];
/* For hex string conversion. */
char hex[3];
if (length < 2) {
rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
"invalid length");
goto shithappens;
}
attrlen = ptr[1];
if (length < attrlen || attrlen < 2) {
rc_log(LOG_ERR, "rc_avpair_gen: received attribute with "
"invalid length");
goto shithappens;
}
/* Advance to the next attribute and process recursively */
if (length != attrlen) {
pair = rc_avpair_gen(rh, pair, ptr + attrlen, length - attrlen,
vendorpec);
if (pair == NULL)
return NULL;
}
/* Actual processing */
attribute = ptr[0] | (vendorpec << 16);
ptr += 2;
attrlen -= 2;
/* VSA */
if (attribute == PW_VENDOR_SPECIFIC) {
if (attrlen < 4) {
rc_log(LOG_ERR, "rc_avpair_gen: received VSA "
"attribute with invalid length");
goto shithappens;
}
memcpy(&lvalue, ptr, 4);
vendorpec = ntohl(lvalue);
if (rc_dict_getvend(rh, vendorpec) == NULL) {
/* Warn and skip over the unknown VSA */
rc_log(LOG_WARNING, "rc_avpair_gen: received VSA "
"attribute with unknown Vendor-Id %d", vendorpec);
return pair;
}
/* Process recursively */
return rc_avpair_gen(rh, pair, ptr + 4, attrlen - 4,
vendorpec);
}
/* Normal */
attr = rc_dict_getattr(rh, attribute);
if (attr == NULL) {
buffer[0] = '\0'; /* Initial length. */
x_ptr = ptr;
for (x_len = attrlen; x_len > 0; x_len--, x_ptr++) {
sprintf(hex, "%2.2X", x_ptr[0]);
strcat(buffer, hex);
}
if (vendorpec == 0) {
rc_log(LOG_WARNING, "rc_avpair_gen: received "
"unknown attribute %d of length %d: 0x%s",
attribute, attrlen + 2, buffer);
} else {
rc_log(LOG_WARNING, "rc_avpair_gen: received "
"unknown VSA attribute %d, vendor %d of "
"length %d: 0x%s", attribute & 0xffff,
VENDOR(attribute), attrlen + 2, buffer);
}
goto shithappens;
}
rpair = malloc(sizeof(*rpair));
if (rpair == NULL) {
rc_log(LOG_CRIT, "rc_avpair_gen: out of memory");
goto shithappens;
}
memset(rpair, '\0', sizeof(*rpair));
/* Insert this new pair at the beginning of the list */
rpair->next = pair;
pair = rpair;
strcpy(pair->name, attr->name);
pair->attribute = attr->value;
pair->type = attr->type;
switch (attr->type) {
case PW_TYPE_STRING:
memcpy(pair->strvalue, (char *)ptr, (size_t)attrlen);
pair->strvalue[attrlen] = '\0';
pair->lvalue = attrlen;
break;
case PW_TYPE_INTEGER:
if (attrlen != 4) {
rc_log(LOG_ERR, "rc_avpair_gen: received INT "
"attribute with invalid length");
goto shithappens;
}
case PW_TYPE_IPADDR:
if (attrlen != 4) {
rc_log(LOG_ERR, "rc_avpair_gen: received IPADDR"
" attribute with invalid length");
goto shithappens;
}
memcpy((char *)&lvalue, (char *)ptr, 4);
pair->lvalue = ntohl(lvalue);
break;
case PW_TYPE_IPV6ADDR:
if (attrlen != 16) {
rc_log(LOG_ERR, "rc_avpair_gen: received IPV6ADDR"
" attribute with invalid length %d (should be %d)", attrlen, 16);
goto shithappens;
}
memcpy(&pair->in6addrvalue, ptr, 16);
//rc_log(LOG_NOTICE, "rc_avpair_gen: PW_TYPE_IPV6ADDR %x:%x:%x:%x:%x:%x:%x:%x\n", NIP6ADDR(&pair->in6addrvalue));
break;
default:
rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type",
attr->name);
goto shithappens;
}
return pair;
shithappens:
while (pair != NULL) {
rpair = pair->next;
free(pair);
pair = rpair;
}
return NULL;
}
/*
* 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, int attrid, int vendorpec)
{
for (; vp != NULL && !(ATTRID(vp->attribute) == ATTRID(attrid) &&
VENDOR(vp->attribute) == vendorpec); vp = vp->next)
{
continue;
}
return vp;
}
/*
* 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 value pair "b" to
* the "a" list after the "p" entry. If "p" is NULL, add
* the value pair "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 (b->next != NULL)
{
rc_log(LOG_CRIT, "rc_avpair_insert: value pair (0x%p) next ptr. (0x%p) not NULL", b, b->next);
abort ();
}
if (*a == NULL)
{
*a = b;
return;
}
vp = *a;
if ( p == NULL) /* run to end of "a" list */
{
while (vp != NULL)
{
this_node = vp;
vp = vp->next;
}
}
else /* look for the "p" entry in the "a" list */
{
this_node = *a;
while (this_node != NULL)
{
if (this_node == p)
{
break;
}
this_node = this_node->next;
}
}
b->next = this_node->next;
this_node->next = b;
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 != 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. Ensure that no more than len - 1
* bytes are copied and that resulting string is terminated
* with '\0'.
*
*/
static void
rc_fieldcpy(char *string, char **uptr, const char *stopat, size_t len)
{
char *ptr, *estring;
ptr = *uptr;
estring = string + len - 1;
if (*ptr == '"')
{
ptr++;
while (*ptr != '"' && *ptr != '\0' && *ptr != '\n')
{
if (string < estring)
*string++ = *ptr;
ptr++;
}
if (*ptr == '"')
{
ptr++;
}
*string = '\0';
*uptr = ptr;
return;
}
while (*ptr != '\0' && strchr(stopat, *ptr) == NULL)
{
if (string < estring)
*string++ = *ptr;
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 (const rc_handle *rh, char *buffer, VALUE_PAIR **first_pair)
{
int mode;
char attrstr[AUTH_ID_LEN];
char valstr[AUTH_STRING_LEN + 1];
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, " \t\n=,", sizeof(attrstr));
if ((attr =
rc_dict_findattr (rh, attrstr)) == NULL)
{
rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute");
if (*first_pair) {
rc_avpair_free(*first_pair);
*first_pair = NULL;
}
return -1;
}
mode = PARSE_MODE_EQUAL;
break;
case PARSE_MODE_EQUAL: /* Equal sign */
if (*buffer == '=')
{
mode = PARSE_MODE_VALUE;
buffer++;
}
else
{
rc_log(LOG_ERR, "rc_avpair_parse: missing or misplaced equal sign");
if (*first_pair) {
rc_avpair_free(*first_pair);
*first_pair = NULL;
}
return -1;
}
break;
case PARSE_MODE_VALUE: /* Value */
rc_fieldcpy (valstr, &buffer, " \t\n,", sizeof(valstr));
if ((pair = malloc (sizeof (VALUE_PAIR))) == NULL)
{
rc_log(LOG_CRIT, "rc_avpair_parse: out of memory");
if (*first_pair) {
rc_avpair_free(*first_pair);
*first_pair = NULL;
}
return -1;
}
strcpy (pair->name, attr->name);
pair->attribute = attr->value;
pair->type = attr->type;
switch (pair->type)
{
case PW_TYPE_STRING:
strcpy (pair->strvalue, valstr);
pair->lvalue = (uint32_t)strlen(valstr);
break;
case PW_TYPE_INTEGER:
if (isdigit (*valstr))
{
pair->lvalue = atoi (valstr);
}
else
{
if ((dval = rc_dict_findval (rh, valstr))
== NULL)
{
rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute value: %s", valstr);
if (*first_pair) {
rc_avpair_free(*first_pair);
*first_pair = NULL;
}
free (pair);
return -1;
}
else
{
pair->lvalue = dval->value;
}
}
break;
case PW_TYPE_IPADDR:
rc_log(LOG_ERR, "rc_avpair_parse: PW_TYPE_IPADDR not allowed");
//rc_get_ipaddr(valstr, (struct in6_addr*)&pair->lvalue);
break;
case PW_TYPE_IPV6ADDR:
//rc_log(LOG_NOTICE, "rc_avpair_parse: PW_TYPE_IPV6ADDR");
rc_get_ipaddr(valstr, (struct in6_addr*)&pair->in6addrvalue);
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 = (uint32_t) timelocal (tm);
#else /* TIMELOCAL */
pair->lvalue = (uint32_t) mktime (tm);
#endif /* TIMELOCAL */
break;
default:
rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute type %d", pair->type);
if (*first_pair) {
rc_avpair_free(*first_pair);
*first_pair = NULL;
}
free (pair);
return -1;
}
/* XXX: Fix up Digest-Attributes */
switch (pair->attribute) {
case PW_DIGEST_REALM:
case PW_DIGEST_NONCE:
case PW_DIGEST_METHOD:
case PW_DIGEST_URI:
case PW_DIGEST_QOP:
case PW_DIGEST_ALGORITHM:
case PW_DIGEST_BODY_DIGEST:
case PW_DIGEST_CNONCE:
case PW_DIGEST_NONCE_COUNT:
case PW_DIGEST_USER_NAME:
/* overlapping! */
if (pair->lvalue > AUTH_STRING_LEN - 2)
pair->lvalue = AUTH_STRING_LEN - 2;
memmove(&pair->strvalue[2], &pair->strvalue[0], pair->lvalue);
pair->strvalue[0] = pair->attribute - PW_DIGEST_REALM + 1;
pair->lvalue += 2;
pair->strvalue[1] = pair->lvalue;
pair->strvalue[pair->lvalue] = '\0';
pair->attribute = PW_DIGEST_ATTRIBUTES;
}
pair->next = NULL;
if (*first_pair == NULL)
{
*first_pair = pair;
}
else
{
link = *first_pair;
while (link->next != 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 (const rc_handle *rh, VALUE_PAIR *pair, char *name, int ln, char *value, int lv)
{
DICT_VALUE *dval;
char buffer[32];
struct in_addr inad;
struct in6_addr in6ad;
unsigned char *ptr;
*name = *value = '\0';
if (!pair || pair->name[0] == '\0') {
rc_log(LOG_ERR, "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;
if (pair->attribute == PW_DIGEST_ATTRIBUTES) {
pair->strvalue[*(ptr + 1)] = '\0';
ptr += 2;
}
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, (char *)ptr, 1);
lv--;
if (lv < 0) break;
}
ptr++;
}
break;
case PW_TYPE_INTEGER:
dval = rc_dict_getval (rh, pair->lvalue, pair->name);
if (dval != NULL)
{
strncpy(value, dval->name, (size_t) lv-1);
}
else
{
sprintf (buffer, "%ld", (long int)pair->lvalue);
strncpy(value, buffer, (size_t) lv);
}
break;
case PW_TYPE_IPADDR:
//rc_log(LOG_NOTICE, "rc_avpair_tostr: PW_TYPE_IPADDR ");
inad.s_addr = htonl(pair->lvalue);
strncpy (value, inet_ntoa (inad), (size_t) lv-1);
break;
case PW_TYPE_IPV6ADDR:
//rc_log(LOG_NOTICE, "rc_avpair_tostr: PW_TYPE_IPV6ADDR ");
if (!inet_ntop(AF_INET6, (const void *) &pair->in6addrvalue, value, (size_t) lv-1)) {
rc_log(LOG_ERR, "rc_avpair_tostr: PW_TYPE_IPV6ADDR error inet_ntop: %s", strerror(errno));
}
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:
rc_log(LOG_ERR, "rc_avpair_tostr: unknown attribute type %d", pair->type);
return -1;
break;
}
return 0;
}
/*
* Function: rc_avpair_log
*
* Purpose: format sequence of attribute value pairs into printable
* string. The string is dynamically allocated and is automatically
* freed when rc_handle is destroyed or rc_avpair_log() is called
* again.
*
*/
char *
rc_avpair_log(rc_handle *rh, VALUE_PAIR *pair)
{
size_t len, nlen;
VALUE_PAIR *vp;
char name[33], value[256];
char *cp;
len = 0;
for (vp = pair; vp != NULL; vp = vp->next) {
if (rc_avpair_tostr(rh, vp, name, sizeof(name), value,
sizeof(value)) == -1)
return NULL;
nlen = len + 32 + 3 + strlen(value) + 2 + 2;
cp = realloc(rh->ppbuf, nlen);
if (cp == NULL) {
rc_log(LOG_ERR, "rc_avpair_log: can't allocate memory");
return NULL;
}
sprintf(cp + len, "%-32s = '%s'\n", name, value);
rh->ppbuf = cp;
len = nlen - 1;
}
return (len > 0) ? rh->ppbuf : NULL;
}
/*
* 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(const rc_handle *rh, 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(rh, q, &vp) < 0) {
rc_log(LOG_ERR, "rc_avpair_readin: malformed attribute: %s", buffer);
rc_avpair_free(vp);
return NULL;
}
}
return vp;
}