2 * rlm_eap_tnc.c Handles that are called from eap
4 * This software is Copyright (C) 2006,2007 FH Hannover
6 * Portions of this code unrelated to FreeRADIUS are available
7 * separately under a commercial license. If you require an
8 * implementation of EAP-TNC that is not under the GPLv2, please
9 * contact tnc@inform.fh-hannover.de for details.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * Modifications to integrate with FreeRADIUS configuration
26 * Copyright (C) 2007 Alan DeKok <aland@deployingradius.com>
29 #include <freeradius-devel/autoconf.h>
34 #include "tncs_connect.h"
37 #include <freeradius-devel/rad_assert.h>
39 typedef struct rlm_eap_tnc_t {
45 static int sessionCounter=0;
48 * Initiate the EAP-MD5 session by sending a challenge to the peer.
49 * Initiate the EAP-TNC session by sending a EAP Request witch Start Bit set
52 static int tnc_initiate(void *type_data, EAP_HANDLER *handler)
54 rlm_eap_tnc_t *inst = type_data;
56 if (!handler->request || !handler->request->parent) {
57 DEBUG2("rlm_eap_tnc: Must be run inside of a TLS method");
61 DEBUG("tnc_initiate: %ld", handler->timestamp);
65 if(connectToTncs(inst->tnc_path)==-1){
66 DEBUG("Could not connect to TNCS");
71 type_data = type_data; /* -Wunused */
73 * Allocate an EAP-MD5 packet.
75 reply = eaptnc_alloc();
77 radlog(L_ERR, "rlm_eap_tnc: out of memory");
84 reply->code = PW_TNC_REQUEST;
85 uint8_t flags_ver = 1; //set version to 1
86 flags_ver = SET_START(flags_ver); //set start-flag
87 DEBUG("$$$$$$$$$$$$$$$$Flags: %d", flags_ver);
88 reply->flags_ver = flags_ver;
89 reply->length = 1+1; /* one byte of flags_ver */
93 * Compose the EAP-TNC packet out of the data structure,
96 eaptnc_compose(handler->eap_ds, reply);
98 //put sessionAttribute to Handler and increase sessionCounter
99 handler->opaque = calloc(sizeof(TNC_ConnectionID), 1);
100 memcpy(handler->opaque, &sessionCounter, sizeof(int));
104 * We don't need to authorize the user at this point.
106 * We also don't need to keep the challenge, as it's
107 * stored in 'handler->eap_ds', which will be given back
110 handler->stage = AUTHENTICATE;
115 static void setVlanAttribute(rlm_eap_tnc_t *inst, EAP_HANDLER *handler,
116 VlanAccessMode mode){
118 char *vlanNumber = NULL;
121 vlanNumber = inst->vlan_isolate;
122 vp = pairfind(handler->request->config_items,
123 PW_TNC_VLAN_ISOLATE);
124 if (vp) vlanNumber = vp->vp_strvalue;
127 vlanNumber = inst->vlan_access;
128 vp = pairfind(handler->request->config_items,
130 if (vp) vlanNumber = vp->vp_strvalue;
134 DEBUG2(" rlm_eap_tnc: Internal error. Not setting vlan number");
137 pairadd(&handler->request->reply->vps,
138 pairmake("Tunnel-Type", "VLAN", T_OP_SET));
140 pairadd(&handler->request->reply->vps,
141 pairmake("Tunnel-Medium-Type", "IEEE-802", T_OP_SET));
143 pairadd(&handler->request->reply->vps,
144 pairmake("Tunnel-Private-Group-ID", vlanNumber, T_OP_SET));
149 * Authenticate a previously sent challenge.
151 static int tnc_authenticate(void *type_arg, EAP_HANDLER *handler)
155 TNC_ConnectionID connId = *((TNC_ConnectionID *) (handler->opaque));
156 rlm_eap_tnc_t *inst = type_arg;
158 DEBUG2("HANDLER_OPAQUE: %d\n", *((TNC_ConnectionID *) (handler->opaque)));
159 DEBUG2("XXXXXXXXXXXX TNC-AUTHENTICATE is starting now for %d..........\n", connId);
162 * Get the User-Password for this user.
164 rad_assert(handler->request != NULL);
165 rad_assert(handler->stage == AUTHENTICATE);
168 * Extract the EAP-TNC packet.
170 if (!(packet = eaptnc_extract(handler->eap_ds)))
175 * Create a reply, and initialize it.
177 reply = eaptnc_alloc();
182 reply->id = handler->eap_ds->request->id;
184 TNC_UInt32 tnccsMsgLength = 0;
185 if(packet->data_length==0){
186 tnccsMsgLength = packet->length-TNC_PACKET_LENGTH_WITHOUT_DATA_LENGTH;
188 tnccsMsgLength = packet->length-TNC_PACKET_LENGTH;
190 TNC_BufferReference outMessage;
191 TNC_UInt32 outMessageLength = 2;
192 int isLengthIncluded = TNC_LENGTH_INCLUDED(packet->flags_ver);
193 TNC_UInt32 overallLength = packet->data_length;
194 int moreFragments = TNC_MORE_FRAGMENTS(packet->flags_ver);
195 int outIsLengthIncluded=0;
196 int outMoreFragments=0;
197 TNC_UInt32 outOverallLength=0;
198 int isAcknowledgement = 0;
199 if(isLengthIncluded == 0
200 && moreFragments == 0
201 && overallLength == 0
202 && tnccsMsgLength == 0
203 && TNC_START(packet->flags_ver)==0){
205 isAcknowledgement = 1;
208 DEBUG("Data received: (%d)\n", tnccsMsgLength);
210 for(i=0;i<tnccsMsgLength;i++){
211 DEBUG2("%c", (packet->data)[i]);
215 TNC_ConnectionState state = exchangeTNCCSMessages(inst->tnc_path,
225 &outIsLengthIncluded,
228 DEBUG("GOT State %d from TNCS", state);
229 if(state == TNC_CONNECTION_EAP_ACKNOWLEDGEMENT){ //send back acknoledgement
230 reply->code = PW_TNC_REQUEST;
232 reply->data_length = 0;
233 reply->flags_ver = 1;
234 reply->length =TNC_PACKET_LENGTH_WITHOUT_DATA_LENGTH;
235 }else{ //send back normal message
236 DEBUG("GOT Message from TNCS (length: %d)", outMessageLength);
238 /* for(i=0;i<outMessageLength;i++){
239 DEBUG2("%c", outMessage[i]);
243 DEBUG("outIsLengthIncluded: %d, outMoreFragments: %d, outOverallLength: %d",
244 outIsLengthIncluded, outMoreFragments, outOverallLength);
245 DEBUG("NEW STATE: %d", state);
247 case TNC_CONNECTION_STATE_HANDSHAKE:
248 reply->code = PW_TNC_REQUEST;
249 DEBUG2("Set Reply->Code to EAP-REQUEST\n");
251 case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
252 reply->code = PW_TNC_SUCCESS;
253 setVlanAttribute(inst, handler,VLAN_ACCESS);
255 case TNC_CONNECTION_STATE_ACCESS_NONE:
256 reply->code = PW_TNC_FAILURE;
257 //setVlanAttribute(inst, handler, VLAN_ISOLATE);
259 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
260 reply->code = PW_TNC_SUCCESS;
261 setVlanAttribute(inst, handler, VLAN_ISOLATE);
264 reply->code= PW_TNC_FAILURE;
267 if(outMessage!=NULL && outMessageLength!=0){
268 reply->data = outMessage;
270 reply->flags_ver = 1;
271 if(outIsLengthIncluded){
272 reply->flags_ver = SET_LENGTH_INCLUDED(reply->flags_ver);
273 reply->data_length = outOverallLength;
274 reply->length = TNC_PACKET_LENGTH + outMessageLength;
275 DEBUG("SET LENGTH: %d", reply->length);
276 DEBUG("SET DATALENGTH: %d", outOverallLength);
278 reply->data_length = 0;
279 reply->length = TNC_PACKET_LENGTH_WITHOUT_DATA_LENGTH + outMessageLength;
280 DEBUG("SET LENGTH: %d", reply->length);
282 if(outMoreFragments){
283 reply->flags_ver = SET_MORE_FRAGMENTS(reply->flags_ver);
288 * Compose the EAP-MD5 packet out of the data structure,
291 eaptnc_compose(handler->eap_ds, reply);
293 handler->stage = AUTHENTICATE;
295 eaptnc_free(&packet);
300 * Detach the EAP-TNC module.
302 static int tnc_detach(void *arg)
309 static CONF_PARSER module_config[] = {
310 { "vlan_access", PW_TYPE_STRING,
311 offsetof(rlm_eap_tnc_t, vlan_access), NULL, NULL },
312 { "vlan_isolate", PW_TYPE_STRING,
313 offsetof(rlm_eap_tnc_t, vlan_isolate), NULL, NULL },
314 { "libtns.so", PW_TYPE_STRING,
315 offsetof(rlm_eap_tnc_t, tnc_path), NULL,
316 "/usr/local/lib/libTNCS.so"},
318 { NULL, -1, 0, NULL, NULL } /* end the list */
322 * Attach the EAP-TNC module.
324 static int tnc_attach(CONF_SECTION *cs, void **instance)
328 inst = malloc(sizeof(*inst));
329 if (!inst) return -1;
330 memset(inst, 0, sizeof(*inst));
332 if (cf_section_parse(cs, inst, module_config) < 0) {
338 if (!inst->vlan_access || !inst->vlan_isolate) {
339 radlog(L_ERR, "rlm_eap_tnc: Must set both vlan_access and vlan_isolate");
349 * The module name should be the only globally exported symbol.
350 * That is, everything else should be 'static'.
352 EAP_TYPE rlm_eap_tnc = {
354 tnc_attach, /* attach */
355 tnc_initiate, /* Start the initial request */
356 NULL, /* authorization */
357 tnc_authenticate, /* authentication */
358 tnc_detach /* detach */