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