[5/5] Add IMSI-prefix authorization policy
diff mbox

Message ID 1462293833-29141-5-git-send-email-msuraev@sysmocom.de
State New
Headers show

Commit Message

Max May 3, 2016, 4:43 p.m. UTC
From: Max <msuraev@sysmocom.de>

* extend "auth policy" vty command with new option "prefix"
* add vty command "authorize-prefix" for setting arbitrary prefix
* add basic vty test
* add optional "imsi-prefix" argument to subscriber-create-on-demand vty
  command

With those in place we can now set the prefix against which MS's IMSI
will be checked.

If IMSI's prefix match our configuration than MS is allowed to access
the network. If subscriber is already marked as authorized in HLR than
it'll be allowed regardless of IMSI prefix.

The same way we can decide whether to create subscribers on-demand
basesd on IMSI prefix match.

Note: this is NITB option, not to be confused with SGSN option with the
same name.

Fixes: OS#1647
---
 openbsc/include/openbsc/gprs_sgsn.h       |  1 -
 openbsc/include/openbsc/gsm_data.h        |  5 +++++
 openbsc/include/openbsc/gsm_subscriber.h  |  1 -
 openbsc/src/libbsc/bsc_vty.c              | 27 ++++++++++++++++++++++++---
 openbsc/src/libbsc/net_init.c             |  1 +
 openbsc/src/libcommon/gsm_data.c          |  1 +
 openbsc/src/libmsc/gsm_04_08.c            | 21 +++++++++++++++++++--
 openbsc/src/libmsc/vty_interface_layer3.c | 16 ++++++++++++----
 openbsc/tests/vty_test_runner.py          | 13 +++++++++++++
 9 files changed, 75 insertions(+), 11 deletions(-)

Comments

Holger Freyther May 9, 2016, 2:44 p.m. UTC | #1
> On 03 May 2016, at 18:43, msuraev@sysmocom.de wrote:
> 
> From: Max <msuraev@sysmocom.de>
> 
> * extend "auth policy" vty command with new option "prefix"
> * add vty command "authorize-prefix" for setting arbitrary prefix
> * add basic vty test
> * add optional "imsi-prefix" argument to subscriber-create-on-demand vty


Why not a regexp? I mean if we have a prefix.. then ^26203 is not really that far away from it?

holger
Neels Hofmeyr May 10, 2016, 9:58 a.m. UTC | #2
On Mon, May 09, 2016 at 04:44:59PM +0200, Holger Freyther wrote:
> 
> > On 03 May 2016, at 18:43, msuraev@sysmocom.de wrote:
> > 
> > From: Max <msuraev@sysmocom.de>
> > 
> > * extend "auth policy" vty command with new option "prefix"
> > * add vty command "authorize-prefix" for setting arbitrary prefix
> > * add basic vty test
> > * add optional "imsi-prefix" argument to subscriber-create-on-demand vty
> 
> 
> Why not a regexp? I mean if we have a prefix.. then ^26203 is not really that far away from it?

actually '26203.*', because it should probably match the entire IMSI.

A regex is of course fully featured, but would introduce corner cases of
invalid regular expressions entered by the user. Code bloat?

~Neels

Patch
diff mbox

diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
index 49d5407..bf18ea1 100644
--- a/openbsc/include/openbsc/gprs_sgsn.h
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -12,7 +12,6 @@ 
 
 #include <openbsc/gsm_data.h>
 
-#define GSM_IMSI_LENGTH 17
 #define GSM_IMEI_LENGTH 17
 #define GSM_EXTENSION_LENGTH 15
 #define GSM_APN_LENGTH 102
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 593a86f..4844412 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -8,6 +8,8 @@ 
 
 #include <openbsc/rest_octets.h>
 
+#define GSM_IMSI_LENGTH 17
+
 /** annotations for msgb ownership */
 #define __uses
 
