summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--netfs/daemon/daemon.cpp46
-rw-r--r--netfs/daemon/daemon.h15
-rw-r--r--netfs/daemon/daemonDirectory.h2
-rw-r--r--netfs/daemon/daemonFile.cpp4
-rw-r--r--netfs/daemon/daemonService.h1
-rw-r--r--netfs/daemon/daemonVolume.cpp97
-rw-r--r--netfs/daemon/ioHelpers.cpp30
-rw-r--r--netfs/daemon/ioHelpers.h11
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
+