/* Copyright (C) 2002-2008 Thomas Ries This file is part of Siproxd. Siproxd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Siproxd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Siproxd; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #include #include #include #include #include "siproxd.h" #include "log.h" static char const ident[]="$Id$"; /* * do security and integrity checks on the received packet * (raw buffer, \0 terminated) * * RETURNS * STS_SUCCESS if ok * STS_FAILURE if the packed did not pass the checks */ int security_check_raw(char *sip_buffer, size_t size) { char *p1=NULL, *p2=NULL; DEBUGC(DBCLASS_BABBLE,"security_check_raw: size=%ld", (long)size); /* * empiric: size must be >= 16 bytes * 2 byte packets have been seen in the wild * also 4 bytes with 0x00 (seem to be used to keep potential UDP * masquerading tunnels open) */ if (size SEC_MAXLINELEN) { /* longer than allowed */ DEBUGC(DBCLASS_SIP,"security_check_raw: line too long or no " "CRLF found"); return STS_FAILURE; } } /* As libosip2 is *VERY* sensitive to corrupt input data, we need to do more stuff here. For example, libosip2 can be crashed (with a " virtual memory exhausted" error - God knows why) by sending the following few bytes. It will die in osip_message_parse() ---BUFFER DUMP follows--- 6e 74 2f 38 30 30 30 0d 0a 61 3d 66 6d 74 70 3a nt/8000..a=fmtp: 31 30 31 20 30 2d 31 35 0d 0a 101 0-15.. ---end of BUFFER DUMP--- By looking at the code in osip_message_parse.c, I'd guess it is the 'only one space present' that leads to a faulty size calculation (VERY BIG NUMBER), which in turn then dies inside osip_malloc. So, we need at least 2 spaces to survive that code part of libosip2. */ p1 = strchr(sip_buffer, ' '); if (p1 && ((p1+1) < (sip_buffer+size))) { p2 = strchr(p1+1, ' '); } else { DEBUGC(DBCLASS_SIP,"security_check_raw: found no space"); return STS_FAILURE; } if (p2==NULL) { DEBUGC(DBCLASS_SIP,"security_check_raw: found only one space"); return STS_FAILURE; } /* libosip2 can be put into an endless loop by trying to parse: ---BUFFER DUMP follows--- 49 4e 56 49 54 45 20 20 53 49 50 2f 32 2e 30 0d INVITE SIP/2.0. 0a 56 69 61 3a 20 53 49 50 2f 32 2e 30 2f 55 44 .Via: SIP/2.0/UD Note, this is an INVITE with no valid SIP URI (INVITE SIP/2.0) */ /* clumsy... */ if (size >20) { if (strncmp(sip_buffer, "INVITE SIP/2.0", 15)==0) return STS_FAILURE; else if (strncmp(sip_buffer, "ACK SIP/2.0", 12)==0) return STS_FAILURE; else if (strncmp(sip_buffer, "BYE SIP/2.0", 12)==0) return STS_FAILURE; else if (strncmp(sip_buffer, "CANCEL SIP/2.0", 15)==0) return STS_FAILURE; else if (strncmp(sip_buffer, "REGISTER SIP/2.0",17)==0) return STS_FAILURE; else if (strncmp(sip_buffer, "OPTIONS SIP/2.0", 16)==0) return STS_FAILURE; else if (strncmp(sip_buffer, "INFO SIP/2.0", 13)==0) return STS_FAILURE; } /* TODO: still way to go here ... */ return STS_SUCCESS; } /* * do security and integrity checks on the received packet * (parsed buffer) * * RETURNS * STS_SUCCESS if ok * STS_FAILURE if the packed did not pass the checks */ int security_check_sip(sip_ticket_t *ticket){ osip_message_t *sip=ticket->sipmsg; if (MSG_IS_REQUEST(sip)) { /* check for existing SIP URI in request */ if ((sip->req_uri == NULL) || (sip->req_uri->scheme == NULL)) { ERROR("security check failed: NULL SIP URI"); return STS_FAILURE; } /* check SIP URI scheme */ if (osip_strcasecmp(sip->req_uri->scheme, "sip")) { ERROR("security check failed: unknown scheme: %s", sip->req_uri->scheme); return STS_FAILURE; } } /* * Check existence of mandatory headers * Rosenberg, et. al. Standards Track [Page 161] RFC 3261 SIP: Session Initiation Protocol June 2002 Header field where proxy ACK BYE CAN INV OPT REG ___________________________________________________________ Accept R - o - o m* o Accept 2xx - - - o m* o Accept 415 - c - c c c Accept-Encoding R - o - o o o Accept-Encoding 2xx - - - o m* o Accept-Encoding 415 - c - c c c Accept-Language R - o - o o o Accept-Language 2xx - - - o m* o Accept-Language 415 - c - c c c Alert-Info R ar - - - o - - Alert-Info 180 ar - - - o - - Allow R - o - o o o Allow 2xx - o - m* m* o Allow r - o - o o o Allow 405 - m - m m m Authentication-Info 2xx - o - o o o Authorization R o o o o o o Call-ID c r m m m m m m Call-Info ar - - - o o o Contact R o - - m o o Contact 1xx - - - o - - Contact 2xx - - - m o o Contact 3xx d - o - o o o Contact 485 - o - o o o Content-Disposition o o - o o o Content-Encoding o o - o o o Content-Language o o - o o o Content-Length ar t t t t t t Content-Type * * - * * * CSeq c r m m m m m m Date a o o o o o o Error-Info 300-699 a - o o o o o Expires - - - o - o From c r m m m m m m In-Reply-To R - - - o - - Max-Forwards R amr m m m m m m Min-Expires 423 - - - - - m MIME-Version o o - o o o Organization ar - - - o o o Table 2: Summary of header fields, A--O Rosenberg, et. al. Standards Track [Page 162] RFC 3261 SIP: Session Initiation Protocol June 2002 Header field where proxy ACK BYE CAN INV OPT REG ___________________________________________________________________ Priority R ar - - - o - - Proxy-Authenticate 407 ar - m - m m m Proxy-Authenticate 401 ar - o o o o o Proxy-Authorization R dr o o - o o o Proxy-Require R ar - o - o o o Record-Route R ar o o o o o - Record-Route 2xx,18x mr - o o o o - Reply-To - - - o - - Require ar - c - c c c Retry-After 404,413,480,486 - o o o o o 500,503 - o o o o o 600,603 - o o o o o Route R adr c c c c c c Server r - o o o o o Subject R - - - o - - Supported R - o o m* o o Supported 2xx - o o m* m* o Timestamp o o o o o o To c(1) r m m m m m m Unsupported 420 - m - m m m User-Agent o o o o o o Via R amr m m m m m m Via rc dr m m m m m m Warning r - o o o o o WWW-Authenticate 401 ar - m - m m m WWW-Authenticate 407 ar - o - o o o */ /* * => Mandatory for ALL requests and responses * Call-ID c r m m m m m m * CSeq c r m m m m m m * From c r m m m m m m * To c(1) r m m m m m m * Via R amr m m m m m m */ /* check for existing Call-ID header */ if ((sip->call_id==NULL)|| ((sip->call_id->number==NULL)&&(sip->call_id->host==NULL))) { ERROR("security check failed: NULL Call-Id Header"); return STS_FAILURE; } /* check for existing CSeq header */ if ((sip->cseq==NULL)|| (sip->cseq->method==NULL)||(sip->cseq->number==NULL)) { ERROR("security check failed: NULL CSeq Header"); return STS_FAILURE; } /* check for existing To: header */ if ((sip->to==NULL)|| (sip->to->url==NULL)||(sip->to->url->host==NULL)) { ERROR("security check failed: NULL To Header"); return STS_FAILURE; } /* check for existing From: header */ if ((sip->from==NULL)|| (sip->from->url==NULL)||(sip->from->url->host==NULL)) { ERROR("security check failed: NULL From Header"); return STS_FAILURE; } /* TODO: still way to go here ... */ return STS_SUCCESS; }