diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index a08938c..31a4ed5 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -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;
diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c
index 46ad457..f4d47b4 100644
--- a/openbsc/src/libbsc/bsc_vty.c
+++ b/openbsc/src/libbsc/bsc_vty.c
@@ -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);
diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c
index 4e235fd..9d794ee 100644
--- a/openbsc/src/libcommon/gsm_data.c
+++ b/openbsc/src/libcommon/gsm_data.c
@@ -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 }
 };
 
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 74da34b..92c4cfe 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -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)
 {
@@ -260,6 +274,13 @@
 
 	switch (subscriber->group->net->auth_policy) {
 	case GSM_AUTH_POLICY_CLOSED:
+		return subscriber->authorized;
+	case GSM_AUTH_POLICY_REGEXP:
+		if (subscriber->authorized)
+			return 1;
+		if (subscr_regexp_check(subscriber->group->net,
+					subscriber->imsi))
+			subscriber->authorized = 1;
 		return subscriber->authorized;
 	case GSM_AUTH_POLICY_TOKEN:
 		if (subscriber->authorized)
@@ -509,10 +530,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 */
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 5d74e04..3f67b9a 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -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;
diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py
index c088855..c264328 100644
--- a/openbsc/tests/vty_test_runner.py
+++ b/openbsc/tests/vty_test_runner.py
@@ -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")
