added: possibility to encode the session cookie (added files core/sessionidmanager.h and core/sessionidmanager.cpp)

added: config options:
       // whether or not we should encode the session cookie
       // (we have a special algorithm)
       // default: false
       bool session_cookie_encode;

       // if session_cookie_encode is true then you should provide
       // a file where AES keys will be stored
       std::wstring session_keys_file;

       // each session has an index -- an unsigned int value
       // this value is sent in the cookie string (is encoded)
       // and is incremented when session_index_time_increment time is passed since the last incrementing
       // if a client sent the cookie back the difference between
       // current index and the index in the cookie should be less than or equal to session_allow_index_difference
       // default: 8
       size_t session_allow_index_difference;

       // the time which should pass after the session index is incremented
       // default: 30
       // (session_allow_index_difference + 1) * session_index_time_increment should be less than a time
       // load of a page and all elements on it such as images (of course it depends on client's download too)
       time_t session_index_time_increment;

       // time in seconds after a new AES key pair should be generated
       // we have 256 pairs of keys so this time multiplied by 256 should not be less than
       // the max time of a session (session_remember_max_idle),
       // by default: 256 * 2 days = 512 days = 1.4 year > 3 months (session_remember_max_idle)
       // default: 172800 = 2 days (max: 2678400 = 1 month, min: 10)
       size_t session_key_renew_time;

changed: when printing the time of a request we print only two non-zero digits






git-svn-id: svn://ttmath.org/publicrep/winix/trunk@994 e52654a7-88a9-db11-a3e9-0013d4bc506e
pull/3/head
Tomasz Sowa 8 years ago
parent 3547d326b8
commit 76314aab10

File diff suppressed because one or more lines are too long

