[svn-commits] wdoekes: branch 1.8 r346899 - /branches/1.8/channels/chan_sip.c
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Sun Dec 4 03:57:08 CST 2011
Author: wdoekes
Date: Sun Dec 4 03:57:02 2011
New Revision: 346899
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=346899
Log:
For SIP REGISTER fix domain-only URIs and domain ACL bypass.
The code that allowed admins to create users with domain-only uri's had
stopped to work in 1.8 because of the reqresp parser rewrites. This is
fixed now: if you have a [mydomain.com] sip user, you can register with
useraddr sip:mydomain.com. Note that in that case -- if you're using
domain ACLs (a configured domain list) -- mydomain.com must be in the
allow list as well.
Reviewboard r1606 shows a list of registration combinations and which
SIP response codes are returned.
Review: https://reviewboard.asterisk.org/r/1533/
Reviewed by: Terry Wilson
(closes issue ASTERISK-18389)
(closes issue ASTERISK-18741)
Modified:
branches/1.8/channels/chan_sip.c
Modified: branches/1.8/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_sip.c?view=diff&rev=346899&r1=346898&r2=346899
==============================================================================
--- branches/1.8/channels/chan_sip.c (original)
+++ branches/1.8/channels/chan_sip.c Sun Dec 4 03:57:02 2011
@@ -13632,7 +13632,12 @@
return TRUE;
}
-/*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled */
+/*! \brief parse uri in a way that allows semicolon stripping if legacy mode is enabled
+ *
+ * \note This calls parse_uri which has the unexpected property that passing more
+ * arguments results in more splitting. Most common is to leave out the pass
+ * argument, causing user to contain user:pass if available.
+ */
static int parse_uri_legacy_check(char *uri, const char *scheme, char **user, char **pass, char **hostport, char **transport)
{
int ret = parse_uri(uri, scheme, user, pass, hostport, transport);
@@ -14492,7 +14497,7 @@
enum check_auth_result res = AUTH_NOT_FOUND;
struct sip_peer *peer;
char tmp[256];
- char *name = NULL, *c, *domain = NULL, *dummy = NULL;
+ char *c, *name, *unused_password, *domain;
char *uri2 = ast_strdupa(uri);
terminate_uri(uri2);
@@ -14502,7 +14507,7 @@
c = get_in_brackets(tmp);
c = remove_uri_parameters(c);
- if (parse_uri_legacy_check(c, "sip:,sips:", &name, &dummy, &domain, NULL)) {
+ if (parse_uri_legacy_check(c, "sip:,sips:", &name, &unused_password, &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;
}
@@ -14512,12 +14517,34 @@
extract_host_from_hostport(&domain);
- /*! \todo XXX here too we interpret a missing @domain as a name-only
- * URI, whereas the RFC says this is a domain-only uri.
- */
- if (!ast_strlen_zero(domain) && !AST_LIST_EMPTY(&domain_list)) {
+ if (ast_strlen_zero(domain)) {
+ /* <sip:name@[EMPTY]>, never good */
+ transmit_response(p, "404 Not found", &p->initreq);
+ return AUTH_UNKNOWN_DOMAIN;
+ }
+
+ if (ast_strlen_zero(name)) {
+ /* <sip:[EMPTY][@]hostport>, unsure whether valid for
+ * registration. RFC 3261, 10.2 states:
+ * "The To header field and the Request-URI field typically
+ * differ, as the former contains a user name."
+ * But, Asterisk has always treated the domain-only uri as a
+ * username: we allow admins to create accounts described by
+ * domain name. */
+ name = domain;
+ }
+
+ /* This here differs from 1.4 and 1.6: the domain matching ACLs were
+ * skipped if it was a domain-only URI (used as username). Here we treat
+ * <sip:hostport> as <sip:host at hostport> and won't forget to test the
+ * domain ACLs against host. */
+ if (!AST_LIST_EMPTY(&domain_list)) {
if (!check_sip_domain(domain, NULL, 0)) {
- transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
+ if (sip_cfg.alwaysauthreject) {
+ transmit_fake_auth_response(p, SIP_REGISTER, &p->initreq, XMIT_UNRELIABLE);
+ } else {
+ transmit_response(p, "404 Not found (unknown domain)", &p->initreq);
+ }
return AUTH_UNKNOWN_DOMAIN;
}
}
@@ -15059,7 +15086,7 @@
*/
static enum sip_get_dest_result get_destination(struct sip_pvt *p, struct sip_request *oreq, int *cc_recall_core_id)
{
- char tmp[256] = "", *uri, *domain, *dummy = NULL;
+ char tmp[256] = "", *uri, *unused_password, *domain;
char tmpf[256] = "", *from = NULL;
struct sip_request *req;
char *decoded_uri;
@@ -15075,7 +15102,7 @@
uri = ast_strdupa(get_in_brackets(tmp));
- if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &dummy, &domain, NULL)) {
+ if (parse_uri_legacy_check(uri, "sip:,sips:", &uri, &unused_password, &domain, NULL)) {
ast_log(LOG_WARNING, "Not a SIP header (%s)?\n", uri);
return SIP_GET_DEST_INVALID_URI;
}
@@ -15850,10 +15877,7 @@
int sipmethod, const char *uri, enum xmittype reliable,
struct ast_sockaddr *addr, struct sip_peer **authpeer)
{
- char from[256] = { 0, };
- char *dummy = NULL; /* dummy return value for parse_uri */
- char *domain = NULL; /* dummy return value for parse_uri */
- char *of;
+ char from[256] = "", *of, *name, *unused_password, *domain;
enum check_auth_result res = AUTH_DONT_KNOW;
char calleridname[50];
char *uri2 = ast_strdupa(uri);
@@ -15870,8 +15894,9 @@
return res;
}
- if (calleridname[0])
+ if (calleridname[0]) {
ast_string_field_set(p, cid_name, calleridname);
+ }
if (ast_strlen_zero(p->exten)) {
char *t = uri2;
@@ -15893,32 +15918,36 @@
/* save the URI part of the From header */
ast_string_field_set(p, from, of);
- /* ignore all fields but name */
- if (parse_uri_legacy_check(of, "sip:,sips:", &of, &dummy, &domain, NULL)) {
+ if (parse_uri_legacy_check(of, "sip:,sips:", &name, &unused_password, &domain, NULL)) {
ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
}
- SIP_PEDANTIC_DECODE(of);
+ SIP_PEDANTIC_DECODE(name);
SIP_PEDANTIC_DECODE(domain);
- if (ast_strlen_zero(of)) {
- /* XXX note: the original code considered a missing @host
- * as a username-only URI. The SIP RFC (19.1.1) says that
- * this is wrong, and it should be considered as a domain-only URI.
- * For backward compatibility, we keep this block, but it is
- * really a mistake and should go away.
- */
-
- extract_host_from_hostport(&domain);
- of = domain;
+ extract_host_from_hostport(&domain);
+
+ if (ast_strlen_zero(domain)) {
+ /* <sip:name@[EMPTY]>, never good */
+ ast_log(LOG_ERROR, "Empty domain name in FROM header\n");
+ return res;
+ }
+
+ if (ast_strlen_zero(name)) {
+ /* <sip:[EMPTY][@]hostport>. Asterisk 1.4 and 1.6 have always
+ * treated that as a username, so we continue the tradition:
+ * uri is now <sip:host at hostport>. */
+ name = domain;
} else {
- char *tmp = ast_strdupa(of);
- /* We need to be able to handle auth-headers looking like
+ /* Non-empty name, try to get caller id from it */
+ char *tmp = ast_strdupa(name);
+ /* We need to be able to handle from-headers looking like
<sip:8164444422;phone-context=+1 at 1.2.3.4:5060;user=phone;tag=SDadkoa01-gK0c3bdb43>
*/
tmp = strsep(&tmp, ";");
- if (global_shrinkcallerid && ast_is_shrinkable_phonenumber(tmp))
+ if (global_shrinkcallerid && ast_is_shrinkable_phonenumber(tmp)) {
ast_shrink_phone_number(tmp);
+ }
ast_string_field_set(p, cid_num, tmp);
}
@@ -15932,20 +15961,22 @@
* pick one or another depending on the request ? XXX
*/
const char *hdr = get_header(req, "Authorization");
- if (ast_strlen_zero(hdr))
+ if (ast_strlen_zero(hdr)) {
hdr = get_header(req, "Proxy-Authorization");
-
- if ( !ast_strlen_zero(hdr) && (hdr = strstr(hdr, "username=\"")) ) {
+ }
+
+ if (!ast_strlen_zero(hdr) && (hdr = strstr(hdr, "username=\""))) {
ast_copy_string(from, hdr + strlen("username=\""), sizeof(from));
- of = from;
- of = strsep(&of, "\"");
- }
- }
-
- res = check_peer_ok(p, of, req, sipmethod, addr,
+ name = from;
+ name = strsep(&name, "\"");
+ }
+ }
+
+ res = check_peer_ok(p, name, req, sipmethod, addr,
authpeer, reliable, calleridname, uri2);
- if (res != AUTH_DONT_KNOW)
+ if (res != AUTH_DONT_KNOW) {
return res;
+ }
/* Finally, apply the guest policy */
if (sip_cfg.allowguest) {
@@ -15958,11 +15989,11 @@
} else {
res = AUTH_RTP_FAILED;
}
- } else if (sip_cfg.alwaysauthreject)
+ } else if (sip_cfg.alwaysauthreject) {
res = AUTH_FAKE_AUTH; /* reject with fake authorization request */
- else
+ } else {
res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */
-
+ }
if (ast_test_flag(&p->flags[1], SIP_PAGE2_RPORT_PRESENT)) {
ast_set_flag(&p->flags[0], SIP_NAT_RPORT_PRESENT);
More information about the svn-commits
mailing list