nta_check.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. * This file is part of the Sofia-SIP package
  3. *
  4. * Copyright (C) 2005 Nokia Corporation.
  5. *
  6. * Contact: Pekka Pessi <pekka.pessi@nokia.com>
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * as published by the Free Software Foundation; either version 2.1 of
  11. * the License, or (at your option) any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  21. * 02110-1301 USA
  22. *
  23. */
  24. /**@CFILE nta_check.c
  25. * @brief Checks for features, MIME types, session timer.
  26. *
  27. * @author Pekka Pessi <Pekka.Pessi@nokia.com>
  28. *
  29. * @date Created: Wed Mar 8 16:35:05 EET 2006 ppessi
  30. */
  31. #include "config.h"
  32. #include <sofia-sip/su_tagarg.h>
  33. #include <sofia-sip/sip_header.h>
  34. #include <sofia-sip/sip_status.h>
  35. #include <sofia-sip/sip_util.h>
  36. #include <sofia-sip/nta.h>
  37. /* ======================================================================== */
  38. /* Request validation */
  39. /**Check that we support all features which UAC requires.
  40. *
  41. * The list of supported features is compared with the list of features
  42. * required by the UAC. If some features are not listed as supported, return
  43. * 420. If @a irq is non-NULL, the 420 response message is sent to the
  44. * client along with list of unsupported features in the @Unsupported
  45. * header, too.
  46. *
  47. * @param irq incoming transaction object (may be NULL).
  48. * @param sip contents of the SIP message
  49. * @param supported list of protocol features supported
  50. * @param tag, value, ... optional list of tagged arguments used
  51. * when responding to the transaction
  52. *
  53. * @return 0 if successful.
  54. * 420 if any of the required features is not supported.
  55. */
  56. int nta_check_required(nta_incoming_t *irq,
  57. sip_t const *sip,
  58. sip_supported_t const *supported,
  59. tag_type_t tag, tag_value_t value, ...)
  60. {
  61. int status = 0;
  62. if (sip->sip_require) {
  63. su_home_t home[SU_HOME_AUTO_SIZE(512)];
  64. sip_unsupported_t *us;
  65. su_home_auto(home, sizeof home);
  66. us = sip_has_unsupported(home, supported, sip->sip_require);
  67. if (us) {
  68. status = 420;
  69. if (irq) {
  70. ta_list ta;
  71. ta_start(ta, tag, value);
  72. nta_incoming_treply(irq,
  73. SIP_420_BAD_EXTENSION,
  74. SIPTAG_UNSUPPORTED(us),
  75. SIPTAG_SUPPORTED(supported),
  76. ta_tags(ta));
  77. ta_end(ta);
  78. }
  79. }
  80. su_home_deinit(home);
  81. }
  82. return status;
  83. }
  84. /** Check that UAC supports all the required features.
  85. *
  86. * The list of required features is compared with the features supported by
  87. * the UAC. If some features are not supported, return 421. If @a irq is
  88. * non-NULL, the 421 response message is sent to the client, too.
  89. *
  90. * @param irq incoming transaction object (may be NULL).
  91. * @param sip contents of the SIP message
  92. * @param require list of required protocol features
  93. * @param tag, value, ... optional list of tagged arguments used
  94. * when responding to the transaction
  95. *
  96. * @return 0 if successful.
  97. * 421 if any of the required features is not supported.
  98. */
  99. int nta_check_supported(nta_incoming_t *irq,
  100. sip_t const *sip,
  101. sip_require_t *require,
  102. tag_type_t tag, tag_value_t value, ...)
  103. {
  104. if (!sip_has_unsupported(NULL, sip->sip_supported, require))
  105. return 0;
  106. if (irq) {
  107. ta_list ta;
  108. ta_start(ta, tag, value);
  109. nta_incoming_treply(irq,
  110. SIP_421_EXTENSION_REQUIRED,
  111. SIPTAG_REQUIRE(require),
  112. ta_tags(ta));
  113. ta_end(ta);
  114. }
  115. return 421;
  116. }
  117. /** Check that we allow the request method.
  118. *
  119. * The request-method is compared with the list of supported methods in @a
  120. * allow. If match is found, 0 is is returned. Otherwise, if the
  121. * request-method is well-known, 405 is returned. If the request-method is
  122. * unknown, 501 is returned. If @a irq is non-NULL, the 405 or 501 response
  123. * message is sent to the client, too.
  124. *
  125. * @param irq incoming transaction object (may be NULL).
  126. * @param sip contents of the SIP message
  127. * @param allow list of allowed methods
  128. * @param tag, value, ... optional list of tagged arguments used
  129. * when responding to the transaction
  130. *
  131. * @return 0 if successful, 405 is request-method is not allowed, 501 if
  132. * request-method is unknown.
  133. */
  134. int nta_check_method(nta_incoming_t *irq,
  135. sip_t const *sip,
  136. sip_allow_t const *allow,
  137. tag_type_t tag, tag_value_t value, ...)
  138. {
  139. /* Check extensions */
  140. sip_method_t method = sip->sip_request->rq_method;
  141. char const *name = sip->sip_request->rq_method_name;
  142. if (sip_is_allowed(allow, method, name))
  143. return 0;
  144. if (irq) {
  145. ta_list ta;
  146. ta_start(ta, tag, value);
  147. if (method != sip_method_unknown)
  148. /* Well-known method */
  149. nta_incoming_treply(irq,
  150. SIP_405_METHOD_NOT_ALLOWED,
  151. SIPTAG_ALLOW(allow),
  152. ta_tags(ta));
  153. else
  154. /* Completeley unknown method */
  155. nta_incoming_treply(irq,
  156. SIP_501_NOT_IMPLEMENTED,
  157. SIPTAG_ALLOW(allow),
  158. ta_tags(ta));
  159. ta_end(ta);
  160. }
  161. return method != sip_method_unknown ? 405 : 501;
  162. }
  163. static char const application_sdp[] = "application/sdp";
  164. /** Check that we understand session content in the request.
  165. *
  166. * If there is no @ContentDisposition header or the @ContentDisposition
  167. * header indicated "session", the message body and content-type is compared
  168. * with the acceptable session content-types listed in @a session_accepts.
  169. * (typically, @c "application/sdp"). If no match is found, a 415 is
  170. * returned. If @a irq is non-NULL, the 415 response message is sent to the
  171. * client, too.
  172. *
  173. * If the @ContentDisposition header indicates something else but "session",
  174. * and it does not contain "handling=optional" parameter, a 415 response is
  175. * returned, too.
  176. *
  177. * Also, the @ContentEncoding header is checked. If it is not empty
  178. * (indicating no content-encoding), a 415 response is returned, too.
  179. *
  180. * @param irq incoming (server) transaction object (may be NULL).
  181. * @param sip contents of the SIP message
  182. * @param session_accepts list of acceptable content-types for "session"
  183. * content disposition
  184. * @param tag, value, ... optional list of tagged arguments used
  185. * when responding to the transaction
  186. *
  187. * @return 0 if successful, 415 if content-type is not acceptable.
  188. */
  189. int nta_check_session_content(nta_incoming_t *irq,
  190. sip_t const *sip,
  191. sip_accept_t const *session_accepts,
  192. tag_type_t tag, tag_value_t value, ...)
  193. {
  194. sip_content_type_t const *c = sip->sip_content_type;
  195. sip_content_disposition_t const *cd = sip->sip_content_disposition;
  196. int acceptable_type = 0, acceptable_encoding = 0;
  197. if (sip->sip_payload == NULL)
  198. return 0;
  199. if (cd == NULL || su_casematch(cd->cd_type, "session")) {
  200. sip_accept_t const *ab = session_accepts;
  201. char const *c_type;
  202. if (c)
  203. c_type = c->c_type;
  204. else if (sip->sip_payload->pl_len > 3 &&
  205. su_casenmatch(sip->sip_payload->pl_data, "v=0", 3))
  206. /* Missing Content-Type, but it looks like SDP */
  207. c_type = application_sdp;
  208. else
  209. /* No chance */
  210. ab = NULL, c_type = NULL;
  211. for (; ab; ab = ab->ac_next) {
  212. if (su_casematch(c_type, ab->ac_type))
  213. break;
  214. }
  215. if (ab)
  216. acceptable_type = 1;
  217. }
  218. else if (cd->cd_optional)
  219. acceptable_type = 1;
  220. /* Empty or missing Content-Encoding */
  221. if (!sip->sip_content_encoding ||
  222. !sip->sip_content_encoding->k_items ||
  223. !sip->sip_content_encoding->k_items[0] ||
  224. !sip->sip_content_encoding->k_items[0][0] ||
  225. !strcasecmp(sip->sip_content_encoding->k_items[0], "gzip") ||
  226. !strcasecmp(sip->sip_content_encoding->k_items[0], "deflate"))
  227. acceptable_encoding = 1;
  228. if (acceptable_type && acceptable_encoding)
  229. return 0;
  230. if (irq) {
  231. ta_list ta;
  232. ta_start(ta, tag, value);
  233. nta_incoming_treply(irq,
  234. SIP_415_UNSUPPORTED_MEDIA,
  235. SIPTAG_ACCEPT(session_accepts),
  236. ta_tags(ta));
  237. ta_end(ta);
  238. }
  239. return 415;
  240. }
  241. /**Check that UAC accepts one of listed MIME content-types.
  242. *
  243. * The list of acceptable content-types are compared with the acceptable
  244. * content-types. If match is found, it is returned in @a return_acceptable.
  245. * If no match is found, a 406 is returned. If @a irq is non-NULL, the 406
  246. * response message is sent to the client, too.
  247. *
  248. * @param irq incoming transaction object (may be NULL).
  249. * @param sip contents of the SIP message
  250. * @param acceptable list of acceptable content types
  251. * @param return_acceptable optional return-value parameter for
  252. * matched content-type
  253. * @param tag, value, ... optional list of tagged arguments used
  254. * when responding to the transaction
  255. *
  256. * @return 406 if no content-type is acceptable by client, 0 if successful.
  257. */
  258. int nta_check_accept(nta_incoming_t *irq,
  259. sip_t const *sip,
  260. sip_accept_t const *acceptable,
  261. sip_accept_t const **return_acceptable,
  262. tag_type_t tag, tag_value_t value, ...)
  263. {
  264. ta_list ta;
  265. sip_accept_t const *ac, *ab;
  266. sip_method_t method;
  267. if (!acceptable)
  268. return 0;
  269. if (sip->sip_request)
  270. method = sip->sip_request->rq_method;
  271. else /* if (sip->sip_cseq) */
  272. method = sip->sip_cseq->cs_method;
  273. /* Missing Accept header implies support for SDP in INVITE and OPTIONS
  274. * (and PRACK and UPDATE?)
  275. */
  276. if (!sip->sip_accept && (method == sip_method_invite ||
  277. method == sip_method_options ||
  278. method == sip_method_prack ||
  279. method == sip_method_update)) {
  280. for (ab = acceptable; ab; ab = ab->ac_next)
  281. if (su_casematch(application_sdp, ab->ac_type)) {
  282. if (return_acceptable) *return_acceptable = ab;
  283. return 0;
  284. }
  285. }
  286. for (ac = sip->sip_accept; ac; ac = ac->ac_next) {
  287. if (sip_q_value(ac->ac_q) == 0 || !ac->ac_type)
  288. continue;
  289. for (ab = acceptable; ab; ab = ab->ac_next)
  290. if (su_casematch(ac->ac_type, ab->ac_type)) {
  291. if (return_acceptable) *return_acceptable = ab;
  292. return 0;
  293. }
  294. }
  295. if (irq) {
  296. ta_start(ta, tag, value);
  297. nta_incoming_treply(irq,
  298. SIP_406_NOT_ACCEPTABLE,
  299. SIPTAG_ACCEPT(acceptable),
  300. ta_tags(ta));
  301. ta_end(ta);
  302. }
  303. return 406;
  304. }
  305. /**Check @SessionExpires header.
  306. *
  307. * If the proposed session-expiration time is smaller than @MinSE or our
  308. * minimal session expiration time, respond with 422 containing shortest
  309. * acceptable session expiration time in @MinSE header.
  310. *
  311. * @param irq incoming transaction object (may be NULL).
  312. * @param sip contents of the SIP message
  313. * @param my_min_se minimal session expiration time in seconds
  314. * @param tag, value, ... optional list of tagged arguments used
  315. * when responding to the transaction
  316. *
  317. * @return 422 if session expiration time is too small, 0 when successful.
  318. */
  319. int nta_check_session_expires(nta_incoming_t *irq,
  320. sip_t const *sip,
  321. sip_time_t my_min_se,
  322. tag_type_t tag, tag_value_t value, ...)
  323. {
  324. unsigned long min_se = my_min_se;
  325. if (sip->sip_min_se && min_se < sip->sip_min_se->min_delta)
  326. min_se = sip->sip_min_se->min_delta;
  327. if (sip->sip_session_expires->x_delta >= min_se)
  328. return 0;
  329. if (irq) {
  330. ta_list ta;
  331. sip_min_se_t min_se0[1];
  332. ta_start(ta, tag, value);
  333. sip_min_se_init(min_se0)->min_delta = min_se;
  334. nta_incoming_treply(irq,
  335. SIP_422_SESSION_TIMER_TOO_SMALL,
  336. SIPTAG_MIN_SE(min_se0),
  337. ta_tags(ta));
  338. ta_end(ta);
  339. }
  340. return 422;
  341. }