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)
|
||||
{
|
||||
p = colon;
|
||||
while(*p < '0' || *p > '9')
|
||||
while(*p && (*p < '0' || *p > '9'))
|
||||
p++;
|
||||
h->req_contentlen = atoi(p);
|
||||
}
|
||||
@ -161,13 +161,13 @@ ParseHttpHeaders(struct upnphttp * h)
|
||||
while(*p == ':' || *p == ' ' || *p == '\t')
|
||||
p++;
|
||||
while(p[n] >= ' ')
|
||||
{
|
||||
n++;
|
||||
}
|
||||
if((p[0] == '"' && p[n-1] == '"')
|
||||
|| (p[0] == '\'' && p[n-1] == '\''))
|
||||
if(n >= 2 &&
|
||||
((p[0] == '"' && p[n-1] == '"') ||
|
||||
(p[0] == '\'' && p[n-1] == '\'')))
|
||||
{
|
||||
p++; n -= 2;
|
||||
p++;
|
||||
n -= 2;
|
||||
}
|
||||
h->req_soapAction = p;
|
||||
h->req_soapActionLen = n;
|
||||
@ -175,10 +175,10 @@ ParseHttpHeaders(struct upnphttp * h)
|
||||
else if(strncasecmp(line, "Callback", 8)==0)
|
||||
{
|
||||
p = colon;
|
||||
while(*p != '<' && *p != '\r' )
|
||||
while(*p && *p != '<' && *p != '\r' )
|
||||
p++;
|
||||
n = 0;
|
||||
while(p[n] != '>' && p[n] != '\r' )
|
||||
while(p[n] && p[n] != '>' && p[n] != '\r' )
|
||||
n++;
|
||||
h->req_Callback = p + 1;
|
||||
h->req_CallbackLen = MAX(0, n - 1);
|
||||
@ -200,7 +200,7 @@ ParseHttpHeaders(struct upnphttp * h)
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
n = 0;
|
||||
while(!isspace(p[n]))
|
||||
while(p[n] && !isspace(p[n]))
|
||||
n++;
|
||||
h->req_SID = p;
|
||||
h->req_SIDLen = n;
|
||||
@ -212,7 +212,7 @@ ParseHttpHeaders(struct upnphttp * h)
|
||||
while(isspace(*p))
|
||||
p++;
|
||||
n = 0;
|
||||
while(!isspace(p[n]))
|
||||
while(p[n] && !isspace(p[n]))
|
||||
n++;
|
||||
h->req_NT = p;
|
||||
h->req_NTLen = n;
|
||||
@ -396,8 +396,11 @@ ParseHttpHeaders(struct upnphttp * h)
|
||||
}
|
||||
}
|
||||
next_header:
|
||||
while(!(line[0] == '\r' && line[1] == '\n'))
|
||||
line++;
|
||||
line = strstr(line, "\r\n");
|
||||
if (!line)
|
||||
{
|
||||
return;
|
||||
}
|
||||
line += 2;
|
||||
}
|
||||
if( h->reqflags & FLAG_CHUNKED )
|
||||
@ -410,9 +413,10 @@ next_header:
|
||||
(h->req_chunklen = strtol(line, &endptr, 16)) &&
|
||||
(endptr != line) )
|
||||
{
|
||||
while(!(endptr[0] == '\r' && endptr[1] == '\n'))
|
||||
endptr = strstr(endptr, "\r\n");
|
||||
if (!endptr)
|
||||
{
|
||||
endptr++;
|
||||
return;
|
||||
}
|
||||
line = endptr+h->req_chunklen+2;
|
||||
}
|
||||
@ -541,18 +545,6 @@ Send501(struct 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 */
|
||||
static void
|
||||
sendXMLdesc(struct upnphttp * h, char * (f)(int *))
|
||||
@ -807,7 +799,7 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
||||
p = h->req_buf;
|
||||
if(!p)
|
||||
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] = '\0';
|
||||
while(*p==' ')
|
||||
@ -818,13 +810,13 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
||||
while(*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] = '\0';
|
||||
while(*p==' ')
|
||||
p++;
|
||||
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] = '\0';
|
||||
/*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 */
|
||||
if( (h->reqflags & FLAG_CHUNKED) )
|
||||
{
|
||||
if( h->req_chunklen == -1)
|
||||
{
|
||||
Send400(h);
|
||||
return;
|
||||
}
|
||||
if( h->req_chunklen )
|
||||
{
|
||||
h->state = 2;
|
||||
@ -856,9 +853,11 @@ ProcessHttpQuery_upnphttp(struct upnphttp * h)
|
||||
|
||||
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;
|
||||
|
||||
@ -1071,7 +1070,7 @@ Process_upnphttp(struct upnphttp * h)
|
||||
h->req_buflen += n;
|
||||
h->req_buf[h->req_buflen] = '\0';
|
||||
/* 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)
|
||||
{
|
||||
h->req_contentoff = endheaders - h->req_buf + 4;
|
||||
@ -1143,56 +1142,43 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
|
||||
time_t curtime = time(NULL);
|
||||
char date[30];
|
||||
int templen;
|
||||
struct string_s res;
|
||||
if(!h->res_buf)
|
||||
{
|
||||
templen = sizeof(httpresphead) + 256 + bodylen;
|
||||
h->res_buf = (char *)malloc(templen);
|
||||
h->res_buf_alloclen = templen;
|
||||
}
|
||||
h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
|
||||
httpresphead, "HTTP/1.1",
|
||||
res.data = h->res_buf;
|
||||
res.size = h->res_buf_alloclen;
|
||||
res.off = 0;
|
||||
strcatf(&res, httpresphead, "HTTP/1.1",
|
||||
respcode, respmsg,
|
||||
(h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
|
||||
bodylen);
|
||||
/* Additional headers */
|
||||
if(h->respflags & FLAG_TIMEOUT) {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"Timeout: Second-");
|
||||
strcatf(&res, "Timeout: Second-");
|
||||
if(h->req_Timeout) {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"%d\r\n", h->req_Timeout);
|
||||
strcatf(&res, "%d\r\n", h->req_Timeout);
|
||||
} else {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"300\r\n");
|
||||
strcatf(&res, "300\r\n");
|
||||
}
|
||||
}
|
||||
if(h->respflags & FLAG_SID) {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
|
||||
strcatf(&res, "SID: %.*s\r\n", h->req_SIDLen, h->req_SID);
|
||||
}
|
||||
if(h->reqflags & FLAG_LANGUAGE) {
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"Content-Language: en\r\n");
|
||||
strcatf(&res, "Content-Language: en\r\n");
|
||||
}
|
||||
strftime(date, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&curtime));
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"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");
|
||||
strcatf(&res, "Date: %s\r\n", date);
|
||||
strcatf(&res, "EXT:\r\n");
|
||||
#if 0 // DLNA
|
||||
h->res_buflen += snprintf(h->res_buf + h->res_buflen,
|
||||
h->res_buf_alloclen - h->res_buflen,
|
||||
"contentFeatures.dlna.org: \r\n");
|
||||
strcatf(&res, "contentFeatures.dlna.org: \r\n");
|
||||
#endif
|
||||
h->res_buf[h->res_buflen++] = '\r';
|
||||
h->res_buf[h->res_buflen++] = '\n';
|
||||
strcatf(&res, "\r\n");
|
||||
h->res_buflen = res.off;
|
||||
if(h->res_buf_alloclen < (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 )
|
||||
{
|
||||
DPRINTF(E_ERROR, L_HTTP, "Error accessing %s\n", path);
|
||||
Send404(h);
|
||||
sqlite3_free(path);
|
||||
return;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user