Add regexp authorization policy for IMSI

* extend "auth policy" vty command with new option "regexp"
* add vty command "authorized-regexp" for setting arbitrary POSIX
  regular expression
* add basic vty test
* add optional "regexp" argument to subscriber-create-on-demand vty
  command

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

If IMSI match the regexp 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 matching.

The same way we can decide whether to create subscribers on-demand
basesd on IMSI regexp match. Similar to authorization this restriction
can be overridden by manually creating subscriber via vty, ctrl
interface or directly in HLR.

Change-Id: I525f4b80676de47d1d422686da2ca012301b0129
Fixes: OS#1647
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,11 +1403,12 @@
 
 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]);
@@ -1413,6 +1419,22 @@
 	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;
+}
+
 DEFUN(cfg_net_reject_cause,
       cfg_net_reject_cause_cmd,
       "location updating reject cause <2-111>",
@@ -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);