@@ -2,6 +2,8 @@
#define _GSM_DATA_H
#include <stdint.h>
+#include <regex.h>
+#include <sys/types.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/select.h>
@@ -22,6 +24,7 @@
enum gsm_subscr_creation_mode {
GSM_SUBSCR_DONT_CREATE = 0,
GSM_SUBSCR_CREAT_W_RAND_EXT = 1,
+ GSM_SUBSCR_CREAT_W_REGEXP = 2,
};
enum gsm_security_event {
@@ -205,6 +208,7 @@
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_REGEXP, /* accept IMSIs matching given regexp */
};
#define GSM_T3101_DEFAULT 10
@@ -219,6 +223,8 @@
char *name_long;
char *name_short;
enum gsm_auth_policy auth_policy;
+ regex_t authorized_regexp;
+ char *authorized_reg_str;
enum gsm48_reject_value reject_cause;
int a5_encryption;
int neci;
@@ -190,8 +190,11 @@
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->authorized_reg_str)
+ vty_out(vty, ", authorized regexp: %s", net->authorized_reg_str);
+ 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,
@@ -791,6 +794,8 @@
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->authorized_reg_str)
+ vty_out(vty, " authorized-regexp %s%s", gsmnet->authorized_reg_str, 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);
@@ -1398,17 +1403,34 @@
DEFUN(cfg_net_auth_policy,
cfg_net_auth_policy_cmd,
- "auth policy (closed|accept-all|token)",
+ "auth policy (closed|accept-all|regexp|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 regular expression for IMSI authorization decision\n"
"Use SMS-token based authentication\n")
{
enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->auth_policy = policy;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_net_authorize_regexp, cfg_net_authorize_regexp_cmd,
+ "authorized-regexp REGEXP",
+ "Set regexp for IMSI which will be used for authorization decision\n"
+ "Regular expression, IMSIs matching it are allowed to use the network\n")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ if (gsm_parse_reg(gsmnet, &gsmnet->authorized_regexp,
+ &gsmnet->authorized_reg_str, argc, argv) != 0) {
+ vty_out(vty, "%%Failed to parse the authorized-regexp: '%s'%s",
+ argv[0], VTY_NEWLINE);
+ return CMD_WARNING;
+ }
return CMD_SUCCESS;
}
@@ -3973,6 +3995,7 @@
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_regexp_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);
@@ -49,7 +49,7 @@
net->subscr_group->net = net;
net->subscr_creation_mode = GSM_SUBSCR_CREAT_W_RAND_EXT;
-
+ net->authorized_reg_str = NULL;
net->country_code = country_code;
net->network_code = network_code;
net->num_bts = 0;
@@ -162,6 +162,7 @@
{ GSM_AUTH_POLICY_CLOSED, "closed" },
{ GSM_AUTH_POLICY_ACCEPT_ALL, "accept-all" },
{ GSM_AUTH_POLICY_TOKEN, "token" },
+ { GSM_AUTH_POLICY_REGEXP, "regexp" },
{ 0, NULL }
};
@@ -25,9 +25,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
#include <errno.h>
#include <time.h>
#include <netinet/in.h>
+#include <regex.h>
+#include <sys/types.h>
#include "bscconfig.h"
@@ -244,6 +247,17 @@
return -EINVAL; /* not reached */
}
+static bool subscr_regexp_check(const struct gsm_network *net, const char *imsi)
+{
+ if (!net->authorized_reg_str)
+ return false;
+
+ if (regexec(&net->authorized_regexp, imsi, 0, NULL, 0) != REG_NOMATCH)
+ return true;
+
+ return false;
+}
+
static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
struct gsm_subscriber *subscriber)
{
@@ -261,6 +275,11 @@
switch (subscriber->group->net->auth_policy) {
case GSM_AUTH_POLICY_CLOSED:
return subscriber->authorized;
+ case GSM_AUTH_POLICY_REGEXP:
+ if (subscriber->authorized)
+ return 1;
+ return subscr_regexp_check(subscriber->group->net,
+ subscriber->imsi);
case GSM_AUTH_POLICY_TOKEN:
if (subscriber->authorized)
return subscriber->authorized;
@@ -509,10 +528,14 @@
static struct gsm_subscriber *subscr_create(const struct gsm_network *net,
const char *imsi)
{
- if (net->subscr_creation_mode != GSM_SUBSCR_DONT_CREATE)
- return subscr_create_subscriber(net->subscr_group, imsi);
+ if (net->subscr_creation_mode == GSM_SUBSCR_DONT_CREATE)
+ return NULL;
- return NULL;
+ if (net->subscr_creation_mode & GSM_SUBSCR_CREAT_W_REGEXP)
+ if (!subscr_regexp_check(net, imsi))
+ return NULL;
+
+ return subscr_create_subscriber(net->subscr_group, imsi);
}
/* Parse Chapter 9.2.11 Identity Response */
@@ -1032,11 +1032,15 @@
}
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 [regexp]",
+ "Make a new record when a subscriber is first seen.\n"
+ "Create subscribers only if IMSI matches the regexp specified in "
+ "authorized-regexp command\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
gsmnet->subscr_creation_mode = GSM_SUBSCR_CREAT_W_RAND_EXT;
+ if (argc)
+ gsmnet->subscr_creation_mode |= GSM_SUBSCR_CREAT_W_REGEXP;
return CMD_SUCCESS;
}
@@ -1070,9 +1074,12 @@
static int config_write_nitb(struct vty *vty)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ enum gsm_subscr_creation_mode scm = gsmnet->subscr_creation_mode;
+ const char *reg = (scm & GSM_SUBSCR_CREAT_W_REGEXP) ? " regexp" : "",
+ *pref = scm ? "" : "no ";
vty_out(vty, "nitb%s", VTY_NEWLINE);
- vty_out(vty, " %ssubscriber-create-on-demand%s",
- gsmnet->subscr_creation_mode ? "" : "no ", VTY_NEWLINE);
+ vty_out(vty, " %ssubscriber-create-on-demand%s%s",
+ pref, reg, VTY_NEWLINE);
vty_out(vty, " %sassign-tmsi%s",
gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
return CMD_SUCCESS;
@@ -231,6 +231,22 @@
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 regexp", ['']))
+ self.assertTrue(self.vty.verify("authorized-regexp ^001", ['']))
+ self.assertTrue(self.vty.verify("authorized-regexp 02$", ['']))
+ self.assertTrue(self.vty.verify("authorized-regexp *123.*", ['']))
+ 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 regexp", ['']))
+ self.vty.command("end")
+
def testSi2Q(self):
self.vty.enable()
self.vty.command("configure terminal")