]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Re-use SIP authentication, aka "The Broadvoice patch" (bug #2917)
authorRussell Bryant <russell@russellbryant.com>
Thu, 30 Dec 2004 18:30:23 +0000 (18:30 +0000)
committerRussell Bryant <russell@russellbryant.com>
Thu, 30 Dec 2004 18:30:23 +0000 (18:30 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4604 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index 764e4a1055c04a4d3f35eb9240fec5689a2cacb8..fef65193079c9b92fbf77a0535f6203811c3471d 100755 (executable)
@@ -323,7 +323,7 @@ static struct sip_pvt {
        char nonce[256];                        /* Authorization nonce */
        char opaque[256];                       /* Opaque nonsense */
        char qop[80];                           /* Quality of Protection, since SIP wasn't complicated enough yet. */
-       char domain[256];                       /* Authorization nonce */
+       char domain[256];                       /* Authorization domain */
        char lastmsg[256];                      /* Last Message sent/received */
        int amaflags;                           /* AMA Flags */
        int pendinginvite;                      /* Any pending invite */
@@ -510,6 +510,15 @@ struct sip_registry {
        char callid[80];                /* Global CallID for this registry */
        unsigned int ocseq;             /* Sequence number we got to for REGISTERs for this registry */
        struct sockaddr_in us;          /* Who the server thinks we are */
+       
+                                       /* Saved headers */
+       char realm[256];                /* Authorization realm */
+       char nonce[256];                /* Authorization nonce */
+       char domain[256];               /* Authorization domain */
+       char opaque[256];               /* Opaque nonsense */
+       char qop[80];                   /* Quality of Protection. */
+       char lastmsg[256];              /* Last Message sent/received */
        struct sip_registry *next;
 };
 
@@ -3981,6 +3990,10 @@ static int sip_reregister(void *data)
 {
        /* if we are here, we know that we need to reregister. */
        struct sip_registry *r=(struct sip_registry *)data;
+
+       if (sipdebug)
+               ast_log(LOG_NOTICE, "   -- Re-registration for  %s@%s\n", r->username, r->hostname);
+
        ast_mutex_lock(&regl.lock);
        r->expire = -1;
        __sip_do_register(r);
@@ -3999,12 +4012,15 @@ static int __sip_do_register(struct sip_registry *r)
 /*--- sip_reg_timeout: Registration timeout, register again */
 static int sip_reg_timeout(void *data)
 {
+
        /* if we are here, our registration timed out, so we'll just do it over */
        struct sip_registry *r=data;
        struct sip_pvt *p;
        int res;
+
        ast_mutex_lock(&regl.lock);
-       ast_log(LOG_NOTICE, "Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname); 
+
+       ast_log(LOG_NOTICE, "   -- Registration for '%s@%s' timed out, trying again\n", r->username, r->hostname); 
        if (r->call) {
                /* Unlink us, destroy old call.  Locking is not relevent here because all this happens
                   in the single SIP manager thread. */
@@ -4016,14 +4032,14 @@ static int sip_reg_timeout(void *data)
                __sip_pretend_ack(p);
        }
        r->regstate=REG_STATE_UNREGISTERED;
-       manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nDomain: %s\r\nStatus: %s\r\n", r->hostname, regstate2str(r->regstate));
+       manager_event(EVENT_FLAG_SYSTEM, "Registry", "Channel: SIP\r\nUser: %s\r\nDomain: %s\r\nStatus: %s\r\n", r->username, r->hostname, regstate2str(r->regstate));
        r->timeout = -1;
        res=transmit_register(r, "REGISTER", NULL, NULL);
        ast_mutex_unlock(&regl.lock);
        return 0;
 }
 
-/*--- transmit_register: Transmit register to SIP proxy ---*/
+/*--- transmit_register: Transmit register to SIP proxy or UA ---*/
 static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char *authheader)
 {
        struct sip_request req;
@@ -4048,31 +4064,37 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
                } else
                        p = r->call;
        } else {
+               /* Build callid for registration if we haven't registred before */
                if (!r->callid_valid) {
                        build_callid(r->callid, sizeof(r->callid), __ourip, default_fromdomain);
                        r->callid_valid = 1;
                }
+               /* Allocate SIP packet for registration */
                p=sip_alloc( r->callid, NULL, 0);
                if (!p) {
                        ast_log(LOG_WARNING, "Unable to allocate registration call\n");
                        return 0;
                }
+               /* Find address to hostname */
                if (create_addr(p,r->hostname)) {
                        sip_destroy(p);
                        return 0;
                }
+
                /* Copy back Call-ID in case create_addr changed it */
                strncpy(r->callid, p->callid, sizeof(r->callid) - 1);
                if (r->portno)
                        p->sa.sin_port = htons(r->portno);
-               p->outgoing = 1;
-               r->call=p;
-               p->registry=r;
-               if (!ast_strlen_zero(r->secret))
+               p->outgoing = 1;                /* Registration is outgoing call */
+               r->call=p;                      /* Save pointer to SIP packet */
+               p->registry=r;                  /* Add pointer to registry in packet */
+               if (!ast_strlen_zero(r->secret))        /* Secret (password) */
                        strncpy(p->peersecret, r->secret, sizeof(p->peersecret)-1);
                if (!ast_strlen_zero(r->md5secret))
                        strncpy(p->peermd5secret, r->md5secret, sizeof(p->peermd5secret)-1);
-               if (!ast_strlen_zero(r->authuser)) {
+               /* User name in this realm  
+               - if authuser is set, use that, otherwise use username */
+               if (!ast_strlen_zero(r->authuser)) {    
                        strncpy(p->peername, r->authuser, sizeof(p->peername)-1);
                        strncpy(p->authname, r->authuser, sizeof(p->authname)-1);
                } else {
@@ -4084,6 +4106,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
                }
                if (!ast_strlen_zero(r->username))
                        strncpy(p->username, r->username, sizeof(p->username)-1);
+               /* Save extension in packet */
                strncpy(p->exten, r->contact, sizeof(p->exten) - 1);
 
                /*
@@ -4099,11 +4122,11 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        /* set up a timeout */
        if (auth==NULL)  {
                if (r->timeout > -1) {
-                       ast_log(LOG_WARNING, "Still have a timeout, %d\n", r->timeout);
+                       ast_log(LOG_WARNING, "Still have a registration timeout, %d\n", r->timeout);    
                        ast_sched_del(sched, r->timeout);
                }
                r->timeout = ast_sched_add(sched, 20*1000, sip_reg_timeout, r);
-               ast_log(LOG_DEBUG, "Scheduled a timeout # %d\n", r->timeout);
+               ast_log(LOG_DEBUG, "Scheduled a registration timeout # %d\n", r->timeout);      
        }
 
        if (strchr(r->username, '@')) {
@@ -4128,6 +4151,7 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        memset(&req, 0, sizeof(req));
        init_req(&req, cmd, addr);
 
+       /* Add to CSEQ */
        snprintf(tmp, sizeof(tmp), "%u %s", ++r->ocseq, cmd);
        p->ocseq = r->ocseq;
 
@@ -4142,8 +4166,27 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char
        add_header(&req, "Call-ID", p->callid);
        add_header(&req, "CSeq", tmp);
        add_header(&req, "User-Agent", default_useragent);
-       if (auth) 
+
+       
+       if (auth)       /* Add auth header */
                add_header(&req, authheader, auth);
+       else if ( !ast_strlen_zero(r->nonce) ) {
+               char digest[1024];
+
+               /* We have auth data to reuse, build a digest header! */
+               if (sipdebug)
+                       ast_log(LOG_DEBUG, "   >>> Re-using Auth data for %s@%s\n", r->username, r->hostname);
+               strncpy(p->realm, r->realm, sizeof(p->realm)-1);
+               strncpy(p->nonce, r->nonce, sizeof(p->nonce)-1);
+               strncpy(p->domain, r->domain, sizeof(p->domain)-1);
+               strncpy(p->opaque, r->opaque, sizeof(p->opaque)-1);
+               strncpy(p->qop, r->qop, sizeof(p->qop)-1);
+
+               memset(digest,0,sizeof(digest));
+               build_reply_digest(p, "REGISTER", digest, sizeof(digest));
+               add_header(&req, "Authorization", digest);
+       
+       }
 
        snprintf(tmp, sizeof(tmp), "%d", default_expiry);
        add_header(&req, "Expires", tmp);
@@ -4238,6 +4281,7 @@ static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int seqno, i
        if (*p->realm)
        {
                char digest[1024];
+
                memset(digest,0,sizeof(digest));
                build_reply_digest(p, msg, digest, sizeof(digest));
                add_header(&resp, "Proxy-Authorization", digest);
@@ -6179,27 +6223,34 @@ static int sip_no_debug(int fd, int argc, char *argv[])
 
 static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, char *digest, int digest_len);
 
-/*--- do_register_auth: Challenge for registration ---*/
+/*--- do_register_auth: Authenticate for outbound registration ---*/
 static int do_register_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader) {
        char digest[1024];
        p->authtries++;
        memset(digest,0,sizeof(digest));
-       if (reply_digest(p,req, header, "REGISTER", digest, sizeof(digest))) {
+       if (reply_digest(p, req, header, "REGISTER", digest, sizeof(digest))) {
                /* There's nothing to use for authentication */
+               /* No digest challenge in request */
+               if (sip_debug_test_pvt(p))
+                       ast_verbose("No authentication challenge, sending blank registration to domain/host name %s\n", p->registry->hostname);
+                       /* No old challenge */
                return -1;
        }
+       if (sip_debug_test_pvt(p))
+               ast_verbose("Responding to challenge, registration to domain/host name %s\n", p->registry->hostname);
        return transmit_register(p->registry,"REGISTER",digest, respheader); 
 }
 
-/*--- do_proxy_auth: Challenge user ---*/
+/*--- do_proxy_auth: Add authentication on outbound SIP packet ---*/
 static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, char *msg, int init) {
        char digest[1024];
        p->authtries++;
        memset(digest,0,sizeof(digest));
-       if (reply_digest(p,req, header, msg, digest, sizeof(digest) )) {
+       if (reply_digest(p, req, header, msg, digest, sizeof(digest) )) {       
                /* No way to authenticate */
                return -1;
        }
+       /* Now we have a reply digest */
        return transmit_invite(p,msg,!strcasecmp(msg, "INVITE"),digest, respheader, NULL,NULL,NULL, init); 
 }
 
@@ -6295,6 +6346,15 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
        strncpy(p->domain, domain, sizeof(p->domain)-1);
        strncpy(p->opaque, opaque, sizeof(p->opaque)-1);
        strncpy(p->qop, qop, sizeof(p->qop)-1);
+
+       /* Save auth data for following registrations */
+       if (p->registry) {
+               strncpy(p->registry->realm, realm, sizeof(p->realm)-1);
+               strncpy(p->registry->nonce, nonce, sizeof(p->nonce)-1);
+               strncpy(p->registry->domain, domain, sizeof(p->domain)-1);
+               strncpy(p->registry->opaque, opaque, sizeof(p->opaque)-1);
+               strncpy(p->registry->qop, qop, sizeof(p->qop)-1);
+       }
        build_reply_digest(p, orig_header, digest, digest_len); 
        return 0;
 }
@@ -6701,20 +6761,25 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                                        if (!expires) expires=atoi(get_header(req, "expires"));
                                        if (!expires) expires=default_expiry;
 
+
                                        expires_ms = expires * 1000;
                                        if (expires <= EXPIRY_GUARD_LIMIT)
                                                expires_ms -= MAX((expires_ms * EXPIRY_GUARD_PCT),EXPIRY_GUARD_MIN);
                                        else
                                                expires_ms -= EXPIRY_GUARD_SECS * 1000;
+                                       if (sipdebug)
+                                               ast_log(LOG_NOTICE, "Outbound Registration: Expiry for %s is %d sec (Scheduling reregistration in %d ms)\n", r->hostname, expires, expires_ms); 
 
                                        r->refresh= (int) expires_ms / 1000;
+
+                                       /* Schedule re-registration before we expire */
                                        r->expire=ast_sched_add(sched, expires_ms, sip_reregister, r); 
                                } else
                                        ast_log(LOG_WARNING, "Got 200 OK on REGISTER that isn't a register\n");
 
                        }
                        break;
-               case 401: /* Not authorized on REGISTER */
+               case 401: /* Not www-authorized on REGISTER */
                        if (!strcasecmp(msg, "INVITE")) {
                                /* First we ACK */
                                transmit_request(p, "ACK", seqno, 0, 0);
@@ -6731,6 +6796,21 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_
                        } else
                                p->needdestroy = 1;
                        break;
+               case 403: /* Forbidden - we failed authentication */
+                       if (!strcasecmp(msg, "INVITE")) {
+                               /* First we ACK */
+                               transmit_request(p, "ACK", seqno, 0, 0);
+                               ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for INVITE to '%s'\n", get_header(&p->initreq, "From"));
+                               if (owner)
+                                       ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+                               p->needdestroy = 1;
+                       } else if (p->registry && !strcasecmp(msg, "REGISTER")) {
+                               ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for REGISTER for '%s' to '%s'\n", p->registry->username, p->registry->hostname);
+                               p->needdestroy = 1;
+                       } else {
+                               ast_log(LOG_WARNING, "Forbidden - wrong password on authentication for %s\n", msg);
+                       }
+                       break;
                case 407:
                        if (!strcasecmp(msg, "INVITE")) {
                                /* First we ACK */