static int generate(char id[34]) { int fd; char buf[16]; char *p, *q; ssize_t k; assert(id); /* First, try reading the D-Bus machine id, unless it is a symlink */ if ((fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW)) >= 0) { k = loop_read(fd, id, 33, false); close_nointr_nofail(fd); if (k >= 32) { id[32] = '\n'; id[33] = 0; log_info("Initializing machine ID from D-Bus machine ID."); return 0; } } /* If that didn't work, generate a random machine id */ if ((fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { log_error("Failed to open /dev/urandom: %m"); return -errno; } k = loop_read(fd, buf, sizeof(buf), false); close_nointr_nofail(fd); if (k != sizeof(buf)) { log_error("Failed to read /dev/urandom: %s", strerror(k < 0 ? -k : EIO)); return k < 0 ? (int) k : -EIO; } for (p = buf, q = id; p < buf + sizeof(buf); p++, q += 2) { q[0] = hexchar(*p >> 4); q[1] = hexchar(*p & 15); } id[32] = '\n'; id[33] = 0; log_info("Initializing machine ID from random generator."); return 0; }
_public_ int sd_id128_randomize(sd_id128_t *ret) { _cleanup_close_ int fd = -1; sd_id128_t t; ssize_t k; assert_return(ret, -EINVAL); fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return -errno; k = loop_read(fd, &t, 16, false); if (k < 0) return (int) k; if (k != 16) return -EIO; /* Turn this into a valid v4 UUID, to be nice. Note that we * only guarantee this for newly generated UUIDs, not for * pre-existing ones.*/ *ret = make_v4_uuid(t); return 0; }
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) { union autofs_v5_packet_union packet; Automount *a = AUTOMOUNT(userdata); ssize_t l; int r; assert(a); assert(fd == a->pipe_fd); if (events != EPOLLIN) { log_error_unit(UNIT(a)->id, "Got invalid poll event on pipe."); goto fail; } l = loop_read(a->pipe_fd, &packet, sizeof(packet), true); if (l != sizeof(packet)) { log_error_unit(UNIT(a)->id, "Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read"); goto fail; } switch (packet.hdr.type) { case autofs_ptype_missing_direct: if (packet.v5_packet.pid > 0) { _cleanup_free_ char *p = NULL; get_process_comm(packet.v5_packet.pid, &p); log_info_unit(UNIT(a)->id, "Got automount request for %s, triggered by "PID_FMT" (%s)", a->where, packet.v5_packet.pid, strna(p)); } else log_debug_unit(UNIT(a)->id, "Got direct mount request on %s", a->where); r = set_ensure_allocated(&a->tokens, trivial_hash_func, trivial_compare_func); if (r < 0) { log_error_unit(UNIT(a)->id, "Failed to allocate token set."); goto fail; } r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token)); if (r < 0) { log_error_unit(UNIT(a)->id, "Failed to remember token: %s", strerror(-r)); goto fail; } automount_enter_runnning(a); break; default: log_error_unit(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type); break; } return 0; fail: automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); return 0; }
_public_ int sd_id128_get_boot(sd_id128_t *ret) { static __thread sd_id128_t saved_boot_id; static __thread bool saved_boot_id_valid = false; _cleanup_close_ int fd = -1; char buf[36]; ssize_t k; unsigned j; sd_id128_t t; char *p; if (!ret) return -EINVAL; if (saved_boot_id_valid) { *ret = saved_boot_id; return 0; } fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return -errno; k = loop_read(fd, buf, 36, false); if (k < 0) return (int) k; if (k != 36) return -EIO; for (j = 0, p = buf; j < 16; j++) { int a, b; if (p >= buf + k) return -EIO; if (*p == '-') p++; a = unhexchar(p[0]); b = unhexchar(p[1]); if (a < 0 || b < 0) return -EIO; t.bytes[j] = a << 4 | b; p += 2; } saved_boot_id = t; saved_boot_id_valid = true; *ret = t; return 0; }
void SopoMygga::loopRead() { int r; qDebug("LR"); m_notifier_write->setEnabled(true); r=loop_read(); if (r!=MOSQ_ERR_SUCCESS) { qWarning() << "Read fail " << r; } }
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { ssize_t n; n = loop_read(fd, buf, nbytes, do_poll); if (n < 0) return (int) n; if ((size_t) n != nbytes) return -EIO; return 0; }
int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) { char buffer[36 + 2]; ssize_t l; assert(fd >= 0); assert(f < _ID128_FORMAT_MAX); /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you * accept". */ l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */ if (l < 0) return (int) l; if (l == 0) /* empty? */ return -ENOMEDIUM; switch (l) { case 33: /* plain UUID with trailing newline */ if (buffer[32] != '\n') return -EINVAL; /* fall through */ case 32: /* plain UUID without trailing newline */ if (f == ID128_UUID) return -EINVAL; buffer[32] = 0; break; case 37: /* RFC UUID with trailing newline */ if (buffer[36] != '\n') return -EINVAL; /* fall through */ case 36: /* RFC UUID without trailing newline */ if (f == ID128_PLAIN) return -EINVAL; buffer[36] = 0; break; default: return -EINVAL; } return sd_id128_from_string(buffer, ret); }
_public_ int sd_id128_get_machine(sd_id128_t *ret) { static __thread sd_id128_t saved_machine_id; static __thread bool saved_machine_id_valid = false; _cleanup_close_ int fd = -1; char buf[33]; ssize_t k; unsigned j; sd_id128_t t; if (!ret) return -EINVAL; if (saved_machine_id_valid) { *ret = saved_machine_id; return 0; } fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return -errno; k = loop_read(fd, buf, 33, false); if (k < 0) return (int) k; if (k != 33) return -EIO; if (buf[32] !='\n') return -EIO; for (j = 0; j < 16; j++) { int a, b; a = unhexchar(buf[j*2]); b = unhexchar(buf[j*2+1]); if (a < 0 || b < 0) return -EIO; t.bytes[j] = a << 4 | b; } saved_machine_id = t; saved_machine_id_valid = true; *ret = t; return 0; }
static void do_journal_append(char *file) { struct iovec iovec[5]; int r, f, j = 0; ssize_t n; _cleanup_free_ char *bootchart_file = NULL, *bootchart_message = NULL, *p = NULL; bootchart_file = strappend("BOOTCHART_FILE=", file); if (bootchart_file) IOVEC_SET_STRING(iovec[j++], bootchart_file); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=7"); bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL); if (bootchart_message) IOVEC_SET_STRING(iovec[j++], bootchart_message); p = malloc(9 + BOOTCHART_MAX); if (!p) { r = log_oom(); return; } memcpy(p, "BOOTCHART=", 10); f = open(file, O_RDONLY); if (f < 0) { log_error("Failed to read bootchart data: %m\n"); return; } n = loop_read(f, p + 10, BOOTCHART_MAX, false); if (n < 0) { log_error("Failed to read bootchart data: %s\n", strerror(-n)); close(f); return; } close(f); iovec[j].iov_base = p; iovec[j].iov_len = 10 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error("Failed to send bootchart: %s", strerror(-r)); }
static int do_journal_append(char *file) { _cleanup_free_ char *bootchart_message = NULL; _cleanup_free_ char *bootchart_file = NULL; _cleanup_free_ char *p = NULL; _cleanup_close_ int fd = -1; struct iovec iovec[5]; int r, j = 0; ssize_t n; bootchart_file = strappend("BOOTCHART_FILE=", file); if (!bootchart_file) return log_oom(); IOVEC_SET_STRING(iovec[j++], bootchart_file); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=7"); bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL); if (!bootchart_message) return log_oom(); IOVEC_SET_STRING(iovec[j++], bootchart_message); p = malloc(10 + BOOTCHART_MAX); if (!p) return log_oom(); memcpy(p, "BOOTCHART=", 10); fd = open(file, O_RDONLY|O_CLOEXEC); if (fd < 0) return log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file); n = loop_read(fd, p + 10, BOOTCHART_MAX, false); if (n < 0) return log_error_errno(n, "Failed to read bootchart data: %m"); iovec[j].iov_base = p; iovec[j].iov_len = 10 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error_errno(r, "Failed to send bootchart: %m"); return 0; }
int main(int argc, char* argv[]) { int r, j = 0; _cleanup_free_ char *p = NULL; ssize_t n; pid_t pid; uid_t uid; gid_t gid; struct iovec iovec[14]; _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL, *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t = NULL; prctl(PR_SET_DUMPABLE, 0); if (argc != _ARG_MAX) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Invalid number of arguments passed from kernel."); r = -EINVAL; goto finish; } r = parse_pid(argv[ARG_PID], &pid); if (r < 0) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Failed to parse PID."); goto finish; } if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { /* Make sure we don't make use of the journal, * if it's the journal which is crashing */ log_set_target(LOG_TARGET_KMSG); log_open(); r = divert_coredump(); goto finish; } core_unit = strappend("COREDUMP_UNIT=", t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) core_unit = strappend("COREDUMP_USER_UNIT=", t); if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence make use of * it */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); r = parse_uid(argv[ARG_UID], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_gid(argv[ARG_GID], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]); if (core_pid) IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]); if (core_uid) IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]); if (core_gid) IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]); if (core_signal) IOVEC_SET_STRING(iovec[j++], core_signal); core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]); if (core_comm) IOVEC_SET_STRING(iovec[j++], core_comm); #ifdef HAVE_LOGIND if (sd_pid_get_session(pid, &t) >= 0) { core_session = strappend("COREDUMP_SESSION=", t); free(t); if (core_session) IOVEC_SET_STRING(iovec[j++], core_session); } #endif if (get_process_exe(pid, &t) >= 0) { core_exe = strappend("COREDUMP_EXE=", t); free(t); if (core_exe) IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strappend("COREDUMP_CMDLINE=", t); free(t); if (core_cmdline) IOVEC_SET_STRING(iovec[j++], core_cmdline); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * his uid. This also ensures that the credentials journald * will see are the ones of the coredumping user, thus making * sure the user himself gets access to the core dump. */ if (setresgid(gid, gid, gid) < 0 || setresuid(uid, uid, uid) < 0) { log_error("Failed to drop privileges: %m"); r = -errno; goto finish; } p = malloc(9 + COREDUMP_MAX); if (!p) { r = log_oom(); goto finish; } memcpy(p, "COREDUMP=", 9); n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false); if (n < 0) { log_error("Failed to read core dump data: %s", strerror(-n)); r = (int) n; goto finish; } iovec[j].iov_base = p; iovec[j].iov_len = 9 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error("Failed to send coredump: %s", strerror(-r)); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char *argv[]) { int seed_fd = -1, random_fd = -1; int ret = EXIT_FAILURE; void* buf; size_t buf_size = 0; ssize_t r; FILE *f; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); /* Read pool size, if possible */ if ((f = fopen("/proc/sys/kernel/random/poolsize", "re"))) { if (fscanf(f, "%zu", &buf_size) > 0) { /* poolsize is in bits on 2.6, but we want bytes */ buf_size /= 8; } fclose(f); } if (buf_size <= POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; if (!(buf = malloc(buf_size))) { log_error("Failed to allocate buffer."); goto finish; } if (mkdir_parents_label(RANDOM_SEED, 0755) < 0) { log_error("Failed to create directories parents of %s: %m", RANDOM_SEED); goto finish; } /* When we load the seed we read it and write it to the device * and then immediately update the saved seed with new data, * to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { if ((seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600)) < 0) { if ((seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { log_error("Failed to open random seed: %m"); goto finish; } } if ((random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600)) < 0) { if ((random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600)) < 0) { log_error("Failed to open /dev/urandom: %m"); goto finish; } } if ((r = loop_read(seed_fd, buf, buf_size, false)) <= 0) { if (r != 0) log_error("Failed to read seed file: %m"); } else { lseek(seed_fd, 0, SEEK_SET); if ((r = loop_write(random_fd, buf, (size_t) r, false)) <= 0) log_error("Failed to write seed to /dev/urandom: %s", r < 0 ? strerror(errno) : "short write"); } } else if (streq(argv[1], "save")) { if ((seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600)) < 0) { log_error("Failed to open random seed: %m"); goto finish; } if ((random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { log_error("Failed to open /dev/urandom: %m"); goto finish; } } else { log_error("Unknown verb %s.", argv[1]); goto finish; } /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ fchmod(seed_fd, 0600); fchown(seed_fd, 0, 0); if ((r = loop_read(random_fd, buf, buf_size, false)) <= 0) log_error("Failed to read new seed from /dev/urandom: %s", r < 0 ? strerror(errno) : "EOF"); else { if ((r = loop_write(seed_fd, buf, (size_t) r, false)) <= 0) log_error("Failed to write new random seed file: %s", r < 0 ? strerror(errno) : "short write"); } ret = EXIT_SUCCESS; finish: if (random_fd >= 0) close_nointr_nofail(random_fd); if (seed_fd >= 0) close_nointr_nofail(seed_fd); free(buf); return ret; }
int decompress_stream_lz4(int fdf, int fdt, off_t max_bytes) { #ifdef HAVE_LZ4 _cleanup_free_ char *buf = NULL, *out = NULL; size_t buf_size = 0; LZ4_streamDecode_t lz4_data = {}; le32_t header; size_t total_in = sizeof(header), total_out = 0; assert(fdf >= 0); assert(fdt >= 0); out = malloc(4*LZ4_BUFSIZE); if (!out) return log_oom(); for (;;) { ssize_t n, m; int r; n = read(fdf, &header, sizeof(header)); if (n < 0) return -errno; if (n != sizeof(header)) return errno ? -errno : -EIO; m = le32toh(header); if (m == 0) break; /* We refuse to use a bigger decompression buffer than * the one used for compression by 4 times. This means * that compression buffer size can be enlarged 4 * times. This can be changed, but old binaries might * not accept buffers compressed by newer binaries then. */ if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) { log_error("Compressed stream block too big: %zd bytes", m); return -EBADMSG; } total_in += sizeof(header) + m; if (!GREEDY_REALLOC(buf, buf_size, m)) return log_oom(); errno = 0; n = loop_read(fdf, buf, m, false); if (n < 0) return n; if (n != m) return errno ? -errno : -EIO; r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE); if (r <= 0) log_error("LZ4 decompression failed."); total_out += r; if (max_bytes != -1 && total_out > (size_t) max_bytes) { log_debug("Decompressed stream longer than %zd bytes", max_bytes); return -EFBIG; } n = loop_write(fdt, out, r, false); if (n < 0) return n; } log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)", total_in, total_out, (double) total_out / total_in * 100); return 0; #else log_error("Cannot decompress file. Compiled without LZ4 support."); return -EPROTONOSUPPORT; #endif }
int main(int argc, char *argv[]) { _cleanup_close_ int seed_fd = -1, random_fd = -1; bool read_seed_file, write_seed_file; _cleanup_free_ void* buf = NULL; size_t buf_size = 0; struct stat st; ssize_t k; FILE *f; int r; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); /* Read pool size, if possible */ f = fopen("/proc/sys/kernel/random/poolsize", "re"); if (f) { if (fscanf(f, "%zu", &buf_size) > 0) /* poolsize is in bits on 2.6, but we want bytes */ buf_size /= 8; fclose(f); } if (buf_size < POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; r = mkdir_parents_label(RANDOM_SEED, 0755); if (r < 0) { log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m"); goto finish; } /* When we load the seed we read it and write it to the device and then immediately update the saved seed with * new data, to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { int open_rw_error; seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); open_rw_error = -errno; if (seed_fd < 0) { write_seed_file = false; seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (seed_fd < 0) { bool missing = errno == ENOENT; log_full_errno(missing ? LOG_DEBUG : LOG_ERR, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m"); r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR, errno, "Failed to open " RANDOM_SEED " for reading: %m"); if (missing) r = 0; goto finish; } } else write_seed_file = true; random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { write_seed_file = false; random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } } read_seed_file = true; } else if (streq(argv[1], "save")) { random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); if (seed_fd < 0) { r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); goto finish; } read_seed_file = false; write_seed_file = true; } else { log_error("Unknown verb '%s'.", argv[1]); r = -EINVAL; goto finish; } if (fstat(seed_fd, &st) < 0) { r = log_error_errno(errno, "Failed to stat() seed file " RANDOM_SEED ": %m"); goto finish; } /* If the seed file is larger than what we expect, then honour the existing size and save/restore as much as it says */ if ((uint64_t) st.st_size > buf_size) buf_size = MIN(st.st_size, POOL_SIZE_MAX); buf = malloc(buf_size); if (!buf) { r = log_oom(); goto finish; } if (read_seed_file) { sd_id128_t mid; int z; k = loop_read(seed_fd, buf, buf_size, false); if (k < 0) r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m"); else if (k == 0) { r = 0; log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding."); } else { (void) lseek(seed_fd, 0, SEEK_SET); r = loop_write(random_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write seed to /dev/urandom: %m"); } /* Let's also write the machine ID into the random seed. Why? As an extra protection against "golden * images" that are put together sloppily, i.e. images which are duplicated on multiple systems but * where the random seed file is not properly reset. Frequently the machine ID is properly reset on * those systems however (simply because it's easier to notice, if it isn't due to address clashes and * so on, while random seed equivalence is generally not noticed easily), hence let's simply write the * machined ID into the random pool too. */ z = sd_id128_get_machine(&mid); if (z < 0) log_debug_errno(z, "Failed to get machine ID, ignoring: %m"); else { z = loop_write(random_fd, &mid, sizeof(mid), false); if (z < 0) log_debug_errno(z, "Failed to write machine ID to /dev/urandom, ignoring: %m"); } } if (write_seed_file) { /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ (void) fchmod(seed_fd, 0600); (void) fchown(seed_fd, 0, 0); k = loop_read(random_fd, buf, buf_size, false); if (k < 0) { r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m"); goto finish; } if (k == 0) { log_error("Got EOF while reading from /dev/urandom."); r = -EIO; goto finish; } r = loop_write(seed_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write new random seed file: %m"); } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int machine_id_setup(void) { int fd, r; bool writable; struct stat st; char id[34]; /* 32 + \n + \0 */ mode_t m; m = umask(0000); /* We create this 0444, to indicate that this isn't really * something you should ever modify. Of course, since the file * will be owned by root it doesn't matter much, but maybe * people look. */ if ((fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444)) >= 0) writable = true; else { if ((fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY)) < 0) { umask(m); log_error("Cannot open /etc/machine-id: %m"); return -errno; } writable = false; } umask(m); if (fstat(fd, &st) < 0) { log_error("fstat() failed: %m"); r = -errno; goto finish; } if (S_ISREG(st.st_mode)) { if (loop_read(fd, id, 32, false) >= 32) { r = 0; goto finish; } } /* Hmm, so, the id currently stored is not useful, then let's * generate one */ if ((r = generate(id)) < 0) goto finish; if (S_ISREG(st.st_mode) && writable) { lseek(fd, 0, SEEK_SET); if (loop_write(fd, id, 33, false) == 33) { r = 0; goto finish; } } close_nointr_nofail(fd); fd = -1; /* Hmm, we couldn't write it? So let's write it to * /run/systemd/machine-id as a replacement */ mkdir_p("/run/systemd", 0755); if ((r = write_one_line_file("/run/systemd/machine-id", id)) < 0) { log_error("Cannot write /run/systemd/machine-id: %s", strerror(-r)); unlink("/run/systemd/machine-id"); goto finish; } /* And now, let's mount it over */ r = mount("/run/systemd/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0; unlink("/run/systemd/machine-id"); if (r < 0) log_error("Failed to mount /etc/machine-id: %s", strerror(-r)); else log_info("Installed transient /etc/machine-id file."); finish: if (fd >= 0) close_nointr_nofail(fd); return r; }
int main(int argc, char *argv[]) { _cleanup_close_ int seed_fd = -1, random_fd = -1; _cleanup_free_ void* buf = NULL; size_t buf_size = 0; ssize_t k; int r, open_rw_error; FILE *f; bool refresh_seed_file = true; if (argc != 2) { log_error("This program requires one argument."); return EXIT_FAILURE; } log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); umask(0022); /* Read pool size, if possible */ f = fopen("/proc/sys/kernel/random/poolsize", "re"); if (f) { if (fscanf(f, "%zu", &buf_size) > 0) /* poolsize is in bits on 2.6, but we want bytes */ buf_size /= 8; fclose(f); } if (buf_size <= POOL_SIZE_MIN) buf_size = POOL_SIZE_MIN; buf = malloc(buf_size); if (!buf) { r = log_oom(); goto finish; } r = mkdir_parents_label(RANDOM_SEED, 0755); if (r < 0) { log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m"); goto finish; } /* When we load the seed we read it and write it to the device * and then immediately update the saved seed with new data, * to make sure the next boot gets seeded differently. */ if (streq(argv[1], "load")) { seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); open_rw_error = -errno; if (seed_fd < 0) { refresh_seed_file = false; seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (seed_fd < 0) { bool missing = errno == ENOENT; log_full_errno(missing ? LOG_DEBUG : LOG_ERR, open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m"); r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR, errno, "Failed to open " RANDOM_SEED " for reading: %m"); if (missing) r = 0; goto finish; } } random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY, 0600); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } } k = loop_read(seed_fd, buf, buf_size, false); if (k < 0) r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m"); else if (k == 0) { r = 0; log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding."); } else { (void) lseek(seed_fd, 0, SEEK_SET); r = loop_write(random_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write seed to /dev/urandom: %m"); } } else if (streq(argv[1], "save")) { seed_fd = open(RANDOM_SEED, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); if (seed_fd < 0) { r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); goto finish; } random_fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (random_fd < 0) { r = log_error_errno(errno, "Failed to open /dev/urandom: %m"); goto finish; } } else { log_error("Unknown verb '%s'.", argv[1]); r = -EINVAL; goto finish; } if (refresh_seed_file) { /* This is just a safety measure. Given that we are root and * most likely created the file ourselves the mode and owner * should be correct anyway. */ (void) fchmod(seed_fd, 0600); (void) fchown(seed_fd, 0, 0); k = loop_read(random_fd, buf, buf_size, false); if (k < 0) { r = log_error_errno(k, "Failed to read new seed from /dev/urandom: %m"); goto finish; } if (k == 0) { log_error("Got EOF while reading from /dev/urandom."); r = -EIO; goto finish; } r = loop_write(seed_fd, buf, (size_t) k, false); if (r < 0) log_error_errno(r, "Failed to write new random seed file: %m"); } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static int generate(char id[34]) { int fd, r; unsigned char *p; sd_id128_t buf; char *q; ssize_t k; const char *vm_id; assert(id); /* First, try reading the D-Bus machine id, unless it is a symlink */ fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fd >= 0) { k = loop_read(fd, id, 32, false); close_nointr_nofail(fd); if (k >= 32) { id[32] = '\n'; id[33] = 0; log_info("Initializing machine ID from D-Bus machine ID."); return 0; } } /* If that didn't work, see if we are running in qemu/kvm and a * machine ID was passed in via -uuid on the qemu/kvm command * line */ r = detect_vm(&vm_id); if (r > 0 && streq(vm_id, "kvm")) { char uuid[37]; fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fd >= 0) { k = loop_read(fd, uuid, 36, false); close_nointr_nofail(fd); if (k >= 36) { r = shorten_uuid(id, uuid); if (r >= 0) { log_info("Initializing machine ID from KVM UUID."); return 0; } } } } /* If that didn't work either, see if we are running in a * container, and a machine ID was passed in via * $container_uuid the way libvirt/LXC does it */ r = detect_container(NULL); if (r > 0) { char *e; r = getenv_for_pid(1, "container_uuid", &e); if (r > 0) { if (strlen(e) >= 36) { r = shorten_uuid(id, e); if (r >= 0) { log_info("Initializing machine ID from container UUID."); free(e); return 0; } } free(e); } } /* If that didn't work, generate a random machine id */ r = sd_id128_randomize(&buf); if (r < 0) { log_error("Failed to open /dev/urandom: %s", strerror(-r)); return r; } for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) { q[0] = hexchar(*p >> 4); q[1] = hexchar(*p & 15); } id[32] = '\n'; id[33] = 0; log_info("Initializing machine ID from random generator."); return 0; }