type.data is malloc'd by everyone BUT radeapclient, which
[freeradius.git] / src / modules / rlm_eap / libeap / eapcommon.c
1 /*
2  * eapcommon.c    rfc2284 & rfc2869 implementation
3  *
4  * code common to clients and to servers.
5  *
6  * Version:     $Id$
7  *
8  *   This program is free software; you can redistribute it and/or modify
9  *   it under the terms of the GNU General Public License as published by
10  *   the Free Software Foundation; either version 2 of the License, or
11  *   (at your option) any later version.
12  *
13  *   This program is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program; if not, write to the Free Software
20  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * Copyright 2000-2003  The FreeRADIUS server project
23  * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com>
24  * Copyright 2003  Alan DeKok <aland@freeradius.org>
25  * Copyright 2003  Michael Richardson <mcr@sandelman.ottawa.on.ca>
26  */
27 /*
28  *  EAP PACKET FORMAT
29  *  --- ------ ------
30  *  0                   1                   2                   3
31  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
32  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33  * |     Code      |  Identifier   |            Length             |
34  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35  * |    Data ...
36  * +-+-+-+-+
37  *
38  *
39  * EAP Request and Response Packet Format
40  * --- ------- --- -------- ------ ------
41  *  0                   1                   2                   3
42  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
43  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44  * |     Code      |  Identifier   |            Length             |
45  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46  * |     Type      |  Type-Data ...
47  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
48  *
49  *
50  * EAP Success and Failure Packet Format
51  * --- ------- --- ------- ------ ------
52  *  0                   1                   2                   3
53  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
54  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55  * |     Code      |  Identifier   |            Length             |
56  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57  *
58  */
59
60 #include "libradius.h"
61 #include "eap_types.h"
62
63 static const char rcsid[] = "$Id$";
64
65 static const char *eap_types[] = {
66   "",
67   "identity",
68   "notification",
69   "nak",                        /* NAK */
70   "md5",
71   "otp",
72   "gtc",
73   "7",
74   "8",
75   "9",
76   "10",
77   "11",
78   "12",
79   "tls",                        /* 13 */
80   "14",
81   "15",
82   "16",
83   "leap",                       /* 17 */
84   "sim",                        /* 18 GSM-SIM authentication */
85   "19",
86   "20",
87   "ttls",                       /* 21 */
88   "22",
89   "23",
90   "24",
91   "peap",                       /* 25 */
92   "mschapv2",                   /* 26 */
93   "27",
94   "28",
95   "cisco_mschapv2"              /* 29 */
96 };
97 #define MAX_EAP_TYPE_NAME 29
98
99 /*
100  *      Return an EAP-Type for a particular name.
101  */
102 int eaptype_name2type(const char *name)
103 {
104         int i;
105
106         for (i = 0; i <= PW_EAP_MAX_TYPES; i++) {
107                 if (strcmp(name, eap_types[i]) == 0) {
108                         return i;
109                 }
110         }
111
112         return -1;
113 }
114
115 /*
116  *      Returns a text string containing the name of the EAP type.
117  */
118 const char *eaptype_type2name(unsigned int type, char *buffer, size_t buflen)
119 {
120         DICT_VALUE      *dval;
121
122         if (type > MAX_EAP_TYPE_NAME) {
123                 /*
124                  *      Prefer the dictionary name over a number,
125                  *      if it exists.
126                  */
127                 dval = dict_valbyattr(PW_EAP_TYPE, type);
128                 if (dval) {
129                         snprintf(buffer, buflen, "%s", dval->name);
130                 }
131
132                 snprintf(buffer, buflen, "%d", type);
133                 return buffer;
134         } else if ((*eap_types[type] >= '0') && (*eap_types[type] <= '9')) {
135                 /*
136                  *      Prefer the dictionary name, if it exists.
137                  */
138                 dval = dict_valbyattr(PW_EAP_TYPE, type);
139                 if (dval) {
140                         snprintf(buffer, buflen, "%s", dval->name);
141                         return buffer;
142                 } /* else it wasn't in the dictionary */
143         } /* else the name in the array was non-numeric */
144
145         /*
146          *      Return the name, whatever it is.
147          */
148         return eap_types[type];
149 }
150
151 /*
152  *      EAP packet format to be sent over the wire
153  *
154  *      i.e. code+id+length+data where data = null/type+typedata
155  *      based on code.
156  *
157  * INPUT to function is reply->code
158  *                      reply->id
159  *                      reply->type   - setup with data
160  *
161  * OUTPUT reply->packet is setup with wire format, and will
162  *                      be malloc()'ed to the right size.
163  *
164  */
165 static int eap_wireformat(EAP_PACKET *reply)
166 {
167
168         eap_packet_t    *hdr;
169         uint16_t total_length = 0;
170
171         if (reply == NULL) return EAP_INVALID;
172
173         /*
174          * if reply->packet is set, then the wire format
175          * has already been calculated, just succeed!
176          */
177         if(reply->packet != NULL)
178         {
179                 return EAP_VALID;
180         }
181
182         total_length = EAP_HEADER_LEN;
183         if (reply->code < 3) {
184                 total_length += 1/*EAPtype*/;
185                 if (reply->type.data && reply->type.length > 0) {
186                         total_length += reply->type.length;
187                 }
188         }
189
190         reply->packet = (unsigned char *)malloc(total_length);
191         hdr = (eap_packet_t *)reply->packet;
192         if (!hdr) {
193                 radlog(L_ERR, "rlm_eap: out of memory");
194                 return EAP_INVALID;
195         }
196
197         hdr->code = (reply->code & 0xFF);
198         hdr->id = (reply->id & 0xFF);
199         total_length = htons(total_length);
200         memcpy(hdr->length, &total_length, sizeof(uint16_t));
201
202         /*
203          *      Request and Response packets are special.
204          */
205         if ((reply->code == PW_EAP_REQUEST) ||
206             (reply->code == PW_EAP_RESPONSE)) {
207                 hdr->data[0] = (reply->type.type & 0xFF);
208
209                 /*
210                  * Here since we cannot know the typedata format and length
211                  *
212                  * Type_data is expected to be wired by each EAP-Type
213                  *
214                  * Zero length/No typedata is supported as long as
215                  * type is defined
216                  */
217                 if (reply->type.data && reply->type.length > 0) {
218                         memcpy(&hdr->data[1], reply->type.data, reply->type.length);
219                         free(reply->type.data);
220                         reply->type.data = reply->packet + EAP_HEADER_LEN + 1/*EAPtype*/;
221                 }
222         }
223
224         return EAP_VALID;
225 }
226
227 /*
228  *      compose EAP reply packet in EAP-Message attr of RADIUS.  If
229  *      EAP exceeds 253, frame it in multiple EAP-Message attrs.
230  */
231 int eap_basic_compose(RADIUS_PACKET *packet, EAP_PACKET *reply)
232 {
233         uint16_t eap_len, len;
234         VALUE_PAIR *eap_msg;
235         VALUE_PAIR *vp;
236         eap_packet_t *eap_packet;
237         unsigned char   *ptr;
238         int rcode;
239
240         if (eap_wireformat(reply) == EAP_INVALID) {
241                 return RLM_MODULE_INVALID;
242         }
243         eap_packet = (eap_packet_t *)reply->packet;
244
245         memcpy(&eap_len, &(eap_packet->length), sizeof(uint16_t));
246         len = eap_len = ntohs(eap_len);
247         ptr = (unsigned char *)eap_packet;
248
249         pairdelete(&(packet->vps), PW_EAP_MESSAGE);
250
251         do {
252                 if (eap_len > 253) {
253                         len = 253;
254                         eap_len -= 253;
255                 } else {
256                         len = eap_len;
257                         eap_len = 0;
258                 }
259
260                 /*
261                  * create a value pair & append it to the packet list
262                  * This memory gets freed up when packet is freed up
263                  */
264                 eap_msg = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS);
265                 memcpy(eap_msg->strvalue, ptr, len);
266                 eap_msg->length = len;
267                 pairadd(&(packet->vps), eap_msg);
268                 ptr += len;
269                 eap_msg = NULL;
270         } while (eap_len);
271
272         /*
273          *      EAP-Message is always associated with
274          *      Message-Authenticator but not vice-versa.
275          *
276          *      Don't add a Message-Authenticator if it's already
277          *      there.
278          */
279         vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR);
280         if (!vp) {
281                 vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
282                 memset(vp->strvalue, 0, AUTH_VECTOR_LEN);
283                 vp->length = AUTH_VECTOR_LEN;
284                 pairadd(&(packet->vps), vp);
285         }
286
287         /* Set request reply code, but only if it's not already set. */
288         rcode = RLM_MODULE_OK;
289         if (!packet->code) switch(reply->code) {
290         case PW_EAP_RESPONSE:
291         case PW_EAP_SUCCESS:
292                 packet->code = PW_AUTHENTICATION_ACK;
293                 rcode = RLM_MODULE_HANDLED;
294                 break;
295         case PW_EAP_FAILURE:
296                 packet->code = PW_AUTHENTICATION_REJECT;
297                 rcode = RLM_MODULE_REJECT;
298                 break;
299         case PW_EAP_REQUEST:
300                 packet->code = PW_ACCESS_CHALLENGE;
301                 rcode = RLM_MODULE_HANDLED;
302                 break;
303         default:
304                 /* Should never enter here */
305                 radlog(L_ERR, "rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code);
306                 packet->code = PW_AUTHENTICATION_REJECT;
307                 break;
308         }
309
310         return rcode;
311 }
312
313 /*
314  * given a radius request with some attributes in the EAP range, build
315  * them all into a single EAP-Message body.
316  *
317  * Note that this function will build multiple EAP-Message bodies
318  * if there are multiple eligible EAP-types. This is incorrect, as the
319  * recipient will in fact concatenate them.
320  *
321  * XXX - we could break the loop once we process one type. Maybe this
322  *       just deserves an assert?
323  *
324  */
325 void map_eap_types(RADIUS_PACKET *req)
326 {
327         VALUE_PAIR *vp, *vpnext;
328         int id, eapcode;
329         EAP_PACKET ep;
330         int eap_type;
331
332         vp = pairfind(req->vps, ATTRIBUTE_EAP_ID);
333         if(vp == NULL) {
334                 id = ((int)getpid() & 0xff);
335         } else {
336                 id = vp->lvalue;
337         }
338
339         vp = pairfind(req->vps, ATTRIBUTE_EAP_CODE);
340         if(vp == NULL) {
341                 eapcode = PW_EAP_REQUEST;
342         } else {
343                 eapcode = vp->lvalue;
344         }
345
346
347         for(vp = req->vps; vp != NULL; vp = vpnext) {
348                 /* save it in case it changes! */
349                 vpnext = vp->next;
350
351                 if(vp->attribute >= ATTRIBUTE_EAP_BASE &&
352                    vp->attribute < ATTRIBUTE_EAP_BASE+256) {
353                         break;
354                 }
355         }
356
357         if(vp == NULL) {
358                 return;
359         }
360
361         eap_type = vp->attribute - ATTRIBUTE_EAP_BASE;
362
363         switch(eap_type) {
364         case PW_EAP_IDENTITY:
365         case PW_EAP_NOTIFICATION:
366         case PW_EAP_NAK:
367         case PW_EAP_MD5:
368         case PW_EAP_OTP:
369         case PW_EAP_GTC:
370         case PW_EAP_TLS:
371         case PW_EAP_LEAP:
372         case PW_EAP_TTLS:
373         case PW_EAP_PEAP:
374         default:
375                 /*
376                  * no known special handling, it is just encoded as an
377                  * EAP-message with the given type.
378                  */
379
380                 /* nuke any existing EAP-Messages */
381                 pairdelete(&req->vps, PW_EAP_MESSAGE);
382
383                 memset(&ep, 0, sizeof(ep));
384                 ep.code = eapcode;
385                 ep.id   = id;
386                 ep.type.type = eap_type;
387                 ep.type.length = vp->length;
388                 ep.type.data = malloc(vp->length);
389                 memcpy(ep.type.data,vp->strvalue, vp->length);
390                 eap_basic_compose(req, &ep);
391         }
392 }
393
394 /*
395  * Handles multiple EAP-Message attrs
396  * ie concatenates all to get the complete EAP packet.
397  *
398  * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
399  *      refer fragmentation in rfc2869.
400  */
401 eap_packet_t *eap_attribute(VALUE_PAIR *vps)
402 {
403         VALUE_PAIR *first, *vp;
404         eap_packet_t *eap_packet;
405         unsigned char *ptr;
406         uint16_t len;
407         int total_len;
408
409         /*
410          *      Get only EAP-Message attribute list
411          */
412         first = pairfind(vps, PW_EAP_MESSAGE);
413         if (first == NULL) {
414                 radlog(L_ERR, "rlm_eap: EAP-Message not found");
415                 return NULL;
416         }
417
418         /*
419          *      Sanity check the length before doing anything.
420          */
421         if (first->length < 4) {
422                 radlog(L_ERR, "rlm_eap: EAP packet is too short.");
423                 return NULL;
424         }
425
426         /*
427          *      Get the Actual length from the EAP packet
428          *      First EAP-Message contains the EAP packet header
429          */
430         memcpy(&len, first->strvalue + 2, sizeof(len));
431         len = ntohs(len);
432
433         /*
434          *      Take out even more weird things.
435          */
436         if (len < 4) {
437                 radlog(L_ERR, "rlm_eap: EAP packet has invalid length.");
438                 return NULL;
439         }
440
441         /*
442          *      Sanity check the length, BEFORE malloc'ing memory.
443          */
444         total_len = 0;
445         for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE)) {
446                 total_len += vp->length;
447
448                 if (total_len > len) {
449                         radlog(L_ERR, "rlm_eap: Malformed EAP packet.  Length in packet header does not match actual length");
450                         return NULL;
451                 }
452         }
453
454         /*
455          *      If the length is SMALLER, die, too.
456          */
457         if (total_len < len) {
458                 radlog(L_ERR, "rlm_eap: Malformed EAP packet.  Length in packet header does not match actual length");
459                 return NULL;
460         }
461
462         /*
463          *      Now that we know the lengths are OK, allocate memory.
464          */
465         eap_packet = (eap_packet_t *) malloc(len);
466         if (eap_packet == NULL) {
467                 radlog(L_ERR, "rlm_eap: out of memory");
468                 return NULL;
469         }
470
471         /*
472          *      Copy the data from EAP-Message's over to out EAP packet.
473          */
474         ptr = (unsigned char *)eap_packet;
475
476         /* RADIUS ensures order of attrs, so just concatenate all */
477         for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE)) {
478                 memcpy(ptr, vp->strvalue, vp->length);
479                 ptr += vp->length;
480         }
481
482         return eap_packet;
483 }
484
485 /*
486  * given a radius request with an EAP-Message body, decode it specific
487  * attributes.
488  */
489 void unmap_eap_types(RADIUS_PACKET *rep)
490 {
491         VALUE_PAIR *eap1;
492         eap_packet_t *e;
493         int len;
494         int type;
495
496         /* find eap message */
497         e = eap_attribute(rep->vps);
498
499         /* nothing to do! */
500         if(e == NULL) return;
501
502         /* create EAP-ID and EAP-CODE attributes to start */
503         eap1 = paircreate(ATTRIBUTE_EAP_ID, PW_TYPE_INTEGER);
504         eap1->lvalue = e->id;
505         pairadd(&(rep->vps), eap1);
506
507         eap1 = paircreate(ATTRIBUTE_EAP_CODE, PW_TYPE_INTEGER);
508         eap1->lvalue = e->code;
509         pairadd(&(rep->vps), eap1);
510
511         switch(e->code)
512         {
513         default:
514         case PW_EAP_SUCCESS:
515         case PW_EAP_FAILURE:
516                 /* no data */
517                 break;
518
519         case PW_EAP_REQUEST:
520         case PW_EAP_RESPONSE:
521                 /* there is a type field, which we use to create
522                  * a new attribute */
523
524                 /* the length was decode already into the attribute
525                  * length, and was checked already. Network byte
526                  * order, just pull it out using math.
527                  */
528                 len = e->length[0]*256 + e->length[1];
529
530                 /* verify the length is big enough to hold type */
531                 if(len < 5)
532                 {
533                         return;
534                 }
535
536                 type = e->data[0];
537
538                 type += ATTRIBUTE_EAP_BASE;
539                 len -= 5;
540
541                 if(len > MAX_STRING_LEN) {
542                         len = MAX_STRING_LEN;
543                 }
544
545                 eap1 = paircreate(type, PW_TYPE_OCTETS);
546                 memcpy(eap1->strvalue, &e->data[1], len);
547                 eap1->length = len;
548                 pairadd(&(rep->vps), eap1);
549                 break;
550         }
551
552         return;
553 }
554