@ -40,32 +40,33 @@ app.o: ../../winix/notify/templatesnotify.h ../../winix/core/config.h
app.o: ../../winix/core/users.h ugcontainer.h lastcontainer.h mounts.h
app.o: mountparser.h crypt.h run.h users.h groups.h group.h loadavg.h image.h
app.o: threadmanager.h timezones.h timezone.h sessionmanager.h
app.o: sessioncontainer.h ipbancontainer.h ../../winix/functions/functions.h
app.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
app.o: ../../winix/core/system.h ../../winix/core/synchro.h
app.o: ../../winix/functions/functionparser.h ../../winix/core/cur.h
app.o: ../../winix/functions/account.h ../../winix/functions/adduser.h
app.o: ../../winix/functions/cat.h ../../winix/functions/chmod.h
app.o: ../../winix/functions/privchanger.h ../../winix/functions/chown.h
app.o: ../../winix/functions/ckeditor.h ../../winix/functions/cp.h
app.o: ../../winix/functions/default.h ../../winix/functions/download.h
app.o: ../../winix/functions/emacs.h ../../winix/functions/env.h
app.o: ../../winix/functions/imgcrop.h ../../winix/functions/last.h
app.o: ../../winix/functions/login.h ../../winix/functions/logout.h
app.o: ../../winix/functions/ln.h ../../winix/functions/ls.h
app.o: ../../winix/functions/man.h ../../winix/functions/meta.h
app.o: ../../winix/functions/mkdir.h ../../winix/functions/mv.h
app.o: ../../winix/functions/nicedit.h ../../winix/functions/node.h
app.o: ../../winix/functions/passwd.h ../../winix/functions/priv.h
app.o: ../../winix/functions/pw.h ../../winix/functions/reload.h
app.o: ../../winix/functions/rm.h ../../winix/functions/rmuser.h
app.o: ../../winix/functions/sort.h ../../winix/functions/specialdefault.h
app.o: ../../winix/functions/stat.h ../../winix/functions/subject.h
app.o: ../../winix/functions/template.h ../../winix/functions/tinymce.h
app.o: ../../winix/functions/uname.h ../../winix/functions/upload.h
app.o: ../../winix/functions/uptime.h ../../winix/functions/who.h
app.o: ../../winix/functions/vim.h ../../winix/core/htmlfilter.h
app.o: ../../winix/templates/templates.h
app.o: sessioncontainer.h ipbancontainer.h sessionidmanager.h
app.o: ../../tito/src/base64.h ../../tito/src/aes.h
app.o: ../../winix/functions/functions.h ../../winix/functions/functionbase.h
app.o: ../../winix/core/request.h ../../winix/core/system.h
app.o: ../../winix/core/synchro.h ../../winix/functions/functionparser.h
app.o: ../../winix/core/cur.h ../../winix/functions/account.h
app.o: ../../winix/functions/adduser.h ../../winix/functions/cat.h
app.o: ../../winix/functions/chmod.h ../../winix/functions/privchanger.h
app.o: ../../winix/functions/chown.h ../../winix/functions/ckeditor.h
app.o: ../../winix/functions/cp.h ../../winix/functions/default.h
app.o: ../../winix/functions/download.h ../../winix/functions/emacs.h
app.o: ../../winix/functions/env.h ../../winix/functions/imgcrop.h
app.o: ../../winix/functions/last.h ../../winix/functions/login.h
app.o: ../../winix/functions/logout.h ../../winix/functions/ln.h
app.o: ../../winix/functions/ls.h ../../winix/functions/man.h
app.o: ../../winix/functions/meta.h ../../winix/functions/mkdir.h
app.o: ../../winix/functions/mv.h ../../winix/functions/nicedit.h
app.o: ../../winix/functions/node.h ../../winix/functions/passwd.h
app.o: ../../winix/functions/priv.h ../../winix/functions/pw.h
app.o: ../../winix/functions/reload.h ../../winix/functions/rm.h
app.o: ../../winix/functions/rmuser.h ../../winix/functions/sort.h
app.o: ../../winix/functions/specialdefault.h ../../winix/functions/stat.h
app.o: ../../winix/functions/subject.h ../../winix/functions/template.h
app.o: ../../winix/functions/tinymce.h ../../winix/functions/uname.h
app.o: ../../winix/functions/upload.h ../../winix/functions/uptime.h
app.o: ../../winix/functions/who.h ../../winix/functions/vim.h
app.o: ../../winix/core/htmlfilter.h ../../winix/templates/templates.h
app.o: ../../winix/templates/patterncacher.h
app.o: ../../winix/templates/indexpatterns.h ../../winix/templates/patterns.h
app.o: ../../winix/templates/changepatterns.h
@ -121,6 +122,7 @@ config.o: ../../winix/core/config.h ../../winix/core/users.h ugcontainer.h
config.o: lastcontainer.h mounts.h mountparser.h crypt.h run.h users.h
config.o: groups.h group.h loadavg.h image.h threadmanager.h timezones.h
config.o: timezone.h sessionmanager.h sessioncontainer.h ipbancontainer.h
config.o: sessionidmanager.h ../../tito/src/base64.h ../../tito/src/aes.h
config.o: ../../winix/functions/functions.h
config.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
config.o: ../../winix/core/system.h ../../winix/core/synchro.h
@ -274,6 +276,7 @@ image.o: ../../winix/core/users.h ugcontainer.h lastcontainer.h mounts.h
image.o: mountparser.h crypt.h run.h users.h groups.h group.h loadavg.h
image.o: threadmanager.h timezones.h timezone.h plugin.h pluginmsg.h
image.o: sessionmanager.h sessioncontainer.h ipbancontainer.h
image.o: sessionidmanager.h ../../tito/src/base64.h ../../tito/src/aes.h
image.o: ../../winix/functions/functions.h
image.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
image.o: ../../winix/core/system.h ../../winix/core/synchro.h
@ -363,6 +366,7 @@ job.o: ../../winix/core/config.h ../../winix/core/users.h ugcontainer.h
job.o: lastcontainer.h mounts.h mountparser.h crypt.h run.h users.h groups.h
job.o: group.h loadavg.h image.h threadmanager.h timezones.h timezone.h
job.o: sessionmanager.h sessioncontainer.h ipbancontainer.h
job.o: sessionidmanager.h ../../tito/src/base64.h ../../tito/src/aes.h
job.o: ../../winix/functions/functions.h ../../winix/functions/functionbase.h
job.o: ../../winix/core/request.h ../../winix/core/system.h
job.o: ../../winix/core/synchro.h ../../winix/functions/functionparser.h
@ -541,6 +545,7 @@ mounts.o: lastcontainer.h mountparser.h plugin.h pluginmsg.h system.h job.h
mounts.o: basethread.h synchro.h crypt.h run.h users.h groups.h group.h
mounts.o: loadavg.h image.h threadmanager.h timezones.h timezone.h
mounts.o: sessionmanager.h sessioncontainer.h ipbancontainer.h
mounts.o: sessionidmanager.h ../../tito/src/base64.h ../../tito/src/aes.h
mounts.o: ../../winix/functions/functions.h
mounts.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
mounts.o: ../../winix/core/system.h ../../winix/core/synchro.h
@ -604,7 +609,8 @@ plugin.o: ../../winix/notify/templatesnotify.h ../../winix/core/config.h
plugin.o: ../../winix/core/users.h ugcontainer.h lastcontainer.h mounts.h
plugin.o: mountparser.h crypt.h run.h users.h groups.h group.h loadavg.h
plugin.o: image.h threadmanager.h timezones.h timezone.h sessionmanager.h
plugin.o: sessioncontainer.h ipbancontainer.h
plugin.o: sessioncontainer.h ipbancontainer.h sessionidmanager.h
plugin.o: ../../tito/src/base64.h ../../tito/src/aes.h
plugin.o: ../../winix/functions/functions.h
plugin.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
plugin.o: ../../winix/core/system.h ../../winix/core/synchro.h
@ -672,7 +678,8 @@ plugindata.o: ../../winix/notify/templatesnotify.h ../../winix/core/config.h
plugindata.o: ../../winix/core/users.h ugcontainer.h lastcontainer.h mounts.h
plugindata.o: mountparser.h crypt.h run.h users.h groups.h group.h loadavg.h
plugindata.o: image.h threadmanager.h timezones.h timezone.h sessionmanager.h
plugindata.o: sessioncontainer.h ipbancontainer.h
plugindata.o: sessioncontainer.h ipbancontainer.h sessionidmanager.h
plugindata.o: ../../tito/src/base64.h ../../tito/src/aes.h
plugindata.o: ../../winix/functions/functions.h
plugindata.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
plugindata.o: ../../winix/core/system.h ../../winix/core/synchro.h
@ -768,6 +775,7 @@ request.o: ../../winix/core/config.h ../../winix/core/users.h ugcontainer.h
request.o: lastcontainer.h mounts.h mountparser.h crypt.h run.h users.h
request.o: groups.h group.h loadavg.h image.h threadmanager.h timezones.h
request.o: timezone.h sessionmanager.h sessioncontainer.h ipbancontainer.h
request.o: sessionidmanager.h ../../tito/src/base64.h ../../tito/src/aes.h
request.o: ../../winix/functions/functions.h
request.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
request.o: ../../winix/core/system.h ../../winix/core/synchro.h
@ -839,6 +847,23 @@ sessioncontainer.o: ../../winix/core/textstream.h misc.h
sessioncontainer.o: ../../pikotools/utf8/utf8.h winix_const.h
sessioncontainer.o: ../../pikotools/space/spacetojson.h mount.h log.h
sessioncontainer.o: logmanipulators.h slog.h ../../winix/templates/locale.h
sessionidmanager.o: sessionidmanager.h ../../tito/src/base64.h
sessionidmanager.o: ../../pikotools/space/space.h
sessionidmanager.o: ../../pikotools/textstream/types.h ../../tito/src/aes.h
sessionidmanager.o: ../../pikotools/space/spaceparser.h
sessionidmanager.o: ../../pikotools/space/space.h ../../pikotools/utf8/utf8.h
sessionidmanager.o: ../../pikotools/date/date.h log.h textstream.h
sessionidmanager.o: logmanipulators.h ../../pikotools/textstream/textstream.h
sessionidmanager.o: ../../pikotools/convert/convert.h
sessionidmanager.o: ../../pikotools/convert/inttostr.h
sessionidmanager.o: ../../pikotools/membuffer/membuffer.h
sessionidmanager.o: ../../pikotools/textstream/types.h slog.h cur.h request.h
sessionidmanager.o: requesttypes.h item.h error.h config.h htmlfilter.h
sessionidmanager.o: ../../winix/templates/htmltextstream.h
sessionidmanager.o: ../../winix/core/textstream.h misc.h winix_const.h
sessionidmanager.o: ../../pikotools/space/spacetojson.h session.h user.h
sessionidmanager.o: plugindata.h rebus.h ipban.h mount.h
sessionidmanager.o: ../../winix/templates/locale.h
sessionmanager.o: sessionmanager.h sessioncontainer.h session.h item.h
sessionmanager.o: ../../pikotools/space/space.h
sessionmanager.o: ../../pikotools/textstream/types.h
@ -879,7 +904,9 @@ sessionmanager.o: ../../winix/notify/templatesnotify.h
sessionmanager.o: ../../winix/core/config.h ../../winix/core/users.h
sessionmanager.o: ugcontainer.h mounts.h mountparser.h crypt.h run.h users.h
sessionmanager.o: groups.h group.h loadavg.h image.h threadmanager.h
sessionmanager.o: timezones.h timezone.h sessionparser.h plugin.h pluginmsg.h
sessionmanager.o: timezones.h timezone.h sessionidmanager.h
sessionmanager.o: ../../tito/src/base64.h ../../tito/src/aes.h
sessionmanager.o: sessionparser.h plugin.h pluginmsg.h
sessionmanager.o: ../../winix/functions/functions.h
sessionmanager.o: ../../winix/functions/functionbase.h
sessionmanager.o: ../../winix/core/request.h ../../winix/core/system.h
@ -1013,7 +1040,8 @@ system.o: ../../winix/functions/template.h ../../winix/functions/tinymce.h
system.o: ../../winix/functions/uname.h ../../winix/functions/upload.h
system.o: ../../winix/functions/uptime.h ../../winix/functions/who.h
system.o: ../../winix/functions/vim.h plugin.h pluginmsg.h sessionmanager.h
system.o: sessioncontainer.h ipbancontainer.h
system.o: sessioncontainer.h ipbancontainer.h sessionidmanager.h
system.o: ../../tito/src/base64.h ../../tito/src/aes.h
threadmanager.o: threadmanager.h basethread.h synchro.h log.h textstream.h
threadmanager.o: logmanipulators.h ../../pikotools/textstream/textstream.h
threadmanager.o: ../../pikotools/space/space.h
@ -1088,7 +1116,8 @@ users.o: ../../ezc/src/patternparser.h ../../winix/notify/notifythread.h
users.o: ../../winix/core/basethread.h ../../winix/notify/templatesnotify.h
users.o: ../../winix/core/config.h ../../winix/core/users.h ugcontainer.h
users.o: mounts.h mountparser.h crypt.h run.h groups.h group.h loadavg.h
users.o: image.h threadmanager.h timezones.h timezone.h plugin.h pluginmsg.h
users.o: image.h threadmanager.h timezones.h timezone.h sessionidmanager.h
users.o: ../../tito/src/base64.h ../../tito/src/aes.h plugin.h pluginmsg.h
users.o: ../../winix/functions/functions.h
users.o: ../../winix/functions/functionbase.h ../../winix/core/request.h
users.o: ../../winix/core/system.h ../../winix/core/synchro.h

