From 6e2d00bc5bb23e632b10997b4e7e06229e3191a9 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Tue, 24 Jan 2012 23:03:36 +0000 Subject: [PATCH] added: now we have a fourth part in permissions (guests) e.g.: 07555 means: 7 for owner 5 for group 5 for others 5 for guests (not logged users) added: the sticky bit for directories e.g. permissions to a directory with a sticky bit set can be set to: 017555 rewritten: rm/mv winix functions to correctly understand the sticky bit added: Dir::FollowLink() recognizes ".." and "." now consequently System::FollowAllLinks recognizes it too added: umask -- calculating privileges for new files/directories all users have their own umask (in meta) and there is one in the config (for guests and when a user has not definied its own one) removed: mount option: only_root_remove git-svn-id: svn://ttmath.org/publicrep/winix/trunk@801 e52654a7-88a9-db11-a3e9-0013d4bc506e --- core/config.cpp | 1 + core/config.h | 5 +- core/dircontainer.h | 4 +- core/dirs.cpp | 63 ++- core/dirs.h | 5 +- core/mounts.cpp | 5 +- core/mounts.h | 8 +- core/pluginmsg.h | 80 ++-- core/system.cpp | 122 +++++- core/system.h | 18 +- functions/Makefile.dep | 7 +- functions/adduser.cpp | 11 +- functions/emacs.cpp | 8 +- functions/functionbase.cpp | 6 +- functions/ln.cpp | 6 +- functions/mkdir.cpp | 4 +- functions/mv.cpp | 747 +++++++++++++++++++++----------- functions/mv.h | 80 ++-- functions/privchanger.cpp | 16 +- functions/reload.cpp | 11 +- functions/reload.h | 3 +- functions/rm.cpp | 345 ++++++++++----- functions/rm.h | 31 +- functions/upload.cpp | 4 +- html/fun_mv.html | 6 +- html/fun_rm.html | 3 +- locale/en | 18 +- locale/pl | 19 + plugins/thread/createthread.cpp | 4 +- plugins/thread/reply.cpp | 4 +- plugins/ticket/createticket.cpp | 2 +- plugins/ticket/sessiondata.cpp | 6 +- plugins/ticket/ticketinfo.cpp | 6 +- templates/priv.cpp | 8 +- 34 files changed, 1109 insertions(+), 557 deletions(-) diff --git a/core/config.cpp b/core/config.cpp index 224f525..be12ea5 100755 --- a/core/config.cpp +++ b/core/config.cpp @@ -229,6 +229,7 @@ void Config::AssignValues(bool stdout_is_closed) pattern_cacher_how_many_delete = Size(L"pattern_cacher_how_many_delete", 30); content_type_header = Int(L"content_type_header", 0); + umask = Int(L"umask", 0222); } diff --git a/core/config.h b/core/config.h index 718d546..4060bcc 100755 --- a/core/config.h +++ b/core/config.h @@ -453,7 +453,10 @@ public: // if utf8 is true then "; charset=UTF-8" will also be appended int content_type_header; - + // global umask + // it is used when an user doesn't have your own umask or for guests (not logged users) + // default: 0222 + int umask; diff --git a/core/dircontainer.h b/core/dircontainer.h index 9ea88e1..27de147 100755 --- a/core/dircontainer.h +++ b/core/dircontainer.h @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2010, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -48,7 +48,7 @@ public: bool DelById(long id); - ParentIterator ParentBegin(); + ParentIterator ParentBegin(); // IMPROVE ME: may it should be renamed to ChildBegin() similarly as FindFirstChild() ? ParentIterator ParentEnd(); ParentSizeType ParentSize(); bool ParentEmpty(); diff --git a/core/dirs.cpp b/core/dirs.cpp index 2f59a19..7cae083 100755 --- a/core/dirs.cpp +++ b/core/dirs.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2011, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -41,7 +41,7 @@ void Dirs::Clear() bool Dirs::HasReadExecAccessForRoot(const Item & item) { // there must be at least one 'x' (for the root) - return (item.privileges & 01111) != 0; // !! in the future there'll be another 'x' + return (item.privileges & 01111) != 0; } @@ -53,8 +53,8 @@ void Dirs::CheckRootDir() { if( !HasReadExecAccessForRoot(*i) ) { - i->privileges = 0755; - log << log1 << "Dirs: there is no access for root (admin) to the root dir, setting 0755 for root dir" << logend; + i->privileges = 07555; + log << log1 << "Dirs: there is no access for a root (admin) to the root dir, setting 07555 for the root directory" << logend; db->EditPrivById(*i, i->id); } @@ -62,7 +62,7 @@ void Dirs::CheckRootDir() } - log << log1 << "Dirs: there is no a root dir in the database (creating one)" << logend; + log << log1 << "Dirs: there is no a root directory in the database (creating one)" << logend; Item root; @@ -70,7 +70,7 @@ void Dirs::CheckRootDir() root.parent_id = -1; root.user_id = -1; root.group_id = -1; - root.privileges = 0755; + root.privileges = 07555; // !! upewnic sie ze baza nie zmieni url (gdyby wczesniej juz byl w bazie pusty url) // !! zrobic jakis wyjatek do wprowadzania roota? @@ -487,7 +487,7 @@ return 0; -// current_dir_tab can be the same container as out_dir_tab +// current_dir_tab can be the same container as out_dir_tab void Dirs::CopyDirTab(const std::vector & in, std::vector & out) { if( &in != &out ) @@ -502,13 +502,13 @@ void Dirs::CopyDirTab(const std::vector & in, std::vector & out) -size_t Dirs::AnalyzeDir(std::vector & dir_tab, const std::wstring & link_to) +bool Dirs::AnalyzeDir(std::vector & dir_tab, const std::wstring & link_to, size_t & i) { - if( dir_tab.empty() ) - return 0; - - size_t i = 0; size_t old_i; + i = 0; + + if( dir_tab.empty() ) + return false; while( true ) { @@ -516,7 +516,7 @@ size_t Dirs::AnalyzeDir(std::vector & dir_tab, const std::wstring & link_ for( ; i & dir_tab, const std::wstring & link_ for( ; iid); - - if( !pdir ) - return old_i; // analyze_temp is not a directory + if( analyze_temp == L".." ) + { + if( dir_tab.size() <= 1 ) + return false; - dir_tab.push_back(pdir); + dir_tab.pop_back(); + } + else + if( analyze_temp != L"." ) + { + Item * pdir = GetDir(analyze_temp, dir_tab.back()->id); + + if( !pdir ) + { + i = old_i; + return true; // analyze_temp is not a directory + } + + dir_tab.push_back(pdir); + } } } @@ -541,7 +555,10 @@ size_t Dirs::AnalyzeDir(std::vector & dir_tab, const std::wstring & link_ int Dirs::FollowLink(std::vector & dir_tab, const std::wstring & link_to, std::wstring & out_item) { - size_t i = AnalyzeDir(dir_tab, link_to); + size_t i; + + if( !AnalyzeDir(dir_tab, link_to, i) ) + return 2; // incorrect link_to if( i < link_to.size() ) { @@ -574,7 +591,7 @@ return 0; 4 - current_dir_tab was empty current_dir_tab can be the same container as out_dir_tab - link_to can be a relative path (without the first slash) + link_to can be a relative path (without the first slash) and can contain ".." or "." */ int Dirs::FollowLink(const std::vector & current_dir_tab, const std::wstring & link_to, std::vector & out_dir_tab, std::wstring & out_item) @@ -693,9 +710,9 @@ Item * Dirs::CreateVarDir() if( root ) { v.parent_id = root->id; - v.user_id = -1; - v.group_id = -1; - v.privileges = 0755; + v.user_id = root->user_id; + v.group_id = root->group_id; + v.privileges = root->privileges; v.subject = L"var"; v.url = L"var"; v.type = Item::dir; diff --git a/core/dirs.h b/core/dirs.h index ae9db6d..ec1702a 100755 --- a/core/dirs.h +++ b/core/dirs.h @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2011, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -47,6 +47,7 @@ public: bool DelDir(long dir_id); + // if returns true then out_dir_tab is not empty bool CreateDirTab(long dir_id, std::vector & out_dir_tab); void LogDir(const std::vector & dir_tab); @@ -98,7 +99,7 @@ private: std::wstring temp_link_to; size_t AnalyzeDir(Item * pdir, const std::wstring & path, long & dir_id, std::wstring & dir); - size_t AnalyzeDir(std::vector & dir_tab, const std::wstring & link_to); + bool AnalyzeDir(std::vector & dir_tab, const std::wstring & link_to, size_t & i); std::wstring analyze_temp; std::wstring get_dir_temp; diff --git a/core/mounts.cpp b/core/mounts.cpp index eae2edc..13959a6 100755 --- a/core/mounts.cpp +++ b/core/mounts.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2009-2011, Tomasz Sowa + * Copyright (c) 2009-2012, Tomasz Sowa * All rights reserved. * */ @@ -53,9 +53,6 @@ void Mounts::CreateMountPar() mount_par_image_size = AddMountPar(L"image_size"); mount_par_image_mode = AddMountPar(L"image_mode"); mount_par_image_quality = AddMountPar(L"image_quality"); - //mount_par_thread = AddMountPar(L"thread"); - //mount_par_createthread_on = AddMountPar(L"createthread_on"); - mount_par_only_root_remove = AddMountPar(L"only_root_remove"); mount_par_emacs_on = AddMountPar(L"emacs_on"); mount_par_mkdir_on = AddMountPar(L"mkdir_on"); mount_par_app = AddMountPar(L"app"); diff --git a/core/mounts.h b/core/mounts.h index 31f0110..baddf85 100755 --- a/core/mounts.h +++ b/core/mounts.h @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2009-2011, Tomasz Sowa + * Copyright (c) 2009-2012, Tomasz Sowa * All rights reserved. * */ @@ -73,9 +73,6 @@ public: int MountParImageSize() { return mount_par_image_size; } int MountParImageMode() { return mount_par_image_mode; } int MountParImageQuality() { return mount_par_image_quality; } - //int MountParThread() { return mount_par_thread; } - //int MountParCreatethreadOn() { return mount_par_createthread_on; } - int MountParOnlyRootRemove() { return mount_par_only_root_remove; } int MountParEmacsOn() { return mount_par_emacs_on; } int MountParMkdirOn() { return mount_par_mkdir_on; } int MountParApp() { return mount_par_app; } @@ -148,9 +145,6 @@ private: int mount_par_image_size; int mount_par_image_mode; int mount_par_image_quality; - //int mount_par_thread; - //int mount_par_createthread_on; - int mount_par_only_root_remove; int mount_par_emacs_on; int mount_par_mkdir_on; int mount_par_app; diff --git a/core/pluginmsg.h b/core/pluginmsg.h index 351566e..8daf267 100755 --- a/core/pluginmsg.h +++ b/core/pluginmsg.h @@ -29,121 +29,137 @@ // winix function and parameters have been parsed // the request.status is OK // (the winix function was not called yet) -#define WINIX_PREPARE_REQUEST 2000 +#define WINIX_PREPARE_REQUEST 20000 // post and get functions have done their jobs // now you can act // this is called only if the request.status is OK -#define WINIX_PROCESS_REQUEST 2001 +#define WINIX_PROCESS_REQUEST 20010 // prepere your content for displaying // this is called after WINIX_PROCESS_REQUEST // and when there is not a redirect // request.status is not checked here -#define WINIX_CONTENT_MAKE 2002 +#define WINIX_CONTENT_MAKE 20020 // here you can attach your own session data (based on PluginDataBase class) // call cur->session->plugin_data.Assign(pointer) -#define WINIX_SESSION_CREATED 3000 +#define WINIX_SESSION_CREATED 30000 // here you should remove your session data // this message can be sent even if you don't assing your plugin data -#define WINIX_SESSION_REMOVE 3001 +#define WINIX_SESSION_REMOVE 30010 // when a session is changed (you can save a pointer to your data here) -#define WINIX_SESSION_CHANGED 3002 +#define WINIX_SESSION_CHANGED 30020 // the winix is closing // the is not any session available (cur->session is null) -#define WINIX_CLOSE 3004 +#define WINIX_CLOSE 30040 + +// preparing to remove a file (rm function) +// in p1 you have a pointer to the Item struct (file) +// valid members are: +// id, parent_id, type, url, file_path, file_fs, file_type, has_thumb, hash, hash_type, file_size +// user_id, group_id, privileges +// (sometimes rest members can be valid as well -- when you call directly fun_rm->RemoveFileOrSymlink() method) +#define WINIX_FILE_PREPARE_TO_REMOVE 30045 // a file or symlink was removed (rm function) // in p1 you have a pointer to the Item struct (old file) -#define WINIX_FILE_REMOVED 3005 - -// directory was removed (rm function) -// PluginInfo::l1 is the dir id -#define WINIX_DIR_REMOVED 3006 +// valid members are the same as in WINIX_FILE_PREPARE_TO_REMOVE +#define WINIX_FILE_REMOVED 30050 // preparing to remove a directory (rm function) // in p1 you have a pointer to the Item struct (directory) -#define WINIX_DIR_PREPARE_TO_REMOVE 3007 +// this message is sent after checking the directory permissions +// so consequently if there is no any database error then the +// directory will be removed +// and after removed WINIX_DIR_REMOVED message is sent +#define WINIX_DIR_PREPARE_TO_REMOVE 30070 + +// directory was removed (rm function) +// PluginInfo::l1 is the directory id +#define WINIX_DIR_REMOVED 30060 // winix is initialized, // now you can initialize your plugin -#define WINIX_PLUGIN_INIT 3008 +#define WINIX_PLUGIN_INIT 30080 // here you can add your own mount point, file systems, mount parameters // for adding a new mount type call: system->mounts.AddMountType("new_mount_name") -#define WINIX_ADD_MOUNTS 3009 +#define WINIX_ADD_MOUNTS 30090 // add plugin functions (winix functions) here // call info.functions->Add() to add a function -#define WINIX_CREATE_FUNCTIONS 3010 +#define WINIX_CREATE_FUNCTIONS 30100 // choose a default function // if you do not select it then it will be choosen by winix -#define WINIX_SELECT_DEFAULT_FUNCTION 3011 +#define WINIX_SELECT_DEFAULT_FUNCTION 30110 // /etc/fstab has been changed // now we have new mount points -#define WINIX_FSTAB_CHANGED 3012 +#define WINIX_FSTAB_CHANGED 30120 // here you add your own template to notification system // call system->notify.AddTemplate() method // with a template file name -#define WINIX_NOTIFY_ADD_TEMPLATE 3013 +#define WINIX_NOTIFY_ADD_TEMPLATE 30130 // the request is being ended // you can clear some of your objects here -#define WINIX_END_REQUEST 3014 +#define WINIX_END_REQUEST 30140 // a new file (page) has been added // in p1 you have a pointer to the Item struct -#define WINIX_FILE_ADDED 3015 +#define WINIX_FILE_ADDED 30150 // a file (page) has been changed (edited) // in p1 you have a pointer to the Item struct -#define WINIX_FILE_CHANGED 3016 +#define WINIX_FILE_CHANGED 30160 // a file (page) has been copied // in p1 you have a pointer to the Item struct // not every fields of Item struct are filled -#define WINIX_FILE_COPIED 3017 +#define WINIX_FILE_COPIED 30170 // a file will be moved // in p1 you have a pointer to the Item struct -// not every fields of Item struct are filled -#define WINIX_FILE_PREPARE_TO_MOVE 3018 +// valid members are: +// id, parent_id, type, url, file_path, file_fs, file_type, has_thumb, hash, hash_type, file_size +// user_id, group_id, privileges, meta +// (sometimes rest members can be valid as well -- when you call directly fun_rm->RemoveFileOrSymlink() method) +#define WINIX_FILE_PREPARE_TO_MOVE 30180 // a file has been moved // in p1 you have a pointer to the Item struct (new file) -// not every fields of Item struct are filled -#define WINIX_FILE_MOVED 3019 +// valid members are the same as in WINIX_FILE_PREPARE_TO_MOVE +#define WINIX_FILE_MOVED 30190 // a thumbnail was created // this message is called from another thread // the thread is called Lock() before sending this message // in p1 you have a pointer to the Item struct -#define WINIX_CREATED_THUMB 3050 +#define WINIX_CREATED_THUMB 30500 // an image has been resized // this message is called from another thread // the thread is called Lock() before sending this message // in p1 you have a pointer to the Item struct -#define WINIX_IMAGE_RESIZED 3052 +#define WINIX_IMAGE_RESIZED 30520 // content of a directory was sorted // (winix 'sort' function was used) // in p1 you have a pointer to the Item struct (of the directory) // this is from system->dirs so you should not change the item -#define WINIX_DIR_CONTENT_SORTED 3050 +#define WINIX_DIR_CONTENT_SORTED 30500 // a user has been logged // send from 'login' winix function // this message is also called when winix starts and reads sessions // from the session file -#define WINIX_USER_LOGGED 3060 +#define WINIX_USER_LOGGED 30600 // here you add your own html templates @@ -154,7 +170,7 @@ // the message will be sent too whenever 'reload/templates' winix function is called // templates you should add only in this message // in other cases after 'reload' function the indexes would be wrong -#define WINIX_ADD_TEMPLATE 3100 +#define WINIX_ADD_TEMPLATE 31000 diff --git a/core/system.cpp b/core/system.cpp index c14edb3..6b26b59 100755 --- a/core/system.cpp +++ b/core/system.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010-2011, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -260,12 +260,12 @@ bool System::CanChangeUser(const Item & item, long new_user_id) // super user is allowed everything return true; - // !! przeciez to prosciej mozna zapisac - // albo dac od razu return false - if( item.user_id != new_user_id ) + if( item.user_id == -1 || new_user_id == -1 || item.user_id != new_user_id ) // only super user can change the owner of an item return false; + // item.user_id is equal new_user_id -- we return true + return true; } @@ -285,10 +285,10 @@ bool System::CanChangeGroup(const Item & item, long 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( !cur->session->puser ) + if( !cur->session->puser || cur->session->puser->id == -1 ) return false; - if( cur->session->puser->id != item.user_id ) + if( item.user_id == -1 || cur->session->puser->id != item.user_id ) return false; if( new_group_id == -1 ) @@ -316,12 +316,12 @@ bool System::CanChangePrivileges(const Item & item, int new_priv) if( item.privileges != new_priv ) { - // the owner of an item is allowed to change the privileges - - if( !cur->session->puser ) + // the owner of an item is allowed to change the privileges + + if( !cur->session->puser || cur->session->puser->id == -1 ) return false; - - if( cur->session->puser->id != item.user_id ) + + if( item.user_id == -1 || cur->session->puser->id != item.user_id ) return false; } @@ -329,7 +329,7 @@ return true; } - +// private bool System::HasAccess(const Item & item, int mask) { if( !cur->session ) @@ -340,20 +340,26 @@ bool System::HasAccess(const Item & item, int mask) // super user is allowed everything return true; - if( cur->session->puser && cur->session->puser->id == item.user_id ) + if( cur->session->puser && item.user_id != -1 && cur->session->puser->id == item.user_id ) { // the owner + return ((item.privileges >> 9) & mask) == mask; + } + + if( cur->session->puser && item.group_id != -1 && cur->session->puser->IsMemberOf(item.group_id) ) + { + // group return ((item.privileges >> 6) & mask) == mask; } - if( cur->session->puser && cur->session->puser->IsMemberOf(item.group_id) ) + if( cur->session->puser ) { - // group + // others -- others logged people return ((item.privileges >> 3) & mask) == mask; } - - // others - + + // guests -- not logged people + return (item.privileges & mask) == mask; } @@ -381,8 +387,8 @@ bool System::HasReadExecAccess(const Item & item) if( cur->session && cur->session->puser && cur->session->puser->super_user ) { // there must be at least one 'x' (for the root) - - return (item.privileges & 0111) != 0; + // !! CHECK ME: is it applicable to directories too? + return (item.privileges & 01111) != 0; } return HasAccess(item, 5); // r+x @@ -468,6 +474,76 @@ size_t i = 0; } +int System::NewPrivileges(int creation_mask) +{ + if( cur && cur->session && cur->session->puser ) + { + int umask = cur->session->puser->env.Int(L"umask", config->umask); + return (~umask) & creation_mask; + } + else + { + return (~config->umask) & creation_mask; + } +} + +/* + from man sticky: + A directory whose `sticky bit' is set becomes an append-only directory, + or, more accurately, a directory in which the deletion of files is + restricted. A file in a sticky directory may only be removed or renamed + by a user if the user has write permission for the directory and the user + is the owner of the file, the owner of the directory, or the super-user. + This feature is usefully applied to directories such as /tmp which must + be publicly writable but should deny users the license to arbitrarily + delete or rename each others' files. +*/ +bool System::CanRemoveRenameChild(const Item & dir, long child_item_user_id) +{ + if( dir.type != Item::dir ) + return false; + + if( !HasWriteAccess(dir) ) + return false; + + if( (dir.privileges & 010000) == 0 ) + // there is no a sticky bit set to this directory + return true; + + if( cur->session->puser ) + { + if( cur->session->puser->super_user ) + return true; + + if( dir.user_id != -1 && cur->session->puser->id != -1 && child_item_user_id != -1 ) + { + if( cur->session->puser->id == child_item_user_id || + cur->session->puser->id == dir.user_id ) + return true; + } + } + +return false; +} + + + + +int System::NewFilePrivileges() +{ + return NewPrivileges(06666); +} + + +int System::NewDirPrivileges() +{ + return NewPrivileges(07777); +} + + + + + bool System::CanUseHtml(long user_id) { return IsMemberOfGroup(user_id, L"allow_html"); @@ -1068,9 +1144,9 @@ bool System::AddCommonFileToVar(const wchar_t * file_path, const wchar_t * url, file_content_item.Clear(); file_content_item.parent_id = var->id; - file_content_item.user_id = -1; - file_content_item.group_id = -1; - file_content_item.privileges = 0755; + file_content_item.user_id = var->user_id; + file_content_item.group_id = var->group_id; + file_content_item.privileges = 07555; // !! IMPROVE ME: may it should be added as a parameter to this function? file_content_item.subject = url; file_content_item.url = url; file_content_item.type = Item::file; diff --git a/core/system.h b/core/system.h index bc1d403..c4fcf60 100755 --- a/core/system.h +++ b/core/system.h @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010-2011, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -88,7 +88,8 @@ public: bool CanChangeUser(const Item & item, long new_user_id); bool CanChangeGroup(const Item & item, long new_group_id); bool CanChangePrivileges(const Item & item, int new_priv); - bool HasAccess(const Item & item, int mask); + + bool HasReadAccess(const Item & item); bool HasWriteAccess(const Item & item); bool HasReadWriteAccess(const Item & item); @@ -99,6 +100,16 @@ public: void CheckAccessToItems(std::vector & item_tab); void CheckWriteAccessToItems(std::vector & item_tab); + /* + this method checks the sticky bit and write permissions + it returns true if we can remove/rename an item for the given child_item_user_id user id + */ + bool CanRemoveRenameChild(const Item & dir, long child_item_user_id); + + int NewFilePrivileges(); + int NewDirPrivileges(); + + bool CanUseHtml(long user_id); bool CanUseBBCode(long user_id); bool CanUseRaw(long user_id); @@ -156,6 +167,9 @@ private: std::vector root_follow_dir_tab; Item temp_follow_item; + bool HasAccess(const Item & item, int mask); + int NewPrivileges(int creation_mask); + bool CreateNewFileSimpleFs(Item & item); bool CreateNewFileHashFs(Item & item); diff --git a/functions/Makefile.dep b/functions/Makefile.dep index 8ed1a83..ee61ac6 100755 --- a/functions/Makefile.dep +++ b/functions/Makefile.dep @@ -29,7 +29,12 @@ adduser.o: ../templates/htmltextstream.h ../core/mounts.h adduser.o: ../core/mountparser.h ../core/crypt.h ../core/users.h adduser.o: ../core/groups.h ../core/group.h ../core/loadavg.h ../core/image.h adduser.o: ../core/basethread.h ../core/threadmanager.h ../core/synchro.h -adduser.o: ../core/slog.h +adduser.o: ../core/slog.h ../core/plugin.h ../core/pluginmsg.h +adduser.o: ../core/system.h ../core/sessionmanager.h +adduser.o: ../core/sessioncontainer.h ../functions/functions.h +adduser.o: ../templates/templates.h ../templates/patterncacher.h +adduser.o: ../templates/indexpatterns.h ../templates/patterns.h +adduser.o: ../templates/changepatterns.h ../core/sessionmanager.h cat.o: cat.h functionbase.h ../core/item.h ../db/db.h ../db/dbbase.h cat.o: ../db/dbconn.h ../db/dbtextstream.h ../core/textstream.h cat.o: ../core/misc.h ../core/item.h ../core/requesttypes.h ../core/error.h diff --git a/functions/adduser.cpp b/functions/adduser.cpp index ac7187a..2938093 100755 --- a/functions/adduser.cpp +++ b/functions/adduser.cpp @@ -9,6 +9,7 @@ #include "adduser.h" #include "core/slog.h" +#include "core/plugin.h" @@ -112,10 +113,14 @@ void AddUser::MakePost() { if( system->users.AddUser(user) ) { - if( !cur->session->puser ) - system->users.LoginUser(user.id, false); - log << log2 << "AddUser: added a new user: " << user.name << logend; + + if( !cur->session->puser ) + { + system->users.LoginUser(user.id, false); + log << log2 << "AddUser: now logged as: " << user.name << logend; + plugin.Call(WINIX_USER_LOGGED); + } } else { diff --git a/functions/emacs.cpp b/functions/emacs.cpp index e5bf008..713db92 100755 --- a/functions/emacs.cpp +++ b/functions/emacs.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2010, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -125,9 +125,9 @@ void Emacs::MakePost() if( adding ) { - cur->request->is_item = true; // !! moze lepiej nie ustawiac is_item? (bo jak wystapi blad np dodania do bazy danych - // to formularz edycji zmieni sie z 'dodaj' na 'edytuj' - cur->request->item.privileges = 0644; // !! tymczasowo, bedzie uzyte umask + cur->request->is_item = true; // !! moze lepiej nie ustawiac is_item? (bo jak wystapi blad np dodania do bazy danych + // to formularz edycji zmieni sie z 'dodaj' na 'edytuj' + cur->request->item.privileges = system->NewFilePrivileges(); cur->request->status = system->AddFile(cur->request->item, NotifyCodeAdd()); } else diff --git a/functions/functionbase.cpp b/functions/functionbase.cpp index e630960..2bb37ab 100755 --- a/functions/functionbase.cpp +++ b/functions/functionbase.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010-2011, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -19,8 +19,8 @@ FunctionBase::FunctionBase() fun.user_id = -1; fun.group_id = -1; - fun.privileges = 0755; - fun.parent_id = -1; // !! temporarily doesn't matter + fun.privileges = 07555; + fun.parent_id = -1; fun.id = -1; fun.type = Item::file; } diff --git a/functions/ln.cpp b/functions/ln.cpp index 7735e74..45427c2 100755 --- a/functions/ln.cpp +++ b/functions/ln.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -37,7 +37,7 @@ void Ln::CreateSymbolicLink(const std::wstring & link_to) item.url = cur->request->PostVar(L"url"); item.link_to = link_to; item.link_redirect = cur->request->IsPostVar(L"makeredirect") ? 1 : 0; - item.privileges = 0644; // !! tymczasowo, bedzie uzyte umask + item.privileges = system->NewFilePrivileges(); functions->SetUser(item); functions->PrepareUrl(item); @@ -64,7 +64,7 @@ void Ln::CreateHardLink(const std::wstring & link_to) item.type = Item::file; item.parent_id = cur->request->dir_tab.back()->id; item.url = cur->request->PostVar(L"url"); - item.privileges = 0644; // !! tymczasowo, bedzie uzyte umask + item.privileges = system->NewFilePrivileges(); functions->SetUser(item); functions->PrepareUrl(item); cur->request->status = db->AddHardLink(item); diff --git a/functions/mkdir.cpp b/functions/mkdir.cpp index cb23306..a7edbda 100755 --- a/functions/mkdir.cpp +++ b/functions/mkdir.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2010, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -79,7 +79,7 @@ void Mkdir::PostFunMkdir(bool add_to_dir_tab, int privileges) void Mkdir::MakePost() { - PostFunMkdir(false, 0755); + PostFunMkdir(false, system->NewDirPrivileges()); } diff --git a/functions/mv.cpp b/functions/mv.cpp index f99dc51..6353619 100755 --- a/functions/mv.cpp +++ b/functions/mv.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2011, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -21,73 +21,131 @@ Mv::Mv() { fun.url = L"mv"; follow_symlinks = false; + + Prepare(); } +// !! CHECK ME +// check if everywhere correct messages are sent (prepare_to, modified item/dir) + + bool Mv::HasAccess() -{ - return CheckAccessFrom(); -} - - - -bool Mv::CheckAccessFromToDir() -{ -Item * last; -Item * last_but_one = 0; -size_t dir_tab_size; - - last = cur->request->dir_tab.back(); - dir_tab_size = cur->request->dir_tab.size(); - - if( dir_tab_size <= 1 ) - return false; // you cannot move the root directory - - last_but_one = cur->request->dir_tab[dir_tab_size - 2]; - - if( cur->request->method != Request::post ) - { - // used in GET or HEAD - // we don't now whether we move the last directory or the last but one - // it depends on the 'onlycontent' parameter - - if( !system->HasWriteAccess(*last) && !system->HasWriteAccess(*last_but_one) ) - return false; - } - else - { - // used in POST when the moving is performed - - if( cur->request->IsPostVar(L"onlycontent") ) - return system->HasWriteAccess(*last); - else - return system->HasWriteAccess(*last_but_one); - } - -return true; -} - - - - -bool Mv::CheckAccessFrom() { if( cur->request->is_item ) { - // moving a file - - if( !system->HasWriteAccess(*cur->request->dir_tab.back()) ) + if( !system->CanRemoveRenameChild(*cur->request->dir_tab.back(), cur->request->item.user_id) ) + return false; + } + else + { + bool only_content = (cur->request->IsParam(L"c") || cur->request->IsPostVar(L"c")); + + if( !CheckAccessFromToDir(*cur->request->dir_tab.back(), only_content) ) + return false; + } + +return true; +} + + +bool Mv::CheckAccessFromToDir(const Item & dir, bool only_content) +{ + if( dir.parent_id == -1 ) + { + if( !only_content ) { - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + // the root directory cannot be moved anywhere return false; } } else + if( only_content ) { - if( !CheckAccessFromToDir() ) - { - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + // sticky bit for a specified child will be checked later + if( !system->HasWriteAccess(dir) ) return false; + } + else + { + Item * last_but_one_dir = system->dirs.GetDir(dir.parent_id); + + if( !last_but_one_dir ) + // ops, there is no a parent dir + return false; + + if( !system->CanRemoveRenameChild(*last_but_one_dir, dir.user_id) ) + return false; + } + +return true; +} + + + + +// !! IMPROVE ME: may a better name? +void Mv::Prepare() +{ + content_dir_iq.SetAll(false, false); + content_dir_iq.sel_parent_id = true; + content_dir_iq.sel_type = true; + content_dir_iq.sel_url = true; + content_dir_iq.sel_file = true; + content_dir_iq.sel_user_id = true; + content_dir_iq.sel_group_id = true; + content_dir_iq.sel_privileges = true; + content_dir_iq.sel_meta = true; + + files_iq.SetAll(false, false); + files_iq.sel_parent_id = true; + files_iq.sel_type = true; + files_iq.sel_url = true; + files_iq.sel_file = true; + files_iq.sel_user_id = true; + files_iq.sel_group_id = true; + files_iq.sel_privileges = true; + files_iq.sel_meta = true; + files_iq.WhereType(Item::dir, false); +} + + + +void Mv::Clear() +{ + out_dir_tab.clear(); + out_item.Clear(); + out_filename.clear(); + files_item_tab.clear(); + item_tab.clear(); +} + + + +bool Mv::ParseDirCheckLastName() +{ + if( out_has_file ) + { + log << log1 << "Mv: incorrent path" << logend; + slog << logerror << T("mv_incorrect_path") << logend; + return false; + } + else + { + Item * dir = system->dirs.GetDir(out_filename, out_dir_tab.back()->id); + + if( dir ) + { + out_dir_tab.push_back(dir); + out_filename.clear(); + } + else + { + if( db->GetItem(out_dir_tab.back()->id, out_filename, out_item) == WINIX_ERR_OK ) + { + out_has_file = true; + out_filename.clear(); + } } } @@ -95,13 +153,48 @@ return true; } -bool Mv::CheckAccessTo() +bool Mv::ParseDir(const std::wstring & dst_path, bool check_access) { - if( dir_tab.empty() || - !system->HasReadExecAccessToPath(dir_tab) || - !system->HasWriteAccess(*dir_tab.back()) ) + if( dst_path.empty() ) + return false; + + // first we should remove the last name from the dst_path + // (it may not exist in current file system and FollowAllLinks will fail) + size_t last_slash = dst_path.find_last_of('/'); + out_path = dst_path; + out_filename.clear(); + + if( last_slash != std::wstring::npos && last_slash + 1 < dst_path.size() ) { - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + out_path.erase(last_slash + 1); // leaving the slash at the end + out_filename = dst_path.c_str() + last_slash + 1; + } + + int res = system->FollowAllLinks(cur->request->dir_tab, out_path, out_dir_tab, out_item, false, false, check_access); + + if( res != 0 && res != 1 ) + { + slog << logerror << T("mv_incorrect_dst_path") << logend; + return false; + } + + out_has_file = (res == 1); + + if( !out_filename.empty() ) + return ParseDirCheckLastName(); + +return true; +} + + +bool Mv::CanRemoveRenameChild(const Item & child) +{ + Item * parent_dir = system->dirs.GetDir(child.parent_id); + + if( !parent_dir || !system->CanRemoveRenameChild(*parent_dir, child.user_id) ) + { + log << log1 << "Mv: permission denied to: " << child.url << logend; + slog << logerror << T("mv_permission_denied_to") << ": " << child.url << logend; return false; } @@ -109,25 +202,6 @@ return true; } - - - -bool Mv::ParseDir() -{ - const std::wstring & new_dir = cur->request->PostVar(L"to"); - int res = system->dirs.FollowLink(cur->request->dir_tab, new_dir, dir_tab, file); - - if( res == 3 ) - cur->request->status = WINIX_ERR_NO_ROOT_DIR; - else - if( res != 0 && res != 1 ) - cur->request->status = WINIX_ERR_INCORRECT_DIR; - -return res == 0 || res == 1; -} - - - bool Mv::MoveStaticFile(const std::wstring & from, const std::wstring & to) { if( from == to ) @@ -143,8 +217,8 @@ bool Mv::MoveStaticFile(const std::wstring & from, const std::wstring & to) } else { - log << log1 << "Mv: can't move a file from: " << from << ", to: " << to << logend; - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + log << log1 << "Mv: cannot move a static file from: " << from << ", to: " << to << logend; + slog << logerror << T("internal_error") << logend; return false; } } @@ -155,124 +229,44 @@ void Mv::MoveStaticFile(Item & item) { bool res1, res2, res3, res4, res5; - res1 = system->MakeFilePath(item, old_path, false); - res2 = !item.has_thumb || system->MakeFilePath(item, old_path_thumb, true); + res1 = system->MakeFilePath(item, old_static_path, false); + res2 = !item.has_thumb || system->MakeFilePath(item, old_static_thumb_path, true); res3 = system->CreateNewFile(item); - res4 = system->MakeFilePath(item, new_path, false, true, config->upload_dirs_chmod); - res5 = !item.has_thumb || system->MakeFilePath(item, new_path_thumb, true, true, config->upload_dirs_chmod); + res4 = system->MakeFilePath(item, new_static_path, false, true, config->upload_dirs_chmod); + res5 = !item.has_thumb || system->MakeFilePath(item, new_static_thumb_path, true, true, config->upload_dirs_chmod); if( !res1 || !res2 || !res3 || !res4 || !res5 ) { - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + log << log1 << "Mv: cannot create a static path" << logend; + slog << logerror << T("internal_error") << logend; return; } - if( MoveStaticFile(old_path, new_path) ) + if( MoveStaticFile(old_static_path, new_static_path) ) { - cur->request->status = db->EditFileById(item, item.id); + if( db->EditFileById(item, item.id) != WINIX_ERR_OK ) + { + log << log1 << "Mv: cannot move static file (database problem)" << logend; + slog << logerror << T("internal_error") << logend; + return; + } if( item.has_thumb ) - MoveStaticFile(old_path_thumb, new_path_thumb); + MoveStaticFile(old_static_thumb_path, new_static_thumb_path); } } - -void Mv::MoveFileOrSymlink(Item & item) +void Mv::MoveFilesPrepareTreeGo(const Item & src_dir) { - plugin.Call(WINIX_FILE_PREPARE_TO_MOVE, &item); - - old_url = item.url; - - if( !file.empty() ) - { - item.url = file; - functions->PrepareUrl(item); - file.clear(); - } - - item.parent_id = dir_tab.back()->id; - cur->request->status = db->EditParentUrlById(item, item.id); - - if( cur->request->status == WINIX_ERR_OK ) - { - if( item.type == Item::file ) - log << log3 << "Mv: file: "; - else - log << log3 << "Mv: symlink: "; - - log << old_url << " was moved to: "; - system->dirs.LogDir(dir_tab); - log << item.url << logend; - - if( item.file_type != WINIX_ITEM_FILETYPE_NONE ) - MoveStaticFile(item); - - plugin.Call(WINIX_FILE_MOVED, &item); - } -} - - - - -void Mv::MoveDirContent(const Item & dir) -{ - content_dir_iq.WhereParentId(dir.id); - db->GetItems(item_tab, content_dir_iq); - - for(size_t i=0 ; idirs.FindFirstChild(dir.id); + DirContainer::ParentIterator i = system->dirs.FindFirstChild(src_dir.id); // go through all directories for( ; i != system->dirs.ParentEnd() ; i = system->dirs.NextChild(i) ) MoveFilesPrepareTree(*(i->second)); - files_iq.WhereParentId(dir.id); + files_iq.WhereParentId(src_dir.id); db->GetItems(files_item_tab, files_iq); for(size_t i=0 ; idirs.FindFirstChild(dir.id); @@ -294,69 +302,193 @@ void Mv::MoveFilesTree(const Item & dir) for(size_t i=0 ; iid; - old_url = dir.url; - if( dst_dir_id == dir.id || system->dirs.HasParent(dst_dir_id, dir.id) ) + +// private +// uses: out_dir_tab, out_filename +bool Mv::MoveDir(Item & src_dir, std::vector & dst_dir_tab, const std::wstring & dst_name) +{ + long dst_dir_id = dst_dir_tab.back()->id; + old_url = src_dir.url; + + if( dst_dir_id == src_dir.id || system->dirs.HasParent(dst_dir_id, src_dir.id) ) { log << log1 << "Mv: cannot move directory to inside it" << logend; - cur->request->status = WINIX_ERR_INCORRECT_DIR; - return; + slog << logerror << T("mv_cannot_move_to_inside"); + return false; } - MoveFilesPrepareTree(dir); + MoveFilesPrepareTree(src_dir); - if( !system->dirs.ChangeParent(dir.id, dst_dir_id) ) + if( !system->dirs.ChangeParent(src_dir.id, dst_dir_id) ) + return false; + + src_dir.parent_id = dst_dir_id; + old_url = src_dir.url; + + if( !dst_name.empty() ) { - cur->request->status = WINIX_ERR_INCORRECT_DIR; - return; + src_dir.url = dst_name; + functions->PrepareUrl(src_dir); } - dir.parent_id = dst_dir_id; + Error status = db->EditParentUrlById(src_dir, src_dir.id); - if( !file.empty() ) - { - dir.url = file; - functions->PrepareUrl(dir); - file.clear(); - } - - cur->request->status = db->EditParentUrlById(dir, dir.id); - - if( cur->request->status == WINIX_ERR_OK ) + if( status == WINIX_ERR_OK ) { log << log3 << "Mv: directory: " << old_url << " was moved to: "; - system->dirs.LogDir(dir_tab); - log << dir.url << logend; + system->dirs.LogDir(dst_dir_tab); + log << src_dir.url << logend; - MoveFilesTree(dir); + MoveFilesTree(src_dir); + return true; } + +return false; +} + + +// public +bool Mv::MoveDir(Item & src_dir, long dst_dir_id, const std::wstring & new_url, bool check_access) +{ + bool res = MoveDir2(src_dir, dst_dir_id, new_url, check_access); + Clear(); + +return res; +} + + +// private +bool Mv::MoveDir2(Item & src_dir, long dst_dir_id, const std::wstring & new_url, bool check_access) +{ + if( src_dir.type != Item::dir ) + { + log << "Mv: a directory required" << logend; + return false; + } + + if( src_dir.parent_id == -1 ) + { + log << log1 << "Mv: the root directory cannot be moved anywhere" << logend; + slog << logerror << T("mv_cant_move_root_dir") << logend; + return false; + } + + if( check_access && !CanRemoveRenameChild(src_dir) ) + return false; + + if( src_dir.id == dst_dir_id ) + { + if( new_url.empty() || src_dir.url == new_url ) + return true; // the same directory -- there is nothing to do + } + + if( !system->dirs.CreateDirTab(dst_dir_id, out_dir_tab) ) + { + log << log1 << "Mv: incorrect directory" << logend; + slog << logerror << T("mv_incorrect_dir") << logend; + return false; + } + + return MoveDir(src_dir, out_dir_tab, new_url); +} + + + +// public +bool Mv::MoveDir(Item & src_dir, const std::wstring & dst_path, bool check_access) +{ + bool res = MoveDir2(src_dir, dst_path, check_access); + Clear(); + +return res; +} + + +// private +bool Mv::MoveDir2(Item & src_dir, const std::wstring & dst_path, bool check_access) +{ + if( src_dir.type != Item::dir ) + { + log << "Mv: a directory required" << logend; + return false; + } + + if( src_dir.parent_id == -1 ) + { + log << log1 << "Mv: the root directory cannot be moved anywhere" << logend; + slog << logerror << T("mv_cant_move_root_dir") << logend; + return false; + } + + if( check_access && !CanRemoveRenameChild(src_dir) ) + return false; + + if( !ParseDir(dst_path, check_access) ) + return false; + + if( out_has_file ) + { + log << log1 << "Mv: directory can be moved only to a directory" << logend; + slog << logerror << T("mv_dir_can_be_moved_to_dir") << logend; + return false; + } + + if( src_dir.id == out_dir_tab.back()->id ) + { + if( out_filename.empty() || src_dir.url == out_filename ) + return true; // the same directory -- there is nothing to do + } + + return MoveDir(src_dir, out_dir_tab, out_filename); } -bool Mv::IsTheSameFile(const Item & item) + +// private +bool Mv::MoveFileOrSymlink(Item & src_file, std::vector & dst_dir_tab, const std::wstring & new_url) { - if( file.empty() ) + plugin.Call(WINIX_FILE_PREPARE_TO_MOVE, &src_file); + + old_url = src_file.url; + + if( !new_url.empty() ) { - if( item.parent_id == dir_tab.back()->id ) - return true; // nothing to do + src_file.url = new_url; + functions->PrepareUrl(src_file); } - else + + src_file.parent_id = dst_dir_tab.back()->id; + Error status = db->EditParentUrlById(src_file, src_file.id); + + if( status == WINIX_ERR_OK ) { - if( item.parent_id == dir_tab.back()->id && item.url == file ) - return true; // nothing to do + if( src_file.type == Item::file ) + log << log3 << "Mv: file: "; + else + log << log3 << "Mv: symlink: "; + + log << old_url << " was moved to: "; + system->dirs.LogDir(dst_dir_tab); + log << src_file.url << logend; + + if( src_file.file_type != WINIX_ITEM_FILETYPE_NONE ) + MoveStaticFile(src_file); + + plugin.Call(WINIX_FILE_MOVED, &src_file); + return true; } return false; @@ -364,48 +496,164 @@ return false; -void Mv::PostMoveFile() +// public +bool Mv::MoveFileOrSymlink(Item & src_file, long dst_dir_id, const std::wstring & new_url, bool check_access) { - if( IsTheSameFile(cur->request->item) ) - return; + bool res = MoveFileOrSymlink2(src_file, dst_dir_id, new_url, check_access); + Clear(); - MoveFileOrSymlink(cur->request->item); +return res; +} - if( cur->request->status == WINIX_ERR_OK ) - system->RedirectTo(cur->request->item); + +// private +bool Mv::MoveFileOrSymlink2(Item & src_file, long dst_dir_id, const std::wstring & new_url, bool check_access) +{ + if( src_file.type == Item::dir ) + { + log << "Mv: a file/symlink required" << logend; + return false; + } + + if( check_access && !CanRemoveRenameChild(src_file) ) + return false; + + if( src_file.parent_id == dst_dir_id ) + { + if( new_url.empty() || src_file.url == new_url ) + return true; // the same file -- there is nothing to do + } + + if( !system->dirs.CreateDirTab(dst_dir_id, out_dir_tab) ) + return false; + + return MoveFileOrSymlink(src_file, out_dir_tab, new_url); +} + + +// public +bool Mv::MoveFileOrSymlink(Item & src_file, const std::wstring & dst_path, bool check_access) +{ + bool res = MoveFileOrSymlink2(src_file, dst_path, check_access); + Clear(); + +return res; +} + + +// private +bool Mv::MoveFileOrSymlink2(Item & src_file, const std::wstring & dst_path, bool check_access) +{ + if( src_file.type == Item::dir ) + { + log << "Mv: a file/symlink required" << logend; + return false; + } + + if( check_access && !CanRemoveRenameChild(src_file) ) + return false; + + if( !ParseDir(dst_path, check_access) ) + return false; + + if( src_file.parent_id == out_dir_tab.back()->id ) + { + // actually out_filename is here empty + // because ParseDir() have been read it to out_item + if( out_filename.empty() || src_file.url == out_filename ) + return true; // the same file -- there is nothing to do + } + + return MoveFileOrSymlink(src_file, out_dir_tab, out_filename); } -void Mv::PostMoveDirContent() +// private +void Mv::MoveAllFilesFromDir(Item & src_dir, std::vector & dst_dir_tab, bool check_access) { - if( !file.empty() ) + content_dir_iq.WhereParentId(src_dir.id); + db->GetItems(item_tab, content_dir_iq); + out_filename.clear(); + + for(size_t i=0 ; irequest->status = WINIX_ERR_INCORRECT_DIR; + if( check_access && !system->CanRemoveRenameChild(src_dir, item_tab[i].user_id) ) + { + log << log1 << "Mv: permission denied to: " << src_dir.url << logend; + slog << logerror << T("mv_permission_denied_to") << ": " << src_dir.url << logend; + } + else + { + if( item_tab[i].type == Item::dir ) + MoveDir(item_tab[i], dst_dir_tab, out_filename); + else + MoveFileOrSymlink(item_tab[i], dst_dir_tab, out_filename); + } + } +} + + + +// public +void Mv::MoveDirContent(Item & src_dir, long dst_dir_id, bool check_access) +{ + MoveDirContent2(src_dir, dst_dir_id, check_access); + Clear(); +} + + + +// private +void Mv::MoveDirContent2(Item & src_dir, long dst_dir_id, bool check_access) +{ + if( src_dir.type != Item::dir ) + { + log << "Mv: a directory required" << logend; return; } - if( cur->request->dir_tab.back()->id == dir_tab.back()->id ) - return; // nothing to do + if( src_dir.parent_id == -1 ) + { + log << log1 << "Mv: the root directory cannot be moved anywhere" << logend; + slog << logerror << T("mv_cant_move_root_dir") << logend; + return; + } - MoveDirContent(*cur->request->dir_tab.back()); - system->RedirectToLastDir(); + if( !system->dirs.CreateDirTab(dst_dir_id, out_dir_tab) ) + { + log << log1 << "Mv: incorrect directory" << logend; + slog << logerror << T("mv_incorrect_dir") << logend; + return; + } + + MoveAllFilesFromDir(src_dir, out_dir_tab, check_access); } -void Mv::PostMoveDir() +// public +void Mv::MoveDirContent(Item & src_dir, const std::wstring & dst_dir, bool check_access) { - Item & last_dir = *cur->request->dir_tab.back(); - Item & new_dir = *dir_tab.back(); + MoveDirContent2(src_dir, dst_dir, check_access); + Clear(); +} - if( file.empty() && new_dir.id == last_dir.id ) - return; // nothing to do - MoveDir(last_dir); - - if( cur->request->status == WINIX_ERR_OK ) - system->RedirectToLastDir(); +// private +void Mv::MoveDirContent2(Item & src_dir, const std::wstring & dst_dir, bool check_access) +{ + if( !ParseDir(dst_dir, check_access) ) + return; + + if( out_has_file || !out_filename.empty() ) + { + log << log1 << "Mv: directory content can be moved only to a directory" << logend; + slog << logerror << T("mv_dir_content_can_be_moved_to_dir") << logend; + return; + } + + MoveDirContent2(src_dir, out_dir_tab.back()->id, check_access); } @@ -413,26 +661,23 @@ void Mv::PostMoveDir() void Mv::MakePost() { - if( CheckAccessFrom() && - ParseDir() && - CheckAccessTo() ) + const std::wstring & dst_path = cur->request->PostVar(L"dst_path"); + bool ok = true; + + if( cur->request->is_item ) { - Prepare(); - - if( cur->request->is_item ) - { - PostMoveFile(); - } - else - { - if( cur->request->IsPostVar(L"onlycontent") ) - PostMoveDirContent(); - else - PostMoveDir(); - } - - Clear(); + ok = MoveFileOrSymlink(cur->request->item, dst_path, true); } + else + { + if( cur->request->IsParam(L"c") || cur->request->IsPostVar(L"c") ) + MoveDirContent(*cur->request->dir_tab.back(), dst_path, true); + else + ok = MoveDir(*cur->request->dir_tab.back(), dst_path, true); + } + + if( ok ) + system->RedirectToLastItem(); } diff --git a/functions/mv.h b/functions/mv.h index e274326..3787ad9 100755 --- a/functions/mv.h +++ b/functions/mv.h @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -28,46 +28,74 @@ public: bool HasAccess(); void MakePost(); + // moving a directory + // new_url can be empty (in such a case the old one is preserved) + // src_dir will be accordingly updated + bool MoveDir(Item & src_dir, long dst_dir_id, const std::wstring & new_url, bool check_access = true); + bool MoveDir(Item & src_dir, const std::wstring & dst_path, bool check_access = true); + + // moving only the content of src_dir + // dst_path should point to an existing directory + // src_dir will be accordingly updated + void MoveDirContent(Item & src_dir, long dst_dir_id, bool check_access = true); + void MoveDirContent(Item & src_dir, const std::wstring & dst_dir, bool check_access = true); + + // moving a file + // new_url can be empty (the old one is used then) + // src_file will be accordingly updated + bool MoveFileOrSymlink(Item & src_file, long dst_dir_id, const std::wstring & new_url, bool check_access = true); + bool MoveFileOrSymlink(Item & src_file, const std::wstring & dst_path, bool check_access = true); + + private: - // destination dir - std::vector dir_tab; - // destination file (if exists) - std::wstring file; + // directories parsed by ParseDir() + std::vector out_dir_tab; // destination directories + Item out_item; // destination file/symlink (if out_has_file is true) + bool out_has_file; // if true then out_item is set + std::wstring out_filename; // the last part in an input path (not an existing directory, file or symlink) + // can be empty - // for copying static files - std::wstring new_path, new_path_thumb; - std::wstring old_path, old_path_thumb; + // temporaries + std::wstring out_path; + std::wstring old_url; - // for files in a directory + std::wstring old_static_path; + std::wstring old_static_thumb_path; + std::wstring new_static_path; + std::wstring new_static_thumb_path; + + // for files/symlinks in a directory std::vector files_item_tab; DbItemQuery files_iq; - // for moving content of a directory + // for moving content of a directory (all dirs/files/symlinks) DbItemQuery content_dir_iq; std::vector item_tab; - // for logging - std::wstring old_url; - bool CheckAccessFromToDir(); - bool CheckAccessFrom(); - bool CheckAccessTo(); - bool ParseDir(); + bool CheckAccessFromToDir(const Item & dir, bool only_content); + bool CanRemoveRenameChild(const Item & child); + void Prepare(); + bool ParseDirCheckLastName(); + bool ParseDir(const std::wstring & dst_path, bool check_access); bool MoveStaticFile(const std::wstring & from, const std::wstring & to); void MoveStaticFile(Item & item); - void MoveFileOrSymlink(Item & item); - void MoveDirContent(const Item & dir); - void Prepare(); - void Clear(); - void MoveFilesPrepareTree(const Item & dir); + void MoveFilesPrepareTreeGo(const Item & src_dir); + void MoveFilesPrepareTree(const Item & src_dir); void MoveFilesTree(const Item & dir); - void MoveDir(Item & dir); - bool IsTheSameFile(const Item & item); - void PostMoveFile(); - void PostMoveDirContent(); - void PostMoveDir(); + bool MoveDir(Item & src_dir, std::vector & dst_dir_tab, const std::wstring & dst_name); + bool MoveFileOrSymlink(Item & src_file, std::vector & dst_dir_tab, const std::wstring & new_url); + void Clear(); + bool MoveDir2(Item & src_dir, long dst_dir_id, const std::wstring & new_url, bool check_access); + bool MoveDir2(Item & src_dir, const std::wstring & dst_path, bool check_access); + bool MoveFileOrSymlink2(Item & src_file, long dst_dir_id, const std::wstring & new_url, bool check_access); + bool MoveFileOrSymlink2(Item & src_file, const std::wstring & dst_path, bool check_access); + void MoveDirContent2(Item & src_dir, long dst_dir_id, bool check_access); + void MoveAllFilesFromDir(Item & src_dir, std::vector & dst_dir_tab, bool check_access); + void MoveDirContent2(Item & src_dir, const std::wstring & dst_dir, bool check_access); + }; diff --git a/functions/privchanger.cpp b/functions/privchanger.cpp index aabbf67..baf1e42 100755 --- a/functions/privchanger.cpp +++ b/functions/privchanger.cpp @@ -51,13 +51,13 @@ bool PrivChanger::ChangeOwner(Item & item, long user_id, long group_id) { if( !system->CanChangeUser(item, user_id) ) { - log << log3 << "Content: can't change the user" << logend; + log << log3 << "Priv: can't change the user" << logend; return false; } if( !system->CanChangeGroup(item, group_id) ) { - log << log3 << "Content: can't change the group" << logend; + log << log3 << "Priv: can't change the group" << logend; return false; } } @@ -76,7 +76,7 @@ bool PrivChanger::ChangePrivileges(Item & item, int privileges) { if( !system->CanChangePrivileges(item, privileges) ) { - log << log3 << "Content: can't change privileges" << logend; + log << log3 << "Priv: can't change privileges" << logend; return false; } } @@ -153,7 +153,7 @@ Item * root = 0; if( id != -1 ) root = system->dirs.GetRootDir(); - log << log3 << "Content: " << what; + log << log3 << "Priv: " << what; if( root && root->id == id ) log << "(root)"; @@ -169,7 +169,7 @@ void PrivChanger::PrivFilesInDir(long parent_id) DbItemQuery iq; iq.SetAll(false, false); - iq.sel_user_id = iq.sel_group_id = iq.sel_guest_name = iq.sel_privileges = true; + iq.sel_user_id = iq.sel_group_id = iq.sel_guest_name = iq.sel_privileges = iq.sel_url = true; iq.WhereParentId(parent_id); iq.WhereType(Item::dir, false); @@ -230,8 +230,8 @@ void PrivChanger::PrivDir() ReadPriv(L"userfile", L"groupfile", L"privilegesfile", user_id_file, group_id_file, priv_file); ReadPriv(L"userdir", L"groupdir", L"privilegesdir", user_id_dir, group_id_dir, priv_dir); - PrivLogStart(L"Content: changes for files: ", user_id_file, group_id_file, priv_file); - PrivLogStart(L"Content: changes for dirs: ", user_id_dir, group_id_dir, priv_dir); + PrivLogStart(L"Priv: changes for files: ", user_id_file, group_id_file, priv_file); + PrivLogStart(L"Priv: changes for dirs: ", user_id_dir, group_id_dir, priv_dir); if( cur->request->IsPostVar(L"changecurrentdir") ) @@ -256,7 +256,7 @@ void PrivChanger::PrivDir() void PrivChanger::PrivOneItem() { ReadPriv(L"user", L"group", L"privileges", user_id_file, group_id_file, priv_file); - PrivLogStart(L"Content: changes: ", user_id_file, group_id_file, priv_file); + PrivLogStart(L"Priv: changes: ", user_id_file, group_id_file, priv_file); if( cur->request->is_item ) { diff --git a/functions/reload.cpp b/functions/reload.cpp index 7712fbf..d25ccc6 100755 --- a/functions/reload.cpp +++ b/functions/reload.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2010, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -18,10 +18,17 @@ namespace Fun Reload::Reload() { fun.url = L"reload"; - fun.privileges = 0700; + fun.privileges = 07000; } +bool Reload::HasAccess() +{ + return cur->session->puser && cur->session->puser->super_user; +} + + + void Reload::FunReloadTemplates() { log << log1 << "Content: reloading html templates" << logend; diff --git a/functions/reload.h b/functions/reload.h index c9118dd..0b3e211 100755 --- a/functions/reload.h +++ b/functions/reload.h @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -23,6 +23,7 @@ class Reload : public FunctionBase public: Reload(); + bool HasAccess(); void MakeGet(); private: diff --git a/functions/rm.cpp b/functions/rm.cpp index d282166..15c3623 100755 --- a/functions/rm.cpp +++ b/functions/rm.cpp @@ -2,13 +2,12 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2010, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ #include -#include #include "rm.h" #include "core/plugin.h" #include "core/misc.h" @@ -27,49 +26,70 @@ Rm::Rm() -bool Rm::HasAccess(const Item & item) +bool Rm::HasAccessToDir(const Item & dir, bool only_content) { - // !! temporarily (we're waiting for the sticky bit to be implemented) - // not logged users cannot remove anything - if( !cur->session->puser ) - return false; - - if( item.parent_id == -1 ) + if( dir.parent_id == -1 ) { + // this is a root directory // we can only remove the content of the root directory - // and here we check only access the the root dir - // "onlycontent" parameter should be check in post method - if( !system->HasWriteAccess(item) ) + // sticky bit for a specified child will be checked later + if( !only_content || !system->HasWriteAccess(dir) ) + return false; + } + else + if( only_content ) + { + // sticky bit for a specified child will be checked later + if( !system->HasWriteAccess(dir) ) return false; } else { - Item * last_but_one_dir = system->dirs.GetDir(item.parent_id); + Item * last_but_one_dir = system->dirs.GetDir(dir.parent_id); if( !last_but_one_dir ) // ops, there is no a parent dir return false; - if( !system->HasWriteAccess(*last_but_one_dir) ) + if( !system->CanRemoveRenameChild(*last_but_one_dir, dir.user_id) ) return false; } - - if( system->mounts.pmount->IsPar(system->mounts.MountParOnlyRootRemove()) ) - if( !cur->session->puser || !cur->session->puser->super_user ) - return false; return true; } + +/* + here we are making a little test -- this method returns false if + we are sure that the permissions is not allowed (consequently the html form + will not be displayed) + the correct checking for permissions is done later in MakePost() method + + parameter 'c' to rm function means removing only the content of a directory + this parameter can be sent either by a get or a post variable +*/ bool Rm::HasAccess() { bool res; - if( !cur->request->is_item ) - res = HasAccess(*cur->request->dir_tab.back()); + if( cur->request->is_item ) + { + res = system->CanRemoveRenameChild(*cur->request->dir_tab.back(), cur->request->item.user_id); + } else - res = HasAccess(cur->request->item); + { + if( cur->request->IsParam(L"r") ) + { + bool only_content = (cur->request->IsParam(L"c") || cur->request->IsPostVar(L"c")); + res = HasAccessToDir(*cur->request->dir_tab.back(), only_content); + } + else + { + log << log3 << "Rm: directories can be removed only with 'r' parameter" << logend; + slog << logerror << T("rm_use_r_option") << logend; + } + } if( !res && cur->request->IsParam(L"jquery_upload") ) CreateJSON(res); @@ -83,66 +103,70 @@ void Rm::Prepare() { // selecting files and symlinks (without directories) content_dir_iq.SetAll(false, false); - content_dir_iq.sel_parent_id = true; - content_dir_iq.sel_type = true; - content_dir_iq.sel_url = true; - content_dir_iq.sel_file = true; + content_dir_iq.sel_parent_id = true; + content_dir_iq.sel_type = true; + content_dir_iq.sel_url = true; + content_dir_iq.sel_file = true; + content_dir_iq.sel_user_id = true; + content_dir_iq.sel_group_id = true; + content_dir_iq.sel_privileges = true; + content_dir_iq.sel_meta = true; content_dir_iq.WhereType(Item::dir, false); - - // selecting files, symlinks and directories - content_dir_iq2.SetAll(false, false); - content_dir_iq2.sel_parent_id = true; - content_dir_iq2.sel_type = true; - content_dir_iq2.sel_url = true; - content_dir_iq2.sel_file = true; } -bool Rm::RemoveStaticFile(const std::wstring & path) + +void Rm::RemoveStaticFile(const std::wstring & path) { if( ::RemoveFile(path) ) { - log << log2 << "Rm: removed static file: " << path << logend; - return true; + log << log2 << "Rm: static file removed: " << path << logend; } else { - log << log1 << "Rm: can't remove a file: " << path << logend; - cur->request->status = WINIX_ERR_PERMISSION_DENIED; - return false; + log << log1 << "Rm: I can't remove a static file: " << path << logend; + slog << logerror << T("rm_cannot_remove_static_file") << ": " << path << logend; } } -void Rm::RemoveStaticFile(Item & item) + +void Rm::RemoveStaticFile(const Item & item) { if( system->MakeFilePath(item, path, false) ) { - if( RemoveStaticFile(path) ) - { - if( item.has_thumb && system->MakeFilePath(item, path, true) ) - RemoveStaticFile(path); + RemoveStaticFile(path); - // we don't change item.file_path and others file_* variables - // they can be used by a plugin - } + if( item.has_thumb && system->MakeFilePath(item, path, true) ) + RemoveStaticFile(path); } else { - cur->request->status = WINIX_ERR_PERMISSION_DENIED; + log << log1 << "Rm: I cannot create a path to a static file, url: " + << item.url << ", id: " << item.id << logend; + + slog << logerror << T("rm_cannot_create_static_path") << ": " << item.url << logend; } } -void Rm::RemoveFileOrSymlink(Item & item) +/* + !! IMPROVE ME: + plugin.Call(WINIX_FILE_REMOVED, &item) is getting its parameter as non-const + in the future we can add a pointer cp1, cp2 (in plugins) but pointing to a const object + and this bool Rm::RemoveFile(Item & item) can became bool Rm::RemoveFile(const Item & item) +*/ +bool Rm::RemoveFile(Item & item) { + plugin.Call(WINIX_FILE_PREPARE_TO_REMOVE, &item); + if( db->DelItem(item) == WINIX_ERR_OK ) { if( item.type == Item::file ) - log << log2 << "Rm: deleted file "; + log << log2 << "Rm: deleted file: "; else - log << log2 << "Rm: deleted symlink "; + log << log2 << "Rm: deleted symlink: "; log << item.url << logend; @@ -152,121 +176,209 @@ void Rm::RemoveFileOrSymlink(Item & item) RemoveStaticFile(item); plugin.Call(WINIX_FILE_REMOVED, &item); + return true; } + +return false; +} + + + +/* + we do not modify item + it is non-const because we use plugin.Call() later with a pointer to this structure + (and we want to avoid casting) +*/ +bool Rm::RemoveFileOrSymlink(Item & item, bool check_access) +{ + if( item.type == Item::dir ) + return false; + + if( check_access ) + { + Item * dir = system->dirs.GetDir(item.parent_id); + + // if there is not 'dir' directory then we can simply remove 'item' + if( dir ) + { + if( !system->CanRemoveRenameChild(*dir, item.user_id) ) + { + log << log1 << "Rm: permission denied to remove: " << item.url << ", id: " << item.id << logend; + slog << logerror << T("rm_permission_denied_to") << ": " << item.url << logend; + return false; + } + } + } + +return RemoveFile(item); } // for other uses (plugins etc) -void Rm::RemoveItemById(long item_id) +void Rm::RemoveItemById(long item_id, bool check_access) { // selecting files, symlinks and directories rm_by_id_iq.SetAll(false, false); - rm_by_id_iq.sel_parent_id = true; - rm_by_id_iq.sel_type = true; - rm_by_id_iq.sel_url = true; - rm_by_id_iq.sel_file = true; + rm_by_id_iq.sel_parent_id = true; + rm_by_id_iq.sel_type = true; + rm_by_id_iq.sel_url = true; + rm_by_id_iq.sel_file = true; + rm_by_id_iq.sel_user_id = true; + rm_by_id_iq.sel_group_id = true; + rm_by_id_iq.sel_privileges = true; + rm_by_id_iq.sel_meta = true; rm_by_id_iq.WhereId(item_id); if( db->GetItem(rm_by_id_item, rm_by_id_iq) == WINIX_ERR_OK ) { if( rm_by_id_item.type == Item::dir ) - RemoveDir(rm_by_id_item); + RemoveDirTree(rm_by_id_item, true, check_access); else - RemoveFileOrSymlink(rm_by_id_item); + RemoveFileOrSymlink(rm_by_id_item, check_access); } } -void Rm::RemoveDirTree(long dir_id) + +bool Rm::RemoveDirFiles(long dir_id, bool check_access) { - DirContainer::ParentIterator pnext, p = system->dirs.FindFirstChild(dir_id); - - for( ; p != system->dirs.ParentEnd() ; p = pnext ) - { - plugin.Call(WINIX_DIR_PREPARE_TO_REMOVE, &(*p->second)); - - // this iterator p will be deleted by the next DeleteDir(p->second->id) - // (the next iterator we must calculate beforehand) - pnext = system->dirs.NextChild(p); - RemoveDirTree(p->second->id); - } - content_dir_iq.WhereParentId(dir_id); db->GetItems(content_item_tab, content_dir_iq); - for(size_t i=0 ; iDelDirById(dir_id) == WINIX_ERR_OK ) + for(size_t i=0 ; iCanRemoveRenameChild(*parent_dir, current_dir->user_id) ) + { + log << log1 << "Rm: permission denied to directory: " << current_dir->url << logend; + slog << logerror << T("rm_permission_denied_to") << ": " << current_dir->url << logend; + return; + } + } + + plugin.Call(WINIX_DIR_PREPARE_TO_REMOVE, current_dir); + + if( db->DelDirById(current_dir->id) == WINIX_ERR_OK ) + { + long dir_id = current_dir->id; + old_url = current_dir->url; system->dirs.DelDir(dir_id); + // don't use current_dir pointer anymore + log << log2 << "Rm: directory removed: " << old_url << logend; plugin.Call(WINIX_DIR_REMOVED, dir_id); } -} - - - -void Rm::RemoveDir(const Item & dir) -{ - plugin.Call(WINIX_DIR_PREPARE_TO_REMOVE, const_cast(&dir)); - - old_url = dir.url; - RemoveDirTree(dir.id); - - // warning: 'dir' has been deleted so don't use the 'dir' reference - - if( cur->request->status == WINIX_ERR_OK ) - log << log3 << "Rm: removed directory " << old_url << logend; -} - - - -void Rm::RemoveFile() -{ - RemoveFileOrSymlink(cur->request->item); -} - - - -void Rm::RemoveDirContent(const Item & dir) -{ - content_dir_iq2.WhereParentId(dir.id); - db->GetItems(content_item_tab2, content_dir_iq2); - - for(size_t i=0 ; iurl << " (database error)" << logend; } } + +/* + parent_dir can be null (when current_dir is pointing to the root directory) + current_dir is pointing to the directory which should be deleted + (contents of this directory is removed but the directory is deleted only if remove_this_dir is true) +*/ +void Rm::RemoveDirTree(Item * parent_dir, Item * current_dir, bool remove_this_dir, bool check_access) +{ + if( check_access && !system->HasReadExecAccess(*current_dir) ) + { + log << log1 << "Rm: permission denied to directory: " << current_dir->url << logend; + slog << logerror << T("rm_permission_denied_to") << ": " << current_dir->url << logend; + return; + } + + DirContainer::ParentIterator pnext, p = system->dirs.FindFirstChild(current_dir->id); + + for( ; p != system->dirs.ParentEnd() ; p = pnext ) + { + Item * child_dir = &(*p->second); + + // this iterator p will be invalidated by the below RemoveDirTree() call + // (the next iterator we must calculate beforehand) + pnext = system->dirs.NextChild(p); + RemoveDirTree(current_dir, child_dir, true, check_access); + } + + bool all_file_removed = RemoveDirFiles(current_dir->id, check_access); + + if( remove_this_dir ) + { + if( all_file_removed ) + { + RemoveCurrentDir(parent_dir, current_dir, check_access); + // don't use current_dir pointer anymore + } + else + { + log << log1 << "Rm: " << current_dir->url << " directory not empty" << logend; + slog << logerror << current_dir->url << T("rm_directory_not_empty") << logend; + } + } +} + + + +void Rm::RemoveDirTree(Item & dir, bool remove_this_dir, bool check_access) +{ + Item * parent = system->dirs.GetDir(dir.parent_id); + RemoveDirTree(parent, &dir, remove_this_dir, check_access); +} + + + + void Rm::RemoveDirContent() { if( !cur->request->IsParam(L"r") ) { cur->request->status = WINIX_ERR_PERMISSION_DENIED; + log << log3 << "Rm: directory content can be removed only with 'r' parameter" << logend; + slog << logerror << T("rm_content_use_r_option") << logend; return; } - RemoveDirContent(*cur->request->dir_tab.back()); + RemoveDirTree(*cur->request->dir_tab.back(), false, true); } void Rm::RemoveDir() { - if( !cur->request->IsParam(L"r") || cur->request->dir_tab.size() <= 1 ) + if( !cur->request->IsParam(L"r") ) { - // we cannot remove the root directory (dir_tab.size()==1) cur->request->status = WINIX_ERR_PERMISSION_DENIED; + log << log3 << "Rm: a directory can be removed only with 'r' parameter" << logend; + slog << logerror << T("rm_use_r_option") << logend; return; } - RemoveDir(*cur->request->dir_tab.back()); + if( cur->request->dir_tab.size() <= 1 ) + { + cur->request->status = WINIX_ERR_PERMISSION_DENIED; + log << log1 << "Rm: the root directory cannot be removed" << logend; + slog << logerror << T("rm_cannot_remove_root_dir") << logend; + return; + } + + RemoveDirTree(*cur->request->dir_tab.back(), true, true); cur->request->dir_tab.erase(--cur->request->dir_tab.end()); } @@ -276,7 +388,6 @@ void Rm::RemoveDir() void Rm::Clear() { content_item_tab.clear(); - content_item_tab2.clear(); } @@ -288,7 +399,7 @@ void Rm::CreateJSON(bool status) else cur->request->page << "false\n"; - cur->request->page_generated = true; + cur->request->page_generated = true; cur->request->use_html_filter = false; } @@ -299,11 +410,11 @@ void Rm::MakePost() if( cur->request->is_item ) { - RemoveFile(); + RemoveFileOrSymlink(cur->request->item, true); } else { - if( cur->request->IsPostVar(L"onlycontent") ) + if( cur->request->IsParam(L"c") || cur->request->IsPostVar(L"c") ) RemoveDirContent(); else RemoveDir(); diff --git a/functions/rm.h b/functions/rm.h index cc995f8..8c0e745 100755 --- a/functions/rm.h +++ b/functions/rm.h @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -26,12 +26,16 @@ public: bool HasAccess(); void MakePost(); - void RemoveDir(const Item & dir); - void RemoveDirContent(const Item & dir); - void RemoveFileOrSymlink(Item & item); + // removing the whole directory structure + // if remove_this_dir is false then only content of dir is removed + void RemoveDirTree(Item & dir, bool remove_this_dir, bool check_access = true); + + // removing either a file or a symlink + bool RemoveFileOrSymlink(Item & item, bool check_access = true); // removing either a directory or a symlink or a file - void RemoveItemById(long item_id); + // if item_id is a directory then the whole subdirectories are removed too + void RemoveItemById(long item_id, bool check_access = true); private: @@ -40,10 +44,6 @@ private: std::vector content_item_tab; std::wstring path; - // for deleting content in a directory (files, symlinks and directories) - DbItemQuery content_dir_iq2; - std::vector content_item_tab2; - // for logging std::wstring old_url; @@ -51,15 +51,18 @@ private: DbItemQuery rm_by_id_iq; Item rm_by_id_item; - bool HasAccess(const Item & item); + bool HasAccessToDir(const Item & dir, bool only_content); void Prepare(); void Clear(); - bool RemoveStaticFile(const std::wstring & path); - void RemoveStaticFile(Item & item); - void RemoveDirTree(long dir_id); + + bool RemoveFile(Item & item); + bool RemoveDirFiles(long dir_id, bool check_access); + void RemoveCurrentDir(Item * parent_dir, Item * current_dir, bool check_access); + void RemoveDirTree(Item * parent_dir, Item * current_dir, bool remove_this_dir, bool check_access); + void RemoveStaticFile(const std::wstring & path); + void RemoveStaticFile(const Item & item); void RemoveDirContent(); void RemoveDir(); - void RemoveFile(); void CreateJSON(bool status); }; diff --git a/functions/upload.cpp b/functions/upload.cpp index 704c170..9c0beb0 100755 --- a/functions/upload.cpp +++ b/functions/upload.cpp @@ -224,7 +224,7 @@ void Upload::UploadMulti() cur->request->item.Clear(); // clearing and setting date cur->request->item.parent_id = cur->request->dir_tab.back()->id; cur->request->item.type = Item::file; - cur->request->item.privileges = 0644; // !! tymczasowo + cur->request->item.privileges = system->NewFilePrivileges(); functions->SetUser(cur->request->item); PostFileTab::iterator i = cur->request->post_file_tab.begin(); @@ -259,7 +259,7 @@ void Upload::UploadSingle() functions->ReadItem(cur->request->item, Item::file); // ReadItem() changes the url if it is empty functions->SetUser(cur->request->item); - cur->request->item.privileges = 0644; // !! tymczasowo + cur->request->item.privileges = system->NewFilePrivileges(); PostFile & post_file = cur->request->post_file_tab.begin()->second; diff --git a/html/fun_mv.html b/html/fun_mv.html index 51cf5de..b35939f 100755 --- a/html/fun_mv.html +++ b/html/fun_mv.html @@ -7,16 +7,16 @@ {mv_form_legend}

