plugins/radius: Handle bindaddr keyword in radiusclient.conf
[ppp.git] / pppd / plugins / radius / avpair.c
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
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 }