From 777860ddb5060b2c8a9058bd63307ff2c96e9bd8 Mon Sep 17 00:00:00 2001 From: Pau Espin Pedrol Date: Mon, 20 Jun 2022 18:02:26 +0200 Subject: [PATCH] ctrl: Introduce CTRL command subscriber.by-*.aud3g This command provides getter and setter to set and retrieve the authentication data for 3g subscribers. Change-Id: Ibe7aeec3cabab0406eb7a84ecd24e529ef1696c2 Related: SYS#5993 --- include/osmocom/hlr/hlr_vty.h | 6 ++ src/ctrl.c | 149 ++++++++++++++++++++++++++++++ src/hlr_vty_subscr.c | 7 +- tests/test_subscriber.ctrl | 25 ++++- tests/test_subscriber_errors.ctrl | 21 +++++ 5 files changed, 200 insertions(+), 8 deletions(-) diff --git a/include/osmocom/hlr/hlr_vty.h b/include/osmocom/hlr/hlr_vty.h index c026d917..10eddc3a 100644 --- a/include/osmocom/hlr/hlr_vty.h +++ b/include/osmocom/hlr/hlr_vty.h @@ -37,6 +37,12 @@ enum hlr_vty_node { 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 c5435590..f101d253 100644 --- a/src/ctrl.c +++ b/src/ctrl.c @@ -31,6 +31,7 @@ #include #include #include +#include #define SEL_BY "by-" #define SEL_BY_IMSI SEL_BY "imsi-" @@ -576,6 +577,153 @@ static int set_subscr_aud2g(struct ctrl_cmd *cmd, void *data) return CTRL_CMD_REPLY; } +/* value format: */ +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 @@ static int hlr_ctrl_cmds_install() 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 a9f461d2..c8510623 100644 --- a/src/hlr_vty_subscr.c +++ b/src/hlr_vty_subscr.c @@ -31,6 +31,7 @@ #include #include #include +#include struct vty; @@ -470,12 +471,6 @@ static bool is_hexkey_valid(struct vty *vty, const char *label, #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 dadad356..ff26d4ce 100644 --- a/tests/test_subscriber.ctrl +++ b/tests/test_subscriber.ctrl @@ -686,5 +686,26 @@ SET_REPLY 115 subscriber.by-imsi-901991234567891.aud2g OK 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 ac9eec7e..6b1ade62 100644 --- a/tests/test_subscriber_errors.ctrl +++ b/tests/test_subscriber_errors.ctrl @@ -132,3 +132,24 @@ ERROR 55 Unknown auth algorithm. 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.