a20e24cc7f9df917d515c490897875a80fd384bb
[ppp.git] / pppd / plugins / radius / radiusclient / lib / avpair.c
1 /*
2  * $Id: avpair.c,v 1.1 2002/01/22 16:03:02 dfs 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 <config.h>
18 #include <includes.h>
19 #include <radiusclient.h>
20
21 static void rc_extract_vendor_specific_attributes(int attrlen,
22                                                   unsigned char *ptr,
23                                                   VALUE_PAIR **vp);
24 /*
25  * Function: rc_avpair_add
26  *
27  * Purpose: add an attribute-value pair to the given list.
28  *
29  * Returns: pointer to added a/v pair upon success, NULL pointer upon failure.
30  *
31  * Remarks: Always appends the new pair to the end of the list.
32  *
33  */
34
35 VALUE_PAIR *rc_avpair_add (VALUE_PAIR **list, int attrid, void *pval, int len,
36                            int vendorcode)
37 {
38         VALUE_PAIR     *vp;
39
40         vp = rc_avpair_new (attrid, pval, len, vendorcode);
41
42         if (vp != (VALUE_PAIR *) NULL)
43         {
44                 rc_avpair_insert (list, (VALUE_PAIR *) NULL, vp);
45         }
46
47         return vp;
48
49 }
50
51 /*
52  * Function: rc_avpair_assign
53  *
54  * Purpose: assign the given value to an attribute-value pair.
55  *
56  * Returns:  0 on success,
57  *          -1 on failure.
58  *
59  */
60
61 int rc_avpair_assign (VALUE_PAIR *vp, void *pval, int len)
62 {
63         int     result = -1;
64
65         switch (vp->type)
66         {
67                 case PW_TYPE_STRING:
68
69                         if (((len == 0) && (strlen ((char *) pval)) > AUTH_STRING_LEN)
70                             || (len > AUTH_STRING_LEN)) {
71                                 rc_log(LOG_ERR, "rc_avpair_assign: bad attribute length");
72                                 return result;
73                     }
74
75                         if (len > 0) {
76                                 memcpy(vp->strvalue, (char *)pval, len);
77                                 vp->strvalue[len] = '\0';
78                                 vp->lvalue = len;
79                         } else {
80                         strncpy (vp->strvalue, (char *) pval, AUTH_STRING_LEN);
81                         vp->lvalue = strlen((char *) pval);
82                         }
83
84                         result = 0;
85                         break;
86
87                 case PW_TYPE_DATE:
88                 case PW_TYPE_INTEGER:
89                 case PW_TYPE_IPADDR:
90
91                         vp->lvalue = * (UINT4 *) pval;
92
93                         result = 0;
94                         break;
95
96                 default:
97                         rc_log(LOG_ERR, "rc_avpair_assign: unknown attribute %d", vp->type);
98         }
99         return result;
100 }
101
102 /*
103  * Function: rc_avpair_new
104  *
105  * Purpose: make a new attribute-value pair with given parameters.
106  *
107  * Returns: pointer to generated a/v pair when successful, NULL when failure.
108  *
109  */
110
111 VALUE_PAIR *rc_avpair_new (int attrid, void *pval, int len, int vendorcode)
112 {
113         VALUE_PAIR     *vp = (VALUE_PAIR *) NULL;
114         DICT_ATTR      *pda;
115
116         if ((pda = rc_dict_getattr (attrid, vendorcode)) == (DICT_ATTR *) NULL)
117         {
118                 rc_log(LOG_ERR,"rc_avpair_new: unknown attribute %d", attrid);
119         }
120         else
121         {
122                 if ((vp = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR)))
123                                                         != (VALUE_PAIR *) NULL)
124                 {
125                         strncpy (vp->name, pda->name, sizeof (vp->name));
126                         vp->attribute = attrid;
127                         vp->vendorcode = vendorcode;
128                         vp->next = (VALUE_PAIR *) NULL;
129                         vp->type = pda->type;
130                         if (rc_avpair_assign (vp, pval, len) == 0)
131                         {
132                                 return vp;
133                         }
134                         free (vp);
135                         vp = (VALUE_PAIR *) NULL;
136                 }
137                 else
138                 {
139                         rc_log(LOG_CRIT,"rc_avpair_new: out of memory");
140                 }
141         }
142         return vp;
143 }
144
145 /*
146  *
147  * Function: rc_avpair_gen
148  *
149  * Purpose: takes attribute/value pairs from buffer and builds a
150  *          value_pair list using allocated memory.
151  *
152  * Returns: value_pair list or NULL on failure
153  */
154
155 VALUE_PAIR *rc_avpair_gen (AUTH_HDR *auth)
156 {
157         int             length;
158         int             x_len;
159         int             attribute;
160         int             attrlen;
161         UINT4           lvalue;
162         unsigned char         *x_ptr;
163         unsigned char         *ptr;
164         DICT_ATTR      *attr;
165         VALUE_PAIR     *vp;
166         VALUE_PAIR     *pair;
167         unsigned char          hex[3];          /* For hex string conversion. */
168         char            buffer[256];
169
170         /*
171          * Extract attribute-value pairs
172          */
173         ptr = auth->data;
174         length = ntohs ((unsigned short) auth->length) - AUTH_HDR_LEN;
175         vp = (VALUE_PAIR *) NULL;
176
177         while (length > 0)
178         {
179                 attribute = *ptr++;
180                 attrlen = *ptr++;
181                 attrlen -= 2;
182                 if (attrlen < 0)
183                 {
184                         rc_log(LOG_ERR, "rc_avpair_gen: received attribute with invalid length");
185                         break;
186                 }
187
188                 /* Handle vendor-specific specially */
189                 if (attribute == PW_VENDOR_SPECIFIC) {
190                     rc_extract_vendor_specific_attributes(attrlen, ptr, &vp);
191                     ptr += attrlen;
192                     length -= (attrlen + 2);
193                     continue;
194                 }
195                 if ((attr = rc_dict_getattr (attribute, VENDOR_NONE)) == (DICT_ATTR *) NULL)
196                 {
197                         *buffer= '\0';  /* Initial length. */
198                         for (x_ptr = ptr, x_len = attrlen ;
199                                 x_len > 0 ;
200                                 x_len--, x_ptr++)
201                         {
202                                 sprintf (hex, "%2.2X", *x_ptr);
203                                 strcat (buffer, hex);
204                         }
205                         rc_log(LOG_WARNING, "rc_avpair_gen: received unknown attribute %d of length %d: 0x%s",
206                                 attribute, attrlen, buffer);
207                 }
208                 else
209                 {
210                         if ((pair =
211                                 (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) ==
212                                         (VALUE_PAIR *) NULL)
213                         {
214                                 rc_log(LOG_CRIT, "rc_avpair_gen: out of memory");
215                                 rc_avpair_free(vp);
216                                 return NULL;
217                         }
218                         strcpy (pair->name, attr->name);
219                         pair->attribute = attr->value;
220                         pair->vendorcode = VENDOR_NONE;
221                         pair->type = attr->type;
222                         pair->next = (VALUE_PAIR *) NULL;
223
224                         switch (attr->type)
225                         {
226
227                             case PW_TYPE_STRING:
228                                 memcpy (pair->strvalue, (char *) ptr, (size_t) attrlen);
229                                 pair->strvalue[attrlen] = '\0';
230                                 pair->lvalue = attrlen;
231                                 rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair);
232                                 break;
233
234                             case PW_TYPE_INTEGER:
235                             case PW_TYPE_IPADDR:
236                                 memcpy ((char *) &lvalue, (char *) ptr,
237                                         sizeof (UINT4));
238                                 pair->lvalue = ntohl (lvalue);
239                                 rc_avpair_insert (&vp, (VALUE_PAIR *) NULL, pair);
240                                 break;
241
242                             default:
243                                 rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type", attr->name);
244                                 free (pair);
245                                 break;
246                         }
247
248                 }
249                 ptr += attrlen;
250                 length -= attrlen + 2;
251         }
252         return (vp);
253 }
254
255 /*
256  * Function: rc_extract_vendor_specific_attributes
257  *
258  * Purpose: Extracts vendor-specific attributes, assuming they are in
259  *          the "SHOULD" format recommended by RCF 2138.
260  *
261  * Returns: found value_pair
262  *
263  */
264 static void rc_extract_vendor_specific_attributes(int attrlen,
265                                                   unsigned char *ptr,
266                                                   VALUE_PAIR **vp)
267 {
268     int vendor_id;
269     int vtype;
270     int vlen;
271     UINT4 lvalue;
272     DICT_ATTR *attr;
273     VALUE_PAIR *pair;
274
275     /* ptr is sitting at vendor-ID */
276     if (attrlen < 8) {
277         /* Nothing to see here... */
278         return;
279     }
280
281     /* High-order octet of Vendor-Id must be zero (RFC2138) */
282     if (*ptr) {
283         return;
284     }
285
286     /* Extract vendor_id */
287     vendor_id = (int) (
288         ((unsigned int) ptr[1]) * 256 * 256 +
289         ((unsigned int) ptr[2]) * 256 +
290         ((unsigned int) ptr[3]));
291     /* Bump ptr up to contents */
292     ptr += 4;
293
294     /* Set attrlen to length of data */
295     attrlen -= 4;
296     for (; attrlen; attrlen -= vlen+2, ptr += vlen) {
297         vtype = *ptr++;
298         vlen = *ptr++;
299         vlen -= 2;
300         if (vlen < 0 || vlen > attrlen - 2) {
301             /* Do not log an error.  We are supposed to be able to cope with
302                arbitrary vendor-specific gunk */
303             return;
304         }
305         /* Looks plausible... */
306         if ((attr = rc_dict_getattr(vtype, vendor_id)) == NULL) {
307             continue;
308         }
309
310         /* TODO: Check that length matches data size!!!!! */
311         pair = (VALUE_PAIR *) malloc(sizeof(VALUE_PAIR));
312         if (!pair) {
313             rc_log(LOG_CRIT, "rc_avpair_gen: out of memory");
314             return;
315         }
316         strcpy(pair->name, attr->name);
317         pair->attribute = attr->value;
318         pair->vendorcode = vendor_id;
319         pair->type = attr->type;
320         pair->next = NULL;
321         switch (attr->type) {
322         case PW_TYPE_STRING:
323             memcpy (pair->strvalue, (char *) ptr, (size_t) vlen);
324             pair->strvalue[vlen] = '\0';
325             pair->lvalue = vlen;
326             rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair);
327             break;
328
329         case PW_TYPE_INTEGER:
330         case PW_TYPE_IPADDR:
331             memcpy ((char *) &lvalue, (char *) ptr,
332                     sizeof (UINT4));
333             pair->lvalue = ntohl (lvalue);
334             rc_avpair_insert (vp, (VALUE_PAIR *) NULL, pair);
335             break;
336
337         default:
338             rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type", attr->name);
339             free (pair);
340             break;
341         }
342     }
343 }
344
345 /*
346  * Function: rc_avpair_get
347  *
348  * Purpose: Find the first attribute value-pair (which matches the given
349  *          attribute) from the specified value-pair list.
350  *
351  * Returns: found value_pair
352  *
353  */
354
355 VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, UINT4 attr)
356 {
357         for (; vp != (VALUE_PAIR *) NULL && vp->attribute != attr; vp = vp->next)
358         {
359                 continue;
360         }
361         return (vp);
362 }
363
364 /*
365  * Function: rc_avpair_insert
366  *
367  * Purpose: Given the address of an existing list "a" and a pointer
368  *          to an entry "p" in that list, add the value pair "b" to
369  *          the "a" list after the "p" entry.  If "p" is NULL, add
370  *          the value pair "b" to the end of "a".
371  *
372  */
373
374 void rc_avpair_insert (VALUE_PAIR **a, VALUE_PAIR *p, VALUE_PAIR *b)
375 {
376         VALUE_PAIR     *this_node = NULL;
377         VALUE_PAIR     *vp;
378
379         if (b->next != (VALUE_PAIR *) NULL)
380         {
381                 rc_log(LOG_CRIT, "rc_avpair_insert: value pair (0x%p) next ptr. (0x%p) not NULL", b, b->next);
382                 abort ();
383         }
384
385         if (*a == (VALUE_PAIR *) NULL)
386         {
387                 *a = b;
388                 return;
389         }
390
391         vp = *a;
392
393         if ( p == (VALUE_PAIR *) NULL) /* run to end of "a" list */
394         {
395                 while (vp != (VALUE_PAIR *) NULL)
396                 {
397                         this_node = vp;
398                         vp = vp->next;
399                 }
400         }
401         else /* look for the "p" entry in the "a" list */
402         {
403                 this_node = *a;
404                 while (this_node != (VALUE_PAIR *) NULL)
405                 {
406                         if (this_node == p)
407                         {
408                                 break;
409                         }
410                         this_node = this_node->next;
411                 }
412         }
413
414         b->next = this_node->next;
415         this_node->next = b;
416
417         return;
418 }
419
420 /*
421  * Function: rc_avpair_free
422  *
423  * Purpose: frees all value_pairs in the list
424  *
425  */
426
427 void rc_avpair_free (VALUE_PAIR *pair)
428 {
429         VALUE_PAIR     *next;
430
431         while (pair != (VALUE_PAIR *) NULL)
432         {
433                 next = pair->next;
434                 free (pair);
435                 pair = next;
436         }
437 }
438
439 /*
440  * Function: rc_fieldcpy
441  *
442  * Purpose: Copy a data field from the buffer.  Advance the buffer
443  *          past the data field.
444  *
445  */
446
447 static void rc_fieldcpy (char *string, char **uptr)
448 {
449         char           *ptr;
450
451         ptr = *uptr;
452         if (*ptr == '"')
453         {
454                 ptr++;
455                 while (*ptr != '"' && *ptr != '\0' && *ptr != '\n')
456                 {
457                         *string++ = *ptr++;
458                 }
459                 *string = '\0';
460                 if (*ptr == '"')
461                 {
462                         ptr++;
463                 }
464                 *uptr = ptr;
465                 return;
466         }
467
468         while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0' && *ptr != '\n' &&
469                         *ptr != '=' && *ptr != ',')
470         {
471                 *string++ = *ptr++;
472         }
473         *string = '\0';
474         *uptr = ptr;
475         return;
476 }
477
478
479 /*
480  * Function: rc_avpair_parse
481  *
482  * Purpose: parses the buffer to extract the attribute-value pairs.
483  *
484  * Returns: 0 = successful parse of attribute-value pair,
485  *         -1 = syntax (or other) error detected.
486  *
487  */
488
489 #define PARSE_MODE_NAME         0
490 #define PARSE_MODE_EQUAL        1
491 #define PARSE_MODE_VALUE        2
492 #define PARSE_MODE_INVALID      3
493
494 int rc_avpair_parse (char *buffer, VALUE_PAIR **first_pair)
495 {
496         int             mode;
497         char            attrstr[AUTH_ID_LEN];
498         char            valstr[AUTH_ID_LEN];
499         DICT_ATTR      *attr = NULL;
500         DICT_VALUE     *dval;
501         VALUE_PAIR     *pair;
502         VALUE_PAIR     *link;
503         struct tm      *tm;
504         time_t          timeval;
505
506         mode = PARSE_MODE_NAME;
507         while (*buffer != '\n' && *buffer != '\0')
508         {
509                 if (*buffer == ' ' || *buffer == '\t')
510                 {
511                         buffer++;
512                         continue;
513                 }
514
515                 switch (mode)
516                 {
517                     case PARSE_MODE_NAME:               /* Attribute Name */
518                         rc_fieldcpy (attrstr, &buffer);
519                         if ((attr =
520                                 rc_dict_findattr (attrstr)) == (DICT_ATTR *) NULL)
521                         {
522                                 rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute");
523                                 if (*first_pair) {
524                                         rc_avpair_free(*first_pair);
525                                         *first_pair = (VALUE_PAIR *) NULL;
526                                 }
527                                 return (-1);
528                         }
529                         mode = PARSE_MODE_EQUAL;
530                         break;
531
532                     case PARSE_MODE_EQUAL:              /* Equal sign */
533                         if (*buffer == '=')
534                         {
535                                 mode = PARSE_MODE_VALUE;
536                                 buffer++;
537                         }
538                         else
539                         {
540                                 rc_log(LOG_ERR, "rc_avpair_parse: missing or misplaced equal sign");
541                                 if (*first_pair) {
542                                         rc_avpair_free(*first_pair);
543                                         *first_pair = (VALUE_PAIR *) NULL;
544                                 }
545                                 return (-1);
546                         }
547                         break;
548
549                     case PARSE_MODE_VALUE:              /* Value */
550                         rc_fieldcpy (valstr, &buffer);
551
552                         if ((pair =
553                                 (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR)))
554                                                         == (VALUE_PAIR *) NULL)
555                         {
556                                 rc_log(LOG_CRIT, "rc_avpair_parse: out of memory");
557                                 if (*first_pair) {
558                                         rc_avpair_free(*first_pair);
559                                         *first_pair = (VALUE_PAIR *) NULL;
560                                 }
561                                 return (-1);
562                         }
563                         strcpy (pair->name, attr->name);
564                         pair->attribute = attr->value;
565                         pair->type = attr->type;
566
567                         switch (pair->type)
568                         {
569
570                             case PW_TYPE_STRING:
571                                 strcpy (pair->strvalue, valstr);
572                                 pair->lvalue = strlen(valstr);
573                                 break;
574
575                             case PW_TYPE_INTEGER:
576                                 if (isdigit (*valstr))
577                                 {
578                                         pair->lvalue = atoi (valstr);
579                                 }
580                                 else
581                                 {
582                                         if ((dval = rc_dict_findval (valstr))
583                                                         == (DICT_VALUE *) NULL)
584                                         {
585                                                 rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute value: %s", valstr);
586                                                 if (*first_pair) {
587                                                         rc_avpair_free(*first_pair);
588                                                         *first_pair = (VALUE_PAIR *) NULL;
589                                                 }
590                                                 free (pair);
591                                                 return (-1);
592                                         }
593                                         else
594                                         {
595                                                 pair->lvalue = dval->value;
596                                         }
597                                 }
598                                 break;
599
600                             case PW_TYPE_IPADDR:
601                                 pair->lvalue = rc_get_ipaddr(valstr);
602                                 break;
603
604                             case PW_TYPE_DATE:
605                                 timeval = time (0);
606                                 tm = localtime (&timeval);
607                                 tm->tm_hour = 0;
608                                 tm->tm_min = 0;
609                                 tm->tm_sec = 0;
610                                 rc_str2tm (valstr, tm);
611 #ifdef TIMELOCAL
612                                 pair->lvalue = (UINT4) timelocal (tm);
613 #else   /* TIMELOCAL */
614                                 pair->lvalue = (UINT4) mktime (tm);
615 #endif  /* TIMELOCAL */
616                                 break;
617
618                             default:
619                                 rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute type %d", pair->type);
620                                 if (*first_pair) {
621                                         rc_avpair_free(*first_pair);
622                                         *first_pair = (VALUE_PAIR *) NULL;
623                                 }
624                                 free (pair);
625                                 return (-1);
626                         }
627                         pair->next = (VALUE_PAIR *) NULL;
628
629                         if (*first_pair == (VALUE_PAIR *) NULL)
630                         {
631                                 *first_pair = pair;
632                         }
633                         else
634                         {
635                                 link = *first_pair;
636                                 while (link->next != (VALUE_PAIR *) NULL)
637                                 {
638                                         link = link->next;
639                                 }
640                                 link->next = pair;
641                         }
642
643                         mode = PARSE_MODE_NAME;
644                         break;
645
646                     default:
647                         mode = PARSE_MODE_NAME;
648                         break;
649                 }
650         }
651         return (0);
652 }
653
654 /*
655  * Function: rc_avpair_tostr
656  *
657  * Purpose: Translate an av_pair into two strings
658  *
659  * Returns: 0 on success, -1 on failure
660  *
661  */
662
663 int rc_avpair_tostr (VALUE_PAIR *pair, char *name, int ln, char *value, int lv)
664 {
665         DICT_VALUE     *dval;
666         char            buffer[32];
667         struct in_addr  inad;
668         unsigned char         *ptr;
669
670         *name = *value = '\0';
671
672         if (!pair || pair->name[0] == '\0') {
673                 rc_log(LOG_ERR, "rc_avpair_tostr: pair is NULL or empty");
674                 return (-1);
675         }
676
677         strncpy(name, pair->name, (size_t) ln);
678
679         switch (pair->type)
680         {
681             case PW_TYPE_STRING:
682                 lv--;
683                 ptr = (unsigned char *) pair->strvalue;
684                 while (*ptr != '\0')
685                 {
686                         if (!(isprint (*ptr)))
687                         {
688                                 sprintf (buffer, "\\%03o", *ptr);
689                                 strncat(value, buffer, (size_t) lv);
690                                 lv -= 4;
691                                 if (lv < 0) break;
692                         }
693                         else
694                         {
695                                 strncat(value, ptr, 1);
696                                 lv--;
697                                 if (lv < 0) break;
698                         }
699                         ptr++;
700                 }
701                 break;
702
703             case PW_TYPE_INTEGER:
704                 dval = rc_dict_getval (pair->lvalue, pair->name);
705                 if (dval != (DICT_VALUE *) NULL)
706                 {
707                         strncpy(value, dval->name, (size_t) lv-1);
708                 }
709                 else
710                 {
711                         sprintf (buffer, "%ld", pair->lvalue);
712                         strncpy(value, buffer, (size_t) lv);
713                 }
714                 break;
715
716             case PW_TYPE_IPADDR:
717                 inad.s_addr = htonl(pair->lvalue);
718                 strncpy (value, inet_ntoa (inad), (size_t) lv-1);
719                 break;
720
721             case PW_TYPE_DATE:
722                 strftime (buffer, sizeof (buffer), "%m/%d/%y %H:%M:%S",
723                           gmtime ((time_t *) & pair->lvalue));
724                 strncpy(value, buffer, lv-1);
725                 break;
726
727             default:
728                 rc_log(LOG_ERR, "rc_avpair_tostr: unknown attribute type %d", pair->type);
729                 return (-1);
730                 break;
731         }
732
733         return 0;
734 }
735
736 /*
737  * Function: rc_avpair_readin
738  *
739  * Purpose: get a sequence of attribute value pairs from the file input
740  *          and make them into a list of value_pairs
741  *
742  */
743
744 VALUE_PAIR *rc_avpair_readin(FILE *input)
745 {
746         VALUE_PAIR *vp = NULL;
747         char buffer[1024], *q;
748
749         while (fgets(buffer, sizeof(buffer), input) != NULL)
750         {
751                 q = buffer;
752
753                 while(*q && isspace(*q)) q++;
754
755                 if ((*q == '\n') || (*q == '#') || (*q == '\0'))
756                         continue;
757
758                 if (rc_avpair_parse(q, &vp) < 0) {
759                         rc_log(LOG_ERR, "rc_avpair_readin: malformed attribute: %s", buffer);
760                         rc_avpair_free(vp);
761                         return NULL;
762                 }
763         }
764
765         return vp;
766 }