utils.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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 "utils.h"
  46. /*
  47. * Find credentials with given realm in a SIP message header
  48. */
  49. inline int ims_find_credentials(struct sip_msg* _m, str* _realm,
  50. hdr_types_t _hftype, struct hdr_field** _h) {
  51. struct hdr_field** hook, *ptr, *prev;
  52. hdr_flags_t hdr_flags;
  53. int res;
  54. str* r;
  55. LM_DBG("Searching credentials in realm [%.*s]\n", _realm->len, _realm->s);
  56. /*
  57. * Determine if we should use WWW-Authorization or
  58. * Proxy-Authorization header fields, this parameter
  59. * is set in www_authorize and proxy_authorize
  60. */
  61. switch (_hftype) {
  62. case HDR_AUTHORIZATION_T:
  63. hook = &(_m->authorization);
  64. hdr_flags = HDR_AUTHORIZATION_F;
  65. break;
  66. case HDR_PROXYAUTH_T:
  67. hook = &(_m->proxy_auth);
  68. hdr_flags = HDR_PROXYAUTH_F;
  69. break;
  70. default:
  71. hook = &(_m->authorization);
  72. hdr_flags = HDR_T2F(_hftype);
  73. break;
  74. }
  75. /*
  76. * If the credentials haven't been parsed yet, do it now
  77. */
  78. if (*hook == 0) {
  79. /* No credentials parsed yet */
  80. LM_DBG("*hook == 0, No credentials parsed yet\n");
  81. if (parse_headers(_m, hdr_flags, 0) == -1) {
  82. LM_ERR("Error while parsing headers\n");
  83. return -1;
  84. }
  85. }
  86. ptr = *hook;
  87. LM_DBG("*hook = %p\n", ptr);
  88. /*
  89. * Iterate through the credentials in the message and
  90. * find credentials with given realm
  91. */
  92. while (ptr) {
  93. res = parse_credentials(ptr);
  94. if (res < 0) {
  95. LM_ERR("Error while parsing credentials\n");
  96. return (res == -1) ? -2 : -3;
  97. } else if (res == 0) {
  98. LM_DBG("Credential parsed successfully\n");
  99. if (_realm->len) {
  100. r = &(((auth_body_t*) (ptr->parsed))->digest.realm);
  101. LM_DBG("Comparing realm <%.*s> and <%.*s>\n", _realm->len, _realm->s, r->len, r->s);
  102. if (r->len == _realm->len) {
  103. if (!strncasecmp(_realm->s, r->s, r->len)) {
  104. *_h = ptr;
  105. return 0;
  106. }
  107. }
  108. } else {
  109. *_h = ptr;
  110. return 0;
  111. }
  112. }
  113. prev = ptr;
  114. if (parse_headers(_m, hdr_flags, 1) == -1) {
  115. LM_ERR("Error while parsing headers\n");
  116. return -4;
  117. } else {
  118. if (prev != _m->last_header) {
  119. if (_m->last_header->type == _hftype)
  120. ptr = _m->last_header;
  121. else
  122. break;
  123. } else
  124. break;
  125. }
  126. }
  127. /*
  128. * Credentials with given realm not found
  129. */
  130. LM_DBG("Credentials with given realm not found\n");
  131. return 1;
  132. }
  133. /**
  134. * Looks for the nonce and response parameters in the Authorization header and returns them
  135. * @param msg - the SIP message
  136. * @param realm - realm to match the right Authorization header
  137. * @param nonce - param to fill with the nonce found
  138. * @param response - param to fill with the response
  139. * @returns 1 if found, 0 if not
  140. */
  141. int get_nonce_response(struct sip_msg *msg, str realm,str *nonce,str *response,
  142. enum qop_type *qop,str *qop_str,str *nc,str *cnonce,str *uri, int is_proxy_auth)
  143. {
  144. struct hdr_field* h = 0;
  145. int ret;
  146. ret = parse_headers(msg, is_proxy_auth ? HDR_PROXYAUTH_F : HDR_AUTHORIZATION_F, 0);
  147. if (ret != 0) {
  148. return 0;
  149. }
  150. if ((!is_proxy_auth && !msg->authorization)
  151. || (is_proxy_auth && !msg->proxy_auth)) {
  152. return 0;
  153. }
  154. LM_DBG("Calling find_credentials with realm [%.*s]\n", realm.len, realm.s);
  155. ret = ims_find_credentials(msg, &realm, is_proxy_auth ? HDR_PROXYAUTH_T : HDR_AUTHORIZATION_T, &h);
  156. if (ret < 0) {
  157. return 0;
  158. } else if (ret > 0) {
  159. LM_DBG("ret > 0");
  160. return 0;
  161. }
  162. if (h && h->parsed) {
  163. if (nonce)
  164. *nonce = ((auth_body_t*) h->parsed)->digest.nonce;
  165. if (response)
  166. *response = ((auth_body_t*) h->parsed)->digest.response;
  167. if (qop)
  168. *qop = ((auth_body_t*) h->parsed)->digest.qop.qop_parsed;
  169. if (qop_str)
  170. *qop_str = ((auth_body_t*) h->parsed)->digest.qop.qop_str;
  171. if (nc)
  172. *nc = ((auth_body_t*) h->parsed)->digest.nc;
  173. if (cnonce)
  174. *cnonce = ((auth_body_t*) h->parsed)->digest.cnonce;
  175. if (uri)
  176. *uri = ((auth_body_t*) h->parsed)->digest.uri;
  177. }
  178. LM_DBG("Found nonce response\n");
  179. return 1;
  180. }
  181. str ims_get_body(struct sip_msg * msg)
  182. {
  183. str x={0,0};
  184. if (parse_headers(msg,HDR_CONTENTLENGTH_F,0)!=0) {
  185. LM_DBG("Error parsing until header Content-Length: \n");
  186. return x;
  187. }
  188. x.len = (int)(long)msg->content_length->parsed;
  189. if (x.len>0)
  190. x.s = get_body(msg);
  191. return x;
  192. }
  193. /**
  194. * Looks for the auts parameter in the Authorization header and returns its value.
  195. * @param msg - the SIP message
  196. * @param realm - realm to match the right Authorization header
  197. * @returns the auts value or an empty string if not found
  198. */
  199. str ims_get_auts(struct sip_msg *msg, str realm, int is_proxy_auth)
  200. {
  201. str name={"auts=\"",6};
  202. struct hdr_field* h=0;
  203. int i,ret;
  204. str auts={0,0};
  205. if (parse_headers(msg, is_proxy_auth ? HDR_PROXYAUTH_F : HDR_AUTHORIZATION_F,0)!=0) {
  206. LM_ERR("Error parsing until header Authorization: \n");
  207. return auts;
  208. }
  209. if ((!is_proxy_auth && !msg->authorization)
  210. || (is_proxy_auth && !msg->proxy_auth)){
  211. LM_ERR("Message does not contain Authorization nor Proxy-Authorization header.\n");
  212. return auts;
  213. }
  214. ret = find_credentials(msg, &realm, is_proxy_auth ? HDR_PROXYAUTH_F : HDR_AUTHORIZATION_F, &h);
  215. if (ret < 0) {
  216. LM_ERR("Error while looking for credentials.\n");
  217. return auts;
  218. } else
  219. if (ret > 0) {
  220. LM_ERR("No credentials for this realm found.\n");
  221. return auts;
  222. }
  223. if (h) {
  224. for(i=0;i<h->body.len-name.len;i++)
  225. if (strncasecmp(h->body.s+i,name.s,name.len)==0){
  226. auts.s = h->body.s+i+name.len;
  227. while(i+auts.len<h->body.len && auts.s[auts.len]!='\"')
  228. auts.len++;
  229. }
  230. }
  231. return auts;
  232. }
  233. /**
  234. * Looks for the nonce parameter in the Authorization header and returns its value.
  235. * @param msg - the SIP message
  236. * @param realm - realm to match the right Authorization header
  237. * @returns the nonce or an empty string if none found
  238. */
  239. str ims_get_nonce(struct sip_msg *msg, str realm)
  240. {
  241. struct hdr_field* h=0;
  242. int ret;
  243. str nonce={0,0};
  244. if (parse_headers(msg,HDR_AUTHORIZATION_F,0)!=0) {
  245. LM_ERR("Error parsing until header Authorization: \n");
  246. return nonce;
  247. }
  248. if (!msg->authorization){
  249. LM_ERR("Message does not contain Authorization header.\n");
  250. return nonce;
  251. }
  252. ret = find_credentials(msg, &realm, HDR_AUTHORIZATION_F, &h);
  253. if (ret < 0) {
  254. LM_ERR("Error while looking for credentials.\n");
  255. return nonce;
  256. } else
  257. if (ret > 0) {
  258. LM_ERR("No credentials for this realm found.\n");
  259. return nonce;
  260. }
  261. if (h&&h->parsed) {
  262. nonce = ((auth_body_t*)h->parsed)->digest.nonce;
  263. }
  264. return nonce;
  265. }
  266. /**
  267. * Adds a header to the reply message
  268. * @param msg - the request to add a header to its reply
  269. * @param content - the str containing the new header
  270. * @returns 1 on succes, 0 on failure
  271. */
  272. int ims_add_header_rpl(struct sip_msg *msg, str *hdr)
  273. {
  274. if (add_lump_rpl( msg, hdr->s, hdr->len, LUMP_RPL_HDR)==0) {
  275. LM_ERR("Can't add header <%.*s>\n",
  276. hdr->len,hdr->s);
  277. return 0;
  278. }
  279. return 1;
  280. }