static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, struct hostapd_acl_query_data *query) { struct radius_msg *msg; char buf[128]; query->radius_id = radius_client_get_id(hapd->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); if (msg == NULL) return -1; if (radius_msg_make_authenticator(msg) < 0) { wpa_printf(MSG_INFO, "Could not make Request Authenticator"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_DEBUG, "Could not add User-Name"); goto fail; } if (!radius_msg_add_attr_user_password( msg, (u8 *) buf, os_strlen(buf), hapd->conf->radius->auth_server->shared_secret, hapd->conf->radius->auth_server->shared_secret_len)) { wpa_printf(MSG_DEBUG, "Could not add User-Password"); goto fail; } if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, NULL, msg) < 0) goto fail; os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id"); goto fail; } os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_DEBUG, "Could not add Connect-Info"); goto fail; } if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0) goto fail; return 0; fail: radius_msg_free(msg); return -1; }
int radius_msg_finish(struct radius_msg *msg, const u8 *secret, size_t secret_len) { if (secret) { u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { wpa_printf(MSG_WARNING, "RADIUS: Could not add " "Message-Authenticator"); return -1; } msg->hdr->length = htons(wpabuf_len(msg->buf)); hmac_md5(secret, secret_len, wpabuf_head(msg->buf), wpabuf_len(msg->buf), (u8 *) (attr + 1)); } else msg->hdr->length = htons(wpabuf_len(msg->buf)); if (wpabuf_len(msg->buf) > 0xffff) { wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", (unsigned long) wpabuf_len(msg->buf)); return -1; } return 0; }
int radius_msg_add_wfa(struct radius_msg *msg, u8 subtype, const u8 *data, size_t len) { struct radius_attr_hdr *attr; u8 *buf, *pos; size_t alen; alen = 4 + 2 + len; buf = os_malloc(alen); if (buf == NULL) return 0; pos = buf; WPA_PUT_BE32(pos, RADIUS_VENDOR_ID_WFA); pos += 4; *pos++ = subtype; *pos++ = 2 + len; os_memcpy(pos, data, len); attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, buf, alen); os_free(buf); if (attr == NULL) return 0; return 1; }
int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len) { if (secret) { u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { printf("WARNING: Could not add " "Message-Authenticator\n"); return -1; } msg->hdr->length = htons(msg->buf_used); hmac_md5(secret, secret_len, msg->buf, msg->buf_used, (u8 *) (attr + 1)); } else msg->hdr->length = htons(msg->buf_used); if (msg->buf_used > 0xffff) { printf("WARNING: too long RADIUS message (%lu)\n", (unsigned long) msg->buf_used); return -1; } return 0; }
static struct radius_msg * radius_server_encapsulate_eap(struct radius_server_data *data, struct radius_client *client, struct radius_session *sess, struct radius_msg *request) { struct radius_msg *msg; int code; unsigned int sess_id; if (sess->eapFail) { code = RADIUS_CODE_ACCESS_REJECT; } else if (sess->eapSuccess) { code = RADIUS_CODE_ACCESS_ACCEPT; } else { code = RADIUS_CODE_ACCESS_CHALLENGE; } msg = radius_msg_new(code, request->hdr->identifier); if (msg == NULL) { return NULL; } sess_id = htonl(sess->sess_id); if (code == RADIUS_CODE_ACCESS_CHALLENGE && !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, (u8 *) &sess_id, sizeof(sess_id))) { RADIUS_DEBUG("Failed to add State attribute"); } if (sess->eapReqData && !radius_msg_add_eap(msg, sess->eapReqData, sess->eapReqDataLen)) { RADIUS_DEBUG("Failed to add EAP-Message attribute"); } if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eapKeyData) { int len; if (sess->eapKeyDataLen > 64) { len = 32; } else { len = sess->eapKeyDataLen / 2; } if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator, (u8 *) client->shared_secret, client->shared_secret_len, sess->eapKeyData + len, len, sess->eapKeyData, len)) { RADIUS_DEBUG("Failed to add MPPE key attributes"); } } if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, client->shared_secret_len, request->hdr->authenticator) < 0) { RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); } return msg; }
static void start_example(void *eloop_ctx, void *timeout_ctx) { struct radius_ctx *ctx = eloop_ctx; struct radius_msg *msg; printf("Sending a RADIUS authentication message\n"); ctx->radius_identifier = radius_client_get_id(ctx->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, ctx->radius_identifier); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return; } radius_msg_make_authenticator(msg, (u8 *) ctx, sizeof(*ctx)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) "user", 4)) { printf("Could not add User-Name\n"); radius_msg_free(msg); return; } if (!radius_msg_add_attr_user_password( msg, (u8 *) "password", 8, ctx->conf.auth_server->shared_secret, ctx->conf.auth_server->shared_secret_len)) { printf("Could not add User-Password\n"); radius_msg_free(msg); return; } if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &ctx->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); radius_msg_free(msg); return; } if (radius_client_send(ctx->radius, msg, RADIUS_AUTH, NULL) < 0) radius_msg_free(msg); }
/* Add User-Password attribute to a RADIUS message and encrypt it as specified * in RFC 2865, Chap. 5.2 */ struct radius_attr_hdr * radius_msg_add_attr_user_password(struct radius_msg *msg, u8 *data, size_t data_len, u8 *secret, size_t secret_len) { u8 buf[128]; int padlen, i; size_t buf_len, pos; const u8 *addr[2]; size_t len[2]; u8 hash[16]; if (data_len > 128) return NULL; os_memcpy(buf, data, data_len); buf_len = data_len; padlen = data_len % 16; if (padlen) { padlen = 16 - padlen; os_memset(buf + data_len, 0, padlen); buf_len += padlen; } addr[0] = secret; len[0] = secret_len; addr[1] = msg->hdr->authenticator; len[1] = 16; md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[i] ^= hash[i]; pos = 16; while (pos < buf_len) { addr[0] = secret; len[0] = secret_len; addr[1] = &buf[pos - 16]; len[1] = 16; md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[pos + i] ^= hash[i]; pos += 16; } return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, buf, buf_len); }
static int add_extra_attr(struct radius_msg *msg, struct extra_radius_attr *attr) { size_t len; char *pos; u32 val; char buf[128]; switch (attr->syntax) { case 's': os_snprintf(buf, sizeof(buf), "%s", attr->data); len = os_strlen(buf); break; case 'n': buf[0] = '\0'; len = 1; break; case 'x': pos = attr->data; if (pos[0] == '0' && pos[1] == 'x') pos += 2; len = os_strlen(pos); if ((len & 1) || (len / 2) > sizeof(buf)) { printf("Invalid extra attribute hexstring\n"); return -1; } len /= 2; if (hexstr2bin(pos, (u8 *) buf, len) < 0) { printf("Invalid extra attribute hexstring\n"); return -1; } break; case 'd': val = htonl(atoi(attr->data)); os_memcpy(buf, &val, 4); len = 4; break; default: printf("Incorrect extra attribute syntax specification\n"); return -1; } if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) { printf("Could not add attribute %d\n", attr->type); return -1; } return 0; }
/* Add User-Password attribute to a RADIUS message and encrypt it as specified * in RFC 2865, Chap. 5.2 */ struct radius_attr_hdr * radius_msg_add_attr_user_password(struct radius_msg *msg, const u8 *data, size_t data_len, const u8 *secret, size_t secret_len) { u8 buf[128]; int res; res = radius_user_password_hide(msg, data, data_len, secret, secret_len, buf, sizeof(buf)); if (res < 0) return NULL; return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, buf, res); }
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, size_t secret_len, const u8 *req_authenticator) { u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; const u8 *addr[4]; size_t len[4]; if (msg->hdr->code != RADIUS_CODE_ACCOUNTING_RESPONSE) { os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { fd_log_debug("WARNING: Could not add Message-Authenticator"); return -1; } msg->hdr->length = htons(msg->buf_used); os_memcpy(msg->hdr->authenticator, req_authenticator, sizeof(msg->hdr->authenticator)); hmac_md5(secret, secret_len, msg->buf, msg->buf_used, (u8 *) (attr + 1)); } else { msg->hdr->length = htons(msg->buf_used); } /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; len[0] = 1 + 1 + 2; addr[1] = req_authenticator; len[1] = MD5_MAC_LEN; addr[2] = (u8 *) (msg->hdr + 1); len[2] = msg->buf_used - sizeof(*msg->hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, msg->hdr->authenticator); if (msg->buf_used > 0xffff) { fd_log_debug("WARNING: too long RADIUS message (%lu)", (unsigned long) msg->buf_used); return -1; } return 0; }
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, u8 type) { struct radius_attr_hdr *attr; size_t i; int count = 0; for (i = 0; i < src->attr_used; i++) { attr = radius_get_attr_hdr(src, i); if (attr->type == type) { if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), attr->length - sizeof(*attr))) return -1; count++; } } return count; }
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, u8 type) { struct radius_attr_hdr *attr = NULL; size_t i; for (i = 0; i < src->attr_used; i++) { if (src->attrs[i]->type == type) { attr = src->attrs[i]; break; } } if (attr == NULL) return 0; if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), attr->length - sizeof(*attr))) return -1; return 1; }
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) { const u8 *pos = data; size_t left = data_len; while (left > 0) { int len; if (left > RADIUS_MAX_ATTR_LEN) len = RADIUS_MAX_ATTR_LEN; else len = left; if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, pos, len)) return 0; pos += len; left -= len; } return 1; }
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, size_t secret_len, const u8 *req_authenticator) { u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; const u8 *addr[4]; size_t len[4]; os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { printf("WARNING: Could not add Message-Authenticator\n"); return -1; } msg->hdr->length = htons(wpabuf_len(msg->buf)); os_memcpy(msg->hdr->authenticator, req_authenticator, sizeof(msg->hdr->authenticator)); hmac_md5(secret, secret_len, wpabuf_head(msg->buf), wpabuf_len(msg->buf), (u8 *) (attr + 1)); /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = (u8 *) msg->hdr; len[0] = 1 + 1 + 2; addr[1] = req_authenticator; len[1] = MD5_MAC_LEN; addr[2] = wpabuf_head_u8(msg->buf) + sizeof(struct radius_hdr); len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr); addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, msg->hdr->authenticator); if (wpabuf_len(msg->buf) > 0xffff) { wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", (unsigned long) wpabuf_len(msg->buf)); return -1; } return 0; }
int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret, size_t secret_len, const struct radius_hdr *req_hdr) { const u8 *addr[2]; size_t len[2]; u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; os_memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN); if (attr == NULL) { wpa_printf(MSG_WARNING, "Could not add Message-Authenticator"); return -1; } msg->hdr->length = host_to_be16(wpabuf_len(msg->buf)); os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16); hmac_md5(secret, secret_len, wpabuf_head(msg->buf), wpabuf_len(msg->buf), (u8 *) (attr + 1)); /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ addr[0] = wpabuf_head_u8(msg->buf); len[0] = wpabuf_len(msg->buf); addr[1] = secret; len[1] = secret_len; if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0) return -1; if (wpabuf_len(msg->buf) > 0xffff) { wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)", (unsigned long) wpabuf_len(msg->buf)); return -1; } return 0; }
static struct radius_msg * accounting_msg(struct hostapd_data *hapd, struct sta_info *sta, int status_type) { struct radius_msg *msg; char buf[128]; u8 *val; size_t len; int i; struct wpabuf *b; msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST, radius_client_get_id(hapd->radius)); if (msg == NULL) { wpa_printf(MSG_INFO, "Could not create new RADIUS packet"); return NULL; } if (sta) { radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); os_snprintf(buf, sizeof(buf), "%08X-%08X", sta->acct_session_id_hi, sta->acct_session_id_lo); if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_INFO, "Could not add Acct-Session-Id"); goto fail; } } else { radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd)); } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE, status_type)) { wpa_printf(MSG_INFO, "Could not add Acct-Status-Type"); goto fail; } if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr, RADIUS_ATTR_ACCT_AUTHENTIC) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC, hapd->conf->ieee802_1x ? RADIUS_ACCT_AUTHENTIC_RADIUS : RADIUS_ACCT_AUTHENTIC_LOCAL)) { wpa_printf(MSG_INFO, "Could not add Acct-Authentic"); goto fail; } if (sta) { /* Use 802.1X identity if available */ val = ieee802_1x_get_identity(sta->eapol_sm, &len); /* Use RADIUS ACL identity if 802.1X provides no identity */ if (!val && sta->identity) { val = (u8 *) sta->identity; len = os_strlen(sta->identity); } /* Use STA MAC if neither 802.1X nor RADIUS ACL provided * identity */ if (!val) { os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(sta->addr)); val = (u8 *) buf; len = os_strlen(buf); } if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val, len)) { wpa_printf(MSG_INFO, "Could not add User-Name"); goto fail; } } if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta, msg) < 0) goto fail; if (sta) { for (i = 0; ; i++) { val = ieee802_1x_get_radius_class(sta->eapol_sm, &len, i); if (val == NULL) break; if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS, val, len)) { wpa_printf(MSG_INFO, "Could not add Class"); goto fail; } } b = ieee802_1x_get_radius_cui(sta->eapol_sm); if (b && !radius_msg_add_attr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, wpabuf_head(b), wpabuf_len(b))) { wpa_printf(MSG_ERROR, "Could not add CUI"); goto fail; } if (!b && sta->radius_cui && !radius_msg_add_attr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, (u8 *) sta->radius_cui, os_strlen(sta->radius_cui))) { wpa_printf(MSG_ERROR, "Could not add CUI from ACL"); goto fail; } } return msg; fail: radius_msg_free(msg); return NULL; }
static int hostapd_radius_acl_query(hostapd *hapd, u8 *addr, struct hostapd_acl_query_data *query) { struct radius_msg *msg; char buf[128]; query->radius_id = radius_client_get_id(hapd); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); if (msg == NULL) return -1; radius_msg_make_authenticator(msg, addr, ETH_ALEN); snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, buf, strlen(buf))) { printf("Could not add User-Name\n"); goto fail; } if (!radius_msg_add_attr_user_password( msg, buf, strlen(buf), hapd->conf->auth_server->shared_secret, hapd->conf->auth_server->shared_secret_len)) { printf("Could not add User-Password\n"); goto fail; } if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &hapd->conf->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } if (hapd->conf->nas_identifier && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, hapd->conf->nas_identifier, strlen(hapd->conf->nas_identifier))) { printf("Could not add NAS-Identifier\n"); goto fail; } snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", MAC2STR(hapd->own_addr), hapd->conf->ssid); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, buf, strlen(buf))) { printf("Could not add Called-Station-Id\n"); goto fail; } snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, buf, strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, buf, strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } radius_client_send(hapd, msg, RADIUS_AUTH, addr); return 0; fail: radius_msg_free(msg); free(msg); return -1; }
static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta, int status_type) { struct radius_msg *msg; char buf[128]; u8 *val; size_t len; msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST, radius_client_get_id(hapd)); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return NULL; } radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(sta)); snprintf(buf, sizeof(buf), "%08X-%08X", hapd->radius->acct_session_id_hi, sta->acct_session_id_lo); if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, buf, strlen(buf))) { printf("Could not add Acct-Session-Id\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE, status_type)) { printf("Could not add Acct-Status-Type\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC, hapd->conf->ieee802_1x ? RADIUS_ACCT_AUTHENTIC_RADIUS : RADIUS_ACCT_AUTHENTIC_LOCAL)) { printf("Could not add Acct-Authentic\n"); goto fail; } val = sta->identity; len = sta->identity_len; if (!val) { snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(sta->addr)); val = buf; len = strlen(val); } if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val, len)) { printf("Could not add User-Name\n"); goto fail; } if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &hapd->conf->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { printf("Could not add NAS-Port\n"); goto fail; } snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", MAC2STR(hapd->own_addr), hapd->conf->ssid); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, buf, strlen(buf))) { printf("Could not add Called-Station-Id\n"); goto fail; } snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(sta->addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, buf, strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, buf, strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } return msg; fail: radius_msg_free(msg); free(msg); return NULL; }
static struct radius_msg * accounting_msg(struct hostapd_data *hapd, struct sta_info *sta, int status_type) { struct radius_msg *msg; char buf[128]; u8 *val; size_t len; int i; msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST, radius_client_get_id(hapd->radius)); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return NULL; } if (sta) { radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta)); os_snprintf(buf, sizeof(buf), "%08X-%08X", sta->acct_session_id_hi, sta->acct_session_id_lo); if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID, (u8 *) buf, os_strlen(buf))) { printf("Could not add Acct-Session-Id\n"); goto fail; } } else { radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd)); } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE, status_type)) { printf("Could not add Acct-Status-Type\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC, hapd->conf->ieee802_1x ? RADIUS_ACCT_AUTHENTIC_RADIUS : RADIUS_ACCT_AUTHENTIC_LOCAL)) { printf("Could not add Acct-Authentic\n"); goto fail; } if (sta) { val = ieee802_1x_get_identity(sta->eapol_sm, &len); if (!val) { os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(sta->addr)); val = (u8 *) buf; len = os_strlen(buf); } if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val, len)) { printf("Could not add User-Name\n"); goto fail; } } if (hapd->conf->own_ip_addr.af == AF_INET && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } #ifdef CONFIG_IPV6 if (hapd->conf->own_ip_addr.af == AF_INET6 && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { printf("Could not add NAS-IPv6-Address\n"); goto fail; } #endif /* CONFIG_IPV6 */ if (hapd->conf->nas_identifier && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, (u8 *) hapd->conf->nas_identifier, os_strlen(hapd->conf->nas_identifier))) { printf("Could not add NAS-Identifier\n"); goto fail; } if (sta && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) { printf("Could not add NAS-Port\n"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, (u8 *) buf, os_strlen(buf))) { printf("Could not add Called-Station-Id\n"); goto fail; } if (sta) { os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(sta->addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, os_strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } if (!radius_msg_add_attr_int32( msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s", radius_sta_rate(hapd, sta) / 2, (radius_sta_rate(hapd, sta) & 1) ? ".5" : "", radius_mode_txt(hapd)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, os_strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } for (i = 0; ; i++) { val = ieee802_1x_get_radius_class(sta->eapol_sm, &len, i); if (val == NULL) break; if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS, val, len)) { printf("Could not add Class\n"); goto fail; } } } return msg; fail: radius_msg_free(msg); os_free(msg); return NULL; }
static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e, const u8 *eap, size_t len) { struct radius_msg *msg; char buf[128]; const struct eap_hdr *hdr; const u8 *pos; wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " "packet"); e->radius_identifier = radius_client_get_id(e->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, e->radius_identifier); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return; } radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e)); hdr = (const struct eap_hdr *) eap; pos = (const u8 *) (hdr + 1); if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE && pos[0] == EAP_TYPE_IDENTITY) { pos++; os_free(e->eap_identity); e->eap_identity_len = len - sizeof(*hdr) - 1; e->eap_identity = os_malloc(e->eap_identity_len); if (e->eap_identity) { os_memcpy(e->eap_identity, pos, e->eap_identity_len); wpa_hexdump(MSG_DEBUG, "Learned identity from " "EAP-Response-Identity", e->eap_identity, e->eap_identity_len); } } if (e->eap_identity && !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, e->eap_identity, e->eap_identity_len)) { printf("Could not add User-Name\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_IP_ADDRESS) && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &e->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(e->wpa_s->own_addr)); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CALLING_STATION_ID) && !radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, os_strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } /* TODO: should probably check MTU from driver config; 2304 is max for * IEEE 802.11, but use 1400 to avoid problems with too large packets */ if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_FRAMED_MTU) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { printf("Could not add Framed-MTU\n"); goto fail; } if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_NAS_PORT_TYPE) && !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } os_snprintf(buf, sizeof(buf), "%s", e->connect_info); if (!find_extra_attr(e->extra_attrs, RADIUS_ATTR_CONNECT_INFO) && !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, os_strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } if (add_extra_attrs(msg, e->extra_attrs) < 0) goto fail; if (eap && !radius_msg_add_eap(msg, eap, len)) { printf("Could not add EAP-Message\n"); goto fail; } /* State attribute must be copied if and only if this packet is * Access-Request reply to the previous Access-Challenge */ if (e->last_recv_radius && radius_msg_get_hdr(e->last_recv_radius)->code == RADIUS_CODE_ACCESS_CHALLENGE) { int res = radius_msg_copy_attr(msg, e->last_recv_radius, RADIUS_ATTR_STATE); if (res < 0) { printf("Could not copy State attribute from previous " "Access-Challenge\n"); goto fail; } if (res > 0) { wpa_printf(MSG_DEBUG, " Copied RADIUS State " "Attribute"); } } radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr); return; fail: radius_msg_free(msg); }
static struct radius_msg * radius_server_encapsulate_eap(struct radius_server_data *data, struct radius_client *client, struct radius_session *sess, struct radius_msg *request) { struct radius_msg *msg; int code; unsigned int sess_id; struct radius_hdr *hdr = radius_msg_get_hdr(request); if (sess->eap_if->eapFail) { sess->eap_if->eapFail = FALSE; code = RADIUS_CODE_ACCESS_REJECT; } else if (sess->eap_if->eapSuccess) { sess->eap_if->eapSuccess = FALSE; code = RADIUS_CODE_ACCESS_ACCEPT; } else { sess->eap_if->eapReq = FALSE; code = RADIUS_CODE_ACCESS_CHALLENGE; } msg = radius_msg_new(code, hdr->identifier); if (msg == NULL) { RADIUS_DEBUG("Failed to allocate reply message"); return NULL; } sess_id = htonl(sess->sess_id); if (code == RADIUS_CODE_ACCESS_CHALLENGE && !radius_msg_add_attr(msg, RADIUS_ATTR_STATE, (u8 *) &sess_id, sizeof(sess_id))) { RADIUS_DEBUG("Failed to add State attribute"); } if (sess->eap_if->eapReqData && !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData), wpabuf_len(sess->eap_if->eapReqData))) { RADIUS_DEBUG("Failed to add EAP-Message attribute"); } if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) { int len; #ifdef CONFIG_RADIUS_TEST if (data->dump_msk_file) { FILE *f; char buf[2 * 64 + 1]; f = fopen(data->dump_msk_file, "a"); if (f) { len = sess->eap_if->eapKeyDataLen; if (len > 64) len = 64; len = wpa_snprintf_hex( buf, sizeof(buf), sess->eap_if->eapKeyData, len); buf[len] = '\0'; fprintf(f, "%s\n", buf); fclose(f); } } #endif /* CONFIG_RADIUS_TEST */ if (sess->eap_if->eapKeyDataLen > 64) { len = 32; } else { len = sess->eap_if->eapKeyDataLen / 2; } if (!radius_msg_add_mppe_keys(msg, hdr->authenticator, (u8 *) client->shared_secret, client->shared_secret_len, sess->eap_if->eapKeyData + len, len, sess->eap_if->eapKeyData, len)) { RADIUS_DEBUG("Failed to add MPPE key attributes"); } } if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) { RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)"); radius_msg_free(msg); return NULL; } if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret, client->shared_secret_len, hdr->authenticator) < 0) { RADIUS_DEBUG("Failed to add Message-Authenticator attribute"); } return msg; }
static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr, struct hostapd_acl_query_data *query) { struct radius_msg *msg; char buf[128]; query->radius_id = radius_client_get_id(hapd->radius); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id); if (msg == NULL) return -1; radius_msg_make_authenticator(msg, addr, ETH_ALEN); os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_DEBUG, "Could not add User-Name"); goto fail; } if (!radius_msg_add_attr_user_password( msg, (u8 *) buf, os_strlen(buf), hapd->conf->radius->auth_server->shared_secret, hapd->conf->radius->auth_server->shared_secret_len)) { wpa_printf(MSG_DEBUG, "Could not add User-Password"); goto fail; } if (hapd->conf->own_ip_addr.af == AF_INET && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) { wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address"); goto fail; } #ifdef CONFIG_IPV6 if (hapd->conf->own_ip_addr.af == AF_INET6 && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS, (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) { wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address"); goto fail; } #endif /* CONFIG_IPV6 */ if (hapd->conf->nas_identifier && !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER, (u8 *) hapd->conf->nas_identifier, os_strlen(hapd->conf->nas_identifier))) { wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s", MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id"); goto fail; } os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type"); goto fail; } os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, (u8 *) buf, os_strlen(buf))) { wpa_printf(MSG_DEBUG, "Could not add Connect-Info"); goto fail; } radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr); return 0; fail: radius_msg_free(msg); return -1; }
int radius_msg_add_mppe_keys(struct radius_msg *msg, const u8 *req_authenticator, const u8 *secret, size_t secret_len, const u8 *send_key, size_t send_key_len, const u8 *recv_key, size_t recv_key_len) { struct radius_attr_hdr *attr; u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); u8 *buf; struct radius_attr_vendor *vhdr; u8 *pos; size_t elen; int hlen; u16 salt; hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; /* MS-MPPE-Send-Key */ buf = os_malloc(hlen + send_key_len + 16); if (buf == NULL) { return 0; } pos = buf; os_memcpy(pos, &vendor_id, sizeof(vendor_id)); pos += sizeof(vendor_id); vhdr = (struct radius_attr_vendor *) pos; vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; pos = (u8 *) (vhdr + 1); salt = os_random() | 0x8000; *pos++ = salt >> 8; *pos++ = salt; encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, secret_len, pos, &elen); vhdr->vendor_length = hlen + elen - sizeof(vendor_id); attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, buf, hlen + elen); os_free(buf); if (attr == NULL) { return 0; } /* MS-MPPE-Recv-Key */ buf = os_malloc(hlen + send_key_len + 16); if (buf == NULL) { return 0; } pos = buf; os_memcpy(pos, &vendor_id, sizeof(vendor_id)); pos += sizeof(vendor_id); vhdr = (struct radius_attr_vendor *) pos; vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; pos = (u8 *) (vhdr + 1); salt ^= 1; *pos++ = salt >> 8; *pos++ = salt; encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, secret_len, pos, &elen); vhdr->vendor_length = hlen + elen - sizeof(vendor_id); attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, buf, hlen + elen); os_free(buf); if (attr == NULL) { return 0; } return 1; }
static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s, u8 *eap, size_t len) { struct radius_msg *msg; char buf[128]; struct wpa_ssid *ssid = wpa_s->current_ssid; u8 *identity; size_t identity_len; wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS " "packet"); wpa_s->radius_identifier = radius_client_get_id(wpa_s); msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, wpa_s->radius_identifier); if (msg == NULL) { printf("Could not create net RADIUS packet\n"); return; } radius_msg_make_authenticator(msg, (u8 *) wpa_s, sizeof(*wpa_s)); if (ssid->anonymous_identity) { identity = ssid->anonymous_identity; identity_len = ssid->anonymous_identity_len; } else { identity = ssid->identity; identity_len = ssid->identity_len; } if (identity && !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, identity, identity_len)) { printf("Could not add User-Name\n"); goto fail; } if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &wpa_s->own_ip_addr, 4)) { printf("Could not add NAS-IP-Address\n"); goto fail; } snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(wpa_s->own_addr)); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, buf, strlen(buf))) { printf("Could not add Calling-Station-Id\n"); goto fail; } /* TODO: should probably check MTU from driver config; 2304 is max for * IEEE 802.11, but use 1400 to avoid problems with too large packets */ if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) { printf("Could not add Framed-MTU\n"); goto fail; } if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11)) { printf("Could not add NAS-Port-Type\n"); goto fail; } snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b"); if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, buf, strlen(buf))) { printf("Could not add Connect-Info\n"); goto fail; } if (eap && !radius_msg_add_eap(msg, eap, len)) { printf("Could not add EAP-Message\n"); goto fail; } /* State attribute must be copied if and only if this packet is * Access-Request reply to the previous Access-Challenge */ if (wpa_s->last_recv_radius && wpa_s->last_recv_radius->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE) { int res = radius_msg_copy_attr(msg, wpa_s->last_recv_radius, RADIUS_ATTR_STATE); if (res < 0) { printf("Could not copy State attribute from previous " "Access-Challenge\n"); goto fail; } if (res > 0) { wpa_printf(MSG_DEBUG, " Copied RADIUS State " "Attribute"); } } radius_client_send(wpa_s, msg, RADIUS_AUTH, wpa_s->own_addr); return; fail: radius_msg_free(msg); free(msg); }