@@ -21,6 +23,7 @@  struct gsm_subscriber_group;
 enum gsm_subscr_ext_alloc_policy {
 	GSM_SUBSCR_DONT_CREATE = 0,
 	GSM_SUBSCR_RANDOM_EXT = 1,
+	GSM_SUBSCR_MATCH_PREF = 2,
 };
 
 enum gsm_security_event {
@@ -206,6 +209,7 @@  enum gsm_auth_policy {
 	GSM_AUTH_POLICY_CLOSED, /* only subscribers authorized in DB */
 	GSM_AUTH_POLICY_ACCEPT_ALL, /* accept everyone, even if not authorized in DB */
 	GSM_AUTH_POLICY_TOKEN, /* accept first, send token per sms, then revoke authorization */
+	GSM_AUTH_POLICY_PREFIX, /* accept IMSIs with a given prefix */
 };
 
 #define GSM_T3101_DEFAULT 10
@@ -220,6 +224,7 @@  struct gsm_network {
 	char *name_long;
 	char *name_short;
 	enum gsm_auth_policy auth_policy;
+	char auth_prefix[GSM_IMSI_LENGTH];
 	enum gsm48_reject_value reject_cause;
 	int a5_encryption;
 	int neci;
diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h
index 7d6c776..7108bff 100644
--- a/openbsc/include/openbsc/gsm_subscriber.h
+++ b/openbsc/include/openbsc/gsm_subscriber.h
@@ -5,7 +5,6 @@ 
 #include <osmocom/core/linuxlist.h>
 
 #define GSM_IMEI_LENGTH 17
-#define GSM_IMSI_LENGTH 17
 #define GSM_NAME_LENGTH 160
 
 #define GSM_EXTENSION_LENGTH 15 /* MSISDN can only be 15 digits length */
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index b928738..dfcca24 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -189,8 +189,11 @@  static void net_dump_vty(struct vty *vty, struct gsm_network *net)
 		net->name_long, VTY_NEWLINE);
 	vty_out(vty, "  Short network name: '%s'%s",
 		net->name_short, VTY_NEWLINE);
-	vty_out(vty, "  Authentication policy: %s%s",
-		gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
+	vty_out(vty, "  Authentication policy: %s",
+		gsm_auth_policy_name(net->auth_policy));
+	if (net->auth_prefix[0] != '\0')
+		vty_out(vty, ", authorized prefix: %s", net->auth_prefix);
+	vty_out(vty, "%s", VTY_NEWLINE);
 	vty_out(vty, "  Location updating reject cause: %u%s",
 		net->reject_cause, VTY_NEWLINE);
 	vty_out(vty, "  Encryption: A5/%u%s", net->a5_encryption,
@@ -776,6 +779,8 @@  static int config_write_net(struct vty *vty)
 	vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
 	vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
 	vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
+	if (gsmnet->auth_prefix[0] != '\0')
+		vty_out(vty, " authorize-prefix %s%s", gsmnet->auth_prefix, VTY_NEWLINE);
 	vty_out(vty, " location updating reject cause %u%s",
 		gsmnet->reject_cause, VTY_NEWLINE);
 	vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
@@ -1384,11 +1389,12 @@  DEFUN(cfg_net_name_long,
 
 DEFUN(cfg_net_auth_policy,
       cfg_net_auth_policy_cmd,
-      "auth policy (closed|accept-all|token)",
+      "auth policy (closed|accept-all|prefix|token)",
 	"Authentication (not cryptographic)\n"
 	"Set the GSM network authentication policy\n"
 	"Require the MS to be activated in HLR\n"
 	"Accept all MS, whether in HLR or not\n"
+      "Use IMSI prefix for authorization decision\n"
 	"Use SMS-token based authentication\n")
 {
 	enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
@@ -1399,6 +1405,20 @@  DEFUN(cfg_net_auth_policy,
 	return CMD_SUCCESS;
 }
 
+/* Note: limit on the prefix length is set by internal vty code limitations */
+DEFUN(cfg_net_authorize_prefix, cfg_net_authorize_prefix_cmd,
+      "authorize-prefix <0-9999999999>",
+      "Set IMSI prefix which will be used for authorization decision\n"
+      "PREFIX of IMSIs which are allowed to use the network\n")
+{
+	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
+	strncpy(gsmnet->auth_prefix, argv[0], GSM_IMSI_LENGTH);
+	gsmnet->auth_prefix[GSM_IMSI_LENGTH - 1] = '\0';
+
+	return CMD_SUCCESS;
+}
+
 DEFUN(cfg_net_reject_cause,
       cfg_net_reject_cause_cmd,
       "location updating reject cause <2-111>",
@@ -3912,6 +3932,7 @@  int bsc_vty_init(const struct log_info *cat)
 	install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
 	install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
 	install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
+	install_element(GSMNET_NODE, &cfg_net_authorize_prefix_cmd);
 	install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
 	install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
 	install_element(GSMNET_NODE, &cfg_net_neci_cmd);
diff --git a/openbsc/src/libbsc/net_init.c b/openbsc/src/libbsc/net_init.c
index 00a8a9b..ed23f33 100644
--- a/openbsc/src/libbsc/net_init.c
+++ b/openbsc/src/libbsc/net_init.c
@@ -54,6 +54,7 @@  struct gsm_network *gsm_network_init(uint16_t country_code, uint16_t network_cod
 	net->network_code = network_code;
 	net->num_bts = 0;
 	net->reject_cause = GSM48_REJECT_ROAMING_NOT_ALLOWED;
+	net->auth_prefix[GSM_IMSI_LENGTH - 1] = '\0';
 	net->T3101 = GSM_T3101_DEFAULT;
 	net->T3105 = GSM_T3105_DEFAULT;
 	net->T3113 = GSM_T3113_DEFAULT;
diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c
index 242c014..4b4be42 100644
--- a/openbsc/src/libcommon/gsm_data.c
+++ b/openbsc/src/libcommon/gsm_data.c
@@ -161,6 +161,7 @@  static const struct value_string auth_policy_names[] = {
 	{ GSM_AUTH_POLICY_CLOSED,	"closed" },
 	{ GSM_AUTH_POLICY_ACCEPT_ALL,	"accept-all" },
 	{ GSM_AUTH_POLICY_TOKEN,	"token" },
+	{ GSM_AUTH_POLICY_PREFIX,	"prefix" },
 	{ 0,				NULL }
 };
 
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index bb1b49a..ab950c7 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -25,6 +25,7 @@ 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <time.h>
 #include <netinet/in.h>
@@ -244,8 +245,15 @@  int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
 	return -EINVAL; /* not reached */
 }
 
+static bool subscr_prefix_check(const char *auth_prefix, const char *imsi)
+{
+	return (strncmp(imsi, auth_prefix, strnlen(auth_prefix,
+						   GSM_IMSI_LENGTH)) == 0);
+}
+
 static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
-				struct gsm_subscriber *subscriber)
+				struct gsm_subscriber *subscriber,
+				const char *auth_prefix)
 {
 	if (!subscriber)
 		return 0;
@@ -261,6 +269,10 @@  static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
 	switch (subscriber->group->net->auth_policy) {
 	case GSM_AUTH_POLICY_CLOSED:
 		return subscriber->authorized;
+	case GSM_AUTH_POLICY_PREFIX:
+		if (subscriber->authorized)
+			return 1;
+		return subscr_prefix_check(auth_prefix, subscriber->imsi);
 	case GSM_AUTH_POLICY_TOKEN:
 		if (subscriber->authorized)
 			return subscriber->authorized;
@@ -366,7 +378,8 @@  static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb
 	if (!conn->loc_operation)
 		return 0;
 
-	if (authorize_subscriber(conn->loc_operation, conn->subscr))
+	if (authorize_subscriber(conn->loc_operation, conn->subscr,
+				 conn->bts->network->auth_prefix))
 		return gsm48_secure_channel(conn,
 			conn->loc_operation->key_seq,
 			_gsm0408_authorize_sec_cb, NULL);
@@ -513,6 +526,10 @@  static struct gsm_subscriber *subscr_create(const struct gsm_network *net,
 	if (GSM_SUBSCR_DONT_CREATE == net->create_subscriber)
 		return NULL;
 
+	if (net->create_subscriber & GSM_SUBSCR_MATCH_PREF)
+		if (!subscr_prefix_check(net->auth_prefix, imsi))
+			return NULL;
+
 	return subscr_create_subscriber(net->subscr_group, imsi);
 }
 
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 4dd0573..0ac2e90 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -1032,11 +1032,15 @@  DEFUN(cfg_nitb, cfg_nitb_cmd,
 }
 
 DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
-      "subscriber-create-on-demand",
-      "Make a new record when a subscriber is first seen.\n")
+      "subscriber-create-on-demand [imsi-prefix]",
+      "Make a new record when a subscriber is first seen.\n"
+      "Create subscribers only if IMSI matches the prefix specified in "
+      "authorize-prefix command \n")
 {
 	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
 	gsmnet->create_subscriber = GSM_SUBSCR_RANDOM_EXT;
+	if (argc)
+		gsmnet->create_subscriber |= GSM_SUBSCR_MATCH_PREF;
 	return CMD_SUCCESS;
 }
 
@@ -1070,9 +1074,13 @@  DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd,
 static int config_write_nitb(struct vty *vty)
 {
 	struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+	const char *pref = gsmnet->create_subscriber ? "" : "no ",
+		*ims = (gsmnet->create_subscriber & GSM_SUBSCR_MATCH_PREF) ?
+		" imsi-prefix" : "";
+
 	vty_out(vty, "nitb%s", VTY_NEWLINE);
-	vty_out(vty, " %ssubscriber-create-on-demand%s",
-		gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE);
+	vty_out(vty, " %ssubscriber-create-on-demand%s%s",
+		pref, ims, VTY_NEWLINE);
 	vty_out(vty, " %sassign-tmsi%s",
 		gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
 	return CMD_SUCCESS;
diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py
index c088855..88f6be9 100644
--- a/openbsc/tests/vty_test_runner.py
+++ b/openbsc/tests/vty_test_runner.py
@@ -231,6 +231,19 @@  class TestVTYNITB(TestVTYGenericBSC):
 
         self.assertEquals(self.vty.node(), 'config-mncc-int')
 
+    def testVtyAuthorization(self):
+        self.vty.enable()
+        self.vty.command("configure terminal")
+        self.vty.command("network")
+        self.assertTrue(self.vty.verify("auth policy closed", ['']))
+        self.assertTrue(self.vty.verify("auth policy prefix", ['']))
+        self.assertTrue(self.vty.verify("authorize-prefix 100500", ['']))
+        self.vty.command("end")
+        self.vty.command("configure terminal")
+        self.vty.command("nitb")
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
+        self.assertTrue(self.vty.verify("subscriber-create-on-demand imsi-prefix", ['']))
+
     def testSi2Q(self):
         self.vty.enable()
         self.vty.command("configure terminal")