Fix compiler warnings
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_pwd / rlm_eap_pwd.c
1 /*
2  * Copyright (c) Dan Harkins, 2012
3  *
4  *  Copyright holder grants permission for redistribution and use in source 
5  *  and binary forms, with or without modification, provided that the 
6  *  following conditions are met:
7  *     1. Redistribution of source code must retain the above copyright
8  *        notice, this list of conditions, and the following disclaimer
9  *        in all source files.
10  *     2. Redistribution in binary form must retain the above copyright
11  *        notice, this list of conditions, and the following disclaimer
12  *        in the documentation and/or other materials provided with the
13  *        distribution.
14  *
15  *  "DISCLAIMER OF LIABILITY
16  *  
17  *  THIS SOFTWARE IS PROVIDED BY DAN HARKINS ``AS IS'' AND
18  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
19  *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
20  *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INDUSTRIAL LOUNGE BE LIABLE
21  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
23  *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  *  SUCH DAMAGE."
28  *
29  * This license and distribution terms cannot be changed. In other words,
30  * this code cannot simply be copied and put under a different distribution
31  * license (including the GNU public license).
32  */
33
34 #include <freeradius-devel/ident.h>
35 RCSID("$Id$")
36
37 #include "rlm_eap_pwd.h"
38
39 #include "eap_pwd.h"
40
41 #define MSK_EMSK_LEN    64
42 #define MPPE_KEY_LEN    32
43
44 static CONF_PARSER pwd_module_config[] = {
45     { "group", PW_TYPE_INTEGER,
46       offsetof(EAP_PWD_CONF, group), NULL, "19"},
47     { "fragment_size", PW_TYPE_INTEGER,
48       offsetof(EAP_PWD_CONF, fragment_size), NULL, "1020"},
49     { "server_id", PW_TYPE_STRING_PTR,
50       offsetof(EAP_PWD_CONF, server_id), NULL, NULL },
51     { "virtual_server", PW_TYPE_STRING_PTR,
52       offsetof(EAP_PWD_CONF, virtual_server), NULL, NULL },
53     { NULL, -1, 0, NULL, NULL }
54 };
55
56 /*
57  * stolen from rlm_eap_sim: Add value pair to reply
58  */
59 static void add_reply(VALUE_PAIR** vp,
60                       const char* name, const uint8_t *value, size_t len)
61 {
62     VALUE_PAIR *reply_attr;
63     reply_attr = pairmake(name, "", T_OP_EQ);
64     if (!reply_attr) {
65         DEBUG("rlm_eap_pwd: "
66               "add_reply failed to create attribute %s: %s\n",
67               name, fr_strerror());
68         return;
69     }
70
71     memcpy(reply_attr->vp_strvalue, value, len);
72     reply_attr->length = len;
73     pairadd(vp, reply_attr);
74 }
75
76 static int
77 eap_pwd_detach (void *arg)
78 {
79     eap_pwd_t *inst;
80
81     inst = (eap_pwd_t *) arg;
82
83     if (inst->bnctx) {
84         BN_CTX_free(inst->bnctx);
85     }
86
87     return 0;
88 }
89
90 static int
91 eap_pwd_attach (CONF_SECTION *cs, void **instance)
92 {
93     eap_pwd_t *inst;
94
95     *instance = inst = talloc_zero(cs, eap_pwd_t);
96     if (!inst) return -1;
97
98     inst->conf = talloc_zero(inst, EAP_PWD_CONF);
99     if (!inst->conf) return -1;
100
101     if (cf_section_parse(cs, inst->conf, pwd_module_config) < 0) {
102         return -1;
103     }
104
105     if ((inst->bnctx = BN_CTX_new()) == NULL) {
106         radlog(L_ERR, "rlm_eap_pwd: failed to get BN context!");
107         return -1;
108     }
109
110     return 0;
111 }
112
113 static void
114 free_session (void *data)
115 {
116     pwd_session_t *session = (pwd_session_t *)data;
117
118     if (session == NULL) {
119         radlog(L_ERR, "rlm_eap_pwd: freeing a NULL session...naughty, naughty");
120         return;
121     }
122     BN_free(session->private_value);
123     BN_free(session->peer_scalar);
124     BN_free(session->my_scalar);
125     BN_free(session->k);
126     EC_POINT_free(session->my_element);
127     EC_POINT_free(session->peer_element);
128     EC_GROUP_free(session->group);
129     EC_POINT_free(session->pwe);
130     BN_free(session->order);
131     BN_free(session->prime);
132
133     free(session);
134 }
135
136 static int
137 send_pwd_request (pwd_session_t *sess, EAP_DS *eap_ds)
138 {
139     int len;
140     uint16_t totlen;
141     pwd_hdr *hdr;
142
143     len = (sess->out_buf_len - sess->out_buf_pos) + sizeof(pwd_hdr);
144     rad_assert(len > 0);
145     eap_ds->request->code = PW_EAP_REQUEST;
146     eap_ds->request->type.type = PW_EAP_PWD;
147     eap_ds->request->type.length = (len > sess->mtu) ? sess->mtu : len;
148     eap_ds->request->type.data = malloc(eap_ds->request->type.length);
149     memset(eap_ds->request->type.data, 0, eap_ds->request->type.length);
150
151     hdr = (pwd_hdr *)eap_ds->request->type.data;
152     switch (sess->state) {
153         case PWD_STATE_ID_REQ:
154             EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_ID);
155             break;
156         case PWD_STATE_COMMIT:
157             EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_COMMIT);
158             break;
159         case PWD_STATE_CONFIRM:
160             EAP_PWD_SET_EXCHANGE(hdr, EAP_PWD_EXCH_CONFIRM);
161             break;
162         default:
163             DEBUG2("pwd state is messed up! Cannot send request");
164             return 0;
165     }
166     /*
167      * are we fragmenting?
168      */
169     if ((int)((sess->out_buf_len - sess->out_buf_pos) + sizeof(pwd_hdr)) > sess->mtu) {
170         EAP_PWD_SET_MORE_BIT(hdr);
171         if (sess->out_buf_pos == 0) {
172             /*
173              * the first fragment, add the total length
174              */
175             EAP_PWD_SET_LENGTH_BIT(hdr);
176             totlen = ntohs(sess->out_buf_len);
177             memcpy(hdr->data, (char *)&totlen, sizeof(totlen));
178             memcpy(hdr->data + sizeof(uint16_t),
179                    sess->out_buf,
180                    sess->mtu - sizeof(pwd_hdr) - sizeof(uint16_t));
181             sess->out_buf_pos += (sess->mtu - sizeof(pwd_hdr) - sizeof(uint16_t));
182         } else {
183             /*
184              * an intermediate fragment
185              */
186             memcpy(hdr->data, sess->out_buf + sess->out_buf_pos, (sess->mtu - sizeof(pwd_hdr)));
187             sess->out_buf_pos += (sess->mtu - sizeof(pwd_hdr));
188         }
189     } else {
190         /*
191          * either it's not a fragment or it's the last fragment. 
192          * The out buffer isn't needed anymore though so get rid of it.
193          */
194         memcpy(hdr->data, sess->out_buf + sess->out_buf_pos, 
195                (sess->out_buf_len - sess->out_buf_pos));
196         free(sess->out_buf);
197         sess->out_buf = NULL;
198         sess->out_buf_pos = sess->out_buf_len = 0;
199     }
200     return 1;
201 }
202
203 static int
204 eap_pwd_initiate (void *type_data, EAP_HANDLER *handler)
205 {
206     pwd_session_t *pwd_session;
207     eap_pwd_t *inst = (eap_pwd_t *)type_data;
208     VALUE_PAIR *vp;
209     pwd_id_packet *pack;
210     
211     if (!inst || !handler) {
212         radlog(L_ERR, "rlm_eap_pwd: initiate, NULL data provided");
213         return -1;
214     }
215
216     /*
217      * make sure the server's been configured properly
218      */
219     if (inst->conf->server_id == NULL) {
220         radlog(L_ERR, "rlm_eap_pwd: server ID is not configured!");
221         return -1;
222     }
223     switch (inst->conf->group) {
224         case 19:
225         case 20:
226         case 21:
227         case 25:
228         case 26:
229             break;
230         default:
231             radlog(L_ERR, "rlm_eap_pwd: group is not supported!");
232             return -1;
233     }
234
235     if ((pwd_session = (pwd_session_t *)malloc(sizeof(*pwd_session))) == NULL) {
236         radlog(L_ERR, "rlm_eap_pwd: initiate, out of memory (1)");
237         return -1;
238     }
239     /*
240      * set things up so they can be free'd reliably
241      */
242     pwd_session->group_num = inst->conf->group;
243     pwd_session->private_value = NULL;
244     pwd_session->peer_scalar = NULL;
245     pwd_session->my_scalar = NULL;
246     pwd_session->k = NULL;
247     pwd_session->my_element = NULL;
248     pwd_session->peer_element = NULL;
249     pwd_session->group = NULL;
250     pwd_session->pwe = NULL;
251     pwd_session->order = NULL;
252     pwd_session->prime = NULL;
253
254     /*
255      * figure out the MTU (basically do what eap-tls does)
256      */
257     pwd_session->mtu = inst->conf->fragment_size;
258     vp = pairfind(handler->request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY);
259     if (vp && ((int)(vp->vp_integer - 9) < pwd_session->mtu)) {
260         /*
261          * 9 = 4 (EAPOL header) + 4 (EAP header) + 1 (EAP type)
262          *
263          * the fragmentation code deals with the included length
264          * so we don't need to subtract that here.
265          */
266         pwd_session->mtu = vp->vp_integer - 9;
267     }
268
269     pwd_session->state = PWD_STATE_ID_REQ;
270     pwd_session->in_buf = NULL;
271     pwd_session->out_buf_pos = 0;
272     handler->opaque = pwd_session;
273     handler->free_opaque = free_session;
274
275     /*
276      * construct an EAP-pwd-ID/Request
277      */
278     pwd_session->out_buf_len = sizeof(pwd_id_packet) + strlen(inst->conf->server_id);
279     if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
280         radlog(L_ERR, "rlm_eap_pwd: initiate, out of memory to send ID request");
281         return -1;
282     }
283     memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);
284
285     pack = (pwd_id_packet *)pwd_session->out_buf;
286     pack->group_num = htons(pwd_session->group_num);
287     pack->random_function = EAP_PWD_DEF_RAND_FUN;
288     pack->prf = EAP_PWD_DEF_PRF;
289     pwd_session->token = random();
290     memcpy(pack->token, (char *)&pwd_session->token, 4);
291     pack->prep = EAP_PWD_PREP_NONE;
292     strcpy(pack->identity, inst->conf->server_id);
293
294     handler->stage = AUTHENTICATE;
295
296     return send_pwd_request(pwd_session, handler->eap_ds);
297 }
298
299 static int
300 eap_pwd_authenticate (void *arg, EAP_HANDLER *handler)
301 {
302     pwd_session_t *pwd_session;
303     pwd_hdr *hdr;
304     pwd_id_packet *id;
305     EAP_PACKET *response;
306     REQUEST *request, *fake;
307     VALUE_PAIR *pw, **outvps, *vp;
308     EAP_DS *eap_ds;
309     int len, ret = 0;
310     eap_pwd_t *inst = (eap_pwd_t *)arg;
311     uint16_t offset;
312     uint8_t exch, *buf, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN];
313     uint8_t peer_confirm[SHA256_DIGEST_LENGTH];
314     BIGNUM *x = NULL, *y = NULL;
315
316     if ((handler == NULL) || 
317         ((eap_ds = handler->eap_ds) == NULL) ||
318         (inst == NULL)) {
319         return 0;
320     }
321     pwd_session = (pwd_session_t *)handler->opaque;
322     request = handler->request;
323     response = handler->eap_ds->response;
324     hdr = (pwd_hdr *)response->type.data;
325
326     buf = hdr->data;
327     len = response->type.length - sizeof(pwd_hdr);
328
329     /*
330      * see if we're fragmenting, if so continue until we're done
331      */
332     if (pwd_session->out_buf_pos) {
333         if (len) {
334             RDEBUG2("pwd got something more than an ACK for a fragment");
335         }
336         return send_pwd_request(pwd_session, eap_ds);
337     }
338
339     /*
340      * the first fragment will have a total length, make a
341      * buffer to hold all the fragments
342      */
343     if (EAP_PWD_GET_LENGTH_BIT(hdr)) {
344         if (pwd_session->in_buf) {
345             RDEBUG2("pwd already alloced buffer for fragments");
346             return 0;
347         }
348         pwd_session->in_buf_len = ntohs(buf[0] * 256 | buf[1]);
349         if ((pwd_session->in_buf = malloc(pwd_session->in_buf_len)) == NULL) {
350             RDEBUG2("pwd cannot malloc %d buffer to hold fragments",
351                     pwd_session->in_buf_len);
352             return 0;
353         }
354         memset(pwd_session->in_buf, 0, pwd_session->in_buf_len);
355         pwd_session->in_buf_pos = 0;
356         buf += sizeof(uint16_t);
357         len -= sizeof(uint16_t);
358     }
359
360     /*
361      * all fragments, including the 1st will have the M(ore) bit set,
362      * buffer those fragments!
363      */
364     if (EAP_PWD_GET_MORE_BIT(hdr)) {
365         rad_assert(pwd_session->in_buf != NULL);
366         if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
367             RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
368             return 0;
369         }
370         memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
371         pwd_session->in_buf_pos += len;
372
373         /*
374          * send back an ACK for this fragment
375          */
376         exch = EAP_PWD_GET_EXCHANGE(hdr);
377         eap_ds->request->code = PW_EAP_REQUEST;
378         eap_ds->request->type.type = PW_EAP_PWD;
379         eap_ds->request->type.length = sizeof(pwd_hdr);
380         if ((eap_ds->request->type.data = malloc(sizeof(pwd_hdr))) == NULL) {
381             radlog(L_ERR, "rlm_eap_pwd: fragment ACK, out of memory");
382             return 0;
383         }
384         hdr = (pwd_hdr *)eap_ds->request->type.data;
385         EAP_PWD_SET_EXCHANGE(hdr, exch);
386         return 1;
387
388     }
389
390     if (pwd_session->in_buf) {
391         /*
392          * the last fragment...
393          */
394         if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) {
395             RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent.");
396             return 0;
397         }
398         memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len);
399         buf = pwd_session->in_buf;
400         len = pwd_session->in_buf_len;
401     }
402
403     switch (pwd_session->state) {
404         case PWD_STATE_ID_REQ:
405             if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) {
406                 RDEBUG2("pwd exchange is incorrect: not ID");
407                 return 0;
408             }
409             id = (pwd_id_packet *)buf;
410             if ((id->prf != EAP_PWD_DEF_PRF) ||
411                 (id->random_function != EAP_PWD_DEF_RAND_FUN) ||
412                 (id->prep != EAP_PWD_PREP_NONE) ||
413                 (memcmp(id->token, (char *)&pwd_session->token, 4)) ||
414                 (id->group_num != ntohs(pwd_session->group_num))) {
415                 RDEBUG2("pwd id response is invalid");
416                 return 0;
417             }
418             /*
419              * we've agreed on the ciphersuite, record it...
420              */
421             ptr = (uint8_t *)&pwd_session->ciphersuite;
422             memcpy(ptr, (char *)&id->group_num, sizeof(uint16_t));
423             ptr += sizeof(uint16_t);
424             *ptr = EAP_PWD_DEF_RAND_FUN;
425             ptr += sizeof(uint8_t);
426             *ptr = EAP_PWD_DEF_PRF;
427             
428             pwd_session->peer_id_len = len - sizeof(pwd_id_packet);
429             if (pwd_session->peer_id_len >= sizeof(pwd_session->peer_id)) {
430                 RDEBUG2("pwd id response is malformed");
431                 return 0;
432             }
433             memcpy(pwd_session->peer_id, id->identity,
434                     pwd_session->peer_id_len);
435             pwd_session->peer_id[pwd_session->peer_id_len] = '\0';
436
437             /*
438              * make fake request to get the password for the usable ID
439              */
440             if ((fake = request_alloc_fake(handler->request)) == NULL) {
441                 RDEBUG("pwd unable to create fake request!");
442                 return 0;
443             }
444             if ((fake->username = pairmake("User-Name", "", T_OP_EQ)) == NULL) {
445                 RDEBUG("pwd unanable to create value pair for username!");
446                 request_free(&fake);
447                 return 0;
448             }
449             memcpy(fake->username->vp_strvalue, pwd_session->peer_id, 
450                    pwd_session->peer_id_len);
451             fake->username->length = pwd_session->peer_id_len;
452             fake->username->vp_strvalue[fake->username->length] = 0;
453
454             if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
455                     fake->server = vp->vp_strvalue;
456                     
457             } else if (inst->conf->virtual_server) {
458                     fake->server = inst->conf->virtual_server;
459                     
460             } /* else fake->server == request->server */
461             
462             if ((debug_flag > 0) && fr_log_fp) {
463                     RDEBUG("Sending tunneled request");
464                     
465                     debug_pair_list(fake->packet->vps);
466                     
467                     fprintf(fr_log_fp, "server %s {\n",
468                             (fake->server == NULL) ? "" : fake->server);
469             }
470             
471             /*
472              *  Call authorization recursively, which will
473              *  get the password.
474              */
475             module_authorize(0, fake);
476             
477             /*
478              *  Note that we don't do *anything* with the reply
479              *  attributes.
480              */
481             if ((debug_flag > 0) && fr_log_fp) {
482                     fprintf(fr_log_fp, "} # server %s\n",
483                             (fake->server == NULL) ? "" : fake->server);
484                     
485                     RDEBUG("Got tunneled reply code %d", fake->reply->code);
486                     
487                     debug_pair_list(fake->reply->vps);
488             }
489
490             if ((pw = pairfind(fake->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) {
491                 DEBUG2("failed to find password for %s to do pwd authentication",
492                        pwd_session->peer_id);
493                 request_free(&fake);
494                 return 0;
495             }
496
497             if (compute_password_element(pwd_session, pwd_session->group_num,
498                                          pw->data.strvalue, strlen(pw->data.strvalue),
499                                          inst->conf->server_id, strlen(inst->conf->server_id),
500                                          pwd_session->peer_id, strlen(pwd_session->peer_id),
501                                          &pwd_session->token)) {
502                 DEBUG2("failed to obtain password element :-(");
503                 request_free(&fake);
504                 return 0;
505             }
506             request_free(&fake);
507
508             /*
509              * compute our scalar and element
510              */
511             if (compute_scalar_element(pwd_session, inst->bnctx)) {
512                 DEBUG2("failed to compute server's scalar and element");
513                 return 0;
514             }
515             if (((x = BN_new()) == NULL) ||
516                 ((y = BN_new()) == NULL)) {
517                 DEBUG2("server point allocation failed");
518                 return 0;
519             }
520             /*
521              * element is a point, get both coordinates: x and y
522              */
523             if (!EC_POINT_get_affine_coordinates_GFp(pwd_session->group,
524                                                      pwd_session->my_element, x, y,
525                                                      inst->bnctx)) {
526                 DEBUG2("server point assignment failed");
527                 BN_free(x);
528                 BN_free(y);
529                 return 0;
530             }
531             /*
532              * construct request
533              */
534             pwd_session->out_buf_len = BN_num_bytes(pwd_session->order) + 
535                 (2 * BN_num_bytes(pwd_session->prime));
536             if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
537                 radlog(L_ERR, "rlm_eap_pwd: out of memory to send commit");
538                 return 0;
539             }
540             memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);
541
542             ptr = pwd_session->out_buf;
543             offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(x);
544             BN_bn2bin(x, ptr + offset);
545
546             ptr += BN_num_bytes(pwd_session->prime);
547             offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(y);
548             BN_bn2bin(y, ptr + offset);
549             
550             ptr += BN_num_bytes(pwd_session->prime);
551             offset = BN_num_bytes(pwd_session->order) - BN_num_bytes(pwd_session->my_scalar);
552             BN_bn2bin(pwd_session->my_scalar, ptr + offset);
553
554             pwd_session->state = PWD_STATE_COMMIT;
555             ret = send_pwd_request(pwd_session, eap_ds);
556             break;
557         case PWD_STATE_COMMIT:
558             if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) {
559                 RDEBUG2("pwd exchange is incorrect: not commit!");
560                 return 0;
561             }
562             /*
563              * process the peer's commit and generate the shared key, k
564              */
565             if (process_peer_commit(pwd_session, buf, inst->bnctx)) {
566                 RDEBUG2("failed to process peer's commit");
567                 return 0;
568             }
569
570             /*
571              * compute our confirm blob
572              */
573             if (compute_server_confirm(pwd_session, pwd_session->my_confirm, inst->bnctx)) {
574                 radlog(L_ERR, "rlm_eap_pwd: failed to compute confirm!");
575                 return 0;
576             }
577             /*
578              * construct a response...which is just our confirm blob
579              */
580             pwd_session->out_buf_len = SHA256_DIGEST_LENGTH;
581             if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) {
582                 radlog(L_ERR, "rlm_eap_pwd: out of memory to send confirm");
583                 return 0;
584             }
585             memset(pwd_session->out_buf, 0, pwd_session->out_buf_len);
586             memcpy(pwd_session->out_buf, pwd_session->my_confirm, SHA256_DIGEST_LENGTH);
587
588             pwd_session->state = PWD_STATE_CONFIRM;
589             ret = send_pwd_request(pwd_session, eap_ds);
590             break;
591         case PWD_STATE_CONFIRM:
592             if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) {
593                 RDEBUG2("pwd exchange is incorrect: not commit!");
594                 return 0;
595             }
596             if (compute_peer_confirm(pwd_session, peer_confirm, inst->bnctx)) {
597                 RDEBUG2("pwd exchange cannot compute peer's confirm");
598                 return 0;
599             }
600             if (memcmp(peer_confirm, buf, SHA256_DIGEST_LENGTH)) {
601                 RDEBUG2("pwd exchange fails: peer confirm is incorrect!");
602                 return 0;
603             }
604             if (compute_keys(pwd_session, peer_confirm, msk, emsk)) {
605                 RDEBUG2("pwd exchange cannot generate (E)MSK!");
606                 return 0;
607             }
608             eap_ds->request->code = PW_EAP_SUCCESS;
609             /*
610              * return the MSK (in halves)
611              */
612             outvps = &handler->request->reply->vps;
613             add_reply(outvps, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN);
614             add_reply(outvps, "MS-MPPE-Send-Key", msk+MPPE_KEY_LEN, MPPE_KEY_LEN);
615             ret = 1;
616             break;
617         default:
618             RDEBUG2("unknown PWD state");
619             return 0;
620     }
621
622     /*
623      * we processed the buffered fragments, get rid of them
624      */
625     if (pwd_session->in_buf) {
626         free(pwd_session->in_buf);
627         pwd_session->in_buf = NULL;
628     }
629
630     return ret;
631 }
632
633
634 EAP_TYPE rlm_eap_pwd = {
635     "eap_pwd",
636     eap_pwd_attach,                     /* attach */
637     eap_pwd_initiate,                   /* initiate to a client */
638     NULL,                               /* no authorization */
639     eap_pwd_authenticate,               /* pwd authentication */
640     eap_pwd_detach                      /* detach */
641 };
642