- [if-one item_is]{mv_page} "[item_url]":[else]{mv_dir} "[dir_without_slash]"[end] + [if-one item_is]{mv_page} [item_url]:[else]{mv_dir} [dir][end]

{suggested_url}

- + [if-no item_is] - + [end] diff --git a/html/fun_rm.html b/html/fun_rm.html index a9db355..db4fb07 100755 --- a/html/fun_rm.html +++ b/html/fun_rm.html @@ -1,5 +1,4 @@

{rm_header}

-[include "error.html"]
@@ -28,7 +27,7 @@ [if-no item_is]

- +

[end] diff --git a/locale/en b/locale/en index 655f748..112d649 100755 --- a/locale/en +++ b/locale/en @@ -25,7 +25,7 @@ by = by error_404 = Error 404 error_404_msg = We are sory but there is no such a page in our service. - +internal_error = Internal error, check system log for more details was_errors = We are sory but there were some problems with the operation. @@ -182,6 +182,14 @@ rm_dir = Do you really want to remove directory rm_only_content = Remove only the content of the directory rm_root = You cannot remove the root directory, you are only allowed to delete the content of the directory rm_submit = Remove +rm_cannot_create_static_path = I cannot create a path to a static file +rm_cannot_remove_static_file = I cannot remove a static file +rm_permission_denied_to = Permission denied to remove +rm_directory_not_empty = directory not empty +rm_use_r_option = This is a directory, use 'r' parameter to remove it +rm_cannot_remove_root_dir = You cannot remove the root directory +rm_content_use_r_option = Content of a directory can be removed only with 'r' parameter + thread_create_new = Create a new thread thread_tab_title = Thread title @@ -306,6 +314,14 @@ mv_form_legend = Move form mv_page = Move page mv_dir = Move directory mv_only_content = Move only content of the directory +mv_cant_move_root_dir = the root directory cannot be moved anywhere +mv_permission_denied_to = Permission denied to +mv_incorrect_path = Incorrent path +mv_dir_can_be_moved_to_dir = A directory can be moved only to an other directory +mv_dir_content_can_be_moved_to_dir = Directory content can be moved only to an other directory +mv_cannot_move_to_inside = A directory cannot be moved to inside it +mv_incorrect_dst_path = Incorrect destination path +mv_incorrect_dir = Incorrect directory cp_header = Copy diff --git a/locale/pl b/locale/pl index dbb0036..f8efacc 100755 --- a/locale/pl +++ b/locale/pl @@ -26,6 +26,8 @@ error_404 = Błąd 404 error_404_msg = Przykro nam ale podanej strony nie ma w naszym serwisie. +internal_error = Błąd wewnętrzny, po więcej szczegółów sprawdź dziennik systemowy + was_errors = Przepraszamy ale wystąpiły problemy z wykonaniem tej operacji. error_code = Kod błędu @@ -201,6 +203,15 @@ rm_dir = Czy napewno usunąć katalog rm_only_content = Usuń jedynie zawartość katalogu rm_root = Nie możesz skasować katalogu głównego, możesz jedynie usunąć jego zawartość rm_submit = Usuń +rm_cannot_create_static_path = Nie mogę utworzyć ścieżki do pliku statycznego +rm_cannot_remove_static_file = Nie mogę usunąć pliku statycznego +rm_permission_denied_to = Brak dostępu do usunięcia +rm_directory_not_empty = katalog nie jest pusty +rm_use_r_option = To jest katalog, aby go usunąć musisz użyć parametru 'r' +rm_cannot_remove_root_dir = Nie możesz usunąć głównego katalogu +rm_content_use_r_option = Zawartość katalogu może zostać usunięta tylko z użyciem parametru 'r' + + thread_create_new = Załóż nowy wątek thread_tab_title = Tytuł wątku @@ -323,6 +334,14 @@ mv_form_legend = Formularz zmiany mv_page = Przenieś stronę mv_dir = Przenieś katalog mv_only_content = Przenieś tylko zawartość katalogu +mv_cant_move_root_dir = Katalog główny nie może być przeniesiony +mv_permission_denied_to = Brak dostępu do +mv_incorrect_path = Nieprawidłowa ścieżka +mv_dir_can_be_moved_to_dir = Katalog może zostać przeniesiony tylko do innego katalogu +mv_dir_content_can_be_moved_to_dir = Zawartość katalogu może zostać przeniesiona tylko do innego katalogu +mv_cannot_move_to_inside = Nie mogę przenieść katalogu do jego środka +mv_incorrect_dst_path = Nieprawidłowa ścieżka docelowa +mv_incorrect_dir = Nieprawidłowy katalog cp_header = Kopiuj diff --git a/plugins/thread/createthread.cpp b/plugins/thread/createthread.cpp index 46efa62..bc99c01 100755 --- a/plugins/thread/createthread.cpp +++ b/plugins/thread/createthread.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2010, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -72,7 +72,7 @@ void CreateThread::MakePost() functions->SetUser(cur->request->item); functions->PrepareUrl(cur->request->item); cur->request->item.parent_id = cur->request->dir_tab.back()->id; - cur->request->item.privileges = 0644; // !! tymczasowo + cur->request->item.privileges = system->NewFilePrivileges(); if( functions->CheckAbuse() ) return; diff --git a/plugins/thread/reply.cpp b/plugins/thread/reply.cpp index e9647b6..9d01b01 100755 --- a/plugins/thread/reply.cpp +++ b/plugins/thread/reply.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2010, Tomasz Sowa + * Copyright (c) 2010-2012, Tomasz Sowa * All rights reserved. * */ @@ -92,7 +92,7 @@ void Reply::MakePost() functions->SetUser(answer); functions->PrepareUrl(answer); answer.parent_id = files_dir->id; - answer.privileges = 0644; // !! tymczasowo + answer.privileges = system->NewFilePrivileges(); if( functions->CheckAbuse() ) return; diff --git a/plugins/ticket/createticket.cpp b/plugins/ticket/createticket.cpp index f81be77..f3c4627 100755 --- a/plugins/ticket/createticket.cpp +++ b/plugins/ticket/createticket.cpp @@ -80,7 +80,7 @@ void CreateTicket::Submit(Ticket & ticket, Item & item) return; functions->SetUser(item); - item.privileges = 0644; // !! tymczasowo + item.privileges = system->NewFilePrivileges(); item.parent_id = cur->request->dir_tab.back()->id; // adding without notificating diff --git a/plugins/ticket/sessiondata.cpp b/plugins/ticket/sessiondata.cpp index 3598691..d73f595 100755 --- a/plugins/ticket/sessiondata.cpp +++ b/plugins/ticket/sessiondata.cpp @@ -61,7 +61,7 @@ void SessionData::RemoveAllFiles(PT::Space & new_space) BuildFileList(new_file_tab, new_space); for(size_t i=0 ; iRemoveItemById(new_file_tab[i]); + fun_rm->RemoveItemById(new_file_tab[i], false); } @@ -86,7 +86,7 @@ void SessionData::RemoveAllStaleFiles(PT::Space & new_space, PT::Space & old_spa { if( new_file_tab[n] < old_file_tab[o] ) { - fun_rm->RemoveItemById(new_file_tab[n]); + fun_rm->RemoveItemById(new_file_tab[n], false); n += 1; } else @@ -103,7 +103,7 @@ void SessionData::RemoveAllStaleFiles(PT::Space & new_space, PT::Space & old_spa while( n < new_file_tab.size() ) { - fun_rm->RemoveItemById(new_file_tab[n]); + fun_rm->RemoveItemById(new_file_tab[n], false); n += 1; } } diff --git a/plugins/ticket/ticketinfo.cpp b/plugins/ticket/ticketinfo.cpp index 07303e3..05a8f67 100755 --- a/plugins/ticket/ticketinfo.cpp +++ b/plugins/ticket/ticketinfo.cpp @@ -132,16 +132,12 @@ bool TicketInfo::ParseTicketConf(long mount_dir_id, const std::wstring & path) { log << log3 << "Ticket: parsing conf file: " << path << logend; - log << log1 << config_file.content << logend; - conf_tab[mount_dir_id].file_name = path; conf_parser.UTF8(true); conf_parser.SetSpace(conf_tab[mount_dir_id].conf); conf_parser.SplitSingle(true); conf_tab[mount_dir_id].conf.Clear(); - //log << log1 << "status: " << conf_parser.Parse(config_file.content) << logend; - return (conf_parser.ParseString(config_file.content) == PT::ConfParser::ok); } @@ -343,7 +339,7 @@ void TicketInfo::ReadTicketValue(PT::Space & space, file.Clear(); // clearing and setting date file.parent_id = upload_dir.id; file.type = Item::file; - file.privileges = 0644; // !! tymczasowo + file.privileges = system->NewFilePrivileges(); file.file_type = SelectFileType(value.filename); file.url = value.filename; functions->PrepareUrl(file); diff --git a/templates/priv.cpp b/templates/priv.cpp index 976fc9e..4f8da30 100755 --- a/templates/priv.cpp +++ b/templates/priv.cpp @@ -2,7 +2,7 @@ * This file is a part of Winix * and is not publicly distributed * - * Copyright (c) 2008-2010, Tomasz Sowa + * Copyright (c) 2008-2012, Tomasz Sowa * All rights reserved. * */ @@ -253,15 +253,13 @@ void priv_privileges(Info & i) void priv_privileges_for_files(Info & i) { - //!! bedzie uzyte umask - i.out << Toa((int)0644, 8); + i.out << Toa(system->NewFilePrivileges(), 8); } void priv_privileges_for_dirs(Info & i) { - //!! bedzie uzyte umask - i.out << Toa((int)0755, 8); + i.out << Toa(system->NewDirPrivileges(), 8); }