diff options
author | Jacob Erlbeck <jerlbeck@sysmocom.de> | 2014-11-28 14:55:25 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-12-24 16:50:30 +0100 |
commit | 98a95ac17f701d94d2fa62d91cfe42a5beef4f23 (patch) | |
tree | a41eba64f19692721521dc927b258387d9151828 /openbsc/src/gprs/sgsn_auth.c | |
parent | 7921ab1593f45f12588e074ad1280472416ae930 (diff) |
sgsn: Add a subscriber based authentication phase
This implements the MAP way of subscriber validation when the MS
tries to perform an Attach Request:
1. perform authentication (optionally invoke the sendAuthInfo
procedure), starts the Auth & Ciph procedure
2. perform update location
3. insert subscriber data
4. finish the update location
5. Attach Accept / Attach Reject
The authentication triplets are used and eventually updated if all of
them have been used.
This is currently accessible via the VTY interface by the following
commands:
- update-subscriber imsi IMSI update-auth-info
- update-subscriber imsi IMSI update-location-result (ok|ERR-CAUSE)
Sponsored-by: On-Waves ehf
Diffstat (limited to 'openbsc/src/gprs/sgsn_auth.c')
-rw-r--r-- | openbsc/src/gprs/sgsn_auth.c | 79 |
1 files changed, 69 insertions, 10 deletions
diff --git a/openbsc/src/gprs/sgsn_auth.c b/openbsc/src/gprs/sgsn_auth.c index b065c061a..3755a51d4 100644 --- a/openbsc/src/gprs/sgsn_auth.c +++ b/openbsc/src/gprs/sgsn_auth.c @@ -23,7 +23,7 @@ #include <openbsc/gprs_sgsn.h> #include <openbsc/gprs_gmm.h> #include <openbsc/gsm_subscriber.h> - +#include <openbsc/gsm_04_08_gprs.h> #include <openbsc/debug.h> const struct value_string auth_state_names[] = { @@ -107,11 +107,12 @@ enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mmctx) if (!mmctx->subscr) return mmctx->auth_state; - if (mmctx->subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING) + if (mmctx->subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING_MASK) return mmctx->auth_state; if (mmctx->subscr->sgsn_data->authenticate && - !mmctx->is_authenticated) + (!mmctx->is_authenticated || + mmctx->subscr->sgsn_data->auth_triplets_updated)) return SGSN_AUTH_AUTHENTICATE; if (mmctx->subscr->authorized) @@ -141,20 +142,60 @@ enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mmctx) return SGSN_AUTH_REJECTED; } +/* + * This function is directly called by e.g. the GMM layer. It returns either + * after calling sgsn_auth_update directly or after triggering an asynchronous + * procedure which will call sgsn_auth_update later on. + */ int sgsn_auth_request(struct sgsn_mm_ctx *mmctx) { + struct gsm_subscriber *subscr; + struct gsm_auth_tuple *at; + int need_update_location; + int rc; + LOGMMCTXP(LOGL_DEBUG, mmctx, "Requesting authorization\n"); - if (sgsn->cfg.auth_policy == SGSN_AUTH_POLICY_REMOTE && !mmctx->subscr) { - if (gprs_subscr_request_update(mmctx) >= 0) { + if (sgsn->cfg.auth_policy != SGSN_AUTH_POLICY_REMOTE) { + sgsn_auth_update(mmctx); + return 0; + } + + need_update_location = + mmctx->subscr == NULL || + mmctx->pending_req == GSM48_MT_GMM_ATTACH_REQ; + + /* This has the side effect of registering the subscr with the mmctx */ + subscr = gprs_subscr_get_or_create_by_mmctx(mmctx); + subscr_put(subscr); + + OSMO_ASSERT(mmctx->subscr != NULL); + + if (mmctx->subscr->sgsn_data->authenticate && !mmctx->is_authenticated) { + /* Find next tuple */ + at = sgsn_auth_get_tuple(mmctx, mmctx->auth_triplet.key_seq); + + if (!at) { + /* No valid tuple found, request fresh ones */ + mmctx->auth_triplet.key_seq = GSM_KEY_SEQ_INVAL; LOGMMCTXP(LOGL_INFO, mmctx, - "Missing information, requesting subscriber data\n"); - return 0; + "Requesting authentication tuples\n"); + rc = gprs_subscr_request_auth_info(mmctx); + if (rc >= 0) + return 0; + + return rc; } + + mmctx->auth_triplet = *at; + } else if (need_update_location) { + LOGMMCTXP(LOGL_INFO, mmctx, + "Missing information, requesting subscriber data\n"); + if (gprs_subscr_request_update_location(mmctx) >= 0) + return 0; } sgsn_auth_update(mmctx); - return 0; } @@ -162,6 +203,7 @@ void sgsn_auth_update(struct sgsn_mm_ctx *mmctx) { enum sgsn_auth_state auth_state; struct gsm_subscriber *subscr = mmctx->subscr; + struct gsm_auth_tuple *at; auth_state = sgsn_auth_state(mmctx); @@ -170,13 +212,27 @@ void sgsn_auth_update(struct sgsn_mm_ctx *mmctx) get_value_string(sgsn_auth_state_names, auth_state)); if (auth_state == SGSN_AUTH_UNKNOWN && subscr && - !(subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING)) { - /* Reject requests if gprs_subscr_request_update fails */ + !(subscr->flags & GPRS_SUBSCRIBER_UPDATE_PENDING_MASK)) { + /* Reject requests if gprs_subscr_request_update_location fails */ LOGMMCTXP(LOGL_ERROR, mmctx, "Missing information, authorization not possible\n"); auth_state = SGSN_AUTH_REJECTED; } + if (auth_state == SGSN_AUTH_AUTHENTICATE && + mmctx->auth_triplet.key_seq == GSM_KEY_SEQ_INVAL) { + /* The current tuple is not valid, but we are possibly called + * because new auth tuples have been received */ + at = sgsn_auth_get_tuple(mmctx, mmctx->auth_triplet.key_seq); + if (!at) { + LOGMMCTXP(LOGL_ERROR, mmctx, + "Missing auth tuples, authorization not possible\n"); + auth_state = SGSN_AUTH_REJECTED; + } else { + mmctx->auth_triplet = *at; + } + } + if (mmctx->auth_state == auth_state) return; @@ -188,6 +244,9 @@ void sgsn_auth_update(struct sgsn_mm_ctx *mmctx) switch (auth_state) { case SGSN_AUTH_AUTHENTICATE: + if (subscr) + subscr->sgsn_data->auth_triplets_updated = 0; + gsm0408_gprs_authenticate(mmctx); break; case SGSN_AUTH_ACCEPTED: |