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@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 
rc_avpair_add(VALUE_PAIR ** list,int attrid,void * pval,int len,int vendorcode)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 
rc_avpair_assign(VALUE_PAIR * vp,void * pval,int len)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 
rc_avpair_new(int attrid,void * pval,int len,int vendorcode)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 
rc_avpair_gen(AUTH_HDR * auth)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  */
rc_extract_vendor_specific_attributes(int attrlen,unsigned char * ptr,VALUE_PAIR ** vp)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 
rc_avpair_get(VALUE_PAIR * vp,UINT4 attr)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  */
rc_avpair_copy(VALUE_PAIR * p)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 
rc_avpair_insert(VALUE_PAIR ** a,VALUE_PAIR * p,VALUE_PAIR * b)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 
rc_avpair_free(VALUE_PAIR * pair)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 
rc_fieldcpy(char * string,char ** uptr)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 
rc_avpair_parse(char * buffer,VALUE_PAIR ** first_pair)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 
rc_avpair_tostr(VALUE_PAIR * pair,char * name,int ln,char * value,int lv)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 
rc_avpair_readin(FILE * input)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