summaryrefslogtreecommitdiff
path: root/channels/chan_sip.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r--channels/chan_sip.c32
1 files changed, 25 insertions, 7 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index ed12bf282..e81796af5 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1809,6 +1809,7 @@ struct sip_pvt {
struct ast_variable *notify_headers; /*!< Custom notify type */
struct sip_auth *peerauth; /*!< Realm authentication */
int noncecount; /*!< Nonce-count */
+ unsigned int stalenonce:1; /*!< Marks the current nonce as responded too */
char lastmsg[256]; /*!< Last Message sent/received */
int amaflags; /*!< AMA Flags */
int pendinginvite; /*!< Any pending INVITE or state NOTIFY (in subscribe pvt's) ? (seqno of this) */
@@ -12505,6 +12506,20 @@ static void build_route(struct sip_pvt *p, struct sip_request *req, int backward
list_route(p->route);
}
+/*! \brief builds the sip_pvt's randdata field which is used for the nonce
+ * challenge. When forceupdate is not set, the nonce is only updated if
+ * the current one is stale. In this case, a stalenonce is one which
+ * has already received a response, if a nonce has not received a response
+ * it is not always necessary or beneficial to create a new one. */
+
+static void set_nonce_randdata(struct sip_pvt *p, int forceupdate)
+{
+ if (p->stalenonce || forceupdate || ast_strlen_zero(p->randdata)) {
+ ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
+ p->stalenonce = 0;
+ }
+}
+
AST_THREADSTORAGE(check_auth_buf);
#define CHECK_AUTH_BUF_INITLEN 256
@@ -12570,7 +12585,7 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
return AUTH_CHALLENGE_SENT;
} else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
/* We have no auth, so issue challenge and request authentication */
- ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
+ set_nonce_randdata(p, 1); /* Create nonce for challenge */
transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
/* Schedule auto destroy in 32 seconds */
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -12621,10 +12636,13 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
return AUTH_USERNAME_MISMATCH;
}
- /* Verify nonce from request matches our nonce. If not, send 401 with new nonce */
- if (strcasecmp(p->randdata, keys[K_NONCE].s)) { /* XXX it was 'n'casecmp ? */
+ /* Verify nonce from request matches our nonce, and the nonce has not already been responded to.
+ * If this check fails, send 401 with new nonce */
+ if (strcasecmp(p->randdata, keys[K_NONCE].s) || p->stalenonce) { /* XXX it was 'n'casecmp ? */
wrongnonce = TRUE;
usednonce = keys[K_NONCE].s;
+ } else {
+ p->stalenonce = 1; /* now, since the nonce has a response, mark it as stale so it can't be sent or responded to again */
}
if (!ast_strlen_zero(md5secret))
@@ -12655,14 +12673,14 @@ static enum check_auth_result check_auth(struct sip_pvt *p, struct sip_request *
if (sipdebug)
ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", get_header(req, "To"));
/* We got working auth token, based on stale nonce . */
- ast_string_field_build(p, randdata, "%08lx", ast_random());
+ set_nonce_randdata(p, 0);
transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, TRUE);
} else {
/* Everything was wrong, so give the device one more try with a new challenge */
if (!req->ignore) {
if (sipdebug)
ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", get_header(req, "To"));
- ast_string_field_build(p, randdata, "%08lx", ast_random());
+ set_nonce_randdata(p, 1);
} else {
if (sipdebug)
ast_log(LOG_NOTICE, "Duplicate authentication received from '%s'\n", get_header(req, "To"));
@@ -12795,7 +12813,7 @@ static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct
return;
} else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
/* We have no auth, so issue challenge and request authentication */
- ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
+ set_nonce_randdata(p, 1);
transmit_response_with_auth(p, response, req, p->randdata, 0, respheader, 0);
/* Schedule auto destroy in 32 seconds */
sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -12840,7 +12858,7 @@ static void transmit_fake_auth_response(struct sip_pvt *p, int sipmethod, struct
/* Verify nonce from request matches our nonce. If not, send 401 with new nonce */
if (strcasecmp(p->randdata, keys[K_NONCE].s)) {
if (!req->ignore) {
- ast_string_field_build(p, randdata, "%08lx", ast_random());
+ set_nonce_randdata(p, 1);
}
transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, FALSE);