Massive changes to clean up the EAP module, in preparation for
authoraland <aland>
Mon, 28 Jul 2003 17:36:42 +0000 (17:36 +0000)
committeraland <aland>
Mon, 28 Jul 2003 17:36:42 +0000 (17:36 +0000)
what we hope will be TTLS & PEAP.  ~20% of the code in the module
is gone, and what's left has more comments, and is simpler, and
cleaner to understand.

There is an 'authorize' section now, in addition to 'authenticate',
in the sub-modules, which may be useful.  But isn't used now...

Moved sub-modules from linked list to indexed array.  Much faster.

EAP types are looked up by type, not by name.  Less code, and faster.

Got rid of 'handler->id', and replaced it with entries inside of
the handler data structure.  Got rid of 'generateid' and
'regenerateid' functions, and swallowed them into the functions
which add/find handlers in a list.

Key active EAP sessions off of the first byte of the state, which
is a random number, instead of putting them all in one list.  This
decreases the work required to find one session.

Got rid of 'clean list' function, and instead clean the list
as we are looking for a session.  Equivalent functionality, less
work, and less code.

Simplify the use of the 'State' attribute.  It's now shorter,
which means more NASes will like it.

Cleaned up EAP-MD5, so it's more obvious what it does, and how
it works.  It should be used as a template for other EAP modules.

free_opaque takes a ptr, not a ptr to a ptr

run valgrind over the modules, and fixed issues.

EAP-TLS cleanups in instantiation & detaching.  (i.e. fix memory
leaks, and other problems)

moved 'add state to reply packet' to the eaplist_add function,
which is the only place where it should be.

Made eaptype_call 'static', as no one outside of eap.c needs it.

MD5, LEAP, & TLS have all been verified to work.
(you were worried, weren't you, considering the length of this
commit message)

16 files changed:
src/modules/rlm_eap/eap.c
src/modules/rlm_eap/eap.h
src/modules/rlm_eap/mem.c
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_eap/rlm_eap.h
src/modules/rlm_eap/state.c
src/modules/rlm_eap/types/rlm_eap_leap/Makefile
src/modules/rlm_eap/types/rlm_eap_leap/eap_leap.c
src/modules/rlm_eap/types/rlm_eap_leap/rlm_eap_leap.c
src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.c
src/modules/rlm_eap/types/rlm_eap_md5/eap_md5.h
src/modules/rlm_eap/types/rlm_eap_md5/rlm_eap_md5.c
src/modules/rlm_eap/types/rlm_eap_tls/eap_tls.c
src/modules/rlm_eap/types/rlm_eap_tls/eap_tls.h
src/modules/rlm_eap/types/rlm_eap_tls/rlm_eap_tls.c
src/modules/rlm_eap/types/rlm_eap_tls/tls.c

index 81710f6..54e7e59 100644 (file)
@@ -85,32 +85,38 @@ static const char *eap_types[] = {
 };
 
 /*
- * Load all the required eap authentication types.
- * Get all the supported EAP-types from config file. 
+ *     Return an EAP-Type for a particular name.
  */
-int eaptype_load(EAP_TYPES **type_list, const char *type_name,
-                CONF_SECTION *cs)
+int eaptype_name2id(const char *name)
 {
-       EAP_TYPES **last, *node;
-       lt_dlhandle handle;
-       char auth_type_name[NAME_LEN];
        int i;
 
-       snprintf(auth_type_name, sizeof(auth_type_name), "rlm_eap_%s", type_name);
-
-       last = type_list;
-       /* Go to the end of the EAP-Type list, if it is not already loaded */
-       for (node = *type_list; node != NULL; node = node->next) {
-               if (strcmp(node->typename, auth_type_name) == 0)
-                       return 0;
-               last = &node->next;
+       for (i = 0; i <= PW_EAP_MAX_TYPES; i++) {
+               if (strcmp(name, eap_types[i]) == 0) {
+                       return i;
+               }
        }
+       
+       return -1;
+}
+
+/*
+ * Load all the required eap authentication types.
+ * Get all the supported EAP-types from config file. 
+ */
+int eaptype_load(EAP_TYPES **type, int id, CONF_SECTION *cs)
+{
+       char            buffer[64];
+       lt_dlhandle     handle;
+       EAP_TYPES       *node;
+
+       snprintf(buffer, sizeof(buffer), "rlm_eap_%s", eap_types[id]);
 
        /* Link the loaded EAP-Type */
-       handle = lt_dlopenext(auth_type_name);
+       handle = lt_dlopenext(buffer);
        if (handle == NULL) {
                radlog(L_ERR, "rlm_eap: Failed to link EAP-Type/%s: %s", 
-                               type_name, lt_dlerror());
+                               eap_types[id], lt_dlerror());
                return -1;
        }
 
@@ -120,103 +126,70 @@ int eaptype_load(EAP_TYPES **type_list, const char *type_name,
                radlog(L_ERR, "rlm_eap: out of memory");
                return -1;
        }
+       memset(node, 0, sizeof(*node));
 
        /* fill in the structure */
-       node->next = NULL;
        node->handle = handle;
        node->cs = cs;
-       node->typeid = 0;
-       memset(node->typename, 0, NAME_LEN);
-       node->type_stuff = NULL;
-       strNcpy(node->typename, type_name, sizeof(node->typename));
-       for (i = PW_EAP_MAX_TYPES; i > 0; i--) {
-               if (!strcmp(type_name, eap_types[i])) {
-                       node->typeid = i;
-                       break;
-               }
-       }
-
-       if (node->typeid == 0) {
-               radlog(L_ERR, "rlm_eap: Invalid type name %s cannot be linked", type_name);
-               free(node);
-               return -1;
-       }
+       node->typeid = id;
+       node->typename = eap_types[id];
+       node->type_data = NULL;
        
-       node->type = (EAP_TYPE *)lt_dlsym(node->handle, auth_type_name);
+       node->type = (EAP_TYPE *)lt_dlsym(node->handle, buffer);
        if (!node->type) {
                radlog(L_ERR, "rlm_eap: Failed linking to %s structure in %s: %s",
-                               auth_type_name, type_name, lt_dlerror());
+                               buffer, eap_types[id], lt_dlerror());
                lt_dlclose(node->handle);       /* ignore any errors */
                free(node);
                return -1;
        }
        if ((node->type->attach) && 
-               ((node->type->attach)(node->cs, &(node->type_stuff)) < 0)) {
+               ((node->type->attach)(node->cs, &(node->type_data)) < 0)) {
 
-               radlog(L_ERR, "rlm_eap: Failed to initialize the type %s", type_name);
+               radlog(L_ERR, "rlm_eap: Failed to initialize the type %s",
+                      eap_types[id]);
                lt_dlclose(node->handle);
                free(node);
                return -1;
        }
 
-       DEBUG("rlm_eap: Loaded and initialized the type %s", type_name);
-       *last = node;
+       DEBUG("rlm_eap: Loaded and initialized the type %s", eap_types[id]);
+       *type = node;
        return 0;
 }
 
-/*
- * Get the handle for the requested authentication type, 
- * if supported.
- */
-EAP_TYPES *eaptype_byid(EAP_TYPES **list, int type)
-{
-       EAP_TYPES *node;
-       for(node = *list; node != NULL; node = node->next) {
-               if (node->typeid == type)
-                       return node;
-       }
-       return NULL;
-}
-
-EAP_TYPES *eaptype_byname(EAP_TYPES **list, const char *name)
-{
-       EAP_TYPES *node;
-       for(node = *list; node != NULL; node = node->next) {
-               if (strcmp(node->typename, name) == 0)
-                       return node;
-       }
-       return NULL;
-}
 
 /*
  * Call the appropriate handle with the right eap_type.
  */
