diff options
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r-- | channels/chan_sip.c | 49 |
1 files changed, 35 insertions, 14 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 7254bf736..8d0b51971 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -1512,7 +1512,7 @@ static int handle_request_cancel(struct sip_pvt *p, struct sip_request *req); static int handle_request_message(struct sip_pvt *p, struct sip_request *req); static int handle_request_subscribe(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e); static void handle_request_info(struct sip_pvt *p, struct sip_request *req); -static int handle_request_options(struct sip_pvt *p, struct sip_request *req); +static int handle_request_options(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e); static int handle_invite_replaces(struct sip_pvt *p, struct sip_request *req, int debug, int seqno, struct ast_sockaddr *addr, int *nounlock); static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, int seqno, const char *e); static int local_attended_transfer(struct sip_pvt *transferer, struct sip_dual *current, struct sip_request *req, int seqno, int *nounlock); @@ -7054,6 +7054,7 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, char *sent_by, *branch; const char *cseq = get_header(req, "Cseq"); unsigned int seqno; + /* get branch parameter from initial Request that started this dialog */ get_viabranch(ast_strdupa(get_header(req, "Via")), &sent_by, &branch); /* only store the branch if it begins with the magic prefix "z9hG4bK", otherwise @@ -7068,7 +7069,8 @@ struct sip_pvt *sip_alloc(ast_string_field callid, struct ast_sockaddr *addr, if (!ast_strlen_zero(cseq) && (sscanf(cseq, "%30u", &seqno) == 1)) { p->init_icseq = seqno; } - set_socket_transport(&p->socket, req->socket.type); /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */ + /* Later in ast_sip_ouraddrfor we need this to choose the right ip and port for the specific transport */ + set_socket_transport(&p->socket, req->socket.type); } else { set_socket_transport(&p->socket, SIP_TRANSPORT_UDP); } @@ -20500,19 +20502,10 @@ static int handle_request_notify(struct sip_pvt *p, struct sip_request *req, str /*! \brief Handle incoming OPTIONS request An OPTIONS request should be answered like an INVITE from the same UA, including SDP */ -static int handle_request_options(struct sip_pvt *p, struct sip_request *req) +static int handle_request_options(struct sip_pvt *p, struct sip_request *req, struct ast_sockaddr *addr, const char *e) { int res; - - /*! XXX get_destination assumes we're already authenticated. This means that a request from - a known device (peer) will end up in the wrong context if this is out-of-dialog. - However, we want to handle OPTIONS as light as possible, so we might want to have - a configuration option whether we care or not. Some devices use this for testing - capabilities, which means that we need to match device to answer with proper - capabilities (including SDP). - \todo Fix handle_request_options device handling with optional authentication - (this needs to be fixed in 1.4 as well) - */ + struct sip_peer *authpeer = NULL; /* Matching Peer */ if (p->lastinvite) { /* if this is a request in an active dialog, just confirm that the dialog exists. */ @@ -20520,6 +20513,29 @@ static int handle_request_options(struct sip_pvt *p, struct sip_request *req) return 0; } + if (sip_cfg.auth_options_requests) { + /* Do authentication if this OPTIONS request began the dialog */ + copy_request(&p->initreq, req); + set_pvt_allowed_methods(p, req); + res = check_user_full(p, req, SIP_OPTIONS, e, XMIT_UNRELIABLE, addr, &authpeer); + if (res == AUTH_CHALLENGE_SENT) { + sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); + return 0; + } + if (res < 0) { /* Something failed in authentication */ + if (res == AUTH_FAKE_AUTH) { + ast_log(LOG_NOTICE, "Sending fake auth rejection for device %s\n", get_header(req, "From")); + transmit_fake_auth_response(p, SIP_OPTIONS, req, XMIT_UNRELIABLE); + } else { + ast_log(LOG_NOTICE, "Failed to authenticate device %s\n", get_header(req, "From")); + transmit_response(p, "403 Forbidden", req); + } + sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); + return 0; + } + } + + /* must go through authentication before getting here */ res = (get_destination(p, req, NULL) == SIP_GET_DEST_EXTEN_FOUND ? 0 : -1); build_contact(p); @@ -23546,7 +23562,7 @@ static int handle_incoming(struct sip_pvt *p, struct sip_request *req, struct as /* Handle various incoming SIP methods in requests */ switch (p->method) { case SIP_OPTIONS: - res = handle_request_options(p, req); + res = handle_request_options(p, req, addr, e); break; case SIP_INVITE: res = handle_request_invite(p, req, debug, seqno, addr, recount, e, nounlock); @@ -26390,6 +26406,7 @@ static int reload_config(enum channelreloadreason reason) sip_cfg.notifyhold = FALSE; /*!< Keep track of hold status for a peer */ sip_cfg.directrtpsetup = FALSE; /* Experimental feature, disabled by default */ sip_cfg.alwaysauthreject = DEFAULT_ALWAYSAUTHREJECT; + sip_cfg.auth_options_requests = 1; sip_cfg.allowsubscribe = FALSE; sip_cfg.disallowed_methods = SIP_UNKNOWN; sip_cfg.contact_ha = NULL; /* Reset the contact ACL */ @@ -26630,6 +26647,10 @@ static int reload_config(enum channelreloadreason reason) } } else if (!strcasecmp(v->name, "alwaysauthreject")) { sip_cfg.alwaysauthreject = ast_true(v->value); + } else if (!strcasecmp(v->name, "auth_options_requests")) { + if (ast_false(v->value)) { + sip_cfg.auth_options_requests = 0; + } } else if (!strcasecmp(v->name, "mohinterpret")) { ast_copy_string(default_mohinterpret, v->value, sizeof(default_mohinterpret)); } else if (!strcasecmp(v->name, "mohsuggest")) { |