/* * This file is a part of CMSLU -- Content Management System like Unix * and is not publicly distributed * * Copyright (c) 2008, Tomasz Sowa * All rights reserved. * */ #include "request.h" Request::Request() : char_empty(0) { Clear(); } void Request::Clear() { // warning: don't clear in, out, err, env get_table.clear(); post_table.clear(); cookie_table.clear(); method = none; headers.str(""); page.str(""); debug.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; session = 0; result = err404; // tutaj moze cos lepszego, cos w stylu 'not implemented' dir = -1; cur_dir_table.clear(); item_table.clear(); dir_table.clear(); item.Clear(); str.clear(); } void Request::CopyFirstItem() { if( !request.item_table.empty() ) request.item = request.item_table[0]; else { request.item.Clear(); log << log1 << "Request::CopyFirstItem: item_table is empty" << logend; request.result = err_internal; } } // value can be null void Request::SetCookie(const char * name, const char * value) { request.headers << "Set-Cookie: " << name << "="; if( value && value[0]!=0 ) request.headers << value; else request.headers << "\"\""; request.headers << "; path=/\r\n"; } void Request::SetCookie(const char * name, long value) { request.headers << "Set-Cookie: " << name << "=" << value << "; path=/\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; p = post_table.find(var); if( p == post_table.end() ) throw Error(Error::no_cookie); return p->second; } // 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"); log << log1 << "IP: " << env_remote_addr << logend; } void Request::CheckMethod() { method = none; if( env_request_method[0] == 'G' ) method = get; else if( env_request_method[0] == 'P' ) method = post; } void Request::ReadParameters() { // some parameters (get) we have always // if( method == get ) { GetParser get_parser(env_request_uri, get_table); get_parser.Parse(); } if( method == post ) { PostParser post_parser(in, post_table); post_parser.Parse(); } CookieParser cookie_parser(env_http_cookie, cookie_table); cookie_parser.Parse(); } // reading everything void Request::Read() { ReadEnvVariables(); CheckMethod(); ReadParameters(); } void Request::SendAll() { if( result == redirect ) { FCGX_PutS("Status: 301 Moved Permanently\r\n", out); FCGX_FPrintF(out, "Location: %s\r\n", str.c_str()); log << log2 << "Redirect into: " << str << logend; } else { FCGX_PutS("Status: 200 OK\r\n", out); FCGX_PutS("Content-Type: Text/Html\r\n", out); } FCGX_PutS(headers.str().c_str(), out); FCGX_PutS("\r\n", out); if( result == redirect ) // if there is a redirect we do not send a content return; FCGX_PutS(page.str().c_str(), out); const std::string & d = debug.str(); if( !d.empty() ) { FCGX_PutS("\n\n", out); } } 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::HasExecAccess(const Item & item) { return HasAccess(item, 5); // r+x }