-int eaptype_call(int eap_type, operation_t action, 
-       EAP_TYPES *type_list, EAP_HANDLER *handler)
+static int eaptype_call(EAP_TYPES *atype, EAP_HANDLER *handler)
 {
-       EAP_TYPES *atype;
-
-       atype = eaptype_byid(&type_list, eap_type);
-       if (!atype) {
-               radlog(L_ERR, "rlm_eap: Unsupported EAP_TYPE %d",
-                       handler->eap_ds->response->type.type);
-               return 0;
-       }
-
        DEBUG2("  rlm_eap: processing type %s", atype->typename);
 
-       switch (action) {
+       switch (handler->stage) {
        case INITIATE:
-               if (!atype->type->initiate(atype->type_stuff, handler))
+               if (!atype->type->initiate(atype->type_data, handler))
                        return 0;
                break;
+
+       case AUTHORIZE:
+               /*
+                *   The called function updates the EAP reply packet.
+                */
+               if (!atype->type->authorize ||
+                   !atype->type->authorize(atype->type_data, handler))
+                       return 0;
+               break;
+
        case AUTHENTICATE:
                /*
-                * when it returns, eap_ds->reply is expected to have complete info
+                *   The called function updates the EAP reply packet.
                 */
-               if (!atype->type->authenticate(atype->type_stuff, handler))
+               if (!atype->type->authenticate ||
+                   !atype->type->authenticate(atype->type_data, handler))
                        return 0;
                break;
+
        default:
                /* Should never enter here */
                radlog(L_DBG, "rlm_eap: Invalid operation  on eap_type");
@@ -230,27 +203,27 @@ int eaptype_call(int eap_type, operation_t action,
  * Default to the configured EAP-Type 
  * for all Unsupported EAP-Types 
  */
-int eaptype_select(EAP_TYPES *type_list, EAP_HANDLER *handler, char *conftype)
+int eaptype_select(rlm_eap_t *inst, EAP_HANDLER *handler)
 {
-       int type = 0, i;
        eaptype_t *eaptype;
 
-       for (i = PW_EAP_MAX_TYPES; i > 0; i--) {
-               if (strcmp(conftype, eap_types[i]) == 0) {
-                       type = i;
-                       break;
-               }
-       }
+       eaptype = &handler->eap_ds->response->type;
 
-       if (type == 0) {
-               radlog(L_ERR, "rlm_eap: Configured  EAP_TYPE is not supported");
+       /*
+        *      Don't trust anyone.
+        */
+       if ((eaptype->type == 0) ||
+           (eaptype->type > PW_EAP_MAX_TYPES)) {
+               return EAP_INVALID;
        }
 
-       eaptype = &handler->eap_ds->response->type;
        switch(eaptype->type) {
        case PW_EAP_IDENTITY:
                DEBUG2("  rlm_eap: EAP Identity");
-               if (eaptype_call(type, INITIATE, type_list, handler) == 0)
+       do_default_type:
+               handler->stage = INITIATE;
+               if (eaptype_call(inst->types[inst->default_eap_id],
+                                handler) == 0)
                        return EAP_INVALID;
                        break;
 
@@ -260,11 +233,21 @@ int eaptype_select(EAP_TYPES *type_list, EAP_HANDLER *handler, char *conftype)
                 * It is invalid to request identity, notification & nak in nak
                 */
                if ((eaptype->data != NULL) &&
-                       (eaptype->data[0] < PW_EAP_MD5)) {
+                   (eaptype->data[0] < PW_EAP_MD5)) {
                        return EAP_INVALID;
                }
 
                /*
+                *      Delete old data, if necessary.
+                */
+               if (handler->opaque && handler->free_opaque) {
+                       handler->free_opaque(handler->opaque);
+                       handler->free_opaque = NULL;
+                       handler->opaque = NULL;
+               }
+               handler->stage = INITIATE;
+
+               /*
                 *      The one byte of NAK data is the preferred EAP type
                 *      of the client.
                 */
@@ -272,23 +255,27 @@ int eaptype_select(EAP_TYPES *type_list, EAP_HANDLER *handler, char *conftype)
                case PW_EAP_MD5:
                case PW_EAP_TLS:
                case PW_EAP_LEAP:
+                       DEBUG2("  rlm_eap: EAP_TYPE - %s",
+                               eap_types[eaptype->data[0]]);
+
                        /*
-                        * eap-type specified in typdata is supported
+                        *      Call the type.
                         */
-                       if (eaptype_call(eaptype->data[0],
-                               INITIATE, type_list, handler) == 0)
+                       if (eaptype_call(inst->types[eaptype->data[0]],
+                                        handler) == 0)
                                return EAP_INVALID;
+                 
                        break;
                default :
-                       DEBUG2("  rlm_eap: Unknown EAP type %d, reverting to default_eap_type",
-                              eaptype->data[0]);
+                       DEBUG2("  rlm_eap: Unknown EAP type %d, reverting to default_eap_type %s",
+                              eaptype->data[0], inst->default_eap_type);
+
                        /*
                         * Unsupported type, default to configured one.
                         * or rather reject it
                         */
                        /* handler->eap_ds->request->code = PW_EAP_FAILURE; */
-                       if (eaptype_call(type, INITIATE, type_list, handler) == 0)
-                               return EAP_INVALID;
+                       goto do_default_type;
                        break;
                }
                break;
@@ -300,10 +287,11 @@ int eaptype_select(EAP_TYPES *type_list, EAP_HANDLER *handler, char *conftype)
                default:
                        DEBUG2("  rlm_eap: EAP_TYPE - %s",
                                eap_types[eaptype->type]);
-                       if (eaptype_call(eaptype->type, AUTHENTICATE,
-                               type_list, handler) == 0) {
+
+                       rad_assert(handler->stage == AUTHENTICATE);
+                       if (eaptype_call(inst->types[eaptype->type],
+                                        handler) == 0)
                                return EAP_INVALID;
-               }
                break;
        }
        return EAP_OK;
@@ -401,9 +389,10 @@ eap_packet_t *eap_attribute(VALUE_PAIR *vps)
 }
 
 /*
- * EAP packet format to be sent over the wire
- * ie code+id+length+data where data = null/type+typedata
- * based on code.
+ *     EAP packet format to be sent over the wire
+ *
+ *     i.e. code+id+length+data where data = null/type+typedata
+ *     based on code.
  */
 int eap_wireformat(EAP_PACKET *reply)
 {
@@ -437,8 +426,11 @@ int eap_wireformat(EAP_PACKET *reply)
 
                /*
                 * Here since we cannot know the typedata format and length
+                *
                 * Type_data is expected to be wired by each EAP-Type
-                * Zero length/No typedata is supported as long as type is defined
+                *
+                * Zero length/No typedata is supported as long as
+                * type is defined
                 */
                if (reply->type.data && reply->type.length > 0) {
                        memcpy(&hdr->data[1], reply->type.data, reply->type.length);
@@ -451,10 +443,11 @@ int eap_wireformat(EAP_PACKET *reply)
 }
 
 /*
- * compose EAP reply packet in EAP-Message attr of RADIUS.
- * If EAP exceeds 253, frame it in multiple EAP-Message attrs.
- * Set the RADIUS reply codes based on EAP request codes
- * Append any additonal VPs to RADIUS reply
+ *     compose EAP reply packet in EAP-Message attr of RADIUS.  If
+ *     EAP exceeds 253, frame it in multiple EAP-Message attrs.
+ *
+ *     Set the RADIUS reply codes based on EAP request codes.  Append
+ *     any additonal VPs to RADIUS reply
  */
 int eap_compose(REQUEST *request, EAP_DS *eap_ds)
 {
@@ -465,16 +458,16 @@ int eap_compose(REQUEST *request, EAP_DS *eap_ds)
        eap_packet_t *eap_packet;
        unsigned char   *ptr;
        EAP_PACKET *reply = eap_ds->request;
+       int rcode;
 
        /*
-        * ID serves to suppport request/response
-        * retransmission in the EAP layer and as
-        * such must be different for 'adjacent'
-        * packets except in case of success/failure-replies.
+        *      ID serves to suppport request/response
+        *      retransmission in the EAP layer and as such must be
+        *      different for 'adjacent' packets except in case of
+        *      success/failure-replies.
         *
-        * RFC2716 (EAP_TLS) requires this to be
-        * incremented, RFC2284 only makes the above-
-        * mentioned restriction.
+        *      RFC2716 (EAP_TLS) requires this to be incremented,
+        *      RFC2284 only makes the above- mentioned restriction.
         */
        eap_msg = pairfind(request->packet->vps, PW_EAP_MESSAGE);
        rq = (EAP_PACKET *)eap_msg->strvalue;
@@ -500,7 +493,7 @@ int eap_compose(REQUEST *request, EAP_DS *eap_ds)
        }
 
        if (eap_wireformat(reply) == EAP_INVALID) {
-               return EAP_INVALID;
+               return RLM_MODULE_INVALID;
        }
        eap_packet = (eap_packet_t *)reply->packet;
 
@@ -544,26 +537,21 @@ int eap_compose(REQUEST *request, EAP_DS *eap_ds)
                pairadd(&(request->reply->vps), vp);
        }
 
-       /*
-        * Generate State, only if it not Identity request
-        */ 
-       if ((eap_packet->code == PW_EAP_REQUEST) &&
-           (eap_packet->data[0] >= PW_EAP_MD5)) {
-               vp = generate_state();
-               pairadd(&(request->reply->vps), vp);
-       }
-               
        /* Set request reply code, but only if it's not already set. */
+       rcode = RLM_MODULE_OK;
        if (!request->reply->code) switch(reply->code) {
        case PW_EAP_RESPONSE:
        case PW_EAP_SUCCESS:
                request->reply->code = PW_AUTHENTICATION_ACK;
+               rcode = RLM_MODULE_HANDLED;
                break;
        case PW_EAP_FAILURE:
                request->reply->code = PW_AUTHENTICATION_REJECT;
+               rcode = RLM_MODULE_REJECT;
                break;
        case PW_EAP_REQUEST:
                request->reply->code = PW_ACCESS_CHALLENGE;
+               rcode = RLM_MODULE_HANDLED;
                break;
        default:
                /* Should never enter here */
@@ -571,7 +559,8 @@ int eap_compose(REQUEST *request, EAP_DS *eap_ds)
                request->reply->code = PW_AUTHENTICATION_REJECT;
                break;
        }
-       return 0;
+
+       return rcode;
 }
 
 /*
@@ -705,29 +694,6 @@ int eap_validation(eap_packet_t *eap_packet)
 
 
 /*
- *  Get the user Identity if at all it is available with us.
- */
-VALUE_PAIR *eap_useridentity(EAP_HANDLER *list, eap_packet_t *eap_packet, unsigned char id[])
-{
-       char *un;
-       VALUE_PAIR *username;
-       EAP_HANDLER *handler;
-
-       if ((un = eap_identity(eap_packet)) != NULL) {
-               username = pairmake("User-Name", un, T_OP_EQ);
-               free(un);
-               return username;
-       }
-
-       /* Get the handler from the list, if present */
-       handler = eaplist_findhandler(list, id);
-       if (handler)
-               return pairmake("User-Name", handler->identity, T_OP_EQ);
-       return NULL;
-}
-
-
-/*
  *  Get the user Identity only from EAP-Identity packets
  */
 char *eap_identity(eap_packet_t *eap_packet)
@@ -737,8 +703,8 @@ char *eap_identity(eap_packet_t *eap_packet)
        char *identity;
 
        if ((eap_packet == NULL) ||
-               (eap_packet->code != PW_EAP_RESPONSE) ||
-               (eap_packet->data[0] != PW_EAP_IDENTITY)) {
+           (eap_packet->code != PW_EAP_RESPONSE) ||
+           (eap_packet->data[0] != PW_EAP_IDENTITY)) {
                return NULL;
        }
 
@@ -822,10 +788,10 @@ static EAP_DS *eap_buildds(eap_packet_t **eap_packet_p)
  * username contains REQUEST->username which might have been stripped.
  * identity contains the one sent in EAP-Identity response
  */
-EAP_HANDLER *eap_handler(EAP_HANDLER **list, eap_packet_t **eap_packet_p, REQUEST *request)
+EAP_HANDLER *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_packet_p,
+                        REQUEST *request)
 {
        EAP_HANDLER     *handler = NULL;
-       unsigned char   *unique;
        eap_packet_t    *eap_packet = NULL;
 
        eap_packet = *eap_packet_p;
@@ -837,14 +803,7 @@ EAP_HANDLER *eap_handler(EAP_HANDLER **list, eap_packet_t **eap_packet_p, REQUES
         * EAP_HANDLER MUST be found in the list if it is not EAP-Identity response
         */
        if (eap_packet->data[0] != PW_EAP_IDENTITY) {
-               unique = eap_regenerateid(request, eap_packet->id);
-               if (unique == NULL) {
-                       return NULL;
-               }
-
-               handler = eaplist_isreply(list, unique);
-               free(unique);
-               unique = NULL;
+               handler = eaplist_find(inst, request, eap_packet->id);
                if (handler == NULL) {
                        /* Either send EAP_Identity or EAP-Fail */
                        radlog(L_ERR, "rlm_eap: Either EAP-request timed out OR"
@@ -858,13 +817,9 @@ EAP_HANDLER *eap_handler(EAP_HANDLER **list, eap_packet_t **eap_packet_p, REQUES
                        return NULL;
                }
 
-               handler->id = NULL;
-               handler->prev_eapds = NULL;
-               handler->eap_ds = NULL;
-               handler->configured = NULL;
-               handler->opaque = NULL;
-               handler->free_opaque = NULL;
-               handler->next = NULL;
+               /*
+                *      all fields are set to zero.
+                */
 
                handler->identity = eap_identity(eap_packet);
                if (handler->identity == NULL) {
@@ -889,30 +844,6 @@ EAP_HANDLER *eap_handler(EAP_HANDLER **list, eap_packet_t **eap_packet_p, REQUES
                }
                */
 
-               /*
-                * Always get the configured values, for each user.
-                * to pass it to the specific EAP-Type
-                *
-                * No Configured information found for a user, means
-                * there is no such user in the database.
-                *
-                * Every user should have, atleast, one item configured
-                * This is required for Authentication purpose.
-                */
-               handler->configured = paircopy(request->config_items);
-               if (handler->configured == NULL) {
-                       DEBUG2("  rlm_eap: No configured information for this user");
-
-                       /*
-                        * FIXME: If there is no config info then
-                        * config_items should provide the same username
-                        * if the user is present in the database.
-                        */
-                       /*
-                       eap_handler_free(&handler);
-                       return NULL;
-                       */
-               }
        }
 
        handler->eap_ds = eap_buildds(eap_packet_p);
@@ -922,86 +853,6 @@ EAP_HANDLER *eap_handler(EAP_HANDLER **list, eap_packet_t **eap_packet_p, REQUES
        }
 
        handler->timestamp = time(NULL);
-       handler->reply_vps = &(request->reply->vps);
        handler->request = request; /* LEAP needs this */
        return handler;
 }
-
-
-/*
- * Regenerate the ID to match the ID stored in the list.
- * This ID is created based on the NAS, State & EAP-Response
- */
-unsigned char *eap_regenerateid(REQUEST *request, unsigned char response_id)
-{
-       VALUE_PAIR      *state = NULL;
-       unsigned char   *id = NULL;
-
-       state = pairfind(request->packet->vps, PW_STATE);
-       if (state == NULL) {
-               DEBUG2("  rlm_eap: NO State Attribute found: Cannot match EAP packet to any existing conversation.");
-               return NULL;
-       }
-       if (verify_state(state) != 0) {
-               radlog(L_ERR, "rlm_eap: State verification failed.");
-               return NULL;
-       }
-
-       id = (unsigned char *)malloc(1/*Length*/ + 1/*Id*/ + state->length + sizeof(request->packet->src_ipaddr));
-       if (id == NULL) {
-               radlog(L_ERR, "rlm_eap: out of memory");
-               return NULL;
-       }
-
-       /*
-        * Generate unique-id to check for the reply 
-        * id = Length + ID + State + Client IP Address
-        *
-        *  Note that we do NOT use NAS-IP-Address, or NAS-Identifier,
-        *  as they may lie to us!
-        */
-       id[0] = (1 + 1 + state->length + sizeof(request->packet->src_ipaddr)) & 0xFF;
-       memcpy(id+1, &response_id, sizeof(unsigned char));
-       memcpy(id+2, state->strvalue, state->length);
-       memcpy(id+2+state->length, &request->packet->src_ipaddr,
-              sizeof(request->packet->src_ipaddr));
-
-       return id;
-}
-
-/*
- * Generate the ID that is used as the search criteria in the list.
- * This ID is created based on the NAS, State & EAP-Request
- */
-unsigned char *eap_generateid(REQUEST *request, unsigned char response_id)
-{
-       VALUE_PAIR      *state = NULL;
-       unsigned char   *id = NULL;
-
-       state = pairfind(request->reply->vps, PW_STATE);
-       if (state == NULL) {
-               DEBUG2("  rlm_eap: NO State Attribute found.  Cannot match the EAP packet to any existing conversation.");
-               return NULL;
-       }
-
-       id = (unsigned char *)malloc(1/*Length*/ + 1/*Id*/ + state->length + sizeof(request->packet->src_ipaddr));
-       if (id == NULL) {
-               radlog(L_ERR, "rlm_eap: out of memory");
-               return NULL;
-       }
-
-       /*
-        * Generate unique-id to check for the reply 
-        * id = Length + ID + State + Client IP Address
-        *
-        *  Note that we do NOT use NAS-IP-Address, or NAS-Identifier,
-        *  as they may lie to us!
-        */
-       id[0] = (1 + 1 + state->length + sizeof(request->packet->src_ipaddr)) & 0xFF;
-       memcpy(id+1, &response_id, sizeof(unsigned char));
-       memcpy(id+2, state->strvalue, state->length);
-       memcpy(id+2+state->length, &request->packet->src_ipaddr,
-               sizeof(request->packet->src_ipaddr));
-
-       return id;
-}
index b2aef4f..29c03c5 100644 (file)
@@ -38,6 +38,7 @@
 #include "radiusd.h"
 #include "modules.h"
 
+#include "rad_assert.h"
 
 #define PW_EAP_REQUEST         1
 #define PW_EAP_RESPONSE                2
@@ -97,15 +98,34 @@ typedef struct eap_ds {
 } EAP_DS;
 
 /*
+ * Currently there are only 2 types
+ * of operations defined, 
+ * apart from attach & detach for each EAP-Type.
+ */
+typedef enum operation_t {
+       INITIATE = 0,
+       AUTHORIZE,
+       AUTHENTICATE
+} operation_t;
+
+
+/*
  * EAP_HANDLER is the interface for any EAP-Type.
  * Each handler contains information for one specific EAP-Type.
  * This way we don't need to change any interfaces in future.
  * It is also a list of EAP-request handlers waiting for EAP-response
+ * eap_id = copy of the eap packet we sent to the 
  *
- * id = Length + Request-ID + State + (NAS-IP-Address|NAS-Identifier)
+ * next = pointer to next
+ * state = state attribute from the reply we sent
+ * state_len = length of data in the state attribute.
+ * src_ipaddr = client which sent us the RADIUS request containing
+ *              this EAP conversation.
+ * eap_id = copy of EAP id we sent to the client.
+ * timestamp  = timestamp when this handler was last used.
  * identity = Identity, as obtained, from EAP-Identity response.
  * username = as obtained in Radius request, It might differ from identity.
- * configured = List of configured values for this user.
+ * request = RADIUS request data structure
  * prev_eapds = Previous EAP request, for which eap_ds contains the response.
  * eap_ds   = Current EAP response.
  * opaque   = EAP-Type holds some data that corresponds to the current
@@ -116,29 +136,32 @@ typedef struct eap_ds {
  *             to avoid any memory leaks in opaque
  *             Hence this pointer should be provided by the EAP-Type
  *             if opaque is not NULL
- * timestamp  = timestamp when this handler is created.
  * status   = finished/onhold/..
  */
+#define EAP_STATE_LEN (AUTH_VECTOR_LEN)
 typedef struct _eap_handler {
-       unsigned char   *id;
+       struct _eap_handler *next;
+
+       uint8_t         state[EAP_STATE_LEN];
+       uint32_t        src_ipaddr;
+       int             eap_id;
 
-       VALUE_PAIR      *username;
-       VALUE_PAIR      *configured;
+       time_t          timestamp;
+
+       VALUE_PAIR      *username; /* SHOULD get rid of this! */
        REQUEST         *request;
-        VALUE_PAIR      **reply_vps;
 
-       char    *identity;
+       char            *identity; /* user identity? Huh? */
 
-       EAP_DS  *prev_eapds;
-       EAP_DS  *eap_ds;
+       EAP_DS          *prev_eapds;
+       EAP_DS          *eap_ds;
 
-       void    *opaque;
-       void    (*free_opaque)(void **opaque);
+       void            *opaque;
+       void            (*free_opaque)(void *opaque);
 
-       time_t  timestamp;
-       int     status;
+       int             status;
 
-       struct _eap_handler *next;
+       int             stage;
 } EAP_HANDLER;
 
 /* 
@@ -146,10 +169,11 @@ typedef struct _eap_handler {
  */
 typedef struct eap_type_t {
        const   char *name;
-       int     (*attach)(CONF_SECTION *conf, void **type_arg);
-       int     (*initiate)(void *type_arg, EAP_HANDLER *handler);
-       int     (*authenticate)(void *type_arg, EAP_HANDLER *handler);
-       int     (*detach)(void **type_arg);
+       int     (*attach)(CONF_SECTION *conf, void **type_data);
+       int     (*initiate)(void *type_data, EAP_HANDLER *handler);
+       int     (*authorize)(void *type_data, EAP_HANDLER *handler);
+       int     (*authenticate)(void *type_data, EAP_HANDLER *handler);
+       int     (*detach)(void *type_data);
 } EAP_TYPE;
 
 #endif /*_EAP_H*/
index 9d3e8ff..dd25e06 100644 (file)
@@ -122,24 +122,20 @@ void eap_handler_free(EAP_HANDLER **handler_p)
                return;
 
        handler = *handler_p;
-       if (handler->id) {
-               free(handler->id);
-               handler->id = NULL;
-       }
-
        if (handler->identity) {
                free(handler->identity);
                handler->identity = NULL;
        }
 
        if (handler->username) pairfree(&(handler->username));
-       if (handler->configured) pairfree(&(handler->configured));
 
        if (handler->prev_eapds) eap_ds_free(&(handler->prev_eapds));
        if (handler->eap_ds) eap_ds_free(&(handler->eap_ds));
 
-       if ((handler->opaque) && (handler->free_opaque))
-               handler->free_opaque(&(handler->opaque));
+       if ((handler->opaque) && (handler->free_opaque)) {
+               handler->free_opaque(handler->opaque);
+               handler->opaque = NULL;
+       }
        else if ((handler->opaque) && (handler->free_opaque == NULL))
                 radlog(L_ERR, "Possible memory leak ...");
 
@@ -151,114 +147,185 @@ void eap_handler_free(EAP_HANDLER **handler_p)
        *handler_p = NULL;
 }
 
-void eaptype_freelist(EAP_TYPES **i)
+void eaptype_free(EAP_TYPES *i)
 {
-       EAP_TYPES       *c, *next;
-
-       c = *i;
-       while (c) {
-               next = c->next;
-               if(c->type->detach) (c->type->detach)(&(c->type_stuff));
-               if (c->handle) lt_dlclose(c->handle);
-               free(c);
-               c = next;
-       }
-       *i = NULL;
+       if (i->type->detach) (i->type->detach)(i->type_data);
+       i->type_data = NULL;
+       if (i->handle) lt_dlclose(i->handle);
 }
 
-void eaplist_free(EAP_HANDLER **list)
+void eaplist_free(rlm_eap_t *inst)
 {
-       EAP_HANDLER *node, *next;
+       int i;
 
-       if (!list) return;
+       /*
+        *      The sessions are split out into an array, which makes
+        *      looking them up a bit faster.
+        */
+       for (i = 0; i < 256; i++) {
+               EAP_HANDLER *node, *next;
 
-       node = *list;
-       while (node) {
-               next = node->next;
-               eap_handler_free(&node);
-               node = next;
-       }
+               if (inst->sessions[i]) continue;
 
-       *list = NULL;
+               node = inst->sessions[i];
+               while (node) {
+                       next = node->next;
+                       eap_handler_free(&node);
+                       node = next;
+               }
+               
+               inst->sessions[i] = NULL;
+       }
 }
 
 /*
- * TODO: For now this is a plain list.
- *  It can be hashed on EAP-Type, EAP-Id
+ *     Add a handler to the set of active sessions.
+ *
+ *     Since we're adding it to the list, we guess that this means
+ *     the packet needs a State attribute.  So add one.
  */
-int eaplist_add(EAP_HANDLER **list, EAP_HANDLER *node)
+int eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler)
 {
        EAP_HANDLER     **last;
-
-       if (node == NULL) return 0;
-       
-       last = list;
+       VALUE_PAIR      *state;
+
+       rad_assert(handler != NULL);
+       rad_assert(handler->request != NULL);
+
+       /*
+        *      Generate State, since we've been asked to add it to
+        *      the list.
+        */
+       state = generate_state(handler->request->timestamp);
+       pairadd(&(handler->request->reply->vps), state);
+               
+       /*
+        *      Create a unique 'key' for the handler, based
+        *      on State, Client-IP-Address, and EAP ID.
+        */
+       rad_assert(state->length == EAP_STATE_LEN);
+
+       memcpy(handler->state, state->strvalue, sizeof(handler->state));
+       handler->src_ipaddr = handler->request->packet->src_ipaddr;
+       handler->eap_id = handler->eap_ds->request->id;
+
+       /*
+        *      We key the array based on the challenge, which is
+        *      a random number.  This "fans out" the sessions, and
+        *      helps to minimize the amount of work we've got to do
+        *      under heavy load.
+        */
+       last = &(inst->sessions[state->strvalue[0]]);
        while (*last) last = &((*last)->next);
        
-       node->timestamp = time(NULL);
-       node->status = 1;
-       node->next = NULL;
+       /*
+        *      The time at which this request was made was the time
+        *      at which it was received by the RADIUS server.
+        */
+       handler->timestamp = handler->request->timestamp;
+       handler->status = 1;
+       handler->next = NULL;
+
+       /*
+        *      We don't need this any more.
+        */
+       handler->request = NULL;
 
-       *last = node;
+       *last = handler;
        return 1;
 }
 
 /*
- * List should contain only recent packets with life < x seconds.
+ *     Find a a previous EAP-Request sent by us, which matches
+ *     the current EAP-Response.
+ *
+ *     Then, release the handle from the list, and return it to
+ *     the caller.
+ *
+ *     Also since we fill the eap_ds with the present EAP-Response we
+ *     got to free the prev_eapds & move the eap_ds to prev_eapds
  */
-void eaplist_clean(EAP_HANDLER **first, time_t limit)
+EAP_HANDLER *eaplist_find(rlm_eap_t *inst, REQUEST *request, int eap_id)
 {
-       time_t  now;
-        EAP_HANDLER *node, *next;
-        EAP_HANDLER **last = first;
+       EAP_HANDLER     *node, *next, *ret = NULL;
+       VALUE_PAIR      *state;
+       EAP_HANDLER     **first,  **last;
+
+       /*
+        *      We key the sessions off of the 'state' attribute, so it
+        *      must exist.
+        */
+       state = pairfind(request->packet->vps, PW_STATE);
+       if (!state ||
+           (state->length != EAP_STATE_LEN)) {
+               return NULL;
+       }
 
-       now = time(NULL);
+       last = first = &(inst->sessions[state->strvalue[0]]);
 
        for (node = *first; node; node = next) {
                next = node->next;
-               if ((now - node->timestamp) > limit) {
-                       DEBUG2("  rlm_eap:  list_clean deleted one item");
+
+               /*
+                *      If the time on this entry has expired, 
+                *      delete it.  We do this while walking the list,
+                *      in order to spread out the work of deleting old
+                *      sessions.
+                */
+               if ((request->timestamp - node->timestamp) > inst->timer_limit) {
                        *last = next;
                        eap_handler_free(&node);
-               } else  {
-                       last = &(node->next);
+                       continue;
                }
-       }
-}
 
-/*
- * If the present EAP-Response is a reply to the previous
- * EAP-Request sent by us, then return the EAP_HANDLER
- * only after releasing from the eaplist
- * Also since we fill the eap_ds with the present EAP-Response
- * we got to free the prev_eapds & move the eap_ds to prev_eapds
- */
-EAP_HANDLER *eaplist_isreply(EAP_HANDLER **first, unsigned char id[])
-{
-       EAP_HANDLER *node, *next, *ret = NULL;
-       EAP_HANDLER **last = first;
-
-       for (node = *first; node; node = next) {
-               next = node->next;
-               if (memcmp(node->id, id, id[0]) == 0) {
+               /*
+                *      Find the previous part of the same conversation,
+                *      keying off of the EAP ID, the client IP, and
+                *      the State attribute.
+                *
+                *      If we've found a conversation, then we don't
+                *      have to check entries later in the list for
+                *      timeout, as they're guaranteed to be newer than
+                *      the one we found.
+                */
+               if ((node->eap_id == eap_id) &&
+                   (node->src_ipaddr == request->packet->src_ipaddr) &&
+                   (memcmp(node->state, state->strvalue, state->length) == 0)) {
+                       /*
+                        *      Check against replays.  The client can
+                        *      re-play a State attribute verbatim, so
+                        *      we wish to ensure that the attribute falls
+                        *      within the valid time window, which is
+                        *      the second at which it was sent out.
+                        */
+                       if (verify_state(state, node->timestamp) != 0) {
+                               radlog(L_ERR, "rlm_eap: State verification failed.");
+                               return NULL;
+                       }
+                       
                        DEBUG2("  rlm_eap: Request found, released from the list");
-                       /* detach the node from the list */
+                       /*
+                        *      detach the node from the list
+                        */
                        *last = next;
                        node->next = NULL;
 
-                       /* clean up the unwanted stuff before returning */
+                       /*
+                        *      Don't bother updating handler->request, etc.
+                        *      eap_handler() will do that for us.
+                        */
 
-                       /* Clear the handler Id */
-                       free(node->id);
-                       node->id = NULL;
-
-                       /* Move the current EAP to prev EAP after clearing prev_eap */
+                       /*
+                        *      Remember what the previous request was.
+                        */
                        eap_ds_free(&(node->prev_eapds));
                        node->prev_eapds = node->eap_ds;
                        node->eap_ds = NULL;
 
-                       ret = node;
-                       break;
+                       /*
+                        *      And return it to the caller.
+                        */
+                       return node;
                } else  {
                        last = &(node->next);
                }
@@ -269,21 +336,3 @@ EAP_HANDLER *eaplist_isreply(EAP_HANDLER **first, unsigned char id[])
        }
        return ret;
 }
-
-EAP_HANDLER *eaplist_findhandler(EAP_HANDLER *list, unsigned char id[])
-{
-       EAP_HANDLER *node;
-       node = list;
-       
-       while (node) {
-               /*
-                * Match is identified by the same IDs 
-                */
-               if (memcmp(node->id, id, id[0]) == 0) {
-                       DEBUG2("  rlm_eap: EAP Handler found in the list ");
-                       return node;
-               }
-               node = node->next;
-       }
-       return NULL;
-}
index 356dc5d..9af5f7a 100644 (file)
 #include "modules.h"
 
 static CONF_PARSER module_config[] = {
-       { "default_eap_type", PW_TYPE_STRING_PTR, offsetof(EAP_CONF, default_eap_type), NULL, "md5" },
-       { "timer_expire", PW_TYPE_INTEGER, offsetof(EAP_CONF, timer_limit), NULL, "60"},
-
+       { "default_eap_type", PW_TYPE_STRING_PTR,
+         offsetof(rlm_eap_t, default_eap_type), NULL, "md5" },
+       { "timer_expire", PW_TYPE_INTEGER,
+         offsetof(rlm_eap_t, timer_limit), NULL, "60"},
+       
        { NULL, -1, 0, NULL, NULL }           /* end the list */
 };
 
@@ -39,136 +41,125 @@ static int eap_init(void)
 
 
 /*
+ * delete all the allocated space by eap module
+ */
+static int eap_detach(void *instance)
+{
+       rlm_eap_t *inst;
+       int i;
+
+       inst = (rlm_eap_t *)instance;
+
+       eaplist_free(inst);
+
+       for (i = 0; i < PW_EAP_MAX_TYPES; i++) {
+               if (inst->types[i]) eaptype_free(inst->types[i]);
+               inst->types[i] = NULL;
+       }
+
+       if (inst->default_eap_type) free(inst->default_eap_type);
+       free(inst);
+
+       return 0;
+}
+
+
+/*
  * read the config section and load all the eap authentication types present.
  */
 static int eap_instantiate(CONF_SECTION *cs, void **instance)
 {
-       char            *auth_type;
+       int             id;
+       int             num_types;
        CONF_SECTION    *scs;
-       EAP_TYPES       *types;
-       EAP_CONF        *conf;
-       rlm_eap_t       **eap_stuff;
+       rlm_eap_t       *inst;
        
-       eap_stuff = (rlm_eap_t **)instance;
-       types    = NULL;
-       conf     = NULL;
-       auth_type = NULL;
-
-       conf = (EAP_CONF *)malloc(sizeof(*conf));
-       if (conf == NULL) {
-               radlog(L_ERR, "rlm_eap: out of memory");
+       inst = (rlm_eap_t *) malloc(sizeof(*inst));
+       if (!inst) {
                return -1;
        }
-       memset(conf, 0, sizeof(*conf));
-       if (cf_section_parse(cs, conf, module_config) < 0) {
-               free(conf);
+       memset(inst, 0, sizeof(*inst));
+       if (cf_section_parse(cs, inst, module_config) < 0) {
+               eap_detach(inst);
                return -1;
        }
 
        /* Load all the configured EAP-Types */
+       num_types = 0;
        for(scs=cf_subsection_find_next(cs, NULL, NULL);
                scs != NULL;
                scs=cf_subsection_find_next(cs, scs, NULL)) {
 
+               char    *auth_type;
+
                auth_type = cf_section_name1(scs);
 
                if (!auth_type)  continue;
 
-               if (eaptype_load(&types, auth_type, scs) < 0) {
-                       free(conf);
+               id = eaptype_name2id(auth_type);
+               if (id < 0) {
+                       radlog(L_ERR|L_CONS, "rlm_eap: Unknown EAP type %s",
+                              auth_type);
+                       eap_detach(inst);
+                       return -1;
+               }
+
+               if (eaptype_load(&inst->types[id], id, scs) < 0) {
+                       eap_detach(inst);
                        return -1;
                }
+
+               num_types++;    /* successfully loaded one more types */
        }
 
-       if (!types) {
-               free(conf->default_eap_type);
-               conf->default_eap_type = NULL;
-               free(conf);
-               conf = NULL;
+       if (num_types == 0) {
+               radlog(L_ERR|L_CONS, "rlm_eap: No EAP type configured, module cannot do anything.");
+               eap_detach(inst);
                return -1;
        }
 
-       *eap_stuff = (rlm_eap_t *)malloc(sizeof(rlm_eap_t));
-       if (*eap_stuff) {
-               (*eap_stuff)->typelist = types;
-               (*eap_stuff)->echolist = NULL;
-               (*eap_stuff)->conf = conf;
-       }  else {
-               radlog(L_ERR, "rlm_eap: out of memory");
-               eaptype_freelist(&types);
-               free(conf->default_eap_type);
-               conf->default_eap_type = NULL;
-               free(conf);
-               conf = NULL;
+       /*
+        *      Ensure that the default EAP type is loaded.
+        */
+       id = eaptype_name2id(inst->default_eap_type);
+       if (id < 0) {
+               radlog(L_ERR|L_CONS, "rlm_eap: Unknown default EAP type %s",
+                      inst->default_eap_type);
+               eap_detach(inst);
                return -1;
        }
 
-       /* Generate a state key, specific to eap */
-       generate_key();
-       return 0;
-}
-
-/*
- * delete all the allocated space by eap module
- */
-static int eap_detach(void *instance)
-{
-       rlm_eap_t *t;
-       t = (rlm_eap_t *)instance;
-
-       eaplist_free(&(t->echolist));
-       eaptype_freelist(&(t->typelist));
-
-       free(t->conf->default_eap_type);
-       free(t->conf);
+       if (inst->types[id] == NULL) {
+               radlog(L_ERR|L_CONS, "rlm_eap: No such sub-type for default EAP type %s",
+                      inst->default_eap_type);
+               eap_detach(inst);
+               return -1;
+       }
+       inst->default_eap_id = id;
 
-       free(t);
-       t = NULL;
+       /*
+        *      List of sessions are set to NULL by the memset
+        *      of 'inst', above.
+        */
 
+       /* Generate a state key, specific to eap */
+       generate_key();
+       
+       *instance = inst;
        return 0;
 }
 
 /*
- * Assumption: Any one of the Authorization module should
- *     get the configured password for any valid user.
- *     If not, Authentication fails to validate.
- *
- * All EAP types will be handled in their respective sub modules.
- *
- * To Handle EAP-response, we keep track of the EAP-request we send.
- * When Success or Failure or when timed out, we delete them.
+ *     For backwards compatibility.
  */
 static int eap_authenticate(void *instance, REQUEST *request)
 {
+       rlm_eap_t       *inst;
        EAP_HANDLER     *handler;
-       rlm_eap_t       *eap_stuff;
        eap_packet_t    *eap_packet;
-       int             status;
-
-       eap_stuff = (rlm_eap_t *)instance;
+       int             rcode;
 
-       /* 
-        * Always, clean the list first as it is not timer based
-        * FIXME: Appropriate cleaning mechanism.
-        */
-       eaplist_clean(&(eap_stuff->echolist), (time_t)eap_stuff->conf->timer_limit);
-
-       /*
-        * Incase if EAP is not configured in autz block
-        * or eap_authorize is not invoked
-        */
-       status = eap_start(request);
-       switch(status) {
-       case EAP_NOOP:
-               return RLM_MODULE_NOOP;
-       case EAP_FAIL:
-               return RLM_MODULE_FAIL;
-       case EAP_FOUND:
-               return RLM_MODULE_OK;
-       case EAP_NOTFOUND:
-       default:
-               break;
-       }
+       inst = (rlm_eap_t *) instance;
 
        /* get the eap packet  to start with */
        eap_packet = eap_attribute(request->packet->vps);
@@ -178,15 +169,15 @@ static int eap_authenticate(void *instance, REQUEST *request)
        }
 
        /*
-        * create the eap handler 
+        *      Create the eap handler 
         */
-       handler = eap_handler(&(eap_stuff->echolist), &eap_packet, request);
+       handler = eap_handler(inst, &eap_packet, request);
        if (handler == NULL) {
                return RLM_MODULE_INVALID;
        }
 
        /*
-        * No User-Name, No authentication
+        *      No User-Name, No authentication
         */
        if (handler->username == NULL) {
                radlog(L_ERR, "rlm_eap: Unknown User, authentication failed");
@@ -196,10 +187,10 @@ static int eap_authenticate(void *instance, REQUEST *request)
        }
 
        /*
-        * Select the appropriate eap_type or default to the configured one
+        *      Select the appropriate eap_type or default to the
+        *      configured one
         */
-       if (eaptype_select(eap_stuff->typelist, handler,
-               eap_stuff->conf->default_eap_type) == EAP_INVALID) {
+       if (eaptype_select(inst, handler) == EAP_INVALID) {
 
                eap_fail(request, handler->eap_ds);
                eap_handler_free(&handler);
@@ -207,24 +198,18 @@ static int eap_authenticate(void *instance, REQUEST *request)
        }
 
        /*
-        * We are done, wrap the EAP-request in RADIUS to send
-        * with all other required radius attributes
+        *      We are done, wrap the EAP-request in RADIUS to send
+        *      with all other required radius attributes
         */
-       eap_compose(request, handler->eap_ds);
+       rcode = eap_compose(request, handler->eap_ds);
 
        /*
-        * Add to the list only if it is EAP-Request,
-        * OR if it's LEAP, and a response.
+        *      Add to the list only if it is EAP-Request, OR if
+        *      it's LEAP, and a response.
         */
        if ((handler->eap_ds->request->code == PW_EAP_REQUEST) &&
            (handler->eap_ds->request->type.type >= PW_EAP_MD5)) {
-               handler->id = eap_generateid(request, (u_char)handler->eap_ds->request->id);
-               if (handler->id == NULL) {
-                       radlog(L_ERR, "rlm_eap: problem in generating ID, Present EAP is not valid");
-                       eap_handler_free(&handler);
-               } else {
-                       eaplist_add(&(eap_stuff->echolist), handler);
-               }
+               eaplist_add(inst, handler);
 
                /*
                 *      LEAP is a little different.  At Stage 4,
@@ -239,33 +224,37 @@ static int eap_authenticate(void *instance, REQUEST *request)
                   (handler->eap_ds->response->type.type == PW_EAP_LEAP) &&
                   (handler->eap_ds->request->code == PW_EAP_SUCCESS) &&
                   (handler->eap_ds->request->type.type == 0)) {
-               VALUE_PAIR *state;
-
-               DEBUG2("  rlm_eap: Saving LEAP state");
-               handler->id = eap_regenerateid(request, (u_char)handler->eap_ds->request->id);
-               if (handler->id == NULL) {
-                       radlog(L_ERR, "rlm_eap: problem in generating ID, Present EAP is not valid");
-                       eap_handler_free(&handler);
-               } else {
-                       eaplist_add(&(eap_stuff->echolist), handler);
-               }
-
-               /*
-                *  And copy the State attribute from the request
-                */
-               state = paircopy2(request->packet->vps, PW_STATE);
 
-               /*
-                *  FIXME: Assert there's only 1 state?
-                */
-               pairadd(&request->reply->vps, state);
+               eaplist_add(inst, handler);
 
        } else {
                DEBUG2("  rlm_eap: Freeing handler");
                /* handler is no more required, free it now */
                eap_handler_free(&handler);
        }
-       return RLM_MODULE_OK;
+
+       /*
+        *      If it's an Access-Accept, RFC 2869, Section 2.3.1
+        *      says that we MUST include a User-Name attribute in the
+        *      Access-Accept.
+        */
+       if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
+           request->username) {
+               VALUE_PAIR *vp;
+
+               /*
+                *      Doesn't exist, add it in.
+                */
+               vp = pairfind(request->reply->vps, PW_USER_NAME);
+               if (!vp) {
+                       vp = pairmake("User-Name", request->username->strvalue,
+                                     T_OP_EQ);
+                       rad_assert(vp != NULL);
+                       pairadd(&(request->reply->vps), vp);
+               }
+       }
+
+       return rcode;
 }
 
 /*
@@ -275,21 +264,28 @@ static int eap_authenticate(void *instance, REQUEST *request)
  */
 static int eap_authorize(void *instance, REQUEST *request)
 {
-       VALUE_PAIR      *atype, *vp;
-       rlm_eap_t       *eap_stuff;
-       eap_packet_t    *eap_packet;
+       rlm_eap_t       *inst;
        int             status;
-       unsigned char   *id;
+       VALUE_PAIR      *vp;
        
-       eap_stuff = (rlm_eap_t *)instance;
+       inst = (rlm_eap_t *)instance;
 
-       /* Authorization not valid for proxies */
+       /*
+        *      We don't do authorization again, once we've seen the
+        *      proxy reply (or the proxied packet)
+        */
        if (request->proxy != NULL)
                 return RLM_MODULE_NOOP;
 
        /*
-        * For EAP_START, send Access-Challenge with EAP Identity request.
-        * even when we have to proxy this request
+        *      For EAP_START, send Access-Challenge with EAP Identity
+        *      request.  even when we have to proxy this request
+        *
+        *      RFC 2869, Section 2.3.1 notes that the "domain" of the
+        *      user, (i.e. where to proxy him) comes from the EAP-Identity,
+        *      so we CANNOT proxy the user, until we know his identity.
+        *
+        *      We therefore send an EAP Identity request.
         */
        status = eap_start(request);
        switch(status) {
@@ -308,60 +304,18 @@ static int eap_authorize(void *instance, REQUEST *request)
         * We should have User-Name to proceed further
         */
        if (request->username == NULL) {
-
-               /* get the eap packet */
-               eap_packet = eap_attribute(request->packet->vps);
-               if (eap_packet == NULL) {
-                       radlog(L_ERR, "rlm_eap: Malformed EAP Message");
-                       return RLM_MODULE_FAIL;
-               }
-
-               id = eap_regenerateid(request, eap_packet->id);
-               if (id == NULL) {
-                       radlog(L_ERR, "rlm_eap: User-Name cannot be obtained");
-                       free(eap_packet);
-                       return RLM_MODULE_FAIL;
-               }
-
-               request->username = eap_useridentity(eap_stuff->echolist, eap_packet, id);
-               if (request->username == NULL) {
-                       radlog(L_ERR, "rlm_eap: Unknown User, authorization failed");
-                       free(eap_packet);
-                       free(id);
-                       return RLM_MODULE_FAIL;
-               }
-               free(eap_packet);
-               free(id);
+               radlog(L_ERR, "rlm_eap: User-Name is required for EAP authentication");
+               return RLM_MODULE_FAIL;
        }
 
-       /*
-        * Enforce EAP authentication
-
-        * Auth-type(s) already set?  overide it with EAP
-        * If EAP-Message is present in RADIUS, then EAP authentication is MUST.
-
-        * TODO: When Multiple authentications are supported in RADIUS, 
-        *     then prioritize EAP by prepending it before all Auth-Types
-        */
-
-       atype = pairfind(request->config_items, PW_AUTHTYPE);
-       if ((atype == NULL) || 
-               ((atype->lvalue != PW_AUTHTYPE_EAP) &&
-               (atype->lvalue != PW_AUTHTYPE_ACCEPT) &&
-               (atype->lvalue != PW_AUTHTYPE_REJECT))) {
-
+       vp = pairfind(request->config_items, PW_AUTH_TYPE);
+       if ((!vp) ||
+           (vp->lvalue != PW_AUTHTYPE_REJECT)) {
                vp = pairmake("Auth-Type", "EAP", T_OP_EQ);
-               if (vp == NULL) {
+               if (!vp) {
                        return RLM_MODULE_FAIL;
                }
-               /* to overide */
-               pairdelete(&request->config_items, PW_AUTHTYPE);
                pairadd(&request->config_items, vp);
-
-               /* To prioritize
-               vp->next = request->config_items;
-               request->config_items = vp;
-               */
        }
 
        return RLM_MODULE_UPDATED;
index b1dd868..844c029 100644 (file)
@@ -48,57 +48,47 @@ typedef struct eap_packet_t {
        unsigned char   data[1];
 } eap_packet_t;
 
-/*
- * Config stuff that rlm_eap depends on.
- */
-typedef struct eap_conf {
-       char    *default_eap_type;
-       int             timer_limit;
-} EAP_CONF;
-
-/*
- * Currently there are only 2 types
- * of operations defined, 
- * apart from attach & detach for each EAP-Type.
- */
-typedef enum operation_t {
-       INITIATE = 0,
-       AUTHENTICATE
-} operation_t;
 
 /*
  * Keep track of which sub modules we've loaded.
  */
 typedef struct eap_types_t {
-       struct eap_types_t      *next;
+       const char      *typename;
        int             typeid;
-       char    typename[NAME_LEN];
        EAP_TYPE        *type;
        lt_dlhandle     handle;
        CONF_SECTION    *cs;
-       void            *type_stuff;
+       void            *type_data;
 } EAP_TYPES;
 
 /*
  * This structure contains eap's persistent data.
- * echolist = EAP_HANDLERs 
+ * sessions[] = EAP_HANDLERS, keyed by the first octet of the State
+ *              attribute, and composed of a linked list, ordered from
+ *              oldest to newest.
  * typelist = All supported EAP-Types
  * conf     = configured values for rlm_eap only.
  */
 typedef struct rlm_eap_t {
-       EAP_HANDLER     *echolist;
-       EAP_TYPES       *typelist;
-       EAP_CONF        *conf;
+       EAP_HANDLER     *sessions[256];
+       EAP_TYPES       *types[PW_EAP_MAX_TYPES + 1];
+
+       /*
+        *      Configuration items.
+        */
+       char            *default_eap_type;
+       int             timer_limit;
+       int             default_eap_id;
 } rlm_eap_t;
 
 /* function definitions */
 /* EAP-Type */
+int            eaptype_name2id(const char *name);
 EAP_TYPES      *eaptype_byid(EAP_TYPES **list, int type);
 EAP_TYPES      *eaptype_byname(EAP_TYPES **list, const char *name);
-int            eaptype_load(EAP_TYPES **tl, const char *tname, CONF_SECTION *cs);
-int            eaptype_select(EAP_TYPES *tl, EAP_HANDLER *h, char *eaptype);
-int            eaptype_call(int type, operation_t act, EAP_TYPES *tl, EAP_HANDLER *h);
-void           eaptype_freelist(EAP_TYPES **tl);
+int            eaptype_load(EAP_TYPES **type, int id, CONF_SECTION *cs);
+int            eaptype_select(rlm_eap_t *inst, EAP_HANDLER *h);
+void           eaptype_free(EAP_TYPES *tl);
 
 /* EAP */
 int            eap_start(REQUEST *request);
@@ -108,11 +98,8 @@ int                 eap_validation(eap_packet_t *eap_msg);
 int            eap_wireformat(EAP_PACKET *packet);
 int            eap_compose(REQUEST *request, EAP_DS *eap_ds);
 eap_packet_t   *eap_attribute(VALUE_PAIR *vps);
-EAP_HANDLER    *eap_handler(EAP_HANDLER **list, eap_packet_t **eap_msg, REQUEST *request);
+EAP_HANDLER    *eap_handler(rlm_eap_t *inst, eap_packet_t **eap_msg, REQUEST *request);
 char           *eap_identity(eap_packet_t *eap_packet);
-VALUE_PAIR     *eap_useridentity(EAP_HANDLER *list, eap_packet_t *eap_packet, unsigned char id[]);
-unsigned char  *eap_generateid(REQUEST *request, unsigned char response_id);
-unsigned char  *eap_regenerateid(REQUEST *request, unsigned char response_id);
 
 /* Memory Management */
 EAP_PACKET     *eap_packet_alloc(void);
@@ -122,15 +109,13 @@ void              eap_packet_free(EAP_PACKET **eap_packet);
 void           eap_ds_free(EAP_DS **eap_ds);
 void           eap_handler_free(EAP_HANDLER **handler);
 
-int            eaplist_add(EAP_HANDLER **list, EAP_HANDLER *handler);
-void           eaplist_clean(EAP_HANDLER **list, time_t limit);
-void           eaplist_free(EAP_HANDLER **list);
-EAP_HANDLER    *eaplist_isreply(EAP_HANDLER **list, unsigned char id[]);
-EAP_HANDLER    *eaplist_findhandler(EAP_HANDLER *list, unsigned char id[]);
+int            eaplist_add(rlm_eap_t *inst, EAP_HANDLER *handler);
+void           eaplist_free(rlm_eap_t *inst);
+EAP_HANDLER    *eaplist_find(rlm_eap_t *inst, REQUEST *request, int id);
 
 /* State */
 void           generate_key(void);
-VALUE_PAIR     *generate_state(void);
-int            verify_state(VALUE_PAIR *state);
+VALUE_PAIR     *generate_state(time_t timestamp);
+int            verify_state(VALUE_PAIR *state, time_t timestamp);
 
 #endif /*_RLM_EAP_H*/
index 82ea466..add7b12 100644 (file)
@@ -30,45 +30,60 @@ static const char rcsid[] = "$Id$";
 /*
  *     Global key to generate & verify State
  *
- *     FIXME: this means that we can't have multiple instances
- *     of the EAP module.
+ *     This is needed only once per instance of the server,
+ *     and putting it in the rlm_eap_t is just too much effort.
+ *
+ *     Putting it here is ugly, but it works.
  */
+static int key_initialized = 0;
 static unsigned char state_key[AUTH_VECTOR_LEN];
 
 /*
- * Generate & Verify the State attribute
- *
- * In the simplest implementation, we would just use the challenge as state.
- * Unfortunately, the RADIUS secret protects only the User-Password
- * attribute; an attacker that can remove packets from the wire and insert
- * new ones can simply insert a replayed state without having to know
- * the secret.  If not for an attacker that can remove packets from the
- * network, I believe trivial state to be secure.
- *
- * So, we have to make up for that deficiency by signing our state with
- * data unique to this specific request.  A NAS would use the Request
- * Authenticator, we don't know what that will be when the State is
- * returned to us, so we'll use the time.  So our replay prevention
- * is limited to a time interval (inst->maxdelay).  We could keep
- * track of all challenges issued over that time interval for
- * better protection.
- *
- * Our state, then, is (challenge + time + hmac(challenge + time, key)),
- * where '+' denotes concatentation, 'challenge' is the ASCII octets of
- * the challenge, 'time' is the 32-bit time (LSB if time_t is 64 bits)
- * in network byte order, and 'key' is a random key, generated once in
- * eap_init().  This means that only the server which generates
- * a challenge can verify it; this should be OK if your NAS's load balance
- * across RADIUS servers by a "first available" algorithm.  If your
- * NAS's round-robin (ugh), you could use the RADIUS secret instead, but
- * read RFC 2104 first, and make very sure you really want to do this.
+ *     Generate & Verify the State attribute
+ *
+ *     In the simplest implementation, we would just use the
+ *     challenge as state.  Unfortunately, the RADIUS secret protects
+ *     only the User-Password attribute; an attacker that can remove
+ *     packets from the wire and insert new ones can simply insert a
+ *     replayed state without having to know the secret.
+ *
+ *     However, RADIUS packets containing EAP conversations MUST be
+ *     signed with Message-Authenticator, at which point, they MUST
+ *     know the secret, in order to get to the EAP module.  And if
+ *     they know the secret, they can do many worse things than
+ *     re-playing a State attribute.  Their only alternative is to
+ *     re-play entire packets, which is caught by the server core.
+ *
+ *     In any case, we sign our state with data unique to this
+ *     specific request.  A NAS would use the Request Authenticator,
+ *     we don't know what that will be when the State is returned to
+ *     us, so we'll use a time stamp.
+ *
+ *     Our replay prevention is limited to a time interval
+ *     (inst->maxdelay).  We could keep track of all challenges
+ *     issued over that time interval, to ensure that the challenges
+ *     were unique.  However, they're 8-bytes of data from a good
+ *     PRNG, which means that it's pretty damn unlikely that they'll
+ *     be re-used.
  *
+ *     Our state, then, is (challenge + hmac(challenge + time, key)),
+ *     where '+' denotes concatentation, 'challenge' is the octets
+ *     of the challenge, 'time' is the 'time_t' in host byte order,
+ *     and 'key' is a random key, generated once in eap_init().
+ *
+ *     This means that only the server which generates a challenge
+ *     can verify it; this should be OK if your NAS's load balance
+ *     across RADIUS servers by a "first available" algorithm.  If
+ *     your NAS's round-robin (ugh), you could use the RADIUS
+ *     secret instead, but read RFC 2104 first, and make very sure
+ *     you really want to do this.
  */
-
 void generate_key(void)
 {
        int i;
 
+       if (key_initialized) return;
+
        /*
         *      Use a cryptographically strong method to generate
         *      pseudo-random numbers.
@@ -76,43 +91,66 @@ void generate_key(void)
        for (i = 0; i < sizeof(state_key); i++) {
                state_key[i] = lrad_rand();
        }
+
+       key_initialized = 1;
 }
 
 /*
+ *     For clarity.  Also, to avoid giving away
+ *     too much information, we only put 8 octets of the HMAC
+ *     into the State attribute, instead of all 16.
+ *
+ *     As a security feature, it's a little hokey, but WTF.
+ *
+ *     Also, ensure that EAP_CHALLENGE_LEN + EAP_USE_OF_HMAC = EAP_STATE_LEN
+ */
+#define EAP_CHALLENGE_LEN (8)
+#define EAP_HMAC_SIZE (16)
+#define EAP_USE_OF_HMAC (8)
+
+/*
  * Our state, is (challenge + time + hmac(challenge + time, key))
+ *
+ *  If it's too long, then some clients chop it (sigh)
  */
-VALUE_PAIR *generate_state(void)
+VALUE_PAIR *generate_state(time_t timestamp)
 {
        int i;
-       unsigned char challenge[AUTH_VECTOR_LEN];
-       unsigned char hmac[AUTH_VECTOR_LEN];
-       unsigned char value[AUTH_VECTOR_LEN+sizeof(time_t)];
+       unsigned char challenge[EAP_CHALLENGE_LEN];
+       unsigned char hmac[EAP_HMAC_SIZE];
+       unsigned char value[EAP_CHALLENGE_LEN + sizeof(timestamp)];
        VALUE_PAIR    *state;
-       time_t now;
 
        /* Generate challenge (a random value).  */
        for (i = 0; i < sizeof(challenge); i++) {
                challenge[i] = lrad_rand();
        }
 
-       now = time(NULL);
-       memcpy(value, challenge, AUTH_VECTOR_LEN);
-       memcpy(value + AUTH_VECTOR_LEN, &now, sizeof(time_t));
-
-       /* Generate hmac.  */
-       lrad_hmac_md5(value, AUTH_VECTOR_LEN + sizeof(time_t),
-              state_key, AUTH_VECTOR_LEN, hmac);
+       memcpy(value, challenge, sizeof(challenge));
+       memcpy(value + sizeof(challenge), &timestamp, sizeof(timestamp));
 
+       /*
+        *      hmac(challenge + timestamp)
+        */
+       lrad_hmac_md5(value, sizeof(value),
+                     state_key, sizeof(state_key), hmac);
 
-       /* Create state attribute.  */
+       /*
+        *      Create the state attribute.
+        *
+        *      Note that the timestamp is used internally, but is NOT
+        *      sent to the client!
+        */
        state = paircreate(PW_STATE, PW_TYPE_OCTETS);
        if (state == NULL) {
                radlog(L_ERR, "rlm_eap: out of memory");
                return NULL;
        }
-       memcpy(state->strvalue, value, AUTH_VECTOR_LEN+sizeof(time_t));
-       memcpy(state->strvalue+AUTH_VECTOR_LEN+sizeof(time_t), hmac, AUTH_VECTOR_LEN);
-       state->length = AUTH_VECTOR_LEN + sizeof(time_t) + AUTH_VECTOR_LEN;
+       memcpy(state->strvalue, challenge, sizeof(challenge));
+       memcpy(state->strvalue + sizeof(challenge), hmac,
+              EAP_USE_OF_HMAC);
+
+       state->length = sizeof(challenge) + EAP_USE_OF_HMAC;
 
        return state;
 }
@@ -120,20 +158,34 @@ VALUE_PAIR *generate_state(void)
 /*
  * Returns 0 on success, non-zero otherwise. 
  */
-int verify_state(VALUE_PAIR *state)
+int verify_state(VALUE_PAIR *state, time_t timestamp)
 {
-       unsigned char prev_hmac[AUTH_VECTOR_LEN];
-       unsigned char hmac[AUTH_VECTOR_LEN];
-       unsigned char value[AUTH_VECTOR_LEN+sizeof(time_t)];
-       
-       /* Get the challenge value & hmac from the State */
-       memcpy(value, state->strvalue, AUTH_VECTOR_LEN+sizeof(time_t));
-       memcpy(prev_hmac, state->strvalue+AUTH_VECTOR_LEN+sizeof(time_t), AUTH_VECTOR_LEN);
+       unsigned char hmac[EAP_HMAC_SIZE];
+       unsigned char value[EAP_CHALLENGE_LEN + sizeof(timestamp)];
        
+       /*
+        *      The length is wrong.  Don't do anything.
+        */
+       if (state->length != EAP_STATE_LEN) {
+               return -1;
+       }
+
+       /*
+        *      The first 16 octets of the State attribute constains
+        *      the random challenge.
+        */
+       memcpy(value, state->strvalue, EAP_CHALLENGE_LEN);
+       memcpy(value + EAP_CHALLENGE_LEN, &timestamp, sizeof(timestamp));
+
        /* Generate hmac.  */
-       lrad_hmac_md5(value, AUTH_VECTOR_LEN + sizeof(time_t),
-              state_key, AUTH_VECTOR_LEN, hmac);
+       lrad_hmac_md5(value, sizeof(value),
+                     state_key, sizeof(state_key), hmac);
 
-       /* verify both the hmacs */
-       return memcmp(hmac, prev_hmac, AUTH_VECTOR_LEN);
+       /*
+        *      Compare the hmac we calculated to the one in the
+        *      packet.
+        */
+       return memcmp(hmac, state->strvalue + EAP_CHALLENGE_LEN,
+                     EAP_USE_OF_HMAC);
 }
+
index ab9b3ce..1b96cdc 100644 (file)
@@ -2,7 +2,7 @@
 TARGET      = rlm_eap_leap
 SRCS        = rlm_eap_leap.c eap_leap.c
 RLM_CFLAGS  = $(INCLTDL) -I../..
-HEADERS     = des.h eap_leap.h
+HEADERS     = eap_leap.h  ../../eap.h ../../rlm_eap.h
 RLM_INSTALL = 
 
 $(STATIC_OBJS): $(HEADERS)
index 2d6c66f..b5d10dd 100644 (file)
@@ -170,8 +170,12 @@ LEAP_PACKET *eapleap_extract(EAP_DS *eap_ds)
 
        /*
         *      The User-Name comes after the challenge.
+        *
+        *      Length of the EAP-LEAP portion of the packet, minus
+        *      3 octets for data, minus the challenge size, is the
+        *      length of the user name.
         */
-       name_len = eap_ds->response->length - 3 - packet->count;
+       name_len = packet->length - 3 - packet->count;
        if (name_len > 0) {
                packet->name = malloc(name_len + 1);
                if (!packet->name) {
index 0672cbc..4631770 100644 (file)
 #include "eap_leap.h"
 
 
-static void leap_session_free(void **opaque)
-{
-       leap_session_t *session;
-
-       if (!opaque) return;
-
-       session = *(leap_session_t **) opaque;
-
-       free(session);
-       *opaque = NULL;
-}
-
 /*
  * send an initial eap-leap request
  * ie access challenge to the user/peer.
@@ -74,13 +62,18 @@ static int leap_initiate(void *instance, EAP_HANDLER *handler)
         *      of filling in the peer response.
         */
        session = (leap_session_t *) handler->opaque;
-       handler->free_opaque = leap_session_free;
+       handler->free_opaque = free; /* just malloc'd memory */
 
        session->stage = 4;     /* the next stage we're in */
        memcpy(session->peer_challenge, reply->challenge, reply->count);
 
        DEBUG2("  rlm_eap_leap: Successfully initiated");
 
+       /*
+        *      The next stage to process the packet.
+        */
+       handler->stage = AUTHENTICATE;
+
        eapleap_free(&reply);
        return 1;
 }
@@ -113,8 +106,8 @@ static int leap_authenticate(void *instance, EAP_HANDLER *handler)
         *      The password is never sent over the wire.
         *      Always get the configured password, for each user.
         */
-       password = pairfind(handler->configured, PW_PASSWORD);
-       if (!password) password = pairfind(handler->configured, PW_NT_PASSWORD);
+       password = pairfind(handler->request->config_items, PW_PASSWORD);
+       if (!password) password = pairfind(handler->request->config_items, PW_NT_PASSWORD);
        if (!password) {
                radlog(L_INFO, "rlm_eap_leap: No User-Password or NT-Password configured for this user");
                eapleap_free(&packet);
@@ -163,7 +156,7 @@ static int leap_authenticate(void *instance, EAP_HANDLER *handler)
                DEBUG2("  rlm_eap_leap: Stage 6");
                reply = eapleap_stage6(packet, handler->request,
                                       handler->username, password,
-                                      session, handler->reply_vps);
+                                      session, &handler->request->reply->vps);
                break;
 
                /*
@@ -199,6 +192,7 @@ EAP_TYPE rlm_eap_leap = {
        "eap_leap",
        NULL,                   /* attach */
        leap_initiate,          /* Start the initial request, after Identity */
+       NULL,                   /* authorization */
        leap_authenticate,      /* authentication */
        NULL,                   /* detach */
 };
index 132c92c..b92fa87 100644 (file)
@@ -76,7 +76,7 @@ void eapmd5_free(MD5_PACKET **md5_packet_ptr)
 }
 
 /* 
- * We expect only RESPONSE for which CHALLENGE, SUCCESS or FAILURE is sent back
+ *     We expect only RESPONSE for which SUCCESS or FAILURE is sent back
  */ 
 MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds)
 {
@@ -84,14 +84,18 @@ MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds)
        MD5_PACKET      *packet;
        unsigned short  name_len;
 
-       if (!eap_ds                                     || 
-           !eap_ds->response                           || 
-           (eap_ds->response->code != PW_MD5_RESPONSE) ||
-           eap_ds->response->type.type != PW_EAP_MD5   ||
-           !eap_ds->response->type.data                ||
-           (eap_ds->response->length < MD5_HEADER_LEN) ||
-           (eap_ds->response->type.data[0] <= 0)       ) {
-         
+       /*
+        *      We need a response, of type EAP-MD5, with at least
+        *      one byte of type data (EAP-MD5) following the 4-byte
+        *      EAP-Packet header.
+        */
+       if (!eap_ds                                      || 
+           !eap_ds->response                            || 
+           (eap_ds->response->code != PW_MD5_RESPONSE)  ||
+           eap_ds->response->type.type != PW_EAP_MD5    ||
+           !eap_ds->response->type.data                 ||
+           (eap_ds->response->length <= MD5_HEADER_LEN) ||
+           (eap_ds->response->type.data[0] <= 0)) {
                radlog(L_ERR, "rlm_eap_md5: corrupted data");
                return NULL;
        }
@@ -100,25 +104,30 @@ MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds)
        if (!packet) return NULL;
 
        /*
-        * Code, id & length for MD5 & EAP are same
-        * but md5_length = eap_length - 1(Type = 1 octet)
+        *      Code & id for MD5 & EAP are same
+        *
+        *      but md5_length = length of the EAP-MD5 data, which
+        *      doesn't include the EAP header, or the octet saying
+        *      EAP-MD5.
         */
        packet->code = eap_ds->response->code;
        packet->id = eap_ds->response->id;
-       packet->length = eap_ds->response->length - 1;
-       packet->value_size = 0;
-       packet->value = NULL;
-       packet->name = NULL;
+       packet->length = eap_ds->response->length - (MD5_HEADER_LEN + 1);
 
+       /*
+        *      Sanity check the EAP-MD5 packet sent to us
+        *      by the client.
+        */
        data = (md5_packet_t *)eap_ds->response->type.data;
 
+       /*
+        *      Already checked the size above.
+        */
        packet->value_size = data->value_size;
-       if (packet->value_size < 1) {
-               radlog(L_ERR, "rlm_eap_md5: Value size is too small");
-               eapmd5_free(&packet);
-               return NULL;
-       }
 
+       /*
+        *      Allocate room for the data, and copy over the data.
+        */
        packet->value = malloc(packet->value_size);
        if (packet->value == NULL) {
                radlog(L_ERR, "rlm_eap_md5: out of memory");
@@ -128,57 +137,37 @@ MD5_PACKET *eapmd5_extract(EAP_DS *eap_ds)
        memcpy(packet->value, data->value_name, packet->value_size);
 
        /*
-        * Name is optional and is present after Value, but we need to check for it
+        *      Name is optional and is present after Value, but we
+        *      need to check for it, as eapmd5_compose()
         */
-       name_len =  packet->length - (packet->value_size + 5);
+       name_len =  packet->length - (packet->value_size + 1);
        if (name_len) {
-               packet->name = malloc(name_len+1);
+               packet->name = malloc(name_len + 1);
                if (!packet->name) {
                        radlog(L_ERR, "rlm_eap_md5: out of memory");
                        eapmd5_free(&packet);
                        return NULL;
                }
-               memset(packet->name, 0, name_len+1);
-               memcpy(packet->name, data->value_name+packet->value_size, name_len);
+               memcpy(packet->name, data->value_name + packet->value_size,
+                      name_len);
+               packet->name[name_len] = 0;
        }
 
        return packet;
 }
 
-/*
- * Generate a random value
- * challenge = MD5(random)
- */
-int eapmd5_challenge(unsigned char *value, int len)
-{
-       int i;
-
-       /*
-        *      Get real pseudo-random numbers.
-        */
-       for (i = 0; i < len; i++) {
-               value[i] = lrad_rand();
-       }
-       radlog(L_INFO, "rlm_eap_md5: Issuing Challenge");
-
-       return 1;
-}
 
 /* 
  * verify = MD5(id+password+challenge_sent)
  */
 int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password, 
-               md5_packet_t *challenge)
+                 uint8_t *challenge)
 {
        char    *ptr;
-       char    string[MAX_STRING_LEN*2];
+       char    string[1 + MAX_STRING_LEN*2];
        unsigned char output[MAX_STRING_LEN];
        unsigned short len;
 
-       if ((password == NULL) || (challenge == NULL)) {
-               return 0;
-       }
-
        /*
         *      Sanity check it.
         */
@@ -190,14 +179,20 @@ int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password,
        len = 0;
        ptr = string;
 
+       /*
+        *      This is really rad_chap_pwencode()...
+        */
        *ptr++ = packet->id;
        len++;
        memcpy(ptr, password->strvalue, password->length);
        ptr += password->length;
        len += password->length;
 
-       memcpy(ptr, challenge->value_name, challenge->value_size);
-       len += challenge->value_size;
+       /*
+        *      The challenge size is hard-coded.
+        */
+       memcpy(ptr, challenge, MD5_CHALLENGE_LEN);
+       len += MD5_CHALLENGE_LEN;
 
        librad_md5_calc((u_char *)output, (u_char *)string, len);
 
@@ -210,124 +205,26 @@ int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password,
        return 1;
 }
 
-/*
- * Identify whether the response that you got is either the
- * response to the challenge that we sent or a new one.
- * If it is a response to the request then issue success/failure
- * else issue a challenge
- */
-MD5_PACKET *eapmd5_process(MD5_PACKET *packet, int id,
-               VALUE_PAIR *username, VALUE_PAIR* password, md5_packet_t *request)
-{
-       unsigned char output[MAX_STRING_LEN];
-       MD5_PACKET *reply;
-
-       if (!username || !password || !packet)
-               return NULL;
-
-       reply = eapmd5_alloc();
-       if (!reply) return NULL;
-       memset(output, 0, MAX_STRING_LEN);
-       reply->id = id;
-       
-       if (request) {
-               /* verify and issue Success/failure */
-               if (eapmd5_verify(packet, password, request) == 0) {
-                       radlog(L_INFO, "rlm_eap_md5: Challenge failed");
-                       reply->code = PW_MD5_FAILURE;
-               }
-               else {
-                       reply->code = PW_MD5_SUCCESS;
-               }
-
-       } else {
-               /*
-                * Previous request not found.
-                * Probably it is timed out.
-                * So send another challenge.
-                * TODO: Later Send these challenges for the configurable
-                *              number of times for each user & stop.
-                */
-
-               /*
-                *      Ensure that the challenge is always of the correct
-                *      length.  i.e. Don't take value size from data
-                *      supplied by the client.
-                */
-               if (reply->value_size != MD5_LEN) {
-                       free(reply->value);
-                       reply->value_size = MD5_LEN;
-                       reply->value = malloc(reply->value_size);
-               }
-
-               eapmd5_challenge(reply->value, reply->value_size);
-               reply->code = PW_MD5_CHALLENGE;
-               radlog(L_INFO, "rlm_eap_md5: Previous request not found");
-               radlog(L_INFO, "rlm_eap_md5: Issuing Challenge to the user - %s",
-                       (char *)username->strvalue);
-       }
-
-       /* fill reply packet */
-       if (reply->code == PW_MD5_CHALLENGE) {
-               reply->value_size = packet->value_size;
-               reply->value = malloc(reply->value_size);
-               if (reply->value == NULL) {
-                       radlog(L_ERR, "rlm_eap_md5: out of memory");
-                       eapmd5_free(&reply);
-                       return NULL;
-               }
-               memcpy(reply->value, output, reply->value_size);
-               reply->length = packet->length;
-       } else {
-               reply->length = MD5_HEADER_LEN;
-       }
-       
-       return reply;
-}
-
-/*
- * If an EAP MD5 request needs to be initiated then
- * create such a packet.
- */
-MD5_PACKET *eapmd5_initiate(EAP_DS *eap_ds)
-{
-       MD5_PACKET      *reply;
-
-       reply = eapmd5_alloc();
-       if (reply == NULL)  {
-               radlog(L_ERR, "rlm_eap_md5: out of memory");
-               return NULL;
-       }
-
-       reply->code = PW_MD5_CHALLENGE;
-       reply->length = MD5_HEADER_LEN + 1/*value_size*/ + MD5_LEN;
-       reply->value_size = MD5_LEN;
-
-       reply->value = malloc(reply->value_size);
-       if (reply->value == NULL) {
-               radlog(L_ERR, "rlm_eap_md5: out of memory");
-               eapmd5_free(&reply);
-               return NULL;
-       }
-
-       eapmd5_challenge(reply->value, reply->value_size);
-
-       return reply;
-}
-
 /* 
- * compose the MD5 reply packet in the EAP reply typedata
+ *     Compose the portions of the reply packet specific to the
+ *     EAP-MD5 protocol, in the EAP reply typedata
  */
 int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply)
 {
        uint8_t *ptr;
        unsigned short name_len;
 
+       /*
+        *      We really only send Challenge (EAP-Identity),
+        *      and EAP-Success, and EAP-Failure.
+        */
        if (reply->code < 3) {
-
                eap_ds->request->type.type = PW_EAP_MD5;
 
-               eap_ds->request->type.data = malloc(reply->length - MD5_HEADER_LEN);
+               rad_assert(reply->length > 0);
+               rad_assert(reply->value_size < 256);
+
+               eap_ds->request->type.data = malloc(reply->length);
                if (eap_ds->request->type.data == NULL) {
                        radlog(L_ERR, "rlm_eap_md5: out of memory");
                        return 0;
@@ -339,7 +236,12 @@ int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply)
                /* Just the Challenge length */
                eap_ds->request->type.length = reply->value_size + 1;
 
-               name_len = reply->length - (reply->value_size + 1 + MD5_HEADER_LEN);
+               /*
+                *      Return the name, if necessary.
+                *
+                *      Don't see why this is *ever* necessary...
+                */
+               name_len = reply->length - (reply->value_size + 1);
                if (name_len && reply->name) {
                        ptr += reply->value_size;
                        memcpy(ptr, reply->name, name_len);
@@ -352,5 +254,7 @@ int eapmd5_compose(EAP_DS *eap_ds, MD5_PACKET *reply)
        }
        eap_ds->request->code = reply->code;
 
+       eapmd5_free(&reply);
+
        return 1;
 }
index 463ddc6..698aab4 100644 (file)
@@ -10,7 +10,7 @@
 #define PW_MD5_MAX_CODES       4
 
 #define MD5_HEADER_LEN                 4
-#define MD5_LEN                16
+#define MD5_CHALLENGE_LEN      16
 
 /*
  ****
@@ -18,6 +18,8 @@
  *     for generalization purpose, complete header should be sent
  *     and not just value_size, value and name.
  *     future implementation.
+ *
+ *     Huh? What does that mean?
  */
 
 /* eap packet structure */
@@ -38,17 +40,8 @@ typedef struct md5_packet {
        unsigned char   value_size;
        unsigned char   *value;
        char            *name;
-/*     char            *message; */
 } MD5_PACKET;
 
-typedef struct md5_list {
-       struct md5_list *next;
-       MD5_PACKET      *packet;
-       char            username[MAX_STRING_LEN];
-       int             processed;
-       time_t          time;
-} MD5_LIST;
-
 /* function declarations here */
 
 MD5_PACKET     *eapmd5_alloc(void);
@@ -56,10 +49,5 @@ void                 eapmd5_free(MD5_PACKET **md5_packet_ptr);
 
 int            eapmd5_compose(EAP_DS *auth, MD5_PACKET *reply);
 MD5_PACKET     *eapmd5_extract(EAP_DS *auth);
-MD5_PACKET     *eapmd5_initiate(EAP_DS *eap_ds);
-MD5_PACKET     *eapmd5_process(MD5_PACKET *packet, int id, 
-                               VALUE_PAIR *username, VALUE_PAIR* password,
-                       md5_packet_t *req);
-int            eapmd5_challenge(unsigned char *value, int len);
-int            eapmd5_verify(MD5_PACKET *pkt, VALUE_PAIR* pwd, md5_packet_t *ch);
+int            eapmd5_verify(MD5_PACKET *pkt, VALUE_PAIR* pwd, uint8_t *ch);
 #endif /*_EAP_MD5_H*/
index 8ef20f0..1965348 100644 (file)
 
 #include "eap_md5.h"
 
-
-static int md5_attach(CONF_SECTION *conf, void **arg)
-{
-       return 0;
-}
+#include <rad_assert.h>
 
 /*
- * send an initial eap-md5 request
- * ie access challenge to the user/peer.
-
- * Frame eap reply packet.
- * len = header + type + md5_typedata
- * md5_typedata = value_size + value
+ *     Initiate the EAP-MD5 session by sending a challenge to the peer.
  */
-static int md5_initiate(void *type_arg, EAP_HANDLER *handler)
+static int md5_initiate(void *type_data, EAP_HANDLER *handler)
 {
+       int             i;
        MD5_PACKET      *reply;
 
-       reply = eapmd5_initiate(handler->eap_ds);
-       if (reply == NULL)
+       type_data = type_data;  /* -Wunused */
+
+       /*
+        *      Allocate an EAP-MD5 packet.
+        */
+       reply = eapmd5_alloc();
+       if (reply == NULL)  {
+               radlog(L_ERR, "rlm_eap_md5: out of memory");
+               return 0;
+       }
+
+       /*
+        *      Fill it with data.
+        */
+       reply->code = PW_MD5_CHALLENGE;
+       reply->length = 1 + MD5_CHALLENGE_LEN; /* one byte of value size */
+       reply->value_size = MD5_CHALLENGE_LEN;
+
+       /*
+        *      Allocate user data.
+        */
+       reply->value = malloc(reply->value_size);
+       if (reply->value == NULL) {
+               radlog(L_ERR, "rlm_eap_md5: out of memory");
+               eapmd5_free(&reply);
                return 0;
+       }
 
+       /*
+        *      Get a random challenge.
+        */
+       for (i = 0; i < reply->value_size; i++) {
+               reply->value[i] = lrad_rand();
+       }
+       radlog(L_INFO, "rlm_eap_md5: Issuing Challenge");
+
+       /*
+        *      Keep track of the challenge.
+        */
+       handler->opaque = malloc(reply->value_size);
+       rad_assert(handler->opaque != NULL);
+       memcpy(handler->opaque, reply->value, reply->value_size);
+       handler->free_opaque = free;
+
+       /*
+        *      Compose the EAP-MD5 packet out of the data structure,
+        *      and free it.
+        */
        eapmd5_compose(handler->eap_ds, reply);
 
-       eapmd5_free(&reply);
+       /*
+        *      We don't need to authorize the user at this point.
+        *
+        *      We also don't need to keep the challenge, as it's
+        *      stored in 'handler->eap_ds', which will be given back
+        *      to us...
+        */
+       handler->stage = AUTHENTICATE;
+       
        return 1;
 }
 
+
+/*
+ *     Authenticate a previously sent challenge.
+ */
 static int md5_authenticate(void *arg, EAP_HANDLER *handler)
 {
        MD5_PACKET      *packet;
        MD5_PACKET      *reply;
-       md5_packet_t    *request;
-       char*           username;
        VALUE_PAIR      *password;
-       EAP_DS          *temp;
 
        /*
-        * Password is never sent over the wire.
-        * Always get the configured password, for each user.
+        *      Get the User-Password for this user.
         */
-       password = pairfind(handler->configured, PW_PASSWORD);
+       rad_assert(handler->request != NULL);
+       rad_assert(handler->stage == AUTHENTICATE);
+
+       password = pairfind(handler->request->config_items, PW_PASSWORD);
        if (password == NULL) {
-               radlog(L_INFO, "rlm_eap_md5: No password configured for this user");
+               radlog(L_INFO, "rlm_eap_md5: User-Password is required for EAP-MD5 authentication");
                return 0;
        }
 
        /*
-        *      Allocate memory AFTER doing sanity checks.
+        *      Extract the EAP-MD5 packet.
         */
        if (!(packet = eapmd5_extract(handler->eap_ds)))
                return 0;
 
-       username = (char *)handler->username->strvalue;
-
-       temp = (EAP_DS *)handler->prev_eapds;
-       request = temp?(md5_packet_t *)(temp->request->type.data):NULL;
-       reply = eapmd5_process(packet, handler->eap_ds->request->id,
-                        handler->username, password, request);
+       /*
+        *      Create a reply, and initialize it.
+        */
+       reply = eapmd5_alloc();
        if (!reply) {
-               eapmd5_free(&packet);
                return 0;
        }
+       reply->id = handler->eap_ds->request->id;
+       reply->length = 0;
+
+       /*
+        *      Verify the received packet against the previous packet
+        *      (i.e. challenge) which we sent out.
+        */
+       if (eapmd5_verify(packet, password, handler->opaque)) {
+               reply->code = PW_MD5_SUCCESS;
+       } else {
+               reply->code = PW_MD5_FAILURE;
+       }
 
+       /*
+        *      Compose the EAP-MD5 packet out of the data structure,
+        *      and free it.
+        */
        eapmd5_compose(handler->eap_ds, reply);
 
-       eapmd5_free(&reply);
        eapmd5_free(&packet);
        return 1;
 }
 
-static int md5_detach(void **arg)
-{
-       return 0;
-}
-
 /*
  *     The module name should be the only globally exported symbol.
  *     That is, everything else should be 'static'.
  */
 EAP_TYPE rlm_eap_md5 = {
        "eap_md5",
-       md5_attach,                     /* attach */
-       md5_initiate,                   /* Start the initial request, after Identity */
+       NULL,                           /* attach */
+       md5_initiate,                   /* Start the initial request */
+       NULL,                           /* authorization */
        md5_authenticate,               /* authentication */
-       md5_detach                      /* detach */
+       NULL                            /* detach */
 };
index 657f34d..f796327 100644 (file)
@@ -224,15 +224,17 @@ eaptls_status_t eaptls_ack_handler(EAP_HANDLER *handler)
 
        case alert:
                eaptls_fail(handler->eap_ds);
-               session_free(&handler->opaque);
+               session_free(handler->opaque);
+               handler->opaque = NULL;
                return EAPTLS_FAIL;
 
        case handshake:
                if (tls_session->info.handshake_type == finished) {
                        eaptls_success(handler->eap_ds);
-                       eaptls_gen_mppe_keys(handler->reply_vps, 
+                       eaptls_gen_mppe_keys(&handler->request->reply->vps, 
                                             tls_session->ssl);
-                       session_free(&handler->opaque);
+                       session_free(handler->opaque);
+                       handler->opaque = NULL;
                        return EAPTLS_SUCCESS;
                } else if (tls_session->fragment > 0) {
                        /* Fragmentation handler, send next fragment */
@@ -246,7 +248,8 @@ eaptls_status_t eaptls_ack_handler(EAP_HANDLER *handler)
 
        default:
                radlog(L_ERR, "rlm_eap_tls: Invalid ACK received");
-               session_free(&handler->opaque);
+               session_free(handler->opaque);
+               handler->opaque = NULL;
                return EAPTLS_NOOP;
        }
 }
@@ -326,7 +329,6 @@ eaptls_status_t eaptls_verify(EAP_DS *eap_ds, EAP_DS *prev_eap_ds)
        /* We donot receive a TLS_START but we send it.  */
        if (TLS_START(eaptls_packet->flags) == 1) {
                radlog(L_ERR, "rlm_eap_tls:  Received EAP-TLS Start message");
-               //return EAPTLS_START;
                return EAPTLS_INVALID;
        }
 
@@ -637,7 +639,6 @@ void eaptls_operation(EAPTLS_PACKET *eaptls_packet, eaptls_status_t status, EAP_
                } else {
                        eaptls_fail(handler->eap_ds);
                }
-               //record_init(&tls_session->dirty_in);
        }
        return;
 }
index c262ac3..6558a09 100644 (file)
@@ -334,7 +334,7 @@ int                 tls_handshake_send(tls_session_t *ssn);
 void           tls_session_information(tls_session_t *tls_session);
 
 /* Session */
-void           session_free(void **ssn);
+void           session_free(void *ssn);
 void           session_close(tls_session_t *ssn);
 void           session_init(tls_session_t *ssn);
 
index 06f9bc1..80185ac 100644 (file)
 #include "eap_tls.h"
 
 static CONF_PARSER module_config[] = {
-       { "rsa_key_exchange", PW_TYPE_BOOLEAN, offsetof(EAP_TLS_CONF, rsa_key), NULL, "no" },
-       { "dh_key_exchange", PW_TYPE_BOOLEAN, offsetof(EAP_TLS_CONF, dh_key), NULL, "yes" },
-       { "rsa_key_length", PW_TYPE_INTEGER, offsetof(EAP_TLS_CONF, rsa_key_length), NULL, "512" },
-       { "dh_key_length", PW_TYPE_INTEGER, offsetof(EAP_TLS_CONF, dh_key_length), NULL, "512" },
-       { "verify_depth", PW_TYPE_INTEGER, offsetof(EAP_TLS_CONF, verify_depth), NULL, "0" },
-       { "CA_path", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, ca_path), NULL, NULL },
-       { "pem_file_type", PW_TYPE_BOOLEAN, offsetof(EAP_TLS_CONF, file_type), NULL, "yes" },
-       { "private_key_file", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, private_key_file), NULL, NULL },
-       { "certificate_file", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, certificate_file), NULL, NULL },
-       { "CA_file", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, ca_file), NULL, NULL },
-       { "private_key_password", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, private_key_password), NULL, NULL },
-       { "dh_file", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, dh_file), NULL, NULL },
-       { "random_file", PW_TYPE_STRING_PTR, offsetof(EAP_TLS_CONF, random_file), NULL, NULL },
-       { "fragment_size", PW_TYPE_INTEGER, offsetof(EAP_TLS_CONF, fragment_size), NULL, "1024" },
-       { "include_length", PW_TYPE_BOOLEAN, offsetof(EAP_TLS_CONF, include_length), NULL, "yes" },
+       { "rsa_key_exchange", PW_TYPE_BOOLEAN,
+         offsetof(EAP_TLS_CONF, rsa_key), NULL, "no" },
+       { "dh_key_exchange", PW_TYPE_BOOLEAN,
+         offsetof(EAP_TLS_CONF, dh_key), NULL, "yes" },
+       { "rsa_key_length", PW_TYPE_INTEGER,
+         offsetof(EAP_TLS_CONF, rsa_key_length), NULL, "512" },
+       { "dh_key_length", PW_TYPE_INTEGER,
+         offsetof(EAP_TLS_CONF, dh_key_length), NULL, "512" },
+       { "verify_depth", PW_TYPE_INTEGER,
+         offsetof(EAP_TLS_CONF, verify_depth), NULL, "0" },
+       { "CA_path", PW_TYPE_STRING_PTR,
+         offsetof(EAP_TLS_CONF, ca_path), NULL, NULL },
+       { "pem_file_type", PW_TYPE_BOOLEAN,
+         offsetof(EAP_TLS_CONF, file_type), NULL, "yes" },
+       { "private_key_file", PW_TYPE_STRING_PTR,
+         offsetof(EAP_TLS_CONF, private_key_file), NULL, NULL },
+       { "certificate_file", PW_TYPE_STRING_PTR,
+         offsetof(EAP_TLS_CONF, certificate_file), NULL, NULL },
+       { "CA_file", PW_TYPE_STRING_PTR,
+         offsetof(EAP_TLS_CONF, ca_file), NULL, NULL },
+       { "private_key_password", PW_TYPE_STRING_PTR,
+         offsetof(EAP_TLS_CONF, private_key_password), NULL, NULL },
+       { "dh_file", PW_TYPE_STRING_PTR,
+         offsetof(EAP_TLS_CONF, dh_file), NULL, NULL },
+       { "random_file", PW_TYPE_STRING_PTR,
+         offsetof(EAP_TLS_CONF, random_file), NULL, NULL },
+       { "fragment_size", PW_TYPE_INTEGER,
+         offsetof(EAP_TLS_CONF, fragment_size), NULL, "1024" },
+       { "include_length", PW_TYPE_BOOLEAN,
+         offsetof(EAP_TLS_CONF, include_length), NULL, "yes" },
 
        { NULL, -1, 0, NULL, NULL }           /* end the list */
 };
 
 
-static int eaptls_attach(CONF_SECTION *cs, void **arg)
+static int eaptls_detach(void *arg)
+{
+       EAP_TLS_CONF     *conf;
+       eap_tls_t        *inst;
+
+       inst = (eap_tls_t *) arg;
+       conf = inst->conf;
+
+       if (conf) {
+               if (conf->dh_file) free(conf->dh_file);
+               conf->dh_file = NULL;
+               if (conf->certificate_file) free(conf->certificate_file);
+               conf->certificate_file = NULL;
+               if (conf->private_key_file) free(conf->private_key_file);
+               conf->private_key_file = NULL;
+               if (conf->private_key_password) free(conf->private_key_password);
+               conf->private_key_password = NULL;
+               if (conf->random_file) free(conf->random_file);
+               conf->random_file = NULL;
+               
+               free(inst->conf);
+               inst->conf = NULL;
+       }
+
+       if (inst->ctx) SSL_CTX_free(inst->ctx);
+       inst->ctx = NULL;
+
+       free(inst);
+
+       return 0;
+}
+
+static int eaptls_attach(CONF_SECTION *cs, void **instance)
 {
        SSL_CTX          *ctx;
        EAP_TLS_CONF     *conf;
-       eap_tls_t        **eaptls;
+       eap_tls_t        *inst;
 
-       eaptls = (eap_tls_t **)arg;
+       /* Store all these values in the data structure for later references */
+       inst = (eap_tls_t *)malloc(sizeof(*inst));
+       if (!inst) {
+               radlog(L_ERR, "rlm_eap_tls: out of memory");
+               return -1;
+       }
+       memset(inst, 0, sizeof(*inst));
 
        /* Parse the config file & get all the configured values */
        conf = (EAP_TLS_CONF *)malloc(sizeof(*conf));
@@ -62,35 +115,32 @@ static int eaptls_attach(CONF_SECTION *cs, void **arg)
                return -1;
        }
        memset(conf, 0, sizeof(*conf));
+
+       inst->conf = conf;
        if (cf_section_parse(cs, conf, module_config) < 0) {
-               free(conf);
+               eaptls_detach(inst);
                return -1;
        }
 
 
        /* Initialize TLS */
        ctx = init_tls_ctx(conf);
-       if (ctx == NULL) return -1;
-
-       if (load_dh_params(ctx, conf->dh_file) < 0) return -1;
-       if (generate_eph_rsa_key(ctx) < 0) return -1;
-
-       /* Store all these values in the data structure for later references */
-       *eaptls = (eap_tls_t *)malloc(sizeof(eap_tls_t));
-       if (*eaptls == NULL) {
-               radlog(L_ERR, "rlm_eap_tls: out of memory");
+       if (ctx == NULL) {
+               eaptls_detach(inst);
+               return -1;
+       }
+       inst->ctx = ctx;
 
-               free(conf->dh_file);
-               free(conf->certificate_file);
-               free(conf->private_key_file);
-               free(conf->private_key_password);
-               free(conf);
+       if (load_dh_params(ctx, conf->dh_file) < 0) {
+               eaptls_detach(inst);
+               return -1;
+       }
+       if (generate_eph_rsa_key(ctx) < 0) {
+               eaptls_detach(inst);
                return -1;
        }
 
-       radlog(L_ERR, "rlm_eap_tls: conf N ctx stored ");
-       (*eaptls)->conf = conf;
-       (*eaptls)->ctx = ctx;
+       *instance = inst;
 
        return 0;
 }
@@ -153,6 +203,11 @@ static int eaptls_initiate(void *type_arg, EAP_HANDLER *handler)
        if (status == 0)
                return 0;
 
+       /*
+        *      The next stage to process the packet.
+        */
+       handler->stage = AUTHENTICATE;
+
        return 1;
 }
 
@@ -210,37 +265,6 @@ static int eaptls_authenticate(void *arg, EAP_HANDLER *handler)
        return 1;
 }
 
-static int eaptls_detach(void **arg)
-{
-       EAP_TLS_CONF     *conf;
-       eap_tls_t        **eaptls;
-
-       eaptls = (eap_tls_t **)arg;
-       conf = (*eaptls)->conf;
-
-       free(conf->dh_file);
-               conf->dh_file = NULL;
-       free(conf->certificate_file);
-               conf->certificate_file = NULL;
-       free(conf->private_key_file);
-               conf->private_key_file = NULL;
-       free(conf->private_key_password);
-               conf->private_key_password = NULL;
-       free(conf->random_file);
-               conf->random_file = NULL;
-
-       free((*eaptls)->conf);
-       (*eaptls)->conf = NULL;
-
-       SSL_CTX_free((*eaptls)->ctx);
-       (*eaptls)->ctx = NULL;
-
-       free(*eaptls);
-       *eaptls = NULL;
-
-       return 0;
-}
-
 /*
  *     The module name should be the only globally exported symbol.
  *     That is, everything else should be 'static'.
@@ -248,7 +272,8 @@ static int eaptls_detach(void **arg)
 EAP_TYPE rlm_eap_tls = {
        "eap_tls",
        eaptls_attach,                  /* attach */
-       eaptls_initiate,                        /* Start the initial request, after Identity */
+       eaptls_initiate,                /* Start the initial request */
+       NULL,                           /* authorization */
        eaptls_authenticate,            /* authentication */
        eaptls_detach                   /* detach */
 };
index a46d84f..1bc6089 100644 (file)
@@ -406,15 +406,14 @@ void session_close(tls_session_t *ssn)
        session_init(ssn);
 }
 
-void session_free(void **ssn)
+void session_free(void *ssn)
 {
-       tls_session_t **sess = (tls_session_t **)ssn;
-       if ((sess == NULL) || (*sess == NULL))
-               return;
+       tls_session_t *sess = (tls_session_t *)ssn;
+
+       if (!ssn) return;
 
-       session_close(*sess);
-       free(*sess);
-       *sess = NULL;
+       session_close(sess);
+       free(sess);
 }
 
 void record_init(record_t *rec)