]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
authenticate OPTIONS requests just like we would an INVITE
authorDavid Vossel <dvossel@digium.com>
Fri, 3 Sep 2010 17:29:02 +0000 (17:29 +0000)
committerDavid Vossel <dvossel@digium.com>
Fri, 3 Sep 2010 17:29:02 +0000 (17:29 +0000)
OPTIONS requests should be treated the same as an INVITE
This includes authentication.  This patch adds the ability for
incoming out of dialog OPTION requests to be authenticated
before providing a response indicating whether an extension
is available or not.  The authentication routine works the
exact same way as it does for incoming INVITEs.  This means
that if a peer has 'insecure=invite' in their peer definition,
the same will be true for the processing of the OPTIONS request.

Review: https://reviewboard.asterisk.org/r/881/

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.8@284950 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
channels/chan_sip.c
channels/sip/include/sip.h
configs/sip.conf.sample

diff --git a/CHANGES b/CHANGES
index 681d7f0f575a823a9f46b69e95f5404b1a9a3d5c..2f63402fbc327c78f34c79fa218cd8f898645eaf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -75,6 +75,9 @@ SIP Changes
    available in device configurations as well as in the dial plan.
  * Addition of the 'subscribe_network_change' option for turning on and off
    res_stun_monitor module support in chan_sip.
+ * Addition of the 'auth_options_requests' option for turning on and off
+   authentication for OPTIONS requests in chan_sip.
+
 
 IAX2 Changes
 -----------
index d74d041c055e75b18b9d0a241d6087257f3f6376..08a803a635fd28917b601752ceb72c057c487b84 100644 (file)
@@ -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);
        }
@@ -20466,19 +20468,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. */
@@ -20486,6 +20479,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);
 
@@ -23512,7 +23528,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);
@@ -26356,6 +26372,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 */
@@ -26596,6 +26613,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")) {
index 9fa37a4d48698544eeddcd7d751920134c130300..2f4411550397e3c0217ac483bb2defc75d09e2d0 100644 (file)
@@ -674,6 +674,7 @@ struct sip_settings {
        int srvlookup;              /*!< SRV Lookup on or off. Default is on */
        int allowguest;             /*!< allow unauthenticated peers to connect? */
        int alwaysauthreject;       /*!< Send 401 Unauthorized for all failing requests */
+       int auth_options_requests;  /*!< Authenticate OPTIONS requests */
        int compactheaders;         /*!< send compact sip headers */
        int allow_external_domains; /*!< Accept calls to external SIP domains? */
        int callevents;             /*!< Whether we send manager events or not */
index b0c7e8d3286b49d3bada262bdbc54290017caecb..08ce0ba778b297c96107656adab9c299af47b5b6 100644 (file)
@@ -370,6 +370,14 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
                                 ; the ability of an attacker to scan for valid SIP usernames.
                                 ; This option is set to "yes" by default.
 
+;auth_options_requests = no     ; sip OPTIONS requests should be treated the exact same as
+                                ; an INVITE, this includes performing authentication.  By default
+                                ; OPTIONS requests are authenticated, however this option allows
+                                ; OPTION requests to proceed unauthenticated in order to increase
+                                ; performance. This may be desirable if OPTIONS are only used to
+                                ; qualify the availabilty of the endpoint/extension.  Disabling
+                                ; this option is not recommended.
+
 ;g726nonstandard = yes          ; If the peer negotiates G726-32 audio, use AAL2 packing
                                 ; order instead of RFC3551 packing order (this is required
                                 ; for Sipura and Grandstream ATAs, among others). This is