Provide authentication for BYE and CANCEL requests
authorMark Spencer <markster@digium.com>
Mon, 7 Apr 2003 03:46:20 +0000 (03:46 +0000)
committerMark Spencer <markster@digium.com>
Mon, 7 Apr 2003 03:46:20 +0000 (03:46 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@764 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index bb57ad5..e924d3a 100755 (executable)
@@ -190,6 +190,8 @@ static struct sip_pvt {
        char callerid[256];                                     /* Caller*ID */
        char via[256];
        char accountcode[256];                          /* Account code */
+       char realm[256];                                /* Authorization realm */
+       char nonce[256];                                /* Authorization nonce */
        int amaflags;                                           /* AMA Flags */
        struct sip_request initreq;                     /* Initial request */
        
@@ -328,6 +330,7 @@ static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *r
 static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
 static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *rand, int reliable);
 static int transmit_request(struct sip_pvt *p, char *msg, int inc, int reliable);
+static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int reliable);
 static int transmit_invite(struct sip_pvt *p, char *msg, int sendsdp, char *auth, char *vxml_url);
 static int transmit_reinvite_with_sdp(struct sip_pvt *p, struct ast_rtp *rtp);
 static int transmit_info_with_digit(struct sip_pvt *p, char digit);
@@ -335,6 +338,7 @@ static int transmit_message_with_text(struct sip_pvt *p, char *text);
 static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req);
 char *getsipuri(char *header);
 static void free_old_route(struct sip_route *route);
