Provide authentication for BYE and CANCEL requests

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@764 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Mark Spencer 2003-04-07 03:46:20 +00:00
parent 85cb2844aa
commit 1680ccf66c
1 changed files with 71 additions and 43 deletions

View File

@ -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")) {