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){
117 char *vlanNumber = NULL;
120 vlanNumber = inst->vlan_isolate;
123 vlanNumber = inst->vlan_access;
127 DEBUG2(" rlm_eap_tnc: Internal error. Not setting vlan number");
130 pairadd(&handler->request->reply->vps,
131 pairmake("Tunnel-Type", "VLAN", T_OP_SET));
133 pairadd(&handler->request->reply->vps,
134 pairmake("Tunnel-Medium-Type", "IEEE-802", T_OP_SET));
136 pairadd(&handler->request->reply->vps,
137 pairmake("Tunnel-Private-Group-ID", vlanNumber, T_OP_SET));
142 * Authenticate a previously sent challenge.
144 static int tnc_authenticate(void *type_arg, EAP_HANDLER *handler)
148 TNC_ConnectionID connId = *((TNC_ConnectionID *) (handler->opaque));
149 rlm_eap_tnc_t *inst = type_arg;
151 DEBUG2("HANDLER_OPAQUE: %d\n", *((TNC_ConnectionID *) (handler->opaque)));
152 DEBUG2("XXXXXXXXXXXX TNC-AUTHENTICATE is starting now for %d..........\n", connId);
155 * Get the User-Password for this user.
157 rad_assert(handler->request != NULL);
158 rad_assert(handler->stage == AUTHENTICATE);
161 * Extract the EAP-TNC packet.
163 if (!(packet = eaptnc_extract(handler->eap_ds)))
168 * Create a reply, and initialize it.
170 reply = eaptnc_alloc();
175 reply->id = handler->eap_ds->request->id;
177 TNC_UInt32 tnccsMsgLength = 0;
178 if(packet->data_length==0){
179 tnccsMsgLength = packet->length-TNC_PACKET_LENGTH_WITHOUT_DATA_LENGTH;
181 tnccsMsgLength = packet->length-TNC_PACKET_LENGTH;
183 TNC_BufferReference outMessage;
184 TNC_UInt32 outMessageLength = 2;
185 int isLengthIncluded = TNC_LENGTH_INCLUDED(packet->flags_ver);
186 TNC_UInt32 overallLength = packet->data_length;
187 int moreFragments = TNC_MORE_FRAGMENTS(packet->flags_ver);
188 int outIsLengthIncluded=0;
189 int outMoreFragments=0;
190 TNC_UInt32 outOverallLength=0;
191 int isAcknowledgement = 0;
192 if(isLengthIncluded == 0
193 && moreFragments == 0
194 && overallLength == 0
195 && tnccsMsgLength == 0
196 && TNC_START(packet->flags_ver)==0){
198 isAcknowledgement = 1;
201 DEBUG("Data received: (%d)\n", tnccsMsgLength);
203 for(i=0;i<tnccsMsgLength;i++){
204 DEBUG2("%c", (packet->data)[i]);
208 TNC_ConnectionState state = exchangeTNCCSMessages(inst->tnc_path,
218 &outIsLengthIncluded,
221 DEBUG("GOT State %d from TNCS", state);
222 if(state == TNC_CONNECTION_EAP_ACKNOWLEDGEMENT){ //send back acknoledgement
223 reply->code = PW_TNC_REQUEST;
225 reply->data_length = 0;
226 reply->flags_ver = 1;
227 reply->length =TNC_PACKET_LENGTH_WITHOUT_DATA_LENGTH;
228 }else{ //send back normal message
229 DEBUG("GOT Message from TNCS (length: %d)", outMessageLength);
231 /* for(i=0;i<outMessageLength;i++){
232 DEBUG2("%c", outMessage[i]);
236 DEBUG("outIsLengthIncluded: %d, outMoreFragments: %d, outOverallLength: %d",
237 outIsLengthIncluded, outMoreFragments, outOverallLength);
238 DEBUG("NEW STATE: %d", state);
240 case TNC_CONNECTION_STATE_HANDSHAKE:
241 reply->code = PW_TNC_REQUEST;
242 DEBUG2("Set Reply->Code to EAP-REQUEST\n");
244 case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
245 reply->code = PW_TNC_SUCCESS;
246 setVlanAttribute(inst, handler,VLAN_ACCESS);
248 case TNC_CONNECTION_STATE_ACCESS_NONE:
249 reply->code = PW_TNC_FAILURE;
250 //setVlanAttribute(inst, handler, VLAN_ISOLATE);
252 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
253 reply->code = PW_TNC_SUCCESS;
254 setVlanAttribute(inst, handler, VLAN_ISOLATE);
257 reply->code= PW_TNC_FAILURE;
260 if(outMessage!=NULL && outMessageLength!=0){
261 reply->data = outMessage;
263 reply->flags_ver = 1;
264 if(outIsLengthIncluded){
265 reply->flags_ver = SET_LENGTH_INCLUDED(reply->flags_ver);
266 reply->data_length = outOverallLength;
267 reply->length = TNC_PACKET_LENGTH + outMessageLength;
268 DEBUG("SET LENGTH: %d", reply->length);
269 DEBUG("SET DATALENGTH: %d", outOverallLength);
271 reply->data_length = 0;
272 reply->length = TNC_PACKET_LENGTH_WITHOUT_DATA_LENGTH + outMessageLength;
273 DEBUG("SET LENGTH: %d", reply->length);
275 if(outMoreFragments){
276 reply->flags_ver = SET_MORE_FRAGMENTS(reply->flags_ver);
281 * Compose the EAP-MD5 packet out of the data structure,
284 eaptnc_compose(handler->eap_ds, reply);
286 handler->stage = AUTHENTICATE;
288 eaptnc_free(&packet);
293 * Detach the EAP-TNC module.
295 static int tnc_detach(void *arg)
302 static CONF_PARSER module_config[] = {
303 { "vlan_access", PW_TYPE_STRING,
304 offsetof(rlm_eap_tnc_t, vlan_access), NULL, NULL },
305 { "vlan_isolate", PW_TYPE_STRING,
306 offsetof(rlm_eap_tnc_t, vlan_isolate), NULL, NULL },
307 { "libtns.so", PW_TYPE_STRING,
308 offsetof(rlm_eap_tnc_t, tnc_path), NULL,
309 "/usr/local/lib/libTNCS.so"},
311 { NULL, -1, 0, NULL, NULL } /* end the list */
315 * Attach the EAP-TNC module.
317 static int tnc_attach(CONF_SECTION *cs, void **instance)
321 inst = malloc(sizeof(*inst));
322 if (!inst) return -1;
323 memset(inst, 0, sizeof(*inst));
325 if (cf_section_parse(cs, inst, module_config) < 0) {
331 if (!inst->vlan_access || !inst->vlan_isolate) {
332 radlog(L_ERR, "rlm_eap_tnc: Must set both vlan_access and vlan_isolate");
342 * The module name should be the only globally exported symbol.
343 * That is, everything else should be 'static'.
345 EAP_TYPE rlm_eap_tnc = {
347 tnc_attach, /* attach */
348 tnc_initiate, /* Start the initial request */
349 NULL, /* authorization */
350 tnc_authenticate, /* authentication */
351 tnc_detach /* detach */