diff options
author | Patrick McHardy <kaber@trash.net> | 2011-07-06 04:52:35 +0200 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-07-06 04:52:35 +0200 |
commit | 916e420bf0c8db7a8cb1f60557cd2807652142cf (patch) | |
tree | ece8aaf3f22e6e1cc545a858cad9e05c34713426 /channels | |
parent | 9364aaccb699c6d19ac2cbe760c208b34ba7838a (diff) | |
parent | 357b97fb29d196a5f336d6a2879278ea135ab08c (diff) |
Merge branch 'master' of 192.168.0.100:/repos/git/asterisk
Diffstat (limited to 'channels')
-rw-r--r-- | channels/chan_bridge.c | 3 | ||||
-rw-r--r-- | channels/chan_dahdi.c | 83 | ||||
-rw-r--r-- | channels/chan_gtalk.c | 2 | ||||
-rw-r--r-- | channels/chan_iax2.c | 22 | ||||
-rw-r--r-- | channels/chan_jingle.c | 2 | ||||
-rw-r--r-- | channels/chan_mgcp.c | 2 | ||||
-rw-r--r-- | channels/chan_sip.c | 821 | ||||
-rw-r--r-- | channels/sip/include/sip.h | 13 | ||||
-rw-r--r-- | channels/sip/reqresp_parser.c | 16 |
9 files changed, 629 insertions, 335 deletions
diff --git a/channels/chan_bridge.c b/channels/chan_bridge.c index a58cfcc59..7b01909ae 100644 --- a/channels/chan_bridge.c +++ b/channels/chan_bridge.c @@ -229,6 +229,9 @@ static struct ast_channel *bridge_request(const char *type, struct ast_format_ca ast_format_copy(&p->input->rawwriteformat, &slin); ast_format_copy(&p->output->rawwriteformat, &slin); + ast_answer(p->output); + ast_answer(p->input); + return p->input; } diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 131279ea0..321be6625 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -38,12 +38,12 @@ */ /*** MODULEINFO - <use>res_smdi</use> + <use type="module">res_smdi</use> <depend>dahdi</depend> <depend>tonezone</depend> - <use>pri</use> - <use>ss7</use> - <use>openr2</use> + <use type="external">pri</use> + <use type="external">ss7</use> + <use type="external">openr2</use> ***/ #include "asterisk.h" @@ -9491,6 +9491,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb int features; struct ast_str *chan_name; struct ast_variable *v; + char *dashptr; + char device_name[AST_CHANNEL_NAME]; if (i->subs[idx].owner) { ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]); @@ -9672,7 +9674,13 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb /* Configure the new channel jb */ ast_jb_configure(tmp, &global_jbconf); - ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name); + /* Set initial device state */ + ast_copy_string(device_name, tmp->name, sizeof(device_name)); + dashptr = strrchr(device_name, '-'); + if (dashptr) { + *dashptr = '\0'; + } + ast_devstate_changed_literal(AST_DEVICE_UNKNOWN, device_name); for (v = i->vars ; v ; v = v->next) pbx_builtin_setvar_helper(tmp, v->name, v->value); @@ -13933,17 +13941,22 @@ static void *mfcr2_monitor(void *data) #endif static void dahdi_pri_message(struct pri *pri, char *s) { - int x, y; - int dchan = -1, span = -1, dchancount = 0; + int x; + int y; + int dchan = -1; + int span = -1; + int dchancount = 0; if (pri) { for (x = 0; x < NUM_SPANS; x++) { for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) { - if (pris[x].pri.dchans[y]) + if (pris[x].pri.dchans[y]) { dchancount++; + } - if (pris[x].pri.dchans[y] == pri) + if (pris[x].pri.dchans[y] == pri) { dchan = y; + } } if (dchan >= 0) { span = x; @@ -13951,14 +13964,18 @@ static void dahdi_pri_message(struct pri *pri, char *s) } dchancount = 0; } - if (dchancount > 1 && (span > -1)) - ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s); - else if (span > -1) - ast_verbose("%d %s", span+1, s); - else - ast_verbose("%s", s); - } else - ast_verbose("%s", s); + if (-1 < span) { + if (1 < dchancount) { + ast_verbose("[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s); + } else { + ast_verbose("PRI Span: %d %s", span + 1, s); + } + } else { + ast_verbose("PRI Span: ? %s", s); + } + } else { + ast_verbose("PRI Span: ? %s", s); + } ast_mutex_lock(&pridebugfdlock); @@ -13975,18 +13992,22 @@ static void dahdi_pri_message(struct pri *pri, char *s) #if defined(HAVE_PRI) static void dahdi_pri_error(struct pri *pri, char *s) { - int x, y; - int dchan = -1, span = -1; + int x; + int y; + int dchan = -1; + int span = -1; int dchancount = 0; if (pri) { for (x = 0; x < NUM_SPANS; x++) { for (y = 0; y < SIG_PRI_NUM_DCHANS; y++) { - if (pris[x].pri.dchans[y]) + if (pris[x].pri.dchans[y]) { dchancount++; + } - if (pris[x].pri.dchans[y] == pri) + if (pris[x].pri.dchans[y] == pri) { dchan = y; + } } if (dchan >= 0) { span = x; @@ -13994,14 +14015,18 @@ static void dahdi_pri_error(struct pri *pri, char *s) } dchancount = 0; } - if ((dchancount > 1) && (span > -1)) - ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s); - else if (span > -1) - ast_log(LOG_ERROR, "%d %s", span+1, s); - else - ast_log(LOG_ERROR, "%s", s); - } else - ast_log(LOG_ERROR, "%s", s); + if (-1 < span) { + if (1 < dchancount) { + ast_log(LOG_ERROR, "[PRI Span: %d D-Channel: %d] %s", span + 1, dchan, s); + } else { + ast_log(LOG_ERROR, "PRI Span: %d %s", span + 1, s); + } + } else { + ast_log(LOG_ERROR, "PRI Span: ? %s", s); + } + } else { + ast_log(LOG_ERROR, "PRI Span: ? %s", s); + } ast_mutex_lock(&pridebugfdlock); diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c index d8dd736e4..3b08d8ce4 100644 --- a/channels/chan_gtalk.c +++ b/channels/chan_gtalk.c @@ -34,7 +34,7 @@ /*** MODULEINFO <depend>iksemel</depend> <depend>res_jabber</depend> - <use>openssl</use> + <use type="external">openssl</use> ***/ #include "asterisk.h" diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 0802474ee..9f5f32deb 100644 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -32,7 +32,7 @@ */ /*** MODULEINFO - <use>crypto</use> + <use type="external">crypto</use> ***/ #include "asterisk.h" @@ -5363,10 +5363,6 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat /* these two cannot be sent, because they require a result */ errno = ENOSYS; return -1; - case AST_OPTION_FORMAT_READ: - case AST_OPTION_FORMAT_WRITE: - case AST_OPTION_MAKE_COMPATIBLE: - return -1; case AST_OPTION_OPRMODE: errno = EINVAL; return -1; @@ -5383,7 +5379,16 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat ast_mutex_unlock(&iaxsl[callno]); return 0; } - default: + /* These options are sent to the other side across the network where + * they will be passed to whatever channel is bridged there. Don't + * do anything silly like pass an option that transmits pointers to + * memory on this machine to a remote machine to use */ + case AST_OPTION_TONE_VERIFY: + case AST_OPTION_TDD: + case AST_OPTION_RELAXDTMF: + case AST_OPTION_AUDIO_MODE: + case AST_OPTION_DIGIT_DETECT: + case AST_OPTION_FAX_DETECT: { unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); struct chan_iax2_pvt *pvt; @@ -5411,7 +5416,12 @@ static int iax2_setoption(struct ast_channel *c, int option, void *data, int dat ast_free(h); return res; } + default: + return -1; } + + /* Just in case someone does a break instead of a return */ + return -1; } static int iax2_queryoption(struct ast_channel *c, int option, void *data, int *datalen) diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c index d0a027c3d..53b1a85e4 100644 --- a/channels/chan_jingle.c +++ b/channels/chan_jingle.c @@ -30,7 +30,7 @@ /*** MODULEINFO <depend>iksemel</depend> <depend>res_jabber</depend> - <use>openssl</use> + <use type="external">openssl</use> ***/ #include "asterisk.h" diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 293a2c1fe..bd92fe9b0 100644 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -30,7 +30,7 @@ */ /*** MODULEINFO - <use>res_pktccops</use> + <use type="module">res_pktccops</use> ***/ #include "asterisk.h" diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 4c0e2a66c..18eba2371 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -162,7 +162,7 @@ */ /*** MODULEINFO - <use>res_crypto</use> + <use type="module">res_crypto</use> <depend>chan_local</depend> ***/ @@ -1121,9 +1121,10 @@ static void temp_pvt_cleanup(void *); /*! \brief A per-thread temporary pvt structure */ AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup); -/*! \brief Authentication list for realm authentication - * \todo Move the sip_auth list to AST_LIST */ -static struct sip_auth *authl = NULL; +/*! \brief Authentication container for realm authentication */ +static struct sip_auth_container *authl = NULL; +/*! \brief Global authentication container protection while adjusting the references. */ +AST_MUTEX_DEFINE_STATIC(authl_lock); /* --- Sockets and networking --------------*/ @@ -1230,8 +1231,8 @@ static int get_address_family_filter(const struct ast_sockaddr *addr); /*--- Transmitting responses and requests */ static int sipsock_read(int *id, int fd, short events, void *ignore); -static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len); -static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int len, int fatal, int sipmethod); +static int __sip_xmit(struct sip_pvt *p, struct ast_str *data); +static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int fatal, int sipmethod); static void add_cc_call_info_to_response(struct sip_pvt *p, struct sip_request *resp); static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable); static int retrans_pkt(const void *data); @@ -1329,13 +1330,11 @@ static int add_sip_domain(const char *domain, const enum domain_mode mode, const static void clear_sip_domains(void); /*--- SIP realm authentication */ -static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno); -static int clear_realm_authentication(struct sip_auth *authlist); /* Clear realm authentication list (at reload) */ -static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm); +static void add_realm_authentication(struct sip_auth_container **credentials, const char *configuration, int lineno); +static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm); /*--- Misc functions */ static void check_rtp_timeout(struct sip_pvt *dialog, time_t t); -static int sip_do_reload(enum channelreloadreason reason); static int reload_config(enum channelreloadreason reason); static int expire_register(const void *data); static void *do_monitor(void *data); @@ -1471,7 +1470,7 @@ static int method_match(enum sipmethod id, const char *name); static void parse_copy(struct sip_request *dst, const struct sip_request *src); static const char *find_alias(const char *name, const char *_default); static const char *__get_header(const struct sip_request *req, const char *name, int *start); -static int lws2sws(char *msgbuf, int len); +static void lws2sws(struct ast_str *msgbuf); static void extract_uri(struct sip_pvt *p, struct sip_request *req); static char *remove_uri_parameters(char *uri); static int get_refer_info(struct sip_pvt *transferer, struct sip_request *outgoing_req); @@ -1549,7 +1548,6 @@ static void handle_response_notify(struct sip_pvt *p, int resp, const char *rest static void handle_response_refer(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno); static void handle_response_subscribe(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno); static int handle_response_register(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno); -static void handle_response_message(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno); static void handle_response(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno); /*------ SRTP Support -------- */ @@ -2639,7 +2637,7 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi req.socket.fd = tcptls_session->fd; /* Read in headers one line at a time */ - while (req.len < 4 || strncmp(REQ_OFFSET_TO_STR(&req, len - 4), "\r\n\r\n", 4)) { + while (ast_str_strlen(req.data) < 4 || strncmp(REQ_OFFSET_TO_STR(&req, data->used - 4), "\r\n\r\n", 4)) { if (!tcptls_session->client && !authenticated ) { if ((timeout = sip_check_authtimeout(start)) < 0) { goto cleanup; @@ -2686,7 +2684,6 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi goto cleanup; } ast_str_append(&req.data, 0, "%s", buf); - req.len = req.data->used; } copy_request(&reqcpy, &req); parse_request(&reqcpy); @@ -2739,7 +2736,6 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi } cl -= strlen(buf); ast_str_append(&req.data, 0, "%s", buf); - req.len = req.data->used; } } /*! \todo XXX If there's no Content-Length or if the content-length and what @@ -3342,13 +3338,18 @@ static inline const char *get_transport_pvt(struct sip_pvt *p) return get_transport(p->socket.type); } -/*! \brief Transmit SIP message - Sends a SIP request or response on a given socket (in the pvt) - Called by retrans_pkt, send_request, send_response and - __sip_reliable_xmit - \return length of transmitted message, XMIT_ERROR on known network failures -1 on other failures. -*/ -static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len) +/*! + * \internal + * \brief Transmit SIP message + * + * \details + * Sends a SIP request or response on a given socket (in the pvt) + * \note + * Called by retrans_pkt, send_request, send_response and __sip_reliable_xmit + * + * \return length of transmitted message, XMIT_ERROR on known network failures -1 on other failures. + */ +static int __sip_xmit(struct sip_pvt *p, struct ast_str *data) { int res = 0; const struct ast_sockaddr *dst = sip_real_dst(p); @@ -3360,9 +3361,9 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len) } if (p->socket.type == SIP_TRANSPORT_UDP) { - res = ast_sendto(p->socket.fd, data->str, len, 0, dst); + res = ast_sendto(p->socket.fd, data->str, ast_str_strlen(data), 0, dst); } else if (p->socket.tcptls_session) { - res = sip_tcptls_write(p->socket.tcptls_session, data->str, len); + res = sip_tcptls_write(p->socket.tcptls_session, data->str, ast_str_strlen(data)); } else { ast_debug(2, "Socket type is TCP but no tcptls_session is present to write to\n"); return XMIT_ERROR; @@ -3378,8 +3379,8 @@ static int __sip_xmit(struct sip_pvt *p, struct ast_str *data, int len) res = XMIT_ERROR; /* Don't bother with trying to transmit again */ } } - if (res != len) { - ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_sockaddr_stringify(dst), res, strerror(errno)); + if (res != ast_str_strlen(data)) { + ast_log(LOG_WARNING, "sip_xmit of %p (len %zu) to %s returned %d: %s\n", data, ast_str_strlen(data), ast_sockaddr_stringify(dst), res, strerror(errno)); } return res; @@ -3394,7 +3395,7 @@ static void build_via(struct sip_pvt *p) /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ snprintf(p->via, sizeof(p->via), "SIP/2.0/%s %s;branch=z9hG4bK%08x%s", get_transport_pvt(p), - ast_sockaddr_stringify(&p->ourip), + ast_sockaddr_stringify_remote(&p->ourip), (int) p->branch, rport); } @@ -3626,7 +3627,7 @@ static int retrans_pkt(const void *data) } append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data->str); - xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen); + xmitres = __sip_xmit(pkt->owner, pkt->data); /* If there was no error during the network transmission, schedule the next retransmission, * but if the next retransmission is going to be beyond our timeout period, mark the packet's @@ -3745,10 +3746,12 @@ static int retrans_pkt(const void *data) return 0; } -/*! \brief Transmit packet with retransmits - \return 0 on success, -1 on failure to allocate packet -*/ -static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int len, int fatal, int sipmethod) +/*! + * \internal + * \brief Transmit packet with retransmits + * \return 0 on success, -1 on failure to allocate packet + */ +static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, struct ast_str *data, int fatal, int sipmethod) { struct sip_pkt *pkt = NULL; int siptimer_a = DEFAULT_RETRANS; @@ -3764,7 +3767,7 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res /* I removed the code from retrans_pkt that does the same thing so it doesn't get loaded into the scheduler */ /*! \todo According to the RFC some packets need to be retransmitted even if its TCP, so this needs to get revisited */ if (!(p->socket.type & SIP_TRANSPORT_UDP)) { - xmitres = __sip_xmit(p, data, len); /* Send packet */ + xmitres = __sip_xmit(p, data); /* Send packet */ if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */ append_history(p, "XmitErr", "%s", fatal ? "(Critical)" : "(Non-critical)"); return AST_FAILURE; @@ -3777,12 +3780,11 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res return AST_FAILURE; } /* copy data, add a terminator and save length */ - if (!(pkt->data = ast_str_create(len))) { + if (!(pkt->data = ast_str_create(ast_str_strlen(data)))) { ast_free(pkt); return AST_FAILURE; } ast_str_set(&pkt->data, 0, "%s%s", data->str, "\0"); - pkt->packetlen = len; /* copy other parameters from the caller */ pkt->method = sipmethod; pkt->seqno = seqno; @@ -3812,7 +3814,7 @@ static enum sip_result __sip_reliable_xmit(struct sip_pvt *p, int seqno, int res ast_debug(4, "*** SIP TIMER: Initializing retransmit timer on packet: Id #%d\n", pkt->retransid); } - xmitres = __sip_xmit(pkt->owner, pkt->data, pkt->packetlen); /* Send packet */ + xmitres = __sip_xmit(pkt->owner, pkt->data); /* Send packet */ if (xmitres == XMIT_ERROR) { /* Serious network trouble, no need to try again */ append_history(pkt->owner, "XmitErr", "%s", pkt->is_fatal ? "(Critical)" : "(Non-critical)"); @@ -4097,7 +4099,6 @@ static void add_blank(struct sip_request *req) if (!req->lines) { /* Add extra empty return. add_header() reserves 4 bytes so cannot be truncated */ ast_str_append(&req->data, 0, "\r\n"); - req->len = ast_str_strlen(req->data); } } @@ -4170,8 +4171,8 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty } res = (reliable) ? - __sip_reliable_xmit(p, seqno, 1, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) : - __sip_xmit(p, req->data, req->len); + __sip_reliable_xmit(p, seqno, 1, req->data, (reliable == XMIT_CRITICAL), req->method) : + __sip_xmit(p, req->data); deinit_req(req); if (res > 0) { return 0; @@ -4179,9 +4180,11 @@ static int send_response(struct sip_pvt *p, struct sip_request *req, enum xmitty return res; } -/*! \brief Send SIP Request to the other part of the dialogue - \return see \ref __sip_xmit -*/ +/*! + * \internal + * \brief Send SIP Request to the other part of the dialogue + * \return see \ref __sip_xmit + */ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittype reliable, int seqno) { int res; @@ -4209,8 +4212,8 @@ static int send_request(struct sip_pvt *p, struct sip_request *req, enum xmittyp deinit_req(&tmp); } res = (reliable) ? - __sip_reliable_xmit(p, seqno, 0, req->data, req->len, (reliable == XMIT_CRITICAL), req->method) : - __sip_xmit(p, req->data, req->len); + __sip_reliable_xmit(p, seqno, 0, req->data, (reliable == XMIT_CRITICAL), req->method) : + __sip_xmit(p, req->data); deinit_req(req); return res; } @@ -4438,8 +4441,11 @@ static const char *sip_get_callid(struct ast_channel *chan) return chan->tech_pvt ? ((struct sip_pvt *) chan->tech_pvt)->callid : ""; } -/*! \brief Send SIP MESSAGE text within a call - Called from PBX core sendtext() application */ +/*! + * \internal + * \brief Send SIP MESSAGE text within a call + * \note Called from PBX core sendtext() application + */ static int sip_sendtext(struct ast_channel *ast, const char *text) { struct sip_pvt *dialog = ast->tech_pvt; @@ -4609,8 +4615,10 @@ static void sip_destroy_peer(struct sip_peer *peer) ast_debug(3, "-REALTIME- peer Destroyed. Name: %s. Realtime Peer objects: %d\n", peer->name, rpeerobjs); } else ast_atomic_fetchadd_int(&speerobjs, -1); - clear_realm_authentication(peer->auth); - peer->auth = NULL; + if (peer->auth) { + ao2_t_ref(peer->auth, -1, "Removing peer authentication"); + peer->auth = NULL; + } if (peer->dnsmgr) ast_dnsmgr_release(peer->dnsmgr); clear_peer_mailboxes(peer); @@ -5111,6 +5119,8 @@ static int dialog_initialize_rtp(struct sip_pvt *dialog) */ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) { + struct sip_auth_container *credentials; + /* this checks that the dialog is contacting the peer on a valid * transport type based on the peers transport configuration, * otherwise, this function bails out */ @@ -5199,12 +5209,26 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) dialog->allowtransfer = peer->allowtransfer; dialog->jointnoncodeccapability = dialog->noncodeccapability; dialog->rtptimeout = peer->rtptimeout; - dialog->peerauth = peer->auth; + + /* Update dialog authorization credentials */ + ao2_lock(peer); + credentials = peer->auth; + if (credentials) { + ao2_t_ref(credentials, +1, "Ref peer auth for dialog"); + } + ao2_unlock(peer); + ao2_lock(dialog); + if (dialog->peerauth) { + ao2_t_ref(dialog->peerauth, -1, "Unref old dialog peer auth"); + } + dialog->peerauth = credentials; + ao2_unlock(dialog); + dialog->maxcallbitrate = peer->maxcallbitrate; dialog->disallowed_methods = peer->disallowed_methods; ast_cc_copy_config_params(dialog->cc_params, peer->cc_params); if (ast_strlen_zero(dialog->tohost)) - ast_string_field_set(dialog, tohost, ast_sockaddr_stringify_host(&dialog->sa)); + ast_string_field_set(dialog, tohost, ast_sockaddr_stringify_host_remote(&dialog->sa)); if (!ast_strlen_zero(peer->fromdomain)) { ast_string_field_set(dialog, fromdomain, peer->fromdomain); if (!dialog->initreq.headers) { @@ -5464,7 +5488,7 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout) return -1; } - if (p->trtp && !p->vsrtp && setup_srtp(&p->tsrtp) < 0) { + if (p->trtp && !p->tsrtp && setup_srtp(&p->tsrtp) < 0) { ast_log(LOG_WARNING, "SRTP text setup failed\n"); return -1; } @@ -5726,6 +5750,12 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist) ao2_ref(p->socket.tcptls_session, -1); p->socket.tcptls_session = NULL; } + + if (p->peerauth) { + ao2_t_ref(p->peerauth, -1, "Removing active peer authentication"); + p->peerauth = NULL; + } + p->caps = ast_format_cap_destroy(p->caps); p->jointcaps = ast_format_cap_destroy(p->jointcaps); p->peercaps = ast_format_cap_destroy(p->peercaps); @@ -7350,7 +7380,7 @@ static char *generate_uri(struct sip_pvt *pvt, char *buf, size_t size) * use the handy random string generation function we already have */ ast_str_append(&uri, 0, "%s", generate_random_string(buf, size)); - ast_str_append(&uri, 0, "@%s", ast_sockaddr_stringify(&pvt->ourip)); + ast_str_append(&uri, 0, "@%s", ast_sockaddr_stringify_remote(&pvt->ourip)); ast_copy_string(buf, ast_str_buffer(uri), size); return buf; } @@ -7360,7 +7390,7 @@ static void build_callid_pvt(struct sip_pvt *pvt) { char buf[33]; - const char *host = S_OR(pvt->fromdomain, ast_sockaddr_stringify(&pvt->ourip)); + const char *host = S_OR(pvt->fromdomain, ast_sockaddr_stringify_remote(&pvt->ourip)); ast_string_field_build(pvt, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host); @@ -7371,7 +7401,7 @@ static void build_callid_registry(struct sip_registry *reg, const struct ast_soc { char buf[33]; - const char *host = S_OR(fromdomain, ast_sockaddr_stringify_host(ourip)); + const char *host = S_OR(fromdomain, ast_sockaddr_stringify_host_remote(ourip)); ast_string_field_build(reg, callid, "%s@%s", generate_random_string(buf, sizeof(buf)), host); } @@ -8291,8 +8321,10 @@ static unsigned int set_pvt_allowed_methods(struct sip_pvt *pvt, struct sip_requ /*! \brief Parse multiline SIP headers into one header This is enabled if pedanticsipchecking is enabled */ -static int lws2sws(char *msgbuf, int len) +static void lws2sws(struct ast_str *data) { + char *msgbuf = data->str; + int len = ast_str_strlen(data); int h = 0, t = 0; int lws = 0; @@ -8332,7 +8364,7 @@ static int lws2sws(char *msgbuf, int len) lws = 0; } msgbuf[t] = '\0'; - return t; + data->used = t; } /*! \brief Parse a SIP message @@ -8708,11 +8740,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action memset(p->offered_media, 0, sizeof(p->offered_media)); - - /* default: novideo and notext set */ - p->novideo = TRUE; - p->notext = TRUE; - if (p->vrtp) { ast_rtp_codecs_payloads_clear(&newvideortp, NULL); } @@ -8770,7 +8797,9 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_debug(3, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED."); } - + /* default: novideo and notext set */ + p->novideo = TRUE; + p->notext = TRUE; /* Scan media stream (m=) specific parameters loop */ while (!ast_strlen_zero(nextm)) { @@ -8789,8 +8818,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action nextm = get_sdp_iterate(&next, req, "m"); /* Search for audio media definition */ - if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || - (sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) { + if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0 && x) || + (sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0 && x)) { if (!strcmp(protocol, "SAVP")) { secure_audio = 1; } else if (strcmp(protocol, "AVP")) { @@ -8817,8 +8846,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec); } /* Search for video media definition */ - } else if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) || - (sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len >= 0)) { + } else if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0 && x) || + (sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len >= 0 && x)) { if (!strcmp(protocol, "SAVP")) { secure_video = 1; } else if (strcmp(protocol, "AVP")) { @@ -8845,8 +8874,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec); } /* Search for text media definition */ - } else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) || - (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0)) { + } else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0 && x) || + (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0 && x)) { text = TRUE; p->notext = FALSE; p->offered_media[SDP_TEXT].offered = TRUE; @@ -8867,8 +8896,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec); } /* Search for image media definition */ - } else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0) || - (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0) )) { + } else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0 && x) || + (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0 && x) )) { image = TRUE; if (debug) ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid); @@ -9707,9 +9736,8 @@ static int add_header(struct sip_request *req, const char *var, const char *valu } ast_str_append(&req->data, 0, "%s: %s\r\n", var, value); - req->header[req->headers] = req->len; + req->header[req->headers] = ast_str_strlen(req->data); - req->len = ast_str_strlen(req->data); req->headers++; return 0; @@ -9743,7 +9771,6 @@ static int finalize_content(struct sip_request *req) if (ast_str_strlen(req->content)) { ast_str_append(&req->data, 0, "\r\n%s", ast_str_buffer(req->content)); - req->len = ast_str_strlen(req->data); } req->lines = ast_str_strlen(req->content) ? 1 : 0; return 0; @@ -9839,13 +9866,13 @@ static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const st /* Add rport to first VIA header if requested */ snprintf(new, sizeof(new), "%s;received=%s;rport=%d%s%s", - leftmost, ast_sockaddr_stringify_addr(&p->recv), + leftmost, ast_sockaddr_stringify_addr_remote(&p->recv), ast_sockaddr_port(&p->recv), others ? "," : "", others ? others : ""); } else { /* We should *always* add a received to the topmost via */ snprintf(new, sizeof(new), "%s;received=%s%s%s", - leftmost, ast_sockaddr_stringify_addr(&p->recv), + leftmost, ast_sockaddr_stringify_addr_remote(&p->recv), others ? "," : "", others ? others : ""); } oh = new; /* the header to copy */ @@ -9981,7 +10008,6 @@ static int init_resp(struct sip_request *resp, const char *msg) goto e_free_data; resp->header[0] = 0; ast_str_set(&resp->data, 0, "SIP/2.0 %s\r\n", msg); - resp->len = resp->data->used; resp->headers++; return 0; @@ -10004,7 +10030,6 @@ static int init_req(struct sip_request *req, int sipmethod, const char *recip) req->method = sipmethod; req->header[0] = 0; ast_str_set(&req->data, 0, "%s %s SIP/2.0\r\n", sip_methods[sipmethod].text, recip); - req->len = ast_str_strlen(req->data); req->headers++; return 0; @@ -10719,7 +10744,7 @@ static int add_rpid(struct sip_request *req, struct sip_pvt *p) return 0; if (ast_strlen_zero(lid_name)) lid_name = lid_num; - fromdomain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip)); + fromdomain = S_OR(p->fromdomain, ast_sockaddr_stringify_host_remote(&p->ourip)); lid_num = ast_uri_encode(lid_num, tmp2, sizeof(tmp2), ast_uri_sip_user); @@ -11200,12 +11225,12 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int p->sessionid, p->sessionversion, (ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ? "IP6" : "IP4", - ast_sockaddr_stringify_addr(&dest)); + ast_sockaddr_stringify_addr_remote(&dest)); snprintf(connection, sizeof(connection), "c=IN %s %s\r\n", (ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ? "IP6" : "IP4", - ast_sockaddr_stringify_addr(&dest)); + ast_sockaddr_stringify_addr_remote(&dest)); if (add_audio) { if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR) { @@ -11388,7 +11413,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int if (!ast_sockaddr_cmp(&udptldest, &dest)) { ast_str_append(&m_modem, 0, "c=IN %s %s\r\n", (ast_sockaddr_is_ipv6(&dest) && !ast_sockaddr_is_ipv4_mapped(&dest)) ? - "IP6" : "IP4", ast_sockaddr_stringify_addr(&udptldest)); + "IP6" : "IP4", ast_sockaddr_stringify_addr_remote(&udptldest)); } ast_str_append(&a_modem, 0, "a=T38FaxVersion:%d\r\n", p->t38.our_parms.version); @@ -11743,10 +11768,10 @@ static void build_contact(struct sip_pvt *p) if (p->socket.type == SIP_TRANSPORT_UDP) { ast_string_field_build(p, our_contact, "<sip:%s%s%s>", user, - ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify(&p->ourip)); + ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip)); } else { ast_string_field_build(p, our_contact, "<sip:%s%s%s;transport=%s>", user, - ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify(&p->ourip), + ast_strlen_zero(user) ? "" : "@", ast_sockaddr_stringify_remote(&p->ourip), get_transport(p->socket.type)); } } @@ -11787,7 +11812,7 @@ static void initreqprep(struct sip_request *req, struct sip_pvt *p, int sipmetho snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text); - d = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip)); + d = S_OR(p->fromdomain, ast_sockaddr_stringify_host_remote(&p->ourip)); if (p->owner) { if ((ast_party_id_presentation(&p->owner->connected.id) & AST_PRES_RESTRICTION) == AST_PRES_ALLOWED) { l = p->owner->connected.id.number.valid ? p->owner->connected.id.number.str : NULL; @@ -11951,11 +11976,11 @@ static void add_diversion_header(struct sip_request *req, struct sip_pvt *pvt) if (!pvt->owner->redirecting.from.name.valid || ast_strlen_zero(diverting_name)) { snprintf(header_text, sizeof(header_text), "<sip:%s@%s>;reason=%s", diverting_number, - ast_sockaddr_stringify_host(&pvt->ourip), reason); + ast_sockaddr_stringify_host_remote(&pvt->ourip), reason); } else { snprintf(header_text, sizeof(header_text), "\"%s\" <sip:%s@%s>;reason=%s", diverting_name, diverting_number, - ast_sockaddr_stringify_host(&pvt->ourip), reason); + ast_sockaddr_stringify_host_remote(&pvt->ourip), reason); } add_header(req, "Diversion", header_text); @@ -12582,7 +12607,7 @@ static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, struct sip_request req; struct ast_str *out = ast_str_alloca(500); int ourport = (p->fromdomainport) ? p->fromdomainport : ast_sockaddr_port(&p->ourip); - const char *domain = S_OR(p->fromdomain, ast_sockaddr_stringify_host(&p->ourip)); + const char *domain = S_OR(p->fromdomain, ast_sockaddr_stringify_host_remote(&p->ourip)); const char *exten = S_OR(vmexten, default_vmexten); initreqprep(&req, p, SIP_NOTIFY, NULL); @@ -12912,6 +12937,19 @@ static int sip_reg_timeout(const void *data) return 0; } +static const char *sip_sanitized_host(const char *host) +{ + struct ast_sockaddr addr = { { 0, 0, }, }; + + /* peer/sip_pvt->tohost and sip_registry->hostname should never have a port + * in them, so we use PARSE_PORT_FORBID here. If this lookup fails, we return + * the original host which is most likely a host name and not an IP. */ + if (!ast_sockaddr_parse(&addr, host, PARSE_PORT_FORBID)) { + return host; + } + return ast_sockaddr_stringify_host_remote(&addr); +} + /*! \brief Transmit register to SIP proxy or UA * auth = NULL on the initial registration (from sip_reregister()) */ @@ -13065,19 +13103,19 @@ static int transmit_register(struct sip_registry *r, int sipmethod, const char * ast_debug(1, "Scheduled a registration timeout for %s id #%d \n", r->hostname, r->timeout); } - snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain,p->tohost), p->tag); + snprintf(from, sizeof(from), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain, sip_sanitized_host(p->tohost)), p->tag); if (!ast_strlen_zero(p->theirtag)) { - snprintf(to, sizeof(to), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain,p->tohost), p->theirtag); + snprintf(to, sizeof(to), "<sip:%s@%s>;tag=%s", r->username, S_OR(r->regdomain, sip_sanitized_host(p->tohost)), p->theirtag); } else { - snprintf(to, sizeof(to), "<sip:%s@%s>", r->username, S_OR(r->regdomain,p->tohost)); + snprintf(to, sizeof(to), "<sip:%s@%s>", r->username, S_OR(r->regdomain, sip_sanitized_host(p->tohost))); } /* Fromdomain is what we are registering to, regardless of actual host name from SRV */ if (portno && portno != STANDARD_SIP_PORT) { - snprintf(addr, sizeof(addr), "sip:%s:%d", S_OR(p->fromdomain,S_OR(r->regdomain,r->hostname)), portno); + snprintf(addr, sizeof(addr), "sip:%s:%d", S_OR(p->fromdomain,S_OR(r->regdomain, sip_sanitized_host(r->hostname))), portno); } else { - snprintf(addr, sizeof(addr), "sip:%s", S_OR(p->fromdomain,S_OR(r->regdomain,r->hostname))); + snprintf(addr, sizeof(addr), "sip:%s", S_OR(p->fromdomain,S_OR(r->regdomain, sip_sanitized_host(r->hostname)))); } ast_string_field_set(p, uri, addr); @@ -13151,6 +13189,7 @@ static int transmit_message_with_msg(struct sip_pvt *p, const struct ast_msg *ms struct ast_msg_var_iterator *i; const char *var, *val; + build_via(p); initreqprep(&req, p, SIP_MESSAGE, NULL); ast_string_field_set(p, msg_body, ast_msg_get_body(msg)); initialize_initreq(p, &req); @@ -13368,7 +13407,7 @@ static int transmit_request(struct sip_pvt *p, int sipmethod, int seqno, enum xm return send_request(p, &resp, reliable, seqno ? seqno : p->ocseq); } -/*! \brief return the request and response heade for a 401 or 407 code */ +/*! \brief return the request and response header for a 401 or 407 code */ static void auth_headers(enum sip_auth_type code, char **header, char **respheader) { if (code == WWW_AUTH) { /* 401 */ @@ -16116,6 +16155,15 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a } } + /* Override the context with the message context _BEFORE_ + * getting the destination. This way we can guarantee the correct + * extension is used in the message context when it is present. */ + if (!ast_strlen_zero(p->messagecontext)) { + ast_string_field_set(p, context, p->messagecontext); + } else if (!ast_strlen_zero(sip_cfg.messagecontext)) { + ast_string_field_set(p, context, sip_cfg.messagecontext); + } + get_destination(p, NULL, NULL); if (!(msg = ast_msg_alloc())) { @@ -16132,14 +16180,7 @@ static void receive_message(struct sip_pvt *p, struct sip_request *req, struct a res = ast_msg_set_to(msg, "%s", to); res |= ast_msg_set_from(msg, "%s", get_in_brackets(from)); res |= ast_msg_set_body(msg, "%s", ast_str_buffer(buf)); - - if (!ast_strlen_zero(p->messagecontext)) { - res |= ast_msg_set_context(msg, "%s", p->messagecontext); - } else if (!ast_strlen_zero(sip_cfg.messagecontext)) { - res |= ast_msg_set_context(msg, "%s", sip_cfg.messagecontext); - } else { - res |= ast_msg_set_context(msg, "%s", p->context); - } + res |= ast_msg_set_context(msg, "%s", p->context); if (!ast_strlen_zero(p->peername)) { res |= ast_msg_set_var(msg, "SIP_PEERNAME", p->peername); @@ -17210,7 +17251,6 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct char codec_buf[512]; struct ast_codec_pref *pref; struct ast_variable *v; - struct sip_auth *auth; int x = 0, load_realtime; struct ast_format codec; int realtimepeers; @@ -17238,6 +17278,15 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct } if (peer && type==0 ) { /* Normal listing */ struct ast_str *mailbox_str = ast_str_alloca(512); + struct sip_auth_container *credentials; + + ao2_lock(peer); + credentials = peer->auth; + if (credentials) { + ao2_t_ref(credentials, +1, "Ref peer auth for show"); + } + ao2_unlock(peer); + ast_cli(fd, "\n\n"); ast_cli(fd, " * Name : %s\n", peer->name); ast_cli(fd, " Description : %s\n", peer->description); @@ -17247,9 +17296,19 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>"); ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"<Not set>":"<Set>"); ast_cli(fd, " Remote Secret: %s\n", ast_strlen_zero(peer->remotesecret)?"<Not set>":"<Set>"); - for (auth = peer->auth; auth; auth = auth->next) { - ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s ", auth->realm, auth->username); - ast_cli(fd, "%s\n", !ast_strlen_zero(auth->secret)?"<Secret set>":(!ast_strlen_zero(auth->md5secret)?"<MD5secret set>" : "<Not set>")); + if (credentials) { + struct sip_auth *auth; + + AST_LIST_TRAVERSE(&credentials->list, auth, node) { + ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s %s\n", + auth->realm, + auth->username, + !ast_strlen_zero(auth->secret) + ? "<Secret set>" + : (!ast_strlen_zero(auth->md5secret) + ? "<MD5secret set>" : "<Not set>")); + } + ao2_t_ref(credentials, -1, "Unref peer auth for show"); } ast_cli(fd, " Context : %s\n", peer->context); ast_cli(fd, " Subscr.Cont. : %s\n", S_OR(peer->subscribecontext, "<Not set>") ); @@ -17339,13 +17398,13 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct ast_cli(fd, " Status : "); peer_status(peer, status, sizeof(status)); ast_cli(fd, "%s\n", status); - ast_cli(fd, " Useragent : %s\n", peer->useragent); - ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact); + ast_cli(fd, " Useragent : %s\n", peer->useragent); + ast_cli(fd, " Reg. Contact : %s\n", peer->fullcontact); ast_cli(fd, " Qualify Freq : %d ms\n", peer->qualifyfreq); if (peer->chanvars) { - ast_cli(fd, " Variables :\n"); + ast_cli(fd, " Variables :\n"); for (v = peer->chanvars ; v ; v = v->next) - ast_cli(fd, " %s = %s\n", v->name, v->value); + ast_cli(fd, " %s = %s\n", v->name, v->value); } ast_cli(fd, " Sess-Timers : %s\n", stmode2str(peer->stimer.st_mode_oper)); @@ -17439,13 +17498,13 @@ static char *_sip_show_peer(int type, int fd, struct mansession *s, const struct astman_append(s, "Status: "); peer_status(peer, status, sizeof(status)); astman_append(s, "%s\r\n", status); - astman_append(s, "SIP-Useragent: %s\r\n", peer->useragent); - astman_append(s, "Reg-Contact: %s\r\n", peer->fullcontact); + astman_append(s, "SIP-Useragent: %s\r\n", peer->useragent); + astman_append(s, "Reg-Contact: %s\r\n", peer->fullcontact); astman_append(s, "QualifyFreq: %d ms\r\n", peer->qualifyfreq); astman_append(s, "Parkinglot: %s\r\n", peer->parkinglot); if (peer->chanvars) { for (v = peer->chanvars ; v ; v = v->next) { - astman_append(s, "ChanVariable: %s=%s\r\n", v->name, v->value); + astman_append(s, "ChanVariable: %s=%s\r\n", v->name, v->value); } } astman_append(s, "SIP-Use-Reason-Header : %s\r\n", (ast_test_flag(&peer->flags[1], SIP_PAGE2_Q850_REASON)) ? "Y" : "N"); @@ -17806,6 +17865,7 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ int realtimeregs; char codec_buf[SIPBUFSIZE]; const char *msg; /* temporary msg pointer */ + struct sip_auth_container *credentials; switch (cmd) { case CLI_INIT: @@ -17818,12 +17878,19 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ return NULL; } + if (a->argc != 3) + return CLI_SHOWUSAGE; realtimepeers = ast_check_realtime("sippeers"); realtimeregs = ast_check_realtime("sipregs"); - if (a->argc != 3) - return CLI_SHOWUSAGE; + ast_mutex_lock(&authl_lock); + credentials = authl; + if (credentials) { + ao2_t_ref(credentials, +1, "Ref global auth for show"); + } + ast_mutex_unlock(&authl_lock); + ast_cli(a->fd, "\n\nGlobal Settings:\n"); ast_cli(a->fd, "----------------\n"); ast_cli(a->fd, " UDP Bindaddress: %s\n", ast_sockaddr_stringify(&bindaddr)); @@ -17847,10 +17914,24 @@ static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_ ast_cli(a->fd, " Allow unknown access: %s\n", AST_CLI_YESNO(sip_cfg.allowguest)); ast_cli(a->fd, " Allow subscriptions: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWSUBSCRIBE))); ast_cli(a->fd, " Allow overlap dialing: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[1], SIP_PAGE2_ALLOWOVERLAP))); - ast_cli(a->fd, " Allow promsic. redir: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR))); + ast_cli(a->fd, " Allow promisc. redir: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR))); ast_cli(a->fd, " Enable call counters: %s\n", AST_CLI_YESNO(global_callcounter)); ast_cli(a->fd, " SIP domain support: %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list))); - ast_cli(a->fd, " Realm. auth: %s\n", AST_CLI_YESNO(authl != NULL)); + ast_cli(a->fd, " Realm. auth: %s\n", AST_CLI_YESNO(credentials != NULL)); + if (credentials) { + struct sip_auth *auth; + + AST_LIST_TRAVERSE(&credentials->list, auth, node) { + ast_cli(a->fd, " Realm. auth entry: Realm %-15.15s User %-10.20s %s\n", + auth->realm, + auth->username, + !ast_strlen_zero(auth->secret) + ? "<Secret set>" + : (!ast_strlen_zero(auth->md5secret) + ? "<MD5secret set>" : "<Not set>")); + } + ao2_t_ref(credentials, -1, "Unref global auth for show"); + } ast_cli(a->fd, " Our auth realm %s\n", sip_cfg.realm); ast_cli(a->fd, " Use domains as realms: %s\n", AST_CLI_YESNO(sip_cfg.domainsasrealm)); ast_cli(a->fd, " Call to non-local dom.: %s\n", AST_CLI_YESNO(sip_cfg.allow_external_domains)); @@ -19048,20 +19129,39 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d const char *username; const char *secret; const char *md5secret; - struct sip_auth *auth = NULL; /* Realm authentication */ + struct sip_auth *auth; /* Realm authentication credential */ + struct sip_auth_container *credentials; if (!ast_strlen_zero(p->domain)) ast_copy_string(uri, p->domain, sizeof(uri)); else if (!ast_strlen_zero(p->uri)) ast_copy_string(uri, p->uri, sizeof(uri)); else - snprintf(uri, sizeof(uri), "sip:%s@%s", p->username, ast_sockaddr_stringify_host(&p->sa)); + snprintf(uri, sizeof(uri), "sip:%s@%s", p->username, ast_sockaddr_stringify_host_remote(&p->sa)); snprintf(cnonce, sizeof(cnonce), "%08lx", ast_random()); - /* Check if we have separate auth credentials */ - if(!(auth = find_realm_authentication(p->peerauth, p->realm))) /* Start with peer list */ - auth = find_realm_authentication(authl, p->realm); /* If not, global list */ + /* Check if we have peer credentials */ + ao2_lock(p); + credentials = p->peerauth; + if (credentials) { + ao2_t_ref(credentials, +1, "Ref peer auth for digest"); + } + ao2_unlock(p); + auth = find_realm_authentication(credentials, p->realm); + if (!auth) { + /* If not, check global credentials */ + if (credentials) { + ao2_t_ref(credentials, -1, "Unref peer auth for digest"); + } + ast_mutex_lock(&authl_lock); + credentials = authl; + if (credentials) { + ao2_t_ref(credentials, +1, "Ref global auth for digest"); + } + ast_mutex_unlock(&authl_lock); + auth = find_realm_authentication(credentials, p->realm); + } if (auth) { ast_debug(3, "use realm [%s] from peer [%s][%s]\n", auth->username, p->peername, p->username); @@ -19075,11 +19175,16 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d username = p->authname; secret = p->relatedpeer && !ast_strlen_zero(p->relatedpeer->remotesecret) - ? p->relatedpeer->remotesecret : p->peersecret; + ? p->relatedpeer->remotesecret : p->peersecret; md5secret = p->peermd5secret; } - if (ast_strlen_zero(username)) /* We have no authentication */ + if (ast_strlen_zero(username)) { + /* We have no authentication */ + if (credentials) { + ao2_t_ref(credentials, -1, "Unref auth for digest"); + } return -1; + } /* Calculate SIP digest response */ snprintf(a1, sizeof(a1), "%s:%s:%s", username, p->realm, secret); @@ -19099,7 +19204,7 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d /* only include the opaque string if it's set */ if (!ast_strlen_zero(p->opaque)) { - snprintf(opaque, sizeof(opaque), ", opaque=\"%s\"", p->opaque); + snprintf(opaque, sizeof(opaque), ", opaque=\"%s\"", p->opaque); } /* XXX We hard code our qop to "auth" for now. XXX */ @@ -19110,6 +19215,9 @@ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int d append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %d", username, p->realm, p->noncecount); + if (credentials) { + ao2_t_ref(credentials, -1, "Unref auth for digest"); + } return 0; } @@ -20586,6 +20694,131 @@ static void handle_response_peerpoke(struct sip_pvt *p, int resp, struct sip_req ref_peer(peer, "adding poke peer ref")); } +/*! + * \internal + * \brief Handle responses to INFO messages + * + * \note The INFO method MUST NOT change the state of calls or + * related sessions (RFC 2976). + */ +static void handle_response_info(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno) +{ + int sipmethod = SIP_INFO; + + switch (resp) { + case 401: /* Not www-authorized on SIP method */ + case 407: /* Proxy auth required */ + ast_log(LOG_WARNING, "Host '%s' requests authentication (%d) for '%s'\n", + ast_sockaddr_stringify(&p->sa), resp, sip_methods[sipmethod].text); + break; + case 405: /* Method not allowed */ + case 501: /* Not Implemented */ + mark_method_unallowed(&p->allowed_methods, sipmethod); + if (p->relatedpeer) { + mark_method_allowed(&p->relatedpeer->disallowed_methods, sipmethod); + } + ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", + ast_sockaddr_stringify(&p->sa), sip_methods[sipmethod].text); + break; + default: + if (300 <= resp && resp < 700) { + ast_verb(3, "Got SIP %s response %d \"%s\" back from host '%s'\n", + sip_methods[sipmethod].text, resp, rest, ast_sockaddr_stringify(&p->sa)); + } + break; + } +} + +/*! + * \internal + * \brief Handle auth requests to a MESSAGE request + * \return TRUE if authentication failed. + */ +static int do_message_auth(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno) +{ + char *header; + char *respheader; + char digest[1024]; + + if (p->options) { + p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH); + } + + if (p->authtries == MAX_AUTHTRIES) { + ast_log(LOG_NOTICE, "Failed to authenticate MESSAGE with host '%s'\n", + ast_sockaddr_stringify(&p->sa)); + return -1; + } + + ++p->authtries; + auth_headers((resp == 401 ? WWW_AUTH : PROXY_AUTH), &header, &respheader); + memset(digest, 0, sizeof(digest)); + if (reply_digest(p, req, header, SIP_MESSAGE, digest, sizeof(digest))) { + /* There's nothing to use for authentication */ + ast_debug(1, "Nothing to use for MESSAGE authentication\n"); + return -1; + } + + if (p->do_history) { + append_history(p, "MessageAuth", "Try: %d", p->authtries); + } + + transmit_message_with_text(p, p->msg_body, 0, 1); + return 0; +} + +/*! + * \internal + * \brief Handle responses to MESSAGE messages + * + * \note The MESSAGE method should not change the state of calls + * or related sessions if associated with a dialog. (Implied by + * RFC 3428 Section 2). + */ +static void handle_response_message(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno) +{ + int sipmethod = SIP_MESSAGE; + int in_dialog = ast_test_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); + + switch (resp) { + case 401: /* Not www-authorized on SIP method */ + case 407: /* Proxy auth required */ + if (do_message_auth(p, resp, rest, req, seqno) && !in_dialog) { + pvt_set_needdestroy(p, "MESSAGE authentication failed"); + } + break; + case 405: /* Method not allowed */ + case 501: /* Not Implemented */ + mark_method_unallowed(&p->allowed_methods, sipmethod); + if (p->relatedpeer) { + mark_method_allowed(&p->relatedpeer->disallowed_methods, sipmethod); + } + ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", + ast_sockaddr_stringify(&p->sa), sip_methods[sipmethod].text); + if (!in_dialog) { + pvt_set_needdestroy(p, "MESSAGE not implemented or allowed"); + } + break; + default: + if (100 <= resp && resp < 200) { + /* Must allow provisional responses for out-of-dialog requests. */ + } else if (200 <= resp && resp < 300) { + p->authtries = 0; /* Reset authentication counter */ + if (!in_dialog) { + pvt_set_needdestroy(p, "MESSAGE delivery accepted"); + } + } else if (300 <= resp && resp < 700) { + ast_verb(3, "Got SIP %s response %d \"%s\" back from host '%s'\n", + sip_methods[sipmethod].text, resp, rest, ast_sockaddr_stringify(&p->sa)); + if (!in_dialog) { + pvt_set_needdestroy(p, (300 <= resp && resp < 600) + ? "MESSAGE delivery failed" : "MESSAGE delivery refused"); + } + } + break; + } +} + /*! \brief Immediately stop RTP, VRTP and UDPTL as applicable */ static void stop_media_flows(struct sip_pvt *p) { @@ -20706,6 +20939,12 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc * we just always call the response handler. Good gravy! */ handle_response_publish(p, resp, rest, req, seqno); + } else if (sipmethod == SIP_INFO) { + /* More good gravy! */ + handle_response_info(p, resp, rest, req, seqno); + } else if (sipmethod == SIP_MESSAGE) { + /* More good gravy! */ + handle_response_message(p, resp, rest, req, seqno); } else if (ast_test_flag(&p->flags[0], SIP_OUTGOING)) { switch(resp) { case 100: /* 100 Trying */ @@ -20719,11 +20958,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc break; case 200: /* 200 OK */ p->authtries = 0; /* Reset authentication counter */ - if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO) { - /* We successfully transmitted a message - or a video update request in INFO */ - /* Nothing happens here - the message is inside a dialog */ - } else if (sipmethod == SIP_INVITE) { + if (sipmethod == SIP_INVITE) { handle_response_invite(p, resp, rest, req, seqno); } else if (sipmethod == SIP_NOTIFY) { handle_response_notify(p, resp, rest, req, seqno); @@ -20749,8 +20984,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc handle_response_register(p, resp, rest, req, seqno); else if (sipmethod == SIP_UPDATE) { handle_response_update(p, resp, rest, req, seqno); - } else if (sipmethod == SIP_MESSAGE) { - handle_response_message(p, resp, rest, req, seqno); } else if (sipmethod == SIP_BYE) { if (p->options) p->options->auth_type = resp; @@ -20852,7 +21085,7 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc pvt_set_needdestroy(p, "received 491 response"); } break; - case 405: + case 405: /* Method not allowed */ case 501: /* Not Implemented */ mark_method_unallowed(&p->allowed_methods, sipmethod); if (p->relatedpeer) { @@ -20863,7 +21096,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc else ast_log(LOG_WARNING, "Host '%s' does not implement '%s'\n", ast_sockaddr_stringify(&p->sa), msg); break; - /* Fallthrough */ default: if ((resp >= 200) && (resp < 300)) { /* on any 2XX response do the following */ if (sipmethod == SIP_INVITE) { @@ -20883,17 +21115,17 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc case 301: /* Moved permanently */ case 302: /* Moved temporarily */ case 305: /* Use Proxy */ - if (p->owner) { - struct ast_party_redirecting redirecting; - struct ast_set_party_redirecting update_redirecting; - - ast_party_redirecting_init(&redirecting); - change_redirecting_information(p, req, &redirecting, - &update_redirecting, TRUE); - ast_channel_set_redirecting(p->owner, &redirecting, - &update_redirecting); - ast_party_redirecting_free(&redirecting); - } + if (p->owner) { + struct ast_party_redirecting redirecting; + struct ast_set_party_redirecting update_redirecting; + + ast_party_redirecting_init(&redirecting); + change_redirecting_information(p, req, &redirecting, + &update_redirecting, TRUE); + ast_channel_set_redirecting(p->owner, &redirecting, + &update_redirecting); + ast_party_redirecting_free(&redirecting); + } /* Fall through */ case 486: /* Busy here */ case 600: /* Busy everywhere */ @@ -20922,15 +21154,14 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc break; default: /* Send hangup */ - if (owner && sipmethod != SIP_MESSAGE && sipmethod != SIP_INFO && sipmethod != SIP_BYE) + if (owner && sipmethod != SIP_BYE) ast_queue_hangup_with_cause(p->owner, AST_CAUSE_PROTOCOL_ERROR); break; } /* ACK on invite */ if (sipmethod == SIP_INVITE) transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE); - if (sipmethod != SIP_MESSAGE && sipmethod != SIP_INFO) - sip_alreadygone(p); + sip_alreadygone(p); if (!p->owner) { pvt_set_needdestroy(p, "transaction completed"); } @@ -20991,10 +21222,6 @@ static void handle_response(struct sip_pvt *p, int resp, const char *rest, struc } } else if (sipmethod == SIP_BYE) { pvt_set_needdestroy(p, "transaction completed"); - } else if (sipmethod == SIP_MESSAGE || sipmethod == SIP_INFO) { - /* We successfully transmitted a message or - a video update request in INFO */ - ; } break; case 401: /* www-auth */ @@ -23298,13 +23525,21 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, int } ast_set_flag(&p->flags[0], SIP_DEFER_BYE_ON_TRANSFER); /* Delay hangup */ - - /* For blind transfers, move the call to the new extensions. For attended transfers on multiple - servers - generate an INVITE with Replaces. Either way, let the dial plan decided */ - /* indicate before masquerade so the indication actually makes it to the real channel - when using local channels with MOH passthru */ - ast_indicate(current.chan2, AST_CONTROL_UNHOLD); - res = ast_async_goto(current.chan2, p->refer->refer_to_context, p->refer->refer_to, 1); + { + char *refer_to_context = ast_strdupa(p->refer->refer_to_context); + char *refer_to = ast_strdupa(p->refer->refer_to); + + /* Do not hold the pvt lock during the indicate and async_goto. Those functions + * lock channels which will invalidate locking order if the pvt lock is held.*/ + ao2_unlock(p); + /* For blind transfers, move the call to the new extensions. For attended transfers on multiple + * servers - generate an INVITE with Replaces. Either way, let the dial plan decided */ + /* indicate before masquerade so the indication actually makes it to the real channel + *when using local channels with MOH passthru */ + ast_indicate(current.chan2, AST_CONTROL_UNHOLD); + res = ast_async_goto(current.chan2, refer_to_context, refer_to, 1); + ao2_lock(p); + } if (!res) { ast_manager_event_multichan(EVENT_FLAG_CALL, "Transfer", 2, chans, @@ -23397,7 +23632,7 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req) } else sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); - if (p->initreq.len > 0) { + if (ast_str_strlen(p->initreq.data) > 0) { struct sip_pkt *pkt, *prev_pkt; /* If the CANCEL we are receiving is a retransmission, and we already have scheduled * a reliable 487, then we don't want to schedule another one on top of the previous @@ -23580,42 +23815,6 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req) return 1; } -/*! - * \internal - * \brief Handle auth requests to a MESSAGE request - */ -static void handle_response_message(struct sip_pvt *p, int resp, const char *rest, struct sip_request *req, int seqno) -{ - char *header, *respheader; - char digest[1024]; - - if (p->options) { - p->options->auth_type = (resp == 401 ? WWW_AUTH : PROXY_AUTH); - } - - if ((p->authtries == MAX_AUTHTRIES)) { - ast_log(LOG_NOTICE, "Failed to authenticate on MESSAGE to '%s'\n", get_header(&p->initreq, "From")); - pvt_set_needdestroy(p, "MESSAGE authentication failed"); - return; - } - - p->authtries++; - auth_headers((resp == 401 ? WWW_AUTH : PROXY_AUTH), &header, &respheader); - memset(digest, 0, sizeof(digest)); - if (reply_digest(p, req, header, SIP_MESSAGE, digest, sizeof(digest))) { - /* There's nothing to use for authentication */ - ast_debug(1, "Nothing to use for MESSAGE authentication\n"); - pvt_set_needdestroy(p, "MESSAGE authentication failed"); - return; - } - - if (p->do_history) { - append_history(p, "MessageAuth", "Try: %d", p->authtries); - } - - transmit_message_with_text(p, p->msg_body, 0, 1); -} - /*! \brief Handle incoming MESSAGE request */ static int handle_request_message(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e) { @@ -23654,6 +23853,8 @@ static int sip_msg_send(const struct ast_msg *msg, const char *to, const char *f } if (ast_strlen_zero(peer)) { ast_log(LOG_WARNING, "MESSAGE(to) is invalid for SIP - '%s'\n", to); + dialog_unlink_all(pvt, TRUE, TRUE); + dialog_unref(pvt, "MESSAGE(to) is invalid for SIP"); return -1; } @@ -25015,7 +25216,6 @@ static int sipsock_read(int *id, int fd, short events, void *ignore) return -1; } - req.len = res; req.socket.fd = sipsock; set_socket_transport(&req.socket, SIP_TRANSPORT_UDP); req.socket.tcptls_session = NULL; @@ -25041,7 +25241,7 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr) if (sip_debug_test_addr(addr)) /* Set the debug flag early on packet level */ req->debug = 1; if (sip_cfg.pedanticsipchecking) - req->len = lws2sws(req->data->str, req->len); /* Fix multiline headers */ + lws2sws(req->data); /* Fix multiline headers */ if (req->debug) { ast_verbose("\n<--- SIP read from %s:%s --->\n%s\n<------------->\n", get_transport(req->socket.type), ast_sockaddr_stringify(addr), req->data->str); @@ -25065,7 +25265,7 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr) /* Find the active SIP dialog or create a new one */ p = find_call(req, addr, req->method); /* returns p with a reference only. _NOT_ locked*/ if (p == NULL) { - ast_debug(1, "Invalid SIP message - rejected , no callid, len %d\n", req->len); + ast_debug(1, "Invalid SIP message - rejected , no callid, len %zu\n", ast_str_strlen(req->data)); ast_mutex_unlock(&netlock); return 1; } @@ -25296,13 +25496,14 @@ create_tcptls_session_fail: /*! * \brief Get cached MWI info - * \retval 0 At least one message is waiting - * \retval 1 no messages waiting + * \return TRUE if found MWI in cache */ static int get_cached_mwi(struct sip_peer *peer, int *new, int *old) { struct sip_mailbox *mailbox; + int in_cache; + in_cache = 0; AST_LIST_TRAVERSE(&peer->mailboxes, mailbox, entry) { struct ast_event *event; event = ast_event_get_cached(AST_EVENT_MWI, @@ -25314,9 +25515,10 @@ static int get_cached_mwi(struct sip_peer *peer, int *new, int *old) *new += ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); *old += ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS); ast_event_destroy(event); + in_cache = 1; } - return (*new || *old) ? 0 : 1; + return in_cache; } /*! \brief Send message waiting indication to alert peer that they've got voicemail */ @@ -25336,12 +25538,11 @@ static int sip_send_mwi_to_peer(struct sip_peer *peer, const struct ast_event *e if (event) { newmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS); oldmsgs = ast_event_get_ie_uint(event, AST_EVENT_IE_OLDMSGS); - } else if (!cache_only) { /* Fall back to manually checking the mailbox */ + } else if (!get_cached_mwi(peer, &newmsgs, &oldmsgs) && !cache_only) { + /* Fall back to manually checking the mailbox */ struct ast_str *mailbox_str = ast_str_alloca(512); peer_mailboxes_to_str(&mailbox_str, peer); ast_app_inboxcount(mailbox_str->str, &newmsgs, &oldmsgs); - } else { - get_cached_mwi(peer, &newmsgs, &oldmsgs); } if (peer->mwipvt) { @@ -25974,7 +26175,7 @@ static int sip_poke_peer(struct sip_peer *peer, int force) if (!ast_strlen_zero(peer->tohost)) ast_string_field_set(p, tohost, peer->tohost); else - ast_string_field_set(p, tohost, ast_sockaddr_stringify_host(&peer->addr)); + ast_string_field_set(p, tohost, ast_sockaddr_stringify_host_remote(&peer->addr)); /* Recalculate our side, and recalculate Call ID */ ast_sip_ouraddrfor(&p->sa, &p->ourip, p); @@ -26605,20 +26806,48 @@ static void clear_sip_domains(void) AST_LIST_UNLOCK(&domain_list); } +/*! + * \internal + * \brief Realm authentication container destructor. + * + * \param obj Container object to destroy. + * + * \return Nothing + */ +static void destroy_realm_authentication(void *obj) +{ + struct sip_auth_container *credentials = obj; + struct sip_auth *auth; + + while ((auth = AST_LIST_REMOVE_HEAD(&credentials->list, node))) { + ast_free(auth); + } +} -/*! \brief Add realm authentication in list */ -static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno) +/*! + * \internal + * \brief Add realm authentication to credentials. + * + * \param credentials Realm authentication container to create/add authentication credentials. + * \param configuration Credential configuration value. + * \param lineno Line number in config file. + * + * \return Nothing + */ +static void add_realm_authentication(struct sip_auth_container **credentials, const char *configuration, int lineno) { - char authcopy[256]; + char *authcopy; char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL; - struct sip_auth *a, *b, *auth; + struct sip_auth *auth; - if (ast_strlen_zero(configuration)) - return authlist; + if (ast_strlen_zero(configuration)) { + /* Nothing to add */ + return; + } ast_debug(1, "Auth config :: %s\n", configuration); - ast_copy_string(authcopy, configuration, sizeof(authcopy)); + authcopy = ast_strdupa(configuration); username = authcopy; /* split user[:secret] and relm */ @@ -26627,7 +26856,7 @@ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, cons *realm++ = '\0'; if (ast_strlen_zero(username) || ast_strlen_zero(realm)) { ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d\n", lineno); - return authlist; + return; } /* parse username at ':' for secret, or '#" for md5secret */ @@ -26637,9 +26866,21 @@ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, cons *md5secret++ = '\0'; } - if (!(auth = ast_calloc(1, sizeof(*auth)))) - return authlist; + /* Create the continer if needed. */ + if (!*credentials) { + *credentials = ao2_t_alloc(sizeof(**credentials), destroy_realm_authentication, + "Create realm auth container."); + if (!*credentials) { + /* Failed to create the credentials container. */ + return; + } + } + /* Create the authentication credential entry. */ + auth = ast_calloc(1, sizeof(*auth)); + if (!auth) { + return; + } ast_copy_string(auth->realm, realm, sizeof(auth->realm)); ast_copy_string(auth->username, username, sizeof(auth->username)); if (secret) @@ -26647,46 +26888,36 @@ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, cons if (md5secret) ast_copy_string(auth->md5secret, md5secret, sizeof(auth->md5secret)); - /* find the end of the list */ - for (b = NULL, a = authlist; a ; b = a, a = a->next) - ; - if (b) - b->next = auth; /* Add structure add end of list */ - else - authlist = auth; + /* Add credential to container list. */ + AST_LIST_INSERT_TAIL(&(*credentials)->list, auth, node); ast_verb(3, "Added authentication for realm %s\n", realm); - - return authlist; - -} - -/*! \brief Clear realm authentication list (at reload) */ -static int clear_realm_authentication(struct sip_auth *authlist) -{ - struct sip_auth *a = authlist; - struct sip_auth *b; - - while (a) { - b = a; - a = a->next; - ast_free(b); - } - - return 1; } -/*! \brief Find authentication for a specific realm */ -static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm) +/*! + * \internal + * \brief Find authentication for a specific realm. + * + * \param credentials Realm authentication container to search. + * \param realm Authentication realm to find. + * + * \return Found authentication credential or NULL. + */ +static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm) { - struct sip_auth *a; + struct sip_auth *auth; - for (a = authlist; a; a = a->next) { - if (!strcasecmp(a->realm, realm)) - break; + if (credentials) { + AST_LIST_TRAVERSE(&credentials->list, auth, node) { + if (!strcasecmp(auth->realm, realm)) { + break; + } + } + } else { + auth = NULL; } - return a; + return auth; } /*! \brief @@ -26932,8 +27163,13 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str peer->portinuri = 0; /* If we have realm authentication information, remove them (reload) */ - clear_realm_authentication(peer->auth); - peer->auth = NULL; + ao2_lock(peer); + if (peer->auth) { + ao2_t_ref(peer->auth, -1, "Removing old peer authentication"); + peer->auth = NULL; + } + ao2_unlock(peer); + /* clear the transport information. We will detect if a default value is required after parsing the config */ peer->default_outbound_transport = 0; peer->transports = 0; @@ -26997,7 +27233,7 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v, str } else if (!strcasecmp(v->name, "md5secret")) { ast_string_field_set(peer, md5secret, v->value); } else if (!strcasecmp(v->name, "auth")) { - peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno); + add_realm_authentication(&peer->auth, v->value, v->lineno); } else if (!strcasecmp(v->name, "callerid")) { char cid_name[80] = { '\0' }, cid_num[80] = { '\0' }; @@ -27609,9 +27845,13 @@ static int reload_config(enum channelreloadreason reason) if (reason != CHANNEL_MODULE_LOAD) { ast_debug(4, "--------------- SIP reload started\n"); - clear_realm_authentication(authl); clear_sip_domains(); - authl = NULL; + ast_mutex_lock(&authl_lock); + if (authl) { + ao2_t_ref(authl, -1, "Removing old global authentication"); + authl = NULL; + } + ast_mutex_unlock(&authl_lock); /* First, destroy all outstanding registry calls */ /* This is needed, since otherwise active registry entries will not be destroyed */ @@ -28340,12 +28580,12 @@ static int reload_config(enum channelreloadreason reason) } /* Build list of authentication to various SIP realms, i.e. service providers */ - for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) { - /* Format for authentication is auth = username:password@realm */ - if (!strcasecmp(v->name, "auth")) { - authl = add_realm_authentication(authl, v->value, v->lineno); + for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) { + /* Format for authentication is auth = username:password@realm */ + if (!strcasecmp(v->name, "auth")) { + add_realm_authentication(&authl, v->value, v->lineno); } - } + } if (bindport) { if (ast_sockaddr_port(&bindaddr)) { @@ -28665,24 +28905,22 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl) { struct sip_pvt *p; + /* Lock the channel and the private safely. */ + ast_channel_lock(chan); p = chan->tech_pvt; if (!p) { + ast_channel_unlock(chan); return -1; } - /* - * Lock both the pvt and it's owner safely. - */ sip_pvt_lock(p); - while (p->owner && ast_channel_trylock(p->owner)) { - sip_pvt_unlock(p); - usleep(1); - sip_pvt_lock(p); - } - - if (!p->owner) { + if (p->owner != chan) { + /* I suppose it could be argued that if this happens it is a bug. */ + ast_debug(1, "The private is not owned by channel %s anymore.\n", chan->name); sip_pvt_unlock(p); + ast_channel_unlock(chan); return 0; } + if (udptl) { ast_udptl_get_peer(udptl, &p->udptlredirip); } else { @@ -28701,8 +28939,8 @@ static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl) } /* Reset lastrtprx timer */ p->lastrtprx = p->lastrtptx = time(NULL); - ast_channel_unlock(p->owner); sip_pvt_unlock(p); + ast_channel_unlock(chan); return 0; } @@ -28809,10 +29047,21 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i struct sip_pvt *p; int changed = 0; + /* Lock the channel and the private safely. */ + ast_channel_lock(chan); p = chan->tech_pvt; if (!p) { + ast_channel_unlock(chan); return -1; } + sip_pvt_lock(p); + if (p->owner != chan) { + /* I suppose it could be argued that if this happens it is a bug. */ + ast_debug(1, "The private is not owned by channel %s anymore.\n", chan->name); + sip_pvt_unlock(p); + ast_channel_unlock(chan); + return 0; + } /* Disable early RTP bridge */ if ((instance || vinstance || tinstance) && @@ -28821,25 +29070,10 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i return 0; } - /* - * Lock both the pvt and it's owner safely. - */ - sip_pvt_lock(p); - while (p->owner && ast_channel_trylock(p->owner)) { - sip_pvt_unlock(p); - usleep(1); - sip_pvt_lock(p); - } - - if (!p->owner) { - sip_pvt_unlock(p); - return 0; - } - if (p->alreadygone) { /* If we're destroyed, don't bother */ - ast_channel_unlock(p->owner); sip_pvt_unlock(p); + ast_channel_unlock(chan); return 0; } @@ -28847,8 +29081,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i that are known to be behind a NAT, then stop the process now */ if (nat_active && !ast_test_flag(&p->flags[0], SIP_DIRECT_MEDIA_NAT)) { - ast_channel_unlock(p->owner); sip_pvt_unlock(p); + ast_channel_unlock(chan); return 0; } @@ -28890,8 +29124,8 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp_instance *i } /* Reset lastrtprx timer */ p->lastrtprx = p->lastrtptx = time(NULL); - ast_channel_unlock(p->owner); sip_pvt_unlock(p); + ast_channel_unlock(chan); return 0; } @@ -29892,6 +30126,7 @@ static int load_module(void) if (!(sip_tech.capabilities = ast_format_cap_alloc())) { return AST_MODULE_LOAD_FAILURE; } + /* the fact that ao2_containers can't resize automatically is a major worry! */ /* if the number of objects gets above MAX_XXX_BUCKETS, things will slow down */ peers = ao2_t_container_alloc(HASH_PEER_SIZE, peer_hash_cb, peer_cmp_cb, "allocate peers"); @@ -29900,6 +30135,11 @@ static int load_module(void) dialogs_needdestroy = ao2_t_container_alloc(HASH_DIALOG_SIZE, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs_needdestroy"); dialogs_rtpcheck = ao2_t_container_alloc(HASH_DIALOG_SIZE, dialog_hash_cb, dialog_cmp_cb, "allocate dialogs for rtpchecks"); threadt = ao2_t_container_alloc(HASH_DIALOG_SIZE, threadt_hash_cb, threadt_cmp_cb, "allocate threadt table"); + if (!peers || !peers_by_ip || !dialogs || !dialogs_needdestroy || !dialogs_rtpcheck + || !threadt) { + ast_log(LOG_ERROR, "Unable to create primary SIP container(s)\n"); + return AST_MODULE_LOAD_FAILURE; + } if (!(sip_cfg.caps = ast_format_cap_alloc())) { return AST_MODULE_LOAD_FAILURE; @@ -29923,7 +30163,7 @@ static int load_module(void) sip_reloadreason = CHANNEL_MODULE_LOAD; can_parse_xml = sip_is_xml_parsable(); - if(reload_config(sip_reloadreason)) { /* Load the configuration from sip.conf */ + if (reload_config(sip_reloadreason)) { /* Load the configuration from sip.conf */ return AST_MODULE_LOAD_DECLINE; } @@ -30133,7 +30373,12 @@ static int unload_module(void) /* Free memory for local network address mask */ ast_free_ha(localaddr); - clear_realm_authentication(authl); + ast_mutex_lock(&authl_lock); + if (authl) { + ao2_t_ref(authl, -1, "Removing global authentication"); + authl = NULL; + } + ast_mutex_unlock(&authl_lock); destroy_escs(); diff --git a/channels/sip/include/sip.h b/channels/sip/include/sip.h index e8dba3067..f5cf93d2b 100644 --- a/channels/sip/include/sip.h +++ b/channels/sip/include/sip.h @@ -745,7 +745,6 @@ struct sip_socket { struct sip_request { ptrdiff_t rlPart1; /*!< Offset of the SIP Method Name or "SIP/2.0" protocol version */ ptrdiff_t rlPart2; /*!< Offset of the Request URI or Response Status */ - int len; /*!< bytes used in data[], excluding trailing null terminator. Rarely used. */ int headers; /*!< # of SIP Headers */ int method; /*!< Method of this request */ int lines; /*!< Body Content */ @@ -830,11 +829,16 @@ struct sip_history { /*! \brief sip_auth: Credentials for authentication to other SIP services */ struct sip_auth { + AST_LIST_ENTRY(sip_auth) node; char realm[AST_MAX_EXTENSION]; /*!< Realm in which these credentials are valid */ char username[256]; /*!< Username */ char secret[256]; /*!< Secret */ char md5secret[256]; /*!< MD5Secret */ - struct sip_auth *next; /*!< Next auth structure in list */ +}; + +/*! \brief Container of SIP authentication credentials. */ +struct sip_auth_container { + AST_LIST_HEAD_NOLOCK(, sip_auth) list; }; /*! \brief T.38 channel settings (at some point we need to make this alloc'ed */ @@ -1047,7 +1051,7 @@ struct sip_pvt { struct ast_channel *owner; /*!< Who owns us (if we have an owner) */ struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */ struct sip_notify *notify; /*!< Custom notify type */ - struct sip_auth *peerauth; /*!< Realm authentication */ + struct sip_auth_container *peerauth;/*!< Realm authentication credentials */ int noncecount; /*!< Nonce-count */ unsigned int stalenonce:1; /*!< Marks the current nonce as responded too */ char lastmsg[256]; /*!< Last Message sent/received */ @@ -1144,7 +1148,6 @@ struct sip_pkt { struct timeval time_sent; /*!< When pkt was sent */ int64_t retrans_stop_time; /*!< Time in ms after 'now' that retransmission must stop */ int retrans_stop; /*!< Timeout is reached, stop retransmission */ - int packetlen; /*!< Length of packet */ struct ast_str *data; }; @@ -1211,7 +1214,7 @@ struct sip_peer { * for incoming calls */ unsigned short deprecated_username:1; /*!< If it's a realtime peer, are they using the deprecated "username" instead of "defaultuser" */ - struct sip_auth *auth; /*!< Realm authentication list */ + struct sip_auth_container *auth;/*!< Realm authentication credentials */ int amaflags; /*!< AMA Flags (for billing) */ int callingpres; /*!< Calling id presentation */ int inUse; /*!< Number of calls in use */ diff --git a/channels/sip/reqresp_parser.c b/channels/sip/reqresp_parser.c index 6c7031730..37d77d418 100644 --- a/channels/sip/reqresp_parser.c +++ b/channels/sip/reqresp_parser.c @@ -1029,14 +1029,14 @@ int get_in_brackets_full(char *tmp,char **out,char **residue) only affects token based display-names there is no danger of brackets being in quotes */ if (first_bracket) { parse = first_bracket; - } else { + } else { parse = tmp; } if ((second_bracket = strchr(parse, '>'))) { *second_bracket++ = '\0'; if (out) { - *out = first_bracket; + *out = (char *) parse; } if (residue) { *residue = second_bracket; @@ -1045,9 +1045,9 @@ int get_in_brackets_full(char *tmp,char **out,char **residue) } if ((first_bracket)) { - ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp); + ast_log(LOG_WARNING, "No closing bracket found in '%s'\n", tmp); return -1; - } + } if (out) { *out = tmp; @@ -1076,6 +1076,7 @@ AST_TEST_DEFINE(get_in_brackets_test) char name_no_quotes[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>"; char no_end_bracket[] = "name not in quotes <sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah"; char no_name_no_brackets[] = "sip:name@host"; + char missing_start_bracket[] = "name not in quotes sip:name:secret@host:port;transport=tcp?headers=testblah&headers2=blahblah>"; char *uri = NULL; switch (cmd) { @@ -1140,6 +1141,13 @@ AST_TEST_DEFINE(get_in_brackets_test) res = AST_TEST_FAIL; } + /* Test 8, no start bracket, but with ending bracket. */ + if (!(uri = get_in_brackets(missing_start_bracket)) || !(strcmp(uri, in_brackets))) { + + ast_test_status_update(test, "Test 8 failed. %s\n", uri); + res = AST_TEST_FAIL; + } + return res; } |