📄 radius.c
字号:
switch (attr[0]) { default: /* don't do anything by default */ break; /* * If there's an EAP-Message, we require * a Message-Authenticator. */ case PW_EAP_MESSAGE: require_ma = 1; break; case PW_MESSAGE_AUTHENTICATOR: if (attr[1] != 2 + AUTH_VECTOR_LEN) { librad_log("WARNING: Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d", ip_ntoa(host_ipaddr, packet->src_ipaddr), attr[1] - 2); free(packet); return NULL; } seen_ma = 1; break; } /* * FIXME: Look up the base 255 attributes in the * dictionary, and switch over their type. For * integer/date/ip, the attribute length SHOULD * be 6. */ count -= attr[1]; /* grab the attribute length */ attr += attr[1]; num_attributes++; /* seen one more attribute */ } /* * If the attributes add up to a packet, it's allowed. * * If not, we complain, and throw the packet away. */ if (count != 0) { librad_log("WARNING: Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet", ip_ntoa(host_ipaddr, packet->src_ipaddr)); free(packet); return NULL; } /* * If we're configured to look for a maximum number of * attributes, and we've seen more than that maximum, * then throw the packet away, as a possible DoS. */ if ((librad_max_attributes > 0) && (num_attributes > librad_max_attributes)) { librad_log("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).", ip_ntoa(host_ipaddr, packet->src_ipaddr), num_attributes, librad_max_attributes); free(packet); return NULL; } /* * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message * * A packet with an EAP-Message attribute MUST also have * a Message-Authenticator attribute. * * A Message-Authenticator all by itself is OK, though. * * Similarly, Status-Server packets MUST contain * Message-Authenticator attributes. */ if (require_ma && ! seen_ma) { librad_log("WARNING: Insecure packet from host %s: Packet does not contain required Message-Authenticator attribute", ip_ntoa(host_ipaddr, packet->src_ipaddr)); free(packet); return NULL; } if (librad_debug) { if ((hdr->code > 0) && (hdr->code < 52)) { printf("rad_recv: %s packet from host %s:%d", packet_codes[hdr->code], ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port); } else { printf("rad_recv: Packet from host %s:%d code=%d", ip_ntoa(host_ipaddr, packet->src_ipaddr), packet->src_port, hdr->code); } printf(", id=%d, length=%d\n", hdr->id, totallen); } /* * Fill RADIUS header fields */ packet->code = hdr->code; packet->id = hdr->id; memcpy(packet->vector, hdr->vector, AUTH_VECTOR_LEN); /* * Now that we've sanity checked the packet, we can allocate * memory for it, and copy the data from the local area to * the packet buffer. */ if ((packet->data = malloc(packet->data_len)) == NULL) { free(packet); librad_log("out of memory"); return NULL; } memcpy(packet->data, data, 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; } lrad_hmac_md5(packet->data, packet->data_len, 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.)", ip_ntoa(buffer, packet->src_ipaddr)); /* Silently drop packet, according to RFC 3579 */ return -2; } /* 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 */ /* * Calculate and/or verify digest. */ switch(packet->code) { int rcode; case PW_AUTHENTICATION_REQUEST: case PW_STATUS_SERVER: case PW_DISCONNECT_REQUEST: /* * The authentication vector is random * nonsense, invented by the client. */ break; case PW_ACCOUNTING_REQUEST: if (calc_acctdigest(packet, secret) > 1) { char buffer[32]; librad_log("Received Accounting-Request packet " "from %s with invalid signature! (Shared secret is incorrect.)", ip_ntoa(buffer, packet->src_ipaddr)); return -1; } break; /* Verify the reply digest */ case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCESS_CHALLENGE: case PW_ACCOUNTING_RESPONSE: rcode = calc_replydigest(packet, original, secret); if (rcode > 1) { char buffer[32]; librad_log("Received %s packet " "from client %s port %d with invalid signature (err=%d)! (Shared secret is incorrect.)", packet_codes[packet->code], ip_ntoa(buffer, packet->src_ipaddr), packet->src_port, rcode); return -1; } break; } return 0;}/* * Parse a RADIUS attribute into a data structure. */static 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->strvalue[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->strvalue, vp->length, secret, original->vector); } else { rad_pwdecode((char *)vp->strvalue, vp->length, secret, packet->vector); } if (vp->attribute == PW_USER_PASSWORD) { vp->length = strlen(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->strvalue, &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->strvalue, my_digest, AUTH_VECTOR_LEN ); vp->strvalue[AUTH_VECTOR_LEN] = '\0'; vp->length = strlen(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_INTEGER: if (vp->length != 4) goto raw; memcpy(&vp->lvalue, vp->strvalue, 4); vp->lvalue = ntohl(vp->lvalue); if (vp->flags.has_tag) vp->lvalue &= 0x00ffffff; /* * Try to get named VALUEs */ { DICT_VALUE *dval; dval = dict_valbyattr(vp->attribute, vp->lvalue); if (dval) { strNcpy(vp->strvalue, dval->name, sizeof(vp->strvalue)); } } break; case PW_TYPE_DATE: if (vp->length != 4) goto raw; memcpy(&vp->lvalue, vp->strvalue, 4); vp->lvalue = ntohl(vp->lvalue); break; /* * IPv4 address. Keep it in network byte order in * vp->lvalue and put ASCII IP address in standard * dot notation into vp->strvalue. */ case PW_TYPE_IPADDR: if (vp->length != 4) goto raw; memcpy(&vp->lvalue, vp->strvalue, 4); ip_ntoa(vp->strvalue, vp->lvalue); break; /* * IPv6 interface ID is 8 octets long. */ case PW_TYPE_IFID: if (vp->length != 8) goto raw; /* vp->vp_ifid == vp->strvalue */ break; /* * IPv6 addresses are 16 octets long */ case PW_TYPE_IPV6ADDR: if (vp->length != 16) goto raw; /* vp->vp_ipv6addr == vp->strvalue */ 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->strvalue[1] > 128) goto raw; /* * FIXME: double-check that * (vp->strvalue[1] >> 3) matches vp->length + 2 */ if (vp->length < 18) { memset(vp->strvalue + vp->length, 0, 18 - vp->length); } break; default: raw: vp->type = PW_TYPE_OCTETS; vp->length = length; memcpy(vp->strvalue, 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. */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; /* * 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; /* * attrlen was checked above. */ memcpy(&lvalue, ptr, 4); myvendor = ntohl(lvalue); /* * Zero isn't allowed. */ if (myvendor == 0) goto create_pair; /* * This is an implementation issue. * We currently pack vendor into the upper * 16 bits of a 32-bit attribute number, * so we can't handle vendor numbers larger * than 16 bits. */ if (myvendor > 65535) goto create_pair; vsa_tlen = vsa_llen = 1; dv = dict_vendorbyvalue(myvendor); if (dv) { vsa_tlen = dv->type; vsa_llen = dv->length; } /* * Sweep through the list of VSA's, * seeing if they exactly fill the * outer Vendor-Specific attribute. * * If not, create a raw Vendor-Specific. */ subptr = ptr + 4; sublen = attrlen - 4; /* * See if we can parse it. */ do { int myattr = 0; /* * Don't have a type, it's bad. */ if (sublen < vsa_tlen) goto create_pair; /* * Ensure that the attribute number * is OK. */ switch (vsa_tlen) { case 1: myattr = subptr[0]; break; case 2: myattr = (subptr[0] << 8) | subptr[1]; break; case 4: if ((subptr[0] != 0) || (subptr[1] != 0)) goto create_pair; myattr = (subptr[2] << 8) | subptr[3]; break; /* * Our dictionary is broken. */ default: goto create_pair; } /* * Not enough room for one more * attribute. Die! */ if (sublen < vsa_tlen + vsa_llen) goto create_pair;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -