Newer
Older
reason = "Peer not found";
break;
default:
break;
}
ast_log(LOG_DEBUG, "SIP REGISTER attempt failed for %s : %s\n",
peer->name, reason);
Kevin P. Fleming
committed
}
}
Mark Spencer
committed
if (peer)
ASTOBJ_UNREF(peer, sip_destroy_peer);
static int get_rdnis(struct sip_pvt *p, struct sip_request *oreq)
{
char tmp[256], *c, *a;
struct sip_request *req;
req = oreq;
if (!req)
req = &p->initreq;
Kevin P. Fleming
committed
ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp));
if (ast_strlen_zero(tmp))
Kevin P. Fleming
committed
c = get_in_brackets(tmp);
if (strncmp(c, "sip:", 4)) {
ast_log(LOG_WARNING, "Huh? Not an RDNIS SIP header (%s)?\n", c);
return -1;
}
c += 4;
a = c;
strsep(&a, "@;"); /* trim anything after @ or ; */
if (sip_debug_test_pvt(p))
ast_string_field_set(p, rdnis, c);
/*! \brief Find out who the call is for
We use the INVITE uri to find out
*/
static int get_destination(struct sip_pvt *p, struct sip_request *oreq)
char tmp[256] = "", *uri, *a;
char tmpf[256] = "", *from;
Olle Johansson
committed
char *colon;
req = oreq;
if (!req)
req = &p->initreq;
/* Find the request URI */
Kevin P. Fleming
committed
ast_copy_string(tmp, req->rlPart2, sizeof(tmp));
if (pedanticsipchecking)
ast_uri_decode(tmp);
uri = get_in_brackets(tmp);
if (strncmp(uri, "sip:", 4)) {
ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", uri);
uri += 4;
/* Now find the From: caller ID and name */
ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf));
if (!ast_strlen_zero(tmpf)) {
if (pedanticsipchecking)
ast_uri_decode(tmpf);
from = get_in_brackets(tmpf);
} else {
from = NULL;
}
if (!ast_strlen_zero(from)) {
if (strncmp(from, "sip:", 4)) {
ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", from);
from += 4;
if ((a = strchr(from, '@')))
*a++ = '\0';
else
a = from; /* just a domain */
from = strsep(&from, ";"); /* Remove userinfo options */
a = strsep(&a, ";"); /* Remove URI options */
ast_string_field_set(p, fromdomain, a);
/* Skip any options and find the domain */
Olle Johansson
committed
/* Get the target domain */
if ((a = strchr(uri, '@'))) {
*a++ = '\0';
Olle Johansson
committed
} else { /* No username part */
a = uri;
uri = "s"; /* Set extension to "s" */
Olle Johansson
committed
colon = strchr(a, ':'); /* Remove :port */
if (colon)
*colon = '\0';
uri = strsep(&uri, ";"); /* Remove userinfo options */
a = strsep(&a, ";"); /* Remove URI options */
Olle Johansson
committed
ast_string_field_set(p, domain, a);
if (!AST_LIST_EMPTY(&domain_list)) {
char domain_context[AST_MAX_EXTENSION];
domain_context[0] = '\0';
if (!check_sip_domain(p->domain, domain_context, sizeof(domain_context))) {
if (!allow_external_domains && (req->method == SIP_INVITE || req->method == SIP_REFER)) {
ast_log(LOG_DEBUG, "Got SIP %s to non-local domain '%s'; refusing request.\n", sip_methods[req->method].text, p->domain);
return -2;
}
}
/* If we have a context defined, overwrite the original context */
if (!ast_strlen_zero(domain_context))
ast_string_field_set(p, context, domain_context);
if (sip_debug_test_pvt(p))
ast_verbose("Looking for %s in %s (domain %s)\n", uri, p->context, p->domain);
/* Check the dialplan for the username part of the request URI,
the domain will be stored in the SIPDOMAIN variable
Return 0 if we have a matching extension */
if (ast_exists_extension(NULL, p->context, uri, 1, from) ||
!strcmp(uri, ast_pickup_ext())) {
if (!oreq)
ast_string_field_set(p, exten, uri);
/* Return 1 for pickup extension or overlap dialling support (if we support it) */
if((ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP) &&
ast_canmatch_extension(NULL, p->context, uri, 1, from)) ||
!strncmp(uri, ast_pickup_ext(), strlen(uri))) {
/*! \brief Lock interface lock and find matching pvt lock
- Their tag is fromtag, our tag is to-tag
- This means that in some transactions, totag needs to be their tag :-)
depending upon the direction
*/
static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag)
struct sip_pvt *sip_pvt_ptr;
ast_mutex_lock(&iflock);
if (option_debug > 3 && totag)
ast_log(LOG_DEBUG, "Looking for callid %s (fromtag %s totag %s)\n", callid, fromtag ? fromtag : "<no fromtag>", totag ? totag : "<no totag>");
/* Search interfaces and find the match */
for (sip_pvt_ptr = iflist; sip_pvt_ptr; sip_pvt_ptr = sip_pvt_ptr->next) {
if (!strcmp(sip_pvt_ptr->callid, callid)) {
int match = 1;
char *ourtag = sip_pvt_ptr->tag;
/* Go ahead and lock it (and its owner) before returning */
ast_mutex_lock(&sip_pvt_ptr->lock);
/* Check if tags match. If not, this is not the call we want
(With a forking SIP proxy, several call legs share the
call id, but have different tags)
*/
if (pedanticsipchecking && (strcmp(fromtag, sip_pvt_ptr->theirtag) || strcmp(totag, ourtag)))
match = 0;
if (!match) {
ast_mutex_unlock(&sip_pvt_ptr->lock);
break;
}
if (option_debug > 3 && totag)
ast_log(LOG_DEBUG, "Matched %s call - their tag is %s Our tag is %s\n",
ast_test_flag(&sip_pvt_ptr->flags[0], SIP_OUTGOING) ? "OUTGOING": "INCOMING",
sip_pvt_ptr->theirtag, sip_pvt_ptr->tag);
/* deadlock avoidance... */
while (sip_pvt_ptr->owner && ast_channel_trylock(sip_pvt_ptr->owner)) {
ast_mutex_unlock(&sip_pvt_ptr->lock);
usleep(1);
ast_mutex_lock(&sip_pvt_ptr->lock);
}
break;
}
}
ast_mutex_unlock(&iflock);
if (option_debug > 3 && !sip_pvt_ptr)
ast_log(LOG_DEBUG, "Found no match for callid %s to-tag %s from-tag %s\n", callid, totag, fromtag);
return sip_pvt_ptr;
}
/*! \brief Call transfer support (the REFER method)
* Extracts Refer headers into pvt dialog structure */
static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req)
const char *p_referred_by = NULL;
char *h_refer_to = NULL;
char *h_referred_by = NULL;
char *refer_to;
const char *p_refer_to;
char *referred_by_uri = NULL;
char *ptr;
struct sip_request *req = NULL;
const char *transfer_context = NULL;
struct sip_refer *referdata;
req = outgoing_req;
referdata = transferer->refer;
req = &transferer->initreq;
Russell Bryant
committed
if (!(p_refer_to = get_header(req, "Refer-To"))) {
ast_log(LOG_WARNING, "Refer-To Header missing. Skipping transfer.\n");
return -2; /* Syntax error */
Russell Bryant
committed
h_refer_to = ast_strdupa(p_refer_to);
Kevin P. Fleming
committed
refer_to = get_in_brackets(h_refer_to);
Russell Bryant
committed
if (pedanticsipchecking)
ast_uri_decode(refer_to);
if (strncasecmp(refer_to, "sip:", 4)) {
ast_log(LOG_WARNING, "Can't transfer to non-sip: URI. (Refer-to: %s)?\n", refer_to);
return -3;
refer_to += 4; /* Skip sip: */
/* Get referred by header if it exists */
if ((p_referred_by = get_header(req, "Referred-By"))) {
char *lessthan;
h_referred_by = ast_strdupa(p_referred_by);
if (pedanticsipchecking)
ast_uri_decode(h_referred_by);
/* Store referrer's caller ID name */
ast_copy_string(referdata->referred_by_name, h_referred_by, sizeof(referdata->referred_by_name));
if ((lessthan = strchr(referdata->referred_by_name, '<'))) {
*(lessthan - 1) = '\0'; /* Space */
}
referred_by_uri = get_in_brackets(h_referred_by);
if(strncasecmp(referred_by_uri, "sip:", 4)) {
ast_log(LOG_WARNING, "Huh? Not a sip: header (Referred-by: %s). Skipping.\n", referred_by_uri);
referred_by_uri = (char *) NULL;
} else {
referred_by_uri += 4; /* Skip sip: */
}
}
/* Check for arguments in the refer_to header */
if ((ptr = strchr(refer_to, '?'))) { /* Search for arguments */
if (!strncasecmp(ptr, "REPLACES=", 9)) {
char *to = NULL, *from = NULL;
/* This is an attended transfer */
referdata->attendedtransfer = 1;
strncpy(referdata->replaces_callid, ptr+9, sizeof(referdata->replaces_callid));
ast_uri_decode(referdata->replaces_callid);
if ((ptr = strchr(referdata->replaces_callid, ';'))) /* Find options */ {
*ptr++ = '\0';
}
if (ptr) {
/* Find the different tags before we destroy the string */
to = strcasestr(ptr, "to-tag=");
from = strcasestr(ptr, "from-tag=");
}
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
8306
8307
8308
8309
8310
8311
8312
/* Grab the to header */
if (to) {
ptr = to + 7;
if ((to = strchr(ptr, '&')))
*to = '\0';
if ((to = strchr(ptr, ';')))
*to = '\0';
ast_copy_string(referdata->replaces_callid_totag, ptr, sizeof(referdata->replaces_callid_totag));
}
if (from) {
ptr = from + 9;
if ((to = strchr(ptr, '&')))
*to = '\0';
if ((to = strchr(ptr, ';')))
*to = '\0';
ast_copy_string(referdata->replaces_callid_fromtag, ptr, sizeof(referdata->replaces_callid_fromtag));
}
if (option_debug > 1) {
if (!pedanticsipchecking)
ast_log(LOG_DEBUG,"Attended transfer: Will use Replace-Call-ID : %s (No check of from/to tags)\n", referdata->replaces_callid );
else
ast_log(LOG_DEBUG,"Attended transfer: Will use Replace-Call-ID : %s F-tag: %s T-tag: %s\n", referdata->replaces_callid, referdata->replaces_callid_fromtag ? referdata->replaces_callid_fromtag : "<none>", referdata->replaces_callid_totag ? referdata->replaces_callid_totag : "<none>" );
}
if ((ptr = strchr(refer_to, '@'))) { /* Separate domain */
char *urioption;
*ptr++ = '\0';
if ((urioption = strchr(ptr, ';')))
*urioption++ = '\0';
/* Save the domain for the dial plan */
strncpy(referdata->refer_to_domain, ptr, sizeof(referdata->refer_to_domain));
if (urioption)
strncpy(referdata->refer_to_urioption, urioption, sizeof(referdata->refer_to_urioption));
}
if ((ptr = strchr(refer_to, ';'))) /* Remove options */
*ptr = '\0';
ast_copy_string(referdata->refer_to, refer_to, sizeof(referdata->refer_to));
Joshua Colp
committed
if (referred_by_uri) {
if ((ptr = strchr(referred_by_uri, ';'))) /* Remove options */
*ptr = '\0';
ast_copy_string(referdata->referred_by, referred_by_uri, sizeof(referdata->referred_by));
} else {
referdata->referred_by[0] = '\0';
}
/* Determine transfer context */
if (transferer->owner) /* Mimic behaviour in res_features.c */
transfer_context = pbx_builtin_getvar_helper(transferer->owner, "TRANSFER_CONTEXT");
/* By default, use the context in the channel sending the REFER */
if (ast_strlen_zero(transfer_context)) {
transfer_context = S_OR(transferer->owner->macrocontext,
S_OR(transferer->context, default_context));
}
strncpy(referdata->refer_to_context, transfer_context, sizeof(referdata->refer_to_context));
/* Either an existing extension or the parking extension */
if (ast_exists_extension(NULL, transfer_context, refer_to, 1, NULL) ) {
if (sip_debug_test_pvt(transferer)) {
ast_verbose("SIP transfer to extension %s@%s by %s\n", refer_to, transfer_context, referred_by_uri);
/* We are ready to transfer to the extension */
}
if (sip_debug_test_pvt(transferer))
ast_verbose("Failed SIP Transfer to non-existing extension %s in context %s\n n", refer_to, transfer_context);
/* Failure, we can't find this extension */
/*! \brief Call transfer support (old way, deprecated by the IETF)--*/
static int get_also_info(struct sip_pvt *p, struct sip_request *oreq)
{
char tmp[256] = "", *c, *a;
struct sip_request *req = oreq ? oreq : &p->initreq;
struct sip_refer *referdata = p->refer;
const char *transfer_context = NULL;
Kevin P. Fleming
committed
ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp));
Kevin P. Fleming
committed
c = get_in_brackets(tmp);
if (pedanticsipchecking)
ast_uri_decode(c);
ast_log(LOG_WARNING, "Huh? Not a SIP header in Also: transfer (%s)?\n", c);
if ((a = strchr(c, '@'))) { /* Separate Domain */
*a++ = '\0';
ast_copy_string(referdata->refer_to_domain, a, sizeof(referdata->refer_to_domain));
}
if ((a = strchr(c, ';'))) /* Remove arguments */
*a = '\0';
if (sip_debug_test_pvt(p))
ast_verbose("Looking for %s in %s\n", c, p->context);
if (p->owner) /* Mimic behaviour in res_features.c */
transfer_context = pbx_builtin_getvar_helper(p->owner, "TRANSFER_CONTEXT");
/* By default, use the context in the channel sending the REFER */
if (ast_strlen_zero(transfer_context)) {
transfer_context = S_OR(p->owner->macrocontext,
S_OR(p->context, default_context));
}
if (ast_exists_extension(NULL, transfer_context, c, 1, NULL)) {
/* This is a blind transfer */
if (option_debug)
ast_log(LOG_DEBUG,"SIP Bye-also transfer to Extension %s@%s \n", c, transfer_context);
ast_copy_string(referdata->refer_to, c, sizeof(referdata->refer_to));
ast_copy_string(referdata->referred_by, "", sizeof(referdata->referred_by));
ast_copy_string(referdata->refer_contact, "", sizeof(referdata->refer_contact));
referdata->refer_call = NULL;
/* Set new context */
ast_string_field_set(p, context, transfer_context);
return 0;
} else if (ast_canmatch_extension(NULL, p->context, c, 1, NULL)) {
return 1;
}
return -1;
}
/*! \brief check Via: header for hostname, port and rport request/answer */
Olle Johansson
committed
static void check_via(struct sip_pvt *p, struct sip_request *req)
Kevin P. Fleming
committed
ast_copy_string(via, get_header(req, "Via"), sizeof(via));
/* Check for rport */
c = strstr(via, ";rport");
if (c && (c[6] != '=')) /* rport query, not answer */
ast_set_flag(&p->flags[0], SIP_NAT_ROUTE);
c = strchr(via, ' ');
if (c) {
*c = '\0';
c = ast_skip_blanks(c+1);
if (strcasecmp(via, "SIP/2.0/UDP")) {
ast_log(LOG_WARNING, "Don't know how to respond via '%s'\n", via);
Olle Johansson
committed
return;
*pt++ = '\0'; /* remember port pointer */
hp = ast_gethostbyname(c, &ahp);
if (!hp) {
ast_log(LOG_WARNING, "'%s' is not a valid host\n", c);
Olle Johansson
committed
return;
}
memset(&p->sa, 0, sizeof(p->sa));
p->sa.sin_family = AF_INET;
memcpy(&p->sa.sin_addr, hp->h_addr, sizeof(p->sa.sin_addr));
p->sa.sin_port = htons(pt ? atoi(pt) : DEFAULT_SIP_PORT);
if (sip_debug_test_pvt(p)) {
const struct sockaddr_in *dst = sip_real_dst(p);
Russell Bryant
committed
ast_verbose("Sending to %s : %d (%s)\n", ast_inet_ntoa(dst->sin_addr), ntohs(dst->sin_port), sip_nat_mode(p));
/*! \brief Get caller id name from SIP headers */
static char *get_calleridname(const char *input, char *output, size_t outputsize)
const char *end = strchr(input,'<'); /* first_bracket */
const char *tmp = strchr(input,'"'); /* first quote */
int bytes = 0;
int maxbytes = outputsize - 1;
if (!end || end == input) /* we require a part in brackets */
/* move away from "<" */
end--;
/* we found "name" */
if (tmp && tmp < end) {
Kevin P. Fleming
committed
bytes = (int) (end - tmp);
/* protect the output buffer */
Kevin P. Fleming
committed
if (bytes > maxbytes)
Kevin P. Fleming
committed
ast_copy_string(output, tmp + 1, bytes);
} else {
/* we didn't find "name" */
/* clear the empty characters in the begining*/
input = ast_skip_blanks(input);
/* clear the empty characters in the end */
while(*end && *end < 33 && end > input)
Kevin P. Fleming
committed
bytes = (int) (end - input) + 2;
/* protect the output buffer */
if (bytes > maxbytes)
Kevin P. Fleming
committed
ast_copy_string(output, input, bytes);
}
return output;
}
/*! \brief Get caller id number from Remote-Party-ID header field
* Returns true if number should be restricted (privacy setting found)
* output is set to NULL if no number found
Mark Spencer
committed
*/
static int get_rpid_num(const char *input, char *output, int maxlen)
Mark Spencer
committed
{
char *start;
char *end;
start = strchr(input,':');
if (!start) {
Mark Spencer
committed
output[0] = '\0';
Mark Spencer
committed
return 0;
}
start++;
/* we found "number" */
Kevin P. Fleming
committed
ast_copy_string(output,start,maxlen);
Mark Spencer
committed
output[maxlen-1] = '\0';
end = strchr(output,'@');
if (end)
*end = '\0';
if (strstr(input,"privacy=full") || strstr(input,"privacy=uri"))
return AST_PRES_PROHIB_USER_NUMBER_NOT_SCREENED;
Mark Spencer
committed
return 0;
}
/*! \brief Check if matching user or peer is defined
Match user on From: user name and peer on IP/port
This is used on first invite (not re-invites) and subscribe requests
\return 0 on success, non-zero on failure
static enum check_auth_result check_user_full(struct sip_pvt *p, struct sip_request *req,
int sipmethod, char *uri, enum xmittype reliable,
struct sockaddr_in *sin, struct sip_peer **authpeer)
Kevin P. Fleming
committed
struct sip_user *user = NULL;
char from[256], *c;
char *of;
char rpid_num[50];
const char *rpid;
enum check_auth_result res = AUTH_SUCCESSFUL;
char calleridname[50];
struct ast_variable *tmpvar = NULL, *v = NULL;
int usenatroute;
while (*t && *t > 32 && *t != ';')
ast_copy_string(from, get_header(req, "From"), sizeof(from)); /* XXX bug in original code, overwrote string */
if (pedanticsipchecking)
ast_uri_decode(from);
/* XXX here tries to map the username for invite things */
memset(calleridname, 0, sizeof(calleridname));
get_calleridname(from, calleridname, sizeof(calleridname));
Kevin P. Fleming
committed
if (calleridname[0])
ast_string_field_set(p, cid_name, calleridname);
Mark Spencer
committed
rpid = get_header(req, "Remote-Party-ID");
memset(rpid_num, 0, sizeof(rpid_num));
p->callingpres = get_rpid_num(rpid, rpid_num, sizeof(rpid_num));
Mark Spencer
committed
Kevin P. Fleming
committed
of = get_in_brackets(from);
if (ast_strlen_zero(p->exten)) {
if (!strncmp(t, "sip:", 4))
t+= 4;
ast_string_field_set(p, exten, t);
t = strchr(p->exten, '@');
if (t)
*t = '\0';
if (ast_strlen_zero(p->our_contact))
build_contact(p);
}
Kevin P. Fleming
committed
/* save the URI part of the From header */
ast_string_field_set(p, from, of);
if (strncmp(of, "sip:", 4)) {
ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n");
} else
Tilghman Lesher
committed
char *tmp;
Tilghman Lesher
committed
tmp = ast_strdupa(of);
Russell Bryant
committed
if (ast_is_shrinkable_phonenumber(tmp))
ast_shrink_phone_number(tmp);
ast_string_field_set(p, cid_num, tmp);
if (ast_strlen_zero(of))
return AUTH_SUCCESSFUL;
Kevin P. Fleming
committed
Kevin P. Fleming
committed
if (!authpeer) /* If we are looking for a peer, don't check the user objects (or realtime) */
Kevin P. Fleming
committed
user = find_user(of, 1);
/* Find user based on user name in the from header */
Kevin P. Fleming
committed
if (user && ast_apply_ha(user->ha, sin)) {
ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
/* copy channel vars */
for (v = user->chanvars ; v ; v = v->next) {
if ((tmpvar = ast_variable_new(v->name, v->value))) {
tmpvar->next = p->chanvars;
p->chanvars = tmpvar;
p->prefs = user->prefs;
/* replace callerid if rpid found, and not restricted */
if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
Tilghman Lesher
committed
char *tmp;
ast_string_field_set(p, cid_name, calleridname);
Tilghman Lesher
committed
tmp = ast_strdupa(rpid_num);
Russell Bryant
committed
if (ast_is_shrinkable_phonenumber(tmp))
ast_shrink_phone_number(tmp);
ast_string_field_set(p, cid_num, tmp);
usenatroute = ast_test_flag(&p->flags[0], SIP_NAT_ROUTE);
ast_log(LOG_DEBUG, "Setting NAT on RTP to %s\n", usenatroute ? "On" : "Off");
ast_rtp_setnat(p->rtp, usenatroute);
ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", usenatroute ? "On" : "Off");
ast_rtp_setnat(p->vrtp, usenatroute);
if (p->udptl) {
if (option_debug)
ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", usenatroute ? "On" : "Off");
ast_udptl_setnat(p->udptl, usenatroute);
}
if (!(res = check_auth(p, req, user->name, user->secret, user->md5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
ast_copy_flags(&p->flags[0], &user->flags[0], SIP_FLAGS_TO_COPY);
ast_copy_flags(&p->flags[1], &user->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
/* Copy SIP extensions profile from INVITE */
if (p->sipoptions)
user->sipoptions = p->sipoptions;
Kevin P. Fleming
committed
if (user->call_limit)
ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
if (!ast_strlen_zero(user->context))
ast_string_field_set(p, context, user->context);
if (!ast_strlen_zero(user->cid_num) && !ast_strlen_zero(p->cid_num)) {
Tilghman Lesher
committed
char *tmp = ast_strdupa(user->cid_num);
Russell Bryant
committed
if (ast_is_shrinkable_phonenumber(tmp))
ast_shrink_phone_number(tmp);
ast_string_field_set(p, cid_num, tmp);
if (!ast_strlen_zero(user->cid_name) && !ast_strlen_zero(p->cid_num))
ast_string_field_set(p, cid_name, user->cid_name);
ast_string_field_set(p, username, user->name);
ast_string_field_set(p, peername, user->name);
ast_string_field_set(p, peersecret, user->secret);
ast_string_field_set(p, peermd5secret, user->md5secret);
ast_string_field_set(p, subscribecontext, user->subscribecontext);
ast_string_field_set(p, accountcode, user->accountcode);
ast_string_field_set(p, language, user->language);
Kevin P. Fleming
committed
ast_string_field_set(p, mohsuggest, user->mohsuggest);
ast_string_field_set(p, mohinterpret, user->mohinterpret);
p->allowtransfer = user->allowtransfer;
p->amaflags = user->amaflags;
p->callgroup = user->callgroup;
p->pickupgroup = user->pickupgroup;
Olle Johansson
committed
if (user->callingpres) /* User callingpres setting will override RPID header */
p->callingpres = user->callingpres;
/* Set default codec settings for this call */
p->capability = user->capability; /* User codec choice */
p->jointcapability = user->capability; /* Our codecs */
if (p->peercapability) /* AND with peer's codecs */
p->jointcapability &= p->peercapability;
if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
(ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
p->noncodeccapability |= AST_RTP_DTMF;
else
p->noncodeccapability &= ~AST_RTP_DTMF;
if (p->t38.peercapability)
p->t38.jointcapability &= p->t38.peercapability;
p->maxcallbitrate = user->maxcallbitrate;
/* If we do not support video, remove video from call structure */
if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
ast_rtp_destroy(p->vrtp);
p->vrtp = NULL;
}
ast_verbose("Found user '%s'\n", user->name);
} else {
Kevin P. Fleming
committed
if (!authpeer && debug)
ast_verbose("Found user '%s', but fails host access\n", user->name);
Mark Spencer
committed
ASTOBJ_UNREF(user,sip_destroy_user);
Mark Spencer
committed
/* If we didn't find a user match, check for peers */
Kevin P. Fleming
committed
if (sipmethod == SIP_SUBSCRIBE)
/* For subscribes, match on peer name only */
peer = find_peer(of, NULL, 1);
else
/* Look for peer based on the IP address we received data from */
/* If peer is registered from this IP address or have this as a default
IP address, this call is from the peer
*/
peer = find_peer(NULL, &p->recv, 1);
ast_verbose("Found peer '%s'\n", peer->name);
Kevin P. Fleming
committed
/* Take the peer */
ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
/* Copy SIP extensions profile to peer */
if (p->sipoptions)
peer->sipoptions = p->sipoptions;
/* replace callerid if rpid found, and not restricted */
if (!ast_strlen_zero(rpid_num) && ast_test_flag(&p->flags[0], SIP_TRUSTRPID)) {
Tilghman Lesher
committed
char *tmp = ast_strdupa(rpid_num);
ast_string_field_set(p, cid_name, calleridname);
Russell Bryant
committed
if (ast_is_shrinkable_phonenumber(tmp))
ast_shrink_phone_number(tmp);
ast_string_field_set(p, cid_num, tmp);
usenatroute = ast_test_flag(&p->flags[0], SIP_NAT_ROUTE);
if (p->rtp) {
ast_log(LOG_DEBUG, "Setting NAT on RTP to %s\n", usenatroute ? "On" : "Off");
ast_rtp_setnat(p->rtp, usenatroute);
}
if (p->vrtp) {
ast_log(LOG_DEBUG, "Setting NAT on VRTP to %s\n", usenatroute ? "On" : "Off");
ast_rtp_setnat(p->vrtp, usenatroute);
if (p->udptl) {
ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %s\n", usenatroute ? "On" : "Off");
ast_udptl_setnat(p->udptl, usenatroute);
}
ast_string_field_set(p, peersecret, peer->secret);
ast_string_field_set(p, peermd5secret, peer->md5secret);
ast_string_field_set(p, subscribecontext, peer->subscribecontext);
Kevin P. Fleming
committed
ast_string_field_set(p, mohinterpret, peer->mohinterpret);
ast_string_field_set(p, mohsuggest, peer->mohsuggest);
Olle Johansson
committed
if (peer->callingpres) /* Peer calling pres setting will override RPID */
p->callingpres = peer->callingpres;
if (peer->maxms && peer->lastms)
p->timer_t1 = peer->lastms;
if (ast_test_flag(&peer->flags[0], SIP_INSECURE_INVITE)) {
/* Pretend there is no required authentication */
ast_string_field_free(p, peersecret);
ast_string_field_free(p, peermd5secret);
if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, ast_test_flag(req, SIP_PKT_IGNORE)))) {
ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
Kevin P. Fleming
committed
if (peer->call_limit)
ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
ast_string_field_set(p, peername, peer->name);
ast_string_field_set(p, authname, peer->name);
/* copy channel vars */
for (v = peer->chanvars ; v ; v = v->next) {
if ((tmpvar = ast_variable_new(v->name, v->value))) {
tmpvar->next = p->chanvars;
p->chanvars = tmpvar;
}
}
Kevin P. Fleming
committed
if (authpeer) {
(*authpeer) = ASTOBJ_REF(peer); /* Add a ref to the object here, to keep it in memory a bit longer if it is realtime */
}
if (!ast_strlen_zero(peer->username)) {
ast_string_field_set(p, username, peer->username);
/* Use the default username for authentication on outbound calls */
/* XXX this takes the name from the caller... can we override ? */
ast_string_field_set(p, authname, peer->username);
Mark Spencer
committed
}
if (!ast_strlen_zero(peer->cid_num) && !ast_strlen_zero(p->cid_num)) {
Tilghman Lesher
committed
char *tmp = ast_strdupa(peer->cid_num);
Russell Bryant
committed
if (ast_is_shrinkable_phonenumber(tmp))
ast_shrink_phone_number(tmp);
ast_string_field_set(p, cid_num, tmp);
}
if (!ast_strlen_zero(peer->cid_name) && !ast_strlen_zero(p->cid_name))
ast_string_field_set(p, cid_name, peer->cid_name);
ast_string_field_set(p, fullcontact, peer->fullcontact);
if (!ast_strlen_zero(peer->context))
ast_string_field_set(p, context, peer->context);
ast_string_field_set(p, peersecret, peer->secret);
ast_string_field_set(p, peermd5secret, peer->md5secret);
ast_string_field_set(p, language, peer->language);
ast_string_field_set(p, accountcode, peer->accountcode);
p->callgroup = peer->callgroup;
p->pickupgroup = peer->pickupgroup;
Kevin P. Fleming
committed
p->prefs = peer->prefs;
p->jointcapability = peer->capability;
if (p->peercapability)
p->jointcapability &= p->peercapability;
if (!ast_test_flag(&p->flags[1], SIP_PAGE2_VIDEOSUPPORT) && p->vrtp) {
if ((ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_RFC2833) ||
(ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
p->noncodeccapability |= AST_RTP_DTMF;
else
p->noncodeccapability &= ~AST_RTP_DTMF;
if (p->t38.peercapability)
p->t38.jointcapability &= p->t38.peercapability;
ASTOBJ_UNREF(peer, sip_destroy_peer);
} else {
if (debug)
Russell Bryant
committed
ast_verbose("Found no matching peer or user for '%s:%d'\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port));
/* do we allow guests? */
if (!global_allowguest) {
if (global_alwaysauthreject)
res = AUTH_FAKE_AUTH; /* reject with fake authorization request */
else
res = AUTH_SECRET_FAILED; /* we don't want any guests, authentication will fail */
}
Mark Spencer
committed
Mark Spencer
committed
if (user)
ASTOBJ_UNREF(user, sip_destroy_user);
/*! \brief Find user
If we get a match, this will add a reference pointer to the user object in ASTOBJ, that needs to be unreferenced
*/
static int check_user(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, enum xmittype reliable, struct sockaddr_in *sin)
Mark Spencer
committed
{
return check_user_full(p, req, sipmethod, uri, reliable, sin, NULL);
Mark Spencer
committed
}
/*! \brief Get text out of a SIP MESSAGE packet */
static int get_msg_text(char *buf, int len, struct sip_request *req)
{
int x;
Mark Spencer
committed
buf[0] = '\0';
y = len - strlen(buf) - 5;
if (y < 0)
y = 0;
strncat(buf, req->line[x], y); /* safe */
y -= strlen(req->line[x]) + 1;
if (y < 0)
y = 0;
if (y != 0)
strcat(buf, "\n"); /* safe */
/*! \brief Receive SIP MESSAGE method messages
\note We only handle messages within current calls currently
Reference: RFC 3428 */
static void receive_message(struct sip_pvt *p, struct sip_request *req)
{
char buf[1024];
struct ast_frame f;
const char *content_type = get_header(req, "Content-Type");
Kevin P. Fleming
committed
if (strcmp(content_type, "text/plain")) { /* No text/plain attachment */
transmit_response(p, "415 Unsupported Media Type", req); /* Good enough, or? */
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
Kevin P. Fleming
committed
return;
}
if (get_msg_text(buf, sizeof(buf), req)) {
ast_log(LOG_WARNING, "Unable to retrieve text from %s\n", p->callid);
Kevin P. Fleming
committed
transmit_response(p, "202 Accepted", req);
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
Kevin P. Fleming
committed
if (sip_debug_test_pvt(p))
memset(&f, 0, sizeof(f));
f.frametype = AST_FRAME_TEXT;
f.subclass = 0;
f.offset = 0;
f.data = buf;
f.datalen = strlen(buf);
ast_queue_frame(p->owner, &f);
Kevin P. Fleming
committed
transmit_response(p, "202 Accepted", req); /* We respond 202 accepted, since we relay the message */
} else { /* Message outside of a call, we do not support that */
ast_log(LOG_WARNING,"Received message to %s from %s, dropped it...\n Content-Type:%s\n Message: %s\n", get_header(req,"To"), get_header(req,"From"), content_type, buf);
transmit_response(p, "405 Method Not Allowed", req); /* Good enough, or? */
ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
Kevin P. Fleming
committed
return;
/*! \brief CLI Command to show calls within limits set by call_limit */
static int sip_show_inuse(int fd, int argc, char *argv[])
{
#define FORMAT "%-25.25s %-15.15s %-15.15s \n"
#define FORMAT2 "%-25.25s %-15.15s %-15.15s \n"
char ilimits[40];
if (argc == 4 && !strcmp(argv[3],"all"))
ast_cli(fd, FORMAT, "* User name", "In use", "Limit");
ASTOBJ_CONTAINER_TRAVERSE(&userl, 1, do {
ASTOBJ_RDLOCK(iterator);
Kevin P. Fleming
committed
if (iterator->call_limit)
snprintf(ilimits, sizeof(ilimits), "%d", iterator->call_limit);
Kevin P. Fleming
committed
ast_copy_string(ilimits, "N/A", sizeof(ilimits));
snprintf(iused, sizeof(iused), "%d", iterator->inUse);
Kevin P. Fleming
committed
if (showall || iterator->call_limit)
ast_cli(fd, FORMAT2, iterator->name, iused, ilimits);
ASTOBJ_UNLOCK(iterator);
} while (0) );
ast_cli(fd, FORMAT, "* Peer name", "In use", "Limit");
ASTOBJ_CONTAINER_TRAVERSE(&peerl, 1, do {
ASTOBJ_RDLOCK(iterator);
Kevin P. Fleming
committed
if (iterator->call_limit)
snprintf(ilimits, sizeof(ilimits), "%d", iterator->call_limit);
Kevin P. Fleming
committed
ast_copy_string(ilimits, "N/A", sizeof(ilimits));
snprintf(iused, sizeof(iused), "%d/%d", iterator->inUse, iterator->inRinging);
Kevin P. Fleming
committed
if (showall || iterator->call_limit)
ast_cli(fd, FORMAT2, iterator->name, iused, ilimits);
ASTOBJ_UNLOCK(iterator);
Mark Spencer
committed
} while (0) );
return RESULT_SUCCESS;
#undef FORMAT
#undef FORMAT2
}
/*! \brief Convert transfer mode to text string */
static char *transfermode2str(enum transfermodes mode)
{
if (mode == TRANSFER_OPENFORALL)
return "open";
else if (mode == TRANSFER_CLOSED)
return "closed";
return "strict";
}
/*! \brief Convert NAT setting to text string */