@ -1 +1 @@
o = acceptbaseparser.o app.o basethread.o bbcodeparser.o compress.o config.o crypt.o dircontainer.o dirs.o groups.o htmlfilter.o httpsimpleparser.o image.o ipbancontainer.o item.o job.o lastcontainer.o loadavg.o lock.o log.o misc.o mount.o mountparser.o mounts.o plugin.o plugindata.o postmultiparser.o rebus.o request.o run.o session.o sessioncontainer.o sessionmanager.o sessionparser.o slog.o synchro.o system.o threadmanager.o timezone.o timezones.o user.o users.o
o = acceptbaseparser.o app.o basethread.o bbcodeparser.o compress.o config.o crypt.o dircontainer.o dirs.o groups.o htmlfilter.o httpsimpleparser.o image.o ipbancontainer.o item.o job.o lastcontainer.o loadavg.o lock.o log.o misc.o mount.o mountparser.o mounts.o plugin.o plugindata.o postmultiparser.o rebus.o request.o run.o session.o sessioncontainer.o sessionidmanager.o sessionmanager.o sessionparser.o slog.o synchro.o system.o threadmanager.o timezone.o timezones.o user.o users.o

@ -221,8 +221,10 @@ bool App::Init()
// init notify after templates (it uses locales from templates)
system.notify.ReadTemplates();
session_manager.InitBanList();
session_manager.InitTmpSession();
session_manager.InitBanList();
session_manager.InitCookieEncoding();
session_manager.LoadSessions();
CreateStaticTree();
@ -860,25 +862,35 @@ void App::CheckKonqueror()
void App::PrepareSessionCookie()
{
if( !cur.session || cur.session->id==0 )
return;
if( config.session_cookie_encode )
{
if( !session_manager.EncodeSessionId(cur.session->id, cur.session->id_index, cookie_id_string) )
Toa(cur.session->id, cookie_id_string);
}
else
{
Toa(cur.session->id, cookie_id_string);
}
if( !cur.session->puser || !cur.session->remember_me )
{
cur.request->AddCookie(config.http_session_id_name, cur.session->id);
cur.request->AddCookie(config.http_session_id_name, cookie_id_string);
}
else
{
PT::Date expires = cur.request->start_time + config.session_remember_max_idle;
cur.request->AddCookie(config.http_session_id_name, cur.session->id, expires);
cur.request->AddCookie(config.http_session_id_name, cookie_id_string, expires);
}
}
bool App::AddHeader(const wchar_t * name, const wchar_t * value)
{
if( !cur.request->out_headers.GetValue(name) )

@ -155,6 +155,7 @@ private:
std::wstring html_filtered;
std::string output_8bit;
BinaryPage compressed_output;
std::wstring cookie_id_string;
bool InitFCGI(char * sock, char * sock_user, char * sock_group);
bool InitFCGIChmodChownSocket(char * sock, char * sock_user, char * sock_group);

@ -216,6 +216,11 @@ void Config::AssignValues(bool stdout_is_closed)
session_remember_max_idle = Int(L"session_remember_max_idle", 16070400); // 3 months
session_file = Text(L"session_file");
session_max = Size(L"session_max", 1000000);
session_cookie_encode = Bool(L"session_cookie_encode", false);
session_keys_file = Text(L"session_keys_file");
session_allow_index_difference = Size(L"session_allow_index_difference", 8);
session_index_time_increment = Long(L"session_index_time_increment", 30);
session_key_renew_time = Size(L"session_key_renew_time", 172800); // 2 days
compression = Bool(L"compression", true);
compression_page_min_size = Size(L"compression_page_min_size", 512);
@ -323,6 +328,12 @@ void Config::SetAdditionalVariables()
locale_files.push_back(L"en");
upload_group_int = GetGroupId(upload_group);
if( session_cookie_encode && session_keys_file.empty() )
session_cookie_encode = false;
if( session_index_time_increment < 0 )
session_index_time_increment = 0;
}

