/* * verify = MD5(id+password+challenge_sent) */ int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password, uint8_t *challenge) { char *ptr; char string[1 + MAX_STRING_LEN*2]; unsigned char output[MAX_STRING_LEN]; unsigned short len; /* * Sanity check it. */ if (packet->value_size != 16) { radlog(L_ERR, "rlm_eap_md5: Expected 16 bytes of response to challenge, got %d", packet->value_size); return 0; } len = 0; ptr = string; /* * This is really rad_chap_pwencode()... */ *ptr++ = packet->id; len++; memcpy(ptr, password->vp_strvalue, password->length); ptr += password->length; len += password->length; /* * The challenge size is hard-coded. */ memcpy(ptr, challenge, MD5_CHALLENGE_LEN); len += MD5_CHALLENGE_LEN; fr_md5_calc((u_char *)output, (u_char *)string, len); /* * The length of the response is always 16 for MD5. */ if (memcmp(output, packet->value, 16) != 0) { return 0; } return 1; }
static int sendrecv_eap(RADIUS_PACKET *rep) { RADIUS_PACKET *req = NULL; VALUE_PAIR *vp, *vpnext; int tried_eap_md5 = 0; if (!rep) return -1; /* * Keep a copy of the the User-Password attribute. */ if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, vp->vp_strvalue, sizeof(password)); } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, vp->vp_strvalue, sizeof(password)); /* * Otherwise keep a copy of the CHAP-Password attribute. */ } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, vp->vp_strvalue, sizeof(password)); } else { *password = '******'; } again: rep->id++; /* * if there are EAP types, encode them into an EAP-Message * */ map_eap_methods(rep); /* * Fix up Digest-Attributes issues */ for (vp = rep->vps; vp != NULL; vp = vp->next) { switch (vp->da->attr) { default: break; case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ { DICT_ATTR const *da; uint8_t *p, *q; p = talloc_array(vp, uint8_t, vp->length + 2); memcpy(p + 2, vp->vp_octets, vp->length); p[0] = vp->da->attr - PW_DIGEST_REALM + 1; vp->length += 2; p[1] = vp->length; da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0); vp->da = da; /* * Re-do pairmemsteal ourselves, * because we play games with * vp->da, and pairmemsteal goes * to GREAT lengths to sanitize * and fix and change and * double-check the various * fields. */ memcpy(&q, &vp->vp_octets, sizeof(q)); talloc_free(q); vp->vp_octets = talloc_steal(vp, p); vp->type = VT_DATA; VERIFY_VP(vp); } break; } } /* * If we've already sent a packet, free up the old * one, and ensure that the next packet has a unique * ID and authentication vector. */ if (rep->data) { talloc_free(rep->data); rep->data = NULL; } fr_md5_calc(rep->vector, rep->vector, sizeof(rep->vector)); if (*password != '\0') { if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); uint8_t *p; p = talloc_zero_array(vp, uint8_t, 17); rad_chap_encode(rep, p, rep->id, vp); pairmemsteal(vp, p); } } /* there WAS a password */ /* send the response, wait for the next request */ send_packet(rep, &req); if (!req) return -1; /* okay got back the packet, go and decode the EAP-Message. */ unmap_eap_methods(req); debug_packet(req, R_RECV); /* now look for the code type. */ for (vp = req->vps; vp != NULL; vp = vpnext) { vpnext = vp->next; switch (vp->da->attr) { default: break; case ATTRIBUTE_EAP_BASE+PW_EAP_MD5: if(respond_eap_md5(req, rep) && tried_eap_md5 < 3) { tried_eap_md5++; goto again; } break; case ATTRIBUTE_EAP_BASE+PW_EAP_SIM: if(respond_eap_sim(req, rep)) { goto again; } break; } } return 1; }
static int sendrecv_eap(RADIUS_PACKET *rep) { RADIUS_PACKET *req = NULL; VALUE_PAIR *vp, *vpnext; int tried_eap_md5 = 0; /* * Keep a copy of the the User-Password attribute. */ if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue)); } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue)); /* * Otherwise keep a copy of the CHAP-Password attribute. */ } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) { strlcpy(password, (char *)vp->vp_strvalue, sizeof(vp->vp_strvalue)); } else { *password = '******'; } again: rep->id++; /* * if there are EAP types, encode them into an EAP-Message * */ map_eap_methods(rep); /* * Fix up Digest-Attributes issues */ for (vp = rep->vps; vp != NULL; vp = vp->next) { switch (vp->da->attribute) { default: break; case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ memmove(&vp->vp_strvalue[2], &vp->vp_octets[0], vp->length); vp->vp_octets[0] = vp->da->attribute - PW_DIGEST_REALM + 1; vp->length += 2; vp->vp_octets[1] = vp->length; vp->da->attribute = PW_DIGEST_ATTRIBUTES; break; } } /* * If we've already sent a packet, free up the old * one, and ensure that the next packet has a unique * ID and authentication vector. */ if (rep->data) { talloc_free(rep->data); rep->data = NULL; } fr_md5_calc(rep->vector, rep->vector, sizeof(rep->vector)); if (*password != '\0') { if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) { pairstrcpy(vp, password); rad_chap_encode(rep, vp->vp_octets, rep->id, vp); vp->length = 17; } } /* there WAS a password */ /* send the response, wait for the next request */ send_packet(rep, &req); /* okay got back the packet, go and decode the EAP-Message. */ unmap_eap_methods(req); debug_packet(req, R_RECV); /* now look for the code type. */ for (vp = req->vps; vp != NULL; vp = vpnext) { vpnext = vp->next; switch (vp->da->attribute) { default: break; case ATTRIBUTE_EAP_BASE+PW_EAP_MD5: if(respond_eap_md5(req, rep) && tried_eap_md5 < 3) { tried_eap_md5++; goto again; } break; case ATTRIBUTE_EAP_BASE+PW_EAP_SIM: if(respond_eap_sim(req, rep)) { goto again; } break; } } return 1; }
/*Note: * We just support EAP proxy. * rad_send_eap_response * send a EAP response to radius server */ int rad_send_eap_response(RADIUS_PACKET* rep,const char* secret,const char* pwd) { VALUE_PAIR* vp; int rc; int old_debug_flag; vp = NULL; rc = 0; old_debug_flag = 0; /* * if there are EAP types, encode them into an EAP-Message * */ map_eap_types(rep); /* * Fix up Digest-Attributes issues */ for (vp = rep->vps; vp != NULL; vp = vp->next) { switch (vp->attribute) { default: break; case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ memmove(&vp->vp_strvalue[2], &vp->vp_octets[0], vp->length); vp->vp_octets[0] = vp->attribute - PW_DIGEST_REALM + 1; vp->length += 2; vp->vp_octets[1] = vp->length; vp->attribute = PW_DIGEST_ATTRIBUTES; break; } } fr_md5_calc(rep->vector, rep->vector, sizeof(rep->vector)); if ((pwd != NULL) && (*pwd != '\0')) { if ((vp = pairfind(rep->vps, PW_CLEARTEXT_PASSWORD)) != NULL) { strncpy((char *)vp->vp_strvalue, pwd, sizeof(vp->vp_strvalue) - 1); vp->length = strlen(pwd); } else if ((vp = pairfind(rep->vps, PW_USER_PASSWORD)) != NULL) { strncpy((char *)vp->vp_strvalue, pwd, sizeof(vp->vp_strvalue) - 1); vp->length = strlen(pwd); } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD)) != NULL) { strncpy((char *)vp->vp_strvalue, pwd, sizeof(vp->vp_strvalue) - 1); vp->length = strlen(pwd); rad_chap_encode(rep, vp->vp_octets, rep->id, vp); vp->length = 17; } } /* there WAS a password */ /* send the response*/ if(fr_debug_flag) { debug_packet(rep,R_SENT); old_debug_flag = fr_debug_flag; fr_debug_flag = 0; /*just turn off the debug-flag to avoid rad_send debug out agin*/ } if(rad_send(rep,NULL,secret) < 0) rc = -1; else rc = 0; if(old_debug_flag) fr_debug_flag = old_debug_flag; return rc; }