+static int build_reply_digest(struct sip_pvt *p, char *orig_header, char *digest, int digest_len);
 
 static int __sip_xmit(struct sip_pvt *p, char *data, int len)
 {
@@ -901,7 +905,7 @@ static int sip_hangup(struct ast_channel *ast)
        if (!p->alreadygone && strlen(p->initreq.data)) {
                if (needcancel) {
                        if (p->outgoing) {
-                               transmit_request(p, "CANCEL", 0, 1);
+                               transmit_request_with_auth(p, "CANCEL", 0, 1);
                                /* Actually don't destroy us yet, wait for the 487 on our original 
                                   INVITE, but do set an autodestruct just in case. */
                                p->needdestroy = 0;
@@ -910,7 +914,7 @@ static int sip_hangup(struct ast_channel *ast)
                                transmit_response_reliable(p, "403 Forbidden", &p->initreq);
                } else {
                        /* Send a hangup */
-                       transmit_request(p, "BYE", 1, 1);
+                       transmit_request_with_auth(p, "BYE", 1, 1);
                }
        }
        ast_pthread_mutex_unlock(&p->lock);
@@ -2543,6 +2547,23 @@ static int transmit_request(struct sip_pvt *p, char *msg, int inc, int reliable)
        return send_request(p, &resp, reliable, p->ocseq);
 }
 
+static int transmit_request_with_auth(struct sip_pvt *p, char *msg, int inc, int reliable)
+{
+       struct sip_request resp;
+       reqprep(&resp, p, msg, inc);
+       if (*p->realm)
+       {
+               char digest[256];
+               memset(digest,0,sizeof(digest));
+               build_reply_digest(p, msg, digest, sizeof(digest));
+               add_header(&resp, "Proxy-Authorization", digest);
+       }
+
+       add_header(&resp, "Content-Length", "0");
+       add_blank_header(&resp);
+       return send_request(p, &resp, reliable, p->ocseq);      
+}
+
 static int expire_register(void *data)
 {
        struct sip_peer *p = data;
@@ -3495,13 +3516,6 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
        char *realm = "";
        char *nonce = "";
        char *c;
-       char a1[256];
-       char a2[256];
-       char a1_hash[256];
-       char a2_hash[256];
-       char resp[256];
-       char resp_hash[256];
-       char uri[256] = "";
 
 
        strncpy(tmp, get_header(req, header),sizeof(tmp) - 1);
@@ -3511,53 +3525,67 @@ static int reply_digest(struct sip_pvt *p, struct sip_request *req, char *header
                while (*c && (*c < 33)) c++;
                if (!*c)
                        break;
-                       if (!strncasecmp(c,"realm=", strlen("realm="))) {
-                               c+=strlen("realm=");
-                               if ((*c == '\"')) {
-                                       realm=++c;
-                                       if ((c = strchr(c,'\"')))
-                                               *c = '\0';
-                               } else {
-                                       realm = c;
-                                       if ((c = strchr(c,',')))
-                                               *c = '\0';
-                               }
-
-                       } else if (!strncasecmp(c, "nonce=", strlen("nonce="))) {
-                               c+=strlen("nonce=");
-                               if ((*c == '\"')) {
-                                       nonce=++c;
-                                       if ((c = strchr(c,'\"')))
-                                               *c = '\0';
-                               } else {
-                                       nonce = c;
-                                       if ((c = strchr(c,',')))
-                                               *c = '\0';
-                               }
-                       } else
-                               c = strchr(c,',');
-                       if (c)
-                               c++;
+               if (!strncasecmp(c,"realm=", strlen("realm="))) {
+                       c+=strlen("realm=");
+                       if ((*c == '\"')) {
+                               realm=++c;
+                               if ((c = strchr(c,'\"')))
+                                       *c = '\0';
+                       } else {
+                               realm = c;
+                               if ((c = strchr(c,',')))
+                                       *c = '\0';
                        }
+               } else if (!strncasecmp(c, "nonce=", strlen("nonce="))) {
+                       c+=strlen("nonce=");
+                       if ((*c == '\"')) {
+                               nonce=++c;
+                               if ((c = strchr(c,'\"')))
+                                       *c = '\0';
+                       } else {
+                               nonce = c;
+                               if ((c = strchr(c,',')))
+                                       *c = '\0';
+                       }
+               } else
+                       c = strchr(c,',');
+               if (c)
+                       c++;
+       }
+
+       /* copy realm and nonce for later authorization of CANCELs and BYEs */
+       strncpy(p->realm, realm, sizeof(p->realm)-1);
+       strncpy(p->nonce, nonce, sizeof(p->nonce)-1);
+
+       build_reply_digest(p, orig_header, digest, digest_len); 
+       return 0;
+}
+
+static int build_reply_digest(struct sip_pvt *p, char* orig_header, char* digest, int digest_len)
+{
+        char a1[256];
+       char a2[256];
+       char a1_hash[256];
+       char a2_hash[256];
+       char resp[256];
+       char resp_hash[256];
+       char uri[256] = "";
 
-       /* Okay.  We've got the realm and nonce from the server.  Now lets build the MD5 digest. */
        snprintf(uri, sizeof(uri), "sip:%s@%s",p->username, inet_ntoa(p->sa.sin_addr));
 
-       snprintf(a1,sizeof(a1),"%s:%s:%s",p->peername,realm,p->peersecret);
+       snprintf(a1,sizeof(a1),"%s:%s:%s",p->peername,p->realm,p->peersecret);
        snprintf(a2,sizeof(a2),"%s:%s",orig_header,uri);
        md5_hash(a1_hash,a1);
        md5_hash(a2_hash,a2);
-       snprintf(resp,sizeof(resp),"%s:%s:%s",a1_hash,nonce,a2_hash);
+       snprintf(resp,sizeof(resp),"%s:%s:%s",a1_hash,p->nonce,a2_hash);
        md5_hash(resp_hash,resp);
 
-       snprintf(digest,digest_len,"Digest username=\"%s\", realm=\"%s\", algorithm=\"MD5\", uri=\"%s\", nonce=\"%s\", response=\"%s\"",p->peername,realm,uri,nonce,resp_hash);
+       snprintf(digest,digest_len,"Digest username=\"%s\", realm=\"%s\", algorithm=\"MD5\", uri=\"%s\", nonce=\"%s\", response=\"%s\"",p->peername,p->realm,uri,p->nonce,resp_hash);
 
        return 0;
 }
        
 
-       
-       
 
 
 static char show_users_usage[] = 
@@ -4159,7 +4187,7 @@ static int handle_request(struct sip_pvt *p, struct sip_request *req, struct soc
                                }
                        }
                        /* Always increment on a BYE */
-                       transmit_request(p, "BYE", 1, 1);
+                       transmit_request_with_auth(p, "BYE", 1, 1);
                        p->alreadygone = 1;
                }
        } else if (!strcasecmp(cmd, "CANCEL")) {