private Boolean UpdateChallenges(TSIP_Response response, Boolean acceptNewVector) { Boolean ret = true; TSIP_HeaderWWWAuthenticate WWW_Authenticate; // TSIP_HeaderProxyAuthenticate Proxy_Authenticate; /* RFC 2617 - HTTP Digest Session * * (A) The client response to a WWW-Authenticate challenge for a protection * space starts an authentication session with that protection space. * The authentication session lasts until the client receives another * WWW-Authenticate challenge from any server in the protection space. * * (B) The server may return a 401 response with a new nonce value, causing the client * to retry the request; by specifying stale=TRUE with this response, * the server tells the client to retry with the new nonce, but without * prompting for a new username and password. */ /* RFC 2617 - 1.2 Access Authentication Framework * The realm directive (case-insensitive) is required for all authentication schemes that issue a challenge. */ /* FIXME: As we perform the same task ==> Use only one loop. */ for (int i = 0; (WWW_Authenticate = (TSIP_HeaderWWWAuthenticate)response.GetHeaderAtIndex(TSIP_Header.tsip_header_type_t.WWW_Authenticate, i)) != null; i++) { Boolean isnew = true; foreach (TSIP_Challenge challenge in mChallenges) { //if(challenge.IProxy) //{ // continue; //} if (String.Equals(challenge.Realm, WWW_Authenticate.Realm, StringComparison.InvariantCultureIgnoreCase) && (WWW_Authenticate.Stale || acceptNewVector)) { /*== (B) ==*/ if (!(ret = challenge.Update(WWW_Authenticate.Scheme, WWW_Authenticate.Realm, WWW_Authenticate.Nonce, WWW_Authenticate.Opaque, WWW_Authenticate.Algorithm, WWW_Authenticate.Qop))) { return(ret); } else { isnew = false; continue; } } else { TSK_Debug.Error("Failed to handle new challenge"); return(false); } } if (isnew) { TSIP_Challenge challenge; if ((challenge = new TSIP_Challenge(this.Stack, false, WWW_Authenticate.Scheme, WWW_Authenticate.Realm, WWW_Authenticate.Nonce, WWW_Authenticate.Opaque, WWW_Authenticate.Algorithm, WWW_Authenticate.Qop)) != null) { mChallenges.Add(challenge); } else { TSK_Debug.Error("Failed to handle new challenge"); return(false); } } } return(ret); }
protected Int64 GetNewDelay(TSIP_Response response) { Int64 expires = mExpires; Int64 newdelay = expires; /* default value */ TSIP_Header hdr; int i; /*== NOTIFY with subscription-state header with expires parameter */ if (response.CSeq.RequestType == TSIP_Message.tsip_request_type_t.NOTIFY) { TSIP_HeaderSubscriptionState hdr_state = response.GetHeader(TSIP_Header.tsip_header_type_t.Subscription_State) as TSIP_HeaderSubscriptionState; if (hdr_state != null && hdr_state.Expires > 0) { expires = TSK_Time.Seconds2Milliseconds(hdr_state.Expires); goto compute; } } /*== Expires header */ if ((hdr = response.GetHeader(TSIP_Header.tsip_header_type_t.Expires)) != null) { expires = TSK_Time.Seconds2Milliseconds((hdr as TSIP_HeaderExpires).DeltaSeconds); goto compute; } /*== Contact header */ for (i = 0; (hdr = response.GetHeaderAtIndex(TSIP_Header.tsip_header_type_t.Contact, i)) != null; i++) { TSIP_HeaderContact contact = hdr as TSIP_HeaderContact; if (contact != null && contact.Uri != null) { String transport = TSK_Param.GetValueByName(contact.Uri.Params, "transport"); TSIP_Uri contactUri = this.Stack.GetContactUri(String.IsNullOrEmpty(transport) ? "udp" : transport); if (contactUri != null) { if (String.Equals(contact.Uri.UserName, contactUri.UserName) && String.Equals(contact.Uri.Host, contactUri.Host) && contact.Uri.Port == contactUri.Port) { if (contact.Expires >= 0) /* No expires parameter ==> -1*/ { expires = TSK_Time.Seconds2Milliseconds(contact.Expires); goto compute; } } } } } /* * 3GPP TS 24.229 - * * The UE shall reregister the public user identity either 600 seconds before the expiration time if the initial * registration was for greater than 1200 seconds, or when half of the time has expired if the initial registration * was for 1200 seconds or less. */ compute: expires = TSK_Time.Milliseconds2Seconds(expires); newdelay = (expires > 1200) ? (expires - 600) : (expires / 2); return(TSK_Time.Seconds2Milliseconds(newdelay)); }
/// <summary> /// Updates the dialog state: /// - Authorizations (using challenges from the @a response message) /// - State (early, established, disconnected, ...) /// - Routes (and Service-Route) /// - Target (remote) /// - ... /// </summary> /// <param name="response"></param> /// <returns></returns> protected Boolean UpdateWithResponse(TSIP_Response response) { if (response == null || response.To == null || response.CSeq == null) { return(false); } String tag = response.To.Tag; /* * 1xx (!100) or 2xx */ /* * 401 or 407 or 421 or 494 */ if (response.StatusCode == 401 || response.StatusCode == 407 || response.StatusCode == 421 || response.StatusCode == 494) { Boolean acceptNewVector; /* 3GPP IMS - Each authentication vector is used only once. * ==> Re-registration/De-registration ==> Allow 401/407 challenge. */ acceptNewVector = (response.CSeq.RequestType == TSIP_Message.tsip_request_type_t.REGISTER && this.State == tsip_dialog_state_t.Established); return(this.UpdateChallenges(response, acceptNewVector)); } else if (100 < response.StatusCode && response.StatusCode < 300) { tsip_dialog_state_t state = this.State; /* 1xx */ if (response.StatusCode <= 199) { if (String.IsNullOrEmpty(response.To.Tag)) { TSK_Debug.Error("Invalid tag parameter"); return(false); } state = tsip_dialog_state_t.Early; } /* 2xx */ else { state = tsip_dialog_state_t.Established; } /* Remote target */ { /* RFC 3261 12.2.1.2 Processing the Responses * When a UAC receives a 2xx response to a target refresh request, it * MUST replace the dialog's remote target URI with the URI from the * Contact header field in that response, if present. * * FIXME: Because PRACK/UPDATE sent before the session is established MUST have * the rigth target URI to be delivered to the UAS ==> Do not not check that we are connected */ if (response.CSeq.RequestType != TSIP_Message.tsip_request_type_t.REGISTER && response.Contact != null && response.Contact.Uri != null) { mUriRemoteTarget = response.Contact.Uri.Clone(true, false); } } /* Route sets */ { int index; TSIP_HeaderRecordRoute recordRoute; mRecordRoutes.Clear(); for (index = 0; (recordRoute = response.GetHeaderAtIndex(TSIP_Header.tsip_header_type_t.Record_Route, index) as TSIP_HeaderRecordRoute) != null; index++) { mRecordRoutes.Insert(0, recordRoute); /* Copy reversed. */ } } /* cseq + tags + ... */ if (this.State == tsip_dialog_state_t.Established && String.Equals(mTagRemote, tag, StringComparison.InvariantCultureIgnoreCase)) { return(true); } else { if (response.CSeq.RequestType != TSIP_Message.tsip_request_type_t.REGISTER && response.CSeq.RequestType != TSIP_Message.tsip_request_type_t.PUBLISH) { /* REGISTER and PUBLISH don't establish dialog */ mTagRemote = tag; } #if NEVER_EXECUTE_00 // PRACK and BYE will have same CSeq value ==> Let CSeq value to be incremented by "tsip_dialog_request_new()" self->cseq_value = response->CSeq ? response->CSeq->seq : self->cseq_value; #endif } this.State = state; return(true); } return(true); }