Remove redundant file from freeradius-abfab list.
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_gtc / rlm_eap_gtc.c
1 /*
2  * rlm_eap_gtc.c    Handles that are called from eap
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2003,2006  The FreeRADIUS server project
21  */
22
23 RCSID("$Id$")
24
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "eap.h"
29
30 #include <freeradius-devel/rad_assert.h>
31
32 /*
33  *      EAP-GTC is just ASCII data carried inside of the EAP session.
34  *      The length of the data is indicated by the encapsulating EAP
35  *      protocol.
36  */
37 typedef struct rlm_eap_gtc_t {
38         char const      *challenge;
39         char const      *auth_type_name;
40         int             auth_type;
41 } rlm_eap_gtc_t;
42
43 static CONF_PARSER module_config[] = {
44         { "challenge", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, challenge), "Password: " },
45         { "auth_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_gtc_t, auth_type_name), "PAP" },
46         CONF_PARSER_TERMINATOR
47 };
48
49
50
51 /*
52  *      Attach the module.
53  */
54 static int mod_instantiate(CONF_SECTION *cs, void **instance)
55 {
56         rlm_eap_gtc_t   *inst;
57         DICT_VALUE      *dval;
58
59         *instance = inst = talloc_zero(cs, rlm_eap_gtc_t);
60         if (!inst) return -1;
61
62         /*
63          *      Parse the configuration attributes.
64          */
65         if (cf_section_parse(cs, inst, module_config) < 0) {
66                 return -1;
67         }
68
69         if (inst->auth_type_name && *inst->auth_type_name) {
70                 dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->auth_type_name);
71                 if (!dval) {
72                         ERROR("rlm_eap_gtc: Unknown Auth-Type %s",
73                               inst->auth_type_name);
74                         return -1;
75                 }
76
77                 inst->auth_type = dval->value;
78         } else {
79                 inst->auth_type = PW_AUTH_TYPE_LOCAL;
80         }
81         return 0;
82 }
83
84 /*
85  *      Initiate the EAP-GTC session by sending a challenge to the peer.
86  */
87 static int mod_session_init(void *instance, eap_handler_t *handler)
88 {
89         char challenge_str[1024];
90         int length;
91         EAP_DS *eap_ds = handler->eap_ds;
92         rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance;
93
94         if (radius_xlat(challenge_str, sizeof(challenge_str), handler->request, inst->challenge, NULL, NULL) < 0) {
95                 return 0;
96         }
97
98         length = strlen(challenge_str);
99
100         /*
101          *      We're sending a request...
102          */
103         eap_ds->request->code = PW_EAP_REQUEST;
104
105         eap_ds->request->type.data = talloc_array(eap_ds->request,
106                                                   uint8_t, length);
107         if (!eap_ds->request->type.data) {
108                 return 0;
109         }
110
111         memcpy(eap_ds->request->type.data, challenge_str, length);
112         eap_ds->request->type.length = length;
113
114         /*
115          *      We don't need to authorize the user at this point.
116          *
117          *      We also don't need to keep the challenge, as it's
118          *      stored in 'handler->eap_ds', which will be given back
119          *      to us...
120          */
121         handler->stage = PROCESS;
122
123         return 1;
124 }
125
126
127 /*
128  *      Authenticate a previously sent challenge.
129  */
130 static int CC_HINT(nonnull) mod_process(void *instance, eap_handler_t *handler)
131 {
132         VALUE_PAIR *vp;
133         EAP_DS *eap_ds = handler->eap_ds;
134         rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance;
135         REQUEST *request = handler->request;
136
137         /*
138          *      Get the Cleartext-Password for this user.
139          */
140         rad_assert(handler->stage == PROCESS);
141
142         /*
143          *      Sanity check the response.  We need at least one byte
144          *      of data.
145          */
146         if (eap_ds->response->length <= 4) {
147                 ERROR("rlm_eap_gtc: corrupted data");
148                 eap_ds->request->code = PW_EAP_FAILURE;
149                 return 0;
150         }
151
152 #if 0
153         if ((rad_debug_lvl > 2) && fr_log_fp) {
154                 int i;
155
156                 for (i = 0; i < eap_ds->response->length - 4; i++) {
157                         if ((i & 0x0f) == 0) fprintf(fr_log_fp, "%d: ", i);
158
159                         fprintf(fr_log_fp, "%02x ", eap_ds->response->type.data[i]);
160
161                         if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
162                 }
163         }
164 #endif
165
166         /*
167          *      Handle passwords here.
168          */
169         if (inst->auth_type == PW_AUTH_TYPE_LOCAL) {
170                 /*
171                  *      For now, do cleartext password authentication.
172                  */
173                 vp = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
174                 if (!vp) {
175                         REDEBUG2("Cleartext-Password is required for authentication");
176                         eap_ds->request->code = PW_EAP_FAILURE;
177                         return 0;
178                 }
179
180                 if (eap_ds->response->type.length != vp->vp_length) {
181                         REDEBUG2("Passwords are of different length. %u %u", (unsigned) eap_ds->response->type.length, (unsigned) vp->vp_length);
182                         eap_ds->request->code = PW_EAP_FAILURE;
183                         return 0;
184                 }
185
186                 if (memcmp(eap_ds->response->type.data,
187                            vp->vp_strvalue, vp->vp_length) != 0) {
188                         REDEBUG2("Passwords are different");
189                         eap_ds->request->code = PW_EAP_FAILURE;
190                         return 0;
191                 }
192
193                 /*
194                  *      EAP packets can be ~64k long maximum, and
195                  *      we don't like that.
196                  */
197         } else if (eap_ds->response->type.length <= 128) {
198                 int rcode;
199                 char *p;
200
201                 /*
202                  *      If there was a User-Password in the request,
203                  *      why the heck are they using EAP-GTC?
204                  */
205                 fr_pair_delete_by_num(&request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
206
207                 vp = pair_make_request("User-Password", NULL, T_OP_EQ);
208                 if (!vp) {
209                         return 0;
210                 }
211                 vp->vp_length = eap_ds->response->type.length;
212                 vp->vp_strvalue = p = talloc_array(vp, char, vp->vp_length + 1);
213                 vp->type = VT_DATA;
214                 memcpy(p, eap_ds->response->type.data, vp->vp_length);
215                 p[vp->vp_length] = 0;
216
217                 /*
218                  *      Add the password to the request, and allow
219                  *      another module to do the work of authenticating it.
220                  */
221                 request->password = vp;
222
223                 /*
224                  *      This is a wild & crazy hack.
225                  */
226                 rcode = process_authenticate(inst->auth_type, request);
227                 if (rcode != RLM_MODULE_OK) {
228                         eap_ds->request->code = PW_EAP_FAILURE;
229                         return 0;
230                 }
231
232         } else {
233                 ERROR("rlm_eap_gtc: Response is too large to understand");
234                 eap_ds->request->code = PW_EAP_FAILURE;
235                 return 0;
236
237         }
238
239         eap_ds->request->code = PW_EAP_SUCCESS;
240
241         return 1;
242 }
243
244 /*
245  *      The module name should be the only globally exported symbol.
246  *      That is, everything else should be 'static'.
247  */
248 extern rlm_eap_module_t rlm_eap_gtc;
249 rlm_eap_module_t rlm_eap_gtc = {
250         .name           = "eap_gtc",
251         .instantiate    = mod_instantiate,      /* Create new submodule instance */
252         .session_init   = mod_session_init,     /* Initialise a new EAP session */
253         .process        = mod_process           /* Process next round of EAP method */
254 };