Review Board 1.7.16


Properly escape characters in URIs

Review Request #1081 - Created Jan. 19, 2011 and submitted

Matthew Nicholson
trunk
Reviewers
asterisk-dev
Asterisk
According to section 19.1.2 of RFC 3261:

  For each component, the set of valid BNF expansions defines exactly
  which characters may appear unescaped.  All other characters MUST be
  escaped.

This patch modifies ast_uri_encode() to encode strings in line with this recommendation.  This patch also adds an ast_escape_quoted() function which escapes '"' and '\' characters in quoted strings in accordance with section 25.1 of RFC 3261.  The ast_uri_encode() function has also been modified to take an ast_flags struct describing the set of rules it should use when escaping characters to allow for it to escape SIP URIs in addition to HTTP URIs and other types of URIs or variations of those two URI types in the future.

The ast_uri_decode() function has also been modified to accept an ast_flags struct describing the set of rules to use when decoding to enable decoding '+' as ' ' in legacy http URLs.
The existing unit test for ast_uri_encode() has been modified to test the new functionality in addition to testing for a buffer overflow.  The new ast_escape_quoted() function has a similar test.
/trunk/channels/chan_sip.c
Revision 302507 New Change
[20] 692 lines
[+20] [+] static unsigned int default_primary_transport; /*!< Default primary Transport (enum sip_transport) for outbound connections to devices */
693
					\note in the future we could have multiple of these (per domain, per device group etc) */
693
					\note in the future we could have multiple of these (per domain, per device group etc) */
694

    
   
694

   
695
/*!< use this macro when ast_uri_decode is dependent on pedantic checking to be on. */
695
/*!< use this macro when ast_uri_decode is dependent on pedantic checking to be on. */
696
#define SIP_PEDANTIC_DECODE(str)	\
696
#define SIP_PEDANTIC_DECODE(str)	\
697
	if (sip_cfg.pedanticsipchecking && !ast_strlen_zero(str)) {	\
697
	if (sip_cfg.pedanticsipchecking && !ast_strlen_zero(str)) {	\
698
		ast_uri_decode(str);	\
698
		ast_uri_decode(str, ast_uri_sip_user);	\
699
	}	\
699
	}	\
700

    
   
700

   
701
static unsigned int chan_idx;       /*!< used in naming sip channel */
701
static unsigned int chan_idx;       /*!< used in naming sip channel */
702
static int global_match_auth_username;    /*!< Match auth username if available instead of From: Default off. */
702
static int global_match_auth_username;    /*!< Match auth username if available instead of From: Default off. */
703

    
   
703

   
[+20] [20] 5993 lines
[+20] [+] static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *title, const char *linkedid)
6697
	if (ast_exists_extension(NULL, i->context, i->exten, 1, i->cid_num)) {
6697
	if (ast_exists_extension(NULL, i->context, i->exten, 1, i->cid_num)) {
6698
		/* encoded in dialplan, so keep extension encoded */
6698
		/* encoded in dialplan, so keep extension encoded */
6699
		ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
6699
		ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
6700
	} else {
6700
	} else {
6701
		decoded_exten = ast_strdupa(i->exten);
6701
		decoded_exten = ast_strdupa(i->exten);
6702
		ast_uri_decode(decoded_exten);
6702
		ast_uri_decode(decoded_exten, ast_uri_sip_user);
6703
		ast_copy_string(tmp->exten, decoded_exten, sizeof(tmp->exten));
6703
		ast_copy_string(tmp->exten, decoded_exten, sizeof(tmp->exten));
6704
	}
6704
	}
6705

    
   
6705

   
6706
	/* Don't use ast_set_callerid() here because it will
6706
	/* Don't use ast_set_callerid() here because it will
6707
	 * generate an unnecessary NewCallerID event  */
6707
	 * generate an unnecessary NewCallerID event  */
[+20] [20] 3534 lines
[+20] [+] static int add_rpid(struct sip_request *req, struct sip_pvt *p)
10242
		return 0;
