1 /*
2 Copyright (C) 2002-2008 Thomas Ries <tries@gmx.net>
3
4 This file is part of Siproxd.
5
6 Siproxd is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 Siproxd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Siproxd; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <netinet/in.h>
29
30 #include <osipparser2/osip_parser.h>
31
32 #include "siproxd.h"
33 #include "log.h"
34
35 static char const ident[]="$Id: security.c 443 2010-01-07 11:31:56Z hb9xar $";
36
37 /*
38 * do security and integrity checks on the received packet
39 * (raw buffer, \0 terminated)
40 *
41 * RETURNS
42 * STS_SUCCESS if ok
43 * STS_FAILURE if the packed did not pass the checks
44 */
security_check_raw(char * sip_buffer,size_t size)45 int security_check_raw(char *sip_buffer, size_t size) {
46 char *p1=NULL, *p2=NULL;
47
48 DEBUGC(DBCLASS_BABBLE,"security_check_raw: size=%ld", (long)size);
49 /*
50 * empiric: size must be >= 16 bytes
51 * 2 byte <CR><LF> packets have been seen in the wild
52 * also 4 bytes with 0x00 (seem to be used to keep potential UDP
53 * masquerading tunnels open)
54 */
55 if (size<SEC_MINLEN) return STS_FAILURE;
56
57 /*
58 * make sure no line (up to the next CRLF) is longer than allowed
59 * empiric: a line should not be longer than 256 characters
60 * (libosip may die with "virtual memory exhausted" otherwise)
61 * Ref: protos test suite c07-sip-r2.jar, test case 203
62 * !! Contact records may all come in one single line, getting QUITE long...
63 * especially on TCP.
64 */
65 for (p1=sip_buffer; (p1+SEC_MAXLINELEN) < (sip_buffer+size); p1=p2+1) {
66 p2=strchr(p1, 10);
67 if ((p2 == 0) || /* no CRLF found */
68 (p2-p1) > SEC_MAXLINELEN) { /* longer than allowed */
69 DEBUGC(DBCLASS_SIP,"security_check_raw: line too long or no "
70 "CRLF found");
71 return STS_FAILURE;
72 }
73 }
74
75
76 /* As libosip2 is *VERY* sensitive to corrupt input data, we need to
77 do more stuff here. For example, libosip2 can be crashed (with a
78 "<port_malloc.c> virtual memory exhausted" error - God knows why)
79 by sending the following few bytes. It will die in osip_message_parse()
80 ---BUFFER DUMP follows---
81 6e 74 2f 38 30 30 30 0d 0a 61 3d 66 6d 74 70 3a nt/8000..a=fmtp:
82 31 30 31 20 30 2d 31 35 0d 0a 101 0-15..
83 ---end of BUFFER DUMP---
84
85 By looking at the code in osip_message_parse.c, I'd guess it is
86 the 'only one space present' that leads to a faulty size
87 calculation (VERY BIG NUMBER), which in turn then dies inside
88 osip_malloc.
89 So, we need at least 2 spaces to survive that code part of libosip2.
90 */
91 p1 = strchr(sip_buffer, ' ');
92 if (p1 && ((p1+1) < (sip_buffer+size))) {
93 p2 = strchr(p1+1, ' ');
94 } else {
95 DEBUGC(DBCLASS_SIP,"security_check_raw: found no space");
96 return STS_FAILURE;
97 }
98 if (p2==NULL) {
99 DEBUGC(DBCLASS_SIP,"security_check_raw: found only one space");
100 return STS_FAILURE;
101 }
102
103 /* libosip2 can be put into an endless loop by trying to parse:
104 ---BUFFER DUMP follows---
105 49 4e 56 49 54 45 20 20 53 49 50 2f 32 2e 30 0d INVITE SIP/2.0.
106 0a 56 69 61 3a 20 53 49 50 2f 32 2e 30 2f 55 44 .Via: SIP/2.0/UD
107 Note, this is an INVITE with no valid SIP URI (INVITE SIP/2.0)
108 */
109 /* clumsy... */
110 if (size >20) {
111 if (strncmp(sip_buffer, "INVITE SIP/2.0", 15)==0) return STS_FAILURE;
112 else if (strncmp(sip_buffer, "ACK SIP/2.0", 12)==0) return STS_FAILURE;
113 else if (strncmp(sip_buffer, "BYE SIP/2.0", 12)==0) return STS_FAILURE;
114 else if (strncmp(sip_buffer, "CANCEL SIP/2.0", 15)==0) return STS_FAILURE;
115 else if (strncmp(sip_buffer, "REGISTER SIP/2.0",17)==0) return STS_FAILURE;
116 else if (strncmp(sip_buffer, "OPTIONS SIP/2.0", 16)==0) return STS_FAILURE;
117 else if (strncmp(sip_buffer, "INFO SIP/2.0", 13)==0) return STS_FAILURE;
118 }
119
120 /* TODO: still way to go here ... */
121 return STS_SUCCESS;
122 }
123
124
125 /*
126 * do security and integrity checks on the received packet
127 * (parsed buffer)
128 *
129 * RETURNS
130 * STS_SUCCESS if ok
131 * STS_FAILURE if the packed did not pass the checks
132 */
security_check_sip(sip_ticket_t * ticket)133 int security_check_sip(sip_ticket_t *ticket){
134 osip_message_t *sip=ticket->sipmsg;
135 if (MSG_IS_REQUEST(sip)) {
136 /* check for existing SIP URI in request */
137 if ((sip->req_uri == NULL) || (sip->req_uri->scheme == NULL)) {
138 ERROR("security check failed: NULL SIP URI");
139 return STS_FAILURE;
140 }
141
142 /* check SIP URI scheme */
143 if (osip_strcasecmp(sip->req_uri->scheme, "sip")) {
144 ERROR("security check failed: unknown scheme: %s",
145 sip->req_uri->scheme);
146 return STS_FAILURE;
147 }
148 }
149
150 /*
151 * Check existence of mandatory headers
152 *
153
154 Rosenberg, et. al. Standards Track [Page 161]
155
156 RFC 3261 SIP: Session Initiation Protocol June 2002
157
158 Header field where proxy ACK BYE CAN INV OPT REG
159 ___________________________________________________________
160 Accept R - o - o m* o
161 Accept 2xx - - - o m* o
162 Accept 415 - c - c c c
163 Accept-Encoding R - o - o o o
164 Accept-Encoding 2xx - - - o m* o
165 Accept-Encoding 415 - c - c c c
166 Accept-Language R - o - o o o
167 Accept-Language 2xx - - - o m* o
168 Accept-Language 415 - c - c c c
169 Alert-Info R ar - - - o - -
170 Alert-Info 180 ar - - - o - -
171 Allow R - o - o o o
172 Allow 2xx - o - m* m* o
173 Allow r - o - o o o
174 Allow 405 - m - m m m
175 Authentication-Info 2xx - o - o o o
176 Authorization R o o o o o o
177 Call-ID c r m m m m m m
178 Call-Info ar - - - o o o
179 Contact R o - - m o o
180 Contact 1xx - - - o - -
181 Contact 2xx - - - m o o
182 Contact 3xx d - o - o o o
183 Contact 485 - o - o o o
184 Content-Disposition o o - o o o
185 Content-Encoding o o - o o o
186 Content-Language o o - o o o
187 Content-Length ar t t t t t t
188 Content-Type * * - * * *
189 CSeq c r m m m m m m
190 Date a o o o o o o
191 Error-Info 300-699 a - o o o o o
192 Expires - - - o - o
193 From c r m m m m m m
194 In-Reply-To R - - - o - -
195 Max-Forwards R amr m m m m m m
196 Min-Expires 423 - - - - - m
197 MIME-Version o o - o o o
198 Organization ar - - - o o o
199
200 Table 2: Summary of header fields, A--O
201
202
203
204
205
206
207 Rosenberg, et. al. Standards Track [Page 162]
208
209 RFC 3261 SIP: Session Initiation Protocol June 2002
210
211
212 Header field where proxy ACK BYE CAN INV OPT REG
213 ___________________________________________________________________
214 Priority R ar - - - o - -
215 Proxy-Authenticate 407 ar - m - m m m
216 Proxy-Authenticate 401 ar - o o o o o
217 Proxy-Authorization R dr o o - o o o
218 Proxy-Require R ar - o - o o o
219 Record-Route R ar o o o o o -
220 Record-Route 2xx,18x mr - o o o o -
221 Reply-To - - - o - -
222 Require ar - c - c c c
223 Retry-After 404,413,480,486 - o o o o o
224 500,503 - o o o o o
225 600,603 - o o o o o
226 Route R adr c c c c c c
227 Server r - o o o o o
228 Subject R - - - o - -
229 Supported R - o o m* o o
230 Supported 2xx - o o m* m* o
231 Timestamp o o o o o o
232 To c(1) r m m m m m m
233 Unsupported 420 - m - m m m
234 User-Agent o o o o o o
235 Via R amr m m m m m m
236 Via rc dr m m m m m m
237 Warning r - o o o o o
238 WWW-Authenticate 401 ar - m - m m m
239 WWW-Authenticate 407 ar - o - o o o
240
241 */
242
243
244 /*
245 * => Mandatory for ALL requests and responses
246 * Call-ID c r m m m m m m
247 * CSeq c r m m m m m m
248 * From c r m m m m m m
249 * To c(1) r m m m m m m
250 * Via R amr m m m m m m
251 */
252
253 /* check for existing Call-ID header */
254 if ((sip->call_id==NULL)||
255 ((sip->call_id->number==NULL)&&(sip->call_id->host==NULL))) {
256 ERROR("security check failed: NULL Call-Id Header");
257 return STS_FAILURE;
258 }
259
260 /* check for existing CSeq header */
261 if ((sip->cseq==NULL)||
262 (sip->cseq->method==NULL)||(sip->cseq->number==NULL)) {
263 ERROR("security check failed: NULL CSeq Header");
264 return STS_FAILURE;
265 }
266
267 /* check for existing To: header */
268 if ((sip->to==NULL)||
269 (sip->to->url==NULL)||(sip->to->url->host==NULL)) {
270 ERROR("security check failed: NULL To Header");
271 return STS_FAILURE;
272 }
273
274 /* check for existing From: header */
275 if ((sip->from==NULL)||
276 (sip->from->url==NULL)||(sip->from->url->host==NULL)) {
277 ERROR("security check failed: NULL From Header");
278 return STS_FAILURE;
279 }
280
281
282
283 /* TODO: still way to go here ... */
284 return STS_SUCCESS;
285 }
286