Beispiel #1
0
int main(int argc, char** argv) {
        const char *p = argv[1] ?: "/tmp";
        char *pattern = strjoina(p, "/systemd-test-XXXXXX");
        _cleanup_close_ int fd, fd2;
        _cleanup_free_ char *cmd, *cmd2, *ans, *ans2;

        log_set_max_level(LOG_DEBUG);
        log_parse_environment();

        fd = open_tmpfile(p, O_RDWR|O_CLOEXEC);
        assert_se(fd >= 0);

        assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0);
        (void) system(cmd);
        assert_se(readlink_malloc(cmd + 6, &ans) >= 0);
        log_debug("link1: %s", ans);
        assert_se(endswith(ans, " (deleted)"));

        fd2 = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC);
        assert_se(fd >= 0);
        assert_se(unlink(pattern) == 0);

        assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0);
        (void) system(cmd2);
        assert_se(readlink_malloc(cmd2 + 6, &ans2) >= 0);
        log_debug("link2: %s", ans2);
        assert_se(endswith(ans2, " (deleted)"));

        return 0;
}
Beispiel #2
0
int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
        _cleanup_close_pair_ int pair[2] = { -1, -1 };
        _cleanup_free_ char *us = NULL, *them = NULL;
        _cleanup_close_ int netns_fd = -1;
        Machine *m = userdata;
        const char *p;
        siginfo_t si;
        pid_t child;
        int r;

        assert(bus);
        assert(message);
        assert(m);

        r = readlink_malloc("/proc/self/ns/net", &us);
        if (r < 0)
                return sd_bus_error_set_errno(error, r);

        p = procfs_file_alloca(m->leader, "ns/net");
        r = readlink_malloc(p, &them);
        if (r < 0)
                return sd_bus_error_set_errno(error, r);

        if (streq(us, them))
                return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);

        r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
        if (r < 0)
                return sd_bus_error_set_errno(error, r);

        if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
                return sd_bus_error_set_errno(error, -errno);

        child = fork();
        if (child < 0)
                return sd_bus_error_set_errno(error, -errno);

        if (child == 0) {
                _cleanup_free_ struct local_address *addresses = NULL;
                struct local_address *a;
                int i, n;

                pair[0] = safe_close(pair[0]);

                r = namespace_enter(-1, -1, netns_fd, -1);
                if (r < 0)
                        _exit(EXIT_FAILURE);

                n = local_addresses(NULL, 0, &addresses);
                if (n < 0)
                        _exit(EXIT_FAILURE);

                for (a = addresses, i = 0; i < n; a++, i++) {
                        struct iovec iov[2] = {
                                { .iov_base = &a->family, .iov_len = sizeof(a->family) },
                                { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
                        };
Beispiel #3
0
int main(int argc, char** argv) {
        _cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL;
        _cleanup_close_ int fd = -1, fd2 = -1;
        const char *p = argv[1] ?: "/tmp";
        char *pattern;

        log_set_max_level(LOG_DEBUG);
        log_parse_environment();

        pattern = strjoina(p, "/systemd-test-XXXXXX");

        fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC);
        assert_se(fd >= 0);

        assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid_cached(), fd) > 0);
        (void) system(cmd);
        assert_se(readlink_malloc(cmd + 6, &ans) >= 0);
        log_debug("link1: %s", ans);
        assert_se(endswith(ans, " (deleted)"));

        fd2 = mkostemp_safe(pattern);
        assert_se(fd >= 0);
        assert_se(unlink(pattern) == 0);

        assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid_cached(), fd2) > 0);
        (void) system(cmd2);
        assert_se(readlink_malloc(cmd2 + 6, &ans2) >= 0);
        log_debug("link2: %s", ans2);
        assert_se(endswith(ans2, " (deleted)"));

        pattern = strjoina(p, "/tmpfiles-test");
        assert_se(tempfn_random(pattern, NULL, &d) >= 0);

        fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp);
        assert_se(fd >= 0);
        assert_se(write(fd, "foobar\n", 7) == 7);

        assert_se(touch(d) >= 0);
        assert_se(link_tmpfile(fd, tmp, d) == -EEXIST);
        assert_se(unlink(d) >= 0);
        assert_se(link_tmpfile(fd, tmp, d) >= 0);

        assert_se(read_one_line_file(d, &line) >= 0);
        assert_se(streq(line, "foobar"));
        assert_se(unlink(d) >= 0);

        return 0;
}
Beispiel #4
0
int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
        char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
        _cleanup_free_ char *s = NULL;
        const char *p;
        dev_t devnr;
        int k;

        assert(r);

        k = get_ctty_devnr(pid, &devnr);
        if (k < 0)
                return k;

        sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));

        k = readlink_malloc(fn, &s);
        if (k < 0) {

                if (k != -ENOENT)
                        return k;

                /* This is an ugly hack */
                if (major(devnr) == 136) {
                        if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
                                return -ENOMEM;
                } else {
                        /* Probably something like the ptys which have no
                         * symlink in /dev/char. Let's return something
                         * vaguely useful. */

                        b = strdup(fn + 5);
                        if (!b)
                                return -ENOMEM;
                }
        } else {
                if (startswith(s, "/dev/"))
                        p = s + 5;
                else if (startswith(s, "../"))
                        p = s + 3;
                else
                        p = s;

                b = strdup(p);
                if (!b)
                        return -ENOMEM;
        }

        *r = b;
        if (_devnr)
                *_devnr = devnr;

        return 0;
}
Beispiel #5
0
void priv_init(void)
{
  uid  = cur_uid  = getuid();
  if (!uid) under_root_login =1;
  euid = cur_euid = geteuid();
  if (!euid) can_do_root_stuff = 1;
  if (!uid) skip_priv_setting = 1;
  gid  = cur_gid  = getgid();
  egid = cur_egid = getegid();

  /* must store the /proc/self/exe symlink contents before dropping
     privs! */
  dosemu_proc_self_exe = readlink_malloc("/proc/self/exe");
  /* For Fedora we must also save a file descriptor to /proc/self/maps */
  dosemu_proc_self_maps_fd = open("/proc/self/maps", O_RDONLY);
  if (under_root_login)
  {
    /* check for sudo and set to original user */
    char *s = getenv("SUDO_GID");
    if (s) {
      gid = cur_gid = atoi(s);
      if (gid) {
        setregid(gid, egid);
      }
    }
    s = getenv("SUDO_UID");
    if (s) {
      uid = cur_uid = atoi(s);
      if (uid) {
        skip_priv_setting = under_root_login = 0;
	using_sudo = 1;
	s = getenv("SUDO_USER");
	if (s) {
	  initgroups(s, gid);
	  setenv("USER", s, 1);
	}
        setreuid(uid, euid);
      }
    }
  }
  
  if (!can_do_root_stuff)
    {
      skip_priv_setting = 1;
    }

  num_groups = getgroups(0,0);
  groups = malloc(num_groups * sizeof(gid_t));
  getgroups(num_groups,groups);

  if (!skip_priv_setting) _priv_off();
}
Beispiel #6
0
static int process_timezone(void) {
        const char *etc_localtime, *e;
        int r;

        etc_localtime = prefix_roota("/etc/localtime");
        if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
                return 0;

        if (arg_copy_timezone && arg_root) {
                _cleanup_free_ char *p = NULL;

                r = readlink_malloc("/etc/localtime", &p);
                if (r != -ENOENT) {
                        if (r < 0) {
                                log_error("Failed to read host timezone: %s", strerror(-r));
                                return r;
                        }

                        mkdir_parents(etc_localtime, 0755);
                        if (symlink(p, etc_localtime) < 0) {
                                log_error("Failed to create %s symlink: %m", etc_localtime);
                                return -errno;
                        }

                        log_info("%s copied.", etc_localtime);
                        return 0;
                }
        }

        r = prompt_timezone();
        if (r < 0)
                return r;

        if (isempty(arg_timezone))
                return 0;

        e = strappenda("../usr/share/zoneinfo/", arg_timezone);

        mkdir_parents(etc_localtime, 0755);
        if (symlink(e, etc_localtime) < 0) {
                log_error("Failed to create %s symlink: %m", etc_localtime);
                return -errno;
        }

        log_info("%s written", etc_localtime);
        return 0;
}
Beispiel #7
0
static int found_override(const char *top, const char *bottom) {
        _cleanup_free_ char *dest = NULL;
        int k;
        pid_t pid;

        assert(top);
        assert(bottom);

        if (null_or_empty_path(top) > 0) {
                notify_override_masked(top, bottom);
                return 0;
        }

        k = readlink_malloc(top, &dest);
        if (k >= 0) {
                if (equivalent(dest, bottom) > 0)
                        notify_override_equivalent(top, bottom);
                else
                        notify_override_redirected(top, bottom);

                return 0;
        }

        notify_override_overridden(top, bottom);
        if (!arg_diff)
                return 0;

        putchar('\n');

        fflush(stdout);

        pid = fork();
        if (pid < 0) {
                log_error("Failed to fork off diff: %m");
                return -errno;
        } else if (pid == 0) {
                execlp("diff", "diff", "-us", "--", bottom, top, NULL);
                log_error("Failed to execute diff: %m");
                _exit(1);
        }

        wait_for_terminate(pid, NULL);

        putchar('\n');

        return 0;
}
JAVA_OBJECT java_io_File_getLinkImpl___byte_1ARRAY(JAVA_OBJECT me, JAVA_OBJECT n1)
{
    //XMLVM_BEGIN_NATIVE[java_io_File_getLinkImpl___byte_1ARRAY]
    const char* fileName = XMLVMUtil_convertFromByteArray(n1);
    char* resolved = readlink_malloc(fileName);
    if(resolved == NULL) {
        return n1;
    } else {
	XMLVMElem _r0;
        int length = strlen(resolved);
        _r0.o = XMLVMArray_createSingleDimension(__CLASS_byte, length);
        char* data = (char*) ((org_xmlvm_runtime_XMLVMArray*) _r0.o)->fields.org_xmlvm_runtime_XMLVMArray.array_;
        XMLVM_MEMCPY(data, resolved, length);
	return _r0.o;
    }
    //XMLVM_END_NATIVE
}
Beispiel #9
0
static int found_override(const char *top, const char *bottom) {
        _cleanup_free_ char *dest = NULL;
        int k;
        pid_t pid;

        assert(top);
        assert(bottom);

        if (null_or_empty_path(top) > 0)
                return notify_override_masked(top, bottom);

        k = readlink_malloc(top, &dest);
        if (k >= 0) {
                if (equivalent(dest, bottom) > 0)
                        return notify_override_equivalent(top, bottom);
                else
                        return notify_override_redirected(top, bottom);
        }

        k = notify_override_overridden(top, bottom);
        if (!arg_diff)
                return k;

        putchar('\n');

        fflush(stdout);

        pid = fork();
        if (pid < 0)
                return log_error_errno(errno, "Failed to fork off diff: %m");
        else if (pid == 0) {

                (void) reset_all_signal_handlers();
                (void) reset_signal_mask();
                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);

                execlp("diff", "diff", "-us", "--", bottom, top, NULL);
                log_error_errno(errno, "Failed to execute diff: %m");
                _exit(EXIT_FAILURE);
        }

        wait_for_terminate_and_warn("diff", pid, false);
        putchar('\n');

        return k;
}
Beispiel #10
0
static int process_timezone(void) {
        const char *etc_localtime, *e;
        int r;

        etc_localtime = prefix_roota(arg_root, "/etc/localtime");
        if (laccess(etc_localtime, F_OK) >= 0)
                return 0;

        if (arg_copy_timezone && arg_root) {
                _cleanup_free_ char *p = NULL;

                r = readlink_malloc("/etc/localtime", &p);
                if (r != -ENOENT) {
                        if (r < 0)
                                return log_error_errno(r, "Failed to read host timezone: %m");

                        mkdir_parents(etc_localtime, 0755);
                        if (symlink(p, etc_localtime) < 0)
                                return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);

                        log_info("%s copied.", etc_localtime);
                        return 0;
                }
        }

        r = prompt_timezone();
        if (r < 0)
                return r;

        if (isempty(arg_timezone))
                return 0;

        e = strjoina("../usr/share/zoneinfo/", arg_timezone);

        mkdir_parents(etc_localtime, 0755);
        if (symlink(e, etc_localtime) < 0)
                return log_error_errno(errno, "Failed to create %s symlink: %m", etc_localtime);

        log_info("%s written", etc_localtime);
        return 0;
}
Beispiel #11
0
void priv_init(void)
{
  uid  = cur_uid  = getuid();
  if (!uid) under_root_login =1;
  euid = cur_euid = geteuid();
  if (!euid) can_do_root_stuff = 1;
  if (!uid) skip_priv_setting = 1;
  gid  = cur_gid  = getgid();
  egid = cur_egid = getegid();

  /* must store the /proc/self/exe symlink contents before dropping
     privs! */
  dosemu_proc_self_exe = readlink_malloc("/proc/self/exe");
  /* For Fedora we must also save a file descriptor to /proc/self/maps */
  dosemu_proc_self_maps_fd = open("/proc/self/maps", O_RDONLY);
  if (under_root_login)
  {
    /* check for sudo and set to original user */
    char *s = getenv("SUDO_GID");
    if (s) {
      gid = cur_gid = atoi(s);
      if (gid) {
        setregid(gid, egid);
      }
    }
    s = getenv("SUDO_UID");
    if (s) {
      uid = cur_uid = atoi(s);
      if (uid) {
	pid_t ppid;
	char *path;
	FILE *fp;
	size_t n;
	char *line;

        skip_priv_setting = under_root_login = 0;
	using_sudo = 1;
	s = getenv("SUDO_USER");
	if (s) {
	  initgroups(s, gid);
	  setenv("USER", s, 1);
	}
        setreuid(uid, euid);

	/* retrieve $HOME from sudo's (the parent process') environment */
	ppid = getppid();
	if (asprintf(&path, "/proc/%d/environ", ppid) != -1) {
	  if ((fp = fopen(path, "r"))) {
	    line = NULL;
	    while(getdelim(&line, &n, '\0', fp) != -1) {
	      if(n>5 && memcmp(line, "HOME=", 5) == 0) {
		setenv("HOME", line+5, 1);
	      }
	    }
	    free(line);
	    fclose(fp);
	  }
	  free(path);
	}
      }
    }
  }

  if (!can_do_root_stuff)
    {
      skip_priv_setting = 1;
    }

  num_groups = getgroups(0,0);
  groups = malloc(num_groups * sizeof(gid_t));
  getgroups(num_groups,groups);

  if (!skip_priv_setting) _priv_off();
}
static int node_symlink(sd_device *dev, const char *node, const char *slink) {
        _cleanup_free_ char *slink_dirname = NULL, *target = NULL;
        const char *id_filename, *slink_tmp;
        struct stat stats;
        int r;

        assert(dev);
        assert(node);
        assert(slink);

        slink_dirname = dirname_malloc(slink);
        if (!slink_dirname)
                return log_oom();

        /* use relative link */
        r = path_make_relative(slink_dirname, node, &target);
        if (r < 0)
                return log_device_error_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node);

        /* preserve link with correct target, do not replace node of other device */
        if (lstat(slink, &stats) == 0) {
                if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
                        log_device_error(dev, "Conflicting device node '%s' found, link to '%s' will not be created.", slink, node);
                        return -EOPNOTSUPP;
                } else if (S_ISLNK(stats.st_mode)) {
                        _cleanup_free_ char *buf = NULL;

                        if (readlink_malloc(slink, &buf) >= 0 &&
                            streq(target, buf)) {
                                log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target);
                                (void) label_fix(slink, LABEL_IGNORE_ENOENT);
                                (void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
                                return 0;
                        }
                }
        } else {
                log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target);
                do {
                        r = mkdir_parents_label(slink, 0755);
                        if (!IN_SET(r, 0, -ENOENT))
                                break;
                        mac_selinux_create_file_prepare(slink, S_IFLNK);
                        if (symlink(target, slink) < 0)
                                r = -errno;
                        mac_selinux_create_file_clear();
                } while (r == -ENOENT);
                if (r == 0)
                        return 0;
                if (r < 0)
                        log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink);
        }

        log_device_debug(dev, "Atomically replace '%s'", slink);
        r = device_get_id_filename(dev, &id_filename);
        if (r < 0)
                return log_device_error_errno(dev, r, "Failed to get id_filename: %m");
        slink_tmp = strjoina(slink, ".tmp-", id_filename);
        (void) unlink(slink_tmp);
        do {
                r = mkdir_parents_label(slink_tmp, 0755);
                if (!IN_SET(r, 0, -ENOENT))
                        break;
                mac_selinux_create_file_prepare(slink_tmp, S_IFLNK);
                if (symlink(target, slink_tmp) < 0)
                        r = -errno;
                mac_selinux_create_file_clear();
        } while (r == -ENOENT);
        if (r < 0)
                return log_device_error_errno(dev, r, "Failed to create symlink '%s' to '%s': %m", slink_tmp, target);

        if (rename(slink_tmp, slink) < 0) {
                r = log_device_error_errno(dev, errno, "Failed to rename '%s' to '%s' failed: %m", slink_tmp, slink);
                (void) unlink(slink_tmp);
        }

        return r;
}
Beispiel #13
0
int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
        _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
        Machine *m = userdata;
        int r;

        assert(message);
        assert(m);

        r = sd_bus_message_new_method_return(message, &reply);
        if (r < 0)
                return r;

        r = sd_bus_message_open_container(reply, 'a', "(iay)");
        if (r < 0)
                return r;

        switch (m->class) {

        case MACHINE_HOST: {
                _cleanup_free_ struct local_address *addresses = NULL;
                struct local_address *a;
                int n, i;

                n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
                if (n < 0)
                        return n;

                for (a = addresses, i = 0; i < n; a++, i++) {

                        r = sd_bus_message_open_container(reply, 'r', "iay");
                        if (r < 0)
                                return r;

                        r = sd_bus_message_append(reply, "i", addresses[i].family);
                        if (r < 0)
                                return r;

                        r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family));
                        if (r < 0)
                                return r;

                        r = sd_bus_message_close_container(reply);
                        if (r < 0)
                                return r;
                }

                break;
        }

        case MACHINE_CONTAINER: {
                _cleanup_close_pair_ int pair[2] = { -1, -1 };
                _cleanup_free_ char *us = NULL, *them = NULL;
                _cleanup_close_ int netns_fd = -1;
                const char *p;
                siginfo_t si;
                pid_t child;

                r = readlink_malloc("/proc/self/ns/net", &us);
                if (r < 0)
                        return r;

                p = procfs_file_alloca(m->leader, "ns/net");
                r = readlink_malloc(p, &them);
                if (r < 0)
                        return r;

                if (streq(us, them))
                        return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);

                r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL);
                if (r < 0)
                        return r;

                if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
                        return -errno;

                child = fork();
                if (child < 0)
                        return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");

                if (child == 0) {
                        _cleanup_free_ struct local_address *addresses = NULL;
                        struct local_address *a;
                        int i, n;

                        pair[0] = safe_close(pair[0]);

                        r = namespace_enter(-1, -1, netns_fd, -1, -1);
                        if (r < 0)
                                _exit(EXIT_FAILURE);

                        n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
                        if (n < 0)
                                _exit(EXIT_FAILURE);

                        for (a = addresses, i = 0; i < n; a++, i++) {
                                struct iovec iov[2] = {
                                        { .iov_base = &a->family, .iov_len = sizeof(a->family) },
                                        { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
                                };

                                r = writev(pair[1], iov, 2);
                                if (r < 0)
                                        _exit(EXIT_FAILURE);
                        }

                        pair[1] = safe_close(pair[1]);

                        _exit(EXIT_SUCCESS);
                }
Beispiel #14
0
/*
 * copy_symlink - copy a symlink
 *
 *	Copy a symlink from src to dst.
 *
 *	statp, mt, old_uid, new_uid, old_gid, and new_gid are used to set
 *	the access and modification and the access rights.
 *
 *	Return 0 on success, -1 on error.
 */
static int copy_symlink (const char *src, const char *dst,
                         unused bool reset_selinux,
                         const struct stat *statp, const struct timeval mt[],
                         uid_t old_uid, uid_t new_uid,
                         gid_t old_gid, gid_t new_gid)
{
    char *oldlink;

    /* copy_tree () must be the entry point */
    assert (NULL != src_orig);
    assert (NULL != dst_orig);

    /*
     * Get the name of the file which the link points
     * to.  If that name begins with the original
     * source directory name, that part of the link
     * name will be replaced with the original
     * destination directory name.
     */

    oldlink = readlink_malloc (src);
    if (NULL == oldlink) {
        return -1;
    }

    /* If src was a link to an entry of the src_orig directory itself,
     * create a link to the corresponding entry in the dst_orig
     * directory.
     */
    if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
        size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
        char *dummy = (char *) xmalloc (len);
        (void) snprintf (dummy, len, "%s%s",
                         dst_orig,
                         oldlink + strlen (src_orig));
        free (oldlink);
        oldlink = dummy;
    }

#ifdef WITH_SELINUX
    if (set_selinux_file_context (dst) != 0) {
        free (oldlink);
        return -1;
    }
#endif				/* WITH_SELINUX */
    if (   (symlink (oldlink, dst) != 0)
            || (lchown_if_needed (dst, statp,
                                  old_uid, new_uid, old_gid, new_gid) != 0)) {
        /* FIXME: there are no modes on symlinks, right?
         *        ACL could be copied, but this would be much more
         *        complex than calling perm_copy_file.
         *        Ditto for Extended Attributes.
         *        We currently only document that ACL and Extended
         *        Attributes are not copied.
         */
        free (oldlink);
        return -1;
    }
    free (oldlink);

#ifdef HAVE_LUTIMES
    /* 2007-10-18: We don't care about
     *  exit status of lutimes because
     *  it returns ENOSYS on many system
     *  - not implemented
     */
    (void) lutimes (dst, mt);
#endif				/* HAVE_LUTIMES */

    return 0;
}
Beispiel #15
0
void server_process_native_file(
                Server *s,
                int fd,
                const struct ucred *ucred,
                const struct timeval *tv,
                const char *label, size_t label_len) {

        struct stat st;
        bool sealed;
        int r;

        /* Data is in the passed fd, since it didn't fit in a
         * datagram. */

        assert(s);
        assert(fd >= 0);

        /* If it's a memfd, check if it is sealed. If so, we can just
         * use map it and use it, and do not need to copy the data
         * out. */
        sealed = memfd_get_sealed(fd) > 0;

        if (!sealed && (!ucred || ucred->uid != 0)) {
                _cleanup_free_ char *sl = NULL, *k = NULL;
                const char *e;

                /* If this is not a sealed memfd, and the peer is unknown or
                 * unprivileged, then verify the path. */

                if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
                        log_oom();
                        return;
                }

                r = readlink_malloc(sl, &k);
                if (r < 0) {
                        log_error_errno(r, "readlink(%s) failed: %m", sl);
                        return;
                }

                e = path_startswith(k, "/dev/shm/");
                if (!e)
                        e = path_startswith(k, "/tmp/");
                if (!e)
                        e = path_startswith(k, "/var/tmp/");
                if (!e) {
                        log_error("Received file outside of allowed directories. Refusing.");
                        return;
                }

                if (!filename_is_valid(e)) {
                        log_error("Received file in subdirectory of allowed directories. Refusing.");
                        return;
                }
        }

        if (fstat(fd, &st) < 0) {
                log_error_errno(errno, "Failed to stat passed file, ignoring: %m");
                return;
        }

        if (!S_ISREG(st.st_mode)) {
                log_error("File passed is not regular. Ignoring.");
                return;
        }

        if (st.st_size <= 0)
                return;

        if (st.st_size > ENTRY_SIZE_MAX) {
                log_error("File passed too large. Ignoring.");
                return;
        }

        if (sealed) {
                void *p;
                size_t ps;

                /* The file is sealed, we can just map it and use it. */

                ps = PAGE_ALIGN(st.st_size);
                p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
                if (p == MAP_FAILED) {
                        log_error_errno(errno, "Failed to map memfd, ignoring: %m");
                        return;
                }

                server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
                assert_se(munmap(p, ps) >= 0);
        } else {
                _cleanup_free_ void *p = NULL;
                struct statvfs vfs;
                ssize_t n;

                if (fstatvfs(fd, &vfs) < 0) {
                        log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m");
                        return;
                }

                /* Refuse operating on file systems that have
                 * mandatory locking enabled, see:
                 *
                 * https://github.com/systemd/systemd/issues/1822
                 */
                if (vfs.f_flag & ST_MANDLOCK) {
                        log_error("Received file descriptor from file system with mandatory locking enable, refusing.");
                        return;
                }

                /* Make the fd non-blocking. On regular files this has
                 * the effect of bypassing mandatory locking. Of
                 * course, this should normally not be necessary given
                 * the check above, but let's better be safe than
                 * sorry, after all NFS is pretty confusing regarding
                 * file system flags, and we better don't trust it,
                 * and so is SMB. */
                r = fd_nonblock(fd, true);
                if (r < 0) {
                        log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m");
                        return;
                }

                /* The file is not sealed, we can't map the file here, since
                 * clients might then truncate it and trigger a SIGBUS for
                 * us. So let's stupidly read it */

                p = malloc(st.st_size);
                if (!p) {
                        log_oom();
                        return;
                }

                n = pread(fd, p, st.st_size, 0);
                if (n < 0)
                        log_error_errno(errno, "Failed to read file, ignoring: %m");
                else if (n > 0)
                        server_process_native_message(s, p, n, ucred, tv, label, label_len);
        }
}
Beispiel #16
0
/*
 * copy_symlink - copy a symlink
 *
 *	Copy a symlink from src to dst.
 *
 *	statp, mt, uid, gid are used to set the access and modification and the
 *	access rights.
 *
 *	Return 0 on success, -1 on error.
 */