10242
		return 0;
10243
	if (ast_strlen_zero(lid_name))
10243
	if (ast_strlen_zero(lid_name))
10244
		lid_name = lid_num;
10244
		lid_name = lid_num;
10245
	fromdomain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip));
10245
	fromdomain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip));
10246

    
   
10246

   
10247
	lid_num = ast_uri_encode(lid_num, tmp2, sizeof(tmp2), 1);
10247
	lid_num = ast_uri_encode(lid_num, tmp2, sizeof(tmp2), ast_uri_sip_user);
10248

    
   
10248

   
10249
	if (ast_test_flag(&p->flags[0], SIP_SENDRPID_PAI)) {
10249
	if (ast_test_flag(&p->flags[0], SIP_SENDRPID_PAI)) {
10250
		if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) {
10250
		if ((lid_pres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) {
10251
			ast_str_set(&tmp, -1, "%s", anonymous_string);
10251
			ast_str_set(&tmp, -1, "%s", anonymous_string);
10252
		} else {
10252
		} else {
[+20] [20] 964 lines
[+20] [+] static void extract_uri(struct sip_pvt *p, struct sip_request *req)
11217

    
   
11217

   
11218
/*! \brief Build contact header - the contact header we send out */
11218
/*! \brief Build contact header - the contact header we send out */
11219
static void build_contact(struct sip_pvt *p)
11219
static void build_contact(struct sip_pvt *p)
11220
{
11220
{
11221
	char tmp[SIPBUFSIZE];
11221
	char tmp[SIPBUFSIZE];
11222
	char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), 1);
11222
	char *user = ast_uri_encode(p->exten, tmp, sizeof(tmp), ast_uri_sip_user);
11223

    
   
11223

   
11224
	if (p->socket.type == SIP_TRANSPORT_UDP) {
11224
	if (p->socket.type == SIP_TRANSPORT_UDP) {
11225
		ast_string_field_build(p, our_contact, "<sip:%s%s%s>", user,
11225
		ast_string_field_build(p, our_contact, "<sip:%s%s%s>", user,
11226
			ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify(&p->ourip));
11226
			ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify(&p->ourip));
11227
	} else {
11227
	} else {
[+20] [20] 77 lines
[+20] [+] static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, const char * const explicit_uri)
11305
		n = p->fromname;
11305
		n = p->fromname;
11306
	else /* Save for any further attempts */
11306
	else /* Save for any further attempts */
11307
		ast_string_field_set(p, fromname, n);
11307
		ast_string_field_set(p, fromname, n);
11308

    
   
11308

   
11309
	if (sip_cfg.pedanticsipchecking) {
11309
	if (sip_cfg.pedanticsipchecking) {
11310
		ast_uri_encode(n, tmp_n, sizeof(tmp_n), 0);
11310
		ast_escape_quoted(n, tmp_n, sizeof(tmp_n));
11311
		n = tmp_n;
11311
		n = tmp_n;
11312
		ast_uri_encode(l, tmp_l, sizeof(tmp_l), 0);
11312
		ast_uri_encode(l, tmp_l, sizeof(tmp_l), ast_uri_sip_user);
11313
		l = tmp_l;
11313
		l = tmp_l;
11314
	}
11314
	}
11315

    
   
11315

   
11316
	ourport = (p->fromdomainport) ? p->fromdomainport : ast_sockaddr_port(&p->ourip);
11316
	ourport = (p->fromdomainport) ? p->fromdomainport : ast_sockaddr_port(&p->ourip);
11317
	if (!sip_standard_port(p->socket.type, ourport)) {
11317
	if (!sip_standard_port(p->socket.type, ourport)) {
[+20] [20] 13 lines
[+20] static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, const char * const explicit_uri)
11331
			/* Otherwise, use the username while waiting for registration */
11331
			/* Otherwise, use the username while waiting for registration */
11332
			ast_str_append(&invite, 0, "sip:");
11332
			ast_str_append(&invite, 0, "sip:");
11333
			if (!ast_strlen_zero(p->username)) {
11333
			if (!ast_strlen_zero(p->username)) {
11334
				n = p->username;
11334
				n = p->username;
11335
				if (sip_cfg.pedanticsipchecking) {
11335
				if (sip_cfg.pedanticsipchecking) {
11336
					ast_uri_encode(n, tmp_n, sizeof(tmp_n), 0);
11336
					ast_uri_encode(n, tmp_n, sizeof(tmp_n), ast_uri_sip_user);
11337
					n = tmp_n;
11337
					n = tmp_n;
11338
				}
11338
				}
11339
				ast_str_append(&invite, 0, "%s@", n);
11339
				ast_str_append(&invite, 0, "%s@", n);
11340
			}
11340
			}
11341
			ast_str_append(&invite, 0, "%s", p->tohost);
11341
			ast_str_append(&invite, 0, "%s", p->tohost);
[+20] [20] 3209 lines
[+20] [+] static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id)
14551
	}
14551
	}
14552

    
   
14552

   
14553
	/* Since extensions.conf can have unescaped characters, try matching a
14553
	/* Since extensions.conf can have unescaped characters, try matching a
14554
	 * decoded uri in addition to the non-decoded uri. */
14554
	 * decoded uri in addition to the non-decoded uri. */
14555
	decoded_uri = ast_strdupa(uri);
14555
	decoded_uri = ast_strdupa(uri);
14556
	ast_uri_decode(decoded_uri);
14556
	ast_uri_decode(decoded_uri, ast_uri_sip_user);
14557

    
   
14557

   
14558
	/* If this is a subscription we actually just need to see if a hint exists for the extension */
14558
	/* If this is a subscription we actually just need to see if a hint exists for the extension */
14559
	if (req->method == SIP_SUBSCRIBE) {
14559
	if (req->method == SIP_SUBSCRIBE) {
14560
		char hint[AST_MAX_EXTENSION];
14560
		char hint[AST_MAX_EXTENSION];
14561
		int which = 0;
14561
		int which = 0;
[+20] [20] 217 lines
[+20] [+] static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req)
14779
		char *to = NULL, *from = NULL;
14779
		char *to = NULL, *from = NULL;
14780
		
14780
		
14781
		/* This is an attended transfer */
14781
		/* This is an attended transfer */
14782
		referdata->attendedtransfer = 1;
14782
		referdata->attendedtransfer = 1;
14783
		ast_copy_string(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid));
14783
		ast_copy_string(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid));
14784
		ast_uri_decode(referdata->replaces_callid);
14784
		ast_uri_decode(referdata->replaces_callid, ast_uri_sip_user);
14785
		if ((ptr = strchr(referdata->replaces_callid, ';'))) 	/* Find options */ {
14785
		if ((ptr = strchr(referdata->replaces_callid, ';'))) 	/* Find options */ {
14786
			*ptr++ = '\0';
14786
			*ptr++ = '\0';
14787
		}
14787
		}
14788
		
14788
		
14789
		if (ptr) {
14789
		if (ptr) {
[+20] [20] 3969 lines
[+20] [+] static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req, char **name, char **number, int set_call_forward)
18759
		else if (!strncasecmp(contact_number, "sips:", 5))
18759
		else if (!strncasecmp(contact_number, "sips:", 5))
18760
			contact_number += 5;
18760
			contact_number += 5;
18761
		separator = strchr(contact_number, ';');	/* And username ; parameters? */
18761
		separator = strchr(contact_number, ';');	/* And username ; parameters? */
18762
		if (separator)
18762
		if (separator)
18763
			*separator = '\0';
18763
			*separator = '\0';
18764
		ast_uri_decode(contact_number);
18764
		ast_uri_decode(contact_number, ast_uri_sip_user);
18765
		if (set_call_forward) {
18765
		if (set_call_forward) {
18766
			ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", contact_number, domain);
18766
			ast_debug(2, "Received 302 Redirect to extension '%s' (domain %s)\n", contact_number, domain);
18767
			if (p->owner) {
18767
			if (p->owner) {
18768
				pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
18768
				pbx_builtin_setvar_helper(p->owner, "SIPDOMAIN", domain);
18769
				ast_string_field_set(p->owner, call_forward, contact_number);
18769
				ast_string_field_set(p->owner, call_forward, contact_number);
[+20] [20] 2477 lines
[+20] [+] static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *recount, const char *e, int *nounlock)
21247

    
   
21247

   
21248
		if (sipdebug)
21248
		if (sipdebug)
21249
			ast_debug(3, "INVITE part of call transfer. Replaces [%s]\n", p_replaces);
21249
			ast_debug(3, "INVITE part of call transfer. Replaces [%s]\n", p_replaces);
21250
		/* Create a buffer we can manipulate */
21250
		/* Create a buffer we can manipulate */
21251
		replace_id = ast_strdupa(p_replaces);
21251
		replace_id = ast_strdupa(p_replaces);
21252
		ast_uri_decode(replace_id);
21252
		ast_uri_decode(replace_id, ast_uri_sip_user);
21253

    
   
21253

   
21254
		if (!p->refer && !sip_refer_allocate(p)) {
21254
		if (!p->refer && !sip_refer_allocate(p)) {
21255
			transmit_response_reliable(p, "500 Server Internal Error", req);
21255
			transmit_response_reliable(p, "500 Server Internal Error", req);
21256
			append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
21256
			append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
21257
			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
21257
			sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
[+20] [20] 301 lines
[+20] static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *recount, const char *e, int *nounlock)
21559
			case SIP_GET_DEST_REFUSED:
21559
			case SIP_GET_DEST_REFUSED:
21560
			default:
21560
			default:
21561
				{
21561
				{
21562
					char *decoded_exten = ast_strdupa(p->exten);
21562
					char *decoded_exten = ast_strdupa(p->exten);
21563
					transmit_response_reliable(p, "404 Not Found", req);
21563
					transmit_response_reliable(p, "404 Not Found", req);
21564
					ast_uri_decode(decoded_exten);
21564
					ast_uri_decode(decoded_exten, ast_uri_sip_user);
21565
					ast_log(LOG_NOTICE, "Call from '%s' to extension"
21565
					ast_log(LOG_NOTICE, "Call from '%s' to extension"
21566
						" '%s' rejected because extension not found in context '%s'.\n",
21566
						" '%s' rejected because extension not found in context '%s'.\n",
21567
						S_OR(p->username, p->peername), decoded_exten, p->context);
21567
						S_OR(p->username, p->peername), decoded_exten, p->context);
21568
				}
21568
				}
21569
			} /* end switch */
21569
			} /* end switch */
[+20] [20] 7636 lines
/trunk/channels/sip/reqresp_parser.c
Revision 302507 New Change
 
/trunk/funcs/func_curl.c
Revision 302507 New Change
 
/trunk/funcs/func_uri.c
Revision 302507 New Change
 
/trunk/include/asterisk/utils.h
Revision 302507 New Change
 
/trunk/main/http.c
Revision 302507 New Change
 
/trunk/main/utils.c
Revision 302507 New Change
 
/trunk/res/res_agi.c
Revision 302507 New Change
 
/trunk/res/res_config_curl.c
Revision 302507 New Change
 
/trunk/tests/test_utils.c
Revision 302507 New Change
 
  1. /trunk/channels/chan_sip.c: Loading...
  2. /trunk/channels/sip/reqresp_parser.c: Loading...
  3. /trunk/funcs/func_curl.c: Loading...
  4. /trunk/funcs/func_uri.c: Loading...
  5. /trunk/include/asterisk/utils.h: Loading...
  6. /trunk/main/http.c: Loading...
  7. /trunk/main/utils.c: Loading...
  8. /trunk/res/res_agi.c: Loading...
  9. /trunk/res/res_config_curl.c: Loading...
  10. /trunk/tests/test_utils.c: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.