struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, const u8 *data, size_t data_len) { size_t buf_needed; struct radius_attr_hdr *attr; if (data_len > RADIUS_MAX_ATTR_LEN) { printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", (unsigned long) data_len); return NULL; } buf_needed = sizeof(*attr) + data_len; if (wpabuf_tailroom(msg->buf) < buf_needed) { /* allocate more space for message buffer */ if (wpabuf_resize(&msg->buf, buf_needed) < 0) return NULL; msg->hdr = wpabuf_mhead(msg->buf); } attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr)); attr->type = type; attr->length = sizeof(*attr) + data_len; wpabuf_put_data(msg->buf, data, data_len); if (radius_msg_add_attr_to_array(msg, attr)) return NULL; return attr; }
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, const u8 *data, size_t data_len) { size_t buf_needed; struct radius_attr_hdr *attr; if (data_len > RADIUS_MAX_ATTR_LEN) { printf("radius_msg_add_attr: too long attribute (%lu bytes)\n", (unsigned long) data_len); return NULL; } buf_needed = msg->buf_used + sizeof(*attr) + data_len; if (msg->buf_size < buf_needed) { /* allocate more space for message buffer */ unsigned char *nbuf; size_t i, nlen = msg->buf_size; int diff; while (nlen < buf_needed) nlen *= 2; nbuf = os_realloc(msg->buf, nlen); if (nbuf == NULL) return NULL; diff = nbuf - msg->buf; msg->buf = nbuf; msg->hdr = (struct radius_hdr *) msg->buf; /* adjust attr pointers to match with the new buffer */ for (i = 0; i < msg->attr_used; i++) msg->attrs[i] = (struct radius_attr_hdr *) (((u8 *) msg->attrs[i]) + diff); os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size); msg->buf_size = nlen; } attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used); attr->type = type; attr->length = sizeof(*attr) + data_len; if (data_len > 0) os_memcpy(attr + 1, data, data_len); msg->buf_used += sizeof(*attr) + data_len; if (radius_msg_add_attr_to_array(msg, attr)) return NULL; return attr; }
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, const u8 *data, size_t data_len) { size_t buf_needed; struct radius_attr_hdr *attr; if (data_len > RADIUS_MAX_ATTR_LEN) { fd_log_debug("radius_msg_add_attr: too long attribute (%lu bytes)", (unsigned long) data_len); return NULL; } buf_needed = msg->buf_used + sizeof(*attr) + data_len; if (msg->buf_size < buf_needed) { /* allocate more space for message buffer */ unsigned char *nbuf; size_t nlen = msg->buf_size; while (nlen < buf_needed) nlen *= 2; nbuf = os_realloc(msg->buf, nlen); if (nbuf == NULL) return NULL; msg->buf = nbuf; msg->hdr = (struct radius_hdr *) msg->buf; os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size); msg->buf_size = nlen; } attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used); attr->type = type; attr->length = sizeof(*attr) + data_len; if (data_len > 0) os_memcpy(attr + 1, data, data_len); msg->buf_used += sizeof(*attr) + data_len; if (radius_msg_add_attr_to_array(msg, attr)) return NULL; return attr; }
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) { printf("Invalid RADIUS message length\n"); return NULL; } if (msg_len < len) { printf("Ignored %lu extra bytes after RADIUS message\n", (unsigned long) len - msg_len); } msg = os_malloc(sizeof(*msg)); if (msg == NULL) return NULL; if (radius_msg_initialize(msg, msg_len)) { os_free(msg); return NULL; } os_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 ((size_t) (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); os_free(msg); return NULL; }
/** * radius_msg_parse - Parse a RADIUS message * @data: RADIUS message to be parsed * @len: Length of data buffer in octets * Returns: Parsed RADIUS message or %NULL on failure * * This parses a RADIUS message and makes a copy of its data. The caller is * responsible for freeing the returned data with radius_msg_free(). */ 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) { wpa_printf(MSG_INFO, "RADIUS: Invalid message length"); return NULL; } if (msg_len < len) { wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after " "RADIUS message", (unsigned long) len - msg_len); } msg = os_zalloc(sizeof(*msg)); if (msg == NULL) return NULL; msg->buf = wpabuf_alloc_copy(data, msg_len); if (msg->buf == NULL || radius_msg_initialize(msg)) { radius_msg_free(msg); return NULL; } msg->hdr = wpabuf_mhead(msg->buf); /* parse attributes */ pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr); end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf); while (pos < end) { if ((size_t) (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); return NULL; }
/* Modified version of radius_msg_parse */ int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg) { struct rgw_radius_msg_meta * temp_msg = NULL; struct radius_hdr *hdr; struct radius_attr_hdr *attr; size_t msg_len; unsigned char *pos, *end; int ret = 0; TRACE_ENTRY("%p %zd %p", buf, len, msg); CHECK_PARAMS( buf && len >= sizeof(*hdr) && msg ); *msg = NULL; /* Parse the RADIUS message */ hdr = (struct radius_hdr *) buf; msg_len = ntohs(hdr->length); if (msg_len < sizeof(*hdr) || msg_len > len) { TRACE_DEBUG(INFO, "Invalid RADIUS message length"); return EINVAL; } if (msg_len < len) { TRACE_DEBUG(INFO, "Ignored %lu extra bytes after RADIUS message", (unsigned long) len - msg_len); } CHECK_MALLOC( temp_msg = malloc(sizeof(struct rgw_radius_msg_meta)) ); memset(temp_msg, 0, sizeof(struct rgw_radius_msg_meta)); if (radius_msg_initialize(&temp_msg->radius, msg_len)) { TRACE_DEBUG(INFO, "Error in radius_msg_initialize, returning ENOMEM."); free(temp_msg); return ENOMEM; } /* Store the received data in the alloc'd buffer */ memcpy(temp_msg->radius.buf, buf, msg_len); temp_msg->radius.buf_size = temp_msg->radius.buf_used = msg_len; /* parse attributes */ pos = (unsigned char *) (temp_msg->radius.hdr + 1); end = temp_msg->radius.buf + temp_msg->radius.buf_used; while (pos < end) { if ((size_t) (end - pos) < sizeof(*attr)) { TRACE_DEBUG(INFO, "Trucated attribute found in RADIUS buffer, EINVAL."); ret = EINVAL; break; } attr = (struct radius_attr_hdr *) pos; if (pos + attr->length > end || attr->length < sizeof(*attr)) { TRACE_DEBUG(INFO, "Trucated attribute found in RADIUS buffer, EINVAL."); ret = EINVAL; break; } if (radius_msg_add_attr_to_array(&temp_msg->radius, attr)) { TRACE_DEBUG(INFO, "Error in radius_msg_add_attr_to_array, ENOMEM"); ret = ENOMEM; break; } if (attr->type == RADIUS_ATTR_PROXY_STATE) temp_msg->ps_nb += 1; pos += attr->length; } if (ret != 0) { radius_msg_free(&temp_msg->radius); free(temp_msg); return ret; } /* Now move all the proxy-state attributes at the end of the attr_pos array */ if (temp_msg->ps_nb) { size_t *temp_ps = NULL; int n, new_n = 0, p = 0; CHECK_MALLOC( temp_ps = calloc(temp_msg->ps_nb, sizeof(size_t)) ); /* Move all the Proxy-State attributes into the temp_ps array */ for (n=0; n < temp_msg->radius.attr_used; n++) { struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(temp_msg->radius.buf + temp_msg->radius.attr_pos[n]); if (attr->type == RADIUS_ATTR_PROXY_STATE) { temp_ps[p++] = temp_msg->radius.attr_pos[n]; } else { temp_msg->radius.attr_pos[new_n++] = temp_msg->radius.attr_pos[n]; } } temp_msg->radius.attr_used = new_n; /* hide the proxy-state to other modules */ temp_msg->ps_first = new_n; /* And back into the array */ memcpy(temp_msg->radius.attr_pos + new_n, temp_ps, p * sizeof(size_t)); free(temp_ps); } *msg = temp_msg; return 0; }