@ -203,6 +203,36 @@ public:
// default: 1000000 (one milion)
size_t session_max;
// whether or not we should encode the session cookie
// (we have a special algorithm)
// default: false
bool session_cookie_encode;
// if session_cookie_encode is true then you should provide
// a file where AES keys will be stored
std::wstring session_keys_file;
// each session has an index -- an unsigned int value
// this value is sent in the cookie string (is encoded)
// and is incremented when session_index_time_increment time is passed since the last incrementing
// if a client sent the cookie back the difference between
// current index and the index in the cookie should be less than or equal to session_allow_index_difference
// default: 8
size_t session_allow_index_difference;
// the time which should pass after the session index is incremented
// default: 30
// (session_allow_index_difference + 1) * session_index_time_increment should be less than a time
// load of a page and all elements on it such as images (of course it depends on client's download too)
time_t session_index_time_increment;
// time in seconds after a new AES key pair should be generated
// we have 256 pairs of keys so this time multiplied by 256 should not be less than
// the max time of a session (session_remember_max_idle),
// by default: 256 * 2 days = 512 days = 1.4 year > 3 months (session_remember_max_idle)
// default: 172800 = 2 days (max: 2678400 = 1 month, min: 10)
size_t session_key_renew_time;
// allow the winix output to be compressed
// default: true
bool compression;

@ -201,8 +201,12 @@ void LoadAvg::StartRequest()
void LoadAvg::StopRequest()
{
char buf[50];
clock_gettime(CLOCK_REALTIME, &stop_req);
double dr = (stop_req.tv_sec - start_req.tv_sec);
@ -216,7 +220,10 @@ void LoadAvg::StopRequest()
current5.req += 1;
current15.req += 1;
log << log2 << "LA: request took: " << dr << "s" << logend;
sprintf(buf, "%f", dr);
SetNonZeroDigitsAfterComma(buf, 2);
log << log2 << "LA: request took: " << buf << "s" << logend;
was_stop_request = true;
}

