All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_eap_peap.c
Go to the documentation of this file.
1 /*
2  * rlm_eap_peap.c contains the interfaces that are called from eap
3  *
4  * Version: $Id: 887d0d10918dbd4e261f67120d541a88e872f0f8 $
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 Alan DeKok <aland@freeradius.org>
21  * Copyright 2006 The FreeRADIUS server project
22  */
23 
24 RCSID("$Id: 887d0d10918dbd4e261f67120d541a88e872f0f8 $")
25 
26 #include "eap_peap.h"
27 
28 typedef struct rlm_eap_peap_t {
29  char const *tls_conf_name; //!< TLS configuration.
30  fr_tls_server_conf_t *tls_conf;
31  char const *default_method_name; //!< Default tunneled EAP type.
34  bool use_tunneled_reply; //!< Use the reply attributes from the tunneled session in
35  //!< the non-tunneled reply to the client.
36 
37  bool copy_request_to_tunnel; //!< Use SOME of the request attributes from outside of the
38  //!< tunneled session in the tunneled request.
39 #ifdef WITH_PROXY
40  bool proxy_tunneled_request_as_eap; //!< Proxy tunneled session as EAP, or as de-capsulated
41  //!< protocol.
42 #endif
43  char const *virtual_server; //!< Virtual server for inner tunnel session.
44 
45  bool soh; //!< Do we do SoH request?
46  char const *soh_virtual_server;
47  bool req_client_cert; //!< Do we do require a client cert?
49 
50 
52  { FR_CONF_OFFSET("tls", PW_TYPE_STRING, rlm_eap_peap_t, tls_conf_name) },
53 
54  { FR_CONF_OFFSET("default_eap_type", PW_TYPE_STRING, rlm_eap_peap_t, default_method_name), .dflt = "mschapv2" },
55 
56  { FR_CONF_OFFSET("copy_request_to_tunnel", PW_TYPE_BOOLEAN, rlm_eap_peap_t, copy_request_to_tunnel), .dflt = "no" },
57 
58  { FR_CONF_OFFSET("use_tunneled_reply", PW_TYPE_BOOLEAN, rlm_eap_peap_t, use_tunneled_reply), .dflt = "no" },
59 
60 #ifdef WITH_PROXY
61  { FR_CONF_OFFSET("proxy_tunneled_request_as_eap", PW_TYPE_BOOLEAN, rlm_eap_peap_t, proxy_tunneled_request_as_eap), .dflt = "yes" },
62 #endif
63 
64  { FR_CONF_OFFSET("virtual_server", PW_TYPE_STRING, rlm_eap_peap_t, virtual_server) },
65 
66  { FR_CONF_OFFSET("soh", PW_TYPE_BOOLEAN, rlm_eap_peap_t, soh), .dflt = "no" },
67 
68  { FR_CONF_OFFSET("require_client_cert", PW_TYPE_BOOLEAN, rlm_eap_peap_t, req_client_cert), .dflt = "no" },
69 
70  { FR_CONF_OFFSET("soh_virtual_server", PW_TYPE_STRING, rlm_eap_peap_t, soh_virtual_server) },
72 };
73 
74 
75 /*
76  * Attach the module.
77  */
78 static int mod_instantiate(CONF_SECTION *cs, void **instance)
79 {
81  fr_dict_enum_t *dv;
82 
83  *instance = inst = talloc_zero(cs, rlm_eap_peap_t);
84  if (!inst) return -1;
85 
86  /*
87  * Parse the configuration attributes.
88  */
89  if (cf_section_parse(cs, inst, module_config) < 0) {
90  return -1;
91  }
92 
93  /*
94  * Convert the name to an integer, to make it easier to
95  * handle.
96  */
98  if (inst->default_method < 0) {
99  ERROR("rlm_eap_peap: Unknown EAP type %s",
100  inst->default_method_name);
101  return -1;
102  }
103 
104  /*
105  * Read tls configuration, either from group given by 'tls'
106  * option, or from the eap-tls configuration.
107  */
108  inst->tls_conf = eap_tls_conf_parse(cs, "tls");
109 
110  if (!inst->tls_conf) {
111  ERROR("rlm_eap_peap: Failed initializing SSL context");
112  return -1;
113  }
114 
115  dv = fr_dict_enum_by_name(NULL, fr_dict_attr_by_num(NULL, 0, PW_AUTH_TYPE), "EAP");
116  if (!dv) {
117  cf_log_err_cs(cs, "Failed to find 'Auth-Type EAP' section. Cannot authenticate users.");
118  return -1;
119  }
120  inst->auth_type_eap = dv->value;
121 
122  return 0;
123 }
124 
125 /*
126  * Allocate the PEAP per-session data
127  */
128 static peap_tunnel_t *peap_alloc(TALLOC_CTX *ctx, rlm_eap_peap_t *inst)
129 {
130  peap_tunnel_t *t;
131 
132  t = talloc_zero(ctx, peap_tunnel_t);
133 
134  t->default_method = inst->default_method;
137 #ifdef WITH_PROXY
139 #endif
140  t->virtual_server = inst->virtual_server;
141  t->soh = inst->soh;
144 
145  return t;
146 }
147 
148 static int CC_HINT(nonnull) mod_process(void *instance, eap_session_t *eap_session);
149 
150 /*
151  * Send an initial eap-tls request to the peer, using the libeap functions.
152  */
153 static int mod_session_init(void *type_arg, eap_session_t *eap_session)
154 {
155  tls_session_t *tls_session;
157  VALUE_PAIR *vp;
158  bool client_cert;
159 
160  inst = type_arg;
161 
162  eap_session->tls = true;
163 
164  /*
165  * Check if we need a client certificate.
166  */
167 
168  /*
169  * EAP-TLS-Require-Client-Cert attribute will override
170  * the require_client_cert configuration option.
171  */
172  vp = fr_pair_find_by_num(eap_session->request->config, 0, PW_EAP_TLS_REQUIRE_CLIENT_CERT, TAG_ANY);
173  if (vp) {
174  client_cert = vp->vp_integer ? true : false;
175  } else {
176  client_cert = inst->req_client_cert;
177  }
178 
179  tls_session = eap_tls_session_init(eap_session, inst->tls_conf, client_cert);
180  if (!tls_session) return 0;
181 
182  eap_session->opaque = ((void *)tls_session);
183 
184  /*
185  * Set up type-specific information.
186  */
187  tls_session->prf_label = "client EAP encryption";
188 
189  /*
190  * As it is a poorly designed protocol, PEAP uses
191  * bits in the TLS header to indicate PEAP
192  * version numbers. For now, we only support
193  * PEAP version 0, so it doesn't matter too much.
194  * However, if we support later versions of PEAP,
195  * we will need this flag to indicate which
196  * version we're currently dealing with.
197  */
198  tls_session->base_flags = 0x00;
199 
200  /*
201  * PEAP version 0 requires 'include_length = no',
202  * so rather than hoping the user figures it out,
203  * we force it here.
204  */
205  tls_session->length_flag = false;
206 
207  /*
208  * TLS session initialization is over. Now handle TLS
209  * related handshaking or application data.
210  */
211  if (eap_tls_start(eap_session) < 0) {
212  talloc_free(tls_session);
213  return 0;
214  }
215 
216  eap_session->process = mod_process;
217 
218  return 1;
219 }
220 
221 /*
222  * Do authentication, by letting EAP-TLS do most of the work.
223  */
224 static int mod_process(void *arg, eap_session_t *eap_session)
225 {
226  int rcode;
227  fr_tls_status_t status;
229  tls_session_t *tls_session = (tls_session_t *) eap_session->opaque;
230  peap_tunnel_t *peap = tls_session->opaque;
231  REQUEST *request = eap_session->request;
232 
233  /*
234  * Session resumption requires the storage of data, so
235  * allocate it if it doesn't already exist.
236  */
237  if (!tls_session->opaque) peap = tls_session->opaque = peap_alloc(tls_session, inst);
238 
239  status = eap_tls_process(eap_session);
240  if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
241  REDEBUG("[eap-tls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
242  } else {
243  RDEBUG2("[eap-tls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
244  }
245 
246  switch (status) {
247  /*
248  * EAP-TLS handshake was successful, tell the
249  * client to keep talking.
250  *
251  * If this was EAP-TLS, we would just return
252  * an EAP-TLS-Success packet here.
253  */
254  case FR_TLS_SUCCESS:
255  peap->status = PEAP_STATUS_TUNNEL_ESTABLISHED;
256  break;
257 
258  /*
259  * The TLS code is still working on the TLS
260  * exchange, and it's a valid TLS request.
261  * do nothing.
262  */
263  case FR_TLS_HANDLED:
264  /*
265  * FIXME: If the SSL session is established, grab the state
266  * and EAP id from the inner tunnel, and update it with
267  * the expected EAP id!
268  */
269  return 1;
270 
271  /*
272  * Handshake is done, proceed with decoding tunneled
273  * data.
274  */
275  case FR_TLS_RECORD_COMPLETE:
276  break;
277 
278  /*
279  * Anything else: fail.
280  */
281  default:
282  return 0;
283  }
284 
285  /*
286  * Session is established, proceed with decoding
287  * tunneled data.
288  */
289  RDEBUG2("Session established. Decoding tunneled attributes");
290 
291  /*
292  * We may need PEAP data associated with the session, so
293  * allocate it here, if it wasn't already alloacted.
294  */
295  if (!tls_session->opaque) {
296  tls_session->opaque = peap_alloc(tls_session, inst);
297  }
298 
299  /*
300  * Process the PEAP portion of the request.
301  */
302  rcode = eap_peap_process(eap_session, tls_session, inst->auth_type_eap);
303  switch (rcode) {
304  case RLM_MODULE_REJECT:
305  eap_tls_fail(eap_session);
306  return 0;
307 
308  case RLM_MODULE_HANDLED:
309  eap_tls_request(eap_session);
310  return 1;
311 
312  case RLM_MODULE_OK:
313  /*
314  * Move the saved VP's from the Access-Accept to
315  * our Access-Accept.
316  */
317  peap = tls_session->opaque;
318  if (peap->soh_reply_vps) {
319  RDEBUG2("Using saved attributes from the SoH reply");
320  rdebug_pair_list(L_DBG_LVL_2, request, peap->soh_reply_vps, NULL);
321  fr_pair_list_mcopy_by_num(eap_session->request->reply, &eap_session->request->reply->vps,
322  &peap->soh_reply_vps, 0, 0, TAG_ANY);
323  }
324  if (peap->accept_vps) {
325  RDEBUG2("Using saved attributes from the original Access-Accept");
326  rdebug_pair_list(L_DBG_LVL_2, request, peap->accept_vps, NULL);
327  fr_pair_list_mcopy_by_num(eap_session->request->reply, &eap_session->request->reply->vps,
328  &peap->accept_vps, 0, 0, TAG_ANY);
329  } else if (peap->use_tunneled_reply) {
330  RDEBUG2("No saved attributes in the original Access-Accept");
331  }
332 
333  /*
334  * Success: Automatically return MPPE keys.
335  */
336  if (eap_tls_success(eap_session) < 0) return 0;
337  return 1;
338 
339  /*
340  * No response packet, MUST be proxying it.
341  * The main EAP module will take care of discovering
342  * that the request now has a "proxy" packet, and
343  * will proxy it, rather than returning an EAP packet.
344  */
345  case RLM_MODULE_UPDATED:
346 #ifdef WITH_PROXY
347  rad_assert(eap_session->request->proxy != NULL);
348 #endif
349  return 1;
350 
351  default:
352  break;
353  }
354 
355  eap_tls_fail(eap_session);
356  return 0;
357 }
358 
359 
360 /*
361  * The module name should be the only globally exported symbol.
362  * That is, everything else should be 'static'.
363  */
365 rlm_eap_module_t rlm_eap_peap = {
366  .name = "eap_peap",
367  .instantiate = mod_instantiate, /* Create new submodule instance */
368  .session_init = mod_session_init, /* Initialise a new EAP session */
369  .process = mod_process /* Process next round of EAP method */
370 };
2nd highest priority debug messages (-xx | -X).
Definition: log.h:52
bool proxy_tunneled_request_as_eap
Definition: eap_peap.h:57
static CONF_PARSER module_config[]
Definition: rlm_eap_peap.c:51
The module is OK, continue.
Definition: radiusd.h:91
void fr_pair_list_mcopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, unsigned int vendor, unsigned int attr, int8_t tag)
Copy / delete matching pairs between VALUE_PAIR lists.
Definition: pair.c:1823
eap_type_t eap_name2type(char const *name)
Return an EAP-Type for a particular name.
Definition: eapcommon.c:88
char const * soh_virtual_server
Definition: eap_peap.h:60
bool copy_request_to_tunnel
Definition: eap_peap.h:55
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
int default_method
Definition: eap_peap.h:54
static int mod_process(void *arg, eap_session_t *eap_session)
Definition: rlm_eap_peap.c:224
#define inst
void * opaque
Opaque data used by EAP methods.
Definition: eap.h:80
bool use_tunneled_reply
Use the reply attributes from the tunneled session in the non-tunneled reply to the client...
Definition: rlm_eap_peap.c:34
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
fr_dict_enum_t * fr_dict_enum_by_name(fr_dict_t *dict, fr_dict_attr_t const *da, char const *val)
Definition: dict.c:3703
REQUEST * request
Request that contains the response we're processing.
Definition: eap.h:71
static int mod_session_init(void *instance, eap_session_t *eap_session)
Definition: rlm_eap_gtc.c:89
RADIUS_PACKET * proxy
Outgoing request to proxy server.
Definition: radiusd.h:237
char const * virtual_server
Virtual server for inner tunnel session.
Definition: rlm_eap_peap.c:43
#define rad_assert(expr)
Definition: rad_assert.h:38
char const * default_method_name
Default tunneled EAP type.
Definition: rlm_eap_peap.c:31
peap_resumption session_resumption_state
Definition: eap_peap.h:62
static int mod_instantiate(CONF_SECTION *cs, void **instance)
Definition: rlm_eap_peap.c:78
char const * virtual_server
Definition: eap_peap.h:58
int eap_tls_success(eap_session_t *eap_session)
Send an EAP-TLS success.
Definition: eap_tls.c:211
Tracks the progress of a single session of any EAP method.
Definition: eap.h:60
int cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables)
Parse a configuration section into user-supplied variables.
Definition: conffile.c:2234
bool copy_request_to_tunnel
Use SOME of the request attributes from outside of the tunneled session in the tunneled request...
Definition: rlm_eap_peap.c:37
Immediately reject the request.
Definition: radiusd.h:89
bool use_tunneled_reply
Definition: eap_peap.h:56
bool proxy_tunneled_request_as_eap
Proxy tunneled session as EAP, or as de-capsulated protocol.
Definition: rlm_eap_peap.c:40
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
fr_tls_status_t eap_tls_process(eap_session_t *eap_session)
Process an EAP TLS request.
Definition: eap_tls.c:708
A truth value.
Definition: radius.h:56
char const * name
The name of the sub-module (without rlm_ prefix).
Definition: eap.h:96
char const * tls_conf_name
TLS configuration.
Definition: rlm_eap_peap.c:29
void rdebug_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of VALUE_PAIRs.
Definition: pair.c:757
#define RDEBUG2(fmt,...)
Definition: log.h:244
rlm_rcode_t eap_peap_process(eap_session_t *eap_session, tls_session_t *tls_session, int auth_type_eap) CC_HINT(nonnull)
Definition: peap.c:730
tls_session_t * eap_tls_session_init(eap_session_t *eap_session, fr_tls_server_conf_t *tls_conf, bool client_cert)
Create a new tls_session_t associated with an eap_session_t.
Definition: eap_tls.c:844
#define TAG_ANY
Definition: pair.h:191
Interface to call EAP sub mdoules.
Definition: eap.h:95
char const * soh_virtual_server
Definition: rlm_eap_peap.c:46
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
struct rlm_eap_peap_t rlm_eap_peap_t
int value
Enum value.
Definition: dict.h:96
#define REDEBUG(fmt,...)
Definition: log.h:254
fr_tls_server_conf_t * tls_conf
Definition: rlm_eap_peap.c:30
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
int eap_tls_fail(eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition: eap_tls.c:254
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
fr_tls_server_conf_t * eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
Parse TLS configuration.
Definition: eap_tls.c:891
fr_dict_attr_t const * fr_dict_attr_by_num(fr_dict_t *dict, unsigned int vendor, unsigned int attr)
Lookup a fr_dict_attr_t by its vendor and attribute numbers.
Definition: dict.c:3519
String of printable characters.
Definition: radius.h:33
bool soh
Do we do SoH request?
Definition: rlm_eap_peap.c:45
#define RCSID(id)
Definition: build.h:135
int eap_tls_request(eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
Definition: eap_tls.c:299
bool req_client_cert
Do we do require a client cert?
Definition: rlm_eap_peap.c:47
OK (pairs modified).
Definition: radiusd.h:97
int eap_tls_start(eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
Definition: eap_tls.c:192
The module handled the request, so stop.
Definition: radiusd.h:92
rlm_eap_module_t rlm_eap_peap
Definition: rlm_eap_peap.c:365
#define ERROR(fmt,...)
Definition: log.h:145
Value of an enumerated attribute.
Definition: dict.h:94
static int CC_HINT(nonnull)
Definition: rlm_eap_peap.c:148
static peap_tunnel_t * peap_alloc(TALLOC_CTX *ctx, rlm_eap_peap_t *inst)
Definition: rlm_eap_peap.c:128