diff --git a/src/digauth.c b/src/digauth.c index 01faa6a..082e4e6 100644 --- a/src/digauth.c +++ b/src/digauth.c @@ -98,7 +98,7 @@ static int get_param_index(char *key) return -1; } -static void strip_lead_trail_char(char *str, char ch) +void strip_lead_trail_char(char *str, char ch) { /* First remove leading strip-char */ const char* first_valid = str; @@ -366,9 +366,33 @@ int http_authentication_failure_resp(FILE *fp, const char *http_meth, const char return 1; } +static void get_relative_path(const char *uri, const char *req_host, char *req_path, size_t size) +{ + if (uri == NULL || req_path == NULL) + return; + + memset(req_path, 0, size); + if (req_host == NULL || strlen(req_host) == 0) { + snprintf(req_path, size, "%s", uri); + return; + } + + size_t host_len = strlen(req_host); + if (strncmp(uri, req_host, host_len) == 0) { + if (strlen(uri) == host_len) { + snprintf(req_path, size, "/"); + } else { + snprintf(req_path, size, "%s", uri + strlen(req_host)); + } + return; + } + + snprintf(req_path, size, "%s", uri); +} + int validate_http_digest_auth(const char *http_meth, const char *uri, const char *hdr, const char *rlm, const char *usr, const char *psw, - unsigned int timeout) + unsigned int timeout, const char *req_host) { get_value_from_header(hdr); @@ -422,13 +446,22 @@ int validate_http_digest_auth(const char *http_meth, const char *uri, const char if (strlen(param[E_URI].value) == 0) return 0; - if (strncmp(param[E_URI].value, uri, strlen(uri)) != 0) { - CWMP_LOG(ERROR, "Authentication failed, URI is not matched"); + CWMP_LOG(INFO, "Requested URI: (%s)", param[E_URI].value); + char req_path[2049] = {0}; + get_relative_path(param[E_URI].value, req_host, req_path, sizeof(req_path)); + if (strlen(req_path) == 0) + return 0; + + CWMP_LOG(INFO, "Abs path: (%s)", req_path); + if (strncmp(req_path, uri, strlen(uri)) != 0) { + CWMP_LOG(ERROR, "Authentication failed, configured uri(%s), req path(%s) not matched", uri, req_path); return 0; } - if ((strcmp(param[E_QOP].value, "auth") != 0) && (strcmp(param[E_QOP].value, "") != 0)) + if ((strcmp(param[E_QOP].value, "auth") != 0) && (strcmp(param[E_QOP].value, "") != 0)) { + CWMP_LOG(ERROR, "Authentication failed, due to qop value: (%s)", param[E_QOP].value); return 0; + } char *tmp; unsigned long int nc_int = strtoul(param[E_NC].value, &tmp, 16); @@ -442,12 +475,17 @@ int validate_http_digest_auth(const char *http_meth, const char *uri, const char char resp[MD5_HASH_HEX_LEN + 1]; get_digest_ha1("md5", usr, rlm, psw, param[E_NONCE].value, param[E_CNONCE].value, ha1, sizeof(ha1)); - get_digest_ha2(http_meth, uri, ha2, sizeof(ha2)); + get_digest_ha2(http_meth, param[E_URI].value, ha2, sizeof(ha2)); get_digest_response(ha1, param[E_NONCE].value, param[E_NC].value, param[E_CNONCE].value, param[E_QOP].value, ha2, resp, sizeof(resp)); - if (strcmp(resp, param[E_RESPONSE].value) != 0) + if (strcmp(resp, param[E_RESPONSE].value) != 0) { + CWMP_LOG(ERROR, "Authentication failed due to response, rec(%s) calc(%s)", param[E_RESPONSE].value, resp); + CWMP_LOG(ERROR, "## received nonce:(%s) nc:(%s) usr:(%s)", param[E_NONCE].value, param[E_NC].value, usr); + CWMP_LOG(ERROR, "## rlm:(%s) psw:(%s) meth:(%s)", rlm, psw, http_meth); + CWMP_LOG(ERROR, "## cnonce:(%s)", param[E_CNONCE].value); return 0; + } return 1; } diff --git a/src/digauth.h b/src/digauth.h index 3f74ab4..ac85103 100644 --- a/src/digauth.h +++ b/src/digauth.h @@ -16,9 +16,10 @@ extern char *nonce_key; int get_nonce_key(void); +void strip_lead_trail_char(char *str, char ch); int validate_http_digest_auth(const char *http_meth, const char *uri, const char *hdr, const char *rlm, const char *usr, const char *psw, - unsigned int timeout); + unsigned int timeout, const char *req_host); int http_authentication_failure_resp(FILE *fp, const char *http_meth, const char *uri, const char *rlm, const char *opq); diff --git a/src/http.c b/src/http.c index 4f66dec..fbfe440 100644 --- a/src/http.c +++ b/src/http.c @@ -317,6 +317,7 @@ static void http_cr_new_client(int client, bool service_available) bool auth_digest_checked = false; bool method_is_get = false; bool internal_error = false; + char request_host[2049] = {0}; char cr_http_get_head[HTTP_GET_HDR_LEN] = {0}; @@ -333,6 +334,11 @@ static void http_cr_new_client(int client, bool service_available) } snprintf(cr_http_get_head, sizeof(cr_http_get_head), "GET %s HTTP/1.1", cwmp_main.conf.connection_request_path); while (fgets(buffer, sizeof(buffer), fp)) { + if (buffer[0] == '\r' || buffer[0] == '\n') { + /* end of http request (empty line) */ + break; + } + if (strstr(buffer, "GET ") != NULL && strstr(buffer, "HTTP/1.1") != NULL) { // check if extra url parameter then ignore extra params int j = 0; @@ -355,21 +361,23 @@ static void http_cr_new_client(int client, bool service_available) method_is_get = true; } + strip_lead_trail_char(buffer, '\n'); + strip_lead_trail_char(buffer, '\r'); if (!strncasecmp(buffer, "Authorization: Digest ", strlen("Authorization: Digest "))) { auth_digest_checked = true; CWMP_STRNCPY(auth_digest_buffer, buffer, BUFSIZ); } - if (buffer[0] == '\r' || buffer[0] == '\n') { - /* end of http request (empty line) */ - break; + if (strncasecmp(buffer, "Host: ", strlen("Host: ")) == 0 && strlen(buffer) > strlen("Host: ")) { + snprintf(request_host, sizeof(request_host), "http://%s", buffer + strlen("Host: ")); } } if (!service_available || !method_is_get) { goto http_end; } - int auth_check = validate_http_digest_auth("GET", cwmp_main.conf.connection_request_path, auth_digest_buffer + strlen("Authorization: Digest "), REALM, username, password, 300); + CWMP_LOG(INFO, "Received host: (%s)", request_host); + int auth_check = validate_http_digest_auth("GET", cwmp_main.conf.connection_request_path, auth_digest_buffer + strlen("Authorization: Digest "), REALM, username, password, 300, request_host); if (auth_check == -1) { /* invalid nonce */ internal_error = true; goto http_end; diff --git a/src/rpc.c b/src/rpc.c index 8300c0d..b702882 100755 --- a/src/rpc.c +++ b/src/rpc.c @@ -101,26 +101,31 @@ int xml_handle_message(struct session *session) } c = (char *)mxmlGetElement(b); + if (c == NULL) { + CWMP_LOG(INFO, "Could not get element from received message"); + goto error; + } + /* convert QName to localPart, check that ns is the expected one */ if (strchr(c, ':')) { char *tmp = strchr(c, ':'); size_t ns_len = tmp - c; if (strlen(ns.cwmp) != ns_len) { - CWMP_LOG(INFO, "Invalid received message"); + CWMP_LOG(INFO, "Namespace length is not matched in string (%s) and expected (%s)", c, ns.cwmp); session->fault_code = FAULT_CPE_REQUEST_DENIED; goto fault; } if (strncmp(ns.cwmp, c, ns_len)) { - CWMP_LOG(INFO, "Invalid received message"); + CWMP_LOG(INFO, "Namespace in string (%s) is not the expected (%s) one", c, ns.cwmp); session->fault_code = FAULT_CPE_REQUEST_DENIED; goto fault; } c = tmp + 1; } else { - CWMP_LOG(INFO, "Invalid received message"); + CWMP_LOG(INFO, "Can not convert QName to local part with received string (%s)", c); session->fault_code = FAULT_CPE_REQUEST_DENIED; goto fault; }