int radius_send(int s, const RADIUS_PACKET* packet, int flags) { ssize_t n; n = send(s, packet->pdata, radius_get_length(packet), flags); if(n != radius_get_length(packet)) return 1; return 0; }
int radius_sendto(int s, const RADIUS_PACKET* packet, int flags, const struct sockaddr* addr, socklen_t len) { ssize_t n; n = sendto(s, packet->pdata, radius_get_length(packet), flags, addr, len); if(n != radius_get_length(packet)) return 1; return 0; }
int radius_put_raw_attr_all(RADIUS_PACKET* packet, u_int8_t type, caddr_t buf, int length) { int off, len0; RADIUS_ATTRIBUTE* newattr; off = 0; while (off < length) { len0 = MIN(length - off, 255-2); if(radius_ensure_add_capacity(packet, len0+2) != 0) return 1; newattr = ATTRS_END(packet->pdata); newattr->type = type; newattr->length = len0 + 2; memcpy(newattr->data, buf, len0); packet->pdata->length = htons(radius_get_length(packet) + len0 + 2); off += len0; } return 0; }
int radius_put_vs_raw_attr_all(RADIUS_PACKET* packet, u_int32_t vendor, u_int8_t vtype, const void* buf, int length) { int off, len0; RADIUS_ATTRIBUTE* newattr; off = 0; while (off < length) { len0 = MIN(length - off, 255-8); if(radius_ensure_add_capacity(packet, len0+8) != 0) return 1; newattr = ATTRS_END(packet->pdata); newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC; newattr->length = len0 + 8; newattr->vendor = htonl(vendor); newattr->vtype = vtype; newattr->vlength = len0 + 2; memcpy(newattr->vdata, buf, len0); packet->pdata->length = htons(radius_get_length(packet) + len0 + 8); off += len0; } return 0; }
void radius_set_response_authenticator(RADIUS_PACKET* packet, const char* secret) { MD5_CTX ctx; MD5Init(&ctx); MD5Update(&ctx, (unsigned char*)packet->pdata, 4); MD5Update(&ctx, (unsigned char*)packet->request->pdata->authenticator, 16); MD5Update(&ctx, (unsigned char*)packet->pdata->attributes, radius_get_length(packet) - 20); MD5Update(&ctx, (unsigned char*)secret, strlen(secret)); MD5Final((unsigned char*)packet->pdata->authenticator ,&ctx); }
void radius_set_request_authenticator(RADIUS_PACKET* packet, const char* secret) { MD5_CTX ctx; u_char zero[16]; memset(zero, 0, sizeof(zero)); MD5Init(&ctx); MD5Update(&ctx, (unsigned char*)packet->pdata, 4); MD5Update(&ctx, zero, 16); MD5Update(&ctx, (unsigned char*)packet->pdata->attributes, radius_get_length(packet) - 20); MD5Update(&ctx, (unsigned char*)secret, strlen(secret)); MD5Final((unsigned char*)packet->pdata->authenticator ,&ctx); }
int radius_put_raw_attr(RADIUS_PACKET* packet, u_int8_t type, const void* buf, u_int8_t length) { RADIUS_ATTRIBUTE* newattr; if(length > 255-2) return 1; if(radius_ensure_add_capacity(packet, length+2) != 0) return 1; newattr = ATTRS_END(packet->pdata); newattr->type = type; newattr->length = length + 2; memcpy(newattr->data, buf, length); packet->pdata->length = htons(radius_get_length(packet) + length + 2); return 0; }
int radius_put_vs_raw_attr(RADIUS_PACKET* packet, u_int32_t vendor, u_int8_t vtype, const void* buf, u_int8_t length) { RADIUS_ATTRIBUTE* newattr; if(length > 255-8) return 1; if(radius_ensure_add_capacity(packet, length+8) != 0) return 1; newattr = ATTRS_END(packet->pdata); newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC; newattr->length = length + 8; newattr->vendor = htonl(vendor); newattr->vtype = vtype; newattr->vlength = length + 2; memcpy(newattr->vdata, buf, length); packet->pdata->length = htons(radius_get_length(packet) + length + 8); return 0; }
int radius_check_response_authenticator(const RADIUS_PACKET* packet, const char* secret) { MD5_CTX ctx; unsigned char authenticator0[16]; /* Assume radius_set_request_packet() was called before calling */ if (packet->request == NULL) return -1; MD5Init(&ctx); MD5Update(&ctx, (unsigned char*)packet->pdata, 4); MD5Update(&ctx, (unsigned char*)packet->request->pdata->authenticator, 16); MD5Update(&ctx, (unsigned char*)packet->pdata->attributes, radius_get_length(packet) - 20); MD5Update(&ctx, (unsigned char*)secret, strlen(secret)); MD5Final((unsigned char *)authenticator0, &ctx); return memcmp(authenticator0, packet->pdata->authenticator, 16); }
void test00(void) { RADIUS_PACKET *packet; uint8_t code; uint8_t id; const uint8_t *pdata; uint8_t authenticator[16]; code = random(); id = random(); packet = radius_new_request_packet(code); radius_set_id(packet, id); pdata = (const uint8_t *)radius_get_data(packet); CHECK(pdata[0] == code); CHECK(radius_get_code(packet) == code); CHECK(pdata[1] == id); CHECK(radius_get_id(packet) == id); CHECK(((pdata[2] << 8) | pdata[3]) == 20); CHECK(radius_get_length(packet) == 20); CHECK(radius_get_authenticator_retval(packet) == pdata + 4); radius_get_authenticator(packet, authenticator); CHECK(memcmp(authenticator, radius_get_authenticator_retval(packet), 16) == 0); }
static void radius_test(struct parse_result *res) { struct addrinfo hints, *ai; int sock, retval; struct sockaddr_storage sockaddr; socklen_t sockaddrlen; RADIUS_PACKET *reqpkt, *respkt; struct sockaddr_in *sin4; struct sockaddr_in6 *sin6; uint32_t u32val; uint8_t id; reqpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST); if (reqpkt == NULL) err(1, "radius_new_request_packet"); id = arc4random(); radius_set_id(reqpkt, id); memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; retval = getaddrinfo(res->hostname, "radius", &hints, &ai); if (retval) errx(1, "%s %s", res->hostname, gai_strerror(retval)); if (res->port != 0) ((struct sockaddr_in *)ai->ai_addr)->sin_port = htons(res->port); sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock == -1) err(1, "socket"); /* Prepare NAS-IP{,V6}-ADDRESS attribute */ if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) err(1, "connect"); sockaddrlen = sizeof(sockaddr); if (getsockname(sock, (struct sockaddr *)&sockaddr, &sockaddrlen) == -1) err(1, "getsockname"); sin4 = (struct sockaddr_in *)&sockaddr; sin6 = (struct sockaddr_in6 *)&sockaddr; switch (sockaddr.ss_family) { case AF_INET: radius_put_ipv4_attr(reqpkt, RADIUS_TYPE_NAS_IP_ADDRESS, sin4->sin_addr); break; case AF_INET6: radius_put_raw_attr(reqpkt, RADIUS_TYPE_NAS_IPV6_ADDRESS, sin6->sin6_addr.s6_addr, sizeof(sin6->sin6_addr.s6_addr)); break; } /* User-Name and User-Password */ radius_put_string_attr(reqpkt, RADIUS_TYPE_USER_NAME, res->username); switch (res->auth_method) { case PAP: if (res->password != NULL) radius_put_user_password_attr(reqpkt, res->password, res->secret); break; case CHAP: { u_char chal[16]; u_char resp[1 + MD5_DIGEST_LENGTH]; /* "1 + " for CHAP Id */ MD5_CTX md5ctx; arc4random_buf(resp, 1); /* CHAP Id is random */ MD5Init(&md5ctx); MD5Update(&md5ctx, resp, 1); if (res->password != NULL) MD5Update(&md5ctx, res->password, strlen(res->password)); MD5Update(&md5ctx, chal, sizeof(chal)); MD5Final(resp + 1, &md5ctx); radius_put_raw_attr(reqpkt, RADIUS_TYPE_CHAP_CHALLENGE, chal, sizeof(chal)); radius_put_raw_attr(reqpkt, RADIUS_TYPE_CHAP_PASSWORD, resp, sizeof(resp)); } break; case MSCHAPV2: { u_char pass[256], chal[16]; u_int i, lpass; struct _resp { u_int8_t ident; u_int8_t flags; char peer_challenge[16]; char reserved[8]; char response[24]; } __packed resp; if (res->password == NULL) { lpass = 0; } else { lpass = strlen(res->password); if (lpass * 2 >= sizeof(pass)) err(1, "password too long"); for (i = 0; i < lpass; i++) { pass[i * 2] = res->password[i]; pass[i * 2 + 1] = 0; } } memset(&resp, 0, sizeof(resp)); resp.ident = arc4random(); arc4random_buf(chal, sizeof(chal)); arc4random_buf(resp.peer_challenge, sizeof(resp.peer_challenge)); mschap_nt_response(chal, resp.peer_challenge, (char *)res->username, strlen(res->username), pass, lpass * 2, resp.response); radius_put_vs_raw_attr(reqpkt, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MS_CHAP_CHALLENGE, chal, sizeof(chal)); radius_put_vs_raw_attr(reqpkt, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MS_CHAP2_RESPONSE, &resp, sizeof(resp)); explicit_bzero(pass, sizeof(pass)); } break; } u32val = htonl(res->nas_port); radius_put_raw_attr(reqpkt, RADIUS_TYPE_NAS_PORT, &u32val, 4); radius_put_message_authenticator(reqpkt, res->secret); /* Send! */ fprintf(stderr, "Sending:\n"); radius_dump(stdout, reqpkt, false, res->secret); if (send(sock, radius_get_data(reqpkt), radius_get_length(reqpkt), 0) == -1) warn("send"); if ((respkt = radius_recv(sock, 0)) == NULL) warn("recv"); else { radius_set_request_packet(respkt, reqpkt); fprintf(stderr, "\nReceived:\n"); radius_dump(stdout, respkt, true, res->secret); } /* Release the resources */ radius_delete_packet(reqpkt); if (respkt) radius_delete_packet(respkt); close(sock); freeaddrinfo(ai); explicit_bzero((char *)res->secret, strlen(res->secret)); if (res->password) explicit_bzero((char *)res->password, strlen(res->password)); return; }