Пример #1
0
int
rpl_fchownat (int fd, char const *file, uid_t owner, gid_t group, int flag)
{
# if FCHOWNAT_NOFOLLOW_BUG
  if (flag == AT_SYMLINK_NOFOLLOW)
    return local_lchownat (fd, file, owner, group);
# endif
# if FCHOWNAT_EMPTY_FILENAME_BUG
  if (file[0] == '\0')
    {
      errno = ENOENT;
      return -1;
    }
# endif
# if CHOWN_TRAILING_SLASH_BUG
  {
    size_t len = strlen (file);
    struct stat st;
    if (len && file[len - 1] == '/')
      {
        if (statat (fd, file, &st))
          return -1;
        if (flag == AT_SYMLINK_NOFOLLOW)
          return fchownat (fd, file, owner, group, 0);
      }
  }
# endif
  return fchownat (fd, file, owner, group, flag);
}
Пример #2
0
static int chown_cgroup_path(const char *path, uid_t uid_shift) {
        _cleanup_close_ int fd = -1;
        const char *fn;

        fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
        if (fd < 0)
                return -errno;

        FOREACH_STRING(fn,
                       ".",
                       "cgroup.clone_children",
                       "cgroup.controllers",
                       "cgroup.events",
                       "cgroup.procs",
                       "cgroup.stat",
                       "cgroup.subtree_control",
                       "cgroup.threads",
                       "notify_on_release",
                       "tasks")
                if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0)
                        log_full_errno(errno == ENOENT ? LOG_DEBUG :  LOG_WARNING, errno,
                                       "Failed to chown \"%s/%s\", ignoring: %m", path, fn);

        return 0;
}
Пример #3
0
/**
 * Copy over owner and mode to the tmpFile (link)
 * NOTE: for symlinks, as we don't have the tmp-file-descriptor for those
 */
