// ---------------------------------------------------------------------- // File: Chmod.cc // Author: Andreas-Joachim Peters - CERN // ---------------------------------------------------------------------- /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2011 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ // ----------------------------------------------------------------------- // This file is included source code in XrdMgmOfs.cc to make the code more // transparent without slowing down the compilation time. // ----------------------------------------------------------------------- /*----------------------------------------------------------------------------*/ int XrdMgmOfs::chmod(const char* inpath, XrdSfsMode Mode, XrdOucErrInfo& error, const XrdSecEntity* client, const char* ininfo) /*----------------------------------------------------------------------------*/ /* * @brief change the mode of a directory * * @param inpath path to chmod * @param Mode mode to set * @param error error object * @param client XRootD authentication object * @param ininfo CGI * * Function calls the internal _chmod function. See info there for details. */ /*----------------------------------------------------------------------------*/ { static const char* epname = "chmod"; const char* tident = error.getErrUser(); // mode_t acc_mode = Mode & S_IAMB; // use a thread private vid eos::common::VirtualIdentity vid; EXEC_TIMING_BEGIN("IdMap"); eos::common::Mapping::IdMap(client, ininfo, tident, vid, gOFS->mTokenAuthz, AOP_Chmod, inpath); EXEC_TIMING_END("IdMap"); NAMESPACEMAP; BOUNCE_ILLEGAL_NAMES; XrdOucEnv chmod_Env(ininfo); AUTHORIZE(client, &chmod_Env, AOP_Chmod, "chmod", inpath, error); gOFS->MgmStats.Add("IdMap", vid.uid, vid.gid, 1); BOUNCE_NOT_ALLOWED; ACCESSMODE_W; MAYSTALL; MAYREDIRECT; return _chmod(path, Mode, error, vid, ininfo); } /*----------------------------------------------------------------------------*/ int XrdMgmOfs::_chmod(const char* path, XrdSfsMode& Mode, XrdOucErrInfo& error, eos::common::VirtualIdentity& vid, const char* ininfo) /*----------------------------------------------------------------------------*/ /* * @brief change mode of a directory or file * * @param path where to chmod * @param Mode mode to set (and effective mode returned) * @param error error object * @param vid virtual identity of the client * @param ininfo CGI * @return SFS_OK on success otherwise SFS_ERR * * EOS supports mode bits only on directories, file inherit them from the parent. * Only the owner, the admin user, the admin group, root and an ACL chmod granted * user are allowed to run this operation on a directory. */ /*----------------------------------------------------------------------------*/ { static const char* epname = "chmod"; EXEC_TIMING_BEGIN("Chmod"); // --------------------------------------------------------------------------- eos::Prefetcher::prefetchContainerMDAndWait(gOFS->eosView, path); eos::Prefetcher::prefetchFileMDAndWait(gOFS->eosView, path); eos::common::RWMutexWriteLock lock(gOFS->eosViewRWMutex); std::shared_ptr cmd; std::shared_ptr pcmd; std::shared_ptr fmd; eos::IContainerMD::XAttrMap attrmap; errno = 0; gOFS->MgmStats.Add("Chmod", vid.uid, vid.gid, 1); eos_info("path=%s mode=%o", path, Mode); eos::common::Path cPath(path); try { cmd = gOFS->eosView->getContainer(path); } catch (eos::MDException& e) { errno = e.getErrno(); } if (!cmd) { errno = 0; // Check if this is a file try { fmd = gOFS->eosView->getFile(path); } catch (eos::MDException& e) { errno = e.getErrno(); } } if (cmd || fmd) try { std::string uri; if (cmd) { uri = gOFS->eosView->getUri(cmd.get()); } else { uri = gOFS->eosView->getUri(fmd.get()); } eos::common::Path pPath(uri.c_str()); pcmd = gOFS->eosView->getContainer(pPath.GetParentPath()); // ACL and permission check Acl acl(pPath.GetParentPath(), error, vid, attrmap, false); if (vid.uid && !acl.IsMutable()) { // immutable directory errno = EPERM; } else { // If owner without revoked chmod permissions if (((fmd && (fmd->getCUid() == vid.uid)) && (!acl.CanNotChmod())) || ((cmd && (cmd->getCUid() == vid.uid)) && (!acl.CanNotChmod())) || (!vid.uid) || // the root user (vid.uid == 3) || // the admin user (vid.gid == 4) || // the admin group (acl.CanChmod()) ) { // a pre-defined mask to apply to the desired modbits // the chmod ACL entry // change the permission mask, but make sure it is set to a directory long mask = 07777777; if (Mode & S_IFREG) { Mode ^= S_IFREG; } if ((Mode & S_ISUID)) { Mode ^= S_ISUID; } eosView->updateContainerStore(pcmd.get()); eos::ContainerIdentifier pcmd_id = pcmd->getIdentifier(); eos::ContainerIdentifier pcmd_pid = pcmd->getParentIdentifier(); eos::ContainerIdentifier cmd_id; eos::ContainerIdentifier cmd_pid; eos::FileIdentifier f_id; if (cmd) { Mode &= mask; cmd->setMode(Mode | S_IFDIR); cmd->setCTimeNow(); // store the in-memory modification time for this directory eosView->updateContainerStore(cmd.get()); cmd_id = cmd->getIdentifier(); cmd_pid = cmd->getParentIdentifier(); } if (fmd) { // we just store 9 bits in flags Mode &= (S_IRWXU | S_IRWXG | S_IRWXO); fmd->setFlags(Mode); eosView->updateFileStore(fmd.get()); f_id = fmd->getIdentifier(); } lock.Release(); gOFS->FuseXCastRefresh(pcmd_id, pcmd_pid); if (cmd) { gOFS->FuseXCastRefresh(cmd_id, cmd_pid); } if (fmd) { gOFS->FuseXCastRefresh(f_id, pcmd_id); } errno = 0; } else { errno = EPERM; } } } catch (eos::MDException& e) { errno = e.getErrno(); } if (cmd && (!errno)) { EXEC_TIMING_END("Chmod"); return SFS_OK; } if (fmd && (!errno)) { EXEC_TIMING_END("Chmod"); return SFS_OK; } return Emsg(epname, error, errno, "chmod", path); }