1 /*
2  * Copyright (C) 2012 Smile Communications, jason.penton@smilecoms.com
3  * Copyright (C) 2012 Smile Communications, richard.good@smilecoms.com
4  *
5  * The initial version of this code was written by Dragos Vingarzan
6  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
7  * Fruanhofer Institute. It was and still is maintained in a separate
8  * branch of the original SER. We are therefore migrating it to
9  * Kamailio/SR and look forward to maintaining it from here on out.
10  * 2011/2012 Smile Communications, Pty. Ltd.
11  * ported/maintained/improved by
12  * Jason Penton (jason(dot)penton(at)smilecoms.com and
13  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an
14  * effort to add full IMS support to Kamailio/SR using a new and
15  * improved architecture
16  *
17  * NB: Alot of this code was originally part of OpenIMSCore,
18  * FhG Fokus.
19  * Copyright (C) 2004-2006 FhG Fokus
20  * Thanks for great work! This is an effort to
21  * break apart the various CSCF functions into logically separate
22  * components. We hope this will drive wider use. We also feel
23  * that in this way the architecture is more complete and thereby easier
24  * to manage in the Kamailio/SR environment
25  *
26  * This file is part of Kamailio, a free SIP server.
27  *
28  * Kamailio is free software; you can redistribute it and/or modify
29  * it under the terms of the GNU General Public License as published by
30  * the Free Software Foundation; either version 2 of the License, or
31  * (at your option) any later version
32  *
33  * Kamailio is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
41  *
42  */
43 
44 #include "stats.h"
45 #include "../cdp/cdp_load.h"
46 #include "../../modules/tm/tm_load.h"
47 #include "../../modules/ims_dialog/dlg_load.h"
48 #include "api.h"
49 #include "cxdx_avp.h"
50 
51 #include "cxdx_mar.h"
52 #include "authorize.h"
53 #include "../../lib/ims/ims_getters.h"
54 #include "utils.h"
55 #include "pvt_message.h"
56 
57 static str empty_s = {0, 0};
58 static str s_empty = {0, 0};
59 extern str auth_scheme_types[];
60 extern str scscf_name_str;
61 extern struct _pv_req_data _pv_treq;
62 
63 //we use pseudo variables to communicate back to config file this takes the result and converys to a return code, publishes it a pseudo variable
64 
create_return_code(int result)65 int create_return_code(int result) {
66     int rc;
67     int_str avp_val, avp_name;
68     avp_name.s.s = "maa_return_code";
69     avp_name.s.len = 15;
70 
71     //build avp spec for uaa_return_code
72     avp_val.n = result;
73 
74     rc = add_avp(AVP_NAME_STR, avp_name, avp_val);
75 
76     if (rc < 0)
77         LM_ERR("couldnt create AVP\n");
78     else
79         LM_INFO("created AVP successfully : [%.*s] - [%d]\n", avp_name.s.len, avp_name.s.s, result);
80 
81     return 1;
82 }
83 
free_saved_transaction_data(saved_transaction_t * data)84 void free_saved_transaction_data(saved_transaction_t* data) {
85     if (!data)
86         return;
87     LM_DBG("Freeing saved transaction data: async\n");
88     if (data->realm.s && data->realm.len) {
89         shm_free(data->realm.s);
90         data->realm.len = 0;
91     }
92 
93     shm_free(data);
94 }
95 
async_cdp_callback(int is_timeout,void * param,AAAMessage * maa,long elapsed_msecs)96 void async_cdp_callback(int is_timeout, void *param, AAAMessage *maa, long elapsed_msecs) {
97     int i, j;
98     int rc = -1, experimental_rc = -1;
99     saved_transaction_t* data = (saved_transaction_t*) param;
100     struct cell *t = 0;
101     int result = CSCF_RETURN_TRUE;
102     int sip_number_auth_items;
103     int items_found = 0;
104     struct auth_data_item_list *adi_list = 0;
105     AAA_AVP *auth_data;
106 	AAA_AVP* avp;
107     auth_data = 0;
108     int item_number;
109     str authenticate = {0, 0}, authorization2 = {0, 0}, ck = {0, 0}, ik = {0, 0}, ip = {0, 0}, ha1 = {0, 0};
110     str line_identifier = {0, 0};
111     str response_auth = {0, 0}, digest_realm = {0, 0};
112     auth_vector *av = 0, **avlist = 0;
113     HASHHEX ha1_hex;
114     HASHHEX result_hex;
115     str etsi_nonce = {0, 0};
116     str private_identity = {0,0};
117 	str public_identity = {0,0};
118     str algorithm;
119     struct sip_msg* req;
120 
121 
122     if (is_timeout) {
123     	update_stat(stat_mar_timeouts, 1);
124         LM_ERR("Transaction timeout - did not get MAA\n");
125         result = CSCF_RETURN_ERROR;
126         goto error;
127     }
128     if (!maa) {
129         LM_ERR("Error sending message via CDP\n");
130         result = CSCF_RETURN_ERROR;
131         goto error;
132     }
133 
134     update_stat(mar_replies_received, 1);
135     update_stat(mar_replies_response_time, elapsed_msecs);
136 
137     if (tmb.t_lookup_ident(&t, data->tindex, data->tlabel) < 0) {
138         LM_ERR("t_continue: transaction not found\n");
139         result = CSCF_RETURN_ERROR;
140         goto error1;
141     }
142 
143     req = get_request_from_tx(t);
144     if (req == NULL) {
145         goto error;
146     }
147 
148     /* get the private_identity */
149 	private_identity = cxdx_get_user_name(maa);
150 	if (!private_identity.len) {
151         LM_ERR("No private identity specified (Authorization: username)\n");
152         stateful_request_reply_async(t, req, 403, MSG_403_NO_PRIVATE);
153         result = CSCF_RETURN_FALSE;
154         goto error;
155     }
156 
157        /* get the public_identity */
158 	avp = cxdx_get_next_public_identity(maa, 0, AVP_IMS_Public_Identity,IMS_vendor_id_3GPP,__FUNCTION__);
159 	if (avp) {
160 		public_identity = avp->data;
161 	}
162 	if (!public_identity.len) {
163         LM_ERR("No public identity specified (To:)\n");
164         stateful_request_reply_async(t, req, 403, MSG_403_NO_PUBLIC);
165         result = CSCF_RETURN_FALSE;
166         goto error;
167     }
168 
169 
170     //get each individual element from the MAA
171     cxdx_get_result_code(maa, &rc);
172     cxdx_get_experimental_result_code(maa, &experimental_rc);
173 
174     if (!cxdx_get_sip_number_auth_items(maa, &sip_number_auth_items)) {
175        sip_number_auth_items = 0;
176     }
177 
178     if (sip_number_auth_items > 0) {
179 	    //now assign the auth_data_item elements
180 	    //there can be many of these in the MAA
181 	    struct auth_data_item *adi;
182 	    int adi_len;
183 	    char *p;
184 	    while ((cxdx_get_auth_data_item_answer(maa, &auth_data, &item_number,
185 		    &algorithm, &authenticate, &authorization2,
186 		    &ck, &ik,
187 		    &ip,
188 		    &ha1, &response_auth, &digest_realm,
189 		    &line_identifier))) {
190 
191 		//create an auth_data_item for each entry in the MAA
192 		adi_len = sizeof (struct auth_data_item) +authenticate.len + authorization2.len + ck.len + ik.len + ip.len + ha1.len + line_identifier.len + response_auth.len + digest_realm.len + algorithm.len;
193 		adi = (struct auth_data_item*) shm_malloc(adi_len);
194 		if (!adi) {
195 		    LM_CRIT("Out of memory!\n");
196 		    result = CSCF_RETURN_ERROR;
197 		    goto done;
198 		}
199 
200 		memset(adi, 0, adi_len);
201 
202 		//put all elements in the auth_data_item entry
203 		p = (char*) (adi + 1);
204 
205 		adi->authenticate.s = p;
206 		adi->authenticate.len = authenticate.len;
207 		memcpy(p, authenticate.s, authenticate.len);
208 		p += authenticate.len;
209 
210 		adi->authorization.s = p;
211 		adi->authorization.len = authorization2.len;
212 		memcpy(p, authorization2.s, authorization2.len);
213 		p += authorization2.len;
214 
215 		adi->auth_scheme.s = p;
216 		adi->auth_scheme.len = algorithm.len;
217 		memcpy(p, algorithm.s, algorithm.len);
218 		p += algorithm.len;
219 
220 		adi->ck.s = p;
221 		adi->ck.len = ck.len;
222 		memcpy(p, ck.s, ck.len);
223 		p += ck.len;
224 
225 		adi->ik.s = p;
226 		adi->ik.len = ik.len;
227 		memcpy(p, ik.s, ik.len);
228 		p += ik.len;
229 
230 		adi->ip.s = p;
231 		adi->ip.len = ip.len;
232 		memcpy(p, ip.s, ip.len);
233 		p += ip.len;
234 
235 		adi->ha1.s = p;
236 		adi->ha1.len = ha1.len;
237 		memcpy(p, ha1.s, ha1.len);
238 		p += ha1.len;
239 
240 		adi->line_identifier.s = p;
241 		adi->line_identifier.len = line_identifier.len;
242 		memcpy(p, line_identifier.s, line_identifier.len);
243 		p += line_identifier.len;
244 
245 		adi->response_auth.s = p;
246 		adi->response_auth.len = response_auth.len;
247 		memcpy(p, response_auth.s, response_auth.len);
248 		p += response_auth.len;
249 
250 		adi->digest_realm.s = p;
251 		adi->digest_realm.len = digest_realm.len;
252 		memcpy(p, digest_realm.s, digest_realm.len);
253 		p += digest_realm.len;
254 
255 		if (p != (((char*) adi) + adi_len)) {
256 		    LM_CRIT("buffer overflow\n");
257 		    shm_free(adi);
258 		    adi = 0;
259 		    result = CSCF_RETURN_ERROR;
260 		    goto done;
261 		}
262 		auth_data->code = -auth_data->code;
263 		adi->item_number = item_number;
264 
265 		int len = sizeof (struct auth_data_item_list);
266 		adi_list = (struct auth_data_item_list*) shm_malloc(len);
267 		memset(adi_list, 0, len);
268 
269 		if (adi_list->first == 0) {
270 		    adi_list->first = adi_list->last = adi;
271 		} else {
272 		    adi_list->last->next = adi;
273 		    adi->previous = adi_list->last;
274 		    adi_list->last = adi;
275 		}
276 
277 		items_found++;
278 	    }
279     }
280 
281     if (!(rc) && !(experimental_rc)) {
282         stateful_request_reply_async(t, req, 480, MSG_480_DIAMETER_MISSING_AVP);
283         result = CSCF_RETURN_FALSE;
284         goto done;
285     }
286 
287     switch (rc) {
288         case -1:
289             switch (experimental_rc) {
290                 case RC_IMS_DIAMETER_ERROR_USER_UNKNOWN:
291                     stateful_request_reply_async(t, req, 403, MSG_403_USER_UNKNOWN);
292                     result = CSCF_RETURN_FALSE;
293                     break;
294                 case RC_IMS_DIAMETER_ERROR_IDENTITIES_DONT_MATCH:
295                     stateful_request_reply_async(t, req, 403, MSG_403_IDENTITIES_DONT_MATCH);
296                     result = CSCF_RETURN_FALSE;
297                     break;
298                 case RC_IMS_DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED:
299                     stateful_request_reply_async(t, req, 403, MSG_403_AUTH_SCHEME_UNSOPPORTED);
300                     result = CSCF_RETURN_FALSE;
301                     break;
302 
303                 default:
304                     stateful_request_reply_async(t, req, 403, MSG_403_UNKOWN_EXPERIMENTAL_RC);
305                     result = CSCF_RETURN_FALSE;
306             }
307             break;
308 
309         case AAA_UNABLE_TO_COMPLY:
310             stateful_request_reply_async(t, req, 403, MSG_403_UNABLE_TO_COMPLY);
311             result = CSCF_RETURN_FALSE;
312             break;
313 
314         case AAA_SUCCESS:
315             goto success;
316             break;
317 
318         default:
319             stateful_request_reply_async(t, req, 403, MSG_403_UNKOWN_RC);
320             result = CSCF_RETURN_FALSE;
321     }
322 
323     goto done;
324 
325 success:
326 
327     if (!sip_number_auth_items || !items_found) {
328         stateful_request_reply_async(t, req, 403, MSG_403_NO_AUTH_DATA);
329         result = CSCF_RETURN_FALSE;
330         goto done;
331     }
332 
333     avlist = shm_malloc(sizeof (auth_vector *) * sip_number_auth_items);
334     if (!avlist) {
335         stateful_request_reply_async(t, req, 403, MSG_480_HSS_ERROR);
336         result = CSCF_RETURN_FALSE;
337         goto done;
338     }
339 
340     sip_number_auth_items = 0;
341 
342     struct auth_data_item *tmp;
343     tmp = adi_list->first;
344 
345     while (tmp) {
346 
347         if (tmp->ip.len)
348             av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s,
349                 tmp->ip, empty_s, empty_s);
350         else if (tmp->line_identifier.len)
351             av = new_auth_vector(tmp->item_number, tmp->auth_scheme, empty_s,
352                 line_identifier, empty_s, empty_s);
353         else if (tmp->ha1.len) {
354             if (tmp->response_auth.len) //HSS check
355             {
356                 memset(ha1_hex, 0, HASHHEXLEN + 1);
357                 memcpy(ha1_hex, tmp->ha1.s,
358                         tmp->ha1.len > HASHHEXLEN ? 32 : tmp->ha1.len);
359 
360                 etsi_nonce.len = tmp->authenticate.len / 2;
361                 etsi_nonce.s = pkg_malloc(etsi_nonce.len);
362                 if (!etsi_nonce.s) {
363                     LM_ERR("error allocating %d bytes\n", etsi_nonce.len);
364                     goto done;
365                 }
366                 etsi_nonce.len = base16_to_bin(tmp->authenticate.s,
367                         tmp->authenticate.len, etsi_nonce.s);
368 
369                 calc_response(ha1_hex, &etsi_nonce, &empty_s, &empty_s,
370                         &empty_s, 0, &(req->first_line.u.request.method),
371                         &scscf_name_str, 0, result_hex);
372                 pkg_free(etsi_nonce.s);
373 
374                 if (tmp->response_auth.len != 32
375                         || strncasecmp(tmp->response_auth.s, result_hex, 32)) {
376                     LM_ERR("The HSS' Response-Auth is different from what we compute locally!\n"
377                             " BUT! If you sent an MAR with auth scheme unknown (HSS-Selected Authentication), this is normal.\n"
378                             "HA1=\t|%s|\nNonce=\t|%.*s|\nMethod=\t|%.*s|\nuri=\t|%.*s|\nxresHSS=\t|%.*s|\nxresSCSCF=\t|%s|\n",
379                             ha1_hex,
380                             tmp->authenticate.len, tmp->authenticate.s,
381                             req->first_line.u.request.method.len, req->first_line.u.request.method.s,
382                             scscf_name_str.len, scscf_name_str.s,
383                             tmp->response_auth.len, tmp->response_auth.s,
384                             result_hex);
385                     //stateful_register_reply(msg,514,MSG_514_HSS_AUTH_FAILURE);
386                     //goto done;
387                 }
388             }
389             av = new_auth_vector(tmp->item_number, tmp->auth_scheme,
390                     tmp->authenticate, tmp->ha1, empty_s, empty_s);
391         } else
392             av = new_auth_vector(tmp->item_number, tmp->auth_scheme,
393                 tmp->authenticate, tmp->authorization, tmp->ck, tmp->ik);
394 
395         if (sip_number_auth_items == 0)
396             avlist[sip_number_auth_items++] = av;
397         else {
398             i = sip_number_auth_items;
399             while (i > 0 && avlist[i - 1]->item_number > av->item_number)
400                 i--;
401             for (j = sip_number_auth_items; j > i; j--)
402                 avlist[j] = avlist[j - 1];
403             avlist[i] = av;
404             sip_number_auth_items++;
405         }
406 
407         //TODO need to confirm that removing this has done no problems
408         //tmp->auth_data->code = -tmp->auth_data->code;
409 
410         tmp = tmp->next;
411     }
412 
413     //MAA returns a whole list of av! Which should we use?
414     //right now we take the first and put the rest in the AV queue
415     //then we use the first one and then add it to the queue as sent!
416 
417     for (i = 1; i < sip_number_auth_items; i++) {
418         if (!add_auth_vector(private_identity, public_identity, avlist[i]))
419             free_auth_vector(avlist[i]);
420     }
421 
422     if (!data->is_resync) {
423 		if (!pack_challenge(req, data->realm, avlist[0], data->is_proxy_auth)) {
424 			stateful_request_reply_async(t, req, 500, MSG_500_PACK_AV);
425 			result = CSCF_RETURN_FALSE;
426 			goto done;
427 		}
428 
429 		if (data->is_proxy_auth)
430 			stateful_request_reply_async(t, req, 407, MSG_407_CHALLENGE);
431 		else
432 			stateful_request_reply_async(t, req, 401, MSG_401_CHALLENGE);
433     }
434 
435 done:
436 
437 	if (avlist) {
438 		if (!data->is_resync)	//only start the timer if we used the vector above - we dont use it resync mode
439 		start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors
440 
441 		//now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT
442 		if (!add_auth_vector(private_identity, public_identity, avlist[0]))
443 			free_auth_vector(avlist[0]);
444 	}
445 
446     //free memory
447     if (maa) cdpb.AAAFreeMessage(&maa);
448     if (avlist) {
449         shm_free(avlist);
450         avlist = 0;
451     }
452 
453     if (adi_list) {
454         struct auth_data_item *tmp1 = adi_list->first;
455         while (tmp1) {
456             struct auth_data_item *tmp2 = tmp1->next;
457             shm_free(tmp1);
458             tmp1 = tmp2;
459         }
460         shm_free(adi_list);
461         adi_list = 0;
462     }
463 
464     LM_DBG("DBG:UAR Async CDP callback: ... Done resuming transaction\n");
465     set_avp_list(AVP_TRACK_FROM | AVP_CLASS_URI, &t->uri_avps_from);
466     set_avp_list(AVP_TRACK_TO | AVP_CLASS_URI, &t->uri_avps_to);
467     set_avp_list(AVP_TRACK_FROM | AVP_CLASS_USER, &t->user_avps_from);
468     set_avp_list(AVP_TRACK_TO | AVP_CLASS_USER, &t->user_avps_to);
469     set_avp_list(AVP_TRACK_FROM | AVP_CLASS_DOMAIN, &t->domain_avps_from);
470     set_avp_list(AVP_TRACK_TO | AVP_CLASS_DOMAIN, &t->domain_avps_to);
471 
472     //make sure we delete any private lumps we created
473     create_return_code(result);
474     if (t) {
475         //del_nonshm_lump_rpl(&req->reply_lump);
476         tmb.unref_cell(t);
477     }
478     tmb.t_continue(data->tindex, data->tlabel, data->act);
479     free_saved_transaction_data(data);
480     return;
481 
482 error:
483     //don't need to set result code as by default it is ERROR!
484 
485     if (t) {
486         //del_nonshm_lump_rpl(&t->uas.request->reply_lump);
487         tmb.unref_cell(t);
488     }
489     tmb.t_continue(data->tindex, data->tlabel, data->act);
490 
491 error1:
492     free_saved_transaction_data(data);
493 }
494 
495 /**
496  * Create and send a Multimedia-Authentication-Request and returns the parsed Answer structure.
497  * This function retrieves authentication vectors from the HSS.
498  * @param msg - the SIP message to send for
499  * @parma public_identity - the public identity of the user
500  * @param private_identity - the private identity of the user
501  * @param count - how many authentication vectors to ask for
502  * @param algorithm - for which algorithm
503  * @param authorization - the authorization value
504  * @param server_name - local name of the S-CSCF to save on the HSS
505  * @returns the parsed maa struct
506  */
cxdx_send_mar(struct sip_msg * msg,str public_identity,str private_identity,unsigned int count,str algorithm,str authorization,str server_name,saved_transaction_t * transaction_data)507 int cxdx_send_mar(struct sip_msg *msg, str public_identity, str private_identity,
508         unsigned int count, str algorithm, str authorization, str server_name, saved_transaction_t* transaction_data) {
509     AAAMessage *mar = 0;
510     AAASession *session = 0;
511 
512     session = cdpb.AAACreateSession(0);
513 
514     mar = cdpb.AAACreateRequest(IMS_Cx, IMS_MAR, Flag_Proxyable, session);
515     if (session) {
516         cdpb.AAADropSession(session);
517         session = 0;
518     }
519     if (!mar) goto error1;
520 
521     if (cxdx_dest_host.len > 0) {
522        if (!cxdx_add_destination_host(mar, cxdx_dest_host)) goto error1;
523     }
524 
525     if (!cxdx_add_destination_realm(mar, cxdx_dest_realm)) goto error1;
526 
527     if (!cxdx_add_vendor_specific_appid(mar, IMS_vendor_id_3GPP, IMS_Cx, 0 /*IMS_Cx*/)) goto error1;
528     if (!cxdx_add_auth_session_state(mar, 1)) goto error1;
529 
530     if (!cxdx_add_public_identity(mar, public_identity)) goto error1;
531     if (!cxdx_add_user_name(mar, private_identity)) goto error1;
532     if (!cxdx_add_sip_number_auth_items(mar, count)) goto error1;
533     if (algorithm.len == auth_scheme_types[AUTH_HTTP_DIGEST_MD5].len &&
534             strncasecmp(algorithm.s, auth_scheme_types[AUTH_HTTP_DIGEST_MD5].s, algorithm.len) == 0) {
535         if (!cxdx_add_sip_auth_data_item_request(mar, algorithm, authorization, private_identity, cxdx_dest_realm,
536                 msg->first_line.u.request.method, server_name)) goto error1;
537     } else {
538         if (!cxdx_add_sip_auth_data_item_request(mar, algorithm, authorization, private_identity, cxdx_dest_realm,
539                 msg->first_line.u.request.method, s_empty)) goto error1;
540     }
541     if (!cxdx_add_server_name(mar, server_name)) goto error1;
542 
543     if (cxdx_forced_peer.len)
544         cdpb.AAASendMessageToPeer(mar, &cxdx_forced_peer, (void*) async_cdp_callback, (void*) transaction_data);
545     else
546         cdpb.AAASendMessage(mar, (void*) async_cdp_callback, (void*) transaction_data);
547 
548 
549     LM_DBG("Successfully sent async diameter\n");
550 
551     return 0;
552 
553 error1: //Only free MAR IFF is has not been passed to CDP
554     if (mar) cdpb.AAAFreeMessage(&mar);
555     LM_ERR("Error occurred trying to send MAR\n");
556     return -1;
557 }
558 
559