590 lines
11 KiB
C++
Executable File
590 lines
11 KiB
C++
Executable File
/*
|
|
* This file is a part of Winix
|
|
* and is not publicly distributed
|
|
*
|
|
* Copyright (c) 2010, Tomasz Sowa
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include "system.h"
|
|
#include "misc.h"
|
|
#include "error.h"
|
|
#include "notify.h"
|
|
#include "functions/functions.h"
|
|
#include "templates/templates.h"
|
|
|
|
|
|
|
|
void System::SetRequest(Request * prequest)
|
|
{
|
|
request = prequest;
|
|
}
|
|
|
|
|
|
void System::SetConfig(Config * pconfig)
|
|
{
|
|
config = pconfig;
|
|
}
|
|
|
|
|
|
void System::SetDb(Db * pdb)
|
|
{
|
|
db = pdb;
|
|
}
|
|
|
|
|
|
void System::SetFunctions(Functions * pfunctions)
|
|
{
|
|
functions = pfunctions;
|
|
}
|
|
|
|
|
|
void System::SetTemplates(Templates * ptemplates)
|
|
{
|
|
templates = ptemplates;
|
|
}
|
|
|
|
|
|
|
|
void System::Init()
|
|
{
|
|
dirs.SetDb(db);
|
|
dirs.SetRequest(request);
|
|
|
|
dirs.ReadDirs();
|
|
|
|
mounts.SetDirs(&dirs);
|
|
mounts.SetDb(db);
|
|
mounts.SetRequest(request);
|
|
mounts.ReadMounts();
|
|
|
|
users.SetRequest(request);
|
|
users.ReadUsers(db);
|
|
groups.ReadGroups(db); // !! chwilowe przekazanie argumentu, db bedzie zmienione
|
|
|
|
rebus.SetRequest(request);
|
|
rebus.Init();
|
|
}
|
|
|
|
|
|
// !! mozna zrobic jakas obsluge kiedy nie mozemy sie redirectnac, np gdy wystapil blad
|
|
// !! moze zwracac jakas wartosc?
|
|
void System::RedirectTo(const Item & item, const char * postfix)
|
|
{
|
|
request->redirect_to = config->base_url;
|
|
|
|
if( item.type == Item::dir )
|
|
{
|
|
// item_id is pointing to a directory
|
|
dirs.MakePath(item.id, path);
|
|
request->redirect_to += path;
|
|
}
|
|
else
|
|
{
|
|
if( !dirs.MakePath(item.parent_id, path) )
|
|
log << log1 << "Content: Can't redirect: no dirs for item id: " << item.id << logend;
|
|
|
|
request->redirect_to += path;
|
|
request->redirect_to += item.url;
|
|
}
|
|
|
|
if( postfix )
|
|
request->redirect_to += postfix;
|
|
}
|
|
|
|
|
|
|
|
void System::RedirectTo(long item_id, const char * postfix)
|
|
{
|
|
std::string path;
|
|
Item * pdir;
|
|
|
|
request->redirect_to = config->base_url;
|
|
pdir = dirs.GetDir(item_id);
|
|
|
|
|
|
if( pdir )
|
|
{
|
|
// item_id is pointing to a directory
|
|
dirs.MakePath(pdir->id, path);
|
|
request->redirect_to += path;
|
|
}
|
|
else
|
|
{
|
|
// !! zrobic nowy interfejs
|
|
// !! GetItem pozamieniac na GetFile
|
|
// !! i nie uzywac request->item_table (zrobic sobie lokalny tutaj)
|
|
db->GetItem(request->item_table, item_id);
|
|
|
|
if( !request->item_table.empty() )
|
|
{
|
|
if( !dirs.MakePath(request->item_table[0].parent_id, path) )
|
|
log << log1 << "Content: Can't redirect: no dirs for item id: " << request->item_table[0].id << ", requested directory id: " << request->item_table[0].parent_id << logend;
|
|
|
|
request->redirect_to += path + request->item_table[0].url;
|
|
}
|
|
else
|
|
{
|
|
log << log1 << "Content: Can't redirect: no such item: id: " << item_id << logend;
|
|
}
|
|
}
|
|
|
|
if( postfix )
|
|
request->redirect_to += postfix;
|
|
}
|
|
|
|
|
|
void System::RedirectToLastDir()
|
|
{
|
|
// !! dac sprawdzenie czy istnieje
|
|
RedirectTo( *request->dir_table.back() );
|
|
}
|
|
|
|
|
|
void System::RedirectToLastItem()
|
|
{
|
|
if( request->is_item )
|
|
RedirectTo(request->item);
|
|
else
|
|
RedirectTo( *request->dir_table.back() );// !! dac sprawdzenie czy istnieje
|
|
}
|
|
|
|
|
|
void System::PrepareUrl(Item & item)
|
|
{
|
|
TrimWhite(item.url);
|
|
|
|
if( item.url.empty() )
|
|
item.url = item.subject; // if the subject is empty then the url will be corrected by CorrectUrlOnlyAllowedChar()
|
|
|
|
CorrectUrlOnlyAllowedChar(item.url);
|
|
|
|
if( functions->Find(item.url) )
|
|
{
|
|
// the name provided by an user is the same as a name of a function
|
|
// we add one underscore character at the beginning
|
|
|
|
// names of functions should not begin with an underscore '_'
|
|
// and we can simply add one '_' at the beginning
|
|
// and the name will be unique
|
|
item.url.insert(item.url.begin(), '_');
|
|
}
|
|
}
|
|
|
|
|
|
bool System::CanChangeUser(const Item & item, long new_user_id)
|
|
{
|
|
if( !request->session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( request->session->puser && request->session->puser->super_user )
|
|
// super user is allowed everything
|
|
return true;
|
|
|
|
if( item.user_id != new_user_id )
|
|
// only super user can change the owner of an item
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool System::CanChangeGroup(const Item & item, long new_group_id)
|
|
{
|
|
if( !request->session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( request->session->puser && request->session->puser->super_user )
|
|
// super user is allowed everything
|
|
return true;
|
|
|
|
if( item.group_id != new_group_id )
|
|
{
|
|
// user is allowed to change the group only if he is an owner of the item
|
|
// he can change only into a group in which he is a member of, or into a 'no_group'
|
|
|
|
if( !request->session->puser )
|
|
return false;
|
|
|
|
if( request->session->puser->id != item.user_id )
|
|
return false;
|
|
|
|
if( new_group_id == -1 )
|
|
return true;
|
|
|
|
if( !request->session->puser->IsMemberOf(new_group_id) )
|
|
return false;
|
|
|
|
// is logged, is the owner of the item, is the member of the new group
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool System::CanChangePrivileges(const Item & item, int new_priv)
|
|
{
|
|
if( !request->session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( request->session->puser && request->session->puser->super_user )
|
|
// super user is allowed everything
|
|
return true;
|
|
|
|
if( item.privileges != new_priv )
|
|
{
|
|
// the owner of an item is allowed to change the privileges
|
|
|
|
if( !request->session->puser )
|
|
return false;
|
|
|
|
if( request->session->puser->id != item.user_id )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool System::HasAccess(const Item & item, int mask)
|
|
{
|
|
if( !request->session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( request->session->puser && request->session->puser->super_user )
|
|
// super user is allowed everything
|
|
return true;
|
|
|
|
if( request->session->puser && request->session->puser->id == item.user_id )
|
|
{
|
|
// the owner
|
|
return ((item.privileges >> 6) & mask) == mask;
|
|
}
|
|
|
|
if( request->session->puser && request->session->puser->IsMemberOf(item.group_id) )
|
|
{
|
|
// group
|
|
return ((item.privileges >> 3) & mask) == mask;
|
|
}
|
|
|
|
// others
|
|
|
|
return (item.privileges & mask) == mask;
|
|
}
|
|
|
|
|
|
bool System::HasReadAccess(const Item & item)
|
|
{
|
|
return HasAccess(item, 4);
|
|
}
|
|
|
|
|
|
bool System::HasWriteAccess(const Item & item)
|
|
{
|
|
return HasAccess(item, 2);
|
|
}
|
|
|
|
|
|
bool System::HasReadWriteAccess(const Item & item)
|
|
{
|
|
return HasAccess(item, 6); // r+w
|
|
}
|
|
|
|
|
|
bool System::HasReadExecAccess(const Item & item)
|
|
{
|
|
if( request->session && request->session->puser && request->session->puser->super_user )
|
|
{
|
|
// there must be at least one 'x' (for the root)
|
|
|
|
return (item.privileges & 0111) != 0;
|
|
}
|
|
|
|
return HasAccess(item, 5); // r+x
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool System::HasReadExecAccessToPath(long dir_id)
|
|
{
|
|
while( true )
|
|
{
|
|
Item * pdir = dirs.GetDir(dir_id);
|
|
|
|
if( !pdir )
|
|
return false;
|
|
|
|
if( !HasReadExecAccess(*pdir) )
|
|
return false;
|
|
|
|
dir_id = pdir->parent_id;
|
|
|
|
if( dir_id == -1 )
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
bool System::DirsHaveReadExecPerm()
|
|
{
|
|
std::vector<Item*>::iterator i;
|
|
|
|
for(i = request->dir_table.begin() ; i!=request->dir_table.end() ; ++i)
|
|
{
|
|
if( !HasReadExecAccess(**i) )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// if we don't have access we only remove the item from the table
|
|
void System::CheckAccessToItems(std::vector<Item> & item_table)
|
|
{
|
|
size_t i = 0;
|
|
|
|
while( i < item_table.size() )
|
|
{
|
|
if( !HasReadAccess(item_table[i]) )
|
|
{
|
|
item_table.erase(item_table.begin() + i);
|
|
}
|
|
else
|
|
{
|
|
i += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool System::CanUseHtml(long user_id)
|
|
{
|
|
return IsMemberOfGroup(user_id, "allow_html");
|
|
}
|
|
|
|
|
|
bool System::CanUseBBCode(long user_id)
|
|
{
|
|
// logged users can use bbcode
|
|
return (user_id != -1);
|
|
}
|
|
|
|
|
|
bool System::CanUseRaw(long user_id)
|
|
{
|
|
return IsMemberOfGroup(user_id, "allow_raw");
|
|
}
|
|
|
|
|
|
|
|
bool System::IsMemberOfGroup(long user_id, const char * group_name)
|
|
{
|
|
User * puser = users.GetUser(user_id);
|
|
|
|
if( !puser )
|
|
return false;
|
|
|
|
if( puser->super_user )
|
|
return true;
|
|
|
|
long group = groups.GetGroupId(group_name);
|
|
|
|
if( group == -1 )
|
|
// there is no such a group
|
|
return false;
|
|
|
|
if( puser->IsMemberOf(group) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool System::MakePathSimpleFs(std::string & path, long dir_id, bool create_dir)
|
|
{
|
|
if( config->auth_simplefs_dir.empty() )
|
|
{
|
|
log << log1 << "System: auth_simplefs_dir is not set in the config file" << logend;
|
|
return false;
|
|
}
|
|
|
|
if( !dirs.MakePath(dir_id, path) )
|
|
return false;
|
|
|
|
if( create_dir && !CreateDirs(config->auth_simplefs_dir, path, 0755) )
|
|
return false;
|
|
|
|
path.insert(0, config->auth_simplefs_dir);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
// the path depends on id
|
|
bool System::MakePathHashFs(std::string & path, long id, bool create_dir)
|
|
{
|
|
char buffer[50];
|
|
char * hash = buffer;
|
|
|
|
// get 'id' as hexadecimal
|
|
buffer[0] = '0';
|
|
sprintf(buffer+1, "%lx", (unsigned long)id);
|
|
|
|
path = config->auth_hashfs_dir;
|
|
if( path.empty() )
|
|
{
|
|
log << log1 << "System: auth_hashfs_dir is not set in the config file" << logend;
|
|
return false;
|
|
}
|
|
|
|
path += '/';
|
|
|
|
// make sure that the length is even
|
|
if( (strlen(hash) & 1) != 0 )
|
|
hash = buffer + 1; // the first character was zero
|
|
|
|
// creating dirs without the last part
|
|
// the last part is a part of a file
|
|
for(size_t i=0 ; hash[i] != 0 ; i+=2)
|
|
{
|
|
path += hash[i];
|
|
path += hash[i+1];
|
|
|
|
if( hash[i+2] != 0 )
|
|
{
|
|
if( create_dir && !CreateDir(path, 0755) )
|
|
return false;
|
|
|
|
path += '/';
|
|
}
|
|
}
|
|
|
|
// one character more to make sure the path is unique
|
|
// (we can have a directory without the character)
|
|
path += "_";
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// making a complete path to a static file
|
|
bool System::MakePath(const Item & item, std::string & path, bool create_dir)
|
|
{
|
|
bool res;
|
|
|
|
Mount * pmount = mounts.CalcMount(item.parent_id);
|
|
|
|
if( !pmount || pmount->fs == Mount::simplefs )
|
|
{
|
|
res = MakePathSimpleFs(path, item.parent_id, create_dir);
|
|
}
|
|
else
|
|
{
|
|
res = MakePathHashFs(path, item.id, create_dir);
|
|
}
|
|
|
|
if( res )
|
|
path += item.url;
|
|
else
|
|
path.clear();
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
bool System::MakePath(Item & item, bool create_dir)
|
|
{
|
|
return MakePath(item, item.auth_path, create_dir);
|
|
}
|
|
|
|
|
|
|
|
Error System::AddFile(Item & item)
|
|
{
|
|
if( item.type == Item::dir )
|
|
return WINIX_ERR_FILE_EXPECTED;
|
|
|
|
Error status = db->AddItem(item);
|
|
|
|
if( status == WINIX_ERR_OK )
|
|
{
|
|
log << log2 << "System: added a new file, url: " << item.url << ", id: " << item.id
|
|
<< ", parent_id: " << item.parent_id << logend;
|
|
|
|
request->notify_code |= WINIX_NOTIFY_ITEM_ADD;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
Error System::EditFile(Item & item, bool with_url)
|
|
{
|
|
if( item.type == Item::dir )
|
|
return WINIX_ERR_FILE_EXPECTED;
|
|
|
|
if( request->session && request->session->puser )
|
|
request->item.modification_user_id = request->session->puser->id;
|
|
else
|
|
request->item.modification_user_id = -1;
|
|
|
|
item.SetDateModifyToNow();
|
|
Error status = db->EditItemById(item, with_url);
|
|
|
|
if( status == WINIX_ERR_OK )
|
|
{
|
|
TemplatesFunctions::pattern_cacher.UpdatePattern(item);
|
|
log << log2 << "System: modified an item" << logend;
|
|
|
|
request->notify_code |= WINIX_NOTIFY_ITEM_EDIT;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
Error System::CheckSpecialFile(const Item & item)
|
|
{
|
|
static std::string fstab = "fstab";
|
|
|
|
Item * etc = dirs.GetEtcDir();
|
|
|
|
if( !etc )
|
|
return WINIX_NOTHING_TO_DO;
|
|
|
|
if( item.parent_id != etc->id )
|
|
return WINIX_NOTHING_TO_DO;
|
|
|
|
if( item.url == fstab )
|
|
{
|
|
log << log3 << "System: reloading mount points" << logend;
|
|
|
|
Error status = mounts.ReadMounts(item.content);
|
|
templates->ReadNewIndexTemplates();
|
|
|
|
return status;
|
|
}
|
|
|
|
return WINIX_NOTHING_TO_DO;
|
|
}
|