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