/** * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface * @config: Configuration data (e.g., file name) * @get_complete_cb: Callback function for reporting availability of triplets * @ctx: Context pointer for get_complete_cb * Returns: Pointer to a private data structure or %NULL on failure */ void * eap_sim_db_init(const char *config, void (*get_complete_cb)(void *ctx, void *session_ctx), void *ctx) { struct eap_sim_db_data *data; data = wpa_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->sock = -1; data->get_complete_cb = get_complete_cb; data->ctx = ctx; data->fname = VM_STRDUP(config); if (data->fname == NULL) goto fail; if (strncmp(data->fname, "unix:", 5) == 0) { if (eap_sim_db_open_socket(data)) goto fail; } return data; fail: eap_sim_db_close_socket(data); VM_FREE(data->fname); VM_FREE(data); return NULL; }
/** * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface * @priv: Private data pointer from eap_sim_db_init() */ void eap_sim_db_deinit(void *priv) { struct eap_sim_db_data *data = priv; struct eap_sim_pseudonym *p, *prev; struct eap_sim_reauth *r, *prevr; struct eap_sim_db_pending *pending, *prev_pending; eap_sim_db_close_socket(data); VM_FREE(data->fname); p = data->pseudonyms; while (p) { prev = p; p = p->next; eap_sim_db_free_pseudonym(prev); } r = data->reauths; while (r) { prevr = r; r = r->next; eap_sim_db_free_reauth(prevr); } pending = data->pending; while (pending) { prev_pending = pending; pending = pending->next; VM_FREE(prev_pending); } VM_FREE(data); }
static struct radius_session * radius_server_get_new_session(struct radius_server_data *data, struct radius_client *client, struct radius_msg *msg) { u8 *user; size_t user_len; const struct hostapd_eap_user *eap_user; int res; struct radius_session *sess; struct eap_config eap_conf; RADIUS_DEBUG("Creating a new session"); user = VM_MALLOC(256); if (user == NULL) { return NULL; } res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256); if (res < 0 || res > 256) { RADIUS_DEBUG("Could not get User-Name"); VM_FREE(user); return NULL; } user_len = res; RADIUS_DUMP_ASCII("User-Name", user, user_len); eap_user = hostapd_get_eap_user(data->hostapd_conf, user, user_len, 0); VM_FREE(user); if (eap_user) { RADIUS_DEBUG("Matching user entry found"); sess = radius_server_new_session(data, client); if (sess == NULL) { RADIUS_DEBUG("Failed to create a new session"); return NULL; } } else { RADIUS_DEBUG("User-Name not found from user database"); return NULL; } memset(&eap_conf, 0, sizeof(eap_conf)); eap_conf.ssl_ctx = data->ssl_ctx; eap_conf.eap_sim_db_priv = data->eap_sim_db_priv; eap_conf.backend_auth = TRUE; sess->eap = eap_sm_init(sess, &radius_server_eapol_cb, &eap_conf); if (sess->eap == NULL) { RADIUS_DEBUG("Failed to initialize EAP state machine for the " "new session"); radius_server_session_free(data, sess); return NULL; } sess->eapRestart = TRUE; sess->portEnabled = TRUE; RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id); return sess; }
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) { if (entry == NULL) return; VM_FREE(entry->identity); ieee802_1x_free_radius_class(&entry->radius_class); VM_FREE(entry); }
static void radius_server_free_clients(struct radius_server_data *data, struct radius_client *clients) { struct radius_client *client, *prev; client = clients; while (client) { prev = client; client = client->next; radius_server_free_sessions(data, prev->sessions); VM_FREE(prev->shared_secret); VM_FREE(prev); } }
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features, size_t num_hw_features) { size_t i; if (hw_features == NULL) return; for (i = 0; i < num_hw_features; i++) { VM_FREE(hw_features[i].channels); VM_FREE(hw_features[i].rates); } VM_FREE(hw_features); }
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry, struct eapol_state_machine *eapol) { if (entry == NULL || eapol == NULL) return; if (entry->identity) { VM_FREE(eapol->identity); eapol->identity = VM_MALLOC(entry->identity_len); if (eapol->identity) { eapol->identity_len = entry->identity_len; memcpy(eapol->identity, entry->identity, entry->identity_len); } wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA", eapol->identity, eapol->identity_len); } ieee802_1x_free_radius_class(&eapol->radius_class); ieee802_1x_copy_radius_class(&eapol->radius_class, &entry->radius_class); if (eapol->radius_class.attr) { wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from " "PMKSA", (unsigned long) eapol->radius_class.count); } eapol->eap_type_authsrv = entry->eap_type_authsrv; eapol->sta->vlan_id = entry->vlan_id; }
/*! frees the given memory to heap \param buffer - address to free */ int FreeToHeap(void * free_buffer) { HEAP_DATA_PTR heap_data_ptr; heap_data_ptr = STRUCT_ADDRESS_FROM_MEMBER( free_buffer, HEAP_DATA, buffer[0]); if ( heap_data_ptr->bucket_index == VM_BUCKET ) VM_FREE( heap_data_ptr, (UINT32)heap_data_ptr->buffer[0] ); return FreeBuffer(heap_data_ptr, &CACHE_FROM_INDEX(heap_data_ptr->bucket_index) ); }
static int radius_server_reject(struct radius_server_data *data, struct radius_client *client, struct radius_msg *request, struct sockaddr *from, socklen_t fromlen, const char *from_addr, int from_port) { struct radius_msg *msg; int ret = 0; struct eap_hdr eapfail; RADIUS_DEBUG("Reject invalid request from %s:%d", from_addr, from_port); msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT, request->hdr->identifier); if (msg == NULL) { return -1; } memset(&eapfail, 0, sizeof(eapfail)); eapfail.code = EAP_CODE_FAILURE; eapfail.identifier = 0; eapfail.length = htons(sizeof(eapfail)); if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) { RADIUS_DEBUG("Failed to add EAP-Message attribute"); } 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); os_free(msg); return -1; } 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"); } if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(msg); } data->counters.access_rejects++; client->counters.access_rejects++; if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0, (struct sockaddr *) from, sizeof(*from)) < 0) { perror("sendto[RADIUS SRV]"); ret = -1; } radius_msg_free(msg); VM_FREE(msg); return ret; }
/** * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry * @priv: Private data pointer from eap_sim_db_init() * @identity: Identity of the user (may be permanent identity or pseudonym) * @identity_len: Length of identity * @reauth_id: reauth_id for this user. This needs to be an allocated buffer, * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not * free it. * @mk: 16-byte MK from the previous full authentication * Returns: 0 on success, -1 on failure * * This function adds a new re-authentication entry for an EAP-SIM user. * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed * anymore. */ int eap_sim_db_add_reauth(void *priv, const u8 *identity, size_t identity_len, char *reauth_id, u16 counter, const u8 *mk) { struct eap_sim_db_data *data = priv; struct eap_sim_reauth *r; wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity", identity, identity_len); wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id); r = eap_sim_db_get_reauth(data, identity, identity_len); if (r == NULL) r = eap_sim_db_get_reauth_id(data, identity, identity_len); if (r) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " "reauth_id: %s", r->reauth_id); VM_FREE(r->reauth_id); r->reauth_id = reauth_id; } else { r = wpa_zalloc(sizeof(*r)); if (r == NULL) { VM_FREE(reauth_id); return -1; } r->next = data->reauths; r->identity = VM_MALLOC(identity_len); if (r->identity == NULL) { VM_FREE(r); VM_FREE(reauth_id); return -1; } memcpy(r->identity, identity, identity_len); r->identity_len = identity_len; r->reauth_id = reauth_id; data->reauths = r; wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry"); } r->counter = counter; memcpy(r->mk, mk, EAP_SIM_MK_LEN); return 0; }
/** * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym * @priv: Private data pointer from eap_sim_db_init() * @identity: Identity of the user (may be permanent identity or pseudonym) * @identity_len: Length of identity * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer, * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not * free it. * Returns: 0 on success, -1 on failure * * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is * responsible of freeing pseudonym buffer once it is not needed anymore. */ int eap_sim_db_add_pseudonym(void *priv, const u8 *identity, size_t identity_len, char *pseudonym) { struct eap_sim_db_data *data = priv; struct eap_sim_pseudonym *p; wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity", identity, identity_len); wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym); /* TODO: could store last two pseudonyms */ p = eap_sim_db_get_pseudonym(data, identity, identity_len); if (p == NULL) p = eap_sim_db_get_pseudonym_id(data, identity, identity_len); if (p) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous " "pseudonym: %s", p->pseudonym); VM_FREE(p->pseudonym); p->pseudonym = pseudonym; return 0; } p = wpa_zalloc(sizeof(*p)); if (p == NULL) { VM_FREE(pseudonym); return -1; } p->next = data->pseudonyms; p->identity = VM_MALLOC(identity_len); if (p->identity == NULL) { VM_FREE(p); VM_FREE(pseudonym); return -1; } memcpy(p->identity, identity, identity_len); p->identity_len = identity_len; p->pseudonym = pseudonym; data->pseudonyms = p; wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry"); return 0; }
static void eap_sim_db_close_socket(struct eap_sim_db_data *data) { if (data->sock >= 0) { eloop_unregister_read_sock(data->sock); close(data->sock); data->sock = -1; } if (data->local_sock) { unlink(data->local_sock); VM_FREE(data->local_sock); data->local_sock = NULL; } }
void radius_server_deinit(struct radius_server_data *data) { if (data == NULL) return; if (data->auth_sock >= 0) { eloop_unregister_read_sock(data->auth_sock); close(data->auth_sock); } radius_server_free_clients(data, data->clients); VM_FREE(data); }
static void radius_server_set_eapReqData(void *ctx, const u8 *eapReqData, size_t eapReqDataLen) { struct radius_session *sess = ctx; if (sess == NULL) return; VM_FREE(sess->eapReqData); sess->eapReqData = VM_MALLOC(eapReqDataLen); if (sess->eapReqData) { memcpy(sess->eapReqData, eapReqData, eapReqDataLen); sess->eapReqDataLen = eapReqDataLen; } else { sess->eapReqDataLen = 0; } }
/** * pmksa_cache_deinit - Free all entries in PMKSA cache * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() */ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) { struct rsn_pmksa_cache_entry *entry, *prev; int i; if (pmksa == NULL) return; entry = pmksa->pmksa; while (entry) { prev = entry; entry = entry->next; _pmksa_cache_free_entry(prev); } eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); for (i = 0; i < PMKID_HASH_SIZE; i++) pmksa->pmkid[i] = NULL; VM_FREE(pmksa); }
void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) { struct radius_client *cli; struct radius_session *s, *sess = NULL; struct radius_msg *msg; if (data == NULL) return; for (cli = data->clients; cli; cli = cli->next) { for (s = cli->sessions; s; s = s->next) { if (s->eap == ctx && s->last_msg) { sess = s; break; } if (sess) break; } if (sess) break; } if (sess == NULL) { RADIUS_DEBUG("No session matched callback ctx"); return; } msg = sess->last_msg; sess->last_msg = NULL; eap_sm_pending_cb(sess->eap); if (radius_server_request(data, msg, (struct sockaddr *) &sess->last_from, sess->last_fromlen, cli, sess->last_from_addr, sess->last_from_port, sess) == -2) return; /* msg was stored with the session */ radius_msg_free(msg); VM_FREE(msg); }
static struct eap_sim_pseudonym * eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity, size_t identity_len) { char *pseudonym; size_t len; struct eap_sim_pseudonym *p; if (identity_len == 0 || (identity[0] != EAP_SIM_PSEUDONYM_PREFIX && identity[0] != EAP_AKA_PSEUDONYM_PREFIX)) return NULL; /* Remove possible realm from identity */ len = 0; while (len < identity_len) { if (identity[len] == '@') break; len++; } pseudonym = VM_MALLOC(len + 1); if (pseudonym == NULL) return NULL; memcpy(pseudonym, identity, len); pseudonym[len] = '\0'; p = data->pseudonyms; while (p) { if (strcmp(p->pseudonym, pseudonym) == 0) break; p = p->next; } VM_FREE(pseudonym); return p; }
static struct eap_sim_reauth * eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity, size_t identity_len) { char *reauth_id; size_t len; struct eap_sim_reauth *r; if (identity_len == 0 || (identity[0] != EAP_SIM_REAUTH_ID_PREFIX && identity[0] != EAP_AKA_REAUTH_ID_PREFIX)) return NULL; /* Remove possible realm from identity */ len = 0; while (len < identity_len) { if (identity[len] == '@') break; len++; } reauth_id = VM_MALLOC(len + 1); if (reauth_id == NULL) return NULL; memcpy(reauth_id, identity, len); reauth_id[len] = '\0'; r = data->reauths; while (r) { if (strcmp(r->reauth_id, reauth_id) == 0) break; r = r->next; } VM_FREE(reauth_id); return r; }
static void radius_server_session_free(struct radius_server_data *data, struct radius_session *sess) { eloop_cancel_timeout(radius_server_session_timeout, data, sess); VM_FREE(sess->eapKeyData); VM_FREE(sess->eapReqData); eap_sm_deinit(sess->eap); if (sess->last_msg) { radius_msg_free(sess->last_msg); VM_FREE(sess->last_msg); } VM_FREE(sess->last_from_addr); if (sess->last_reply) { radius_msg_free(sess->last_reply); VM_FREE(sess->last_reply); } VM_FREE(sess); data->num_sess--; }
static void radius_server_receive_auth(int sock, void *eloop_ctx, void *sock_ctx) { struct radius_server_data *data = eloop_ctx; u8 *buf = NULL; struct sockaddr from; socklen_t fromlen; int len; struct radius_client *client = NULL; struct radius_msg *msg = NULL; char abuf[50]; int from_port = 0; buf = VM_MALLOC(RADIUS_MAX_MSG_LEN); if (buf == NULL) { goto fail; } fromlen = sizeof(from); len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0, (struct sockaddr *) &from, &fromlen); if (len < 0) { perror("recvfrom[radius_server]"); goto fail; } #ifdef CONFIG_IPV6 if (data->ipv6) { struct sockaddr_in6 *from6 = (struct sockaddr_in6 *) &from; if (inet_ntop(AF_INET6, &from6->sin6_addr, abuf, sizeof(abuf)) == NULL) abuf[0] = '\0'; from_port = ntohs(from6->sin6_port); RADIUS_DEBUG("Received %d bytes from %s:%d", len, abuf, from_port); client = radius_server_get_client(data, (struct in_addr *) &from6->sin6_addr, 1); } #endif /* CONFIG_IPV6 */ if (!data->ipv6) { struct sockaddr_in *from4 = (struct sockaddr_in *) &from; snprintf(abuf, sizeof(abuf), "%s", inet_ntoa(from4->sin_addr)); from_port = ntohs(from4->sin_port); RADIUS_DEBUG("Received %d bytes from %s:%d", len, abuf, from_port); client = radius_server_get_client(data, &from4->sin_addr, 0); } RADIUS_DUMP("Received data", buf, len); if (client == NULL) { RADIUS_DEBUG("Unknown client %s - packet ignored", abuf); data->counters.invalid_requests++; goto fail; } msg = radius_msg_parse(buf, len); if (msg == NULL) { RADIUS_DEBUG("Parsing incoming RADIUS frame failed"); data->counters.malformed_access_requests++; client->counters.malformed_access_requests++; goto fail; } VM_FREE(buf); buf = NULL; if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(msg); } if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) { RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code); data->counters.unknown_types++; client->counters.unknown_types++; goto fail; } data->counters.access_requests++; client->counters.access_requests++; if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret, client->shared_secret_len, NULL)) { RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf); data->counters.bad_authenticators++; client->counters.bad_authenticators++; goto fail; } if (radius_server_request(data, msg, (struct sockaddr *) &from, fromlen, client, abuf, from_port, NULL) == -2) return; /* msg was stored with the session */ fail: if (msg) { radius_msg_free(msg); VM_FREE(msg); } VM_FREE(buf); }
static struct radius_client * radius_server_read_clients(const char *client_file, int ipv6) { FILE *f; const int buf_size = 1024; char *buf, *pos; struct radius_client *clients, *tail, *entry; int line = 0, mask, failed = 0, i; struct in_addr addr; #ifdef CONFIG_IPV6 struct in6_addr addr6; #endif /* CONFIG_IPV6 */ unsigned int val; f = fopen(client_file, "r"); if (f == NULL) { RADIUS_ERROR("Could not open client file '%s'", client_file); return NULL; } buf = VM_MALLOC(buf_size); if (buf == NULL) { fclose(f); return NULL; } clients = tail = NULL; while (fgets(buf, buf_size, f)) { /* Configuration file format: * 192.168.1.0/24 secret * 192.168.1.2 secret * fe80::211:22ff:fe33:4455/64 secretipv6 */ line++; buf[buf_size - 1] = '\0'; pos = buf; while (*pos != '\0' && *pos != '\n') pos++; if (*pos == '\n') *pos = '\0'; if (*buf == '\0' || *buf == '#') continue; pos = buf; while ((*pos >= '0' && *pos <= '9') || *pos == '.' || (*pos >= 'a' && *pos <= 'f') || *pos == ':' || (*pos >= 'A' && *pos <= 'F')) { pos++; } if (*pos == '\0') { failed = 1; break; } if (*pos == '/') { char *end; *pos++ = '\0'; mask = strtol(pos, &end, 10); if ((pos == end) || (mask < 0 || mask > (ipv6 ? 128 : 32))) { failed = 1; break; } pos = end; } else { mask = ipv6 ? 128 : 32; *pos++ = '\0'; } if (!ipv6 && hostapd_inet_aton(buf, &addr) == 0) { failed = 1; break; } #ifdef CONFIG_IPV6 if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) { if (inet_pton(AF_INET, buf, &addr) <= 0) { failed = 1; break; } /* Convert IPv4 address to IPv6 */ if (mask <= 32) mask += (128 - 32); memset(addr6.s6_addr, 0, 10); addr6.s6_addr[10] = 0xff; addr6.s6_addr[11] = 0xff; memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, 4); } #endif /* CONFIG_IPV6 */ while (*pos == ' ' || *pos == '\t') { pos++; } if (*pos == '\0') { failed = 1; break; } entry = wpa_zalloc(sizeof(*entry)); if (entry == NULL) { failed = 1; break; } entry->shared_secret = VM_STRDUP(pos); if (entry->shared_secret == NULL) { failed = 1; VM_FREE(entry); break; } entry->shared_secret_len = strlen(entry->shared_secret); entry->addr.s_addr = addr.s_addr; if (!ipv6) { val = 0; for (i = 0; i < mask; i++) val |= 1 << (31 - i); entry->mask.s_addr = htonl(val); } #ifdef CONFIG_IPV6 if (ipv6) { int offset = mask / 8; memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16); memset(entry->mask6.s6_addr, 0xff, offset); val = 0; for (i = 0; i < (mask % 8); i++) val |= 1 << (7 - i); if (offset < 16) entry->mask6.s6_addr[offset] = val; } #endif /* CONFIG_IPV6 */ if (tail == NULL) { clients = tail = entry; } else { tail->next = entry; tail = entry; } } if (failed) { RADIUS_ERROR("Invalid line %d in '%s'", line, client_file); radius_server_free_clients(NULL, clients); clients = NULL; } VM_FREE(buf); fclose(f); return clients; }
/** * eap_sim_db_get_aka_auth - Get AKA authentication values * @priv: Private data pointer from eap_sim_db_init() * @identity: User name identity * @identity_len: Length of identity in bytes * @_rand: Buffer for RAND value * @autn: Buffer for AUTN value * @ik: Buffer for IK value * @ck: Buffer for CK value * @res: Buffer for RES value * @res_len: Buffer for RES length * @cb_session_ctx: Session callback context for get_complete_cb() * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this * case, the callback function registered with eap_sim_db_init() will be * called once the results become available. * * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in * ASCII format. * * When using an external server for AKA authentication, this function can * always start a request and return EAP_SIM_DB_PENDING immediately if * authentication triplets are not available. Once the authentication data are * received, callback function registered with eap_sim_db_init() is called to * notify EAP state machine to reprocess the message. This * eap_sim_db_get_aka_auth() function will then be called again and the newly * received triplets will then be given to the caller. */ int eap_sim_db_get_aka_auth(void *priv, const u8 *identity, size_t identity_len, u8 *_rand, u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len, void *cb_session_ctx) { struct eap_sim_db_data *data = priv; struct eap_sim_db_pending *entry; int len; size_t i; char msg[40]; if (identity_len < 2 || identity == NULL || identity[0] != EAP_AKA_PERMANENT_PREFIX) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); return EAP_SIM_DB_FAILURE; } identity++; identity_len--; for (i = 0; i < identity_len; i++) { if (identity[i] == '@') { identity_len = i; break; } } if (identity_len + 1 > sizeof(entry->imsi)) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); return EAP_SIM_DB_FAILURE; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI", identity, identity_len); entry = eap_sim_db_get_pending(data, identity, identity_len, 1); if (entry) { if (entry->state == FAILURE) { VM_FREE(entry); wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure"); return EAP_SIM_DB_FAILURE; } if (entry->state == PENDING) { eap_sim_db_add_pending(data, entry); wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending"); return EAP_SIM_DB_PENDING; } wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully " "received authentication data"); memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN); memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN); memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN); memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN); memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN); *res_len = entry->u.aka.res_len; VM_FREE(entry); return 0; } if (data->sock < 0) { if (eap_sim_db_open_socket(data) < 0) return EAP_SIM_DB_FAILURE; } len = snprintf(msg, sizeof(msg), "AKA-REQ-AUTH "); if (len < 0 || len + identity_len >= sizeof(msg)) return EAP_SIM_DB_FAILURE; memcpy(msg + len, identity, identity_len); len += identity_len; wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication " "data for IMSI", identity, identity_len); if (eap_sim_db_send(data, msg, len) < 0) return EAP_SIM_DB_FAILURE; entry = wpa_zalloc(sizeof(*entry)); if (entry == NULL) return EAP_SIM_DB_FAILURE; os_get_time(&entry->timestamp); entry->aka = 1; memcpy(entry->imsi, identity, identity_len); entry->imsi_len = identity_len; entry->cb_session_ctx = cb_session_ctx; entry->state = PENDING; eap_sim_db_add_pending(data, entry); eap_sim_db_expire_pending(data); return EAP_SIM_DB_PENDING; }
static void eap_vendor_test_reset(struct eap_sm *sm, void *priv) { struct eap_vendor_test_data *data = priv; VM_FREE(data); }
/** * eap_sim_db_get_gsm_triplets - Get GSM triplets * @priv: Private data pointer from eap_sim_db_init() * @identity: User name identity * @identity_len: Length of identity in bytes * @max_chal: Maximum number of triplets * @_rand: Buffer for RAND values * @kc: Buffer for Kc values * @sres: Buffer for SRES values * @cb_session_ctx: Session callback context for get_complete_cb() * Returns: Number of triplets received (has to be less than or equal to * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the * callback function registered with eap_sim_db_init() will be called once the * results become available. * * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in * ASCII format. * * When using an external server for GSM triplets, this function can always * start a request and return EAP_SIM_DB_PENDING immediately if authentication * triplets are not available. Once the triplets are received, callback * function registered with eap_sim_db_init() is called to notify EAP state * machine to reprocess the message. This eap_sim_db_get_gsm_triplets() * function will then be called again and the newly received triplets will then * be given to the caller. */ int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity, size_t identity_len, int max_chal, u8 *_rand, u8 *kc, u8 *sres, void *cb_session_ctx) { struct eap_sim_db_data *data = priv; struct eap_sim_db_pending *entry; int len, ret; size_t i; char msg[40]; if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); return EAP_SIM_DB_FAILURE; } identity++; identity_len--; for (i = 0; i < identity_len; i++) { if (identity[i] == '@') { identity_len = i; break; } } if (identity_len + 1 > sizeof(entry->imsi)) { wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity", identity, identity_len); return EAP_SIM_DB_FAILURE; } wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI", identity, identity_len); entry = eap_sim_db_get_pending(data, identity, identity_len, 0); if (entry) { int num_chal; if (entry->state == FAILURE) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " "failure"); VM_FREE(entry); return EAP_SIM_DB_FAILURE; } if (entry->state == PENDING) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " "still pending"); eap_sim_db_add_pending(data, entry); return EAP_SIM_DB_PENDING; } wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> " "%d challenges", entry->u.sim.num_chal); num_chal = entry->u.sim.num_chal; if (num_chal > max_chal) num_chal = max_chal; memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN); memcpy(sres, entry->u.sim.sres, num_chal * EAP_SIM_SRES_LEN); memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN); VM_FREE(entry); return num_chal; } if (data->sock < 0) { if (eap_sim_db_open_socket(data) < 0) return EAP_SIM_DB_FAILURE; } len = snprintf(msg, sizeof(msg), "SIM-REQ-AUTH "); if (len < 0 || len + identity_len >= sizeof(msg)) return EAP_SIM_DB_FAILURE; memcpy(msg + len, identity, identity_len); len += identity_len; ret = snprintf(msg + len, sizeof(msg) - len, " %d", max_chal); if (ret < 0 || (size_t) ret >= sizeof(msg) - len) return EAP_SIM_DB_FAILURE; len += ret; wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication " "data for IMSI", identity, identity_len); if (eap_sim_db_send(data, msg, len) < 0) return EAP_SIM_DB_FAILURE; entry = wpa_zalloc(sizeof(*entry)); if (entry == NULL) return EAP_SIM_DB_FAILURE; os_get_time(&entry->timestamp); memcpy(entry->imsi, identity, identity_len); entry->imsi_len = identity_len; entry->cb_session_ctx = cb_session_ctx; entry->state = PENDING; eap_sim_db_add_pending(data, entry); eap_sim_db_expire_pending(data); return EAP_SIM_DB_PENDING; }
static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data, const char *imsi, char *buf) { char *start, *end; struct eap_sim_db_pending *entry; /* * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> * AKA-RESP-AUTH <IMSI> FAILURE * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string) */ entry = eap_sim_db_get_pending(data, (u8 *) imsi, strlen(imsi), 1); if (entry == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " "received message found"); return; } start = buf; if (strncmp(start, "FAILURE", 7) == 0) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " "failure"); entry->state = FAILURE; eap_sim_db_add_pending(data, entry); data->get_complete_cb(data->ctx, entry->cb_session_ctx); return; } end = strchr(start, ' '); if (end == NULL) goto parse_fail; *end = '\0'; if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN)) goto parse_fail; start = end + 1; end = strchr(start, ' '); if (end == NULL) goto parse_fail; *end = '\0'; if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN)) goto parse_fail; start = end + 1; end = strchr(start, ' '); if (end == NULL) goto parse_fail; *end = '\0'; if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN)) goto parse_fail; start = end + 1; end = strchr(start, ' '); if (end == NULL) goto parse_fail; *end = '\0'; if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN)) goto parse_fail; start = end + 1; end = strchr(start, ' '); if (end) *end = '\0'; else { end = start; while (*end) end++; } entry->u.aka.res_len = (end - start) / 2; if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES"); entry->u.aka.res_len = 0; goto parse_fail; } if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len)) goto parse_fail; entry->state = SUCCESS; wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " "successfully - callback"); eap_sim_db_add_pending(data, entry); data->get_complete_cb(data->ctx, entry->cb_session_ctx); return; parse_fail: wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); VM_FREE(entry); }
static void eap_sim_db_free_reauth(struct eap_sim_reauth *r) { VM_FREE(r->identity); VM_FREE(r->reauth_id); VM_FREE(r); }
static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p) { VM_FREE(p->identity); VM_FREE(p->pseudonym); VM_FREE(p); }
static int radius_server_request(struct radius_server_data *data, struct radius_msg *msg, struct sockaddr *from, socklen_t fromlen, struct radius_client *client, const char *from_addr, int from_port, struct radius_session *force_sess) { u8 *eap = NULL; size_t eap_len; int res, state_included = 0; u8 statebuf[4], resp_id; unsigned int state; struct radius_session *sess; struct radius_msg *reply; struct eap_hdr *hdr; if (force_sess) sess = force_sess; else { res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf, sizeof(statebuf)); state_included = res >= 0; if (res == sizeof(statebuf)) { state = (statebuf[0] << 24) | (statebuf[1] << 16) | (statebuf[2] << 8) | statebuf[3]; sess = radius_server_get_session(client, state); } else { sess = NULL; } } if (sess) { RADIUS_DEBUG("Request for session 0x%x", sess->sess_id); } else if (state_included) { RADIUS_DEBUG("State attribute included but no session found"); radius_server_reject(data, client, msg, from, fromlen, from_addr, from_port); return -1; } else { sess = radius_server_get_new_session(data, client, msg); if (sess == NULL) { RADIUS_DEBUG("Could not create a new session"); radius_server_reject(data, client, msg, from, fromlen, from_addr, from_port); return -1; } } if (sess->last_from_port == from_port && sess->last_identifier == msg->hdr->identifier && os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) == 0) { RADIUS_DEBUG("Duplicate message from %s", from_addr); data->counters.dup_access_requests++; client->counters.dup_access_requests++; if (sess->last_reply) { res = sendto(data->auth_sock, sess->last_reply->buf, sess->last_reply->buf_used, 0, (struct sockaddr *) from, fromlen); if (res < 0) { perror("sendto[RADIUS SRV]"); } return 0; } RADIUS_DEBUG("No previous reply available for duplicate " "message"); return -1; } eap = radius_msg_get_eap(msg, &eap_len); if (eap == NULL) { RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s", from_addr); data->counters.packets_dropped++; client->counters.packets_dropped++; return -1; } RADIUS_DUMP("Received EAP data", eap, eap_len); if (eap_len >= sizeof(*hdr)) { hdr = (struct eap_hdr *) eap; resp_id = hdr->identifier; } else { resp_id = 0; } /* FIX: if Code is Request, Success, or Failure, send Access-Reject; * RFC3579 Sect. 2.6.2. * Include EAP-Response/Nak with no preferred method if * code == request. * If code is not 1-4, discard the packet silently. * Or is this already done by the EAP state machine? */ eap_set_eapRespData(sess->eap, eap, eap_len); VM_FREE(eap); eap = NULL; sess->eapResp = TRUE; eap_sm_step(sess->eap); if (sess->eapReqData) { RADIUS_DUMP("EAP data from the state machine", sess->eapReqData, sess->eapReqDataLen); } else if (sess->eapFail) { RADIUS_DEBUG("No EAP data from the state machine, but eapFail " "set - generate EAP-Failure"); hdr = wpa_zalloc(sizeof(*hdr)); if (hdr) { hdr->identifier = resp_id; hdr->length = htons(sizeof(*hdr)); sess->eapReqData = (u8 *) hdr; sess->eapReqDataLen = sizeof(*hdr); } } else if (eap_sm_method_pending(sess->eap)) { if (sess->last_msg) { radius_msg_free(sess->last_msg); VM_FREE(sess->last_msg); } sess->last_msg = msg; sess->last_from_port = from_port; VM_FREE(sess->last_from_addr); sess->last_from_addr = VM_STRDUP(from_addr); sess->last_fromlen = fromlen; memcpy(&sess->last_from, from, fromlen); return -2; } else { RADIUS_DEBUG("No EAP data from the state machine - ignore this" " Access-Request silently (assuming it was a " "duplicate)"); data->counters.packets_dropped++; client->counters.packets_dropped++; return -1; } reply = radius_server_encapsulate_eap(data, client, sess, msg); VM_FREE(sess->eapReqData); sess->eapReqData = NULL; sess->eapReqDataLen = 0; if (reply) { RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port); if (wpa_debug_level <= MSG_MSGDUMP) { radius_msg_dump(reply); } switch (reply->hdr->code) { case RADIUS_CODE_ACCESS_ACCEPT: data->counters.access_accepts++; client->counters.access_accepts++; break; case RADIUS_CODE_ACCESS_REJECT: data->counters.access_rejects++; client->counters.access_rejects++; break; case RADIUS_CODE_ACCESS_CHALLENGE: data->counters.access_challenges++; client->counters.access_challenges++; break; } res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0, (struct sockaddr *) from, fromlen); if (res < 0) { perror("sendto[RADIUS SRV]"); } if (sess->last_reply) { radius_msg_free(sess->last_reply); VM_FREE(sess->last_reply); } sess->last_reply = reply; sess->last_from_port = from_port; sess->last_identifier = msg->hdr->identifier; os_memcpy(sess->last_authenticator, msg->hdr->authenticator, 16); } else { data->counters.packets_dropped++; client->counters.packets_dropped++; } if (sess->eapSuccess || sess->eapFail) { RADIUS_DEBUG("Removing completed session 0x%x after timeout", sess->sess_id); eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess); eloop_register_timeout(10, 0, radius_server_session_remove_timeout, data, sess); } return 0; }
static int hostapd_prepare_rates(struct hostapd_data *hapd, struct hostapd_hw_modes *mode) { int i, num_basic_rates = 0; int basic_rates_a[] = { 60, 120, 240, -1 }; int basic_rates_b[] = { 10, 20, -1 }; int basic_rates_g[] = { 10, 20, 55, 110, -1 }; int *basic_rates; if (hapd->iconf->basic_rates) basic_rates = hapd->iconf->basic_rates; else switch (mode->mode) { case HOSTAPD_MODE_IEEE80211A: basic_rates = basic_rates_a; break; case HOSTAPD_MODE_IEEE80211B: basic_rates = basic_rates_b; break; case HOSTAPD_MODE_IEEE80211G: basic_rates = basic_rates_g; break; default: return -1; } if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates, basic_rates, mode->mode)) { printf("Failed to update rate sets in kernel module\n"); } VM_FREE(hapd->iface->current_rates); hapd->iface->num_rates = 0; hapd->iface->current_rates = VM_MALLOC(mode->num_rates * sizeof(struct hostapd_rate_data)); if (!hapd->iface->current_rates) { printf("Failed to allocate memory for rate table.\n"); return -1; } for (i = 0; i < mode->num_rates; i++) { struct hostapd_rate_data *rate; if (hapd->iconf->supported_rates && !hostapd_rate_found(hapd->iconf->supported_rates, mode->rates[i].rate)) continue; rate = &hapd->iface->current_rates[hapd->iface->num_rates]; memcpy(rate, &mode->rates[i], sizeof(struct hostapd_rate_data)); if (hostapd_rate_found(basic_rates, rate->rate)) { rate->flags |= HOSTAPD_RATE_BASIC; num_basic_rates++; } else rate->flags &= ~HOSTAPD_RATE_BASIC; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RATE[%d] rate=%d flags=0x%x\n", hapd->iface->num_rates, rate->rate, rate->flags); hapd->iface->num_rates++; } if (hapd->iface->num_rates == 0 || num_basic_rates == 0) { printf("No rates remaining in supported/basic rate sets " "(%d,%d).\n", hapd->iface->num_rates, num_basic_rates); return -1; } return 0; }
static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data, const char *imsi, char *buf) { char *start, *end, *pos; struct eap_sim_db_pending *entry; int num_chal; /* * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ... * SIM-RESP-AUTH <IMSI> FAILURE * (IMSI = ASCII string, Kc/SRES/RAND = hex string) */ entry = eap_sim_db_get_pending(data, (u8 *) imsi, strlen(imsi), 0); if (entry == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the " "received message found"); return; } start = buf; if (strncmp(start, "FAILURE", 7) == 0) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported " "failure"); entry->state = FAILURE; eap_sim_db_add_pending(data, entry); data->get_complete_cb(data->ctx, entry->cb_session_ctx); return; } num_chal = 0; while (num_chal < EAP_SIM_MAX_CHAL) { end = strchr(start, ' '); if (end) *end = '\0'; pos = strchr(start, ':'); if (pos == NULL) goto parse_fail; *pos = '\0'; if (hexstr2bin(start, entry->u.sim.kc[num_chal], EAP_SIM_KC_LEN)) goto parse_fail; start = pos + 1; pos = strchr(start, ':'); if (pos == NULL) goto parse_fail; *pos = '\0'; if (hexstr2bin(start, entry->u.sim.sres[num_chal], EAP_SIM_SRES_LEN)) goto parse_fail; start = pos + 1; if (hexstr2bin(start, entry->u.sim.rand[num_chal], GSM_RAND_LEN)) goto parse_fail; num_chal++; if (end == NULL) break; else start = end + 1; } entry->u.sim.num_chal = num_chal; entry->state = SUCCESS; wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed " "successfully - callback"); eap_sim_db_add_pending(data, entry); data->get_complete_cb(data->ctx, entry->cb_session_ctx); return; parse_fail: wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string"); VM_FREE(entry); }