ctrl: Introduce CTRL command subscriber.by-*.aud3g <algo[,KI,(op|opc),OP_C[,ind_bitlen]]>
This command provides getter and setter to set and retrieve the
authentication data for 3g subscribers.
Change-Id: Ibe7aeec3cabab0406eb7a84ecd24e529ef1696c2
Related: SYS#5993
diff --git a/include/osmocom/hlr/hlr_vty.h b/include/osmocom/hlr/hlr_vty.h
index c026d91..10eddc3 100644
--- a/include/osmocom/hlr/hlr_vty.h
+++ b/include/osmocom/hlr/hlr_vty.h
@@ -37,6 +37,12 @@
MSLOOKUP_CLIENT_NODE,
};
+
+#define A38_XOR_MIN_KEY_LEN 12
+#define A38_XOR_MAX_KEY_LEN 16
+#define A38_COMP128_KEY_LEN 16
+#define MILENAGE_KEY_LEN 16
+
int hlr_vty_is_config_node(struct vty *vty, int node);
int hlr_vty_go_parent(struct vty *vty);
void hlr_vty_init(void);
diff --git a/src/ctrl.c b/src/ctrl.c
index c543559..f101d25 100644
--- a/src/ctrl.c
+++ b/src/ctrl.c
@@ -31,6 +31,7 @@
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/ctrl.h>
#include <osmocom/hlr/db.h>
+#include <osmocom/hlr/hlr_vty.h>
#define SEL_BY "by-"
#define SEL_BY_IMSI SEL_BY "imsi-"
@@ -576,6 +577,153 @@
return CTRL_CMD_REPLY;
}
+/* value format: <algo[,KI,(op|opc),OP_C[,ind_bitlen]]> */
+CTRL_CMD_DEFINE(subscr_aud3g, "aud3g");
+static int verify_subscr_aud3g(struct ctrl_cmd *cmd, const char *value, void *data)
+{
+ if (!value)
+ return 1;
+ if (strcasecmp(value, "none") != 0 && !strchr(value, ','))
+ return 1;
+ return 0;
+}
+static int get_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
+{
+ struct hlr_subscriber subscr;
+ struct hlr *hlr = data;
+ const char *by_selector = cmd->node;
+ struct osmo_sub_auth_data aud2g_unused;
+ struct osmo_sub_auth_data aud3g;
+ int rc;
+
+ if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
+ return CTRL_CMD_ERROR;
+
+ rc = db_get_auth_data(hlr->dbc, subscr.imsi, &aud2g_unused, &aud3g, NULL);
+ switch (rc) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ENOKEY:
+ aud3g.algo = OSMO_AUTH_ALG_NONE;
+ break;
+ default:
+ cmd->reply = "Error retrieving data from database.";
+ return CTRL_CMD_ERROR;
+ }
+
+ if (aud3g.algo == OSMO_AUTH_ALG_NONE) {
+ cmd->reply = "none";
+ return CTRL_CMD_REPLY;
+ }
+
+ cmd->reply = talloc_asprintf(cmd, "%s,%s,%s,%s,%u", osmo_auth_alg_name(aud3g.algo),
+ osmo_hexdump_nospc_c(cmd, aud3g.u.umts.k, sizeof(aud3g.u.umts.k)),
+ aud3g.u.umts.opc_is_op ? "OP" : "OPC",
+ osmo_hexdump_nospc_c(cmd, aud3g.u.umts.opc, sizeof(aud3g.u.umts.opc)),
+ aud3g.u.umts.ind_bitlen);
+ return CTRL_CMD_REPLY;
+}
+static int set_subscr_aud3g(struct ctrl_cmd *cmd, void *data)
+{
+ struct hlr_subscriber subscr;
+ struct hlr *hlr = data;
+ const char *by_selector = cmd->node;
+ char *tmp = NULL, *tok, *saveptr;
+ int minlen = 0;
+ int maxlen = 0;
+ struct sub_auth_data_str aud3g = {
+ .type = OSMO_AUTH_TYPE_UMTS,
+ .u.umts = {
+ .ind_bitlen = 5,
+ },
+ };
+ bool ind_bitlen_present;
+
+ if (!get_subscriber(hlr->dbc, by_selector, &subscr, cmd))
+ return CTRL_CMD_ERROR;
+
+ tmp = talloc_strdup(cmd, cmd->value);
+ if (!tmp) {
+ cmd->reply = "OOM";
+ return CTRL_CMD_ERROR;
+ }
+
+ /* Parse alg_type: */
+ tok = strtok_r(tmp, ",", &saveptr);
+ if (!tok) {
+ cmd->reply = "Invalid format.";
+ return CTRL_CMD_ERROR;
+ }
+ if (strcmp(tok, "none") == 0) {
+ aud3g.algo = OSMO_AUTH_ALG_NONE;
+ } else if (!auth_algo_parse(tok, &aud3g.algo, &minlen, &maxlen)) {
+ cmd->reply = "Unknown auth algorithm.";
+ return CTRL_CMD_ERROR;
+ }
+
+ if (aud3g.algo != OSMO_AUTH_ALG_NONE) {
+ /* Parse K */
+ tok = strtok_r(NULL, ",", &saveptr);
+ if (!tok) {
+ cmd->reply = "Invalid format.";
+ return CTRL_CMD_ERROR;
+ }
+ aud3g.u.umts.k = tok;
+ if (!osmo_is_hexstr(aud3g.u.umts.k, minlen * 2, maxlen * 2, true)) {
+ cmd->reply = "Invalid KI.";
+ return CTRL_CMD_ERROR;
+ }
+
+ /* Parse OP/OPC choice */
+ tok = strtok_r(NULL, ",", &saveptr);
+ if (!tok) {
+ cmd->reply = "Invalid format.";
+ return CTRL_CMD_ERROR;
+ }
+ if (strcasecmp(tok, "op") == 0) {
+ aud3g.u.umts.opc_is_op = true;
+ } else if (strcasecmp(tok, "opc") == 0) {
+ aud3g.u.umts.opc_is_op = false;
+ } else {
+ cmd->reply = "Invalid format.";
+ return CTRL_CMD_ERROR;
+ }
+
+ /* Parse OP/OPC value */
+ ind_bitlen_present = !!strchr(saveptr, ',');
+ tok = strtok_r(NULL, ind_bitlen_present ? "," : "\0", &saveptr);
+ if (!tok) {
+ cmd->reply = "Invalid format.";
+ return CTRL_CMD_ERROR;
+ }
+
+ aud3g.u.umts.opc = tok;
+ if (!osmo_is_hexstr(aud3g.u.umts.opc, MILENAGE_KEY_LEN * 2, MILENAGE_KEY_LEN * 2, true)) {
+ cmd->reply = talloc_asprintf(cmd, "Invalid OP/OPC.");
+ return CTRL_CMD_ERROR;
+ }
+
+ if (ind_bitlen_present) {
+ /* Parse bitlen_ind */
+ tok = strtok_r(NULL, "\0", &saveptr);
+ if (!tok || tok[0] == '\0') {
+ cmd->reply = "Invalid format.";
+ return CTRL_CMD_ERROR;
+ }
+ aud3g.u.umts.ind_bitlen = atoi(tok);
+ }
+ }
+
+ if (db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud3g)) {
+ cmd->reply = "Update aud3g failed.";
+ return CTRL_CMD_ERROR;
+ }
+
+ cmd->reply = "OK";
+ return CTRL_CMD_REPLY;
+}
+
static int hlr_ctrl_node_lookup(void *data, vector vline, int *node_type,
void **node_data, int *i)
{
@@ -615,6 +763,7 @@
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_cs_enabled);
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_msisdn);
rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_aud2g);
+ rc |= ctrl_cmd_install(CTRL_NODE_SUBSCR_BY, &cmd_subscr_aud3g);
return rc;
}
diff --git a/src/hlr_vty_subscr.c b/src/hlr_vty_subscr.c
index a9f461d..c851062 100644
--- a/src/hlr_vty_subscr.c
+++ b/src/hlr_vty_subscr.c
@@ -31,6 +31,7 @@
#include <osmocom/hlr/hlr.h>
#include <osmocom/hlr/db.h>
#include <osmocom/hlr/timestamp.h>
+#include <osmocom/hlr/hlr_vty.h>
struct vty;
@@ -470,12 +471,6 @@
#define AUTH_ALG_TYPES_3G_HELP \
"Use Milenage algorithm\n"
-#define A38_XOR_MIN_KEY_LEN 12
-#define A38_XOR_MAX_KEY_LEN 16
-#define A38_COMP128_KEY_LEN 16
-
-#define MILENAGE_KEY_LEN 16
-
bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
int *minlen, int *maxlen)
{
diff --git a/tests/test_subscriber.ctrl b/tests/test_subscriber.ctrl
index dadad35..ff26d4c 100644
--- a/tests/test_subscriber.ctrl
+++ b/tests/test_subscriber.ctrl
@@ -686,5 +686,26 @@
GET 116 subscriber.by-imsi-901991234567891.aud2g
GET_REPLY 116 subscriber.by-imsi-901991234567891.aud2g none
-SET 117 subscriber.delete 901991234567891
-SET_REPLY 117 subscriber.delete 124
+GET 117 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 117 subscriber.by-imsi-901991234567891.aud3g none
+
+SET 118 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,FB2A3D1B360F599ABAB99DB8669F8308
+SET_REPLY 118 subscriber.by-imsi-901991234567891.aud3g OK
+
+GET 119 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 119 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OP,fb2a3d1b360f599abab99db8669f8308,5
+
+SET 120 subscriber.by-imsi-901991234567891.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,FB2A3D1B360F599ABAB99DB8669F8308,7
+SET_REPLY 120 subscriber.by-imsi-901991234567891.aud3g OK
+
+GET 121 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 121 subscriber.by-imsi-901991234567891.aud3g MILENAGE,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,7
+
+SET 122 subscriber.by-imsi-901991234567891.aud3g none
+SET_REPLY 122 subscriber.by-imsi-901991234567891.aud3g OK
+
+GET 123 subscriber.by-imsi-901991234567891.aud3g
+GET_REPLY 123 subscriber.by-imsi-901991234567891.aud3g none
+
+SET 124 subscriber.delete 901991234567891
+SET_REPLY 124 subscriber.delete 124
diff --git a/tests/test_subscriber_errors.ctrl b/tests/test_subscriber_errors.ctrl
index ac9eec7..6b1ade6 100644
--- a/tests/test_subscriber_errors.ctrl
+++ b/tests/test_subscriber_errors.ctrl
@@ -132,3 +132,24 @@
SET 56 subscriber.by-imsi-901990000000003.aud2g xor,2134
ERROR 56 Invalid KI.
+
+SET 57 subscriber.by-imsi-901990000000003.aud3g foobar
+ERROR 57 Value failed verification.
+
+SET 58 subscriber.by-imsi-901990000000003.aud3g foobar,2134
+ERROR 58 Unknown auth algorithm.
+
+SET 60 subscriber.by-imsi-901990000000003.aud3g milenage,2134
+ERROR 60 Invalid KI.
+
+SET 61 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,AAA
+ERROR 61 Invalid format.
+
+SET 62 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC
+ERROR 62 Invalid format.
+
+SET 63 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,zzz
+ERROR 63 Invalid OP/OPC.
+
+SET 64 subscriber.by-imsi-901990000000003.aud3g milenage,c01ffedc1cadaeac1d1f1edacac1ab0a,OPC,fb2a3d1b360f599abab99db8669f8308,
+ERROR 64 Invalid format.