diff --git a/include/osmocom/gsupclient/gsup_req.h b/include/osmocom/gsupclient/gsup_req.h index 2d3cf38e..c219d00e 100644 --- a/include/osmocom/gsupclient/gsup_req.h +++ b/include/osmocom/gsupclient/gsup_req.h @@ -80,6 +80,10 @@ struct osmo_gsup_req { /* A decoded GSUP message still points into the received msgb. For a decoded osmo_gsup_message to remain valid, * we also need to keep the msgb. */ struct msgb *msg; + + /* The pseudonymous IMSI in gsup->imsi is replaced with the real IMSI right after receiving the message. A + * copy of the pseudonymous IMSI is stored here for the reply. */ + char imsi_pseudo[OSMO_IMSI_BUF_SIZE]; }; struct osmo_gsup_req *osmo_gsup_req_new(void *ctx, const struct osmo_cni_peer_id *from_peer, struct msgb *msg, diff --git a/include/osmocom/hlr/db.h b/include/osmocom/hlr/db.h index abb73573..35357a6f 100644 --- a/include/osmocom/hlr/db.h +++ b/include/osmocom/hlr/db.h @@ -37,6 +37,7 @@ enum stmt_idx { DB_STMT_PSEUDO_INSERT, DB_STMT_PSEUDO_DELETE, DB_STMT_PSEUDO_NEXT, + DB_STMT_PSEUDO_RESOLVE, _NUM_DB_STMT }; diff --git a/include/osmocom/hlr/imsi_pseudo.h b/include/osmocom/hlr/imsi_pseudo.h index e1118c39..329d1ba2 100644 --- a/include/osmocom/hlr/imsi_pseudo.h +++ b/include/osmocom/hlr/imsi_pseudo.h @@ -17,3 +17,4 @@ int db_get_imsi_pseudo_data(struct db_context *dbc, int64_t subscr_id, struct im int db_alloc_imsi_pseudo(struct db_context *dbc, int64_t subscr_id, const char *imsi_pseudo, int64_t imsi_pseudo_i); int db_dealloc_imsi_pseudo(struct db_context *dbc, const char *imsi_pseudo); int db_get_imsi_pseudo_next(struct db_context *dbc, char *imsi_pseudo); +int db_get_imsi_pseudo_resolve(struct db_context *dbc, const char *imsi_pseudo, char *imsi); diff --git a/src/db.c b/src/db.c index 2949d2f3..7ed05fcf 100644 --- a/src/db.c +++ b/src/db.c @@ -102,6 +102,11 @@ static const char *stmt_sql[] = { " WHERE imsi_pseudo IS NULL" " ORDER BY RANDOM()" " LIMIT 1", + [DB_STMT_PSEUDO_RESOLVE] = + "SELECT imsi" + " FROM subscriber" + " LEFT JOIN subscriber_imsi_pseudo ON subscriber_id = subscriber.id" + " WHERE imsi_pseudo = $imsi_pseudo", }; static void sql3_error_log_cb(void *arg, int err_code, const char *msg) diff --git a/src/db_imsi_pseudo.c b/src/db_imsi_pseudo.c index d1c09ab4..e6fd68f1 100644 --- a/src/db_imsi_pseudo.c +++ b/src/db_imsi_pseudo.c @@ -141,3 +141,37 @@ int db_get_imsi_pseudo_next(struct db_context *dbc, char *imsi_pseudo) db_remove_reset(stmt); return ret; } + +/*! Resolve a pseudo IMSI to the real IMSI. + * \param[in] dbc database context. + * \param[in] imsi_pseudo the IMSI to be resolved + * \param[out] imsi buffer with length GSM23003_IMSI_MAX_DIGITS+1. + * \returns 0: success, -1: no associated real IMSI, -2: SQL error. */ +int db_get_imsi_pseudo_resolve(struct db_context *dbc, const char *imsi_pseudo, char *imsi) +{ + sqlite3_stmt *stmt = dbc->stmt[DB_STMT_PSEUDO_RESOLVE]; + int rc, ret=0; + + if (!db_bind_text(stmt, "$imsi_pseudo", imsi_pseudo)) + return -EIO; + + rc = sqlite3_step(stmt); + switch (rc) { + case SQLITE_ROW: + /* Can't use copy_sqlite3_text_to_buf, as it assumes the wrong size for imsi_pseudo */ + osmo_strlcpy(imsi, (const char *)sqlite3_column_text(stmt, 0), GSM23003_IMSI_MAX_DIGITS + 1); + break; + case SQLITE_DONE: + LOGP(DPSEUDO, LOGL_NOTICE, "cannot resolve pseudonymous IMSI '%s': no associated real IMSI found\n", + imsi_pseudo); + ret = -1; + break; + default: + LOGP(DPSEUDO, LOGL_ERROR, "cannot resolve pseudonymous IMSI '%s': SQL error: %d\n", imsi_pseudo, rc); + ret = -2; + break; + } + + db_remove_reset(stmt); + return ret; +} diff --git a/src/gsup_server.c b/src/gsup_server.c index 888507cf..ca2ad5ff 100644 --- a/src/gsup_server.c +++ b/src/gsup_server.c @@ -30,6 +30,7 @@ #include #include +#include #define LOG_GSUP_CONN(conn, level, fmt, args...) \ LOGP(DLGSUP, level, "GSUP peer %s: " fmt, \ @@ -95,6 +96,11 @@ static void gsup_server_send_req_response(struct osmo_gsup_req *req, struct osmo return; } + if (req->imsi_pseudo[0]) { + LOGP(DPSEUDO, LOGL_DEBUG, "pseudo IMSI scramble: '%s' => '%s'\n", response->imsi, req->imsi_pseudo); + strncpy(response->imsi, req->imsi_pseudo, sizeof(response->imsi)); + } + rc = osmo_gsup_encode(msg, response); if (rc) { LOG_GSUP_REQ(req, LOGL_ERROR, "Unable to encode: {%s}\n", diff --git a/src/hlr.c b/src/hlr.c index e4d6c239..634312cb 100644 --- a/src/hlr.c +++ b/src/hlr.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -512,6 +513,19 @@ static int read_cb(struct osmo_gsup_conn *conn, struct msgb *msg) return 0; } + /* Resolve pseudonymous IMSI */ + if (g_hlr->imsi_pseudo) { + char imsi[OSMO_IMSI_BUF_SIZE]; + if (db_get_imsi_pseudo_resolve(g_hlr->dbc, req->gsup.imsi, imsi) == 0) { + LOGP(DPSEUDO, LOGL_DEBUG, "pseudo IMSI resolve: '%s' => '%s'\n", req->gsup.imsi, imsi); + strncpy(req->imsi_pseudo, req->gsup.imsi, sizeof(req->imsi_pseudo)); + strncpy((char *)req->gsup.imsi, imsi, sizeof(req->gsup.imsi)); + } else { + osmo_gsup_req_respond_err(req, GMM_CAUSE_IMSI_UNKNOWN, "pseudonymous IMSI unknown"); + return -1; + } + } + /* HLR related messages that are handled at this HLR instance */ switch (req->gsup.message_type) { /* requests sent to us */