static ret_t build_HA1 (cherokee_connection_t *conn, cherokee_buffer_t *buf) { cherokee_buffer_add_va (buf, "%s:%s:%s", conn->validator->user.buf, conn->realm_ref->buf, conn->validator->passwd.buf); cherokee_buffer_encode_md5_digest (buf); return ret_ok; }
static ret_t digest_HA2 (cherokee_validator_t *validator, cherokee_buffer_t *buf, cherokee_connection_t *conn) { ret_t ret; const char *method; cuint_t method_len; /* Sanity check */ if (cherokee_buffer_is_empty (&validator->uri)) return ret_deny; ret = cherokee_http_method_to_string (conn->header.method, &method, &method_len); if (unlikely (ret != ret_ok)) return ret; cherokee_buffer_ensure_size (buf, method_len + 1 + validator->uri.len); cherokee_buffer_add (buf, method, method_len); cherokee_buffer_add_str (buf, ":"); cherokee_buffer_add_buffer (buf, &validator->uri); cherokee_buffer_encode_md5_digest (buf); return ret_ok; }
ret_t cherokee_validator_digest_response (cherokee_validator_t *validator, char *A1, cherokee_buffer_t *buf, cherokee_connection_t *conn) { ret_t ret; cherokee_buffer_t a2 = CHEROKEE_BUF_INIT; /* A1 has to be in string of length 32: * MD5_digest(user":"******":"passwd) */ /* Sanity checks */ if (A1 == NULL) return ret_deny; if (cherokee_buffer_is_empty (&validator->nonce)) return ret_deny; /* Build A2 */ ret = digest_HA2 (validator, &a2, conn); if (ret != ret_ok) goto error; /* Build the final string */ cherokee_buffer_ensure_size (buf, 32 + a2.len + validator->nonce.len + 4); cherokee_buffer_add (buf, A1, 32); cherokee_buffer_add_str (buf, ":"); cherokee_buffer_add_buffer (buf, &validator->nonce); cherokee_buffer_add_str (buf, ":"); if (!cherokee_buffer_is_empty (&validator->qop)) { if (!cherokee_buffer_is_empty (&validator->nc)) cherokee_buffer_add_buffer (buf, &validator->nc); cherokee_buffer_add_str (buf, ":"); if (!cherokee_buffer_is_empty (&validator->cnonce)) cherokee_buffer_add_buffer (buf, &validator->cnonce); cherokee_buffer_add_str (buf, ":"); cherokee_buffer_add_buffer (buf, &validator->qop); cherokee_buffer_add_str (buf, ":"); } cherokee_buffer_add_buffer (buf, &a2); cherokee_buffer_encode_md5_digest (buf); cherokee_buffer_mrproper (&a2); return ret_ok; error: cherokee_buffer_mrproper (&a2); return ret; }
ret_t cherokee_validator_digest_check (cherokee_validator_t *validator, cherokee_buffer_t *passwd, cherokee_connection_t *conn) { ret_t ret; int re = -1; cherokee_buffer_t a1 = CHEROKEE_BUF_INIT; cherokee_buffer_t buf = CHEROKEE_BUF_INIT; /* Sanity check */ if (cherokee_buffer_is_empty (&validator->user) || cherokee_buffer_is_empty (&validator->realm)) return ret_deny; /* Build A1 */ cherokee_buffer_ensure_size (&a1, validator->user.len + 1 + validator->realm.len + 1 + passwd->len); cherokee_buffer_add_buffer (&a1, &validator->user); cherokee_buffer_add_str (&a1, ":"); cherokee_buffer_add_buffer (&a1, &validator->realm); cherokee_buffer_add_str (&a1, ":"); cherokee_buffer_add_buffer (&a1, passwd); cherokee_buffer_encode_md5_digest (&a1); /* Build a possible response */ ret = cherokee_validator_digest_response (validator, a1.buf, &buf, conn); if (unlikely(ret != ret_ok)) goto go_out; /* Compare and return */ re = cherokee_buffer_cmp_buf (&conn->validator->response, &buf); go_out: cherokee_buffer_mrproper (&a1); cherokee_buffer_mrproper (&buf); return (re == 0) ? ret_ok : ret_deny; }
ret_t cherokee_handler_secdownload_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props) { int re; ret_t ret; char *p; cuint_t path_len; time_t time_url; char *time_s; cherokee_buffer_t md5 = CHEROKEE_BUF_INIT; cherokee_connection_t *conn = CONN(cnt); TRACE(ENTRIES, "Analyzing request '%s'\n", conn->request.buf); /* Sanity check */ if (conn->request.len <= 1 + 32 + 2) { TRACE(ENTRIES, "Malformed URL. Too short: len=%d.\n", conn->request.len); conn->error_code = http_not_found; return ret_error; } if (conn->request.buf[0] != '/') { TRACE(ENTRIES, "Malformed URL: %s\n", "Not slash (1)"); conn->error_code = http_not_found; return ret_error; } p = conn->request.buf + 1; if (check_hex (p, 32)) { TRACE(ENTRIES, "Malformed URL: %s\n", "No MD5"); conn->error_code = http_not_found; return ret_error; } p += 32; if (*p != '/') { TRACE(ENTRIES, "Malformed URL: %s\n", "Not slash (2)"); conn->error_code = http_not_found; return ret_error; } p += 1; time_s = p; if (check_hex (p, 8)) { TRACE(ENTRIES, "Malformed URL: %s\n", "No MD5 (2)"); conn->error_code = http_not_found; return ret_error; } p += 8; /* Check the time */ time_url = get_time (time_s); if ((cherokee_bogonow_now - time_url) > (int)PROP_SECDOWN(props)->timeout) { TRACE(ENTRIES, "Time out: %d (now=%d)\n", time_url, cherokee_bogonow_now); conn->error_code = http_gone; return ret_error; } /* Check the MD5 * [secret][path][hex(time)] */ path_len = (conn->request.buf + conn->request.len) - p; cherokee_buffer_add_buffer (&md5, &PROP_SECDOWN(props)->secret); cherokee_buffer_add (&md5, p, path_len); cherokee_buffer_add (&md5, time_s, 8); cherokee_buffer_encode_md5_digest (&md5); re = strncasecmp (md5.buf, &conn->request.buf[1], 32); if (re != 0) { TRACE(ENTRIES, "MD5 (%s) didn't match\n", md5.buf); cherokee_buffer_mrproper(&md5); conn->error_code = http_access_denied; return ret_error; } cherokee_buffer_mrproper (&md5); /* At this point the request has been validated */ if (cherokee_buffer_is_empty (&conn->request_original)) { cherokee_buffer_add_buffer (&conn->request_original, &conn->request); cherokee_buffer_add_buffer (&conn->query_string_original, &conn->query_string); } cherokee_buffer_clean (&conn->request); cherokee_buffer_add (&conn->request, p, path_len); /* Instance the File handler */ ret = cherokee_handler_file_new (hdl, cnt, MODULE_PROPS(PROP_SECDOWN(props)->props_file)); if (ret != ret_ok) return ret_ok; return ret_ok; }