Reimplemented memory management in dirlisting generation
This should eliminate all bufferoverflows introduced by the previous usage of strcat() and various assumptions.
This commit is contained in:
parent
4722639ae1
commit
1bcc672503
|
@ -17,5 +17,6 @@
|
||||||
|
|
||||||
void remove_trailing_slash(char *str);
|
void remove_trailing_slash(char *str);
|
||||||
void urlencode(const char *str, char *result);
|
void urlencode(const char *str, char *result);
|
||||||
|
char* safe_append(char *target, size_t *targetsize, const char *src);
|
||||||
|
|
||||||
#endif // UTIL_H
|
#endif // UTIL_H
|
||||||
|
|
|
@ -79,21 +79,20 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
|
||||||
result = malloc(allocated * sizeof(char));
|
result = malloc(allocated * sizeof(char));
|
||||||
result[0] = '\0';
|
result[0] = '\0';
|
||||||
|
|
||||||
// this is still safe
|
result = safe_append(result, &allocated, HEADER1);
|
||||||
strcat(result, HEADER1);
|
|
||||||
|
|
||||||
snprintf(buf, BUFSIZE, "<title>Directory listing for %s</title>", url);
|
snprintf(buf, BUFSIZE, "<title>Directory listing for %s</title>", url);
|
||||||
strcat(result, buf);
|
result = safe_append(result, &allocated, buf);
|
||||||
|
|
||||||
strcat(result, HEADER2);
|
result = safe_append(result, &allocated, HEADER2);
|
||||||
|
|
||||||
snprintf(buf, BUFSIZE, "<h1>Directory listing for %s</h1>", url);
|
snprintf(buf, BUFSIZE, "<h1>Directory listing for %s</h1>", url);
|
||||||
strcat(result, buf);
|
result = safe_append(result, &allocated, buf);
|
||||||
|
|
||||||
int isrootdir = strcmp(url, "/") == 0;
|
int isrootdir = strcmp(url, "/") == 0;
|
||||||
|
|
||||||
// Begin Navigation
|
// Begin Navigation
|
||||||
strcat(result, "<p>Navigation: ");
|
result = safe_append(result, &allocated, "<p>Navigation: ");
|
||||||
|
|
||||||
// tokenize the URL: init
|
// tokenize the URL: init
|
||||||
char *token, *urlclone;
|
char *token, *urlclone;
|
||||||
|
@ -103,30 +102,31 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
|
||||||
strcpy(fullpath, "/");
|
strcpy(fullpath, "/");
|
||||||
|
|
||||||
if(isrootdir) {
|
if(isrootdir) {
|
||||||
strcat(result, "/");
|
result = safe_append(result, &allocated, "/");
|
||||||
} else {
|
} else {
|
||||||
strcat(result, "<a href=\"/\">/</a>");
|
result = safe_append(result, &allocated, "<a href=\"/\">/</a>");
|
||||||
|
|
||||||
// create a link for each token in URL
|
// create a link for each token in URL
|
||||||
do {
|
do {
|
||||||
LOG(LVL_DUMP, "Found token of %s: %s", url, token);
|
LOG(LVL_DUMP, "Found token of %s: %s", url, token);
|
||||||
|
|
||||||
|
// TODO: check if this is safe
|
||||||
strcat(fullpath, token);
|
strcat(fullpath, token);
|
||||||
strcat(fullpath, "/");
|
strcat(fullpath, "/");
|
||||||
|
|
||||||
snprintf(buf, BUFSIZE, " <a href=\"%s\">%s</a> /", fullpath, token);
|
snprintf(buf, BUFSIZE, " <a href=\"%s\">%s</a> /", fullpath, token);
|
||||||
strcat(result, buf);
|
result = safe_append(result, &allocated, buf);
|
||||||
}
|
}
|
||||||
while((token = strtok(NULL, "/")) != NULL);
|
while((token = strtok(NULL, "/")) != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(urlclone);
|
free(urlclone);
|
||||||
|
|
||||||
strcat(result, "</p>");
|
result = safe_append(result, &allocated, "</p>");
|
||||||
|
|
||||||
// begin listing subdirs
|
// begin listing subdirs
|
||||||
strcat(result, "<h2>Sub-directories</h2>");
|
result = safe_append(result, &allocated, "<h2>Sub-directories</h2>");
|
||||||
strcat(result, "<ul>");
|
result = safe_append(result, &allocated, "<ul>");
|
||||||
|
|
||||||
for(i = 0; i < numentries; i++) {
|
for(i = 0; i < numentries; i++) {
|
||||||
// skip all non-directories
|
// skip all non-directories
|
||||||
|
@ -135,21 +135,6 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
|
||||||
|
|
||||||
urlencode(entries[i].name, encName);
|
urlencode(entries[i].name, encName);
|
||||||
|
|
||||||
size_t entrylen = 64 + strlen(url) + strlen(entries[i].name) + strlen(encName);
|
|
||||||
size_t resultlen = strlen(result);
|
|
||||||
|
|
||||||
if(allocated < resultlen + entrylen) {
|
|
||||||
allocated = 2*allocated + entrylen; // be on the safe side
|
|
||||||
LOG(LVL_DEBUG, "reallocating result string (subdirs) - new size: %lu bytes", allocated * sizeof(char));
|
|
||||||
char *tmpresult = realloc(result, allocated * sizeof(char));
|
|
||||||
if(!tmpresult) {
|
|
||||||
LOG(LVL_ERR, "realloc failed for result string: %s", strerror(errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = tmpresult;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isrootdir) {
|
if(isrootdir) {
|
||||||
snprintf(buf, BUFSIZE, "<li><a href=\"/%s/\">%s/</a></li>\n",
|
snprintf(buf, BUFSIZE, "<li><a href=\"/%s/\">%s/</a></li>\n",
|
||||||
encName, entries[i].name);
|
encName, entries[i].name);
|
||||||
|
@ -157,14 +142,14 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
|
||||||
snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s/\">%s/</a></li>\n",
|
snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s/\">%s/</a></li>\n",
|
||||||
url, encName, entries[i].name);
|
url, encName, entries[i].name);
|
||||||
}
|
}
|
||||||
strcat(result, buf);
|
result = safe_append(result, &allocated, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcat(result, "</ul>");
|
result = safe_append(result, &allocated, "</ul>");
|
||||||
|
|
||||||
// begin listing files
|
// begin listing files
|
||||||
strcat(result, "<h2>Files</h2>");
|
result = safe_append(result, &allocated, "<h2>Files</h2>");
|
||||||
strcat(result, "<ul>");
|
result = safe_append(result, &allocated, "<ul>");
|
||||||
|
|
||||||
// here the listing entries are generated
|
// here the listing entries are generated
|
||||||
for(i = 0; i < numentries; i++) {
|
for(i = 0; i < numentries; i++) {
|
||||||
|
@ -174,21 +159,6 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
|
||||||
|
|
||||||
urlencode(entries[i].name, encName);
|
urlencode(entries[i].name, encName);
|
||||||
|
|
||||||
size_t entrylen = 64 + strlen(url) + strlen(entries[i].name) + strlen(encName);
|
|
||||||
size_t resultlen = strlen(result);
|
|
||||||
|
|
||||||
if(allocated < resultlen + entrylen) {
|
|
||||||
allocated = 2*allocated + entrylen; // be on the safe side
|
|
||||||
LOG(LVL_DEBUG, "reallocating result string (files) - new size: %lu bytes", allocated * sizeof(char));
|
|
||||||
char *tmpresult = realloc(result, allocated * sizeof(char));
|
|
||||||
if(!tmpresult) {
|
|
||||||
LOG(LVL_ERR, "realloc failed for result string: %s", strerror(errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = tmpresult;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isrootdir) {
|
if(isrootdir) {
|
||||||
snprintf(buf, BUFSIZE, "<li><a href=\"/%s\">%s</a> [%s]</li>\n",
|
snprintf(buf, BUFSIZE, "<li><a href=\"/%s\">%s</a> [%s]</li>\n",
|
||||||
encName, entries[i].name, format_size(entries[i].size));
|
encName, entries[i].name, format_size(entries[i].size));
|
||||||
|
@ -196,15 +166,15 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
|
||||||
snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s\">%s</a> [%s]</li>\n",
|
snprintf(buf, BUFSIZE, "<li><a href=\"%s/%s\">%s</a> [%s]</li>\n",
|
||||||
url, encName, entries[i].name, format_size(entries[i].size));
|
url, encName, entries[i].name, format_size(entries[i].size));
|
||||||
}
|
}
|
||||||
strcat(result, buf);
|
result = safe_append(result, &allocated, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcat(result, "</ul>");
|
result = safe_append(result, &allocated, "</ul>");
|
||||||
|
|
||||||
if(uploadEnabled) {
|
if(uploadEnabled) {
|
||||||
strcat(result, "<h2>Upload</h2>");
|
result = safe_append(result, &allocated, "<h2>Upload</h2>");
|
||||||
strcat(result, "<p>Upload a file to this directory:</p>");
|
result = safe_append(result, &allocated, "<p>Upload a file to this directory:</p>");
|
||||||
strcat(result,
|
result = safe_append(result, &allocated,
|
||||||
"<p>"
|
"<p>"
|
||||||
" <form method=\"POST\" action=\".\" enctype=\"multipart/form-data\">"
|
" <form method=\"POST\" action=\".\" enctype=\"multipart/form-data\">"
|
||||||
" <input name=\"data\" type=\"file\" size=\"30\">"
|
" <input name=\"data\" type=\"file\" size=\"30\">"
|
||||||
|
@ -214,7 +184,7 @@ char* gen_html(const char *url, struct Entry *entries, size_t numentries, int up
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcat(result, FOOTER);
|
result = safe_append(result, &allocated, FOOTER);
|
||||||
|
|
||||||
LOG(LVL_DEBUG, "result string (files) usage: %lu/%lu bytes", strlen(result), allocated);
|
LOG(LVL_DEBUG, "result string (files) usage: %lu/%lu bytes", strlen(result), allocated);
|
||||||
|
|
||||||
|
|
34
src/util.c
34
src/util.c
|
@ -11,8 +11,11 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
void remove_trailing_slash(char *str) {
|
void remove_trailing_slash(char *str) {
|
||||||
size_t offset = strlen(str)-1;
|
size_t offset = strlen(str)-1;
|
||||||
|
@ -49,3 +52,34 @@ void urlencode(const char *str, char *result) {
|
||||||
str++;
|
str++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Append src to target, reallocating target on the way if necessary.
|
||||||
|
*
|
||||||
|
* \param target The string to append to.
|
||||||
|
* \param targetsize A pointer to the size of target. Will be updated by this
|
||||||
|
* function when target is reallocated.
|
||||||
|
* \param src The string to append to target.
|
||||||
|
* \returns A pointer to new string (target becomes invalid in the
|
||||||
|
* event of reallocation) or NULL on a realloc error.
|
||||||
|
*/
|
||||||
|
char* safe_append(char *target, size_t *targetsize, const char *src) {
|
||||||
|
size_t targetlen = strlen(target);
|
||||||
|
size_t srclen = strlen(src);
|
||||||
|
size_t newsize = targetlen + 2*srclen + 1;
|
||||||
|
|
||||||
|
// check if reallocation is necessary
|
||||||
|
if((targetlen + srclen) > *targetsize) {
|
||||||
|
LOG(LVL_DEBUG, "safe_append: reallocating target string: %lu -> %lu characters", *targetsize, newsize);
|
||||||
|
|
||||||
|
target = realloc(target, newsize * sizeof(char));
|
||||||
|
if(target == NULL) {
|
||||||
|
LOG(LVL_ERR, "safe_append: realloc failed: %s", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*targetsize = newsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return strcat(target, src);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue