int radius_put_uint32_attr(RADIUS_PACKET* packet, u_int8_t type, u_int32_t val) { u_int32_t nval; nval = htonl(val); return radius_put_raw_attr(packet, type, &nval, sizeof(u_int32_t)); }
/* RFC 3579 */ int radius_put_message_authenticator(RADIUS_PACKET *packet, const char *secret) { int rval; u_char md5result[16]; RADIUS_ATTRIBUTE* attr; RADIUS_ATTRIBUTE* end; if ((rval = radius_put_raw_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR, md5result, sizeof(md5result))) != 0) return rval; radius_hmac_md5(packet, secret, strlen(secret), (caddr_t)md5result, 0); attr = ATTRS_BEGIN(packet->pdata); end = ATTRS_END(packet->pdata); for(; attr<end; ADVANCE(attr)) { if (attr->type == RADIUS_TYPE_MESSAGE_AUTHENTICATOR) { memcpy(attr->data, md5result, sizeof(md5result)); break; } } return 0; }
int radius_put_ipv4_attr(RADIUS_PACKET* packet, u_int8_t type, struct in_addr addr) { return radius_put_raw_attr(packet, type, &addr, sizeof(struct in_addr)); }
int radius_put_string_attr(RADIUS_PACKET* packet, u_int8_t type, const char* str) { return radius_put_raw_attr(packet, type, str, strlen(str)); }
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; }
/************************************************************************ * Functions for RADIUS * RFC 2058: RADIUS * RFC 2548: Microsoft Vendor-specific RADIUS Attributes ************************************************************************/ static void chap_radius_authenticate(chap *_this, int id, char *username, u_char *challenge, int lchallenge, u_char *response) { void *radctx; RADIUS_PACKET *radpkt; radius_req_setting *rad_setting; int lpkt; u_char *pkt; char buf0[MAX_USERNAME_LENGTH]; radpkt = NULL; radctx = NULL; if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd, _this->ppp)) == NULL) { goto fail; /* no radius server */ } pkt = ppp_packetbuf(_this->ppp, PPP_PROTO_CHAP) + HEADERLEN; lpkt = _this->ppp->mru - HEADERLEN; if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST)) == NULL) goto fail; if (radius_prepare(rad_setting, _this, &radctx, chap_radius_response) != 0) { radius_delete_packet(radpkt); goto fail; } if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt) != 0) goto fail; if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME, npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp, username, buf0)) != 0) goto fail; switch (_this->type) { case PPP_AUTH_CHAP_MD5: { u_char md5response[17]; md5response[0] = _this->challid; memcpy(&md5response[1], response, 16); if (radius_put_raw_attr(radpkt, RADIUS_TYPE_CHAP_PASSWORD, md5response, 17) != 0) goto fail; if (radius_put_raw_attr(radpkt, RADIUS_TYPE_CHAP_CHALLENGE, challenge, lchallenge) != 0) goto fail; break; } case PPP_AUTH_CHAP_MS_V2: { struct RADIUS_MS_CHAP2_RESPONSE msresponse; /* Preparing RADIUS_MS_CHAP2_RESPONSE */ memset(&msresponse, 0, sizeof(msresponse)); msresponse.ident = id; msresponse.flags = response[48]; memcpy(&msresponse.peer_challenge, response, 16); memcpy(&msresponse.response, response + 24, 24); if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MS_CHAP_CHALLENGE, challenge, 16) != 0) goto fail; if (radius_put_vs_raw_attr(radpkt, RADIUS_VENDOR_MICROSOFT, RADIUS_VTYPE_MS_CHAP2_RESPONSE, &msresponse, sizeof(msresponse)) != 0) goto fail; break; } } radius_get_authenticator(radpkt, _this->authenticator); /* Cancel previous request */ if (_this->radctx != NULL) radius_cancel_request(_this->radctx); /* Send a request */ _this->radctx = radctx; radius_request(radctx, radpkt); return; fail: switch (_this->type) { case PPP_AUTH_CHAP_MD5: /* No extra information, just "FAILED" */ chap_send_error(_this, "FAILED"); break; case PPP_AUTH_CHAP_MS_V2: /* No extra information */ mschapv2_send_error(_this, ERROR_AUTHENTICATION_FAILURE, 0); break; } if (radctx != NULL) radius_cancel_request(radctx); }
static void pap_radius_authenticate(pap *_this, const char *username, const char *password) { void *radctx; RADIUS_PACKET *radpkt; MD5_CTX md5ctx; int i, j, s_len, passlen; u_char ra[16], digest[16], pass[128]; const char *s; radius_req_setting *rad_setting = NULL; char buf0[MAX_USERNAME_LENGTH]; if ((rad_setting = npppd_get_radius_auth_setting(_this->ppp->pppd, _this->ppp)) == NULL) goto fail; if ((radpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST)) == NULL) goto fail; if (radius_prepare(rad_setting, _this, &radctx, pap_radius_response) != 0) { radius_delete_packet(radpkt); goto fail; } if (ppp_set_radius_attrs_for_authreq(_this->ppp, rad_setting, radpkt) != 0) goto fail; if (radius_put_string_attr(radpkt, RADIUS_TYPE_USER_NAME, npppd_ppp_get_username_for_auth(_this->ppp->pppd, _this->ppp, username, buf0)) != 0) goto fail; if (_this->radctx != NULL) radius_cancel_request(_this->radctx); _this->radctx = radctx; /* Create RADIUS User-Password Attribute (RFC 2865, 5.2.) */ s = radius_get_server_secret(_this->radctx); s_len = strlen(s); memset(pass, 0, sizeof(pass)); /* null padding */ passlen = MINIMUM(strlen(password), sizeof(pass)); memcpy(pass, password, passlen); if ((passlen % 16) != 0) passlen += 16 - (passlen % 16); radius_get_authenticator(radpkt, ra); MD5Init(&md5ctx); MD5Update(&md5ctx, s, s_len); MD5Update(&md5ctx, ra, 16); MD5Final(digest, &md5ctx); for (i = 0; i < 16; i++) pass[i] ^= digest[i]; while (i < passlen) { MD5Init(&md5ctx); MD5Update(&md5ctx, s, s_len); MD5Update(&md5ctx, &pass[i - 16], 16); MD5Final(digest, &md5ctx); for (j = 0; j < 16; j++, i++) pass[i] ^= digest[j]; } if (radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD, pass, passlen) != 0) goto fail; radius_request(_this->radctx, radpkt); return; fail: if (_this->radctx != NULL) radius_cancel_request(_this->radctx); pap_log(_this, LOG_ERR, "%s() failed: %m", __func__); pap_response(_this, 0, DEFAULT_ERROR_MESSAGE); return; }