From d04f7cc41b34b68a24c584a969d8035ad9547806 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Wed, 12 Nov 2014 10:18:09 +0100 Subject: [PATCH] sgsn: Integrate subscriber handling into the SGSN This commit adds a new authorization policy 'remote' and uses the subscriber cache for authorization when this policy is being used. Note that there is no remote backend implemented yet. After the IMSI/IMEI have been acquired, a request would be sent to the remote peer. The attach/auth-ciph procedure continues when authorization info has been received from the peer. This means, that gprs_subscr_update() must be called then to tell the GMM layer that it can proceed. A later commit will add VTY commands to do this manually. Sponsored-by: On-Waves ehf --- openbsc/include/openbsc/sgsn.h | 3 +- openbsc/src/gprs/gprs_sgsn.c | 27 ++++++++++++++- openbsc/src/gprs/sgsn_auth.c | 29 ++++++++++++++-- openbsc/src/gprs/sgsn_vty.c | 8 +++-- openbsc/tests/sgsn/Makefile.am | 3 +- openbsc/tests/sgsn/sgsn_test.c | 57 ++++++++++++++++++++++++++++++-- openbsc/tests/sgsn/sgsn_test.ok | 3 +- openbsc/tests/vty_test_runner.py | 3 ++ 8 files changed, 120 insertions(+), 13 deletions(-) diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index 33bc72f9..6b83337d 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.h @@ -10,7 +10,8 @@ enum sgsn_auth_policy { SGSN_AUTH_POLICY_OPEN, SGSN_AUTH_POLICY_CLOSED, - SGSN_AUTH_POLICY_ACL_ONLY + SGSN_AUTH_POLICY_ACL_ONLY, + SGSN_AUTH_POLICY_REMOTE }; struct sgsn_config { diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 71cd742d..525bfab1 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -187,6 +187,14 @@ void sgsn_mm_ctx_free(struct sgsn_mm_ctx *mm) osmo_timer_del(&mm->timer); } + /* Detach from subscriber which is possibly freed then */ + if (mm->subscr) { + struct gsm_subscriber *subscr = mm->subscr; + mm->subscr = NULL; + subscr->mm = NULL; + gprs_subscr_delete(subscr); + } + /* Unlink from global list of MM contexts */ llist_del(&mm->list); @@ -455,7 +463,24 @@ int sgsn_force_reattach_oldmsg(struct msgb *oldmsg) void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx, struct gsm_subscriber *subscr) { - OSMO_ASSERT(mmctx); + if (!mmctx && subscr && strlen(subscr->imsi) > 0) { + mmctx = sgsn_mm_ctx_by_imsi(subscr->imsi); + OSMO_ASSERT(!mmctx || !mmctx->subscr || mmctx->subscr == subscr); + } + + if (!mmctx) { + LOGP(DMM, LOGL_INFO, + "Subscriber data update for unregistered MM context, IMSI %s\n", + subscr->imsi); + return; + } + + LOGMMCTXP(LOGL_INFO, mmctx, "Subscriber data update"); + + if (!subscr->mm && !mmctx->subscr) { + mmctx->subscr = subscr_get(subscr); + mmctx->subscr->mm = mmctx; + } sgsn_auth_update(mmctx); } diff --git a/openbsc/src/gprs/sgsn_auth.c b/openbsc/src/gprs/sgsn_auth.c index eb85d45f..071bdab8 100644 --- a/openbsc/src/gprs/sgsn_auth.c +++ b/openbsc/src/gprs/sgsn_auth.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -101,6 +102,18 @@ enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mmctx) case SGSN_AUTH_POLICY_ACL_ONLY: check_acl = 1; break; + + case SGSN_AUTH_POLICY_REMOTE: + if (!mmctx->subscr) + return mmctx->auth_state; + + if (mmctx->subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING) + return mmctx->auth_state; + + if (mmctx->subscr->authorized) + return SGSN_AUTH_ACCEPTED; + + return SGSN_AUTH_REJECTED; } if (!strlen(mmctx->imsi)) { @@ -126,7 +139,15 @@ enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mmctx) int sgsn_auth_request(struct sgsn_mm_ctx *mmctx) { - /* TODO: Add remote subscriber update requests here */ + LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting authorization\n"); + + if (sgsn->cfg.auth_policy == SGSN_AUTH_POLICY_REMOTE && !mmctx->subscr) { + if (gprs_subscr_request_update(mmctx) >= 0) { + LOGMMCTXP(LOGL_INFO, mmctx, + "Missing information, requesting subscriber data\n"); + return 0; + } + } sgsn_auth_update(mmctx); @@ -136,12 +157,14 @@ int sgsn_auth_request(struct sgsn_mm_ctx *mmctx) void sgsn_auth_update(struct sgsn_mm_ctx *mmctx) { enum sgsn_auth_state auth_state; + struct gsm_subscriber *subscr = mmctx->subscr; LOGMMCTXP(LOGL_DEBUG, mmctx, "Updating authorization\n"); auth_state = sgsn_auth_state(mmctx); - if (auth_state == SGSN_AUTH_UNKNOWN) { - /* Reject requests since remote updates are NYI */ + if (auth_state == SGSN_AUTH_UNKNOWN && subscr && + !(subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING)) { + /* Reject requests if gprs_subscr_request_update fails */ LOGMMCTXP(LOGL_ERROR, mmctx, "Missing information, authorization not possible\n"); auth_state = SGSN_AUTH_REJECTED; diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index 63816710..5fb230f4 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -45,6 +45,7 @@ const struct value_string sgsn_auth_pol_strs[] = { { SGSN_AUTH_POLICY_OPEN, "accept-all" }, { SGSN_AUTH_POLICY_CLOSED, "closed" }, { SGSN_AUTH_POLICY_ACL_ONLY, "acl-only" }, + { SGSN_AUTH_POLICY_REMOTE, "remote" }, { 0, NULL } }; @@ -358,14 +359,15 @@ DEFUN(imsi_acl, cfg_imsi_acl_cmd, } DEFUN(cfg_auth_policy, cfg_auth_policy_cmd, - "auth-policy (accept-all|closed|acl-only)", + "auth-policy (accept-all|closed|acl-only|remote)", "Autorization Policy of SGSN\n" "Accept all IMSIs (DANGEROUS)\n" "Accept only home network subscribers or those in the ACL\n" - "Accept only subscribers in the ACL\n") + "Accept only subscribers in the ACL\n" + "Use remote subscription data only (HLR)\n") { int val = get_string_value(sgsn_auth_pol_strs, argv[0]); - OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_ACL_ONLY); + OSMO_ASSERT(val >= SGSN_AUTH_POLICY_OPEN && val <= SGSN_AUTH_POLICY_REMOTE); g_cfg->auth_policy = val; return CMD_SUCCESS; diff --git a/openbsc/tests/sgsn/Makefile.am b/openbsc/tests/sgsn/Makefile.am index 0e5d009e..970311d0 100644 --- a/openbsc/tests/sgsn/Makefile.am +++ b/openbsc/tests/sgsn/Makefile.am @@ -7,7 +7,8 @@ noinst_PROGRAMS = sgsn_test sgsn_test_SOURCES = sgsn_test.c sgsn_test_LDFLAGS = \ - -Wl,--wrap=sgsn_update_subscriber_data + -Wl,--wrap=sgsn_update_subscriber_data \ + -Wl,--wrap=gprs_subscr_request_update sgsn_test_LDADD = \ $(top_builddir)/src/gprs/gprs_llc_parse.o \ diff --git a/openbsc/tests/sgsn/sgsn_test.c b/openbsc/tests/sgsn/sgsn_test.c index 2eb6f388..981a557c 100644 --- a/openbsc/tests/sgsn/sgsn_test.c +++ b/openbsc/tests/sgsn/sgsn_test.c @@ -67,6 +67,14 @@ void __wrap_sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx, (*update_subscriber_data_cb)(mmctx, subscr); } +/* override, requires '-Wl,--wrap=gprs_subscr_request_update' */ +int __real_gprs_subscr_request_update(struct sgsn_mm_ctx *mmctx); +int (*subscr_request_update_cb)(struct sgsn_mm_ctx *mmctx) = + &__real_gprs_subscr_request_update; + +int __wrap_gprs_subscr_request_update(struct sgsn_mm_ctx *mmctx) { + return (*subscr_request_update_cb)(mmctx); +}; static int count(struct llist_head *head) { @@ -477,8 +485,6 @@ static void test_gmm_attach(void) * again */ srand(1); - sgsn_acl_add("123456789012345", &sgsn->cfg); - foreign_tlli = gprs_tmsi2tlli(0xc0000023, TLLI_FOREIGN); /* Create a LLE/LLME */ @@ -537,8 +543,52 @@ static void test_gmm_attach(void) OSMO_ASSERT(count(gprs_llme_list()) == 0); ictx = sgsn_mm_ctx_by_tlli(local_tlli, &raid); OSMO_ASSERT(!ictx); +} +static void test_gmm_attach_acl(void) +{ + const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; + + sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_CLOSED; + sgsn_acl_add("123456789012345", &sgsn->cfg); + printf("Auth policy 'closed': "); + test_gmm_attach(); sgsn_acl_del("123456789012345", &sgsn->cfg); + + sgsn->cfg.auth_policy = saved_auth_policy; +} + +int my_subscr_request_update(struct sgsn_mm_ctx *mmctx) { + int rc; + rc = __real_gprs_subscr_request_update(mmctx); + if (rc == -ENOTSUP) { + OSMO_ASSERT(mmctx->subscr); + gprs_subscr_update(mmctx->subscr); + } + return rc; +}; + +static void test_gmm_attach_subscr(void) +{ + const enum sgsn_auth_policy saved_auth_policy = sgsn->cfg.auth_policy; + struct gsm_subscriber *subscr; + + sgsn_inst.cfg.auth_policy = SGSN_AUTH_POLICY_REMOTE; + subscr_request_update_cb = my_subscr_request_update; + + subscr = gprs_subscr_get_or_create("123456789012345"); + subscr->authorized = 1; + subscr_put(subscr); + + printf("Auth policy 'remote': "); + test_gmm_attach(); + + subscr = gprs_subscr_get_by_imsi("123456789012345"); + OSMO_ASSERT(subscr != NULL); + gprs_subscr_delete(subscr); + + sgsn->cfg.auth_policy = saved_auth_policy; + subscr_request_update_cb = __real_gprs_subscr_request_update; } /* @@ -944,7 +994,8 @@ int main(int argc, char **argv) test_gmm_detach_no_mmctx(); test_gmm_detach_accept_unexpected(); test_gmm_status_no_mmctx(); - test_gmm_attach(); + test_gmm_attach_acl(); + test_gmm_attach_subscr(); test_gmm_reject(); test_gmm_ptmsi_allocation(); printf("Done\n"); diff --git a/openbsc/tests/sgsn/sgsn_test.ok b/openbsc/tests/sgsn/sgsn_test.ok index 1ee80be7..86dd0a21 100644 --- a/openbsc/tests/sgsn/sgsn_test.ok +++ b/openbsc/tests/sgsn/sgsn_test.ok @@ -5,7 +5,8 @@ Testing GMM detach (power off) Testing GMM detach (no MMCTX) Testing GMM detach accept (unexpected) Testing GMM Status (no MMCTX) -Testing GMM attach +Auth policy 'closed': Testing GMM attach +Auth policy 'remote': Testing GMM attach Testing GMM reject - Attach Request (invalid MI length) - Attach Request (invalid MI type) diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py index 40053e30..64437a19 100644 --- a/openbsc/tests/vty_test_runner.py +++ b/openbsc/tests/vty_test_runner.py @@ -752,6 +752,9 @@ class TestVTYSGSN(TestVTYGenericBSC): self.assertTrue(self.vty.verify('auth-policy closed', [''])) res = self.vty.command("show running-config") self.assert_(res.find('auth-policy closed') > 0) + self.assertTrue(self.vty.verify('auth-policy remote', [''])) + res = self.vty.command("show running-config") + self.assert_(res.find('auth-policy remote') > 0) def add_nat_test(suite, workdir): if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc_nat/osmo-bsc_nat")):