upnphttp: improve robustness against malformed (possibly malicious) requests
This commit is contained in:
parent
01532b0490
commit
57c6510fe4
107
upnphttp.c
107
upnphttp.c
@ -150,7 +150,7 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
if(strncasecmp(line, "Content-Length", 14)==0)
|
if(strncasecmp(line, "Content-Length", 14)==0)
|
||||||
{
|
{
|
||||||
p = colon;
|
p = colon;
|
||||||
while(*p < '0' || *p > '9')
|
while(*p && (*p < '0' || *p > '9'))
|
||||||
p++;
|
p++;
|
||||||
h->req_contentlen = atoi(p);
|
h->req_contentlen = atoi(p);
|
||||||
}
|
}
|
||||||
@ -161,13 +161,13 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
while(*p == ':' || *p == ' ' || *p == '\t')
|
while(*p == ':' || *p == ' ' || *p == '\t')
|
||||||
p++;
|
p++;
|
||||||
while(p[n] >= ' ')
|
while(p[n] >= ' ')
|
||||||
{
|
|
||||||
n++;
|
n++;
|
||||||
}
|
if(n >= 2 &&
|
||||||
if((p[0] == '"' && p[n-1] == '"')
|
((p[0] == '"' && p[n-1] == '"') ||
|
||||||
|| (p[0] == '\'' && p[n-1] == '\''))
|
(p[0] == '\'' && p[n-1] == '\'')))
|
||||||
{
|
{
|
||||||
p++; n -= 2;
|
p++;
|
||||||
|
n -= 2;
|
||||||
}
|
}
|
||||||
h->req_soapAction = p;
|
h->req_soapAction = p;
|
||||||
h->req_soapActionLen = n;
|
h->req_soapActionLen = n;
|
||||||
@ -175,10 +175,10 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
else if(strncasecmp(line, "Callback", 8)==0)
|
else if(strncasecmp(line, "Callback", 8)==0)
|
||||||
{
|
{
|
||||||
p = colon;
|
p = colon;
|
||||||
while(*p != '<' && *p != '\r' )
|
while(*p && *p != '<' && *p != '\r' )
|
||||||
p++;
|
p++;
|
||||||
n = 0;
|
n = 0;
|
||||||
while(p[n] != '>' && p[n] != '\r' )
|
while(p[n] && p[n] != '>' && p[n] != '\r' )
|
||||||
n++;
|
n++;
|
||||||
h->req_Callback = p + 1;
|
h->req_Callback = p + 1;
|
||||||
h->req_CallbackLen = MAX(0, n - 1);
|
h->req_CallbackLen = MAX(0, n - 1);
|
||||||
@ -200,7 +200,7 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
while(isspace(*p))
|
while(isspace(*p))
|
||||||
p++;
|
p++;
|
||||||
n = 0;
|
n = 0;
|
||||||
while(!isspace(p[n]))
|
while(p[n] && !isspace(p[n]))
|
||||||
n++;
|
n++;
|
||||||
h->req_SID = p;
|
h->req_SID = p;
|
||||||
h->req_SIDLen = n;
|
h->req_SIDLen = n;
|
||||||
@ -212,7 +212,7 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
while(isspace(*p))
|
while(isspace(*p))
|
||||||
p++;
|
p++;
|
||||||
n = 0;
|
n = 0;
|
||||||
while(!isspace(p[n]))
|
while(p[n] && !isspace(p[n]))
|
||||||
n++;
|
n++;
|
||||||
h->req_NT = p;
|
h->req_NT = p;
|
||||||
h->req_NTLen = n;
|
h->req_NTLen = n;
|
||||||
@ -396,8 +396,11 @@ ParseHttpHeaders(struct upnphttp * h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
next_header:
|
next_header:
|
||||||
while(!(line[0] == '\r' && line[1] == '\n'))
|
line = strstr(line, "\r\n");
|
||||||
line++;
|
if (!line)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
line += 2;
|
line += 2;
|
||||||
}
|
}
|
||||||
if( h->reqflags & FLAG_CHUNKED )
|
if( h->reqflags & FLAG_CHUNKED )
|
||||||
@ -410,9 +413,10 @@ next_header:
|
|||||||
(h->req_chunklen = strtol(line, &endptr, 16)) &&
|
(h->req_chunklen = strtol(line, &endptr, 16)) &&
|
||||||
(endptr != line) )
|
(endptr != line) )
|
||||||
{
|
{
|
||||||
while(!(endptr[0] == '\r' && endptr[1] == '\n'))
|
endptr = strstr(endptr, "\r\n");
|
||||||
|
if (!endptr)
|
||||||
{
|
{
|
||||||
endptr++;
|
return;
|
||||||
}
|
}
|
||||||
line = endptr+h->req_chunklen+2;
|
line = endptr+h->req_chunklen+2;
|
||||||
}
|
}
|
||||||
@ -541,18 +545,6 @@ Send501(struct upnphttp * h)
|
|||||||
CloseSocket_upnphttp(h);
|
CloseSocket_upnphttp(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
|
||||||
findendheaders(const char * s, int len)
|
|
||||||
{
|
|
||||||
while(len-- > 0)
|
|
||||||
{
|
|
||||||
if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
|
|
||||||
return s;
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sends the description generated by the parameter */
|
/* Sends the description generated by the parameter */
|
||||||
static void
|
static void
|
||||||
sendXMLdesc(struct upnphttp * h, char * (f)(int *))
|
sendXMLdesc(struct upnphttp * h, char * (f)(int *))
|
||||||
@ -807,7 +799,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
|||||||
p = h->req_buf;
|
p = h->req_buf;
|
||||||
if(!p)
|
if(!p)
|
||||||
return;
|
return;
|
||||||
for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
|
for(i = 0; i<15 && *p && *p != ' ' && *p != '\r'; i++)
|
||||||
HttpCommand[i] = *(p++);
|
HttpCommand[i] = *(p++);
|
||||||
HttpCommand[i] = '\0';
|
HttpCommand[i] = '\0';
|
||||||
while(*p==' ')
|
while(*p==' ')
|
||||||
@ -818,13 +810,13 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
|||||||
while(*p!='/')
|
while(*p!='/')
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
for(i = 0; i<511 && *p != ' ' && *p != '\r'; i++)
|
for(i = 0; i<511 && *p && *p != ' ' && *p != '\r'; i++)
|
||||||
HttpUrl[i] = *(p++);
|
HttpUrl[i] = *(p++);
|
||||||
HttpUrl[i] = '\0';
|
HttpUrl[i] = '\0';
|
||||||
while(*p==' ')
|
while(*p==' ')
|
||||||
p++;
|
p++;
|
||||||
HttpVer = h->HttpVer;
|
HttpVer = h->HttpVer;
|
||||||
for(i = 0; i<15 && *p != '\r'; i++)
|
for(i = 0; i<15 && *p && *p != '\r'; i++)
|
||||||
HttpVer[i] = *(p++);
|
HttpVer[i] = *(p++);
|
||||||
HttpVer[i] = '\0';
|
HttpVer[i] = '\0';
|
||||||
/*DPRINTF(E_INFO, L_HTTP, "HTTP REQUEST : %s %s (%s)\n",
|
/*DPRINTF(E_INFO, L_HTTP, "HTTP REQUEST : %s %s (%s)\n",
|
||||||
@ -846,6 +838,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
|||||||
/* see if we need to wait for remaining data */
|
/* see if we need to wait for remaining data */
|
||||||
if( (h->reqflags & FLAG_CHUNKED) )
|
if( (h->reqflags & FLAG_CHUNKED) )
|
||||||
{
|
{
|
||||||
|
if( h->req_chunklen == -1)
|
||||||
|
{
|
||||||
|
Send400(h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if( h->req_chunklen )
|
if( h->req_chunklen )
|
||||||
{
|
{
|
||||||
h->state = 2;
|
h->state = 2;
|
||||||
@ -856,9 +853,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
|||||||
|
|
||||||
while( (h->req_chunklen = strtol(chunk, &endptr, 16)) && (endptr != chunk) )
|
while( (h->req_chunklen = strtol(chunk, &endptr, 16)) && (endptr != chunk) )
|
||||||
{
|
{
|
||||||
while(!(endptr[0] == '\r' && endptr[1] == '\n'))
|
endptr = strstr(endptr, "\r\n");
|
||||||
|
if (!endptr)
|
||||||
{
|
{
|
||||||
endptr++;
|
Send400(h);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
endptr += 2;
|
endptr += 2;
|
||||||
|
|
||||||
@ -1071,7 +1070,7 @@ Process_upnphttp(struct upnphttp * h)
|
|||||||
h->req_buflen += n;
|
h->req_buflen += n;
|
||||||
h->req_buf[h->req_buflen] = '\0';
|
h->req_buf[h->req_buflen] = '\0';
|
||||||
/* search for the string "\r\n\r\n" */
|
/* search for the string "\r\n\r\n" */
|
||||||
endheaders = findendheaders(h->req_buf, h->req_buflen);
|
endheaders = strstr(h->req_buf, "\r\n\r\n");
|
||||||
if(endheaders)
|
if(endheaders)
|
||||||
{
|
{
|
||||||
h->req_contentoff = endheaders - h->req_buf + 4;
|
h->req_contentoff = endheaders - h->req_buf + 4;
|
||||||
@ -1143,56 +1142,43 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
|
|||||||
time_t curtime = time(NULL);
|
time_t curtime = time(NULL);
|
||||||
char date[30];
|
char date[30];
|
||||||
int templen;
|
int templen;
|
||||||
|
struct string_s res;
|
||||||
if(!h->res_buf)
|
if(!h->res_buf)
|
||||||
{
|
{
|
||||||
templen = sizeof(httpresphead) + 256 + bodylen;
|
templen = sizeof(httpresphead) + 256 + bodylen;
|
||||||
h->res_buf = (char *)malloc(templen);
|
h->res_buf = (char *)malloc(templen);
|
||||||
h->res_buf_alloclen = templen;
|
h->res_buf_alloclen = templen;
|
||||||
}
|
}
|
||||||
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
|
res.data = h->res_buf;
|
||||||
httpresphead, "HTTP/1.1",
|
res.size = h->res_buf_alloclen;
|
||||||
|
res.off = 0;
|
||||||
|
strcatf(&res, httpresphead, "HTTP/1.1",
|
||||||
respcode, respmsg,
|
respcode, respmsg,
|
||||||
(h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
|
(h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
|
||||||
bodylen);
|
bodylen);
|
||||||
/* Additional headers */
|
/* Additional headers */
|
||||||
if(h->respflags & FLAG_TIMEOUT) {
|
if(h->respflags & FLAG_TIMEOUT) {
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
strcatf(&res, "Timeout: Second-");
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"Timeout: Second-");
|
|
||||||
if(h->req_Timeout) {
|
if(h->req_Timeout) {
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
strcatf(&res, "%d\r\n", h->req_Timeout);
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"%d\r\n", h->req_Timeout);
|
|
||||||
} else {
|
} else {
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
strcatf(&res, "300\r\n");
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"300\r\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(h->respflags & FLAG_SID) {
|
if(h->respflags & FLAG_SID) {
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
strcatf(&res, "SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
|
|
||||||
}
|
}
|
||||||
if(h->reqflags & FLAG_LANGUAGE) {
|
if(h->reqflags & FLAG_LANGUAGE) {
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
strcatf(&res, "Content-Language: en\r\n");
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"Content-Language: en\r\n");
|
|
||||||
}
|
}
|
||||||
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
strcatf(&res, "Date: %s\r\n", date);
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
strcatf(&res, "EXT:\r\n");
|
||||||
"Date: %s\r\n", date);
|
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"EXT:\r\n");
|
|
||||||
#if 0 // DLNA
|
#if 0 // DLNA
|
||||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
strcatf(&res, "contentFeatures.dlna.org: \r\n");
|
||||||
h->res_buf_alloclen - h->res_buflen,
|
|
||||||
"contentFeatures.dlna.org: \r\n");
|
|
||||||
#endif
|
#endif
|
||||||
h->res_buf[h->res_buflen++] = '\r';
|
strcatf(&res, "\r\n");
|
||||||
h->res_buf[h->res_buflen++] = '\n';
|
h->res_buflen = res.off;
|
||||||
if(h->res_buf_alloclen < (h->res_buflen + bodylen))
|
if(h->res_buf_alloclen < (h->res_buflen + bodylen))
|
||||||
{
|
{
|
||||||
h->res_buf = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
|
h->res_buf = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
|
||||||
@ -1524,6 +1510,7 @@ SendResp_thumbnail(struct upnphttp * h, char * object)
|
|||||||
if( access(path, F_OK) != 0 )
|
if( access(path, F_OK) != 0 )
|
||||||
{
|
{
|
||||||
DPRINTF(E_ERROR, L_HTTP, "Error accessing %s\n", path);
|
DPRINTF(E_ERROR, L_HTTP, "Error accessing %s\n", path);
|
||||||
|
Send404(h);
|
||||||
sqlite3_free(path);
|
sqlite3_free(path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user