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