1064 lines
20 KiB
C++
Executable File
1064 lines
20 KiB
C++
Executable File
/*
|
|
* This file is a part of Winix
|
|
* and is not publicly distributed
|
|
*
|
|
* Copyright (c) 2008-2010, Tomasz Sowa
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include <ctime>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include "request.h"
|
|
#include "getparser.h"
|
|
#include "postparser.h"
|
|
#include "cookieparser.h"
|
|
#include "log.h"
|
|
#include "data.h"
|
|
#include "plugin.h"
|
|
#include "misc.h"
|
|
#include "db.h"
|
|
|
|
|
|
Request::Request() : char_empty(0)
|
|
{
|
|
id = 0;
|
|
Clear();
|
|
}
|
|
|
|
void Request::Init()
|
|
{
|
|
compress.Init();
|
|
}
|
|
|
|
|
|
void Request::ClearPostFileTmp()
|
|
{
|
|
// deleting temporary files (if exists)
|
|
|
|
while( !post_file_table.empty() )
|
|
{
|
|
const std::string & tmp_filename = post_file_table.begin()->second.tmp_filename;
|
|
|
|
if( unlink(tmp_filename.c_str()) == 0 )
|
|
log << log3 << "Request: deleted tmp file: " << tmp_filename << logend;
|
|
|
|
post_file_table.erase(post_file_table.begin());
|
|
}
|
|
}
|
|
|
|
|
|
void Request::Clear()
|
|
{
|
|
// warning: don't clear: in, out, err, env
|
|
|
|
// id is never 0
|
|
if( ++id == 0 )
|
|
++id;
|
|
|
|
get_table.clear();
|
|
post_table.clear();
|
|
post_file_table.clear();
|
|
cookie_table.clear();
|
|
|
|
method = none;
|
|
role = responder;
|
|
|
|
headers.str("");
|
|
page.str("");
|
|
debug.str("");
|
|
notify.str("");
|
|
|
|
env_request_method = &char_empty;
|
|
env_request_uri = &char_empty;
|
|
env_http_cookie = &char_empty;
|
|
env_remote_addr = &char_empty;
|
|
env_http_host = &char_empty;
|
|
env_http_user_agent = &char_empty;
|
|
env_http_accept_encoding = &char_empty;
|
|
env_fcgi_role = &char_empty;
|
|
env_content_type = &char_empty;
|
|
|
|
|
|
session = 0;
|
|
|
|
item_table.clear();
|
|
item.Clear();
|
|
dir_table.clear();
|
|
is_item = false;
|
|
pfunction = 0;
|
|
param_table.clear();
|
|
|
|
status = WINIX_ERR_OK;
|
|
|
|
is_thread = false;
|
|
thread.Clear();
|
|
thread_tab.clear();
|
|
|
|
is_ticket = false;
|
|
ticket.Clear();
|
|
ticket_tab.clear();
|
|
|
|
notify_code = 0;
|
|
browser_msie = false;
|
|
redirect_to.clear();
|
|
x_sendfile.clear();
|
|
send_as_attachment = false;
|
|
|
|
plugin.Call(WINIX_REQUEST_CLEAR);
|
|
}
|
|
|
|
|
|
|
|
|
|
// value can be null
|
|
void Request::SetCookie(const char * name, const char * value, tm * expires)
|
|
{
|
|
headers << "Set-Cookie: " << name << "=";
|
|
|
|
if( value && value[0]!=0 )
|
|
headers << value;
|
|
else
|
|
headers << "\"\"";
|
|
|
|
if( expires )
|
|
headers << "; expires=" << DateToStrCookie(expires) << " GMT";
|
|
|
|
headers << "; path=/; domain=." << data.base_server << "\r\n";
|
|
}
|
|
|
|
|
|
|
|
void Request::SetCookie(const char * name, long value, tm * expires)
|
|
{
|
|
headers << "Set-Cookie: " << name << "=" << value;
|
|
|
|
if( expires )
|
|
headers << "; expires=" << DateToStrCookie(expires) << " GMT";
|
|
|
|
headers << "; path=/; domain=." << data.base_server << "\r\n";
|
|
}
|
|
|
|
|
|
|
|
bool Request::IsPostVar(const char * var)
|
|
{
|
|
PostTable::iterator p;
|
|
|
|
p = post_table.find(var);
|
|
|
|
if( p == post_table.end() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
std::string * Request::PostVar(const char * var)
|
|
{
|
|
PostTable::iterator p = post_table.find(var);
|
|
|
|
if( p == post_table.end() )
|
|
return 0;
|
|
|
|
return &(p->second);
|
|
}
|
|
|
|
|
|
|
|
bool Request::PostVar(const char * var, std::string & result)
|
|
{
|
|
PostTable::iterator p = post_table.find(var);
|
|
|
|
if( p == post_table.end() )
|
|
{
|
|
result.clear();
|
|
return false;
|
|
}
|
|
|
|
result = p->second;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
void Request::PrintGetTable()
|
|
{
|
|
debug << "get_table: " << get_table.size() << "\n";
|
|
|
|
for(GetTable::iterator i = get_table.begin() ; i != get_table.end() ; ++i)
|
|
debug << " \"" << *i << "\"\n";
|
|
|
|
debug << std::endl;
|
|
}
|
|
|
|
|
|
void Request::PrintEnv()
|
|
{
|
|
char ** e;
|
|
|
|
debug << "environment variables:\n";
|
|
|
|
for( e = env ; *e ; ++e )
|
|
debug << ' ' << *e << "\n";
|
|
|
|
debug << std::endl;
|
|
}
|
|
|
|
|
|
|
|
|
|
void Request::PrintIn()
|
|
{
|
|
char buf[100];
|
|
int buf_len = sizeof(buf) / sizeof(char);
|
|
int len;
|
|
|
|
debug << "fcgi input:\n";
|
|
|
|
do
|
|
{
|
|
len = FCGX_GetStr(buf, buf_len - 1, in);
|
|
|
|
if( len != 0 )
|
|
{
|
|
buf[len] = 0;
|
|
debug << buf;
|
|
}
|
|
}
|
|
while( len == buf_len - 1 );
|
|
|
|
debug << std::endl;
|
|
}
|
|
|
|
|
|
|
|
const char * Request::SetEnvVar(const char * var)
|
|
{
|
|
const char * v = FCGX_GetParam(var, env);
|
|
|
|
if( v )
|
|
return v;
|
|
|
|
// char_empty contains '\0'
|
|
return &char_empty;
|
|
}
|
|
|
|
|
|
|
|
void Request::ReadEnvVariables()
|
|
{
|
|
// we store that values because FCGX_GetParam has O(n) complexity
|
|
// with this variables (env_*) we have O(1)
|
|
|
|
env_request_method = SetEnvVar("REQUEST_METHOD");
|
|
env_request_uri = SetEnvVar("REQUEST_URI");
|
|
env_http_cookie = SetEnvVar("HTTP_COOKIE");
|
|
env_remote_addr = SetEnvVar("REMOTE_ADDR");
|
|
env_http_host = SetEnvVar("HTTP_HOST");
|
|
env_http_user_agent = SetEnvVar("HTTP_USER_AGENT");
|
|
env_http_accept_encoding = SetEnvVar("HTTP_ACCEPT_ENCODING");
|
|
env_fcgi_role = SetEnvVar("FCGI_ROLE");
|
|
env_content_type = SetEnvVar("CONTENT_TYPE");
|
|
}
|
|
|
|
|
|
|
|
void Request::CheckIE()
|
|
{
|
|
char * msie = strstr(env_http_user_agent, "MSIE");
|
|
|
|
if( msie )
|
|
browser_msie = true;
|
|
else
|
|
browser_msie = false;
|
|
}
|
|
|
|
|
|
|
|
void Request::CheckKonqueror()
|
|
{
|
|
char * kon = strstr(env_http_user_agent, "Konqueror");
|
|
|
|
if( kon )
|
|
browser_konqueror = true;
|
|
else
|
|
browser_konqueror = false;
|
|
}
|
|
|
|
|
|
|
|
void Request::CheckMethod()
|
|
{
|
|
method = none;
|
|
|
|
if( ToSmall(env_request_method[0]) == 'g' )
|
|
method = get;
|
|
else
|
|
if( ToSmall(env_request_method[0]) == 'p' )
|
|
method = post;
|
|
|
|
|
|
// default we assume 'responder'
|
|
role = responder;
|
|
|
|
if( ToSmall(env_fcgi_role[0]) == 'a' )
|
|
role = authorizer;
|
|
}
|
|
|
|
|
|
bool Request::AllPostVarEmpty()
|
|
{
|
|
PostTable::iterator i;
|
|
|
|
for(i=post_table.begin() ; i!=post_table.end() ; ++i)
|
|
if( !i->second.empty() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void Request::ReadParameters()
|
|
{
|
|
// !! wrzucic jako skladowa klasy
|
|
GetParser get_parser(env_request_uri, get_table);
|
|
get_parser.Parse();
|
|
|
|
if( method == post )
|
|
{
|
|
if( IsSubStringNoCase("multipart/form-data", env_content_type) )
|
|
{
|
|
log << log3 << "Request: post content type: multipart/form-data" << logend;
|
|
|
|
post_multi_parser.Parse(in, post_table, post_file_table);
|
|
}
|
|
else
|
|
{
|
|
// !! wrzucic jako skladowa klasy
|
|
PostParser post_parser(in, post_table);
|
|
post_parser.Parse();
|
|
}
|
|
}
|
|
|
|
CookieParser cookie_parser(env_http_cookie, cookie_table);
|
|
cookie_parser.Parse();
|
|
|
|
accept_encoding_parser.Parse(env_http_accept_encoding);
|
|
}
|
|
|
|
|
|
|
|
void Request::StandardLog()
|
|
{
|
|
log.PutDate(log1);
|
|
log << env_remote_addr << ' ' << env_request_method << ' ';
|
|
log << env_http_host << env_request_uri << ' ' << env_http_user_agent << logend;
|
|
}
|
|
|
|
|
|
|
|
// reading everything
|
|
void Request::Read()
|
|
{
|
|
ReadEnvVariables();
|
|
CheckMethod();
|
|
StandardLog();
|
|
ReadParameters();
|
|
CheckIE();
|
|
|
|
if( role == authorizer )
|
|
log << log3 << "Request: fast cgi role: authorizer" << logend;
|
|
|
|
CheckKonqueror();
|
|
}
|
|
|
|
|
|
|
|
void Request::SendSessionCookie()
|
|
{
|
|
if( !session || session->id==0 )
|
|
return;
|
|
|
|
if( !session->puser || !session->remember_me )
|
|
{
|
|
SetCookie(data.http_session_id_name.c_str(), session->id);
|
|
return;
|
|
}
|
|
|
|
time_t t = time(0) + data.session_remember_max_idle;
|
|
tm * expires = localtime(&t);
|
|
|
|
if( !expires )
|
|
{
|
|
// oops, something wrong
|
|
SetCookie(data.http_session_id_name.c_str(), session->id);
|
|
return;
|
|
}
|
|
|
|
SetCookie(data.http_session_id_name.c_str(), session->id, expires);
|
|
}
|
|
|
|
|
|
void Request::SendHeaders(bool compressing, Header header)
|
|
{
|
|
if( send_as_attachment )
|
|
FCGX_PutS("Content-Disposition: attachment\r\n", out);
|
|
|
|
if( !redirect_to.empty() )
|
|
{
|
|
FCGX_PutS("Status: 301 Moved Permanently\r\n", out);
|
|
FCGX_FPrintF(out, "Location: %s\r\n", redirect_to.c_str());
|
|
log << log2 << "Redirect to: " << redirect_to << logend;
|
|
}
|
|
else
|
|
if( !x_sendfile.empty() )
|
|
{
|
|
FCGX_FPrintF(out, "X-LIGHTTPD-send-file: %s\r\n", x_sendfile.c_str());
|
|
FCGX_PutS("Status: 200 OK\r\n", out);
|
|
log << log2 << "Sending file: " << x_sendfile << logend;
|
|
}
|
|
else
|
|
{
|
|
switch(header)
|
|
{
|
|
case h_404:
|
|
FCGX_PutS("Status: 404 Not Found\r\n", out);
|
|
FCGX_PutS("Content-Type: text/html\r\n", out);
|
|
log << log2 << "Request: response: 404 Not Found" << logend;
|
|
break;
|
|
|
|
case h_403:
|
|
FCGX_PutS("Status: 403 Forbidden\r\n", out);
|
|
FCGX_PutS("Content-Type: text/html\r\n", out);
|
|
log << log2 << "Request: response: 403 Forbidden" << logend;
|
|
break;
|
|
|
|
default:
|
|
FCGX_PutS("Status: 200 OK\r\n", out);
|
|
|
|
if( role != authorizer )
|
|
FCGX_PutS("Content-Type: text/html\r\n", out);
|
|
}
|
|
|
|
}
|
|
|
|
if( compressing )
|
|
FCGX_PutS("Content-Encoding: deflate\r\n", out);
|
|
|
|
FCGX_PutS(headers.str().c_str(), out);
|
|
FCGX_PutS("\r\n", out);
|
|
}
|
|
|
|
|
|
|
|
void Request::AddDebugInfo()
|
|
{
|
|
const std::string & d = debug.str();
|
|
|
|
if( !d.empty() )
|
|
{
|
|
page << "\n<!--\n";
|
|
page << d;
|
|
page << "\n-->\n";
|
|
}
|
|
}
|
|
|
|
|
|
void Request::SendPage(bool compressing, const std::string & source_ref)
|
|
{
|
|
const std::string * source = &source_ref;
|
|
|
|
bool raw = request.is_item && request.item.content_type == Item::ct_raw && request.status == WINIX_ERR_OK &&
|
|
request.pfunction && (request.pfunction->code == FUN_CAT || request.pfunction->code == FUN_RUN);
|
|
|
|
if( data.html_filter && !raw )
|
|
{
|
|
html_filter.TrimWhite(true);
|
|
html_filter.BreakLines(60);
|
|
html_filter.InsertTabs(2);
|
|
html_filter.CheckOrphans(HTMLFilter::lang_pl, HTMLFilter::orphan_160space);
|
|
|
|
html_filter.Filter(*source, clean_html);
|
|
source = &clean_html;
|
|
}
|
|
|
|
if( compressing )
|
|
compress.CompressAndPut(source->c_str(), source->length(), out);
|
|
else
|
|
FCGX_PutS(source->c_str(), out);
|
|
}
|
|
|
|
|
|
void Request::SendAll()
|
|
{
|
|
const std::string & source = page.str();
|
|
Header header = h_200;
|
|
bool compressing = data.compression && role == responder && redirect_to.empty() && x_sendfile.empty() &&
|
|
!browser_msie && !browser_konqueror &&
|
|
accept_encoding_parser.AcceptDeflate() && source.size() >= 512;
|
|
|
|
if( status == WINIX_ERR_NO_ITEM || status == WINIX_ERR_NO_FUNCTION || status == WINIX_ERR_UNKNOWN_PARAM )
|
|
header = h_404;
|
|
|
|
if( status == WINIX_ERR_PERMISSION_DENIED || status == WINIX_ERR_CANT_CHANGE_USER || status == WINIX_ERR_CANT_CHANGE_GROUP )
|
|
header = h_403;
|
|
|
|
SendSessionCookie();
|
|
SendHeaders(compressing, header);
|
|
|
|
if( !redirect_to.empty() || !x_sendfile.empty() )
|
|
// if there is a redirect or a file to send then we do not send a content
|
|
return;
|
|
|
|
if( header == h_200 && role == authorizer && is_item && item.auth != Item::auth_none )
|
|
// if there is an item and the item has 'file' storage we do not send a content
|
|
return;
|
|
|
|
// adding debug info if exists
|
|
AddDebugInfo();
|
|
|
|
// sending content
|
|
SendPage(compressing, source);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Request::IsParam(const char * s)
|
|
{
|
|
std::vector<std::string*>::iterator i;
|
|
|
|
for(i=param_table.begin() ; i!=param_table.end() ; ++i)
|
|
{
|
|
if( **i == s )
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
bool Request::CanChangeUser(const Item & item, long new_user_id)
|
|
{
|
|
if( !session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( session->puser && 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 Request::CanChangeGroup(const Item & item, long new_group_id)
|
|
{
|
|
if( !session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( session->puser && 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( !session->puser )
|
|
return false;
|
|
|
|
if( session->puser->id != item.user_id )
|
|
return false;
|
|
|
|
if( new_group_id == -1 )
|
|
return true;
|
|
|
|
if( !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 Request::CanChangePrivileges(const Item & item, int new_priv)
|
|
{
|
|
if( !session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( session->puser && 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( !session->puser )
|
|
return false;
|
|
|
|
if( session->puser->id != item.user_id )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool Request::HasAccess(const Item & item, int mask)
|
|
{
|
|
if( !session )
|
|
// session must be set
|
|
return false;
|
|
|
|
if( session->puser && session->puser->super_user )
|
|
// super user is allowed everything
|
|
return true;
|
|
|
|
if( session->puser && session->puser->id == item.user_id )
|
|
{
|
|
// the owner
|
|
return ((item.privileges >> 6) & mask) == mask;
|
|
}
|
|
|
|
if( session->puser && session->puser->IsMemberOf(item.group_id) )
|
|
{
|
|
// group
|
|
return ((item.privileges >> 3) & mask) == mask;
|
|
}
|
|
|
|
// others
|
|
|
|
return (item.privileges & mask) == mask;
|
|
}
|
|
|
|
|
|
bool Request::HasReadAccess(const Item & item)
|
|
{
|
|
return HasAccess(item, 4);
|
|
}
|
|
|
|
|
|
bool Request::HasWriteAccess(const Item & item)
|
|
{
|
|
return HasAccess(item, 2);
|
|
}
|
|
|
|
|
|
bool Request::HasReadWriteAccess(const Item & item)
|
|
{
|
|
return HasAccess(item, 6); // r+w
|
|
}
|
|
|
|
|
|
bool Request::HasReadExecAccess(const Item & item)
|
|
{
|
|
if( session && session->puser && 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 Request::HasReadExecAccessForRoot(const Item & item)
|
|
{
|
|
// there must be at least one 'x' (for the root)
|
|
|
|
return (item.privileges & 0111) != 0;
|
|
}
|
|
|
|
|
|
|
|
bool Request::HasReadExecAccessToPath(long dir_id)
|
|
{
|
|
while( true )
|
|
{
|
|
Item * pdir = data.dirs.GetDir(dir_id);
|
|
|
|
if( !pdir )
|
|
return false;
|
|
|
|
if( !HasReadExecAccess(*pdir) )
|
|
return false;
|
|
|
|
dir_id = pdir->parent_id;
|
|
|
|
if( dir_id == -1 )
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// returning true if we can create a thread in the current directory
|
|
bool Request::CanCreateThread(bool check_root)
|
|
{
|
|
if( request.dir_table.empty() )
|
|
return false;
|
|
|
|
if( request.is_item )
|
|
return false;
|
|
|
|
if( !HasWriteAccess(*request.dir_table.back()) )
|
|
return false;
|
|
|
|
if( !data.mounts.pmount || data.mounts.pmount->type != Mount::thread )
|
|
return false;
|
|
|
|
if( !check_root && session && session->puser && session->puser->super_user )
|
|
// super can create thread regardless of the restrictcreatethread option
|
|
return true;
|
|
|
|
if( !data.mounts.pmount->IsPar(Mount::par_createthread_on) )
|
|
return true;
|
|
|
|
if( data.mounts.pmount->IsArg(Mount::par_createthread_on, request.dir_table.size()) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
// returning true if we can create a ticket in the current directory
|
|
bool Request::CanCreateTicket(bool check_root)
|
|
{
|
|
if( request.dir_table.empty() )
|
|
return false;
|
|
|
|
if( request.is_item )
|
|
return false;
|
|
|
|
if( !HasWriteAccess(*request.dir_table.back()) )
|
|
return false;
|
|
|
|
if( !data.mounts.pmount || data.mounts.pmount->type != Mount::ticket )
|
|
return false;
|
|
|
|
|
|
// checking for par_createticket_on mount option
|
|
|
|
if( !check_root && session && session->puser && session->puser->super_user )
|
|
// super can create tickets regardless of the createticket_on option
|
|
return true;
|
|
|
|
if( !data.mounts.pmount->IsPar(Mount::par_createticket_on) )
|
|
return true;
|
|
|
|
if( data.mounts.pmount->IsArg(Mount::par_createticket_on, request.dir_table.size()) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
bool Request::CanEditTicket()
|
|
{
|
|
// not logged users cannot edit tickets
|
|
if( !request.session->puser )
|
|
return false;
|
|
|
|
if( request.dir_table.empty() )
|
|
return false;
|
|
|
|
if( request.is_item || !request.is_ticket )
|
|
return false;
|
|
|
|
if( !HasWriteAccess(*request.dir_table.back()) )
|
|
return false;
|
|
|
|
if( !data.mounts.pmount || data.mounts.pmount->type != Mount::ticket )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
bool Request::CanRemove(const Item & item)
|
|
{
|
|
// !! temporarily (we're waiting for the sticky bit to be implemented)
|
|
// not logged users cannot remove anything
|
|
if( !request.session->puser )
|
|
return false;
|
|
|
|
if( item.parent_id == -1 )
|
|
{
|
|
// rm for the root dir
|
|
// only the superuser can do it
|
|
if( !request.session->puser || !request.session->puser->super_user )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Item * last_but_one_dir = data.dirs.GetDir(item.parent_id);
|
|
|
|
if( !last_but_one_dir )
|
|
// ops, there is no a parent dir
|
|
return false;
|
|
|
|
if( !request.HasWriteAccess(*last_but_one_dir) )
|
|
return false;
|
|
}
|
|
|
|
if( data.mounts.pmount->IsPar(Mount::par_only_root_remove) )
|
|
if( !request.session->puser || !request.session->puser->super_user )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Request::CanUseEmacs(const Item & item, bool check_root)
|
|
{
|
|
if( !check_root && request.session->puser && request.session->puser->super_user )
|
|
// super user can use emacs everywhere
|
|
return true;
|
|
|
|
if( !request.HasWriteAccess(item) )
|
|
return false;
|
|
|
|
if( !data.mounts.pmount->IsPar(Mount::par_emacs_on) )
|
|
return true;
|
|
|
|
if( data.mounts.pmount->IsArg(Mount::par_emacs_on, request.dir_table.size()) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool Request::CanUseMkdir(const Item & item, bool check_root)
|
|
{
|
|
// you can create a directory only in a directory
|
|
if( item.type != Item::dir )
|
|
return false;
|
|
|
|
if( !check_root && request.session->puser && request.session->puser->super_user )
|
|
// super user can use mkdir everywhere
|
|
return true;
|
|
|
|
if( !request.HasWriteAccess(item) )
|
|
return false;
|
|
|
|
if( !data.mounts.pmount->IsPar(Mount::par_mkdir_on) )
|
|
return true;
|
|
|
|
if( data.mounts.pmount->IsArg(Mount::par_mkdir_on, request.dir_table.size()) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool Request::CanUseUpload(const Item & item, bool check_root)
|
|
{
|
|
// you can use 'upload' only in a directory
|
|
if( item.type != Item::dir )
|
|
return false;
|
|
|
|
// we must know where to store the file
|
|
if( !data.mounts.pmount )
|
|
return false;
|
|
|
|
if( data.mounts.pmount->fs == Mount::simplefs && data.auth_simplefs_dir.empty() )
|
|
{
|
|
log << log1 << "Request: can't use upload function, auth_simplefs_dir must be set in the config file" << logend;
|
|
return false;
|
|
}
|
|
|
|
if( data.mounts.pmount->fs == Mount::hashfs && data.auth_hashfs_dir.empty() )
|
|
{
|
|
log << log1 << "Request: can't use upload function, auth_hashfs_dir must be set in the config file" << logend;
|
|
return false;
|
|
}
|
|
|
|
if( data.auth_tmp_dir.empty() )
|
|
{
|
|
log << log1 << "Request: can't use upload function, auth_tmp_dir must be set in the config file" << logend;
|
|
return false;
|
|
}
|
|
|
|
if( !check_root && request.session->puser && request.session->puser->super_user )
|
|
// super user can use upload everywhere
|
|
return true;
|
|
|
|
if( !request.HasWriteAccess(item) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Request::CanUseHtml(long user_id)
|
|
{
|
|
return CanUse(user_id, "allow_html");
|
|
}
|
|
|
|
|
|
bool Request::CanUseBBCode(long user_id)
|
|
{
|
|
// logged users can use bbcode
|
|
return (user_id != -1);
|
|
}
|
|
|
|
|
|
bool Request::CanUseRaw(long user_id)
|
|
{
|
|
return CanUse(user_id, "allow_raw");
|
|
}
|
|
|
|
|
|
bool Request::CanUse(long user_id, const char * group_name)
|
|
{
|
|
User * puser = data.users.GetUser(user_id);
|
|
|
|
if( !puser )
|
|
return false;
|
|
|
|
if( puser->super_user )
|
|
return true;
|
|
|
|
long group = data.groups.GetGroupId(group_name);
|
|
|
|
if( group == -1 )
|
|
// there is no such a group
|
|
return false;
|
|
|
|
if( puser->IsMemberOf(group) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Request::MakePathSimpleFs(std::string & path, long dir_id, bool create_dir)
|
|
{
|
|
if( data.auth_simplefs_dir.empty() )
|
|
{
|
|
log << log1 << "Request: auth_simplefs_dir is not set in the config file" << logend;
|
|
return false;
|
|
}
|
|
|
|
if( !data.dirs.MakePath(dir_id, path) )
|
|
return false;
|
|
|
|
if( create_dir && !CreateDirs(data.auth_simplefs_dir, path, 0755) )
|
|
return false;
|
|
|
|
path.insert(0, data.auth_simplefs_dir);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
// the path depends on id
|
|
bool Request::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 = data.auth_hashfs_dir;
|
|
if( path.empty() )
|
|
{
|
|
log << log1 << "Request: 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 Request::MakePath(const Item & item, std::string & path, bool create_dir)
|
|
{
|
|
bool res;
|
|
|
|
Mount * pmount = data.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 Request::MakePath(Item & item, bool create_dir)
|
|
{
|
|
return MakePath(item, item.auth_path, create_dir);
|
|
}
|