Beispiel #1
0
// helper function -- apply a functor to a cipher path, given the plain path
static int withCipherPath(const char *opName, const char *path,
                          function<int(EncFS_Context *, const string &)> op,
                          bool passReturnCode = false) {
  EncFS_Context *ctx = context();

  int res = -EIO;
  std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if (!FSRoot) return res;

  try {
    string cyName = FSRoot->cipherPath(path);
    VLOG(1) << "op: " << opName << " : " << cyName;

    res = op(ctx, cyName);

    if (res == -1) {
      int eno = errno;
      VLOG(1) << "op: " << opName << " error: " << strerror(eno);
      res = -eno;
    } else if (!passReturnCode) {
      res = ESUCCESS;
    }
  } catch (encfs::Error &err) {
    RLOG(ERROR) << "withCipherPath: error caught in " << opName << ": "
                << err.what();
  }
  return res;
}
Beispiel #2
0
static int withFileNode( const char *opName,
	const char *path, struct fuse_file_info *fi, 
	int (*op)(FileNode *, T data ), T data )
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {
	shared_ptr<FileNode> fnode;

	if(fi != NULL)
	    fnode = GET_FN(ctx, fi);
	else
	    fnode = FSRoot->lookupNode( path, opName );

	rAssert(fnode != NULL);
	rLog(Info, "%s %s", opName, fnode->cipherName());
	res = op( fnode.get(), data );

	if(res < 0)
	    rInfo("%s error: %s", opName, strerror(-res));
    } catch( rlog::Error &err )
    {
	rError("error caught in %s", opName);
	err.log( _RLWarningChannel );
    }
    return res;
}
Beispiel #3
0
int _do_getattr(FileNode *fnode, struct stat *stbuf) {
  int res = fnode->getAttr(stbuf);
  if (res == ESUCCESS && S_ISLNK(stbuf->st_mode)) {
    EncFS_Context *ctx = context();
    std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if (FSRoot) {
      // determine plaintext link size..  Easiest to read and decrypt..
      std::vector<char> buf(stbuf->st_size + 1, '\0');

      res = ::readlink(fnode->cipherName(), buf.data(), stbuf->st_size);
      if (res >= 0) {
        // other functions expect c-strings to be null-terminated, which
        // readlink doesn't provide
        buf[res] = '\0';

        stbuf->st_size = FSRoot->plainPath(buf.data()).length();

        res = ESUCCESS;
      } else {
        res = -errno;
      }
    }
  }

  return res;
}
Beispiel #4
0
static int withCipherPath( const char *opName, const char *path,
    int (*op)(EncFS_Context *, const string &name, T data ), T data,
    bool passReturnCode = false )
{
  EncFS_Context *ctx = context();

  int res = -EIO;
  shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if(!FSRoot)
    return res;

  try
  {
    string cyName = FSRoot->cipherPath( path );
    VLOG(1) << opName << " " << cyName.c_str();

    res = op( ctx, cyName, data );

    if(res == -1)
    {
      res = -errno;
      LOG(INFO) << opName << " error: " << strerror(-res);
    } else if(!passReturnCode)
      res = ESUCCESS;
  } catch( Error &err )
  {
    LOG(ERROR) << "error caught in " << opName << 
      ":" << err.what();
  }
  return res;
}
Beispiel #5
0
static int withCipherPath( const char *opName, const char *path,
	int (*op)(EncFS_Context *, const string &name, T data ), T data,
        bool passReturnCode = false )
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {
	string cyName = FSRoot->cipherPath( path );
	rLog(Info, "%s %s", opName, cyName.c_str());

	res = op( ctx, cyName, data );
	
	if(res == -1)
	{
	    int eno = errno;
	    rInfo("%s error: %s", opName, strerror(eno));
	    res = -eno;
	} else if(!passReturnCode)
	    res = ESUCCESS;
    } catch( rlog::Error &err )
    {
	rError("error caught in %s", opName);
	err.log( _RLWarningChannel );
    }
    return res;
}
Beispiel #6
0
int encfs_mkdir(const char *path, mode_t mode) {
  fuse_context *fctx = fuse_get_context();
  EncFS_Context *ctx = context();

  if (isReadOnly(ctx)) return -EROFS;

  int res = -EIO;
  std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if (!FSRoot) return res;

  try {
    uid_t uid = 0;
    gid_t gid = 0;
    if (ctx->publicFilesystem) {
      uid = fctx->uid;
      gid = fctx->gid;
    }
    res = FSRoot->mkdir(path, mode, uid, gid);
    // Is this error due to access problems?
    if (ctx->publicFilesystem && -res == EACCES) {
      // try again using the parent dir's group
      string parent = parentDirectory(path);
      std::shared_ptr<FileNode> dnode =
          FSRoot->lookupNode(parent.c_str(), "mkdir");

      struct stat st;
      if (dnode->getAttr(&st) == 0)
        res = FSRoot->mkdir(path, mode, uid, st.st_gid);
    }
  } catch (encfs::Error &err) {
    RLOG(ERROR) << "error caught in mkdir: " << err.what();
  }
  return res;
}
Beispiel #7
0
static int withFileNode( const char *opName,
    const char *path, struct fuse_file_info *fi, 
    int (*op)(FileNode *, T data ), T data )
{
  EncFS_Context *ctx = context();

  int res = -EIO;
  shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if(!FSRoot)
    return res;

  try
  {
    shared_ptr<FileNode> fnode;

    if(fi != NULL)
      fnode = GET_FN(ctx, fi);
    else
      fnode = FSRoot->lookupNode( path, opName );

    rAssert(fnode != NULL);
    VLOG(1) << opName << " " << fnode->cipherName();
    res = op( fnode.get(), data );

    LOG_IF(INFO, res < 0) << opName << " error: " << strerror(-res);
  } catch( Error &err )
  {
    LOG(ERROR) << "error caught in " << opName << 
      ":" << err.what();
  }
  return res;
}
Beispiel #8
0
int encfs_open(const char *path, struct fuse_file_info *file)
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {
	shared_ptr<FileNode> fnode = 
	    FSRoot->openNode( path, "open", file->flags, &res );

	if(fnode)
	{
	    rLog(Info, "encfs_open for %s, flags %i", fnode->cipherName(), 
		    file->flags);

	    if( res >= 0 )
	    {
		file->fh = (uintptr_t)ctx->putNode(path, fnode);
		res = ESUCCESS;
	    }
	}
    } catch( rlog::Error &err )
    {
	rError("error caught in open");
	err.log( _RLWarningChannel );
    }

    return res;
}
Beispiel #9
0
int encfs_open(const char *path, struct fuse_file_info *file) {
  EncFS_Context *ctx = context();

  if (isReadOnly(ctx) && (file->flags & O_WRONLY || file->flags & O_RDWR))
    return -EROFS;

  int res = -EIO;
  std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if (!FSRoot) return res;

  try {
    std::shared_ptr<FileNode> fnode =
        FSRoot->openNode(path, "open", file->flags, &res);

    if (fnode) {
      VLOG(1) << "encfs_open for " << fnode->cipherName() << ", flags "
              << file->flags;

      if (res >= 0) {
        file->fh =
            reinterpret_cast<uintptr_t>(ctx->putNode(path, std::move(fnode)));
        res = ESUCCESS;
      }
    }
  } catch (encfs::Error &err) {
    RLOG(ERROR) << "error caught in open: " << err.what();
  }

  return res;
}
Beispiel #10
0
int encfs_open(const char *path, struct fuse_file_info *file)
{
  EncFS_Context *ctx = context();

  int res = -EIO;
  shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if(!FSRoot)
    return res;

  try
  {
    shared_ptr<FileNode> fnode = 
      FSRoot->openNode( path, "open", file->flags, &res );

    if(fnode)
    {
      VLOG(1) << "encfs_open for " << fnode->cipherName()
              << ", flags " << file->flags;

      if( res >= 0 )
      {
        file->fh = (uintptr_t)ctx->putNode(path, fnode);
        res = ESUCCESS;
      }
    }
  } catch( Error &err )
  {
    LOG(ERROR) << "error caught in open: " << err.what();
  }

  return res;
}
Beispiel #11
0
static uint32_t encfs_win_get_attributes(const char *fn)
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

   std::wstring path = utf8_to_wfn(FSRoot->cipherPath(fn));
   // TODO error
   return GetFileAttributesW(path.c_str());
}
Beispiel #12
0
static int encfs_win_set_attributes(const char *fn, uint32_t attr)
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

   std::wstring path = utf8_to_wfn(FSRoot->cipherPath(fn));
   if (SetFileAttributesW(path.c_str(), attr))
        return 0;
   return -win32_error_to_errno(GetLastError());
}
Beispiel #13
0
int encfs_rename(const char *from, const char *to) {
  EncFS_Context *ctx = context();

  if (isReadOnly(ctx)) return -EROFS;

  int res = -EIO;
  std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if (!FSRoot) return res;

  try {
    res = FSRoot->rename(from, to);
  } catch (encfs::Error &err) {
    RLOG(ERROR) << "error caught in rename: " << err.what();
  }
  return res;
}
Beispiel #14
0
int encfs_symlink(const char *from, const char *to)
{
    EncFS_Context *ctx = context();

	return -EIO;
#if 0
    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {
	// allow fully qualified names in symbolic links.
	string fromCName = FSRoot->relativeCipherPath( from );
	string toCName = FSRoot->cipherPath( to );
	
	rLog(Info, "symlink %s -> %s", fromCName.c_str(), toCName.c_str());

	// use setfsuid / setfsgid so that the new link will be owned by the
	// uid/gid provided by the fuse_context.
	int olduid = -1;
	int oldgid = -1;
	if(ctx->publicFilesystem)
	{
	    fuse_context *context = fuse_get_context();
	    olduid = setfsuid( context->uid );
	    oldgid = setfsgid( context->gid );
	}
	res = ::symlink( fromCName.c_str(), toCName.c_str() );
	if(olduid >= 0)
	    setfsuid( olduid );
	if(oldgid >= 0)
	    setfsgid( oldgid );

	if(res == -1)
	    res = -errno;
	else
	    res = ESUCCESS;
    } catch( rlog::Error &err )
    {
	rError("error caught in symlink");
	err.log( _RLWarningChannel );
    }
    return res;
#endif
}
Beispiel #15
0
int encfs_mknod(const char *path, mode_t mode, dev_t rdev)
{
  EncFS_Context *ctx = context();

  int res = -EIO;
  shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if(!FSRoot)
    return res;

  try
  {
    shared_ptr<FileNode> fnode = FSRoot->lookupNode( path, "mknod" );

    VLOG(1) << "mknod on " << fnode->cipherName()
            << ", mode " << mode << ", dev " << rdev;

    uid_t uid = 0;
    gid_t gid = 0;
    if(ctx->publicFilesystem)
    {
      fuse_context *context = fuse_get_context();
      uid = context->uid;
      gid = context->gid;
    }
    res = fnode->mknod( mode, rdev, uid, gid );
    // Is this error due to access problems?
    if(ctx->publicFilesystem && -res == EACCES)
    {
      // try again using the parent dir's group
      string parent = fnode->plaintextParent();
      LOG(INFO) << "attempting public filesystem workaround for " 
                << parent.c_str();
      shared_ptr<FileNode> dnode = 
        FSRoot->lookupNode( parent.c_str(), "mknod" );

      struct stat st;
      if(dnode->getAttr( &st ) == 0)
        res = fnode->mknod( mode, rdev, uid, st.st_gid );
    }
  } catch( Error &err )
  {
    LOG(ERROR) << "error caught in mknod: " << err.what();
  }
  return res;
}
Beispiel #16
0
int encfs_mknod(const char *path, mode_t mode, dev_t rdev)
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {
	shared_ptr<FileNode> fnode = FSRoot->lookupNode( path, "mknod" );

	rLog(Info, "mknod on %s, mode %i, dev %" PRIi64,
		fnode->cipherName(), mode, (int64_t)rdev);

	uid_t uid = 0;
	gid_t gid = 0;
	if(ctx->publicFilesystem)
	{
	    fuse_context *context = fuse_get_context();
	    uid = context->uid;
	    gid = context->gid;
	}
	res = fnode->mknod( mode, rdev, uid, gid );
	// Is this error due to access problems?
	if(ctx->publicFilesystem && -res == EACCES)
	{
	    // try again using the parent dir's group
	    string parent = fnode->plaintextParent();
	    rInfo("trying public filesystem workaround for %s", parent.c_str());
	    shared_ptr<FileNode> dnode = 
		FSRoot->lookupNode( parent.c_str(), "mknod" );

	    struct stat st;
	    if(dnode->getAttr( &st ) == 0)
		res = fnode->mknod( mode, rdev, uid, st.st_gid );
	}
    } catch( rlog::Error &err )
    {
	rError("error caught in mknod");
	err.log( _RLWarningChannel );
    }
    return res;
}
Beispiel #17
0
int encfs_unlink(const char *path) {
  EncFS_Context *ctx = context();

  if (isReadOnly(ctx)) return -EROFS;

  int res = -EIO;
  std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if (!FSRoot) return res;

  try {
    // let DirNode handle it atomically so that it can handle race
    // conditions
    res = FSRoot->unlink(path);
  } catch (encfs::Error &err) {
    RLOG(ERROR) << "error caught in unlink: " << err.what();
  }
  return res;
}
Beispiel #18
0
int encfs_link(const char *from, const char *to)
{
  EncFS_Context *ctx = context();

  int res = -EIO;
  shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if(!FSRoot)
    return res;

  try
  {
    res = FSRoot->link( from, to );
  } catch( Error &err )
  {
    LOG(ERROR) << "error caught in link: " << err.what();
  }
  return res;
}
Beispiel #19
0
int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
    EncFS_Context *ctx = context();

    int res = ESUCCESS;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {

	DirTraverse dt = FSRoot->openDir( path );

	rLog(Info, "getdir on %s", FSRoot->cipherPath(path).c_str());

	if(dt.valid())
	{
	    int fileType = 0;
	    ino_t inode = 0;

	    std::string name = dt.nextPlaintextName( &fileType, &inode );
	    while( !name.empty() )
	    {
		res = filler( h, name.c_str(), fileType, inode );

		if(res != ESUCCESS)
		    break;

		name = dt.nextPlaintextName( &fileType, &inode );
	    } 
	} else
	{
	    rInfo("getdir request invalid, path: '%s'", path);
	}

	return res;
    } catch( rlog::Error &err )
    {
	rError("Error caught in getdir");
	err.log( _RLWarningChannel );
	return -EIO;
    }
}
Beispiel #20
0
int encfs_symlink(const char *from, const char *to)
{
  EncFS_Context *ctx = context();

  int res = -EIO;
  shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if(!FSRoot)
    return res;

  try
  {
    // allow fully qualified names in symbolic links.
    string fromCName = FSRoot->relativeCipherPath( from );
    string toCName = FSRoot->cipherPath( to );

    VLOG(1) << "symlink " << fromCName << " -> " << toCName;

    // use setfsuid / setfsgid so that the new link will be owned by the
    // uid/gid provided by the fuse_context.
    int olduid = -1;
    int oldgid = -1;
    if(ctx->publicFilesystem)
    {
      fuse_context *context = fuse_get_context();
      olduid = setfsuid( context->uid );
      oldgid = setfsgid( context->gid );
    }
    res = ::symlink( fromCName.c_str(), toCName.c_str() );
    if(olduid >= 0)
      setfsuid( olduid );
    if(oldgid >= 0)
      setfsgid( oldgid );

    if(res == -1)
      res = -errno;
    else
      res = ESUCCESS;
  } catch( Error &err )
  {
    LOG(ERROR) << "error caught in symlink: " << err.what();
  }
  return res;
}
Beispiel #21
0
int encfs_rename(const char *from, const char *to)
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {
	res = FSRoot->rename( from, to );
    } catch( rlog::Error &err )
    {
	rError("error caught in rename");
	err.log( _RLWarningChannel );
    }
    return res;
}
Beispiel #22
0
int encfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
  EncFS_Context *ctx = context();

  int res = ESUCCESS;
  shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if(!FSRoot)
    return res;

  try
  {

    DirTraverse dt = FSRoot->openDir( path );

    VLOG(1) << "getdir on " << FSRoot->cipherPath(path);

    if(dt.valid())
    {
      int fileType = 0;
      ino_t inode = 0;

      std::string name = dt.nextPlaintextName( &fileType, &inode );
      while( !name.empty() )
      {
        res = filler( h, name.c_str(), fileType, inode );

        if(res != ESUCCESS)
          break;

        name = dt.nextPlaintextName( &fileType, &inode );
      } 
    } else
    {
      LOG(INFO) << "getdir request invalid, path: '" << path << "'";
    }

    return res;
  } catch( Error &err )
  {
    LOG(ERROR) << "error caught in getdir: " << err.what();
    return -EIO;
  }
}
Beispiel #23
0
int encfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                  off_t offset, struct fuse_file_info *finfo) {
  EncFS_Context *ctx = context();

  int res = ESUCCESS;
  std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if (!FSRoot) return res;

  try {

    DirTraverse dt = FSRoot->openDir(path);

    VLOG(1) << "readdir on " << FSRoot->cipherPath(path);

    if (dt.valid()) {
      int fileType = 0;
      ino_t inode = 0;

      std::string name = dt.nextPlaintextName(&fileType, &inode);
      while (!name.empty()) {
        struct stat st;
        st.st_ino = inode;
        st.st_mode = fileType << 12;

        // TODO: add offset support.
#if defined(fuse_fill_dir_flags)
        if (filler(buf, name.c_str(), &st, 0, 0)) break;
#else
        if (filler(buf, name.c_str(), &st, 0)) break;
#endif

        name = dt.nextPlaintextName(&fileType, &inode);
      }
    } else {
      VLOG(1) << "readdir request invalid, path: '" << path << "'";
    }

    return res;
  } catch (encfs::Error &err) {
    RLOG(ERROR) << "Error caught in readdir";
    return -EIO;
  }
}
Beispiel #24
0
int encfs_unlink(const char *path)
{
    EncFS_Context *ctx = context();

    int res = -EIO;
    shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
    if(!FSRoot)
	return res;

    try
    {
	// let DirNode handle it atomically so that it can handle race
	// conditions
	res = FSRoot->unlink( path );
    } catch( rlog::Error &err )
    {
	rError("error caught in unlink");
	err.log( _RLWarningChannel );
    }
    return res;
}
Beispiel #25
0
// helper function -- apply a functor to a node
static int withFileNode(const char *opName, const char *path,
                        struct fuse_file_info *fi,
                        function<int(FileNode *)> op) {
  EncFS_Context *ctx = context();

  int res = -EIO;
  std::shared_ptr<DirNode> FSRoot = ctx->getRoot(&res);
  if (!FSRoot) return res;

  try {

    auto do_op = [&FSRoot, opName, &op](FileNode *fnode) {
      rAssert(fnode != nullptr);
      VLOG(1) << "op: " << opName << " : " << fnode->cipherName();

      // check that we're not recursing into the mount point itself
      if (FSRoot->touchesMountpoint(fnode->cipherName())) {
        VLOG(1) << "op: " << opName << " error: Tried to touch mountpoint: '"
                << fnode->cipherName() << "'";
        return -EIO;
      }
      return op(fnode);
    };

    if (fi != nullptr)
      res = do_op(reinterpret_cast<FileNode *>(fi->fh));
    else
      res = do_op(FSRoot->lookupNode(path, opName).get());

    if (res < 0) {
      RLOG(DEBUG) << "op: " << opName << " error: " << strerror(-res);
    }
  } catch (encfs::Error &err) {
    RLOG(ERROR) << "withFileNode: error caught in " << opName << ": "
                << err.what();
  }
  return res;
}