?? eap_sim_db.c
字號:
* @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); os_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; os_free(prev_pending); } os_free(data);}static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg, size_t len){ int _errno = 0; if (send(data->sock, msg, len, 0) < 0) { _errno = errno; perror("send[EAP-SIM DB UNIX]"); } if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || _errno == ECONNREFUSED) { /* Try to reconnect */ eap_sim_db_close_socket(data); if (eap_sim_db_open_socket(data) < 0) return -1; wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the " "external server"); if (send(data->sock, msg, len, 0) < 0) { perror("send[EAP-SIM DB UNIX]"); return -1; } } return 0;}static void eap_sim_db_expire_pending(struct eap_sim_db_data *data){ /* TODO: add limit for maximum length for pending list; remove latest * (i.e., last) entry from the list if the limit is reached; could also * use timeout to expire pending entries */}/** * 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"); os_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; os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN); os_memcpy(sres, entry->u.sim.sres, num_chal * EAP_SIM_SRES_LEN); os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN); os_free(entry); return num_chal; } if (data->sock < 0) { if (eap_sim_db_open_socket(data) < 0) return EAP_SIM_DB_FAILURE; } len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH "); if (len < 0 || len + identity_len >= sizeof(msg)) return EAP_SIM_DB_FAILURE; os_memcpy(msg + len, identity, identity_len); len += identity_len; ret = os_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 = os_zalloc(sizeof(*entry)); if (entry == NULL) return EAP_SIM_DB_FAILURE; os_get_time(&entry->timestamp); os_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 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 = os_malloc(len + 1); if (pseudonym == NULL) return NULL; os_memcpy(pseudonym, identity, len); pseudonym[len] = '\0'; p = data->pseudonyms; while (p) { if (os_strcmp(p->pseudonym, pseudonym) == 0) break; p = p->next; } os_free(pseudonym); return p;}static struct eap_sim_pseudonym *eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity, size_t identity_len){ struct eap_sim_pseudonym *p; if (identity_len == 0 || (identity[0] != EAP_SIM_PERMANENT_PREFIX && identity[0] != EAP_AKA_PERMANENT_PREFIX)) return NULL; p = data->pseudonyms; while (p) { if (identity_len == p->identity_len && os_memcmp(p->identity, identity, identity_len) == 0) break; p = p->next; } 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 = os_malloc(len + 1); if (reauth_id == NULL) return NULL; os_memcpy(reauth_id, identity, len); reauth_id[len] = '\0'; r = data->reauths; while (r) { if (os_strcmp(r->reauth_id, reauth_id) == 0) break; r = r->next; } os_free(reauth_id); return r;}static struct eap_sim_reauth *eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity, size_t identity_len){ struct eap_sim_pseudonym *p; struct eap_sim_reauth *r; if (identity_len == 0) return NULL; 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) { identity = p->identity; identity_len = p->identity_len; } r = data->reauths; while (r) { if (identity_len == r->identity_len && os_memcmp(r->identity, identity, identity_len) == 0) break; r = r->next; } return r;}/** * eap_sim_db_identity_known - Verify whether the given identity is known * @priv: Private data pointer from eap_sim_db_init() * @identity: User name identity * @identity_len: Length of identity in bytes * Returns: 0 if the user is found or -1 on failure * * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id. */int eap_sim_db_identity_known(void *priv, const u8 *identity, size_t identity_len){ struct eap_sim_db_data *data = priv; if (identity == NULL || identity_len < 2) return -1; if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX || identity[0] == EAP_AKA_PSEUDONYM_PREFIX) { struct eap_sim_pseudonym *p = eap_sim_db_get_pseudonym(data, identity, identity_len); return p ? 0 : -1; } if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX || identity[0] == EAP_AKA_REAUTH_ID_PREFIX) { struct eap_sim_reauth *r = eap_sim_db_get_reauth(data, identity, identity_len); return r ? 0 : -1; } if (identity[0] != EAP_SIM_PERMANENT_PREFIX && identity[0] != EAP_AKA_PERMANENT_PREFIX) { /* Unknown identity prefix */ return -1; } /* TODO: Should consider asking HLR/AuC gateway whether this permanent * identity is known. If it is, EAP-SIM/AKA can skip identity request. * In case of EAP-AKA, this would reduce number of needed round-trips. * Ideally, this would be done with one wait, i.e., just request * authentication data and store it for the next use. This would then * need to use similar pending-request functionality as the normal * request for authentication data at later phase. */ return -1;}static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix){ char *id, *pos, *end; u8 buf[10]; if (os_get_random(buf, sizeof(buf))) return NULL; id = os_malloc(sizeof(buf) * 2 + 2); if (id == NULL) return NULL; pos = id; end = id + sizeof(buf) * 2 + 2; *pos++ = prefix; pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf)); return id;}/** * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym * @priv: Private data pointer from eap_sim_db_init() * @aka: Using EAP-AKA instead of EAP-SIM * Returns: Next pseudonym (allocated string) or %NULL on failure * * This function is used to generate a pseudonym for EAP-SIM. The returned * pseudonym is not added to database at this point; it will need to be added * with eap_sim_db_add_pseudonym() once the authentication has been completed * successfully. Caller is responsible for freeing the returned buffer. */char * eap_sim_db_get_next_pseudonym(void *priv, int aka){ struct eap_sim_db_data *data = priv; return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX : EAP_SIM_PSEUDONYM_PREFIX);}/** * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id * @priv: Private data pointer from eap_sim_db_init() * @aka: Using EAP-AKA instead of EAP-SIM * Returns: Next reauth_id (allocated string) or %NULL on failure * * This function is used to generate a fast re-authentication identity for * EAP-SIM. The returned reauth_id is not added to database at this point; it * will need to be added with eap_sim_db_add_reauth() once the authentication * has been completed successfully. Caller is responsible for freeing the * returned buffer. */char * eap_sim_db_get_next_reauth_id(void *priv, int aka){ struct eap_sim_db_data *data = priv; return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX : EAP_SIM_REAUTH_ID_PREFIX);}/** * 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,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -