Possible crash at userlog_read() when an argument is a null pointer

This commit is contained in:
xboi209 2016-08-05 00:48:42 -07:00
parent 0a57d3f700
commit 179c547459
2 changed files with 80 additions and 68 deletions

View file

@ -17,12 +17,14 @@
*/
#include "common/setup_before.h"
#include <algorithm>
#include <cctype>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <string>
#include "compat/strcasecmp.h"
#include "compat/pdir.h"
@ -153,80 +155,81 @@ namespace pvpgn
}
// read "count" lines from the end starting from "startline"
extern std::map<long, char*> userlog_read(const char * username, long startline, const char * search_substr)
extern std::map<long, char*> userlog_read(const char* username, long startline, const char* search_substr)
{
std::map<long, char*> lines;
if (!username)
throw std::exception("username is a nullptr");
FILE* fp = std::fopen(userlog_filename(username), "r");
if (!fp)
throw std::exception("Could not open userlog");
// set position to the end of file
std::fseek(fp, 0, SEEK_END);
long pos = std::ftell(fp);
char c = {}, prev_c = {};
std::map<long, char*> lines;
long linecount = 0;
char line[MAX_MESSAGE_LEN+1];
char line[MAX_MESSAGE_LEN + 1] = {};
int linepos = 0;
char c, prev_c = 0;
long pos;
size_t search_substrlen = std::strlen(search_substr);
char * filename = userlog_filename(username);
if (FILE *fp = fopen(filename, "r"))
// read file in reverse, byte by byte
do
{
// set position to the end of file
fseek(fp, 0, SEEK_END);
pos = ftell(fp);
pos--;
std::fseek(fp, pos, SEEK_SET);
c = std::fgetc(fp);
// read file reversely by byte
do {
pos--;
fseek(fp, pos, SEEK_SET);
c = fgetc(fp);
// add char into line array
if (c != '\n')
line[linepos] = c;
// add char into line array
if (c != '\n')
line[linepos] = c;
// end of line (or start of file)
if ((c == '\n' && c != prev_c) || pos == -1)
// end of line (or start of file)
if ((c == '\n' && c != prev_c) || pos == -1)
{
// hack for large lines (instead we will receive cut line without start symbols)
if (linepos == MAX_MESSAGE_LEN)
{
// hack for large lines (instead we will receive cut line without start symbols)
if (linepos == MAX_MESSAGE_LEN)
{
// return carriage to read whole line to(from) start
pos = pos + MAX_MESSAGE_LEN;
linepos = 0;
}
if (linepos > 0)
{
line[linepos] = '\0'; // set end of string
strreverse(line);
linepos = 0; // reset position inside line
linecount++;
if (linecount >= startline)
{
if (search_substr && search_substrlen > 0)
{
if (find_substr(line, search_substr))
lines[linecount] = xstrdup(line);
}
else
{
lines[linecount] = xstrdup(line);
}
}
// limitation of results
if (lines.size() >= userlog_max_output_lines)
break;
}
// return carriage to read whole line to(from) start
pos = pos + MAX_MESSAGE_LEN;
linepos = 0;
}
prev_c = c;
if (c != '\n' && linepos < MAX_MESSAGE_LEN)
linepos++;
} while (c != EOF);
if (linepos > 0)
{
line[linepos] = '\0'; // set end of string
strreverse(line);
linepos = 0; // reset position inside line
linecount++;
if (linecount >= startline)
{
if (search_substr && std::strlen(search_substr) > 0)
{
if (find_substr(line, search_substr))
lines[linecount] = xstrdup(line);
}
else
{
lines[linecount] = xstrdup(line);
}
}
// limitation of results
if (lines.size() >= userlog_max_output_lines)
break;
}
}
prev_c = c;
if (c != '\n' && linepos < MAX_MESSAGE_LEN)
linepos++;
} while (c != EOF);
std::fclose(fp);
fclose(fp);
}
return lines;
}
@ -306,7 +309,15 @@ namespace pvpgn
if (!args[3].empty())
startline = atoi(args[3].c_str());
lines = userlog_read(username, startline);
try
{
lines = userlog_read(username, startline);
}
catch (const std::exception& e)
{
message_send_text(c, message_type_error, c, "Could not read user log");
return 0;
}
}
// find
else if (subcommand[0] == 'f')

View file

@ -20,9 +20,10 @@
#ifndef INCLUDED_USERLOGS_PROTOS
#define INCLUDED_USERLOGS_PROTOS
#define JUST_NEED_TYPES
#include <string>
#include <vector>
#define JUST_NEED_TYPES
#include "connection.h"
#undef JUST_NEED_TYPES
@ -34,7 +35,7 @@ namespace pvpgn
extern void userlog_init();
extern void userlog_append(t_account * account, const char * text);
extern std::map<long, char*> userlog_read(const char * username, long startline, const char * search_substr = NULL);
extern std::map<long, char*> userlog_read(const char* username, long startline, const char* search_substr = nullptr);
extern std::map<long, char*> userlog_find_text(const char * username, const char * search_substr, long startline);
extern char * userlog_filename(const char * username, bool force_create_path = false);