/* * verify = MD5(id+password+challenge_sent) */ int eapmd5_verify(MD5_PACKET *packet, VALUE_PAIR* password, md5_packet_t *challenge) { char *ptr; char string[MAX_STRING_LEN*2]; unsigned char output[MAX_STRING_LEN]; unsigned short len; if ((password == NULL) || (challenge == NULL)) { return 0; } /* * 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; *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; librad_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; }
/* * Compare two RADIUS_PACKET data structures, based on a number * of criteria. */ static int send_one_packet(radclient_t *radclient) { int i; assert(radclient->done == 0); /* * Remember when we have to wake up, to re-send the * request, of we didn't receive a response. */ if ((sleep_time == -1) || (sleep_time > (int) timeout)) { sleep_time = (int) timeout; } /* * Haven't sent the packet yet. Initialize it. */ if (radclient->request->id == -1) { int found = 0; assert(radclient->reply == NULL); /* * Find a free packet Id */ for (i = 0; i < 256; i++) { if (radius_id[(last_used_id + i) & 0xff] == 0) { last_used_id = (last_used_id + i) & 0xff; radius_id[last_used_id] = 1; radclient->request->id = last_used_id++; found = 1; break; } } /* * Didn't find a free packet ID, we're not done, * we don't sleep, and we stop trying to process * this packet. */ if (!found) { done = 0; sleep_time = 0; return 0; } assert(radclient->request->id != -1); assert(radclient->request->data == NULL); librad_md5_calc(radclient->request->vector, radclient->request->vector, sizeof(radclient->request->vector)); /* * Update the password, so it can be encrypted with the * new authentication vector. */ if (radclient->password[0] != '\0') { VALUE_PAIR *vp; if ((vp = pairfind(radclient->request->vps, PW_PASSWORD)) != NULL) { strNcpy((char *)vp->strvalue, radclient->password, sizeof(vp->strvalue)); vp->length = strlen(vp->strvalue); } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD)) != NULL) { strNcpy((char *)vp->strvalue, radclient->password, sizeof(vp->strvalue)); vp->length = strlen(vp->strvalue); rad_chap_encode(radclient->request, (char *) vp->strvalue, radclient->request->id, vp); vp->length = 17; } } radclient->timestamp = time(NULL); radclient->tries = 1; radclient->resend++; /* * Duplicate found. Serious error! */ } else /* radclient->request->id >= 0 */ { time_t now = time(NULL); /* * FIXME: Accounting packets are never retried! * The Acct-Delay-Time attribute is updated to * reflect the delay, and the packet is re-sent * from scratch! */ /* * Not time for a retry, do so. */ if ((now - radclient->timestamp) < timeout) { /* * When we walk over the tree sending * packets, we update the minimum time * required to sleep. */ if ((sleep_time == -1) || (sleep_time > (now - radclient->timestamp))) { sleep_time = now - radclient->timestamp; } return 0; } /* * We're not trying later, maybe the packet is done. */ if (radclient->tries == retries) { assert(radclient->request->id >= 0); /* * Delete the request from the tree of * outstanding requests. */ fprintf(stderr, "radclient: no response from server for ID %d\n", radclient->request->id); /* * Normally we mark it "done" when we've received * the response, but this is a special case. */ if (radclient->resend == resend_count) { radclient->done = 1; } totallost++; return -1; } /* * We are trying later. */ radclient->timestamp = now; radclient->tries++; } /* * Send the packet. */ if (rad_send(radclient->request, NULL, secret) < 0) { fprintf(stderr, "radclient: Failed to send packet for ID %d: %s\n", radclient->request->id, librad_errstr); } return 0; }
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, ATTRIBUTE_EAP_MD5_PASSWORD)) != NULL) { strNcpy(password, (char *)vp->strvalue, sizeof(vp->strvalue)); } else if ((vp = pairfind(rep->vps, PW_PASSWORD)) != NULL) { strNcpy(password, (char *)vp->strvalue, sizeof(vp->strvalue)); /* * Otherwise keep a copy of the CHAP-Password attribute. */ } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD)) != NULL) { strNcpy(password, (char *)vp->strvalue, sizeof(vp->strvalue)); } else { *password = '******'; } again: rep->id++; printf("\n+++> About to send encoded packet:\n"); vp_printlist(stdout, rep->vps); /* * 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->strvalue[2], &vp->strvalue[0], vp->length); vp->strvalue[0] = vp->attribute - PW_DIGEST_REALM + 1; vp->length += 2; vp->strvalue[1] = vp->length; vp->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) { free(rep->data); rep->data = NULL; } librad_md5_calc(rep->vector, rep->vector, sizeof(rep->vector)); if (*password != '\0') { if ((vp = pairfind(rep->vps, PW_PASSWORD)) != NULL) { strNcpy((char *)vp->strvalue, password, strlen(password) + 1); vp->length = strlen(password); } else if ((vp = pairfind(rep->vps, PW_CHAP_PASSWORD)) != NULL) { strNcpy((char *)vp->strvalue, password, strlen(password) + 1); vp->length = strlen(password); rad_chap_encode(rep, (char *) vp->strvalue, 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_types(req); printf("<+++ EAP decoded packet:\n"); vp_printlist(stdout, req->vps); /* now look for the code type. */ for (vp = req->vps; vp != NULL; vp = vpnext) { vpnext = vp->next; switch (vp->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; }