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
changes/97/28397/2
Pau Espin 6 months ago
parent 1d0a030aa4
commit 777860ddb5
  1. 6
      include/osmocom/hlr/hlr_vty.h
  2. 149
      src/ctrl.c
  3. 7
      src/hlr_vty_subscr.c
  4. 25
      tests/test_subscriber.ctrl
  5. 21
      tests/test_subscriber_errors.ctrl

@ -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);

@ -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 @@ static int set_subscr_aud2g(struct ctrl_cmd *cmd, void *data)
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 @@ 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;
}

@ -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 @@ 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)
{

@ -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

@ -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.

Loading…
Cancel
Save