+/* some simple nonce generator */
+static void generate_nonce(char *result)
+{
+ UPRINT(result, "%08x", (unsigned int)random());
+ result += 8;
+ UPRINT(result, "%08x", (unsigned int)random());
+ result += 8;
+ UPRINT(result, "%08x", (unsigned int)random());
+ result += 8;
+ UPRINT(result, "%08x", (unsigned int)random());
+}
+
+/* check authorization */
+static int check_authorization(sip_authorization_t const *authorization, const char *regstr, const char *check_user, const char *check_pass, const char *check_realm, const char *check_nonce, const char **auth_text)
+{
+ int ret = 500;
+ *auth_text = "Internal Server Error";
+
+ char *username = NULL;
+ char *realm = NULL;
+ char *nonce = NULL;
+ char *uri = NULL;
+ char *qop = NULL;
+ char *cnonce = NULL;
+ char *nc = NULL;
+ char *response = NULL;
+
+ int indexnum;
+ const char *cur;
+
+ char temp[256], first_digest[2 * SU_MD5_DIGEST_SIZE + 1], second_digest[2 * SU_MD5_DIGEST_SIZE + 1], third_digest[2 * SU_MD5_DIGEST_SIZE + 1];
+ su_md5_t md5_ctx;
+
+ if (!check_nonce || !check_nonce[0] || !authorization || !authorization->au_params) {
+ if (!strcmp(regstr, "REGISTER")) {
+ *auth_text = "Unauthorized";
+ ret = 401;
+ } else {
+ *auth_text = "Proxy Authentication Required";
+ ret = 407;
+ }
+ goto end;
+ }
+
+ /* parse header (stolen from freeswitch) */
+ for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) {
+ char *var, *val, *p, *work;
+ var = val = work = NULL;
+ if ((work = strdup(cur))) {
+ var = work;
+ if ((val = strchr(var, '='))) {
+ *val++ = '\0';
+ while (*val == '"') {
+ *val++ = '\0';
+ }
+ if ((p = strchr(val, '"'))) {
+ *p = '\0';
+ }
+
+ PDEBUG(DEBUG_SIP, "Found in Auth header: %s = %s\n", var, val);
+ if (!strcasecmp(var, "username")) {
+ username = strdup(val);
+ } else if (!strcasecmp(var, "realm")) {
+ realm = strdup(val);
+ } else if (!strcasecmp(var, "nonce")) {
+ nonce = strdup(val);
+ } else if (!strcasecmp(var, "uri")) {
+ uri = strdup(val);
+ } else if (!strcasecmp(var, "qop")) {
+ qop = strdup(val);
+ } else if (!strcasecmp(var, "cnonce")) {
+ cnonce = strdup(val);
+ } else if (!strcasecmp(var, "response")) {
+ response = strdup(val);
+ } else if (!strcasecmp(var, "nc")) {
+ nc = strdup(val);
+ }
+ }
+
+ free(work);
+ }
+ }
+
+ if (!username || !realm || !nonce || ! uri || !response) {
+ *auth_text = "Authorization header incomplete";
+ ret = 400;
+ goto end;
+ }
+
+ if (!!strcmp(username, check_user)) {
+ *auth_text = "Authorization Username Missmatch";
+ ret = 403;
+ goto end;
+ }
+ if (!!strcmp(realm, check_realm)) {
+ *auth_text = "Authorization Realm Missmatch";
+ ret = 403;
+ goto end;
+ }
+ if (!!strcmp(nonce, check_nonce)) {
+ *auth_text = "Authorization Nonce Missmatch";
+ ret = 403;
+ goto end;
+ }
+
+ /* perform hash */
+ SPRINT(temp, "%s:%s:%s", check_user, realm, check_pass);
+ PDEBUG(DEBUG_SIP, "First hash: %s\n", temp);
+ su_md5_init(&md5_ctx);
+ su_md5_strupdate(&md5_ctx, temp);
+ su_md5_hexdigest(&md5_ctx, first_digest);
+ su_md5_deinit(&md5_ctx);
+
+ SPRINT(temp, "%s:%s", regstr, uri);
+ PDEBUG(DEBUG_SIP, "First hash: %s\n", temp);
+ su_md5_init(&md5_ctx);
+ su_md5_strupdate(&md5_ctx, temp);
+ su_md5_hexdigest(&md5_ctx, second_digest);
+ su_md5_deinit(&md5_ctx);
+
+ if (nc && cnonce && qop)
+ SPRINT(temp, "%s:%s:%s:%s:%s:%s", first_digest, nonce, nc, cnonce, qop, second_digest);
+ else
+ SPRINT(temp, "%s:%s:%s", first_digest, nonce, second_digest);
+ PDEBUG(DEBUG_SIP, "Third hash: %s\n", temp);
+ su_md5_init(&md5_ctx);
+ su_md5_strupdate(&md5_ctx, temp);
+ su_md5_hexdigest(&md5_ctx, third_digest);
+ su_md5_deinit(&md5_ctx);
+
+ if (!!strcmp(response, third_digest)) {
+ *auth_text = "Authorization Failed";
+ ret = 403;
+ goto end;
+ }
+
+ *auth_text = "Authorization Success";
+ ret = 200;
+
+end:
+ free(username);
+ free(realm);
+ free(nonce);
+ free(uri);
+ free(qop);
+ free(cnonce);
+ free(nc);
+ free(response);
+
+ return ret;
+}
+