Index: chan_sip.c =================================================================== --- channels/chan_sip.c (revision 8901) +++ channels/chan_sip.c (working copy) @@ -6188,13 +5990,11 @@ char *uri, int reliable, int ignore) { int res = -1; - char *response = "407 Proxy Authentication Required"; - char *reqheader = "Proxy-Authorization"; - char *respheader = "Proxy-Authenticate"; - char *authtoken; -#ifdef OSP_SUPPORT - char *osptoken; -#endif + const char *response = "407 Proxy Authentication Required"; + const char *reqheader = "Proxy-Authorization"; + const char *respheader = "Proxy-Authenticate"; + const char *authtoken; + /* Always OK if no secret */ if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret) #ifdef OSP_SUPPORT @@ -6213,6 +6013,7 @@ } #ifdef OSP_SUPPORT else { + char *osptoken; ast_log (LOG_DEBUG, "Checking OSP Authentication!\n"); osptoken = get_header (req, "P-OSP-Auth-Token"); switch (ast_test_flag (p, SIP_OSPAUTH)) { @@ -6220,29 +6021,23 @@ break; case SIP_OSPAUTH_GATEWAY: if (ast_strlen_zero (osptoken)) { - if (ast_strlen_zero (secret) && ast_strlen_zero (md5secret)) { + if (ast_strlen_zero(secret) && ast_strlen_zero (md5secret)) return 0; - } - } - else { + } else { return check_osptoken (p, osptoken); } break; case SIP_OSPAUTH_PROXY: - if (ast_strlen_zero (osptoken)) { + if (ast_strlen_zero (osptoken)) return 0; - } - else { + else return check_osptoken (p, osptoken); - } break; case SIP_OSPAUTH_EXCLUSIVE: - if (ast_strlen_zero (osptoken)) { + if (ast_strlen_zero (osptoken)) return -1; - } - else { + else return check_osptoken (p, osptoken); - } break; default: return -1; @@ -6272,115 +6067,90 @@ } else { /* Whoever came up with the authentication section of SIP can suck my %&#$&* for not putting an example in the spec of just what it is you're doing a hash on. */ - char a1[256]; - char a2[256]; char a1_hash[256]; - char a2_hash[256]; - char resp[256]; char resp_hash[256]=""; char tmp[256]; char *c; - char *z; - char *ua_hash =""; - char *resp_uri =""; - char *nonce = ""; - char *digestusername = ""; int wrongnonce = FALSE; - const char *usednonce = p->randdata; + int good_response; + const char *usednonce = p->randdata; /* XXX check */ - /* Find their response among the mess that we'r sent for comparison */ + /* table of recognised keywords, and their value in the digest */ + enum keys { K_RESP, K_URI, K_USER, K_NONCE, K_LAST }; + struct x { + const char *key; + const char *s; + } *i, keys[] = { + [K_RESP] = { "response=", "" }, + [K_URI] = { "uri=", "" }, + [K_USER] = { "username=", "" }, + [K_NONCE] = { "nonce=", "" }, + [K_LAST] = { NULL, NULL} + }; + + /* Make a copy of the response and parse it */ ast_copy_string(tmp, authtoken, sizeof(tmp)); c = tmp; - while(c) { - c = ast_skip_blanks(c); - if (!*c) - break; - if (!strncasecmp(c, "response=", strlen("response="))) { - c+= strlen("response="); - if ((*c == '\"')) { - ua_hash=++c; - if ((c = strchr(c,'\"'))) - *c = '\0'; + while(c && *(c = ast_skip_blanks(c)) ) { /* lookup for keys */ + for (i = keys; i->key != NULL; i++) { + const char *separator = ","; /* default */ - } else { - ua_hash=c; - if ((c = strchr(c,','))) - *c = '\0'; + if (strncasecmp(c, i->key, strlen(i->key)) != 0) + continue; + /* Found. Skip keyword, take text in quotes or up to the separator. */ + c += strlen(i->key); + if (*c == '"') { /* in quotes. Skip first and look for last */ + c++; + separator = "\""; } - - } else if (!strncasecmp(c, "uri=", strlen("uri="))) { - c+= strlen("uri="); - if ((*c == '\"')) { - resp_uri=++c; - if ((c = strchr(c,'\"'))) - *c = '\0'; - } else { - resp_uri=c; - if ((c = strchr(c,','))) - *c = '\0'; - } - - } else if (!strncasecmp(c, "username=", strlen("username="))) { - c+= strlen("username="); - if ((*c == '\"')) { - digestusername=++c; - if((c = strchr(c,'\"'))) - *c = '\0'; - } else { - digestusername=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 - if ((z = strchr(c,' ')) || (z = strchr(c,','))) c=z; - if (c) - c++; + i->s = c; + strsep(&c, separator); + break; + } + if (i->key == NULL) /* not found, jump after space or comma */ + strsep(&c, " ,"); } /* Verify that digest username matches the username we auth as */ - if (strcmp(username, digestusername)) { + if (strcmp(username, keys[K_USER].s)) { + ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n", + username, keys[K_USER].s); /* Oops, we're trying something here */ return -2; } /* Verify nonce from request matches our nonce. If not, send 401 with new nonce */ - if (strcasecmp(p->randdata, nonce)) { + if (strcasecmp(p->randdata, keys[K_NONCE].s)) { /* XXX it was 'n'casecmp ? */ wrongnonce = TRUE; - usednonce = nonce; + usednonce = keys[K_NONCE].s; } - snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret); - - if (!ast_strlen_zero(resp_uri)) - snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text, resp_uri); - else - snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text, uri); - if (!ast_strlen_zero(md5secret)) - snprintf(a1_hash, sizeof(a1_hash), "%s", md5secret); - else + ast_copy_string(a1_hash, md5secret, sizeof(a1_hash)); + else { + char a1[256]; + snprintf(a1, sizeof(a1), "%s:%s:%s", username, global_realm, secret); ast_md5_hash(a1_hash, a1); + } - ast_md5_hash(a2_hash, a2); + /* compute the expected response to compare with what we received */ + { + char a2[256]; + char a2_hash[256]; + char resp[256]; - snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, usednonce, a2_hash); - ast_md5_hash(resp_hash, resp); + snprintf(a2, sizeof(a2), "%s:%s", sip_methods[sipmethod].text, + !ast_strlen_zero(keys[K_URI].s) ? keys[K_URI].s : uri); + ast_md5_hash(a2_hash, a2); + snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, usednonce, a2_hash); + ast_md5_hash(resp_hash, resp); + } + good_response = keys[K_RESP].s && + !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash)); if (wrongnonce) { ast_string_field_build(p, randdata, "%08x", thread_safe_rand()); - if (ua_hash && !strncasecmp(ua_hash, resp_hash, strlen(resp_hash))) { + if (good_response) { if (sipdebug) ast_log(LOG_NOTICE, "stale nonce received from '%s'\n", get_header(req, "To")); /* We got working auth token, based on stale nonce . */ @@ -6394,13 +6164,10 @@ /* Schedule auto destroy in 15 seconds */ sip_scheddestroy(p, 15000); - return 1; + return 1; /* XXX should it be -1 ? */ } - /* resp_hash now has the expected response, compare the two */ - if (ua_hash && !strncasecmp(ua_hash, resp_hash, strlen(resp_hash))) { - /* Auth is OK */ + if (good_response) /* Auth is OK */ res = 0; - } } /* Failure */ return res;