summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Nicholson <mnicholson@digium.com>2009-08-12 22:18:09 +0000
committerMatthew Nicholson <mnicholson@digium.com>2009-08-12 22:18:09 +0000
commit5583a4e9555ae2fa79573d1fcfbe1a2a90d8dea2 (patch)
tree86def3af5d2ac2dc989dc1d932f82c0e2e9a854e
parentb65c0edd52087a3057f19d4e3b023f08e620251e (diff)
This patch adds support for choosing a realm based on the domain in the From or To header in the incoming request. Eligible domains are taken from the domains list in the config file. This functionality is enabled when domainsasrealm is enabled in the config file.
(closes issue #11361) Reported by: arkadia Patches: sip_realm_mnich_to_added_2.patch uploaded by arkadia (license 233) Tested by: arkadia git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@211947 65c4cc65-6c06-0410-ace0-fbb531ad65f3
-rw-r--r--channels/chan_sip.c89
-rw-r--r--configs/sip.conf.sample6
2 files changed, 93 insertions, 2 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 84e99ff73..e64b090be 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1118,6 +1118,7 @@ static const char *sip_reason_code_to_str(enum AST_REDIRECTING_REASON code)
#define DEFAULT_COS_TEXT 5 /*!< Level 2 class of service for text media (T.140) */
#define DEFAULT_ALLOW_EXT_DOM TRUE /*!< Allow external domains */
#define DEFAULT_REALM "asterisk" /*!< Realm for HTTP digest authentication */
+#define DEFAULT_DOMAINSASREALM FALSE /*!< Use the domain option to guess the realm for registration and invite requests */
#define DEFAULT_NOTIFYRINGING TRUE /*!< Notify devicestate system on ringing state */
#define DEFAULT_NOTIFYCID DISABLED /*!< Include CID with ringing notifications */
#define DEFAULT_PEDANTIC FALSE /*!< Avoid following SIP standards for dialog matching */
@@ -1195,6 +1196,7 @@ struct sip_settings {
int allowsubscribe; /*!< Flag for disabling ALL subscriptions, this is FALSE only if all peers are FALSE
the global setting is in globals_flags[1] */
char realm[MAXHOSTNAMELEN]; /*!< Default realm */
+ int domainsasrealm; /*!< Use domains lists as realms */
struct sip_proxy outboundproxy; /*!< Outbound proxy */
char default_context[AST_MAX_CONTEXT];
char default_subscribecontext[AST_MAX_CONTEXT];
@@ -2637,6 +2639,8 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full, int tim
static void update_connectedline(struct sip_pvt *p, const void *data, size_t datalen);
static void update_redirecting(struct sip_pvt *p, const void *data, size_t datalen);
static void change_redirecting_information(struct sip_pvt *p, struct sip_request *req, struct ast_party_redirecting *redirecting, int set_call_forward);
+static int get_domain(const char *str, char *domain, int len);
+static void get_realm(struct sip_pvt *p, const struct sip_request *req);
/*-- TCP connection handling ---*/
static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session);
@@ -9479,9 +9483,12 @@ static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const
ast_log(LOG_WARNING, "Unable to determine sequence number from '%s'\n", get_header(req, "CSeq"));
return -1;
}
+ /* Choose Realm */
+ get_realm(p, req);
+
/* 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", sip_cfg.realm, randdata, stale ? ", stale=true" : "");
+ snprintf(tmp, sizeof(tmp), "Digest algorithm=MD5, realm=\"%s\", nonce=\"%s\"%s", p->realm, randdata, stale ? ", stale=true" : "");
respprep(&resp, p, msg, req);
add_header(&resp, header, tmp);
add_header_contentLength(&resp, 0);
@@ -9489,6 +9496,80 @@ static int transmit_response_with_auth(struct sip_pvt *p, const char *msg, const
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 and then To header or use globaly configured realm.
+ Realm from From/To header should be listed among served domains in config file: domain=...
+*/
+static void get_realm(struct sip_pvt *p, const struct sip_request *req)
+{
+ char domain[MAXHOSTNAMELEN];
+
+ if (!ast_strlen_zero(p->realm))
+ return;
+
+ if (sip_cfg.domainsasrealm &&
+ !AST_LIST_EMPTY(&domain_list))
+ {
+ /* Check From header first */
+ if (!get_domain(get_header(req, "From"), domain, sizeof(domain))) {
+ if (check_sip_domain(domain, NULL, 0)) {
+ ast_string_field_set(p, realm, domain);
+ return;
+ }
+ }
+ /* Check To header */
+ if (!get_domain(get_header(req, "To"), domain, sizeof(domain))) {
+ if (check_sip_domain(domain, NULL, 0)) {
+ ast_string_field_set(p, realm, domain);
+ return;
+ }
+ }
+ }
+
+ /* Use default realm from config file */
+ ast_string_field_set(p, realm, sip_cfg.realm);
+}
+
/*! \brief Add text body to SIP message */
static int add_text(struct sip_request *req, const char *text)
{
@@ -12561,7 +12642,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
else {
char a1[256];
- snprintf(a1, sizeof(a1), "%s:%s:%s", username, sip_cfg.realm, secret);
+ snprintf(a1, sizeof(a1), "%s:%s:%s", username, p->realm, secret);
ast_md5_hash(a1_hash, a1);
}
@@ -15915,6 +15996,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_
ast_cli(a->fd, " SIP domain support: %s\n", cli_yesno(!AST_LIST_EMPTY(&domain_list)));
ast_cli(a->fd, " Realm. auth: %s\n", cli_yesno(authl != NULL));
ast_cli(a->fd, " Our auth realm %s\n", sip_cfg.realm);
+ ast_cli(a->fd, " Use domains as realms: %s\n", cli_yesno(sip_cfg.domainsasrealm));
ast_cli(a->fd, " Call to non-local dom.: %s\n", cli_yesno(sip_cfg.allow_external_domains));
ast_cli(a->fd, " URI user is phone no: %s\n", cli_yesno(ast_test_flag(&global_flags[0], SIP_USEREQPHONE)));
ast_cli(a->fd, " Always auth rejects: %s\n", cli_yesno(sip_cfg.alwaysauthreject));
@@ -24559,6 +24641,7 @@ static int reload_config(enum channelreloadreason reason)
snprintf(global_sdpowner, sizeof(global_sdpowner), "%s", DEFAULT_SDPOWNER);
ast_copy_string(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime));
ast_copy_string(sip_cfg.realm, S_OR(ast_config_AST_SYSTEM_NAME, DEFAULT_REALM), sizeof(sip_cfg.realm));
+ sip_cfg.domainsasrealm = DEFAULT_DOMAINSASREALM;
ast_copy_string(default_callerid, DEFAULT_CALLERID, sizeof(default_callerid));
ast_copy_string(default_mwi_from, DEFAULT_MWI_FROM, sizeof(default_mwi_from));
sip_cfg.compactheaders = DEFAULT_COMPACTHEADERS;
@@ -24651,6 +24734,8 @@ static int reload_config(enum channelreloadreason reason)
sip_cfg.allowguest = ast_true(v->value) ? 1 : 0;
} else if (!strcasecmp(v->name, "realm")) {
ast_copy_string(sip_cfg.realm, v->value, sizeof(sip_cfg.realm));
+ } else if (!strcasecmp(v->name, "domainsasrealm")) {
+ sip_cfg.domainsasrealm = ast_true(v->value);
} else if (!strcasecmp(v->name, "useragent")) {
ast_copy_string(global_useragent, v->value, sizeof(global_useragent));
ast_debug(1, "Setting SIP channel User-Agent Name to %s\n", global_useragent);
diff --git a/configs/sip.conf.sample b/configs/sip.conf.sample
index ba9b0c619..4116037dc 100644
--- a/configs/sip.conf.sample
+++ b/configs/sip.conf.sample
@@ -98,6 +98,12 @@ allowoverlap=no ; Disable overlap dialing support. (Default is y
; 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
+;domainsasrealm=no ; Use domans list as realms
+ ; You can serve multiple Realms specifying several
+ ; 'domain=...' directives (see below).
+ ; In this case Realm will be based on request 'From'/'To' header
+ ; and should match one of domain names.
+ ; Otherwise default 'realm=...' will be used.
udpbindaddr=0.0.0.0 ; IP address to bind UDP listen socket to (0.0.0.0 binds to all)
; Optionally add a port number, 192.168.1.1:5062 (default is port 5060)