blob: cf6e4f845d95a7cd613de5f9579db40433927585 [file] [log] [blame]
Harald Weltee687be52016-05-03 18:49:27 +02001/* (C) 2015 by Harald Welte <laforge@gnumonks.org>
2 *
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
20#include <string.h>
Max00b37152017-02-20 11:09:27 +010021#include <errno.h>
Neels Hofmeyrf7c3e6e2017-10-09 17:55:16 +020022#include <inttypes.h>
Harald Weltee687be52016-05-03 18:49:27 +020023
24#include <osmocom/core/utils.h>
25#include <osmocom/crypt/auth.h>
Neels Hofmeyrf7c3e6e2017-10-09 17:55:16 +020026#include <osmocom/gsm/gsm23003.h>
Harald Weltee687be52016-05-03 18:49:27 +020027
28#include <sqlite3.h>
29
30#include "logging.h"
31#include "db.h"
32
Neels Hofmeyr40aa61c2017-10-09 17:56:04 +020033#define LOGHLR(imsi, level, fmt, args ...) LOGP(DAUC, level, "IMSI='%s': " fmt, imsi, ## args)
Harald Weltee687be52016-05-03 18:49:27 +020034
Neels Hofmeyr1e31d182017-10-10 23:20:09 +020035#define SL3_TXT(x, stmt, idx) \
36 do { \
37 const char *_txt = (const char *) sqlite3_column_text(stmt, idx);\
38 if (_txt) \
39 strncpy(x, _txt, sizeof(x)); \
40 x[sizeof(x)-1] = '\0'; \
41 } while (0)
Harald Weltee687be52016-05-03 18:49:27 +020042
Neels Hofmeyrf7c3e6e2017-10-09 17:55:16 +020043int db_subscr_create(struct db_context *dbc, const char *imsi)
44{
45 sqlite3_stmt *stmt;
46 int rc;
47
48 if (!osmo_imsi_str_valid(imsi)) {
49 LOGP(DAUC, LOGL_ERROR, "Cannot create subscriber: invalid IMSI: '%s'\n",
50 imsi);
51 return -EINVAL;
52 }
53
54 stmt = dbc->stmt[DB_STMT_SUBSCR_CREATE];
55
56 if (!db_bind_text(stmt, "$imsi", imsi))
57 return -EIO;
58
59 /* execute the statement */
60 rc = sqlite3_step(stmt);
61 db_remove_reset(stmt);
62 if (rc != SQLITE_DONE) {
63 LOGHLR(imsi, LOGL_ERROR, "Cannot create subscriber: SQL error: (%d) %s\n",
64 rc, sqlite3_errmsg(dbc->db));
65 return -EIO;
66 }
67
68 return 0;
69}
70
71int db_subscr_delete_by_id(struct db_context *dbc, int64_t subscr_id)
72{
73 int rc;
Neels Hofmeyr1332a172017-10-10 02:25:00 +020074 struct sub_auth_data_str aud;
Neels Hofmeyrf7c3e6e2017-10-09 17:55:16 +020075 int ret = 0;
76
77 sqlite3_stmt *stmt = dbc->stmt[DB_STMT_DEL_BY_ID];
78
79 if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
80 return -EIO;
81
82 /* execute the statement */
83 rc = sqlite3_step(stmt);
84 if (rc != SQLITE_DONE) {
85 LOGP(DAUC, LOGL_ERROR,
86 "Cannot delete subscriber ID=%"PRId64": SQL error: (%d) %s\n",
87 subscr_id, rc, sqlite3_errmsg(dbc->db));
88 db_remove_reset(stmt);
89 return -EIO;
90 }
91
92 /* verify execution result */
93 rc = sqlite3_changes(dbc->db);
94 if (!rc) {
95 LOGP(DAUC, LOGL_ERROR, "Cannot delete: no such subscriber: ID=%"PRId64"\n",
96 subscr_id);
97 ret = -ENOENT;
98 } else if (rc != 1) {
99 LOGP(DAUC, LOGL_ERROR, "Delete subscriber ID=%"PRId64
100 ": SQL modified %d rows (expected 1)\n", subscr_id, rc);
101 ret = -EIO;
102 }
Neels Hofmeyrf7c3e6e2017-10-09 17:55:16 +0200103 db_remove_reset(stmt);
Neels Hofmeyr1332a172017-10-10 02:25:00 +0200104
105 /* make sure to remove authentication data for this subscriber id, for
106 * both 2G and 3G. */
107
108 aud = (struct sub_auth_data_str){
109 .type = OSMO_AUTH_TYPE_GSM,
110 .algo = OSMO_AUTH_ALG_NONE,
111 };
112 rc = db_subscr_update_aud_by_id(dbc, subscr_id, &aud);
113 if (ret == -ENOENT && !rc)
114 ret = 0;
115
116 aud = (struct sub_auth_data_str){
117 .type = OSMO_AUTH_TYPE_UMTS,
118 .algo = OSMO_AUTH_ALG_NONE,
119 };
120 rc = db_subscr_update_aud_by_id(dbc, subscr_id, &aud);
121 if (ret == -ENOENT && !rc)
122 ret = 0;
123
Neels Hofmeyrf7c3e6e2017-10-09 17:55:16 +0200124 return ret;
125}
126
127int db_subscr_update_msisdn_by_imsi(struct db_context *dbc, const char *imsi,
128 const char *msisdn)
129{
130 int rc;
131 int ret = 0;
132
133 if (!osmo_msisdn_str_valid(msisdn)) {
134 LOGHLR(imsi, LOGL_ERROR,
135 "Cannot update subscriber: invalid MSISDN: '%s'\n",
136 msisdn);
137 return -EINVAL;
138 }
139
140 sqlite3_stmt *stmt = dbc->stmt[DB_STMT_SET_MSISDN_BY_IMSI];
141
142 if (!db_bind_text(stmt, "$imsi", imsi))
143 return -EIO;
144 if (!db_bind_text(stmt, "$msisdn", msisdn))
145 return -EIO;
146
147 /* execute the statement */
148 rc = sqlite3_step(stmt);
149 if (rc != SQLITE_DONE) {
150 LOGHLR(imsi, LOGL_ERROR,
151 "Cannot update subscriber's MSISDN: SQL error: (%d) %s\n",
152 rc, sqlite3_errmsg(dbc->db));
153 ret = -EIO;
154 goto out;
155 }
156
157 /* verify execution result */
158 rc = sqlite3_changes(dbc->db);
159 if (!rc) {
160 LOGP(DAUC, LOGL_ERROR, "Cannot update MSISDN: no such subscriber: IMSI='%s'\n",
161 imsi);
162 ret = -ENOENT;
163 goto out;
164 } else if (rc != 1) {
165 LOGHLR(imsi, LOGL_ERROR, "Update MSISDN: SQL modified %d rows (expected 1)\n", rc);
166 ret = -EIO;
167 }
168
169out:
170 db_remove_reset(stmt);
171 return ret;
172
173}
174
Neels Hofmeyr1332a172017-10-10 02:25:00 +0200175/* Insert or update 2G or 3G authentication tokens in the database.
176 * If aud->type is OSMO_AUTH_TYPE_GSM, the auc_2g table entry for the
177 * subscriber will be added or modified; if aud->algo is OSMO_AUTH_ALG_NONE,
178 * however, the auc_2g entry for the subscriber is deleted. If aud->type is
179 * OSMO_AUTH_TYPE_UMTS, the auc_3g table is updated; again, if aud->algo is
180 * OSMO_AUTH_ALG_NONE, the auc_3g entry is deleted.
181 * Returns 0 if successful, -EINVAL for unknown aud->type, -ENOENT for unknown
182 * subscr_id, -EIO for SQL errors.
183 */
184int db_subscr_update_aud_by_id(struct db_context *dbc, int64_t subscr_id,
185 const struct sub_auth_data_str *aud)
186{
187 sqlite3_stmt *stmt_del;
188 sqlite3_stmt *stmt_ins;
189 sqlite3_stmt *stmt;
190 const char *label;
191 int rc;
192 int ret = 0;
193
194 switch (aud->type) {
195 case OSMO_AUTH_TYPE_GSM:
196 label = "auc_2g";
197 stmt_del = dbc->stmt[DB_STMT_AUC_2G_DELETE];
198 stmt_ins = dbc->stmt[DB_STMT_AUC_2G_INSERT];
199
200 switch (aud->algo) {
201 case OSMO_AUTH_ALG_NONE:
202 case OSMO_AUTH_ALG_COMP128v1:
203 case OSMO_AUTH_ALG_COMP128v2:
204 case OSMO_AUTH_ALG_COMP128v3:
205 case OSMO_AUTH_ALG_XOR:
206 break;
207 case OSMO_AUTH_ALG_MILENAGE:
208 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
209 " auth algo not suited for 2G: %s\n",
210 osmo_auth_alg_name(aud->algo));
211 return -EINVAL;
212 default:
213 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
214 " Unknown auth algo: %d\n", aud->algo);
215 return -EINVAL;
216 }
217
218 if (aud->algo == OSMO_AUTH_ALG_NONE)
219 break;
220 if (!osmo_is_hexstr(aud->u.gsm.ki, 32, 32, true)) {
221 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
222 " Invalid KI: '%s'\n", aud->u.gsm.ki);
223 return -EINVAL;
224 }
225 break;
226
227 case OSMO_AUTH_TYPE_UMTS:
228 label = "auc_3g";
229 stmt_del = dbc->stmt[DB_STMT_AUC_3G_DELETE];
230 stmt_ins = dbc->stmt[DB_STMT_AUC_3G_INSERT];
231 switch (aud->algo) {
232 case OSMO_AUTH_ALG_NONE:
233 case OSMO_AUTH_ALG_MILENAGE:
234 break;
235 case OSMO_AUTH_ALG_COMP128v1:
236 case OSMO_AUTH_ALG_COMP128v2:
237 case OSMO_AUTH_ALG_COMP128v3:
238 case OSMO_AUTH_ALG_XOR:
239 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
240 " auth algo not suited for 3G: %s\n",
241 osmo_auth_alg_name(aud->algo));
242 return -EINVAL;
243 default:
244 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
245 " Unknown auth algo: %d\n", aud->algo);
246 return -EINVAL;
247 }
248
249 if (aud->algo == OSMO_AUTH_ALG_NONE)
250 break;
251 if (!osmo_is_hexstr(aud->u.umts.k, 32, 32, true)) {
252 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
253 " Invalid K: '%s'\n", aud->u.umts.k);
254 return -EINVAL;
255 }
256 if (!osmo_is_hexstr(aud->u.umts.opc, 32, 32, true)) {
257 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
258 " Invalid OP/OPC: '%s'\n", aud->u.umts.opc);
259 return -EINVAL;
260 }
261 if (aud->u.umts.ind_bitlen > OSMO_MILENAGE_IND_BITLEN_MAX) {
262 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
263 " Invalid ind_bitlen: %d\n", aud->u.umts.ind_bitlen);
264 return -EINVAL;
265 }
266 break;
267 default:
268 LOGP(DAUC, LOGL_ERROR, "Cannot update auth tokens:"
269 " unknown auth type: %d\n", aud->type);
270 return -EINVAL;
271 }
272
273 stmt = stmt_del;
274
275 if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
276 return -EIO;
277
278 /* execute the statement */
279 rc = sqlite3_step(stmt);
280 if (rc != SQLITE_DONE) {
281 LOGP(DAUC, LOGL_ERROR,
282 "Cannot delete %s row: SQL error: (%d) %s\n",
283 label, rc, sqlite3_errmsg(dbc->db));
284 ret = -EIO;
285 goto out;
286 }
287
288 /* verify execution result */
289 rc = sqlite3_changes(dbc->db);
290 if (!rc)
291 /* Leave "no such entry" logging to the caller -- during
292 * db_subscr_delete_by_id(), we call this to make sure it is
293 * empty, and no entry is not an error then.*/
294 ret = -ENOENT;
295 else if (rc != 1) {
296 LOGP(DAUC, LOGL_ERROR, "Delete subscriber ID=%"PRId64
297 " from %s: SQL modified %d rows (expected 1)\n",
298 subscr_id, label, rc);
299 ret = -EIO;
300 }
301
302 db_remove_reset(stmt);
303
304 /* Error situation? Return now. */
305 if (ret && ret != -ENOENT)
306 return ret;
307
308 /* Just delete requested? */
309 if (aud->algo == OSMO_AUTH_ALG_NONE)
310 return ret;
311
312 /* Don't return -ENOENT if inserting new data. */
313 ret = 0;
314
315 /* Insert new row */
316 stmt = stmt_ins;
317
318 if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
319 return -EIO;
320
321 switch (aud->type) {
322 case OSMO_AUTH_TYPE_GSM:
323 if (!db_bind_int(stmt, "$algo_id_2g", aud->algo))
324 return -EIO;
325 if (!db_bind_text(stmt, "$ki", aud->u.gsm.ki))
326 return -EIO;
327 break;
328 case OSMO_AUTH_TYPE_UMTS:
329 if (!db_bind_int(stmt, "$algo_id_3g", aud->algo))
330 return -EIO;
331 if (!db_bind_text(stmt, "$k", aud->u.umts.k))
332 return -EIO;
333 if (!db_bind_text(stmt, "$op",
334 aud->u.umts.opc_is_op ? aud->u.umts.opc : NULL))
335 return -EIO;
336 if (!db_bind_text(stmt, "$opc",
337 aud->u.umts.opc_is_op ? NULL : aud->u.umts.opc))
338 return -EIO;
339 if (!db_bind_int(stmt, "$ind_bitlen", aud->u.umts.ind_bitlen))
340 return -EIO;
341 break;
342 default:
343 OSMO_ASSERT(false);
344 }
345
346 /* execute the statement */
347 rc = sqlite3_step(stmt);
348 if (rc != SQLITE_DONE) {
349 LOGP(DAUC, LOGL_ERROR,
350 "Cannot insert %s row: SQL error: (%d) %s\n",
351 label, rc, sqlite3_errmsg(dbc->db));
352 ret = -EIO;
353 goto out;
354 }
355
356out:
357 db_remove_reset(stmt);
358 return ret;
359}
360
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200361/* Common code for db_subscr_get_by_*() functions. */
362static int db_sel(struct db_context *dbc, sqlite3_stmt *stmt, struct hlr_subscriber *subscr,
363 const char **err)
Harald Weltee687be52016-05-03 18:49:27 +0200364{
Maxadc66482017-02-20 11:23:20 +0100365 int rc;
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200366 int ret = 0;
Harald Weltee687be52016-05-03 18:49:27 +0200367
368 /* execute the statement */
369 rc = sqlite3_step(stmt);
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200370 if (rc == SQLITE_DONE) {
371 ret = -ENOENT;
372 goto out;
373 }
Harald Weltee687be52016-05-03 18:49:27 +0200374 if (rc != SQLITE_ROW) {
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200375 ret = -EIO;
376 goto out;
Maxadc66482017-02-20 11:23:20 +0100377 }
378
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200379 if (!subscr)
380 goto out;
Harald Weltee687be52016-05-03 18:49:27 +0200381
Neels Hofmeyrb6837e32017-10-10 23:20:26 +0200382 *subscr = (struct hlr_subscriber){};
383
Harald Weltee687be52016-05-03 18:49:27 +0200384 /* obtain the various columns */
385 subscr->id = sqlite3_column_int64(stmt, 0);
386 SL3_TXT(subscr->imsi, stmt, 1);
387 SL3_TXT(subscr->msisdn, stmt, 2);
Harald Welte99909272016-05-05 18:24:15 +0200388 /* FIXME: These should all be BLOBs as they might contain NUL */
Harald Weltee687be52016-05-03 18:49:27 +0200389 SL3_TXT(subscr->vlr_number, stmt, 3);
390 SL3_TXT(subscr->sgsn_number, stmt, 4);
391 SL3_TXT(subscr->sgsn_address, stmt, 5);
392 subscr->periodic_lu_timer = sqlite3_column_int(stmt, 6);
393 subscr->periodic_rau_tau_timer = sqlite3_column_int(stmt, 7);
394 subscr->nam_cs = sqlite3_column_int(stmt, 8);
395 subscr->nam_ps = sqlite3_column_int(stmt, 9);
396 subscr->lmsi = sqlite3_column_int(stmt, 10);
397 subscr->ms_purged_cs = sqlite3_column_int(stmt, 11);
398 subscr->ms_purged_ps = sqlite3_column_int(stmt, 12);
399
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200400out:
Max00b37152017-02-20 11:09:27 +0100401 db_remove_reset(stmt);
Harald Weltee687be52016-05-03 18:49:27 +0200402
Neels Hofmeyr9c2bbc82017-10-09 17:30:32 +0200403 switch (ret) {
404 case 0:
405 *err = NULL;
406 break;
407 case -ENOENT:
408 *err = "No such subscriber";
409 break;
410 default:
411 *err = sqlite3_errmsg(dbc->db);
412 break;
413 }
414 return ret;
415}
416
417int db_subscr_get_by_imsi(struct db_context *dbc, const char *imsi,
418 struct hlr_subscriber *subscr)
419{
420 sqlite3_stmt *stmt = dbc->stmt[DB_STMT_SEL_BY_IMSI];
421 const char *err;
422 int rc;
423
424 if (!db_bind_text(stmt, NULL, imsi))
425 return -EIO;
426
427 rc = db_sel(dbc, stmt, subscr, &err);
428 if (rc)
429 LOGP(DAUC, LOGL_ERROR, "Cannot read subscriber from db: IMSI='%s': %s\n",
430 imsi, err);
431 return rc;
432}
433
434int db_subscr_get_by_msisdn(struct db_context *dbc, const char *msisdn,
435 struct hlr_subscriber *subscr)
436{
437 sqlite3_stmt *stmt = dbc->stmt[DB_STMT_SEL_BY_MSISDN];
438 const char *err;
439 int rc;
440
441 if (!db_bind_text(stmt, NULL, msisdn))
442 return -EIO;
443
444 rc = db_sel(dbc, stmt, subscr, &err);
445 if (rc)
446 LOGP(DAUC, LOGL_ERROR, "Cannot read subscriber from db: MSISDN='%s': %s\n",
447 msisdn, err);
448 return rc;
449}
450
451int db_subscr_get_by_id(struct db_context *dbc, int64_t id,
452 struct hlr_subscriber *subscr)
453{
454 sqlite3_stmt *stmt = dbc->stmt[DB_STMT_SEL_BY_ID];
455 const char *err;
456 int rc;
457
458 if (!db_bind_int64(stmt, NULL, id))
459 return -EIO;
460
461 rc = db_sel(dbc, stmt, subscr, &err);
462 if (rc)
463 LOGP(DAUC, LOGL_ERROR, "Cannot read subscriber from db: ID=%"PRId64": %s\n",
464 id, err);
465 return rc;
Harald Weltee687be52016-05-03 18:49:27 +0200466}
467
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200468/* Enable or disable PS or CS for a subscriber.
469 * For the subscriber with the given imsi, set nam_ps (when is_ps == true) or
470 * nam_cs (when is_ps == false) to nam_val in the database.
471 * Returns 0 on success, -ENOENT when the given IMSI does not exist, -EINVAL if
472 * the SQL statement could not be composed, -ENOEXEC if running the SQL
473 * statement failed, -EIO if the amount of rows modified is unexpected.
474 */
475int db_subscr_nam(struct db_context *dbc, const char *imsi, bool nam_val, bool is_ps)
Max3ce36862017-02-20 11:18:04 +0100476{
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200477 sqlite3_stmt *stmt;
Max3ce36862017-02-20 11:18:04 +0100478 int rc;
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200479 int ret = 0;
Max3ce36862017-02-20 11:18:04 +0100480
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200481 stmt = dbc->stmt[is_ps ? DB_STMT_UPD_NAM_PS_BY_IMSI
482 : DB_STMT_UPD_NAM_CS_BY_IMSI];
Max3ce36862017-02-20 11:18:04 +0100483
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200484 if (!db_bind_text(stmt, "$imsi", imsi))
485 return -EIO;
486 if (!db_bind_int(stmt, "$val", nam_val ? 1 : 0))
487 return -EIO;
488
489 /* execute the statement */
490 rc = sqlite3_step(stmt);
Max3ce36862017-02-20 11:18:04 +0100491 if (rc != SQLITE_DONE) {
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200492 LOGHLR(imsi, LOGL_ERROR, "%s %s: SQL error: %s\n",
493 nam_val ? "enable" : "disable",
494 is_ps ? "PS" : "CS",
495 sqlite3_errmsg(dbc->db));
496 ret = -EIO;
497 goto out;
Max3ce36862017-02-20 11:18:04 +0100498 }
499
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200500 /* verify execution result */
501 rc = sqlite3_changes(dbc->db);
502 if (!rc) {
503 LOGP(DAUC, LOGL_ERROR, "Cannot %s %s: no such subscriber: IMSI='%s'\n",
504 nam_val ? "enable" : "disable",
505 is_ps ? "PS" : "CS",
506 imsi);
507 ret = -ENOENT;
508 goto out;
509 } else if (rc != 1) {
510 LOGHLR(imsi, LOGL_ERROR, "%s %s: SQL modified %d rows (expected 1)\n",
511 nam_val ? "enable" : "disable",
512 is_ps ? "PS" : "CS",
Max3ce36862017-02-20 11:18:04 +0100513 rc);
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200514 ret = -EIO;
Max3ce36862017-02-20 11:18:04 +0100515 }
516
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200517out:
Max3ce36862017-02-20 11:18:04 +0100518 db_remove_reset(stmt);
Neels Hofmeyre8ccd502017-10-06 04:10:06 +0200519 return ret;
Max3ce36862017-02-20 11:18:04 +0100520}
521
Neels Hofmeyrdd783052017-10-09 17:36:08 +0200522int db_subscr_lu(struct db_context *dbc, int64_t subscr_id,
523 const char *vlr_or_sgsn_number, bool is_ps)
Harald Weltee687be52016-05-03 18:49:27 +0200524{
Neels Hofmeyrdd783052017-10-09 17:36:08 +0200525 sqlite3_stmt *stmt;
Harald Weltee687be52016-05-03 18:49:27 +0200526 int rc, ret = 0;
527
Neels Hofmeyrdd783052017-10-09 17:36:08 +0200528 stmt = dbc->stmt[is_ps ? DB_STMT_UPD_SGSN_BY_ID
529 : DB_STMT_UPD_VLR_BY_ID];
Harald Weltee687be52016-05-03 18:49:27 +0200530
Neels Hofmeyrdd783052017-10-09 17:36:08 +0200531 if (!db_bind_int64(stmt, "$subscriber_id", subscr_id))
532 return -EIO;
Harald Weltee687be52016-05-03 18:49:27 +0200533
Neels Hofmeyrdd783052017-10-09 17:36:08 +0200534 if (!db_bind_text(stmt, "$number", vlr_or_sgsn_number))
535 return -EIO;
Harald Weltee687be52016-05-03 18:49:27 +0200536
537 /* execute the statement */
538 rc = sqlite3_step(stmt);
539 if (rc != SQLITE_DONE) {
Neels Hofmeyrdd783052017-10-09 17:36:08 +0200540 LOGP(DAUC, LOGL_ERROR, "Update %s number for subscriber ID=%"PRId64": SQL Error: %s\n",
541 is_ps? "SGSN" : "VLR", subscr_id, sqlite3_errmsg(dbc->db));
542 ret = -EIO;
543 goto out;
Harald Weltee687be52016-05-03 18:49:27 +0200544 }
Neels Hofmeyrdd783052017-10-09 17:36:08 +0200545
546 /* verify execution result */
547 rc = sqlite3_changes(dbc->db);
548 if (!rc) {
549 LOGP(DAUC, LOGL_ERROR, "Cannot update %s number for subscriber ID=%"PRId64
550 ": no such subscriber\n",
551 is_ps? "SGSN" : "VLR", subscr_id);
552 ret = -ENOENT;
553 } else if (rc != 1) {
554 LOGP(DAUC, LOGL_ERROR, "Update %s number for subscriber ID=%"PRId64
555 ": SQL modified %d rows (expected 1)\n",
556 is_ps? "SGSN" : "VLR", subscr_id, rc);
557 ret = -EIO;
558 }
559
Harald Weltee687be52016-05-03 18:49:27 +0200560out:
Max00b37152017-02-20 11:09:27 +0100561 db_remove_reset(stmt);
Harald Weltee687be52016-05-03 18:49:27 +0200562 return ret;
563}
Harald Welteb18f0e02016-05-05 21:03:03 +0200564
Neels Hofmeyre50121e2017-10-09 17:48:51 +0200565int db_subscr_purge(struct db_context *dbc, const char *by_imsi,
566 bool purge_val, bool is_ps)
Harald Welteb18f0e02016-05-05 21:03:03 +0200567{
Neels Hofmeyre50121e2017-10-09 17:48:51 +0200568 sqlite3_stmt *stmt;
569 int rc, ret = 0;
Harald Welteb18f0e02016-05-05 21:03:03 +0200570
Neels Hofmeyre50121e2017-10-09 17:48:51 +0200571 stmt = dbc->stmt[is_ps ? DB_STMT_UPD_PURGE_PS_BY_IMSI
572 : DB_STMT_UPD_PURGE_CS_BY_IMSI];
Harald Welteb18f0e02016-05-05 21:03:03 +0200573
Neels Hofmeyre50121e2017-10-09 17:48:51 +0200574 if (!db_bind_text(stmt, "$imsi", by_imsi))
575 return -EIO;
576 if (!db_bind_int(stmt, "$val", purge_val ? 1 : 0))
577 return -EIO;
Harald Welteb18f0e02016-05-05 21:03:03 +0200578
579 /* execute the statement */
580 rc = sqlite3_step(stmt);
581 if (rc != SQLITE_DONE) {
Neels Hofmeyre50121e2017-10-09 17:48:51 +0200582 LOGP(DAUC, LOGL_ERROR, "%s %s: SQL error: %s\n",
583 purge_val ? "purge" : "un-purge",
584 is_ps ? "PS" : "CS",
585 sqlite3_errmsg(dbc->db));
586 ret = -EIO;
587 goto out;
Harald Welteb18f0e02016-05-05 21:03:03 +0200588 }
Max00b37152017-02-20 11:09:27 +0100589
Neels Hofmeyre50121e2017-10-09 17:48:51 +0200590 /* verify execution result */
591 rc = sqlite3_changes(dbc->db);
592 if (!rc) {
593 LOGP(DAUC, LOGL_ERROR, "Cannot %s %s: no such subscriber: IMSI='%s'\n",
594 purge_val ? "purge" : "un-purge",
595 is_ps ? "PS" : "CS",
596 by_imsi);
597 ret = -ENOENT;
598 goto out;
599 } else if (rc != 1) {
600 LOGHLR(by_imsi, LOGL_ERROR, "%s %s: SQL modified %d rows (expected 1)\n",
601 purge_val ? "purge" : "un-purge",
602 is_ps ? "PS" : "CS",
603 rc);
604 ret = -EIO;
605 }
606
607out:
Max00b37152017-02-20 11:09:27 +0100608 db_remove_reset(stmt);
Harald Welteb18f0e02016-05-05 21:03:03 +0200609
610 return ret;
611}