blob: 983a71c7d1340aaa8d298f739840abec76ccd798 [file] [log] [blame]
Neels Hofmeyr183e7002017-10-06 02:59:54 +02001/* OsmoHLR subscriber management VTY implementation */
2/* (C) 2017 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
14 *
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <stdlib.h>
20#include <inttypes.h>
21#include <string.h>
22#include <errno.h>
Stefan Sperling5c14c9c2018-12-07 12:30:21 +010023#include <sys/types.h>
24#include <time.h>
Neels Hofmeyr183e7002017-10-06 02:59:54 +020025
26#include <osmocom/gsm/gsm23003.h>
27#include <osmocom/vty/vty.h>
28#include <osmocom/vty/command.h>
29#include <osmocom/core/utils.h>
Neels Hofmeyr2fb33f12018-12-26 01:49:53 +010030#include <osmocom/gsm/gsm_utils.h>
Neels Hofmeyr183e7002017-10-06 02:59:54 +020031
32#include "hlr.h"
33#include "db.h"
34
35struct vty;
36
37#define hexdump_buf(buf) osmo_hexdump_nospc((void*)buf, sizeof(buf))
38
Neels Hofmeyr18a1b012018-12-25 17:23:41 +010039static char *get_datestr(const time_t *t)
Stefan Sperling5c14c9c2018-12-07 12:30:21 +010040{
Neels Hofmeyr18a1b012018-12-25 17:23:41 +010041 static char buf[32];
42 struct tm tm;
Stefan Sperling5c14c9c2018-12-07 12:30:21 +010043
Neels Hofmeyr18a1b012018-12-25 17:23:41 +010044 tm = *gmtime(t);
45
46 strftime(buf, sizeof(buf), "%FT%T+00:00", &tm);
47 return buf;
Stefan Sperling5c14c9c2018-12-07 12:30:21 +010048}
49
Neels Hofmeyr183e7002017-10-06 02:59:54 +020050static void subscr_dump_full_vty(struct vty *vty, struct hlr_subscriber *subscr)
51{
52 int rc;
Neels Hofmeyr2fb33f12018-12-26 01:49:53 +010053 int i;
Neels Hofmeyr183e7002017-10-06 02:59:54 +020054 struct osmo_sub_auth_data aud2g;
55 struct osmo_sub_auth_data aud3g;
56
57 vty_out(vty, " ID: %"PRIu64"%s", subscr->id, VTY_NEWLINE);
58
Neels Hofmeyr36bec872017-10-23 18:44:23 +020059 vty_out(vty, " IMSI: %s%s", *subscr->imsi ? subscr->imsi : "none", VTY_NEWLINE);
Neels Hofmeyr183e7002017-10-06 02:59:54 +020060 vty_out(vty, " MSISDN: %s%s", *subscr->msisdn ? subscr->msisdn : "none", VTY_NEWLINE);
61 if (*subscr->vlr_number)
62 vty_out(vty, " VLR number: %s%s", subscr->vlr_number, VTY_NEWLINE);
63 if (*subscr->sgsn_number)
64 vty_out(vty, " SGSN number: %s%s", subscr->sgsn_number, VTY_NEWLINE);
65 if (*subscr->sgsn_address)
66 vty_out(vty, " SGSN address: %s%s", subscr->sgsn_address, VTY_NEWLINE);
67 if (subscr->periodic_lu_timer)
68 vty_out(vty, " Periodic LU timer: %u%s", subscr->periodic_lu_timer, VTY_NEWLINE);
69 if (subscr->periodic_rau_tau_timer)
70 vty_out(vty, " Periodic RAU/TAU timer: %u%s", subscr->periodic_rau_tau_timer, VTY_NEWLINE);
71 if (subscr->lmsi)
72 vty_out(vty, " LMSI: %x%s", subscr->lmsi, VTY_NEWLINE);
73 if (!subscr->nam_cs)
74 vty_out(vty, " CS disabled%s", VTY_NEWLINE);
75 if (subscr->ms_purged_cs)
76 vty_out(vty, " CS purged%s", VTY_NEWLINE);
77 if (!subscr->nam_ps)
78 vty_out(vty, " PS disabled%s", VTY_NEWLINE);
79 if (subscr->ms_purged_ps)
80 vty_out(vty, " PS purged%s", VTY_NEWLINE);
Stefan Sperling5c14c9c2018-12-07 12:30:21 +010081 if (subscr->last_lu_seen)
Neels Hofmeyr18a1b012018-12-25 17:23:41 +010082 vty_out(vty, " last LU seen: %s%s", get_datestr(&subscr->last_lu_seen), VTY_NEWLINE);
Neels Hofmeyr0f9daa62018-12-29 03:28:38 +010083 if (subscr->last_lu_rat[0])
84 vty_out(vty, " last LU RAT: %s%s", subscr->last_lu_rat, VTY_NEWLINE);
Neels Hofmeyr2fb33f12018-12-26 01:49:53 +010085 for (i = OSMO_RAT_UNKNOWN + 1; i < ARRAY_SIZE(subscr->rat_types); i++) {
86 vty_out(vty, " %s: %s%s", osmo_rat_type_name(i), subscr->rat_types[i] ? "allowed" : "forbidden",
87 VTY_NEWLINE);
88 }
89 if (subscr->ms_purged_cs)
90 vty_out(vty, " CS purged%s", VTY_NEWLINE);
Neels Hofmeyr183e7002017-10-06 02:59:54 +020091
92 if (!*subscr->imsi)
93 return;
94
95 OSMO_ASSERT(g_hlr);
96 rc = db_get_auth_data(g_hlr->dbc, subscr->imsi, &aud2g, &aud3g, NULL);
97
Neels Hofmeyrbd1dca02017-11-23 15:25:30 +010098 switch (rc) {
99 case 0:
100 break;
101 case -ENOENT:
102 case -ENOKEY:
103 aud2g.algo = OSMO_AUTH_ALG_NONE;
104 aud3g.algo = OSMO_AUTH_ALG_NONE;
105 break;
106 default:
107 vty_out(vty, "%% Error retrieving data from database (%d)%s", rc, VTY_NEWLINE);
108 return;
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200109 }
110
111 if (aud2g.type != OSMO_AUTH_TYPE_NONE && aud2g.type != OSMO_AUTH_TYPE_GSM) {
112 vty_out(vty, "%% Error: 2G auth data is not of type 'GSM'%s", VTY_NEWLINE);
113 aud2g = (struct osmo_sub_auth_data){};
114 }
115
116 if (aud3g.type != OSMO_AUTH_TYPE_NONE && aud3g.type != OSMO_AUTH_TYPE_UMTS) {
117 vty_out(vty, "%% Error: 3G auth data is not of type 'UMTS'%s", VTY_NEWLINE);
118 aud3g = (struct osmo_sub_auth_data){};
119 }
120
121 if (aud2g.algo != OSMO_AUTH_ALG_NONE && aud2g.type != OSMO_AUTH_TYPE_NONE) {
122 vty_out(vty, " 2G auth: %s%s",
123 osmo_auth_alg_name(aud2g.algo), VTY_NEWLINE);
124 vty_out(vty, " KI=%s%s",
125 hexdump_buf(aud2g.u.gsm.ki), VTY_NEWLINE);
126 }
127
128 if (aud3g.algo != OSMO_AUTH_ALG_NONE && aud3g.type != OSMO_AUTH_TYPE_NONE) {
129 vty_out(vty, " 3G auth: %s%s", osmo_auth_alg_name(aud3g.algo), VTY_NEWLINE);
130 vty_out(vty, " K=%s%s", hexdump_buf(aud3g.u.umts.k), VTY_NEWLINE);
131 vty_out(vty, " %s=%s%s", aud3g.u.umts.opc_is_op? "OP" : "OPC",
132 hexdump_buf(aud3g.u.umts.opc), VTY_NEWLINE);
133 vty_out(vty, " IND-bitlen=%u", aud3g.u.umts.ind_bitlen);
134 if (aud3g.u.umts.sqn)
135 vty_out(vty, " last-SQN=%"PRIu64, aud3g.u.umts.sqn);
136 vty_out(vty, VTY_NEWLINE);
137 }
138}
139
140static int get_subscr_by_argv(struct vty *vty, const char *type, const char *id, struct hlr_subscriber *subscr)
141{
142 int rc = -1;
143 if (strcmp(type, "imsi") == 0)
144 rc = db_subscr_get_by_imsi(g_hlr->dbc, id, subscr);
145 else if (strcmp(type, "msisdn") == 0)
146 rc = db_subscr_get_by_msisdn(g_hlr->dbc, id, subscr);
147 else if (strcmp(type, "id") == 0)
148 rc = db_subscr_get_by_id(g_hlr->dbc, atoll(id), subscr);
149 if (rc)
150 vty_out(vty, "%% No subscriber for %s = '%s'%s",
151 type, id, VTY_NEWLINE);
152 return rc;
153}
154
155#define SUBSCR_CMD "subscriber "
156#define SUBSCR_CMD_HELP "Subscriber management commands\n"
157
Neels Hofmeyr8aa780b2018-12-02 18:52:49 +0100158#define SUBSCR_ID "(imsi|msisdn|id) IDENT"
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200159#define SUBSCR_ID_HELP \
160 "Identify subscriber by IMSI\n" \
161 "Identify subscriber by MSISDN (phone number)\n" \
162 "Identify subscriber by database ID\n" \
163 "IMSI/MSISDN/ID of the subscriber\n"
164
Neels Hofmeyr8aa780b2018-12-02 18:52:49 +0100165#define SUBSCR SUBSCR_CMD SUBSCR_ID " "
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200166#define SUBSCR_HELP SUBSCR_CMD_HELP SUBSCR_ID_HELP
167
168#define SUBSCR_UPDATE SUBSCR "update "
169#define SUBSCR_UPDATE_HELP SUBSCR_HELP "Set or update subscriber data\n"
Neels Hofmeyra820ea12018-12-02 19:46:46 +0100170#define SUBSCR_MSISDN_HELP "Set MSISDN (phone number) of the subscriber\n"
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200171
172DEFUN(subscriber_show,
173 subscriber_show_cmd,
174 SUBSCR "show",
175 SUBSCR_HELP "Show subscriber information\n")
176{
177 struct hlr_subscriber subscr;
178 const char *id_type = argv[0];
179 const char *id = argv[1];
180
181 if (get_subscr_by_argv(vty, id_type, id, &subscr))
182 return CMD_WARNING;
183
184 subscr_dump_full_vty(vty, &subscr);
185 return CMD_SUCCESS;
186}
187
Neels Hofmeyr8aa780b2018-12-02 18:52:49 +0100188ALIAS(subscriber_show, show_subscriber_cmd,
189 "show " SUBSCR_CMD SUBSCR_ID,
190 SHOW_STR SUBSCR_CMD_HELP SUBSCR_ID_HELP);
191
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200192DEFUN(subscriber_create,
193 subscriber_create_cmd,
194 SUBSCR_CMD "imsi IDENT create",
195 SUBSCR_CMD_HELP
Vadim Yanitskiyf473c7b2018-07-30 14:29:39 +0700196 "Identify subscriber by IMSI\n"
197 "IMSI/MSISDN/ID of the subscriber\n"
198 "Create subscriber by IMSI\n")
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200199{
200 int rc;
201 struct hlr_subscriber subscr;
202 const char *imsi = argv[0];
203
204 if (!osmo_imsi_str_valid(imsi)) {
205 vty_out(vty, "%% Not a valid IMSI: %s%s", imsi, VTY_NEWLINE);
206 return CMD_WARNING;
207 }
208
209 rc = db_subscr_create(g_hlr->dbc, imsi);
210
211 if (rc) {
212 if (rc == -EEXIST)
213 vty_out(vty, "%% Subscriber already exists for IMSI = %s%s",
214 imsi, VTY_NEWLINE);
215 else
216 vty_out(vty, "%% Error (rc=%d): cannot create subscriber for IMSI = %s%s",
217 rc, imsi, VTY_NEWLINE);
218 return CMD_WARNING;
219 }
220
221 rc = db_subscr_get_by_imsi(g_hlr->dbc, imsi, &subscr);
222 vty_out(vty, "%% Created subscriber %s%s", imsi, VTY_NEWLINE);
223
224 subscr_dump_full_vty(vty, &subscr);
225
226 return CMD_SUCCESS;
227}
228
229DEFUN(subscriber_delete,
230 subscriber_delete_cmd,
231 SUBSCR "delete",
232 SUBSCR_HELP "Delete subscriber from database\n")
233{
234 struct hlr_subscriber subscr;
235 int rc;
236 const char *id_type = argv[0];
237 const char *id = argv[1];
238
239 /* Find out the IMSI regardless of which way the caller decided to
240 * identify the subscriber by. */
241 if (get_subscr_by_argv(vty, id_type, id, &subscr))
242 return CMD_WARNING;
243
244 rc = db_subscr_delete_by_id(g_hlr->dbc, subscr.id);
245 if (rc) {
246 vty_out(vty, "%% Error: Failed to remove subscriber for IMSI '%s'%s",
247 subscr.imsi, VTY_NEWLINE);
248 return CMD_WARNING;
249 }
250
251 vty_out(vty, "%% Deleted subscriber for IMSI '%s'%s", subscr.imsi, VTY_NEWLINE);
252 return CMD_SUCCESS;
253}
254
255DEFUN(subscriber_msisdn,
256 subscriber_msisdn_cmd,
Neels Hofmeyra820ea12018-12-02 19:46:46 +0100257 SUBSCR_UPDATE "msisdn (none|MSISDN)",
258 SUBSCR_UPDATE_HELP SUBSCR_MSISDN_HELP
259 "Remove MSISDN (phone number)\n"
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200260 "New MSISDN (phone number)\n")
261{
262 struct hlr_subscriber subscr;
263 const char *id_type = argv[0];
264 const char *id = argv[1];
265 const char *msisdn = argv[2];
266
Neels Hofmeyra820ea12018-12-02 19:46:46 +0100267 if (strcmp(msisdn, "none") == 0)
268 msisdn = NULL;
269 else {
270 if (strlen(msisdn) > sizeof(subscr.msisdn) - 1) {
271 vty_out(vty, "%% MSISDN is too long, max. %zu characters are allowed%s",
272 sizeof(subscr.msisdn)-1, VTY_NEWLINE);
273 return CMD_WARNING;
274 }
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200275
Neels Hofmeyra820ea12018-12-02 19:46:46 +0100276 if (!osmo_msisdn_str_valid(msisdn)) {
277 vty_out(vty, "%% MSISDN invalid: '%s'%s", msisdn, VTY_NEWLINE);
278 return CMD_WARNING;
279 }
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200280 }
281
282 if (get_subscr_by_argv(vty, id_type, id, &subscr))
283 return CMD_WARNING;
284
285 if (db_subscr_update_msisdn_by_imsi(g_hlr->dbc, subscr.imsi, msisdn)) {
286 vty_out(vty, "%% Error: cannot update MSISDN for subscriber IMSI='%s'%s",
287 subscr.imsi, VTY_NEWLINE);
288 return CMD_WARNING;
289 }
290
Neels Hofmeyra820ea12018-12-02 19:46:46 +0100291 if (msisdn) {
292 vty_out(vty, "%% Updated subscriber IMSI='%s' to MSISDN='%s'%s",
293 subscr.imsi, msisdn, VTY_NEWLINE);
Stefan Sperlingf1622522018-04-09 11:39:16 +0200294
Neels Hofmeyra820ea12018-12-02 19:46:46 +0100295 if (db_subscr_get_by_msisdn(g_hlr->dbc, msisdn, &subscr) == 0)
296 osmo_hlr_subscriber_update_notify(&subscr);
297 } else {
298 vty_out(vty, "%% Updated subscriber IMSI='%s': removed MSISDN%s",
299 subscr.imsi, VTY_NEWLINE);
300
Stefan Sperlingf1622522018-04-09 11:39:16 +0200301 osmo_hlr_subscriber_update_notify(&subscr);
Neels Hofmeyra820ea12018-12-02 19:46:46 +0100302 }
Stefan Sperlingf1622522018-04-09 11:39:16 +0200303
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200304 return CMD_SUCCESS;
305}
306
307static bool is_hexkey_valid(struct vty *vty, const char *label,
308 const char *hex_str, int minlen, int maxlen)
309{
310 if (osmo_is_hexstr(hex_str, minlen * 2, maxlen * 2, true))
311 return true;
312 vty_out(vty, "%% Invalid value for %s: '%s'%s", label, hex_str, VTY_NEWLINE);
313 return false;
314}
315
316#define AUTH_ALG_TYPES_2G "(comp128v1|comp128v2|comp128v3|xor)"
317#define AUTH_ALG_TYPES_2G_HELP \
318 "Use COMP128v1 algorithm\n" \
319 "Use COMP128v2 algorithm\n" \
320 "Use COMP128v3 algorithm\n" \
321 "Use XOR algorithm\n"
322
323#define AUTH_ALG_TYPES_3G "milenage"
324#define AUTH_ALG_TYPES_3G_HELP \
325 "Use Milenage algorithm\n"
326
327#define A38_XOR_MIN_KEY_LEN 12
328#define A38_XOR_MAX_KEY_LEN 16
329#define A38_COMP128_KEY_LEN 16
330
331#define MILENAGE_KEY_LEN 16
332
333static bool auth_algo_parse(const char *alg_str, enum osmo_auth_algo *algo,
334 int *minlen, int *maxlen)
335{
336 if (!strcasecmp(alg_str, "none")) {
337 *algo = OSMO_AUTH_ALG_NONE;
338 *minlen = *maxlen = 0;
339 } else if (!strcasecmp(alg_str, "comp128v1")) {
340 *algo = OSMO_AUTH_ALG_COMP128v1;
341 *minlen = *maxlen = A38_COMP128_KEY_LEN;
342 } else if (!strcasecmp(alg_str, "comp128v2")) {
343 *algo = OSMO_AUTH_ALG_COMP128v2;
344 *minlen = *maxlen = A38_COMP128_KEY_LEN;
345 } else if (!strcasecmp(alg_str, "comp128v3")) {
346 *algo = OSMO_AUTH_ALG_COMP128v3;
347 *minlen = *maxlen = A38_COMP128_KEY_LEN;
348 } else if (!strcasecmp(alg_str, "xor")) {
349 *algo = OSMO_AUTH_ALG_XOR;
350 *minlen = A38_XOR_MIN_KEY_LEN;
351 *maxlen = A38_XOR_MAX_KEY_LEN;
352 } else if (!strcasecmp(alg_str, "milenage")) {
353 *algo = OSMO_AUTH_ALG_MILENAGE;
354 *minlen = *maxlen = MILENAGE_KEY_LEN;
355 } else
356 return false;
357 return true;
358}
359
360DEFUN(subscriber_no_aud2g,
361 subscriber_no_aud2g_cmd,
362 SUBSCR_UPDATE "aud2g none",
363 SUBSCR_UPDATE_HELP
364 "Set 2G authentication data\n"
365 "Delete 2G authentication data\n")
366{
367 struct hlr_subscriber subscr;
368 int rc;
369 const char *id_type = argv[0];
370 const char *id = argv[1];
371 struct sub_auth_data_str aud = {
372 .type = OSMO_AUTH_TYPE_GSM,
373 .algo = OSMO_AUTH_ALG_NONE,
374 };
375
376 if (get_subscr_by_argv(vty, id_type, id, &subscr))
377 return CMD_WARNING;
378
379 rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud);
380
Harald Welte880a34d2018-03-01 21:32:01 +0100381 if (rc && rc != -ENOENT) {
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200382 vty_out(vty, "%% Error: cannot disable 2G auth data for IMSI='%s'%s",
383 subscr.imsi, VTY_NEWLINE);
384 return CMD_WARNING;
385 }
386 return CMD_SUCCESS;
387}
388
389DEFUN(subscriber_aud2g,
390 subscriber_aud2g_cmd,
391 SUBSCR_UPDATE "aud2g " AUTH_ALG_TYPES_2G " ki KI",
392 SUBSCR_UPDATE_HELP
393 "Set 2G authentication data\n"
394 AUTH_ALG_TYPES_2G_HELP
395 "Set Ki Encryption Key\n" "Ki as 32 hexadecimal characters\n")
396{
397 struct hlr_subscriber subscr;
398 int rc;
399 int minlen = 0;
400 int maxlen = 0;
401 const char *id_type = argv[0];
402 const char *id = argv[1];
403 const char *alg_type = argv[2];
404 const char *ki = argv[3];
405 struct sub_auth_data_str aud2g = {
406 .type = OSMO_AUTH_TYPE_GSM,
407 .u.gsm.ki = ki,
408 };
409
410 if (!auth_algo_parse(alg_type, &aud2g.algo, &minlen, &maxlen)) {
411 vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
412 return CMD_WARNING;
413 }
414
415 if (!is_hexkey_valid(vty, "KI", aud2g.u.gsm.ki, minlen, maxlen))
416 return CMD_WARNING;
417
418 if (get_subscr_by_argv(vty, id_type, id, &subscr))
419 return CMD_WARNING;
420
421 rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud2g);
422
423 if (rc) {
424 vty_out(vty, "%% Error: cannot set 2G auth data for IMSI='%s'%s",
425 subscr.imsi, VTY_NEWLINE);
426 return CMD_WARNING;
427 }
428 return CMD_SUCCESS;
429}
430
431DEFUN(subscriber_no_aud3g,
432 subscriber_no_aud3g_cmd,
433 SUBSCR_UPDATE "aud3g none",
434 SUBSCR_UPDATE_HELP
435 "Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
436 "Delete 3G authentication data\n")
437{
438 struct hlr_subscriber subscr;
439 int rc;
440 const char *id_type = argv[0];
441 const char *id = argv[1];
442 struct sub_auth_data_str aud = {
443 .type = OSMO_AUTH_TYPE_UMTS,
444 .algo = OSMO_AUTH_ALG_NONE,
445 };
446
447 if (get_subscr_by_argv(vty, id_type, id, &subscr))
448 return CMD_WARNING;
449
450 rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud);
451
Harald Welte880a34d2018-03-01 21:32:01 +0100452 if (rc && rc != -ENOENT) {
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200453 vty_out(vty, "%% Error: cannot disable 3G auth data for IMSI='%s'%s",
454 subscr.imsi, VTY_NEWLINE);
455 return CMD_WARNING;
456 }
457 return CMD_SUCCESS;
458}
459
460DEFUN(subscriber_aud3g,
461 subscriber_aud3g_cmd,
462 SUBSCR_UPDATE "aud3g " AUTH_ALG_TYPES_3G
463 " k K"
464 " (op|opc) OP_C"
465 " [ind-bitlen] [<0-28>]",
466 SUBSCR_UPDATE_HELP
467 "Set UMTS authentication data (3G, and 2G with UMTS AKA)\n"
468 AUTH_ALG_TYPES_3G_HELP
469 "Set Encryption Key K\n" "K as 32 hexadecimal characters\n"
470 "Set OP key\n" "Set OPC key\n" "OP or OPC as 32 hexadecimal characters\n"
471 "Set IND bit length\n" "IND bit length value (default: 5)\n")
472{
473 struct hlr_subscriber subscr;
474 int minlen = 0;
475 int maxlen = 0;
476 int rc;
477 const char *id_type = argv[0];
478 const char *id = argv[1];
479 const char *alg_type = AUTH_ALG_TYPES_3G;
480 const char *k = argv[2];
481 bool opc_is_op = (strcasecmp("op", argv[3]) == 0);
482 const char *op_opc = argv[4];
483 int ind_bitlen = argc > 6? atoi(argv[6]) : 5;
484 struct sub_auth_data_str aud3g = {
485 .type = OSMO_AUTH_TYPE_UMTS,
486 .u.umts = {
487 .k = k,
488 .opc_is_op = opc_is_op,
489 .opc = op_opc,
490 .ind_bitlen = ind_bitlen,
491 },
492 };
493
494 if (!auth_algo_parse(alg_type, &aud3g.algo, &minlen, &maxlen)) {
495 vty_out(vty, "%% Unknown auth algorithm: '%s'%s", alg_type, VTY_NEWLINE);
496 return CMD_WARNING;
497 }
498
499 if (!is_hexkey_valid(vty, "K", aud3g.u.umts.k, minlen, maxlen))
500 return CMD_WARNING;
501
502 if (!is_hexkey_valid(vty, opc_is_op ? "OP" : "OPC", aud3g.u.umts.opc,
503 MILENAGE_KEY_LEN, MILENAGE_KEY_LEN))
504 return CMD_WARNING;
505
506 if (get_subscr_by_argv(vty, id_type, id, &subscr))
507 return CMD_WARNING;
508
509 rc = db_subscr_update_aud_by_id(g_hlr->dbc, subscr.id, &aud3g);
510
511 if (rc) {
512 vty_out(vty, "%% Error: cannot set 3G auth data for IMSI='%s'%s",
513 subscr.imsi, VTY_NEWLINE);
514 return CMD_WARNING;
515 }
516 return CMD_SUCCESS;
517}
518
Neels Hofmeyr2fb33f12018-12-26 01:49:53 +0100519DEFUN(subscriber_rat,
520 subscriber_rat_cmd,
521 SUBSCR_UPDATE "rat (geran-a|utran-iu) (allowed|forbidden)",
522 SUBSCR_UPDATE_HELP
523 "Allow or forbid specific Radio Access Types\n"
524 "Set access to GERAN-A\n"
525 "Set access to UTRAN-Iu\n"
526 "Allow access\n"
527 "Forbid access\n")
528{
529 struct hlr_subscriber subscr;
530 const char *id_type = argv[0];
531 const char *id = argv[1];
532 const char *rat_str = argv[2];
533 const char *allowed_forbidden = argv[3];
534 enum osmo_rat_type rat;
535 bool allowed;
536 int rc;
537
538 if (strcmp(rat_str, "geran-a") == 0)
539 rat = OSMO_RAT_GERAN_A;
540 else if (strcmp(rat_str, "utran-iu") == 0)
541 rat = OSMO_RAT_UTRAN_IU;
542
543 allowed = (strcmp(allowed_forbidden, "allowed") == 0);
544
545 if (get_subscr_by_argv(vty, id_type, id, &subscr))
546 return CMD_WARNING;
547
548 rc = hlr_subscr_rat_flag(g_hlr, &subscr, rat, allowed);
549
550 if (rc && rc != -ENOEXEC) {
551 vty_out(vty, "%% Error: cannot set %s to %s%s",
552 osmo_rat_type_name(rat), allowed ? "allowed" : "forbidden", VTY_NEWLINE);
553 return CMD_WARNING;
554 }
555 return CMD_SUCCESS;
556}
557
Harald Welted5807b82018-07-29 12:27:41 +0200558void hlr_vty_subscriber_init(void)
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200559{
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200560 install_element_ve(&subscriber_show_cmd);
Neels Hofmeyr8aa780b2018-12-02 18:52:49 +0100561 install_element_ve(&show_subscriber_cmd);
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200562 install_element(ENABLE_NODE, &subscriber_create_cmd);
563 install_element(ENABLE_NODE, &subscriber_delete_cmd);
564 install_element(ENABLE_NODE, &subscriber_msisdn_cmd);
565 install_element(ENABLE_NODE, &subscriber_no_aud2g_cmd);
566 install_element(ENABLE_NODE, &subscriber_aud2g_cmd);
567 install_element(ENABLE_NODE, &subscriber_no_aud3g_cmd);
568 install_element(ENABLE_NODE, &subscriber_aud3g_cmd);
Neels Hofmeyr2fb33f12018-12-26 01:49:53 +0100569 install_element(ENABLE_NODE, &subscriber_rat_cmd);
Neels Hofmeyr183e7002017-10-06 02:59:54 +0200570}