diff options
author | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-12-12 04:25:59 +0000 |
---|---|---|
committer | markster <markster@f38db490-d61c-443f-a65b-d21fe96a405b> | 2004-12-12 04:25:59 +0000 |
commit | 3f0d2ea849ac95ca80bbb68d4b5bcae806f48596 (patch) | |
tree | 9601b70ee8a3fe94126e1321ba0eaf4fb0bdf336 /channels | |
parent | a83c8caaf5d21694a29f02d8b85e4f0506edfeae (diff) |
Merge SIP authentication reuse patch (bug #2917) aka "The Broadvoice Patch" with modifications
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@4435 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels')
-rwxr-xr-x | channels/chan_sip.c | 116 |
1 files changed, 98 insertions, 18 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 7bdb91b42..97e844e7a 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -327,7 +327,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 */ @@ -522,6 +522,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; }; @@ -4039,6 +4048,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(®l.lock); r->expire = -1; __sip_do_register(r); @@ -4057,12 +4070,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(®l.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. */ @@ -4074,14 +4090,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(®l.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; @@ -4109,31 +4125,37 @@ static int transmit_register(struct sip_registry *r, char *cmd, char *auth, char p->theirtag[0]='\0'; /* forget their old tag, so we don't match tags when getting response */ } } 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 { @@ -4145,6 +4167,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); /* @@ -4160,11 +4183,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, global_reg_timeout*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, '@')) { @@ -4189,6 +4212,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; @@ -4203,8 +4227,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); @@ -4299,6 +4342,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); @@ -6293,27 +6337,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, 0, init); } @@ -6409,6 +6460,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; } @@ -6815,20 +6875,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); @@ -6845,7 +6910,22 @@ static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_ } else p->needdestroy = 1; break; - case 407: /* 407 Proxy Authentication Required */ + 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: /* Proxy auth required */ if (!strcasecmp(msg, "INVITE")) { /* First we ACK */ transmit_request(p, "ACK", seqno, 0, 0); |