?? eap_sim_db.c
字號:
/* * hostapd / EAP-SIM database/authenticator gateway * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. * * This is an example implementation of the EAP-SIM/AKA database/authentication * gateway interface that is using an external program as an SS7 gateway to * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example * implementation of such a gateway program. This eap_sim_db.c takes care of * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different * gateway implementations for HLR/AuC access. Alternatively, it can also be * completely replaced if the in-memory database of pseudonyms/re-auth * identities is not suitable for some cases. */#include "includes.h"#include <sys/un.h>#include "common.h"#include "eap_common/eap_sim_common.h"#include "eap_server/eap_sim_db.h"#include "eloop.h"struct eap_sim_pseudonym { struct eap_sim_pseudonym *next; u8 *identity; size_t identity_len; char *pseudonym;};struct eap_sim_db_pending { struct eap_sim_db_pending *next; u8 imsi[20]; size_t imsi_len; enum { PENDING, SUCCESS, FAILURE } state; void *cb_session_ctx; struct os_time timestamp; int aka; union { struct { u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN]; u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN]; u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN]; int num_chal; } sim; struct { u8 rand[EAP_AKA_RAND_LEN]; u8 autn[EAP_AKA_AUTN_LEN]; u8 ik[EAP_AKA_IK_LEN]; u8 ck[EAP_AKA_CK_LEN]; u8 res[EAP_AKA_RES_MAX_LEN]; size_t res_len; } aka; } u;};struct eap_sim_db_data { int sock; char *fname; char *local_sock; void (*get_complete_cb)(void *ctx, void *session_ctx); void *ctx; struct eap_sim_pseudonym *pseudonyms; struct eap_sim_reauth *reauths; struct eap_sim_db_pending *pending;};static struct eap_sim_db_pending *eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi, size_t imsi_len, int aka){ struct eap_sim_db_pending *entry, *prev = NULL; entry = data->pending; while (entry) { if (entry->aka == aka && entry->imsi_len == imsi_len && os_memcmp(entry->imsi, imsi, imsi_len) == 0) { if (prev) prev->next = entry->next; else data->pending = entry->next; break; } prev = entry; entry = entry->next; } return entry;}static void eap_sim_db_add_pending(struct eap_sim_db_data *data, struct eap_sim_db_pending *entry){ entry->next = data->pending; data->pending = entry;}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, os_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 (os_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 = os_strchr(start, ' '); if (end) *end = '\0'; pos = os_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 = os_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"); os_free(entry);}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, os_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 (os_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 = os_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 = os_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 = os_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 = os_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 = os_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"); os_free(entry);}static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx){ struct eap_sim_db_data *data = eloop_ctx; char buf[1000], *pos, *cmd, *imsi; int res; res = recv(sock, buf, sizeof(buf), 0); if (res < 0) return; wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an " "external source", (u8 *) buf, res); if (res == 0) return; if (res >= (int) sizeof(buf)) res = sizeof(buf) - 1; buf[res] = '\0'; if (data->get_complete_cb == NULL) { wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb " "registered"); return; } /* <cmd> <IMSI> ... */ cmd = buf; pos = os_strchr(cmd, ' '); if (pos == NULL) goto parse_fail; *pos = '\0'; imsi = pos + 1; pos = os_strchr(imsi, ' '); if (pos == NULL) goto parse_fail; *pos = '\0'; wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s", cmd, imsi); if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0) eap_sim_db_sim_resp_auth(data, imsi, pos + 1); else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0) eap_sim_db_aka_resp_auth(data, imsi, pos + 1); else wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response " "'%s'", cmd); return;parse_fail: wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");}static int eap_sim_db_open_socket(struct eap_sim_db_data *data){ struct sockaddr_un addr; static int counter = 0; if (os_strncmp(data->fname, "unix:", 5) != 0) return -1; data->sock = socket(PF_UNIX, SOCK_DGRAM, 0); if (data->sock < 0) { perror("socket(eap_sim_db)"); return -1; } os_memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; os_snprintf(addr.sun_path, sizeof(addr.sun_path), "/tmp/eap_sim_db_%d-%d", getpid(), counter++); data->local_sock = os_strdup(addr.sun_path); if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind(eap_sim_db)"); close(data->sock); data->sock = -1; return -1; } os_memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path)); if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("connect(eap_sim_db)"); wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket", (u8 *) addr.sun_path, os_strlen(addr.sun_path)); close(data->sock); data->sock = -1; return -1; } eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL); 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); os_free(data->local_sock); data->local_sock = NULL; }}/** * 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 = os_zalloc(sizeof(*data)); if (data == NULL) return NULL; data->sock = -1; data->get_complete_cb = get_complete_cb; data->ctx = ctx; data->fname = os_strdup(config); if (data->fname == NULL) goto fail; if (os_strncmp(data->fname, "unix:", 5) == 0) { if (eap_sim_db_open_socket(data)) goto fail; } return data;fail: eap_sim_db_close_socket(data); os_free(data->fname); os_free(data); return NULL;}static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p){ os_free(p->identity); os_free(p->pseudonym); os_free(p);}static void eap_sim_db_free_reauth(struct eap_sim_reauth *r){ os_free(r->identity); os_free(r->reauth_id); os_free(r);}/** * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -