📄 radius.c
字号:
(seen_eap != (PW_EAP_MESSAGE | PW_MESSAGE_AUTHENTICATOR))) { librad_log("WARNING: Insecure packet from host %s: Received EAP-Message with no Message-Authenticator.", 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;}/* * 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 length; int attribute; int attrlen; int vendorlen; radius_packet_t *hdr; hdr = (radius_packet_t *)packet->data; /* * Before we allocate memory for the attributes, do more * sanity checking. */ ptr = hdr->data; 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_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)); 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 */ /* * 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_ACCOUNTING_RESPONSE: rcode = calc_replydigest(packet, original, secret); if (rcode > 1) { char buffer[32]; librad_log("Received %s packet " "from %s:%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; } /* * Extract attribute-value pairs */ ptr = hdr->data; 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; while (length > 0) { if (vendorlen > 0) { attribute = *ptr++ | (vendorcode << 16); attrlen = *ptr++; } else { attribute = *ptr++; attrlen = *ptr++; } attrlen -= 2; length -= 2; /* * This could be a Vendor-Specific attribute. */ if ((vendorlen <= 0) && (attribute == PW_VENDOR_SPECIFIC)) { int sublen; uint8_t *subptr; /* * attrlen was checked to be >= 6, in rad_recv */ memcpy(&lvalue, ptr, 4); vendorcode = ntohl(lvalue); /* * 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 (vendorcode > 65535) goto create_pair; /* * vendorcode was checked to be non-zero * above, in rad_recv. */ /* * First, check to see if the * sub-attributes fill the VSA, as * defined by the RFC. If not, then it * may be a USR-style VSA, or it may be a * vendor who packs all of the * information into one nonsense * attribute */ subptr = ptr + 4; sublen = attrlen - 4; while (sublen > 0) { if (subptr[1] < 2) { /* too short */ break; } if (subptr[1] > sublen) { /* too long */ break; } sublen -= subptr[1]; /* just right */ subptr += subptr[1]; } /* * If the attribute is RFC compatible, * then allow it as an RFC style VSA. */ if (sublen == 0) { ptr += 4; vendorlen = attrlen - 4; attribute = *ptr++ | (vendorcode << 16); attrlen = *ptr++; attrlen -= 2; length -= 6; /* * USR-style attributes are 4 octets, * with the upper 2 octets being zero. * * The upper octets may not be zero, * but that then means we won't be * able to pack the vendor & attribute * into a 32-bit number, so we can't * handle it. * * * FIXME: Update the dictionaries so * that we key off of per-attribute * flags "4-octet", instead of hard * coding USR here. This will also * let us send packets with other * vendors having 4-octet attributes. */ } else if ((vendorcode == VENDORPEC_USR) && ((ptr[4] == 0) && (ptr[5] == 0)) && (attrlen >= 8)) { DICT_ATTR *da; da = dict_attrbyvalue((vendorcode << 16) | (ptr[6] << 8) | ptr[7]); /* * See if it's in the dictionary. * If so, it's a valid USR style * attribute. If not, it's not... * * Don't touch 'attribute' until * we know what to do! */ if (da != NULL) { attribute = ((vendorcode << 16) | (ptr[6] << 8) | ptr[7]); ptr += 8; attrlen -= 8; length -= 8; } /* else it's not in the dictionary */ } /* else it was a stupid vendor format */ } /* else it wasn't a VSA */ /* * Create the attribute, setting the default type * to 'octects'. If the type in the dictionary * is different, then the dictionary type will * over-ride this one. */ create_pair: if ((pair = paircreate(attribute, PW_TYPE_OCTETS)) == NULL) { pairfree(&packet->vps); librad_log("out of memory"); return -1; } pair->length = attrlen; pair->operator = T_OP_EQ; pair->next = NULL; switch (pair->type) { /* * The attribute may be zero length, * or it may have a tag, and then no data... */ case PW_TYPE_STRING: if (pair->flags.has_tag) { int offset = 0; /* * If there's sufficient room for * a tag, and the tag looks valid, * then use it. */ if ((pair->length > 0) && TAG_VALID_ZERO(*ptr)) { pair->flags.tag = *ptr; pair->length--; offset = 1; /* * If the leading tag * isn't valid, then it's * ignored for the tunnel * password attribute. */ } else if (pair->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) { /* * from RFC2868 - 3.5. Tunnel-Password * If the value of the Tag field is greater than * 0x00 and less than or equal to 0x1F, it SHOULD * be interpreted as indicating which tunnel * (of several alternatives) this attribute pertains; * otherwise, the Tag field SHOULD be ignored. */ pair->flags.tag = 0x00; if (pair->length > 0) pair->length--; offset = 1; } else { pair->flags.tag = 0x00; } /* * pair->length MAY be zero here. */ memcpy(pair->strvalue, ptr + offset, pair->length); } else { /* * Ascend binary attributes never have a * tag, and neither do the 'octets' type. */ case PW_TYPE_ABINARY: case PW_TYPE_OCTETS: /* attrlen always < MAX_STRING_LEN */ memcpy(pair->strvalue, ptr, attrlen); pair->flags.tag = 0; } /* * Decrypt passwords here. */ switch (pair->flags.encrypt) { default: break; /* * User-Password */ case FLAG_ENCRYPT_USER_PASSWORD: if (original) { rad_pwdecode((char *)pair->strvalue, pair->length, secret, (char *)original->vector); } else { rad_pwdecode((char *)pair->strvalue, pair->length, secret, (char *)packet->vector); } if (pair->attribute == PW_USER_PASSWORD) { pair->length = strlen(pair->strvalue); } break; /* * Tunnel-Password's may go ONLY * in response packets. */ case FLAG_ENCRYPT_TUNNEL_PASSWORD: if (!original) { librad_log("ERROR: Tunnel-Password attribute in request: Cannot decrypt it."); free(pair); return -1; } if (rad_tunnel_pwdecode(pair->strvalue, &pair->length, secret, (char *)original->vector) < 0) { free(pair); return -1; } break; /* * Ascend-Send-Secret * Ascend-Receive-Secret */ case FLAG_ENCRYPT_ASCEND_SECRET: if (!original) { librad_log("ERROR: Ascend-Send-Secret attribute in request: Cannot decrypt it."); free(pair); return -1; } else { uint8_t my_digest[AUTH_VECTOR_LEN]; make_secret(my_digest, original->vector, secret, ptr); memcpy(pair->strvalue, my_digest, AUTH_VECTOR_LEN ); pair->strvalue[AUTH_VECTOR_LEN] = '\0'; pair->length = strlen(pair->strvalue); } break; } /* switch over encryption flags */ break; /* from octets/string/abinary */ case PW_TYPE_INTEGER: case PW_TYPE_DATE: case PW_TYPE_IPADDR: /* * Check for RFC compliance. If the * attribute isn't compliant, turn it * into a string of raw octets. * * Also set the lvalue to something * which should never match anything. */ if (attrlen != 4) { pair->type = PW_TYPE_OCTETS; memcpy(pair->strvalue, ptr, attrlen); pair->lvalue = 0xbad1bad1; break; } memcpy(&lvalue, ptr, 4); if (pair->type != PW_TYPE_IPADDR) { pair->lvalue = ntohl(lvalue); } else { /* * It's an IP address, keep it in network * byte order, and put the ASCII IP * address or host name into the string * value. */ pair->lvalue = lvalue; ip_ntoa(pair->strvalue, pair->lvalue); } /* * Tagged attributes of type integer have * special treatment. */ if (pair->flags.has_tag && pair->type == PW_TYPE_INTEGER) { pair->flags.tag = (pair->lvalue >> 24) & 0xff; pair->lvalue &= 0x00ffffff; } /* * Try to get the name for integer * attributes. */ if (pair->type == PW_TYPE_INTEGER) { DICT_VALUE *dval; dval = dict_valbyattr(pair->attribute, pair->lvalue); if (dval) { strNcpy(pair->strvalue, dval->name, sizeof(pair->strvalue)); } } break; /* * IPv6 interface ID is 8 octets long. */ case PW_TYPE_IFID: if (attrlen != 8) pair->type = PW_TYPE_OCTETS; memcpy(pair->strvalue, ptr, attrlen); break; /* * IPv6 addresses are 16 octets long */ case PW_TYPE_IPV6ADDR: if (attrlen != 16) pair->type = PW_TYPE_OCTETS; memcpy(pair->strvalue, ptr, attrlen); 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 (attrlen < 2 || attrlen > 18) pair->type = PW_TYPE_OCTETS; if (attrlen >= 2) { if (ptr[1] > 128) { pair->type = PW_TYPE_OCTETS; } /* * FIXME: double-check that * (ptr[1] >> 3) matches attrlen + 2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -