📄 vqp.c
字号:
return NULL; } ptr = packet->data; if (0) { int i; for (i = 0; i < packet->data_len; i++) { if ((i & 0x0f) == 0) fprintf(stderr, "%02x: ", i); fprintf(stderr, "%02x ", ptr[i]); if ((i & 0x0f) == 0x0f) fprintf(stderr, "\n"); } } if (ptr[3] > VQP_MAX_ATTRIBUTES) { librad_log("Too many VQP attributes"); rad_free(&packet); return NULL; } if (packet->data_len > VQP_HDR_LEN) { int attrlen; /* * Skip the header. */ ptr += VQP_HDR_LEN; length = packet->data_len - VQP_HDR_LEN; while (length > 0) { if (length < 7) { librad_log("Packet contains malformed attribute"); rad_free(&packet); return NULL; } /* * Attributes are 4 bytes * 0x00000c01 ... 0x00000c08 */ if ((ptr[0] != 0) || (ptr[1] != 0) || (ptr[2] != 0x0c) || (ptr[3] < 1) || (ptr[3] > 8)) { librad_log("Packet contains invalid attribute"); rad_free(&packet); return NULL; } /* * Length is 2 bytes * * We support lengths 1..253, for internal * server reasons. Also, there's no reason * for bigger lengths to exist... admins * won't be typing in a 32K vlan name. */ if ((ptr[4] != 0) || (ptr[5] > 253)) { librad_log("Packet contains attribute with invalid length %02x %02x", ptr[4], ptr[5]); rad_free(&packet); return NULL; } attrlen = ptr[5]; ptr += 6 + attrlen; length -= (6 + attrlen); } } packet->sockfd = sockfd; packet->vps = NULL; /* * This is more than a bit of a hack. */ packet->code = PW_AUTHENTICATION_REQUEST; memcpy(&id, packet->data + 4, 4); packet->id = ntohl(id); /* * FIXME: Create a fake "request authenticator", to * avoid duplicates? Or is the VQP sequence number * adequate for this purpose? */ return packet;}/* * We do NOT mirror the old-style RADIUS code that does encode, * sign && send in one function. For VQP, the caller MUST perform * each task manually, and separately. */int vqp_send(RADIUS_PACKET *packet){ if (!packet || !packet->data || (packet->data_len < 8)) return -1; /* * Don't print out the attributes, they were printed out * when it was encoded. */ /* * And send it on it's way. */ return vqp_sendto(packet->sockfd, packet->data, packet->data_len, 0, &packet->src_ipaddr, &packet->dst_ipaddr, packet->dst_port);}int vqp_decode(RADIUS_PACKET *packet){ uint8_t *ptr, *end; int attribute, length; VALUE_PAIR *vp, **tail; if (!packet || !packet->data) return -1; if (packet->data_len < VQP_HDR_LEN) return -1; tail = &packet->vps; vp = paircreate(PW_VQP_PACKET_TYPE, PW_TYPE_OCTETS); if (!vp) { librad_log("No memory"); return -1; } vp->lvalue = packet->data[1]; debug_pair(vp); *tail = vp; tail = &(vp->next); vp = paircreate(PW_VQP_ERROR_CODE, PW_TYPE_OCTETS); if (!vp) { librad_log("No memory"); return -1; } vp->lvalue = packet->data[2]; debug_pair(vp); *tail = vp; tail = &(vp->next); vp = paircreate(PW_VQP_SEQUENCE_NUMBER, PW_TYPE_OCTETS); if (!vp) { librad_log("No memory"); return -1; } vp->lvalue = packet->id; /* already set by vqp_recv */ debug_pair(vp); *tail = vp; tail = &(vp->next); ptr = packet->data + VQP_HDR_LEN; end = packet->data + packet->data_len; /* * Note that vqp_recv() MUST ensure that the packet is * formatted in a way we expect, and that vqp_recv() MUST * be called before vqp_decode(). */ while (ptr < end) { attribute = (ptr[2] << 8) | ptr[3]; length = ptr[5]; ptr += 6; /* * Hack to get the dictionaries to work correctly. */ attribute |= 0x2000; vp = paircreate(attribute, PW_TYPE_OCTETS); if (!vp) { pairfree(&packet->vps); librad_log("No memory"); return -1; } switch (vp->type) { case PW_TYPE_IPADDR: if (length == 4) { memcpy(&vp->vp_ipaddr, ptr, 4); vp->length = 4; break; } vp->type = PW_TYPE_OCTETS; /* FALL-THROUGH */ default: case PW_TYPE_STRING: case PW_TYPE_OCTETS: memcpy(vp->vp_octets, ptr, length); vp->length = length; break; } ptr += length; debug_pair(vp); *tail = vp; tail = &(vp->next); } /* * FIXME: Map attributes to Calling-Station-Id, etc... */ return 0;}/* * These are the MUST HAVE contents for a VQP packet. * * We don't allow the caller to give less than these, because * it won't work. We don't encode more than these, because the * clients will ignore it. * * FIXME: Be more generous? Look for CISCO + VQP attributes? */static int contents[5][VQP_MAX_ATTRIBUTES] = { { 0, 0, 0, 0, 0, 0 }, { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c05 }, /* Join request */ { 0x0c03, 0x0c08, 0, 0, 0, 0 }, /* Join Response */ { 0x0c01, 0x0c02, 0x0c03, 0x0c04, 0x0c07, 0x0c08 }, /* Reconfirm */ { 0x0c03, 0x0c08, 0, 0, 0, 0 }};int vqp_encode(RADIUS_PACKET *packet, RADIUS_PACKET *original){ int i, code, length; VALUE_PAIR *vp; uint8_t *ptr; VALUE_PAIR *vps[VQP_MAX_ATTRIBUTES]; if (!packet) { librad_log("Failed encoding VQP"); return -1; } if (packet->data) return 0; vp = pairfind(packet->vps, PW_VQP_PACKET_TYPE); if (!vp) { librad_log("Failed to find VQP-Packet-Type in response packet"); return -1; } code = vp->lvalue; if ((code < 1) || (code > 4)) { librad_log("Invalid value %d for VQP-Packet-Type", code); return -1; } length = VQP_HDR_LEN; memset(vps, 0, sizeof(vps)); vp = pairfind(packet->vps, PW_VQP_ERROR_CODE); /* * FIXME: Map attributes from calling-station-Id, etc. * * Maybe do this via rlm_vqp? That's probably the * best place to add the code... */ /* * No error: encode attributes. */ if (!vp) for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) { if (!contents[code][i]) break; vps[i] = pairfind(packet->vps, contents[code][i] | 0x2000); /* * FIXME: Print the name... */ if (!vps[i]) { librad_log("Failed to find VQP attribute %02x", contents[code][i]); return -1; } length += 6; length += vps[i]->length; } packet->data = malloc(length); if (!packet->data) { librad_log("No memory"); return -1; } packet->data_len = length; ptr = packet->data; ptr[0] = VQP_VERSION; ptr[1] = code; if (!vp) { ptr[2] = 0; } else { ptr[2] = vp->lvalue & 0xff; return 0; } /* * The number of attributes is hard-coded. */ if ((code == 1) || (code == 3)) { uint32_t sequence; ptr[3] = VQP_MAX_ATTRIBUTES; sequence = htonl(packet->id); memcpy(ptr + 4, &sequence, 4); } else { if (!original) { librad_log("Cannot send VQP response without request"); return -1; } /* * Packet Sequence Number */ memcpy(ptr + 4, original->data + 4, 4); ptr[3] = 2; } ptr += 8; /* * Encode the VP's. */ for (i = 0; i < VQP_MAX_ATTRIBUTES; i++) { if (!vps[i]) break; vp = vps[i]; debug_pair(vp); /* * Type. Note that we look at only the lower 8 * bits, as the upper 8 bits have been hacked. * See also dictionary.vqp */ ptr[0] = 0; ptr[1] = 0; ptr[2] = 0x0c; ptr[3] = vp->attribute & 0xff; /* Length */ ptr[4] = 0; ptr[5] = vp->length & 0xff; ptr += 6; /* Data */ switch (vp->type) { case PW_TYPE_IPADDR: memcpy(ptr, &vp->vp_ipaddr, 4); break; default: case PW_TYPE_OCTETS: case PW_TYPE_STRING: memcpy(ptr, vp->vp_octets, vp->length); break; } ptr += vp->length; } return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -