LCOV - code coverage report
Current view: top level - src/eap_server - eap_sim_db.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 552 715 77.2 %
Date: 2016-10-02 Functions: 41 43 95.3 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP-SIM database/authenticator gateway
       3             :  * Copyright (c) 2005-2010, 2012, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  *
       8             :  * This is an example implementation of the EAP-SIM/AKA database/authentication
       9             :  * gateway interface that is using an external program as an SS7 gateway to
      10             :  * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
      11             :  * implementation of such a gateway program. This eap_sim_db.c takes care of
      12             :  * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
      13             :  * gateway implementations for HLR/AuC access. Alternatively, it can also be
      14             :  * completely replaced if the in-memory database of pseudonyms/re-auth
      15             :  * identities is not suitable for some cases.
      16             :  */
      17             : 
      18             : #include "includes.h"
      19             : #include <sys/un.h>
      20             : #ifdef CONFIG_SQLITE
      21             : #include <sqlite3.h>
      22             : #endif /* CONFIG_SQLITE */
      23             : 
      24             : #include "common.h"
      25             : #include "crypto/random.h"
      26             : #include "eap_common/eap_sim_common.h"
      27             : #include "eap_server/eap_sim_db.h"
      28             : #include "eloop.h"
      29             : 
      30             : struct eap_sim_pseudonym {
      31             :         struct eap_sim_pseudonym *next;
      32             :         char *permanent; /* permanent username */
      33             :         char *pseudonym; /* pseudonym username */
      34             : };
      35             : 
      36             : struct eap_sim_db_pending {
      37             :         struct eap_sim_db_pending *next;
      38             :         char imsi[20];
      39             :         enum { PENDING, SUCCESS, FAILURE } state;
      40             :         void *cb_session_ctx;
      41             :         int aka;
      42             :         union {
      43             :                 struct {
      44             :                         u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
      45             :                         u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
      46             :                         u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
      47             :                         int num_chal;
      48             :                 } sim;
      49             :                 struct {
      50             :                         u8 rand[EAP_AKA_RAND_LEN];
      51             :                         u8 autn[EAP_AKA_AUTN_LEN];
      52             :                         u8 ik[EAP_AKA_IK_LEN];
      53             :                         u8 ck[EAP_AKA_CK_LEN];
      54             :                         u8 res[EAP_AKA_RES_MAX_LEN];
      55             :                         size_t res_len;
      56             :                 } aka;
      57             :         } u;
      58             : };
      59             : 
      60             : struct eap_sim_db_data {
      61             :         int sock;
      62             :         char *fname;
      63             :         char *local_sock;
      64             :         void (*get_complete_cb)(void *ctx, void *session_ctx);
      65             :         void *ctx;
      66             :         struct eap_sim_pseudonym *pseudonyms;
      67             :         struct eap_sim_reauth *reauths;
      68             :         struct eap_sim_db_pending *pending;
      69             :         unsigned int eap_sim_db_timeout;
      70             : #ifdef CONFIG_SQLITE
      71             :         sqlite3 *sqlite_db;
      72             :         char db_tmp_identity[100];
      73             :         char db_tmp_pseudonym_str[100];
      74             :         struct eap_sim_pseudonym db_tmp_pseudonym;
      75             :         struct eap_sim_reauth db_tmp_reauth;
      76             : #endif /* CONFIG_SQLITE */
      77             : };
      78             : 
      79             : 
      80             : static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx);
      81             : static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx);
      82             : 
      83             : 
      84             : #ifdef CONFIG_SQLITE
      85             : 
      86          12 : static int db_table_exists(sqlite3 *db, const char *name)
      87             : {
      88             :         char cmd[128];
      89          12 :         os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
      90          12 :         return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
      91             : }
      92             : 
      93             : 
      94           6 : static int db_table_create_pseudonym(sqlite3 *db)
      95             : {
      96           6 :         char *err = NULL;
      97           6 :         const char *sql =
      98             :                 "CREATE TABLE pseudonyms("
      99             :                 "  permanent CHAR(21) PRIMARY KEY,"
     100             :                 "  pseudonym CHAR(21) NOT NULL"
     101             :                 ");";
     102             : 
     103           6 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
     104             :                    "pseudonym information");
     105           6 :         if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
     106           0 :                 wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
     107           0 :                 sqlite3_free(err);
     108           0 :                 return -1;
     109             :         }
     110             : 
     111           6 :         return 0;
     112             : }
     113             : 
     114             : 
     115           6 : static int db_table_create_reauth(sqlite3 *db)
     116             : {
     117           6 :         char *err = NULL;
     118           6 :         const char *sql =
     119             :                 "CREATE TABLE reauth("
     120             :                 "  permanent CHAR(21) PRIMARY KEY,"
     121             :                 "  reauth_id CHAR(21) NOT NULL,"
     122             :                 "  counter INTEGER,"
     123             :                 "  mk CHAR(40),"
     124             :                 "  k_encr CHAR(32),"
     125             :                 "  k_aut CHAR(64),"
     126             :                 "  k_re CHAR(64)"
     127             :                 ");";
     128             : 
     129           6 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
     130             :                    "reauth information");
     131           6 :         if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
     132           0 :                 wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
     133           0 :                 sqlite3_free(err);
     134           0 :                 return -1;
     135             :         }
     136             : 
     137           6 :         return 0;
     138             : }
     139             : 
     140             : 
     141           6 : static sqlite3 * db_open(const char *db_file)
     142             : {
     143             :         sqlite3 *db;
     144             : 
     145           6 :         if (sqlite3_open(db_file, &db)) {
     146           0 :                 wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
     147             :                            "%s: %s", db_file, sqlite3_errmsg(db));
     148           0 :                 sqlite3_close(db);
     149           0 :                 return NULL;
     150             :         }
     151             : 
     152          12 :         if (!db_table_exists(db, "pseudonyms") &&
     153           6 :             db_table_create_pseudonym(db) < 0) {
     154           0 :                 sqlite3_close(db);
     155           0 :                 return NULL;
     156             :         }
     157             : 
     158          12 :         if (!db_table_exists(db, "reauth") &&
     159           6 :             db_table_create_reauth(db) < 0) {
     160           0 :                 sqlite3_close(db);
     161           0 :                 return NULL;
     162             :         }
     163             : 
     164           6 :         return db;
     165             : }
     166             : 
     167             : 
     168         121 : static int valid_db_string(const char *str)
     169             : {
     170         121 :         const char *pos = str;
     171        2558 :         while (*pos) {
     172        2907 :                 if ((*pos < '0' || *pos > '9') &&
     173        1182 :                     (*pos < 'a' || *pos > 'f'))
     174           0 :                         return 0;
     175        2316 :                 pos++;
     176             :         }
     177         121 :         return 1;
     178             : }
     179             : 
     180             : 
     181          18 : static int db_add_pseudonym(struct eap_sim_db_data *data,
     182             :                             const char *permanent, char *pseudonym)
     183             : {
     184             :         char cmd[128];
     185          18 :         char *err = NULL;
     186             : 
     187          18 :         if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
     188           0 :                 os_free(pseudonym);
     189           0 :                 return -1;
     190             :         }
     191             : 
     192          18 :         os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
     193             :                     "(permanent, pseudonym) VALUES ('%s', '%s');",
     194             :                     permanent, pseudonym);
     195          18 :         os_free(pseudonym);
     196          18 :         if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
     197             :         {
     198           0 :                 wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
     199           0 :                 sqlite3_free(err);
     200           0 :                 return -1;
     201             :         }
     202             : 
     203          18 :         return 0;
     204             : }
     205             : 
     206             : 
     207           6 : static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
     208             : {
     209           6 :         struct eap_sim_db_data *data = ctx;
     210             :         int i;
     211             : 
     212          12 :         for (i = 0; i < argc; i++) {
     213           6 :                 if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
     214           6 :                         os_strlcpy(data->db_tmp_identity, argv[i],
     215             :                                    sizeof(data->db_tmp_identity));
     216             :                 }
     217             :         }
     218             : 
     219           6 :         return 0;
     220             : }
     221             : 
     222             : 
     223             : static char *
     224           9 : db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
     225             : {
     226             :         char cmd[128];
     227             : 
     228           9 :         if (!valid_db_string(pseudonym))
     229           0 :                 return NULL;
     230           9 :         os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
     231           9 :         os_snprintf(cmd, sizeof(cmd),
     232             :                     "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
     233             :                     pseudonym);
     234           9 :         if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
     235             :             SQLITE_OK)
     236           0 :                 return NULL;
     237           9 :         if (data->db_tmp_identity[0] == '\0')
     238           3 :                 return NULL;
     239           6 :         return data->db_tmp_identity;
     240             : }
     241             : 
     242             : 
     243          24 : static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
     244             :                          char *reauth_id, u16 counter, const u8 *mk,
     245             :                          const u8 *k_encr, const u8 *k_aut, const u8 *k_re)
     246             : {
     247             :         char cmd[2000], *pos, *end;
     248          24 :         char *err = NULL;
     249             : 
     250          24 :         if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
     251           0 :                 os_free(reauth_id);
     252           0 :                 return -1;
     253             :         }
     254             : 
     255          24 :         pos = cmd;
     256          24 :         end = pos + sizeof(cmd);
     257          24 :         pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth "
     258             :                            "(permanent, reauth_id, counter%s%s%s%s) "
     259             :                            "VALUES ('%s', '%s', %u",
     260             :                            mk ? ", mk" : "",
     261             :                            k_encr ? ", k_encr" : "",
     262             :                            k_aut ? ", k_aut" : "",
     263             :                            k_re ? ", k_re" : "",
     264             :                            permanent, reauth_id, counter);
     265          24 :         os_free(reauth_id);
     266             : 
     267          24 :         if (mk) {
     268          16 :                 pos += os_snprintf(pos, end - pos, ", '");
     269          16 :                 pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN);
     270          16 :                 pos += os_snprintf(pos, end - pos, "'");
     271             :         }
     272             : 
     273          24 :         if (k_encr) {
     274           8 :                 pos += os_snprintf(pos, end - pos, ", '");
     275           8 :                 pos += wpa_snprintf_hex(pos, end - pos, k_encr,
     276             :                                         EAP_SIM_K_ENCR_LEN);
     277           8 :                 pos += os_snprintf(pos, end - pos, "'");
     278             :         }
     279             : 
     280          24 :         if (k_aut) {
     281           8 :                 pos += os_snprintf(pos, end - pos, ", '");
     282           8 :                 pos += wpa_snprintf_hex(pos, end - pos, k_aut,
     283             :                                         EAP_AKA_PRIME_K_AUT_LEN);
     284           8 :                 pos += os_snprintf(pos, end - pos, "'");
     285             :         }
     286             : 
     287          24 :         if (k_re) {
     288           8 :                 pos += os_snprintf(pos, end - pos, ", '");
     289           8 :                 pos += wpa_snprintf_hex(pos, end - pos, k_re,
     290             :                                         EAP_AKA_PRIME_K_RE_LEN);
     291           8 :                 pos += os_snprintf(pos, end - pos, "'");
     292             :         }
     293             : 
     294          24 :         os_snprintf(pos, end - pos, ");");
     295             : 
     296          24 :         if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
     297             :         {
     298           0 :                 wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
     299           0 :                 sqlite3_free(err);
     300           0 :                 return -1;
     301             :         }
     302             : 
     303          24 :         return 0;
     304             : }
     305             : 
     306             : 
     307          15 : static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[])
     308             : {
     309          15 :         struct eap_sim_db_data *data = ctx;
     310             :         int i;
     311          15 :         struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
     312             : 
     313         120 :         for (i = 0; i < argc; i++) {
     314         105 :                 if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
     315          15 :                         os_strlcpy(data->db_tmp_identity, argv[i],
     316             :                                    sizeof(data->db_tmp_identity));
     317          15 :                         reauth->permanent = data->db_tmp_identity;
     318          90 :                 } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
     319          15 :                         reauth->counter = atoi(argv[i]);
     320          75 :                 } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) {
     321          10 :                         hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk));
     322          65 :                 } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) {
     323           5 :                         hexstr2bin(argv[i], reauth->k_encr,
     324             :                                    sizeof(reauth->k_encr));
     325          60 :                 } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) {
     326           5 :                         hexstr2bin(argv[i], reauth->k_aut,
     327             :                                    sizeof(reauth->k_aut));
     328          55 :                 } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) {
     329           5 :                         hexstr2bin(argv[i], reauth->k_re,
     330             :                                    sizeof(reauth->k_re));
     331             :                 }
     332             :         }
     333             : 
     334          15 :         return 0;
     335             : }
     336             : 
     337             : 
     338             : static struct eap_sim_reauth *
     339          25 : db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id)
     340             : {
     341             :         char cmd[256];
     342             : 
     343          25 :         if (!valid_db_string(reauth_id))
     344           0 :                 return NULL;
     345          25 :         os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth));
     346          25 :         os_strlcpy(data->db_tmp_pseudonym_str, reauth_id,
     347             :                    sizeof(data->db_tmp_pseudonym_str));
     348          25 :         data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str;
     349          25 :         os_snprintf(cmd, sizeof(cmd),
     350             :                     "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id);
     351          25 :         if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) !=
     352             :             SQLITE_OK)
     353           0 :                 return NULL;
     354          25 :         if (data->db_tmp_reauth.permanent == NULL)
     355          10 :                 return NULL;
     356          15 :         return &data->db_tmp_reauth;
     357             : }
     358             : 
     359             : 
     360           3 : static void db_remove_reauth(struct eap_sim_db_data *data,
     361             :                              struct eap_sim_reauth *reauth)
     362             : {
     363             :         char cmd[256];
     364             : 
     365           3 :         if (!valid_db_string(reauth->permanent))
     366           3 :                 return;
     367           3 :         os_snprintf(cmd, sizeof(cmd),
     368             :                     "DELETE FROM reauth WHERE permanent='%s';",
     369             :                     reauth->permanent);
     370           3 :         sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
     371             : }
     372             : 
     373             : #endif /* CONFIG_SQLITE */
     374             : 
     375             : 
     376             : static struct eap_sim_db_pending *
     377         438 : eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
     378             : {
     379         438 :         struct eap_sim_db_pending *entry, *prev = NULL;
     380             : 
     381         438 :         entry = data->pending;
     382         876 :         while (entry) {
     383         291 :                 if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
     384         291 :                         if (prev)
     385           0 :                                 prev->next = entry->next;
     386             :                         else
     387         291 :                                 data->pending = entry->next;
     388         291 :                         break;
     389             :                 }
     390           0 :                 prev = entry;
     391           0 :                 entry = entry->next;
     392             :         }
     393         438 :         return entry;
     394             : }
     395             : 
     396             : 
     397         291 : static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
     398             :                                    struct eap_sim_db_pending *entry)
     399             : {
     400         291 :         entry->next = data->pending;
     401         291 :         data->pending = entry;
     402         291 : }
     403             : 
     404             : 
     405         146 : static void eap_sim_db_free_pending(struct eap_sim_db_data *data,
     406             :                                     struct eap_sim_db_pending *entry)
     407             : {
     408         146 :         eloop_cancel_timeout(eap_sim_db_query_timeout, data, entry);
     409         146 :         eloop_cancel_timeout(eap_sim_db_del_timeout, data, entry);
     410         146 :         os_free(entry);
     411         146 : }
     412             : 
     413             : 
     414           0 : static void eap_sim_db_del_pending(struct eap_sim_db_data *data,
     415             :                                    struct eap_sim_db_pending *entry)
     416             : {
     417           0 :         struct eap_sim_db_pending **pp = &data->pending;
     418             : 
     419           0 :         while (*pp != NULL) {
     420           0 :                 if (*pp == entry) {
     421           0 :                         *pp = entry->next;
     422           0 :                         eap_sim_db_free_pending(data, entry);
     423           0 :                         return;
     424             :                 }
     425           0 :                 pp = &(*pp)->next;
     426             :         }
     427             : }
     428             : 
     429             : 
     430           0 : static void eap_sim_db_del_timeout(void *eloop_ctx, void *user_ctx)
     431             : {
     432           0 :         struct eap_sim_db_data *data = eloop_ctx;
     433           0 :         struct eap_sim_db_pending *entry = user_ctx;
     434             : 
     435           0 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Delete query timeout for %p", entry);
     436           0 :         eap_sim_db_del_pending(data, entry);
     437           0 : }
     438             : 
     439             : 
     440           1 : static void eap_sim_db_query_timeout(void *eloop_ctx, void *user_ctx)
     441             : {
     442           1 :         struct eap_sim_db_data *data = eloop_ctx;
     443           1 :         struct eap_sim_db_pending *entry = user_ctx;
     444             : 
     445             :         /*
     446             :          * Report failure and allow some time for EAP server to process it
     447             :          * before deleting the query.
     448             :          */
     449           1 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Query timeout for %p", entry);
     450           1 :         entry->state = FAILURE;
     451           1 :         data->get_complete_cb(data->ctx, entry->cb_session_ctx);
     452           1 :         eloop_register_timeout(1, 0, eap_sim_db_del_timeout, data, entry);
     453           1 : }
     454             : 
     455             : 
     456          76 : static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
     457             :                                      const char *imsi, char *buf)
     458             : {
     459             :         char *start, *end, *pos;
     460             :         struct eap_sim_db_pending *entry;
     461             :         int num_chal;
     462             : 
     463             :         /*
     464             :          * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
     465             :          * SIM-RESP-AUTH <IMSI> FAILURE
     466             :          * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
     467             :          */
     468             : 
     469          76 :         entry = eap_sim_db_get_pending(data, imsi, 0);
     470          76 :         if (entry == NULL) {
     471           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
     472             :                            "received message found");
     473           0 :                 return;
     474             :         }
     475             : 
     476          76 :         start = buf;
     477          76 :         if (os_strncmp(start, "FAILURE", 7) == 0) {
     478           1 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
     479             :                            "failure");
     480           1 :                 entry->state = FAILURE;
     481           1 :                 eap_sim_db_add_pending(data, entry);
     482           1 :                 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
     483           1 :                 return;
     484             :         }
     485             : 
     486          75 :         num_chal = 0;
     487         300 :         while (num_chal < EAP_SIM_MAX_CHAL) {
     488         225 :                 end = os_strchr(start, ' ');
     489         225 :                 if (end)
     490         150 :                         *end = '\0';
     491             : 
     492         225 :                 pos = os_strchr(start, ':');
     493         225 :                 if (pos == NULL)
     494           0 :                         goto parse_fail;
     495         225 :                 *pos = '\0';
     496         225 :                 if (hexstr2bin(start, entry->u.sim.kc[num_chal],
     497             :                                EAP_SIM_KC_LEN))
     498           0 :                         goto parse_fail;
     499             : 
     500         225 :                 start = pos + 1;
     501         225 :                 pos = os_strchr(start, ':');
     502         225 :                 if (pos == NULL)
     503           0 :                         goto parse_fail;
     504         225 :                 *pos = '\0';
     505         225 :                 if (hexstr2bin(start, entry->u.sim.sres[num_chal],
     506             :                                EAP_SIM_SRES_LEN))
     507           0 :                         goto parse_fail;
     508             : 
     509         225 :                 start = pos + 1;
     510         225 :                 if (hexstr2bin(start, entry->u.sim.rand[num_chal],
     511             :                                GSM_RAND_LEN))
     512           0 :                         goto parse_fail;
     513             : 
     514         225 :                 num_chal++;
     515         225 :                 if (end == NULL)
     516          75 :                         break;
     517             :                 else
     518         150 :                         start = end + 1;
     519             :         }
     520          75 :         entry->u.sim.num_chal = num_chal;
     521             : 
     522          75 :         entry->state = SUCCESS;
     523          75 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
     524             :                    "successfully - callback");
     525          75 :         eap_sim_db_add_pending(data, entry);
     526          75 :         data->get_complete_cb(data->ctx, entry->cb_session_ctx);
     527          75 :         return;
     528             : 
     529             : parse_fail:
     530           0 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
     531           0 :         eap_sim_db_free_pending(data, entry);
     532             : }
     533             : 
     534             : 
     535          69 : static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
     536             :                                      const char *imsi, char *buf)
     537             : {
     538             :         char *start, *end;
     539             :         struct eap_sim_db_pending *entry;
     540             : 
     541             :         /*
     542             :          * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
     543             :          * AKA-RESP-AUTH <IMSI> FAILURE
     544             :          * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
     545             :          */
     546             : 
     547          69 :         entry = eap_sim_db_get_pending(data, imsi, 1);
     548          69 :         if (entry == NULL) {
     549           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
     550             :                            "received message found");
     551           0 :                 return;
     552             :         }
     553             : 
     554          69 :         start = buf;
     555          69 :         if (os_strncmp(start, "FAILURE", 7) == 0) {
     556           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
     557             :                            "failure");
     558           0 :                 entry->state = FAILURE;
     559           0 :                 eap_sim_db_add_pending(data, entry);
     560           0 :                 data->get_complete_cb(data->ctx, entry->cb_session_ctx);
     561           0 :                 return;
     562             :         }
     563             : 
     564          69 :         end = os_strchr(start, ' ');
     565          69 :         if (end == NULL)
     566           0 :                 goto parse_fail;
     567          69 :         *end = '\0';
     568          69 :         if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
     569           0 :                 goto parse_fail;
     570             : 
     571          69 :         start = end + 1;
     572          69 :         end = os_strchr(start, ' ');
     573          69 :         if (end == NULL)
     574           0 :                 goto parse_fail;
     575          69 :         *end = '\0';
     576          69 :         if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
     577           0 :                 goto parse_fail;
     578             : 
     579          69 :         start = end + 1;
     580          69 :         end = os_strchr(start, ' ');
     581          69 :         if (end == NULL)
     582           0 :                 goto parse_fail;
     583          69 :         *end = '\0';
     584          69 :         if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
     585           0 :                 goto parse_fail;
     586             : 
     587          69 :         start = end + 1;
     588          69 :         end = os_strchr(start, ' ');
     589          69 :         if (end == NULL)
     590           0 :                 goto parse_fail;
     591          69 :         *end = '\0';
     592          69 :         if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
     593           0 :                 goto parse_fail;
     594             : 
     595          69 :         start = end + 1;
     596          69 :         end = os_strchr(start, ' ');
     597          69 :         if (end)
     598           0 :                 *end = '\0';
     599             :         else {
     600          69 :                 end = start;
     601        1242 :                 while (*end)
     602        1104 :                         end++;
     603             :         }
     604          69 :         entry->u.aka.res_len = (end - start) / 2;
     605          69 :         if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
     606           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
     607           0 :                 entry->u.aka.res_len = 0;
     608           0 :                 goto parse_fail;
     609             :         }
     610          69 :         if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
     611           0 :                 goto parse_fail;
     612             : 
     613          69 :         entry->state = SUCCESS;
     614          69 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
     615             :                    "successfully - callback");
     616          69 :         eap_sim_db_add_pending(data, entry);
     617          69 :         data->get_complete_cb(data->ctx, entry->cb_session_ctx);
     618          69 :         return;
     619             : 
     620             : parse_fail:
     621           0 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
     622           0 :         eap_sim_db_free_pending(data, entry);
     623             : }
     624             : 
     625             : 
     626         150 : static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
     627             : {
     628         150 :         struct eap_sim_db_data *data = eloop_ctx;
     629             :         char buf[1000], *pos, *cmd, *imsi;
     630             :         int res;
     631             : 
     632         150 :         res = recv(sock, buf, sizeof(buf) - 1, 0);
     633         150 :         if (res < 0)
     634         148 :                 return;
     635         150 :         buf[res] = '\0';
     636         150 :         wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
     637             :                               "external source", (u8 *) buf, res);
     638         150 :         if (res == 0)
     639           2 :                 return;
     640             : 
     641         148 :         if (data->get_complete_cb == NULL) {
     642           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
     643             :                            "registered");
     644           0 :                 return;
     645             :         }
     646             : 
     647             :         /* <cmd> <IMSI> ... */
     648             : 
     649         148 :         cmd = buf;
     650         148 :         pos = os_strchr(cmd, ' ');
     651         148 :         if (pos == NULL)
     652           1 :                 goto parse_fail;
     653         147 :         *pos = '\0';
     654         147 :         imsi = pos + 1;
     655         147 :         pos = os_strchr(imsi, ' ');
     656         147 :         if (pos == NULL)
     657           1 :                 goto parse_fail;
     658         146 :         *pos = '\0';
     659         146 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
     660             :                    cmd, imsi);
     661             : 
     662         146 :         if (os_strcmp(cmd, "SIM-RESP-AUTH") == 0)
     663          76 :                 eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
     664          70 :         else if (os_strcmp(cmd, "AKA-RESP-AUTH") == 0)
     665          69 :                 eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
     666             :         else
     667           1 :                 wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
     668             :                            "'%s'", cmd);
     669         146 :         return;
     670             : 
     671             : parse_fail:
     672           2 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
     673             : }
     674             : 
     675             : 
     676          20 : static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
     677             : {
     678             :         struct sockaddr_un addr;
     679             :         static int counter = 0;
     680             : 
     681          20 :         if (os_strncmp(data->fname, "unix:", 5) != 0)
     682           0 :                 return -1;
     683             : 
     684          20 :         data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
     685          20 :         if (data->sock < 0) {
     686           0 :                 wpa_printf(MSG_INFO, "socket(eap_sim_db): %s", strerror(errno));
     687           0 :                 return -1;
     688             :         }
     689             : 
     690          20 :         os_memset(&addr, 0, sizeof(addr));
     691          20 :         addr.sun_family = AF_UNIX;
     692          20 :         os_snprintf(addr.sun_path, sizeof(addr.sun_path),
     693             :                     "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
     694          20 :         os_free(data->local_sock);
     695          20 :         data->local_sock = os_strdup(addr.sun_path);
     696          20 :         if (data->local_sock == NULL) {
     697           0 :                 close(data->sock);
     698           0 :                 data->sock = -1;
     699           0 :                 return -1;
     700             :         }
     701          20 :         if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
     702           0 :                 wpa_printf(MSG_INFO, "bind(eap_sim_db): %s", strerror(errno));
     703           0 :                 close(data->sock);
     704           0 :                 data->sock = -1;
     705           0 :                 return -1;
     706             :         }
     707             : 
     708          20 :         os_memset(&addr, 0, sizeof(addr));
     709          20 :         addr.sun_family = AF_UNIX;
     710          20 :         os_strlcpy(addr.sun_path, data->fname + 5, sizeof(addr.sun_path));
     711          20 :         if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
     712           2 :                 wpa_printf(MSG_INFO, "connect(eap_sim_db): %s",
     713           2 :                            strerror(errno));
     714           2 :                 wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
     715             :                                   (u8 *) addr.sun_path,
     716             :                                   os_strlen(addr.sun_path));
     717           2 :                 close(data->sock);
     718           2 :                 data->sock = -1;
     719           2 :                 unlink(data->local_sock);
     720           2 :                 os_free(data->local_sock);
     721           2 :                 data->local_sock = NULL;
     722           2 :                 return -1;
     723             :         }
     724             : 
     725          18 :         eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
     726             : 
     727          18 :         return 0;
     728             : }
     729             : 
     730             : 
     731          18 : static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
     732             : {
     733          18 :         if (data->sock >= 0) {
     734          18 :                 eloop_unregister_read_sock(data->sock);
     735          18 :                 close(data->sock);
     736          18 :                 data->sock = -1;
     737             :         }
     738          18 :         if (data->local_sock) {
     739          18 :                 unlink(data->local_sock);
     740          18 :                 os_free(data->local_sock);
     741          18 :                 data->local_sock = NULL;
     742             :         }
     743          18 : }
     744             : 
     745             : 
     746             : /**
     747             :  * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
     748             :  * @config: Configuration data (e.g., file name)
     749             :  * @db_timeout: Database lookup timeout
     750             :  * @get_complete_cb: Callback function for reporting availability of triplets
     751             :  * @ctx: Context pointer for get_complete_cb
     752             :  * Returns: Pointer to a private data structure or %NULL on failure
     753             :  */
     754             : struct eap_sim_db_data *
     755          18 : eap_sim_db_init(const char *config, unsigned int db_timeout,
     756             :                 void (*get_complete_cb)(void *ctx, void *session_ctx),
     757             :                 void *ctx)
     758             : {
     759             :         struct eap_sim_db_data *data;
     760             :         char *pos;
     761             : 
     762          18 :         data = os_zalloc(sizeof(*data));
     763          18 :         if (data == NULL)
     764           0 :                 return NULL;
     765             : 
     766          18 :         data->sock = -1;
     767          18 :         data->get_complete_cb = get_complete_cb;
     768          18 :         data->ctx = ctx;
     769          18 :         data->eap_sim_db_timeout = db_timeout;
     770          18 :         data->fname = os_strdup(config);
     771          18 :         if (data->fname == NULL)
     772           0 :                 goto fail;
     773          18 :         pos = os_strstr(data->fname, " db=");
     774          18 :         if (pos) {
     775           6 :                 *pos = '\0';
     776             : #ifdef CONFIG_SQLITE
     777           6 :                 pos += 4;
     778           6 :                 data->sqlite_db = db_open(pos);
     779           6 :                 if (data->sqlite_db == NULL)
     780           0 :                         goto fail;
     781             : #endif /* CONFIG_SQLITE */
     782             :         }
     783             : 
     784          18 :         if (os_strncmp(data->fname, "unix:", 5) == 0) {
     785          18 :                 if (eap_sim_db_open_socket(data)) {
     786           1 :                         wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
     787             :                                    "connection not available - will retry "
     788             :                                    "later");
     789             :                 }
     790             :         }
     791             : 
     792          18 :         return data;
     793             : 
     794             : fail:
     795           0 :         eap_sim_db_close_socket(data);
     796           0 :         os_free(data->fname);
     797           0 :         os_free(data);
     798           0 :         return NULL;
     799             : }
     800             : 
     801             : 
     802          28 : static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
     803             : {
     804          28 :         os_free(p->permanent);
     805          28 :         os_free(p->pseudonym);
     806          28 :         os_free(p);
     807          28 : }
     808             : 
     809             : 
     810          28 : static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
     811             : {
     812          28 :         os_free(r->permanent);
     813          28 :         os_free(r->reauth_id);
     814          28 :         os_free(r);
     815          28 : }
     816             : 
     817             : 
     818             : /**
     819             :  * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
     820             :  * @priv: Private data pointer from eap_sim_db_init()
     821             :  */
     822          18 : void eap_sim_db_deinit(void *priv)
     823             : {
     824          18 :         struct eap_sim_db_data *data = priv;
     825             :         struct eap_sim_pseudonym *p, *prev;
     826             :         struct eap_sim_reauth *r, *prevr;
     827             :         struct eap_sim_db_pending *pending, *prev_pending;
     828             : 
     829             : #ifdef CONFIG_SQLITE
     830          18 :         if (data->sqlite_db) {
     831           6 :                 sqlite3_close(data->sqlite_db);
     832           6 :                 data->sqlite_db = NULL;
     833             :         }
     834             : #endif /* CONFIG_SQLITE */
     835             : 
     836          18 :         eap_sim_db_close_socket(data);
     837          18 :         os_free(data->fname);
     838             : 
     839          18 :         p = data->pseudonyms;
     840          64 :         while (p) {
     841          28 :                 prev = p;
     842          28 :                 p = p->next;
     843          28 :                 eap_sim_db_free_pseudonym(prev);
     844             :         }
     845             : 
     846          18 :         r = data->reauths;
     847          64 :         while (r) {
     848          28 :                 prevr = r;
     849          28 :                 r = r->next;
     850          28 :                 eap_sim_db_free_reauth(prevr);
     851             :         }
     852             : 
     853          18 :         pending = data->pending;
     854          36 :         while (pending) {
     855           0 :                 prev_pending = pending;
     856           0 :                 pending = pending->next;
     857           0 :                 eap_sim_db_free_pending(data, prev_pending);
     858             :         }
     859             : 
     860          18 :         os_free(data);
     861          18 : }
     862             : 
     863             : 
     864         151 : static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
     865             :                            size_t len)
     866             : {
     867         151 :         int _errno = 0;
     868             : 
     869         151 :         if (send(data->sock, msg, len, 0) < 0) {
     870           0 :                 _errno = errno;
     871           0 :                 wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
     872           0 :                            strerror(errno));
     873             :         }
     874             : 
     875         151 :         if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
     876             :             _errno == ECONNREFUSED) {
     877             :                 /* Try to reconnect */
     878           0 :                 eap_sim_db_close_socket(data);
     879           0 :                 if (eap_sim_db_open_socket(data) < 0)
     880           0 :                         return -1;
     881           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
     882             :                            "external server");
     883           0 :                 if (send(data->sock, msg, len, 0) < 0) {
     884           0 :                         wpa_printf(MSG_INFO, "send[EAP-SIM DB UNIX]: %s",
     885           0 :                                    strerror(errno));
     886           0 :                         return -1;
     887             :                 }
     888             :         }
     889             : 
     890         151 :         return 0;
     891             : }
     892             : 
     893             : 
     894         146 : static void eap_sim_db_expire_pending(struct eap_sim_db_data *data,
     895             :                                       struct eap_sim_db_pending *entry)
     896             : {
     897         146 :         eloop_register_timeout(data->eap_sim_db_timeout, 0,
     898             :                                eap_sim_db_query_timeout, data, entry);
     899         146 : }
     900             : 
     901             : 
     902             : /**
     903             :  * eap_sim_db_get_gsm_triplets - Get GSM triplets
     904             :  * @data: Private data pointer from eap_sim_db_init()
     905             :  * @username: Permanent username (prefix | IMSI)
     906             :  * @max_chal: Maximum number of triplets
     907             :  * @_rand: Buffer for RAND values
     908             :  * @kc: Buffer for Kc values
     909             :  * @sres: Buffer for SRES values
     910             :  * @cb_session_ctx: Session callback context for get_complete_cb()
     911             :  * Returns: Number of triplets received (has to be less than or equal to
     912             :  * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
     913             :  * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
     914             :  * callback function registered with eap_sim_db_init() will be called once the
     915             :  * results become available.
     916             :  *
     917             :  * When using an external server for GSM triplets, this function can always
     918             :  * start a request and return EAP_SIM_DB_PENDING immediately if authentication
     919             :  * triplets are not available. Once the triplets are received, callback
     920             :  * function registered with eap_sim_db_init() is called to notify EAP state
     921             :  * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
     922             :  * function will then be called again and the newly received triplets will then
     923             :  * be given to the caller.
     924             :  */
     925         155 : int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
     926             :                                 const char *username, int max_chal,
     927             :                                 u8 *_rand, u8 *kc, u8 *sres,
     928             :                                 void *cb_session_ctx)
     929             : {
     930             :         struct eap_sim_db_pending *entry;
     931             :         int len, ret;
     932             :         char msg[40];
     933             :         const char *imsi;
     934             :         size_t imsi_len;
     935             : 
     936         310 :         if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
     937         310 :             username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
     938           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
     939             :                            username);
     940           0 :                 return EAP_SIM_DB_FAILURE;
     941             :         }
     942         155 :         imsi = username + 1;
     943         155 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
     944             :                    imsi);
     945             : 
     946         155 :         entry = eap_sim_db_get_pending(data, imsi, 0);
     947         155 :         if (entry) {
     948             :                 int num_chal;
     949          77 :                 if (entry->state == FAILURE) {
     950           2 :                         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
     951             :                                    "failure");
     952           2 :                         eap_sim_db_free_pending(data, entry);
     953           2 :                         return EAP_SIM_DB_FAILURE;
     954             :                 }
     955             : 
     956          75 :                 if (entry->state == PENDING) {
     957           0 :                         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
     958             :                                    "still pending");
     959           0 :                         eap_sim_db_add_pending(data, entry);
     960           0 :                         return EAP_SIM_DB_PENDING;
     961             :                 }
     962             : 
     963          75 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
     964             :                            "%d challenges", entry->u.sim.num_chal);
     965          75 :                 num_chal = entry->u.sim.num_chal;
     966          75 :                 if (num_chal > max_chal)
     967           0 :                         num_chal = max_chal;
     968          75 :                 os_memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
     969          75 :                 os_memcpy(sres, entry->u.sim.sres,
     970             :                           num_chal * EAP_SIM_SRES_LEN);
     971          75 :                 os_memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
     972          75 :                 eap_sim_db_free_pending(data, entry);
     973          75 :                 return num_chal;
     974             :         }
     975             : 
     976          78 :         if (data->sock < 0) {
     977           2 :                 if (eap_sim_db_open_socket(data) < 0)
     978           1 :                         return EAP_SIM_DB_FAILURE;
     979             :         }
     980             : 
     981          77 :         imsi_len = os_strlen(imsi);
     982          77 :         len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
     983         154 :         if (os_snprintf_error(sizeof(msg), len) ||
     984          77 :             len + imsi_len >= sizeof(msg))
     985           0 :                 return EAP_SIM_DB_FAILURE;
     986          77 :         os_memcpy(msg + len, imsi, imsi_len);
     987          77 :         len += imsi_len;
     988          77 :         ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
     989          77 :         if (os_snprintf_error(sizeof(msg) - len, ret))
     990           0 :                 return EAP_SIM_DB_FAILURE;
     991          77 :         len += ret;
     992             : 
     993          77 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
     994             :                    "data for IMSI '%s'", imsi);
     995          77 :         if (eap_sim_db_send(data, msg, len) < 0)
     996           0 :                 return EAP_SIM_DB_FAILURE;
     997             : 
     998          77 :         entry = os_zalloc(sizeof(*entry));
     999          77 :         if (entry == NULL)
    1000           0 :                 return EAP_SIM_DB_FAILURE;
    1001             : 
    1002          77 :         os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
    1003          77 :         entry->cb_session_ctx = cb_session_ctx;
    1004          77 :         entry->state = PENDING;
    1005          77 :         eap_sim_db_add_pending(data, entry);
    1006          77 :         eap_sim_db_expire_pending(data, entry);
    1007          77 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
    1008             : 
    1009          77 :         return EAP_SIM_DB_PENDING;
    1010             : }
    1011             : 
    1012             : 
    1013         319 : static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
    1014             : {
    1015             :         char *id, *pos, *end;
    1016             :         u8 buf[10];
    1017             : 
    1018         319 :         if (random_get_bytes(buf, sizeof(buf)))
    1019           0 :                 return NULL;
    1020         319 :         id = os_malloc(sizeof(buf) * 2 + 2);
    1021         319 :         if (id == NULL)
    1022           0 :                 return NULL;
    1023             : 
    1024         319 :         pos = id;
    1025         319 :         end = id + sizeof(buf) * 2 + 2;
    1026         319 :         *pos++ = prefix;
    1027         319 :         wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
    1028             :         
    1029         319 :         return id;
    1030             : }
    1031             : 
    1032             : 
    1033             : /**
    1034             :  * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
    1035             :  * @data: Private data pointer from eap_sim_db_init()
    1036             :  * @method: EAP method (SIM/AKA/AKA')
    1037             :  * Returns: Next pseudonym (allocated string) or %NULL on failure
    1038             :  *
    1039             :  * This function is used to generate a pseudonym for EAP-SIM. The returned
    1040             :  * pseudonym is not added to database at this point; it will need to be added
    1041             :  * with eap_sim_db_add_pseudonym() once the authentication has been completed
    1042             :  * successfully. Caller is responsible for freeing the returned buffer.
    1043             :  */
    1044         144 : char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
    1045             :                                      enum eap_sim_db_method method)
    1046             : {
    1047         144 :         char prefix = EAP_SIM_REAUTH_ID_PREFIX;
    1048             : 
    1049         144 :         switch (method) {
    1050             :         case EAP_SIM_DB_SIM:
    1051          75 :                 prefix = EAP_SIM_PSEUDONYM_PREFIX;
    1052          75 :                 break;
    1053             :         case EAP_SIM_DB_AKA:
    1054          51 :                 prefix = EAP_AKA_PSEUDONYM_PREFIX;
    1055          51 :                 break;
    1056             :         case EAP_SIM_DB_AKA_PRIME:
    1057          18 :                 prefix = EAP_AKA_PRIME_PSEUDONYM_PREFIX;
    1058          18 :                 break;
    1059             :         }
    1060             : 
    1061         144 :         return eap_sim_db_get_next(data, prefix);
    1062             : }
    1063             : 
    1064             : 
    1065             : /**
    1066             :  * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
    1067             :  * @data: Private data pointer from eap_sim_db_init()
    1068             :  * @method: EAP method (SIM/AKA/AKA')
    1069             :  * Returns: Next reauth_id (allocated string) or %NULL on failure
    1070             :  *
    1071             :  * This function is used to generate a fast re-authentication identity for
    1072             :  * EAP-SIM. The returned reauth_id is not added to database at this point; it
    1073             :  * will need to be added with eap_sim_db_add_reauth() once the authentication
    1074             :  * has been completed successfully. Caller is responsible for freeing the
    1075             :  * returned buffer.
    1076             :  */
    1077         175 : char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
    1078             :                                      enum eap_sim_db_method method)
    1079             : {
    1080         175 :         char prefix = EAP_SIM_REAUTH_ID_PREFIX;
    1081             : 
    1082         175 :         switch (method) {
    1083             :         case EAP_SIM_DB_SIM:
    1084          89 :                 prefix = EAP_SIM_REAUTH_ID_PREFIX;
    1085          89 :                 break;
    1086             :         case EAP_SIM_DB_AKA:
    1087          60 :                 prefix = EAP_AKA_REAUTH_ID_PREFIX;
    1088          60 :                 break;
    1089             :         case EAP_SIM_DB_AKA_PRIME:
    1090          26 :                 prefix = EAP_AKA_PRIME_REAUTH_ID_PREFIX;
    1091          26 :                 break;
    1092             :         }
    1093             : 
    1094         175 :         return eap_sim_db_get_next(data, prefix);
    1095             : }
    1096             : 
    1097             : 
    1098             : /**
    1099             :  * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
    1100             :  * @data: Private data pointer from eap_sim_db_init()
    1101             :  * @permanent: Permanent username
    1102             :  * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
    1103             :  * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
    1104             :  * free it.
    1105             :  * Returns: 0 on success, -1 on failure
    1106             :  *
    1107             :  * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
    1108             :  * responsible of freeing pseudonym buffer once it is not needed anymore.
    1109             :  */
    1110          83 : int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
    1111             :                              const char *permanent, char *pseudonym)
    1112             : {
    1113             :         struct eap_sim_pseudonym *p;
    1114          83 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
    1115             :                    "username '%s'", pseudonym, permanent);
    1116             : 
    1117             :         /* TODO: could store last two pseudonyms */
    1118             : #ifdef CONFIG_SQLITE
    1119          83 :         if (data->sqlite_db)
    1120          18 :                 return db_add_pseudonym(data, permanent, pseudonym);
    1121             : #endif /* CONFIG_SQLITE */
    1122         102 :         for (p = data->pseudonyms; p; p = p->next) {
    1123          74 :                 if (os_strcmp(permanent, p->permanent) == 0)
    1124          37 :                         break;
    1125             :         }
    1126          65 :         if (p) {
    1127          37 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
    1128             :                            "pseudonym: %s", p->pseudonym);
    1129          37 :                 os_free(p->pseudonym);
    1130          37 :                 p->pseudonym = pseudonym;
    1131          37 :                 return 0;
    1132             :         }
    1133             : 
    1134          28 :         p = os_zalloc(sizeof(*p));
    1135          28 :         if (p == NULL) {
    1136           0 :                 os_free(pseudonym);
    1137           0 :                 return -1;
    1138             :         }
    1139             : 
    1140          28 :         p->next = data->pseudonyms;
    1141          28 :         p->permanent = os_strdup(permanent);
    1142          28 :         if (p->permanent == NULL) {
    1143           0 :                 os_free(p);
    1144           0 :                 os_free(pseudonym);
    1145           0 :                 return -1;
    1146             :         }
    1147          28 :         p->pseudonym = pseudonym;
    1148          28 :         data->pseudonyms = p;
    1149             : 
    1150          28 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
    1151          28 :         return 0;
    1152             : }
    1153             : 
    1154             : 
    1155             : static struct eap_sim_reauth *
    1156          79 : eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
    1157             :                            const char *permanent,
    1158             :                            char *reauth_id, u16 counter)
    1159             : {
    1160             :         struct eap_sim_reauth *r;
    1161             : 
    1162         117 :         for (r = data->reauths; r; r = r->next) {
    1163          89 :                 if (os_strcmp(r->permanent, permanent) == 0)
    1164          51 :                         break;
    1165             :         }
    1166             : 
    1167          79 :         if (r) {
    1168          51 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
    1169             :                            "reauth_id: %s", r->reauth_id);
    1170          51 :                 os_free(r->reauth_id);
    1171          51 :                 r->reauth_id = reauth_id;
    1172             :         } else {
    1173          28 :                 r = os_zalloc(sizeof(*r));
    1174          28 :                 if (r == NULL) {
    1175           0 :                         os_free(reauth_id);
    1176           0 :                         return NULL;
    1177             :                 }
    1178             : 
    1179          28 :                 r->next = data->reauths;
    1180          28 :                 r->permanent = os_strdup(permanent);
    1181          28 :                 if (r->permanent == NULL) {
    1182           0 :                         os_free(r);
    1183           0 :                         os_free(reauth_id);
    1184           0 :                         return NULL;
    1185             :                 }
    1186          28 :                 r->reauth_id = reauth_id;
    1187          28 :                 data->reauths = r;
    1188          28 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
    1189             :         }
    1190             : 
    1191          79 :         r->counter = counter;
    1192             : 
    1193          79 :         return r;
    1194             : }
    1195             : 
    1196             : 
    1197             : /**
    1198             :  * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
    1199             :  * @priv: Private data pointer from eap_sim_db_init()
    1200             :  * @permanent: Permanent username
    1201             :  * @identity_len: Length of identity
    1202             :  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
    1203             :  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
    1204             :  * free it.
    1205             :  * @counter: AT_COUNTER value for fast re-authentication
    1206             :  * @mk: 16-byte MK from the previous full authentication or %NULL
    1207             :  * Returns: 0 on success, -1 on failure
    1208             :  *
    1209             :  * This function adds a new re-authentication entry for an EAP-SIM user.
    1210             :  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
    1211             :  * anymore.
    1212             :  */
    1213          85 : int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
    1214             :                           char *reauth_id, u16 counter, const u8 *mk)
    1215             : {
    1216             :         struct eap_sim_reauth *r;
    1217             : 
    1218          85 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
    1219             :                    "identity '%s'", reauth_id, permanent);
    1220             : 
    1221             : #ifdef CONFIG_SQLITE
    1222          85 :         if (data->sqlite_db)
    1223          16 :                 return db_add_reauth(data, permanent, reauth_id, counter, mk,
    1224             :                                      NULL, NULL, NULL);
    1225             : #endif /* CONFIG_SQLITE */
    1226          69 :         r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
    1227          69 :         if (r == NULL)
    1228           0 :                 return -1;
    1229             : 
    1230          69 :         os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
    1231             : 
    1232          69 :         return 0;
    1233             : }
    1234             : 
    1235             : 
    1236             : #ifdef EAP_SERVER_AKA_PRIME
    1237             : /**
    1238             :  * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
    1239             :  * @data: Private data pointer from eap_sim_db_init()
    1240             :  * @permanent: Permanent username
    1241             :  * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
    1242             :  * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
    1243             :  * free it.
    1244             :  * @counter: AT_COUNTER value for fast re-authentication
    1245             :  * @k_encr: K_encr from the previous full authentication
    1246             :  * @k_aut: K_aut from the previous full authentication
    1247             :  * @k_re: 32-byte K_re from the previous full authentication
    1248             :  * Returns: 0 on success, -1 on failure
    1249             :  *
    1250             :  * This function adds a new re-authentication entry for an EAP-AKA' user.
    1251             :  * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
    1252             :  * anymore.
    1253             :  */
    1254          18 : int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
    1255             :                                 const char *permanent, char *reauth_id,
    1256             :                                 u16 counter, const u8 *k_encr,
    1257             :                                 const u8 *k_aut, const u8 *k_re)
    1258             : {
    1259             :         struct eap_sim_reauth *r;
    1260             : 
    1261          18 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
    1262             :                    "identity '%s'", reauth_id, permanent);
    1263             : 
    1264             : #ifdef CONFIG_SQLITE
    1265          18 :         if (data->sqlite_db)
    1266           8 :                 return db_add_reauth(data, permanent, reauth_id, counter, NULL,
    1267             :                                      k_encr, k_aut, k_re);
    1268             : #endif /* CONFIG_SQLITE */
    1269          10 :         r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
    1270          10 :         if (r == NULL)
    1271           0 :                 return -1;
    1272             : 
    1273          10 :         os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
    1274          10 :         os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
    1275          10 :         os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
    1276             : 
    1277          10 :         return 0;
    1278             : }
    1279             : #endif /* EAP_SERVER_AKA_PRIME */
    1280             : 
    1281             : 
    1282             : /**
    1283             :  * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
    1284             :  * @data: Private data pointer from eap_sim_db_init()
    1285             :  * @pseudonym: Pseudonym username
    1286             :  * Returns: Pointer to permanent username or %NULL if not found
    1287             :  */
    1288             : const char *
    1289          18 : eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
    1290             : {
    1291             :         struct eap_sim_pseudonym *p;
    1292             : 
    1293             : #ifdef CONFIG_SQLITE
    1294          18 :         if (data->sqlite_db)
    1295           9 :                 return db_get_pseudonym(data, pseudonym);
    1296             : #endif /* CONFIG_SQLITE */
    1297             : 
    1298           9 :         p = data->pseudonyms;
    1299          19 :         while (p) {
    1300           7 :                 if (os_strcmp(p->pseudonym, pseudonym) == 0)
    1301           6 :                         return p->permanent;
    1302           1 :                 p = p->next;
    1303             :         }
    1304             : 
    1305           3 :         return NULL;
    1306             : }
    1307             : 
    1308             : 
    1309             : /**
    1310             :  * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
    1311             :  * @data: Private data pointer from eap_sim_db_init()
    1312             :  * @reauth_id: Fast re-authentication username
    1313             :  * Returns: Pointer to the re-auth entry, or %NULL if not found
    1314             :  */
    1315             : struct eap_sim_reauth *
    1316          44 : eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
    1317             :                             const char *reauth_id)
    1318             : {
    1319             :         struct eap_sim_reauth *r;
    1320             : 
    1321             : #ifdef CONFIG_SQLITE
    1322          44 :         if (data->sqlite_db)
    1323          25 :                 return db_get_reauth(data, reauth_id);
    1324             : #endif /* CONFIG_SQLITE */
    1325             : 
    1326          19 :         r = data->reauths;
    1327          39 :         while (r) {
    1328          20 :                 if (os_strcmp(r->reauth_id, reauth_id) == 0)
    1329          19 :                         break;
    1330           1 :                 r = r->next;
    1331             :         }
    1332             : 
    1333          19 :         return r;
    1334             : }
    1335             : 
    1336             : 
    1337             : /**
    1338             :  * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
    1339             :  * @data: Private data pointer from eap_sim_db_init()
    1340             :  * @reauth: Pointer to re-authentication entry from
    1341             :  * eap_sim_db_get_reauth_entry()
    1342             :  */
    1343           3 : void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
    1344             :                               struct eap_sim_reauth *reauth)
    1345             : {
    1346           3 :         struct eap_sim_reauth *r, *prev = NULL;
    1347             : #ifdef CONFIG_SQLITE
    1348           3 :         if (data->sqlite_db) {
    1349           3 :                 db_remove_reauth(data, reauth);
    1350           3 :                 return;
    1351             :         }
    1352             : #endif /* CONFIG_SQLITE */
    1353           0 :         r = data->reauths;
    1354           0 :         while (r) {
    1355           0 :                 if (r == reauth) {
    1356           0 :                         if (prev)
    1357           0 :                                 prev->next = r->next;
    1358             :                         else
    1359           0 :                                 data->reauths = r->next;
    1360           0 :                         eap_sim_db_free_reauth(r);
    1361           0 :                         return;
    1362             :                 }
    1363           0 :                 prev = r;
    1364           0 :                 r = r->next;
    1365             :         }
    1366             : }
    1367             : 
    1368             : 
    1369             : /**
    1370             :  * eap_sim_db_get_aka_auth - Get AKA authentication values
    1371             :  * @data: Private data pointer from eap_sim_db_init()
    1372             :  * @username: Permanent username (prefix | IMSI)
    1373             :  * @_rand: Buffer for RAND value
    1374             :  * @autn: Buffer for AUTN value
    1375             :  * @ik: Buffer for IK value
    1376             :  * @ck: Buffer for CK value
    1377             :  * @res: Buffer for RES value
    1378             :  * @res_len: Buffer for RES length
    1379             :  * @cb_session_ctx: Session callback context for get_complete_cb()
    1380             :  * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
    1381             :  * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
    1382             :  * case, the callback function registered with eap_sim_db_init() will be
    1383             :  * called once the results become available.
    1384             :  *
    1385             :  * When using an external server for AKA authentication, this function can
    1386             :  * always start a request and return EAP_SIM_DB_PENDING immediately if
    1387             :  * authentication triplets are not available. Once the authentication data are
    1388             :  * received, callback function registered with eap_sim_db_init() is called to
    1389             :  * notify EAP state machine to reprocess the message. This
    1390             :  * eap_sim_db_get_aka_auth() function will then be called again and the newly
    1391             :  * received triplets will then be given to the caller.
    1392             :  */
    1393         138 : int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
    1394             :                             u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
    1395             :                             u8 *res, size_t *res_len, void *cb_session_ctx)
    1396             : {
    1397             :         struct eap_sim_db_pending *entry;
    1398             :         int len;
    1399             :         char msg[40];
    1400             :         const char *imsi;
    1401             :         size_t imsi_len;
    1402             : 
    1403         276 :         if (username == NULL ||
    1404         174 :             (username[0] != EAP_AKA_PERMANENT_PREFIX &&
    1405         174 :              username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
    1406         276 :             username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
    1407           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
    1408             :                            username);
    1409           0 :                 return EAP_SIM_DB_FAILURE;
    1410             :         }
    1411         138 :         imsi = username + 1;
    1412         138 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
    1413             :                    imsi);
    1414             : 
    1415         138 :         entry = eap_sim_db_get_pending(data, imsi, 1);
    1416         138 :         if (entry) {
    1417          69 :                 if (entry->state == FAILURE) {
    1418           0 :                         eap_sim_db_free_pending(data, entry);
    1419           0 :                         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
    1420           0 :                         return EAP_SIM_DB_FAILURE;
    1421             :                 }
    1422             : 
    1423          69 :                 if (entry->state == PENDING) {
    1424           0 :                         eap_sim_db_add_pending(data, entry);
    1425           0 :                         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
    1426           0 :                         return EAP_SIM_DB_PENDING;
    1427             :                 }
    1428             : 
    1429          69 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
    1430             :                            "received authentication data");
    1431          69 :                 os_memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
    1432          69 :                 os_memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
    1433          69 :                 os_memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
    1434          69 :                 os_memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
    1435          69 :                 os_memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
    1436          69 :                 *res_len = entry->u.aka.res_len;
    1437          69 :                 eap_sim_db_free_pending(data, entry);
    1438          69 :                 return 0;
    1439             :         }
    1440             : 
    1441          69 :         if (data->sock < 0) {
    1442           0 :                 if (eap_sim_db_open_socket(data) < 0)
    1443           0 :                         return EAP_SIM_DB_FAILURE;
    1444             :         }
    1445             : 
    1446          69 :         imsi_len = os_strlen(imsi);
    1447          69 :         len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
    1448         138 :         if (os_snprintf_error(sizeof(msg), len) ||
    1449          69 :             len + imsi_len >= sizeof(msg))
    1450           0 :                 return EAP_SIM_DB_FAILURE;
    1451          69 :         os_memcpy(msg + len, imsi, imsi_len);
    1452          69 :         len += imsi_len;
    1453             : 
    1454          69 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
    1455             :                     "data for IMSI '%s'", imsi);
    1456          69 :         if (eap_sim_db_send(data, msg, len) < 0)
    1457           0 :                 return EAP_SIM_DB_FAILURE;
    1458             : 
    1459          69 :         entry = os_zalloc(sizeof(*entry));
    1460          69 :         if (entry == NULL)
    1461           0 :                 return EAP_SIM_DB_FAILURE;
    1462             : 
    1463          69 :         entry->aka = 1;
    1464          69 :         os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
    1465          69 :         entry->cb_session_ctx = cb_session_ctx;
    1466          69 :         entry->state = PENDING;
    1467          69 :         eap_sim_db_add_pending(data, entry);
    1468          69 :         eap_sim_db_expire_pending(data, entry);
    1469          69 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added query %p", entry);
    1470             : 
    1471          69 :         return EAP_SIM_DB_PENDING;
    1472             : }
    1473             : 
    1474             : 
    1475             : /**
    1476             :  * eap_sim_db_resynchronize - Resynchronize AKA AUTN
    1477             :  * @data: Private data pointer from eap_sim_db_init()
    1478             :  * @username: Permanent username
    1479             :  * @auts: AUTS value from the peer
    1480             :  * @_rand: RAND value used in the rejected message
    1481             :  * Returns: 0 on success, -1 on failure
    1482             :  *
    1483             :  * This function is called when the peer reports synchronization failure in the
    1484             :  * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
    1485             :  * HLR/AuC to allow it to resynchronize with the peer. After this,
    1486             :  * eap_sim_db_get_aka_auth() will be called again to to fetch updated
    1487             :  * RAND/AUTN values for the next challenge.
    1488             :  */
    1489           5 : int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
    1490             :                              const char *username,
    1491             :                              const u8 *auts, const u8 *_rand)
    1492             : {
    1493             :         const char *imsi;
    1494             :         size_t imsi_len;
    1495             : 
    1496          10 :         if (username == NULL ||
    1497           5 :             (username[0] != EAP_AKA_PERMANENT_PREFIX &&
    1498           5 :              username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
    1499          10 :             username[1] == '\0' || os_strlen(username) > 20) {
    1500           0 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
    1501             :                            username);
    1502           0 :                 return -1;
    1503             :         }
    1504           5 :         imsi = username + 1;
    1505           5 :         wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
    1506             :                    imsi);
    1507             : 
    1508           5 :         if (data->sock >= 0) {
    1509             :                 char msg[100];
    1510             :                 int len, ret;
    1511             : 
    1512           5 :                 imsi_len = os_strlen(imsi);
    1513           5 :                 len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
    1514          10 :                 if (os_snprintf_error(sizeof(msg), len) ||
    1515           5 :                     len + imsi_len >= sizeof(msg))
    1516           0 :                         return -1;
    1517           5 :                 os_memcpy(msg + len, imsi, imsi_len);
    1518           5 :                 len += imsi_len;
    1519             : 
    1520           5 :                 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
    1521           5 :                 if (os_snprintf_error(sizeof(msg) - len, ret))
    1522           0 :                         return -1;
    1523           5 :                 len += ret;
    1524           5 :                 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
    1525             :                                         auts, EAP_AKA_AUTS_LEN);
    1526           5 :                 ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
    1527           5 :                 if (os_snprintf_error(sizeof(msg) - len, ret))
    1528           0 :                         return -1;
    1529           5 :                 len += ret;
    1530           5 :                 len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
    1531             :                                         _rand, EAP_AKA_RAND_LEN);
    1532           5 :                 wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
    1533             :                            "IMSI '%s'", imsi);
    1534           5 :                 if (eap_sim_db_send(data, msg, len) < 0)
    1535           0 :                         return -1;
    1536             :         }
    1537             : 
    1538           5 :         return 0;
    1539             : }
    1540             : 
    1541             : 
    1542             : /**
    1543             :  * sim_get_username - Extract username from SIM identity
    1544             :  * @identity: Identity
    1545             :  * @identity_len: Identity length
    1546             :  * Returns: Allocated buffer with the username part of the identity
    1547             :  *
    1548             :  * Caller is responsible for freeing the returned buffer with os_free().
    1549             :  */
    1550         385 : char * sim_get_username(const u8 *identity, size_t identity_len)
    1551             : {
    1552             :         size_t pos;
    1553             : 
    1554         385 :         if (identity == NULL)
    1555           0 :                 return NULL;
    1556             : 
    1557        6812 :         for (pos = 0; pos < identity_len; pos++) {
    1558        6466 :                 if (identity[pos] == '@' || identity[pos] == '\0')
    1559             :                         break;
    1560             :         }
    1561             : 
    1562         385 :         return dup_binstr(identity, pos);
    1563             : }

Generated by: LCOV version 1.10