Home | History | Annotate | Download | only in radius
      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