static int copy_symlink (const char *src, const char *dst,
                         const struct stat *statp, const struct timeval mt[],
                         long int uid, long int gid)
{
	char *oldlink;

	/* copy_tree () must be the entry point */
	assert (NULL != src_orig);
	assert (NULL != dst_orig);

	/*
	 * Get the name of the file which the link points
	 * to.  If that name begins with the original
	 * source directory name, that part of the link
	 * name will be replaced with the original
	 * destination directory name.
	 */

	oldlink = readlink_malloc (src);
	if (NULL == oldlink) {
		return -1;
	}

	/* If src was a link to an entry of the src_orig directory itself,
	 * create a link to the corresponding entry in the dst_orig
	 * directory.
	 * FIXME: This may change a relative link to an absolute link
	 */
	if (strncmp (oldlink, src_orig, strlen (src_orig)) == 0) {
		size_t len = strlen (dst_orig) + strlen (oldlink) - strlen (src_orig) + 1;
		char *dummy = (char *) malloc (len);
		snprintf (dummy, len, "%s%s",
		          dst_orig,
		          oldlink + strlen (src_orig));
		free (oldlink);
		oldlink = dummy;
	}

#ifdef WITH_SELINUX
	selinux_file_context (dst);
#endif
	if (   (symlink (oldlink, dst) != 0)
	    || (lchown (dst,
	                (uid == -1) ? statp->st_uid : (uid_t) uid,
	                (gid == -1) ? statp->st_gid : (gid_t) gid) != 0)) {
		free (oldlink);
		return -1;
	}
	free (oldlink);

#ifdef HAVE_LUTIMES
	/* 2007-10-18: We don't care about
	 *  exit status of lutimes because
	 *  it returns ENOSYS on many system
	 *  - not implemented
	 */
	lutimes (dst, mt);
#endif

	return 0;
}
Beispiel #17
0
static int create_item(Item *i) {
        int r, e;
        mode_t u;
        struct stat st;

        assert(i);

        switch (i->type) {

        case IGNORE_PATH:
        case IGNORE_DIRECTORY_PATH:
        case REMOVE_PATH:
        case RECURSIVE_REMOVE_PATH:
                return 0;

        case CREATE_FILE:
        case TRUNCATE_FILE:
                r = write_one_file(i, i->path);
                if (r < 0)
                        return r;
                break;
        case WRITE_FILE:
                r = glob_item(i, write_one_file);
                if (r < 0)
                        return r;

                break;

        case TRUNCATE_DIRECTORY:
        case CREATE_DIRECTORY:

                u = umask(0);
                mkdir_parents_label(i->path, 0755);
                r = mkdir(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create directory %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISDIR(st.st_mode)) {
                        log_error("%s is not a directory.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_FIFO:

                u = umask(0);
                r = mkfifo(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create fifo %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISFIFO(st.st_mode)) {
                        log_error("%s is not a fifo.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_SYMLINK: {
                char *x;

                label_context_set(i->path, S_IFLNK);
                r = symlink(i->argument, i->path);
                e = errno;
                label_context_clear();
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
                        return -errno;
                }

                r = readlink_malloc(i->path, &x);
                if (r < 0) {
                        log_error("readlink(%s) failed: %s", i->path, strerror(-r));
                        return -errno;
                }

                if (!streq(i->argument, x)) {
                        free(x);
                        log_error("%s is not the right symlinks.", i->path);
                        return -EEXIST;
                }

                free(x);
                break;
        }

        case CREATE_BLOCK_DEVICE:
        case CREATE_CHAR_DEVICE: {
                mode_t file_type;

                if (have_effective_cap(CAP_MKNOD) == 0) {
                        /* In a container we lack CAP_MKNOD. We
                        shouldnt attempt to create the device node in
                        that case to avoid noise, and we don't support
                        virtualized devices in containers anyway. */

                        log_debug("We lack CAP_MKNOD, skipping creation of device node %s.", i->path);
                        return 0;
                }

                file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);

                u = umask(0);
                label_context_set(i->path, file_type);
                r = mknod(i->path, i->mode | file_type, i->major_minor);
                e = errno;
                label_context_clear();
                umask(u);
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create device node %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if ((st.st_mode & S_IFMT) != file_type) {
                        log_error("%s is not a device node.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;
        }

        case RELABEL_PATH:

                r = glob_item(i, item_set_perms);
                if (r < 0)
                        return 0;
                break;

        case RECURSIVE_RELABEL_PATH:

                r = glob_item(i, recursive_relabel);
                if (r < 0)
                        return r;
        }

        log_debug("%s created successfully.", i->path);

        return 0;
}
Beispiel #18
0
static int import_tar(int argc, char *argv[], void *userdata) {
        _cleanup_(tar_import_unrefp) TarImport *import = NULL;
        _cleanup_event_unref_ sd_event *event = NULL;
        const char *path = NULL, *local = NULL;
        _cleanup_free_ char *ll = NULL;
        _cleanup_close_ int open_fd = -1;
        int r, fd;

        if (argc >= 2)
                path = argv[1];
        if (isempty(path) || streq(path, "-"))
                path = NULL;

        if (argc >= 3)
                local = argv[2];
        else if (path)
                local = basename(path);
        if (isempty(local) || streq(local, "-"))
                local = NULL;

        if (local) {
                r = tar_strip_suffixes(local, &ll);
                if (r < 0)
                        return log_oom();

                local = ll;

                if (!machine_name_is_valid(local)) {
                        log_error("Local image name '%s' is not valid.", local);
                        return -EINVAL;
                }

                if (!arg_force) {
                        r = image_find(local, NULL);
                        if (r < 0)
                                return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local);
                        else if (r > 0) {
                                log_error_errno(EEXIST, "Image '%s' already exists.", local);
                                return -EEXIST;
                        }
                }
        } else
                local = "imported";

        if (path) {
                open_fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
                if (open_fd < 0)
                        return log_error_errno(errno, "Failed to open tar image to import: %m");

                fd = open_fd;

                log_info("Importing '%s', saving as '%s'.", path, local);
        } else {
                _cleanup_free_ char *pretty = NULL;

                fd = STDIN_FILENO;

                (void) readlink_malloc("/proc/self/fd/0", &pretty);
                log_info("Importing '%s', saving as '%s'.", strna(pretty), local);
        }

        r = sd_event_default(&event);
        if (r < 0)
                return log_error_errno(r, "Failed to allocate event loop: %m");

        assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
        (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler,  NULL);
        (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL);

        r = tar_import_new(&import, event, arg_image_root, on_tar_finished, event);
        if (r < 0)
                return log_error_errno(r, "Failed to allocate importer: %m");

        r = tar_import_start(import, fd, local, arg_force, arg_read_only);
        if (r < 0)
                return log_error_errno(r, "Failed to import image: %m");

        r = sd_event_loop(event);
        if (r < 0)
                return log_error_errno(r, "Failed to run event loop: %m");

        log_info("Exiting.");
        return -r;
}
Beispiel #19
0
/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */
static int mount_legacy_cgns_unsupported(
                const char *dest,
                CGroupUnified unified_requested,
                bool userns,
                uid_t uid_shift,
                uid_t uid_range,
                const char *selinux_apifs_context) {

        _cleanup_set_free_free_ Set *controllers = NULL;
        const char *cgroup_root;
        int r;

        cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");

        (void) mkdir_p(cgroup_root, 0755);

        /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
        r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
        if (r < 0)
                return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
        if (r == 0) {
                _cleanup_free_ char *options = NULL;

                r = tmpfs_patch_options("mode=755", uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
                if (r < 0)
                        return log_oom();

                r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
                                  MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
                if (r < 0)
                        return r;
        }

        r = cg_all_unified();
        if (r < 0)
                return r;
        if (r > 0)
                goto skip_controllers;

        r = cg_kernel_controllers(&controllers);
        if (r < 0)
                return log_error_errno(r, "Failed to determine cgroup controllers: %m");

        for (;;) {
                _cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;

                controller = set_steal_first(controllers);
                if (!controller)
                        break;

                origin = prefix_root("/sys/fs/cgroup/", controller);
                if (!origin)
                        return log_oom();

                r = readlink_malloc(origin, &combined);
                if (r == -EINVAL) {
                        /* Not a symbolic link, but directly a single cgroup hierarchy */

                        r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true);
                        if (r < 0)
                                return r;

                } else if (r < 0)
                        return log_error_errno(r, "Failed to read link %s: %m", origin);
                else {
                        _cleanup_free_ char *target = NULL;

                        target = prefix_root(dest, origin);
                        if (!target)
                                return log_oom();

                        /* A symbolic link, a combination of controllers in one hierarchy */

                        if (!filename_is_valid(combined)) {
                                log_warning("Ignoring invalid combined hierarchy %s.", combined);
                                continue;
                        }

                        r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true);
                        if (r < 0)
                                return r;

                        r = symlink_idempotent(combined, target, false);
                        if (r == -EINVAL)
                                return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
                        if (r < 0)
                                return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
                }
        }

skip_controllers:
        if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
                r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
                if (r < 0)
                        return r;
        }

        r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
        if (r < 0)
                return r;

        return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
                             MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
}
Beispiel #20
0
static int create_item(Item *i) {
        int r, e;
        mode_t u;
        struct stat st;

        assert(i);

        switch (i->type) {

        case IGNORE_PATH:
        case REMOVE_PATH:
        case RECURSIVE_REMOVE_PATH:
                return 0;

        case CREATE_FILE:
        case TRUNCATE_FILE:
        case WRITE_FILE: {
                int fd, flags;

                flags = i->type == CREATE_FILE ? O_CREAT|O_APPEND :
                        i->type == TRUNCATE_FILE ? O_CREAT|O_TRUNC : 0;

                u = umask(0);
                label_context_set(i->path, S_IFREG);
                fd = open(i->path, flags|O_NDELAY|O_CLOEXEC|O_WRONLY|O_NOCTTY|O_NOFOLLOW, i->mode);
                e = errno;
                label_context_clear();
                umask(u);
                errno = e;

                if (fd < 0) {
                        if (i->type == WRITE_FILE && errno == ENOENT)
                                break;

                        log_error("Failed to create file %s: %m", i->path);
                        return -errno;
                }

                if (i->argument) {
                        ssize_t n;
                        size_t l;
                        struct iovec iovec[2];
                        static const char new_line = '\n';

                        l = strlen(i->argument);

                        zero(iovec);
                        iovec[0].iov_base = i->argument;
                        iovec[0].iov_len = l;

                        iovec[1].iov_base = (void*) &new_line;
                        iovec[1].iov_len = 1;

                        n = writev(fd, iovec, 2);

                        /* It's OK if we don't write the trailing
                         * newline, hence we check for l, instead of
                         * l+1 here. Files in /sys often refuse
                         * writing of the trailing newline. */
                        if (n < 0 || (size_t) n < l) {
                                log_error("Failed to write file %s: %s", i->path, n < 0 ? strerror(-n) : "Short write");
                                close_nointr_nofail(fd);
                                return n < 0 ? n : -EIO;
                        }
                }

                close_nointr_nofail(fd);

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISREG(st.st_mode)) {
                        log_error("%s is not a file.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;
        }

        case TRUNCATE_DIRECTORY:
        case CREATE_DIRECTORY:

                u = umask(0);
                mkdir_parents_label(i->path, 0755);
                r = mkdir(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create directory %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISDIR(st.st_mode)) {
                        log_error("%s is not a directory.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_FIFO:

                u = umask(0);
                r = mkfifo(i->path, i->mode);
                umask(u);

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create fifo %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if (!S_ISFIFO(st.st_mode)) {
                        log_error("%s is not a fifo.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;

        case CREATE_SYMLINK: {
                char *x;

                label_context_set(i->path, S_IFLNK);
                r = symlink(i->argument, i->path);
                e = errno;
                label_context_clear();
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("symlink(%s, %s) failed: %m", i->argument, i->path);
                        return -errno;
                }

                r = readlink_malloc(i->path, &x);
                if (r < 0) {
                        log_error("readlink(%s) failed: %s", i->path, strerror(-r));
                        return -errno;
                }

                if (!streq(i->argument, x)) {
                        free(x);
                        log_error("%s is not the right symlinks.", i->path);
                        return -EEXIST;
                }

                free(x);
                break;
        }

        case CREATE_BLOCK_DEVICE:
        case CREATE_CHAR_DEVICE: {
                mode_t file_type = (i->type == CREATE_BLOCK_DEVICE ? S_IFBLK : S_IFCHR);

                u = umask(0);
                label_context_set(i->path, file_type);
                r = mknod(i->path, i->mode | file_type, i->major_minor);
                e = errno;
                label_context_clear();
                umask(u);
                errno = e;

                if (r < 0 && errno != EEXIST) {
                        log_error("Failed to create device node %s: %m", i->path);
                        return -errno;
                }

                if (stat(i->path, &st) < 0) {
                        log_error("stat(%s) failed: %m", i->path);
                        return -errno;
                }

                if ((st.st_mode & S_IFMT) != file_type) {
                        log_error("%s is not a device node.", i->path);
                        return -EEXIST;
                }

                r = item_set_perms(i, i->path);
                if (r < 0)
                        return r;

                break;
        }

        case RELABEL_PATH:

                r = glob_item(i, item_set_perms);
                if (r < 0)
                        return 0;
                break;

        case RECURSIVE_RELABEL_PATH:

                r = glob_item(i, recursive_relabel);
                if (r < 0)
                        return r;
        }

        log_debug("%s created successfully.", i->path);

        return 0;
}