mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-01 03:04:19 +00:00
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) git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@346899 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -13632,7 +13632,12 @@ 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 */
|
||||
/*! \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 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
|
||||
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 @@ 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_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 @@ static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sock
|
||||
|
||||
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@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)) {
|
||||
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 int get_rdnis(struct sip_pvt *p, struct sip_request *oreq, char **name, c
|
||||
*/
|
||||
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 @@ 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_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 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
|
||||
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 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
|
||||
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 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
|
||||
/* 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;
|
||||
|
||||
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@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@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 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
|
||||
* 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=\""))) {
|
||||
ast_copy_string(from, hdr + strlen("username=\""), sizeof(from));
|
||||
of = from;
|
||||
of = strsep(&of, "\"");
|
||||
name = from;
|
||||
name = strsep(&name, "\"");
|
||||
}
|
||||
}
|
||||
|
||||
res = check_peer_ok(p, of, req, sipmethod, addr,
|
||||
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 @@ static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_requ
|
||||
} 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);
|
||||
|
||||
Reference in New Issue
Block a user