diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4a01cd434176c5a87df198e951964974e401f4ab..75e902e5c523d523bb74e408de507f4eec5b2eda 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -13524,6 +13524,18 @@ static int parse_ok_contact(struct sip_pvt *pvt, struct sip_request *req) return TRUE; } +/*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled */ +static int parse_uri_legacy_check(char *uri, const char *scheme, char **user, char **pass, char **domain, char **transport) { + int ret = parse_uri(uri, scheme, user, pass, domain, transport); + if (sip_cfg.legacy_useroption_parsing) { /* if legacy mode is active, strip semis from the user field */ + char *p; + if ((p = strchr(uri, (int)';'))) { + *p = '\0'; + } + } + return ret; +} + static int __set_address_from_contact(const char *fullcontact, struct ast_sockaddr *addr, int tcp) { char *domain, *transport; @@ -13541,7 +13553,7 @@ static int __set_address_from_contact(const char *fullcontact, struct ast_sockad * We still need to be able to send to the remote agent through the proxy. */ - if (parse_uri(contact, "sip:,sips:", &contact, NULL, &domain, + if (parse_uri_legacy_check(contact, "sip:,sips:", &contact, NULL, &domain, &transport)) { ast_log(LOG_WARNING, "Invalid contact uri %s (missing sip: or sips:), attempting to use anyway\n", fullcontact); } @@ -13670,7 +13682,7 @@ static enum parse_register_result parse_register_contact(struct sip_pvt *pvt, st ast_string_field_build(pvt, our_contact, "<%s>", curi); /* Make sure it's a SIP URL */ - if (parse_uri(curi, "sip:,sips:", &curi, NULL, &domain, &transport)) { + if (parse_uri_legacy_check(curi, "sip:,sips:", &curi, NULL, &domain, &transport)) { ast_log(LOG_NOTICE, "Not a valid SIP contact (missing sip:/sips:) trying to use anyway\n"); } @@ -14371,7 +14383,7 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock c = get_in_brackets(tmp); c = remove_uri_parameters(c); - if (parse_uri(c, "sip:,sips:", &name, &dummy, &domain, NULL)) { + if (parse_uri_legacy_check(c, "sip:,sips:", &name, &dummy, &domain, NULL)) { ast_log(LOG_NOTICE, "Invalid to address: '%s' from %s (missing sip:) trying to use anyway...\n", c, ast_sockaddr_stringify_addr(addr)); return -1; } @@ -14952,7 +14964,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re uri = ast_strdupa(get_in_brackets(tmp)); - if (parse_uri(uri, "sip:,sips:", &uri, &dummy, &domain, NULL)) { + if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &dummy, &domain, NULL)) { ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri); return SIP_GET_DEST_INVALID_URI; } @@ -14977,7 +14989,7 @@ static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_re ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf)); if (!ast_strlen_zero(tmpf)) { from = get_in_brackets(tmpf); - if (parse_uri(from, "sip:,sips:", &from, NULL, &domain, NULL)) { + if (parse_uri_legacy_check(from, "sip:,sips:", &from, NULL, &domain, NULL)) { ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", from); return SIP_GET_DEST_INVALID_URI; } @@ -15388,7 +15400,7 @@ static int get_also_info(struct sip_pvt *p, struct sip_request *oreq) ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp)); c = get_in_brackets(tmp); - if (parse_uri(c, "sip:,sips:", &c, NULL, &a, NULL)) { + if (parse_uri_legacy_check(c, "sip:,sips:", &c, NULL, &a, NULL)) { ast_log(LOG_WARNING, "Huh? Not a SIP header in Also: transfer (%s)?\n", c); return -1; } @@ -15764,7 +15776,7 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ ast_string_field_set(p, from, of); /* ignore all fields but name */ - if (parse_uri(of, "sip:,sips:", &of, &dummy, &domain, NULL)) { + if (parse_uri_legacy_check(of, "sip:,sips:", &of, &dummy, &domain, NULL)) { ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n"); } @@ -17619,6 +17631,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, " Regexten on Qualify: %s\n", AST_CLI_YESNO(sip_cfg.regextenonqualify)); ast_cli(a->fd, " Trust RPID: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_TRUSTRPID))); ast_cli(a->fd, " Send RPID: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_SENDRPID))); + ast_cli(a->fd, " Legacy userfield parse: %s\n", AST_CLI_YESNO(sip_cfg.legacy_useroption_parsing)); ast_cli(a->fd, " Caller ID: %s\n", default_callerid); if ((default_fromdomainport) && (default_fromdomainport != STANDARD_SIP_PORT)) { ast_cli(a->fd, " From: Domain: %s:%d\n", default_fromdomain, default_fromdomainport); @@ -27303,6 +27316,7 @@ static int reload_config(enum channelreloadreason reason) sip_cfg.regcontext[0] = '\0'; sip_set_default_format_capabilities(sip_cfg.caps); sip_cfg.regextenonqualify = DEFAULT_REGEXTENONQUALIFY; + sip_cfg.legacy_useroption_parsing = DEFAULT_LEGACY_USEROPTION_PARSING; sip_cfg.notifyringing = DEFAULT_NOTIFYRINGING; sip_cfg.notifycid = DEFAULT_NOTIFYCID; sip_cfg.notifyhold = FALSE; /*!< Keep track of hold status for a peer */ @@ -27576,6 +27590,8 @@ static int reload_config(enum channelreloadreason reason) ast_copy_string(sip_cfg.regcontext, v->value, sizeof(sip_cfg.regcontext)); } else if (!strcasecmp(v->name, "regextenonqualify")) { sip_cfg.regextenonqualify = ast_true(v->value); + } else if (!strcasecmp(v->name, "legacy_useroption_parsing")) { + sip_cfg.legacy_useroption_parsing = ast_true(v->value); } else if (!strcasecmp(v->name, "callerid")) { ast_copy_string(default_callerid, v->value, sizeof(default_callerid)); } else if (!strcasecmp(v->name, "mwi_from")) { diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index b856a7f3e54df578fef8c6b38e54dfb9bf138b4c..4b69010b3b596baec69184278c697da17953f017 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -212,6 +212,7 @@ #define DEFAULT_ALWAYSAUTHREJECT TRUE /*!< Don't reject authentication requests always */ #define DEFAULT_AUTH_OPTIONS FALSE #define DEFAULT_REGEXTENONQUALIFY FALSE +#define DEFAULT_LEGACY_USEROPTION_PARSING FALSE #define DEFAULT_T1MIN 100 /*!< 100 MS for minimal roundtrip time */ #define DEFAULT_MAX_CALL_BITRATE (384) /*!< Max bitrate for video */ #ifndef DEFAULT_USERAGENT @@ -683,6 +684,7 @@ struct sip_settings { int allow_external_domains; /*!< Accept calls to external SIP domains? */ int callevents; /*!< Whether we send manager events or not */ int regextenonqualify; /*!< Whether to add/remove regexten when qualifying peers */ + int legacy_useroption_parsing; /*!< Whether to strip useroptions in URI via semicolons */ int matchexternaddrlocally; /*!< Match externaddr/externhost setting against localnet setting */ char regcontext[AST_MAX_CONTEXT]; /*!< Context for auto-extensions */ unsigned int disallowed_methods; /*!< methods that we should never try to use */ diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample index 1726299d34fc73066c69a3750ca8e870f31b22a8..179678a3955054f883897f6cadc2109049717d3c 100644 --- a/configs/sip.conf.sample +++ b/configs/sip.conf.sample @@ -432,6 +432,14 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls ; If you have qualify on and the peer becomes unreachable ; this setting will enforce inactivation of the regexten ; extension for the peer +;legacy_useroption_parsing=yes ; Default "no" ; If you have this option enabled and there are semicolons + ; in the user field of a sip URI, the field be truncated + ; at the first semicolon seen. This effectively makes + ; semicolon a non-usable character for peer names, extensions, + ; and maybe other, less tested things. This can be useful + ; for improving compatability with devices that like to use + ; user options for whatever reason. The behavior is similar to + ; how SIP URI's were typically handled in 1.6.2, hence the name. ; The shrinkcallerid function removes '(', ' ', ')', non-trailing '.', and '-' not ; in square brackets. For example, the caller id value 555.5555 becomes 5555555