📄 radius.c
字号:
/* * Check for socket errors. */ if (packet->data_len < 0) { librad_log("Error receiving packet: %s", strerror(errno)); /* packet->data is NULL */ free(packet); return NULL; } /* * If the packet is too big, then rad_recvfrom did NOT * allocate memory. Instead, it just discarded the * packet. */ if (packet->data_len > MAX_PACKET_LEN) { librad_log("Discarding packet: Larger than RFC limitation of 4096 bytes."); /* packet->data is NULL */ free(packet); return NULL; } /* * Read no data. Continue. * This check is AFTER the MAX_PACKET_LEN check above, because * if the packet is larger than MAX_PACKET_LEN, we also have * packet->data == NULL */ if ((packet->data_len == 0) || !packet->data) { librad_log("Empty packet: Socket is not ready."); free(packet); return NULL; } /* * See if it's a well-formed RADIUS packet. */ if (!rad_packet_ok(packet, flags)) { rad_free(&packet); return NULL; } /* * Remember which socket we read the packet from. */ packet->sockfd = fd; /* * FIXME: Do even more filtering by only permitting * certain IP's. The problem is that we don't know * how to do this properly for all possible clients... */ /* * Explicitely set the VP list to empty. */ packet->vps = NULL; if (librad_debug) { char host_ipaddr[128]; if ((packet->code > 0) && (packet->code < MAX_PACKET_CODE)) { DEBUG("rad_recv: %s packet from host %s port %d", packet_codes[packet->code], inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), packet->src_port); } else { DEBUG("rad_recv: Packet from host %s port %d code=%d", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, host_ipaddr, sizeof(host_ipaddr)), packet->src_port, packet->code); } DEBUG(", id=%d, length=%d\n", packet->id, packet->data_len); } return packet;}/* * Verify the signature of a packet. */int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret){ uint8_t *ptr; int length; int attrlen; if (!packet || !packet->data) return -1; /* * Before we allocate memory for the attributes, do more * sanity checking. */ ptr = packet->data + AUTH_HDR_LEN; length = packet->data_len - AUTH_HDR_LEN; while (length > 0) { uint8_t msg_auth_vector[AUTH_VECTOR_LEN]; uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; attrlen = ptr[1]; switch (ptr[0]) { default: /* don't do anything. */ break; /* * Note that more than one Message-Authenticator * attribute is invalid. */ case PW_MESSAGE_AUTHENTICATOR: memcpy(msg_auth_vector, &ptr[2], sizeof(msg_auth_vector)); memset(&ptr[2], 0, AUTH_VECTOR_LEN); switch (packet->code) { default: break; case PW_ACCOUNTING_REQUEST: case PW_ACCOUNTING_RESPONSE: case PW_DISCONNECT_REQUEST: case PW_DISCONNECT_ACK: case PW_DISCONNECT_NAK: case PW_COA_REQUEST: case PW_COA_ACK: case PW_COA_NAK: memset(packet->data + 4, 0, AUTH_VECTOR_LEN); break; case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCESS_CHALLENGE: if (!original) { librad_log("ERROR: Cannot validate Message-Authenticator in response packet without a request packet."); return -1; } memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN); break; } fr_hmac_md5(packet->data, packet->data_len, (const uint8_t *) secret, strlen(secret), calc_auth_vector); if (memcmp(calc_auth_vector, msg_auth_vector, sizeof(calc_auth_vector)) != 0) { char buffer[32]; librad_log("Received packet from %s with invalid Message-Authenticator! (Shared secret is incorrect.)", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer))); /* Silently drop packet, according to RFC 3579 */ return -1; } /* else the message authenticator was good */ /* * Reinitialize Authenticators. */ memcpy(&ptr[2], msg_auth_vector, AUTH_VECTOR_LEN); memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN); break; } /* switch over the attributes */ ptr += attrlen; length -= attrlen; } /* loop over the packet, sanity checking the attributes */ /* * It looks like a RADIUS packet, but we can't validate * the signature. */ if ((packet->code == 0) || (packet->code >= MAX_PACKET_CODE)) { char buffer[32]; librad_log("Received Unknown packet code %d " "from client %s port %d: Cannot validate signature.", packet->code, inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer)), packet->src_port); return -1; } /* * Calculate and/or verify digest. */ switch(packet->code) { int rcode; char buffer[32]; case PW_AUTHENTICATION_REQUEST: case PW_STATUS_SERVER: /* * The authentication vector is random * nonsense, invented by the client. */ break; case PW_COA_REQUEST: case PW_DISCONNECT_REQUEST: case PW_ACCOUNTING_REQUEST: if (calc_acctdigest(packet, secret) > 1) { librad_log("Received %s packet " "from %s with invalid signature! (Shared secret is incorrect.)", packet_codes[packet->code], inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer))); return -1; } break; /* Verify the reply digest */ case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCESS_CHALLENGE: case PW_ACCOUNTING_RESPONSE: case PW_DISCONNECT_ACK: case PW_DISCONNECT_NAK: case PW_COA_ACK: case PW_COA_NAK: rcode = calc_replydigest(packet, original, secret); if (rcode > 1) { librad_log("Received %s packet " "from client %s port %d with invalid signature (err=%d)! (Shared secret is incorrect.)", packet_codes[packet->code], inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer)), packet->src_port, rcode); return -1; } break; default: librad_log("Received Unknown packet code %d " "from client %s port %d: Cannot validate signature", packet->code, inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer)), packet->src_port); return -1; } return 0;}/* * Parse a RADIUS attribute into a data structure. */VALUE_PAIR *rad_attr2vp(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, const char *secret, int attribute, int length, const uint8_t *data){ int offset = 0; VALUE_PAIR *vp; if ((vp = paircreate(attribute, PW_TYPE_OCTETS)) == NULL) { return NULL; } /* * If length is greater than 253, something is SERIOUSLY * wrong. */ if (length > 253) length = 253; /* paranoia (pair-anoia?) */ vp->length = length; vp->operator = T_OP_EQ; vp->next = NULL; /* * Handle tags. */ if (vp->flags.has_tag) { if (TAG_VALID(data[0]) || (vp->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD)) { /* * Tunnel passwords REQUIRE a tag, even * if don't have a valid tag. */ vp->flags.tag = data[0]; if ((vp->type == PW_TYPE_STRING) || (vp->type == PW_TYPE_OCTETS)) offset = 1; } } /* * Copy the data to be decrypted */ memcpy(&vp->vp_octets[0], data + offset, length - offset); vp->length -= offset; /* * Decrypt the attribute. */ switch (vp->flags.encrypt) { /* * User-Password */ case FLAG_ENCRYPT_USER_PASSWORD: if (original) { rad_pwdecode((char *)vp->vp_strvalue, vp->length, secret, original->vector); } else { rad_pwdecode((char *)vp->vp_strvalue, vp->length, secret, packet->vector); } if (vp->attribute == PW_USER_PASSWORD) { vp->length = strlen(vp->vp_strvalue); } break; /* * Tunnel-Password's may go ONLY * in response packets. */ case FLAG_ENCRYPT_TUNNEL_PASSWORD: if (!original) goto raw; if (rad_tunnel_pwdecode(vp->vp_octets, &vp->length, secret, original->vector) < 0) { goto raw; } break; /* * Ascend-Send-Secret * Ascend-Receive-Secret */ case FLAG_ENCRYPT_ASCEND_SECRET: if (!original) { goto raw; } else { uint8_t my_digest[AUTH_VECTOR_LEN]; make_secret(my_digest, original->vector, secret, data); memcpy(vp->vp_strvalue, my_digest, AUTH_VECTOR_LEN ); vp->vp_strvalue[AUTH_VECTOR_LEN] = '\0'; vp->length = strlen(vp->vp_strvalue); } break; default: break; } /* switch over encryption flags */ switch (vp->type) { case PW_TYPE_STRING: case PW_TYPE_OCTETS: case PW_TYPE_ABINARY: /* nothing more to do */ break; case PW_TYPE_BYTE: if (vp->length != 1) goto raw; vp->vp_integer = vp->vp_octets[0]; break; case PW_TYPE_SHORT: if (vp->length != 2) goto raw; vp->vp_integer = (vp->vp_octets[0] << 8) | vp->vp_octets[1]; break; case PW_TYPE_INTEGER: if (vp->length != 4) goto raw; memcpy(&vp->vp_integer, vp->vp_octets, 4); vp->vp_integer = ntohl(vp->vp_integer); if (vp->flags.has_tag) vp->vp_integer &= 0x00ffffff; /* * Try to get named VALUEs */ { DICT_VALUE *dval; dval = dict_valbyattr(vp->attribute, vp->vp_integer); if (dval) { strlcpy(vp->vp_strvalue, dval->name, sizeof(vp->vp_strvalue)); } } break; case PW_TYPE_DATE: if (vp->length != 4) goto raw; memcpy(&vp->vp_date, vp->vp_octets, 4); vp->vp_date = ntohl(vp->vp_date); break; case PW_TYPE_IPADDR: if (vp->length != 4) goto raw; memcpy(&vp->vp_ipaddr, vp->vp_octets, 4); break; /* * IPv6 interface ID is 8 octets long. */ case PW_TYPE_IFID: if (vp->length != 8) goto raw; /* vp->vp_ifid == vp->vp_octets */ break; /* * IPv6 addresses are 16 octets long */ case PW_TYPE_IPV6ADDR: if (vp->length != 16) goto raw; /* vp->vp_ipv6addr == vp->vp_octets */ break; /* * IPv6 prefixes are 2 to 18 octets long. * * RFC 3162: The first octet is unused. * The second is the length of the prefix * the rest are the prefix data. * * The prefix length can have value 0 to 128. */ case PW_TYPE_IPV6PREFIX: if (vp->length < 2 || vp->length > 18) goto raw; if (vp->vp_octets[1] > 128) goto raw; /* * FIXME: double-check that * (vp->vp_octets[1] >> 3) matches vp->length + 2 */ if (vp->length < 18) { memset(vp->vp_octets + vp->length, 0, 18 - vp->length); } break; default: raw: vp->type = PW_TYPE_OCTETS; vp->length = length; memcpy(vp->vp_octets, data, length); /* * Ensure there's no encryption or tag stuff, * we just pass the attribute as-is. */ memset(&vp->flags, 0, sizeof(vp->flags)); } return vp;}/* * Calculate/check digest, and decode radius attributes. * Returns: * -1 on decoding error * 0 on success */int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, const char *secret){ uint32_t lvalue; uint32_t vendorcode; VALUE_PAIR **tail; VALUE_PAIR *pair; uint8_t *ptr; int packet_length; int attribute; int attrlen; int vendorlen; radius_packet_t *hdr; int vsa_tlen, vsa_llen; DICT_VENDOR *dv = NULL; int num_attributes = 0; /* * Extract attribute-value pairs */ hdr = (radius_packet_t *)packet->data; ptr = hdr->data; packet_length = packet->data_len - AUTH_HDR_LEN; /* * There may be VP's already in the packet. Don't * destroy them. */ for (tail = &packet->vps; *tail != NULL; tail = &((*tail)->next)) { /* nothing */ } vendorcode = 0; vendorlen = 0; vsa_tlen = vsa_llen = 1; /* * We have to read at least two bytes. * * rad_recv() above ensures that this is OK. */ while (packet_length > 0) { attribute = -1; attrlen = -1; /* * Normal attribute, handle it like normal. */ if (vendorcode == 0) { /* * No room to read attr/length, * or bad attribute, or attribute is * too short, or attribute is too long, * stop processing the packet. */ if ((packet_length < 2) || (ptr[0] == 0) || (ptr[1] < 2) || (ptr[1] > packet_length)) break; attribute = *ptr++; attrlen = *ptr++; attrlen -= 2; packet_length -= 2; if (attribute != PW_VENDOR_SPECIFIC) goto create_pair; /* * No vendor code, or ONLY vendor code. */ if (attrlen <= 4) goto create_pair; vendorlen = 0; } /* * Handle Vendor-Specific */ if (vendorlen == 0) { uint8_t *subptr; int sublen; int myvendor;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -