cxdx_mar.c 19 KB

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