static void Radius_client_list_add(rtapd *rtapd, struct radius_msg *msg, RadiusType msg_type, u8 *shared_secret, size_t shared_secret_len) { struct radius_msg_list *entry, *prev; if (eloop_terminated()) { /* No point in adding entries to retransmit queue since event * loop has already been terminated. */ DBGPRINT(RT_DEBUG_TRACE,"eloop_terminate \n"); Radius_msg_free(msg); free(msg); return; } entry = malloc(sizeof(*entry)); if (entry == NULL) { DBGPRINT(RT_DEBUG_TRACE,"Failed to add RADIUS packet into retransmit list\n"); Radius_msg_free(msg); free(msg); return; } memset(entry, 0, sizeof(*entry)); entry->msg = msg; entry->msg_type = msg_type; entry->shared_secret = shared_secret; entry->shared_secret_len = shared_secret_len; time(&entry->first_try); entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; entry->attempts = 1; entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; if (!rtapd->radius->msgs) eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, Radius_client_timer, rtapd, NULL); entry->next = rtapd->radius->msgs; rtapd->radius->msgs = entry; if (rtapd->radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) { DBGPRINT(RT_DEBUG_TRACE,"Removing the oldest un-ACKed RADIUS packet due to retransmit list limits.\n"); prev = NULL; while (entry->next) { prev = entry; entry = entry->next; } if (prev) { prev->next = NULL; Radius_client_msg_free(entry); } } else rtapd->radius->num_msgs++; }
struct radius_msg *Radius_msg_parse(const u8 *data, size_t len) { struct radius_msg *msg; struct radius_hdr *hdr; struct radius_attr_hdr *attr; size_t msg_len; unsigned char *pos, *end; if (data == NULL || len < sizeof(*hdr)) return NULL; hdr = (struct radius_hdr *) data; msg_len = ntohs(hdr->length); if (msg_len < sizeof(*hdr) || msg_len > len) { DBGPRINT(RT_DEBUG_ERROR,"Invalid RADIUS message length\n"); return NULL; } if (msg_len < len) { DBGPRINT(RT_DEBUG_INFO,"Ignored %d extra bytes after RADIUS message\n", len - msg_len); } msg = (struct radius_msg *) malloc(sizeof(*msg)); if (msg == NULL) return NULL; if (Radius_msg_initialize(msg, msg_len)) { free(msg); return NULL; } memcpy(msg->buf, data, msg_len); msg->buf_size = msg->buf_used = msg_len; /* parse attributes */ pos = (unsigned char *) (msg->hdr + 1); end = msg->buf + msg->buf_used; while (pos < end) { if (end - pos < sizeof(*attr)) goto fail; attr = (struct radius_attr_hdr *) pos; if (pos + attr->length > end || attr->length < sizeof(*attr)) goto fail; /* TODO: check that attr->length is suitable for attr->type */ if (Radius_msg_add_attr_to_array(msg, attr)) goto fail; pos += attr->length; } return msg; fail: Radius_msg_free(msg); free(msg); return NULL; }
static void Radius_client_msg_free(struct radius_msg_list *req) { Radius_msg_free(req->msg); free(req->msg); free(req); }
static void Radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) { rtapd *rtapd = eloop_ctx; RadiusType msg_type = (RadiusType) sock_ctx; int len, i,len_80211hdr=24; unsigned char buf[3000]; struct radius_msg *msg; struct radius_rx_handler *handlers; size_t num_handlers; struct radius_msg_list *req, *prev_req; DBGPRINT(RT_DEBUG_INFO,"RADIUS_CLIENT_RECEIVE : msg_type= %d \n", msg_type); len = recv(sock, buf, sizeof(buf), 0); if (len < 0) { perror("recv[RADIUS]"); return; } if (len == sizeof(buf)) { DBGPRINT(RT_DEBUG_ERROR,"Possibly too long UDP frame for our buffer - dropping it\n"); return; } if(buf[0]!=0xff) { int i; DBGPRINT(RT_DEBUG_INFO," r_dump %d bytes:",len); for (i = 0; i < len_80211hdr; i++) DBGPRINT(RT_DEBUG_INFO," %02x", buf[i]); DBGPRINT(RT_DEBUG_INFO,"\n"); } msg = Radius_msg_parse(buf, len); if (msg == NULL) { DBGPRINT(RT_DEBUG_ERROR,"Parsing incoming RADIUS frame failed\n"); return; } handlers = rtapd->radius->auth_handlers; num_handlers = rtapd->radius->num_auth_handlers; prev_req = NULL; req = rtapd->radius->msgs; while (req) { /* TODO: also match by src addr:port of the packet when using * alternative RADIUS servers (?) */ if (req->msg_type == msg_type && req->msg->hdr->identifier == msg->hdr->identifier) break; prev_req = req; req = req->next; } if (req == NULL) { goto fail; } /* Remove ACKed RADIUS packet from retransmit list */ if (prev_req) prev_req->next = req->next; else rtapd->radius->msgs = req->next; rtapd->radius->num_msgs--; for (i = 0; i < num_handlers; i++) { RadiusRxResult res; res = handlers[i].handler(rtapd, msg, req->msg, req->shared_secret, req->shared_secret_len, handlers[i].data); switch (res) { case RADIUS_RX_PROCESSED: Radius_msg_free(msg); free(msg); /* continue */ case RADIUS_RX_QUEUED: Radius_client_msg_free(req); return; case RADIUS_RX_UNKNOWN: /* continue with next handler */ break; } } DBGPRINT(RT_DEBUG_ERROR,"No RADIUS RX handler found (type=%d code=%d id=%d) - dropping " "packet\n", msg_type, msg->hdr->code, msg->hdr->identifier); Radius_client_msg_free(req); fail: Radius_msg_free(msg); free(msg); }