2 * rlm_eap_gtc.c Handles that are called from eap
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.
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.
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
20 * Copyright 2003,2006 The FreeRADIUS server project
30 #include <freeradius-devel/rad_assert.h>
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
37 typedef struct rlm_eap_gtc_t {
38 char const *challenge;
39 char const *auth_type_name;
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
54 static int mod_instantiate(CONF_SECTION *cs, void **instance)
59 *instance = inst = talloc_zero(cs, rlm_eap_gtc_t);
63 * Parse the configuration attributes.
65 if (cf_section_parse(cs, inst, module_config) < 0) {
69 if (inst->auth_type_name && *inst->auth_type_name) {
70 dval = dict_valbyname(PW_AUTH_TYPE, 0, inst->auth_type_name);
72 ERROR("rlm_eap_gtc: Unknown Auth-Type %s",
73 inst->auth_type_name);
77 inst->auth_type = dval->value;
79 inst->auth_type = PW_AUTH_TYPE_LOCAL;
85 * Initiate the EAP-GTC session by sending a challenge to the peer.
87 static int mod_session_init(void *instance, eap_handler_t *handler)
89 char challenge_str[1024];
91 EAP_DS *eap_ds = handler->eap_ds;
92 rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance;
94 if (radius_xlat(challenge_str, sizeof(challenge_str), handler->request, inst->challenge, NULL, NULL) < 0) {
98 length = strlen(challenge_str);
101 * We're sending a request...
103 eap_ds->request->code = PW_EAP_REQUEST;
105 eap_ds->request->type.data = talloc_array(eap_ds->request,
107 if (!eap_ds->request->type.data) {
111 memcpy(eap_ds->request->type.data, challenge_str, length);
112 eap_ds->request->type.length = length;
115 * We don't need to authorize the user at this point.
117 * We also don't need to keep the challenge, as it's
118 * stored in 'handler->eap_ds', which will be given back
121 handler->stage = PROCESS;
128 * Authenticate a previously sent challenge.
130 static int CC_HINT(nonnull) mod_process(void *instance, eap_handler_t *handler)
133 EAP_DS *eap_ds = handler->eap_ds;
134 rlm_eap_gtc_t *inst = (rlm_eap_gtc_t *) instance;
135 REQUEST *request = handler->request;
138 * Get the Cleartext-Password for this user.
140 rad_assert(handler->stage == PROCESS);
143 * Sanity check the response. We need at least one byte
146 if (eap_ds->response->length <= 4) {
147 ERROR("rlm_eap_gtc: corrupted data");
148 eap_ds->request->code = PW_EAP_FAILURE;
153 if ((rad_debug_lvl > 2) && fr_log_fp) {
156 for (i = 0; i < eap_ds->response->length - 4; i++) {
157 if ((i & 0x0f) == 0) fprintf(fr_log_fp, "%d: ", i);
159 fprintf(fr_log_fp, "%02x ", eap_ds->response->type.data[i]);
161 if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
167 * Handle passwords here.
169 if (inst->auth_type == PW_AUTH_TYPE_LOCAL) {
171 * For now, do cleartext password authentication.
173 vp = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY);
175 REDEBUG2("Cleartext-Password is required for authentication");
176 eap_ds->request->code = PW_EAP_FAILURE;
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;
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;
194 * EAP packets can be ~64k long maximum, and
195 * we don't like that.
197 } else if (eap_ds->response->type.length <= 128) {
202 * If there was a User-Password in the request,
203 * why the heck are they using EAP-GTC?
205 fr_pair_delete_by_num(&request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
207 vp = pair_make_request("User-Password", NULL, T_OP_EQ);
211 vp->vp_length = eap_ds->response->type.length;
212 vp->vp_strvalue = p = talloc_array(vp, char, vp->vp_length + 1);
214 memcpy(p, eap_ds->response->type.data, vp->vp_length);
215 p[vp->vp_length] = 0;
218 * Add the password to the request, and allow
219 * another module to do the work of authenticating it.
221 request->password = vp;
224 * This is a wild & crazy hack.
226 rcode = process_authenticate(inst->auth_type, request);
227 if (rcode != RLM_MODULE_OK) {
228 eap_ds->request->code = PW_EAP_FAILURE;
233 ERROR("rlm_eap_gtc: Response is too large to understand");
234 eap_ds->request->code = PW_EAP_FAILURE;
239 eap_ds->request->code = PW_EAP_SUCCESS;
245 * The module name should be the only globally exported symbol.
246 * That is, everything else should be 'static'.
248 extern rlm_eap_module_t rlm_eap_gtc;
249 rlm_eap_module_t rlm_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 */