bool MigrateFile::copyOwnerAndModeLink(struct stat* fromStatData)
{
   /* NOTE: Set the owner first and only then the mode, as otherwise there will be a brief
            security issue (e.g. s-bit is set... */
   int chownRes = fchownat(this->dirFD, this->tmpName.c_str(), fromStatData->st_uid,
      fromStatData->st_gid, AT_SYMLINK_NOFOLLOW);
   if (chownRes)
   {
      std::cerr << "Setting the owner failed (" << this->filePath << "): "
         << System::getErrString() << std::endl;
      return false;
   }

#if 0
   int chmodRes = fchmodat(this->dirFD, this->tmpName.c_str(), 0644,
      AT_SYMLINK_NOFOLLOW);
   if (chmodRes)
   {
      std::cerr << "Setting the file mode failed (" << this->filePath << "): "
         << System::getErrString() << std::endl;
      return false;
   }
#endif // fchmodat(...,..., mode, AT_SYMLINK_NOFOLLOW) not (yet) supported in linux

   return true;
}
Пример #4
0
void test_create_file_at()
{
  char *file = alloc_filename("file");
  char *hardlink = alloc_filename("hardlink");
  char *hardlink2 = alloc_filename("hardlink2");
  int dir_fd = get_dir_fd(".");
  struct stat st;
  int fd = openat(dir_fd, file, O_CREAT | O_WRONLY | O_EXCL, 0777);
  t_check(fd >= 0);
  t_check_zero(fstat(fd, &st));
  t_check_zero(close(fd));

  t_check_zero(fstatat(dir_fd, file, &st, 0));
  t_check_zero(faccessat(dir_fd, file, R_OK | W_OK, 0));
  t_check_zero(fchmodat(dir_fd, file, 0777, 0));
  t_check_zero(fchownat(dir_fd, file, -1, -1, 0));
  struct timeval times[2] = { { 123, 321 }, { 456, 654 } };
  t_check_zero(futimesat(dir_fd, file, times));

  t_check_zero(linkat(dir_fd, file, dir_fd, hardlink, 0));
  t_check_zero(renameat(dir_fd, hardlink, dir_fd, hardlink2));
  t_check_zero(unlinkat(dir_fd, hardlink2, 0));
  t_check_zero(unlinkat(dir_fd, file, 0));
  close(dir_fd);
  free(file);
  free(hardlink);
  free(hardlink2);
}
Пример #5
0
int chown_cgroup(pid_t pid, uid_t uid_shift) {
        _cleanup_free_ char *path = NULL, *fs = NULL;
        _cleanup_close_ int fd = -1;
        const char *fn;
        int r;

        r = cg_pid_get_path(NULL, pid, &path);
        if (r < 0)
                return log_error_errno(r, "Failed to get container cgroup path: %m");

        r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, NULL, &fs);
        if (r < 0)
                return log_error_errno(r, "Failed to get file system path for container cgroup: %m");

        fd = open(fs, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
        if (fd < 0)
                return log_error_errno(errno, "Failed to open %s: %m", fs);

        FOREACH_STRING(fn,
                       ".",
                       "tasks",
                       "notify_on_release",
                       "cgroup.procs",
                       "cgroup.events",
                       "cgroup.clone_children",
                       "cgroup.controllers",
                       "cgroup.subtree_control")
                if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0)
                        log_full_errno(errno == ENOENT ? LOG_DEBUG :  LOG_WARNING, errno,
                                       "Failed to chown() cgroup file %s, ignoring: %m", fn);

        return 0;
}
Пример #6
0
int main()
{
  int fd;

  fd = open("foobar",O_WRONLY|O_CREAT, 0666);
  //staptest// open ("foobar", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?, 0666) = NNNN

  chmod("foobar", 0644);
  //staptest// chmod ("foobar", 0644) = 0

  fchmod(fd, 0444);
  //staptest// fchmod (NNNN, 0444) = 0

#if GLIBC_SUPPORT
  fchmodat(AT_FDCWD, "foobar", 0644, 0);
  //staptest// fchmodat (AT_FDCWD, "foobar", 0644) = 0
#endif

  chown("foobar", 5000, -1);
  //staptest// chown ("foobar", 5000, -1) =

  chown("foobar", -1, 5001);
  //staptest// chown ("foobar", -1, 5001) =

  fchown(fd, 5002, -1);
  //staptest// fchown (NNNN, 5002, -1) =

#if GLIBC_SUPPORT
  fchownat(AT_FDCWD, "foobar", 5002, -1, 0);
  //staptest// fchownat (AT_FDCWD, "foobar", 5002, -1, 0x0) =
#endif

  fchown(fd, -1, 5003);
  //staptest// fchown (NNNN, -1, 5003) =

  lchown("foobar", 5004, -1);
  //staptest// lchown ("foobar", 5004, -1) =

  lchown("foobar", -1, 5005);
  //staptest// lchown ("foobar", -1, 5005) =

#ifdef __i386__
  syscall(SYS_chown, "foobar", 5000, -1);
  //staptest// chown16 ("foobar", 5000, -1) =
  syscall(SYS_chown, "foobar", -1, 5001);
  //staptest// chown16 ("foobar", -1, 5001) =
  syscall(SYS_fchown, fd, 5002, -1);
  //staptest// fchown16 (NNNN, 5002, -1) =
  syscall(SYS_fchown, fd, -1, 5003);
  //staptest// fchown16 (NNNN, -1, 5003) =
  syscall(SYS_lchown, "foobar", 5004, -1);
  //staptest// lchown16 ("foobar", 5004, -1) =
  syscall(SYS_lchown, "foobar", -1, 5005);
  //staptest// lchown16 ("foobar", -1, 5005) =
#endif

  close(fd);
  return 0;
}
Пример #7
0
static int
callback_chown (const char *path, uid_t uid, gid_t gid)
{
  path = ENSURE_RELPATH (path);
  VERIFY_WRITE(path);
  if (fchownat (basefd, path, uid, gid, 0) != 0)
    return -errno;
  return 0;
}
Пример #8
0
static void fchownat_verify(void)
{
	TEST(fchownat(dirfd, TESTFILE_LINK, set_uid, set_gid,
		      AT_SYMLINK_NOFOLLOW));

	if (TEST_RETURN != 0) {
		tst_resm(TFAIL | TTERRNO, "fchownat() failed, errno=%d : %s",
			 TEST_ERRNO, strerror(TEST_ERRNO));
	} else {
		test_verify();
	}
}
Пример #9
0
int
ast_fchownat(int cwd, const char* path, uid_t owner, gid_t group, int flags)
{
	int	r = -1;

	PATHIFY(cwd, path, 1, 0);
	if (path == dot && cwd >= 0)
		RESTART(r, fchown(cwd, owner, group));
	else
		RESTART(r, fchownat(cwd, path, owner, group, flags));
	PATHEND();

	return r;
}
Пример #10
0
int main() {
  struct stat st;
  struct stat st2;

  openat(AT_FDCWD, PWD "openat.txt", O_CREAT | O_WRONLY, 0644);
  assert(stat("openat.txt", &st) == 0); // relative path

  assert(faccessat(AT_FDCWD, PWD "openat.txt", F_OK, 0) == 0);
  assert(fstatat(AT_FDCWD, PWD "openat.txt", &st2, 0) == 0);
  assert(fchmodat(AT_FDCWD, PWD "openat.txt", 0777, 0) == 0);

  struct timeval my_times[2];
  my_times[0].tv_sec = 0;
  my_times[0].tv_usec = 0;
  my_times[1].tv_sec = 0;
  my_times[1].tv_usec = 0;
  assert(futimesat(AT_FDCWD, PWD "openat.txt", my_times, 0) == 0);

  // see /etc/passwd, user 'pgbovine' is 508:100
  assert(fchownat(AT_FDCWD, PWD "openat.txt", 508, 100, 0) == 0);

  assert(linkat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_hardlink.txt", 0) == 0);
  assert(stat("openat_hardlink.txt", &st) == 0); // relative path

  assert(symlinkat(PWD "openat.txt", AT_FDCWD, PWD "openat_symlink.txt") == 0);
  assert(lstat("openat_symlink.txt", &st) == 0); // relative path

  char res[300];
  assert(readlinkat(AT_FDCWD, PWD "openat_symlink.txt", res, sizeof(res)) > 0);

  assert(renameat(AT_FDCWD, PWD "openat.txt", AT_FDCWD, PWD "openat_newname.txt", 0) == 0);
  assert(stat("openat.txt", &st) != 0); // should not exist anymore
  assert(stat("openat_newname.txt", &st) == 0); // relative path

  unlinkat(AT_FDCWD, PWD "openat_newname.txt", 0);
  unlinkat(AT_FDCWD, PWD "openat_hardlink.txt", 0);
  unlinkat(AT_FDCWD, PWD "openat_symlink.txt", 0);


  mknodat(AT_FDCWD, PWD "mknodat.fifo", S_IFIFO);
  assert(stat("mknodat.fifo", &st) == 0); // relative path
  unlinkat(AT_FDCWD, PWD "mknodat.fifo", 0);

  mkdirat(AT_FDCWD, PWD "mkdirat_dir", 0);
  assert(stat("mkdirat_dir", &st) == 0); // relative path
  unlinkat(AT_FDCWD, PWD "mkdirat_dir", AT_REMOVEDIR); // like 'rmdir'

  return 0;
}
void sc_cgroup_freezer_join(const char *snap_name, pid_t pid)
{
	// Format the name of the cgroup hierarchy.
	char buf[PATH_MAX] = { 0 };
	sc_must_snprintf(buf, sizeof buf, "snap.%s", snap_name);

	// Open the freezer cgroup directory.
	int cgroup_fd SC_CLEANUP(sc_cleanup_close) = -1;
	cgroup_fd = open(freezer_cgroup_dir,
			 O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (cgroup_fd < 0) {
		die("cannot open freezer cgroup (%s)", freezer_cgroup_dir);
	}
	// Create the freezer hierarchy for the given snap.
	if (mkdirat(cgroup_fd, buf, 0755) < 0 && errno != EEXIST) {
		die("cannot create freezer cgroup hierarchy for snap %s",
		    snap_name);
	}
	// Open the hierarchy directory for the given snap.
	int hierarchy_fd SC_CLEANUP(sc_cleanup_close) = -1;
	hierarchy_fd = openat(cgroup_fd, buf,
			      O_PATH | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
	if (hierarchy_fd < 0) {
		die("cannot open freezer cgroup hierarchy for snap %s",
		    snap_name);
	}
	// Since we may be running from a setuid but not setgid executable, ensure
	// that the group and owner of the hierarchy directory is root.root.
	if (fchownat(hierarchy_fd, "", 0, 0, AT_EMPTY_PATH) < 0) {
		die("cannot change owner of freezer cgroup hierarchy for snap %s to root.root", snap_name);
	}
	// Open the tasks file.
	int tasks_fd SC_CLEANUP(sc_cleanup_close) = -1;
	tasks_fd = openat(hierarchy_fd, "tasks",
			  O_WRONLY | O_NOFOLLOW | O_CLOEXEC);
	if (tasks_fd < 0) {
		die("cannot open tasks file for freezer cgroup hierarchy for snap %s", snap_name);
	}
	// Write the process (task) number to the tasks file. Linux task IDs are
	// limited to 2^29 so a long int is enough to represent it.
	// See include/linux/threads.h in the kernel source tree for details.
	int n = sc_must_snprintf(buf, sizeof buf, "%ld", (long)pid);
	if (write(tasks_fd, buf, n) < n) {
		die("cannot move process %ld to freezer cgroup hierarchy for snap %s", (long)pid, snap_name);
	}
	debug("moved process %ld to freezer cgroup hierarchy for snap %s",
	      (long)pid, snap_name);
}
Пример #12
0
int
set_ids(char *fnm, uid_t uid, gid_t gid)
{
	if (fchownat(AT_FDCWD, fnm, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) {
		/*
		 * ignore EPERM unless in verbose mode or being run by root.
		 * if running as pax, POSIX requires a warning.
		 */
		if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
		    geteuid() == 0)
			syswarn(1, errno, "Unable to set file uid/gid of %s",
			    fnm);
		return(-1);
	}
	return(0);
}
Пример #13
0
void
psync_chown(const char *fn, uid_t uid, gid_t gid, int flags)
{
//	static int mask;
//
 //retry:
//	if (mask)
//		flags &= ~mask;
	if (fchownat(AT_FDCWD, fn, uid, gid, flags) == -1) {
//		if (errno == ENOTSUP && flags & AT_SYMLINK_NOFOLLOW) {
//			mask = AT_SYMLINK_NOFOLLOW;
//			goto retry;
//		}
		psynclog_warn("chown %s", fn);
	}
}
Пример #14
0
static int fd_copy_node(int df, const char *from, const struct stat *st, int dt, const char *to) {
        int r;

        assert(from);
        assert(st);
        assert(to);

        r = mknodat(dt, to, st->st_mode, st->st_rdev);
        if (r < 0)
                return -errno;

        if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
                r = -errno;

        if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0)
                r = -errno;

        return r;
}
Пример #15
0
static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
        _cleanup_free_ char *target = NULL;
        int r;

        assert(from);
        assert(st);
        assert(to);

        r = readlinkat_malloc(df, from, &target);
        if (r < 0)
                return r;

        if (symlinkat(target, dt, to) < 0)
                return -errno;

        if (fchownat(dt, to, st->st_uid, st->st_gid, AT_SYMLINK_NOFOLLOW) < 0)
                return -errno;

        return 0;
}
Пример #16
0
static inline int make_file_safe(struct vfs_fsal_obj_handle *dir_hdl,
				 const struct req_op_context *opctx,
				 int dir_fd, const char *name, mode_t unix_mode,
				 uid_t user, gid_t group,
				 struct vfs_fsal_obj_handle **hdl)
{
	int retval;
	struct stat stat;
	vfs_file_handle_t *fh;

	vfs_alloc_handle(fh);

	retval = fchownat(dir_fd, name, user, group, AT_SYMLINK_NOFOLLOW);
	if (retval < 0)
		goto fileerr;

	/* now that it is owned properly, set accessible mode */

	retval = fchmodat(dir_fd, name, unix_mode, 0);
	if (retval < 0)
		goto fileerr;
	retval = vfs_name_to_handle(dir_fd, dir_hdl->obj_handle.fs, name, fh);
	if (retval < 0)
		goto fileerr;
	retval = fstatat(dir_fd, name, &stat, AT_SYMLINK_NOFOLLOW);
	if (retval < 0)
		goto fileerr;

	/* allocate an obj_handle and fill it up */
	*hdl = alloc_handle(dir_fd, fh, dir_hdl->obj_handle.fs, &stat,
			    dir_hdl->handle, name, opctx->fsal_export);
	if (*hdl == NULL)
		return ENOMEM;
	return 0;

 fileerr:
	retval = errno;
	return retval;
}
Пример #17
0
static void fchownat_verify(const struct test_case_t *test)
{
	TEST(fchownat(*(test->fds), test->filenames, geteuid(),
		      getegid(), test->flag));

	if (TEST_RETURN != test->exp_ret) {
		tst_resm(TFAIL | TTERRNO,
			 "fchownat() returned %ld, expected %d, errno=%d",
			 TEST_RETURN, test->exp_ret, test->exp_errno);
		return;
	}

	if (TEST_ERRNO == test->exp_errno) {
		tst_resm(TPASS | TTERRNO,
			 "fchownat() returned the expected errno %d: %s",
			 test->exp_ret, strerror(test->exp_errno));
	} else {
		tst_resm(TFAIL | TTERRNO,
			 "fchownat() failed unexpectedly; expected: %d - %s",
			 test->exp_errno, strerror(test->exp_errno));
	}
}
Пример #18
0
/*
 * Given a file descriptor, create a capability with specific rights and
 * make sure only those rights work. 
*/
static int
try_file_ops(int filefd, int dirfd, cap_rights_t rights)
{
	struct stat sb;
	struct statfs sf;
	cap_rights_t erights;
	int fd_cap, fd_capcap, dfd_cap;
	ssize_t ssize, ssize2;
	off_t off;
	void *p;
	char ch;
	int ret, is_nfs;
	struct pollfd pollfd;
	int success = -1;

	REQUIRE(fstatfs(filefd, &sf));
	is_nfs = (strcmp("nfs", sf.f_fstypename) == 0);

	REQUIRE(fd_cap = cap_new(filefd, rights));
	CHECK(cap_getrights(fd_cap, &erights) == 0);
	CHECK(rights == erights);
	REQUIRE(fd_capcap = cap_new(fd_cap, rights));
	CHECK(cap_getrights(fd_capcap, &erights) == 0);
	CHECK(rights == erights);
	CHECK(fd_capcap != fd_cap);
	REQUIRE(dfd_cap = cap_new(dirfd, rights));
	CHECK(cap_getrights(dfd_cap, &erights) == 0);
	CHECK(rights == erights);

	ssize = read(fd_cap, &ch, sizeof(ch));
	CHECK_RESULT(read, CAP_READ, ssize >= 0);

	ssize = write(fd_cap, &ch, sizeof(ch));
	CHECK_RESULT(write, CAP_WRITE, ssize >= 0);

	off = lseek(fd_cap, 0, SEEK_SET);
	CHECK_RESULT(lseek, CAP_SEEK, off >= 0);

	ssize = pread(fd_cap, &ch, sizeof(ch), 0);
	ssize2 = pread(fd_cap, &ch, sizeof(ch), 0);
	CHECK_RESULT(pread, CAP_PREAD, ssize >= 0);
	CHECK(ssize == ssize2);

	ssize = pwrite(fd_cap, &ch, sizeof(ch), 0);
	CHECK_RESULT(pwrite, CAP_PWRITE, ssize >= 0);

	p = mmap(NULL, getpagesize(), PROT_NONE, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP);

	p = mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_R);

	p = mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_W);

	p = mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_X);

	p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED,
	    fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_RW);

	p = mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_SHARED,
	    fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_RX);

	p = mmap(NULL, getpagesize(), PROT_EXEC | PROT_WRITE, MAP_SHARED,
	    fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_WX);

	p = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC,
	    MAP_SHARED, fd_cap, 0);
	CHECK_MMAP_RESULT(CAP_MMAP_RWX);

	ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDONLY, 0600);
	CHECK_RESULT(openat(O_CREATE | O_RDONLY),
	    CAP_CREATE | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);
	ret = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY | O_APPEND,
	    0600);
	CHECK_RESULT(openat(O_CREATE | O_WRONLY | O_APPEND),
	    CAP_CREATE | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);
	ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR | O_APPEND, 0600);
	CHECK_RESULT(openat(O_CREATE | O_RDWR | O_APPEND),
	    CAP_CREATE | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);

	ret = fsync(fd_cap);
	CHECK_RESULT(fsync, CAP_FSYNC, ret == 0);

	ret = openat(dirfd, "cap_fsync", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDONLY);
	CHECK_RESULT(openat(O_FSYNC | O_RDONLY),
	    CAP_FSYNC | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY | O_APPEND);
	CHECK_RESULT(openat(O_FSYNC | O_WRONLY | O_APPEND),
	    CAP_FSYNC | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR | O_APPEND);
	CHECK_RESULT(openat(O_FSYNC | O_RDWR | O_APPEND),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDONLY);
	CHECK_RESULT(openat(O_SYNC | O_RDONLY),
	    CAP_FSYNC | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY | O_APPEND);
	CHECK_RESULT(openat(O_SYNC | O_WRONLY | O_APPEND),
	    CAP_FSYNC | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR | O_APPEND);
	CHECK_RESULT(openat(O_SYNC | O_RDWR | O_APPEND),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(unlinkat(dirfd, "cap_fsync", 0) == 0);

	ret = ftruncate(fd_cap, 0);
	CHECK_RESULT(ftruncate, CAP_FTRUNCATE, ret == 0);

	ret = openat(dirfd, "cap_ftruncate", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDONLY);
	CHECK_RESULT(openat(O_TRUNC | O_RDONLY),
	    CAP_FTRUNCATE | CAP_READ | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_WRONLY);
	CHECK_RESULT(openat(O_TRUNC | O_WRONLY),
	    CAP_FTRUNCATE | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_ftruncate", O_TRUNC | O_RDWR);
	CHECK_RESULT(openat(O_TRUNC | O_RDWR),
	    CAP_FTRUNCATE | CAP_READ | CAP_WRITE | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(unlinkat(dirfd, "cap_ftruncate", 0) == 0);

	ret = openat(dfd_cap, "cap_create", O_CREAT | O_WRONLY, 0600);
	CHECK_RESULT(openat(O_CREATE | O_WRONLY),
	    CAP_CREATE | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);
	ret = openat(dfd_cap, "cap_create", O_CREAT | O_RDWR, 0600);
	CHECK_RESULT(openat(O_CREATE | O_RDWR),
	    CAP_CREATE | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP,
	    ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_create", 0) == 0);

	ret = openat(dirfd, "cap_fsync", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_WRONLY);
	CHECK_RESULT(openat(O_FSYNC | O_WRONLY),
	    CAP_FSYNC | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_FSYNC | O_RDWR);
	CHECK_RESULT(openat(O_FSYNC | O_RDWR),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_WRONLY);
	CHECK_RESULT(openat(O_SYNC | O_WRONLY),
	    CAP_FSYNC | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	ret = openat(dfd_cap, "cap_fsync", O_SYNC | O_RDWR);
	CHECK_RESULT(openat(O_SYNC | O_RDWR),
	    CAP_FSYNC | CAP_READ | CAP_WRITE | CAP_SEEK | CAP_LOOKUP, ret >= 0);
	CHECK(ret == -1 || close(ret) == 0);
	CHECK(unlinkat(dirfd, "cap_fsync", 0) == 0);

	/*
	 * Note: this is not expected to work over NFS.
	 */
	ret = fchflags(fd_cap, UF_NODUMP);
	CHECK_RESULT(fchflags, CAP_FCHFLAGS,
	    ret == 0 || (is_nfs && errno == EOPNOTSUPP));

	ret = openat(dirfd, "cap_chflagsat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = chflagsat(dfd_cap, "cap_chflagsat", UF_NODUMP, 0);
	CHECK_RESULT(chflagsat, CAP_CHFLAGSAT | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_chflagsat", 0) == 0);

	ret = fchown(fd_cap, -1, -1);
	CHECK_RESULT(fchown, CAP_FCHOWN, ret == 0);

	ret = openat(dirfd, "cap_fchownat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = fchownat(dfd_cap, "cap_fchownat", -1, -1, 0);
	CHECK_RESULT(fchownat, CAP_FCHOWN | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_fchownat", 0) == 0);

	ret = fchmod(fd_cap, 0644);
	CHECK_RESULT(fchmod, CAP_FCHMOD, ret == 0);

	ret = openat(dirfd, "cap_fchmodat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = fchmodat(dfd_cap, "cap_fchmodat", 0600, 0);
	CHECK_RESULT(fchmodat, CAP_FCHMOD | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_fchmodat", 0) == 0);

	ret = fcntl(fd_cap, F_GETFL);
	CHECK_RESULT(fcntl(F_GETFL), CAP_FCNTL, ret >= 0);
	ret = fcntl(fd_cap, F_SETFL, ret);
	CHECK_RESULT(fcntl(F_SETFL), CAP_FCNTL, ret == 0);

	/* XXX flock */

	ret = fstat(fd_cap, &sb);
	CHECK_RESULT(fstat, CAP_FSTAT, ret == 0);

	ret = openat(dirfd, "cap_fstatat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = fstatat(dfd_cap, "cap_fstatat", &sb, 0);
	CHECK_RESULT(fstatat, CAP_FSTAT | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_fstatat", 0) == 0);

	ret = fstatfs(fd_cap, &sf);
	CHECK_RESULT(fstatfs, CAP_FSTATFS, ret == 0);

	ret = fpathconf(fd_cap, _PC_NAME_MAX);
	CHECK_RESULT(fpathconf, CAP_FPATHCONF, ret >= 0);

	ret = futimes(fd_cap, NULL);
	CHECK_RESULT(futimes, CAP_FUTIMES, ret == 0);

	ret = openat(dirfd, "cap_futimesat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = futimesat(dfd_cap, "cap_futimesat", NULL);
	CHECK_RESULT(futimesat, CAP_FUTIMES | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_futimesat", 0) == 0);

	ret = openat(dirfd, "cap_linkat_src", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = linkat(dirfd, "cap_linkat_src", dfd_cap, "cap_linkat_dst", 0);
	CHECK_RESULT(linkat, CAP_LINKAT | CAP_LOOKUP, ret == 0);
	CHECK(unlinkat(dirfd, "cap_linkat_src", 0) == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_linkat_dst", 0) == 0);

	ret = mkdirat(dfd_cap, "cap_mkdirat", 0700);
	CHECK_RESULT(mkdirat, CAP_MKDIRAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_mkdirat", AT_REMOVEDIR) == 0);

	ret = mkfifoat(dfd_cap, "cap_mkfifoat", 0600);
	CHECK_RESULT(mkfifoat, CAP_MKFIFOAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_mkfifoat", 0) == 0);

	ret = mknodat(dfd_cap, "cap_mknodat", S_IFCHR | 0600, 0);
	CHECK_RESULT(mknodat, CAP_MKNODAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_mknodat", 0) == 0);

	/* TODO: renameat(2) */

	ret = symlinkat("test", dfd_cap, "cap_symlinkat");
	CHECK_RESULT(symlinkat, CAP_SYMLINKAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == -1 || unlinkat(dirfd, "cap_symlinkat", 0) == 0);

	ret = openat(dirfd, "cap_unlinkat", O_CREAT, 0600);
	CHECK(ret >= 0);
	CHECK(close(ret) == 0);
	ret = unlinkat(dfd_cap, "cap_unlinkat", 0);
	CHECK_RESULT(unlinkat, CAP_UNLINKAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == 0 || unlinkat(dirfd, "cap_unlinkat", 0) == 0);
	ret = mkdirat(dirfd, "cap_unlinkat", 0700);
	CHECK(ret == 0);
	ret = unlinkat(dfd_cap, "cap_unlinkat", AT_REMOVEDIR);
	CHECK_RESULT(unlinkat, CAP_UNLINKAT | CAP_LOOKUP, ret == 0);
	CHECK(ret == 0 || unlinkat(dirfd, "cap_unlinkat", AT_REMOVEDIR) == 0);

	pollfd.fd = fd_cap;
	pollfd.events = POLLIN | POLLERR | POLLHUP;
	pollfd.revents = 0;

	ret = poll(&pollfd, 1, 0);
	if (rights & CAP_EVENT)
		CHECK((pollfd.revents & POLLNVAL) == 0);
	else
		CHECK((pollfd.revents & POLLNVAL) != 0);

	/* XXX: select, kqueue */

	close(fd_cap);
	close(fd_capcap);

	if (success == -1) {
		fprintf(stderr, "No tests for rights 0x%jx.\n",
		    (uintmax_t)rights);
		success = FAILED;
	}
	return (success);
}
Пример #19
0
int
main(int argc, char *argv[])
{
	FTS *ftsp;
	FTSENT *p;
	void *set;
	unsigned long val;
	int oct;
	mode_t omode;
	int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, atflags;
	uid_t uid;
	gid_t gid;
	u_int32_t fclear, fset;
	char *ep, *mode, *cp, *flags;

	if (strlen(__progname) > 2) {
		ischown = __progname[2] == 'o';
		ischgrp = __progname[2] == 'g';
		ischmod = __progname[2] == 'm';
		ischflags = __progname[2] == 'f';
	}

	uid = (uid_t)-1;
	gid = (gid_t)-1;
	Hflag = Lflag = Rflag = fflag = hflag = 0;
	while ((ch = getopt(argc, argv, "HLPRXfghorstuwx")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':		/* no longer documented. */
			fflag = 1;
			break;
		case 'h':
			hflag = 1;
			break;
		/*
		 * If this is a symbolic mode argument rather than
		 * an option, we are done with option processing.
		 */
		case 'g': case 'o': case 'r': case 's':
		case 't': case 'u': case 'w': case 'X': case 'x':
			if (!ischmod)
				usage();
			/*
			 * If getopt() moved past the argument, back up.
			 * If the argument contains option letters before
			 * mode letters, setmode() will catch them.
			 */
			if (optind > 1) {
				cp = argv[optind - 1];
				if (cp[strlen(cp) - 1] == ch)
					--optind;
			}
			goto done;
		default:
			usage();
		}
done:
	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	/*
	 * We alter the symlink itself if doing -h or -RP, or
	 * if doing -RH and the symlink wasn't a command line arg.
	 */
	atflags = AT_SYMLINK_NOFOLLOW;

	fts_options = FTS_PHYSICAL;
	if (Rflag) {
		if (hflag)
			errx(1,
		"the -R and -h options may not be specified together.");
		if (Hflag)
			fts_options |= FTS_COMFOLLOW;
		if (Lflag) {
			fts_options &= ~FTS_PHYSICAL;
			fts_options |= FTS_LOGICAL;
			atflags = 0;
		}
	} else if (!hflag) {
		fts_options |= FTS_COMFOLLOW;
		atflags = 0;
	}

	if (ischflags) {
		if (pledge("stdio rpath fattr", NULL) == -1)
			err(1, "pledge");

		flags = *argv;
		if (*flags >= '0' && *flags <= '7') {
			errno = 0;
			val = strtoul(flags, &ep, 8);
			if (val > UINT_MAX)
				errno = ERANGE;
			if (errno)
				err(1, "invalid flags: %s", flags);
			if (*ep)
				errx(1, "invalid flags: %s", flags);
			fset = val;
			oct = 1;
		} else {
			if (strtofflags(&flags, &fset, &fclear))
				errx(1, "invalid flag: %s", flags);
			fclear = ~fclear;
			oct = 0;
		}
	} else if (ischmod) {
		mode = *argv;
		if (*mode >= '0' && *mode <= '7') {
			errno = 0;
			val = strtoul(mode, &ep, 8);
			if (val > INT_MAX)
				errno = ERANGE;
			if (errno)
				err(1, "invalid file mode: %s", mode);
			if (*ep)
				errx(1, "invalid file mode: %s", mode);
			omode = val;
			oct = 1;
		} else {
			if ((set = setmode(mode)) == NULL)
				errx(1, "invalid file mode: %s", mode);
			oct = 0;
		}
	} else if (ischown) {
		/* Both UID and GID are given. */
		if ((cp = strchr(*argv, ':')) != NULL) {
			*cp++ = '\0';
			gid = a_gid(cp);
		}
		/*
		 * UID and GID are separated by a dot and UID exists.
		 * required for backwards compatibility pre-dating POSIX.2
		 * likely to stay here forever
		 */
		else if ((cp = strchr(*argv, '.')) != NULL &&
		    (uid = a_uid(*argv, 1)) == (uid_t)-1) {
			*cp++ = '\0';
			gid = a_gid(cp);
		}
		if (uid == (uid_t)-1)
			uid = a_uid(*argv, 0);
	} else
		gid = a_gid(*argv);

	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
		err(1, NULL);
	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		switch (p->fts_info) {
		case FTS_D:
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			if (ischmod)
				break;
			else
				continue;
		case FTS_DNR:			/* Warn, chmod, continue. */
			warnc(p->fts_errno, "%s", p->fts_path);
			rval = 1;
			break;
		case FTS_DP:			/* Already changed at FTS_D. */
			if (ischmod)
				continue;
			else
				break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnc(p->fts_errno, "%s", p->fts_path);
			rval = 1;
			continue;
		case FTS_SL:			/* Ignore. */
		case FTS_SLNONE:
			/*
			 * The only symlinks that end up here are ones that
			 * don't point to anything or that loop and ones
			 * that we found doing a physical walk.
			 */
			if (!hflag && (fts_options & FTS_LOGICAL))
				continue;
			break;
		default:
			break;
		}

		/*
		 * For -RH, the decision of how to handle symlinks depends
		 * on the level: follow it iff it's a command line arg.
		 */
		if (fts_options & FTS_COMFOLLOW) {
			atflags = p->fts_level == FTS_ROOTLEVEL ? 0 : 
			    AT_SYMLINK_NOFOLLOW;
		}

		if (ischmod) {
			if (!fchmodat(AT_FDCWD, p->fts_accpath, oct ? omode :
			    getmode(set, p->fts_statp->st_mode), atflags)
			    || fflag)
				continue;
		} else if (!ischflags) {
			if (!fchownat(AT_FDCWD, p->fts_accpath, uid, gid,
			    atflags) || fflag)
				continue;
		} else {
			if (!chflagsat(AT_FDCWD, p->fts_accpath, oct ? fset :
			    (p->fts_statp->st_flags | fset) & fclear, atflags))
				continue;
		}

		/* error case */
		warn("%s", p->fts_path);
		rval = 1;
	}
	if (errno)
		err(1, "fts_read");
	fts_close(ftsp);
	return (rval);
}
Пример #20
0
/**
 * @brief Set attributes on an object
 *
 * This function sets attributes on an object.  Which attributes are
 * set is determined by attrib_set->mask. The FSAL must manage bypass
 * or not of share reservations, and a state may be passed.
 *
 * @param[in] obj_hdl    File on which to operate
 * @param[in] state      state_t to use for this operation
 * @param[in] attrib_set Attributes to set
 *
 * @return FSAL status.
 */
fsal_status_t vfs_setattr2(struct fsal_obj_handle *obj_hdl,
			   bool bypass,
			   struct state_t *state,
			   struct attrlist *attrib_set)
{
	struct vfs_fsal_obj_handle *myself;
	fsal_status_t status = {0, 0};
	int retval = 0;
	fsal_openflags_t openflags = FSAL_O_ANY;
	bool has_lock = false;
	bool need_fsync = false;
	bool closefd = false;
	int my_fd;
	const char *func;

	/* apply umask, if mode attribute is to be changed */
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE))
		attrib_set->mode &=
		    ~op_ctx->fsal_export->exp_ops.fs_umask(op_ctx->fsal_export);

	myself = container_of(obj_hdl, struct vfs_fsal_obj_handle, obj_handle);

	if (obj_hdl->fsal != obj_hdl->fs->fsal) {
		LogDebug(COMPONENT_FSAL,
			 "FSAL %s operation for handle belonging to FSAL %s, return EXDEV",
			 obj_hdl->fsal->name,
			 obj_hdl->fs->fsal != NULL
				? obj_hdl->fs->fsal->name
				: "(none)");
		return fsalstat(posix2fsal_error(EXDEV), EXDEV);
	}

#ifdef ENABLE_VFS_DEBUG_ACL
#ifdef ENABLE_RFC_ACL
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE) &&
	    !FSAL_TEST_MASK(attrib_set->mask, ATTR_ACL)) {
		/* Set ACL from MODE */
		struct attrlist attrs;

		fsal_prepare_attrs(&attrs, ATTR_ACL);

		status = obj_hdl->obj_ops.getattrs(obj_hdl, &attrs);

		if (FSAL_IS_ERROR(status))
			return status;

		status = fsal_mode_to_acl(attrib_set, attrs.acl);

		/* Done with the attrs */
		fsal_release_attrs(&attrs);
	} else {
		/* If ATTR_ACL is set, mode needs to be adjusted no matter what.
		 * See 7530 s 6.4.1.3 */
		if (!FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE))
			attrib_set->mode = myself->mode;
		status = fsal_acl_to_mode(attrib_set);
	}

	if (FSAL_IS_ERROR(status))
		return status;
#endif /* ENABLE_RFC_ACL */
#endif

	/* This is yet another "you can't get there from here".  If this object
	 * is a socket (AF_UNIX), an fd on the socket s useless _period_.
	 * If it is for a symlink, without O_PATH, you will get an ELOOP error
	 * and (f)chmod doesn't work for a symlink anyway - not that it matters
	 * because access checking is not done on the symlink but the final
	 * target.
	 * AF_UNIX sockets are also ozone material.  If the socket is already
	 * active listeners et al, you can manipulate the mode etc.  If it is
	 * just sitting there as in you made it with a mknod.
	 * (one of those leaky abstractions...)
	 * or the listener forgot to unlink it, it is lame duck.
	 */

	/* Test if size is being set, make sure file is regular and if so,
	 * require a read/write file descriptor.
	 */
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) {
		if (obj_hdl->type != REGULAR_FILE) {
			LogFullDebug(COMPONENT_FSAL,
				     "Setting size on non-regular file");
			return fsalstat(ERR_FSAL_INVAL, EINVAL);
		}
		openflags = FSAL_O_RDWR;
	}

	/* Get a usable file descriptor. Share conflict is only possible if
	 * size is being set.
	 */
	status = find_fd(&my_fd, obj_hdl, bypass, state, openflags,
			 &has_lock, &need_fsync, &closefd, false);

	if (FSAL_IS_ERROR(status)) {
		if (obj_hdl->type == SYMBOLIC_LINK &&
		    status.major == ERR_FSAL_PERM) {
			/* You cannot open_by_handle (XFS) a symlink and it
			 * throws an EPERM error for it.  open_by_handle_at
			 * does not throw that error for symlinks so we play a
			 * game here.  Since there is not much we can do with
			 * symlinks anyway, say that we did it
			 * but don't actually do anything.
			 * If you *really* want to tweek things
			 * like owners, get a modern linux kernel...
			 */
			status = fsalstat(ERR_FSAL_NO_ERROR, 0);
		}
		LogFullDebug(COMPONENT_FSAL,
			     "find_fd status=%s",
			     fsal_err_txt(status));
		goto out;
	}

	/** TRUNCATE **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_SIZE)) {
		retval = ftruncate(my_fd, attrib_set->filesize);
		if (retval != 0) {
			/** @todo FSF: is this still necessary?
			 *
			 * XXX ESXi volume creation pattern reliably
			 * reached this point in the past, however now that we
			 * only use the already open file descriptor if it is
			 * open read/write, this may no longer fail.
			 * If there is some other error from ftruncate, then
			 * we will needlessly retry, but without more detail
			 * of the original failure, we can't be sure.
			 * Fortunately permission checking is done by
			 * Ganesha before calling here, so we won't get an
			 * EACCES since this call is done as root. We could
			 * get EFBIG, EPERM, or EINVAL.
			 */
			/** @todo FSF: re-open if we really still need this
			 */

			retval = ftruncate(my_fd, attrib_set->filesize);
			if (retval != 0) {
				func = "truncate";
				goto fileerr;
			}
		}
	}

	/** CHMOD **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MODE)) {
		/* The POSIX chmod call doesn't affect the symlink object, but
		 * the entry it points to. So we must ignore it.
		 */
		if (obj_hdl->type != SYMBOLIC_LINK) {
			if (vfs_unopenable_type(obj_hdl->type))
				retval = fchmodat(
					my_fd,
					myself->u.unopenable.name,
					fsal2unix_mode(attrib_set->mode),
					0);
			else
				retval = fchmod(
					my_fd,
					fsal2unix_mode(attrib_set->mode));

			if (retval != 0) {
				func = "chmod";
				goto fileerr;
			}
		}
	}

	/**  CHOWN  **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER | ATTR_GROUP)) {
		uid_t user = FSAL_TEST_MASK(attrib_set->mask, ATTR_OWNER)
		    ? (int)attrib_set->owner : -1;
		gid_t group = FSAL_TEST_MASK(attrib_set->mask, ATTR_GROUP)
		    ? (int)attrib_set->group : -1;

		if (vfs_unopenable_type(obj_hdl->type))
			retval = fchownat(my_fd, myself->u.unopenable.name,
					  user, group, AT_SYMLINK_NOFOLLOW);
		else if (obj_hdl->type == SYMBOLIC_LINK)
			retval = fchownat(my_fd, "", user, group,
					  AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH);
		else
			retval = fchown(my_fd, user, group);

		if (retval) {
			func = "chown";
			goto fileerr;
		}
	}

	/**  UTIME  **/
	if (FSAL_TEST_MASK(attrib_set->mask, ATTRS_SET_TIME)) {
		struct timespec timebuf[2];

		if (obj_hdl->type == SYMBOLIC_LINK)
			goto out; /* Setting time on symlinks is illegal */
		/* Atime */
		if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME_SERVER)) {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_ATIME)) {
			timebuf[0] = attrib_set->atime;
		} else {
			timebuf[0].tv_sec = 0;
			timebuf[0].tv_nsec = UTIME_OMIT;
		}

		/* Mtime */
		if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME_SERVER)) {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_NOW;
		} else if (FSAL_TEST_MASK(attrib_set->mask, ATTR_MTIME)) {
			timebuf[1] = attrib_set->mtime;
		} else {
			timebuf[1].tv_sec = 0;
			timebuf[1].tv_nsec = UTIME_OMIT;
		}
		if (vfs_unopenable_type(obj_hdl->type))
			retval = vfs_utimesat(my_fd, myself->u.unopenable.name,
					      timebuf, AT_SYMLINK_NOFOLLOW);
		else
			retval = vfs_utimes(my_fd, timebuf);
		if (retval != 0) {
			func = "utimes";
			goto fileerr;
		}
	}

	/** SUBFSAL **/
	if (myself->sub_ops && myself->sub_ops->setattrs) {
		status = myself->sub_ops->setattrs(
					myself,
					my_fd,
					attrib_set->mask, attrib_set);
		if (FSAL_IS_ERROR(status))
			goto out;
	}

	errno = 0;

 fileerr:

	retval = errno;

	if (retval != 0) {
		LogDebug(COMPONENT_FSAL,
			 "%s returned %s",
			 func, strerror(retval));
	}

	status = fsalstat(posix2fsal_error(retval), retval);

 out:

	if (closefd)
		close(my_fd);

	if (has_lock)
		PTHREAD_RWLOCK_unlock(&obj_hdl->lock);

	return status;
}
Пример #21
0
int
lchown(const char *path, uid_t owner, gid_t group)
{

	return (fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW));
}
Пример #22
0
static int
do_test (void)
{
  /* fdopendir takes over the descriptor, make a copy.  */
  int dupfd = dup (dir_fd);
  if (dupfd == -1)
    {
      puts ("dup failed");
      return 1;
    }
  if (lseek (dupfd, 0, SEEK_SET) != 0)
    {
      puts ("1st lseek failed");
      return 1;
    }

  /* The directory should be empty safe the . and .. files.  */
  DIR *dir = fdopendir (dupfd);
  if (dir == NULL)
    {
      puts ("fdopendir failed");
      return 1;
    }
  struct dirent64 *d;
  while ((d = readdir64 (dir)) != NULL)
    if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
      {
	printf ("temp directory contains file \"%s\"\n", d->d_name);
	return 1;
      }
  closedir (dir);

  /* Try to create a file.  */
  int fd = openat (dir_fd, "some-file", O_CREAT|O_RDWR|O_EXCL, 0666);
  if (fd == -1)
    {
      if (errno == ENOSYS)
	{
	  puts ("*at functions not supported");
	  return 0;
	}

      puts ("file creation failed");
      return 1;
    }
  write (fd, "hello", 5);
  puts ("file created");

  struct stat64 st1;
  if (fstat64 (fd, &st1) != 0)
    {
      puts ("fstat64 failed");
      return 1;
    }

  /* Before closing the file, try using this file descriptor to open
     another file.  This must fail.  */
  if (fchownat (fd, "some-file", 1, 1, 0) != -1)
    {
      puts ("fchownat using descriptor for normal file worked");
      return 1;
    }
  if (errno != ENOTDIR)
    {
      puts ("\
error for fchownat using descriptor for normal file not ENOTDIR ");
      return 1;
    }
Пример #23
0
int
main(int argc, char **argv)
{
	FTS *ftsp;
	FTSENT *p;
	int Hflag, Lflag, Rflag, fflag, hflag, vflag, xflag;
	int ch, fts_options, rval;
	char *cp;

	ischown = (strcmp(basename(argv[0]), "chown") == 0);

	Hflag = Lflag = Rflag = fflag = hflag = vflag = xflag = 0;
	while ((ch = getopt(argc, argv, "HLPRfhvx")) != -1)
		switch (ch) {
		case 'H':
			Hflag = 1;
			Lflag = 0;
			break;
		case 'L':
			Lflag = 1;
			Hflag = 0;
			break;
		case 'P':
			Hflag = Lflag = 0;
			break;
		case 'R':
			Rflag = 1;
			break;
		case 'f':
			fflag = 1;
			break;
		case 'h':
			hflag = 1;
			break;
		case 'v':
			vflag++;
			break;
		case 'x':
			xflag = 1;
			break;
		case '?':
		default:
			usage();
		}
	argv += optind;
	argc -= optind;

	if (argc < 2)
		usage();

	if (Rflag) {
		if (hflag && (Hflag || Lflag))
			errx(1, "the -R%c and -h options may not be "
			    "specified together", Hflag ? 'H' : 'L');
		if (Lflag) {
			fts_options = FTS_LOGICAL;
		} else {
			fts_options = FTS_PHYSICAL;

			if (Hflag) {
				fts_options |= FTS_COMFOLLOW;
			}
		}
	} else if (hflag) {
		fts_options = FTS_PHYSICAL;
	} else {
		fts_options = FTS_LOGICAL;
	}

	if (xflag)
		fts_options |= FTS_XDEV;

	uid = (uid_t)-1;
	gid = (gid_t)-1;
	if (ischown) {
		if ((cp = strchr(*argv, ':')) != NULL) {
			*cp++ = '\0';
			a_gid(cp);
		}
#ifdef SUPPORT_DOT
		else if ((cp = strchr(*argv, '.')) != NULL) {
			warnx("separation of user and group with a period is deprecated");
			*cp++ = '\0';
			a_gid(cp);
		}
#endif
		a_uid(*argv);
	} else
		a_gid(*argv);

	if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
		err(1, NULL);

	for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
		int atflag;

		if ((fts_options & FTS_LOGICAL) ||
		    ((fts_options & FTS_COMFOLLOW) &&
		    p->fts_level == FTS_ROOTLEVEL))
			atflag = 0;
		else
			atflag = AT_SYMLINK_NOFOLLOW;

		switch (p->fts_info) {
		case FTS_D:			/* Change it at FTS_DP. */
			if (!Rflag)
				fts_set(ftsp, p, FTS_SKIP);
			continue;
		case FTS_DNR:			/* Warn, chown. */
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			break;
		case FTS_ERR:			/* Warn, continue. */
		case FTS_NS:
			warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
			rval = 1;
			continue;
		default:
			break;
		}
		if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) &&
		    (gid == (gid_t)-1 || gid == p->fts_statp->st_gid))
			continue;
		if (fchownat(AT_FDCWD, p->fts_accpath, uid, gid, atflag)
		    == -1 && !fflag) {
			chownerr(p->fts_path);
			rval = 1;
		} else if (vflag) {
			printf("%s", p->fts_path);
			if (vflag > 1) {
				if (ischown) {
					printf(": %ju:%ju -> %ju:%ju",
					    (uintmax_t)
					    p->fts_statp->st_uid, 
					    (uintmax_t)
					    p->fts_statp->st_gid,
					    (uid == (uid_t)-1) ? 
					    (uintmax_t)
					    p->fts_statp->st_uid : 
					    (uintmax_t)uid,
					    (gid == (gid_t)-1) ? 
					    (uintmax_t)
					    p->fts_statp->st_gid :
					    (uintmax_t)gid);
				} else {
					printf(": %ju -> %ju",
					    (uintmax_t)
					    p->fts_statp->st_gid,
					    (gid == (gid_t)-1) ? 
					    (uintmax_t)
					    p->fts_statp->st_gid : 
					    (uintmax_t)gid);
				}
			}
			printf("\n");
		}
	}
	if (errno)
		err(1, "fts_read");
	exit(rval);
}
Пример #24
0
int chown(const char* path, uid_t uid, gid_t gid) {
  return fchownat(AT_FDCWD, path, uid, gid, 0);
}
Пример #25
0
void
copymkdir(int rootfd, char const * dir, int skelfd, mode_t mode, uid_t uid,
    gid_t gid, int flags)
{
	char		*p, lnk[MAXPATHLEN], copybuf[4096];
	int		len, homefd, srcfd, destfd;
	ssize_t		sz;
	struct stat     st;
	struct dirent  *e;
	DIR		*d;

	if (*dir == '/')
		dir++;

	if (mkdirat(rootfd, dir, mode) != 0 && errno != EEXIST) {
		warn("mkdir(%s)", dir);
		return;
	}
	fchownat(rootfd, dir, uid, gid, AT_SYMLINK_NOFOLLOW);
	if (flags > 0)
		chflagsat(rootfd, dir, flags, AT_SYMLINK_NOFOLLOW);

	if (skelfd == -1)
		return;

	homefd = openat(rootfd, dir, O_DIRECTORY);
	if ((d = fdopendir(skelfd)) == NULL) {
		close(skelfd);
		close(homefd);
		return;
	}

	while ((e = readdir(d)) != NULL) {
		if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0)
			continue;

		p = e->d_name;
		if (fstatat(skelfd, p, &st, AT_SYMLINK_NOFOLLOW) == -1)
			continue;

		if (strncmp(p, "dot.", 4) == 0)	/* Conversion */
			p += 3;

		if (S_ISDIR(st.st_mode)) {
			copymkdir(homefd, p, openat(skelfd, e->d_name, O_DIRECTORY),
			    st.st_mode & _DEF_DIRMODE, uid, gid, st.st_flags);
			continue;
		}

		if (S_ISLNK(st.st_mode) &&
		    (len = readlinkat(skelfd, e->d_name, lnk, sizeof(lnk) -1))
		    != -1) {
			lnk[len] = '\0';
			symlinkat(lnk, homefd, p);
			fchownat(homefd, p, uid, gid, AT_SYMLINK_NOFOLLOW);
			continue;
		}

		if (!S_ISREG(st.st_mode))
			continue;

		if ((srcfd = openat(skelfd, e->d_name, O_RDONLY)) == -1)
			continue;
		destfd = openat(homefd, p, O_RDWR | O_CREAT | O_EXCL,
		    st.st_mode);
		if (destfd == -1) {
			close(srcfd);
			continue;
		}

		while ((sz = read(srcfd, copybuf, sizeof(copybuf))) > 0)
			write(destfd, copybuf, sz);

		close(srcfd);
		/*
		 * Propagate special filesystem flags
		 */
		fchown(destfd, uid, gid);
		fchflags(destfd, st.st_flags);
		close(destfd);
	}
	closedir(d);
}
Пример #26
0
static unsigned int
call_syscall(struct syscall_desc *scall, char *argv[])
{
	struct stat64 sb;
	long long flags;
	unsigned int i;
	char *endp;
	int name, rval;
	union {
		char *str;
		long long num;
	} args[MAX_ARGS];
#ifdef HAS_FREEBSD_ACL
	int entry_id = ACL_FIRST_ENTRY;
	acl_t acl, newacl;
	acl_entry_t entry, newentry;
#endif

	/*
	 * Verify correctness of the arguments.
	 */
	for (i = 0; i < sizeof(args)/sizeof(args[0]); i++) {
		if (scall->sd_args[i] == TYPE_NONE) {
			if (argv[i] == NULL || strcmp(argv[i], ":") == 0)
				break;
			fprintf(stderr, "too many arguments [%s]\n", argv[i]);
			exit(1);
		} else {
			if (argv[i] == NULL || strcmp(argv[i], ":") == 0) {
				if (scall->sd_args[i] & TYPE_OPTIONAL)
					break;
				fprintf(stderr, "too few arguments\n");
				exit(1);
			}
			if ((scall->sd_args[i] & TYPE_MASK) == TYPE_STRING) {
				if (strcmp(argv[i], "NULL") == 0)
					args[i].str = NULL;
				else if (strcmp(argv[i], "DEADCODE") == 0)
					args[i].str = (void *)0xdeadc0de;
				else
					args[i].str = argv[i];
			} else if ((scall->sd_args[i] & TYPE_MASK) ==
			    TYPE_NUMBER) {
				args[i].num = strtoll(argv[i], &endp, 0);
				if (*endp != '\0' &&
				    !isspace((unsigned char)*endp)) {
					fprintf(stderr,
					    "invalid argument %u, number expected [%s]\n",
					    i, endp);
					exit(1);
				}
			} else if ((scall->sd_args[i] & TYPE_MASK) ==
			    TYPE_DESCRIPTOR) {
				if (strcmp(argv[i], "AT_FDCWD") == 0) {
					args[i].num = AT_FDCWD;
				} else if (strcmp(argv[i], "BADFD") == 0) {
					/* In case AT_FDCWD is -1 on some systems... */
					if (AT_FDCWD == -1)
						args[i].num = -2;
					else
						args[i].num = -1;
				} else {
					int pos;

					pos = strtoll(argv[i], &endp, 0);
					if (*endp != '\0' &&
					    !isspace((unsigned char)*endp)) {
						fprintf(stderr,
						    "invalid argument %u, number expected [%s]\n",
						    i, endp);
						exit(1);
					}
					args[i].num = descriptor_get(pos);
				}
			}
		}
	}
	/*
	 * Call the given syscall.
	 */
#define	NUM(n)	(args[(n)].num)
#define	STR(n)	(args[(n)].str)
	switch (scall->sd_action) {
	case ACTION_OPEN:
		flags = str2flags(open_flags, STR(1));
		if (flags & O_CREAT) {
			if (i == 2) {
				fprintf(stderr, "too few arguments\n");
				exit(1);
			}
			rval = open(STR(0), (int)flags, (mode_t)NUM(2));
		} else {
			if (i == 3) {
				fprintf(stderr, "too many arguments\n");
				exit(1);
			}
			rval = open(STR(0), (int)flags);
		}
		if (rval >= 0)
			descriptor_add(rval);
		break;
	case ACTION_OPENAT:
		flags = str2flags(open_flags, STR(2));
		if (flags & O_CREAT) {
			if (i == 3) {
				fprintf(stderr, "too few arguments\n");
				exit(1);
			}
			rval = openat(NUM(0), STR(1), (int)flags,
			    (mode_t)NUM(3));
		} else {
			if (i == 4) {
				fprintf(stderr, "too many arguments\n");
				exit(1);
			}
			rval = openat(NUM(0), STR(1), (int)flags);
		}
		if (rval >= 0)
			descriptor_add(rval);
		break;
	case ACTION_CREATE:
		rval = open(STR(0), O_CREAT | O_EXCL, (mode_t)NUM(1));
		if (rval >= 0)
			close(rval);
		break;
	case ACTION_UNLINK:
		rval = unlink(STR(0));
		break;
	case ACTION_UNLINKAT:
		rval = unlinkat(NUM(0), STR(1),
		    (int)str2flags(unlinkat_flags, STR(2)));
		break;
	case ACTION_MKDIR:
		rval = mkdir(STR(0), (mode_t)NUM(1));
		break;
	case ACTION_MKDIRAT:
		rval = mkdirat(NUM(0), STR(1), (mode_t)NUM(2));
		break;
	case ACTION_RMDIR:
		rval = rmdir(STR(0));
		break;
	case ACTION_LINK:
		rval = link(STR(0), STR(1));
		break;
	case ACTION_LINKAT:
		rval = linkat(NUM(0), STR(1), NUM(2), STR(3),
		    (int)str2flags(linkat_flags, STR(4)));
		break;
	case ACTION_SYMLINK:
		rval = symlink(STR(0), STR(1));
		break;
	case ACTION_SYMLINKAT:
		rval = symlinkat(STR(0), NUM(1), STR(2));
		break;
	case ACTION_RENAME:
		rval = rename(STR(0), STR(1));
		break;
	case ACTION_RENAMEAT:
		rval = renameat(NUM(0), STR(1), NUM(2), STR(3));
		break;
	case ACTION_MKFIFO:
		rval = mkfifo(STR(0), (mode_t)NUM(1));
		break;
	case ACTION_MKFIFOAT:
		rval = mkfifoat(NUM(0), STR(1), (mode_t)NUM(2));
		break;
	case ACTION_MKNOD:
	case ACTION_MKNODAT:
	    {
		mode_t ntype;
		dev_t dev;
		int fa;

		switch (scall->sd_action) {
		case ACTION_MKNOD:
			fa = 0;
			break;
		case ACTION_MKNODAT:
			fa = 1;
			break;
		default:
			abort();
		}

		dev = makedev(NUM(fa + 3), NUM(fa + 4));
		if (strcmp(STR(fa + 1), "c") == 0)	/* character device */
			ntype = S_IFCHR;
		else if (strcmp(STR(fa + 1), "b") == 0)	/* block device */
			ntype = S_IFBLK;
		else if (strcmp(STR(fa + 1), "f") == 0)	/* fifo special */
			ntype = S_IFIFO;
		else if (strcmp(STR(fa + 1), "d") == 0)	/* directory */
			ntype = S_IFDIR;
		else if (strcmp(STR(fa + 1), "o") == 0)	/* regular file */
			ntype = S_IFREG;
		else {
			fprintf(stderr, "wrong argument 1\n");
			exit(1);
		}
		switch (scall->sd_action) {
		case ACTION_MKNOD:
			rval = mknod(STR(0), ntype | NUM(2), dev);
			break;
		case ACTION_MKNODAT:
			rval = mknodat(NUM(0), STR(1), ntype | NUM(3), dev);
			break;
		default:
			abort();
		}
		break;
	    }
	case ACTION_BIND:
	    {
		struct sockaddr_un sunx;

		sunx.sun_family = AF_UNIX;
		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
		rval = socket(AF_UNIX, SOCK_STREAM, 0);
		if (rval < 0)
			break;
		rval = bind(rval, (struct sockaddr *)&sunx, sizeof(sunx));
		break;
	    }
#ifdef HAS_BINDAT
	case ACTION_BINDAT:
	    {
		struct sockaddr_un sunx;

		sunx.sun_family = AF_UNIX;
		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
		rval = socket(AF_UNIX, SOCK_STREAM, 0);
		if (rval < 0)
			break;
		rval = bindat(NUM(0), rval, (struct sockaddr *)&sunx,
		    sizeof(sunx));
		break;
	    }
#endif
	case ACTION_CONNECT:
	    {
		struct sockaddr_un sunx;

		sunx.sun_family = AF_UNIX;
		strncpy(sunx.sun_path, STR(0), sizeof(sunx.sun_path) - 1);
		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
		rval = socket(AF_UNIX, SOCK_STREAM, 0);
		if (rval < 0)
			break;
		rval = connect(rval, (struct sockaddr *)&sunx, sizeof(sunx));
		break;
	    }
#ifdef HAS_CONNECTAT
	case ACTION_CONNECTAT:
	    {
		struct sockaddr_un sunx;

		sunx.sun_family = AF_UNIX;
		strncpy(sunx.sun_path, STR(1), sizeof(sunx.sun_path) - 1);
		sunx.sun_path[sizeof(sunx.sun_path) - 1] = '\0';
		rval = socket(AF_UNIX, SOCK_STREAM, 0);
		if (rval < 0)
			break;
		rval = connectat(NUM(0), rval, (struct sockaddr *)&sunx,
		    sizeof(sunx));
		break;
	    }
#endif
	case ACTION_CHMOD:
		rval = chmod(STR(0), (mode_t)NUM(1));
		break;
	case ACTION_FCHMOD:
		rval = fchmod(NUM(0), (mode_t)NUM(1));
		break;
#ifdef HAS_LCHMOD
	case ACTION_LCHMOD:
		rval = lchmod(STR(0), (mode_t)NUM(1));
		break;
#endif
	case ACTION_FCHMODAT:
		rval = fchmodat(NUM(0), STR(1), (mode_t)NUM(2),
		    str2flags(fchmodat_flags, STR(3)));
		break;
	case ACTION_CHOWN:
		rval = chown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
		break;
	case ACTION_FCHOWN:
		rval = fchown(NUM(0), (uid_t)NUM(1), (gid_t)NUM(2));
		break;
	case ACTION_LCHOWN:
		rval = lchown(STR(0), (uid_t)NUM(1), (gid_t)NUM(2));
		break;
	case ACTION_FCHOWNAT:
		rval = fchownat(NUM(0), STR(1), (uid_t)NUM(2), (gid_t)NUM(3),
		    (int)str2flags(fchownat_flags, STR(4)));
		break;
#ifdef HAS_CHFLAGS
	case ACTION_CHFLAGS:
		rval = chflags(STR(0),
		    (unsigned long)str2flags(chflags_flags, STR(1)));
		break;
#endif
#ifdef HAS_FCHFLAGS
	case ACTION_FCHFLAGS:
		rval = fchflags(NUM(0),
		    (unsigned long)str2flags(chflags_flags, STR(1)));
		break;
#endif
#ifdef HAS_CHFLAGSAT
	case ACTION_CHFLAGSAT:
		rval = chflagsat(NUM(0), STR(1),
		    (unsigned long)str2flags(chflags_flags, STR(2)),
		    (int)str2flags(chflagsat_flags, STR(3)));
		break;
#endif
#ifdef HAS_LCHFLAGS
	case ACTION_LCHFLAGS:
		rval = lchflags(STR(0),
		    (unsigned long)str2flags(chflags_flags, STR(1)));
		break;
#endif
	case ACTION_TRUNCATE:
		rval = truncate64(STR(0), NUM(1));
		break;
	case ACTION_FTRUNCATE:
		rval = ftruncate64(NUM(0), NUM(1));
		break;
	case ACTION_STAT:
		rval = stat64(STR(0), &sb);
		if (rval == 0) {
			show_stats(&sb, STR(1));
			return (i);
		}
		break;
	case ACTION_FSTAT:
		rval = fstat64(NUM(0), &sb);
		if (rval == 0) {
			show_stats(&sb, STR(1));
			return (i);
		}
		break;
	case ACTION_LSTAT:
		rval = lstat64(STR(0), &sb);
		if (rval == 0) {
			show_stats(&sb, STR(1));
			return (i);
		}
		break;
	case ACTION_FSTATAT:
		rval = fstatat(NUM(0), STR(1), &sb,
		    (int)str2flags(fstatat_flags, STR(2)));
		if (rval == 0) {
			show_stats(&sb, STR(3));
			return (i);
		}
		break;
	case ACTION_PATHCONF:
	case ACTION_FPATHCONF:
	case ACTION_LPATHCONF:
	    {
		long lrval;

		name = str2name(pathconf_names, STR(1));
		if (name == -1) {
			fprintf(stderr, "unknown name %s", STR(1));
			exit(1);
		}
		errno = 0;
		switch (scall->sd_action) {
		case ACTION_PATHCONF:
			lrval = pathconf(STR(0), name);
			break;
		case ACTION_FPATHCONF:
			lrval = fpathconf(NUM(0), name);
			break;
		case ACTION_LPATHCONF:
			lrval = lpathconf(STR(0), name);
			break;
		default:
			abort();
		}
		if (lrval == -1 && errno == 0) {
			printf("unlimited\n");
			return (i);
		} else if (lrval >= 0) {
			printf("%ld\n", lrval);
			return (i);
		}
		rval = -1;
		break;
	    }
#ifdef HAS_FREEBSD_ACL
	case ACTION_PREPENDACL:
		rval = -1;

		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
		if (acl == NULL)
			break;

		newacl = acl_from_text(STR(1));
		if (acl == NULL)
			break;

		while (acl_get_entry(newacl, entry_id, &newentry) == 1) {
			entry_id = ACL_NEXT_ENTRY;

			if (acl_create_entry_np(&acl, &entry, 0))
				break;

			if (acl_copy_entry(entry, newentry))
				break;
		}

		rval = acl_set_file(STR(0), ACL_TYPE_NFS4, acl);
		break;
	case ACTION_READACL:
		acl = acl_get_file(STR(0), ACL_TYPE_NFS4);
		if (acl == NULL)
			rval = -1;
		else
			rval = 0;
		break;
#endif
	case ACTION_WRITE:
		rval = write(NUM(0), STR(1), strlen(STR(1)));
		break;
	default:
		fprintf(stderr, "unsupported syscall\n");
		exit(1);
	}
#undef STR
#undef NUM
	if (rval < 0) {
		const char *serrno;

		serrno = err2str(errno);
		fprintf(stderr, "%s returned %d\n", scall->sd_name, rval);
		printf("%s\n", serrno);
		exit(1);
	}
	printf("0\n");
	return (i);
}
Пример #27
0
static void
mkdir_home_parents(int dfd, const char *dir)
{
	struct stat st;
	char *dirs, *tmp;

	if (*dir != '/')
		errx(EX_DATAERR, "invalid base directory for home '%s'", dir);

	dir++;

	if (fstatat(dfd, dir, &st, 0) != -1) {
		if (S_ISDIR(st.st_mode))
			return;
		errx(EX_OSFILE, "root home `/%s' is not a directory", dir);
	}

	dirs = strdup(dir);
	if (dirs == NULL)
		errx(EX_UNAVAILABLE, "out of memory");

	tmp = strrchr(dirs, '/');
	if (tmp == NULL) {
		free(dirs);
		return;
	}
	tmp[0] = '\0';

	/*
	 * This is a kludge especially for Joerg :)
	 * If the home directory would be created in the root partition, then
	 * we really create it under /usr which is likely to have more space.
	 * But we create a symlink from cnf->home -> "/usr" -> cnf->home
	 */
	if (strchr(dirs, '/') == NULL) {
		asprintf(&tmp, "usr/%s", dirs);
		if (tmp == NULL)
			errx(EX_UNAVAILABLE, "out of memory");
		if (mkdirat(dfd, tmp, _DEF_DIRMODE) != -1 || errno == EEXIST) {
			fchownat(dfd, tmp, 0, 0, 0);
			symlinkat(tmp, dfd, dirs);
		}
		free(tmp);
	}
	tmp = dirs;
	if (fstatat(dfd, dirs, &st, 0) == -1) {
		while ((tmp = strchr(tmp + 1, '/')) != NULL) {
			*tmp = '\0';
			if (fstatat(dfd, dirs, &st, 0) == -1) {
				if (mkdirat(dfd, dirs, _DEF_DIRMODE) == -1)
					err(EX_OSFILE,  "'%s' (root home parent) is not a directory", dirs);
			}
			*tmp = '/';
		}
	}
	if (fstatat(dfd, dirs, &st, 0) == -1) {
		if (mkdirat(dfd, dirs, _DEF_DIRMODE) == -1)
			err(EX_OSFILE,  "'%s' (root home parent) is not a directory", dirs);
		fchownat(dfd, dirs, 0, 0, 0);
	}

	free(dirs);
}
Пример #28
0
static void change_group_at(const char* path, gid_t new_gid) {
  test_assert(0 == fchownat(AT_FDCWD, path, geteuid(), new_gid, 0));
}
Пример #29
0
static gboolean
checkout_file_from_input_at (OstreeRepo     *self,
                             OstreeRepoCheckoutOptions *options,
                             GFileInfo      *file_info,
                             GVariant       *xattrs,
                             GInputStream   *input,
                             int             destination_dfd,
                             const char     *destination_name,
                             GCancellable   *cancellable,
                             GError        **error)
{
  gboolean ret = FALSE;
  int res;

  if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK)
    {
      do
        res = symlinkat (g_file_info_get_symlink_target (file_info),
                         destination_dfd, destination_name);
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (res == -1)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }

      if (options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
        {
          if (G_UNLIKELY (fchownat (destination_dfd, destination_name,
                                    g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
                                    g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
                                    AT_SYMLINK_NOFOLLOW) == -1))
            {
              glnx_set_error_from_errno (error);
              goto out;
            }

          if (xattrs)
            {
              if (!glnx_dfd_name_set_all_xattrs (destination_dfd, destination_name,
                                                   xattrs, cancellable, error))
                goto out;
            }
        }
    }
  else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
    {
      g_autoptr(GOutputStream) temp_out = NULL;
      int fd;
      guint32 file_mode;

      file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
      /* Don't make setuid files on checkout when we're doing --user */
      if (options->mode == OSTREE_REPO_CHECKOUT_MODE_USER)
        file_mode &= ~(S_ISUID|S_ISGID);

      do
        fd = openat (destination_dfd, destination_name, O_WRONLY | O_CREAT | O_EXCL, file_mode);
      while (G_UNLIKELY (fd == -1 && errno == EINTR));
      if (fd == -1)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
      temp_out = g_unix_output_stream_new (fd, TRUE);
      fd = -1; /* Transfer ownership */

      if (!write_regular_file_content (self, options, temp_out, file_info, xattrs, input,
                                       cancellable, error))
        goto out;
    }
  else
    g_assert_not_reached ();
  
  ret = TRUE;
 out:
  return ret;
}
Пример #30
0
Файл: pkg_add.c Проект: hytd/pkg
static int
set_attrs(int fd, char *path, mode_t perm, uid_t uid, gid_t gid,
    const struct timespec *ats, const struct timespec *mts)
{

#ifdef HAVE_UTIMENSAT
	struct timespec times[2];

	times[0] = *ats;
	times[1] = *mts;
	if (utimensat(fd, RELATIVE_PATH(path), times,
	    AT_SYMLINK_NOFOLLOW) == -1){
		pkg_emit_error("Fail to set time on %s: %s", path,
		    strerror(errno));
		return (EPKG_FATAL);
	}
#else
	struct timeval tv[2];
	char *saved_cwd[MAXPATHLEN];

	tv[0].tv_sec = ats->tv_sec;
	tv[0].tv_usec = ats->tv_nsec / 1000;
	tv[1].tv_sec = mts->tv_sec;
	tv[1].tv_usec = mts->tv_nsec / 1000;

	memset(saved_cwd, 0, sizeof (saved_cwd));

	if (getcwd(saved_cwd, sizeof(saved_cwd) - 1) == NULL) {
		pkg_emit_error("Fail to call getcwd: %s", strerror(errno));
		return (EPKG_FATAL);
	}

	fchdir(fd);

	if (lutimes(RELATIVE_PATH(path), tv) == -1) {

		if (errno != ENOSYS) {
			pkg_emit_error("Fail to set time on %s: %s", path,
					strerror(errno));
			return (EPKG_FATAL);
		}
		else {
			/* Fallback to utimes */
			if (utimes(RELATIVE_PATH(path), tv) == -1) {
				pkg_emit_error("Fail to set time(fallback) on %s: %s", path,
						strerror(errno));
				return (EPKG_FATAL);
			}
		}
	}
	chdir(saved_cwd);
#endif

	if (getenv("INSTALL_AS_USER") == NULL) {
		if (fchownat(fd, RELATIVE_PATH(path), uid, gid,
				AT_SYMLINK_NOFOLLOW) == -1) {
			if (errno == ENOTSUP) {
				if (fchownat(fd, RELATIVE_PATH(path), uid, gid, 0) == -1) {
					pkg_emit_error("Fail to chown(fallback) %s: %s", path, strerror(errno));
					return (EPKG_FATAL);
				}
			}
			else {
				pkg_emit_error("Fail to chown %s: %s", path, strerror(errno));
				return (EPKG_FATAL);
			}
		}
	}

	/* zfs drops the setuid on fchownat */
	if (fchmodat(fd, RELATIVE_PATH(path), perm, AT_SYMLINK_NOFOLLOW) == -1) {
		if (errno == ENOTSUP) {
			if (fchmodat(fd, RELATIVE_PATH(path), perm, 0) == -1) {
				pkg_emit_error("Fail to chmod(fallback) %s: %s", path, strerror(errno));
				return (EPKG_FATAL);
			}
		}
		else {
			pkg_emit_error("Fail to chmod %s: %s", path, strerror(errno));
			return (EPKG_FATAL);
		}
	}

	return (EPKG_OK);
}