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; }
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) }, };
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; }
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; }
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(); }
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; }
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 }
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; }
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; }
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; }
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); }
/* * 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; }
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); } }
/* * 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; }
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; }
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; }
/* 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"); }
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; }