update otp_hotp() to support 6,7,8,9 digit otp's
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_psk / rlm_eap_psk.cpp
1 /* $Id$ */
2
3 /*
4  * rlm_eap_psk.cpp
5  *
6  * Implementation of the interface between the radius server and 
7  * the eap-psk protocol
8  *
9  * 
10  * Copyright (C) France Télécom R&D (DR&D/MAPS/NSS)
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25  *
26  */
27
28
29
30 #include "autoconf.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34
35
36 #include "eap_psk.h"
37 #include "eap_psk_ssm.h"
38
39 static CONF_PARSER moduleConfig[] = {
40         { "private_key", PW_TYPE_STRING_PTR,
41           offsetof(PSK_CONF, privateKey), NULL, NULL },
42         { "server_name", PW_TYPE_STRING_PTR,
43           offsetof(PSK_CONF, id_s), NULL, "pskserver" },
44         { "peer_nai_attribute", PW_TYPE_STRING_PTR,
45           offsetof(PSK_CONF, peerNaiAttribute), NULL, "eapPskPeerNAI" },
46         { "peer_key_attribute", PW_TYPE_STRING_PTR,
47           offsetof(PSK_CONF, peerKeyAttribute), NULL, "eapPskPeerKey" },
48         { "users_file_path", PW_TYPE_STRING_PTR,
49           offsetof(PSK_CONF, usersFilePath), NULL, "/etc/raddb/users.psk" },
50         { "nb_retry", PW_TYPE_INTEGER,
51           offsetof(PSK_CONF, nbRetry), NULL, "3" },
52         { "max_delay", PW_TYPE_INTEGER,
53           offsetof(PSK_CONF, maxDelay), NULL, "5" },
54         { NULL, -1, 0, NULL, NULL }           /* end the list */
55 };
56
57
58 /** 
59  *@memo         this function add value pair to reply
60  */
61 static void addReply(VALUE_PAIR** vp, 
62                       const char* name, unsigned char* value, int len)
63 {
64         VALUE_PAIR *reply_attr;
65         reply_attr = pairmake(name, "", T_OP_EQ);
66         if (!reply_attr) {
67                 DEBUG("rlm_eap_psk: "
68                       "add_reply failed to create attribute %s: %s\n", 
69                       name, librad_errstr);
70                 return;
71         }
72
73         memcpy(reply_attr->vp_octets, value, len);
74         reply_attr->length = len;
75         pairadd(vp, reply_attr);
76 }
77
78 /*
79  *@memo         this function detaches the module
80  */
81 static int pskDetach(void *arg)
82 {
83         PSK_CONF *inst = (PSK_CONF *) arg;
84
85         if (inst->privateKey) free(inst->privateKey);
86         if (inst->id_s) free(inst->id_s);
87         if (inst->peerNaiAttribute) free(inst->peerNaiAttribute);
88         if (inst->peerKeyAttribute) free(inst->peerKeyAttribute);
89         if(inst->usersFilePath) free(inst->usersFilePath);
90
91         free(inst);
92
93         return 0;
94 }
95
96
97 /*
98  *@memo          this function attaches the module
99  */
100 static int pskAttach(CONF_SECTION *cs, void **instance)
101 {
102         PSK_CONF *inst;
103
104         inst = (PSK_CONF*)malloc(sizeof(*inst));
105         if (!inst) {
106                 radlog(L_ERR, "rlm_eap_psk: out of memory");
107                 return -1;
108         }
109         memset(inst, 0, sizeof(*inst));
110
111         // parse the configuration attributes
112         if (cf_section_parse(cs, inst, moduleConfig) < 0) {
113           pskDetach(inst);
114           return -1;
115         }
116         
117         *instance = inst;
118         return 0;
119 }
120
121
122
123 /** 
124  *@memo         this function begins the conversation when the EAP-Identity response is received
125  *              send an initial eap-psk request, ie IDREQ
126  *@param        handler, pointer to specific information about the eap-psk protocol
127  */
128 static int pskInitiate(void *type_arg, EAP_HANDLER *handler)
129 {
130   PSK_SESSION *session;
131   PSK_CONF *conf=(PSK_CONF*)type_arg;
132
133   if(conf==NULL)
134     {
135       radlog(L_ERR,"rlm_eap_psk: Cannot initiate EAP-PSK without having its configuration");
136       return 0;
137     }
138
139   DEBUG2("rlm_eap_psk: privateKey: %s",conf->privateKey);
140   DEBUG2("rlm_eap_psk: id_s: %s", conf->id_s);
141   DEBUG2("rlm_eap_psk: peerNaiAttribute: %s", conf->peerNaiAttribute);
142   DEBUG2("rlm_eap_psk: peerKeyAttribute: %s", conf->peerKeyAttribute);
143   DEBUG2("rlm_eap_psk: usersFilePath: %s", conf->usersFilePath);
144
145   // allocate memory in order to save the state of session
146   handler->opaque=malloc(sizeof(PSK_SESSION));
147   if(!handler->opaque) {
148     radlog(L_ERR,"rlm_eap_psk: Out of memory");
149     return 0;
150   }
151
152   // save this pointer in the handler
153   session=(PSK_SESSION *)handler->opaque;
154   handler->free_opaque=pskFreeSession;
155
156   // initializing session information
157   memset(session,0,sizeof(PSK_SESSION));
158   session->state=INIT;
159    
160   handler->stage=AUTHENTICATE;
161
162   // initiate the eap-psk protocol
163   return pskProcess(conf,session,NULL,handler->eap_ds->request);
164   
165 }
166
167
168
169
170 /** 
171  *@memo         this function uses specific EAP-Type authentication mechanism to authenticate the user
172  *              may be called many times
173  *@param        handler, pointer to specific information about the eap-psk protocol
174  */
175 static int pskAuthenticate(void *arg, EAP_HANDLER *handler)
176 {
177   PSK_SESSION *session;
178   PSK_CONF *conf=(PSK_CONF*)arg;
179   int resul;
180   
181   if(conf==NULL)
182     {
183       radlog(L_ERR,"rlm_eap_psk: Cannot authenticate without having EAP-PSK configuration");
184       return 0;
185     }
186   
187   if(!handler->opaque) {
188     radlog(L_ERR,"rlm_eap_psk: Cannot authenticate without EAP-PSK session information");
189     return 0;
190   }
191   
192   // find the session information
193   session=(PSK_SESSION *)handler->opaque;
194
195   resul=pskProcess(conf,session,handler->eap_ds->response,handler->eap_ds->request);
196   
197   if(handler->eap_ds->request->code==PW_EAP_SUCCESS) {
198     // sending keys
199     addReply(&handler->request->reply->vps,"MS-MPPE-Recv-Key",session->msk,32);
200     addReply(&handler->request->reply->vps,"MS-MPPE-Send-Key",&session->msk[32],32);
201   }
202   
203   return resul;
204   
205 }
206
207
208 EAP_TYPE rlm_eap_psk = {
209         "eap_psk",
210         pskAttach,              // attach
211         pskInitiate,            // Start the initial request, after Identity
212         NULL,
213         pskAuthenticate,        // authentication
214         pskDetach               // detach
215 };