diff options
| author | randomdan <randomdan@localhost> | 2014-05-25 13:52:39 +0000 | 
|---|---|---|
| committer | randomdan <randomdan@localhost> | 2014-05-25 13:52:39 +0000 | 
| commit | 1225d9e44c4db5d3c7ee7458327e4573cd19bb53 (patch) | |
| tree | 648a1f76dce50e4144661de306cba9e5f9920da6 | |
| parent | Use single shared entCache (diff) | |
| download | netfs-1225d9e44c4db5d3c7ee7458327e4573cd19bb53.tar.bz2 netfs-1225d9e44c4db5d3c7ee7458327e4573cd19bb53.tar.xz netfs-1225d9e44c4db5d3c7ee7458327e4573cd19bb53.zip | |
No more setuid/setgid because it's not thread-safe, instead we handle permissions ourself
| -rw-r--r-- | netfs/daemon/daemon.cpp | 46 | ||||
| -rw-r--r-- | netfs/daemon/daemon.h | 15 | ||||
| -rw-r--r-- | netfs/daemon/daemonDirectory.h | 2 | ||||
| -rw-r--r-- | netfs/daemon/daemonFile.cpp | 4 | ||||
| -rw-r--r-- | netfs/daemon/daemonService.h | 1 | ||||
| -rw-r--r-- | netfs/daemon/daemonVolume.cpp | 97 | ||||
| -rw-r--r-- | netfs/daemon/ioHelpers.cpp | 30 | ||||
| -rw-r--r-- | netfs/daemon/ioHelpers.h | 11 | 
8 files changed, 160 insertions, 46 deletions
| diff --git a/netfs/daemon/daemon.cpp b/netfs/daemon/daemon.cpp index 0cbe2ad..3736167 100644 --- a/netfs/daemon/daemon.cpp +++ b/netfs/daemon/daemon.cpp @@ -6,6 +6,8 @@  #include "daemonConfig.h"  #include "daemonService.h"  #include "daemonVolume.h" +#include "ioHelpers.h" +#include <sys/stat.h>  int16_t  makeHostID() @@ -44,30 +46,40 @@ extern "C" {  	}  } -TempPrivs::TempPrivs(uid_t u, gid_t g) : -        myu(u), oldu(geteuid()), -        myg(g), oldg(getegid()) +TempPrivs::TempPrivs(const NetFS::ReqEnv & re, const UserEntCache * uec, const GroupEntCache * gec, const boost::filesystem::path & r) : +	myu(uec->getID(re.user)), +	myg(gec->getID(re.grp)), +	root(r)  { -	if (setegid(myg)) -		throw NetFS::SystemError(errno); -	if (seteuid(myu)) -		throw NetFS::SystemError(errno);  } -TempPrivs::TempPrivs(const NetFS::ReqEnv & re, const UserEntCache * uec, const GroupEntCache * gec) : -        myu(uec->getID(re.user)), oldu(geteuid()), -        myg(gec->getID(re.grp)), oldg(getegid()) +void +TempPrivs::AssertRead(const boost::filesystem::path & p) const  { -	if (setegid(myg)) -		throw NetFS::SystemError(errno); -	if (seteuid(myu)) +	if (p != root) { +		AssertRead(p.parent_path()); +	} +	struct stat s; +	if (::lstat(p.string().c_str(), &s) != 0) {  		throw NetFS::SystemError(errno); +	} +	if (!ReadableBy(s, myu, myg)) { +		throw NetFS::SystemError(EACCES); +	}  } -TempPrivs::~TempPrivs() +void +TempPrivs::AssertWrite(const boost::filesystem::path & p) const  { -	if (seteuid(oldu)) -		throw NetFS::SystemError(errno); -	if (setegid(oldg)) +	if (p != root) { +		AssertRead(p.parent_path()); +	} +	struct stat s; +	if (::lstat(p.string().c_str(), &s) != 0) {  		throw NetFS::SystemError(errno); +	} +	if (!WritableBy(s, myu, myg)) { +		throw NetFS::SystemError(EACCES); +	}  } + diff --git a/netfs/daemon/daemon.h b/netfs/daemon/daemon.h index c6f91cf..a28ddac 100644 --- a/netfs/daemon/daemon.h +++ b/netfs/daemon/daemon.h @@ -9,9 +9,7 @@  #include <boost/nondet_random.hpp>  #include "daemonConfig.h"  #include <types.h> -#include <volume.h>  #include <entCache.h> -#include <dirent.h>  class NetFSDaemon : public IceBox::Service {  	public: @@ -25,13 +23,14 @@ class NetFSDaemon : public IceBox::Service {  class TempPrivs {  	public: -		TempPrivs(uid_t u, gid_t g); -		TempPrivs(const NetFS::ReqEnv & re, const UserEntCache * uec, const GroupEntCache * gec); -		virtual ~TempPrivs(); +		TempPrivs(const NetFS::ReqEnv & re, const UserEntCache * uec, const GroupEntCache * gec, const boost::filesystem::path &); -	private: -		const uid_t myu, oldu; -		const gid_t myg, oldg; +		void AssertRead(const boost::filesystem::path &) const; +		void AssertWrite(const boost::filesystem::path &) const; + +		const uid_t myu; +		const gid_t myg; +		const boost::filesystem::path & root;  };  #endif diff --git a/netfs/daemon/daemonDirectory.h b/netfs/daemon/daemonDirectory.h index c1ef3c6..2909dae 100644 --- a/netfs/daemon/daemonDirectory.h +++ b/netfs/daemon/daemonDirectory.h @@ -2,7 +2,7 @@  #define DAEMONDIRECTORY_H  #include <directory.h> -#include "entCache.h" +#include <dirent.h>  class DirectoryServer : public NetFS::Directory {  	public: diff --git a/netfs/daemon/daemonFile.cpp b/netfs/daemon/daemonFile.cpp index 5c74fda..dd8b706 100644 --- a/netfs/daemon/daemonFile.cpp +++ b/netfs/daemon/daemonFile.cpp @@ -20,7 +20,7 @@ FileServer::~FileServer()  void  FileServer::ftruncate(const NetFS::ReqEnv & re, Ice::Long size, const Ice::Current&)  { -	TempPrivs tp(re, uentries, gentries); +	(void)re;  	errno = 0;  	if (::ftruncate(fd, size) != 0) {  		throw NetFS::SystemError(errno); @@ -30,7 +30,7 @@ FileServer::ftruncate(const NetFS::ReqEnv & re, Ice::Long size, const Ice::Curre  NetFS::Attr  FileServer::fgetattr(const NetFS::ReqEnv & re, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	(void)re;  	struct stat s;  	if (::fstat(fd, &s) != 0) {  		throw NetFS::SystemError(errno); diff --git a/netfs/daemon/daemonService.h b/netfs/daemon/daemonService.h index 7bdce16..d41af54 100644 --- a/netfs/daemon/daemonService.h +++ b/netfs/daemon/daemonService.h @@ -2,6 +2,7 @@  #define DAEMONSERVICE_H  #include <service.h> +#include <entCache.h>  class ServiceServer : public NetFS::Service {  	public: diff --git a/netfs/daemon/daemonVolume.cpp b/netfs/daemon/daemonVolume.cpp index ef64529..0779043 100644 --- a/netfs/daemon/daemonVolume.cpp +++ b/netfs/daemon/daemonVolume.cpp @@ -10,6 +10,8 @@  #include "daemonFile.h"  #include "daemonDirectory.h"  #include "lockHelpers.h" +#include "ioHelpers.h" +#include <boost/filesystem/operations.hpp>  extern std::map<Ice::Int, int> files; @@ -33,17 +35,36 @@ VolumeServer::disconnect(const Ice::Current & ice)  Ice::Int  VolumeServer::access(const NetFS::ReqEnv & re, const std::string & path, Ice::Int mode, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root); +	struct stat s;  	boost::filesystem::path p(resolvePath(path)); -	return ::access(p.string().c_str(), mode); +	if (::stat(p.string().c_str(), &s) != 0) { +		return errno; +	} +	if (mode == F_OK) { +		// stat succeeded, file must exist +		return 0; +	} +	tp.AssertRead(p.parent_path()); +	if (mode & R_OK && !ReadableBy(s, tp.myu, tp.myg)) { +		return EACCES; +	} +	if (mode & W_OK && !WritableBy(s, tp.myu, tp.myg)) { +		return EACCES; +	} +	if (mode & X_OK && !ExecutableBy(s, tp.myu, tp.myg)) { +		return EACCES; +	} +	return 0;  }  NetFS::Attr  VolumeServer::getattr(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	struct stat s;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertRead(p.parent_path());  	if (::lstat(p.string().c_str(), &s) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -55,33 +76,50 @@ VolumeServer::getattr(const NetFS::ReqEnv & re, const std::string & path, const  void  VolumeServer::symlink(const NetFS::ReqEnv & re, const std::string & path1, const std::string & path2, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path2)); +	tp.AssertWrite(p.parent_path());  	if (::symlink(path1.c_str(), p.string().c_str()) != 0) {  		throw NetFS::SystemError(errno);  	} +	if (::lchown(p.string().c_str(), tp.myu, tp.myg) != 0) { +		::unlink(p.string().c_str()); +		throw NetFS::SystemError(errno); +	}  }  void  VolumeServer::link(const NetFS::ReqEnv & re, const std::string & path1, const std::string & path2, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p1(resolvePath(path1));  	boost::filesystem::path p2(resolvePath(path2));  	if (::link(p1.string().c_str(), p2.string().c_str()) != 0) {  		throw NetFS::SystemError(errno);  	} +	if (::chown(p2.string().c_str(), tp.myu, tp.myg) != 0) { +		::unlink(p2.string().c_str()); +		throw NetFS::SystemError(errno); +	}  }  void  VolumeServer::rename(const NetFS::ReqEnv & re, const std::string & from, const std::string & to, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path f(resolvePath(from));  	boost::filesystem::path t(resolvePath(to)); +	tp.AssertWrite(f.parent_path()); +	tp.AssertWrite(f); +	if (boost::filesystem::is_directory(t)) { +		tp.AssertWrite(t); +	} +	else { +		tp.AssertWrite(t.parent_path()); +	}  	if (::rename(f.string().c_str(), t.string().c_str()) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -90,10 +128,11 @@ VolumeServer::rename(const NetFS::ReqEnv & re, const std::string & from, const s  std::string  VolumeServer::readlink(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	char buf[PATH_MAX];  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertRead(p);  	ssize_t rc = ::readlink(p.string().c_str(), buf, PATH_MAX);  	if (rc == -1) {  		throw NetFS::SystemError(errno); @@ -104,9 +143,10 @@ VolumeServer::readlink(const NetFS::ReqEnv & re, const std::string & path, const  void  VolumeServer::chmod(const NetFS::ReqEnv & re, const std::string & path, Ice::Int mode, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p);  	if (::chmod(p.string().c_str(), mode) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -115,9 +155,10 @@ VolumeServer::chmod(const NetFS::ReqEnv & re, const std::string & path, Ice::Int  void  VolumeServer::chown(const NetFS::ReqEnv & re, const std::string & path, Ice::Int uid, Ice::Int gid, const Ice::Current &)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p);  	if (::lchown(p.string().c_str(), uid, gid) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -127,7 +168,7 @@ void  VolumeServer::utimens(const NetFS::ReqEnv & re, const std::string & path,  		Ice::Long s0, Ice::Long ns0, Ice::Long s1, Ice::Long ns1, const Ice::Current&)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	struct timespec times[2];  	times[0].tv_sec = s0; @@ -135,6 +176,7 @@ VolumeServer::utimens(const NetFS::ReqEnv & re, const std::string & path,  	times[1].tv_sec = s1;  	times[1].tv_nsec = ns1;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p);  	if (::utimensat(0, p.string().c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -143,10 +185,11 @@ VolumeServer::utimens(const NetFS::ReqEnv & re, const std::string & path,  NetFS::VFS  VolumeServer::statfs(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current&)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	struct statvfs s;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertRead(p);  	if (::statvfs(p.string().c_str(), &s) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -158,9 +201,10 @@ VolumeServer::statfs(const NetFS::ReqEnv & re, const std::string & path, const I  void  VolumeServer::truncate(const NetFS::ReqEnv & re, const std::string & path, Ice::Long size, const Ice::Current&)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p);  	if (::truncate(p.string().c_str(), size) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -169,9 +213,11 @@ VolumeServer::truncate(const NetFS::ReqEnv & re, const std::string & path, Ice::  void  VolumeServer::unlink(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current&)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p); +	tp.AssertWrite(p.parent_path());  	if (::unlink(p.string().c_str()) != 0) {  		throw NetFS::SystemError(errno);  	} @@ -186,9 +232,10 @@ VolumeServer::openReadOnly(const NetFS::ReqEnv & re, const std::string & path, I  NetFS::FilePrx  VolumeServer::open(const NetFS::ReqEnv & re, const std::string & path, Ice::Int flags, const Ice::Current & ice)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertRead(p);  	int fd = ::open(p.string().c_str(), flags);  	if (fd == -1) {  		throw NetFS::SystemError(errno); @@ -199,22 +246,29 @@ VolumeServer::open(const NetFS::ReqEnv & re, const std::string & path, Ice::Int  NetFS::FilePrx  VolumeServer::create(const NetFS::ReqEnv & re, const std::string & path, Ice::Int flags, Ice::Int mode, const Ice::Current & ice)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p.parent_path());  	int fd = ::open(p.string().c_str(), O_CREAT | flags, mode);  	if (fd == -1) {  		throw NetFS::SystemError(errno);  	} +	if (fchown(fd, tp.myu, tp.myg) != 0) { +		::close(fd); +		::unlink(p.string().c_str()); +		throw NetFS::SystemError(errno); +	}  	return NetFS::FilePrx::checkedCast(ice.adapter->addWithUUID(new FileServer(fd, uentries, gentries)));  }  NetFS::DirectoryPrx  VolumeServer::opendir(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current & ice)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertRead(p);  	DIR * od = ::opendir(p.string().c_str());  	if (!od) {  		throw NetFS::SystemError(errno); @@ -225,20 +279,27 @@ VolumeServer::opendir(const NetFS::ReqEnv & re, const std::string & path, const  void  VolumeServer::mkdir(const NetFS::ReqEnv & re, const std::string & path, Ice::Int mode, const Ice::Current&)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p.parent_path());  	if (::mkdir(p.string().c_str(), mode) != 0) {  		throw NetFS::SystemError(errno);  	} +	if (::chown(p.string().c_str(), tp.myu, tp.myg) != 0) { +		::rmdir(p.string().c_str()); +		throw NetFS::SystemError(errno); +	}  }  void  VolumeServer::rmdir(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current&)  { -	TempPrivs tp(re, uentries, gentries); +	TempPrivs tp(re, uentries, gentries, root);  	errno = 0;  	boost::filesystem::path p(resolvePath(path)); +	tp.AssertWrite(p); +	tp.AssertWrite(p.parent_path());  	if (::rmdir(p.string().c_str()) != 0) {  		throw NetFS::SystemError(errno);  	} diff --git a/netfs/daemon/ioHelpers.cpp b/netfs/daemon/ioHelpers.cpp new file mode 100644 index 0000000..0bf873c --- /dev/null +++ b/netfs/daemon/ioHelpers.cpp @@ -0,0 +1,30 @@ +#include "ioHelpers.h" + +bool ReadableBy(const struct stat & s, uid_t u, gid_t g) +{ +	if (u == 0) return true; +	if (s.st_mode & S_IROTH) return true; +	if (s.st_mode & S_IRGRP && s.st_gid == g) return true; +	if (s.st_mode & S_IRUSR && s.st_uid == u) return true; +	return false; +} + +bool WritableBy(const struct stat & s, uid_t u, gid_t g) +{ +	if (u == 0) return true; +	if (s.st_mode & S_IWOTH) return true; +	if (s.st_mode & S_IWGRP && s.st_gid == g) return true; +	if (s.st_mode & S_IWUSR && s.st_uid == u) return true; +	return false; +} + +bool ExecutableBy(const struct stat & s, uid_t u, gid_t g) +{ +	if (u == 0 && (s.st_mode & (S_IWOTH | S_IWGRP | S_IWUSR))) return true; +	if (s.st_mode & S_IWOTH) return true; +	if (s.st_mode & S_IWGRP && s.st_gid == g) return true; +	if (s.st_mode & S_IWUSR && s.st_uid == u) return true; +	return false; +} + + diff --git a/netfs/daemon/ioHelpers.h b/netfs/daemon/ioHelpers.h new file mode 100644 index 0000000..ed2d60b --- /dev/null +++ b/netfs/daemon/ioHelpers.h @@ -0,0 +1,11 @@ +#ifndef NETFS_DAEMON_IOHELPERS +#define NETFS_DAEMON_IOHELPERS + +#include <sys/stat.h> + +bool ReadableBy(const struct stat &, uid_t u, gid_t g); +bool WritableBy(const struct stat &, uid_t u, gid_t g); +bool ExecutableBy(const struct stat &, uid_t u, gid_t g); + +#endif + | 
