make eap channel bindings functional (at least with with ttls-mschap)
authorKevin <kevin@debian.suchdamage.org>
Sun, 5 Feb 2012 20:09:17 +0000 (15:09 -0500)
committerKevin <kevin@debian.suchdamage.org>
Sun, 5 Feb 2012 20:09:17 +0000 (15:09 -0500)
src/modules/rlm_eap/libeap/eap_chbind.c
src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c

index 78dcf68..66d2b38 100644 (file)
@@ -106,22 +106,39 @@ int chbind_process(REQUEST *req, CHBIND_REQ *chbind_req)
   pairadd(&fake->packet->vps, vp);*/
 
   /* Add the channel binding attributes to the fake packet */
-  if (0 != (datalen = chbind_get_data((CHBIND_PACKET_T *)chbind_req->chbind_req_pkt, chbind_req->chbind_req_len, 
+  if (0 != (datalen = chbind_get_data((CHBIND_PACKET_T *)chbind_req->chbind_req_pkt, 
+                                     chbind_req->chbind_req_len, 
                                      CHBIND_NSID_RADIUS, &attr_data))) {
-    if (rad_attr2vp(NULL, NULL, NULL, attr_data, datalen, &vp) <= 0) {
-      /* If radaddr2vp fails, return NULL string for channel binding response */
-      request_free(&fake);
-      return PW_AUTHENTICATION_ACK;
-    }
-    if (vp)
-      pairadd(&fake->packet->vps, vp);
+         while(datalen > 0) {
+                 int mylen = rad_attr2vp(NULL, NULL, NULL, attr_data, datalen, &vp);
+                 if (mylen <= 0) {
+                         /* If radaddr2vp fails, return NULL string for 
+                            channel binding response */
+                         request_free(&fake);
+                         return PW_AUTHENTICATION_ACK;
+                 }
+                 /* TODO: need to account for the possibility of rad_attr2vp generating 
+                    multiple vps */
+                 if (vp)
+                         pairadd(&fake->packet->vps, vp);
+                 attr_data += mylen;
+                 datalen -= mylen;
+         }
   }
 
   /* Set virtual server based on configuration for channel bindings,
      this is hard-coded to "chbind" for now */
-  fake->server = pairmake("Virtual-Server", "chbind", T_OP_EQ);
+  fake->server = "chbind";
 
   /* Call rad_authenticate */
+  if ((debug_flag > 0) && fr_log_fp) {
+         DEBUG("prcoessing chbind request");
+
+         debug_pair_list(fake->packet->vps);
+
+         fprintf(fr_log_fp, "server %s {\n",
+           (fake->server == NULL) ? "" : fake->server);
+  }
   rcode = rad_authenticate(fake);
 
   switch(rcode) {
@@ -183,7 +200,7 @@ size_t chbind_get_data(CHBIND_PACKET_T *chbind_packet,
 
 uint8_t *chbind_build_response(REQUEST *req, size_t *resp_len)
 {
-  uint8_t *resp, *rp = NULL;
+  uint8_t *resp;
   uint16_t rlen, len = 0;
   VALUE_PAIR *vp = NULL;
 
@@ -200,11 +217,16 @@ uint8_t *chbind_build_response(REQUEST *req, size_t *resp_len)
 
   resp[3] = CHBIND_NSID_RADIUS;
 
+  if ((debug_flag > 0) && fr_log_fp) {
+         DEBUG("Sending chbind response: code %i\n", (int )(resp[0]));
+         debug_pair_list(req->reply->vps);
+         DEBUG("end chbind response\n");
+  }
   /* Encode the chbind attributes into the response */
   for (vp = req->reply->vps, rlen = 4; 
        (vp != NULL) && (rlen < MAX_PACKET_LEN + 4); 
        rlen += len) {
-    len = rad_vp2attr(NULL, NULL, NULL, vp, resp[rlen], (MAX_PACKET_LEN + 4) - rlen);
+    len = rad_vp2attr(NULL, NULL, NULL, &vp, &resp[rlen], (MAX_PACKET_LEN + 4) - rlen);
   }
 
   /* Write the length field into the header */
index 9507150..4c12e8a 100644 (file)
@@ -721,11 +721,17 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session,
                        pairfree(&vp);
                }
 
+               /* move channel binding responses; we need to send them */
+               pairmove2(&vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA);
+
                /*
                 *      Handle the ACK, by tunneling any necessary reply
                 *      VP's back to the client.
                 */
                if (vp) {
+                       RDEBUG("sending tunneled reply attributes");
+                       debug_pair_list(vp);
+                       RDEBUG("end tunneled reply attributes");
                        vp2diameter(request, tls_session, vp);
                        pairfree(&vp);
                }
@@ -787,6 +793,9 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session,
                 */
                pairmove2(&vp, &reply->vps, PW_REPLY_MESSAGE, 0);
 
+               /* also move chbind messages, if any */
+               pairmove2(&vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA);
+
                /*
                 *      Handle the ACK, by tunneling any necessary reply
                 *      VP's back to the client.
@@ -1205,7 +1214,9 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session)
         */
        chbind_len = eap_chbind_vp2packet(fake->packet->vps, &chbind_packet);
        if (chbind_len > 0) {
+               int chbind_rcode;
                CHBIND_REQ *req = chbind_allocate();
+
                RDEBUG("received chbind request");
                req->chbind_req_pkt = (uint8_t *)chbind_packet;
                req->chbind_req_len = chbind_len;
@@ -1216,7 +1227,7 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session)
                        req->username = NULL;
                        req->username_len = 0;
                }
-               chbind_process(request, req);
+               chbind_rcode = chbind_process(request, req);
 
                /* free the chbind packet; we're done with it */
                free(chbind_packet);
@@ -1225,14 +1236,17 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session)
                if (req->chbind_resp_len > 0) {
                        RDEBUG("sending chbind response");
                        pairadd(&fake->reply->vps,
-                               eap_chbind_packet2vp((eap_chbind_packet_t *)req->chbind_resp,
-                                                    req->chbind_resp_len));
+                                eap_chbind_packet2vp((eap_chbind_packet_t *)req->chbind_resp,
+                                                     req->chbind_resp_len));
                } else {
                        RDEBUG("no chbind response");
                }
 
                /* clean up chbind req */
                chbind_free(req);
+
+               if (chbind_rcode != PW_AUTHENTICATION_ACK)
+                       return chbind_rcode;
        }
 
        /*