@@ -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
@@ -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;
@@ -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 */
@@ -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);
@@ -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;
@@ -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 }
};
@@ -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);
}
@@ -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;
@@ -231,6 +231,20 @@ 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 220380", ['']))
+ 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", ['']))
+ self.vty.command("end")
+
def testSi2Q(self):
self.vty.enable()
self.vty.command("configure terminal")
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. Similar to authorization this restriction can be overridden by manually creating subscriber via vty, ctrl interface or directly in HLR. 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 | 14 ++++++++++++++ 9 files changed, 76 insertions(+), 11 deletions(-)