@ -236,6 +236,43 @@ size_t len = sizeof(buffer) / sizeof(wchar_t);
void SetNonZeroDigitsAfterComma(char * str, size_t digits)
{
bool was_comma = false;
bool was_not_zero = false;
size_t zeroes = 0;
size_t not_zeroes = 0;
for(size_t i=0 ; str[i] != 0 ; ++i)
{
if( str[i] == '.' || str[i] == ',' )
{
was_comma = true;
}
else
if( was_comma )
{
if( str[i] == '0' && !was_not_zero )
{
zeroes += 1;
}
else
{
was_not_zero = true;
not_zeroes += 1;
if( not_zeroes >= digits )
{
str[i+1] = 0;
break;
}
}
}
}
}
bool CorrectUrlChar(wchar_t c)
{

@ -214,6 +214,20 @@ void Toa(int value, std::wstring & res, int base = 10, bool clear = true);
void Toa(long value, std::wstring & res, int base = 10, bool clear = true);
/*
* this method make sure that there is no more than 'digits' non zero digits
* in the given string
*
*
* samples (if parameter 'digits' is equal to two):
* "0.0001234" -> "0.00012"
* "10" -> "10"
* "123.345" -> "123.34"
* "55.1003" -> "55.10"
*
*/
void SetNonZeroDigitsAfterComma(char * str, size_t digits);
bool CorrectUrlChar(wchar_t c);
void CorrectUrlDots(std::wstring & url);

@ -89,18 +89,20 @@ void Session::SetTimesTo(time_t time)
// clear_plugin_data is used when clearing the temporary session
void Session::Clear(bool clear_plugin_data)
{
id = 0;
puser = 0;
rebus_item = 0;
rebus_checked = false;
remember_me = false;
new_session = true;
spam_score = 0;
remove_me = false;
start_time = 0;
last_time = 0;
last_time_get = 0;
id = 0;
id_index = 0;
id_index_changed = 0;
puser = 0;
rebus_item = 0;
rebus_checked = false;
remember_me = false;
new_session = true;
spam_score = 0;
remove_me = false;
start_time = 0;
last_time = 0;
last_time_get = 0;
start_date.Clear();
last_date.Clear();

@ -67,6 +67,13 @@ struct Session
// 0 - means that there is a temporary session
long id;
// a session index
// incremented each time a request to this session is made
unsigned int id_index;
// the last time when id_index was incremented
time_t id_index_changed;
// true if the session was created now
bool new_session;

@ -0,0 +1,561 @@
/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2014, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include "sessionidmanager.h"
#include "space/spaceparser.h"
#include "utf8/utf8.h"
#include "date/date.h"
#include "log.h"
#include "misc.h"
namespace Winix
{
SessionIdManager::SessionIdManager()
{
algorithm_type = 'a';
key_tab_size = 256;
key_index = 0;
last_key_generated = 0;
key_renew_time = 60;
was_inited = false;
}
void SessionIdManager::Init(const std::wstring & keys_file)
{
was_inited = true;
key_tab1.resize(key_tab_size);
key_tab2.resize(key_tab_size);
aes1.resize(key_tab_size);
aes2.resize(key_tab_size);
key_file_name = keys_file;
ReadKeysFromFile(key_file_name);
}
void SessionIdManager::SetKeyRenewTime(time_t renew_time)
{
key_renew_time = renew_time;
if( key_renew_time < 10 )
key_renew_time = 10;
time_t one_month = 60 * 60 * 24 * 31;
if( key_renew_time > one_month )
key_renew_time = one_month;
}
void SessionIdManager::ReadKey(const wchar_t * name, PT::Space & space, std::vector<std::string> & dest_key)
{
std::vector<std::wstring> keys;
std::string key_ascii, key_base64_decoded;
space.ListText(name, keys);
for(size_t i=0 ; i<key_tab_size ; ++i)
dest_key[i].clear();
for(size_t i=0 ; i<keys.size() && i<key_tab_size ; ++i)
{
dest_key[i].clear();
if( PT::WideToUTF8(keys[i], key_ascii) )
{
if( base64.Decode(key_ascii, key_base64_decoded) )
{
size_t len = key_base64_decoded.size();
if( len == 16 || len == 24 || len == 32 )
{
dest_key[i] = key_base64_decoded;
}
}
}
}
}
void SessionIdManager::InitializeAesKeys(size_t index)
{
if( !aes1[index].Key((unsigned char*)key_tab1[index].c_str(), key_tab1[index].size()) )
log << log1 << "SIM: I cannot initialize a key1, size of the key: " << key_tab1[index].size() << logend;
if( !aes2[index].Key((unsigned char*)key_tab2[index].c_str(), key_tab2[index].size()) )
log << log1 << "SIM: I cannot initialize a key2, size of the key: " << key_tab2[index].size() << logend;
}
void SessionIdManager::InitializeAesKeys()
{
for(size_t i=0 ; i < key_tab_size ; ++i)
{
if( AreKeysCorrect(i) )
InitializeAesKeys(i);
}
}
bool SessionIdManager::ReadKeysFromFile(const wchar_t * file)
{
PT::Space space;
PT::SpaceParser parser;
PT::Date date;
parser.SetSpace(space);
PT::SpaceParser::Status status = parser.Parse(file);
if( status == PT::SpaceParser::ok )
{
key_index = space.Size(L"key_index");
if( key_index >= 256 )
key_index = 0;
if( date.Parse(space.Text(L"last_key_generated", L"0")) )
last_key_generated = date.ToTime();
ReadKey(L"key_tab1", space, key_tab1);
ReadKey(L"key_tab2", space, key_tab2);
InitializeAesKeys();
}
else
{
log << log1 << "SIM: I cannot read the session keys from: " << file << logend;
}
return status == PT::SpaceParser::ok;
}
bool SessionIdManager::ReadKeysFromFile(const std::wstring & file)
{
return ReadKeysFromFile(file.c_str());
}
void SessionIdManager::SaveKeysToFile(std::vector<std::string> & keys)
{
out_file << "(\n";
for(size_t i=0 ; i<keys.size() ; ++i)
{
base64.Encode(keys[i], tmp_key_base64_encoded);
out_file << '\"' << tmp_key_base64_encoded << "\"\n";
}
out_file << ")\n\n";
tmp_key_base64_encoded.clear();
}
bool SessionIdManager::SaveKeysToFile(const wchar_t * file)
{
PT::Date date = last_key_generated;
PT::WideToUTF8(file, file_name_ascii);
out_file.clear();
out_file.open(file_name_ascii, std::ios_base::binary | std::ios_base::out);
if( out_file )
{
out_file << "key_index = " << key_index << "\n";
out_file << "last_key_generated = \"";
date.Serialize(out_file);
out_file << "\"\n\n";
out_file << "key_tab1 = ";
SaveKeysToFile(key_tab1);
out_file << "key_tab2 = ";
SaveKeysToFile(key_tab2);
out_file.flush();
}
out_file.close();
file_name_ascii.clear();
SetPriv(file, 0600);
return !out_file.fail();
}
bool SessionIdManager::SaveKeysToFile(const std::wstring & file)
{
return SaveKeysToFile(file.c_str());
}
bool SessionIdManager::AreKeysCorrect(size_t index)
{
if( index >= 256 )
return false;
size_t len = key_tab1[index].size();
if( len != 16 && len != 24 && len != 32 )
return false;
len = key_tab2[index].size();
if( len != 16 && len != 24 && len != 32 )
return false;
return true;
}
/*
* IMPROVE ME
* we need a better algorithm
*/
void SessionIdManager::GenerateKey(std::string & key, time_t cur_utc_time)
{
unsigned int pid = (unsigned int)getpid();
unsigned int t = (unsigned int)cur_utc_time;
key.clear();
for(size_t i=0 ; i<16 ; ++i)
{
unsigned int r = rand();
unsigned int v = r ^ pid ^ t;
v = ((v >> 24) ^ (v >> 16) ^ (v >> 8) ^ v) & 0xff;
key.push_back((unsigned char)v);
}
}
void SessionIdManager::GenerateKeys(size_t index, time_t cur_utc_time)
{
GenerateKey(key_tab1[index], cur_utc_time);
GenerateKey(key_tab2[index], cur_utc_time);
InitializeAesKeys(index);
last_key_generated = cur_utc_time;
if( !SaveKeysToFile(key_file_name) )
log << log2 << "SIM: I cannot save the session keys to: " << key_file_name << logend;
}
void SessionIdManager::CheckKeys(time_t cur_utc_time)
{
if( !AreKeysCorrect(key_index) )
{
log << log1 << "SIM: keys with index: " << key_index << " are incorrect, generating new keys" << logend;
GenerateKeys(key_index, cur_utc_time);
}
else
if( last_key_generated + key_renew_time < cur_utc_time )
{
key_index += 1;
if( key_index >= key_tab_size )
key_index = 0;
log << log2 << "SIM: generating new AES keys with index: " << key_index << logend;
GenerateKeys(key_index, cur_utc_time);
}
}
void SessionIdManager::RandPadding(size_t & pad_top_size, char & pad_top_value,
size_t & pad_bottom_size, char & pad_bottom_value)
{
pad_top_size = (std::rand() * 5) / RAND_MAX; // multiply by 5 (not by 4)
if( pad_top_size > 4 )
pad_top_size = 4;
pad_top_size += 5; // now pad_top_size is from <5;9>
pad_top_value = (char)std::rand();
pad_bottom_size = 14 - pad_top_size; // pad_bottom_size is from <5;9> too
pad_bottom_value = (char)std::rand();
}
void SessionIdManager::AppendSum(std::string & str)
{
int s = 0;
for(size_t i=0 ; i<str.size() ; ++i)
s += (int)(unsigned char)str[i];
str += (unsigned char)s;
}
void SessionIdManager::AppendXor(std::string & str)
{
int s = 0;
for(size_t i=0 ; i<str.size() ; ++i)
s ^= (int)(unsigned char)str[i];
str += (unsigned char)s;
}
void SessionIdManager::CopyString(const std::string & in, std::wstring & out)
{
out.clear();
if( out.capacity() < in.size() )
out.reserve(in.size());
for(size_t i=0 ; i<in.size() ; ++i)
out += in[i];
}
void SessionIdManager::CopyString(const std::wstring & in, std::string & out)
{
out.clear();
if( out.capacity() < in.size() )
out.reserve(in.size());
for(size_t i=0 ; i<in.size() ; ++i)
out += in[i];
}
bool SessionIdManager::Encode(std::string & str)
{
if( str.size() != 34 )
return false;
if( !aes1[key_index].Encode((unsigned char*)string_token.c_str()+2, 16) )
{
log << log1 << "SIM: I cannot AES encode the first part of the token" << logend;
return false;
}
if( !aes2[key_index].Encode((unsigned char*)string_token.c_str()+16+2, 16) )
{
log << log1 << "SIM: I cannot AES encode the second part of the token" << logend;
return false;
}
return true;
}
bool SessionIdManager::EncodeToken(size_t id, unsigned int index, time_t cur_utc_time, std::wstring & token)
{
size_t pad_top_size;
size_t pad_bottom_size;
char pad_top_value;
char pad_bottom_value;
string_token.clear();
string_token.reserve(50);
if( !was_inited )
return false;
CheckKeys(cur_utc_time);
RandPadding(pad_top_size, pad_top_value, pad_bottom_size, pad_bottom_value);
string_token += algorithm_type;
string_token += (unsigned char)key_index;
string_token += pad_top_value;
string_token += pad_bottom_value;
string_token += (unsigned char)pad_top_size;
string_token += (unsigned char)pad_bottom_size;
string_token.append(pad_top_size, pad_top_value);
Append(string_token, id);
Append(string_token, index);
string_token.append(pad_bottom_size, pad_bottom_value);
AppendSum(string_token);
AppendXor(string_token);
if( !Encode(string_token) )
return false;
base64.Encode(string_token, string_token_base64);
CopyString(string_token_base64, token);
return true;
}
bool SessionIdManager::IsPaddingCorrect(const char * str, size_t len, char val)
{
if( len < 5 || len > 9 )
return false;
for(size_t i=0 ; i<len ; ++i)
if( str[i] != val )
return false;
return true;
}
bool SessionIdManager::DecodeAES(const char * str, size_t key)
{
if( !aes1[key].Decode((unsigned char*)str, 16) )
{
log << log1 << "SIM: I cannot AES decode the first block" << logend;
return false;
}
if( !aes2[key].Decode((unsigned char*)str + 16, 16) )
{
log << log1 << "SIM: I cannot AES decode the second block" << logend;
return false;
}
return true;
}
bool SessionIdManager::CheckControlSums(const char * str)
{
char old_sum = *(str++);
char old_xor = *(str++);
string_token.erase(string_token.size()-2);
AppendSum(string_token);
AppendXor(string_token);
if( old_sum != string_token[string_token.size()-2] ||
old_xor != string_token[string_token.size()-1] )
return false;
return true;
}
bool SessionIdManager::DecodeTokenA(size_t & id, unsigned int & index)
{
size_t pad_top_size;
size_t pad_bottom_size;
char pad_top_value;
char pad_bottom_value;
const char * str = string_token.c_str() + 1;
size_t key = (unsigned char)(*str);
str += 1;
if( !DecodeAES(str, key) )
return false;
pad_top_value = *(str++);
pad_bottom_value = *(str++);
pad_top_size = (unsigned char)*(str++);
pad_bottom_size = (unsigned char)*(str++);
if( pad_bottom_size != 14 - pad_top_size )
return false;
if( !IsPaddingCorrect(str, pad_top_size, pad_top_value) )
return false;
str += pad_top_size;
Read(str, id);
str += 8; // sizeof(id), it's better to use constant '8' instead of sizeof() operator
// because at the beginning we are making a test whether the string size is equal to 34
// (in the future sizeof(size_t) can be different from 8)
Read(str, index);
str += 4; // sizeof(index)
if( !IsPaddingCorrect(str, pad_bottom_size, pad_bottom_value) )
return false;
str += pad_bottom_size;
return CheckControlSums(str);
}
bool SessionIdManager::DecodeToken(const std::wstring & token, size_t & id, unsigned int & index)
{
if( !was_inited )
return false;
CopyString(token, string_token_base64);
if( !base64.Decode(string_token_base64, string_token) )
return false;
if( string_token.size() != 34 )
return false;
if( string_token[0] == 'a' )
return DecodeTokenA(id, index);
return false;
}
} // namespace Winix

@ -0,0 +1,199 @@
/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2014, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef headerfile_winix_core_sessionidmanager
#define headerfile_winix_core_sessionidmanager
#include <string>
#include <vector>
#include <ctime>
#include <fstream>
#include "base64.h"
#include "space/space.h"
#include "aes.h"
namespace Winix
{
/*
* this class is used to encode/decode the session cookie
* in which there is a session id and a session's index
*
* session index is incremented each time a request comes to this session
*
* format of the encoded token:
* 1 byte - algorithm type, currently only one algorithm: 'a'
* 1 byte - an AES keys pair index
* ---- below everything is encoded by AES (two 128 bits blocks, first block
* is encoded by the first key and the second block is encoded by the second key) ------
* 1 byte - top padding value
* 1 byte - bottom padding value
* 1 byte - top padding size
* 1 byte - bottom padding size
* 5-9 bytes - top padding
* 8 bytes - the session id
* 4 bytes - the session index
* 5-9 bytes - bottom padding (bottom_padding_size = 14 - top_padding_size)
* 1 byte - the sum of all previous bytes
* 1 byte - the xor of all previous bytes (with the previous sum too)
*
* and at the end everyting is base64 encoded
*
*
*/
class SessionIdManager
{
public:
SessionIdManager();
/*
* initialization
* this method takes about 1MB memory more (for AES key expansions)
* if you do not need the session cookie to be enrypted then don't call this method
*
*/
void Init(const std::wstring & keys_file);
/*
* how often a new AES key pairs should be generated
*/
void SetKeyRenewTime(time_t renew_time);
/*
* encode/decode the session cookie
* make sure the Init() method is called first
*/
bool EncodeToken(size_t id, unsigned int index, time_t cur_utc_time, std::wstring & token);
bool DecodeToken(const std::wstring & token, size_t & id, unsigned int & index);
private:
bool was_inited;
char algorithm_type;
std::string string_token, string_token_base64;
std::vector<std::string> key_tab1, key_tab2;
size_t key_index;
time_t last_key_generated;
time_t key_renew_time;
Tito::Base64 base64;
size_t key_tab_size;
std::ofstream out_file;
std::string tmp_key_base64_encoded;
std::wstring key_file_name;
std::string file_name_ascii;
std::vector<Tito::AES> aes1, aes2;
bool ReadKeysFromFile(const wchar_t * file);
bool ReadKeysFromFile(const std::wstring & file);
bool SaveKeysToFile(const wchar_t * file);
bool SaveKeysToFile(const std::wstring & file);
void ReadKey(const wchar_t * name, PT::Space & space, std::vector<std::string> & dest_key);
bool AreKeysCorrect(size_t index);
void GenerateKeys(size_t index, time_t cur_utc_time);
void CheckKeys(time_t cur_utc_time);
void GenerateKey(std::string & key, time_t cur_utc_time);
void SaveKeysToFile(std::vector<std::string> & keys);
void InitializeAesKeys();
void RandPadding(size_t & pad_top_size, char & pad_top_value, size_t & pad_bottom_size, char & pad_bottom_value);
void AppendSum(std::string & str);
void AppendXor(std::string & str);
void CopyString(const std::string & in, std::wstring & out);
void CopyString(const std::wstring & in, std::string & out);
bool Encode(std::string & str);
bool DecodeTokenA(size_t & id, unsigned int & index);
bool IsPaddingCorrect(const char * str, size_t len, char val);
bool CheckControlSums(const char * str);
void InitializeAesKeys(size_t index);
bool DecodeAES(const char * str, size_t key);
template<typename Value>
void Append(std::string & str, Value val);
template<typename Value>
void Read(const char * str, Value & val);
};
template<typename Value>
void SessionIdManager::Append(std::string & str, Value val)
{
int move = sizeof(Value) * 8 - 8;
int v;
do
{
if( move > 0 )
v = ((val >> move) & 0xff);
else
v = val & 0xff;
str += (unsigned char)v;
move -= 8;
}
while( move >= 0 );
}
template<typename Value>
void SessionIdManager::Read(const char * str, Value & val)
{
val = 0;
for(size_t i=0 ; i<sizeof(Value) ; ++i)
{
val = val << 8;
val = val | (unsigned char)str[i];
}
}
} // namespace Winix
#endif

@ -33,6 +33,7 @@
*/
#include <sys/stat.h>
#include <limits>
#include "sessionmanager.h"
#include "request.h"
#include "log.h"
@ -85,12 +86,26 @@ void SessionManager::SetLastContainer(LastContainer * plast_container)
}
void SessionManager::InitBanList()
{
ban_tab.SetMaxSize(config->ban_list_soft_max_size, config->ban_list_max_size);
}
void SessionManager::InitCookieEncoding()
{
if( config->session_cookie_encode && !config->session_keys_file.empty() )
session_id_manager.Init(config->session_keys_file);
session_id_manager.SetKeyRenewTime(config->session_key_renew_time);
}
size_t SessionManager::Size()
{
return session_tab.Size();
@ -106,6 +121,11 @@ return true;
}
bool SessionManager::EncodeSessionId(long id, unsigned int index, std::wstring & str)
{
return session_id_manager.EncodeToken((size_t)id, index, cur->request->start_time, str);
}
long SessionManager::CreateSessionId()
{
@ -162,13 +182,14 @@ SessionContainer::Iterator i = session_tab.End();
session = &(*i);
session->new_session = true;
session->SetTimesTo(cur->request->start_time);
session->id_index = (unsigned int)session->id;
session->id_index += std::rand();
log << log2 << "SM: created a new session: " << session->id << logend;
}
else
{
// there is a problem with generating a new session id
// we do not set a session cookie
log << log1 << "SM: cannot create a session id (temporary used: with id 0)" << logend;
SetTemporarySession();
}
@ -184,36 +205,111 @@ void SessionManager::SetTemporarySession()
}
unsigned int SessionManager::SetSessionCalcDifference(Session & ses, unsigned int index)
{
unsigned int difference;
bool SessionManager::SetSessionFromCookie(const std::wstring & cookie)
if( index > ses.id_index )
difference = std::numeric_limits<unsigned int>::max() - index + ses.id_index + 1;
else
difference = ses.id_index - index;
return difference;
}
void SessionManager::SetSessionPutLogInfo(Session & ses, bool has_index, unsigned int difference)
{
log << log2 << "SM: session: " << ses.id;
if( has_index )
log << ", index difference: " << (size_t)difference;
if( ses.puser )
log << log2 << ", user: " << ses.puser->name << ", id: " << ses.puser->id;
log << log2 << logend;
}
bool SessionManager::SetSessionFromCookie(long id, bool has_index, unsigned int index)
{
long id = Tol(cookie.c_str());
unsigned int difference = 0;
SessionContainer::Iterator s = session_tab.FindById(id);
if( s == session_tab.End() || s->remove_me )
if( s == session_tab.End() )
{
log << log3 << "SM: there is no a session with id: " << id << logend;
return false;
}
if( s->remove_me )
{
log << log3 << "SM: session: " << id << " is marked for removing" << logend;
return false;
}
if( has_index )
{
difference = SetSessionCalcDifference(*s, index);
if( (size_t)difference > config->session_allow_index_difference )
{
log << log2 << "SM: an incorrect session index for session: " << id
<< ", index difference: " << (size_t)difference << logend;
return false;
}
}
// that session is in the table
session = &(*s);
session->new_session = false;
session->last_time = cur->request->start_time;
session->last_date = cur->request->start_time;
session->last_date = cur->request->start_date;
if( session->id_index_changed + config->session_index_time_increment < cur->request->start_time )
{
session->id_index += 1;
session->id_index_changed = cur->request->start_time;
}
if( cur->request->method == Request::get )
session->last_time_get = cur->request->start_time;
log << log2 << "SM: session: " << session->id;
if( session->puser )
log << log2 << ", user: " << session->puser->name << ", id: " << session->puser->id;
log << log2 << logend;
SetSessionPutLogInfo(*session, has_index, difference);
return true;
}