Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revision 89537) +++ channels/chan_sip.c (working copy) @@ -1712,6 +1712,8 @@ static int get_destination(struct sip_pvt *p, struct sip_request *oreq); static int get_msg_text(char *buf, int len, struct sip_request *req); static int transmit_state_notify(struct sip_pvt *p, int state, int full, int timeout); +static int get_domain(const char *str, char *domain, int len); +static int get_realm(const struct sip_request *req, char *realm, int len); /*--- Constructing requests and responses */ static void initialize_initreq(struct sip_pvt *p, struct sip_request *req); @@ -6738,14 +6740,18 @@ struct sip_request resp; char tmp[512]; int seqno = 0; + char realm[MAXHOSTNAMELEN]; if (reliable && (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1)) { ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq")); return -1; } + /* Choose Realm */ + get_realm(req, realm, sizeof(realm)); + /* Stale means that they sent us correct authentication, but based it on an old challenge (nonce) */ - snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", global_realm, randdata, stale ? ", stale=true" : ""); + snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", realm, randdata, stale ? ", stale=true" : ""); respprep(&resp, p, msg, req); add_header(&resp, header, tmp); add_header_contentLength(&resp, 0); @@ -6753,6 +6759,68 @@ return send_response(p, &resp, reliable, seqno); } +/*! + \brief Extract domain from SIP To/From header + \return -1 on error, 1 if domain string is empty, 0 if domain was properly extracted + \note TODO: Such code is all over SIP channel, there is a sense to organize + this patern in one function +*/ +static int get_domain(const char *str, char *domain, int len) +{ + char tmpf[256]; + char *a, *from; + + *domain = '\0'; + ast_copy_string(tmpf, str, sizeof(tmpf)); + from = get_in_brackets(tmpf); + if (!ast_strlen_zero(from)) { + if (strncasecmp(from, "sip:", 4)) { + ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", from); + return -1; + } + from += 4; + } else + from = NULL; + + if (from) { + /* Strip any params or options from user */ + if ((a = strchr(from, ';'))) + *a = '\0'; + /* Strip port from domain if present */ + if ((a = strchr(from, ':'))) + *a = '\0'; + if ((a = strchr(from, '@'))) { + *a = '\0'; + ast_copy_string(domain, a + 1, len); + } else + ast_copy_string(domain, from, len); + } + + return ast_strlen_zero(domain); +} + +/*! + \brief Choose realm based on From header or use globaly configured realm. + Realm from From header should be listed among served domains in config file: domain=... +*/ +static int get_realm(const struct sip_request *req, char *realm, int len) +{ + char fromdomain[MAXHOSTNAMELEN]; + char *r = NULL; + + if (!AST_LIST_EMPTY(&domain_list) && + !get_domain(get_header(req, "From"), fromdomain, sizeof(fromdomain))) + { + if (check_sip_domain(fromdomain, NULL, 0)) + r = fromdomain; + } + if (!r) + r = global_realm; + ast_copy_string(realm, r, len); + + return 0; +} + /*! \brief Add text body to SIP message */ static int add_text(struct sip_request *req, const char *text) { @@ -9123,7 +9191,10 @@ ast_copy_string(a1_hash, md5secret, sizeof(a1_hash)); else { char a1[256]; - snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret); + char realm[MAXHOSTNAMELEN]; + /* Choose Realm */ + get_realm(req, realm, sizeof(realm)); + snprintf(a1, sizeof(a1), "%s:%s:%s", username, realm, secret); ast_md5_hash(a1_hash, a1); } Index: configs/sip.conf.sample =================================================================== --- configs/sip.conf.sample (revision 89537) +++ configs/sip.conf.sample (working copy) @@ -38,6 +38,12 @@ ; asterisk.conf, it defaults to that system name ; Realms MUST be globally unique according to RFC 3261 ; Set this to your host name or domain name + ; You can serve multiple Realms specifying several + ; 'domain=...' directives (see below). + ; In this case Realm will be based on request 'From' header + ; and should match one of domain names. + ; Otherwise default 'realm=...' will be used. + bindport=5060 ; UDP Port to bind to (SIP standard port is 5060) ; bindport is the local UDP port that Asterisk will listen on bindaddr=0.0.0.0 ; IP address to bind to (0.0.0.0 binds to all)